diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..c34a5754a3fde8ad1ff6e128781c88d1144b32b8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,40 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text +apps/ckpts/InstantMeshes filter=lfs diff=lfs merge=lfs -text +apps/third_party/Wonder3D/assets/fig_teaser.png filter=lfs diff=lfs merge=lfs -text +asset/video_cover.png filter=lfs diff=lfs merge=lfs -text +apps/InstantMeshes filter=lfs diff=lfs merge=lfs -text +apps/third_party/InstantMeshes filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..681f9d0b268f9fb82b9bf4088ce7bf224176aa62 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +gradio_cached_dir \ No newline at end of file diff --git a/README.md b/README.md new file mode 100755 index 0000000000000000000000000000000000000000..a2052e199c34c1db63be01f2362e358bda99f302 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +--- +title: 'CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner' +emoji: 🚀 +colorFrom: indigo +colorTo: pink +sdk: gradio +sdk_version: 4.31.5 +app_file: gradio_app.py +pinned: false +license: agpl-3.0 +--- \ No newline at end of file diff --git a/README_zh.md b/README_zh.md new file mode 100755 index 0000000000000000000000000000000000000000..0bfdf58424df709d44acbac6d2bfae1b81987e9b --- /dev/null +++ b/README_zh.md @@ -0,0 +1,173 @@ +

+ +

+ +###
匠心:基于3D原生扩模型和交互式几何优化的高质量网格模型生成
+#####

[Weiyu Li1,2](https://wyysf-98.github.io/), Jiarui Liu1,2, [Rui Chen1,2](https://aruichen.github.io/), [Yixun Liang3,2g](https://yixunliang.github.io/), [Xuelin Chen4](https://xuelin-chen.github.io/), [Ping Tan1,2](https://ece.hkust.edu.hk/pingtan), [Xiaoxiao Long5](https://www.xxlong.site/)

+#####

1香港科技大学, 2光影幻象, 3香港科技大学(广州), 4腾讯 AI Lab, 5香港大学

+
+   +   +   +
+ +#### TL; DR: **CraftsMan (又名 匠心)** 是一个两阶段的文本/图像到3D网格生成模型。通过模仿艺术家/工匠的建模工作流程,我们提出首先使用3D扩散模型生成一个具有平滑几何形状的粗糙网格(5秒),然后使用2D法线扩散生成的增强型多视图法线图进行细化(20秒),这也可以通过类似Zbrush的交互方式进行。 + + +## ✨ 总览 +这个仓库包含了我们3D网格生成项目的源代码(训练/推理)、预训练权重和gradio演示代码,你可以在我们的[项目页面](https://github.com/Craftsman3D.github.io/)找到更多的可视化内容。如果你有高质量的3D数据或其他想法,我们非常欢迎任何形式的合作。 +
完整摘要 +我们提出了一个新颖的3D建模系统,匠心。它可以生成具有多样形状、规则网格拓扑和光滑表面的高保真3D几何,并且值得注意的是,它可以和人工建模流程一样以交互方式细化几何体。尽管3D生成领域取得了显著进展,但现有方法仍然难以应对漫长的优化过程、不规则的网格拓扑、嘈杂的表面以及难以适应用户编辑的问题,因此阻碍了它们在3D建模软件中的广泛采用和实施。我们的工作受到工匠建模的启发,他们通常会首先粗略地勾勒出作品的整体形状,然后详细描绘表面细节。具体来说,我们采用了一个3D原生扩散模型,该模型在从基于潜在集的3D表示学习到的潜在空间上操作,只需几秒钟就可以生成具有规则网格拓扑的粗糙几何体。特别是,这个过程以文本提示或参考图像作为输入,并利用强大的多视图(MV)二维扩散模型生成粗略几何体的多个视图,这些视图被输入到我们的多视角条件3D扩散模型中,用于生成3D几何,显著提高其了鲁棒性和泛化能力。随后,使用基于法线的几何细化器显著增强表面细节。这种细化可以自动执行,或者通过用户提供的编辑以交互方式进行。广泛的实验表明,我们的方法在生成优于现有方法的高质量3D资产方面十分高效。 +
+ +

+ +

+ + +## 内容 +* [视频](#Video) +* [预训练模型](##-Pretrained-models) +* [Gradio & Huggingface 示例](#Gradio-demo) +* [推理代码](#Inference) +* [训练代码](#Train) +* [数据准备](#data) +* [致谢](#Acknowledgements) +* [引用](#Bibtex) + +## 环境搭建 + +
硬件 +我们在32个A800 GPU上以每GPU 32的批量大小训练模型,训练了7天。 + +网格细化部分在GTX 3080 GPU上执行。 + + +
+
运行环境搭建 + +:smiley: 为了方便使用,我们提供了docker镜像文件[Setup using Docker](./docker/README.md). + + - Python 3.10.0 + - PyTorch 2.1.0 + - Cuda Toolkit 11.8.0 + - Ubuntu 22.04 + +克隆这个仓库. + +```sh +git clone git@github.com:wyysf-98/CraftsMan.git +``` + +安装所需要的依赖包. + +```sh +conda create -n CraftsMan python=3.10 +conda activate CraftsMan +conda install -c pytorch pytorch=2.3.0 torchvision=0.18.0 cudatoolkit=11.8 && \ +pip install -r docker/requirements.txt +``` + +
+ + +# 🎥 视频 + +[![观看视频](asset/video_cover.png)](https://www.youtube.com/watch?v=WhEs4tS4mGo) + + +# 三维原生扩散模型 (Latent Set Diffusion Model) +我们在这里提供了训练和推理代码,以便于未来的研究。 +The latent set diffusion model 在很大程度上基于[Michelangelo](https://github.com/NeuralCarver/Michelangelo), +采用了 [perceiver](https://github.com/google-deepmind/deepmind-research/blob/master/perceiver/perceiver.py) 架构,并且参数量仅为104M. + +## 预训练模型 +目前,我们提供了以4视图图像作为条件,并通过ModLN将相机信息注入到clip特征提取器的模型。 +我们将根据实际情况考虑开源进一步的模型。 + +我们的推理脚本将自动下载模型。或者,您可以手动下载模型并将它们放在ckpts/目录下。 + + +## Gradio 示例 +我们提供了不同的文本/图像到多视角图像扩散模型的gradio演示,例如[CRM](https://github.com/thu-ml/CRM), [Wonder3D](https://github.com/xxlong0/Wonder3D/) and [LGM](https://github.com/3DTopia/LGM). 您可以选择不同的模型以获得更好的结果。要在本地机器上运行gradio演示,请简单运行: + +```bash +python app/ +``` + +## 模型推理 +要通过命令行从图像文件夹生成3D网格,简单运行: + +```bash +python launch.py --config .configs/image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6.yaml \ + --validate --gpu 0 +``` +我们默认使用 [rembg](https://github.com/danielgatis/rembg) 来通过前景对象分割。如果输入图像已经有alpha蒙版,请指定no_rembg标志符: + +如果您有其他视图的图像(左,右,背面),您可以通过下面指令指定图像: + + +## 从头开始训练 +我们提供了我们的训练代码以方便未来的研究。我们将在接下来的几天内提供少量的数据样本。 +有关更多的训练细节和配置,请参考configs文件夹。 + +```bash +### training the shape-autoencoder +python launch.py --config ./configs/shape-autoencoder/l256-e64-ne8-nd16.yaml \ + --train --gpu 0 + +### training the image-to-shape diffusion model +python launch.py --config .configs/image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6.yaml \ + --train --gpu 0 + +``` + +# 2D法线增强扩散模型(即将推出) + +我们正在努力发布我们的三维网格细化代码。感谢您的耐心等待,我们将为这个激动人心的发展做最后的努力。" 🔧🚀 + +您也可以在视频中找到网格细化部分的结果。 + + +# ❓常见问题 +问题: 如何获得更好的结果? +1. 匠心模型将多视图图像作为3D扩散模型的条件。通过我们的实验,与像([Wonder3D](https://github.com/xxlong0/Wonder3D/), [InstantMesh](https://github.com/TencentARC/InstantMesh/tree/main))这样的重建模型相比, 我们的方法对多视图不一致性更加稳健。由于我们依赖图像到MV模型,输入图像的面对方向非常重要,并且总是会导致良好的重建。 +2. 如果您有自己的多视图图像,这将是一个不错的选择来 +3. 就像2D扩散模型一样,尝试不同的随机数种子,调整CFG比例或不同的调度器。 +4. 我们将在后期考虑提供一个以文本提示为条件的版本,因此您可以使用一些正面和负面的提示。 + + +# 💪 待办事项 + +- [x] 推理代码 +- [x] 训练代码 +- [x] Gradio & Hugging Face演示 +- [x] 模型库,我们将在未来发布更多的ckpt +- [ ] 环境设置 +- [ ] 数据样本 +- [ ] Google Colab示例 +- [ ] 网格细化代码 + + +# 🤗 致谢 + +- 感谢[光影幻像](https://www.lightillusions.com/)提供计算资源和潘建雄进行数据预处理。如果您对高质量的3D生成有任何想法,欢迎与我们联系! +- Thanks to [Hugging Face](https://github.com/huggingface) for sponsoring the nicely demo! +- Thanks to [3DShape2VecSet](https://github.com/1zb/3DShape2VecSet/tree/master) for their amazing work, the latent set representation provides an efficient way to represent 3D shape! +- Thanks to [Michelangelo](https://github.com/NeuralCarver/Michelangelo) for their great work, our model structure is heavily build on this repo! +- Thanks to [CRM](https://github.com/thu-ml/CRM), [Wonder3D](https://github.com/xxlong0/Wonder3D/) and [LGM](https://github.com/3DTopia/LGM) for their released model about multi-view images generation. If you have a more advanced version and want to contribute to the community, we are welcome to update. +- 感谢 [Objaverse](https://objaverse.allenai.org/), [Objaverse-MIX](https://huggingface.co/datasets/BAAI/Objaverse-MIX/tree/main) 开源的数据,这帮助我们进行了许多验证实验。 +- 感谢 [ThreeStudio](https://github.com/threestudio-project/threestudio) 实现了一个完整的框架,我们参考他们出色且易于使用的代码结构。 + +# 📑许可证 +CraftsMan在[AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html)下,因此任何包含CraftsMan代码或训练模型(无论是预训练还是自定义训练)的下游解决方案和产品(包括云服务)都应该是开源的,以符合AGPL的条件。如果您对CraftsMan的使用有任何疑问,请先与我们联系。 + +# 📖 BibTeX + + @misc{li2024craftsman, + title = {CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner}, + author = {Weiyu Li and Jiarui Liu and Rui Chen and Yixun Liang and Xuelin Chen and Ping Tan and Xiaoxiao Long}, + year = {2024}, + archivePrefix = {arXiv}, + primaryClass = {cs.CG} + } diff --git a/apps/.vscode/launch.json b/apps/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..6b76b4fabc20a488b0a750c32ea100719ca322d1 --- /dev/null +++ b/apps/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Current File", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/apps/__pycache__/mv_models.cpython-310.pyc b/apps/__pycache__/mv_models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41f91e76e35983274f95b061a40d06c4746aa6b1 Binary files /dev/null and b/apps/__pycache__/mv_models.cpython-310.pyc differ diff --git a/apps/__pycache__/mv_models.cpython-38.pyc b/apps/__pycache__/mv_models.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ad6b37d624aa233fdefeb9092eb243e73789b93 Binary files /dev/null and b/apps/__pycache__/mv_models.cpython-38.pyc differ diff --git a/apps/__pycache__/utils.cpython-310.pyc b/apps/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..afb65e7ae5c432f4ccbc2f14bb7e74428df1f2b4 Binary files /dev/null and b/apps/__pycache__/utils.cpython-310.pyc differ diff --git a/apps/__pycache__/utils.cpython-38.pyc b/apps/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8d9b87e7e872d2dfb225b85bb91461656daf214 Binary files /dev/null and b/apps/__pycache__/utils.cpython-38.pyc differ diff --git a/apps/examples/1_cute_girl.webp b/apps/examples/1_cute_girl.webp new file mode 100644 index 0000000000000000000000000000000000000000..648206b5aa91124707cd5513bcc6ed8e866e1de6 Binary files /dev/null and b/apps/examples/1_cute_girl.webp differ diff --git a/apps/examples/blue_monster.webp b/apps/examples/blue_monster.webp new file mode 100644 index 0000000000000000000000000000000000000000..7204f5fa63d86843269210c306488444e0efafe1 Binary files /dev/null and b/apps/examples/blue_monster.webp differ diff --git a/apps/examples/boy.webp b/apps/examples/boy.webp new file mode 100644 index 0000000000000000000000000000000000000000..ddffb99f48504aa5a890d676a48f39236a004631 Binary files /dev/null and b/apps/examples/boy.webp differ diff --git a/apps/examples/boy2.webp b/apps/examples/boy2.webp new file mode 100644 index 0000000000000000000000000000000000000000..a2e1615efd6ca3f87aac3f43884666b85a804dc4 Binary files /dev/null and b/apps/examples/boy2.webp differ diff --git a/apps/examples/bulldog.webp b/apps/examples/bulldog.webp new file mode 100644 index 0000000000000000000000000000000000000000..318fcf22cf756b31e25364f8fe28a3852c72fc9c Binary files /dev/null and b/apps/examples/bulldog.webp differ diff --git a/apps/examples/catman.webp b/apps/examples/catman.webp new file mode 100644 index 0000000000000000000000000000000000000000..5dd68d7308d4785f314e976561facc43e9d9e53a Binary files /dev/null and b/apps/examples/catman.webp differ diff --git a/apps/examples/cyberpunk_man.webp b/apps/examples/cyberpunk_man.webp new file mode 100644 index 0000000000000000000000000000000000000000..4c609f49d6dcfcb93d11c85b675fe1b0641300c9 Binary files /dev/null and b/apps/examples/cyberpunk_man.webp differ diff --git a/apps/examples/dinosaur_boy.webp b/apps/examples/dinosaur_boy.webp new file mode 100644 index 0000000000000000000000000000000000000000..afd68e6205bba8dc5dd178ec8dcd0a6fd24287bb Binary files /dev/null and b/apps/examples/dinosaur_boy.webp differ diff --git a/apps/examples/dog.webp b/apps/examples/dog.webp new file mode 100644 index 0000000000000000000000000000000000000000..47fdee13499f2669bd008433936edbe8ed4db0a7 Binary files /dev/null and b/apps/examples/dog.webp differ diff --git a/apps/examples/doraemon.webp b/apps/examples/doraemon.webp new file mode 100644 index 0000000000000000000000000000000000000000..b5923198c1a6d3da835f9d9f6299ad8f3ad81732 Binary files /dev/null and b/apps/examples/doraemon.webp differ diff --git a/apps/examples/dragon.webp b/apps/examples/dragon.webp new file mode 100644 index 0000000000000000000000000000000000000000..2debdc5f7c546e8830ee6f79b7470edc43aff33a Binary files /dev/null and b/apps/examples/dragon.webp differ diff --git a/apps/examples/elf.webp b/apps/examples/elf.webp new file mode 100644 index 0000000000000000000000000000000000000000..ec483a7a23edec5d4c88ec7f49e6c76e5f257a24 Binary files /dev/null and b/apps/examples/elf.webp differ diff --git a/apps/examples/ghost-eating-burger.webp b/apps/examples/ghost-eating-burger.webp new file mode 100644 index 0000000000000000000000000000000000000000..34d32f31dc8161d6eba92f9a33a4afc518abf669 Binary files /dev/null and b/apps/examples/ghost-eating-burger.webp differ diff --git a/apps/examples/girl1.webp b/apps/examples/girl1.webp new file mode 100644 index 0000000000000000000000000000000000000000..3e42bbdffd07d3a5449399e4c2e229d3cd1da7ec Binary files /dev/null and b/apps/examples/girl1.webp differ diff --git a/apps/examples/gun.webp b/apps/examples/gun.webp new file mode 100644 index 0000000000000000000000000000000000000000..589c5391e53bb89c98673d5b2b2e0d76677bcb32 Binary files /dev/null and b/apps/examples/gun.webp differ diff --git a/apps/examples/kunkun.webp b/apps/examples/kunkun.webp new file mode 100644 index 0000000000000000000000000000000000000000..a0c45d3c7091cdad8ef69374a9cbd065353e7982 Binary files /dev/null and b/apps/examples/kunkun.webp differ diff --git a/apps/examples/link.webp b/apps/examples/link.webp new file mode 100644 index 0000000000000000000000000000000000000000..1b5bcfc99fd3e2e6d674b5c877f4128109355900 Binary files /dev/null and b/apps/examples/link.webp differ diff --git a/apps/examples/mushroom1.webp b/apps/examples/mushroom1.webp new file mode 100644 index 0000000000000000000000000000000000000000..bc41abe7d5113bb147a85fdb4f5b8f2d8e1e3851 Binary files /dev/null and b/apps/examples/mushroom1.webp differ diff --git a/apps/examples/mushroom2.webp b/apps/examples/mushroom2.webp new file mode 100644 index 0000000000000000000000000000000000000000..08d870a503df6970534797730f7e429e57a84ab8 Binary files /dev/null and b/apps/examples/mushroom2.webp differ diff --git a/apps/examples/pikachu.webp b/apps/examples/pikachu.webp new file mode 100644 index 0000000000000000000000000000000000000000..0c314f13f56e10968cfc67b194a51e48e934ed2d Binary files /dev/null and b/apps/examples/pikachu.webp differ diff --git a/apps/examples/plants.webp b/apps/examples/plants.webp new file mode 100644 index 0000000000000000000000000000000000000000..73816008cc72abea18705e8f7c565f1fc57ccf1a Binary files /dev/null and b/apps/examples/plants.webp differ diff --git a/apps/examples/rose.webp b/apps/examples/rose.webp new file mode 100644 index 0000000000000000000000000000000000000000..d245944b32d29a5a7c56bf72b595fcc2b7de6650 Binary files /dev/null and b/apps/examples/rose.webp differ diff --git a/apps/examples/shoe.webp b/apps/examples/shoe.webp new file mode 100644 index 0000000000000000000000000000000000000000..41bbb431f566663f3fb8ebd5dc32533cd4a2b990 Binary files /dev/null and b/apps/examples/shoe.webp differ diff --git a/apps/examples/sports_girl.webp b/apps/examples/sports_girl.webp new file mode 100644 index 0000000000000000000000000000000000000000..15006e2e0608f602aa79d17ea0f24d94b9e62061 Binary files /dev/null and b/apps/examples/sports_girl.webp differ diff --git a/apps/examples/stone.webp b/apps/examples/stone.webp new file mode 100644 index 0000000000000000000000000000000000000000..c462867d2f5d5a0f9ab7414b20af8b6adb46e2ae Binary files /dev/null and b/apps/examples/stone.webp differ diff --git a/apps/examples/sweater.webp b/apps/examples/sweater.webp new file mode 100644 index 0000000000000000000000000000000000000000..31bcb40ca77d0b2a6cb37ebde421c1d72fd44ddd Binary files /dev/null and b/apps/examples/sweater.webp differ diff --git a/apps/examples/sword.webp b/apps/examples/sword.webp new file mode 100644 index 0000000000000000000000000000000000000000..be576fa4a76ca8ddcc934d81caaa65eac2faa04c Binary files /dev/null and b/apps/examples/sword.webp differ diff --git a/apps/examples/teapot.webp b/apps/examples/teapot.webp new file mode 100644 index 0000000000000000000000000000000000000000..a1e5809eeae47e05149c9f7b19d80810de58d19f Binary files /dev/null and b/apps/examples/teapot.webp differ diff --git a/apps/examples/toy1.webp b/apps/examples/toy1.webp new file mode 100644 index 0000000000000000000000000000000000000000..793c6e07fd960e7ae710738151fea81f9d71d1ce Binary files /dev/null and b/apps/examples/toy1.webp differ diff --git a/apps/examples/toy_bear.webp b/apps/examples/toy_bear.webp new file mode 100644 index 0000000000000000000000000000000000000000..7cfff09ab76ea5f0ea6ac6a180d349e593e05fee Binary files /dev/null and b/apps/examples/toy_bear.webp differ diff --git a/apps/examples/toy_dog.webp b/apps/examples/toy_dog.webp new file mode 100644 index 0000000000000000000000000000000000000000..9e9d6aae6fa32807b734df2351a3d07e7e1ffa55 Binary files /dev/null and b/apps/examples/toy_dog.webp differ diff --git a/apps/examples/toy_pig.webp b/apps/examples/toy_pig.webp new file mode 100644 index 0000000000000000000000000000000000000000..600edfaea0c067f78d9db4c1e9af044b92437c91 Binary files /dev/null and b/apps/examples/toy_pig.webp differ diff --git a/apps/examples/toy_rabbit.webp b/apps/examples/toy_rabbit.webp new file mode 100644 index 0000000000000000000000000000000000000000..0c51b6e83ba928031967ae091c31b40efd9580ae Binary files /dev/null and b/apps/examples/toy_rabbit.webp differ diff --git a/apps/examples/wings.webp b/apps/examples/wings.webp new file mode 100644 index 0000000000000000000000000000000000000000..41b9e0e629d029bd27674b420d6a9fe0b3655156 Binary files /dev/null and b/apps/examples/wings.webp differ diff --git a/apps/gradio_app.py b/apps/gradio_app.py new file mode 100644 index 0000000000000000000000000000000000000000..916f50d926d685b235571480226754424163ad0e --- /dev/null +++ b/apps/gradio_app.py @@ -0,0 +1,272 @@ +import argparse +import os +import json +import torch +import sys +import time +import importlib +import numpy as np +from omegaconf import OmegaConf +from huggingface_hub import hf_hub_download + +from collections import OrderedDict +import trimesh +from einops import repeat, rearrange +import pytorch_lightning as pl +from typing import Dict, Optional, Tuple, List +import gradio as gr +from utils import * + +proj_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(os.path.join(proj_dir)) + +import craftsman +from craftsman.systems.base import BaseSystem +from craftsman.utils.config import ExperimentConfig, load_config + +from mv_models import GenMVImage + +_TITLE = '''CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner''' +_DESCRIPTION = ''' +
+Select or upload a image, then just click 'Generate'. +
+By mimicking the artist/craftsman modeling workflow, we propose CraftsMan (aka 匠心) that uses 3D Latent Set Diffusion Model that directly generate coarse meshes, +then a multi-view normal enhanced image generation model is used to refine the mesh. +We provide the coarse 3D diffusion part here. +
+If you found Crafts is helpful, please help to ⭐ the Github Repo. Thanks! + +
+*please note that the model is fliped due to the gradio viewer, please download the obj file and you will get the correct mesh. +
+*If you have your own multi-view images, you can directly upload it. +
+''' +_CITE_ = r""" +--- +📝 **Citation** +If you find our work useful for your research or applications, please cite using this bibtex: +```bibtex +@article{craftsman, +author = {Weiyu Li and Jiarui Liu and Rui Chen and Yixun Liang and Xuelin Chen and Ping Tan and Xiaoxiao Long}, +title = {CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner}, +journal = {arxiv:xxx}, +year = {2024}, +} +``` +🤗 **Acknowledgements** +We use Instant Meshes to remesh the generated mesh to a lower face count, thanks to the authors for the great work. +📋 **License** +CraftsMan is under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html), so any downstream solution and products (including cloud services) that include CraftsMan code or a trained model (both pretrained or custom trained) inside it should be open-sourced to comply with the AGPL conditions. If you have any questions about the usage of CraftsMan, please contact us first. +📧 **Contact** +If you have any questions, feel free to open a discussion or contact us at weiyuli.cn@gmail.com. +""" + +model = None +cached_dir = None + +def image2mesh(view_front: np.ndarray, + view_right: np.ndarray, + view_back: np.ndarray, + view_left: np.ndarray, + more: bool = False, + scheluder_name: str ="DDIMScheduler", + guidance_scale: int = 7.5, + seed: int = 4, + octree_depth: int = 7): + + sample_inputs = { + "mvimages": [[ + Image.fromarray(view_front), + Image.fromarray(view_right), + Image.fromarray(view_back), + Image.fromarray(view_left) + ]] + } + + global model + latents = model.sample( + sample_inputs, + sample_times=1, + guidance_scale=guidance_scale, + return_intermediates=False, + seed=seed + + )[0] + + # decode the latents to mesh + box_v = 1.1 + mesh_outputs, _ = model.shape_model.extract_geometry( + latents, + bounds=[-box_v, -box_v, -box_v, box_v, box_v, box_v], + octree_depth=octree_depth + ) + assert len(mesh_outputs) == 1, "Only support single mesh output for gradio demo" + mesh = trimesh.Trimesh(mesh_outputs[0][0], mesh_outputs[0][1]) + filepath = f"{cached_dir}/{time.time()}.obj" + mesh.export(filepath, include_normals=True) + + if 'Remesh' in more: + print("Remeshing with Instant Meshes...") + target_face_count = int(len(mesh.faces)/10) + command = f"{proj_dir}/apps/third_party/InstantMeshes {filepath} -f {target_face_count} -d -S 0 -r 6 -p 6 -o {filepath.replace('.obj', '_remeshed.obj')}" + os.system(command) + filepath = filepath.replace('.obj', '_remeshed.obj') + + return filepath + +if __name__=="__main__": + parser = argparse.ArgumentParser() + # parser.add_argument("--model_path", type=str, required=True, help="Path to the object file",) + parser.add_argument("--cached_dir", type=str, default="./gradio_cached_dir") + parser.add_argument("--device", type=int, default=0) + args = parser.parse_args() + + cached_dir = args.cached_dir + os.makedirs(args.cached_dir, exist_ok=True) + device = torch.device(f"cuda:{args.device}" if torch.cuda.is_available() else "cpu") + print(f"using device: {device}") + + # for multi-view images generation + background_choice = OrderedDict({ + "Alpha as Mask": "Alpha as Mask", + "Auto Remove Background": "Auto Remove Background", + "Original Image": "Original Image", + }) + mvimg_model_config_list = ["CRM", "ImageDream", "Wonder3D"] + + # for 3D latent set diffusion + # for 3D latent set diffusion + ckpt_path = hf_hub_download(repo_id="wyysf/CraftsMan", filename="image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6/model.ckpt", repo_type="model") + config_path = hf_hub_download(repo_id="wyysf/CraftsMan", filename="image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6/config.yaml", repo_type="model") + scheluder_dict = OrderedDict({ + "DDIMScheduler": 'diffusers.schedulers.DDIMScheduler', + # "DPMSolverMultistepScheduler": 'diffusers.schedulers.DPMSolverMultistepScheduler', # not support yet + # "UniPCMultistepScheduler": 'diffusers.schedulers.UniPCMultistepScheduler', # not support yet + }) + + # main GUI + custom_theme = gr.themes.Soft(primary_hue="blue").set( + button_secondary_background_fill="*neutral_100", + button_secondary_background_fill_hover="*neutral_200") + custom_css = '''#disp_image { + text-align: center; /* Horizontally center the content */ + }''' + + with gr.Blocks(title=_TITLE, theme=custom_theme, css=custom_css) as demo: + with gr.Row(): + with gr.Column(scale=1): + gr.Markdown('# ' + _TITLE) + gr.Markdown(_DESCRIPTION) + + with gr.Row(): + with gr.Column(scale=2): + with gr.Row(): + image_input = gr.Image( + label="Image Input", + image_mode="RGBA", + sources="upload", + type="pil", + ) + with gr.Row(): + text = gr.Textbox(label="Prompt (Optional, only works for mvdream)", visible=False) + with gr.Row(): + gr.Markdown('''Try a different seed if the result is unsatisfying. Good Luck :)''') + with gr.Row(): + seed = gr.Number(42, label='Seed', show_label=True) + more = gr.CheckboxGroup(["Remesh", "Symmetry(TBD)"], label="More", show_label=False) + # remesh = gr.Checkbox(value=False, label='Remesh') + # symmetry = gr.Checkbox(value=False, label='Symmetry(TBD)', interactive=False) + run_btn = gr.Button('Generate', variant='primary', interactive=True) + + with gr.Row(): + gr.Examples( + examples=[os.path.join("./apps/examples", i) for i in os.listdir("./apps/examples")], + inputs=[image_input], + examples_per_page=8 + ) + + with gr.Column(scale=4): + with gr.Row(): + output_model_obj = gr.Model3D( + label="Output Model (OBJ Format)", + camera_position=(90.0, 90.0, 3.5), + interactive=False, + ) + + with gr.Row(): + view_front = gr.Image(label="Front", interactive=True, show_label=True) + view_right = gr.Image(label="Right", interactive=True, show_label=True) + view_back = gr.Image(label="Back", interactive=True, show_label=True) + view_left = gr.Image(label="Left", interactive=True, show_label=True) + + with gr.Accordion('Advanced options', open=False): + with gr.Row(equal_height=True): + run_mv_btn = gr.Button('Only Generate 2D', interactive=True) + run_3d_btn = gr.Button('Only Generate 3D', interactive=True) + + with gr.Accordion('Advanced options (2D)', open=False): + with gr.Row(): + crop_size = gr.Number(224, label='Crop size') + mvimg_model = gr.Dropdown(value="CRM", label="MV Image Model", choices=mvimg_model_config_list) + + with gr.Row(): + foreground_ratio = gr.Slider( + label="Foreground Ratio", + minimum=0.5, + maximum=1.0, + value=1.0, + step=0.05, + ) + + with gr.Row(): + background_choice = gr.Dropdown(label="Backgroud Choice", value="Auto Remove Background",choices=list(background_choice.keys())) + rmbg_type = gr.Dropdown(label="Backgroud Remove Type", value="rembg",choices=['sam', "rembg"]) + backgroud_color = gr.ColorPicker(label="Background Color", value="#FFFFFF", interactive=True) + + with gr.Row(): + mvimg_guidance_scale = gr.Number(value=3.5, minimum=3, maximum=10, label="2D Guidance Scale") + mvimg_steps = gr.Number(value=50, minimum=20, maximum=100, label="2D Sample Steps", precision=0) + + with gr.Accordion('Advanced options (3D)', open=False): + with gr.Row(): + guidance_scale = gr.Number(label="3D Guidance Scale", value=7.5, minimum=3.0, maximum=10.0) + steps = gr.Number(value=50, minimum=20, maximum=100, label="3D Sample Steps", precision=0) + + with gr.Row(): + scheduler = gr.Dropdown(label="scheluder", value="DDIMScheduler",choices=list(scheluder_dict.keys())) + octree_depth = gr.Slider(label="Octree Depth", value=7, minimum=4, maximum=8, step=1) + + gr.Markdown(_CITE_) + + outputs = [output_model_obj] + rmbg = RMBG(device) + + gen_mvimg = GenMVImage(device) + model = load_model(ckpt_path, config_path, device) + + run_btn.click(fn=check_input_image, inputs=[image_input] + ).success( + fn=rmbg.run, + inputs=[rmbg_type, image_input, crop_size, foreground_ratio, background_choice, backgroud_color], + outputs=[image_input] + ).success( + fn=gen_mvimg.run, + inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps], + outputs=[view_front, view_right, view_back, view_left] + ).success( + fn=image2mesh, + inputs=[view_front, view_right, view_back, view_left, more, scheduler, guidance_scale, seed, octree_depth], + outputs=outputs, + api_name="generate_img2obj") + run_mv_btn.click(fn=gen_mvimg.run, + inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps], + outputs=[view_front, view_right, view_back, view_left] + ) + run_3d_btn.click(fn=image2mesh, + inputs=[view_front, view_right, view_back, view_left, more, scheduler, guidance_scale, seed, octree_depth], + outputs=outputs, + api_name="generate_img2obj") + + demo.queue().launch(share=True, allowed_paths=[args.cached_dir]) \ No newline at end of file diff --git a/apps/mv_models.py b/apps/mv_models.py new file mode 100644 index 0000000000000000000000000000000000000000..1a764216db118cb203a668057e222c30b2adb113 --- /dev/null +++ b/apps/mv_models.py @@ -0,0 +1,162 @@ +import gradio as gr +import numpy as np +import torch +import PIL +from PIL import Image +import os +import sys +import rembg +import time +import json +import cv2 +from datetime import datetime +from einops import repeat, rearrange +from omegaconf import OmegaConf +from typing import Dict, Optional, Tuple, List +from dataclasses import dataclass +from .utils import * +from huggingface_hub import hf_hub_download + +parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +class GenMVImage(object): + def __init__(self, device): + self.seed = 1024 + self.guidance_scale = 7.5 + self.step = 50 + self.pipelines = {} + self.device = device + + def gen_image_from_crm(self, image): + + from .third_party.CRM.pipelines import TwoStagePipeline + specs = json.load(open(f"{parent_dir}/apps/third_party/CRM/configs/specs_objaverse_total.json")) + stage1_config = OmegaConf.load(f"{parent_dir}/apps/third_party/CRM/configs/nf7_v3_SNR_rd_size_stroke.yaml").config + stage1_sampler_config = stage1_config.sampler + stage1_model_config = stage1_config.models + stage1_model_config.resume = hf_hub_download(repo_id="Zhengyi/CRM", filename="pixel-diffusion.pth", repo_type="model") + stage1_model_config.config = f"{parent_dir}/apps/third_party/CRM/" + stage1_model_config.config + if "crm" in self.pipelines.keys(): + pipeline = self.pipelines['crm'] + else: + self.pipelines['crm'] = TwoStagePipeline( + stage1_model_config, + stage1_sampler_config, + device=self.device, + dtype=torch.float16 + ) + pipeline = self.pipelines['crm'] + pipeline.set_seed(self.seed) + rt_dict = pipeline(image, scale=self.guidance_scale, step=self.step) + mv_imgs = rt_dict["stage1_images"] + return mv_imgs[5], mv_imgs[3], mv_imgs[2], mv_imgs[0] + + def gen_image_from_mvdream(self, image, text): + from .third_party.mvdream_diffusers.pipeline_mvdream import MVDreamPipeline + if image is None: + if "mvdream" in self.pipelines.keys(): + pipe_MVDream = self.pipelines['mvdream'] + else: + self.pipelines['mvdream'] = MVDreamPipeline.from_pretrained( + "ashawkey/mvdream-sd2.1-diffusers", # remote weights + torch_dtype=torch.float16, + trust_remote_code=True, + ) + self.pipelines['mvdream'] = self.pipelines['mvdream'].to(self.device) + pipe_MVDream = self.pipelines['mvdream'] + mv_imgs = pipe_MVDream( + text, + negative_prompt="ugly, deformed, disfigured, poor details, bad anatomy", + num_inference_steps=self.step, + guidance_scale=self.guidance_scale, + generator = torch.Generator(self.device).manual_seed(self.seed) + ) + else: + image = np.array(image) + image = image.astype(np.float32) / 255.0 + image = image[..., :3] * image[..., 3:4] + (1 - image[..., 3:4]) + if "imagedream" in self.pipelines.keys(): + pipe_imagedream = self.pipelines['imagedream'] + else: + self.pipelines['imagedream'] = MVDreamPipeline.from_pretrained( + "ashawkey/imagedream-ipmv-diffusers", # remote weights + torch_dtype=torch.float16, + trust_remote_code=True, + ) + self.pipelines['imagedream'] = self.pipelines['imagedream'].to(self.device) + pipe_imagedream = self.pipelines['imagedream'] + mv_imgs = pipe_imagedream( + text, + image, + negative_prompt="ugly, deformed, disfigured, poor details, bad anatomy", + num_inference_steps=self.step, + guidance_scale=self.guidance_scale, + generator = torch.Generator(self.device).manual_seed(self.seed) + ) + return mv_imgs[1], mv_imgs[2], mv_imgs[3], mv_imgs[0] + + def gen_image_from_wonder3d(self, image, crop_size): + sys.path.append(f"{parent_dir}/apps/third_party/Wonder3D") + from .third_party.Wonder3D.mvdiffusion.pipelines.pipeline_mvdiffusion_image import MVDiffusionImagePipeline + weight_dtype = torch.float16 + batch = prepare_data(image, crop_size) + + if "wonder3d" in self.pipelines.keys(): + pipeline = self.pipelines['wonder3d'] + else: + self.pipelines['wonder3d'] = MVDiffusionImagePipeline.from_pretrained( + 'flamehaze1115/wonder3d-v1.0', + custom_pipeline=f'{parent_dir}/apps/third_party/Wonder3D/mvdiffusion/pipelines/pipeline_mvdiffusion_image.py', + torch_dtype=weight_dtype + ) + self.pipelines['wonder3d'].unet.enable_xformers_memory_efficient_attention() + self.pipelines['wonder3d'].to(self.device) + self.pipelines['wonder3d'].set_progress_bar_config(disable=True) + pipeline = self.pipelines['wonder3d'] + + generator = torch.Generator(device=pipeline.unet.device).manual_seed(self.seed) + # repeat (2B, Nv, 3, H, W) + imgs_in = torch.cat([batch['imgs_in']] * 2, dim=0).to(weight_dtype) + + # (2B, Nv, Nce) + camera_embeddings = torch.cat([batch['camera_embeddings']] * 2, dim=0).to(weight_dtype) + + task_embeddings = torch.cat([batch['normal_task_embeddings'], batch['color_task_embeddings']], dim=0).to(weight_dtype) + + camera_embeddings = torch.cat([camera_embeddings, task_embeddings], dim=-1).to(weight_dtype) + + # (B*Nv, 3, H, W) + imgs_in = rearrange(imgs_in, "Nv C H W -> (Nv) C H W") + # (B*Nv, Nce) + + out = pipeline( + imgs_in, + # camera_embeddings, + generator=generator, + guidance_scale=self.guidance_scale, + num_inference_steps=self.step, + output_type='pt', + num_images_per_prompt=1, + **{'eta': 1.0}, + ).images + + bsz = out.shape[0] // 2 + normals_pred = out[:bsz] + images_pred = out[bsz:] + + normals_pred = [save_image(normals_pred[i]) for i in range(bsz)] + images_pred = [save_image(images_pred[i]) for i in range(bsz)] + + mv_imgs = images_pred + return mv_imgs[0], mv_imgs[2], mv_imgs[4], mv_imgs[5] + + def run(self, mvimg_model, text, image, crop_size, seed, guidance_scale, step): + self.seed = seed + self.guidance_scale = guidance_scale + self.step = step + if mvimg_model.upper() == "CRM": + return self.gen_image_from_crm(image) + elif mvimg_model.upper() == "IMAGEDREAM": + return self.gen_image_from_mvdream(image, text) + elif mvimg_model.upper() == "WONDER3D": + return self.gen_image_from_wonder3d(image, crop_size) \ No newline at end of file diff --git a/apps/third_party/CRM/.gitignore b/apps/third_party/CRM/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e0657c2567d50f3b94175aab31fefaa991429bd4 --- /dev/null +++ b/apps/third_party/CRM/.gitignore @@ -0,0 +1,155 @@ +# 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/ + +out/ \ No newline at end of file diff --git a/apps/third_party/CRM/LICENSE b/apps/third_party/CRM/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..8840910d3e0d809884ce88440d615cf493475272 --- /dev/null +++ b/apps/third_party/CRM/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 TSAIL group + +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/apps/third_party/CRM/README.md b/apps/third_party/CRM/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0fb9821a04f51330e00206575bab88fce08fb786 --- /dev/null +++ b/apps/third_party/CRM/README.md @@ -0,0 +1,85 @@ +# Convolutional Reconstruction Model + +Official implementation for *CRM: Single Image to 3D Textured Mesh with Convolutional Reconstruction Model*. + +**CRM is a feed-forward model which can generate 3D textured mesh in 10 seconds.** + +## [Project Page](https://ml.cs.tsinghua.edu.cn/~zhengyi/CRM/) | [Arxiv](https://arxiv.org/abs/2403.05034) | [HF-Demo](https://huggingface.co/spaces/Zhengyi/CRM) | [Weights](https://huggingface.co/Zhengyi/CRM) + +https://github.com/thu-ml/CRM/assets/40787266/8b325bc0-aa74-4c26-92e8-a8f0c1079382 + +## Try CRM 🍻 +* Try CRM at [Huggingface Demo](https://huggingface.co/spaces/Zhengyi/CRM). +* Try CRM at [Replicate Demo](https://replicate.com/camenduru/crm). Thanks [@camenduru](https://github.com/camenduru)! + +## Install + +### Step 1 - Base + +Install package one by one, we use **python 3.9** + +```bash +pip install torch==1.13.0+cu117 torchvision==0.14.0+cu117 torchaudio==0.13.0 --extra-index-url https://download.pytorch.org/whl/cu117 +pip install torch-scatter==2.1.1 -f https://data.pyg.org/whl/torch-1.13.1+cu117.html +pip install kaolin==0.14.0 -f https://nvidia-kaolin.s3.us-east-2.amazonaws.com/torch-1.13.1_cu117.html +pip install -r requirements.txt +``` + +besides, one by one need to install xformers manually according to the official [doc](https://github.com/facebookresearch/xformers?tab=readme-ov-file#installing-xformers) (**conda no need**), e.g. + +```bash +pip install ninja +pip install -v -U git+https://github.com/facebookresearch/xformers.git@main#egg=xformers +``` + +### Step 2 - Nvdiffrast + +Install nvdiffrast according to the official [doc](https://nvlabs.github.io/nvdiffrast/#installation), e.g. + +```bash +pip install git+https://github.com/NVlabs/nvdiffrast +``` + + + +## Inference + +We suggest gradio for a visualized inference. + +``` +gradio app.py +``` + +![image](https://github.com/thu-ml/CRM/assets/40787266/4354d22a-a641-4531-8408-c761ead8b1a2) + +For inference in command lines, simply run +```bash +CUDA_VISIBLE_DEVICES="0" python run.py --inputdir "examples/kunkun.webp" +``` +It will output the preprocessed image, generated 6-view images and CCMs and a 3D model in obj format. + +**Tips:** (1) If the result is unsatisfatory, please check whether the input image is correctly pre-processed into a grey background. Otherwise the results will be unpredictable. +(2) Different from the [Huggingface Demo](https://huggingface.co/spaces/Zhengyi/CRM), this official implementation uses UV texture instead of vertex color. It has better texture than the online demo but longer generating time owing to the UV texturing. + +## Todo List +- [x] Release inference code. +- [x] Release pretrained models. +- [ ] Optimize inference code to fit in low memery GPU. +- [ ] Upload training code. + +## Acknowledgement +- [ImageDream](https://github.com/bytedance/ImageDream) +- [nvdiffrast](https://github.com/NVlabs/nvdiffrast) +- [kiuikit](https://github.com/ashawkey/kiuikit) +- [GET3D](https://github.com/nv-tlabs/GET3D) + +## Citation + +``` +@article{wang2024crm, + title={CRM: Single Image to 3D Textured Mesh with Convolutional Reconstruction Model}, + author={Zhengyi Wang and Yikai Wang and Yifei Chen and Chendong Xiang and Shuo Chen and Dajiang Yu and Chongxuan Li and Hang Su and Jun Zhu}, + journal={arXiv preprint arXiv:2403.05034}, + year={2024} +} +``` diff --git a/apps/third_party/CRM/__init__.py b/apps/third_party/CRM/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/app.py b/apps/third_party/CRM/app.py new file mode 100644 index 0000000000000000000000000000000000000000..dae2f6baf19cf3bb2817f166c81679ae4eec0685 --- /dev/null +++ b/apps/third_party/CRM/app.py @@ -0,0 +1,228 @@ +# Not ready to use yet +import argparse +import numpy as np +import gradio as gr +from omegaconf import OmegaConf +import torch +from PIL import Image +import PIL +from pipelines import TwoStagePipeline +from huggingface_hub import hf_hub_download +import os +import rembg +from typing import Any +import json +import os +import json +import argparse + +from model import CRM +from inference import generate3d + +pipeline = None +rembg_session = rembg.new_session() + + +def expand_to_square(image, bg_color=(0, 0, 0, 0)): + # expand image to 1:1 + width, height = image.size + if width == height: + return image + new_size = (max(width, height), max(width, height)) + new_image = Image.new("RGBA", new_size, bg_color) + paste_position = ((new_size[0] - width) // 2, (new_size[1] - height) // 2) + new_image.paste(image, paste_position) + return new_image + +def check_input_image(input_image): + if input_image is None: + raise gr.Error("No image uploaded!") + + +def remove_background( + image: PIL.Image.Image, + rembg_session = None, + force: bool = False, + **rembg_kwargs, +) -> PIL.Image.Image: + do_remove = True + if image.mode == "RGBA" and image.getextrema()[3][0] < 255: + # explain why current do not rm bg + print("alhpa channl not enpty, skip remove background, using alpha channel as mask") + background = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image = Image.alpha_composite(background, image) + do_remove = False + do_remove = do_remove or force + if do_remove: + image = rembg.remove(image, session=rembg_session, **rembg_kwargs) + return image + +def do_resize_content(original_image: Image, scale_rate): + # resize image content wile retain the original image size + if scale_rate != 1: + # Calculate the new size after rescaling + new_size = tuple(int(dim * scale_rate) for dim in original_image.size) + # Resize the image while maintaining the aspect ratio + resized_image = original_image.resize(new_size) + # Create a new image with the original size and black background + padded_image = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) + paste_position = ((original_image.width - resized_image.width) // 2, (original_image.height - resized_image.height) // 2) + padded_image.paste(resized_image, paste_position) + return padded_image + else: + return original_image + +def add_background(image, bg_color=(255, 255, 255)): + # given an RGBA image, alpha channel is used as mask to add background color + background = Image.new("RGBA", image.size, bg_color) + return Image.alpha_composite(background, image) + + +def preprocess_image(image, background_choice, foreground_ratio, backgroud_color): + """ + input image is a pil image in RGBA, return RGB image + """ + print(background_choice) + if background_choice == "Alpha as mask": + background = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image = Image.alpha_composite(background, image) + else: + image = remove_background(image, rembg_session, force_remove=True) + image = do_resize_content(image, foreground_ratio) + image = expand_to_square(image) + image = add_background(image, backgroud_color) + return image.convert("RGB") + + +def gen_image(input_image, seed, scale, step): + global pipeline, model, args + pipeline.set_seed(seed) + rt_dict = pipeline(input_image, scale=scale, step=step) + stage1_images = rt_dict["stage1_images"] + stage2_images = rt_dict["stage2_images"] + np_imgs = np.concatenate(stage1_images, 1) + np_xyzs = np.concatenate(stage2_images, 1) + + glb_path, obj_path = generate3d(model, np_imgs, np_xyzs, args.device) + return Image.fromarray(np_imgs), Image.fromarray(np_xyzs), glb_path, obj_path + + +parser = argparse.ArgumentParser() +parser.add_argument( + "--stage1_config", + type=str, + default="configs/nf7_v3_SNR_rd_size_stroke.yaml", + help="config for stage1", +) +parser.add_argument( + "--stage2_config", + type=str, + default="configs/stage2-v2-snr.yaml", + help="config for stage2", +) + +parser.add_argument("--device", type=str, default="cuda") +args = parser.parse_args() + +crm_path = hf_hub_download(repo_id="Zhengyi/CRM", filename="CRM.pth") +specs = json.load(open("configs/specs_objaverse_total.json")) +model = CRM(specs).to(args.device) +model.load_state_dict(torch.load(crm_path, map_location = args.device), strict=False) + +stage1_config = OmegaConf.load(args.stage1_config).config +stage2_config = OmegaConf.load(args.stage2_config).config +stage2_sampler_config = stage2_config.sampler +stage1_sampler_config = stage1_config.sampler + +stage1_model_config = stage1_config.models +stage2_model_config = stage2_config.models + +xyz_path = hf_hub_download(repo_id="Zhengyi/CRM", filename="ccm-diffusion.pth") +pixel_path = hf_hub_download(repo_id="Zhengyi/CRM", filename="pixel-diffusion.pth") +stage1_model_config.resume = pixel_path +stage2_model_config.resume = xyz_path + +pipeline = TwoStagePipeline( + stage1_model_config, + stage2_model_config, + stage1_sampler_config, + stage2_sampler_config, + device=args.device, + dtype=torch.float16 +) + +with gr.Blocks() as demo: + gr.Markdown("# CRM: Single Image to 3D Textured Mesh with Convolutional Reconstruction Model") + with gr.Row(): + with gr.Column(): + with gr.Row(): + image_input = gr.Image( + label="Image input", + image_mode="RGBA", + sources="upload", + type="pil", + ) + processed_image = gr.Image(label="Processed Image", interactive=False, type="pil", image_mode="RGB") + with gr.Row(): + with gr.Column(): + with gr.Row(): + background_choice = gr.Radio([ + "Alpha as mask", + "Auto Remove background" + ], value="Auto Remove background", + label="backgroud choice") + # do_remove_background = gr.Checkbox(label=, value=True) + # force_remove = gr.Checkbox(label=, value=False) + back_groud_color = gr.ColorPicker(label="Background Color", value="#7F7F7F", interactive=False) + foreground_ratio = gr.Slider( + label="Foreground Ratio", + minimum=0.5, + maximum=1.0, + value=1.0, + step=0.05, + ) + + with gr.Column(): + seed = gr.Number(value=1234, label="seed", precision=0) + guidance_scale = gr.Number(value=5.5, minimum=3, maximum=10, label="guidance_scale") + step = gr.Number(value=50, minimum=30, maximum=100, label="sample steps", precision=0) + text_button = gr.Button("Generate 3D shape") + gr.Examples( + examples=[os.path.join("examples", i) for i in os.listdir("examples")], + inputs=[image_input], + ) + with gr.Column(): + image_output = gr.Image(interactive=False, label="Output RGB image") + xyz_ouput = gr.Image(interactive=False, label="Output CCM image") + + output_model = gr.Model3D( + label="Output GLB", + interactive=False, + ) + gr.Markdown("Note: The GLB model shown here has a darker lighting and enlarged UV seams. Download for correct results.") + output_obj = gr.File(interactive=False, label="Output OBJ") + + inputs = [ + processed_image, + seed, + guidance_scale, + step, + ] + outputs = [ + image_output, + xyz_ouput, + output_model, + output_obj, + ] + + + text_button.click(fn=check_input_image, inputs=[image_input]).success( + fn=preprocess_image, + inputs=[image_input, background_choice, foreground_ratio, back_groud_color], + outputs=[processed_image], + ).success( + fn=gen_image, + inputs=inputs, + outputs=outputs, + ) + demo.queue().launch() diff --git a/apps/third_party/CRM/configs/nf7_v3_SNR_rd_size_stroke.yaml b/apps/third_party/CRM/configs/nf7_v3_SNR_rd_size_stroke.yaml new file mode 100644 index 0000000000000000000000000000000000000000..760f41f2728a94114f674e2160a75a65a8a3a656 --- /dev/null +++ b/apps/third_party/CRM/configs/nf7_v3_SNR_rd_size_stroke.yaml @@ -0,0 +1,21 @@ +config: +# others + seed: 1234 + num_frames: 7 + mode: pixel + offset_noise: true +# model related + models: + config: imagedream/configs/sd_v2_base_ipmv_zero_SNR.yaml + resume: models/pixel.pth +# sampler related + sampler: + target: libs.sample.ImageDreamDiffusion + params: + mode: pixel + num_frames: 7 + camera_views: [1, 2, 3, 4, 5, 0, 0] + ref_position: 6 + random_background: false + offset_noise: true + resize_rate: 1.0 \ No newline at end of file diff --git a/apps/third_party/CRM/configs/specs_objaverse_total.json b/apps/third_party/CRM/configs/specs_objaverse_total.json new file mode 100644 index 0000000000000000000000000000000000000000..c99ebee563a7d44859338382b197ef55963e87d0 --- /dev/null +++ b/apps/third_party/CRM/configs/specs_objaverse_total.json @@ -0,0 +1,57 @@ +{ + "Input": { + "img_num": 16, + "class": "all", + "camera_angle_num": 8, + "tet_grid_size": 80, + "validate_num": 16, + "scale": 0.95, + "radius": 3, + "resolution": [256, 256] + }, + + "Pretrain": { + "mode": null, + "sdf_threshold": 0.1, + "sdf_scale": 10, + "batch_infer": false, + "lr": 1e-4, + "radius": 0.5 + }, + + "Train": { + "mode": "rnd", + "num_epochs": 500, + "grad_acc": 1, + "warm_up": 0, + "decay": 0.000, + "learning_rate": { + "init": 1e-4, + "sdf_decay": 1, + "rgb_decay": 1 + }, + "batch_size": 4, + "eva_iter": 80, + "eva_all_epoch": 10, + "tex_sup_mode": "blender", + "exp_uv_mesh": false, + "doub": false, + "random_bg": false, + "shift": 0, + "aug_shift": 0, + "geo_type": "flex" + }, + + "ArchSpecs": { + "unet_type": "diffusers", + "use_3D_aware": false, + "fea_concat": false, + "mlp_bias": true + }, + + "DecoderSpecs": { + "c_dim": 32, + "plane_resolution": 256 + } +} + diff --git a/apps/third_party/CRM/configs/stage2-v2-snr.yaml b/apps/third_party/CRM/configs/stage2-v2-snr.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8e76d1a2a8ff71ba1318c9ff6ff6c59a7a9e606e --- /dev/null +++ b/apps/third_party/CRM/configs/stage2-v2-snr.yaml @@ -0,0 +1,25 @@ +config: +# others + seed: 1234 + num_frames: 6 + mode: pixel + offset_noise: true + gd_type: xyz +# model related + models: + config: imagedream/configs/sd_v2_base_ipmv_chin8_zero_snr.yaml + resume: models/xyz.pth + +# eval related + sampler: + target: libs.sample.ImageDreamDiffusionStage2 + params: + mode: pixel + num_frames: 6 + camera_views: [1, 2, 3, 4, 5, 0] + ref_position: null + random_background: false + offset_noise: true + resize_rate: 1.0 + + diff --git "a/apps/third_party/CRM/examples/3D\345\215\241\351\200\232\347\213\227.webp" "b/apps/third_party/CRM/examples/3D\345\215\241\351\200\232\347\213\227.webp" new file mode 100644 index 0000000000000000000000000000000000000000..47fdee13499f2669bd008433936edbe8ed4db0a7 Binary files /dev/null and "b/apps/third_party/CRM/examples/3D\345\215\241\351\200\232\347\213\227.webp" differ diff --git a/apps/third_party/CRM/examples/astronaut.webp b/apps/third_party/CRM/examples/astronaut.webp new file mode 100644 index 0000000000000000000000000000000000000000..e260e30f5909bc014d0f9afd4e37399511e07c57 Binary files /dev/null and b/apps/third_party/CRM/examples/astronaut.webp differ diff --git a/apps/third_party/CRM/examples/bulldog.webp b/apps/third_party/CRM/examples/bulldog.webp new file mode 100644 index 0000000000000000000000000000000000000000..318fcf22cf756b31e25364f8fe28a3852c72fc9c Binary files /dev/null and b/apps/third_party/CRM/examples/bulldog.webp differ diff --git a/apps/third_party/CRM/examples/ghost-eating-burger.webp b/apps/third_party/CRM/examples/ghost-eating-burger.webp new file mode 100644 index 0000000000000000000000000000000000000000..34d32f31dc8161d6eba92f9a33a4afc518abf669 Binary files /dev/null and b/apps/third_party/CRM/examples/ghost-eating-burger.webp differ diff --git a/apps/third_party/CRM/examples/kunkun.webp b/apps/third_party/CRM/examples/kunkun.webp new file mode 100644 index 0000000000000000000000000000000000000000..a0c45d3c7091cdad8ef69374a9cbd065353e7982 Binary files /dev/null and b/apps/third_party/CRM/examples/kunkun.webp differ diff --git "a/apps/third_party/CRM/examples/\344\270\207\345\234\243\345\215\227\347\223\234.webp" "b/apps/third_party/CRM/examples/\344\270\207\345\234\243\345\215\227\347\223\234.webp" new file mode 100644 index 0000000000000000000000000000000000000000..6ec4eb34c8387480ab66ecf205535750dea76f8a Binary files /dev/null and "b/apps/third_party/CRM/examples/\344\270\207\345\234\243\345\215\227\347\223\234.webp" differ diff --git "a/apps/third_party/CRM/examples/\344\272\272\347\211\251\351\252\221\351\251\254.webp" "b/apps/third_party/CRM/examples/\344\272\272\347\211\251\351\252\221\351\251\254.webp" new file mode 100644 index 0000000000000000000000000000000000000000..eec24ab04a9dec91f930513a6466e0fae9d67f5f Binary files /dev/null and "b/apps/third_party/CRM/examples/\344\272\272\347\211\251\351\252\221\351\251\254.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\210\235\351\237\263\346\234\252\346\235\245\347\216\251\345\201\266.webp" "b/apps/third_party/CRM/examples/\345\210\235\351\237\263\346\234\252\346\235\245\347\216\251\345\201\266.webp" new file mode 100644 index 0000000000000000000000000000000000000000..793c6e07fd960e7ae710738151fea81f9d71d1ce Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\210\235\351\237\263\346\234\252\346\235\245\347\216\251\345\201\266.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\215\241\351\200\232\346\201\220\351\276\231.webp" "b/apps/third_party/CRM/examples/\345\215\241\351\200\232\346\201\220\351\276\231.webp" new file mode 100644 index 0000000000000000000000000000000000000000..2debdc5f7c546e8830ee6f79b7470edc43aff33a Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\215\241\351\200\232\346\201\220\351\276\231.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\215\241\351\200\232\346\211\213\346\236\252\346\210\252\345\233\276.webp" "b/apps/third_party/CRM/examples/\345\215\241\351\200\232\346\211\213\346\236\252\346\210\252\345\233\276.webp" new file mode 100644 index 0000000000000000000000000000000000000000..589c5391e53bb89c98673d5b2b2e0d76677bcb32 Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\215\241\351\200\232\346\211\213\346\236\252\346\210\252\345\233\276.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\215\241\351\200\232\347\214\253.webp" "b/apps/third_party/CRM/examples/\345\215\241\351\200\232\347\214\253.webp" new file mode 100644 index 0000000000000000000000000000000000000000..bec01263d72e3f3e0e17cabd0e7a874f1bd04d55 Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\215\241\351\200\232\347\214\253.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\215\241\351\200\232\350\230\221\350\217\207\345\245\227\350\243\205.webp" "b/apps/third_party/CRM/examples/\345\215\241\351\200\232\350\230\221\350\217\207\345\245\227\350\243\205.webp" new file mode 100644 index 0000000000000000000000000000000000000000..a8d2d485b8fcd46abad4b0caf7b52b84e77024bb Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\215\241\351\200\232\350\230\221\350\217\207\345\245\227\350\243\205.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\217\257\347\210\261\347\216\204\347\255\226.webp" "b/apps/third_party/CRM/examples/\345\217\257\347\210\261\347\216\204\347\255\226.webp" new file mode 100644 index 0000000000000000000000000000000000000000..ddffb99f48504aa5a890d676a48f39236a004631 Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\217\257\347\210\261\347\216\204\347\255\226.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\244\247\345\244\264\346\263\241\346\263\241\351\251\254\347\211\271.webp" "b/apps/third_party/CRM/examples/\345\244\247\345\244\264\346\263\241\346\263\241\351\251\254\347\211\271.webp" new file mode 100644 index 0000000000000000000000000000000000000000..3e42bbdffd07d3a5449399e4c2e229d3cd1da7ec Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\244\247\345\244\264\346\263\241\346\263\241\351\251\254\347\211\271.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\275\251\350\211\262\350\230\221\350\217\207.webp" "b/apps/third_party/CRM/examples/\345\275\251\350\211\262\350\230\221\350\217\207.webp" new file mode 100644 index 0000000000000000000000000000000000000000..bc41abe7d5113bb147a85fdb4f5b8f2d8e1e3851 Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\275\251\350\211\262\350\230\221\350\217\207.webp" differ diff --git "a/apps/third_party/CRM/examples/\345\275\251\350\211\262\350\230\221\350\217\2072.webp" "b/apps/third_party/CRM/examples/\345\275\251\350\211\262\350\230\221\350\217\2072.webp" new file mode 100644 index 0000000000000000000000000000000000000000..08d870a503df6970534797730f7e429e57a84ab8 Binary files /dev/null and "b/apps/third_party/CRM/examples/\345\275\251\350\211\262\350\230\221\350\217\2072.webp" differ diff --git "a/apps/third_party/CRM/examples/\346\201\220\351\276\231\345\245\227\350\243\205.webp" "b/apps/third_party/CRM/examples/\346\201\220\351\276\231\345\245\227\350\243\205.webp" new file mode 100644 index 0000000000000000000000000000000000000000..afd68e6205bba8dc5dd178ec8dcd0a6fd24287bb Binary files /dev/null and "b/apps/third_party/CRM/examples/\346\201\220\351\276\231\345\245\227\350\243\205.webp" differ diff --git "a/apps/third_party/CRM/examples/\346\211\213\345\212\236.webp" "b/apps/third_party/CRM/examples/\346\211\213\345\212\236.webp" new file mode 100644 index 0000000000000000000000000000000000000000..648206b5aa91124707cd5513bcc6ed8e866e1de6 Binary files /dev/null and "b/apps/third_party/CRM/examples/\346\211\213\345\212\236.webp" differ diff --git "a/apps/third_party/CRM/examples/\346\234\272\346\242\260\347\213\227\350\243\201\345\210\207.webp" "b/apps/third_party/CRM/examples/\346\234\272\346\242\260\347\213\227\350\243\201\345\210\207.webp" new file mode 100644 index 0000000000000000000000000000000000000000..839c455378b356c5e76ebbc122291bd56e71d89d Binary files /dev/null and "b/apps/third_party/CRM/examples/\346\234\272\346\242\260\347\213\227\350\243\201\345\210\207.webp" differ diff --git "a/apps/third_party/CRM/examples/\346\236\227\345\205\213.webp" "b/apps/third_party/CRM/examples/\346\236\227\345\205\213.webp" new file mode 100644 index 0000000000000000000000000000000000000000..1b5bcfc99fd3e2e6d674b5c877f4128109355900 Binary files /dev/null and "b/apps/third_party/CRM/examples/\346\236\227\345\205\213.webp" differ diff --git "a/apps/third_party/CRM/examples/\346\244\215\347\211\2511.webp" "b/apps/third_party/CRM/examples/\346\244\215\347\211\2511.webp" new file mode 100644 index 0000000000000000000000000000000000000000..73816008cc72abea18705e8f7c565f1fc57ccf1a Binary files /dev/null and "b/apps/third_party/CRM/examples/\346\244\215\347\211\2511.webp" differ diff --git "a/apps/third_party/CRM/examples/\346\255\246\345\231\250-\345\211\221.webp" "b/apps/third_party/CRM/examples/\346\255\246\345\231\250-\345\211\221.webp" new file mode 100644 index 0000000000000000000000000000000000000000..be576fa4a76ca8ddcc934d81caaa65eac2faa04c Binary files /dev/null and "b/apps/third_party/CRM/examples/\346\255\246\345\231\250-\345\211\221.webp" differ diff --git "a/apps/third_party/CRM/examples/\346\257\233\347\272\277\350\241\243.webp" "b/apps/third_party/CRM/examples/\346\257\233\347\272\277\350\241\243.webp" new file mode 100644 index 0000000000000000000000000000000000000000..31bcb40ca77d0b2a6cb37ebde421c1d72fd44ddd Binary files /dev/null and "b/apps/third_party/CRM/examples/\346\257\233\347\272\277\350\241\243.webp" differ diff --git "a/apps/third_party/CRM/examples/\346\265\267\351\276\237.webp" "b/apps/third_party/CRM/examples/\346\265\267\351\276\237.webp" new file mode 100644 index 0000000000000000000000000000000000000000..0b1cb65946958b85d4ba977e277d46b96d3ad754 Binary files /dev/null and "b/apps/third_party/CRM/examples/\346\265\267\351\276\237.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\214\253\344\272\272.webp" "b/apps/third_party/CRM/examples/\347\214\253\344\272\272.webp" new file mode 100644 index 0000000000000000000000000000000000000000..5dd68d7308d4785f314e976561facc43e9d9e53a Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\214\253\344\272\272.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\214\253\345\244\264\351\271\260.webp" "b/apps/third_party/CRM/examples/\347\214\253\345\244\264\351\271\260.webp" new file mode 100644 index 0000000000000000000000000000000000000000..ea70b91fd162b1eed0d35b28314123a80e701a3b Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\214\253\345\244\264\351\271\260.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\216\251\345\205\267\345\205\224.webp" "b/apps/third_party/CRM/examples/\347\216\251\345\205\267\345\205\224.webp" new file mode 100644 index 0000000000000000000000000000000000000000..0c51b6e83ba928031967ae091c31b40efd9580ae Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\216\251\345\205\267\345\205\224.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\216\251\345\205\267\347\206\212.webp" "b/apps/third_party/CRM/examples/\347\216\251\345\205\267\347\206\212.webp" new file mode 100644 index 0000000000000000000000000000000000000000..7cfff09ab76ea5f0ea6ac6a180d349e593e05fee Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\216\251\345\205\267\347\206\212.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\216\251\345\205\267\347\214\252.webp" "b/apps/third_party/CRM/examples/\347\216\251\345\205\267\347\214\252.webp" new file mode 100644 index 0000000000000000000000000000000000000000..9e9d6aae6fa32807b734df2351a3d07e7e1ffa55 Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\216\251\345\205\267\347\214\252.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\216\253\347\221\260.webp" "b/apps/third_party/CRM/examples/\347\216\253\347\221\260.webp" new file mode 100644 index 0000000000000000000000000000000000000000..d245944b32d29a5a7c56bf72b595fcc2b7de6650 Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\216\253\347\221\260.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\232\256\345\215\241\344\270\230.webp" "b/apps/third_party/CRM/examples/\347\232\256\345\215\241\344\270\230.webp" new file mode 100644 index 0000000000000000000000000000000000000000..0c314f13f56e10968cfc67b194a51e48e934ed2d Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\232\256\345\215\241\344\270\230.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\232\256\351\236\213.webp" "b/apps/third_party/CRM/examples/\347\232\256\351\236\213.webp" new file mode 100644 index 0000000000000000000000000000000000000000..41bbb431f566663f3fb8ebd5dc32533cd4a2b990 Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\232\256\351\236\213.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\237\263\345\244\264.webp" "b/apps/third_party/CRM/examples/\347\237\263\345\244\264.webp" new file mode 100644 index 0000000000000000000000000000000000000000..c462867d2f5d5a0f9ab7414b20af8b6adb46e2ae Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\237\263\345\244\264.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\237\263\345\244\264\345\223\206\345\225\246A\346\242\246.webp" "b/apps/third_party/CRM/examples/\347\237\263\345\244\264\345\223\206\345\225\246A\346\242\246.webp" new file mode 100644 index 0000000000000000000000000000000000000000..b5923198c1a6d3da835f9d9f6299ad8f3ad81732 Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\237\263\345\244\264\345\223\206\345\225\246A\346\242\246.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\272\242\347\216\251\345\205\267\347\214\252.webp" "b/apps/third_party/CRM/examples/\347\272\242\347\216\251\345\205\267\347\214\252.webp" new file mode 100644 index 0000000000000000000000000000000000000000..600edfaea0c067f78d9db4c1e9af044b92437c91 Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\272\242\347\216\251\345\205\267\347\214\252.webp" differ diff --git "a/apps/third_party/CRM/examples/\347\277\205\350\206\200\351\201\223\345\205\267.webp" "b/apps/third_party/CRM/examples/\347\277\205\350\206\200\351\201\223\345\205\267.webp" new file mode 100644 index 0000000000000000000000000000000000000000..41b9e0e629d029bd27674b420d6a9fe0b3655156 Binary files /dev/null and "b/apps/third_party/CRM/examples/\347\277\205\350\206\200\351\201\223\345\205\267.webp" differ diff --git "a/apps/third_party/CRM/examples/\350\214\266\345\243\266.webp" "b/apps/third_party/CRM/examples/\350\214\266\345\243\266.webp" new file mode 100644 index 0000000000000000000000000000000000000000..a1e5809eeae47e05149c9f7b19d80810de58d19f Binary files /dev/null and "b/apps/third_party/CRM/examples/\350\214\266\345\243\266.webp" differ diff --git "a/apps/third_party/CRM/examples/\350\215\211\347\263\273\347\262\276\347\201\265.webp" "b/apps/third_party/CRM/examples/\350\215\211\347\263\273\347\262\276\347\201\265.webp" new file mode 100644 index 0000000000000000000000000000000000000000..ec483a7a23edec5d4c88ec7f49e6c76e5f257a24 Binary files /dev/null and "b/apps/third_party/CRM/examples/\350\215\211\347\263\273\347\262\276\347\201\265.webp" differ diff --git "a/apps/third_party/CRM/examples/\350\223\235\350\211\262\345\260\217\346\200\252\347\211\251.webp" "b/apps/third_party/CRM/examples/\350\223\235\350\211\262\345\260\217\346\200\252\347\211\251.webp" new file mode 100644 index 0000000000000000000000000000000000000000..7204f5fa63d86843269210c306488444e0efafe1 Binary files /dev/null and "b/apps/third_party/CRM/examples/\350\223\235\350\211\262\345\260\217\346\200\252\347\211\251.webp" differ diff --git "a/apps/third_party/CRM/examples/\350\223\235\350\211\262\346\263\241\346\263\241\351\251\254\347\211\271.webp" "b/apps/third_party/CRM/examples/\350\223\235\350\211\262\346\263\241\346\263\241\351\251\254\347\211\271.webp" new file mode 100644 index 0000000000000000000000000000000000000000..a2e1615efd6ca3f87aac3f43884666b85a804dc4 Binary files /dev/null and "b/apps/third_party/CRM/examples/\350\223\235\350\211\262\346\263\241\346\263\241\351\251\254\347\211\271.webp" differ diff --git "a/apps/third_party/CRM/examples/\350\223\235\350\211\262\347\214\253.webp" "b/apps/third_party/CRM/examples/\350\223\235\350\211\262\347\214\253.webp" new file mode 100644 index 0000000000000000000000000000000000000000..8742e98a69f2441a4fab1094313fb30bf60d843d Binary files /dev/null and "b/apps/third_party/CRM/examples/\350\223\235\350\211\262\347\214\253.webp" differ diff --git "a/apps/third_party/CRM/examples/\350\265\233\345\215\232\346\234\213\345\205\213-\347\224\267.webp" "b/apps/third_party/CRM/examples/\350\265\233\345\215\232\346\234\213\345\205\213-\347\224\267.webp" new file mode 100644 index 0000000000000000000000000000000000000000..4c609f49d6dcfcb93d11c85b675fe1b0641300c9 Binary files /dev/null and "b/apps/third_party/CRM/examples/\350\265\233\345\215\232\346\234\213\345\205\213-\347\224\267.webp" differ diff --git "a/apps/third_party/CRM/examples/\350\267\257\347\201\257.webp" "b/apps/third_party/CRM/examples/\350\267\257\347\201\257.webp" new file mode 100644 index 0000000000000000000000000000000000000000..909a3c906ca7ccafb49860be4aba73b827a627a4 Binary files /dev/null and "b/apps/third_party/CRM/examples/\350\267\257\347\201\257.webp" differ diff --git "a/apps/third_party/CRM/examples/\350\277\220\345\212\250\347\263\273\346\211\213\345\212\236.webp" "b/apps/third_party/CRM/examples/\350\277\220\345\212\250\347\263\273\346\211\213\345\212\236.webp" new file mode 100644 index 0000000000000000000000000000000000000000..15006e2e0608f602aa79d17ea0f24d94b9e62061 Binary files /dev/null and "b/apps/third_party/CRM/examples/\350\277\220\345\212\250\347\263\273\346\211\213\345\212\236.webp" differ diff --git a/apps/third_party/CRM/imagedream/__init__.py b/apps/third_party/CRM/imagedream/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..326f18c2d65a018b1c214c71f1c44428a8a8089b --- /dev/null +++ b/apps/third_party/CRM/imagedream/__init__.py @@ -0,0 +1 @@ +from .model_zoo import build_model diff --git a/apps/third_party/CRM/imagedream/camera_utils.py b/apps/third_party/CRM/imagedream/camera_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..6fb352745d737d96b2652f80c23778058e81f6e6 --- /dev/null +++ b/apps/third_party/CRM/imagedream/camera_utils.py @@ -0,0 +1,99 @@ +import numpy as np +import torch + + +def create_camera_to_world_matrix(elevation, azimuth): + elevation = np.radians(elevation) + azimuth = np.radians(azimuth) + # Convert elevation and azimuth angles to Cartesian coordinates on a unit sphere + x = np.cos(elevation) * np.sin(azimuth) + y = np.sin(elevation) + z = np.cos(elevation) * np.cos(azimuth) + + # Calculate camera position, target, and up vectors + camera_pos = np.array([x, y, z]) + target = np.array([0, 0, 0]) + up = np.array([0, 1, 0]) + + # Construct view matrix + forward = target - camera_pos + forward /= np.linalg.norm(forward) + right = np.cross(forward, up) + right /= np.linalg.norm(right) + new_up = np.cross(right, forward) + new_up /= np.linalg.norm(new_up) + cam2world = np.eye(4) + cam2world[:3, :3] = np.array([right, new_up, -forward]).T + cam2world[:3, 3] = camera_pos + return cam2world + + +def convert_opengl_to_blender(camera_matrix): + if isinstance(camera_matrix, np.ndarray): + # Construct transformation matrix to convert from OpenGL space to Blender space + flip_yz = np.array([[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) + camera_matrix_blender = np.dot(flip_yz, camera_matrix) + else: + # Construct transformation matrix to convert from OpenGL space to Blender space + flip_yz = torch.tensor( + [[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]] + ) + if camera_matrix.ndim == 3: + flip_yz = flip_yz.unsqueeze(0) + camera_matrix_blender = torch.matmul(flip_yz.to(camera_matrix), camera_matrix) + return camera_matrix_blender + + +def normalize_camera(camera_matrix): + """normalize the camera location onto a unit-sphere""" + if isinstance(camera_matrix, np.ndarray): + camera_matrix = camera_matrix.reshape(-1, 4, 4) + translation = camera_matrix[:, :3, 3] + translation = translation / ( + np.linalg.norm(translation, axis=1, keepdims=True) + 1e-8 + ) + camera_matrix[:, :3, 3] = translation + else: + camera_matrix = camera_matrix.reshape(-1, 4, 4) + translation = camera_matrix[:, :3, 3] + translation = translation / ( + torch.norm(translation, dim=1, keepdim=True) + 1e-8 + ) + camera_matrix[:, :3, 3] = translation + return camera_matrix.reshape(-1, 16) + + +def get_camera( + num_frames, + elevation=15, + azimuth_start=0, + azimuth_span=360, + blender_coord=True, + extra_view=False, +): + angle_gap = azimuth_span / num_frames + cameras = [] + for azimuth in np.arange(azimuth_start, azimuth_span + azimuth_start, angle_gap): + camera_matrix = create_camera_to_world_matrix(elevation, azimuth) + if blender_coord: + camera_matrix = convert_opengl_to_blender(camera_matrix) + cameras.append(camera_matrix.flatten()) + + if extra_view: + dim = len(cameras[0]) + cameras.append(np.zeros(dim)) + return torch.tensor(np.stack(cameras, 0)).float() + + +def get_camera_for_index(data_index): + """ + 按照当前我们的数据格式, 以000为正对我们的情况: + 000是正面, ev: 0, azimuth: 0 + 001是左边, ev: 0, azimuth: -90 + 002是下面, ev: -90, azimuth: 0 + 003是背面, ev: 0, azimuth: 180 + 004是右边, ev: 0, azimuth: 90 + 005是上面, ev: 90, azimuth: 0 + """ + params = [(0, 0), (0, -90), (-90, 0), (0, 180), (0, 90), (90, 0)] + return get_camera(1, *params[data_index]) \ No newline at end of file diff --git a/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv.yaml b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b4ecc2a694dbbde82d45bc3b16d1ebbb27ac552a --- /dev/null +++ b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv.yaml @@ -0,0 +1,61 @@ +model: + target: imagedream.ldm.interface.LatentDiffusionInterface + params: + linear_start: 0.00085 + linear_end: 0.0120 + timesteps: 1000 + scale_factor: 0.18215 + parameterization: "eps" + + unet_config: + target: imagedream.ldm.modules.diffusionmodules.openaimodel.MultiViewUNetModel + params: + image_size: 32 # unused + in_channels: 4 + out_channels: 4 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_head_channels: 64 # need to fix for flash-attn + use_spatial_transformer: True + use_linear_in_transformer: True + transformer_depth: 1 + context_dim: 1024 + use_checkpoint: False + legacy: False + camera_dim: 16 + with_ip: True + ip_dim: 16 # ip token length + ip_mode: "local_resample" + + vae_config: + target: imagedream.ldm.models.autoencoder.AutoencoderKL + params: + embed_dim: 4 + monitor: val/rec_loss + ddconfig: + #attn_type: "vanilla-xformers" + double_z: true + z_channels: 4 + resolution: 256 + in_channels: 3 + out_ch: 3 + ch: 128 + ch_mult: + - 1 + - 2 + - 4 + - 4 + num_res_blocks: 2 + attn_resolutions: [] + dropout: 0.0 + lossconfig: + target: torch.nn.Identity + + clip_config: + target: imagedream.ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder + params: + freeze: True + layer: "penultimate" + ip_mode: "local_resample" diff --git a/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_ch8.yaml b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_ch8.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ee80712395fa6323bceb437a40b4829bb497adf7 --- /dev/null +++ b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_ch8.yaml @@ -0,0 +1,61 @@ +model: + target: imagedream.ldm.interface.LatentDiffusionInterface + params: + linear_start: 0.00085 + linear_end: 0.0120 + timesteps: 1000 + scale_factor: 0.18215 + parameterization: "eps" + + unet_config: + target: imagedream.ldm.modules.diffusionmodules.openaimodel.MultiViewUNetModel + params: + image_size: 32 # unused + in_channels: 8 + out_channels: 8 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_head_channels: 64 # need to fix for flash-attn + use_spatial_transformer: True + use_linear_in_transformer: True + transformer_depth: 1 + context_dim: 1024 + use_checkpoint: False + legacy: False + camera_dim: 16 + with_ip: True + ip_dim: 16 # ip token length + ip_mode: "local_resample" + + vae_config: + target: imagedream.ldm.models.autoencoder.AutoencoderKL + params: + embed_dim: 4 + monitor: val/rec_loss + ddconfig: + #attn_type: "vanilla-xformers" + double_z: true + z_channels: 4 + resolution: 256 + in_channels: 3 + out_ch: 3 + ch: 128 + ch_mult: + - 1 + - 2 + - 4 + - 4 + num_res_blocks: 2 + attn_resolutions: [] + dropout: 0.0 + lossconfig: + target: torch.nn.Identity + + clip_config: + target: imagedream.ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder + params: + freeze: True + layer: "penultimate" + ip_mode: "local_resample" diff --git a/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_chin8.yaml b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_chin8.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ce64b053fc76ded2ed85af7c5d398e2981e51c3d --- /dev/null +++ b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_chin8.yaml @@ -0,0 +1,61 @@ +model: + target: imagedream.ldm.interface.LatentDiffusionInterface + params: + linear_start: 0.00085 + linear_end: 0.0120 + timesteps: 1000 + scale_factor: 0.18215 + parameterization: "eps" + + unet_config: + target: imagedream.ldm.modules.diffusionmodules.openaimodel.MultiViewUNetModelStage2 + params: + image_size: 32 # unused + in_channels: 8 + out_channels: 4 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_head_channels: 64 # need to fix for flash-attn + use_spatial_transformer: True + use_linear_in_transformer: True + transformer_depth: 1 + context_dim: 1024 + use_checkpoint: False + legacy: False + camera_dim: 16 + with_ip: True + ip_dim: 16 # ip token length + ip_mode: "local_resample" + + vae_config: + target: imagedream.ldm.models.autoencoder.AutoencoderKL + params: + embed_dim: 4 + monitor: val/rec_loss + ddconfig: + #attn_type: "vanilla-xformers" + double_z: true + z_channels: 4 + resolution: 256 + in_channels: 3 + out_ch: 3 + ch: 128 + ch_mult: + - 1 + - 2 + - 4 + - 4 + num_res_blocks: 2 + attn_resolutions: [] + dropout: 0.0 + lossconfig: + target: torch.nn.Identity + + clip_config: + target: imagedream.ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder + params: + freeze: True + layer: "penultimate" + ip_mode: "local_resample" diff --git a/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_chin8_zero_snr.yaml b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_chin8_zero_snr.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bd9c835f06707aeffcd5cd8fd4cd7ec262646905 --- /dev/null +++ b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_chin8_zero_snr.yaml @@ -0,0 +1,62 @@ +model: + target: imagedream.ldm.interface.LatentDiffusionInterface + params: + linear_start: 0.00085 + linear_end: 0.0120 + timesteps: 1000 + scale_factor: 0.18215 + parameterization: "eps" + zero_snr: true + + unet_config: + target: imagedream.ldm.modules.diffusionmodules.openaimodel.MultiViewUNetModelStage2 + params: + image_size: 32 # unused + in_channels: 8 + out_channels: 4 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_head_channels: 64 # need to fix for flash-attn + use_spatial_transformer: True + use_linear_in_transformer: True + transformer_depth: 1 + context_dim: 1024 + use_checkpoint: False + legacy: False + camera_dim: 16 + with_ip: True + ip_dim: 16 # ip token length + ip_mode: "local_resample" + + vae_config: + target: imagedream.ldm.models.autoencoder.AutoencoderKL + params: + embed_dim: 4 + monitor: val/rec_loss + ddconfig: + #attn_type: "vanilla-xformers" + double_z: true + z_channels: 4 + resolution: 256 + in_channels: 3 + out_ch: 3 + ch: 128 + ch_mult: + - 1 + - 2 + - 4 + - 4 + num_res_blocks: 2 + attn_resolutions: [] + dropout: 0.0 + lossconfig: + target: torch.nn.Identity + + clip_config: + target: imagedream.ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder + params: + freeze: True + layer: "penultimate" + ip_mode: "local_resample" diff --git a/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_local.yaml b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_local.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b4fbe27c84d5c2b05737894dc8970f45f08ba606 --- /dev/null +++ b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_local.yaml @@ -0,0 +1,62 @@ +model: + target: imagedream.ldm.interface.LatentDiffusionInterface + params: + linear_start: 0.00085 + linear_end: 0.0120 + timesteps: 1000 + scale_factor: 0.18215 + parameterization: "eps" + + unet_config: + target: imagedream.ldm.modules.diffusionmodules.openaimodel.MultiViewUNetModel + params: + image_size: 32 # unused + in_channels: 4 + out_channels: 4 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_head_channels: 64 # need to fix for flash-attn + use_spatial_transformer: True + use_linear_in_transformer: True + transformer_depth: 1 + context_dim: 1024 + use_checkpoint: False + legacy: False + camera_dim: 16 + with_ip: True + ip_dim: 16 # ip token length + ip_mode: "local_resample" + ip_weight: 1.0 # adjust for similarity to image + + vae_config: + target: imagedream.ldm.models.autoencoder.AutoencoderKL + params: + embed_dim: 4 + monitor: val/rec_loss + ddconfig: + #attn_type: "vanilla-xformers" + double_z: true + z_channels: 4 + resolution: 256 + in_channels: 3 + out_ch: 3 + ch: 128 + ch_mult: + - 1 + - 2 + - 4 + - 4 + num_res_blocks: 2 + attn_resolutions: [] + dropout: 0.0 + lossconfig: + target: torch.nn.Identity + + clip_config: + target: imagedream.ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder + params: + freeze: True + layer: "penultimate" + ip_mode: "local_resample" diff --git a/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_zero_SNR.yaml b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_zero_SNR.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5824cd7f25a9d1ef2e397341a39f7c724eb1cf76 --- /dev/null +++ b/apps/third_party/CRM/imagedream/configs/sd_v2_base_ipmv_zero_SNR.yaml @@ -0,0 +1,62 @@ +model: + target: imagedream.ldm.interface.LatentDiffusionInterface + params: + linear_start: 0.00085 + linear_end: 0.0120 + timesteps: 1000 + scale_factor: 0.18215 + parameterization: "eps" + zero_snr: true + + unet_config: + target: imagedream.ldm.modules.diffusionmodules.openaimodel.MultiViewUNetModel + params: + image_size: 32 # unused + in_channels: 4 + out_channels: 4 + model_channels: 320 + attention_resolutions: [ 4, 2, 1 ] + num_res_blocks: 2 + channel_mult: [ 1, 2, 4, 4 ] + num_head_channels: 64 # need to fix for flash-attn + use_spatial_transformer: True + use_linear_in_transformer: True + transformer_depth: 1 + context_dim: 1024 + use_checkpoint: False + legacy: False + camera_dim: 16 + with_ip: True + ip_dim: 16 # ip token length + ip_mode: "local_resample" + + vae_config: + target: imagedream.ldm.models.autoencoder.AutoencoderKL + params: + embed_dim: 4 + monitor: val/rec_loss + ddconfig: + #attn_type: "vanilla-xformers" + double_z: true + z_channels: 4 + resolution: 256 + in_channels: 3 + out_ch: 3 + ch: 128 + ch_mult: + - 1 + - 2 + - 4 + - 4 + num_res_blocks: 2 + attn_resolutions: [] + dropout: 0.0 + lossconfig: + target: torch.nn.Identity + + clip_config: + target: imagedream.ldm.modules.encoders.modules.FrozenOpenCLIPEmbedder + params: + freeze: True + layer: "penultimate" + ip_mode: "local_resample" diff --git a/apps/third_party/CRM/imagedream/ldm/__init__.py b/apps/third_party/CRM/imagedream/ldm/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/imagedream/ldm/interface.py b/apps/third_party/CRM/imagedream/ldm/interface.py new file mode 100644 index 0000000000000000000000000000000000000000..3bbeed7921ea30efb81573c3efed42d8375cb21a --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/interface.py @@ -0,0 +1,206 @@ +from typing import List +from functools import partial + +import numpy as np +import torch +import torch.nn as nn + +from .modules.diffusionmodules.util import ( + make_beta_schedule, + extract_into_tensor, + enforce_zero_terminal_snr, + noise_like, +) +from .util import exists, default, instantiate_from_config +from .modules.distributions.distributions import DiagonalGaussianDistribution + + +class DiffusionWrapper(nn.Module): + def __init__(self, diffusion_model): + super().__init__() + self.diffusion_model = diffusion_model + + def forward(self, *args, **kwargs): + return self.diffusion_model(*args, **kwargs) + + +class LatentDiffusionInterface(nn.Module): + """a simple interface class for LDM inference""" + + def __init__( + self, + unet_config, + clip_config, + vae_config, + parameterization="eps", + scale_factor=0.18215, + beta_schedule="linear", + timesteps=1000, + linear_start=0.00085, + linear_end=0.0120, + cosine_s=8e-3, + given_betas=None, + zero_snr=False, + *args, + **kwargs, + ): + super().__init__() + + unet = instantiate_from_config(unet_config) + self.model = DiffusionWrapper(unet) + self.clip_model = instantiate_from_config(clip_config) + self.vae_model = instantiate_from_config(vae_config) + + self.parameterization = parameterization + self.scale_factor = scale_factor + self.register_schedule( + given_betas=given_betas, + beta_schedule=beta_schedule, + timesteps=timesteps, + linear_start=linear_start, + linear_end=linear_end, + cosine_s=cosine_s, + zero_snr=zero_snr + ) + + def register_schedule( + self, + given_betas=None, + beta_schedule="linear", + timesteps=1000, + linear_start=1e-4, + linear_end=2e-2, + cosine_s=8e-3, + zero_snr=False + ): + if exists(given_betas): + betas = given_betas + else: + betas = make_beta_schedule( + beta_schedule, + timesteps, + linear_start=linear_start, + linear_end=linear_end, + cosine_s=cosine_s, + ) + if zero_snr: + print("--- using zero snr---") + betas = enforce_zero_terminal_snr(betas).numpy() + alphas = 1.0 - betas + alphas_cumprod = np.cumprod(alphas, axis=0) + alphas_cumprod_prev = np.append(1.0, alphas_cumprod[:-1]) + + (timesteps,) = betas.shape + self.num_timesteps = int(timesteps) + self.linear_start = linear_start + self.linear_end = linear_end + assert ( + alphas_cumprod.shape[0] == self.num_timesteps + ), "alphas have to be defined for each timestep" + + to_torch = partial(torch.tensor, dtype=torch.float32) + + self.register_buffer("betas", to_torch(betas)) + self.register_buffer("alphas_cumprod", to_torch(alphas_cumprod)) + self.register_buffer("alphas_cumprod_prev", to_torch(alphas_cumprod_prev)) + + # calculations for diffusion q(x_t | x_{t-1}) and others + self.register_buffer("sqrt_alphas_cumprod", to_torch(np.sqrt(alphas_cumprod))) + self.register_buffer( + "sqrt_one_minus_alphas_cumprod", to_torch(np.sqrt(1.0 - alphas_cumprod)) + ) + self.register_buffer( + "log_one_minus_alphas_cumprod", to_torch(np.log(1.0 - alphas_cumprod)) + ) + eps = 1e-8 # adding small epsilon value to avoid devide by zero error + self.register_buffer( + "sqrt_recip_alphas_cumprod", to_torch(np.sqrt(1.0 / (alphas_cumprod + eps))) + ) + self.register_buffer( + "sqrt_recipm1_alphas_cumprod", to_torch(np.sqrt(1.0 / (alphas_cumprod + eps) - 1)) + ) + + # calculations for posterior q(x_{t-1} | x_t, x_0) + self.v_posterior = 0 + posterior_variance = (1 - self.v_posterior) * betas * ( + 1.0 - alphas_cumprod_prev + ) / (1.0 - alphas_cumprod) + self.v_posterior * betas + # above: equal to 1. / (1. / (1. - alpha_cumprod_tm1) + alpha_t / beta_t) + self.register_buffer("posterior_variance", to_torch(posterior_variance)) + # below: log calculation clipped because the posterior variance is 0 at the beginning of the diffusion chain + self.register_buffer( + "posterior_log_variance_clipped", + to_torch(np.log(np.maximum(posterior_variance, 1e-20))), + ) + self.register_buffer( + "posterior_mean_coef1", + to_torch(betas * np.sqrt(alphas_cumprod_prev) / (1.0 - alphas_cumprod)), + ) + self.register_buffer( + "posterior_mean_coef2", + to_torch( + (1.0 - alphas_cumprod_prev) * np.sqrt(alphas) / (1.0 - alphas_cumprod) + ), + ) + + def q_sample(self, x_start, t, noise=None): + noise = default(noise, lambda: torch.randn_like(x_start)) + return ( + extract_into_tensor(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start + + extract_into_tensor(self.sqrt_one_minus_alphas_cumprod, t, x_start.shape) + * noise + ) + + def get_v(self, x, noise, t): + return ( + extract_into_tensor(self.sqrt_alphas_cumprod, t, x.shape) * noise + - extract_into_tensor(self.sqrt_one_minus_alphas_cumprod, t, x.shape) * x + ) + + def predict_start_from_noise(self, x_t, t, noise): + return ( + extract_into_tensor(self.sqrt_recip_alphas_cumprod, t, x_t.shape) * x_t + - extract_into_tensor(self.sqrt_recipm1_alphas_cumprod, t, x_t.shape) + * noise + ) + + def predict_start_from_z_and_v(self, x_t, t, v): + return ( + extract_into_tensor(self.sqrt_alphas_cumprod, t, x_t.shape) * x_t + - extract_into_tensor(self.sqrt_one_minus_alphas_cumprod, t, x_t.shape) * v + ) + + def predict_eps_from_z_and_v(self, x_t, t, v): + return ( + extract_into_tensor(self.sqrt_alphas_cumprod, t, x_t.shape) * v + + extract_into_tensor(self.sqrt_one_minus_alphas_cumprod, t, x_t.shape) + * x_t + ) + + def apply_model(self, x_noisy, t, cond, **kwargs): + assert isinstance(cond, dict), "cond has to be a dictionary" + return self.model(x_noisy, t, **cond, **kwargs) + + def get_learned_conditioning(self, prompts: List[str]): + return self.clip_model(prompts) + + def get_learned_image_conditioning(self, images): + return self.clip_model.forward_image(images) + + def get_first_stage_encoding(self, encoder_posterior): + if isinstance(encoder_posterior, DiagonalGaussianDistribution): + z = encoder_posterior.sample() + elif isinstance(encoder_posterior, torch.Tensor): + z = encoder_posterior + else: + raise NotImplementedError( + f"encoder_posterior of type '{type(encoder_posterior)}' not yet implemented" + ) + return self.scale_factor * z + + def encode_first_stage(self, x): + return self.vae_model.encode(x) + + def decode_first_stage(self, z): + z = 1.0 / self.scale_factor * z + return self.vae_model.decode(z) diff --git a/apps/third_party/CRM/imagedream/ldm/models/__init__.py b/apps/third_party/CRM/imagedream/ldm/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/imagedream/ldm/models/autoencoder.py b/apps/third_party/CRM/imagedream/ldm/models/autoencoder.py new file mode 100644 index 0000000000000000000000000000000000000000..92f83096ddaf2146772f6b49b23d8f99e787fbb4 --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/models/autoencoder.py @@ -0,0 +1,270 @@ +import torch +import torch.nn.functional as F +from contextlib import contextmanager + +from ..modules.diffusionmodules.model import Encoder, Decoder +from ..modules.distributions.distributions import DiagonalGaussianDistribution + +from ..util import instantiate_from_config +from ..modules.ema import LitEma + + +class AutoencoderKL(torch.nn.Module): + def __init__( + self, + ddconfig, + lossconfig, + embed_dim, + ckpt_path=None, + ignore_keys=[], + image_key="image", + colorize_nlabels=None, + monitor=None, + ema_decay=None, + learn_logvar=False, + ): + super().__init__() + self.learn_logvar = learn_logvar + self.image_key = image_key + self.encoder = Encoder(**ddconfig) + self.decoder = Decoder(**ddconfig) + self.loss = instantiate_from_config(lossconfig) + assert ddconfig["double_z"] + self.quant_conv = torch.nn.Conv2d(2 * ddconfig["z_channels"], 2 * embed_dim, 1) + self.post_quant_conv = torch.nn.Conv2d(embed_dim, ddconfig["z_channels"], 1) + self.embed_dim = embed_dim + if colorize_nlabels is not None: + assert type(colorize_nlabels) == int + self.register_buffer("colorize", torch.randn(3, colorize_nlabels, 1, 1)) + if monitor is not None: + self.monitor = monitor + + self.use_ema = ema_decay is not None + if self.use_ema: + self.ema_decay = ema_decay + assert 0.0 < ema_decay < 1.0 + self.model_ema = LitEma(self, decay=ema_decay) + print(f"Keeping EMAs of {len(list(self.model_ema.buffers()))}.") + + if ckpt_path is not None: + self.init_from_ckpt(ckpt_path, ignore_keys=ignore_keys) + + def init_from_ckpt(self, path, ignore_keys=list()): + sd = torch.load(path, map_location="cpu")["state_dict"] + keys = list(sd.keys()) + for k in keys: + for ik in ignore_keys: + if k.startswith(ik): + print("Deleting key {} from state_dict.".format(k)) + del sd[k] + self.load_state_dict(sd, strict=False) + print(f"Restored from {path}") + + @contextmanager + def ema_scope(self, context=None): + if self.use_ema: + self.model_ema.store(self.parameters()) + self.model_ema.copy_to(self) + if context is not None: + print(f"{context}: Switched to EMA weights") + try: + yield None + finally: + if self.use_ema: + self.model_ema.restore(self.parameters()) + if context is not None: + print(f"{context}: Restored training weights") + + def on_train_batch_end(self, *args, **kwargs): + if self.use_ema: + self.model_ema(self) + + def encode(self, x): + h = self.encoder(x) + moments = self.quant_conv(h) + posterior = DiagonalGaussianDistribution(moments) + return posterior + + def decode(self, z): + z = self.post_quant_conv(z) + dec = self.decoder(z) + return dec + + def forward(self, input, sample_posterior=True): + posterior = self.encode(input) + if sample_posterior: + z = posterior.sample() + else: + z = posterior.mode() + dec = self.decode(z) + return dec, posterior + + def get_input(self, batch, k): + x = batch[k] + if len(x.shape) == 3: + x = x[..., None] + x = x.permute(0, 3, 1, 2).to(memory_format=torch.contiguous_format).float() + return x + + def training_step(self, batch, batch_idx, optimizer_idx): + inputs = self.get_input(batch, self.image_key) + reconstructions, posterior = self(inputs) + + if optimizer_idx == 0: + # train encoder+decoder+logvar + aeloss, log_dict_ae = self.loss( + inputs, + reconstructions, + posterior, + optimizer_idx, + self.global_step, + last_layer=self.get_last_layer(), + split="train", + ) + self.log( + "aeloss", + aeloss, + prog_bar=True, + logger=True, + on_step=True, + on_epoch=True, + ) + self.log_dict( + log_dict_ae, prog_bar=False, logger=True, on_step=True, on_epoch=False + ) + return aeloss + + if optimizer_idx == 1: + # train the discriminator + discloss, log_dict_disc = self.loss( + inputs, + reconstructions, + posterior, + optimizer_idx, + self.global_step, + last_layer=self.get_last_layer(), + split="train", + ) + + self.log( + "discloss", + discloss, + prog_bar=True, + logger=True, + on_step=True, + on_epoch=True, + ) + self.log_dict( + log_dict_disc, prog_bar=False, logger=True, on_step=True, on_epoch=False + ) + return discloss + + def validation_step(self, batch, batch_idx): + log_dict = self._validation_step(batch, batch_idx) + with self.ema_scope(): + log_dict_ema = self._validation_step(batch, batch_idx, postfix="_ema") + return log_dict + + def _validation_step(self, batch, batch_idx, postfix=""): + inputs = self.get_input(batch, self.image_key) + reconstructions, posterior = self(inputs) + aeloss, log_dict_ae = self.loss( + inputs, + reconstructions, + posterior, + 0, + self.global_step, + last_layer=self.get_last_layer(), + split="val" + postfix, + ) + + discloss, log_dict_disc = self.loss( + inputs, + reconstructions, + posterior, + 1, + self.global_step, + last_layer=self.get_last_layer(), + split="val" + postfix, + ) + + self.log(f"val{postfix}/rec_loss", log_dict_ae[f"val{postfix}/rec_loss"]) + self.log_dict(log_dict_ae) + self.log_dict(log_dict_disc) + return self.log_dict + + def configure_optimizers(self): + lr = self.learning_rate + ae_params_list = ( + list(self.encoder.parameters()) + + list(self.decoder.parameters()) + + list(self.quant_conv.parameters()) + + list(self.post_quant_conv.parameters()) + ) + if self.learn_logvar: + print(f"{self.__class__.__name__}: Learning logvar") + ae_params_list.append(self.loss.logvar) + opt_ae = torch.optim.Adam(ae_params_list, lr=lr, betas=(0.5, 0.9)) + opt_disc = torch.optim.Adam( + self.loss.discriminator.parameters(), lr=lr, betas=(0.5, 0.9) + ) + return [opt_ae, opt_disc], [] + + def get_last_layer(self): + return self.decoder.conv_out.weight + + @torch.no_grad() + def log_images(self, batch, only_inputs=False, log_ema=False, **kwargs): + log = dict() + x = self.get_input(batch, self.image_key) + x = x.to(self.device) + if not only_inputs: + xrec, posterior = self(x) + if x.shape[1] > 3: + # colorize with random projection + assert xrec.shape[1] > 3 + x = self.to_rgb(x) + xrec = self.to_rgb(xrec) + log["samples"] = self.decode(torch.randn_like(posterior.sample())) + log["reconstructions"] = xrec + if log_ema or self.use_ema: + with self.ema_scope(): + xrec_ema, posterior_ema = self(x) + if x.shape[1] > 3: + # colorize with random projection + assert xrec_ema.shape[1] > 3 + xrec_ema = self.to_rgb(xrec_ema) + log["samples_ema"] = self.decode( + torch.randn_like(posterior_ema.sample()) + ) + log["reconstructions_ema"] = xrec_ema + log["inputs"] = x + return log + + def to_rgb(self, x): + assert self.image_key == "segmentation" + if not hasattr(self, "colorize"): + self.register_buffer("colorize", torch.randn(3, x.shape[1], 1, 1).to(x)) + x = F.conv2d(x, weight=self.colorize) + x = 2.0 * (x - x.min()) / (x.max() - x.min()) - 1.0 + return x + + +class IdentityFirstStage(torch.nn.Module): + def __init__(self, *args, vq_interface=False, **kwargs): + self.vq_interface = vq_interface + super().__init__() + + def encode(self, x, *args, **kwargs): + return x + + def decode(self, x, *args, **kwargs): + return x + + def quantize(self, x, *args, **kwargs): + if self.vq_interface: + return x, None, [None, None, None] + return x + + def forward(self, x, *args, **kwargs): + return x diff --git a/apps/third_party/CRM/imagedream/ldm/models/diffusion/__init__.py b/apps/third_party/CRM/imagedream/ldm/models/diffusion/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/imagedream/ldm/models/diffusion/ddim.py b/apps/third_party/CRM/imagedream/ldm/models/diffusion/ddim.py new file mode 100644 index 0000000000000000000000000000000000000000..4c10321c39078e985f18a0ca7b388086a4aa4e2f --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/models/diffusion/ddim.py @@ -0,0 +1,430 @@ +"""SAMPLING ONLY.""" + +import torch +import numpy as np +from tqdm import tqdm +from functools import partial + +from ...modules.diffusionmodules.util import ( + make_ddim_sampling_parameters, + make_ddim_timesteps, + noise_like, + extract_into_tensor, +) + + +class DDIMSampler(object): + def __init__(self, model, schedule="linear", **kwargs): + super().__init__() + self.model = model + self.ddpm_num_timesteps = model.num_timesteps + self.schedule = schedule + + def register_buffer(self, name, attr): + if type(attr) == torch.Tensor: + if attr.device != torch.device("cuda"): + attr = attr.to(torch.device("cuda")) + setattr(self, name, attr) + + def make_schedule( + self, ddim_num_steps, ddim_discretize="uniform", ddim_eta=0.0, verbose=True + ): + self.ddim_timesteps = make_ddim_timesteps( + ddim_discr_method=ddim_discretize, + num_ddim_timesteps=ddim_num_steps, + num_ddpm_timesteps=self.ddpm_num_timesteps, + verbose=verbose, + ) + alphas_cumprod = self.model.alphas_cumprod + assert ( + alphas_cumprod.shape[0] == self.ddpm_num_timesteps + ), "alphas have to be defined for each timestep" + to_torch = lambda x: x.clone().detach().to(torch.float32).to(self.model.device) + + self.register_buffer("betas", to_torch(self.model.betas)) + self.register_buffer("alphas_cumprod", to_torch(alphas_cumprod)) + self.register_buffer( + "alphas_cumprod_prev", to_torch(self.model.alphas_cumprod_prev) + ) + + # calculations for diffusion q(x_t | x_{t-1}) and others + self.register_buffer( + "sqrt_alphas_cumprod", to_torch(np.sqrt(alphas_cumprod.cpu())) + ) + self.register_buffer( + "sqrt_one_minus_alphas_cumprod", + to_torch(np.sqrt(1.0 - alphas_cumprod.cpu())), + ) + self.register_buffer( + "log_one_minus_alphas_cumprod", to_torch(np.log(1.0 - alphas_cumprod.cpu())) + ) + self.register_buffer( + "sqrt_recip_alphas_cumprod", to_torch(np.sqrt(1.0 / alphas_cumprod.cpu())) + ) + self.register_buffer( + "sqrt_recipm1_alphas_cumprod", + to_torch(np.sqrt(1.0 / alphas_cumprod.cpu() - 1)), + ) + + # ddim sampling parameters + ddim_sigmas, ddim_alphas, ddim_alphas_prev = make_ddim_sampling_parameters( + alphacums=alphas_cumprod.cpu(), + ddim_timesteps=self.ddim_timesteps, + eta=ddim_eta, + verbose=verbose, + ) + self.register_buffer("ddim_sigmas", ddim_sigmas) + self.register_buffer("ddim_alphas", ddim_alphas) + self.register_buffer("ddim_alphas_prev", ddim_alphas_prev) + self.register_buffer("ddim_sqrt_one_minus_alphas", np.sqrt(1.0 - ddim_alphas)) + sigmas_for_original_sampling_steps = ddim_eta * torch.sqrt( + (1 - self.alphas_cumprod_prev) + / (1 - self.alphas_cumprod) + * (1 - self.alphas_cumprod / self.alphas_cumprod_prev) + ) + self.register_buffer( + "ddim_sigmas_for_original_num_steps", sigmas_for_original_sampling_steps + ) + + @torch.no_grad() + def sample( + self, + S, + batch_size, + shape, + conditioning=None, + callback=None, + normals_sequence=None, + img_callback=None, + quantize_x0=False, + eta=0.0, + mask=None, + x0=None, + temperature=1.0, + noise_dropout=0.0, + score_corrector=None, + corrector_kwargs=None, + verbose=True, + x_T=None, + log_every_t=100, + unconditional_guidance_scale=1.0, + unconditional_conditioning=None, + # this has to come in the same format as the conditioning, # e.g. as encoded tokens, ... + **kwargs, + ): + if conditioning is not None: + if isinstance(conditioning, dict): + cbs = conditioning[list(conditioning.keys())[0]].shape[0] + if cbs != batch_size: + print( + f"Warning: Got {cbs} conditionings but batch-size is {batch_size}" + ) + else: + if conditioning.shape[0] != batch_size: + print( + f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}" + ) + + self.make_schedule(ddim_num_steps=S, ddim_eta=eta, verbose=verbose) + # sampling + C, H, W = shape + size = (batch_size, C, H, W) + + samples, intermediates = self.ddim_sampling( + conditioning, + size, + callback=callback, + img_callback=img_callback, + quantize_denoised=quantize_x0, + mask=mask, + x0=x0, + ddim_use_original_steps=False, + noise_dropout=noise_dropout, + temperature=temperature, + score_corrector=score_corrector, + corrector_kwargs=corrector_kwargs, + x_T=x_T, + log_every_t=log_every_t, + unconditional_guidance_scale=unconditional_guidance_scale, + unconditional_conditioning=unconditional_conditioning, + **kwargs, + ) + return samples, intermediates + + @torch.no_grad() + def ddim_sampling( + self, + cond, + shape, + x_T=None, + ddim_use_original_steps=False, + callback=None, + timesteps=None, + quantize_denoised=False, + mask=None, + x0=None, + img_callback=None, + log_every_t=100, + temperature=1.0, + noise_dropout=0.0, + score_corrector=None, + corrector_kwargs=None, + unconditional_guidance_scale=1.0, + unconditional_conditioning=None, + **kwargs, + ): + """ + when inference time: all values of parameter + cond.keys(): dict_keys(['context', 'camera', 'num_frames', 'ip', 'ip_img']) + shape: (5, 4, 32, 32) + x_T: None + ddim_use_original_steps: False + timesteps: None + callback: None + quantize_denoised: False + mask: None + image_callback: None + log_every_t: 100 + temperature: 1.0 + noise_dropout: 0.0 + score_corrector: None + corrector_kwargs: None + unconditional_guidance_scale: 5 + unconditional_conditioning.keys(): dict_keys(['context', 'camera', 'num_frames', 'ip', 'ip_img']) + kwargs: {} + """ + device = self.model.betas.device + b = shape[0] + if x_T is None: + img = torch.randn(shape, device=device) # shape: torch.Size([5, 4, 32, 32]) mean: -0.00, std: 1.00, min: -3.64, max: 3.94 + else: + img = x_T + + if timesteps is None: # equal with set time step in hf + timesteps = ( + self.ddpm_num_timesteps + if ddim_use_original_steps + else self.ddim_timesteps + ) + elif timesteps is not None and not ddim_use_original_steps: + subset_end = ( + int( + min(timesteps / self.ddim_timesteps.shape[0], 1) + * self.ddim_timesteps.shape[0] + ) + - 1 + ) + timesteps = self.ddim_timesteps[:subset_end] + + intermediates = {"x_inter": [img], "pred_x0": [img]} + time_range = ( # reversed timesteps + reversed(range(0, timesteps)) + if ddim_use_original_steps + else np.flip(timesteps) + ) + total_steps = timesteps if ddim_use_original_steps else timesteps.shape[0] + iterator = tqdm(time_range, desc="DDIM Sampler", total=total_steps) + for i, step in enumerate(iterator): + index = total_steps - i - 1 + ts = torch.full((b,), step, device=device, dtype=torch.long) + + if mask is not None: + assert x0 is not None + img_orig = self.model.q_sample( + x0, ts + ) # TODO: deterministic forward pass? + img = img_orig * mask + (1.0 - mask) * img + + outs = self.p_sample_ddim( + img, + cond, + ts, + index=index, + use_original_steps=ddim_use_original_steps, + quantize_denoised=quantize_denoised, + temperature=temperature, + noise_dropout=noise_dropout, + score_corrector=score_corrector, + corrector_kwargs=corrector_kwargs, + unconditional_guidance_scale=unconditional_guidance_scale, + unconditional_conditioning=unconditional_conditioning, + **kwargs, + ) + img, pred_x0 = outs + if callback: + callback(i) + if img_callback: + img_callback(pred_x0, i) + + if index % log_every_t == 0 or index == total_steps - 1: + intermediates["x_inter"].append(img) + intermediates["pred_x0"].append(pred_x0) + + return img, intermediates + + @torch.no_grad() + def p_sample_ddim( + self, + x, + c, + t, + index, + repeat_noise=False, + use_original_steps=False, + quantize_denoised=False, + temperature=1.0, + noise_dropout=0.0, + score_corrector=None, + corrector_kwargs=None, + unconditional_guidance_scale=1.0, + unconditional_conditioning=None, + dynamic_threshold=None, + **kwargs, + ): + b, *_, device = *x.shape, x.device + + if unconditional_conditioning is None or unconditional_guidance_scale == 1.0: + model_output = self.model.apply_model(x, t, c) + else: + x_in = torch.cat([x] * 2) + t_in = torch.cat([t] * 2) + if isinstance(c, dict): + assert isinstance(unconditional_conditioning, dict) + c_in = dict() + for k in c: + if isinstance(c[k], list): + c_in[k] = [ + torch.cat([unconditional_conditioning[k][i], c[k][i]]) + for i in range(len(c[k])) + ] + elif isinstance(c[k], torch.Tensor): + c_in[k] = torch.cat([unconditional_conditioning[k], c[k]]) + else: + assert c[k] == unconditional_conditioning[k] + c_in[k] = c[k] + elif isinstance(c, list): + c_in = list() + assert isinstance(unconditional_conditioning, list) + for i in range(len(c)): + c_in.append(torch.cat([unconditional_conditioning[i], c[i]])) + else: + c_in = torch.cat([unconditional_conditioning, c]) + model_uncond, model_t = self.model.apply_model(x_in, t_in, c_in).chunk(2) + model_output = model_uncond + unconditional_guidance_scale * ( + model_t - model_uncond + ) + + + if self.model.parameterization == "v": + print("using v!") + e_t = self.model.predict_eps_from_z_and_v(x, t, model_output) + else: + e_t = model_output + + if score_corrector is not None: + assert self.model.parameterization == "eps", "not implemented" + e_t = score_corrector.modify_score( + self.model, e_t, x, t, c, **corrector_kwargs + ) + + alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas + alphas_prev = ( + self.model.alphas_cumprod_prev + if use_original_steps + else self.ddim_alphas_prev + ) + sqrt_one_minus_alphas = ( + self.model.sqrt_one_minus_alphas_cumprod + if use_original_steps + else self.ddim_sqrt_one_minus_alphas + ) + sigmas = ( + self.model.ddim_sigmas_for_original_num_steps + if use_original_steps + else self.ddim_sigmas + ) + # select parameters corresponding to the currently considered timestep + a_t = torch.full((b, 1, 1, 1), alphas[index], device=device) + a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device) + sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device) + sqrt_one_minus_at = torch.full( + (b, 1, 1, 1), sqrt_one_minus_alphas[index], device=device + ) + + # current prediction for x_0 + if self.model.parameterization != "v": + pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt() + else: + pred_x0 = self.model.predict_start_from_z_and_v(x, t, model_output) + + if quantize_denoised: + pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0) + + if dynamic_threshold is not None: + raise NotImplementedError() + + # direction pointing to x_t + dir_xt = (1.0 - a_prev - sigma_t**2).sqrt() * e_t + noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature + if noise_dropout > 0.0: + noise = torch.nn.functional.dropout(noise, p=noise_dropout) + x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise + return x_prev, pred_x0 + + @torch.no_grad() + def stochastic_encode(self, x0, t, use_original_steps=False, noise=None): + # fast, but does not allow for exact reconstruction + # t serves as an index to gather the correct alphas + if use_original_steps: + sqrt_alphas_cumprod = self.sqrt_alphas_cumprod + sqrt_one_minus_alphas_cumprod = self.sqrt_one_minus_alphas_cumprod + else: + sqrt_alphas_cumprod = torch.sqrt(self.ddim_alphas) + sqrt_one_minus_alphas_cumprod = self.ddim_sqrt_one_minus_alphas + + if noise is None: + noise = torch.randn_like(x0) + return ( + extract_into_tensor(sqrt_alphas_cumprod, t, x0.shape) * x0 + + extract_into_tensor(sqrt_one_minus_alphas_cumprod, t, x0.shape) * noise + ) + + @torch.no_grad() + def decode( + self, + x_latent, + cond, + t_start, + unconditional_guidance_scale=1.0, + unconditional_conditioning=None, + use_original_steps=False, + **kwargs, + ): + timesteps = ( + np.arange(self.ddpm_num_timesteps) + if use_original_steps + else self.ddim_timesteps + ) + timesteps = timesteps[:t_start] + + time_range = np.flip(timesteps) + total_steps = timesteps.shape[0] + + iterator = tqdm(time_range, desc="Decoding image", total=total_steps) + x_dec = x_latent + for i, step in enumerate(iterator): + index = total_steps - i - 1 + ts = torch.full( + (x_latent.shape[0],), step, device=x_latent.device, dtype=torch.long + ) + x_dec, _ = self.p_sample_ddim( + x_dec, + cond, + ts, + index=index, + use_original_steps=use_original_steps, + unconditional_guidance_scale=unconditional_guidance_scale, + unconditional_conditioning=unconditional_conditioning, + **kwargs, + ) + return x_dec diff --git a/apps/third_party/CRM/imagedream/ldm/modules/__init__.py b/apps/third_party/CRM/imagedream/ldm/modules/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/imagedream/ldm/modules/attention.py b/apps/third_party/CRM/imagedream/ldm/modules/attention.py new file mode 100644 index 0000000000000000000000000000000000000000..72c65ad4088fefdc6c8aa3a07596d602b312a407 --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/modules/attention.py @@ -0,0 +1,456 @@ +from inspect import isfunction +import math +import torch +import torch.nn.functional as F +from torch import nn, einsum +from einops import rearrange, repeat +from typing import Optional, Any + +from .diffusionmodules.util import checkpoint + + +try: + import xformers + import xformers.ops + + XFORMERS_IS_AVAILBLE = True +except: + XFORMERS_IS_AVAILBLE = False + +# CrossAttn precision handling +import os + +_ATTN_PRECISION = os.environ.get("ATTN_PRECISION", "fp32") + + +def exists(val): + return val is not None + + +def uniq(arr): + return {el: True for el in arr}.keys() + + +def default(val, d): + if exists(val): + return val + return d() if isfunction(d) else d + + +def max_neg_value(t): + return -torch.finfo(t.dtype).max + + +def init_(tensor): + dim = tensor.shape[-1] + std = 1 / math.sqrt(dim) + tensor.uniform_(-std, std) + return tensor + + +# feedforward +class GEGLU(nn.Module): + def __init__(self, dim_in, dim_out): + super().__init__() + self.proj = nn.Linear(dim_in, dim_out * 2) + + def forward(self, x): + x, gate = self.proj(x).chunk(2, dim=-1) + return x * F.gelu(gate) + + +class FeedForward(nn.Module): + def __init__(self, dim, dim_out=None, mult=4, glu=False, dropout=0.0): + super().__init__() + inner_dim = int(dim * mult) + dim_out = default(dim_out, dim) + project_in = ( + nn.Sequential(nn.Linear(dim, inner_dim), nn.GELU()) + if not glu + else GEGLU(dim, inner_dim) + ) + + self.net = nn.Sequential( + project_in, nn.Dropout(dropout), nn.Linear(inner_dim, dim_out) + ) + + def forward(self, x): + return self.net(x) + + +def zero_module(module): + """ + Zero out the parameters of a module and return it. + """ + for p in module.parameters(): + p.detach().zero_() + return module + + +def Normalize(in_channels): + return torch.nn.GroupNorm( + num_groups=32, num_channels=in_channels, eps=1e-6, affine=True + ) + + +class SpatialSelfAttention(nn.Module): + def __init__(self, in_channels): + super().__init__() + self.in_channels = in_channels + + self.norm = Normalize(in_channels) + self.q = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.k = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.v = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.proj_out = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + + def forward(self, x): + h_ = x + h_ = self.norm(h_) + q = self.q(h_) + k = self.k(h_) + v = self.v(h_) + + # compute attention + b, c, h, w = q.shape + q = rearrange(q, "b c h w -> b (h w) c") + k = rearrange(k, "b c h w -> b c (h w)") + w_ = torch.einsum("bij,bjk->bik", q, k) + + w_ = w_ * (int(c) ** (-0.5)) + w_ = torch.nn.functional.softmax(w_, dim=2) + + # attend to values + v = rearrange(v, "b c h w -> b c (h w)") + w_ = rearrange(w_, "b i j -> b j i") + h_ = torch.einsum("bij,bjk->bik", v, w_) + h_ = rearrange(h_, "b c (h w) -> b c h w", h=h) + h_ = self.proj_out(h_) + + return x + h_ + + +class MemoryEfficientCrossAttention(nn.Module): + # https://github.com/MatthieuTPHR/diffusers/blob/d80b531ff8060ec1ea982b65a1b8df70f73aa67c/src/diffusers/models/attention.py#L223 + def __init__(self, query_dim, context_dim=None, heads=8, dim_head=64, dropout=0.0, **kwargs): + super().__init__() + print( + f"Setting up {self.__class__.__name__}. Query dim is {query_dim}, context_dim is {context_dim} and using " + f"{heads} heads." + ) + inner_dim = dim_head * heads + context_dim = default(context_dim, query_dim) + + self.heads = heads + self.dim_head = dim_head + + self.with_ip = kwargs.get("with_ip", False) + if self.with_ip and (context_dim is not None): + self.to_k_ip = nn.Linear(context_dim, inner_dim, bias=False) + self.to_v_ip = nn.Linear(context_dim, inner_dim, bias=False) + self.ip_dim= kwargs.get("ip_dim", 16) + self.ip_weight = kwargs.get("ip_weight", 1.0) + + self.to_q = nn.Linear(query_dim, inner_dim, bias=False) + self.to_k = nn.Linear(context_dim, inner_dim, bias=False) + self.to_v = nn.Linear(context_dim, inner_dim, bias=False) + + self.to_out = nn.Sequential( + nn.Linear(inner_dim, query_dim), nn.Dropout(dropout) + ) + self.attention_op: Optional[Any] = None + + def forward(self, x, context=None, mask=None): + q = self.to_q(x) + + has_ip = self.with_ip and (context is not None) + if has_ip: + # context dim [(b frame_num), (77 + img_token), 1024] + token_len = context.shape[1] + context_ip = context[:, -self.ip_dim:, :] + k_ip = self.to_k_ip(context_ip) + v_ip = self.to_v_ip(context_ip) + context = context[:, :(token_len - self.ip_dim), :] + + context = default(context, x) + k = self.to_k(context) + v = self.to_v(context) + + b, _, _ = q.shape + q, k, v = map( + lambda t: t.unsqueeze(3) + .reshape(b, t.shape[1], self.heads, self.dim_head) + .permute(0, 2, 1, 3) + .reshape(b * self.heads, t.shape[1], self.dim_head) + .contiguous(), + (q, k, v), + ) + + # actually compute the attention, what we cannot get enough of + out = xformers.ops.memory_efficient_attention( + q, k, v, attn_bias=None, op=self.attention_op + ) + + if has_ip: + k_ip, v_ip = map( + lambda t: t.unsqueeze(3) + .reshape(b, t.shape[1], self.heads, self.dim_head) + .permute(0, 2, 1, 3) + .reshape(b * self.heads, t.shape[1], self.dim_head) + .contiguous(), + (k_ip, v_ip), + ) + # actually compute the attention, what we cannot get enough of + out_ip = xformers.ops.memory_efficient_attention( + q, k_ip, v_ip, attn_bias=None, op=self.attention_op + ) + out = out + self.ip_weight * out_ip + + if exists(mask): + raise NotImplementedError + out = ( + out.unsqueeze(0) + .reshape(b, self.heads, out.shape[1], self.dim_head) + .permute(0, 2, 1, 3) + .reshape(b, out.shape[1], self.heads * self.dim_head) + ) + return self.to_out(out) + + +class BasicTransformerBlock(nn.Module): + def __init__( + self, + dim, + n_heads, + d_head, + dropout=0.0, + context_dim=None, + gated_ff=True, + checkpoint=True, + disable_self_attn=False, + **kwargs + ): + super().__init__() + assert XFORMERS_IS_AVAILBLE, "xformers is not available" + attn_cls = MemoryEfficientCrossAttention + self.disable_self_attn = disable_self_attn + self.attn1 = attn_cls( + query_dim=dim, + heads=n_heads, + dim_head=d_head, + dropout=dropout, + context_dim=context_dim if self.disable_self_attn else None, + ) # is a self-attention if not self.disable_self_attn + self.ff = FeedForward(dim, dropout=dropout, glu=gated_ff) + self.attn2 = attn_cls( + query_dim=dim, + context_dim=context_dim, + heads=n_heads, + dim_head=d_head, + dropout=dropout, + **kwargs + ) # is self-attn if context is none + self.norm1 = nn.LayerNorm(dim) + self.norm2 = nn.LayerNorm(dim) + self.norm3 = nn.LayerNorm(dim) + self.checkpoint = checkpoint + + def forward(self, x, context=None): + return checkpoint( + self._forward, (x, context), self.parameters(), self.checkpoint + ) + + def _forward(self, x, context=None): + x = ( + self.attn1( + self.norm1(x), context=context if self.disable_self_attn else None + ) + + x + ) + x = self.attn2(self.norm2(x), context=context) + x + x = self.ff(self.norm3(x)) + x + return x + + +class SpatialTransformer(nn.Module): + """ + Transformer block for image-like data. + First, project the input (aka embedding) + and reshape to b, t, d. + Then apply standard transformer action. + Finally, reshape to image + NEW: use_linear for more efficiency instead of the 1x1 convs + """ + + def __init__( + self, + in_channels, + n_heads, + d_head, + depth=1, + dropout=0.0, + context_dim=None, + disable_self_attn=False, + use_linear=False, + use_checkpoint=True, + **kwargs + ): + super().__init__() + if exists(context_dim) and not isinstance(context_dim, list): + context_dim = [context_dim] + self.in_channels = in_channels + inner_dim = n_heads * d_head + self.norm = Normalize(in_channels) + if not use_linear: + self.proj_in = nn.Conv2d( + in_channels, inner_dim, kernel_size=1, stride=1, padding=0 + ) + else: + self.proj_in = nn.Linear(in_channels, inner_dim) + + self.transformer_blocks = nn.ModuleList( + [ + BasicTransformerBlock( + inner_dim, + n_heads, + d_head, + dropout=dropout, + context_dim=context_dim[d], + disable_self_attn=disable_self_attn, + checkpoint=use_checkpoint, + **kwargs + ) + for d in range(depth) + ] + ) + if not use_linear: + self.proj_out = zero_module( + nn.Conv2d(inner_dim, in_channels, kernel_size=1, stride=1, padding=0) + ) + else: + self.proj_out = zero_module(nn.Linear(in_channels, inner_dim)) + self.use_linear = use_linear + + def forward(self, x, context=None): + # note: if no context is given, cross-attention defaults to self-attention + if not isinstance(context, list): + context = [context] + b, c, h, w = x.shape + x_in = x + x = self.norm(x) + if not self.use_linear: + x = self.proj_in(x) + x = rearrange(x, "b c h w -> b (h w) c").contiguous() + if self.use_linear: + x = self.proj_in(x) + for i, block in enumerate(self.transformer_blocks): + x = block(x, context=context[i]) + if self.use_linear: + x = self.proj_out(x) + x = rearrange(x, "b (h w) c -> b c h w", h=h, w=w).contiguous() + if not self.use_linear: + x = self.proj_out(x) + return x + x_in + + +class BasicTransformerBlock3D(BasicTransformerBlock): + def forward(self, x, context=None, num_frames=1): + return checkpoint( + self._forward, (x, context, num_frames), self.parameters(), self.checkpoint + ) + + def _forward(self, x, context=None, num_frames=1): + x = rearrange(x, "(b f) l c -> b (f l) c", f=num_frames).contiguous() + x = ( + self.attn1( + self.norm1(x), + context=context if self.disable_self_attn else None + ) + + x + ) + x = rearrange(x, "b (f l) c -> (b f) l c", f=num_frames).contiguous() + x = self.attn2(self.norm2(x), context=context) + x + x = self.ff(self.norm3(x)) + x + return x + + +class SpatialTransformer3D(nn.Module): + """3D self-attention""" + + def __init__( + self, + in_channels, + n_heads, + d_head, + depth=1, + dropout=0.0, + context_dim=None, + disable_self_attn=False, + use_linear=False, + use_checkpoint=True, + **kwargs + ): + super().__init__() + if exists(context_dim) and not isinstance(context_dim, list): + context_dim = [context_dim] + self.in_channels = in_channels + inner_dim = n_heads * d_head + self.norm = Normalize(in_channels) + if not use_linear: + self.proj_in = nn.Conv2d( + in_channels, inner_dim, kernel_size=1, stride=1, padding=0 + ) + else: + self.proj_in = nn.Linear(in_channels, inner_dim) + + self.transformer_blocks = nn.ModuleList( + [ + BasicTransformerBlock3D( + inner_dim, + n_heads, + d_head, + dropout=dropout, + context_dim=context_dim[d], + disable_self_attn=disable_self_attn, + checkpoint=use_checkpoint, + **kwargs + ) + for d in range(depth) + ] + ) + if not use_linear: + self.proj_out = zero_module( + nn.Conv2d(inner_dim, in_channels, kernel_size=1, stride=1, padding=0) + ) + else: + self.proj_out = zero_module(nn.Linear(in_channels, inner_dim)) + self.use_linear = use_linear + + def forward(self, x, context=None, num_frames=1): + # note: if no context is given, cross-attention defaults to self-attention + if not isinstance(context, list): + context = [context] + b, c, h, w = x.shape + x_in = x + x = self.norm(x) + if not self.use_linear: + x = self.proj_in(x) + x = rearrange(x, "b c h w -> b (h w) c").contiguous() + if self.use_linear: + x = self.proj_in(x) + for i, block in enumerate(self.transformer_blocks): + x = block(x, context=context[i], num_frames=num_frames) + if self.use_linear: + x = self.proj_out(x) + x = rearrange(x, "b (h w) c -> b c h w", h=h, w=w).contiguous() + if not self.use_linear: + x = self.proj_out(x) + return x + x_in diff --git a/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/__init__.py b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/adaptors.py b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/adaptors.py new file mode 100644 index 0000000000000000000000000000000000000000..8d66e480728073294015cf0eb906dba471d602ca --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/adaptors.py @@ -0,0 +1,163 @@ +# modified from https://github.com/mlfoundations/open_flamingo/blob/main/open_flamingo/src/helpers.py +import math + +import torch +import torch.nn as nn + + +# FFN +def FeedForward(dim, mult=4): + inner_dim = int(dim * mult) + return nn.Sequential( + nn.LayerNorm(dim), + nn.Linear(dim, inner_dim, bias=False), + nn.GELU(), + nn.Linear(inner_dim, dim, bias=False), + ) + + +def reshape_tensor(x, heads): + bs, length, width = x.shape + #(bs, length, width) --> (bs, length, n_heads, dim_per_head) + x = x.view(bs, length, heads, -1) + # (bs, length, n_heads, dim_per_head) --> (bs, n_heads, length, dim_per_head) + x = x.transpose(1, 2) + # (bs, n_heads, length, dim_per_head) --> (bs*n_heads, length, dim_per_head) + x = x.reshape(bs, heads, length, -1) + return x + + +class PerceiverAttention(nn.Module): + def __init__(self, *, dim, dim_head=64, heads=8): + super().__init__() + self.scale = dim_head**-0.5 + self.dim_head = dim_head + self.heads = heads + inner_dim = dim_head * heads + + self.norm1 = nn.LayerNorm(dim) + self.norm2 = nn.LayerNorm(dim) + + self.to_q = nn.Linear(dim, inner_dim, bias=False) + self.to_kv = nn.Linear(dim, inner_dim * 2, bias=False) + self.to_out = nn.Linear(inner_dim, dim, bias=False) + + + def forward(self, x, latents): + """ + Args: + x (torch.Tensor): image features + shape (b, n1, D) + latent (torch.Tensor): latent features + shape (b, n2, D) + """ + x = self.norm1(x) + latents = self.norm2(latents) + + b, l, _ = latents.shape + + q = self.to_q(latents) + kv_input = torch.cat((x, latents), dim=-2) + k, v = self.to_kv(kv_input).chunk(2, dim=-1) + + q = reshape_tensor(q, self.heads) + k = reshape_tensor(k, self.heads) + v = reshape_tensor(v, self.heads) + + # attention + scale = 1 / math.sqrt(math.sqrt(self.dim_head)) + weight = (q * scale) @ (k * scale).transpose(-2, -1) # More stable with f16 than dividing afterwards + weight = torch.softmax(weight.float(), dim=-1).type(weight.dtype) + out = weight @ v + + out = out.permute(0, 2, 1, 3).reshape(b, l, -1) + + return self.to_out(out) + + +class ImageProjModel(torch.nn.Module): + """Projection Model""" + def __init__(self, + cross_attention_dim=1024, + clip_embeddings_dim=1024, + clip_extra_context_tokens=4): + super().__init__() + self.cross_attention_dim = cross_attention_dim + self.clip_extra_context_tokens = clip_extra_context_tokens + + # from 1024 -> 4 * 1024 + self.proj = torch.nn.Linear( + clip_embeddings_dim, + self.clip_extra_context_tokens * cross_attention_dim) + self.norm = torch.nn.LayerNorm(cross_attention_dim) + + def forward(self, image_embeds): + embeds = image_embeds + clip_extra_context_tokens = self.proj(embeds).reshape(-1, self.clip_extra_context_tokens, self.cross_attention_dim) + clip_extra_context_tokens = self.norm(clip_extra_context_tokens) + return clip_extra_context_tokens + + +class SimpleReSampler(nn.Module): + def __init__(self, embedding_dim=1280, output_dim=1024): + super().__init__() + self.proj_out = nn.Linear(embedding_dim, output_dim) + self.norm_out = nn.LayerNorm(output_dim) + + def forward(self, latents): + """ + latents: B 256 N + """ + latents = self.proj_out(latents) + return self.norm_out(latents) + + +class Resampler(nn.Module): + def __init__( + self, + dim=1024, + depth=8, + dim_head=64, + heads=16, + num_queries=8, + embedding_dim=768, + output_dim=1024, + ff_mult=4, + ): + super().__init__() + self.latents = nn.Parameter(torch.randn(1, num_queries, dim) / dim**0.5) + self.proj_in = nn.Linear(embedding_dim, dim) + self.proj_out = nn.Linear(dim, output_dim) + self.norm_out = nn.LayerNorm(output_dim) + + self.layers = nn.ModuleList([]) + for _ in range(depth): + self.layers.append( + nn.ModuleList( + [ + PerceiverAttention(dim=dim, + dim_head=dim_head, + heads=heads), + FeedForward(dim=dim, mult=ff_mult), + ] + ) + ) + + def forward(self, x): + latents = self.latents.repeat(x.size(0), 1, 1) + x = self.proj_in(x) + for attn, ff in self.layers: + latents = attn(x, latents) + latents + latents = ff(latents) + latents + + latents = self.proj_out(latents) + return self.norm_out(latents) + + +if __name__ == '__main__': + resampler = Resampler(embedding_dim=1280) + resampler = SimpleReSampler(embedding_dim=1280) + tensor = torch.rand(4, 257, 1280) + embed = resampler(tensor) + # embed = (tensor) + print(embed.shape) diff --git a/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/model.py b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/model.py new file mode 100644 index 0000000000000000000000000000000000000000..3fd14f9bd16212e4858ee44d410cb3b411248058 --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/model.py @@ -0,0 +1,1018 @@ +# pytorch_diffusion + derived encoder decoder +import math +import torch +import torch.nn as nn +import numpy as np +from einops import rearrange +from typing import Optional, Any + +from ..attention import MemoryEfficientCrossAttention + +try: + import xformers + import xformers.ops + + XFORMERS_IS_AVAILBLE = True +except: + XFORMERS_IS_AVAILBLE = False + print("No module 'xformers'. Proceeding without it.") + + +def get_timestep_embedding(timesteps, embedding_dim): + """ + This matches the implementation in Denoising Diffusion Probabilistic Models: + From Fairseq. + Build sinusoidal embeddings. + This matches the implementation in tensor2tensor, but differs slightly + from the description in Section 3.5 of "Attention Is All You Need". + """ + assert len(timesteps.shape) == 1 + + half_dim = embedding_dim // 2 + emb = math.log(10000) / (half_dim - 1) + emb = torch.exp(torch.arange(half_dim, dtype=torch.float32) * -emb) + emb = emb.to(device=timesteps.device) + emb = timesteps.float()[:, None] * emb[None, :] + emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=1) + if embedding_dim % 2 == 1: # zero pad + emb = torch.nn.functional.pad(emb, (0, 1, 0, 0)) + return emb + + +def nonlinearity(x): + # swish + return x * torch.sigmoid(x) + + +def Normalize(in_channels, num_groups=32): + return torch.nn.GroupNorm( + num_groups=num_groups, num_channels=in_channels, eps=1e-6, affine=True + ) + + +class Upsample(nn.Module): + def __init__(self, in_channels, with_conv): + super().__init__() + self.with_conv = with_conv + if self.with_conv: + self.conv = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=3, stride=1, padding=1 + ) + + def forward(self, x): + x = torch.nn.functional.interpolate(x, scale_factor=2.0, mode="nearest") + if self.with_conv: + x = self.conv(x) + return x + + +class Downsample(nn.Module): + def __init__(self, in_channels, with_conv): + super().__init__() + self.with_conv = with_conv + if self.with_conv: + # no asymmetric padding in torch conv, must do it ourselves + self.conv = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=3, stride=2, padding=0 + ) + + def forward(self, x): + if self.with_conv: + pad = (0, 1, 0, 1) + x = torch.nn.functional.pad(x, pad, mode="constant", value=0) + x = self.conv(x) + else: + x = torch.nn.functional.avg_pool2d(x, kernel_size=2, stride=2) + return x + + +class ResnetBlock(nn.Module): + def __init__( + self, + *, + in_channels, + out_channels=None, + conv_shortcut=False, + dropout, + temb_channels=512, + ): + super().__init__() + self.in_channels = in_channels + out_channels = in_channels if out_channels is None else out_channels + self.out_channels = out_channels + self.use_conv_shortcut = conv_shortcut + + self.norm1 = Normalize(in_channels) + self.conv1 = torch.nn.Conv2d( + in_channels, out_channels, kernel_size=3, stride=1, padding=1 + ) + if temb_channels > 0: + self.temb_proj = torch.nn.Linear(temb_channels, out_channels) + self.norm2 = Normalize(out_channels) + self.dropout = torch.nn.Dropout(dropout) + self.conv2 = torch.nn.Conv2d( + out_channels, out_channels, kernel_size=3, stride=1, padding=1 + ) + if self.in_channels != self.out_channels: + if self.use_conv_shortcut: + self.conv_shortcut = torch.nn.Conv2d( + in_channels, out_channels, kernel_size=3, stride=1, padding=1 + ) + else: + self.nin_shortcut = torch.nn.Conv2d( + in_channels, out_channels, kernel_size=1, stride=1, padding=0 + ) + + def forward(self, x, temb): + h = x + h = self.norm1(h) + h = nonlinearity(h) + h = self.conv1(h) + + if temb is not None: + h = h + self.temb_proj(nonlinearity(temb))[:, :, None, None] + + h = self.norm2(h) + h = nonlinearity(h) + h = self.dropout(h) + h = self.conv2(h) + + if self.in_channels != self.out_channels: + if self.use_conv_shortcut: + x = self.conv_shortcut(x) + else: + x = self.nin_shortcut(x) + + return x + h + + +class AttnBlock(nn.Module): + def __init__(self, in_channels): + super().__init__() + self.in_channels = in_channels + + self.norm = Normalize(in_channels) + self.q = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.k = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.v = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.proj_out = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + + def forward(self, x): + h_ = x + h_ = self.norm(h_) + q = self.q(h_) + k = self.k(h_) + v = self.v(h_) + + # compute attention + b, c, h, w = q.shape + q = q.reshape(b, c, h * w) + q = q.permute(0, 2, 1) # b,hw,c + k = k.reshape(b, c, h * w) # b,c,hw + w_ = torch.bmm(q, k) # b,hw,hw w[b,i,j]=sum_c q[b,i,c]k[b,c,j] + w_ = w_ * (int(c) ** (-0.5)) + w_ = torch.nn.functional.softmax(w_, dim=2) + + # attend to values + v = v.reshape(b, c, h * w) + w_ = w_.permute(0, 2, 1) # b,hw,hw (first hw of k, second of q) + h_ = torch.bmm(v, w_) # b, c,hw (hw of q) h_[b,c,j] = sum_i v[b,c,i] w_[b,i,j] + h_ = h_.reshape(b, c, h, w) + + h_ = self.proj_out(h_) + + return x + h_ + + +class MemoryEfficientAttnBlock(nn.Module): + """ + Uses xformers efficient implementation, + see https://github.com/MatthieuTPHR/diffusers/blob/d80b531ff8060ec1ea982b65a1b8df70f73aa67c/src/diffusers/models/attention.py#L223 + Note: this is a single-head self-attention operation + """ + + # + def __init__(self, in_channels): + super().__init__() + self.in_channels = in_channels + + self.norm = Normalize(in_channels) + self.q = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.k = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.v = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.proj_out = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0 + ) + self.attention_op: Optional[Any] = None + + def forward(self, x): + h_ = x + h_ = self.norm(h_) + q = self.q(h_) + k = self.k(h_) + v = self.v(h_) + + # compute attention + B, C, H, W = q.shape + q, k, v = map(lambda x: rearrange(x, "b c h w -> b (h w) c"), (q, k, v)) + + q, k, v = map( + lambda t: t.unsqueeze(3) + .reshape(B, t.shape[1], 1, C) + .permute(0, 2, 1, 3) + .reshape(B * 1, t.shape[1], C) + .contiguous(), + (q, k, v), + ) + out = xformers.ops.memory_efficient_attention( + q, k, v, attn_bias=None, op=self.attention_op + ) + + out = ( + out.unsqueeze(0) + .reshape(B, 1, out.shape[1], C) + .permute(0, 2, 1, 3) + .reshape(B, out.shape[1], C) + ) + out = rearrange(out, "b (h w) c -> b c h w", b=B, h=H, w=W, c=C) + out = self.proj_out(out) + return x + out + + +class MemoryEfficientCrossAttentionWrapper(MemoryEfficientCrossAttention): + def forward(self, x, context=None, mask=None): + b, c, h, w = x.shape + x = rearrange(x, "b c h w -> b (h w) c") + out = super().forward(x, context=context, mask=mask) + out = rearrange(out, "b (h w) c -> b c h w", h=h, w=w, c=c) + return x + out + + +def make_attn(in_channels, attn_type="vanilla", attn_kwargs=None): + assert attn_type in [ + "vanilla", + "vanilla-xformers", + "memory-efficient-cross-attn", + "linear", + "none", + ], f"attn_type {attn_type} unknown" + if XFORMERS_IS_AVAILBLE and attn_type == "vanilla": + attn_type = "vanilla-xformers" + print(f"making attention of type '{attn_type}' with {in_channels} in_channels") + if attn_type == "vanilla": + assert attn_kwargs is None + return AttnBlock(in_channels) + elif attn_type == "vanilla-xformers": + print(f"building MemoryEfficientAttnBlock with {in_channels} in_channels...") + return MemoryEfficientAttnBlock(in_channels) + elif type == "memory-efficient-cross-attn": + attn_kwargs["query_dim"] = in_channels + return MemoryEfficientCrossAttentionWrapper(**attn_kwargs) + elif attn_type == "none": + return nn.Identity(in_channels) + else: + raise NotImplementedError() + + +class Model(nn.Module): + def __init__( + self, + *, + ch, + out_ch, + ch_mult=(1, 2, 4, 8), + num_res_blocks, + attn_resolutions, + dropout=0.0, + resamp_with_conv=True, + in_channels, + resolution, + use_timestep=True, + use_linear_attn=False, + attn_type="vanilla", + ): + super().__init__() + if use_linear_attn: + attn_type = "linear" + self.ch = ch + self.temb_ch = self.ch * 4 + self.num_resolutions = len(ch_mult) + self.num_res_blocks = num_res_blocks + self.resolution = resolution + self.in_channels = in_channels + + self.use_timestep = use_timestep + if self.use_timestep: + # timestep embedding + self.temb = nn.Module() + self.temb.dense = nn.ModuleList( + [ + torch.nn.Linear(self.ch, self.temb_ch), + torch.nn.Linear(self.temb_ch, self.temb_ch), + ] + ) + + # downsampling + self.conv_in = torch.nn.Conv2d( + in_channels, self.ch, kernel_size=3, stride=1, padding=1 + ) + + curr_res = resolution + in_ch_mult = (1,) + tuple(ch_mult) + self.down = nn.ModuleList() + for i_level in range(self.num_resolutions): + block = nn.ModuleList() + attn = nn.ModuleList() + block_in = ch * in_ch_mult[i_level] + block_out = ch * ch_mult[i_level] + for i_block in range(self.num_res_blocks): + block.append( + ResnetBlock( + in_channels=block_in, + out_channels=block_out, + temb_channels=self.temb_ch, + dropout=dropout, + ) + ) + block_in = block_out + if curr_res in attn_resolutions: + attn.append(make_attn(block_in, attn_type=attn_type)) + down = nn.Module() + down.block = block + down.attn = attn + if i_level != self.num_resolutions - 1: + down.downsample = Downsample(block_in, resamp_with_conv) + curr_res = curr_res // 2 + self.down.append(down) + + # middle + self.mid = nn.Module() + self.mid.block_1 = ResnetBlock( + in_channels=block_in, + out_channels=block_in, + temb_channels=self.temb_ch, + dropout=dropout, + ) + self.mid.attn_1 = make_attn(block_in, attn_type=attn_type) + self.mid.block_2 = ResnetBlock( + in_channels=block_in, + out_channels=block_in, + temb_channels=self.temb_ch, + dropout=dropout, + ) + + # upsampling + self.up = nn.ModuleList() + for i_level in reversed(range(self.num_resolutions)): + block = nn.ModuleList() + attn = nn.ModuleList() + block_out = ch * ch_mult[i_level] + skip_in = ch * ch_mult[i_level] + for i_block in range(self.num_res_blocks + 1): + if i_block == self.num_res_blocks: + skip_in = ch * in_ch_mult[i_level] + block.append( + ResnetBlock( + in_channels=block_in + skip_in, + out_channels=block_out, + temb_channels=self.temb_ch, + dropout=dropout, + ) + ) + block_in = block_out + if curr_res in attn_resolutions: + attn.append(make_attn(block_in, attn_type=attn_type)) + up = nn.Module() + up.block = block + up.attn = attn + if i_level != 0: + up.upsample = Upsample(block_in, resamp_with_conv) + curr_res = curr_res * 2 + self.up.insert(0, up) # prepend to get consistent order + + # end + self.norm_out = Normalize(block_in) + self.conv_out = torch.nn.Conv2d( + block_in, out_ch, kernel_size=3, stride=1, padding=1 + ) + + def forward(self, x, t=None, context=None): + # assert x.shape[2] == x.shape[3] == self.resolution + if context is not None: + # assume aligned context, cat along channel axis + x = torch.cat((x, context), dim=1) + if self.use_timestep: + # timestep embedding + assert t is not None + temb = get_timestep_embedding(t, self.ch) + temb = self.temb.dense[0](temb) + temb = nonlinearity(temb) + temb = self.temb.dense[1](temb) + else: + temb = None + + # downsampling + hs = [self.conv_in(x)] + for i_level in range(self.num_resolutions): + for i_block in range(self.num_res_blocks): + h = self.down[i_level].block[i_block](hs[-1], temb) + if len(self.down[i_level].attn) > 0: + h = self.down[i_level].attn[i_block](h) + hs.append(h) + if i_level != self.num_resolutions - 1: + hs.append(self.down[i_level].downsample(hs[-1])) + + # middle + h = hs[-1] + h = self.mid.block_1(h, temb) + h = self.mid.attn_1(h) + h = self.mid.block_2(h, temb) + + # upsampling + for i_level in reversed(range(self.num_resolutions)): + for i_block in range(self.num_res_blocks + 1): + h = self.up[i_level].block[i_block]( + torch.cat([h, hs.pop()], dim=1), temb + ) + if len(self.up[i_level].attn) > 0: + h = self.up[i_level].attn[i_block](h) + if i_level != 0: + h = self.up[i_level].upsample(h) + + # end + h = self.norm_out(h) + h = nonlinearity(h) + h = self.conv_out(h) + return h + + def get_last_layer(self): + return self.conv_out.weight + + +class Encoder(nn.Module): + def __init__( + self, + *, + ch, + out_ch, + ch_mult=(1, 2, 4, 8), + num_res_blocks, + attn_resolutions, + dropout=0.0, + resamp_with_conv=True, + in_channels, + resolution, + z_channels, + double_z=True, + use_linear_attn=False, + attn_type="vanilla", + **ignore_kwargs, + ): + super().__init__() + if use_linear_attn: + attn_type = "linear" + self.ch = ch + self.temb_ch = 0 + self.num_resolutions = len(ch_mult) + self.num_res_blocks = num_res_blocks + self.resolution = resolution + self.in_channels = in_channels + + # downsampling + self.conv_in = torch.nn.Conv2d( + in_channels, self.ch, kernel_size=3, stride=1, padding=1 + ) + + curr_res = resolution + in_ch_mult = (1,) + tuple(ch_mult) + self.in_ch_mult = in_ch_mult + self.down = nn.ModuleList() + for i_level in range(self.num_resolutions): + block = nn.ModuleList() + attn = nn.ModuleList() + block_in = ch * in_ch_mult[i_level] + block_out = ch * ch_mult[i_level] + for i_block in range(self.num_res_blocks): + block.append( + ResnetBlock( + in_channels=block_in, + out_channels=block_out, + temb_channels=self.temb_ch, + dropout=dropout, + ) + ) + block_in = block_out + if curr_res in attn_resolutions: + attn.append(make_attn(block_in, attn_type=attn_type)) + down = nn.Module() + down.block = block + down.attn = attn + if i_level != self.num_resolutions - 1: + down.downsample = Downsample(block_in, resamp_with_conv) + curr_res = curr_res // 2 + self.down.append(down) + + # middle + self.mid = nn.Module() + self.mid.block_1 = ResnetBlock( + in_channels=block_in, + out_channels=block_in, + temb_channels=self.temb_ch, + dropout=dropout, + ) + self.mid.attn_1 = make_attn(block_in, attn_type=attn_type) + self.mid.block_2 = ResnetBlock( + in_channels=block_in, + out_channels=block_in, + temb_channels=self.temb_ch, + dropout=dropout, + ) + + # end + self.norm_out = Normalize(block_in) + self.conv_out = torch.nn.Conv2d( + block_in, + 2 * z_channels if double_z else z_channels, + kernel_size=3, + stride=1, + padding=1, + ) + + def forward(self, x): + # timestep embedding + temb = None + + # downsampling + hs = [self.conv_in(x)] + for i_level in range(self.num_resolutions): + for i_block in range(self.num_res_blocks): + h = self.down[i_level].block[i_block](hs[-1], temb) + if len(self.down[i_level].attn) > 0: + h = self.down[i_level].attn[i_block](h) + hs.append(h) + if i_level != self.num_resolutions - 1: + hs.append(self.down[i_level].downsample(hs[-1])) + + # middle + h = hs[-1] + h = self.mid.block_1(h, temb) + h = self.mid.attn_1(h) + h = self.mid.block_2(h, temb) + + # end + h = self.norm_out(h) + h = nonlinearity(h) + h = self.conv_out(h) + return h + + +class Decoder(nn.Module): + def __init__( + self, + *, + ch, + out_ch, + ch_mult=(1, 2, 4, 8), + num_res_blocks, + attn_resolutions, + dropout=0.0, + resamp_with_conv=True, + in_channels, + resolution, + z_channels, + give_pre_end=False, + tanh_out=False, + use_linear_attn=False, + attn_type="vanilla", + **ignorekwargs, + ): + super().__init__() + if use_linear_attn: + attn_type = "linear" + self.ch = ch + self.temb_ch = 0 + self.num_resolutions = len(ch_mult) + self.num_res_blocks = num_res_blocks + self.resolution = resolution + self.in_channels = in_channels + self.give_pre_end = give_pre_end + self.tanh_out = tanh_out + + # compute in_ch_mult, block_in and curr_res at lowest res + in_ch_mult = (1,) + tuple(ch_mult) + block_in = ch * ch_mult[self.num_resolutions - 1] + curr_res = resolution // 2 ** (self.num_resolutions - 1) + self.z_shape = (1, z_channels, curr_res, curr_res) + print( + "Working with z of shape {} = {} dimensions.".format( + self.z_shape, np.prod(self.z_shape) + ) + ) + + # z to block_in + self.conv_in = torch.nn.Conv2d( + z_channels, block_in, kernel_size=3, stride=1, padding=1 + ) + + # middle + self.mid = nn.Module() + self.mid.block_1 = ResnetBlock( + in_channels=block_in, + out_channels=block_in, + temb_channels=self.temb_ch, + dropout=dropout, + ) + self.mid.attn_1 = make_attn(block_in, attn_type=attn_type) + self.mid.block_2 = ResnetBlock( + in_channels=block_in, + out_channels=block_in, + temb_channels=self.temb_ch, + dropout=dropout, + ) + + # upsampling + self.up = nn.ModuleList() + for i_level in reversed(range(self.num_resolutions)): + block = nn.ModuleList() + attn = nn.ModuleList() + block_out = ch * ch_mult[i_level] + for i_block in range(self.num_res_blocks + 1): + block.append( + ResnetBlock( + in_channels=block_in, + out_channels=block_out, + temb_channels=self.temb_ch, + dropout=dropout, + ) + ) + block_in = block_out + if curr_res in attn_resolutions: + attn.append(make_attn(block_in, attn_type=attn_type)) + up = nn.Module() + up.block = block + up.attn = attn + if i_level != 0: + up.upsample = Upsample(block_in, resamp_with_conv) + curr_res = curr_res * 2 + self.up.insert(0, up) # prepend to get consistent order + + # end + self.norm_out = Normalize(block_in) + self.conv_out = torch.nn.Conv2d( + block_in, out_ch, kernel_size=3, stride=1, padding=1 + ) + + def forward(self, z): + # assert z.shape[1:] == self.z_shape[1:] + self.last_z_shape = z.shape + + # timestep embedding + temb = None + + # z to block_in + h = self.conv_in(z) + + # middle + h = self.mid.block_1(h, temb) + h = self.mid.attn_1(h) + h = self.mid.block_2(h, temb) + + # upsampling + for i_level in reversed(range(self.num_resolutions)): + for i_block in range(self.num_res_blocks + 1): + h = self.up[i_level].block[i_block](h, temb) + if len(self.up[i_level].attn) > 0: + h = self.up[i_level].attn[i_block](h) + if i_level != 0: + h = self.up[i_level].upsample(h) + + # end + if self.give_pre_end: + return h + + h = self.norm_out(h) + h = nonlinearity(h) + h = self.conv_out(h) + if self.tanh_out: + h = torch.tanh(h) + return h + + +class SimpleDecoder(nn.Module): + def __init__(self, in_channels, out_channels, *args, **kwargs): + super().__init__() + self.model = nn.ModuleList( + [ + nn.Conv2d(in_channels, in_channels, 1), + ResnetBlock( + in_channels=in_channels, + out_channels=2 * in_channels, + temb_channels=0, + dropout=0.0, + ), + ResnetBlock( + in_channels=2 * in_channels, + out_channels=4 * in_channels, + temb_channels=0, + dropout=0.0, + ), + ResnetBlock( + in_channels=4 * in_channels, + out_channels=2 * in_channels, + temb_channels=0, + dropout=0.0, + ), + nn.Conv2d(2 * in_channels, in_channels, 1), + Upsample(in_channels, with_conv=True), + ] + ) + # end + self.norm_out = Normalize(in_channels) + self.conv_out = torch.nn.Conv2d( + in_channels, out_channels, kernel_size=3, stride=1, padding=1 + ) + + def forward(self, x): + for i, layer in enumerate(self.model): + if i in [1, 2, 3]: + x = layer(x, None) + else: + x = layer(x) + + h = self.norm_out(x) + h = nonlinearity(h) + x = self.conv_out(h) + return x + + +class UpsampleDecoder(nn.Module): + def __init__( + self, + in_channels, + out_channels, + ch, + num_res_blocks, + resolution, + ch_mult=(2, 2), + dropout=0.0, + ): + super().__init__() + # upsampling + self.temb_ch = 0 + self.num_resolutions = len(ch_mult) + self.num_res_blocks = num_res_blocks + block_in = in_channels + curr_res = resolution // 2 ** (self.num_resolutions - 1) + self.res_blocks = nn.ModuleList() + self.upsample_blocks = nn.ModuleList() + for i_level in range(self.num_resolutions): + res_block = [] + block_out = ch * ch_mult[i_level] + for i_block in range(self.num_res_blocks + 1): + res_block.append( + ResnetBlock( + in_channels=block_in, + out_channels=block_out, + temb_channels=self.temb_ch, + dropout=dropout, + ) + ) + block_in = block_out + self.res_blocks.append(nn.ModuleList(res_block)) + if i_level != self.num_resolutions - 1: + self.upsample_blocks.append(Upsample(block_in, True)) + curr_res = curr_res * 2 + + # end + self.norm_out = Normalize(block_in) + self.conv_out = torch.nn.Conv2d( + block_in, out_channels, kernel_size=3, stride=1, padding=1 + ) + + def forward(self, x): + # upsampling + h = x + for k, i_level in enumerate(range(self.num_resolutions)): + for i_block in range(self.num_res_blocks + 1): + h = self.res_blocks[i_level][i_block](h, None) + if i_level != self.num_resolutions - 1: + h = self.upsample_blocks[k](h) + h = self.norm_out(h) + h = nonlinearity(h) + h = self.conv_out(h) + return h + + +class LatentRescaler(nn.Module): + def __init__(self, factor, in_channels, mid_channels, out_channels, depth=2): + super().__init__() + # residual block, interpolate, residual block + self.factor = factor + self.conv_in = nn.Conv2d( + in_channels, mid_channels, kernel_size=3, stride=1, padding=1 + ) + self.res_block1 = nn.ModuleList( + [ + ResnetBlock( + in_channels=mid_channels, + out_channels=mid_channels, + temb_channels=0, + dropout=0.0, + ) + for _ in range(depth) + ] + ) + self.attn = AttnBlock(mid_channels) + self.res_block2 = nn.ModuleList( + [ + ResnetBlock( + in_channels=mid_channels, + out_channels=mid_channels, + temb_channels=0, + dropout=0.0, + ) + for _ in range(depth) + ] + ) + + self.conv_out = nn.Conv2d( + mid_channels, + out_channels, + kernel_size=1, + ) + + def forward(self, x): + x = self.conv_in(x) + for block in self.res_block1: + x = block(x, None) + x = torch.nn.functional.interpolate( + x, + size=( + int(round(x.shape[2] * self.factor)), + int(round(x.shape[3] * self.factor)), + ), + ) + x = self.attn(x) + for block in self.res_block2: + x = block(x, None) + x = self.conv_out(x) + return x + + +class MergedRescaleEncoder(nn.Module): + def __init__( + self, + in_channels, + ch, + resolution, + out_ch, + num_res_blocks, + attn_resolutions, + dropout=0.0, + resamp_with_conv=True, + ch_mult=(1, 2, 4, 8), + rescale_factor=1.0, + rescale_module_depth=1, + ): + super().__init__() + intermediate_chn = ch * ch_mult[-1] + self.encoder = Encoder( + in_channels=in_channels, + num_res_blocks=num_res_blocks, + ch=ch, + ch_mult=ch_mult, + z_channels=intermediate_chn, + double_z=False, + resolution=resolution, + attn_resolutions=attn_resolutions, + dropout=dropout, + resamp_with_conv=resamp_with_conv, + out_ch=None, + ) + self.rescaler = LatentRescaler( + factor=rescale_factor, + in_channels=intermediate_chn, + mid_channels=intermediate_chn, + out_channels=out_ch, + depth=rescale_module_depth, + ) + + def forward(self, x): + x = self.encoder(x) + x = self.rescaler(x) + return x + + +class MergedRescaleDecoder(nn.Module): + def __init__( + self, + z_channels, + out_ch, + resolution, + num_res_blocks, + attn_resolutions, + ch, + ch_mult=(1, 2, 4, 8), + dropout=0.0, + resamp_with_conv=True, + rescale_factor=1.0, + rescale_module_depth=1, + ): + super().__init__() + tmp_chn = z_channels * ch_mult[-1] + self.decoder = Decoder( + out_ch=out_ch, + z_channels=tmp_chn, + attn_resolutions=attn_resolutions, + dropout=dropout, + resamp_with_conv=resamp_with_conv, + in_channels=None, + num_res_blocks=num_res_blocks, + ch_mult=ch_mult, + resolution=resolution, + ch=ch, + ) + self.rescaler = LatentRescaler( + factor=rescale_factor, + in_channels=z_channels, + mid_channels=tmp_chn, + out_channels=tmp_chn, + depth=rescale_module_depth, + ) + + def forward(self, x): + x = self.rescaler(x) + x = self.decoder(x) + return x + + +class Upsampler(nn.Module): + def __init__(self, in_size, out_size, in_channels, out_channels, ch_mult=2): + super().__init__() + assert out_size >= in_size + num_blocks = int(np.log2(out_size // in_size)) + 1 + factor_up = 1.0 + (out_size % in_size) + print( + f"Building {self.__class__.__name__} with in_size: {in_size} --> out_size {out_size} and factor {factor_up}" + ) + self.rescaler = LatentRescaler( + factor=factor_up, + in_channels=in_channels, + mid_channels=2 * in_channels, + out_channels=in_channels, + ) + self.decoder = Decoder( + out_ch=out_channels, + resolution=out_size, + z_channels=in_channels, + num_res_blocks=2, + attn_resolutions=[], + in_channels=None, + ch=in_channels, + ch_mult=[ch_mult for _ in range(num_blocks)], + ) + + def forward(self, x): + x = self.rescaler(x) + x = self.decoder(x) + return x + + +class Resize(nn.Module): + def __init__(self, in_channels=None, learned=False, mode="bilinear"): + super().__init__() + self.with_conv = learned + self.mode = mode + if self.with_conv: + print( + f"Note: {self.__class__.__name} uses learned downsampling and will ignore the fixed {mode} mode" + ) + raise NotImplementedError() + assert in_channels is not None + # no asymmetric padding in torch conv, must do it ourselves + self.conv = torch.nn.Conv2d( + in_channels, in_channels, kernel_size=4, stride=2, padding=1 + ) + + def forward(self, x, scale_factor=1.0): + if scale_factor == 1.0: + return x + else: + x = torch.nn.functional.interpolate( + x, mode=self.mode, align_corners=False, scale_factor=scale_factor + ) + return x diff --git a/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/openaimodel.py b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/openaimodel.py new file mode 100644 index 0000000000000000000000000000000000000000..2f12a389584a729e1177af8683d631e5c5d77fd5 --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/openaimodel.py @@ -0,0 +1,1135 @@ +from abc import abstractmethod +import math + +import numpy as np +import torch +import torch as th +import torch.nn as nn +import torch.nn.functional as F +from einops import rearrange, repeat + +from imagedream.ldm.modules.diffusionmodules.util import ( + checkpoint, + conv_nd, + linear, + avg_pool_nd, + zero_module, + normalization, + timestep_embedding, + convert_module_to_f16, + convert_module_to_f32 +) +from imagedream.ldm.modules.attention import ( + SpatialTransformer, + SpatialTransformer3D, + exists +) +from imagedream.ldm.modules.diffusionmodules.adaptors import ( + Resampler, + ImageProjModel +) + +## go +class AttentionPool2d(nn.Module): + """ + Adapted from CLIP: https://github.com/openai/CLIP/blob/main/clip/model.py + """ + + def __init__( + self, + spacial_dim: int, + embed_dim: int, + num_heads_channels: int, + output_dim: int = None, + ): + super().__init__() + self.positional_embedding = nn.Parameter( + th.randn(embed_dim, spacial_dim**2 + 1) / embed_dim**0.5 + ) + self.qkv_proj = conv_nd(1, embed_dim, 3 * embed_dim, 1) + self.c_proj = conv_nd(1, embed_dim, output_dim or embed_dim, 1) + self.num_heads = embed_dim // num_heads_channels + self.attention = QKVAttention(self.num_heads) + + def forward(self, x): + b, c, *_spatial = x.shape + x = x.reshape(b, c, -1) # NC(HW) + x = th.cat([x.mean(dim=-1, keepdim=True), x], dim=-1) # NC(HW+1) + x = x + self.positional_embedding[None, :, :].to(x.dtype) # NC(HW+1) + x = self.qkv_proj(x) + x = self.attention(x) + x = self.c_proj(x) + return x[:, :, 0] + + +class TimestepBlock(nn.Module): + """ + Any module where forward() takes timestep embeddings as a second argument. + """ + + @abstractmethod + def forward(self, x, emb): + """ + Apply the module to `x` given `emb` timestep embeddings. + """ + + +class TimestepEmbedSequential(nn.Sequential, TimestepBlock): + """ + A sequential module that passes timestep embeddings to the children that + support it as an extra input. + """ + + def forward(self, x, emb, context=None, num_frames=1): + for layer in self: + if isinstance(layer, TimestepBlock): + x = layer(x, emb) + elif isinstance(layer, SpatialTransformer3D): + x = layer(x, context, num_frames=num_frames) + elif isinstance(layer, SpatialTransformer): + x = layer(x, context) + else: + x = layer(x) + return x + + +class Upsample(nn.Module): + """ + An upsampling layer with an optional convolution. + :param channels: channels in the inputs and outputs. + :param use_conv: a bool determining if a convolution is applied. + :param dims: determines if the signal is 1D, 2D, or 3D. If 3D, then + upsampling occurs in the inner-two dimensions. + """ + + def __init__(self, channels, use_conv, dims=2, out_channels=None, padding=1): + super().__init__() + self.channels = channels + self.out_channels = out_channels or channels + self.use_conv = use_conv + self.dims = dims + if use_conv: + self.conv = conv_nd( + dims, self.channels, self.out_channels, 3, padding=padding + ) + + def forward(self, x): + assert x.shape[1] == self.channels + if self.dims == 3: + x = F.interpolate( + x, (x.shape[2], x.shape[3] * 2, x.shape[4] * 2), mode="nearest" + ) + else: + x = F.interpolate(x, scale_factor=2, mode="nearest") + if self.use_conv: + x = self.conv(x) + return x + + +class TransposedUpsample(nn.Module): + "Learned 2x upsampling without padding" + + def __init__(self, channels, out_channels=None, ks=5): + super().__init__() + self.channels = channels + self.out_channels = out_channels or channels + + self.up = nn.ConvTranspose2d( + self.channels, self.out_channels, kernel_size=ks, stride=2 + ) + + def forward(self, x): + return self.up(x) + + +class Downsample(nn.Module): + """ + A downsampling layer with an optional convolution. + :param channels: channels in the inputs and outputs. + :param use_conv: a bool determining if a convolution is applied. + :param dims: determines if the signal is 1D, 2D, or 3D. If 3D, then + downsampling occurs in the inner-two dimensions. + """ + + def __init__(self, channels, use_conv, dims=2, out_channels=None, padding=1): + super().__init__() + self.channels = channels + self.out_channels = out_channels or channels + self.use_conv = use_conv + self.dims = dims + stride = 2 if dims != 3 else (1, 2, 2) + if use_conv: + self.op = conv_nd( + dims, + self.channels, + self.out_channels, + 3, + stride=stride, + padding=padding, + ) + else: + assert self.channels == self.out_channels + self.op = avg_pool_nd(dims, kernel_size=stride, stride=stride) + + def forward(self, x): + assert x.shape[1] == self.channels + return self.op(x) + + +class ResBlock(TimestepBlock): + """ + A residual block that can optionally change the number of channels. + :param channels: the number of input channels. + :param emb_channels: the number of timestep embedding channels. + :param dropout: the rate of dropout. + :param out_channels: if specified, the number of out channels. + :param use_conv: if True and out_channels is specified, use a spatial + convolution instead of a smaller 1x1 convolution to change the + channels in the skip connection. + :param dims: determines if the signal is 1D, 2D, or 3D. + :param use_checkpoint: if True, use gradient checkpointing on this module. + :param up: if True, use this block for upsampling. + :param down: if True, use this block for downsampling. + """ + + def __init__( + self, + channels, + emb_channels, + dropout, + out_channels=None, + use_conv=False, + use_scale_shift_norm=False, + dims=2, + use_checkpoint=False, + up=False, + down=False, + ): + super().__init__() + self.channels = channels + self.emb_channels = emb_channels + self.dropout = dropout + self.out_channels = out_channels or channels + self.use_conv = use_conv + self.use_checkpoint = use_checkpoint + self.use_scale_shift_norm = use_scale_shift_norm + + self.in_layers = nn.Sequential( + normalization(channels), + nn.SiLU(), + conv_nd(dims, channels, self.out_channels, 3, padding=1), + ) + + self.updown = up or down + + if up: + self.h_upd = Upsample(channels, False, dims) + self.x_upd = Upsample(channels, False, dims) + elif down: + self.h_upd = Downsample(channels, False, dims) + self.x_upd = Downsample(channels, False, dims) + else: + self.h_upd = self.x_upd = nn.Identity() + + self.emb_layers = nn.Sequential( + nn.SiLU(), + linear( + emb_channels, + 2 * self.out_channels if use_scale_shift_norm else self.out_channels, + ), + ) + self.out_layers = nn.Sequential( + normalization(self.out_channels), + nn.SiLU(), + nn.Dropout(p=dropout), + zero_module( + conv_nd(dims, self.out_channels, self.out_channels, 3, padding=1) + ), + ) + + if self.out_channels == channels: + self.skip_connection = nn.Identity() + elif use_conv: + self.skip_connection = conv_nd( + dims, channels, self.out_channels, 3, padding=1 + ) + else: + self.skip_connection = conv_nd(dims, channels, self.out_channels, 1) + + def forward(self, x, emb): + """ + Apply the block to a Tensor, conditioned on a timestep embedding. + :param x: an [N x C x ...] Tensor of features. + :param emb: an [N x emb_channels] Tensor of timestep embeddings. + :return: an [N x C x ...] Tensor of outputs. + """ + return checkpoint( + self._forward, (x, emb), self.parameters(), self.use_checkpoint + ) + + def _forward(self, x, emb): + if self.updown: + in_rest, in_conv = self.in_layers[:-1], self.in_layers[-1] + h = in_rest(x) + h = self.h_upd(h) + x = self.x_upd(x) + h = in_conv(h) + else: + h = self.in_layers(x) + emb_out = self.emb_layers(emb).type(h.dtype) + while len(emb_out.shape) < len(h.shape): + emb_out = emb_out[..., None] + if self.use_scale_shift_norm: + out_norm, out_rest = self.out_layers[0], self.out_layers[1:] + scale, shift = th.chunk(emb_out, 2, dim=1) + h = out_norm(h) * (1 + scale) + shift + h = out_rest(h) + else: + h = h + emb_out + h = self.out_layers(h) + return self.skip_connection(x) + h + + +class AttentionBlock(nn.Module): + """ + An attention block that allows spatial positions to attend to each other. + Originally ported from here, but adapted to the N-d case. + https://github.com/hojonathanho/diffusion/blob/1e0dceb3b3495bbe19116a5e1b3596cd0706c543/diffusion_tf/models/unet.py#L66. + """ + + def __init__( + self, + channels, + num_heads=1, + num_head_channels=-1, + use_checkpoint=False, + use_new_attention_order=False, + ): + super().__init__() + self.channels = channels + if num_head_channels == -1: + self.num_heads = num_heads + else: + assert ( + channels % num_head_channels == 0 + ), f"q,k,v channels {channels} is not divisible by num_head_channels {num_head_channels}" + self.num_heads = channels // num_head_channels + self.use_checkpoint = use_checkpoint + self.norm = normalization(channels) + self.qkv = conv_nd(1, channels, channels * 3, 1) + if use_new_attention_order: + # split qkv before split heads + self.attention = QKVAttention(self.num_heads) + else: + # split heads before split qkv + self.attention = QKVAttentionLegacy(self.num_heads) + + self.proj_out = zero_module(conv_nd(1, channels, channels, 1)) + + def forward(self, x): + return checkpoint( + self._forward, (x,), self.parameters(), True + ) # TODO: check checkpoint usage, is True # TODO: fix the .half call!!! + # return pt_checkpoint(self._forward, x) # pytorch + + def _forward(self, x): + b, c, *spatial = x.shape + x = x.reshape(b, c, -1) + qkv = self.qkv(self.norm(x)) + h = self.attention(qkv) + h = self.proj_out(h) + return (x + h).reshape(b, c, *spatial) + + +def count_flops_attn(model, _x, y): + """ + A counter for the `thop` package to count the operations in an + attention operation. + Meant to be used like: + macs, params = thop.profile( + model, + inputs=(inputs, timestamps), + custom_ops={QKVAttention: QKVAttention.count_flops}, + ) + """ + b, c, *spatial = y[0].shape + num_spatial = int(np.prod(spatial)) + # We perform two matmuls with the same number of ops. + # The first computes the weight matrix, the second computes + # the combination of the value vectors. + matmul_ops = 2 * b * (num_spatial**2) * c + model.total_ops += th.DoubleTensor([matmul_ops]) + + +class QKVAttentionLegacy(nn.Module): + """ + A module which performs QKV attention. Matches legacy QKVAttention + input/ouput heads shaping + """ + + def __init__(self, n_heads): + super().__init__() + self.n_heads = n_heads + + def forward(self, qkv): + """ + Apply QKV attention. + :param qkv: an [N x (H * 3 * C) x T] tensor of Qs, Ks, and Vs. + :return: an [N x (H * C) x T] tensor after attention. + """ + bs, width, length = qkv.shape + assert width % (3 * self.n_heads) == 0 + ch = width // (3 * self.n_heads) + q, k, v = qkv.reshape(bs * self.n_heads, ch * 3, length).split(ch, dim=1) + scale = 1 / math.sqrt(math.sqrt(ch)) + weight = th.einsum( + "bct,bcs->bts", q * scale, k * scale + ) # More stable with f16 than dividing afterwards + weight = th.softmax(weight.float(), dim=-1).type(weight.dtype) + a = th.einsum("bts,bcs->bct", weight, v) + return a.reshape(bs, -1, length) + + @staticmethod + def count_flops(model, _x, y): + return count_flops_attn(model, _x, y) + + +class QKVAttention(nn.Module): + """ + A module which performs QKV attention and splits in a different order. + """ + + def __init__(self, n_heads): + super().__init__() + self.n_heads = n_heads + + def forward(self, qkv): + """ + Apply QKV attention. + :param qkv: an [N x (3 * H * C) x T] tensor of Qs, Ks, and Vs. + :return: an [N x (H * C) x T] tensor after attention. + """ + bs, width, length = qkv.shape + assert width % (3 * self.n_heads) == 0 + ch = width // (3 * self.n_heads) + q, k, v = qkv.chunk(3, dim=1) + scale = 1 / math.sqrt(math.sqrt(ch)) + weight = th.einsum( + "bct,bcs->bts", + (q * scale).view(bs * self.n_heads, ch, length), + (k * scale).view(bs * self.n_heads, ch, length), + ) # More stable with f16 than dividing afterwards + weight = th.softmax(weight.float(), dim=-1).type(weight.dtype) + a = th.einsum("bts,bcs->bct", weight, v.reshape(bs * self.n_heads, ch, length)) + return a.reshape(bs, -1, length) + + @staticmethod + def count_flops(model, _x, y): + return count_flops_attn(model, _x, y) + + +class Timestep(nn.Module): + def __init__(self, dim): + super().__init__() + self.dim = dim + + def forward(self, t): + return timestep_embedding(t, self.dim) + + +class MultiViewUNetModel(nn.Module): + """ + The full multi-view UNet model with attention, timestep embedding and camera embedding. + :param in_channels: channels in the input Tensor. + :param model_channels: base channel count for the model. + :param out_channels: channels in the output Tensor. + :param num_res_blocks: number of residual blocks per downsample. + :param attention_resolutions: a collection of downsample rates at which + attention will take place. May be a set, list, or tuple. + For example, if this contains 4, then at 4x downsampling, attention + will be used. + :param dropout: the dropout probability. + :param channel_mult: channel multiplier for each level of the UNet. + :param conv_resample: if True, use learned convolutions for upsampling and + downsampling. + :param dims: determines if the signal is 1D, 2D, or 3D. + :param num_classes: if specified (as an int), then this model will be + class-conditional with `num_classes` classes. + :param use_checkpoint: use gradient checkpointing to reduce memory usage. + :param num_heads: the number of attention heads in each attention layer. + :param num_heads_channels: if specified, ignore num_heads and instead use + a fixed channel width per attention head. + :param num_heads_upsample: works with num_heads to set a different number + of heads for upsampling. Deprecated. + :param use_scale_shift_norm: use a FiLM-like conditioning mechanism. + :param resblock_updown: use residual blocks for up/downsampling. + :param use_new_attention_order: use a different attention pattern for potentially + increased efficiency. + :param camera_dim: dimensionality of camera input. + """ + + def __init__( + self, + image_size, + in_channels, + model_channels, + out_channels, + num_res_blocks, + attention_resolutions, + dropout=0, + channel_mult=(1, 2, 4, 8), + conv_resample=True, + dims=2, + num_classes=None, + use_checkpoint=False, + use_fp16=False, + use_bf16=False, + num_heads=-1, + num_head_channels=-1, + num_heads_upsample=-1, + use_scale_shift_norm=False, + resblock_updown=False, + use_new_attention_order=False, + use_spatial_transformer=False, # custom transformer support + transformer_depth=1, # custom transformer support + context_dim=None, # custom transformer support + n_embed=None, # custom support for prediction of discrete ids into codebook of first stage vq model + legacy=True, + disable_self_attentions=None, + num_attention_blocks=None, + disable_middle_self_attn=False, + use_linear_in_transformer=False, + adm_in_channels=None, + camera_dim=None, + with_ip=False, # wether add image prompt images + ip_dim=0, # number of extra token, 4 for global 16 for local + ip_weight=1.0, # weight for image prompt context + ip_mode="local_resample", # which mode of adaptor, global or local + ): + super().__init__() + if use_spatial_transformer: + assert ( + context_dim is not None + ), "Fool!! You forgot to include the dimension of your cross-attention conditioning..." + + if context_dim is not None: + assert ( + use_spatial_transformer + ), "Fool!! You forgot to use the spatial transformer for your cross-attention conditioning..." + from omegaconf.listconfig import ListConfig + + if type(context_dim) == ListConfig: + context_dim = list(context_dim) + + if num_heads_upsample == -1: + num_heads_upsample = num_heads + + if num_heads == -1: + assert ( + num_head_channels != -1 + ), "Either num_heads or num_head_channels has to be set" + + if num_head_channels == -1: + assert ( + num_heads != -1 + ), "Either num_heads or num_head_channels has to be set" + + self.image_size = image_size + self.in_channels = in_channels + self.model_channels = model_channels + self.out_channels = out_channels + if isinstance(num_res_blocks, int): + self.num_res_blocks = len(channel_mult) * [num_res_blocks] + else: + if len(num_res_blocks) != len(channel_mult): + raise ValueError( + "provide num_res_blocks either as an int (globally constant) or " + "as a list/tuple (per-level) with the same length as channel_mult" + ) + self.num_res_blocks = num_res_blocks + if disable_self_attentions is not None: + # should be a list of booleans, indicating whether to disable self-attention in TransformerBlocks or not + assert len(disable_self_attentions) == len(channel_mult) + if num_attention_blocks is not None: + assert len(num_attention_blocks) == len(self.num_res_blocks) + assert all( + map( + lambda i: self.num_res_blocks[i] >= num_attention_blocks[i], + range(len(num_attention_blocks)), + ) + ) + print( + f"Constructor of UNetModel received num_attention_blocks={num_attention_blocks}. " + f"This option has LESS priority than attention_resolutions {attention_resolutions}, " + f"i.e., in cases where num_attention_blocks[i] > 0 but 2**i not in attention_resolutions, " + f"attention will still not be set." + ) + + self.attention_resolutions = attention_resolutions + self.dropout = dropout + self.channel_mult = channel_mult + self.conv_resample = conv_resample + self.num_classes = num_classes + self.use_checkpoint = use_checkpoint + self.dtype = th.float16 if use_fp16 else th.float32 + self.dtype = th.bfloat16 if use_bf16 else self.dtype + self.num_heads = num_heads + self.num_head_channels = num_head_channels + self.num_heads_upsample = num_heads_upsample + self.predict_codebook_ids = n_embed is not None + + self.with_ip = with_ip # wether there is image prompt + self.ip_dim = ip_dim # num of extra token, 4 for global 16 for local + self.ip_weight = ip_weight + assert ip_mode in ["global", "local_resample"] + self.ip_mode = ip_mode # which mode of adaptor + + time_embed_dim = model_channels * 4 + self.time_embed = nn.Sequential( + linear(model_channels, time_embed_dim), + nn.SiLU(), + linear(time_embed_dim, time_embed_dim), + ) + + if camera_dim is not None: + time_embed_dim = model_channels * 4 + self.camera_embed = nn.Sequential( + linear(camera_dim, time_embed_dim), + nn.SiLU(), + linear(time_embed_dim, time_embed_dim), + ) + + if self.num_classes is not None: + if isinstance(self.num_classes, int): + self.label_emb = nn.Embedding(num_classes, time_embed_dim) + elif self.num_classes == "continuous": + print("setting up linear c_adm embedding layer") + self.label_emb = nn.Linear(1, time_embed_dim) + elif self.num_classes == "sequential": + assert adm_in_channels is not None + self.label_emb = nn.Sequential( + nn.Sequential( + linear(adm_in_channels, time_embed_dim), + nn.SiLU(), + linear(time_embed_dim, time_embed_dim), + ) + ) + else: + raise ValueError() + + if self.with_ip and (context_dim is not None) and ip_dim > 0: + if self.ip_mode == "local_resample": + # ip-adapter-plus + hidden_dim = 1280 + self.image_embed = Resampler( + dim=context_dim, + depth=4, + dim_head=64, + heads=12, + num_queries=ip_dim, # num token + embedding_dim=hidden_dim, + output_dim=context_dim, + ff_mult=4, + ) + elif self.ip_mode == "global": + self.image_embed = ImageProjModel( + cross_attention_dim=context_dim, + clip_extra_context_tokens=ip_dim) + else: + raise ValueError(f"{self.ip_mode} is not supported") + + self.input_blocks = nn.ModuleList( + [ + TimestepEmbedSequential( + conv_nd(dims, in_channels, model_channels, 3, padding=1) + ) + ] + ) + self._feature_size = model_channels + input_block_chans = [model_channels] + ch = model_channels + ds = 1 + for level, mult in enumerate(channel_mult): + for nr in range(self.num_res_blocks[level]): + layers = [ + ResBlock( + ch, + time_embed_dim, + dropout, + out_channels=mult * model_channels, + dims=dims, + use_checkpoint=use_checkpoint, + use_scale_shift_norm=use_scale_shift_norm, + ) + ] + ch = mult * model_channels + if ds in attention_resolutions: + if num_head_channels == -1: + dim_head = ch // num_heads + else: + num_heads = ch // num_head_channels + dim_head = num_head_channels + if legacy: + # num_heads = 1 + dim_head = ( + ch // num_heads + if use_spatial_transformer + else num_head_channels + ) + if exists(disable_self_attentions): + disabled_sa = disable_self_attentions[level] + else: + disabled_sa = False + + if ( + not exists(num_attention_blocks) + or nr < num_attention_blocks[level] + ): + layers.append( + AttentionBlock( + ch, + use_checkpoint=use_checkpoint, + num_heads=num_heads, + num_head_channels=dim_head, + use_new_attention_order=use_new_attention_order, + ) + if not use_spatial_transformer + else SpatialTransformer3D( + ch, + num_heads, + dim_head, + depth=transformer_depth, + context_dim=context_dim, + disable_self_attn=disabled_sa, + use_linear=use_linear_in_transformer, + use_checkpoint=use_checkpoint, + with_ip=self.with_ip, + ip_dim=self.ip_dim, + ip_weight=self.ip_weight + ) + ) + self.input_blocks.append(TimestepEmbedSequential(*layers)) + self._feature_size += ch + input_block_chans.append(ch) + + if level != len(channel_mult) - 1: + out_ch = ch + self.input_blocks.append( + TimestepEmbedSequential( + ResBlock( + ch, + time_embed_dim, + dropout, + out_channels=out_ch, + dims=dims, + use_checkpoint=use_checkpoint, + use_scale_shift_norm=use_scale_shift_norm, + down=True, + ) + if resblock_updown + else Downsample( + ch, conv_resample, dims=dims, out_channels=out_ch + ) + ) + ) + ch = out_ch + input_block_chans.append(ch) + ds *= 2 + self._feature_size += ch + + if num_head_channels == -1: + dim_head = ch // num_heads + else: + num_heads = ch // num_head_channels + dim_head = num_head_channels + if legacy: + # num_heads = 1 + dim_head = ch // num_heads if use_spatial_transformer else num_head_channels + self.middle_block = TimestepEmbedSequential( + ResBlock( + ch, + time_embed_dim, + dropout, + dims=dims, + use_checkpoint=use_checkpoint, + use_scale_shift_norm=use_scale_shift_norm, + ), + AttentionBlock( + ch, + use_checkpoint=use_checkpoint, + num_heads=num_heads, + num_head_channels=dim_head, + use_new_attention_order=use_new_attention_order, + ) + if not use_spatial_transformer + else SpatialTransformer3D( # always uses a self-attn + ch, + num_heads, + dim_head, + depth=transformer_depth, + context_dim=context_dim, + disable_self_attn=disable_middle_self_attn, + use_linear=use_linear_in_transformer, + use_checkpoint=use_checkpoint, + with_ip=self.with_ip, + ip_dim=self.ip_dim, + ip_weight=self.ip_weight + ), + ResBlock( + ch, + time_embed_dim, + dropout, + dims=dims, + use_checkpoint=use_checkpoint, + use_scale_shift_norm=use_scale_shift_norm, + ), + ) + self._feature_size += ch + + self.output_blocks = nn.ModuleList([]) + for level, mult in list(enumerate(channel_mult))[::-1]: + for i in range(self.num_res_blocks[level] + 1): + ich = input_block_chans.pop() + layers = [ + ResBlock( + ch + ich, + time_embed_dim, + dropout, + out_channels=model_channels * mult, + dims=dims, + use_checkpoint=use_checkpoint, + use_scale_shift_norm=use_scale_shift_norm, + ) + ] + ch = model_channels * mult + if ds in attention_resolutions: + if num_head_channels == -1: + dim_head = ch // num_heads + else: + num_heads = ch // num_head_channels + dim_head = num_head_channels + if legacy: + # num_heads = 1 + dim_head = ( + ch // num_heads + if use_spatial_transformer + else num_head_channels + ) + if exists(disable_self_attentions): + disabled_sa = disable_self_attentions[level] + else: + disabled_sa = False + + if ( + not exists(num_attention_blocks) + or i < num_attention_blocks[level] + ): + layers.append( + AttentionBlock( + ch, + use_checkpoint=use_checkpoint, + num_heads=num_heads_upsample, + num_head_channels=dim_head, + use_new_attention_order=use_new_attention_order, + ) + if not use_spatial_transformer + else SpatialTransformer3D( + ch, + num_heads, + dim_head, + depth=transformer_depth, + context_dim=context_dim, + disable_self_attn=disabled_sa, + use_linear=use_linear_in_transformer, + use_checkpoint=use_checkpoint, + with_ip=self.with_ip, + ip_dim=self.ip_dim, + ip_weight=self.ip_weight + ) + ) + if level and i == self.num_res_blocks[level]: + out_ch = ch + layers.append( + ResBlock( + ch, + time_embed_dim, + dropout, + out_channels=out_ch, + dims=dims, + use_checkpoint=use_checkpoint, + use_scale_shift_norm=use_scale_shift_norm, + up=True, + ) + if resblock_updown + else Upsample(ch, conv_resample, dims=dims, out_channels=out_ch) + ) + ds //= 2 + self.output_blocks.append(TimestepEmbedSequential(*layers)) + self._feature_size += ch + + self.out = nn.Sequential( + normalization(ch), + nn.SiLU(), + zero_module(conv_nd(dims, model_channels, out_channels, 3, padding=1)), + ) + if self.predict_codebook_ids: + self.id_predictor = nn.Sequential( + normalization(ch), + conv_nd(dims, model_channels, n_embed, 1), + # nn.LogSoftmax(dim=1) # change to cross_entropy and produce non-normalized logits + ) + + def convert_to_fp16(self): + """ + Convert the torso of the model to float16. + """ + self.input_blocks.apply(convert_module_to_f16) + self.middle_block.apply(convert_module_to_f16) + self.output_blocks.apply(convert_module_to_f16) + + def convert_to_fp32(self): + """ + Convert the torso of the model to float32. + """ + self.input_blocks.apply(convert_module_to_f32) + self.middle_block.apply(convert_module_to_f32) + self.output_blocks.apply(convert_module_to_f32) + + def forward( + self, + x, + timesteps=None, + context=None, + y=None, + camera=None, + num_frames=1, + **kwargs, + ): + """ + Apply the model to an input batch. + :param x: an [(N x F) x C x ...] Tensor of inputs. F is the number of frames (views). + :param timesteps: a 1-D batch of timesteps. + :param context: a dict conditioning plugged in via crossattn + :param y: an [N] Tensor of labels, if class-conditional, default None. + :param num_frames: a integer indicating number of frames for tensor reshaping. + :return: an [(N x F) x C x ...] Tensor of outputs. F is the number of frames (views). + """ + assert ( + x.shape[0] % num_frames == 0 + ), "[UNet] input batch size must be dividable by num_frames!" + assert (y is not None) == ( + self.num_classes is not None + ), "must specify y if and only if the model is class-conditional" + + hs = [] + t_emb = timestep_embedding(timesteps, self.model_channels, repeat_only=False) # shape: torch.Size([B, 320]) mean: 0.18, std: 0.68, min: -1.00, max: 1.00 + emb = self.time_embed(t_emb) # shape: torch.Size([B, 1280]) mean: 0.12, std: 0.57, min: -5.73, max: 6.51 + + if self.num_classes is not None: + assert y.shape[0] == x.shape[0] + emb = emb + self.label_emb(y) + + # Add camera embeddings + if camera is not None: + assert camera.shape[0] == emb.shape[0] + # camera embed: shape: torch.Size([B, 1280]) mean: -0.02, std: 0.27, min: -7.23, max: 2.04 + emb = emb + self.camera_embed(camera) + ip = kwargs.get("ip", None) + ip_img = kwargs.get("ip_img", None) + + if ip_img is not None: + x[(num_frames-1)::num_frames, :, :, :] = ip_img + + if ip is not None: + ip_emb = self.image_embed(ip) # shape: torch.Size([B, 16, 1024]) mean: -0.00, std: 1.00, min: -11.65, max: 7.31 + context = torch.cat((context, ip_emb), 1) # shape: torch.Size([B, 93, 1024]) mean: -0.00, std: 1.00, min: -11.65, max: 7.31 + + h = x.type(self.dtype) + for module in self.input_blocks: + h = module(h, emb, context, num_frames=num_frames) + hs.append(h) + h = self.middle_block(h, emb, context, num_frames=num_frames) + for module in self.output_blocks: + h = th.cat([h, hs.pop()], dim=1) + h = module(h, emb, context, num_frames=num_frames) + h = h.type(x.dtype) # shape: torch.Size([10, 320, 32, 32]) mean: -0.67, std: 3.96, min: -42.74, max: 25.58 + if self.predict_codebook_ids: # False + return self.id_predictor(h) + else: + return self.out(h) # shape: torch.Size([10, 4, 32, 32]) mean: -0.00, std: 0.91, min: -3.65, max: 3.93 + + + + +class MultiViewUNetModelStage2(MultiViewUNetModel): + """ + The full multi-view UNet model with attention, timestep embedding and camera embedding. + :param in_channels: channels in the input Tensor. + :param model_channels: base channel count for the model. + :param out_channels: channels in the output Tensor. + :param num_res_blocks: number of residual blocks per downsample. + :param attention_resolutions: a collection of downsample rates at which + attention will take place. May be a set, list, or tuple. + For example, if this contains 4, then at 4x downsampling, attention + will be used. + :param dropout: the dropout probability. + :param channel_mult: channel multiplier for each level of the UNet. + :param conv_resample: if True, use learned convolutions for upsampling and + downsampling. + :param dims: determines if the signal is 1D, 2D, or 3D. + :param num_classes: if specified (as an int), then this model will be + class-conditional with `num_classes` classes. + :param use_checkpoint: use gradient checkpointing to reduce memory usage. + :param num_heads: the number of attention heads in each attention layer. + :param num_heads_channels: if specified, ignore num_heads and instead use + a fixed channel width per attention head. + :param num_heads_upsample: works with num_heads to set a different number + of heads for upsampling. Deprecated. + :param use_scale_shift_norm: use a FiLM-like conditioning mechanism. + :param resblock_updown: use residual blocks for up/downsampling. + :param use_new_attention_order: use a different attention pattern for potentially + increased efficiency. + :param camera_dim: dimensionality of camera input. + """ + + def __init__( + self, + image_size, + in_channels, + model_channels, + out_channels, + num_res_blocks, + attention_resolutions, + dropout=0, + channel_mult=(1, 2, 4, 8), + conv_resample=True, + dims=2, + num_classes=None, + use_checkpoint=False, + use_fp16=False, + use_bf16=False, + num_heads=-1, + num_head_channels=-1, + num_heads_upsample=-1, + use_scale_shift_norm=False, + resblock_updown=False, + use_new_attention_order=False, + use_spatial_transformer=False, # custom transformer support + transformer_depth=1, # custom transformer support + context_dim=None, # custom transformer support + n_embed=None, # custom support for prediction of discrete ids into codebook of first stage vq model + legacy=True, + disable_self_attentions=None, + num_attention_blocks=None, + disable_middle_self_attn=False, + use_linear_in_transformer=False, + adm_in_channels=None, + camera_dim=None, + with_ip=False, # wether add image prompt images + ip_dim=0, # number of extra token, 4 for global 16 for local + ip_weight=1.0, # weight for image prompt context + ip_mode="local_resample", # which mode of adaptor, global or local + ): + super().__init__( + image_size, + in_channels, + model_channels, + out_channels, + num_res_blocks, + attention_resolutions, + dropout, + channel_mult, + conv_resample, + dims, + num_classes, + use_checkpoint, + use_fp16, + use_bf16, + num_heads, + num_head_channels, + num_heads_upsample, + use_scale_shift_norm, + resblock_updown, + use_new_attention_order, + use_spatial_transformer, + transformer_depth, + context_dim, + n_embed, + legacy, + disable_self_attentions, + num_attention_blocks, + disable_middle_self_attn, + use_linear_in_transformer, + adm_in_channels, + camera_dim, + with_ip, + ip_dim, + ip_weight, + ip_mode, + ) + + def forward( + self, + x, + timesteps=None, + context=None, + y=None, + camera=None, + num_frames=1, + **kwargs, + ): + """ + Apply the model to an input batch. + :param x: an [(N x F) x C x ...] Tensor of inputs. F is the number of frames (views). + :param timesteps: a 1-D batch of timesteps. + :param context: a dict conditioning plugged in via crossattn + :param y: an [N] Tensor of labels, if class-conditional, default None. + :param num_frames: a integer indicating number of frames for tensor reshaping. + :return: an [(N x F) x C x ...] Tensor of outputs. F is the number of frames (views). + """ + assert ( + x.shape[0] % num_frames == 0 + ), "[UNet] input batch size must be dividable by num_frames!" + assert (y is not None) == ( + self.num_classes is not None + ), "must specify y if and only if the model is class-conditional" + + hs = [] + t_emb = timestep_embedding(timesteps, self.model_channels, repeat_only=False) # shape: torch.Size([B, 320]) mean: 0.18, std: 0.68, min: -1.00, max: 1.00 + emb = self.time_embed(t_emb) # shape: torch.Size([B, 1280]) mean: 0.12, std: 0.57, min: -5.73, max: 6.51 + + if self.num_classes is not None: + assert y.shape[0] == x.shape[0] + emb = emb + self.label_emb(y) + + # Add camera embeddings + if camera is not None: + assert camera.shape[0] == emb.shape[0] + # camera embed: shape: torch.Size([B, 1280]) mean: -0.02, std: 0.27, min: -7.23, max: 2.04 + emb = emb + self.camera_embed(camera) + ip = kwargs.get("ip", None) + ip_img = kwargs.get("ip_img", None) + pixel_images = kwargs.get("pixel_images", None) + + if ip_img is not None: + x[(num_frames-1)::num_frames, :, :, :] = ip_img + + x = torch.cat((x, pixel_images), dim=1) + + if ip is not None: + ip_emb = self.image_embed(ip) # shape: torch.Size([B, 16, 1024]) mean: -0.00, std: 1.00, min: -11.65, max: 7.31 + context = torch.cat((context, ip_emb), 1) # shape: torch.Size([B, 93, 1024]) mean: -0.00, std: 1.00, min: -11.65, max: 7.31 + + h = x.type(self.dtype) + for module in self.input_blocks: + h = module(h, emb, context, num_frames=num_frames) + hs.append(h) + h = self.middle_block(h, emb, context, num_frames=num_frames) + for module in self.output_blocks: + h = th.cat([h, hs.pop()], dim=1) + h = module(h, emb, context, num_frames=num_frames) + h = h.type(x.dtype) # shape: torch.Size([10, 320, 32, 32]) mean: -0.67, std: 3.96, min: -42.74, max: 25.58 + if self.predict_codebook_ids: # False + return self.id_predictor(h) + else: + return self.out(h) # shape: torch.Size([10, 4, 32, 32]) mean: -0.00, std: 0.91, min: -3.65, max: 3.93 + \ No newline at end of file diff --git a/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/util.py b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/util.py new file mode 100644 index 0000000000000000000000000000000000000000..af744261d41deab5d686aead790726efcdfaf961 --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/modules/diffusionmodules/util.py @@ -0,0 +1,353 @@ +# adopted from +# https://github.com/openai/improved-diffusion/blob/main/improved_diffusion/gaussian_diffusion.py +# and +# https://github.com/lucidrains/denoising-diffusion-pytorch/blob/7706bdfc6f527f58d33f84b7b522e61e6e3164b3/denoising_diffusion_pytorch/denoising_diffusion_pytorch.py +# and +# https://github.com/openai/guided-diffusion/blob/0ba878e517b276c45d1195eb29f6f5f72659a05b/guided_diffusion/nn.py +# +# thanks! + + +import os +import math +import torch +import torch.nn as nn +import numpy as np +from einops import repeat +import importlib + + +def instantiate_from_config(config): + if not "target" in config: + if config == "__is_first_stage__": + return None + elif config == "__is_unconditional__": + return None + raise KeyError("Expected key `target` to instantiate.") + return get_obj_from_str(config["target"])(**config.get("params", dict())) + + +def get_obj_from_str(string, reload=False): + module, cls = string.rsplit(".", 1) + if reload: + module_imp = importlib.import_module(module) + importlib.reload(module_imp) + return getattr(importlib.import_module(module, package=None), cls) + + +def make_beta_schedule( + schedule, n_timestep, linear_start=1e-4, linear_end=2e-2, cosine_s=8e-3 +): + if schedule == "linear": + betas = ( + torch.linspace( + linear_start**0.5, linear_end**0.5, n_timestep, dtype=torch.float64 + ) + ** 2 + ) + + elif schedule == "cosine": + timesteps = ( + torch.arange(n_timestep + 1, dtype=torch.float64) / n_timestep + cosine_s + ) + alphas = timesteps / (1 + cosine_s) * np.pi / 2 + alphas = torch.cos(alphas).pow(2) + alphas = alphas / alphas[0] + betas = 1 - alphas[1:] / alphas[:-1] + betas = np.clip(betas, a_min=0, a_max=0.999) + + elif schedule == "sqrt_linear": + betas = torch.linspace( + linear_start, linear_end, n_timestep, dtype=torch.float64 + ) + elif schedule == "sqrt": + betas = ( + torch.linspace(linear_start, linear_end, n_timestep, dtype=torch.float64) + ** 0.5 + ) + else: + raise ValueError(f"schedule '{schedule}' unknown.") + return betas.numpy() + +def enforce_zero_terminal_snr(betas): + betas = torch.tensor(betas) if not isinstance(betas, torch.Tensor) else betas + # Convert betas to alphas_bar_sqrt + alphas =1 - betas + alphas_bar = alphas.cumprod(0) + alphas_bar_sqrt = alphas_bar.sqrt() + # Store old values. + alphas_bar_sqrt_0 = alphas_bar_sqrt[0].clone() + alphas_bar_sqrt_T = alphas_bar_sqrt[-1].clone() + # Shift so last timestep is zero. + alphas_bar_sqrt -= alphas_bar_sqrt_T + # Scale so first timestep is back to old value. + alphas_bar_sqrt *= alphas_bar_sqrt_0 / (alphas_bar_sqrt_0 - alphas_bar_sqrt_T) + # Convert alphas_bar_sqrt to betas + alphas_bar = alphas_bar_sqrt ** 2 + alphas = alphas_bar[1:] / alphas_bar[:-1] + alphas = torch.cat ([alphas_bar[0:1], alphas]) + betas = 1 - alphas + return betas + + +def make_ddim_timesteps( + ddim_discr_method, num_ddim_timesteps, num_ddpm_timesteps, verbose=True +): + if ddim_discr_method == "uniform": + c = num_ddpm_timesteps // num_ddim_timesteps + ddim_timesteps = np.asarray(list(range(0, num_ddpm_timesteps, c))) + elif ddim_discr_method == "quad": + ddim_timesteps = ( + (np.linspace(0, np.sqrt(num_ddpm_timesteps * 0.8), num_ddim_timesteps)) ** 2 + ).astype(int) + else: + raise NotImplementedError( + f'There is no ddim discretization method called "{ddim_discr_method}"' + ) + + # assert ddim_timesteps.shape[0] == num_ddim_timesteps + # add one to get the final alpha values right (the ones from first scale to data during sampling) + steps_out = ddim_timesteps + 1 + if verbose: + print(f"Selected timesteps for ddim sampler: {steps_out}") + return steps_out + + +def make_ddim_sampling_parameters(alphacums, ddim_timesteps, eta, verbose=True): + # select alphas for computing the variance schedule + alphas = alphacums[ddim_timesteps] + alphas_prev = np.asarray([alphacums[0]] + alphacums[ddim_timesteps[:-1]].tolist()) + + # according the the formula provided in https://arxiv.org/abs/2010.02502 + sigmas = eta * np.sqrt( + (1 - alphas_prev) / (1 - alphas) * (1 - alphas / alphas_prev) + ) + if verbose: + print( + f"Selected alphas for ddim sampler: a_t: {alphas}; a_(t-1): {alphas_prev}" + ) + print( + f"For the chosen value of eta, which is {eta}, " + f"this results in the following sigma_t schedule for ddim sampler {sigmas}" + ) + return sigmas, alphas, alphas_prev + + +def betas_for_alpha_bar(num_diffusion_timesteps, alpha_bar, max_beta=0.999): + """ + Create a beta schedule that discretizes the given alpha_t_bar function, + which defines the cumulative product of (1-beta) over time from t = [0,1]. + :param num_diffusion_timesteps: the number of betas to produce. + :param alpha_bar: a lambda that takes an argument t from 0 to 1 and + produces the cumulative product of (1-beta) up to that + part of the diffusion process. + :param max_beta: the maximum beta to use; use values lower than 1 to + prevent singularities. + """ + betas = [] + for i in range(num_diffusion_timesteps): + t1 = i / num_diffusion_timesteps + t2 = (i + 1) / num_diffusion_timesteps + betas.append(min(1 - alpha_bar(t2) / alpha_bar(t1), max_beta)) + return np.array(betas) + + +def extract_into_tensor(a, t, x_shape): + b, *_ = t.shape + out = a.gather(-1, t) + return out.reshape(b, *((1,) * (len(x_shape) - 1))) + + +def checkpoint(func, inputs, params, flag): + """ + Evaluate a function without caching intermediate activations, allowing for + reduced memory at the expense of extra compute in the backward pass. + :param func: the function to evaluate. + :param inputs: the argument sequence to pass to `func`. + :param params: a sequence of parameters `func` depends on but does not + explicitly take as arguments. + :param flag: if False, disable gradient checkpointing. + """ + if flag: + args = tuple(inputs) + tuple(params) + return CheckpointFunction.apply(func, len(inputs), *args) + else: + return func(*inputs) + + +class CheckpointFunction(torch.autograd.Function): + @staticmethod + def forward(ctx, run_function, length, *args): + ctx.run_function = run_function + ctx.input_tensors = list(args[:length]) + ctx.input_params = list(args[length:]) + + with torch.no_grad(): + output_tensors = ctx.run_function(*ctx.input_tensors) + return output_tensors + + @staticmethod + def backward(ctx, *output_grads): + ctx.input_tensors = [x.detach().requires_grad_(True) for x in ctx.input_tensors] + with torch.enable_grad(): + # Fixes a bug where the first op in run_function modifies the + # Tensor storage in place, which is not allowed for detach()'d + # Tensors. + shallow_copies = [x.view_as(x) for x in ctx.input_tensors] + output_tensors = ctx.run_function(*shallow_copies) + input_grads = torch.autograd.grad( + output_tensors, + ctx.input_tensors + ctx.input_params, + output_grads, + allow_unused=True, + ) + del ctx.input_tensors + del ctx.input_params + del output_tensors + return (None, None) + input_grads + + +def timestep_embedding(timesteps, dim, max_period=10000, repeat_only=False): + """ + Create sinusoidal timestep embeddings. + :param timesteps: a 1-D Tensor of N indices, one per batch element. + These may be fractional. + :param dim: the dimension of the output. + :param max_period: controls the minimum frequency of the embeddings. + :return: an [N x dim] Tensor of positional embeddings. + """ + if not repeat_only: + half = dim // 2 + freqs = torch.exp( + -math.log(max_period) + * torch.arange(start=0, end=half, dtype=torch.float32) + / half + ).to(device=timesteps.device) + args = timesteps[:, None].float() * freqs[None] + embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) + if dim % 2: + embedding = torch.cat( + [embedding, torch.zeros_like(embedding[:, :1])], dim=-1 + ) + else: + embedding = repeat(timesteps, "b -> b d", d=dim) + # import pdb; pdb.set_trace() + return embedding + + +def zero_module(module): + """ + Zero out the parameters of a module and return it. + """ + for p in module.parameters(): + p.detach().zero_() + return module + + +def scale_module(module, scale): + """ + Scale the parameters of a module and return it. + """ + for p in module.parameters(): + p.detach().mul_(scale) + return module + + +def mean_flat(tensor): + """ + Take the mean over all non-batch dimensions. + """ + return tensor.mean(dim=list(range(1, len(tensor.shape)))) + + +def normalization(channels): + """ + Make a standard normalization layer. + :param channels: number of input channels. + :return: an nn.Module for normalization. + """ + return GroupNorm32(32, channels) + + +# PyTorch 1.7 has SiLU, but we support PyTorch 1.5. +class SiLU(nn.Module): + def forward(self, x): + return x * torch.sigmoid(x) + + +class GroupNorm32(nn.GroupNorm): + def forward(self, x): + return super().forward(x.float()).type(x.dtype) + + +def conv_nd(dims, *args, **kwargs): + """ + Create a 1D, 2D, or 3D convolution module. + """ + if dims == 1: + return nn.Conv1d(*args, **kwargs) + elif dims == 2: + return nn.Conv2d(*args, **kwargs) + elif dims == 3: + return nn.Conv3d(*args, **kwargs) + raise ValueError(f"unsupported dimensions: {dims}") + + +def linear(*args, **kwargs): + """ + Create a linear module. + """ + return nn.Linear(*args, **kwargs) + + +def avg_pool_nd(dims, *args, **kwargs): + """ + Create a 1D, 2D, or 3D average pooling module. + """ + if dims == 1: + return nn.AvgPool1d(*args, **kwargs) + elif dims == 2: + return nn.AvgPool2d(*args, **kwargs) + elif dims == 3: + return nn.AvgPool3d(*args, **kwargs) + raise ValueError(f"unsupported dimensions: {dims}") + + +class HybridConditioner(nn.Module): + def __init__(self, c_concat_config, c_crossattn_config): + super().__init__() + self.concat_conditioner = instantiate_from_config(c_concat_config) + self.crossattn_conditioner = instantiate_from_config(c_crossattn_config) + + def forward(self, c_concat, c_crossattn): + c_concat = self.concat_conditioner(c_concat) + c_crossattn = self.crossattn_conditioner(c_crossattn) + return {"c_concat": [c_concat], "c_crossattn": [c_crossattn]} + + +def noise_like(shape, device, repeat=False): + repeat_noise = lambda: torch.randn((1, *shape[1:]), device=device).repeat( + shape[0], *((1,) * (len(shape) - 1)) + ) + noise = lambda: torch.randn(shape, device=device) + return repeat_noise() if repeat else noise() + + +# dummy replace +def convert_module_to_f16(l): + """ + Convert primitive modules to float16. + """ + if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Conv3d)): + l.weight.data = l.weight.data.half() + if l.bias is not None: + l.bias.data = l.bias.data.half() + +def convert_module_to_f32(l): + """ + Convert primitive modules to float32, undoing convert_module_to_f16(). + """ + if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Conv3d)): + l.weight.data = l.weight.data.float() + if l.bias is not None: + l.bias.data = l.bias.data.float() diff --git a/apps/third_party/CRM/imagedream/ldm/modules/distributions/__init__.py b/apps/third_party/CRM/imagedream/ldm/modules/distributions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/imagedream/ldm/modules/distributions/distributions.py b/apps/third_party/CRM/imagedream/ldm/modules/distributions/distributions.py new file mode 100644 index 0000000000000000000000000000000000000000..92f4428a3defd8fbae18fcd323c9d404036c652e --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/modules/distributions/distributions.py @@ -0,0 +1,102 @@ +import torch +import numpy as np + + +class AbstractDistribution: + def sample(self): + raise NotImplementedError() + + def mode(self): + raise NotImplementedError() + + +class DiracDistribution(AbstractDistribution): + def __init__(self, value): + self.value = value + + def sample(self): + return self.value + + def mode(self): + return self.value + + +class DiagonalGaussianDistribution(object): + def __init__(self, parameters, deterministic=False): + self.parameters = parameters + self.mean, self.logvar = torch.chunk(parameters, 2, dim=1) + self.logvar = torch.clamp(self.logvar, -30.0, 20.0) + self.deterministic = deterministic + self.std = torch.exp(0.5 * self.logvar) + self.var = torch.exp(self.logvar) + if self.deterministic: + self.var = self.std = torch.zeros_like(self.mean).to( + device=self.parameters.device + ) + + def sample(self): + x = self.mean + self.std * torch.randn(self.mean.shape).to( + device=self.parameters.device + ) + return x + + def kl(self, other=None): + if self.deterministic: + return torch.Tensor([0.0]) + else: + if other is None: + return 0.5 * torch.sum( + torch.pow(self.mean, 2) + self.var - 1.0 - self.logvar, + dim=[1, 2, 3], + ) + else: + return 0.5 * torch.sum( + torch.pow(self.mean - other.mean, 2) / other.var + + self.var / other.var + - 1.0 + - self.logvar + + other.logvar, + dim=[1, 2, 3], + ) + + def nll(self, sample, dims=[1, 2, 3]): + if self.deterministic: + return torch.Tensor([0.0]) + logtwopi = np.log(2.0 * np.pi) + return 0.5 * torch.sum( + logtwopi + self.logvar + torch.pow(sample - self.mean, 2) / self.var, + dim=dims, + ) + + def mode(self): + return self.mean + + +def normal_kl(mean1, logvar1, mean2, logvar2): + """ + source: https://github.com/openai/guided-diffusion/blob/27c20a8fab9cb472df5d6bdd6c8d11c8f430b924/guided_diffusion/losses.py#L12 + Compute the KL divergence between two gaussians. + Shapes are automatically broadcasted, so batches can be compared to + scalars, among other use cases. + """ + tensor = None + for obj in (mean1, logvar1, mean2, logvar2): + if isinstance(obj, torch.Tensor): + tensor = obj + break + assert tensor is not None, "at least one argument must be a Tensor" + + # Force variances to be Tensors. Broadcasting helps convert scalars to + # Tensors, but it does not work for torch.exp(). + logvar1, logvar2 = [ + x if isinstance(x, torch.Tensor) else torch.tensor(x).to(tensor) + for x in (logvar1, logvar2) + ] + + return 0.5 * ( + -1.0 + + logvar2 + - logvar1 + + torch.exp(logvar1 - logvar2) + + ((mean1 - mean2) ** 2) * torch.exp(-logvar2) + ) diff --git a/apps/third_party/CRM/imagedream/ldm/modules/ema.py b/apps/third_party/CRM/imagedream/ldm/modules/ema.py new file mode 100644 index 0000000000000000000000000000000000000000..a073e116975f3313fb630b7d4ac115171c1fe31d --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/modules/ema.py @@ -0,0 +1,86 @@ +import torch +from torch import nn + + +class LitEma(nn.Module): + def __init__(self, model, decay=0.9999, use_num_upates=True): + super().__init__() + if decay < 0.0 or decay > 1.0: + raise ValueError("Decay must be between 0 and 1") + + self.m_name2s_name = {} + self.register_buffer("decay", torch.tensor(decay, dtype=torch.float32)) + self.register_buffer( + "num_updates", + torch.tensor(0, dtype=torch.int) + if use_num_upates + else torch.tensor(-1, dtype=torch.int), + ) + + for name, p in model.named_parameters(): + if p.requires_grad: + # remove as '.'-character is not allowed in buffers + s_name = name.replace(".", "") + self.m_name2s_name.update({name: s_name}) + self.register_buffer(s_name, p.clone().detach().data) + + self.collected_params = [] + + def reset_num_updates(self): + del self.num_updates + self.register_buffer("num_updates", torch.tensor(0, dtype=torch.int)) + + def forward(self, model): + decay = self.decay + + if self.num_updates >= 0: + self.num_updates += 1 + decay = min(self.decay, (1 + self.num_updates) / (10 + self.num_updates)) + + one_minus_decay = 1.0 - decay + + with torch.no_grad(): + m_param = dict(model.named_parameters()) + shadow_params = dict(self.named_buffers()) + + for key in m_param: + if m_param[key].requires_grad: + sname = self.m_name2s_name[key] + shadow_params[sname] = shadow_params[sname].type_as(m_param[key]) + shadow_params[sname].sub_( + one_minus_decay * (shadow_params[sname] - m_param[key]) + ) + else: + assert not key in self.m_name2s_name + + def copy_to(self, model): + m_param = dict(model.named_parameters()) + shadow_params = dict(self.named_buffers()) + for key in m_param: + if m_param[key].requires_grad: + m_param[key].data.copy_(shadow_params[self.m_name2s_name[key]].data) + else: + assert not key in self.m_name2s_name + + def store(self, parameters): + """ + Save the current parameters for restoring later. + Args: + parameters: Iterable of `torch.nn.Parameter`; the parameters to be + temporarily stored. + """ + self.collected_params = [param.clone() for param in parameters] + + def restore(self, parameters): + """ + Restore the parameters stored with the `store` method. + Useful to validate the model with EMA parameters without affecting the + original optimization process. Store the parameters before the + `copy_to` method. After validation (or model saving), use this to + restore the former parameters. + Args: + parameters: Iterable of `torch.nn.Parameter`; the parameters to be + updated with the stored parameters. + """ + for c_param, param in zip(self.collected_params, parameters): + param.data.copy_(c_param.data) diff --git a/apps/third_party/CRM/imagedream/ldm/modules/encoders/__init__.py b/apps/third_party/CRM/imagedream/ldm/modules/encoders/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/imagedream/ldm/modules/encoders/modules.py b/apps/third_party/CRM/imagedream/ldm/modules/encoders/modules.py new file mode 100644 index 0000000000000000000000000000000000000000..a19d2c193d660535f101fa1cc3f1b857ce1197fc --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/modules/encoders/modules.py @@ -0,0 +1,329 @@ +import torch +import torch.nn as nn +from torch.utils.checkpoint import checkpoint + +from transformers import T5Tokenizer, T5EncoderModel, CLIPTokenizer, CLIPTextModel + +import numpy as np +import open_clip +from PIL import Image +from ...util import default, count_params + + +class AbstractEncoder(nn.Module): + def __init__(self): + super().__init__() + + def encode(self, *args, **kwargs): + raise NotImplementedError + + +class IdentityEncoder(AbstractEncoder): + def encode(self, x): + return x + + +class ClassEmbedder(nn.Module): + def __init__(self, embed_dim, n_classes=1000, key="class", ucg_rate=0.1): + super().__init__() + self.key = key + self.embedding = nn.Embedding(n_classes, embed_dim) + self.n_classes = n_classes + self.ucg_rate = ucg_rate + + def forward(self, batch, key=None, disable_dropout=False): + if key is None: + key = self.key + # this is for use in crossattn + c = batch[key][:, None] + if self.ucg_rate > 0.0 and not disable_dropout: + mask = 1.0 - torch.bernoulli(torch.ones_like(c) * self.ucg_rate) + c = mask * c + (1 - mask) * torch.ones_like(c) * (self.n_classes - 1) + c = c.long() + c = self.embedding(c) + return c + + def get_unconditional_conditioning(self, bs, device="cuda"): + uc_class = ( + self.n_classes - 1 + ) # 1000 classes --> 0 ... 999, one extra class for ucg (class 1000) + uc = torch.ones((bs,), device=device) * uc_class + uc = {self.key: uc} + return uc + + +def disabled_train(self, mode=True): + """Overwrite model.train with this function to make sure train/eval mode + does not change anymore.""" + return self + + +class FrozenT5Embedder(AbstractEncoder): + """Uses the T5 transformer encoder for text""" + + def __init__( + self, version="google/t5-v1_1-large", device="cuda", max_length=77, freeze=True + ): # others are google/t5-v1_1-xl and google/t5-v1_1-xxl + super().__init__() + self.tokenizer = T5Tokenizer.from_pretrained(version) + self.transformer = T5EncoderModel.from_pretrained(version) + self.device = device + self.max_length = max_length # TODO: typical value? + if freeze: + self.freeze() + + def freeze(self): + self.transformer = self.transformer.eval() + # self.train = disabled_train + for param in self.parameters(): + param.requires_grad = False + + def forward(self, text): + batch_encoding = self.tokenizer( + text, + truncation=True, + max_length=self.max_length, + return_length=True, + return_overflowing_tokens=False, + padding="max_length", + return_tensors="pt", + ) + tokens = batch_encoding["input_ids"].to(self.device) + outputs = self.transformer(input_ids=tokens) + + z = outputs.last_hidden_state + return z + + def encode(self, text): + return self(text) + + +class FrozenCLIPEmbedder(AbstractEncoder): + """Uses the CLIP transformer encoder for text (from huggingface)""" + + LAYERS = ["last", "pooled", "hidden"] + + def __init__( + self, + version="openai/clip-vit-large-patch14", + device="cuda", + max_length=77, + freeze=True, + layer="last", + layer_idx=None, + ): # clip-vit-base-patch32 + super().__init__() + assert layer in self.LAYERS + self.tokenizer = CLIPTokenizer.from_pretrained(version) + self.transformer = CLIPTextModel.from_pretrained(version) + self.device = device + self.max_length = max_length + if freeze: + self.freeze() + self.layer = layer + self.layer_idx = layer_idx + if layer == "hidden": + assert layer_idx is not None + assert 0 <= abs(layer_idx) <= 12 + + def freeze(self): + self.transformer = self.transformer.eval() + # self.train = disabled_train + for param in self.parameters(): + param.requires_grad = False + + def forward(self, text): + batch_encoding = self.tokenizer( + text, + truncation=True, + max_length=self.max_length, + return_length=True, + return_overflowing_tokens=False, + padding="max_length", + return_tensors="pt", + ) + tokens = batch_encoding["input_ids"].to(self.device) + outputs = self.transformer( + input_ids=tokens, output_hidden_states=self.layer == "hidden" + ) + if self.layer == "last": + z = outputs.last_hidden_state + elif self.layer == "pooled": + z = outputs.pooler_output[:, None, :] + else: + z = outputs.hidden_states[self.layer_idx] + return z + + def encode(self, text): + return self(text) + + +class FrozenOpenCLIPEmbedder(AbstractEncoder, nn.Module): + """ + Uses the OpenCLIP transformer encoder for text + """ + + LAYERS = [ + # "pooled", + "last", + "penultimate", + ] + + def __init__( + self, + arch="ViT-H-14", + version="laion2b_s32b_b79k", + device="cuda", + max_length=77, + freeze=True, + layer="last", + ip_mode=None + ): + """_summary_ + + Args: + ip_mode (str, optional): what is the image promcessing mode. Defaults to None. + + """ + super().__init__() + assert layer in self.LAYERS + model, _, preprocess = open_clip.create_model_and_transforms( + arch, device=torch.device("cpu"), pretrained=version + ) + if ip_mode is None: + del model.visual + + self.model = model + self.preprocess = preprocess + self.device = device + self.max_length = max_length + self.ip_mode = ip_mode + if freeze: + self.freeze() + self.layer = layer + if self.layer == "last": + self.layer_idx = 0 + elif self.layer == "penultimate": + self.layer_idx = 1 + else: + raise NotImplementedError() + + def freeze(self): + self.model = self.model.eval() + for param in self.parameters(): + param.requires_grad = False + + def forward(self, text): + tokens = open_clip.tokenize(text) + z = self.encode_with_transformer(tokens.to(self.device)) + return z + + def forward_image(self, pil_image): + if isinstance(pil_image, Image.Image): + pil_image = [pil_image] + if isinstance(pil_image, torch.Tensor): + pil_image = pil_image.cpu().numpy() + if isinstance(pil_image, np.ndarray): + if pil_image.ndim == 3: + pil_image = pil_image[None, :, :, :] + pil_image = [Image.fromarray(x) for x in pil_image] + + images = [] + for image in pil_image: + images.append(self.preprocess(image).to(self.device)) + + image = torch.stack(images, 0) # to [b, 3, h, w] + if self.ip_mode == "global": + image_features = self.model.encode_image(image) + image_features /= image_features.norm(dim=-1, keepdim=True) + elif "local" in self.ip_mode: + image_features = self.encode_image_with_transformer(image) + + return image_features # b, l + + def encode_image_with_transformer(self, x): + visual = self.model.visual + x = visual.conv1(x) # shape = [*, width, grid, grid] + x = x.reshape(x.shape[0], x.shape[1], -1) # shape = [*, width, grid ** 2] + x = x.permute(0, 2, 1) # shape = [*, grid ** 2, width] + + # class embeddings and positional embeddings + x = torch.cat( + [visual.class_embedding.to(x.dtype) + \ + torch.zeros(x.shape[0], 1, x.shape[-1], dtype=x.dtype, device=x.device), + x], dim=1) # shape = [*, grid ** 2 + 1, width] + x = x + visual.positional_embedding.to(x.dtype) + + # a patch_dropout of 0. would mean it is disabled and this function would do nothing but return what was passed in + # x = visual.patch_dropout(x) + x = visual.ln_pre(x) + + x = x.permute(1, 0, 2) # NLD -> LND + hidden = self.image_transformer_forward(x) + x = hidden[-2].permute(1, 0, 2) # LND -> NLD + return x + + def image_transformer_forward(self, x): + encoder_states = () + trans = self.model.visual.transformer + for r in trans.resblocks: + if trans.grad_checkpointing and not torch.jit.is_scripting(): + # TODO: handle kwargs https://github.com/pytorch/pytorch/issues/79887#issuecomment-1161758372 + x = checkpoint(r, x, None, None, None) + else: + x = r(x, attn_mask=None) + encoder_states = encoder_states + (x, ) + return encoder_states + + def encode_with_transformer(self, text): + x = self.model.token_embedding(text) # [batch_size, n_ctx, d_model] + x = x + self.model.positional_embedding + x = x.permute(1, 0, 2) # NLD -> LND + x = self.text_transformer_forward(x, attn_mask=self.model.attn_mask) + x = x.permute(1, 0, 2) # LND -> NLD + x = self.model.ln_final(x) + return x + + def text_transformer_forward(self, x: torch.Tensor, attn_mask=None): + for i, r in enumerate(self.model.transformer.resblocks): + if i == len(self.model.transformer.resblocks) - self.layer_idx: + break + if ( + self.model.transformer.grad_checkpointing + and not torch.jit.is_scripting() + ): + x = checkpoint(r, x, attn_mask) + else: + x = r(x, attn_mask=attn_mask) + return x + + def encode(self, text): + return self(text) + + +class FrozenCLIPT5Encoder(AbstractEncoder): + def __init__( + self, + clip_version="openai/clip-vit-large-patch14", + t5_version="google/t5-v1_1-xl", + device="cuda", + clip_max_length=77, + t5_max_length=77, + ): + super().__init__() + self.clip_encoder = FrozenCLIPEmbedder( + clip_version, device, max_length=clip_max_length + ) + self.t5_encoder = FrozenT5Embedder(t5_version, device, max_length=t5_max_length) + print( + f"{self.clip_encoder.__class__.__name__} has {count_params(self.clip_encoder)*1.e-6:.2f} M parameters, " + f"{self.t5_encoder.__class__.__name__} comes with {count_params(self.t5_encoder)*1.e-6:.2f} M params." + ) + + def encode(self, text): + return self(text) + + def forward(self, text): + clip_z = self.clip_encoder.encode(text) + t5_z = self.t5_encoder.encode(text) + return [clip_z, t5_z] diff --git a/apps/third_party/CRM/imagedream/ldm/util.py b/apps/third_party/CRM/imagedream/ldm/util.py new file mode 100644 index 0000000000000000000000000000000000000000..91a257c15fe6bc2782cb93cc3ab7b0817060f80f --- /dev/null +++ b/apps/third_party/CRM/imagedream/ldm/util.py @@ -0,0 +1,231 @@ +import importlib + +import random +import torch +import numpy as np +from collections import abc + +import multiprocessing as mp +from threading import Thread +from queue import Queue + +from inspect import isfunction +from PIL import Image, ImageDraw, ImageFont + + +def log_txt_as_img(wh, xc, size=10): + # wh a tuple of (width, height) + # xc a list of captions to plot + b = len(xc) + txts = list() + for bi in range(b): + txt = Image.new("RGB", wh, color="white") + draw = ImageDraw.Draw(txt) + font = ImageFont.truetype("data/DejaVuSans.ttf", size=size) + nc = int(40 * (wh[0] / 256)) + lines = "\n".join( + xc[bi][start : start + nc] for start in range(0, len(xc[bi]), nc) + ) + + try: + draw.text((0, 0), lines, fill="black", font=font) + except UnicodeEncodeError: + print("Cant encode string for logging. Skipping.") + + txt = np.array(txt).transpose(2, 0, 1) / 127.5 - 1.0 + txts.append(txt) + txts = np.stack(txts) + txts = torch.tensor(txts) + return txts + + +def ismap(x): + if not isinstance(x, torch.Tensor): + return False + return (len(x.shape) == 4) and (x.shape[1] > 3) + + +def isimage(x): + if not isinstance(x, torch.Tensor): + return False + return (len(x.shape) == 4) and (x.shape[1] == 3 or x.shape[1] == 1) + + +def exists(x): + return x is not None + + +def default(val, d): + if exists(val): + return val + return d() if isfunction(d) else d + + +def mean_flat(tensor): + """ + https://github.com/openai/guided-diffusion/blob/27c20a8fab9cb472df5d6bdd6c8d11c8f430b924/guided_diffusion/nn.py#L86 + Take the mean over all non-batch dimensions. + """ + return tensor.mean(dim=list(range(1, len(tensor.shape)))) + + +def count_params(model, verbose=False): + total_params = sum(p.numel() for p in model.parameters()) + if verbose: + print(f"{model.__class__.__name__} has {total_params * 1.e-6:.2f} M params.") + return total_params + + +def instantiate_from_config(config): + if not "target" in config: + if config == "__is_first_stage__": + return None + elif config == "__is_unconditional__": + return None + raise KeyError("Expected key `target` to instantiate.") + # import pdb; pdb.set_trace() + return get_obj_from_str(config["target"])(**config.get("params", dict())) + + +def get_obj_from_str(string, reload=False): + module, cls = string.rsplit(".", 1) + # import pdb; pdb.set_trace() + if reload: + module_imp = importlib.import_module(module) + importlib.reload(module_imp) + + if 'imagedream' in module: + module = 'third_party.CRM.'+module + if 'lib' in module: + module = 'third_party.CRM.'+module + return getattr(importlib.import_module(module, package=None), cls) + + +def _do_parallel_data_prefetch(func, Q, data, idx, idx_to_fn=False): + # create dummy dataset instance + + # run prefetching + if idx_to_fn: + res = func(data, worker_id=idx) + else: + res = func(data) + Q.put([idx, res]) + Q.put("Done") + + +def parallel_data_prefetch( + func: callable, + data, + n_proc, + target_data_type="ndarray", + cpu_intensive=True, + use_worker_id=False, +): + # if target_data_type not in ["ndarray", "list"]: + # raise ValueError( + # "Data, which is passed to parallel_data_prefetch has to be either of type list or ndarray." + # ) + if isinstance(data, np.ndarray) and target_data_type == "list": + raise ValueError("list expected but function got ndarray.") + elif isinstance(data, abc.Iterable): + if isinstance(data, dict): + print( + f'WARNING:"data" argument passed to parallel_data_prefetch is a dict: Using only its values and disregarding keys.' + ) + data = list(data.values()) + if target_data_type == "ndarray": + data = np.asarray(data) + else: + data = list(data) + else: + raise TypeError( + f"The data, that shall be processed parallel has to be either an np.ndarray or an Iterable, but is actually {type(data)}." + ) + + if cpu_intensive: + Q = mp.Queue(1000) + proc = mp.Process + else: + Q = Queue(1000) + proc = Thread + # spawn processes + if target_data_type == "ndarray": + arguments = [ + [func, Q, part, i, use_worker_id] + for i, part in enumerate(np.array_split(data, n_proc)) + ] + else: + step = ( + int(len(data) / n_proc + 1) + if len(data) % n_proc != 0 + else int(len(data) / n_proc) + ) + arguments = [ + [func, Q, part, i, use_worker_id] + for i, part in enumerate( + [data[i : i + step] for i in range(0, len(data), step)] + ) + ] + processes = [] + for i in range(n_proc): + p = proc(target=_do_parallel_data_prefetch, args=arguments[i]) + processes += [p] + + # start processes + print(f"Start prefetching...") + import time + + start = time.time() + gather_res = [[] for _ in range(n_proc)] + try: + for p in processes: + p.start() + + k = 0 + while k < n_proc: + # get result + res = Q.get() + if res == "Done": + k += 1 + else: + gather_res[res[0]] = res[1] + + except Exception as e: + print("Exception: ", e) + for p in processes: + p.terminate() + + raise e + finally: + for p in processes: + p.join() + print(f"Prefetching complete. [{time.time() - start} sec.]") + + if target_data_type == "ndarray": + if not isinstance(gather_res[0], np.ndarray): + return np.concatenate([np.asarray(r) for r in gather_res], axis=0) + + # order outputs + return np.concatenate(gather_res, axis=0) + elif target_data_type == "list": + out = [] + for r in gather_res: + out.extend(r) + return out + else: + return gather_res + +def set_seed(seed=None): + random.seed(seed) + np.random.seed(seed) + if seed is not None: + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + +def add_random_background(image, bg_color=None): + bg_color = np.random.rand() * 255 if bg_color is None else bg_color + image = np.array(image) + rgb, alpha = image[..., :3], image[..., 3:] + alpha = alpha.astype(np.float32) / 255.0 + image_new = rgb * alpha + bg_color * (1 - alpha) + return Image.fromarray(image_new.astype(np.uint8)) \ No newline at end of file diff --git a/apps/third_party/CRM/imagedream/model_zoo.py b/apps/third_party/CRM/imagedream/model_zoo.py new file mode 100644 index 0000000000000000000000000000000000000000..45d6b678bdc554f5b2ad19903f8ed9976ece024e --- /dev/null +++ b/apps/third_party/CRM/imagedream/model_zoo.py @@ -0,0 +1,64 @@ +""" Utiliy functions to load pre-trained models more easily """ +import os +import pkg_resources +from omegaconf import OmegaConf + +import torch +from huggingface_hub import hf_hub_download + +from imagedream.ldm.util import instantiate_from_config + + +PRETRAINED_MODELS = { + "sd-v2.1-base-4view-ipmv": { + "config": "sd_v2_base_ipmv.yaml", + "repo_id": "Peng-Wang/ImageDream", + "filename": "sd-v2.1-base-4view-ipmv.pt", + }, + "sd-v2.1-base-4view-ipmv-local": { + "config": "sd_v2_base_ipmv_local.yaml", + "repo_id": "Peng-Wang/ImageDream", + "filename": "sd-v2.1-base-4view-ipmv-local.pt", + }, +} + + +def get_config_file(config_path): + cfg_file = pkg_resources.resource_filename( + "imagedream", os.path.join("configs", config_path) + ) + if not os.path.exists(cfg_file): + raise RuntimeError(f"Config {config_path} not available!") + return cfg_file + + +def build_model(model_name, config_path=None, ckpt_path=None, cache_dir=None): + if (config_path is not None) and (ckpt_path is not None): + config = OmegaConf.load(config_path) + model = instantiate_from_config(config.model) + model.load_state_dict(torch.load(ckpt_path, map_location="cpu"), strict=False) + return model + + if not model_name in PRETRAINED_MODELS: + raise RuntimeError( + f"Model name {model_name} is not a pre-trained model. Available models are:\n- " + + "\n- ".join(PRETRAINED_MODELS.keys()) + ) + model_info = PRETRAINED_MODELS[model_name] + + # Instiantiate the model + print(f"Loading model from config: {model_info['config']}") + config_file = get_config_file(model_info["config"]) + config = OmegaConf.load(config_file) + model = instantiate_from_config(config.model) + + # Load pre-trained checkpoint from huggingface + if not ckpt_path: + ckpt_path = hf_hub_download( + repo_id=model_info["repo_id"], + filename=model_info["filename"], + cache_dir=cache_dir, + ) + print(f"Loading model from cache file: {ckpt_path}") + model.load_state_dict(torch.load(ckpt_path, map_location="cpu"), strict=False) + return model diff --git a/apps/third_party/CRM/inference.py b/apps/third_party/CRM/inference.py new file mode 100644 index 0000000000000000000000000000000000000000..a6fc2a9e49d606dc44d0cb8ae0cfbf223b44dcd4 --- /dev/null +++ b/apps/third_party/CRM/inference.py @@ -0,0 +1,91 @@ +import numpy as np +import torch +import time +import nvdiffrast.torch as dr +from util.utils import get_tri +import tempfile +from mesh import Mesh +import zipfile +def generate3d(model, rgb, ccm, device): + + color_tri = torch.from_numpy(rgb)/255 + xyz_tri = torch.from_numpy(ccm[:,:,(2,1,0)])/255 + color = color_tri.permute(2,0,1) + xyz = xyz_tri.permute(2,0,1) + + + def get_imgs(color): + # color : [C, H, W*6] + color_list = [] + color_list.append(color[:,:,256*5:256*(1+5)]) + for i in range(0,5): + color_list.append(color[:,:,256*i:256*(1+i)]) + return torch.stack(color_list, dim=0)# [6, C, H, W] + + triplane_color = get_imgs(color).permute(0,2,3,1).unsqueeze(0).to(device)# [1, 6, H, W, C] + + color = get_imgs(color) + xyz = get_imgs(xyz) + + color = get_tri(color, dim=0, blender= True, scale = 1).unsqueeze(0) + xyz = get_tri(xyz, dim=0, blender= True, scale = 1, fix= True).unsqueeze(0) + + triplane = torch.cat([color,xyz],dim=1).to(device) + # 3D visualize + model.eval() + glctx = dr.RasterizeCudaContext() + + if model.denoising == True: + tnew = 20 + tnew = torch.randint(tnew, tnew+1, [triplane.shape[0]], dtype=torch.long, device=triplane.device) + noise_new = torch.randn_like(triplane) *0.5+0.5 + triplane = model.scheduler.add_noise(triplane, noise_new, tnew) + start_time = time.time() + with torch.no_grad(): + triplane_feature2 = model.unet2(triplane,tnew) + end_time = time.time() + elapsed_time = end_time - start_time + print(f"unet takes {elapsed_time}s") + else: + triplane_feature2 = model.unet2(triplane) + + + with torch.no_grad(): + data_config = { + 'resolution': [1024, 1024], + "triview_color": triplane_color.to(device), + } + + verts, faces = model.decode(data_config, triplane_feature2) + + data_config['verts'] = verts[0] + data_config['faces'] = faces + + + from kiui.mesh_utils import clean_mesh + verts, faces = clean_mesh(data_config['verts'].squeeze().cpu().numpy().astype(np.float32), data_config['faces'].squeeze().cpu().numpy().astype(np.int32), repair = False, remesh=False, remesh_size=0.005) + data_config['verts'] = torch.from_numpy(verts).cuda().contiguous() + data_config['faces'] = torch.from_numpy(faces).cuda().contiguous() + + start_time = time.time() + with torch.no_grad(): + mesh_path_obj = tempfile.NamedTemporaryFile(suffix=f"", delete=False).name + model.export_mesh_wt_uv(glctx, data_config, mesh_path_obj, "", device, res=(1024,1024), tri_fea_2=triplane_feature2) + + mesh = Mesh.load(mesh_path_obj+".obj", bound=0.9, front_dir="+z") + mesh_path_glb = tempfile.NamedTemporaryFile(suffix=f"", delete=False).name + mesh.write(mesh_path_glb+".glb") + + # mesh_obj2 = trimesh.load(mesh_path_glb+".glb", file_type='glb') + # mesh_path_obj2 = tempfile.NamedTemporaryFile(suffix=f"", delete=False).name + # mesh_obj2.export(mesh_path_obj2+".obj") + + with zipfile.ZipFile(mesh_path_obj+'.zip', 'w') as myzip: + myzip.write(mesh_path_obj+'.obj', mesh_path_obj.split("/")[-1]+'.obj') + myzip.write(mesh_path_obj+'.png', mesh_path_obj.split("/")[-1]+'.png') + myzip.write(mesh_path_obj+'.mtl', mesh_path_obj.split("/")[-1]+'.mtl') + + end_time = time.time() + elapsed_time = end_time - start_time + print(f"uv takes {elapsed_time}s") + return mesh_path_glb+".glb", mesh_path_obj+'.zip' diff --git a/apps/third_party/CRM/libs/__init__.py b/apps/third_party/CRM/libs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/libs/base_utils.py b/apps/third_party/CRM/libs/base_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..c90a548286e80ded1f317126d8f560f67a85e0d8 --- /dev/null +++ b/apps/third_party/CRM/libs/base_utils.py @@ -0,0 +1,84 @@ +import numpy as np +import cv2 +import torch +import numpy as np +from PIL import Image + + +def instantiate_from_config(config): + if not "target" in config: + raise KeyError("Expected key `target` to instantiate.") + return get_obj_from_str(config["target"])(**config.get("params", dict())) + + +def get_obj_from_str(string, reload=False): + import importlib + module, cls = string.rsplit(".", 1) + if reload: + module_imp = importlib.import_module(module) + importlib.reload(module_imp) + return getattr(importlib.import_module(module, package=None), cls) + + +def tensor_detail(t): + assert type(t) == torch.Tensor + print(f"shape: {t.shape} mean: {t.mean():.2f}, std: {t.std():.2f}, min: {t.min():.2f}, max: {t.max():.2f}") + + + +def drawRoundRec(draw, color, x, y, w, h, r): + drawObject = draw + + '''Rounds''' + drawObject.ellipse((x, y, x + r, y + r), fill=color) + drawObject.ellipse((x + w - r, y, x + w, y + r), fill=color) + drawObject.ellipse((x, y + h - r, x + r, y + h), fill=color) + drawObject.ellipse((x + w - r, y + h - r, x + w, y + h), fill=color) + + '''rec.s''' + drawObject.rectangle((x + r / 2, y, x + w - (r / 2), y + h), fill=color) + drawObject.rectangle((x, y + r / 2, x + w, y + h - (r / 2)), fill=color) + + +def do_resize_content(original_image: Image, scale_rate): + # resize image content wile retain the original image size + if scale_rate != 1: + # Calculate the new size after rescaling + new_size = tuple(int(dim * scale_rate) for dim in original_image.size) + # Resize the image while maintaining the aspect ratio + resized_image = original_image.resize(new_size) + # Create a new image with the original size and black background + padded_image = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) + paste_position = ((original_image.width - resized_image.width) // 2, (original_image.height - resized_image.height) // 2) + padded_image.paste(resized_image, paste_position) + return padded_image + else: + return original_image + +def add_stroke(img, color=(255, 255, 255), stroke_radius=3): + # color in R, G, B format + if isinstance(img, Image.Image): + assert img.mode == "RGBA" + img = cv2.cvtColor(np.array(img), cv2.COLOR_RGBA2BGRA) + else: + assert img.shape[2] == 4 + gray = img[:,:, 3] + ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) + contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) + res = cv2.drawContours(img, contours,-1, tuple(color)[::-1] + (255,), stroke_radius) + return Image.fromarray(cv2.cvtColor(res,cv2.COLOR_BGRA2RGBA)) + +def make_blob(image_size=(512, 512), sigma=0.2): + """ + make 2D blob image with: + I(x, y)=1-\exp \left(-\frac{(x-H / 2)^2+(y-W / 2)^2}{2 \sigma^2 HS}\right) + """ + import numpy as np + H, W = image_size + x = np.arange(0, W, 1, float) + y = np.arange(0, H, 1, float) + x, y = np.meshgrid(x, y) + x0 = W // 2 + y0 = H // 2 + img = 1 - np.exp(-((x - x0) ** 2 + (y - y0) ** 2) / (2 * sigma ** 2 * H * W)) + return (img * 255).astype(np.uint8) \ No newline at end of file diff --git a/apps/third_party/CRM/libs/sample.py b/apps/third_party/CRM/libs/sample.py new file mode 100644 index 0000000000000000000000000000000000000000..1756863162c3800a4a035007949ad4893d36e254 --- /dev/null +++ b/apps/third_party/CRM/libs/sample.py @@ -0,0 +1,384 @@ +import numpy as np +import torch +from imagedream.camera_utils import get_camera_for_index +from imagedream.ldm.util import set_seed, add_random_background +# import os +# import sys +# proj_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +# sys.path.append(proj_dir) +from third_party.CRM.libs.base_utils import do_resize_content +from imagedream.ldm.models.diffusion.ddim import DDIMSampler +from torchvision import transforms as T + + +class ImageDreamDiffusion: + def __init__( + self, + model, + device, + dtype, + mode, + num_frames, + camera_views, + ref_position, + random_background=False, + offset_noise=False, + resize_rate=1, + image_size=256, + seed=1234, + ) -> None: + assert mode in ["pixel", "local"] + size = image_size + self.seed = seed + batch_size = max(4, num_frames) + + neg_texts = "uniform low no texture ugly, boring, bad anatomy, blurry, pixelated, obscure, unnatural colors, poor lighting, dull, and unclear." + uc = model.get_learned_conditioning([neg_texts]).to(device) + sampler = DDIMSampler(model) + + # pre-compute camera matrices + camera = [get_camera_for_index(i).squeeze() for i in camera_views] + camera[ref_position] = torch.zeros_like(camera[ref_position]) # set ref camera to zero + camera = torch.stack(camera) + camera = camera.repeat(batch_size // num_frames, 1).to(device) + + self.image_transform = T.Compose( + [ + T.Resize((size, size)), + T.ToTensor(), + T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), + ] + ) + self.dtype = dtype + self.ref_position = ref_position + self.mode = mode + self.random_background = random_background + self.resize_rate = resize_rate + self.num_frames = num_frames + self.size = size + self.device = device + self.batch_size = batch_size + self.model = model + self.sampler = sampler + self.uc = uc + self.camera = camera + self.offset_noise = offset_noise + + @staticmethod + def i2i( + model, + image_size, + prompt, + uc, + sampler, + ip=None, + step=20, + scale=5.0, + batch_size=8, + ddim_eta=0.0, + dtype=torch.float32, + device="cuda", + camera=None, + num_frames=4, + pixel_control=False, + transform=None, + offset_noise=False, + ): + """ The function supports additional image prompt. + Args: + model (_type_): the image dream model + image_size (_type_): size of diffusion output (standard 256) + prompt (_type_): text prompt for the image (prompt in type str) + uc (_type_): unconditional vector (tensor in shape [1, 77, 1024]) + sampler (_type_): imagedream.ldm.models.diffusion.ddim.DDIMSampler + ip (Image, optional): the image prompt. Defaults to None. + step (int, optional): _description_. Defaults to 20. + scale (float, optional): _description_. Defaults to 7.5. + batch_size (int, optional): _description_. Defaults to 8. + ddim_eta (float, optional): _description_. Defaults to 0.0. + dtype (_type_, optional): _description_. Defaults to torch.float32. + device (str, optional): _description_. Defaults to "cuda". + camera (_type_, optional): camera info in tensor, shape: torch.Size([5, 16]) mean: 0.11, std: 0.49, min: -1.00, max: 1.00 + num_frames (int, optional): _num of frames (views) to generate + pixel_control: whether to use pixel conditioning. Defaults to False, True when using pixel mode + transform: Compose( + Resize(size=(256, 256), interpolation=bilinear, max_size=None, antialias=warn) + ToTensor() + Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)) + ) + """ + ip_raw = ip + if type(prompt) != list: + prompt = [prompt] + with torch.no_grad(), torch.autocast(device_type=torch.device(device).type, dtype=dtype): + c = model.get_learned_conditioning(prompt).to( + device + ) # shape: torch.Size([1, 77, 1024]) mean: -0.17, std: 1.02, min: -7.50, max: 13.05 + c_ = {"context": c.repeat(batch_size, 1, 1)} # batch_size + uc_ = {"context": uc.repeat(batch_size, 1, 1)} + + if camera is not None: + c_["camera"] = uc_["camera"] = ( + camera # shape: torch.Size([5, 16]) mean: 0.11, std: 0.49, min: -1.00, max: 1.00 + ) + c_["num_frames"] = uc_["num_frames"] = num_frames + + if ip is not None: + ip_embed = model.get_learned_image_conditioning(ip).to( + device + ) # shape: torch.Size([1, 257, 1280]) mean: 0.06, std: 0.53, min: -6.83, max: 11.12 + ip_ = ip_embed.repeat(batch_size, 1, 1) + c_["ip"] = ip_ + uc_["ip"] = torch.zeros_like(ip_) + + if pixel_control: + assert camera is not None + ip = transform(ip).to( + device + ) # shape: torch.Size([3, 256, 256]) mean: 0.33, std: 0.37, min: -1.00, max: 1.00 + ip_img = model.get_first_stage_encoding( + model.encode_first_stage(ip[None, :, :, :]) + ) # shape: torch.Size([1, 4, 32, 32]) mean: 0.23, std: 0.77, min: -4.42, max: 3.55 + c_["ip_img"] = ip_img + uc_["ip_img"] = torch.zeros_like(ip_img) + + shape = [4, image_size // 8, image_size // 8] # [4, 32, 32] + if offset_noise: + ref = transform(ip_raw).to(device) + ref_latent = model.get_first_stage_encoding(model.encode_first_stage(ref[None, :, :, :])) + ref_mean = ref_latent.mean(dim=(-1, -2), keepdim=True) + time_steps = torch.randint(model.num_timesteps - 1, model.num_timesteps, (batch_size,), device=device) + x_T = model.q_sample(torch.ones([batch_size] + shape, device=device) * ref_mean, time_steps) + + samples_ddim, _ = ( + sampler.sample( # shape: torch.Size([5, 4, 32, 32]) mean: 0.29, std: 0.85, min: -3.38, max: 4.43 + S=step, + conditioning=c_, + batch_size=batch_size, + shape=shape, + verbose=False, + unconditional_guidance_scale=scale, + unconditional_conditioning=uc_, + eta=ddim_eta, + x_T=x_T if offset_noise else None, + ) + ) + + x_sample = model.decode_first_stage(samples_ddim) + x_sample = torch.clamp((x_sample + 1.0) / 2.0, min=0.0, max=1.0) + x_sample = 255.0 * x_sample.permute(0, 2, 3, 1).cpu().numpy() + + return list(x_sample.astype(np.uint8)) + + def diffuse(self, t, ip, n_test=2): + set_seed(self.seed) + ip = do_resize_content(ip, self.resize_rate) + if self.random_background: + ip = add_random_background(ip) + + images = [] + for _ in range(n_test): + img = self.i2i( + self.model, + self.size, + t, + self.uc, + self.sampler, + ip=ip, + step=50, + scale=5, + batch_size=self.batch_size, + ddim_eta=0.0, + dtype=self.dtype, + device=self.device, + camera=self.camera, + num_frames=self.num_frames, + pixel_control=(self.mode == "pixel"), + transform=self.image_transform, + offset_noise=self.offset_noise, + ) + img = np.concatenate(img, 1) + img = np.concatenate((img, ip.resize((self.size, self.size))), axis=1) + images.append(img) + set_seed() # unset random and numpy seed + return images + + +class ImageDreamDiffusionStage2: + def __init__( + self, + model, + device, + dtype, + num_frames, + camera_views, + ref_position, + random_background=False, + offset_noise=False, + resize_rate=1, + mode="pixel", + image_size=256, + seed=1234, + ) -> None: + assert mode in ["pixel", "local"] + + size = image_size + self.seed = seed + batch_size = max(4, num_frames) + + neg_texts = "uniform low no texture ugly, boring, bad anatomy, blurry, pixelated, obscure, unnatural colors, poor lighting, dull, and unclear." + uc = model.get_learned_conditioning([neg_texts]).to(device) + sampler = DDIMSampler(model) + + # pre-compute camera matrices + camera = [get_camera_for_index(i).squeeze() for i in camera_views] + if ref_position is not None: + camera[ref_position] = torch.zeros_like(camera[ref_position]) # set ref camera to zero + camera = torch.stack(camera) + camera = camera.repeat(batch_size // num_frames, 1).to(device) + + self.image_transform = T.Compose( + [ + T.Resize((size, size)), + T.ToTensor(), + T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), + ] + ) + + self.dtype = dtype + self.mode = mode + self.ref_position = ref_position + self.random_background = random_background + self.resize_rate = resize_rate + self.num_frames = num_frames + self.size = size + self.device = device + self.batch_size = batch_size + self.model = model + self.sampler = sampler + self.uc = uc + self.camera = camera + self.offset_noise = offset_noise + + @staticmethod + def i2iStage2( + model, + image_size, + prompt, + uc, + sampler, + pixel_images, + ip=None, + step=20, + scale=5.0, + batch_size=8, + ddim_eta=0.0, + dtype=torch.float32, + device="cuda", + camera=None, + num_frames=4, + pixel_control=False, + transform=None, + offset_noise=False, + ): + ip_raw = ip + if type(prompt) != list: + prompt = [prompt] + with torch.no_grad(), torch.autocast(device_type=torch.device(device).type, dtype=dtype): + c = model.get_learned_conditioning(prompt).to( + device + ) # shape: torch.Size([1, 77, 1024]) mean: -0.17, std: 1.02, min: -7.50, max: 13.05 + c_ = {"context": c.repeat(batch_size, 1, 1)} # batch_size + uc_ = {"context": uc.repeat(batch_size, 1, 1)} + + if camera is not None: + c_["camera"] = uc_["camera"] = ( + camera # shape: torch.Size([5, 16]) mean: 0.11, std: 0.49, min: -1.00, max: 1.00 + ) + c_["num_frames"] = uc_["num_frames"] = num_frames + + if ip is not None: + ip_embed = model.get_learned_image_conditioning(ip).to( + device + ) # shape: torch.Size([1, 257, 1280]) mean: 0.06, std: 0.53, min: -6.83, max: 11.12 + ip_ = ip_embed.repeat(batch_size, 1, 1) + c_["ip"] = ip_ + uc_["ip"] = torch.zeros_like(ip_) + + if pixel_control: + assert camera is not None + + transed_pixel_images = torch.stack([transform(i).to(device) for i in pixel_images]) + latent_pixel_images = model.get_first_stage_encoding(model.encode_first_stage(transed_pixel_images)) + + c_["pixel_images"] = latent_pixel_images + uc_["pixel_images"] = torch.zeros_like(latent_pixel_images) + + shape = [4, image_size // 8, image_size // 8] # [4, 32, 32] + if offset_noise: + ref = transform(ip_raw).to(device) + ref_latent = model.get_first_stage_encoding(model.encode_first_stage(ref[None, :, :, :])) + ref_mean = ref_latent.mean(dim=(-1, -2), keepdim=True) + time_steps = torch.randint(model.num_timesteps - 1, model.num_timesteps, (batch_size,), device=device) + x_T = model.q_sample(torch.ones([batch_size] + shape, device=device) * ref_mean, time_steps) + + samples_ddim, _ = ( + sampler.sample( # shape: torch.Size([5, 4, 32, 32]) mean: 0.29, std: 0.85, min: -3.38, max: 4.43 + S=step, + conditioning=c_, + batch_size=batch_size, + shape=shape, + verbose=False, + unconditional_guidance_scale=scale, + unconditional_conditioning=uc_, + eta=ddim_eta, + x_T=x_T if offset_noise else None, + ) + ) + x_sample = model.decode_first_stage(samples_ddim) + x_sample = torch.clamp((x_sample + 1.0) / 2.0, min=0.0, max=1.0) + x_sample = 255.0 * x_sample.permute(0, 2, 3, 1).cpu().numpy() + + return list(x_sample.astype(np.uint8)) + + @torch.no_grad() + def diffuse(self, t, ip, pixel_images, n_test=2): + set_seed(self.seed) + ip = do_resize_content(ip, self.resize_rate) + pixel_images = [do_resize_content(i, self.resize_rate) for i in pixel_images] + + if self.random_background: + bg_color = np.random.rand() * 255 + ip = add_random_background(ip, bg_color) + pixel_images = [add_random_background(i, bg_color) for i in pixel_images] + + images = [] + for _ in range(n_test): + img = self.i2iStage2( + self.model, + self.size, + t, + self.uc, + self.sampler, + pixel_images=pixel_images, + ip=ip, + step=50, + scale=5, + batch_size=self.batch_size, + ddim_eta=0.0, + dtype=self.dtype, + device=self.device, + camera=self.camera, + num_frames=self.num_frames, + pixel_control=(self.mode == "pixel"), + transform=self.image_transform, + offset_noise=self.offset_noise, + ) + img = np.concatenate(img, 1) + img = np.concatenate( + (img, ip.resize((self.size, self.size)), *[i.resize((self.size, self.size)) for i in pixel_images]), + axis=1, + ) + images.append(img) + set_seed() # unset random and numpy seed + return images diff --git a/apps/third_party/CRM/mesh.py b/apps/third_party/CRM/mesh.py new file mode 100644 index 0000000000000000000000000000000000000000..b98dea041fb41d207b6e95ed927216344854d25c --- /dev/null +++ b/apps/third_party/CRM/mesh.py @@ -0,0 +1,845 @@ +import os +import cv2 +import torch +import trimesh +import numpy as np + +from kiui.op import safe_normalize, dot +from kiui.typing import * + +class Mesh: + """ + A torch-native trimesh class, with support for ``ply/obj/glb`` formats. + + Note: + This class only supports one mesh with a single texture image (an albedo texture and a metallic-roughness texture). + """ + def __init__( + self, + v: Optional[Tensor] = None, + f: Optional[Tensor] = None, + vn: Optional[Tensor] = None, + fn: Optional[Tensor] = None, + vt: Optional[Tensor] = None, + ft: Optional[Tensor] = None, + vc: Optional[Tensor] = None, # vertex color + albedo: Optional[Tensor] = None, + metallicRoughness: Optional[Tensor] = None, + device: Optional[torch.device] = None, + ): + """Init a mesh directly using all attributes. + + Args: + v (Optional[Tensor]): vertices, float [N, 3]. Defaults to None. + f (Optional[Tensor]): faces, int [M, 3]. Defaults to None. + vn (Optional[Tensor]): vertex normals, float [N, 3]. Defaults to None. + fn (Optional[Tensor]): faces for normals, int [M, 3]. Defaults to None. + vt (Optional[Tensor]): vertex uv coordinates, float [N, 2]. Defaults to None. + ft (Optional[Tensor]): faces for uvs, int [M, 3]. Defaults to None. + vc (Optional[Tensor]): vertex colors, float [N, 3]. Defaults to None. + albedo (Optional[Tensor]): albedo texture, float [H, W, 3], RGB format. Defaults to None. + metallicRoughness (Optional[Tensor]): metallic-roughness texture, float [H, W, 3], metallic(Blue) = metallicRoughness[..., 2], roughness(Green) = metallicRoughness[..., 1]. Defaults to None. + device (Optional[torch.device]): torch device. Defaults to None. + """ + self.device = device + self.v = v + self.vn = vn + self.vt = vt + self.f = f + self.fn = fn + self.ft = ft + # will first see if there is vertex color to use + self.vc = vc + # only support a single albedo image + self.albedo = albedo + # pbr extension, metallic(Blue) = metallicRoughness[..., 2], roughness(Green) = metallicRoughness[..., 1] + # ref: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html + self.metallicRoughness = metallicRoughness + + self.ori_center = 0 + self.ori_scale = 1 + + @classmethod + def load(cls, path, resize=True, clean=False, renormal=True, retex=False, bound=0.9, front_dir='+z', **kwargs): + """load mesh from path. + + Args: + path (str): path to mesh file, supports ply, obj, glb. + clean (bool, optional): perform mesh cleaning at load (e.g., merge close vertices). Defaults to False. + resize (bool, optional): auto resize the mesh using ``bound`` into [-bound, bound]^3. Defaults to True. + renormal (bool, optional): re-calc the vertex normals. Defaults to True. + retex (bool, optional): re-calc the uv coordinates, will overwrite the existing uv coordinates. Defaults to False. + bound (float, optional): bound to resize. Defaults to 0.9. + front_dir (str, optional): front-view direction of the mesh, should be [+-][xyz][ 123]. Defaults to '+z'. + device (torch.device, optional): torch device. Defaults to None. + + Note: + a ``device`` keyword argument can be provided to specify the torch device. + If it's not provided, we will try to use ``'cuda'`` as the device if it's available. + + Returns: + Mesh: the loaded Mesh object. + """ + # obj supports face uv + if path.endswith(".obj"): + mesh = cls.load_obj(path, **kwargs) + # trimesh only supports vertex uv, but can load more formats + else: + mesh = cls.load_trimesh(path, **kwargs) + + # clean + if clean: + from kiui.mesh_utils import clean_mesh + vertices = mesh.v.detach().cpu().numpy() + triangles = mesh.f.detach().cpu().numpy() + vertices, triangles = clean_mesh(vertices, triangles, remesh=False) + mesh.v = torch.from_numpy(vertices).contiguous().float().to(mesh.device) + mesh.f = torch.from_numpy(triangles).contiguous().int().to(mesh.device) + + print(f"[Mesh loading] v: {mesh.v.shape}, f: {mesh.f.shape}") + # auto-normalize + if resize: + mesh.auto_size(bound=bound) + # auto-fix normal + if renormal or mesh.vn is None: + mesh.auto_normal() + print(f"[Mesh loading] vn: {mesh.vn.shape}, fn: {mesh.fn.shape}") + # auto-fix texcoords + if retex or (mesh.albedo is not None and mesh.vt is None): + mesh.auto_uv(cache_path=path) + print(f"[Mesh loading] vt: {mesh.vt.shape}, ft: {mesh.ft.shape}") + + # rotate front dir to +z + if front_dir != "+z": + # axis switch + if "-z" in front_dir: + T = torch.tensor([[1, 0, 0], [0, 1, 0], [0, 0, -1]], device=mesh.device, dtype=torch.float32) + elif "+x" in front_dir: + T = torch.tensor([[0, 0, 1], [0, 1, 0], [1, 0, 0]], device=mesh.device, dtype=torch.float32) + elif "-x" in front_dir: + T = torch.tensor([[0, 0, -1], [0, 1, 0], [1, 0, 0]], device=mesh.device, dtype=torch.float32) + elif "+y" in front_dir: + T = torch.tensor([[1, 0, 0], [0, 0, 1], [0, 1, 0]], device=mesh.device, dtype=torch.float32) + elif "-y" in front_dir: + T = torch.tensor([[1, 0, 0], [0, 0, -1], [0, 1, 0]], device=mesh.device, dtype=torch.float32) + else: + T = torch.tensor([[1, 0, 0], [0, 1, 0], [0, 0, 1]], device=mesh.device, dtype=torch.float32) + # rotation (how many 90 degrees) + if '1' in front_dir: + T @= torch.tensor([[0, -1, 0], [1, 0, 0], [0, 0, 1]], device=mesh.device, dtype=torch.float32) + elif '2' in front_dir: + T @= torch.tensor([[1, 0, 0], [0, -1, 0], [0, 0, 1]], device=mesh.device, dtype=torch.float32) + elif '3' in front_dir: + T @= torch.tensor([[0, 1, 0], [-1, 0, 0], [0, 0, 1]], device=mesh.device, dtype=torch.float32) + mesh.v @= T + mesh.vn @= T + + return mesh + + # load from obj file + @classmethod + def load_obj(cls, path, albedo_path=None, device=None): + """load an ``obj`` mesh. + + Args: + path (str): path to mesh. + albedo_path (str, optional): path to the albedo texture image, will overwrite the existing texture path if specified in mtl. Defaults to None. + device (torch.device, optional): torch device. Defaults to None. + + Note: + We will try to read `mtl` path from `obj`, else we assume the file name is the same as `obj` but with `mtl` extension. + The `usemtl` statement is ignored, and we only use the last material path in `mtl` file. + + Returns: + Mesh: the loaded Mesh object. + """ + assert os.path.splitext(path)[-1] == ".obj" + + mesh = cls() + + # device + if device is None: + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + mesh.device = device + + # load obj + with open(path, "r") as f: + lines = f.readlines() + + def parse_f_v(fv): + # pass in a vertex term of a face, return {v, vt, vn} (-1 if not provided) + # supported forms: + # f v1 v2 v3 + # f v1/vt1 v2/vt2 v3/vt3 + # f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 + # f v1//vn1 v2//vn2 v3//vn3 + xs = [int(x) - 1 if x != "" else -1 for x in fv.split("/")] + xs.extend([-1] * (3 - len(xs))) + return xs[0], xs[1], xs[2] + + vertices, texcoords, normals = [], [], [] + faces, tfaces, nfaces = [], [], [] + mtl_path = None + + for line in lines: + split_line = line.split() + # empty line + if len(split_line) == 0: + continue + prefix = split_line[0].lower() + # mtllib + if prefix == "mtllib": + mtl_path = split_line[1] + # usemtl + elif prefix == "usemtl": + pass # ignored + # v/vn/vt + elif prefix == "v": + vertices.append([float(v) for v in split_line[1:]]) + elif prefix == "vn": + normals.append([float(v) for v in split_line[1:]]) + elif prefix == "vt": + val = [float(v) for v in split_line[1:]] + texcoords.append([val[0], 1.0 - val[1]]) + elif prefix == "f": + vs = split_line[1:] + nv = len(vs) + v0, t0, n0 = parse_f_v(vs[0]) + for i in range(nv - 2): # triangulate (assume vertices are ordered) + v1, t1, n1 = parse_f_v(vs[i + 1]) + v2, t2, n2 = parse_f_v(vs[i + 2]) + faces.append([v0, v1, v2]) + tfaces.append([t0, t1, t2]) + nfaces.append([n0, n1, n2]) + + mesh.v = torch.tensor(vertices, dtype=torch.float32, device=device) + mesh.vt = ( + torch.tensor(texcoords, dtype=torch.float32, device=device) + if len(texcoords) > 0 + else None + ) + mesh.vn = ( + torch.tensor(normals, dtype=torch.float32, device=device) + if len(normals) > 0 + else None + ) + + mesh.f = torch.tensor(faces, dtype=torch.int32, device=device) + mesh.ft = ( + torch.tensor(tfaces, dtype=torch.int32, device=device) + if len(texcoords) > 0 + else None + ) + mesh.fn = ( + torch.tensor(nfaces, dtype=torch.int32, device=device) + if len(normals) > 0 + else None + ) + + # see if there is vertex color + use_vertex_color = False + if mesh.v.shape[1] == 6: + use_vertex_color = True + mesh.vc = mesh.v[:, 3:] + mesh.v = mesh.v[:, :3] + print(f"[load_obj] use vertex color: {mesh.vc.shape}") + + # try to load texture image + if not use_vertex_color: + # try to retrieve mtl file + mtl_path_candidates = [] + if mtl_path is not None: + mtl_path_candidates.append(mtl_path) + mtl_path_candidates.append(os.path.join(os.path.dirname(path), mtl_path)) + mtl_path_candidates.append(path.replace(".obj", ".mtl")) + + mtl_path = None + for candidate in mtl_path_candidates: + if os.path.exists(candidate): + mtl_path = candidate + break + + # if albedo_path is not provided, try retrieve it from mtl + metallic_path = None + roughness_path = None + if mtl_path is not None and albedo_path is None: + with open(mtl_path, "r") as f: + lines = f.readlines() + + for line in lines: + split_line = line.split() + # empty line + if len(split_line) == 0: + continue + prefix = split_line[0] + + if "map_Kd" in prefix: + # assume relative path! + albedo_path = os.path.join(os.path.dirname(path), split_line[1]) + print(f"[load_obj] use texture from: {albedo_path}") + elif "map_Pm" in prefix: + metallic_path = os.path.join(os.path.dirname(path), split_line[1]) + elif "map_Pr" in prefix: + roughness_path = os.path.join(os.path.dirname(path), split_line[1]) + + # still not found albedo_path, or the path doesn't exist + if albedo_path is None or not os.path.exists(albedo_path): + # init an empty texture + print(f"[load_obj] init empty albedo!") + # albedo = np.random.rand(1024, 1024, 3).astype(np.float32) + albedo = np.ones((1024, 1024, 3), dtype=np.float32) * np.array([0.5, 0.5, 0.5]) # default color + else: + albedo = cv2.imread(albedo_path, cv2.IMREAD_UNCHANGED) + albedo = cv2.cvtColor(albedo, cv2.COLOR_BGR2RGB) + albedo = albedo.astype(np.float32) / 255 + print(f"[load_obj] load texture: {albedo.shape}") + + mesh.albedo = torch.tensor(albedo, dtype=torch.float32, device=device) + + # try to load metallic and roughness + if metallic_path is not None and roughness_path is not None: + print(f"[load_obj] load metallicRoughness from: {metallic_path}, {roughness_path}") + metallic = cv2.imread(metallic_path, cv2.IMREAD_UNCHANGED) + metallic = metallic.astype(np.float32) / 255 + roughness = cv2.imread(roughness_path, cv2.IMREAD_UNCHANGED) + roughness = roughness.astype(np.float32) / 255 + metallicRoughness = np.stack([np.zeros_like(metallic), roughness, metallic], axis=-1) + + mesh.metallicRoughness = torch.tensor(metallicRoughness, dtype=torch.float32, device=device).contiguous() + + return mesh + + @classmethod + def load_trimesh(cls, path, device=None): + """load a mesh using ``trimesh.load()``. + + Can load various formats like ``glb`` and serves as a fallback. + + Note: + We will try to merge all meshes if the glb contains more than one, + but **this may cause the texture to lose**, since we only support one texture image! + + Args: + path (str): path to the mesh file. + device (torch.device, optional): torch device. Defaults to None. + + Returns: + Mesh: the loaded Mesh object. + """ + mesh = cls() + + # device + if device is None: + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + mesh.device = device + + # use trimesh to load ply/glb + _data = trimesh.load(path) + if isinstance(_data, trimesh.Scene): + if len(_data.geometry) == 1: + _mesh = list(_data.geometry.values())[0] + else: + print(f"[load_trimesh] concatenating {len(_data.geometry)} meshes.") + _concat = [] + # loop the scene graph and apply transform to each mesh + scene_graph = _data.graph.to_flattened() # dict {name: {transform: 4x4 mat, geometry: str}} + for k, v in scene_graph.items(): + name = v['geometry'] + if name in _data.geometry and isinstance(_data.geometry[name], trimesh.Trimesh): + transform = v['transform'] + _concat.append(_data.geometry[name].apply_transform(transform)) + _mesh = trimesh.util.concatenate(_concat) + else: + _mesh = _data + + if _mesh.visual.kind == 'vertex': + vertex_colors = _mesh.visual.vertex_colors + vertex_colors = np.array(vertex_colors[..., :3]).astype(np.float32) / 255 + mesh.vc = torch.tensor(vertex_colors, dtype=torch.float32, device=device) + print(f"[load_trimesh] use vertex color: {mesh.vc.shape}") + elif _mesh.visual.kind == 'texture': + _material = _mesh.visual.material + if isinstance(_material, trimesh.visual.material.PBRMaterial): + texture = np.array(_material.baseColorTexture).astype(np.float32) / 255 + # load metallicRoughness if present + if _material.metallicRoughnessTexture is not None: + metallicRoughness = np.array(_material.metallicRoughnessTexture).astype(np.float32) / 255 + mesh.metallicRoughness = torch.tensor(metallicRoughness, dtype=torch.float32, device=device).contiguous() + elif isinstance(_material, trimesh.visual.material.SimpleMaterial): + texture = np.array(_material.to_pbr().baseColorTexture).astype(np.float32) / 255 + else: + raise NotImplementedError(f"material type {type(_material)} not supported!") + mesh.albedo = torch.tensor(texture[..., :3], dtype=torch.float32, device=device).contiguous() + print(f"[load_trimesh] load texture: {texture.shape}") + else: + texture = np.ones((1024, 1024, 3), dtype=np.float32) * np.array([0.5, 0.5, 0.5]) + mesh.albedo = torch.tensor(texture, dtype=torch.float32, device=device) + print(f"[load_trimesh] failed to load texture.") + + vertices = _mesh.vertices + + try: + texcoords = _mesh.visual.uv + texcoords[:, 1] = 1 - texcoords[:, 1] + except Exception as e: + texcoords = None + + try: + normals = _mesh.vertex_normals + except Exception as e: + normals = None + + # trimesh only support vertex uv... + faces = tfaces = nfaces = _mesh.faces + + mesh.v = torch.tensor(vertices, dtype=torch.float32, device=device) + mesh.vt = ( + torch.tensor(texcoords, dtype=torch.float32, device=device) + if texcoords is not None + else None + ) + mesh.vn = ( + torch.tensor(normals, dtype=torch.float32, device=device) + if normals is not None + else None + ) + + mesh.f = torch.tensor(faces, dtype=torch.int32, device=device) + mesh.ft = ( + torch.tensor(tfaces, dtype=torch.int32, device=device) + if texcoords is not None + else None + ) + mesh.fn = ( + torch.tensor(nfaces, dtype=torch.int32, device=device) + if normals is not None + else None + ) + + return mesh + + # sample surface (using trimesh) + def sample_surface(self, count: int): + """sample points on the surface of the mesh. + + Args: + count (int): number of points to sample. + + Returns: + torch.Tensor: the sampled points, float [count, 3]. + """ + _mesh = trimesh.Trimesh(vertices=self.v.detach().cpu().numpy(), faces=self.f.detach().cpu().numpy()) + points, face_idx = trimesh.sample.sample_surface(_mesh, count) + points = torch.from_numpy(points).float().to(self.device) + return points + + # aabb + def aabb(self): + """get the axis-aligned bounding box of the mesh. + + Returns: + Tuple[torch.Tensor]: the min xyz and max xyz of the mesh. + """ + return torch.min(self.v, dim=0).values, torch.max(self.v, dim=0).values + + # unit size + @torch.no_grad() + def auto_size(self, bound=0.9): + """auto resize the mesh. + + Args: + bound (float, optional): resizing into ``[-bound, bound]^3``. Defaults to 0.9. + """ + vmin, vmax = self.aabb() + self.ori_center = (vmax + vmin) / 2 + self.ori_scale = 2 * bound / torch.max(vmax - vmin).item() + self.v = (self.v - self.ori_center) * self.ori_scale + + def auto_normal(self): + """auto calculate the vertex normals. + """ + i0, i1, i2 = self.f[:, 0].long(), self.f[:, 1].long(), self.f[:, 2].long() + v0, v1, v2 = self.v[i0, :], self.v[i1, :], self.v[i2, :] + + face_normals = torch.cross(v1 - v0, v2 - v0) + + # Splat face normals to vertices + vn = torch.zeros_like(self.v) + vn.scatter_add_(0, i0[:, None].repeat(1, 3), face_normals) + vn.scatter_add_(0, i1[:, None].repeat(1, 3), face_normals) + vn.scatter_add_(0, i2[:, None].repeat(1, 3), face_normals) + + # Normalize, replace zero (degenerated) normals with some default value + vn = torch.where( + dot(vn, vn) > 1e-20, + vn, + torch.tensor([0.0, 0.0, 1.0], dtype=torch.float32, device=vn.device), + ) + vn = safe_normalize(vn) + + self.vn = vn + self.fn = self.f + + def auto_uv(self, cache_path=None, vmap=True): + """auto calculate the uv coordinates. + + Args: + cache_path (str, optional): path to save/load the uv cache as a npz file, this can avoid calculating uv every time when loading the same mesh, which is time-consuming. Defaults to None. + vmap (bool, optional): remap vertices based on uv coordinates, so each v correspond to a unique vt (necessary for formats like gltf). + Usually this will duplicate the vertices on the edge of uv atlas. Defaults to True. + """ + # try to load cache + if cache_path is not None: + cache_path = os.path.splitext(cache_path)[0] + "_uv.npz" + if cache_path is not None and os.path.exists(cache_path): + data = np.load(cache_path) + vt_np, ft_np, vmapping = data["vt"], data["ft"], data["vmapping"] + else: + import xatlas + + v_np = self.v.detach().cpu().numpy() + f_np = self.f.detach().int().cpu().numpy() + atlas = xatlas.Atlas() + atlas.add_mesh(v_np, f_np) + chart_options = xatlas.ChartOptions() + # chart_options.max_iterations = 4 + atlas.generate(chart_options=chart_options) + vmapping, ft_np, vt_np = atlas[0] # [N], [M, 3], [N, 2] + + # save to cache + if cache_path is not None: + np.savez(cache_path, vt=vt_np, ft=ft_np, vmapping=vmapping) + + vt = torch.from_numpy(vt_np.astype(np.float32)).to(self.device) + ft = torch.from_numpy(ft_np.astype(np.int32)).to(self.device) + self.vt = vt + self.ft = ft + + if vmap: + vmapping = torch.from_numpy(vmapping.astype(np.int64)).long().to(self.device) + self.align_v_to_vt(vmapping) + + def align_v_to_vt(self, vmapping=None): + """ remap v/f and vn/fn to vt/ft. + + Args: + vmapping (np.ndarray, optional): the mapping relationship from f to ft. Defaults to None. + """ + if vmapping is None: + ft = self.ft.view(-1).long() + f = self.f.view(-1).long() + vmapping = torch.zeros(self.vt.shape[0], dtype=torch.long, device=self.device) + vmapping[ft] = f # scatter, randomly choose one if index is not unique + + self.v = self.v[vmapping] + self.f = self.ft + + if self.vn is not None: + self.vn = self.vn[vmapping] + self.fn = self.ft + + def to(self, device): + """move all tensor attributes to device. + + Args: + device (torch.device): target device. + + Returns: + Mesh: self. + """ + self.device = device + for name in ["v", "f", "vn", "fn", "vt", "ft", "albedo", "vc", "metallicRoughness"]: + tensor = getattr(self, name) + if tensor is not None: + setattr(self, name, tensor.to(device)) + return self + + def write(self, path): + """write the mesh to a path. + + Args: + path (str): path to write, supports ply, obj and glb. + """ + if path.endswith(".ply"): + self.write_ply(path) + elif path.endswith(".obj"): + self.write_obj(path) + elif path.endswith(".glb") or path.endswith(".gltf"): + self.write_glb(path) + else: + raise NotImplementedError(f"format {path} not supported!") + + def write_ply(self, path): + """write the mesh in ply format. Only for geometry! + + Args: + path (str): path to write. + """ + + if self.albedo is not None: + print(f'[WARN] ply format does not support exporting texture, will ignore!') + + v_np = self.v.detach().cpu().numpy() + f_np = self.f.detach().cpu().numpy() + + _mesh = trimesh.Trimesh(vertices=v_np, faces=f_np) + _mesh.export(path) + + + def write_glb(self, path): + """write the mesh in glb/gltf format. + This will create a scene with a single mesh. + + Args: + path (str): path to write. + """ + + # assert self.v.shape[0] == self.vn.shape[0] and self.v.shape[0] == self.vt.shape[0] + if self.vt is not None and self.v.shape[0] != self.vt.shape[0]: + self.align_v_to_vt() + + import pygltflib + + f_np = self.f.detach().cpu().numpy().astype(np.uint32) + f_np_blob = f_np.flatten().tobytes() + + v_np = self.v.detach().cpu().numpy().astype(np.float32) + v_np_blob = v_np.tobytes() + + blob = f_np_blob + v_np_blob + byteOffset = len(blob) + + # base mesh + gltf = pygltflib.GLTF2( + scene=0, + scenes=[pygltflib.Scene(nodes=[0])], + nodes=[pygltflib.Node(mesh=0)], + meshes=[pygltflib.Mesh(primitives=[pygltflib.Primitive( + # indices to accessors (0 is triangles) + attributes=pygltflib.Attributes( + POSITION=1, + ), + indices=0, + )])], + buffers=[ + pygltflib.Buffer(byteLength=len(f_np_blob) + len(v_np_blob)) + ], + # buffer view (based on dtype) + bufferViews=[ + # triangles; as flatten (element) array + pygltflib.BufferView( + buffer=0, + byteLength=len(f_np_blob), + target=pygltflib.ELEMENT_ARRAY_BUFFER, # GL_ELEMENT_ARRAY_BUFFER (34963) + ), + # positions; as vec3 array + pygltflib.BufferView( + buffer=0, + byteOffset=len(f_np_blob), + byteLength=len(v_np_blob), + byteStride=12, # vec3 + target=pygltflib.ARRAY_BUFFER, # GL_ARRAY_BUFFER (34962) + ), + ], + accessors=[ + # 0 = triangles + pygltflib.Accessor( + bufferView=0, + componentType=pygltflib.UNSIGNED_INT, # GL_UNSIGNED_INT (5125) + count=f_np.size, + type=pygltflib.SCALAR, + max=[int(f_np.max())], + min=[int(f_np.min())], + ), + # 1 = positions + pygltflib.Accessor( + bufferView=1, + componentType=pygltflib.FLOAT, # GL_FLOAT (5126) + count=len(v_np), + type=pygltflib.VEC3, + max=v_np.max(axis=0).tolist(), + min=v_np.min(axis=0).tolist(), + ), + ], + ) + + # append texture info + if self.vt is not None: + + vt_np = self.vt.detach().cpu().numpy().astype(np.float32) + vt_np_blob = vt_np.tobytes() + + albedo = self.albedo.detach().cpu().numpy() + albedo = (albedo * 255).astype(np.uint8) + albedo = cv2.cvtColor(albedo, cv2.COLOR_RGB2BGR) + albedo_blob = cv2.imencode('.png', albedo)[1].tobytes() + + # update primitive + gltf.meshes[0].primitives[0].attributes.TEXCOORD_0 = 2 + gltf.meshes[0].primitives[0].material = 0 + + # update materials + gltf.materials.append(pygltflib.Material( + pbrMetallicRoughness=pygltflib.PbrMetallicRoughness( + baseColorTexture=pygltflib.TextureInfo(index=0, texCoord=0), + metallicFactor=0.0, + roughnessFactor=1.0, + ), + alphaMode=pygltflib.OPAQUE, + alphaCutoff=None, + doubleSided=True, + )) + + gltf.textures.append(pygltflib.Texture(sampler=0, source=0)) + gltf.samplers.append(pygltflib.Sampler(magFilter=pygltflib.LINEAR, minFilter=pygltflib.LINEAR_MIPMAP_LINEAR, wrapS=pygltflib.REPEAT, wrapT=pygltflib.REPEAT)) + gltf.images.append(pygltflib.Image(bufferView=3, mimeType="image/png")) + + # update buffers + gltf.bufferViews.append( + # index = 2, texcoords; as vec2 array + pygltflib.BufferView( + buffer=0, + byteOffset=byteOffset, + byteLength=len(vt_np_blob), + byteStride=8, # vec2 + target=pygltflib.ARRAY_BUFFER, + ) + ) + + gltf.accessors.append( + # 2 = texcoords + pygltflib.Accessor( + bufferView=2, + componentType=pygltflib.FLOAT, + count=len(vt_np), + type=pygltflib.VEC2, + max=vt_np.max(axis=0).tolist(), + min=vt_np.min(axis=0).tolist(), + ) + ) + + blob += vt_np_blob + byteOffset += len(vt_np_blob) + + gltf.bufferViews.append( + # index = 3, albedo texture; as none target + pygltflib.BufferView( + buffer=0, + byteOffset=byteOffset, + byteLength=len(albedo_blob), + ) + ) + + blob += albedo_blob + byteOffset += len(albedo_blob) + + gltf.buffers[0].byteLength = byteOffset + + # append metllic roughness + if self.metallicRoughness is not None: + metallicRoughness = self.metallicRoughness.detach().cpu().numpy() + metallicRoughness = (metallicRoughness * 255).astype(np.uint8) + metallicRoughness = cv2.cvtColor(metallicRoughness, cv2.COLOR_RGB2BGR) + metallicRoughness_blob = cv2.imencode('.png', metallicRoughness)[1].tobytes() + + # update texture definition + gltf.materials[0].pbrMetallicRoughness.metallicFactor = 1.0 + gltf.materials[0].pbrMetallicRoughness.roughnessFactor = 1.0 + gltf.materials[0].pbrMetallicRoughness.metallicRoughnessTexture = pygltflib.TextureInfo(index=1, texCoord=0) + + gltf.textures.append(pygltflib.Texture(sampler=1, source=1)) + gltf.samplers.append(pygltflib.Sampler(magFilter=pygltflib.LINEAR, minFilter=pygltflib.LINEAR_MIPMAP_LINEAR, wrapS=pygltflib.REPEAT, wrapT=pygltflib.REPEAT)) + gltf.images.append(pygltflib.Image(bufferView=4, mimeType="image/png")) + + # update buffers + gltf.bufferViews.append( + # index = 4, metallicRoughness texture; as none target + pygltflib.BufferView( + buffer=0, + byteOffset=byteOffset, + byteLength=len(metallicRoughness_blob), + ) + ) + + blob += metallicRoughness_blob + byteOffset += len(metallicRoughness_blob) + + gltf.buffers[0].byteLength = byteOffset + + + # set actual data + gltf.set_binary_blob(blob) + + # glb = b"".join(gltf.save_to_bytes()) + gltf.save(path) + + + def write_obj(self, path): + """write the mesh in obj format. Will also write the texture and mtl files. + + Args: + path (str): path to write. + """ + + mtl_path = path.replace(".obj", ".mtl") + albedo_path = path.replace(".obj", "_albedo.png") + metallic_path = path.replace(".obj", "_metallic.png") + roughness_path = path.replace(".obj", "_roughness.png") + + v_np = self.v.detach().cpu().numpy() + vt_np = self.vt.detach().cpu().numpy() if self.vt is not None else None + vn_np = self.vn.detach().cpu().numpy() if self.vn is not None else None + f_np = self.f.detach().cpu().numpy() + ft_np = self.ft.detach().cpu().numpy() if self.ft is not None else None + fn_np = self.fn.detach().cpu().numpy() if self.fn is not None else None + + with open(path, "w") as fp: + fp.write(f"mtllib {os.path.basename(mtl_path)} \n") + + for v in v_np: + fp.write(f"v {v[0]} {v[1]} {v[2]} \n") + + if vt_np is not None: + for v in vt_np: + fp.write(f"vt {v[0]} {1 - v[1]} \n") + + if vn_np is not None: + for v in vn_np: + fp.write(f"vn {v[0]} {v[1]} {v[2]} \n") + + fp.write(f"usemtl defaultMat \n") + for i in range(len(f_np)): + fp.write( + f'f {f_np[i, 0] + 1}/{ft_np[i, 0] + 1 if ft_np is not None else ""}/{fn_np[i, 0] + 1 if fn_np is not None else ""} \ + {f_np[i, 1] + 1}/{ft_np[i, 1] + 1 if ft_np is not None else ""}/{fn_np[i, 1] + 1 if fn_np is not None else ""} \ + {f_np[i, 2] + 1}/{ft_np[i, 2] + 1 if ft_np is not None else ""}/{fn_np[i, 2] + 1 if fn_np is not None else ""} \n' + ) + + with open(mtl_path, "w") as fp: + fp.write(f"newmtl defaultMat \n") + fp.write(f"Ka 1 1 1 \n") + fp.write(f"Kd 1 1 1 \n") + fp.write(f"Ks 0 0 0 \n") + fp.write(f"Tr 1 \n") + fp.write(f"illum 1 \n") + fp.write(f"Ns 0 \n") + if self.albedo is not None: + fp.write(f"map_Kd {os.path.basename(albedo_path)} \n") + if self.metallicRoughness is not None: + # ref: https://en.wikipedia.org/wiki/Wavefront_.obj_file#Physically-based_Rendering + fp.write(f"map_Pm {os.path.basename(metallic_path)} \n") + fp.write(f"map_Pr {os.path.basename(roughness_path)} \n") + + if self.albedo is not None: + albedo = self.albedo.detach().cpu().numpy() + albedo = (albedo * 255).astype(np.uint8) + cv2.imwrite(albedo_path, cv2.cvtColor(albedo, cv2.COLOR_RGB2BGR)) + + if self.metallicRoughness is not None: + metallicRoughness = self.metallicRoughness.detach().cpu().numpy() + metallicRoughness = (metallicRoughness * 255).astype(np.uint8) + cv2.imwrite(metallic_path, metallicRoughness[..., 2]) + cv2.imwrite(roughness_path, metallicRoughness[..., 1]) + diff --git a/apps/third_party/CRM/model/__init__.py b/apps/third_party/CRM/model/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b339e3ea9dac5482a6daed63b069e4d1eda000a8 --- /dev/null +++ b/apps/third_party/CRM/model/__init__.py @@ -0,0 +1 @@ +from model.crm.model import CRM \ No newline at end of file diff --git a/apps/third_party/CRM/model/archs/__init__.py b/apps/third_party/CRM/model/archs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/model/archs/decoders/__init__.py b/apps/third_party/CRM/model/archs/decoders/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d3f5a12faa99758192ecc4ed3fc22c9249232e86 --- /dev/null +++ b/apps/third_party/CRM/model/archs/decoders/__init__.py @@ -0,0 +1 @@ + diff --git a/apps/third_party/CRM/model/archs/decoders/shape_texture_net.py b/apps/third_party/CRM/model/archs/decoders/shape_texture_net.py new file mode 100644 index 0000000000000000000000000000000000000000..5e5ddd78215b9f48b281757a91b8de6f73e4742a --- /dev/null +++ b/apps/third_party/CRM/model/archs/decoders/shape_texture_net.py @@ -0,0 +1,62 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class TetTexNet(nn.Module): + def __init__(self, plane_reso=64, padding=0.1, fea_concat=True): + super().__init__() + # self.c_dim = c_dim + self.plane_reso = plane_reso + self.padding = padding + self.fea_concat = fea_concat + + def forward(self, rolled_out_feature, query): + # rolled_out_feature: rolled-out triplane feature + # query: queried xyz coordinates (should be scaled consistently to ptr cloud) + + plane_reso = self.plane_reso + + triplane_feature = dict() + triplane_feature['xy'] = rolled_out_feature[:, :, :, 0: plane_reso] + triplane_feature['yz'] = rolled_out_feature[:, :, :, plane_reso: 2 * plane_reso] + triplane_feature['zx'] = rolled_out_feature[:, :, :, 2 * plane_reso:] + + query_feature_xy = self.sample_plane_feature(query, triplane_feature['xy'], 'xy') + query_feature_yz = self.sample_plane_feature(query, triplane_feature['yz'], 'yz') + query_feature_zx = self.sample_plane_feature(query, triplane_feature['zx'], 'zx') + + if self.fea_concat: + query_feature = torch.cat((query_feature_xy, query_feature_yz, query_feature_zx), dim=1) + else: + query_feature = query_feature_xy + query_feature_yz + query_feature_zx + + output = query_feature.permute(0, 2, 1) + + return output + + # uses values from plane_feature and pixel locations from vgrid to interpolate feature + def sample_plane_feature(self, query, plane_feature, plane): + # CYF note: + # for pretraining, query are uniformly sampled positions w.i. [-scale, scale] + # for training, query are essentially tetrahedra grid vertices, which are + # also within [-scale, scale] in the current version! + # xy range [-scale, scale] + if plane == 'xy': + xy = query[:, :, [0, 1]] + elif plane == 'yz': + xy = query[:, :, [1, 2]] + elif plane == 'zx': + xy = query[:, :, [2, 0]] + else: + raise ValueError("Error! Invalid plane type!") + + xy = xy[:, :, None].float() + # not seem necessary to rescale the grid, because from + # https://pytorch.org/docs/stable/generated/torch.nn.functional.grid_sample.html, + # it specifies sampling locations normalized by plane_feature's spatial dimension, + # which is within [-scale, scale] as specified by encoder's calling of coordinate2index() + vgrid = 1.0 * xy + sampled_feat = F.grid_sample(plane_feature, vgrid, padding_mode='border', align_corners=True, mode='bilinear').squeeze(-1) + + return sampled_feat diff --git a/apps/third_party/CRM/model/archs/mlp_head.py b/apps/third_party/CRM/model/archs/mlp_head.py new file mode 100644 index 0000000000000000000000000000000000000000..33d7dcdbf58374dd036d9f3f5f0bfd3f248e845b --- /dev/null +++ b/apps/third_party/CRM/model/archs/mlp_head.py @@ -0,0 +1,40 @@ +import torch.nn as nn +import torch.nn.functional as F + + +class SdfMlp(nn.Module): + def __init__(self, input_dim, hidden_dim=512, bias=True): + super().__init__() + self.input_dim = input_dim + self.hidden_dim = hidden_dim + + self.fc1 = nn.Linear(input_dim, hidden_dim, bias=bias) + self.fc2 = nn.Linear(hidden_dim, hidden_dim, bias=bias) + self.fc3 = nn.Linear(hidden_dim, 4, bias=bias) + + + def forward(self, input): + x = F.relu(self.fc1(input)) + x = F.relu(self.fc2(x)) + out = self.fc3(x) + return out + + +class RgbMlp(nn.Module): + def __init__(self, input_dim, hidden_dim=512, bias=True): + super().__init__() + self.input_dim = input_dim + self.hidden_dim = hidden_dim + + self.fc1 = nn.Linear(input_dim, hidden_dim, bias=bias) + self.fc2 = nn.Linear(hidden_dim, hidden_dim, bias=bias) + self.fc3 = nn.Linear(hidden_dim, 3, bias=bias) + + def forward(self, input): + x = F.relu(self.fc1(input)) + x = F.relu(self.fc2(x)) + out = self.fc3(x) + + return out + + \ No newline at end of file diff --git a/apps/third_party/CRM/model/archs/unet.py b/apps/third_party/CRM/model/archs/unet.py new file mode 100644 index 0000000000000000000000000000000000000000..e427c18b1bed00089e87fe25b0e810042538d6b3 --- /dev/null +++ b/apps/third_party/CRM/model/archs/unet.py @@ -0,0 +1,53 @@ +''' +Codes are from: +https://github.com/jaxony/unet-pytorch/blob/master/model.py +''' + +import torch +import torch.nn as nn +from diffusers import UNet2DModel +import einops +class UNetPP(nn.Module): + ''' + Wrapper for UNet in diffusers + ''' + def __init__(self, in_channels): + super(UNetPP, self).__init__() + self.in_channels = in_channels + self.unet = UNet2DModel( + sample_size=[256, 256*3], + in_channels=in_channels, + out_channels=32, + layers_per_block=2, + block_out_channels=(64, 128, 128, 128*2, 128*2, 128*4, 128*4), + down_block_types=( + "DownBlock2D", + "DownBlock2D", + "DownBlock2D", + "AttnDownBlock2D", + "AttnDownBlock2D", + "AttnDownBlock2D", + "DownBlock2D", + ), + up_block_types=( + "UpBlock2D", + "AttnUpBlock2D", + "AttnUpBlock2D", + "AttnUpBlock2D", + "UpBlock2D", + "UpBlock2D", + "UpBlock2D", + ), + ) + + self.unet.enable_xformers_memory_efficient_attention() + if in_channels > 12: + self.learned_plane = torch.nn.parameter.Parameter(torch.zeros([1,in_channels-12,256,256*3])) + + def forward(self, x, t=256): + learned_plane = self.learned_plane + if x.shape[1] < self.in_channels: + learned_plane = einops.repeat(learned_plane, '1 C H W -> B C H W', B=x.shape[0]).to(x.device) + x = torch.cat([x, learned_plane], dim = 1) + return self.unet(x, t).sample + diff --git a/apps/third_party/CRM/model/crm/model.py b/apps/third_party/CRM/model/crm/model.py new file mode 100644 index 0000000000000000000000000000000000000000..9eb164266a0c23295ab3451d99d720ec12afa468 --- /dev/null +++ b/apps/third_party/CRM/model/crm/model.py @@ -0,0 +1,213 @@ +import torch.nn as nn +import torch +import torch.nn.functional as F + +import numpy as np + + +from pathlib import Path +import cv2 +import trimesh +import nvdiffrast.torch as dr + +from model.archs.decoders.shape_texture_net import TetTexNet +from model.archs.unet import UNetPP +from util.renderer import Renderer +from model.archs.mlp_head import SdfMlp, RgbMlp +import xatlas + + +class Dummy: + pass + +class CRM(nn.Module): + def __init__(self, specs): + super(CRM, self).__init__() + + self.specs = specs + # configs + input_specs = specs["Input"] + self.input = Dummy() + self.input.scale = input_specs['scale'] + self.input.resolution = input_specs['resolution'] + self.tet_grid_size = input_specs['tet_grid_size'] + self.camera_angle_num = input_specs['camera_angle_num'] + + self.arch = Dummy() + self.arch.fea_concat = specs["ArchSpecs"]["fea_concat"] + self.arch.mlp_bias = specs["ArchSpecs"]["mlp_bias"] + + self.dec = Dummy() + self.dec.c_dim = specs["DecoderSpecs"]["c_dim"] + self.dec.plane_resolution = specs["DecoderSpecs"]["plane_resolution"] + + self.geo_type = specs["Train"].get("geo_type", "flex") # "dmtet" or "flex" + + self.unet2 = UNetPP(in_channels=self.dec.c_dim) + + mlp_chnl_s = 3 if self.arch.fea_concat else 1 # 3 for queried triplane feature concatenation + self.decoder = TetTexNet(plane_reso=self.dec.plane_resolution, fea_concat=self.arch.fea_concat) + + if self.geo_type == "flex": + self.weightMlp = nn.Sequential( + nn.Linear(mlp_chnl_s * 32 * 8, 512), + nn.SiLU(), + nn.Linear(512, 21)) + + self.sdfMlp = SdfMlp(mlp_chnl_s * 32, 512, bias=self.arch.mlp_bias) + self.rgbMlp = RgbMlp(mlp_chnl_s * 32, 512, bias=self.arch.mlp_bias) + self.renderer = Renderer(tet_grid_size=self.tet_grid_size, camera_angle_num=self.camera_angle_num, + scale=self.input.scale, geo_type = self.geo_type) + + + self.spob = True if specs['Pretrain']['mode'] is None else False # whether to add sphere + self.radius = specs['Pretrain']['radius'] # used when spob + + self.denoising = True + from diffusers import DDIMScheduler + self.scheduler = DDIMScheduler.from_pretrained("stabilityai/stable-diffusion-2-1-base", subfolder="scheduler") + + def decode(self, data, triplane_feature2): + if self.geo_type == "flex": + tet_verts = self.renderer.flexicubes.verts.unsqueeze(0) + tet_indices = self.renderer.flexicubes.indices + + dec_verts = self.decoder(triplane_feature2, tet_verts) + out = self.sdfMlp(dec_verts) + + weight = None + if self.geo_type == "flex": + grid_feat = torch.index_select(input=dec_verts, index=self.renderer.flexicubes.indices.reshape(-1),dim=1) + grid_feat = grid_feat.reshape(dec_verts.shape[0], self.renderer.flexicubes.indices.shape[0], self.renderer.flexicubes.indices.shape[1] * dec_verts.shape[-1]) + weight = self.weightMlp(grid_feat) + weight = weight * 0.1 + + pred_sdf, deformation = out[..., 0], out[..., 1:] + if self.spob: + pred_sdf = pred_sdf + self.radius - torch.sqrt((tet_verts**2).sum(-1)) + + _, verts, faces = self.renderer(data, pred_sdf, deformation, tet_verts, tet_indices, weight= weight) + return verts[0].unsqueeze(0), faces[0].int() + + def export_mesh(self, data, out_dir, ind, device=None, tri_fea_2 = None): + verts = data['verts'] + faces = data['faces'] + + dec_verts = self.decoder(tri_fea_2, verts.unsqueeze(0)) + colors = self.rgbMlp(dec_verts).squeeze().detach().cpu().numpy() + # Expect predicted colors value range from [-1, 1] + colors = (colors * 0.5 + 0.5).clip(0, 1) + + verts = verts.squeeze().cpu().numpy() + faces = faces[..., [2, 1, 0]].squeeze().cpu().numpy() + + # export the final mesh + with torch.no_grad(): + mesh = trimesh.Trimesh(verts, faces, vertex_colors=colors, process=False) # important, process=True leads to seg fault... + mesh.export(out_dir / f'{ind}.obj') + + def export_mesh_wt_uv(self, ctx, data, out_dir, ind, device, res, tri_fea_2=None): + + mesh_v = data['verts'].squeeze().cpu().numpy() + mesh_pos_idx = data['faces'].squeeze().cpu().numpy() + + def interpolate(attr, rast, attr_idx, rast_db=None): + return dr.interpolate(attr.contiguous(), rast, attr_idx, rast_db=rast_db, + diff_attrs=None if rast_db is None else 'all') + + vmapping, indices, uvs = xatlas.parametrize(mesh_v, mesh_pos_idx) + + mesh_v = torch.tensor(mesh_v, dtype=torch.float32, device=device) + mesh_pos_idx = torch.tensor(mesh_pos_idx, dtype=torch.int64, device=device) + + # Convert to tensors + indices_int64 = indices.astype(np.uint64, casting='same_kind').view(np.int64) + + uvs = torch.tensor(uvs, dtype=torch.float32, device=mesh_v.device) + mesh_tex_idx = torch.tensor(indices_int64, dtype=torch.int64, device=mesh_v.device) + # mesh_v_tex. ture + uv_clip = uvs[None, ...] * 2.0 - 1.0 + + # pad to four component coordinate + uv_clip4 = torch.cat((uv_clip, torch.zeros_like(uv_clip[..., 0:1]), torch.ones_like(uv_clip[..., 0:1])), dim=-1) + + # rasterize + rast, _ = dr.rasterize(ctx, uv_clip4, mesh_tex_idx.int(), res) + + # Interpolate world space position + gb_pos, _ = interpolate(mesh_v[None, ...], rast, mesh_pos_idx.int()) + mask = rast[..., 3:4] > 0 + + # return uvs, mesh_tex_idx, gb_pos, mask + gb_pos_unsqz = gb_pos.view(-1, 3) + mask_unsqz = mask.view(-1) + tex_unsqz = torch.zeros_like(gb_pos_unsqz) + 1 + + gb_mask_pos = gb_pos_unsqz[mask_unsqz] + + gb_mask_pos = gb_mask_pos[None, ] + + with torch.no_grad(): + + dec_verts = self.decoder(tri_fea_2, gb_mask_pos) + colors = self.rgbMlp(dec_verts).squeeze() + + # Expect predicted colors value range from [-1, 1] + lo, hi = (-1, 1) + colors = (colors - lo) * (255 / (hi - lo)) + colors = colors.clip(0, 255) + + tex_unsqz[mask_unsqz] = colors + + tex = tex_unsqz.view(res + (3,)) + + verts = mesh_v.squeeze().cpu().numpy() + faces = mesh_pos_idx[..., [2, 1, 0]].squeeze().cpu().numpy() + # faces = mesh_pos_idx + # faces = faces.detach().cpu().numpy() + # faces = faces[..., [2, 1, 0]] + indices = indices[..., [2, 1, 0]] + + # xatlas.export(f"{out_dir}/{ind}.obj", verts[vmapping], indices, uvs) + matname = f'{out_dir}.mtl' + # matname = f'{out_dir}/{ind}.mtl' + fid = open(matname, 'w') + fid.write('newmtl material_0\n') + fid.write('Kd 1 1 1\n') + fid.write('Ka 1 1 1\n') + # fid.write('Ks 0 0 0\n') + fid.write('Ks 0.4 0.4 0.4\n') + fid.write('Ns 10\n') + fid.write('illum 2\n') + fid.write(f'map_Kd {out_dir.split("/")[-1]}.png\n') + fid.close() + + fid = open(f'{out_dir}.obj', 'w') + # fid = open(f'{out_dir}/{ind}.obj', 'w') + fid.write('mtllib %s.mtl\n' % out_dir.split("/")[-1]) + + for pidx, p in enumerate(verts): + pp = p + fid.write('v %f %f %f\n' % (pp[0], pp[2], - pp[1])) + + for pidx, p in enumerate(uvs): + pp = p + fid.write('vt %f %f\n' % (pp[0], 1 - pp[1])) + + fid.write('usemtl material_0\n') + for i, f in enumerate(faces): + f1 = f + 1 + f2 = indices[i] + 1 + fid.write('f %d/%d %d/%d %d/%d\n' % (f1[0], f2[0], f1[1], f2[1], f1[2], f2[2])) + fid.close() + + img = np.asarray(tex.data.cpu().numpy(), dtype=np.float32) + mask = np.sum(img.astype(float), axis=-1, keepdims=True) + mask = (mask <= 3.0).astype(float) + kernel = np.ones((3, 3), 'uint8') + dilate_img = cv2.dilate(img, kernel, iterations=1) + img = img * (1 - mask) + dilate_img * mask + img = img.clip(0, 255).astype(np.uint8) + + cv2.imwrite(f'{out_dir}.png', img[..., [2, 1, 0]]) + # cv2.imwrite(f'{out_dir}/{ind}.png', img[..., [2, 1, 0]]) diff --git a/apps/third_party/CRM/pipelines.py b/apps/third_party/CRM/pipelines.py new file mode 100644 index 0000000000000000000000000000000000000000..0882f64e8f2c66650355300c95d02529166f0628 --- /dev/null +++ b/apps/third_party/CRM/pipelines.py @@ -0,0 +1,216 @@ +import torch +import os +import sys +proj_dir = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(proj_dir) +from .libs.base_utils import do_resize_content +from .imagedream.ldm.util import ( + instantiate_from_config, + get_obj_from_str, +) +from omegaconf import OmegaConf +from PIL import Image +import PIL +import rembg +class TwoStagePipeline(object): + def __init__( + self, + stage1_model_config, + # stage2_model_config, + stage1_sampler_config, + # stage2_sampler_config, + device="cuda", + dtype=torch.float16, + resize_rate=1, + ) -> None: + """ + only for two stage generate process. + - the first stage was condition on single pixel image, gererate multi-view pixel image, based on the v2pp config + - the second stage was condition on multiview pixel image generated by the first stage, generate the final image, based on the stage2-test config + """ + self.resize_rate = resize_rate + + self.stage1_model = instantiate_from_config(OmegaConf.load(stage1_model_config.config).model) + self.stage1_model.load_state_dict(torch.load(stage1_model_config.resume, map_location="cpu"), strict=False) + self.stage1_model = self.stage1_model.to(device).to(dtype) + + # self.stage2_model = instantiate_from_config(OmegaConf.load(stage2_model_config.config).model) + # sd = torch.load(stage2_model_config.resume, map_location="cpu") + # self.stage2_model.load_state_dict(sd, strict=False) + # self.stage2_model = self.stage2_model.to(device).to(dtype) + + self.stage1_model.device = device + # self.stage2_model.device = device + self.device = device + self.dtype = dtype + self.stage1_sampler = get_obj_from_str(stage1_sampler_config.target)( + self.stage1_model, device=device, dtype=dtype, **stage1_sampler_config.params + ) + # self.stage2_sampler = get_obj_from_str(stage2_sampler_config.target)( + # self.stage2_model, device=device, dtype=dtype, **stage2_sampler_config.params + # ) + + def stage1_sample( + self, + pixel_img, + prompt="3D assets", + neg_texts="uniform low no texture ugly, boring, bad anatomy, blurry, pixelated, obscure, unnatural colors, poor lighting, dull, and unclear.", + step=50, + scale=5, + ddim_eta=0.0, + ): + if type(pixel_img) == str: + pixel_img = Image.open(pixel_img) + + if isinstance(pixel_img, Image.Image): + if pixel_img.mode == "RGBA": + background = Image.new('RGBA', pixel_img.size, (0, 0, 0, 0)) + pixel_img = Image.alpha_composite(background, pixel_img).convert("RGB") + else: + pixel_img = pixel_img.convert("RGB") + else: + raise + uc = self.stage1_sampler.model.get_learned_conditioning([neg_texts]).to(self.device) + stage1_images = self.stage1_sampler.i2i( + self.stage1_sampler.model, + self.stage1_sampler.size, + prompt, + uc=uc, + sampler=self.stage1_sampler.sampler, + ip=pixel_img, + step=step, + scale=scale, + batch_size=self.stage1_sampler.batch_size, + ddim_eta=ddim_eta, + dtype=self.stage1_sampler.dtype, + device=self.stage1_sampler.device, + camera=self.stage1_sampler.camera, + num_frames=self.stage1_sampler.num_frames, + pixel_control=(self.stage1_sampler.mode == "pixel"), + transform=self.stage1_sampler.image_transform, + offset_noise=self.stage1_sampler.offset_noise, + ) + + stage1_images = [Image.fromarray(img) for img in stage1_images] + stage1_images.pop(self.stage1_sampler.ref_position) + return stage1_images + + def stage2_sample(self, pixel_img, stage1_images, scale=5, step=50): + if type(pixel_img) == str: + pixel_img = Image.open(pixel_img) + + if isinstance(pixel_img, Image.Image): + if pixel_img.mode == "RGBA": + background = Image.new('RGBA', pixel_img.size, (0, 0, 0, 0)) + pixel_img = Image.alpha_composite(background, pixel_img).convert("RGB") + else: + pixel_img = pixel_img.convert("RGB") + else: + raise + stage2_images = self.stage2_sampler.i2iStage2( + self.stage2_sampler.model, + self.stage2_sampler.size, + "3D assets", + self.stage2_sampler.uc, + self.stage2_sampler.sampler, + pixel_images=stage1_images, + ip=pixel_img, + step=step, + scale=scale, + batch_size=self.stage2_sampler.batch_size, + ddim_eta=0.0, + dtype=self.stage2_sampler.dtype, + device=self.stage2_sampler.device, + camera=self.stage2_sampler.camera, + num_frames=self.stage2_sampler.num_frames, + pixel_control=(self.stage2_sampler.mode == "pixel"), + transform=self.stage2_sampler.image_transform, + offset_noise=self.stage2_sampler.offset_noise, + ) + stage2_images = [Image.fromarray(img) for img in stage2_images] + return stage2_images + + def set_seed(self, seed): + self.stage1_sampler.seed = seed + # self.stage2_sampler.seed = seed + + def __call__(self, pixel_img, prompt="3D assets", scale=5, step=50): + pixel_img = do_resize_content(pixel_img, self.resize_rate) + stage1_images = self.stage1_sample(pixel_img, prompt, scale=scale, step=step) + # stage2_images = self.stage2_sample(pixel_img, stage1_images, scale=scale, step=step) + + return { + "ref_img": pixel_img, + "stage1_images": stage1_images, + # "stage2_images": stage2_images, + } + +rembg_session = rembg.new_session() + +def expand_to_square(image, bg_color=(0, 0, 0, 0)): + # expand image to 1:1 + width, height = image.size + if width == height: + return image + new_size = (max(width, height), max(width, height)) + new_image = Image.new("RGBA", new_size, bg_color) + paste_position = ((new_size[0] - width) // 2, (new_size[1] - height) // 2) + new_image.paste(image, paste_position) + return new_image + +def remove_background( + image: PIL.Image.Image, + rembg_session = None, + force: bool = False, + **rembg_kwargs, +) -> PIL.Image.Image: + do_remove = True + if image.mode == "RGBA" and image.getextrema()[3][0] < 255: + # explain why current do not rm bg + print("alhpa channl not enpty, skip remove background, using alpha channel as mask") + background = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image = Image.alpha_composite(background, image) + do_remove = False + do_remove = do_remove or force + if do_remove: + image = rembg.remove(image, session=rembg_session, **rembg_kwargs) + return image + +def do_resize_content(original_image: Image, scale_rate): + # resize image content wile retain the original image size + if scale_rate != 1: + # Calculate the new size after rescaling + new_size = tuple(int(dim * scale_rate) for dim in original_image.size) + # Resize the image while maintaining the aspect ratio + resized_image = original_image.resize(new_size) + # Create a new image with the original size and black background + padded_image = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) + paste_position = ((original_image.width - resized_image.width) // 2, (original_image.height - resized_image.height) // 2) + padded_image.paste(resized_image, paste_position) + return padded_image + else: + return original_image + +def add_background(image, bg_color=(255, 255, 255)): + # given an RGBA image, alpha channel is used as mask to add background color + background = Image.new("RGBA", image.size, bg_color) + return Image.alpha_composite(background, image) + + +def preprocess_image(image, background_choice, foreground_ratio, backgroud_color): + """ + input image is a pil image in RGBA, return RGB image + """ + print(background_choice) + if background_choice == "Alpha as mask": + background = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image = Image.alpha_composite(background, image) + else: + image = remove_background(image, rembg_session, force_remove=True) + image = do_resize_content(image, foreground_ratio) + image = expand_to_square(image) + image = add_background(image, backgroud_color) + return image.convert("RGB") + + + diff --git a/apps/third_party/CRM/requirements.txt b/apps/third_party/CRM/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..8501f40d7ec31f64b3b6b77549fb2b7623f2d382 --- /dev/null +++ b/apps/third_party/CRM/requirements.txt @@ -0,0 +1,16 @@ +gradio +huggingface-hub +diffusers==0.24.0 +einops==0.7.0 +Pillow==10.1.0 +transformers==4.27.1 +open-clip-torch==2.7.0 +opencv-contrib-python-headless==4.9.0.80 +opencv-python-headless==4.9.0.80 +omegaconf +rembg +pygltflib +kiui +trimesh +xatlas +pymeshlab diff --git a/apps/third_party/CRM/run.py b/apps/third_party/CRM/run.py new file mode 100644 index 0000000000000000000000000000000000000000..8e14be6e7c7cb1d314d1e82a23a6d250e79ce3b7 --- /dev/null +++ b/apps/third_party/CRM/run.py @@ -0,0 +1,160 @@ +import torch +from libs.base_utils import do_resize_content +from imagedream.ldm.util import ( + instantiate_from_config, + get_obj_from_str, +) +from omegaconf import OmegaConf +from PIL import Image +import numpy as np +from inference import generate3d +from huggingface_hub import hf_hub_download +import json +import argparse +import shutil +from model import CRM +import PIL +import rembg +import os +from pipelines import TwoStagePipeline + +rembg_session = rembg.new_session() + +def expand_to_square(image, bg_color=(0, 0, 0, 0)): + # expand image to 1:1 + width, height = image.size + if width == height: + return image + new_size = (max(width, height), max(width, height)) + new_image = Image.new("RGBA", new_size, bg_color) + paste_position = ((new_size[0] - width) // 2, (new_size[1] - height) // 2) + new_image.paste(image, paste_position) + return new_image + +def remove_background( + image: PIL.Image.Image, + rembg_session = None, + force: bool = False, + **rembg_kwargs, +) -> PIL.Image.Image: + do_remove = True + if image.mode == "RGBA" and image.getextrema()[3][0] < 255: + # explain why current do not rm bg + print("alhpa channl not enpty, skip remove background, using alpha channel as mask") + background = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image = Image.alpha_composite(background, image) + do_remove = False + do_remove = do_remove or force + if do_remove: + image = rembg.remove(image, session=rembg_session, **rembg_kwargs) + return image + +def do_resize_content(original_image: Image, scale_rate): + # resize image content wile retain the original image size + if scale_rate != 1: + # Calculate the new size after rescaling + new_size = tuple(int(dim * scale_rate) for dim in original_image.size) + # Resize the image while maintaining the aspect ratio + resized_image = original_image.resize(new_size) + # Create a new image with the original size and black background + padded_image = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) + paste_position = ((original_image.width - resized_image.width) // 2, (original_image.height - resized_image.height) // 2) + padded_image.paste(resized_image, paste_position) + return padded_image + else: + return original_image + +def add_background(image, bg_color=(255, 255, 255)): + # given an RGBA image, alpha channel is used as mask to add background color + background = Image.new("RGBA", image.size, bg_color) + return Image.alpha_composite(background, image) + + +def preprocess_image(image, background_choice, foreground_ratio, backgroud_color): + """ + input image is a pil image in RGBA, return RGB image + """ + print(background_choice) + if background_choice == "Alpha as mask": + background = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image = Image.alpha_composite(background, image) + else: + image = remove_background(image, rembg_session, force_remove=True) + image = do_resize_content(image, foreground_ratio) + image = expand_to_square(image) + image = add_background(image, backgroud_color) + return image.convert("RGB") + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument( + "--inputdir", + type=str, + default="examples/kunkun.webp", + help="dir for input image", + ) + parser.add_argument( + "--scale", + type=float, + default=5.0, + ) + parser.add_argument( + "--step", + type=int, + default=50, + ) + parser.add_argument( + "--bg_choice", + type=str, + default="Auto Remove background", + help="[Auto Remove background] or [Alpha as mask]", + ) + parser.add_argument( + "--outdir", + type=str, + default="out/", + ) + args = parser.parse_args() + + + img = Image.open(args.inputdir) + img = preprocess_image(img, args.bg_choice, 1.0, (127, 127, 127)) + os.makedirs(args.outdir, exist_ok=True) + img.save(args.outdir+"preprocessed_image.png") + + crm_path = hf_hub_download(repo_id="Zhengyi/CRM", filename="CRM.pth") + specs = json.load(open("configs/specs_objaverse_total.json")) + model = CRM(specs).to("cuda") + model.load_state_dict(torch.load(crm_path, map_location = "cuda"), strict=False) + + stage1_config = OmegaConf.load("configs/nf7_v3_SNR_rd_size_stroke.yaml").config + stage2_config = OmegaConf.load("configs/stage2-v2-snr.yaml").config + stage2_sampler_config = stage2_config.sampler + stage1_sampler_config = stage1_config.sampler + + stage1_model_config = stage1_config.models + stage2_model_config = stage2_config.models + + xyz_path = hf_hub_download(repo_id="Zhengyi/CRM", filename="ccm-diffusion.pth") + pixel_path = hf_hub_download(repo_id="Zhengyi/CRM", filename="pixel-diffusion.pth") + stage1_model_config.resume = pixel_path + stage2_model_config.resume = xyz_path + + pipeline = TwoStagePipeline( + stage1_model_config, + stage2_model_config, + stage1_sampler_config, + stage2_sampler_config, + ) + + rt_dict = pipeline(img, scale=args.scale, step=args.step) + stage1_images = rt_dict["stage1_images"] + stage2_images = rt_dict["stage2_images"] + np_imgs = np.concatenate(stage1_images, 1) + np_xyzs = np.concatenate(stage2_images, 1) + Image.fromarray(np_imgs).save(args.outdir+"pixel_images.png") + Image.fromarray(np_xyzs).save(args.outdir+"xyz_images.png") + + glb_path, obj_path = generate3d(model, np_imgs, np_xyzs, "cuda") + shutil.copy(obj_path, args.outdir+"output3d.zip") \ No newline at end of file diff --git a/apps/third_party/CRM/util/__init__.py b/apps/third_party/CRM/util/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/CRM/util/flexicubes.py b/apps/third_party/CRM/util/flexicubes.py new file mode 100644 index 0000000000000000000000000000000000000000..0e12d371362ea7f7f315bd33d866f4bb3510eadb --- /dev/null +++ b/apps/third_party/CRM/util/flexicubes.py @@ -0,0 +1,579 @@ +# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited. +import torch +from util.tables import * + +__all__ = [ + 'FlexiCubes' +] + + +class FlexiCubes: + """ + This class implements the FlexiCubes method for extracting meshes from scalar fields. + It maintains a series of lookup tables and indices to support the mesh extraction process. + FlexiCubes, a differentiable variant of the Dual Marching Cubes (DMC) scheme, enhances + the geometric fidelity and mesh quality of reconstructed meshes by dynamically adjusting + the surface representation through gradient-based optimization. + + During instantiation, the class loads DMC tables from a file and transforms them into + PyTorch tensors on the specified device. + + Attributes: + device (str): Specifies the computational device (default is "cuda"). + dmc_table (torch.Tensor): Dual Marching Cubes (DMC) table that encodes the edges + associated with each dual vertex in 256 Marching Cubes (MC) configurations. + num_vd_table (torch.Tensor): Table holding the number of dual vertices in each of + the 256 MC configurations. + check_table (torch.Tensor): Table resolving ambiguity in cases C16 and C19 + of the DMC configurations. + tet_table (torch.Tensor): Lookup table used in tetrahedralizing the isosurface. + quad_split_1 (torch.Tensor): Indices for splitting a quad into two triangles + along one diagonal. + quad_split_2 (torch.Tensor): Alternative indices for splitting a quad into + two triangles along the other diagonal. + quad_split_train (torch.Tensor): Indices for splitting a quad into four triangles + during training by connecting all edges to their midpoints. + cube_corners (torch.Tensor): Defines the positions of a standard unit cube's + eight corners in 3D space, ordered starting from the origin (0,0,0), + moving along the x-axis, then y-axis, and finally z-axis. + Used as a blueprint for generating a voxel grid. + cube_corners_idx (torch.Tensor): Cube corners indexed as powers of 2, used + to retrieve the case id. + cube_edges (torch.Tensor): Edge connections in a cube, listed in pairs. + Used to retrieve edge vertices in DMC. + edge_dir_table (torch.Tensor): A mapping tensor that associates edge indices with + their corresponding axis. For instance, edge_dir_table[0] = 0 indicates that the + first edge is oriented along the x-axis. + dir_faces_table (torch.Tensor): A tensor that maps the corresponding axis of shared edges + across four adjacent cubes to the shared faces of these cubes. For instance, + dir_faces_table[0] = [5, 4] implies that for four cubes sharing an edge along + the x-axis, the first and second cubes share faces indexed as 5 and 4, respectively. + This tensor is only utilized during isosurface tetrahedralization. + adj_pairs (torch.Tensor): + A tensor containing index pairs that correspond to neighboring cubes that share the same edge. + qef_reg_scale (float): + The scaling factor applied to the regularization loss to prevent issues with singularity + when solving the QEF. This parameter is only used when a 'grad_func' is specified. + weight_scale (float): + The scale of weights in FlexiCubes. Should be between 0 and 1. + """ + + def __init__(self, device="cuda", qef_reg_scale=1e-3, weight_scale=0.99): + + self.device = device + self.dmc_table = torch.tensor(dmc_table, dtype=torch.long, device=device, requires_grad=False) + self.num_vd_table = torch.tensor(num_vd_table, + dtype=torch.long, device=device, requires_grad=False) + self.check_table = torch.tensor( + check_table, + dtype=torch.long, device=device, requires_grad=False) + + self.tet_table = torch.tensor(tet_table, dtype=torch.long, device=device, requires_grad=False) + self.quad_split_1 = torch.tensor([0, 1, 2, 0, 2, 3], dtype=torch.long, device=device, requires_grad=False) + self.quad_split_2 = torch.tensor([0, 1, 3, 3, 1, 2], dtype=torch.long, device=device, requires_grad=False) + self.quad_split_train = torch.tensor( + [0, 1, 1, 2, 2, 3, 3, 0], dtype=torch.long, device=device, requires_grad=False) + + self.cube_corners = torch.tensor([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [ + 1, 0, 1], [0, 1, 1], [1, 1, 1]], dtype=torch.float, device=device) + self.cube_corners_idx = torch.pow(2, torch.arange(8, requires_grad=False)) + self.cube_edges = torch.tensor([0, 1, 1, 5, 4, 5, 0, 4, 2, 3, 3, 7, 6, 7, 2, 6, + 2, 0, 3, 1, 7, 5, 6, 4], dtype=torch.long, device=device, requires_grad=False) + + self.edge_dir_table = torch.tensor([0, 2, 0, 2, 0, 2, 0, 2, 1, 1, 1, 1], + dtype=torch.long, device=device) + self.dir_faces_table = torch.tensor([ + [[5, 4], [3, 2], [4, 5], [2, 3]], + [[5, 4], [1, 0], [4, 5], [0, 1]], + [[3, 2], [1, 0], [2, 3], [0, 1]] + ], dtype=torch.long, device=device) + self.adj_pairs = torch.tensor([0, 1, 1, 3, 3, 2, 2, 0], dtype=torch.long, device=device) + self.qef_reg_scale = qef_reg_scale + self.weight_scale = weight_scale + + def construct_voxel_grid(self, res): + """ + Generates a voxel grid based on the specified resolution. + + Args: + res (int or list[int]): The resolution of the voxel grid. If an integer + is provided, it is used for all three dimensions. If a list or tuple + of 3 integers is provided, they define the resolution for the x, + y, and z dimensions respectively. + + Returns: + (torch.Tensor, torch.Tensor): Returns the vertices and the indices of the + cube corners (index into vertices) of the constructed voxel grid. + The vertices are centered at the origin, with the length of each + dimension in the grid being one. + """ + base_cube_f = torch.arange(8).to(self.device) + if isinstance(res, int): + res = (res, res, res) + voxel_grid_template = torch.ones(res, device=self.device) + + res = torch.tensor([res], dtype=torch.float, device=self.device) + coords = torch.nonzero(voxel_grid_template).float() / res # N, 3 + verts = (self.cube_corners.unsqueeze(0) / res + coords.unsqueeze(1)).reshape(-1, 3) + cubes = (base_cube_f.unsqueeze(0) + + torch.arange(coords.shape[0], device=self.device).unsqueeze(1) * 8).reshape(-1) + + verts_rounded = torch.round(verts * 10**5) / (10**5) + verts_unique, inverse_indices = torch.unique(verts_rounded, dim=0, return_inverse=True) + cubes = inverse_indices[cubes.reshape(-1)].reshape(-1, 8) + + return verts_unique - 0.5, cubes + + def __call__(self, x_nx3, s_n, cube_fx8, res, beta_fx12=None, alpha_fx8=None, + gamma_f=None, training=False, output_tetmesh=False, grad_func=None): + r""" + Main function for mesh extraction from scalar field using FlexiCubes. This function converts + discrete signed distance fields, encoded on voxel grids and additional per-cube parameters, + to triangle or tetrahedral meshes using a differentiable operation as described in + `Flexible Isosurface Extraction for Gradient-Based Mesh Optimization`_. FlexiCubes enhances + mesh quality and geometric fidelity by adjusting the surface representation based on gradient + optimization. The output surface is differentiable with respect to the input vertex positions, + scalar field values, and weight parameters. + + If you intend to extract a surface mesh from a fixed Signed Distance Field without the + optimization of parameters, it is suggested to provide the "grad_func" which should + return the surface gradient at any given 3D position. When grad_func is provided, the process + to determine the dual vertex position adapts to solve a Quadratic Error Function (QEF), as + described in the `Manifold Dual Contouring`_ paper, and employs an smart splitting strategy. + Please note, this approach is non-differentiable. + + For more details and example usage in optimization, refer to the + `Flexible Isosurface Extraction for Gradient-Based Mesh Optimization`_ SIGGRAPH 2023 paper. + + Args: + x_nx3 (torch.Tensor): Coordinates of the voxel grid vertices, can be deformed. + s_n (torch.Tensor): Scalar field values at each vertex of the voxel grid. Negative values + denote that the corresponding vertex resides inside the isosurface. This affects + the directions of the extracted triangle faces and volume to be tetrahedralized. + cube_fx8 (torch.Tensor): Indices of 8 vertices for each cube in the voxel grid. + res (int or list[int]): The resolution of the voxel grid. If an integer is provided, it + is used for all three dimensions. If a list or tuple of 3 integers is provided, they + specify the resolution for the x, y, and z dimensions respectively. + beta_fx12 (torch.Tensor, optional): Weight parameters for the cube edges to adjust dual + vertices positioning. Defaults to uniform value for all edges. + alpha_fx8 (torch.Tensor, optional): Weight parameters for the cube corners to adjust dual + vertices positioning. Defaults to uniform value for all vertices. + gamma_f (torch.Tensor, optional): Weight parameters to control the splitting of + quadrilaterals into triangles. Defaults to uniform value for all cubes. + training (bool, optional): If set to True, applies differentiable quad splitting for + training. Defaults to False. + output_tetmesh (bool, optional): If set to True, outputs a tetrahedral mesh, otherwise, + outputs a triangular mesh. Defaults to False. + grad_func (callable, optional): A function to compute the surface gradient at specified + 3D positions (input: Nx3 positions). The function should return gradients as an Nx3 + tensor. If None, the original FlexiCubes algorithm is utilized. Defaults to None. + + Returns: + (torch.Tensor, torch.LongTensor, torch.Tensor): Tuple containing: + - Vertices for the extracted triangular/tetrahedral mesh. + - Faces for the extracted triangular/tetrahedral mesh. + - Regularizer L_dev, computed per dual vertex. + + .. _Flexible Isosurface Extraction for Gradient-Based Mesh Optimization: + https://research.nvidia.com/labs/toronto-ai/flexicubes/ + .. _Manifold Dual Contouring: + https://people.engr.tamu.edu/schaefer/research/dualsimp_tvcg.pdf + """ + + surf_cubes, occ_fx8 = self._identify_surf_cubes(s_n, cube_fx8) + if surf_cubes.sum() == 0: + return torch.zeros( + (0, 3), + device=self.device), torch.zeros( + (0, 4), + dtype=torch.long, device=self.device) if output_tetmesh else torch.zeros( + (0, 3), + dtype=torch.long, device=self.device), torch.zeros( + (0), + device=self.device) + beta_fx12, alpha_fx8, gamma_f = self._normalize_weights(beta_fx12, alpha_fx8, gamma_f, surf_cubes) + + case_ids = self._get_case_id(occ_fx8, surf_cubes, res) + + surf_edges, idx_map, edge_counts, surf_edges_mask = self._identify_surf_edges(s_n, cube_fx8, surf_cubes) + + vd, L_dev, vd_gamma, vd_idx_map = self._compute_vd( + x_nx3, cube_fx8[surf_cubes], surf_edges, s_n, case_ids, beta_fx12, alpha_fx8, gamma_f, idx_map, grad_func) + vertices, faces, s_edges, edge_indices = self._triangulate( + s_n, surf_edges, vd, vd_gamma, edge_counts, idx_map, vd_idx_map, surf_edges_mask, training, grad_func) + if not output_tetmesh: + return vertices, faces, L_dev + else: + vertices, tets = self._tetrahedralize( + x_nx3, s_n, cube_fx8, vertices, faces, surf_edges, s_edges, vd_idx_map, case_ids, edge_indices, + surf_cubes, training) + return vertices, tets, L_dev + + def _compute_reg_loss(self, vd, ue, edge_group_to_vd, vd_num_edges): + """ + Regularizer L_dev as in Equation 8 + """ + dist = torch.norm(ue - torch.index_select(input=vd, index=edge_group_to_vd, dim=0), dim=-1) + mean_l2 = torch.zeros_like(vd[:, 0]) + mean_l2 = (mean_l2).index_add_(0, edge_group_to_vd, dist) / vd_num_edges.squeeze(1).float() + mad = (dist - torch.index_select(input=mean_l2, index=edge_group_to_vd, dim=0)).abs() + return mad + + def _normalize_weights(self, beta_fx12, alpha_fx8, gamma_f, surf_cubes): + """ + Normalizes the given weights to be non-negative. If input weights are None, it creates and returns a set of weights of ones. + """ + n_cubes = surf_cubes.shape[0] + + if beta_fx12 is not None: + beta_fx12 = (torch.tanh(beta_fx12) * self.weight_scale + 1) + else: + beta_fx12 = torch.ones((n_cubes, 12), dtype=torch.float, device=self.device) + + if alpha_fx8 is not None: + alpha_fx8 = (torch.tanh(alpha_fx8) * self.weight_scale + 1) + else: + alpha_fx8 = torch.ones((n_cubes, 8), dtype=torch.float, device=self.device) + + if gamma_f is not None: + gamma_f = torch.sigmoid(gamma_f) * self.weight_scale + (1 - self.weight_scale)/2 + else: + gamma_f = torch.ones((n_cubes), dtype=torch.float, device=self.device) + + return beta_fx12[surf_cubes], alpha_fx8[surf_cubes], gamma_f[surf_cubes] + + @torch.no_grad() + def _get_case_id(self, occ_fx8, surf_cubes, res): + """ + Obtains the ID of topology cases based on cell corner occupancy. This function resolves the + ambiguity in the Dual Marching Cubes (DMC) configurations as described in Section 1.3 of the + supplementary material. It should be noted that this function assumes a regular grid. + """ + case_ids = (occ_fx8[surf_cubes] * self.cube_corners_idx.to(self.device).unsqueeze(0)).sum(-1) + + problem_config = self.check_table.to(self.device)[case_ids] + to_check = problem_config[..., 0] == 1 + problem_config = problem_config[to_check] + if not isinstance(res, (list, tuple)): + res = [res, res, res] + + # The 'problematic_configs' only contain configurations for surface cubes. Next, we construct a 3D array, + # 'problem_config_full', to store configurations for all cubes (with default config for non-surface cubes). + # This allows efficient checking on adjacent cubes. + problem_config_full = torch.zeros(list(res) + [5], device=self.device, dtype=torch.long) + vol_idx = torch.nonzero(problem_config_full[..., 0] == 0) # N, 3 + vol_idx_problem = vol_idx[surf_cubes][to_check] + problem_config_full[vol_idx_problem[..., 0], vol_idx_problem[..., 1], vol_idx_problem[..., 2]] = problem_config + vol_idx_problem_adj = vol_idx_problem + problem_config[..., 1:4] + + within_range = ( + vol_idx_problem_adj[..., 0] >= 0) & ( + vol_idx_problem_adj[..., 0] < res[0]) & ( + vol_idx_problem_adj[..., 1] >= 0) & ( + vol_idx_problem_adj[..., 1] < res[1]) & ( + vol_idx_problem_adj[..., 2] >= 0) & ( + vol_idx_problem_adj[..., 2] < res[2]) + + vol_idx_problem = vol_idx_problem[within_range] + vol_idx_problem_adj = vol_idx_problem_adj[within_range] + problem_config = problem_config[within_range] + problem_config_adj = problem_config_full[vol_idx_problem_adj[..., 0], + vol_idx_problem_adj[..., 1], vol_idx_problem_adj[..., 2]] + # If two cubes with cases C16 and C19 share an ambiguous face, both cases are inverted. + to_invert = (problem_config_adj[..., 0] == 1) + idx = torch.arange(case_ids.shape[0], device=self.device)[to_check][within_range][to_invert] + case_ids.index_put_((idx,), problem_config[to_invert][..., -1]) + return case_ids + + @torch.no_grad() + def _identify_surf_edges(self, s_n, cube_fx8, surf_cubes): + """ + Identifies grid edges that intersect with the underlying surface by checking for opposite signs. As each edge + can be shared by multiple cubes, this function also assigns a unique index to each surface-intersecting edge + and marks the cube edges with this index. + """ + occ_n = s_n < 0 + all_edges = cube_fx8[surf_cubes][:, self.cube_edges].reshape(-1, 2) + unique_edges, _idx_map, counts = torch.unique(all_edges, dim=0, return_inverse=True, return_counts=True) + + unique_edges = unique_edges.long() + mask_edges = occ_n[unique_edges.reshape(-1)].reshape(-1, 2).sum(-1) == 1 + + surf_edges_mask = mask_edges[_idx_map] + counts = counts[_idx_map] + + mapping = torch.ones((unique_edges.shape[0]), dtype=torch.long, device=cube_fx8.device) * -1 + mapping[mask_edges] = torch.arange(mask_edges.sum(), device=cube_fx8.device) + # Shaped as [number of cubes x 12 edges per cube]. This is later used to map a cube edge to the unique index + # for a surface-intersecting edge. Non-surface-intersecting edges are marked with -1. + idx_map = mapping[_idx_map] + surf_edges = unique_edges[mask_edges] + return surf_edges, idx_map, counts, surf_edges_mask + + @torch.no_grad() + def _identify_surf_cubes(self, s_n, cube_fx8): + """ + Identifies grid cubes that intersect with the underlying surface by checking if the signs at + all corners are not identical. + """ + occ_n = s_n < 0 + occ_fx8 = occ_n[cube_fx8.reshape(-1)].reshape(-1, 8) + _occ_sum = torch.sum(occ_fx8, -1) + surf_cubes = (_occ_sum > 0) & (_occ_sum < 8) + return surf_cubes, occ_fx8 + + def _linear_interp(self, edges_weight, edges_x): + """ + Computes the location of zero-crossings on 'edges_x' using linear interpolation with 'edges_weight'. + """ + edge_dim = edges_weight.dim() - 2 + assert edges_weight.shape[edge_dim] == 2 + edges_weight = torch.cat([torch.index_select(input=edges_weight, index=torch.tensor(1, device=self.device), dim=edge_dim), - + torch.index_select(input=edges_weight, index=torch.tensor(0, device=self.device), dim=edge_dim)], edge_dim) + denominator = edges_weight.sum(edge_dim) + ue = (edges_x * edges_weight).sum(edge_dim) / denominator + return ue + + def _solve_vd_QEF(self, p_bxnx3, norm_bxnx3, c_bx3=None): + p_bxnx3 = p_bxnx3.reshape(-1, 7, 3) + norm_bxnx3 = norm_bxnx3.reshape(-1, 7, 3) + c_bx3 = c_bx3.reshape(-1, 3) + A = norm_bxnx3 + B = ((p_bxnx3) * norm_bxnx3).sum(-1, keepdims=True) + + A_reg = (torch.eye(3, device=p_bxnx3.device) * self.qef_reg_scale).unsqueeze(0).repeat(p_bxnx3.shape[0], 1, 1) + B_reg = (self.qef_reg_scale * c_bx3).unsqueeze(-1) + A = torch.cat([A, A_reg], 1) + B = torch.cat([B, B_reg], 1) + dual_verts = torch.linalg.lstsq(A, B).solution.squeeze(-1) + return dual_verts + + def _compute_vd(self, x_nx3, surf_cubes_fx8, surf_edges, s_n, case_ids, beta_fx12, alpha_fx8, gamma_f, idx_map, grad_func): + """ + Computes the location of dual vertices as described in Section 4.2 + """ + alpha_nx12x2 = torch.index_select(input=alpha_fx8, index=self.cube_edges, dim=1).reshape(-1, 12, 2) + surf_edges_x = torch.index_select(input=x_nx3, index=surf_edges.reshape(-1), dim=0).reshape(-1, 2, 3) + surf_edges_s = torch.index_select(input=s_n, index=surf_edges.reshape(-1), dim=0).reshape(-1, 2, 1) + zero_crossing = self._linear_interp(surf_edges_s, surf_edges_x) + + idx_map = idx_map.reshape(-1, 12) + num_vd = torch.index_select(input=self.num_vd_table, index=case_ids, dim=0) + edge_group, edge_group_to_vd, edge_group_to_cube, vd_num_edges, vd_gamma = [], [], [], [], [] + + total_num_vd = 0 + vd_idx_map = torch.zeros((case_ids.shape[0], 12), dtype=torch.long, device=self.device, requires_grad=False) + if grad_func is not None: + normals = torch.nn.functional.normalize(grad_func(zero_crossing), dim=-1) + vd = [] + for num in torch.unique(num_vd): + cur_cubes = (num_vd == num) # consider cubes with the same numbers of vd emitted (for batching) + curr_num_vd = cur_cubes.sum() * num + curr_edge_group = self.dmc_table[case_ids[cur_cubes], :num].reshape(-1, num * 7) + curr_edge_group_to_vd = torch.arange( + curr_num_vd, device=self.device).unsqueeze(-1).repeat(1, 7) + total_num_vd + total_num_vd += curr_num_vd + curr_edge_group_to_cube = torch.arange(idx_map.shape[0], device=self.device)[ + cur_cubes].unsqueeze(-1).repeat(1, num * 7).reshape_as(curr_edge_group) + + curr_mask = (curr_edge_group != -1) + edge_group.append(torch.masked_select(curr_edge_group, curr_mask)) + edge_group_to_vd.append(torch.masked_select(curr_edge_group_to_vd.reshape_as(curr_edge_group), curr_mask)) + edge_group_to_cube.append(torch.masked_select(curr_edge_group_to_cube, curr_mask)) + vd_num_edges.append(curr_mask.reshape(-1, 7).sum(-1, keepdims=True)) + vd_gamma.append(torch.masked_select(gamma_f, cur_cubes).unsqueeze(-1).repeat(1, num).reshape(-1)) + + if grad_func is not None: + with torch.no_grad(): + cube_e_verts_idx = idx_map[cur_cubes] + curr_edge_group[~curr_mask] = 0 + + verts_group_idx = torch.gather(input=cube_e_verts_idx, dim=1, index=curr_edge_group) + verts_group_idx[verts_group_idx == -1] = 0 + verts_group_pos = torch.index_select( + input=zero_crossing, index=verts_group_idx.reshape(-1), dim=0).reshape(-1, num.item(), 7, 3) + v0 = x_nx3[surf_cubes_fx8[cur_cubes][:, 0]].reshape(-1, 1, 1, 3).repeat(1, num.item(), 1, 1) + curr_mask = curr_mask.reshape(-1, num.item(), 7, 1) + verts_centroid = (verts_group_pos * curr_mask).sum(2) / (curr_mask.sum(2)) + + normals_bx7x3 = torch.index_select(input=normals, index=verts_group_idx.reshape(-1), dim=0).reshape( + -1, num.item(), 7, + 3) + curr_mask = curr_mask.squeeze(2) + vd.append(self._solve_vd_QEF((verts_group_pos - v0) * curr_mask, normals_bx7x3 * curr_mask, + verts_centroid - v0.squeeze(2)) + v0.reshape(-1, 3)) + edge_group = torch.cat(edge_group) + edge_group_to_vd = torch.cat(edge_group_to_vd) + edge_group_to_cube = torch.cat(edge_group_to_cube) + vd_num_edges = torch.cat(vd_num_edges) + vd_gamma = torch.cat(vd_gamma) + + if grad_func is not None: + vd = torch.cat(vd) + L_dev = torch.zeros([1], device=self.device) + else: + vd = torch.zeros((total_num_vd, 3), device=self.device) + beta_sum = torch.zeros((total_num_vd, 1), device=self.device) + + idx_group = torch.gather(input=idx_map.reshape(-1), dim=0, index=edge_group_to_cube * 12 + edge_group) + + x_group = torch.index_select(input=surf_edges_x, index=idx_group.reshape(-1), dim=0).reshape(-1, 2, 3) + s_group = torch.index_select(input=surf_edges_s, index=idx_group.reshape(-1), dim=0).reshape(-1, 2, 1) + + zero_crossing_group = torch.index_select( + input=zero_crossing, index=idx_group.reshape(-1), dim=0).reshape(-1, 3) + + alpha_group = torch.index_select(input=alpha_nx12x2.reshape(-1, 2), dim=0, + index=edge_group_to_cube * 12 + edge_group).reshape(-1, 2, 1) + ue_group = self._linear_interp(s_group * alpha_group, x_group) + + beta_group = torch.gather(input=beta_fx12.reshape(-1), dim=0, + index=edge_group_to_cube * 12 + edge_group).reshape(-1, 1) + beta_sum = beta_sum.index_add_(0, index=edge_group_to_vd, source=beta_group) + vd = vd.index_add_(0, index=edge_group_to_vd, source=ue_group * beta_group) / beta_sum + L_dev = self._compute_reg_loss(vd, zero_crossing_group, edge_group_to_vd, vd_num_edges) + + v_idx = torch.arange(vd.shape[0], device=self.device) # + total_num_vd + + vd_idx_map = (vd_idx_map.reshape(-1)).scatter(dim=0, index=edge_group_to_cube * + 12 + edge_group, src=v_idx[edge_group_to_vd]) + + return vd, L_dev, vd_gamma, vd_idx_map + + def _triangulate(self, s_n, surf_edges, vd, vd_gamma, edge_counts, idx_map, vd_idx_map, surf_edges_mask, training, grad_func): + """ + Connects four neighboring dual vertices to form a quadrilateral. The quadrilaterals are then split into + triangles based on the gamma parameter, as described in Section 4.3. + """ + with torch.no_grad(): + group_mask = (edge_counts == 4) & surf_edges_mask # surface edges shared by 4 cubes. + group = idx_map.reshape(-1)[group_mask] + vd_idx = vd_idx_map[group_mask] + edge_indices, indices = torch.sort(group, stable=True) + quad_vd_idx = vd_idx[indices].reshape(-1, 4) + + # Ensure all face directions point towards the positive SDF to maintain consistent winding. + s_edges = s_n[surf_edges[edge_indices.reshape(-1, 4)[:, 0]].reshape(-1)].reshape(-1, 2) + flip_mask = s_edges[:, 0] > 0 + quad_vd_idx = torch.cat((quad_vd_idx[flip_mask][:, [0, 1, 3, 2]], + quad_vd_idx[~flip_mask][:, [2, 3, 1, 0]])) + if grad_func is not None: + # when grad_func is given, split quadrilaterals along the diagonals with more consistent gradients. + with torch.no_grad(): + vd_gamma = torch.nn.functional.normalize(grad_func(vd), dim=-1) + quad_gamma = torch.index_select(input=vd_gamma, index=quad_vd_idx.reshape(-1), dim=0).reshape(-1, 4, 3) + gamma_02 = (quad_gamma[:, 0] * quad_gamma[:, 2]).sum(-1, keepdims=True) + gamma_13 = (quad_gamma[:, 1] * quad_gamma[:, 3]).sum(-1, keepdims=True) + else: + quad_gamma = torch.index_select(input=vd_gamma, index=quad_vd_idx.reshape(-1), dim=0).reshape(-1, 4) + gamma_02 = torch.index_select(input=quad_gamma, index=torch.tensor( + 0, device=self.device), dim=1) * torch.index_select(input=quad_gamma, index=torch.tensor(2, device=self.device), dim=1) + gamma_13 = torch.index_select(input=quad_gamma, index=torch.tensor( + 1, device=self.device), dim=1) * torch.index_select(input=quad_gamma, index=torch.tensor(3, device=self.device), dim=1) + if not training: + mask = (gamma_02 > gamma_13).squeeze(1) + faces = torch.zeros((quad_gamma.shape[0], 6), dtype=torch.long, device=quad_vd_idx.device) + faces[mask] = quad_vd_idx[mask][:, self.quad_split_1] + faces[~mask] = quad_vd_idx[~mask][:, self.quad_split_2] + faces = faces.reshape(-1, 3) + else: + vd_quad = torch.index_select(input=vd, index=quad_vd_idx.reshape(-1), dim=0).reshape(-1, 4, 3) + vd_02 = (torch.index_select(input=vd_quad, index=torch.tensor(0, device=self.device), dim=1) + + torch.index_select(input=vd_quad, index=torch.tensor(2, device=self.device), dim=1)) / 2 + vd_13 = (torch.index_select(input=vd_quad, index=torch.tensor(1, device=self.device), dim=1) + + torch.index_select(input=vd_quad, index=torch.tensor(3, device=self.device), dim=1)) / 2 + weight_sum = (gamma_02 + gamma_13) + 1e-8 + vd_center = ((vd_02 * gamma_02.unsqueeze(-1) + vd_13 * gamma_13.unsqueeze(-1)) / + weight_sum.unsqueeze(-1)).squeeze(1) + vd_center_idx = torch.arange(vd_center.shape[0], device=self.device) + vd.shape[0] + vd = torch.cat([vd, vd_center]) + faces = quad_vd_idx[:, self.quad_split_train].reshape(-1, 4, 2) + faces = torch.cat([faces, vd_center_idx.reshape(-1, 1, 1).repeat(1, 4, 1)], -1).reshape(-1, 3) + return vd, faces, s_edges, edge_indices + + def _tetrahedralize( + self, x_nx3, s_n, cube_fx8, vertices, faces, surf_edges, s_edges, vd_idx_map, case_ids, edge_indices, + surf_cubes, training): + """ + Tetrahedralizes the interior volume to produce a tetrahedral mesh, as described in Section 4.5. + """ + occ_n = s_n < 0 + occ_fx8 = occ_n[cube_fx8.reshape(-1)].reshape(-1, 8) + occ_sum = torch.sum(occ_fx8, -1) + + inside_verts = x_nx3[occ_n] + mapping_inside_verts = torch.ones((occ_n.shape[0]), dtype=torch.long, device=self.device) * -1 + mapping_inside_verts[occ_n] = torch.arange(occ_n.sum(), device=self.device) + vertices.shape[0] + """ + For each grid edge connecting two grid vertices with different + signs, we first form a four-sided pyramid by connecting one + of the grid vertices with four mesh vertices that correspond + to the grid edge and then subdivide the pyramid into two tetrahedra + """ + inside_verts_idx = mapping_inside_verts[surf_edges[edge_indices.reshape(-1, 4)[:, 0]].reshape(-1, 2)[ + s_edges < 0]] + if not training: + inside_verts_idx = inside_verts_idx.unsqueeze(1).expand(-1, 2).reshape(-1) + else: + inside_verts_idx = inside_verts_idx.unsqueeze(1).expand(-1, 4).reshape(-1) + + tets_surface = torch.cat([faces, inside_verts_idx.unsqueeze(-1)], -1) + """ + For each grid edge connecting two grid vertices with the + same sign, the tetrahedron is formed by the two grid vertices + and two vertices in consecutive adjacent cells + """ + inside_cubes = (occ_sum == 8) + inside_cubes_center = x_nx3[cube_fx8[inside_cubes].reshape(-1)].reshape(-1, 8, 3).mean(1) + inside_cubes_center_idx = torch.arange( + inside_cubes_center.shape[0], device=inside_cubes.device) + vertices.shape[0] + inside_verts.shape[0] + + surface_n_inside_cubes = surf_cubes | inside_cubes + edge_center_vertex_idx = torch.ones(((surface_n_inside_cubes).sum(), 13), + dtype=torch.long, device=x_nx3.device) * -1 + surf_cubes = surf_cubes[surface_n_inside_cubes] + inside_cubes = inside_cubes[surface_n_inside_cubes] + edge_center_vertex_idx[surf_cubes, :12] = vd_idx_map.reshape(-1, 12) + edge_center_vertex_idx[inside_cubes, 12] = inside_cubes_center_idx + + all_edges = cube_fx8[surface_n_inside_cubes][:, self.cube_edges].reshape(-1, 2) + unique_edges, _idx_map, counts = torch.unique(all_edges, dim=0, return_inverse=True, return_counts=True) + unique_edges = unique_edges.long() + mask_edges = occ_n[unique_edges.reshape(-1)].reshape(-1, 2).sum(-1) == 2 + mask = mask_edges[_idx_map] + counts = counts[_idx_map] + mapping = torch.ones((unique_edges.shape[0]), dtype=torch.long, device=self.device) * -1 + mapping[mask_edges] = torch.arange(mask_edges.sum(), device=self.device) + idx_map = mapping[_idx_map] + + group_mask = (counts == 4) & mask + group = idx_map.reshape(-1)[group_mask] + edge_indices, indices = torch.sort(group) + cube_idx = torch.arange((_idx_map.shape[0] // 12), dtype=torch.long, + device=self.device).unsqueeze(1).expand(-1, 12).reshape(-1)[group_mask] + edge_idx = torch.arange((12), dtype=torch.long, device=self.device).unsqueeze( + 0).expand(_idx_map.shape[0] // 12, -1).reshape(-1)[group_mask] + # Identify the face shared by the adjacent cells. + cube_idx_4 = cube_idx[indices].reshape(-1, 4) + edge_dir = self.edge_dir_table[edge_idx[indices]].reshape(-1, 4)[..., 0] + shared_faces_4x2 = self.dir_faces_table[edge_dir].reshape(-1) + cube_idx_4x2 = cube_idx_4[:, self.adj_pairs].reshape(-1) + # Identify an edge of the face with different signs and + # select the mesh vertex corresponding to the identified edge. + case_ids_expand = torch.ones((surface_n_inside_cubes).sum(), dtype=torch.long, device=x_nx3.device) * 255 + case_ids_expand[surf_cubes] = case_ids + cases = case_ids_expand[cube_idx_4x2] + quad_edge = edge_center_vertex_idx[cube_idx_4x2, self.tet_table[cases, shared_faces_4x2]].reshape(-1, 2) + mask = (quad_edge == -1).sum(-1) == 0 + inside_edge = mapping_inside_verts[unique_edges[mask_edges][edge_indices].reshape(-1)].reshape(-1, 2) + tets_inside = torch.cat([quad_edge, inside_edge], -1)[mask] + + tets = torch.cat([tets_surface, tets_inside]) + vertices = torch.cat([vertices, inside_verts, inside_cubes_center]) + return vertices, tets diff --git a/apps/third_party/CRM/util/flexicubes_geometry.py b/apps/third_party/CRM/util/flexicubes_geometry.py new file mode 100644 index 0000000000000000000000000000000000000000..5dec7635e7f275f6ef3867223ea2700d3af6f4ea --- /dev/null +++ b/apps/third_party/CRM/util/flexicubes_geometry.py @@ -0,0 +1,116 @@ +# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited. + +import torch +from util.flexicubes import FlexiCubes # replace later +# from dmtet import sdf_reg_loss_batch +import torch.nn.functional as F + +def get_center_boundary_index(grid_res, device): + v = torch.zeros((grid_res + 1, grid_res + 1, grid_res + 1), dtype=torch.bool, device=device) + v[grid_res // 2 + 1, grid_res // 2 + 1, grid_res // 2 + 1] = True + center_indices = torch.nonzero(v.reshape(-1)) + + v[grid_res // 2 + 1, grid_res // 2 + 1, grid_res // 2 + 1] = False + v[:2, ...] = True + v[-2:, ...] = True + v[:, :2, ...] = True + v[:, -2:, ...] = True + v[:, :, :2] = True + v[:, :, -2:] = True + boundary_indices = torch.nonzero(v.reshape(-1)) + return center_indices, boundary_indices + +############################################################################### +# Geometry interface +############################################################################### +class FlexiCubesGeometry(object): + def __init__( + self, grid_res=64, scale=2.0, device='cuda', renderer=None, + render_type='neural_render', args=None): + super(FlexiCubesGeometry, self).__init__() + self.grid_res = grid_res + self.device = device + self.args = args + self.fc = FlexiCubes(device, weight_scale=0.5) + self.verts, self.indices = self.fc.construct_voxel_grid(grid_res) + if isinstance(scale, list): + self.verts[:, 0] = self.verts[:, 0] * scale[0] + self.verts[:, 1] = self.verts[:, 1] * scale[1] + self.verts[:, 2] = self.verts[:, 2] * scale[1] + else: + self.verts = self.verts * scale + + all_edges = self.indices[:, self.fc.cube_edges].reshape(-1, 2) + self.all_edges = torch.unique(all_edges, dim=0) + + # Parameters used for fix boundary sdf + self.center_indices, self.boundary_indices = get_center_boundary_index(self.grid_res, device) + self.renderer = renderer + self.render_type = render_type + + def getAABB(self): + return torch.min(self.verts, dim=0).values, torch.max(self.verts, dim=0).values + + def get_mesh(self, v_deformed_nx3, sdf_n, weight_n=None, with_uv=False, indices=None, is_training=False): + if indices is None: + indices = self.indices + + verts, faces, v_reg_loss = self.fc(v_deformed_nx3, sdf_n, indices, self.grid_res, + beta_fx12=weight_n[:, :12], alpha_fx8=weight_n[:, 12:20], + gamma_f=weight_n[:, 20], training=is_training + ) + return verts, faces, v_reg_loss + + + def render_mesh(self, mesh_v_nx3, mesh_f_fx3, camera_mv_bx4x4, resolution=256, hierarchical_mask=False): + return_value = dict() + if self.render_type == 'neural_render': + tex_pos, mask, hard_mask, rast, v_pos_clip, mask_pyramid, depth = self.renderer.render_mesh( + mesh_v_nx3.unsqueeze(dim=0), + mesh_f_fx3.int(), + camera_mv_bx4x4, + mesh_v_nx3.unsqueeze(dim=0), + resolution=resolution, + device=self.device, + hierarchical_mask=hierarchical_mask + ) + + return_value['tex_pos'] = tex_pos + return_value['mask'] = mask + return_value['hard_mask'] = hard_mask + return_value['rast'] = rast + return_value['v_pos_clip'] = v_pos_clip + return_value['mask_pyramid'] = mask_pyramid + return_value['depth'] = depth + else: + raise NotImplementedError + + return return_value + + def render(self, v_deformed_bxnx3=None, sdf_bxn=None, camera_mv_bxnviewx4x4=None, resolution=256): + # Here I assume a batch of meshes (can be different mesh and geometry), for the other shapes, the batch is 1 + v_list = [] + f_list = [] + n_batch = v_deformed_bxnx3.shape[0] + all_render_output = [] + for i_batch in range(n_batch): + verts_nx3, faces_fx3 = self.get_mesh(v_deformed_bxnx3[i_batch], sdf_bxn[i_batch]) + v_list.append(verts_nx3) + f_list.append(faces_fx3) + render_output = self.render_mesh(verts_nx3, faces_fx3, camera_mv_bxnviewx4x4[i_batch], resolution) + all_render_output.append(render_output) + + # Concatenate all render output + return_keys = all_render_output[0].keys() + return_value = dict() + for k in return_keys: + value = [v[k] for v in all_render_output] + return_value[k] = value + # We can do concatenation outside of the render + return return_value diff --git a/apps/third_party/CRM/util/renderer.py b/apps/third_party/CRM/util/renderer.py new file mode 100644 index 0000000000000000000000000000000000000000..2d1dc69dcaaf902cbb70af06834015ed1730dc0e --- /dev/null +++ b/apps/third_party/CRM/util/renderer.py @@ -0,0 +1,49 @@ + +import torch +import torch.nn as nn +import nvdiffrast.torch as dr +from util.flexicubes_geometry import FlexiCubesGeometry + +class Renderer(nn.Module): + def __init__(self, tet_grid_size, camera_angle_num, scale, geo_type): + super().__init__() + + self.tet_grid_size = tet_grid_size + self.camera_angle_num = camera_angle_num + self.scale = scale + self.geo_type = geo_type + self.glctx = dr.RasterizeCudaContext() + + if self.geo_type == "flex": + self.flexicubes = FlexiCubesGeometry(grid_res = self.tet_grid_size) + + def forward(self, data, sdf, deform, verts, tets, training=False, weight = None): + + results = {} + + deform = torch.tanh(deform) / self.tet_grid_size * self.scale / 0.95 + if self.geo_type == "flex": + deform = deform *0.5 + + v_deformed = verts + deform + + verts_list = [] + faces_list = [] + reg_list = [] + n_shape = verts.shape[0] + for i in range(n_shape): + verts_i, faces_i, reg_i = self.flexicubes.get_mesh(v_deformed[i], sdf[i].squeeze(dim=-1), + with_uv=False, indices=tets, weight_n=weight[i], is_training=training) + + verts_list.append(verts_i) + faces_list.append(faces_i) + reg_list.append(reg_i) + verts = verts_list + faces = faces_list + + flexicubes_surface_reg = torch.cat(reg_list).mean() + flexicubes_weight_reg = (weight ** 2).mean() + results["flex_surf_loss"] = flexicubes_surface_reg + results["flex_weight_loss"] = flexicubes_weight_reg + + return results, verts, faces \ No newline at end of file diff --git a/apps/third_party/CRM/util/tables.py b/apps/third_party/CRM/util/tables.py new file mode 100644 index 0000000000000000000000000000000000000000..936a4bc5e2f95891f72651f2c42272e01a3a2bc3 --- /dev/null +++ b/apps/third_party/CRM/util/tables.py @@ -0,0 +1,791 @@ +# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited. +dmc_table = [ +[[-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 8, 9, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [4, 7, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 7, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [4, 5, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 5, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 5, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 7, 8, 9, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 5, 7, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 5, 7, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 5, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 8, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 8, 9, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 7, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [4, 7, 8, -1, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 7, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 8, 11, -1, -1, -1], [4, 5, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 5, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 5, 8, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 7, 8, 9, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 5, 7, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 5, 7, 8, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 5, 7, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 9, 10, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 8, 9, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 7, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 9, 10, -1, -1, -1], [4, 7, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 7, 9, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [4, 5, 9, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 5, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 5, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 7, 8, 9, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 5, 7, 9, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 5, 7, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 5, 7, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 8, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 9, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[8, 9, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [1, 3, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 7, 10, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 9, 10, 11, -1, -1], [4, 7, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 9, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [1, 3, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 8, 10, 11, -1, -1], [4, 5, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 5, 10, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 8, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 7, 8, 9, -1, -1, -1], [1, 3, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 5, 7, 9, 10, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 5, 7, 8, 10, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 7, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 8, 9, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 6, 8, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 6, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [4, 6, 8, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 6, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [4, 5, 9, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 5, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 5, 8, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 6, 8, 9, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 5, 6, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 5, 6, 8, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 5, 6, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 6, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 6, 7, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [2, 3, 6, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 6, 7, 8, 9, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 6, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 6, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [2, 3, 4, 6, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 6, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [2, 3, 6, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 6, 7, 8, -1, -1], [4, 5, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 5, -1, -1, -1], [2, 3, 6, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 5, 6, 7, 8], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 5, 6, 8, 9, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 5, 6, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 2, 3, 5, 6, 8], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 5, 6, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 10, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 9, 10, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 8, 9, 10, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 6, 8, 11, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 6, 11, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 9, 10, -1, -1, -1], [4, 6, 8, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 6, 9, 10, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [4, 5, 9, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1]], +[[0, 2, 4, 5, 10, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 5, 8, 10, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 6, 8, 9, 11, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 5, 6, 9, 11, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 5, 6, 8, 10, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 5, 6, 10, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 6, 7, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 6, 7, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 6, 7, 9, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[6, 7, 8, 9, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 6, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 6, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 6, 8, 9, 10], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 6, 9, 10, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [1, 3, 6, 7, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 6, 7, 8, 10, -1], [4, 5, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 5, 6, 7, 10], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 6, 7, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 5, 6, 8, 9, 10], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 5, 6, 9, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 8, 9, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 7, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [4, 7, 8, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 7, 9, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 6, 9, 10, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [4, 6, 9, 10, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 6, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 6, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[6, 7, 8, 9, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 6, 7, 9, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 6, 7, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 6, 7, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 11, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 8, 11, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 8, 9, 11, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 7, 11, -1, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [4, 7, 8, -1, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [5, 6, 10, -1, -1, -1, -1]], +[[1, 2, 4, 7, 9, 11, -1], [5, 6, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 6, 9, 10, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 8, 11, -1, -1, -1], [4, 6, 9, 10, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 6, 10, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 6, 8, 10, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[6, 7, 8, 9, 10, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 6, 7, 9, 10, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 6, 7, 8, 10, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 6, 7, 10, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 5, 6, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [1, 2, 5, 6, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 5, 6, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 5, 6, 8, 9, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [1, 2, 5, 6, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 7, -1, -1, -1], [1, 2, 5, 6, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 5, 6, 9, -1, -1], [4, 7, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 5, 6, 7, 9], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 6, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [1, 2, 4, 6, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 6, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 6, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 6, 7, 8, 9, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 2, 3, 6, 7, 9], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 6, 7, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 6, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 5, 6, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 5, 6, 8, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 5, 6, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 6, 8, 9, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [1, 3, 5, 6, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 5, 6, 7, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 5, 6, 9, 11, -1], [4, 7, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 6, 7, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 6, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 6, 8, 9, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 6, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 6, 8, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 6, 7, 8, 9, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 6, 7, 8, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[6, 7, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 7, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [5, 7, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [5, 7, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 8, 9, -1, -1, -1], [5, 7, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 8, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 5, 10, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [4, 5, 8, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 5, 9, 10, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 9, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [4, 7, 9, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 7, 10, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 7, 8, 10, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[8, 9, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 9, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 8, 10, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 10, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 5, 7, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 5, 7, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [2, 3, 5, 7, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 5, 7, 8, 9, 10], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 5, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 5, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [2, 3, 4, 5, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 5, 9, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 7, 9, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 7, 8, 9, 10], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 2, 3, 4, 7, 10], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 8, 9, 10, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 9, 10, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 2, 3, 8, 10, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 10, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 5, 7, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [1, 2, 5, 7, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 5, 7, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 5, 7, 8, 9, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 5, 8, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 2, 3, 4, 5, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 5, 8, 9, 11], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 4, 7, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [1, 2, 4, 7, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 4, 7, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 4, 7, 8, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 2, 8, 9, 11, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 2, 3, 9, 11, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 2, 8, 11, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[2, 3, 11, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 5, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 5, 7, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 5, 7, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[5, 7, 8, 9, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 5, 8, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 5, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 5, 8, 9, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 5, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 4, 7, 9, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 4, 7, 8, 9, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 4, 7, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[4, 7, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[1, 3, 8, 9, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 1, 9, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[0, 3, 8, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]], +[[-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1]] +] +num_vd_table = [0, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 2, 2, +2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 2, 3, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, +1, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 3, 2, 2, 1, 1, 1, 1, +1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 3, 2, 2, 2, 2, 2, 1, 3, 4, 2, +2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, +3, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 3, 2, 3, 2, 4, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, +2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, +1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, +1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0] +check_table = [ +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 1, 0, 0, 194], +[1, -1, 0, 0, 193], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 1, 0, 164], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, -1, 0, 161], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 0, 1, 152], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 0, 1, 145], +[1, 0, 0, 1, 144], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 0, -1, 137], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 1, 0, 133], +[1, 0, 1, 0, 132], +[1, 1, 0, 0, 131], +[1, 1, 0, 0, 130], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 0, 1, 100], +[0, 0, 0, 0, 0], +[1, 0, 0, 1, 98], +[0, 0, 0, 0, 0], +[1, 0, 0, 1, 96], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 1, 0, 88], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, -1, 0, 82], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 1, 0, 74], +[0, 0, 0, 0, 0], +[1, 0, 1, 0, 72], +[0, 0, 0, 0, 0], +[1, 0, 0, -1, 70], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, -1, 0, 0, 67], +[0, 0, 0, 0, 0], +[1, -1, 0, 0, 65], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 1, 0, 0, 56], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, -1, 0, 0, 52], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 1, 0, 0, 44], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 1, 0, 0, 40], +[0, 0, 0, 0, 0], +[1, 0, 0, -1, 38], +[1, 0, -1, 0, 37], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, -1, 0, 33], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, -1, 0, 0, 28], +[0, 0, 0, 0, 0], +[1, 0, -1, 0, 26], +[1, 0, 0, -1, 25], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, -1, 0, 0, 20], +[0, 0, 0, 0, 0], +[1, 0, -1, 0, 18], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 0, -1, 9], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[1, 0, 0, -1, 6], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0], +[0, 0, 0, 0, 0] +] +tet_table = [ +[-1, -1, -1, -1, -1, -1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[4, 4, 4, 4, 4, 4], +[0, 0, 0, 0, 0, 0], +[4, 0, 0, 4, 4, -1], +[1, 1, 1, 1, 1, 1], +[4, 4, 4, 4, 4, 4], +[0, 4, 0, 4, 4, -1], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[5, 5, 5, 5, 5, 5], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[2, 2, 2, 2, 2, 2], +[0, 0, 0, 0, 0, 0], +[2, 0, 2, -1, 0, 2], +[1, 1, 1, 1, 1, 1], +[2, -1, 2, 4, 4, 2], +[0, 0, 0, 0, 0, 0], +[2, 0, 2, 4, 4, 2], +[1, 1, 1, 1, 1, 1], +[2, 4, 2, 4, 4, 2], +[0, 4, 0, 4, 4, 0], +[2, 0, 2, 0, 0, 2], +[1, 1, 1, 1, 1, 1], +[2, 5, 2, 5, 5, 2], +[0, 0, 0, 0, 0, 0], +[2, 0, 2, 0, 0, 2], +[1, 1, 1, 1, 1, 1], +[1, 1, 1, 1, 1, 1], +[0, 1, 1, -1, 0, 1], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[4, 1, 1, 4, 4, 1], +[0, 1, 1, 0, 0, 1], +[4, 0, 0, 4, 4, 0], +[2, 2, 2, 2, 2, 2], +[-1, 1, 1, 4, 4, 1], +[0, 1, 1, 4, 4, 1], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[5, 1, 1, 5, 5, 1], +[0, 1, 1, 0, 0, 1], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[8, 8, 8, 8, 8, 8], +[1, 1, 1, 4, 4, 1], +[0, 0, 0, 0, 0, 0], +[4, 0, 0, 4, 4, 0], +[4, 4, 4, 4, 4, 4], +[1, 1, 1, 4, 4, 1], +[0, 4, 0, 4, 4, 0], +[0, 0, 0, 0, 0, 0], +[4, 4, 4, 4, 4, 4], +[1, 1, 1, 5, 5, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[5, 5, 5, 5, 5, 5], +[6, 6, 6, 6, 6, 6], +[6, -1, 0, 6, 0, 6], +[6, 0, 0, 6, 0, 6], +[6, 1, 1, 6, 1, 6], +[4, 4, 4, 4, 4, 4], +[0, 0, 0, 0, 0, 0], +[4, 0, 0, 4, 4, 4], +[1, 1, 1, 1, 1, 1], +[6, 4, -1, 6, 4, 6], +[6, 4, 0, 6, 4, 6], +[6, 0, 0, 6, 0, 6], +[6, 1, 1, 6, 1, 6], +[5, 5, 5, 5, 5, 5], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[2, 2, 2, 2, 2, 2], +[0, 0, 0, 0, 0, 0], +[2, 0, 2, 2, 0, 2], +[1, 1, 1, 1, 1, 1], +[2, 2, 2, 2, 2, 2], +[0, 0, 0, 0, 0, 0], +[2, 0, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[2, 4, 2, 2, 4, 2], +[0, 4, 0, 4, 4, 0], +[2, 0, 2, 2, 0, 2], +[1, 1, 1, 1, 1, 1], +[2, 2, 2, 2, 2, 2], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[6, 1, 1, 6, -1, 6], +[6, 1, 1, 6, 0, 6], +[6, 0, 0, 6, 0, 6], +[6, 2, 2, 6, 2, 6], +[4, 1, 1, 4, 4, 1], +[0, 1, 1, 0, 0, 1], +[4, 0, 0, 4, 4, 4], +[2, 2, 2, 2, 2, 2], +[6, 1, 1, 6, 4, 6], +[6, 1, 1, 6, 4, 6], +[6, 0, 0, 6, 0, 6], +[6, 2, 2, 6, 2, 6], +[5, 1, 1, 5, 5, 1], +[0, 1, 1, 0, 0, 1], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[6, 6, 6, 6, 6, 6], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[4, 4, 4, 4, 4, 4], +[1, 1, 1, 1, 4, 1], +[0, 4, 0, 4, 4, 0], +[0, 0, 0, 0, 0, 0], +[4, 4, 4, 4, 4, 4], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 5, 0, 5, 0, 5], +[5, 5, 5, 5, 5, 5], +[5, 5, 5, 5, 5, 5], +[0, 5, 0, 5, 0, 5], +[-1, 5, 0, 5, 0, 5], +[1, 5, 1, 5, 1, 5], +[4, 5, -1, 5, 4, 5], +[0, 5, 0, 5, 0, 5], +[4, 5, 0, 5, 4, 5], +[1, 5, 1, 5, 1, 5], +[4, 4, 4, 4, 4, 4], +[0, 4, 0, 4, 4, 4], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[6, 6, 6, 6, 6, 6], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[2, 5, 2, 5, -1, 5], +[0, 5, 0, 5, 0, 5], +[2, 5, 2, 5, 0, 5], +[1, 5, 1, 5, 1, 5], +[2, 5, 2, 5, 4, 5], +[0, 5, 0, 5, 0, 5], +[2, 5, 2, 5, 4, 5], +[1, 5, 1, 5, 1, 5], +[2, 4, 2, 4, 4, 2], +[0, 4, 0, 4, 4, 4], +[2, 0, 2, 0, 0, 2], +[1, 1, 1, 1, 1, 1], +[2, 6, 2, 6, 6, 2], +[0, 0, 0, 0, 0, 0], +[2, 0, 2, 0, 0, 2], +[1, 1, 1, 1, 1, 1], +[1, 1, 1, 1, 1, 1], +[0, 1, 1, 1, 0, 1], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[4, 1, 1, 1, 4, 1], +[0, 1, 1, 1, 0, 1], +[4, 0, 0, 4, 4, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[0, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[5, 5, 5, 5, 5, 5], +[1, 1, 1, 1, 4, 1], +[0, 0, 0, 0, 0, 0], +[4, 0, 0, 4, 4, 0], +[4, 4, 4, 4, 4, 4], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[4, 4, 4, 4, 4, 4], +[1, 1, 1, 1, 1, 1], +[6, 0, 0, 6, 0, 6], +[0, 0, 0, 0, 0, 0], +[6, 6, 6, 6, 6, 6], +[5, 5, 5, 5, 5, 5], +[5, 5, 0, 5, 0, 5], +[5, 5, 0, 5, 0, 5], +[5, 5, 1, 5, 1, 5], +[4, 4, 4, 4, 4, 4], +[0, 0, 0, 0, 0, 0], +[4, 4, 0, 4, 4, 4], +[1, 1, 1, 1, 1, 1], +[4, 4, 4, 4, 4, 4], +[4, 4, 0, 4, 4, 4], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[8, 8, 8, 8, 8, 8], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[2, 2, 2, 2, 2, 2], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 0, 2], +[1, 1, 1, 1, 1, 1], +[2, 2, 2, 2, 2, 2], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[2, 2, 2, 2, 2, 2], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[4, 1, 1, 4, 4, 1], +[2, 2, 2, 2, 2, 2], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1], +[1, 1, 1, 1, 1, 1], +[1, 1, 1, 1, 0, 1], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[2, 4, 2, 4, 4, 2], +[1, 1, 1, 1, 1, 1], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[2, 2, 2, 2, 2, 2], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[5, 5, 5, 5, 5, 5], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[4, 4, 4, 4, 4, 4], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[4, 4, 4, 4, 4, 4], +[1, 1, 1, 1, 1, 1], +[0, 0, 0, 0, 0, 0], +[0, 0, 0, 0, 0, 0], +[12, 12, 12, 12, 12, 12] +] diff --git a/apps/third_party/CRM/util/utils.py b/apps/third_party/CRM/util/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..ab3cad9b703b1cdd9a3d6a66e82f898185ebf6c8 --- /dev/null +++ b/apps/third_party/CRM/util/utils.py @@ -0,0 +1,194 @@ +import numpy as np +import torch +import random + + +# Reworked so this matches gluPerspective / glm::perspective, using fovy +def perspective(fovx=0.7854, aspect=1.0, n=0.1, f=1000.0, device=None): + # y = np.tan(fovy / 2) + x = np.tan(fovx / 2) + return torch.tensor([[1/x, 0, 0, 0], + [ 0, -aspect/x, 0, 0], + [ 0, 0, -(f+n)/(f-n), -(2*f*n)/(f-n)], + [ 0, 0, -1, 0]], dtype=torch.float32, device=device) + + +def translate(x, y, z, device=None): + return torch.tensor([[1, 0, 0, x], + [0, 1, 0, y], + [0, 0, 1, z], + [0, 0, 0, 1]], dtype=torch.float32, device=device) + + +def rotate_x(a, device=None): + s, c = np.sin(a), np.cos(a) + return torch.tensor([[1, 0, 0, 0], + [0, c, -s, 0], + [0, s, c, 0], + [0, 0, 0, 1]], dtype=torch.float32, device=device) + + +def rotate_y(a, device=None): + s, c = np.sin(a), np.cos(a) + return torch.tensor([[ c, 0, s, 0], + [ 0, 1, 0, 0], + [-s, 0, c, 0], + [ 0, 0, 0, 1]], dtype=torch.float32, device=device) + + +def rotate_z(a, device=None): + s, c = np.sin(a), np.cos(a) + return torch.tensor([[c, -s, 0, 0], + [s, c, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1]], dtype=torch.float32, device=device) + +@torch.no_grad() +def batch_random_rotation_translation(b, t, device=None): + m = np.random.normal(size=[b, 3, 3]) + m[:, 1] = np.cross(m[:, 0], m[:, 2]) + m[:, 2] = np.cross(m[:, 0], m[:, 1]) + m = m / np.linalg.norm(m, axis=2, keepdims=True) + m = np.pad(m, [[0, 0], [0, 1], [0, 1]], mode='constant') + m[:, 3, 3] = 1.0 + m[:, :3, 3] = np.random.uniform(-t, t, size=[b, 3]) + return torch.tensor(m, dtype=torch.float32, device=device) + +@torch.no_grad() +def random_rotation_translation(t, device=None): + m = np.random.normal(size=[3, 3]) + m[1] = np.cross(m[0], m[2]) + m[2] = np.cross(m[0], m[1]) + m = m / np.linalg.norm(m, axis=1, keepdims=True) + m = np.pad(m, [[0, 1], [0, 1]], mode='constant') + m[3, 3] = 1.0 + m[:3, 3] = np.random.uniform(-t, t, size=[3]) + return torch.tensor(m, dtype=torch.float32, device=device) + + +@torch.no_grad() +def random_rotation(device=None): + m = np.random.normal(size=[3, 3]) + m[1] = np.cross(m[0], m[2]) + m[2] = np.cross(m[0], m[1]) + m = m / np.linalg.norm(m, axis=1, keepdims=True) + m = np.pad(m, [[0, 1], [0, 1]], mode='constant') + m[3, 3] = 1.0 + m[:3, 3] = np.array([0,0,0]).astype(np.float32) + return torch.tensor(m, dtype=torch.float32, device=device) + + +def dot(x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return torch.sum(x*y, -1, keepdim=True) + + +def length(x: torch.Tensor, eps: float =1e-20) -> torch.Tensor: + return torch.sqrt(torch.clamp(dot(x,x), min=eps)) # Clamp to avoid nan gradients because grad(sqrt(0)) = NaN + + +def safe_normalize(x: torch.Tensor, eps: float =1e-20) -> torch.Tensor: + return x / length(x, eps) + + +def lr_schedule(iter, warmup_iter, scheduler_decay): + if iter < warmup_iter: + return iter / warmup_iter + return max(0.0, 10 ** ( + -(iter - warmup_iter) * scheduler_decay)) + + +def trans_depth(depth): + depth = depth[0].detach().cpu().numpy() + valid = depth > 0 + depth[valid] -= depth[valid].min() + depth[valid] = ((depth[valid] / depth[valid].max()) * 255) + return depth.astype('uint8') + + +def nan_to_num(input, nan=0.0, posinf=None, neginf=None, *, out=None): + assert isinstance(input, torch.Tensor) + if posinf is None: + posinf = torch.finfo(input.dtype).max + if neginf is None: + neginf = torch.finfo(input.dtype).min + assert nan == 0 + return torch.clamp(input.unsqueeze(0).nansum(0), min=neginf, max=posinf, out=out) + + +def load_item(filepath): + with open(filepath, 'r') as f: + items = [name.strip() for name in f.readlines()] + return set(items) + +def load_prompt(filepath): + uuid2prompt = {} + with open(filepath, 'r') as f: + for line in f.readlines(): + list_line = line.split(',') + uuid2prompt[list_line[0]] = ','.join(list_line[1:]).strip() + return uuid2prompt + +def resize_and_center_image(image_tensor, scale=0.95, c = 0, shift = 0, rgb=False, aug_shift = 0): + if scale == 1: + return image_tensor + B, C, H, W = image_tensor.shape + new_H, new_W = int(H * scale), int(W * scale) + resized_image = torch.nn.functional.interpolate(image_tensor, size=(new_H, new_W), mode='bilinear', align_corners=False).squeeze(0) + background = torch.zeros_like(image_tensor) + c + start_y, start_x = (H - new_H) // 2, (W - new_W) // 2 + if shift == 0: + background[:, :, start_y:start_y + new_H, start_x:start_x + new_W] = resized_image + else: + for i in range(B): + randx = random.randint(-shift, shift) + randy = random.randint(-shift, shift) + if rgb == True: + if i == 0 or i==2 or i==4: + randx = 0 + randy = 0 + background[i, :, start_y+randy:start_y + new_H+randy, start_x+randx:start_x + new_W+randx] = resized_image[i] + if aug_shift == 0: + return background + for i in range(B): + for j in range(C): + background[i, j, :, :] += (random.random() - 0.5)*2 * aug_shift / 255 + return background + +def get_tri(triview_color, dim = 1, blender=True, c = 0, scale=0.95, shift = 0, fix = False, rgb=False, aug_shift = 0): + # triview_color: [6,C,H,W] + # rgb is useful when shift is not 0 + triview_color = resize_and_center_image(triview_color, scale=scale, c = c, shift=shift,rgb=rgb, aug_shift = aug_shift) + if blender is False: + triview_color0 = torch.rot90(triview_color[0],k=2,dims=[1,2]) + triview_color1 = torch.rot90(triview_color[4],k=1,dims=[1,2]).flip(2).flip(1) + triview_color2 = torch.rot90(triview_color[5],k=1,dims=[1,2]).flip(2) + triview_color3 = torch.rot90(triview_color[3],k=2,dims=[1,2]).flip(2) + triview_color4 = torch.rot90(triview_color[1],k=3,dims=[1,2]).flip(1) + triview_color5 = torch.rot90(triview_color[2],k=3,dims=[1,2]).flip(1).flip(2) + else: + triview_color0 = torch.rot90(triview_color[2],k=2,dims=[1,2]) + triview_color1 = torch.rot90(triview_color[4],k=0,dims=[1,2]).flip(2).flip(1) + triview_color2 = torch.rot90(torch.rot90(triview_color[0],k=3,dims=[1,2]).flip(2), k=2,dims=[1,2]) + triview_color3 = torch.rot90(torch.rot90(triview_color[5],k=2,dims=[1,2]).flip(2), k=2,dims=[1,2]) + triview_color4 = torch.rot90(triview_color[1],k=2,dims=[1,2]).flip(1).flip(1).flip(2) + triview_color5 = torch.rot90(triview_color[3],k=1,dims=[1,2]).flip(1).flip(2) + if fix == True: + triview_color0[1] = triview_color0[1] * 0 + triview_color0[2] = triview_color0[2] * 0 + triview_color3[1] = triview_color3[1] * 0 + triview_color3[2] = triview_color3[2] * 0 + + triview_color1[0] = triview_color1[0] * 0 + triview_color1[1] = triview_color1[1] * 0 + triview_color4[0] = triview_color4[0] * 0 + triview_color4[1] = triview_color4[1] * 0 + + triview_color2[0] = triview_color2[0] * 0 + triview_color2[2] = triview_color2[2] * 0 + triview_color5[0] = triview_color5[0] * 0 + triview_color5[2] = triview_color5[2] * 0 + color_tensor1_gt = torch.cat((triview_color0, triview_color1, triview_color2), dim=2) + color_tensor2_gt = torch.cat((triview_color3, triview_color4, triview_color5), dim=2) + color_tensor_gt = torch.cat((color_tensor1_gt, color_tensor2_gt), dim = dim) + return color_tensor_gt + diff --git a/apps/third_party/InstantMeshes b/apps/third_party/InstantMeshes new file mode 100644 index 0000000000000000000000000000000000000000..2350cb16946fb0e157b7195fd0688a4c0a2e4596 --- /dev/null +++ b/apps/third_party/InstantMeshes @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1946606e15d452b3d16ff3ec0161ff12053b6e0c8568d3eab6cd7e97486448d +size 2759416 diff --git a/apps/third_party/Wonder3D/.gitignore b/apps/third_party/Wonder3D/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..061fb1affd69161b70eb17c92f8172eb60cf92d6 --- /dev/null +++ b/apps/third_party/Wonder3D/.gitignore @@ -0,0 +1,192 @@ +# Initially taken from Github's Python gitignore file + +ckpts +sam_pt +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# tests and logs +tests/fixtures/cached_*_text.txt +logs/ +lightning_logs/ +lang_code_data/ + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +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 +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# 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/ + +# vscode +.vs +.vscode + +# Pycharm +.idea + +# TF code +tensorflow_code + +# Models +proc_data + +# examples +runs +/runs_old +/wandb +/examples/runs +/examples/**/*.args +/examples/rag/sweep + +# data +/data +serialization_dir + +# emacs +*.*~ +debug.env + +# vim +.*.swp + +#ctags +tags + +# pre-commit +.pre-commit* + +# .lock +*.lock + +# DS_Store (MacOS) +.DS_Store +# RL pipelines may produce mp4 outputs +*.mp4 + +# dependencies +/transformers + +# ruff +.ruff_cache + +# ckpts +*.ckpt + +outputs/* + +NeuS/exp/* +NeuS/test_scenes/* +NeuS/mesh2tex/* +neus_configs +vast/* +render_results +experiments/* +ckpts/* +neus/* +instant-nsr-pl/exp/* \ No newline at end of file diff --git a/apps/third_party/Wonder3D/1gpu.yaml b/apps/third_party/Wonder3D/1gpu.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ac5e9f453e944be76e55ce2a3992788f054f5cff --- /dev/null +++ b/apps/third_party/Wonder3D/1gpu.yaml @@ -0,0 +1,15 @@ +compute_environment: LOCAL_MACHINE +distributed_type: 'NO' +downcast_bf16: 'no' +gpu_ids: '0' +machine_rank: 0 +main_training_function: main +mixed_precision: 'no' +num_machines: 1 +num_processes: 1 +rdzv_backend: static +same_network: true +tpu_env: [] +tpu_use_cluster: false +tpu_use_sudo: false +use_cpu: false diff --git a/apps/third_party/Wonder3D/8gpu.yaml b/apps/third_party/Wonder3D/8gpu.yaml new file mode 100644 index 0000000000000000000000000000000000000000..10ba6f1e6b9bf4b238e0b7245a78fd4ea22fc7a9 --- /dev/null +++ b/apps/third_party/Wonder3D/8gpu.yaml @@ -0,0 +1,15 @@ +compute_environment: LOCAL_MACHINE +distributed_type: MULTI_GPU +downcast_bf16: 'no' +gpu_ids: all +machine_rank: 0 +main_training_function: main +mixed_precision: 'no' +num_machines: 1 +num_processes: 8 +rdzv_backend: static +same_network: true +tpu_env: [] +tpu_use_cluster: false +tpu_use_sudo: false +use_cpu: false diff --git a/apps/third_party/Wonder3D/LICENSE b/apps/third_party/Wonder3D/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..0ad25db4bd1d86c452db3f9602ccdbe172438f52 --- /dev/null +++ b/apps/third_party/Wonder3D/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/apps/third_party/Wonder3D/NeuS/confs/wmask.conf b/apps/third_party/Wonder3D/NeuS/confs/wmask.conf new file mode 100644 index 0000000000000000000000000000000000000000..d37c91eb9462b269218600a812077746c614c128 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/confs/wmask.conf @@ -0,0 +1,95 @@ +general { + base_exp_dir = ./exp/neus/CASE_NAME/ + recording = [ + ./, + ./models + ] +} + +dataset { + data_dir = ./outputs/ + object_name = CASE_NAME + object_viewidx = 1 + imSize = [256, 256] + load_color = True + stage = coarse + mtype = mlp + normal_system: front + num_views = 6 +} + +train { + learning_rate = 5e-4 + learning_rate_alpha = 0.05 + end_iter = 1000 # longer time, better result. 1w will be ok for most cases + + batch_size = 512 + validate_resolution_level = 1 + warm_up_end = 500 + anneal_end = 0 + use_white_bkgd = True + + save_freq = 5000 + val_freq = 5000 + val_mesh_freq =5000 + report_freq = 100 + + color_weight = 1.0 + igr_weight = 0.1 + mask_weight = 1.0 + normal_weight = 1.0 + sparse_weight = 0.1 + +} + +model { + nerf { + D = 8, + d_in = 4, + d_in_view = 3, + W = 256, + multires = 10, + multires_view = 4, + output_ch = 4, + skips=[4], + use_viewdirs=True + } + + sdf_network { + d_out = 257 + d_in = 3 + d_hidden = 256 + n_layers = 8 + skip_in = [4] + multires = 6 + bias = 0.5 + scale = 1.0 + geometric_init = True + weight_norm = True + } + + variance_network { + init_val = 0.3 + } + + rendering_network { + d_feature = 256 + mode = no_view_dir + d_in = 6 + d_out = 3 + d_hidden = 256 + n_layers = 4 + weight_norm = True + multires_view = 0 + squeeze_out = True + } + + neus_renderer { + n_samples = 64 + n_importance = 64 + n_outside = 0 + up_sample_steps = 4 # 1 for simple coarse-to-fine sampling + perturb = 1.0 + sdf_decay_param = 100 + } +} diff --git a/apps/third_party/Wonder3D/NeuS/exp_runner.py b/apps/third_party/Wonder3D/NeuS/exp_runner.py new file mode 100644 index 0000000000000000000000000000000000000000..e383051563a72af91e2d32b0d0410bde9b21308e --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/exp_runner.py @@ -0,0 +1,559 @@ +import os +import time +import logging +import argparse +import numpy as np +import cv2 as cv +import trimesh +import torch +import torch.nn.functional as F +from torch.utils.tensorboard import SummaryWriter +from shutil import copyfile +from icecream import ic +from tqdm import tqdm +from pyhocon import ConfigFactory +from models.dataset_mvdiff import Dataset +from models.fields import RenderingNetwork, SDFNetwork, SingleVarianceNetwork, NeRF +from models.renderer import NeuSRenderer +import pdb +import math + + +def ranking_loss(error, penalize_ratio=0.7, type='mean'): + error, indices = torch.sort(error) + # only sum relatively small errors + s_error = torch.index_select(error, 0, index=indices[: int(penalize_ratio * indices.shape[0])]) + if type == 'mean': + return torch.mean(s_error) + elif type == 'sum': + return torch.sum(s_error) + + +class Runner: + def __init__(self, conf_path, mode='train', case='CASE_NAME', is_continue=False, data_dir=None): + self.device = torch.device('cuda') + + # Configuration + self.conf_path = conf_path + f = open(self.conf_path) + conf_text = f.read() + conf_text = conf_text.replace('CASE_NAME', case) + f.close() + + self.conf = ConfigFactory.parse_string(conf_text) + self.conf['dataset']['data_dir'] = data_dir + self.conf['dataset.data_dir'] = self.conf['dataset.data_dir'].replace('CASE_NAME', case) + self.base_exp_dir = self.conf['general.base_exp_dir'] + os.makedirs(self.base_exp_dir, exist_ok=True) + self.dataset = Dataset(self.conf['dataset']) + self.dataloader = torch.utils.data.DataLoader( + self.dataset, + batch_size=self.conf['train']['batch_size'], + shuffle=True, + num_workers=64, + ) + self.iter_step = 1 + + # Training parameters + self.end_iter = self.conf.get_int('train.end_iter') + self.save_freq = self.conf.get_int('train.save_freq') + self.report_freq = self.conf.get_int('train.report_freq') + self.val_freq = self.conf.get_int('train.val_freq') + self.val_mesh_freq = self.conf.get_int('train.val_mesh_freq') + self.batch_size = self.conf.get_int('train.batch_size') + self.validate_resolution_level = self.conf.get_int('train.validate_resolution_level') + self.learning_rate = self.conf.get_float('train.learning_rate') + self.learning_rate_alpha = self.conf.get_float('train.learning_rate_alpha') + self.use_white_bkgd = self.conf.get_bool('train.use_white_bkgd') + self.warm_up_end = self.conf.get_float('train.warm_up_end', default=0.0) + self.anneal_end = self.conf.get_float('train.anneal_end', default=0.0) + + # Weights + self.color_weight = self.conf.get_float('train.color_weight') + self.igr_weight = self.conf.get_float('train.igr_weight') + self.mask_weight = self.conf.get_float('train.mask_weight') + self.normal_weight = self.conf.get_float('train.normal_weight') + self.sparse_weight = self.conf.get_float('train.sparse_weight') + self.is_continue = is_continue + self.mode = mode + self.model_list = [] + self.writer = None + + # Networks + params_to_train_slow = [] + self.nerf_outside = NeRF(**self.conf['model.nerf']).to(self.device) + self.sdf_network = SDFNetwork(**self.conf['model.sdf_network']).to(self.device) + self.deviation_network = SingleVarianceNetwork(**self.conf['model.variance_network']).to(self.device) + self.color_network = RenderingNetwork(**self.conf['model.rendering_network']).to(self.device) + # params_to_train += list(self.nerf_outside.parameters()) + params_to_train_slow += list(self.sdf_network.parameters()) + params_to_train_slow += list(self.deviation_network.parameters()) + # params_to_train += list(self.color_network.parameters()) + + self.optimizer = torch.optim.Adam( + [{'params': params_to_train_slow}, {'params': self.color_network.parameters(), 'lr': self.learning_rate * 2}], lr=self.learning_rate + ) + + self.renderer = NeuSRenderer( + self.nerf_outside, self.sdf_network, self.deviation_network, self.color_network, **self.conf['model.neus_renderer'] + ) + + # Load checkpoint + latest_model_name = None + if is_continue: + model_list_raw = os.listdir(os.path.join(self.base_exp_dir, 'checkpoints')) + model_list = [] + for model_name in model_list_raw: + if model_name[-3:] == 'pth' and int(model_name[5:-4]) <= self.end_iter: + model_list.append(model_name) + model_list.sort() + latest_model_name = model_list[-1] + + if latest_model_name is not None: + logging.info('Find checkpoint: {}'.format(latest_model_name)) + self.load_checkpoint(latest_model_name) + + # Backup codes and configs for debug + if self.mode[:5] == 'train': + self.file_backup() + + def train(self): + self.writer = SummaryWriter(log_dir=os.path.join(self.base_exp_dir, 'logs')) + self.update_learning_rate() + res_step = self.end_iter - self.iter_step + image_perm = self.get_image_perm() + + num_train_epochs = math.ceil(res_step / len(self.dataloader)) + + print("training ", num_train_epochs, " epoches") + + for epoch in range(num_train_epochs): + # for iter_i in tqdm(range(res_step)): + print("epoch ", epoch) + for iter_i, data in enumerate(self.dataloader): + # img_idx = image_perm[self.iter_step % len(image_perm)] + # data = self.dataset.gen_random_rays_at(img_idx, self.batch_size) + data = data.cuda() + + rays_o, rays_d, true_rgb, mask, true_normal, cosines = ( + data[:, :3], + data[:, 3:6], + data[:, 6:9], + data[:, 9:10], + data[:, 10:13], + data[:, 13:], + ) + # near, far = self.dataset.near_far_from_sphere(rays_o, rays_d) + near, far = self.dataset.get_near_far() + + background_rgb = None + if self.use_white_bkgd: + background_rgb = torch.ones([1, 3]) + + if self.mask_weight > 0.0: + mask = (mask > 0.5).float() + else: + mask = torch.ones_like(mask) + + cosines[cosines > -0.1] = 0 + mask = ((mask > 0) & (cosines < -0.1)).to(torch.float32) + + mask_sum = mask.sum() + 1e-5 + render_out = self.renderer.render( + rays_o, rays_d, near, far, background_rgb=background_rgb, cos_anneal_ratio=self.get_cos_anneal_ratio() + ) + + color_fine = render_out['color_fine'] + s_val = render_out['s_val'] + cdf_fine = render_out['cdf_fine'] + gradient_error = render_out['gradient_error'] + weight_max = render_out['weight_max'] + weight_sum = render_out['weight_sum'] + + # Loss + # color_error = (color_fine - true_rgb) * mask + # color_fine_loss = F.l1_loss(color_error, torch.zeros_like(color_error), reduction='sum') / mask_sum + + color_errors = (color_fine - true_rgb).abs().sum(dim=1) + color_fine_loss = ranking_loss(color_errors[mask[:, 0] > 0]) + + psnr = 20.0 * torch.log10(1.0 / (((color_fine - true_rgb) ** 2 * mask).sum() / (mask_sum * 3.0)).sqrt()) + + eikonal_loss = gradient_error + + # pdb.set_trace() + mask_errors = F.binary_cross_entropy(weight_sum.clip(1e-3, 1.0 - 1e-3), mask, reduction='none') + mask_loss = ranking_loss(mask_errors[:, 0], penalize_ratio=0.8) + + def feasible(key): + return (key in render_out) and (render_out[key] is not None) + + # calculate normal loss + n_samples = self.renderer.n_samples + self.renderer.n_importance + normals = render_out['gradients'] * render_out['weights'][:, :n_samples, None] + if feasible('inside_sphere'): + normals = normals * render_out['inside_sphere'][..., None] + normals = normals.sum(dim=1) + + # pdb.set_trace() + normal_errors = 1 - F.cosine_similarity(normals, true_normal, dim=1) + # normal_error = normal_error * mask[:, 0] + # normal_loss = F.l1_loss(normal_error, torch.zeros_like(normal_error), reduction='sum') / mask_sum + normal_errors = normal_errors * torch.exp(cosines.abs()[:, 0]) / torch.exp(cosines.abs()).sum() + normal_loss = ranking_loss(normal_errors[mask[:, 0] > 0], penalize_ratio=0.9, type='sum') + + sparse_loss = render_out['sparse_loss'] + + loss = ( + color_fine_loss * self.color_weight + + eikonal_loss * self.igr_weight + + sparse_loss * self.sparse_weight + + mask_loss * self.mask_weight + + normal_loss * self.normal_weight + ) + + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + + self.writer.add_scalar('Loss/loss', loss, self.iter_step) + self.writer.add_scalar('Loss/color_loss', color_fine_loss, self.iter_step) + self.writer.add_scalar('Loss/eikonal_loss', eikonal_loss, self.iter_step) + self.writer.add_scalar('Statistics/s_val', s_val.mean(), self.iter_step) + self.writer.add_scalar('Statistics/cdf', (cdf_fine[:, :1] * mask).sum() / mask_sum, self.iter_step) + self.writer.add_scalar('Statistics/weight_max', (weight_max * mask).sum() / mask_sum, self.iter_step) + self.writer.add_scalar('Statistics/psnr', psnr, self.iter_step) + + if self.iter_step % self.report_freq == 0: + print(self.base_exp_dir) + print( + 'iter:{:8>d} loss = {:4>f} color_ls = {:4>f} eik_ls = {:4>f} normal_ls = {:4>f} mask_ls = {:4>f} sparse_ls = {:4>f} lr={:5>f}'.format( + self.iter_step, + loss, + color_fine_loss, + eikonal_loss, + normal_loss, + mask_loss, + sparse_loss, + self.optimizer.param_groups[0]['lr'], + ) + ) + print('iter:{:8>d} s_val = {:4>f}'.format(self.iter_step, s_val.mean())) + + if self.iter_step % self.val_mesh_freq == 0: + self.validate_mesh(resolution=256) + + self.update_learning_rate() + + self.iter_step += 1 + + if self.iter_step % self.val_freq == 0: + self.validate_image(idx=0) + self.validate_image(idx=1) + self.validate_image(idx=2) + self.validate_image(idx=3) + + if self.iter_step % self.save_freq == 0: + self.save_checkpoint() + + if self.iter_step % len(image_perm) == 0: + image_perm = self.get_image_perm() + + def get_image_perm(self): + return torch.randperm(self.dataset.n_images) + + def get_cos_anneal_ratio(self): + if self.anneal_end == 0.0: + return 1.0 + else: + return np.min([1.0, self.iter_step / self.anneal_end]) + + def update_learning_rate(self): + if self.iter_step < self.warm_up_end: + learning_factor = self.iter_step / self.warm_up_end + else: + alpha = self.learning_rate_alpha + progress = (self.iter_step - self.warm_up_end) / (self.end_iter - self.warm_up_end) + learning_factor = (np.cos(np.pi * progress) + 1.0) * 0.5 * (1 - alpha) + alpha + + for g in self.optimizer.param_groups: + g['lr'] = self.learning_rate * learning_factor + + def file_backup(self): + dir_lis = self.conf['general.recording'] + os.makedirs(os.path.join(self.base_exp_dir, 'recording'), exist_ok=True) + for dir_name in dir_lis: + cur_dir = os.path.join(self.base_exp_dir, 'recording', dir_name) + os.makedirs(cur_dir, exist_ok=True) + files = os.listdir(dir_name) + for f_name in files: + if f_name[-3:] == '.py': + copyfile(os.path.join(dir_name, f_name), os.path.join(cur_dir, f_name)) + + copyfile(self.conf_path, os.path.join(self.base_exp_dir, 'recording', 'config.conf')) + + def load_checkpoint(self, checkpoint_name): + checkpoint = torch.load(os.path.join(self.base_exp_dir, 'checkpoints', checkpoint_name), map_location=self.device) + self.nerf_outside.load_state_dict(checkpoint['nerf']) + self.sdf_network.load_state_dict(checkpoint['sdf_network_fine']) + self.deviation_network.load_state_dict(checkpoint['variance_network_fine']) + self.color_network.load_state_dict(checkpoint['color_network_fine']) + self.optimizer.load_state_dict(checkpoint['optimizer']) + self.iter_step = checkpoint['iter_step'] + + logging.info('End') + + def save_checkpoint(self): + checkpoint = { + 'nerf': self.nerf_outside.state_dict(), + 'sdf_network_fine': self.sdf_network.state_dict(), + 'variance_network_fine': self.deviation_network.state_dict(), + 'color_network_fine': self.color_network.state_dict(), + 'optimizer': self.optimizer.state_dict(), + 'iter_step': self.iter_step, + } + + os.makedirs(os.path.join(self.base_exp_dir, 'checkpoints'), exist_ok=True) + torch.save(checkpoint, os.path.join(self.base_exp_dir, 'checkpoints', 'ckpt_{:0>6d}.pth'.format(self.iter_step))) + + def validate_image(self, idx=-1, resolution_level=-1): + if idx < 0: + idx = np.random.randint(self.dataset.n_images) + + print('Validate: iter: {}, camera: {}'.format(self.iter_step, idx)) + + if resolution_level < 0: + resolution_level = self.validate_resolution_level + rays_o, rays_d = self.dataset.gen_rays_at(idx, resolution_level=resolution_level) + H, W, _ = rays_o.shape + rays_o = rays_o.reshape(-1, 3).split(self.batch_size) + rays_d = rays_d.reshape(-1, 3).split(self.batch_size) + + out_rgb_fine = [] + out_normal_fine = [] + out_mask = [] + + for rays_o_batch, rays_d_batch in zip(rays_o, rays_d): + # near, far = self.dataset.near_far_from_sphere(rays_o_batch, rays_d_batch) + near, far = self.dataset.get_near_far() + background_rgb = torch.ones([1, 3]) if self.use_white_bkgd else None + + render_out = self.renderer.render( + rays_o_batch, rays_d_batch, near, far, cos_anneal_ratio=self.get_cos_anneal_ratio(), background_rgb=background_rgb + ) + + def feasible(key): + return (key in render_out) and (render_out[key] is not None) + + if feasible('color_fine'): + out_rgb_fine.append(render_out['color_fine'].detach().cpu().numpy()) + if feasible('gradients') and feasible('weights'): + n_samples = self.renderer.n_samples + self.renderer.n_importance + normals = render_out['gradients'] * render_out['weights'][:, :n_samples, None] + if feasible('inside_sphere'): + normals = normals * render_out['inside_sphere'][..., None] + normals = normals.sum(dim=1).detach().cpu().numpy() + out_normal_fine.append(normals) + + if feasible('weight_sum'): + out_mask.append(render_out['weight_sum'].detach().clip(0, 1).cpu().numpy()) + + del render_out + + img_fine = None + if len(out_rgb_fine) > 0: + img_fine = (np.concatenate(out_rgb_fine, axis=0).reshape([H, W, 3, -1]) * 256).clip(0, 255) + + mask_map = None + if len(out_mask) > 0: + mask_map = (np.concatenate(out_mask, axis=0).reshape([H, W, -1]) * 256).clip(0, 255) + + normal_img = None + if len(out_normal_fine) > 0: + normal_img = np.concatenate(out_normal_fine, axis=0) + rot = np.linalg.inv(self.dataset.pose_all[idx, :3, :3].detach().cpu().numpy()) + normal_img = (np.matmul(rot[None, :, :], normal_img[:, :, None]).reshape([H, W, 3, -1]) * 128 + 128).clip(0, 255) + + os.makedirs(os.path.join(self.base_exp_dir, 'validations_fine'), exist_ok=True) + os.makedirs(os.path.join(self.base_exp_dir, 'normals'), exist_ok=True) + + for i in range(img_fine.shape[-1]): + if len(out_rgb_fine) > 0: + cv.imwrite( + os.path.join(self.base_exp_dir, 'validations_fine', '{:0>8d}_{}_{}.png'.format(self.iter_step, i, idx)), + np.concatenate( + [ + img_fine[..., i], + self.dataset.image_at(idx, resolution_level=resolution_level), + self.dataset.mask_at(idx, resolution_level=resolution_level), + ] + ), + ) + if len(out_normal_fine) > 0: + cv.imwrite( + os.path.join(self.base_exp_dir, 'normals', '{:0>8d}_{}_{}.png'.format(self.iter_step, i, idx)), + np.concatenate([normal_img[..., i], self.dataset.normal_cam_at(idx, resolution_level=resolution_level)])[:, :, ::-1], + ) + if len(out_mask) > 0: + cv.imwrite(os.path.join(self.base_exp_dir, 'normals', '{:0>8d}_{}_{}_mask.png'.format(self.iter_step, i, idx)), mask_map[..., i]) + + def save_maps(self, idx, img_idx, resolution_level=1): + view_types = ['front', 'back', 'left', 'right'] + print('Validate: iter: {}, camera: {}'.format(self.iter_step, idx)) + + rays_o, rays_d = self.dataset.gen_rays_at(idx, resolution_level=resolution_level) + H, W, _ = rays_o.shape + rays_o = rays_o.reshape(-1, 3).split(self.batch_size) + rays_d = rays_d.reshape(-1, 3).split(self.batch_size) + + out_rgb_fine = [] + out_normal_fine = [] + out_mask = [] + + for rays_o_batch, rays_d_batch in zip(rays_o, rays_d): + # near, far = self.dataset.near_far_from_sphere(rays_o_batch, rays_d_batch) + near, far = self.dataset.get_near_far() + background_rgb = torch.ones([1, 3]) if self.use_white_bkgd else None + + render_out = self.renderer.render( + rays_o_batch, rays_d_batch, near, far, cos_anneal_ratio=self.get_cos_anneal_ratio(), background_rgb=background_rgb + ) + + def feasible(key): + return (key in render_out) and (render_out[key] is not None) + + if feasible('color_fine'): + out_rgb_fine.append(render_out['color_fine'].detach().cpu().numpy()) + if feasible('gradients') and feasible('weights'): + n_samples = self.renderer.n_samples + self.renderer.n_importance + normals = render_out['gradients'] * render_out['weights'][:, :n_samples, None] + if feasible('inside_sphere'): + normals = normals * render_out['inside_sphere'][..., None] + normals = normals.sum(dim=1).detach().cpu().numpy() + out_normal_fine.append(normals) + + if feasible('weight_sum'): + out_mask.append(render_out['weight_sum'].detach().clip(0, 1).cpu().numpy()) + + del render_out + + img_fine = None + if len(out_rgb_fine) > 0: + img_fine = (np.concatenate(out_rgb_fine, axis=0).reshape([H, W, 3]) * 256).clip(0, 255) + + mask_map = None + if len(out_mask) > 0: + mask_map = (np.concatenate(out_mask, axis=0).reshape([H, W, 1]) * 256).clip(0, 255) + + normal_img = None + if len(out_normal_fine) > 0: + normal_img = np.concatenate(out_normal_fine, axis=0) + # rot = np.linalg.inv(self.dataset.pose_all[idx, :3, :3].detach().cpu().numpy()) + world_normal_img = (normal_img.reshape([H, W, 3]) * 128 + 128).clip(0, 255) + + os.makedirs(os.path.join(self.base_exp_dir, 'coarse_maps'), exist_ok=True) + img_rgba = np.concatenate([img_fine[:, :, ::-1], mask_map], axis=-1) + normal_rgba = np.concatenate([world_normal_img[:, :, ::-1], mask_map], axis=-1) + + cv.imwrite(os.path.join(self.base_exp_dir, 'coarse_maps', "normals_mlp_%03d_%s.png" % (img_idx, view_types[idx])), img_rgba) + cv.imwrite(os.path.join(self.base_exp_dir, 'coarse_maps', "normals_grad_%03d_%s.png" % (img_idx, view_types[idx])), normal_rgba) + + def render_novel_image(self, idx_0, idx_1, ratio, resolution_level): + """ + Interpolate view between two cameras. + """ + rays_o, rays_d = self.dataset.gen_rays_between(idx_0, idx_1, ratio, resolution_level=resolution_level) + H, W, _ = rays_o.shape + rays_o = rays_o.reshape(-1, 3).split(self.batch_size) + rays_d = rays_d.reshape(-1, 3).split(self.batch_size) + + out_rgb_fine = [] + for rays_o_batch, rays_d_batch in zip(rays_o, rays_d): + # near, far = self.dataset.near_far_from_sphere(rays_o_batch, rays_d_batch) + near, far = self.dataset.get_near_far() + background_rgb = torch.ones([1, 3]) if self.use_white_bkgd else None + + render_out = self.renderer.render( + rays_o_batch, rays_d_batch, near, far, cos_anneal_ratio=self.get_cos_anneal_ratio(), background_rgb=background_rgb + ) + + out_rgb_fine.append(render_out['color_fine'].detach().cpu().numpy()) + + del render_out + + img_fine = (np.concatenate(out_rgb_fine, axis=0).reshape([H, W, 3]) * 256).clip(0, 255).astype(np.uint8) + return img_fine + + def validate_mesh(self, world_space=False, resolution=64, threshold=0.0): + bound_min = torch.tensor(self.dataset.object_bbox_min, dtype=torch.float32) + bound_max = torch.tensor(self.dataset.object_bbox_max, dtype=torch.float32) + + vertices, triangles, vertex_colors = self.renderer.extract_geometry(bound_min, bound_max, resolution=resolution, threshold=threshold) + os.makedirs(os.path.join(self.base_exp_dir, 'meshes'), exist_ok=True) + + if world_space: + vertices = vertices * self.dataset.scale_mats_np[0][0, 0] + self.dataset.scale_mats_np[0][:3, 3][None] + + mesh = trimesh.Trimesh(vertices, triangles, vertex_colors=vertex_colors) + # mesh.export(os.path.join(self.base_exp_dir, 'meshes', '{:0>8d}.ply'.format(self.iter_step))) + # export as glb + mesh.export(os.path.join(self.base_exp_dir, 'meshes', 'tmp.glb')) + + logging.info('End') + + def interpolate_view(self, img_idx_0, img_idx_1): + images = [] + n_frames = 60 + for i in range(n_frames): + print(i) + images.append(self.render_novel_image(img_idx_0, img_idx_1, np.sin(((i / n_frames) - 0.5) * np.pi) * 0.5 + 0.5, resolution_level=4)) + for i in range(n_frames): + images.append(images[n_frames - i - 1]) + + fourcc = cv.VideoWriter_fourcc(*'mp4v') + video_dir = os.path.join(self.base_exp_dir, 'render') + os.makedirs(video_dir, exist_ok=True) + h, w, _ = images[0].shape + writer = cv.VideoWriter(os.path.join(video_dir, '{:0>8d}_{}_{}.mp4'.format(self.iter_step, img_idx_0, img_idx_1)), fourcc, 30, (w, h)) + + for image in images: + writer.write(image) + + writer.release() + + +if __name__ == '__main__': + print('Hello Wooden') + + torch.set_default_tensor_type('torch.FloatTensor') + + FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s" + logging.basicConfig(level=logging.DEBUG, format=FORMAT) + + parser = argparse.ArgumentParser() + parser.add_argument('--conf', type=str, default='./confs/base.conf') + parser.add_argument('--mode', type=str, default='train') + parser.add_argument('--mcube_threshold', type=float, default=0.0) + parser.add_argument('--is_continue', default=False, action="store_true") + parser.add_argument('--gpu', type=int, default=0) + parser.add_argument('--case', type=str, default='') + parser.add_argument('--data_dir', type=str, default='') + + args = parser.parse_args() + + torch.cuda.set_device(args.gpu) + runner = Runner(args.conf, args.mode, args.case, args.is_continue, args.data_dir) + + if args.mode == 'train': + runner.train() + runner.validate_mesh(world_space=False, resolution=256, threshold=args.mcube_threshold) + elif args.mode == 'save_maps': + for i in range(4): + runner.save_maps(idx=i, img_idx=runner.dataset.object_viewidx) + elif args.mode == 'validate_mesh': + runner.validate_mesh(world_space=False, resolution=512, threshold=args.mcube_threshold) + elif args.mode.startswith('interpolate'): # Interpolate views given two image indices + _, img_idx_0, img_idx_1 = args.mode.split('_') + img_idx_0 = int(img_idx_0) + img_idx_1 = int(img_idx_1) + runner.interpolate_view(img_idx_0, img_idx_1) diff --git a/apps/third_party/Wonder3D/NeuS/models/dataset_mvdiff.py b/apps/third_party/Wonder3D/NeuS/models/dataset_mvdiff.py new file mode 100644 index 0000000000000000000000000000000000000000..ed1385ea69251df2d8e5b13eda34d4823fae6ea8 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/dataset_mvdiff.py @@ -0,0 +1,343 @@ +import torch +import torch.nn.functional as F +import cv2 +import numpy as np +import os +from glob import glob +from icecream import ic +from scipy.spatial.transform import Rotation as Rot +from scipy.spatial.transform import Slerp +import PIL.Image +from glob import glob +import pdb + +def camNormal2worldNormal(rot_c2w, camNormal): + H,W,_ = camNormal.shape + normal_img = np.matmul(rot_c2w[None, :, :], camNormal.reshape(-1,3)[:, :, None]).reshape([H, W, 3]) + + return normal_img + +def worldNormal2camNormal(rot_w2c, worldNormal): + H,W,_ = worldNormal.shape + normal_img = np.matmul(rot_w2c[None, :, :], worldNormal.reshape(-1,3)[:, :, None]).reshape([H, W, 3]) + + return normal_img + +def trans_normal(normal, RT_w2c, RT_w2c_target): + + normal_world = camNormal2worldNormal(np.linalg.inv(RT_w2c[:3,:3]), normal) + normal_target_cam = worldNormal2camNormal(RT_w2c_target[:3,:3], normal_world) + + return normal_target_cam + +def img2normal(img): + return (img/255.)*2-1 + +def normal2img(normal): + return np.uint8((normal*0.5+0.5)*255) + +def norm_normalize(normal, dim=-1): + + normal = normal/(np.linalg.norm(normal, axis=dim, keepdims=True)+1e-6) + + return normal + +def RT_opengl2opencv(RT): + # Build the coordinate transform matrix from world to computer vision camera + # R_world2cv = R_bcam2cv@R_world2bcam + # T_world2cv = R_bcam2cv@T_world2bcam + + R = RT[:3, :3] + t = RT[:3, 3] + + R_bcam2cv = np.asarray([[1, 0, 0], [0, -1, 0], [0, 0, -1]], np.float32) + + R_world2cv = R_bcam2cv @ R + t_world2cv = R_bcam2cv @ t + + RT = np.concatenate([R_world2cv,t_world2cv[:,None]],1) + + return RT + +def normal_opengl2opencv(normal): + H,W,C = np.shape(normal) + # normal_img = np.reshape(normal, (H*W,C)) + R_bcam2cv = np.array([1, -1, -1], np.float32) + normal_cv = normal * R_bcam2cv[None, None, :] + + print(np.shape(normal_cv)) + + return normal_cv + +def inv_RT(RT): + RT_h = np.concatenate([RT, np.array([[0,0,0,1]])], axis=0) + RT_inv = np.linalg.inv(RT_h) + + return RT_inv[:3, :] + +def load_a_prediction(root_dir, test_object, imSize, view_types, load_color=False, cam_pose_dir=None, normal_system='front'): + + all_images = [] + all_normals = [] + all_normals_world = [] + all_masks = [] + all_poses = [] + all_w2cs = [] + print(cam_pose_dir) + RT_front = np.loadtxt(glob(os.path.join(cam_pose_dir, '*_%s_RT.txt'%( 'front')))[0]) # world2cam matrix + RT_front_cv = RT_opengl2opencv(RT_front) # convert normal from opengl to opencv + for idx, view in enumerate(view_types): + print(os.path.join(root_dir,test_object)) + normal_filepath = os.path.join(root_dir,test_object, 'normals_000_%s.png'%( view)) + # Load key frame + if load_color: # use bgr + image =np.array(PIL.Image.open(normal_filepath.replace("normals", "rgb")).resize(imSize))[:, :, ::-1] + + normal = np.array(PIL.Image.open(normal_filepath).resize(imSize)) + mask = normal[:, :, 3] + normal = normal[:, :, :3] + + RT = np.loadtxt(os.path.join(cam_pose_dir, '000_%s_RT.txt'%( view))) # world2cam matrix + + normal = img2normal(normal) + + normal[mask==0] = [0,0,0] + mask = mask> (0.5*255) + if load_color: + all_images.append(image) + + all_masks.append(mask) + RT_cv = RT_opengl2opencv(RT) # convert normal from opengl to opencv + all_poses.append(inv_RT(RT_cv)) # cam2world + all_w2cs.append(RT_cv) + + # whether to + normal_cam_cv = normal_opengl2opencv(normal) + + if normal_system == 'front': + normal_world = camNormal2worldNormal(inv_RT(RT_front_cv)[:3, :3], normal_cam_cv) + elif normal_system == 'self': + normal_world = camNormal2worldNormal(inv_RT(RT_cv)[:3, :3], normal_cam_cv) + all_normals.append(normal_cam_cv) + all_normals_world.append(normal_world) + + if not load_color: + all_images = [normal2img(x) for x in all_normals_world] + + return np.stack(all_images), np.stack(all_masks), np.stack(all_normals), np.stack(all_normals_world), np.stack(all_poses), np.stack(all_w2cs) + + +class Dataset: + def __init__(self, conf): + super(Dataset, self).__init__() + print('Load data: Begin') + self.device = torch.device('cuda') + self.conf = conf + + self.data_dir = conf.get_string('data_dir') + self.object_name = conf.get_string('object_name') + self.object_viewidx = conf.get_int('object_viewidx') + self.imSize = conf['imSize'] + self.load_color = conf['load_color'] + self.stage = conf['stage'] + self.mtype = conf['mtype'] + self.num_views = conf['num_views'] + + self.normal_system = conf['normal_system'] + + self.cam_pose_dir = "./models/fixed_poses/" + + if self.num_views == 4: + view_types = ['front', 'right', 'back', 'left'] + elif self.num_views == 5: + view_types = ['front', 'front_right', 'right', 'back', 'left'] + elif self.num_views == 6: + view_types = ['front', 'front_right', 'right', 'back', 'left', 'front_left'] + + self.images_np, self.masks_np, self.normals_cam_np, \ + self.normals_world_np ,self.pose_all_np, self.w2c_all_np = load_a_prediction( + self.data_dir, self.object_name, self.imSize, view_types, self.load_color, + self.cam_pose_dir, normal_system=self.normal_system) + + self.n_images = self.images_np.shape[0] + + self.images = torch.from_numpy(self.images_np.astype(np.float32)).cpu() / 255. # [n_images, H, W, 3] + self.masks = torch.from_numpy(self.masks_np.astype(np.float32)).cpu() # [n_images, H, W, 3] + self.normals_cam = torch.from_numpy(self.normals_cam_np.astype(np.float32)).cpu() # [n_images, H, W, 3] + self.normals_world = torch.from_numpy(self.normals_world_np.astype(np.float32)).cpu() # [n_images, H, W, 3] + self.pose_all = torch.from_numpy(self.pose_all_np.astype(np.float32)).cpu() # [n_images,3, 4] cam2world + + # self.pose_all = torch.stack(self.pose_all).to(self.device) # [n_images, 4, 4] + self.H, self.W = self.images.shape[1], self.images.shape[2] + self.image_pixels = self.H * self.W + + self.intrinsic = torch.from_numpy(np.array([ + [self.W/2.0, 0, self.W / 2.0, 0], + [0, self.H/2.0, self.H/ 2.0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1] + ]).astype(np.float32)) + + self.intrinsics_all = torch.stack([self.intrinsic]*self.num_views, dim=0).cpu() + self.intrinsics_all_inv = torch.inverse(self.intrinsics_all).cpu() # [n_images, 4, 4] + + object_bbox_min = np.array([-1.01, -1.01, -1.01, 1.0]) + object_bbox_max = np.array([ 1.01, 1.01, 1.01, 1.0]) + + self.object_bbox_min = object_bbox_min[:3] + self.object_bbox_max = object_bbox_max[:3] + + self.near = 0.2 + self.far = 2.4 + + self.cos = torch.nn.CosineSimilarity(dim=1, eps=1e-6) + self.all_rays = self.prepare_all_rays() + print('Load data: End') + + def gen_rays_at(self, img_idx, resolution_level=1): + """ + Generate rays at world space from one camera. + """ + l = resolution_level + tx = torch.linspace(0, self.W - 1, self.W // l) + ty = torch.linspace(0, self.H - 1, self.H // l) + pixels_x, pixels_y = torch.meshgrid(tx, ty) + q = torch.stack([(pixels_x/self.W-0.5)*2, (pixels_y/self.H-0.5)*2, torch.zeros_like(pixels_y)], dim=-1) # W, H, 3 + + v = torch.stack([torch.zeros_like(pixels_y), torch.zeros_like(pixels_y), torch.ones_like(pixels_y)], dim=-1) # W, H, 3 + + # orthogonal projection + rays_v = v / torch.linalg.norm(v, ord=2, dim=-1, keepdim=True) # W, H, 3 + rays_v = torch.matmul(self.pose_all[img_idx, None, None, :3, :3].cuda(), rays_v[:, :, :, None].cuda()).squeeze() # W, H, 3 + + rays_o = torch.matmul(self.pose_all[img_idx, None, None, :3, :3].cuda(), q[:, :, :, None].cuda()).squeeze() # W, H, 3 + rays_o = self.pose_all[img_idx, None, None, :3, 3].expand(rays_v.shape).cuda() + rays_o # W, H, 3 + return rays_o.transpose(0, 1), rays_v.transpose(0, 1) + + def gen_random_rays_at(self, img_idx, batch_size): + """ + Generate random rays at world space from one camera. + """ + pixels_x = torch.randint(low=0, high=self.W, size=[batch_size]).cpu() + pixels_y = torch.randint(low=0, high=self.H, size=[batch_size]).cpu() + color = self.images[img_idx][(pixels_y, pixels_x)] # batch_size, 3 + mask = self.masks[img_idx][(pixels_y, pixels_x)] # batch_size, 3 + normal = self.normals_world[img_idx][(pixels_y, pixels_x)] # batch_size, 3 + + q = torch.stack([(pixels_x / self.W-0.5)*2, (pixels_y / self.H-0.5)*2, torch.zeros_like(pixels_y)], dim=-1).float() # batch_size, 3 + v = torch.stack([torch.zeros_like(pixels_y), torch.zeros_like(pixels_y), torch.ones_like(pixels_y)], dim=-1).float() + + # q = torch.stack([pixels_x, pixels_y, torch.ones_like(pixels_y)], dim=-1).float() # bsz, 3 + # q = torch.matmul(self.intrinsics_all_inv[img_idx, None, :3, :3], q[:, :, None]).squeeze() # bsz, 3 + # q[:, 2] = 0 + + rays_v = v / torch.linalg.norm(v, ord=2, dim=-1, keepdim=True) # batch_size, 3 + rays_v = torch.matmul(self.pose_all[img_idx, None, :3, :3], rays_v[:, :, None]).squeeze() # batch_size, 3 + + rays_o = torch.matmul(self.pose_all[img_idx, None, :3, :3], q[:, :, None]).squeeze() # batch_size, 3 + rays_o = self.pose_all[img_idx, None, :3, 3].expand(rays_v.shape) + rays_o # batch_size, 3 + + return torch.cat([rays_o.cpu(), rays_v.cpu(), color, mask[:, None], normal], dim=-1).cuda() # batch_size, 10 + + def prepare_rays_a_view(self, img_idx): + """ + Generate random rays at world space from one camera. + """ + tx = torch.linspace(0, self.W - 1, self.W) + ty = torch.linspace(0, self.H - 1, self.H) + pixels_x, pixels_y = torch.meshgrid(tx, ty) + + pixels_x = pixels_x.reshape(-1).long() + pixels_y = pixels_y.reshape(-1).long() + color = self.images[img_idx][(pixels_y, pixels_x)] # batch_size, 3 + mask = self.masks[img_idx][(pixels_y, pixels_x)] # batch_size, 3 + normal = self.normals_world[img_idx][(pixels_y, pixels_x)] # batch_size, 3 + + q = torch.stack([(pixels_x / self.W-0.5)*2, (pixels_y / self.H-0.5)*2, torch.zeros_like(pixels_y)], dim=-1).float() # batch_size, 3 + v = torch.stack([torch.zeros_like(pixels_y), torch.zeros_like(pixels_y), torch.ones_like(pixels_y)], dim=-1).float() + + rays_v = v / torch.linalg.norm(v, ord=2, dim=-1, keepdim=True) # batch_size, 3 + rays_v = torch.matmul(self.pose_all[img_idx, None, :3, :3], rays_v[:, :, None]).squeeze() # batch_size, 3 + + rays_o = torch.matmul(self.pose_all[img_idx, None, :3, :3], q[:, :, None]).squeeze() # batch_size, 3 + rays_o = self.pose_all[img_idx, None, :3, 3].expand(rays_v.shape) + rays_o # batch_size, 3 + + cosines = self.cos(rays_v, normal) + + # pdb.set_trace() + + return torch.cat([rays_o.cpu(), rays_v.cpu(), color, mask[:, None], normal, cosines[:, None]], dim=-1) # batch_size, 10 + + + def prepare_all_rays(self,): + all_rays = [] + for idx in range(self.n_images): + rays = self.prepare_rays_a_view(idx) + all_rays.append(rays) + all_rays = torch.concat(all_rays, dim=0) + return all_rays + + def __getitem__(self, idx): + return self.all_rays[idx] + + def __len__(self): + return self.all_rays.shape[0] + + def gen_rays_between(self, idx_0, idx_1, ratio, resolution_level=1): + """ + Interpolate pose between two cameras. + """ + l = resolution_level + tx = torch.linspace(0, self.W - 1, self.W // l) + ty = torch.linspace(0, self.H - 1, self.H // l) + pixels_x, pixels_y = torch.meshgrid(tx, ty) + p = torch.stack([pixels_x, pixels_y, torch.ones_like(pixels_y)], dim=-1) # W, H, 3 + p = torch.matmul(self.intrinsics_all_inv[0, None, None, :3, :3], p[:, :, :, None]).squeeze() # W, H, 3 + rays_v = p / torch.linalg.norm(p, ord=2, dim=-1, keepdim=True) # W, H, 3 + trans = self.pose_all[idx_0, :3, 3] * (1.0 - ratio) + self.pose_all[idx_1, :3, 3] * ratio + pose_0 = self.pose_all[idx_0].detach().cpu().numpy() + pose_1 = self.pose_all[idx_1].detach().cpu().numpy() + pose_0 = np.linalg.inv(pose_0) + pose_1 = np.linalg.inv(pose_1) + rot_0 = pose_0[:3, :3] + rot_1 = pose_1[:3, :3] + rots = Rot.from_matrix(np.stack([rot_0, rot_1])) + key_times = [0, 1] + slerp = Slerp(key_times, rots) + rot = slerp(ratio) + pose = np.diag([1.0, 1.0, 1.0, 1.0]) + pose = pose.astype(np.float32) + pose[:3, :3] = rot.as_matrix() + pose[:3, 3] = ((1.0 - ratio) * pose_0 + ratio * pose_1)[:3, 3] + pose = np.linalg.inv(pose) + rot = torch.from_numpy(pose[:3, :3]).cuda() + trans = torch.from_numpy(pose[:3, 3]).cuda() + rays_v = torch.matmul(rot[None, None, :3, :3], rays_v[:, :, :, None]).squeeze() # W, H, 3 + rays_o = trans[None, None, :3].expand(rays_v.shape) # W, H, 3 + return rays_o.transpose(0, 1), rays_v.transpose(0, 1) + + def near_far_from_sphere(self, rays_o, rays_d): + a = torch.sum(rays_d**2, dim=-1, keepdim=True) + b = 2.0 * torch.sum(rays_o * rays_d, dim=-1, keepdim=True) + mid = 0.5 * (-b) / a + near = mid - 1.0 + far = mid + 1.0 + return near, far + + def get_near_far(self,): + return self.near, self.far + + def image_at(self, idx, resolution_level): + img = self.images_np[idx] + return (cv2.resize(img, (self.W // resolution_level, self.H // resolution_level))).clip(0, 255) + + def normal_cam_at(self, idx, resolution_level): + normal_cam = self.normals_cam_np[idx] + img = normal2img(normal_cam) + return (cv2.resize(img, (self.W // resolution_level, self.H // resolution_level))).clip(0, 255) + + def mask_at(self, idx, resolution_level): + mask = np.uint8(self.masks_np[idx]*255)[:, :, None] + mask = np.concatenate([mask]*3, axis=-1) + return (cv2.resize(mask, (self.W // resolution_level, self.H // resolution_level))).clip(0, 255) + diff --git a/apps/third_party/Wonder3D/NeuS/models/embedder.py b/apps/third_party/Wonder3D/NeuS/models/embedder.py new file mode 100644 index 0000000000000000000000000000000000000000..c74f16bd03f6425bf9e9e8db814171d6a7b04bfd --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/embedder.py @@ -0,0 +1,51 @@ +import torch +import torch.nn as nn + + +# Positional encoding embedding. Code was taken from https://github.com/bmild/nerf. +class Embedder: + def __init__(self, **kwargs): + self.kwargs = kwargs + self.create_embedding_fn() + + def create_embedding_fn(self): + embed_fns = [] + d = self.kwargs['input_dims'] + out_dim = 0 + if self.kwargs['include_input']: + embed_fns.append(lambda x: x) + out_dim += d + + max_freq = self.kwargs['max_freq_log2'] + N_freqs = self.kwargs['num_freqs'] + + if self.kwargs['log_sampling']: + freq_bands = 2. ** torch.linspace(0., max_freq, N_freqs) + else: + freq_bands = torch.linspace(2.**0., 2.**max_freq, N_freqs) + + for freq in freq_bands: + for p_fn in self.kwargs['periodic_fns']: + embed_fns.append(lambda x, p_fn=p_fn, freq=freq: p_fn(x * freq)) + out_dim += d + + self.embed_fns = embed_fns + self.out_dim = out_dim + + def embed(self, inputs): + return torch.cat([fn(inputs) for fn in self.embed_fns], -1) + + +def get_embedder(multires, input_dims=3): + embed_kwargs = { + 'include_input': True, + 'input_dims': input_dims, + 'max_freq_log2': multires-1, + 'num_freqs': multires, + 'log_sampling': True, + 'periodic_fns': [torch.sin, torch.cos], + } + + embedder_obj = Embedder(**embed_kwargs) + def embed(x, eo=embedder_obj): return eo.embed(x) + return embed, embedder_obj.out_dim diff --git a/apps/third_party/Wonder3D/NeuS/models/fields.py b/apps/third_party/Wonder3D/NeuS/models/fields.py new file mode 100644 index 0000000000000000000000000000000000000000..a557cd2c5191738b1ad6e2f99eefc548cb6e0078 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fields.py @@ -0,0 +1,264 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +from models.embedder import get_embedder + + +# This implementation is borrowed from IDR: https://github.com/lioryariv/idr +class SDFNetwork(nn.Module): + def __init__(self, + d_in, + d_out, + d_hidden, + n_layers, + skip_in=(4,), + multires=0, + bias=0.5, + scale=1, + geometric_init=True, + weight_norm=True, + inside_outside=False): + super(SDFNetwork, self).__init__() + + dims = [d_in] + [d_hidden for _ in range(n_layers)] + [d_out] + + self.embed_fn_fine = None + + if multires > 0: + embed_fn, input_ch = get_embedder(multires, input_dims=d_in) + self.embed_fn_fine = embed_fn + dims[0] = input_ch + + self.num_layers = len(dims) + self.skip_in = skip_in + self.scale = scale + + for l in range(0, self.num_layers - 1): + if l + 1 in self.skip_in: + out_dim = dims[l + 1] - dims[0] + else: + out_dim = dims[l + 1] + + lin = nn.Linear(dims[l], out_dim) + + if geometric_init: + if l == self.num_layers - 2: + if not inside_outside: + torch.nn.init.normal_(lin.weight, mean=np.sqrt(np.pi) / np.sqrt(dims[l]), std=0.0001) + torch.nn.init.constant_(lin.bias, -bias) + else: + torch.nn.init.normal_(lin.weight, mean=-np.sqrt(np.pi) / np.sqrt(dims[l]), std=0.0001) + torch.nn.init.constant_(lin.bias, bias) + elif multires > 0 and l == 0: + torch.nn.init.constant_(lin.bias, 0.0) + torch.nn.init.constant_(lin.weight[:, 3:], 0.0) + torch.nn.init.normal_(lin.weight[:, :3], 0.0, np.sqrt(2) / np.sqrt(out_dim)) + elif multires > 0 and l in self.skip_in: + torch.nn.init.constant_(lin.bias, 0.0) + torch.nn.init.normal_(lin.weight, 0.0, np.sqrt(2) / np.sqrt(out_dim)) + torch.nn.init.constant_(lin.weight[:, -(dims[0] - 3):], 0.0) + else: + torch.nn.init.constant_(lin.bias, 0.0) + torch.nn.init.normal_(lin.weight, 0.0, np.sqrt(2) / np.sqrt(out_dim)) + + if weight_norm: + lin = nn.utils.weight_norm(lin) + + setattr(self, "lin" + str(l), lin) + + self.activation = nn.Softplus(beta=100) + + def forward(self, inputs): + inputs = inputs * self.scale + if self.embed_fn_fine is not None: + inputs = self.embed_fn_fine(inputs) + + x = inputs + for l in range(0, self.num_layers - 1): + lin = getattr(self, "lin" + str(l)) + + if l in self.skip_in: + x = torch.cat([x, inputs], 1) / np.sqrt(2) + + x = lin(x) + + if l < self.num_layers - 2: + x = self.activation(x) + return torch.cat([x[:, :1] / self.scale, x[:, 1:]], dim=-1) + + def sdf(self, x): + return self.forward(x)[:, :1] + + def sdf_hidden_appearance(self, x): + return self.forward(x) + + def gradient(self, x): + x.requires_grad_(True) + with torch.enable_grad(): + y = self.sdf(x) + d_output = torch.ones_like(y, requires_grad=False, device=y.device) + gradients = torch.autograd.grad( + outputs=y, + inputs=x, + grad_outputs=d_output, + create_graph=True, + retain_graph=True, + only_inputs=True)[0] + return gradients.unsqueeze(1) + + +# This implementation is borrowed from IDR: https://github.com/lioryariv/idr +class RenderingNetwork(nn.Module): + def __init__(self, + d_feature, + mode, + d_in, + d_out, + d_hidden, + n_layers, + weight_norm=True, + multires_view=0, + squeeze_out=True): + super().__init__() + + self.mode = mode + self.squeeze_out = squeeze_out + dims = [d_in + d_feature] + [d_hidden for _ in range(n_layers)] + [d_out] + + self.embedview_fn = None + if multires_view > 0: + embedview_fn, input_ch = get_embedder(multires_view) + self.embedview_fn = embedview_fn + dims[0] += (input_ch - 3) + + self.num_layers = len(dims) + + for l in range(0, self.num_layers - 1): + out_dim = dims[l + 1] + lin = nn.Linear(dims[l], out_dim) + + if weight_norm: + lin = nn.utils.weight_norm(lin) + + setattr(self, "lin" + str(l), lin) + + self.relu = nn.ReLU() + + def forward(self, points, normals, view_dirs, feature_vectors): + if self.embedview_fn is not None: + view_dirs = self.embedview_fn(view_dirs) + + rendering_input = None + + if self.mode == 'idr': + rendering_input = torch.cat([points, view_dirs, normals, feature_vectors], dim=-1) + elif self.mode == 'no_view_dir': + rendering_input = torch.cat([points, normals, feature_vectors], dim=-1) + elif self.mode == 'no_normal': + rendering_input = torch.cat([points, view_dirs, feature_vectors], dim=-1) + + x = rendering_input + + for l in range(0, self.num_layers - 1): + lin = getattr(self, "lin" + str(l)) + + x = lin(x) + + if l < self.num_layers - 2: + x = self.relu(x) + + if self.squeeze_out: + x = torch.sigmoid(x) + return x + + +# This implementation is borrowed from nerf-pytorch: https://github.com/yenchenlin/nerf-pytorch +class NeRF(nn.Module): + def __init__(self, + D=8, + W=256, + d_in=3, + d_in_view=3, + multires=0, + multires_view=0, + output_ch=4, + skips=[4], + use_viewdirs=False): + super(NeRF, self).__init__() + self.D = D + self.W = W + self.d_in = d_in + self.d_in_view = d_in_view + self.input_ch = 3 + self.input_ch_view = 3 + self.embed_fn = None + self.embed_fn_view = None + + if multires > 0: + embed_fn, input_ch = get_embedder(multires, input_dims=d_in) + self.embed_fn = embed_fn + self.input_ch = input_ch + + if multires_view > 0: + embed_fn_view, input_ch_view = get_embedder(multires_view, input_dims=d_in_view) + self.embed_fn_view = embed_fn_view + self.input_ch_view = input_ch_view + + self.skips = skips + self.use_viewdirs = use_viewdirs + + self.pts_linears = nn.ModuleList( + [nn.Linear(self.input_ch, W)] + + [nn.Linear(W, W) if i not in self.skips else nn.Linear(W + self.input_ch, W) for i in range(D - 1)]) + + ### Implementation according to the official code release + ### (https://github.com/bmild/nerf/blob/master/run_nerf_helpers.py#L104-L105) + self.views_linears = nn.ModuleList([nn.Linear(self.input_ch_view + W, W // 2)]) + + ### Implementation according to the paper + # self.views_linears = nn.ModuleList( + # [nn.Linear(input_ch_views + W, W//2)] + [nn.Linear(W//2, W//2) for i in range(D//2)]) + + if use_viewdirs: + self.feature_linear = nn.Linear(W, W) + self.alpha_linear = nn.Linear(W, 1) + self.rgb_linear = nn.Linear(W // 2, 3) + else: + self.output_linear = nn.Linear(W, output_ch) + + def forward(self, input_pts, input_views): + if self.embed_fn is not None: + input_pts = self.embed_fn(input_pts) + if self.embed_fn_view is not None: + input_views = self.embed_fn_view(input_views) + + h = input_pts + for i, l in enumerate(self.pts_linears): + h = self.pts_linears[i](h) + h = F.relu(h) + if i in self.skips: + h = torch.cat([input_pts, h], -1) + + if self.use_viewdirs: + alpha = self.alpha_linear(h) + feature = self.feature_linear(h) + h = torch.cat([feature, input_views], -1) + + for i, l in enumerate(self.views_linears): + h = self.views_linears[i](h) + h = F.relu(h) + + rgb = self.rgb_linear(h) + return alpha, rgb + else: + assert False + + +class SingleVarianceNetwork(nn.Module): + def __init__(self, init_val): + super(SingleVarianceNetwork, self).__init__() + self.register_parameter('variance', nn.Parameter(torch.tensor(init_val))) + + def forward(self, x): + return torch.ones([len(x), 1]).to(x.device) * torch.exp(self.variance * 10.0) diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ef2610bdbde3f9c9db89c05fc5606362adc7d0c --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_RT.txt @@ -0,0 +1,3 @@ +-5.266582965850830078e-01 7.410295009613037109e-01 -4.165407419204711914e-01 -5.960464477539062500e-08 +5.865638996738198330e-08 4.900035560131072998e-01 8.717204332351684570e-01 -9.462351613365171943e-08 +8.500770330429077148e-01 4.590988159179687500e-01 -2.580644786357879639e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_left_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..7db25bbbec8a0d5a26724aa65681603e5bee6744 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_left_RT.txt @@ -0,0 +1,3 @@ +-9.734988808631896973e-01 1.993551850318908691e-01 -1.120596975088119507e-01 -1.713633537292480469e-07 +3.790224578636980368e-09 4.900034964084625244e-01 8.717204928398132324e-01 1.772203575001185527e-07 +2.286916375160217285e-01 8.486189246177673340e-01 -4.770178496837615967e-01 -1.838477611541748047e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_right_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..be45ed8f30f6625421524d141aa1c325dc2fdb8b --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_back_right_RT.txt @@ -0,0 +1,3 @@ +2.286914736032485962e-01 8.486190438270568848e-01 -4.770178198814392090e-01 1.564621925354003906e-07 +-3.417914484771245043e-08 4.900034070014953613e-01 8.717205524444580078e-01 -7.293811421504869941e-08 +9.734990000724792480e-01 -1.993550658226013184e-01 1.120596155524253845e-01 -1.838477969169616699e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..8278639ec5ec9d0f1e4c88d54295a0cd4acee593 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_RT.txt @@ -0,0 +1,3 @@ +5.266583561897277832e-01 -7.410295009613037109e-01 4.165407419204711914e-01 0.000000000000000000e+00 +5.865638996738198330e-08 4.900035560131072998e-01 8.717204332351684570e-01 9.462351613365171943e-08 +-8.500770330429077148e-01 -4.590988159179687500e-01 2.580645382404327393e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_left_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..6255b9f84ccb1bf3527897ef648811ff171aa025 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_left_RT.txt @@ -0,0 +1,3 @@ +-2.286916971206665039e-01 -8.486189842224121094e-01 4.770179092884063721e-01 -2.458691596984863281e-07 +9.085837859856837895e-09 4.900034666061401367e-01 8.717205524444580078e-01 1.205695667749751010e-07 +-9.734990000724792480e-01 1.993551701307296753e-01 -1.120597645640373230e-01 -1.838477969169616699e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_right_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1d76c85c1a05de1d6bf3dd70ed02721a40f73c2 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_front_right_RT.txt @@ -0,0 +1,3 @@ +9.734989404678344727e-01 -1.993551850318908691e-01 1.120596975088119507e-01 -1.415610313415527344e-07 +3.790224578636980368e-09 4.900034964084625244e-01 8.717204928398132324e-01 -1.772203575001185527e-07 +-2.286916375160217285e-01 -8.486189246177673340e-01 4.770178794860839844e-01 -1.838477611541748047e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_left_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd42197eaae14526b00cb4676528a2465cbaf1dd --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_left_RT.txt @@ -0,0 +1,3 @@ +-8.500771522521972656e-01 -4.590989053249359131e-01 2.580644488334655762e-01 0.000000000000000000e+00 +-4.257411134744870651e-08 4.900034964084625244e-01 8.717204928398132324e-01 9.006067358541258727e-08 +-5.266583561897277832e-01 7.410295605659484863e-01 -4.165408313274383545e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_right_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d37c0219db99aeeede6b48815b932058538adc6 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_right_RT.txt @@ -0,0 +1,3 @@ +8.500770330429077148e-01 4.590989053249359131e-01 -2.580644488334655762e-01 5.960464477539062500e-08 +-4.257411134744870651e-08 4.900034964084625244e-01 8.717204928398132324e-01 -9.006067358541258727e-08 +5.266583561897277832e-01 -7.410295605659484863e-01 4.165407419204711914e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_top_RT.txt b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_top_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d71f22664b502cd5e1039f4621bec6ef41b1231 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/fixed_poses/000_top_RT.txt @@ -0,0 +1,3 @@ +9.958608150482177734e-01 7.923202216625213623e-02 -4.453715682029724121e-02 -3.098167056236889039e-09 +-9.089154005050659180e-02 8.681122064590454102e-01 -4.879753291606903076e-01 5.784738377201392723e-08 +-2.028124157504862524e-08 4.900035560131072998e-01 8.717204332351684570e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/NeuS/models/normal_utils.py b/apps/third_party/Wonder3D/NeuS/models/normal_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..dff3730a312e96a2ed82dfd5a337d263baa0f2d8 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/normal_utils.py @@ -0,0 +1,45 @@ +import numpy as np + +def camNormal2worldNormal(rot_c2w, camNormal): + H,W,_ = camNormal.shape + normal_img = np.matmul(rot_c2w[None, :, :], camNormal.reshape(-1,3)[:, :, None]).reshape([H, W, 3]) + + return normal_img + +def worldNormal2camNormal(rot_w2c, normal_map_world): + H,W,_ = normal_map_world.shape + # normal_img = np.matmul(rot_w2c[None, :, :], worldNormal.reshape(-1,3)[:, :, None]).reshape([H, W, 3]) + + # faster version + # Reshape the normal map into a 2D array where each row represents a normal vector + normal_map_flat = normal_map_world.reshape(-1, 3) + + # Transform the normal vectors using the transformation matrix + normal_map_camera_flat = np.dot(normal_map_flat, rot_w2c.T) + + # Reshape the transformed normal map back to its original shape + normal_map_camera = normal_map_camera_flat.reshape(normal_map_world.shape) + + return normal_map_camera + +def trans_normal(normal, RT_w2c, RT_w2c_target): + + # normal_world = camNormal2worldNormal(np.linalg.inv(RT_w2c[:3,:3]), normal) + # normal_target_cam = worldNormal2camNormal(RT_w2c_target[:3,:3], normal_world) + + relative_RT = np.matmul(RT_w2c_target[:3,:3], np.linalg.inv(RT_w2c[:3,:3])) + normal_target_cam = worldNormal2camNormal(relative_RT[:3,:3], normal) + + return normal_target_cam + +def img2normal(img): + return (img/255.)*2-1 + +def normal2img(normal): + return np.uint8((normal*0.5+0.5)*255) + +def norm_normalize(normal, dim=-1): + + normal = normal/(np.linalg.norm(normal, axis=dim, keepdims=True)+1e-6) + + return normal \ No newline at end of file diff --git a/apps/third_party/Wonder3D/NeuS/models/ops.py b/apps/third_party/Wonder3D/NeuS/models/ops.py new file mode 100644 index 0000000000000000000000000000000000000000..526635c96eb657b0cfc0ef0b2cc446e5d159e516 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/ops.py @@ -0,0 +1,19 @@ +import cv2 +import numpy as np + +def visualize_depth_numpy(depth, minmax=None, cmap=cv2.COLORMAP_JET): + """ + depth: (H, W) + """ + + x = np.nan_to_num(depth) # change nan to 0 + if minmax is None: + mi = np.min(x[x > 0]) # get minimum positive depth (ignore background) + ma = np.max(x) + else: + mi, ma = minmax + + x = (x - mi) / (ma - mi + 1e-8) # normalize to 0~1 + x = (255 * x).astype(np.uint8) + x_ = cv2.applyColorMap(x, cmap) + return x_, [mi, ma] \ No newline at end of file diff --git a/apps/third_party/Wonder3D/NeuS/models/renderer.py b/apps/third_party/Wonder3D/NeuS/models/renderer.py new file mode 100644 index 0000000000000000000000000000000000000000..b2f90164dcc9285921e7fcb5faeb2320724125bc --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/models/renderer.py @@ -0,0 +1,435 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +import logging +import mcubes +from icecream import ic +import pdb + +def extract_fields(bound_min, bound_max, resolution, query_func): + N = 64 + X = torch.linspace(bound_min[0], bound_max[0], resolution).split(N) + Y = torch.linspace(bound_min[1], bound_max[1], resolution).split(N) + Z = torch.linspace(bound_min[2], bound_max[2], resolution).split(N) + + u = np.zeros([resolution, resolution, resolution], dtype=np.float32) + with torch.no_grad(): + for xi, xs in enumerate(X): + for yi, ys in enumerate(Y): + for zi, zs in enumerate(Z): + xx, yy, zz = torch.meshgrid(xs, ys, zs) + pts = torch.cat([xx.reshape(-1, 1), yy.reshape(-1, 1), zz.reshape(-1, 1)], dim=-1) + val = query_func(pts.cuda()).reshape(len(xs), len(ys), len(zs)).detach().cpu().numpy() + u[xi * N: xi * N + len(xs), yi * N: yi * N + len(ys), zi * N: zi * N + len(zs)] = val + return u + + +def extract_geometry(bound_min, bound_max, resolution, threshold, query_func, color_func): + print('threshold: {}'.format(threshold)) + u = extract_fields(bound_min, bound_max, resolution, query_func) + vertices, triangles = mcubes.marching_cubes(u, threshold) + b_max_np = bound_max.detach().cpu().numpy() + b_min_np = bound_min.detach().cpu().numpy() + + vertices = vertices / (resolution - 1.0) * (b_max_np - b_min_np)[None, :] + b_min_np[None, :] + + vertices_color = color_func(vertices) + + return vertices, triangles, vertices_color + + +def sample_pdf(bins, weights, n_samples, det=False): + # This implementation is from NeRF + # Get pdf + device = weights.device + weights = weights + 1e-5 # prevent nans + pdf = weights / torch.sum(weights, -1, keepdim=True) + cdf = torch.cumsum(pdf, -1) + cdf = torch.cat([torch.zeros_like(cdf[..., :1]), cdf], -1) + # Take uniform samples + if det: + u = torch.linspace(0. + 0.5 / n_samples, 1. - 0.5 / n_samples, steps=n_samples).to(device) + u = u.expand(list(cdf.shape[:-1]) + [n_samples]) + else: + u = torch.rand(list(cdf.shape[:-1]) + [n_samples]).to(device) + + # Invert CDF + u = u.contiguous() + inds = torch.searchsorted(cdf, u, right=True) + below = torch.max(torch.zeros_like(inds - 1).to(device), inds - 1) + above = torch.min((cdf.shape[-1] - 1) * torch.ones_like(inds).to(device), inds) + inds_g = torch.stack([below, above], -1) # (batch, N_samples, 2) + + matched_shape = [inds_g.shape[0], inds_g.shape[1], cdf.shape[-1]] + cdf_g = torch.gather(cdf.unsqueeze(1).expand(matched_shape), 2, inds_g) + bins_g = torch.gather(bins.unsqueeze(1).expand(matched_shape), 2, inds_g) + + denom = (cdf_g[..., 1] - cdf_g[..., 0]) + denom = torch.where(denom < 1e-5, torch.ones_like(denom).to(device), denom) + t = (u - cdf_g[..., 0]) / denom + samples = bins_g[..., 0] + t * (bins_g[..., 1] - bins_g[..., 0]) + + return samples + + +class NeuSRenderer: + def __init__(self, + nerf, + sdf_network, + deviation_network, + color_network, + n_samples, + n_importance, + n_outside, + up_sample_steps, + perturb, + sdf_decay_param): + self.nerf = nerf + self.sdf_network = sdf_network + self.deviation_network = deviation_network + self.color_network = color_network + self.n_samples = n_samples + self.n_importance = n_importance + self.n_outside = n_outside + self.up_sample_steps = up_sample_steps + self.perturb = perturb + + self.sdf_decay_param = sdf_decay_param + + def render_core_outside(self, rays_o, rays_d, z_vals, sample_dist, nerf, background_rgb=None): + """ + Render background + """ + batch_size, n_samples = z_vals.shape + + # Section length + dists = z_vals[..., 1:] - z_vals[..., :-1] + dists = torch.cat([dists, torch.Tensor([sample_dist]).expand(dists[..., :1].shape)], -1) + mid_z_vals = z_vals + dists * 0.5 + + # Section midpoints + pts = rays_o[:, None, :] + rays_d[:, None, :] * mid_z_vals[..., :, None] # batch_size, n_samples, 3 + + dis_to_center = torch.linalg.norm(pts, ord=2, dim=-1, keepdim=True).clip(1.0, 1e10) + pts = torch.cat([pts / dis_to_center, 1.0 / dis_to_center], dim=-1) # batch_size, n_samples, 4 + + dirs = rays_d[:, None, :].expand(batch_size, n_samples, 3) + + pts = pts.reshape(-1, 3 + int(self.n_outside > 0)) + dirs = dirs.reshape(-1, 3) + + density, sampled_color = nerf(pts, dirs) + sampled_color = torch.sigmoid(sampled_color) + alpha = 1.0 - torch.exp(-F.softplus(density.reshape(batch_size, n_samples)) * dists) + alpha = alpha.reshape(batch_size, n_samples) + weights = alpha * torch.cumprod(torch.cat([torch.ones([batch_size, 1]), 1. - alpha + 1e-7], -1), -1)[:, :-1] + sampled_color = sampled_color.reshape(batch_size, n_samples, 3) + color = (weights[:, :, None] * sampled_color).sum(dim=1) + if background_rgb is not None: + color = color + background_rgb * (1.0 - weights.sum(dim=-1, keepdim=True)) + + return { + 'color': color, + 'sampled_color': sampled_color, + 'alpha': alpha, + 'weights': weights, + } + + def up_sample(self, rays_o, rays_d, z_vals, sdf, n_importance, inv_s): + """ + Up sampling give a fixed inv_s + """ + device = rays_o.device + batch_size, n_samples = z_vals.shape + pts = rays_o[:, None, :] + rays_d[:, None, :] * z_vals[..., :, None] # n_rays, n_samples, 3 + radius = torch.linalg.norm(pts, ord=2, dim=-1, keepdim=False) + inside_sphere = (radius[:, :-1] < 1.0) | (radius[:, 1:] < 1.0) + sdf = sdf.reshape(batch_size, n_samples) + prev_sdf, next_sdf = sdf[:, :-1], sdf[:, 1:] + prev_z_vals, next_z_vals = z_vals[:, :-1], z_vals[:, 1:] + mid_sdf = (prev_sdf + next_sdf) * 0.5 + cos_val = (next_sdf - prev_sdf) / (next_z_vals - prev_z_vals + 1e-5) + + # ---------------------------------------------------------------------------------------------------------- + # Use min value of [ cos, prev_cos ] + # Though it makes the sampling (not rendering) a little bit biased, this strategy can make the sampling more + # robust when meeting situations like below: + # + # SDF + # ^ + # |\ -----x----... + # | \ / + # | x x + # |---\----/-------------> 0 level + # | \ / + # | \/ + # | + # ---------------------------------------------------------------------------------------------------------- + prev_cos_val = torch.cat([torch.zeros([batch_size, 1]).to(device), cos_val[:, :-1]], dim=-1) + cos_val = torch.stack([prev_cos_val, cos_val], dim=-1) + cos_val, _ = torch.min(cos_val, dim=-1, keepdim=False) + cos_val = cos_val.clip(-1e3, 0.0) * inside_sphere + + dist = (next_z_vals - prev_z_vals) + prev_esti_sdf = mid_sdf - cos_val * dist * 0.5 + next_esti_sdf = mid_sdf + cos_val * dist * 0.5 + prev_cdf = torch.sigmoid(prev_esti_sdf * inv_s) + next_cdf = torch.sigmoid(next_esti_sdf * inv_s) + alpha = (prev_cdf - next_cdf + 1e-5) / (prev_cdf + 1e-5) + weights = alpha * torch.cumprod( + torch.cat([torch.ones([batch_size, 1]).to(device), 1. - alpha + 1e-7], -1), -1)[:, :-1] + + z_samples = sample_pdf(z_vals, weights, n_importance, det=True).detach() + return z_samples + + def cat_z_vals(self, rays_o, rays_d, z_vals, new_z_vals, sdf, last=False): + batch_size, n_samples = z_vals.shape + _, n_importance = new_z_vals.shape + pts = rays_o[:, None, :] + rays_d[:, None, :] * new_z_vals[..., :, None] + z_vals = torch.cat([z_vals, new_z_vals], dim=-1) + z_vals, index = torch.sort(z_vals, dim=-1) + + if not last: + new_sdf = self.sdf_network.sdf(pts.reshape(-1, 3)).reshape(batch_size, n_importance) + sdf = torch.cat([sdf, new_sdf], dim=-1) + xx = torch.arange(batch_size)[:, None].expand(batch_size, n_samples + n_importance).reshape(-1) + index = index.reshape(-1) + sdf = sdf[(xx, index)].reshape(batch_size, n_samples + n_importance) + + return z_vals, sdf + + def render_core(self, + rays_o, + rays_d, + z_vals, + sample_dist, + sdf_network, + deviation_network, + color_network, + background_alpha=None, + background_sampled_color=None, + background_rgb=None, + cos_anneal_ratio=0.0): + batch_size, n_samples = z_vals.shape + device = rays_o.device + # Section length + dists = z_vals[..., 1:] - z_vals[..., :-1] + dists = torch.cat([dists, torch.Tensor([sample_dist]).expand(dists[..., :1].shape).to(device)], -1) + mid_z_vals = z_vals + dists * 0.5 + + # Section midpoints + pts = rays_o[:, None, :] + rays_d[:, None, :] * mid_z_vals[..., :, None] # n_rays, n_samples, 3 + dirs = rays_d[:, None, :].expand(pts.shape) + + pts = pts.reshape(-1, 3) + dirs = dirs.reshape(-1, 3) + + sdf_nn_output = sdf_network(pts) + sdf = sdf_nn_output[:, :1] + feature_vector = sdf_nn_output[:, 1:] + + gradients = sdf_network.gradient(pts).squeeze() + sampled_color = color_network(pts, gradients, dirs, feature_vector).reshape(batch_size, n_samples, 3) + + inv_s = deviation_network(torch.zeros([1, 3]).to(device))[:, :1].clip(1e-6, 1e6) # Single parameter + inv_s = inv_s.expand(batch_size * n_samples, 1) + + true_cos = (dirs * gradients).sum(-1, keepdim=True) + + # "cos_anneal_ratio" grows from 0 to 1 in the beginning training iterations. The anneal strategy below makes + # the cos value "not dead" at the beginning training iterations, for better convergence. + iter_cos = -(F.relu(-true_cos * 0.5 + 0.5) * (1.0 - cos_anneal_ratio) + + F.relu(-true_cos) * cos_anneal_ratio) # always non-positive + + # Estimate signed distances at section points + estimated_next_sdf = sdf + iter_cos * dists.reshape(-1, 1) * 0.5 + estimated_prev_sdf = sdf - iter_cos * dists.reshape(-1, 1) * 0.5 + + prev_cdf = torch.sigmoid(estimated_prev_sdf * inv_s) + next_cdf = torch.sigmoid(estimated_next_sdf * inv_s) + + p = prev_cdf - next_cdf + c = prev_cdf + + alpha = ((p + 1e-5) / (c + 1e-5)).reshape(batch_size, n_samples).clip(0.0, 1.0) + + pts_norm = torch.linalg.norm(pts, ord=2, dim=-1, keepdim=True).reshape(batch_size, n_samples) + inside_sphere = (pts_norm < 1.0).float().detach() + relax_inside_sphere = (pts_norm < 1.2).float().detach() + + # Render with background + if background_alpha is not None: + alpha = alpha * inside_sphere + background_alpha[:, :n_samples] * (1.0 - inside_sphere) + alpha = torch.cat([alpha, background_alpha[:, n_samples:]], dim=-1) + sampled_color = sampled_color * inside_sphere[:, :, None] +\ + background_sampled_color[:, :n_samples] * (1.0 - inside_sphere)[:, :, None] + sampled_color = torch.cat([sampled_color, background_sampled_color[:, n_samples:]], dim=1) + + weights = alpha * torch.cumprod(torch.cat([torch.ones([batch_size, 1]).to(device), 1. - alpha + 1e-7], -1), -1)[:, :-1] + weights_sum = weights.sum(dim=-1, keepdim=True) + + color = (sampled_color * weights[:, :, None]).sum(dim=1) + if background_rgb is not None: # Fixed background, usually black + color = color + background_rgb.to(device) * (1.0 - weights_sum) + + # Eikonal loss + gradient_error = (torch.linalg.norm(gradients.reshape(batch_size, n_samples, 3), ord=2, + dim=-1) - 1.0) ** 2 + gradient_error = (relax_inside_sphere * gradient_error).sum() / (relax_inside_sphere.sum() + 1e-5) + + depth = (mid_z_vals * weights[:, :n_samples]).sum(dim=1, keepdim=True) + + return { + 'color': color, + 'sdf': sdf, + 'dists': dists, + 'gradients': gradients.reshape(batch_size, n_samples, 3), + 's_val': 1.0 / inv_s, + 'mid_z_vals': mid_z_vals, + 'weights': weights, + 'cdf': c.reshape(batch_size, n_samples), + 'gradient_error': gradient_error, + 'inside_sphere': inside_sphere, + 'depth': depth, + } + + def render(self, rays_o, rays_d, near, far, perturb_overwrite=-1, background_rgb=None, cos_anneal_ratio=0.0): + batch_size = len(rays_o) + device = rays_o.device + sample_dist = 2.0 / self.n_samples # Assuming the region of interest is a unit sphere + z_vals = torch.linspace(0.0, 1.0, self.n_samples) + z_vals = near + (far - near) * z_vals[None, :] + + z_vals_outside = None + if self.n_outside > 0: + z_vals_outside = torch.linspace(1e-3, 1.0 - 1.0 / (self.n_outside + 1.0), self.n_outside) + + n_samples = self.n_samples + perturb = self.perturb + + if perturb_overwrite >= 0: + perturb = perturb_overwrite + if perturb > 0: + t_rand = (torch.rand([batch_size, 1]) - 0.5) + z_vals = z_vals + t_rand * 2.0 / self.n_samples + z_vals = z_vals.to(device) + + if self.n_outside > 0: + mids = .5 * (z_vals_outside[..., 1:] + z_vals_outside[..., :-1]) + upper = torch.cat([mids, z_vals_outside[..., -1:]], -1) + lower = torch.cat([z_vals_outside[..., :1], mids], -1) + t_rand = torch.rand([batch_size, z_vals_outside.shape[-1]]) + z_vals_outside = lower[None, :] + (upper - lower)[None, :] * t_rand + + if self.n_outside > 0: + z_vals_outside = far / torch.flip(z_vals_outside, dims=[-1]) + 1.0 / self.n_samples + + background_alpha = None + background_sampled_color = None + + # Up sample + if self.n_importance > 0: + with torch.no_grad(): + pts = rays_o[:, None, :] + rays_d[:, None, :] * z_vals[..., :, None] + sdf = self.sdf_network.sdf(pts.reshape(-1, 3)).reshape(batch_size, self.n_samples) + + for i in range(self.up_sample_steps): + new_z_vals = self.up_sample(rays_o, + rays_d, + z_vals, + sdf, + self.n_importance // self.up_sample_steps, + 64 * 2**i) + z_vals, sdf = self.cat_z_vals(rays_o, + rays_d, + z_vals, + new_z_vals, + sdf, + last=(i + 1 == self.up_sample_steps)) + + n_samples = self.n_samples + self.n_importance + + # Background model + if self.n_outside > 0: + z_vals_feed = torch.cat([z_vals, z_vals_outside], dim=-1) + z_vals_feed, _ = torch.sort(z_vals_feed, dim=-1) + ret_outside = self.render_core_outside(rays_o, rays_d, z_vals_feed, sample_dist, self.nerf) + + background_sampled_color = ret_outside['sampled_color'] + background_alpha = ret_outside['alpha'] + + # Render core + ret_fine = self.render_core(rays_o, + rays_d, + z_vals, + sample_dist, + self.sdf_network, + self.deviation_network, + self.color_network, + background_rgb=background_rgb, + background_alpha=background_alpha, + background_sampled_color=background_sampled_color, + cos_anneal_ratio=cos_anneal_ratio) + + color_fine = ret_fine['color'] + weights = ret_fine['weights'] + weights_sum = weights.sum(dim=-1, keepdim=True) + gradients = ret_fine['gradients'] + s_val = ret_fine['s_val'].reshape(batch_size, n_samples).mean(dim=-1, keepdim=True) + + + # - randomly sample points from the volume, and maximize the sdf + pts_random = torch.rand([1024, 3]).float().cuda() * 2 - 1 # normalized to (-1, 1) + sdf_random = self.sdf_network(pts_random)[:, :1] + + sparse_loss_1 = torch.exp( + -1 * torch.abs(sdf_random) * self.sdf_decay_param).mean() # - should equal + sparse_loss_2 = torch.exp(-1 * torch.abs(ret_fine['sdf']) * self.sdf_decay_param).mean() + sparse_loss = (sparse_loss_1 + sparse_loss_2) / 2 + + return { + 'color_fine': color_fine, + 'depth': ret_fine['depth'], + 's_val': s_val, + 'sparse_loss': sparse_loss, + 'cdf_fine': ret_fine['cdf'], + 'weight_sum': weights_sum, + 'weight_max': torch.max(weights, dim=-1, keepdim=True)[0], + 'gradients': gradients, + 'weights': weights, + 'gradient_error': ret_fine['gradient_error'], + 'inside_sphere': ret_fine['inside_sphere'] + } + + + def get_vertex_colors(self, vertices): + """ + @param vertices: n,3 + @return: + """ + V = vertices.shape[0] + bn = 20480 + verts_colors = [] + with torch.no_grad(): + for vi in range(0, V, bn): + verts = torch.from_numpy(vertices[vi:vi+bn].astype(np.float32)).cuda() + feats = self.sdf_network(verts)[..., 1:] + # pdb.set_trace() + gradients = self.sdf_network.gradient(verts) # ...,3 + gradients = F.normalize(gradients, dim=-1).squeeze(1) + # pdb.set_trace() + colors = self.color_network(verts, gradients, gradients, feats) + colors = torch.clamp(colors,min=0,max=1).cpu().numpy() + verts_colors.append(colors) + + verts_colors = (np.concatenate(verts_colors, 0)*255).astype(np.uint8) + return verts_colors[:, ::-1] + + def extract_geometry(self, bound_min, bound_max, resolution, threshold=0.0): + return extract_geometry(bound_min, + bound_max, + resolution=resolution, + threshold=threshold, + query_func=lambda pts: -self.sdf_network.sdf(pts), + color_func=lambda pts: self.get_vertex_colors(pts)) diff --git a/apps/third_party/Wonder3D/NeuS/run.sh b/apps/third_party/Wonder3D/NeuS/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..d541df1abca748171b8450bac7433f319272f093 --- /dev/null +++ b/apps/third_party/Wonder3D/NeuS/run.sh @@ -0,0 +1 @@ +python exp_runner.py --mode train --conf ./confs/wmask.conf --case $2 --data_dir $1 diff --git a/apps/third_party/Wonder3D/README.md b/apps/third_party/Wonder3D/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0c6ab8ce53ae04d5e6718f784d77c96eab8f4608 --- /dev/null +++ b/apps/third_party/Wonder3D/README.md @@ -0,0 +1,227 @@ +**中文版本 [中文](README_zh.md)** +# Wonder3D +Single Image to 3D using Cross-Domain Diffusion +## [Paper](https://arxiv.org/abs/2310.15008) | [Project page](https://www.xxlong.site/Wonder3D/) | [Hugging Face Demo](https://huggingface.co/spaces/flamehaze1115/Wonder3D-demo) | [Colab from @camenduru](https://github.com/camenduru/Wonder3D-colab) + +![](assets/fig_teaser.png) + +Wonder3D reconstructs highly-detailed textured meshes from a single-view image in only 2 ∼ 3 minutes. Wonder3D first generates consistent multi-view normal maps with corresponding color images via a cross-domain diffusion model, and then leverages a novel normal fusion method to achieve fast and high-quality reconstruction. + +## News +- Fixed a severe training bug. The "zero_init_camera_projection" in 'configs/train/stage1-mix-6views-lvis.yaml' should be False. Otherwise, the domain control and pose control will be invalid in the training. +- 2024.03.19 Checkout our new model [GeoWizard](https://github.com/fuxiao0719/GeoWizard) that jointly produces depth and normal with high fidelity from single images. + +## Usage +```bash + +# First clone the repo, and use the commands in the repo + +import torch +import requests +from PIL import Image +import numpy as np +from torchvision.utils import make_grid, save_image +from diffusers import DiffusionPipeline # only tested on diffusers[torch]==0.19.3, may have conflicts with newer versions of diffusers + +def load_wonder3d_pipeline(): + + pipeline = DiffusionPipeline.from_pretrained( + 'flamehaze1115/wonder3d-v1.0', # or use local checkpoint './ckpts' + custom_pipeline='flamehaze1115/wonder3d-pipeline', + torch_dtype=torch.float16 + ) + + # enable xformers + pipeline.unet.enable_xformers_memory_efficient_attention() + + if torch.cuda.is_available(): + pipeline.to('cuda:0') + return pipeline + +pipeline = load_wonder3d_pipeline() + +# Download an example image. +cond = Image.open(requests.get("https://d.skis.ltd/nrp/sample-data/lysol.png", stream=True).raw) + +# The object should be located in the center and resized to 80% of image height. +cond = Image.fromarray(np.array(cond)[:, :, :3]) + +# Run the pipeline! +images = pipeline(cond, num_inference_steps=20, output_type='pt', guidance_scale=1.0).images + +result = make_grid(images, nrow=6, ncol=2, padding=0, value_range=(0, 1)) + +save_image(result, 'result.png') +``` + +## Collaborations +Our overarching mission is to enhance the speed, affordability, and quality of 3D AIGC, making the creation of 3D content accessible to all. While significant progress has been achieved in the recent years, we acknowledge there is still a substantial journey ahead. We enthusiastically invite you to engage in discussions and explore potential collaborations in any capacity. **If you're interested in connecting or partnering with us, please don't hesitate to reach out via email (xxlong@connect.hku.hk)** . + +## News + +- 2024.02 We release the training codes. Welcome to train wonder3D on your personal data. +- 2023.10 We release the inference model and codes. + + +### Preparation for inference + +#### Linux System Setup. +```angular2html +conda create -n wonder3d +conda activate wonder3d +pip install -r requirements.txt +pip install git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch +``` +#### Windows System Setup. + +Please switch to branch `main-windows` to see details of windows setup. + +#### Docker Setup +see [docker/README.MD](docker/README.md) + +### Training +Here we provide two training scripts `train_mvdiffusion_image.py` and `train_mvdiffusion_joint.py`. + +The training has two stages: 1) first train multi-view attentions by randomly taking normal or color flag; 2) add cross-domain attention modules into the SD model, and only optimize the newly added parameters. + +You need to modify `root_dir` that contain the data of the config files `configs/train/stage1-mix-6views-lvis.yaml` and `configs/train/stage2-joint-6views-lvis.yaml` accordingly. + +``` +# stage 1: +accelerate launch --config_file 8gpu.yaml train_mvdiffusion_image.py --config configs/train/stage1-mix-6views-lvis.yaml + +# stage 2 +accelerate launch --config_file 8gpu.yaml train_mvdiffusion_joint.py --config configs/train/stage2-joint-6views-lvis.yaml +``` + +### Prepare the training data +see [render_codes/README.md](render_codes/README.md). + +### Inference +1. Optional. If you have troubles to connect to huggingface. Make sure you have downloaded the following models. +Download the [checkpoints](https://connecthkuhk-my.sharepoint.com/:f:/g/personal/xxlong_connect_hku_hk/Ej7fMT1PwXtKvsELTvDuzuMBebQXEkmf2IwhSjBWtKAJiA) and into the root folder. + +If you are in mainland China, you may download via [aliyun](https://www.alipan.com/s/T4rLUNAVq6V). + +```bash +Wonder3D +|-- ckpts + |-- unet + |-- scheduler + |-- vae + ... +``` +Then modify the file ./configs/mvdiffusion-joint-ortho-6views.yaml, set `pretrained_model_name_or_path="./ckpts"` + +2. Download the [SAM](https://huggingface.co/spaces/abhishek/StableSAM/blob/main/sam_vit_h_4b8939.pth) model. Put it to the ``sam_pt`` folder. +``` +Wonder3D +|-- sam_pt + |-- sam_vit_h_4b8939.pth +``` +3. Predict foreground mask as the alpha channel. We use [Clipdrop](https://clipdrop.co/remove-background) to segment the foreground object interactively. +You may also use `rembg` to remove the backgrounds. +```bash +# !pip install rembg +import rembg +result = rembg.remove(result) +result.show() +``` +4. Run Wonder3d to produce multiview-consistent normal maps and color images. Then you can check the results in the folder `./outputs`. (we use `rembg` to remove backgrounds of the results, but the segmentations are not always perfect. May consider using [Clipdrop](https://clipdrop.co/remove-background) to get masks for the generated normal maps and color images, since the quality of masks will significantly influence the reconstructed mesh quality.) +```bash +accelerate launch --config_file 1gpu.yaml test_mvdiffusion_seq.py \ + --config configs/mvdiffusion-joint-ortho-6views.yaml validation_dataset.root_dir={your_data_path} \ + validation_dataset.filepaths=['your_img_file'] save_dir={your_save_path} +``` + +see example: + +```bash +accelerate launch --config_file 1gpu.yaml test_mvdiffusion_seq.py \ + --config configs/mvdiffusion-joint-ortho-6views.yaml validation_dataset.root_dir=./example_images \ + validation_dataset.filepaths=['owl.png'] save_dir=./outputs +``` + +#### Interactive inference: run your local gradio demo. (Only generate normals and colors without reconstruction) +```bash +python gradio_app_mv.py # generate multi-view normals and colors +``` + +5. Mesh Extraction + +#### Instant-NSR Mesh Extraction + +```bash +cd ./instant-nsr-pl +python launch.py --config configs/neuralangelo-ortho-wmask.yaml --gpu 0 --train dataset.root_dir=../{your_save_path}/cropsize-{crop_size}-cfg{guidance_scale:.1f}/ dataset.scene={scene} +``` + +see example: + +```bash +cd ./instant-nsr-pl +python launch.py --config configs/neuralangelo-ortho-wmask.yaml --gpu 0 --train dataset.root_dir=../outputs/cropsize-192-cfg1.0/ dataset.scene=owl +``` + +Our generated normals and color images are defined in orthographic views, so the reconstructed mesh is also in orthographic camera space. If you use MeshLab to view the meshes, you can click `Toggle Orthographic Camera` in `View` tab. + +#### Interactive inference: run your local gradio demo. (First generate normals and colors, and then do reconstructions. No need to perform gradio_app_mv.py first.) +```bash +python gradio_app_recon.py +``` + +#### NeuS-based Mesh Extraction + +Since there are many complaints about the Windows setup of instant-nsr-pl, we provide the NeuS-based reconstruction, which may get rid of the requirement problems. + +NeuS consumes less GPU memory and favors smooth surfaces without parameters tuning. However, NeuS consumes more times and its texture may be less sharp. If you are not sensitive to time, we recommend NeuS for optimization due to its robustness. + +```bash +cd ./NeuS +bash run.sh output_folder_path scene_name +``` + +## Common questions +Q: Tips to get better results. +1. Wonder3D is sensitive the facing direciton of input images. By experiments, front-facing images always lead to good reconstruction. +2. Limited by resources, current implemetation only supports limited views (6 views) and low resolution (256x256). Any images will be first resized into 256x256 for generation, so images after such a downsample that still keep clear and sharp features will lead to good results. +3. Images with occlusions will cause worse reconstructions, since 6 views cannot cover the complete object. Images with less occlsuions lead to better results. +4. Increate optimization steps in instant-nsr-pl, modify `trainer.max_steps: 3000` in `instant-nsr-pl/configs/neuralangelo-ortho-wmask.yaml` to more steps like `trainer.max_steps: 10000`. Longer optimization leads to better texture. + +Q: The evelation and azimuth degrees of the generated views? + +A: Unlike that the prior works such as Zero123, SyncDreamer and One2345 adopt object world system, our views are defined in the camera system of the input image. The six views are in the plane with 0 elevation degree in the camera system of the input image. Therefore we don't need to estimate an elevation degree for input image. The azimuth degrees of the six views are 0, 45, 90, 180, -90, -45 respectively. + +Q: The focal length of the generated views? + +A: We assume the input images are captured by orthographic camera, so the generated views are also in orthographic space. This design enables our model to keep strong generlaization on unreal images, but sometimes it may suffer from focal lens distortions on real-captured images. + +## Details about the camera system and camera poses +![](assets/coordinate.png) +In practice, the target object is assumed to be placed along the gravity direction. +1) **Canonical coordinate system.** Some prior works (e.g. MVDream and SyncDreamer) adopt a shared canonical system for all objects, whose axis $Z_c$ shares the same direction with gravity (a). +2) **Input view related system.** Wonder3D adopts an independent coordinate system for each object that is related to the input view. +Its $Z_v$ and $X_v$ axes are aligned with the UV dimension of 2D input image space, and its $Y_v$ axis is vertical to the 2D image plane and passes through the center of ROI (Region of Interests) (b). +3) **Camera poses.** Wonder3D outputs 6 views $\{v_i, i=0,...,5\}$ that are sampled at the $X_vOY_v$ plane of the input-view related system with a fixed radius, where the front view $v_0$ is initialized as input view and the other views are sampled with pre-defined azimuth degrees (see (b)). + +## Acknowledgement +We have intensively borrow codes from the following repositories. Many thanks to the authors for sharing their codes. +- [stable diffusion](https://github.com/CompVis/stable-diffusion) +- [zero123](https://github.com/cvlab-columbia/zero123) +- [NeuS](https://github.com/Totoro97/NeuS) +- [SyncDreamer](https://github.com/liuyuan-pal/SyncDreamer) +- [instant-nsr-pl](https://github.com/bennyguo/instant-nsr-pl) + +## License +Wonder3D is under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html), so any downstream solution and products (including cloud services) that include wonder3d code or a trained model (both pretrained or custom trained) inside it should be open-sourced to comply with the AGPL conditions. If you have any questions about the usage of Wonder3D, please contact us first. + +## Citation +If you find this repository useful in your project, please cite the following work. :) +``` +@article{long2023wonder3d, + title={Wonder3D: Single Image to 3D using Cross-Domain Diffusion}, + author={Long, Xiaoxiao and Guo, Yuan-Chen and Lin, Cheng and Liu, Yuan and Dou, Zhiyang and Liu, Lingjie and Ma, Yuexin and Zhang, Song-Hai and Habermann, Marc and Theobalt, Christian and others}, + journal={arXiv preprint arXiv:2310.15008}, + year={2023} +} +``` diff --git a/apps/third_party/Wonder3D/README_zh.md b/apps/third_party/Wonder3D/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..d7f3e24d909bedc3c8c21652fb64e1debbc02d5a --- /dev/null +++ b/apps/third_party/Wonder3D/README_zh.md @@ -0,0 +1,203 @@ +**其他语言版本 [English](README.md)** + +# Wonder3D +Single Image to 3D using Cross-Domain Diffusion +## [Paper](https://arxiv.org/abs/2310.15008) | [Project page](https://www.xxlong.site/Wonder3D/) | [Hugging Face Demo](https://huggingface.co/spaces/flamehaze1115/Wonder3D-demo) | [Colab from @camenduru](https://github.com/camenduru/Wonder3D-colab) + +![](assets/fig_teaser.png) + +Wonder3D仅需2至3分钟即可从单视图图像中重建出高度详细的纹理网格。Wonder3D首先通过跨域扩散模型生成一致的多视图法线图与相应的彩色图像,然后利用一种新颖的法线融合方法实现快速且高质量的重建。 + +## Usage 使用 +```bash + +import torch +import requests +from PIL import Image +import numpy as np +from torchvision.utils import make_grid, save_image +from diffusers import DiffusionPipeline # only tested on diffusers[torch]==0.19.3, may have conflicts with newer versions of diffusers + +def load_wonder3d_pipeline(): + + pipeline = DiffusionPipeline.from_pretrained( + 'flamehaze1115/wonder3d-v1.0', # or use local checkpoint './ckpts' + custom_pipeline='flamehaze1115/wonder3d-pipeline', + torch_dtype=torch.float16 + ) + + # enable xformers + pipeline.unet.enable_xformers_memory_efficient_attention() + + if torch.cuda.is_available(): + pipeline.to('cuda:0') + return pipeline + +pipeline = load_wonder3d_pipeline() + +# Download an example image. +cond = Image.open(requests.get("https://d.skis.ltd/nrp/sample-data/lysol.png", stream=True).raw) + +# The object should be located in the center and resized to 80% of image height. +cond = Image.fromarray(np.array(cond)[:, :, :3]) + +# Run the pipeline! +images = pipeline(cond, num_inference_steps=20, output_type='pt', guidance_scale=1.0).images + +result = make_grid(images, nrow=6, ncol=2, padding=0, value_range=(0, 1)) + +save_image(result, 'result.png') +``` + +## Collaborations 合作 +我们的总体使命是提高3D人工智能图形生成(3D AIGC)的速度、可负担性和质量,使所有人都能够轻松创建3D内容。尽管近年来取得了显著的进展,我们承认前方仍有很长的路要走。我们热切邀请您参与讨论并在任何方面探索潜在的合作机会。**如果您有兴趣与我们联系或合作,请随时通过电子邮件(xxlong@connect.hku.hk)联系我们**。 + +## More features + +The repo is still being under construction, thanks for your patience. +- [x] Local gradio demo. +- [x] Detailed tutorial. +- [x] GUI demo for mesh reconstruction +- [x] Windows support +- [x] Docker support + +## Schedule +- [x] Inference code and pretrained models. +- [x] Huggingface demo. +- [ ] New model with higher resolution. + + +### Preparation for inference 测试准备 + +#### Linux System Setup. +```angular2html +conda create -n wonder3d +conda activate wonder3d +pip install -r requirements.txt +pip install git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch +``` +#### Windows System Setup. + +请切换到`main-windows`分支以查看Windows设置的详细信息。 + +#### Docker Setup +详见 [docker/README.MD](docker/README.md) + +### Inference +1. 可选。如果您在连接到Hugging Face时遇到问题,请确保已下载以下模型。 +下载[checkpoints](https://connecthkuhk-my.sharepoint.com/:f:/g/personal/xxlong_connect_hku_hk/Ej7fMT1PwXtKvsELTvDuzuMBebQXEkmf2IwhSjBWtKAJiA)并放入根文件夹中。 + +国内用户可下载: [阿里云盘](https://www.alipan.com/s/T4rLUNAVq6V) + +```bash +Wonder3D +|-- ckpts + |-- unet + |-- scheduler + |-- vae + ... +``` +然后更改文件 ./configs/mvdiffusion-joint-ortho-6views.yaml, 设置 `pretrained_model_name_or_path="./ckpts"` + +2. 下载模型 [SAM](https://huggingface.co/spaces/abhishek/StableSAM/blob/main/sam_vit_h_4b8939.pth) . 放置在 ``sam_pt`` 文件夹. +``` +Wonder3D +|-- sam_pt + |-- sam_vit_h_4b8939.pth +``` +3. 预测前景蒙版作为阿尔法通道。我们使用[Clipdrop](https://clipdrop.co/remove-background)来交互地分割前景对象。 +您还可以使用`rembg`来去除背景。 +```bash +# !pip install rembg +import rembg +result = rembg.remove(result) +result.show() +``` +4. 运行Wonder3D以生成多视角一致的法线图和彩色图像。然后,您可以在文件夹`./outputs`中检查结果(我们使用`rembg`去除结果的背景,但分割并不总是完美的。可以考虑使用[Clipdrop](https://clipdrop.co/remove-background)获取生成的法线图和彩色图像的蒙版,因为蒙版的质量将显著影响重建的网格质量)。 +```bash +accelerate launch --config_file 1gpu.yaml test_mvdiffusion_seq.py \ + --config configs/mvdiffusion-joint-ortho-6views.yaml validation_dataset.root_dir={your_data_path} \ + validation_dataset.filepaths=['your_img_file'] save_dir={your_save_path} +``` + +示例: + +```bash +accelerate launch --config_file 1gpu.yaml test_mvdiffusion_seq.py \ + --config configs/mvdiffusion-joint-ortho-6views.yaml validation_dataset.root_dir=./example_images \ + validation_dataset.filepaths=['owl.png'] save_dir=./outputs +``` + +#### 运行本地的Gradio演示。仅生成法线和颜色,无需进行重建。 +```bash +python gradio_app_mv.py # generate multi-view normals and colors +``` + +5. Mesh Extraction + +#### Instant-NSR Mesh Extraction + +```bash +cd ./instant-nsr-pl +python launch.py --config configs/neuralangelo-ortho-wmask.yaml --gpu 0 --train dataset.root_dir=../{your_save_path}/cropsize-{crop_size}-cfg{guidance_scale:.1f}/ dataset.scene={scene} +``` + +示例: + +```bash +cd ./instant-nsr-pl +python launch.py --config configs/neuralangelo-ortho-wmask.yaml --gpu 0 --train dataset.root_dir=../outputs/cropsize-192-cfg1.0/ dataset.scene=owl +``` + +我们生成的法线图和彩色图像是在正交视图中定义的,因此重建的网格也处于正交摄像机空间。如果您使用MeshLab查看网格,可以在“View”选项卡中单击“Toggle Orthographic Camera”切换到正交相机。 + +#### 运行本地的Gradio演示。首先生成法线和颜色,然后进行重建。无需首先执行`gradio_app_mv.py`。 +```bash +python gradio_app_recon.py +``` + +#### NeuS-based Mesh Extraction + +由于许多用户对于instant-nsr-pl的Windows设置提出了抱怨,我们提供了基于NeuS的重建,这可能消除了一些要求方面的问题。 + +NeuS消耗较少的GPU内存,对平滑表面有利,无需参数调整。然而,NeuS需要更多时间,其纹理可能不够清晰。如果您对时间不太敏感,我们建议由于其稳健性而使用NeuS进行优化。 + +```bash +cd ./NeuS +bash run.sh output_folder_path scene_name +``` + +## 常见问题 +**获取更好结果的提示:** +1. **图片朝向方向敏感:** Wonder3D对输入图像的面向方向敏感。通过实验证明,面向前方的图像通常会导致良好的重建结果。 +2. **图像分辨率:** 受资源限制,当前实现仅支持有限的视图(6个视图)和低分辨率(256x256)。任何图像都将首先调整大小为256x256进行生成,因此在这样的降采样后仍然保持清晰而锐利特征的图像将导致良好的结果。 +3. **处理遮挡:** 具有遮挡的图像会导致更差的重建,因为6个视图无法完全覆盖整个对象。具有较少遮挡的图像通常会产生更好的结果。 +4. **增加instant-nsr-pl中的优化步骤:** 在instant-nsr-pl中增加优化步骤。在`instant-nsr-pl/configs/neuralangelo-ortho-wmask.yaml`中修改`trainer.max_steps: 3000`为更多步骤,例如`trainer.max_steps: 10000`。更长的优化步骤会导致更好的纹理。 + +**生成视图信息:** +- **仰角和方位角度:** 与Zero123、SyncDreamer和One2345等先前作品采用对象世界系统不同,我们的视图是在输入图像的相机系统中定义的。六个视图在输入图像的相机系统中的平面上,仰角为0度。因此,我们不需要为输入图像估算仰角。六个视图的方位角度分别为0、45、90、180、-90、-45。 + +**生成视图的焦距:** +- 我们假设输入图像是由正交相机捕获的,因此生成的视图也在正交空间中。这种设计使得我们的模型能够在虚构图像上保持强大的泛化能力,但有时可能在实际捕获的图像上受到焦距镜头畸变的影响。 + +## 致谢 +We have intensively borrow codes from the following repositories. Many thanks to the authors for sharing their codes. +- [stable diffusion](https://github.com/CompVis/stable-diffusion) +- [zero123](https://github.com/cvlab-columbia/zero123) +- [NeuS](https://github.com/Totoro97/NeuS) +- [SyncDreamer](https://github.com/liuyuan-pal/SyncDreamer) +- [instant-nsr-pl](https://github.com/bennyguo/instant-nsr-pl) + +## 协议 +Wonder3D采用[AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html)许可,因此任何包含Wonder3D代码或其中训练的模型(无论是预训练还是定制训练)的下游解决方案和产品(包括云服务)都应该开源以符合AGPL条件。如果您对Wonder3D的使用有任何疑问,请首先与我们联系。 + +## 引用 +如果您在项目中发现这个项目对您有用,请引用以下工作。 :) +``` +@article{long2023wonder3d, + title={Wonder3D: Single Image to 3D using Cross-Domain Diffusion}, + author={Long, Xiaoxiao and Guo, Yuan-Chen and Lin, Cheng and Liu, Yuan and Dou, Zhiyang and Liu, Lingjie and Ma, Yuexin and Zhang, Song-Hai and Habermann, Marc and Theobalt, Christian and others}, + journal={arXiv preprint arXiv:2310.15008}, + year={2023} +} +``` diff --git a/apps/third_party/Wonder3D/assets/coordinate.png b/apps/third_party/Wonder3D/assets/coordinate.png new file mode 100644 index 0000000000000000000000000000000000000000..fb31905187cdfbc615089ef6b29a36fd7fed536f Binary files /dev/null and b/apps/third_party/Wonder3D/assets/coordinate.png differ diff --git a/apps/third_party/Wonder3D/assets/fig_teaser.png b/apps/third_party/Wonder3D/assets/fig_teaser.png new file mode 100644 index 0000000000000000000000000000000000000000..40cc76812117e7ae142042eb4f03769ea2911d78 --- /dev/null +++ b/apps/third_party/Wonder3D/assets/fig_teaser.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e366d3fe06124b2f36ee43aca4da522a42e6ebf7d776cc0f5e8d0974cdc2971b +size 1271319 diff --git a/apps/third_party/Wonder3D/configs/mvdiffusion-joint-ortho-6views.yaml b/apps/third_party/Wonder3D/configs/mvdiffusion-joint-ortho-6views.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6444b96d014d63ae885693aeaebe5a4339c2b885 --- /dev/null +++ b/apps/third_party/Wonder3D/configs/mvdiffusion-joint-ortho-6views.yaml @@ -0,0 +1,42 @@ +pretrained_model_name_or_path: './ckpts/Wonder3D/models--flamehaze1115--wonder3d-v1.0/snapshots/d6d2efc033a06a74d3761268de7295c97e6935d2' # or './ckpts' +revision: null +validation_dataset: + root_dir: "./third_party/Wonder3D/example_images" # the folder path stores testing images + num_views: 6 + bg_color: 'white' + img_wh: [256, 256] + num_validation_samples: 1000 + crop_size: 192 + filepaths: ['owl.png'] # the test image names. leave it empty, test all images in the folder + +save_dir: './third_party/Wonder3D/outputs/' + +pred_type: 'joint' +seed: 42 +validation_batch_size: 1 +dataloader_num_workers: 64 + +local_rank: -1 + +pipe_kwargs: + camera_embedding_type: 'e_de_da_sincos' + num_views: 6 + +validation_guidance_scales: [1.0] +pipe_validation_kwargs: + eta: 1.0 +validation_grid_nrow: 6 + +unet_from_pretrained_kwargs: + camera_embedding_type: 'e_de_da_sincos' + projection_class_embeddings_input_dim: 10 + num_views: 6 + sample_size: 32 + cd_attention_mid: true + zero_init_conv_in: false + zero_init_camera_projection: false + +num_views: 6 +camera_embedding_type: 'e_de_da_sincos' + +enable_xformers_memory_efficient_attention: true \ No newline at end of file diff --git a/apps/third_party/Wonder3D/configs/train/stage1-mix-6views-lvis.yaml b/apps/third_party/Wonder3D/configs/train/stage1-mix-6views-lvis.yaml new file mode 100644 index 0000000000000000000000000000000000000000..884c5acc7f2c2f4c8fd88ddceeb3f2ff8ade84ec --- /dev/null +++ b/apps/third_party/Wonder3D/configs/train/stage1-mix-6views-lvis.yaml @@ -0,0 +1,112 @@ +pretrained_model_name_or_path: 'lambdalabs/sd-image-variations-diffusers' +revision: null +train_dataset: + root_dir: '/mnt/pfs/data/objaverse_renderings_ortho_9views/' # change to your path + object_list: './data_lists/lvis_uids_filter_by_vertex.json' + invalid_list: './data_lists/lvis_invalid_uids_nineviews.json' + num_views: 6 + groups_num: 1 + bg_color: 'three_choices' + img_wh: [256, 256] + validation: false + num_validation_samples: 32 + # read_normal: true + # read_color: true + mix_color_normal: true +validation_dataset: + root_dir: '/mnt/pfs/data/objaverse_renderings_ortho_9views/' # change to your path + object_list: './data_lists/lvis_uids_filter_by_vertex.json' + invalid_list: './data_lists/lvis_invalid_uids_nineviews.json' + num_views: 6 + groups_num: 1 + bg_color: 'white' + img_wh: [256, 256] + validation: true + num_validation_samples: 32 + # read_normal: true + # read_color: true + mix_color_normal: true +validation_train_dataset: + root_dir: '/mnt/pfs/data/objaverse_renderings_ortho_9views/' # change to your path + object_list: './data_lists/lvis_uids_filter_by_vertex.json' + invalid_list: './data_lists/lvis_invalid_uids_nineviews.json' + num_views: 6 + groups_num: 1 + bg_color: 'white' + img_wh: [256, 256] + validation: false + num_validation_samples: 32 + num_samples: 32 + # read_normal: true + # read_color: true + mix_color_normal: true + +pred_type: 'mix' + +output_dir: 'outputs/wonder3D-mix' +seed: 42 +train_batch_size: 32 +validation_batch_size: 16 +validation_train_batch_size: 16 +max_train_steps: 30000 +gradient_accumulation_steps: 2 +gradient_checkpointing: true +learning_rate: 1.e-4 +scale_lr: false +lr_scheduler: "constant_with_warmup" +lr_warmup_steps: 100 +snr_gamma: 5.0 +use_8bit_adam: false +allow_tf32: true +use_ema: true +dataloader_num_workers: 64 +adam_beta1: 0.9 +adam_beta2: 0.999 +adam_weight_decay: 1.e-2 +adam_epsilon: 1.e-08 +max_grad_norm: 1.0 +prediction_type: null +vis_dir: vis +logging_dir: logs +mixed_precision: "fp16" +report_to: 'tensorboard' +local_rank: -1 +checkpointing_steps: 5000 +checkpoints_total_limit: 20 +resume_from_checkpoint: latest +enable_xformers_memory_efficient_attention: true +validation_steps: 1250 +validation_sanity_check: true +tracker_project_name: 'mvdiffusion-image-v1' + +trainable_modules: null +use_classifier_free_guidance: true +condition_drop_rate: 0.05 +drop_type: 'drop_as_a_whole' # modify +camera_embedding_lr_mult: 10. +scale_input_latents: true + +pipe_kwargs: + camera_embedding_type: 'e_de_da_sincos' + num_views: 6 + +validation_guidance_scales: [1., 3.] +pipe_validation_kwargs: + eta: 1.0 +validation_grid_nrow: 12 + +unet_from_pretrained_kwargs: + camera_embedding_type: 'e_de_da_sincos' + projection_class_embeddings_input_dim: 10 # modify + num_views: 6 + sample_size: 32 + zero_init_conv_in: true + zero_init_camera_projection: false + cd_attention_last: false + cd_attention_mid: false + multiview_attention: true + sparse_mv_attention: false + mvcd_attention: false + +num_views: 6 +camera_embedding_type: 'e_de_da_sincos' diff --git a/apps/third_party/Wonder3D/configs/train/stage2-joint-6views-lvis.yaml b/apps/third_party/Wonder3D/configs/train/stage2-joint-6views-lvis.yaml new file mode 100644 index 0000000000000000000000000000000000000000..68e707f29c7ed8c1b0d8955d29e850648ecc8073 --- /dev/null +++ b/apps/third_party/Wonder3D/configs/train/stage2-joint-6views-lvis.yaml @@ -0,0 +1,115 @@ +pretrained_model_name_or_path: 'lambdalabs/sd-image-variations-diffusers' +# modify the unet path; use the stage 1 checkpoint +pretrained_unet_path: 'outputs/wonder3D-mix/checkpoint-30000/' +# pretrained_unet_path: null +revision: null +train_dataset: + root_dir: '/mnt/pfs/data/objaverse_renderings_ortho_9views/' # change to your path + object_list: './data_lists/lvis_uids_filter_by_vertex.json' + invalid_list: './data_lists/lvis_invalid_uids_nineviews.json' + num_views: 6 + groups_num: 1 + bg_color: 'three_choices' + img_wh: [256, 256] + validation: false + num_validation_samples: 32 + read_normal: true + read_color: true +validation_dataset: + root_dir: '/mnt/pfs/data/objaverse_renderings_ortho_9views/' # change to your path + object_list: './data_lists/lvis_uids_filter_by_vertex.json' + invalid_list: './data_lists/lvis_invalid_uids_nineviews.json' + num_views: 6 + groups_num: 1 + bg_color: 'white' + img_wh: [256, 256] + validation: true + num_validation_samples: 32 + read_normal: true + read_color: true +validation_train_dataset: + root_dir: '/mnt/pfs/data/objaverse_renderings_ortho_9views/' # change to your path + object_list: './data_lists/lvis_uids_filter_by_vertex.json' + invalid_list: './data_lists/lvis_invalid_uids_nineviews.json' + num_views: 6 + groups_num: 1 + bg_color: 'three_choices' + img_wh: [256, 256] + validation: false + num_validation_samples: 32 + num_samples: 32 + read_normal: true + read_color: true + +# output_dir: 'outputs/debug' +output_dir: 'outputs/wonder3D-joint' +seed: 42 +train_batch_size: 32 # original paper uses 32 +validation_batch_size: 16 +validation_train_batch_size: 16 +max_train_steps: 20000 +gradient_accumulation_steps: 2 +gradient_checkpointing: true +learning_rate: 5.e-5 +scale_lr: false +lr_scheduler: "constant_with_warmup" +lr_warmup_steps: 100 +snr_gamma: 5.0 +use_8bit_adam: false +allow_tf32: true +use_ema: true +dataloader_num_workers: 64 +adam_beta1: 0.9 +adam_beta2: 0.999 +adam_weight_decay: 1.e-2 +adam_epsilon: 1.e-08 +max_grad_norm: 1.0 +prediction_type: null +vis_dir: vis +logging_dir: logs +mixed_precision: "fp16" +report_to: 'tensorboard' +local_rank: -1 +checkpointing_steps: 5000 +checkpoints_total_limit: null +last_global_step: 5000 + +resume_from_checkpoint: latest +enable_xformers_memory_efficient_attention: true +validation_steps: 1000 +validation_sanity_check: true +tracker_project_name: 'mvdiffusion-image-v1' + +trainable_modules: ['joint_mid'] +use_classifier_free_guidance: true +condition_drop_rate: 0.05 +drop_type: 'drop_as_a_whole' # modify +camera_embedding_lr_mult: 10. +scale_input_latents: true + +pipe_kwargs: + camera_embedding_type: 'e_de_da_sincos' + num_views: 6 + +validation_guidance_scales: [1., 3.] +pipe_validation_kwargs: + eta: 1.0 +validation_grid_nrow: 12 + +unet_from_pretrained_kwargs: + camera_embedding_type: 'e_de_da_sincos' + projection_class_embeddings_input_dim: 10 # modify + num_views: 6 + sample_size: 32 + zero_init_conv_in: false + zero_init_camera_projection: false + cd_attention_last: false + cd_attention_mid: true + multiview_attention: true + sparse_mv_attention: false + mvcd_attention: false + +num_views: 6 +camera_embedding_type: 'e_de_da_sincos' + + diff --git a/apps/third_party/Wonder3D/data_lists/lvis_invalid_uids_nineviews.json b/apps/third_party/Wonder3D/data_lists/lvis_invalid_uids_nineviews.json new file mode 100644 index 0000000000000000000000000000000000000000..d2118ead08b824720a2d18bd419af2c408e0ca08 --- /dev/null +++ b/apps/third_party/Wonder3D/data_lists/lvis_invalid_uids_nineviews.json @@ -0,0 +1,3675 @@ +[ + "c9433cb2268f497491a3dfb5bab1870e", + "580615867c9545fbbba3176bf14169c9", + "606358954b0b421d85916e441997c3ef", + "0acd00b0410c4600a910899bc277b039", + "2b7d17764811472595b298f2b328760f", + "892e75e941b5425d918613fda34e4d1d", + "8cb30e472fda43788ca754aac2d42541", + "ea3c2447dd1442a3bda1322b4b1001bd", + "98c3f3ec677249359d8a61a4dbc79a34", + "a884bf6ce8b74648b6813564a443824a", + "be16353c31aa4a168c11b4a58a79f3d9", + "d415ec55aec448f4941ebd3c6e2d35bd", + "0d381d2a89104f59ae500c4157aa912f", + "6e9108a963d547f8b83af09bd905836e", + "3a7d0075025d4abb9f9790390fdd5b07", + "f911a85438e34044bee12417ea361c2d", + "33dedbfe99e24379a422db4d5c809752", + "7dc8c30e10cc46a1a052e7a30cab8a83", + "6000c9c630f848e8b516408e6eab610b", + "ab7497ab861a4a63b83d00f318e0976f", + "a82cdd603fc240b98e21dfdf3aba3245", + "da9675eb54df434584c38b35c1b6acdf", + "1a11f7daa5c746cba6957c1897ec1442", + "d25f2b7d0b094eea960e7b6c5277e60e", + "1ba1c6aabda2468b89e743386cfe5b51", + "7646f7866c984898b7e5924025bb032f", + "67010fac463641f7904c97a78629d697", + "97818b211e0b44c79f452333e7b79988", + "6bf69ad84c1e44b8bae38cfca8da309d", + "8e87806126c448aab98c71055a501921", + "df22b00f6ef942278aa2be7899ec07e6", + "7824b6d021264d32a5fd7894021e9461", + "219e25d6174745ae8d9c37f53aafea03", + "e2b8e628073e4416b54ba3fa91a09c1e", + "26a47b71d54a418c994ec43c0eabfa58", + "f4a521903e854546b8a694bf582dc418", + "4dce18fafd3d4ea4ad39c3a06dfe4977", + "0f3e07963aab47f9aa75a2c157acb334", + "5d23f5626f324b8bb8cd634c90a8de8d", + "5af10566d7744ebca0827e996ef1378d", + "4ffa3d242d624f0cb53782451f43b92e", + "64e34cad33634a2fb09d3bf37dae98e3", + "6419b8a1fc004446b4adf705433b7f51", + "d8f92e96cf0b4758a4c9bd5856163467", + "ecaad147e96f49f2a2158bbb3e7cb083", + "ec6cf358c4dd4cbda7be67f7846cbc9e", + "6ed5f68246594b87b33c7504939b9031", + "5b9e03a46de84bd58d3894cab9f40a78", + "e0918443eee5439d93e4e6bc67ea5509", + "8cda6e3eaa30404fa650b47f6a9bddff", + "50cf7bc1f7444c38b8a89e4c516a4fd0", + "73d21c990e634589b0c130777751be28", + "f1bab970dbb541ae87116217470c1cb3", + "520d70532512441696a02f3971f6dcf2", + "791f5ba13bfc4d659a73f076587de66f", + "2390dfb117f148d4ab971fef73a293a4", + "78ebe1fb7b354fd8a000b55775bf9570", + "a9100d0735734854bd1741233b902fa3", + "b9617543ef6041c2a557e909d2990f94", + "22ecbc49f81d4f9bada84a7638effedf", + "0f3e87f7cc8f4fd0bbe0e9a4f92a9b93", + "c887f92d3d9441b7b46f4ed25476139c", + "b08d8f5a40894169b851d269b18ebbbd", + "9ab7bd74b12d44d1928c6b0b08a92b85", + "e5083bf139484216911e99d2f3557fd5", + "24208e6a58f14bb7a890489c8484051c", + "074a4a23e33b4c71b7cd200db490f23f", + "b1dd6e4881b648039779b58a9c82d72c", + "00f665c4abc04d48bdcb430131bc5b73", + "e867291098e44a55920a1f59fc69dfd4", + "2cc5c44b4e67438cbb26de6b20e72c79", + "d56b00311db345e087f63e1f90f6dbcb", + "712a551ed8124820908029199922bd22", + "46602814e52d47eaa86f8f73d9ecdc30", + "bb2a24ab8dce4888ad34fd8ee6c8f1ea", + "eff5dfd09ae74881b03b5cb27da97e3f", + "fb0a0301abf6431485b70e497aa3f5bc", + "82e943e3cfac4da5a20d189ddbd6abdf", + "780876970a2c4106a98a838c4383a847", + "5369d70668b441eda59a5e1dba46ef1c", + "824175c1876e4db9bb7dbe666affff06", + "909a985281c648db897ad1dc1a85905b", + "7d2fe8532a1742beaa6b15d22f8de53f", + "072e3ae09bf84f2f9b8556e6e4f15e5f", + "7decd476a5f0454d8ffe9edc21f9ffe1", + "2622e68968cd443db5c082af71ddf5e8", + "d60610e421414a4882321cd9fa3c12ea", + "6ca6bbf15371417a934e464b652f8ec0", + "97d56ed21a3f4a8b824ff519196ed2a9", + "690310e9ed434c7b8520c73fb419fbf3", + "c2d86a911115433bbc40fb1d96e7c727", + "d54e1c79c9ab4e409d2107fe7eb999b9", + "720814e7f1cd40ffa5ba8f82b5357ae3", + "e561533cfea045dead0be4d3423625a8", + "4816ff67ec6b4c3497e6b28b7f04ae5f", + "f8e29184e97541a18880d2a48637070d", + "750b7ec1cf8c4eccb29a7bcdbab15b0a", + "f323dd4bb9f640a4859bd8dd31ec233c", + "cdc4064cab1947e7995598aedc17ecc8", + "f88ab02d623a4bfeb6a11ccf285f1db8", + "326423c8c2474960ba3c4bef4dc8eec4", + "53b9bc12a01c4b1688a4b560c9f5548d", + "a7f5127362284174bb723fceae47732c", + "fdf1673f1f6d41a99a90312db9bb2351", + "c9a94056e33a4fe29ead7bb2464218aa", + "81b129ecf5724f63b5b044702a3140c2", + "c347c6f0357a4deca3a47299c1d6d83c", + "d00b0f80275d433e9946d43a6ba01e4b", + "f58e43eb40f244f2b1c9b399e43a9bdb", + "a647bc9f973e46178bd672c7211b6a2e", + "51ab56d0ca164927969792937db93a2f", + "15880f6cd0f544889704fbacaea21592", + "9a33812786564517a7d644354131167c", + "5d6119734e064d78ac12419e028a6b14", + "e5263e91e4154fbd95f424b29888be78", + "be9ea98f8fba4883aa5419efbb25aa64", + "40141581e7154d65937ba4ae75284e38", + "7674fe6adda84cf08512b72fee4f0a8b", + "9f8958d54d96451d911c75f65ff072da", + "af930f73ef304cf4a4a6d09841c7eba6", + "17bdf341fcc047888935f67a05dd2fea", + "eff40b1550e0466a9c3273a519139143", + "a5b2875156214bd4b62e43db65c5bc60", + "654fa56fcd98402081e8c2dc4b473f47", + "9f25e7c83840435396225970ba47b75e", + "ca54754dc83c41539c5d543ebeb0396f", + "9840d5beac004d818b5b8b670aca4024", + "fe58e81e5fa940319e79796e23053182", + "64eb3f327d3e40b4a01df1f9538883a4", + "2823ab7ecb514c7ead868f9cba9f6ff6", + "f9a56a1bd4094bfc8b60117928d731b1", + "ba96f32c3beb41d5ba4594c69c3dfac0", + "3ddc195b71994042b32b96c23b1577d6", + "89fcd105c05849109695462b29762559", + "fcc0c0e457c74270991415750298a5a0", + "e0304800688647d488200a993f1ff930", + "e00bf205f549406b80b1254fe921dd55", + "6d676e1653454b8aa426aa28f9fea87a", + "e2d4a227deb14e0fb77d1b02d44ab4ad", + "e400c7a42e24465695a12eae5de51b2b", + "5ed35a4df6324ec38e4b8806ee14a24c", + "7ed09e4f0ef54c47b5e2ef884f24a91e", + "b7df14a7d5c549e88800ef0fd96162e7", + "6718a71416714e82a8eb6157616e8d6e", + "f69ca3ba5a8d49bd9265de758ebe676e", + "7852ac9958be44d5ae16b5d9834155dd", + "63e0b7d1cff348308cf588a9d55a304c", + "c86b8ff0eb954ed291ba3db8a922b954", + "ded421ba06fc432e88692f9078d99959", + "5b6d0f3a343d4031af3046f5ca9e0d6d", + "4b60f54b19b843b1b5c5b752e74d1069", + "3c22408ba46840d189fcfbdbdc044f72", + "cf3ed83c1b87486d90435f54c074e16e", + "b2e9d11db44e4d6a94f049d94e5b96a0", + "272cfff0dc244bfd9c4ca8658a3013fb", + "bf02e2c57f3b4beba33eca34b720f86a", + "422820f79eed4502ac419b2fe9875696", + "b0ee36a6fece46b5bd8f713fc88efaac", + "563a7fb115e9407cbca8f3a4d486cb08", + "f9e70bc184da4a6b97ca4bac4b056f5a", + "d7955e29c0184bfa87f96c2927107c86", + "65ff77a1624949789cbbcaa315021186", + "dc53315bc20f455eb6a0f1b650f8db41", + "f5a15ee9d42b4154b8e66541b9ae1a0f", + "dd1436c8136541438bcf131f0cd25d54", + "0509a0fbccae4cc59fe3643d8735846a", + "640dd3a7507a4feb9df3c3aec0b4e885", + "0750072969dc4e1fa5ff221df1b93c3b", + "faa43e3d8fc849a3bd5a81d8054d039d", + "b3501c8ab955444da12be6b49ae449ab", + "a5f3815707bf4a218680f51aa48305f6", + "43400d1c8bfc46eea64c9252275b8ea7", + "38a9cf12bb1b454cbaaf1ada13b91fbd", + "6c9dad5c781841dbae2dcbd9fc3e95fb", + "259f7cd8c86b469bbceaa81aae533aa6", + "13ab607699e240eb9a69be694b0d81cf", + "e79a07b4d48e49009d8ade1df7abc109", + "2cc3c9adcfdd498c82fff3d6623d5c32", + "a6f121b7315d487da82bd3baa46a37ac", + "1af05d5ebd334e36933f043355f54c25", + "fa291637769541dda0b940a3f826b9f1", + "dd82dcb8975543658f4ee5097637cb39", + "230264f6d9e045ca9addfa56b694e62d", + "837171e3015b43498b087f3852f9b8cc", + "115a4de0551b4caa9ff726d263dceaeb", + "8361aa8f2ac148d397dce51b921f0041", + "8c7f2110e5e240e08ace774094b0d843", + "eb77223ebfd946e69fb58ffe9ad32adf", + "4c9fb3a232f249a39c7d7cb76b64ca7f", + "7b14d44bd6b04014a8b53cb38c90b903", + "bf8cfacb09b14ab7afbd7890cf1b2d21", + "9ef4c782e9074e79b433ae55458bc2af", + "23405a46bd55450faf20617f15433da4", + "0917c63e36cc45718b80a92dd5aa7b62", + "3674e79090ed40b9b06e5b3fd56780ad", + "c8961fec0f5049fb978b39d059eaf860", + "6f5480698a7a43c7a8c0a8b1e295e4a0", + "a9e81d1bdbc14ce18e098ac3773e4111", + "aa67b378bd9c4322a0bb1f98adab8174", + "f155509637cf44ed903d8b3a671248c6", + "1ad11254efff4f59905e09f1a9e8ed41", + "59909f9f4f984a26bdd795c789bb91be", + "9bb1507c07fc432babd9254289c0d7e6", + "8bb9c087abce495ea493b63d112f86c5", + "2aa8947b216b4da294abe28ab1dfecc9", + "fdd27718d3da45abbedd15d4b2c0a262", + "605b458f5f034a2694d8c3814d075b54", + "5121b091d31f4b74a72d604bd53c5daa", + "3fb4baff1ad546d4ad76938f268ca2d7", + "680e090566ae4ae9841e6e3ae5a5cebf", + "90f97e0a658d464f87dd6a478196b26f", + "037539f91cb34368a44f70eec628db67", + "405945594fdb4494a434029e75c4d00a", + "c506ba42e60148cc9e00a07b1ac7d707", + "fdea34e69537480e969cd72bdb6b6781", + "f23f8aa6eeea4dfb96b95bb4c36717e8", + "b9dd582c978341ea865cbddc92edb5a2", + "dd034472beb1473ab94544f5acf0fd91", + "8894d5da5a494ebf9e42ee37b41e9aa7", + "7d353e95d8094f7ba3338e3c0cf76c38", + "0d44f84ec5824261837ab03694b5a8d5", + "f62d2239a9874ef9b44890231e4a8f5a", + "b737399e49184eeb9a4e954828434a34", + "4643fcab808a4860b8d54f2688bff8f3", + "5982ab03c0804662b47ccb49c4d55b5a", + "ddd34c84b93649e2b1de4b1afecb58a0", + "4dadaa5050a345d9b362367752eb7c1b", + "afb3d4c6128843f9b322de543abe48db", + "fe25295eafe54a0cbe4bad579e2f0aed", + "ff9fb3fc5bfa4fa19a4e8f07141fa4df", + "01f1cc659cb847a4a7366b84844641c2", + "d356b7e88ad046dc8bb0c0f625ce01ba", + "1e2cac5238dc4168a6a2eb333451d27d", + "c65f5d6c86874c6ea406c2fee8640a21", + "795fa0620bc44db8afcb06720a4dadd7", + "5a0c81d951f5450f94b6ac32972dd290", + "0e8155b9bf94494f9754901c53764942", + "678119818b7e4465aa21461d1c1c1c70", + "0cea33fa41eb49d3a8b00d9e4d325053", + "5340eb4804364b19b1666feef8d6d9dc", + "3a98284a462041d5b482996dfd848a2a", + "7df4b9ae20514b65b5330a68c8b459f8", + "5a8af945feaa4be396186ae61a53d334", + "f64c5eea213748458d28a927e0b1ae69", + "74bb2c7441cc4d078dcd5d82ca47da09", + "7e96dbb3daac49de93b6b0f31964eb68", + "f46f5558e77c46869342f015efed4f0a", + "cd476fedd600421791f805593d7c8d01", + "07b07f7292ed41019a8b6aebd98a5c29", + "8d86c0da0a9f4fa2b4e4b5be830b7781", + "09a4e785583044c782b43c4a18cf2008", + "e17af92232fd4c81828c56c2cc0a06cf", + "5c069acaa23647eca5b69db3417f560f", + "644836d3f8b34c5989dd6de0ea56cabe", + "fd52e107fa8647da946b990054d8283b", + "f957752d945e4493a6bd9a229353d3bf", + "7e32a74d66904627a5053b1003973639", + "43a64cd729954a5bae9a2d21e918cd93", + "600f9ba87a9f469c92e7e3b56be1869e", + "ff28ce784aa04d90bfeec0defb2bcdbb", + "bb3f11a47f8c4301a8940b4156621a50", + "3896055eea9a42e788d119e89d63a715", + "2a8254d16e1a4e329b4fac13d9ed656b", + "bb06db406f8f415ab3ac597a3a202c27", + "a8ec3aa1abaf4b84b144e64f9deed635", + "e32f65b299c14862832ef9647df51b19", + "5fe98d86b1314c249ec635cbfd055efa", + "7f2daeea9eea45f8a9ef854661e99ee4", + "2a4e890cc8e041fca0d62e26209d81c0", + "de2bcff379b14db59be4e57376b50d9c", + "e9d1dd2b28284bd88f02564b7dd2c046", + "92dcc31fb7864ca2a232990fdc36fe42", + "c4c6397c9c47404cbbf09bf5a6edda24", + "f031c8de09764978bfec1b2cc9094f1f", + "fbc6be2bcbb34d7d9d41113bb6c938ee", + "7b16af2078f54e48985fea38634a2102", + "2aa050ea66254bcb811a00f13da64cef", + "557b448ad7b44870b8a2409a7d7e768d", + "e46f3e28baf044d88cdb337a1264ad61", + "8e5f7932521b460688c93c6aac79481d", + "93974967271e4c4db08efec0023d06bc", + "dfecd6bf789e4aaaa7df7da5e5b1a19e", + "1d0066575968438cab7f9aa2ba893160", + "2e8caf8eff2647759cc246fae68fb9cb", + "52f94ba7690446ee99df878f13d5247d", + "0176be079c2449e7aaebfb652910a854", + "eb42b12a68e24365a85c8832c3709e56", + "1ecc04eb85b14f46a398316586de6308", + "a360670b31d4446cab42db6455c29611", + "eb0f2125b09042808397993c24fdf965", + "f80f09787b644975b1cfb3f52d8a1943", + "9eb9a00a95f14977bc2bb89a3690283f", + "cc16f75c4db54dfc8521735043534141", + "889ef5336d414177bbf65d896ebd4d4d", + "428e94d194004de6832257a7287e4afd", + "0de5f69c103e4d9eacf3dfd3dc14070c", + "f164d7cd880249a08367e32500f5b512", + "46a294a3d35146f79b0fa1a1761a7d2e", + "2bd3fcc82c9f43cfb0c8cf26c7d0107c", + "b8817926c0c74e43b6664a3fb0f76960", + "eabdae85cce9456e8a194e89d42d0958", + "3a0a70f412e14b0685848748e0828138", + "66830647970a47eab781c55c23746105", + "a7bb63a8c1864953a214c350b6c92f93", + "f965adcdd1b84dc6b0f144450475e17d", + "15f9b57f69d642968bebf56ef6179ca5", + "afebd0f2418a4daca865cca0e485726f", + "f9939905b39e4c0a91da9e165a191f89", + "8b389d99a7da4e3499f0f84c2123b6d0", + "fba21404c4a44db58e905e330586f043", + "bb96e13d69c640dc809ea6148bb803e2", + "a22a5ec25ed747b1a1614ef0ee59725b", + "e25fd144cdb447968f20d4f4a6166d4c", + "72f73dec9f794404b68779830b3583cc", + "ff12ae13bf3748e58f4fbd94d8f0a728", + "9c7956fe92e44f7b9c4582973203c690", + "f5307b774b1245d88845538d43ce1f9a", + "529f0f57bd48470ca9d4922551cd78b4", + "538e1ff6ba0f44fc9ff498b62d89f970", + "c7c9f3c0961e406986a0e7e3d5af3bba", + "b983f3959db641ef8b2870489de95b04", + "c42d069236174467a2fb536f7d42d7f0", + "544ed0d93221467c812c30467afd8e91", + "ddfbc802f6cd4f11a58226c37e2fd4da", + "b874f4ffbafd4152b3f28868e2fa79f4", + "b6c3662d06f94b9eacdcc311cac51587", + "3f08823a3a8d408bb98af066b938c742", + "f6a69b6ebbbc4f6baa151eef92213271", + "5df23f426fd349f8b448cc2fbd34bddf", + "6b273f972c494413a2cb1e1e8d57026a", + "3bd45e3b76324f358cef8b4ec0df47b5", + "e4bfd493951a435da340fceef6079d6c", + "4615c80caadf49a2b695ef31811a861c", + "3d9dd0b02300445fb0d85d5c2c5f369d", + "65d1720bf3ed40f085723b3d214f0f21", + "bb0ada380894441faac7c929787dbf84", + "aeccf29d3ab04639bc5e30090d43413a", + "e63063d93b894b42952277574bb7860d", + "b946f87c9b7341909f99590d2bbf92da", + "0bf7985bf5f94236b8b5c2965270e08b", + "ebd8b09732dc4a2ab7f38e615c2a1607", + "f0a9fc8b51004680904f320e7133e951", + "5f988ebf336a4e6a959fec74a188b041", + "c626625486104768a6cab5eb4ecf9cf3", + "07c3f7e48501443b9ef83adb13083532", + "4127a49df7534d74a787f35a743dc87e", + "fd72e7845cf24342ab74b1c80fecb1e1", + "2e10a793298347439452bd8d99672015", + "67d3cd1be64f4bd398073e446b2455e8", + "82105cda3eb541debec026cba74381ec", + "c7b7fa5ae4094dcc891e9266ebe486b8", + "8d829f900c61496baacb9785a787af7e", + "feadb91bad934c41ab9d0ebd6a9ee091", + "e0f835cbbd2040f2a4b9d4bf696b6bba", + "dac6cbe10dd44d2eaf8037e54e37dedf", + "b10ee58a01b649d381598d899850176c", + "8be0320aee584613af8d2b52425b25c6", + "fd206144d8b64a019de9aa0aa1203946", + "71f421347c224f19b757f507be6a016a", + "2ad4ab1992c84b2084889c82ba110905", + "a6b69fc12d8842f58df2ae0a4ef3ef54", + "b352356a4f394b25bc9c0bc37c52aee4", + "f5bb6ebd8c9d4a5780bbc43155f2396b", + "91bcf402b3a4409f8dc0a64179963a75", + "dab1778875214c4f8e4a09fc330aaed3", + "75ca8e0250024a25a14b93ac7f8e0bbf", + "a79995916d8d4a2a903640edb92433af", + "2d1835d41e7045c3b20099736e18c680", + "4533a21c002542b2ae6649d66369991e", + "902ef5795d8c45cb9fadc35788a98a81", + "fcd4bea617444c818b026bb702b311af", + "e76da4eef4e84e1c959260a384fc1c28", + "02bd26e1454448e7b58964bc2d702418", + "775ecaaf8a4f495fa8a8483865f3cea4", + "4dd64ee00ff94f7488ff7793c74a8cdf", + "6401c4ae87524c3c99f838d8ee21b093", + "1aa6739d774348efa691340e3a12b870", + "eb08662d958c48be80bb688f2100a205", + "31d3c281316b4f6bbbac480517139434", + "74723877ee174c05b8dbacf902ca6cdb", + "e3cb417fca3e458f809588b63809da29", + "9934ea7f2406447cbcc48586009b259c", + "1b1245352f35414c8af77be29e1b2135", + "22d0f22388264d2cb641cb8c20acc548", + "c2a207678875416d8eaff99fa366e452", + "1cf7a367acda4ae39291fc3e46706c53", + "433a785e17694d5bb0afdc5b666664d9", + "03dcea329c5c438aa2bd1b2986940baa", + "f46022e565ff4a75b9c7b2251308f423", + "848ad9fa849e418ba6510ef9f31070f8", + "6ae2e1e424374dd5b635d1748f7e61f9", + "b4811706b0f348ca9c722d9782a36e30", + "98c4a9e2634148aba741da07d0ac3812", + "ffaa371e3c8f4d918af69be84c39651a", + "a3dfd0b7c45345968c229b0e6f9867da", + "e36f0003b0be4209b74e093aa5514b2b", + "87fbd378fd404311962747c90b4e9237", + "dae37cc4869a4155b6999efe26df710c", + "1139ae9eaa494ae98dc39ab87b2e6eac", + "2d012e643288403baa8f1c145779ba40", + "0c8df5efed3d4bcf93ab2ca341cd34cb", + "71c931156b9e4be3b8545e9641c73888", + "e434980262d0440b939bc32a8b9affea", + "bf60a7c7c7b141ef93dcb9c56cc3de53", + "76a98aae56704c6cad909de049a827cb", + "cf82dcad77e34c49ba2910451fe96f59", + "7ac1593042e047efaba4add0c6668542", + "d796ac8f56db4dc78ed18be534939225", + "0e464ea48ce74f5bb3aa06bec605908a", + "d41bf6e274044c5b8d2646f7b489d5b7", + "ed127ed844dd4b6a8ff8b787c7028d66", + "5b64159df5624baaa369423db7235ee4", + "c5ddc586f0854a4981638287f30c651a", + "6ad4a11e5d9e4aada46e896f13145efe", + "ba6161760e6841e6aff2bfd352892262", + "f379cf2c400645b8b22f3989cc5ff6dc", + "31dececa02c340efbbe5f3cc5cecb813", + "eda924f23ba04cd5b1e5160abf2320fa", + "440cfd6ead814445baf4e3031efd7d45", + "9eedfb865cf84cd59a15e65f7f2d393b", + "ff8590a609684e3fa170ca9672e5c0d6", + "495b31d94bea4d0b811e70e5c98de56a", + "18a797777a8a4da686960575de652d8e", + "eb353582e5174076b8245ed823bef9e9", + "b193b648824040559bbb618ad5a33a51", + "f083b05bf7374b12b42f8282fb2ca556", + "95da985c92914e3c92aeb4c018892ca6", + "e1074677ee7b4bcc855f55508ef8920c", + "73b64c5ef8e0468583c84e1b9e1ae59d", + "e8819353e9684f04899f6e5c93927da0", + "3a24ff09948341ed9581b768abcd384f", + "050d92eccdaf4832a50f843dda6b7c34", + "3d0de232fe264410a4dfc77203c985b5", + "20c6eb43f5bb474289cb3aa370ce3121", + "58019f16d1784063bfb95a5bbc4575e3", + "b88c3c8225a249f289b256fcf5ba8729", + "f395579ab95e4a20a4e484d7ef3c6dd0", + "081194da071d494395827b3f9a277f8a", + "bd44c05b4353483eaf89745feb95b059", + "94545320d6964614b111322e5596e9be", + "c7c711c0f5c648009516a971ecac95a8", + "cfef1fdda6e1436590eec63eac16c422", + "dc4ecf9e517044b296e8ebb7505b42e7", + "b1227d257aef4baf9be6ca72754ab32c", + "5eac4e57097f4d49ad9803a554b309c4", + "e11f3fe101f140119e655940e4776f08", + "3671b1ae12ec454bafd62d8ece7fed95", + "dab93bda54de4470a46b07d5a520d0b3", + "3c4373bf947b4745ba4058505d2a86a5", + "6701efe87ebd436c9be16fea288ee268", + "91e9c4b64cca4063aaf58efa8f41be75", + "d9c07a512d6e4c22971367ee693dbf02", + "cab10f9eb7d6453db458046e3d1ce32b", + "c785b55867114028b592d5fbf0089d33", + "b140f762f97d43f5b48d13997e0d997b", + "4390e3589d8a42e6838c001d697c79d5", + "edc42b3b030a48eaa87e9d1b128a1e94", + "1f58e72897434513926bae262831f1da", + "1bd870512aff40efba5678a97e7b05f4", + "a3f75371603b4d29a5ab2b4e5ee25e2c", + "f31179077c7e4733a7bc5bc2b0638cd2", + "e1349e9e905a4587b816f327953debc7", + "0b98857657764b02b2ae2eddac987a11", + "e68622d45dbc49148ecf492c541b3d76", + "f3ea9a8ef79d4a5c9714399532b0f6ca", + "c54a374f085d4732a14351a5845dd80a", + "e184a48c42914fb59ca92b093380ae11", + "e912f2e3d3ee4070b1614489f40d6aa1", + "62f95f8c60f84e6babf9aabe22808307", + "dd2bb2b0034b495385367529829eb211", + "cef14ca597054ad5abcd4904541968fd", + "7f43d4bd5a6d45fe95b7f7077835f4e5", + "3a840207f026420184005478dea65f55", + "0c0fdfaaba9249e88c63c65ce950286a", + "f6b4dd71d8a241898531f1a0f70e8e65", + "f77acf98f116492a9f8bc927ba375123", + "a37b84b1c11a443cbe2713cf27f268ba", + "3b7fded75f2d411ca393e4c4150ba5ac", + "3e3cfe7a291f402899dbe46cc6ba963c", + "21fc2bf84daa45d79e483655997d58b5", + "4ad79dd647d24b9da9cb9a1232f814ff", + "77f27fc1933c4d6095eb8fb36adf70f4", + "7d4406b23e5e4525a7afe7f3b25d141f", + "4bdcdb888f324c7daef328f9c6b84de3", + "e6b4fbc8ec404d32a67cc67d574adaec", + "72a864afb37046e3b5f65387d36d5747", + "1f3b996fde954abebce4d4c4fc5a66f1", + "7413762d0651496fb5e753801f4322bf", + "cb7021f1ca3d4316b3714ca3262e6830", + "1e5bdfc4b4cc4957add70e0626254cd9", + "1ad51f6676bd436eab77a198dbe991c6", + "1a149be991c14025a6af4a11e8ed84a2", + "3039a94d5dc34429b13b67d6318f4747", + "19ad9302ef634b2d8641aa87cd035b05", + "06a5ae799acf4af1846b1d4b8cea20c8", + "4dc24ce9621c49cb8d6cc50594b5e38a", + "792e44e9d6c043629f15ff34e16dbb2e", + "b592e9af729d4ea49ef658433b7253af", + "8fa9f20549c74bc99dc209ac795d7ca1", + "abe28d3df0ba41a08375fddf471b7172", + "6ed021016ff94232a94073d5eaf1b756", + "8fbfab629a474631aba7f80d81609302", + "f298cace43054f929cdd580e2923ac27", + "480e633e5496497fae60332ea50923a7", + "2cc26e76d457469e827c5f03ca21f8a6", + "93a474cea7de4c44b3f4741e5fae4b3f", + "21ce12eaaede4527a9703d72e9bb5c06", + "e05800f3d32e46698ca99a45e797ea73", + "0eb6c94aa40c41b480cf35de229e8e88", + "a7830bb1abc348bd9390d126648377fd", + "a9d4e134a68c4dc4a2a375bd1b227f6b", + "10b7a0e221ff4a7783cf178e242a5ea2", + "df7abc62458c4752800522eebaa99bfd", + "4a480769d48841618cfb371e7dd44eb5", + "97188bc15d6741cd93fcf58aa97cb015", + "cbe93b42cf9047e5b55a2767886cef35", + "61ac73177fe34cc4973ff98830e10b21", + "8d6be6f1ef0a4f2fbfba2b77adc0b374", + "6f2e90d6157a40958a500ace8c454a76", + "940e996b136e4db0a364a88be43ef0ff", + "a4d4dc74c3d04053a4578f3b734aabaa", + "7212d41012594906a72d3b5adc260d0c", + "45fbae98d08c4c11b5f1cee392ff7d35", + "c935e4a7176042e5a5aff2a409c53b07", + "7625966239174504b1280c68a6c1a550", + "f43c23c42e9f4fb49c46a761ec9d8d77", + "6684c165507d495a805b3b62349ec712", + "ba355e12b7264777874e47c20d19d363", + "e72a40a1adde489b9e0149f94eb7d967", + "ca59b0f7ccd940939dac845de4ac486e", + "0367336574904207b7386f39f631750f", + "fa78ca4e798c43f7a7bcca2751712120", + "2adc430b322c4130bdaadc4f9c92886c", + "13ad88e449e143b69f8e6642c665602b", + "0948b5dcafdb4551a3eb20220b82bfaa", + "00d1cb5aa82745228a3b764c97f867de", + "a838f6c330594956ada7df8d75bbc297", + "ae252eac5e2e4299be268aa0b320cd8a", + "9c72d883d97848de87fdbe74fb61c2aa", + "49e07d6a217240d4a69a81e22ab0f846", + "af936b0e9b6f46c187cee334e957519a", + "17ba30c2d85d43298d85b3367748df73", + "1d98103d4d4c4972a960c642fb6a28e2", + "77c0313ad21144dcb904915d66a163b3", + "892c3c4705b54efd804377ffad907d0d", + "ae9fb0d6de684331b3ab8514a83425c6", + "016627cce41a42cfb48db34becd7cbd8", + "b89a06e6e7554c5db7ecd1c51edd3bbe", + "11bdd46c89cf49639227034f0da41a59", + "e34246f2fcdd4c81b0d982a2053b854c", + "23eea4471bfa479cbae18a5ee5c943e8", + "560b013c4aed4cc093de013c517b696d", + "d2caadf8ffb44adda573de6d905e8a90", + "8d1a02e110374e33b3b6b773b14abee4", + "114f819c01b74a6dbca9eb09dfe6046a", + "ee74fcdacb694abfb444cbcc5954526a", + "f2cfbdbf70cd4af7ab765232442ca91f", + "3935db5647c8476b9e4ca17d188bbb41", + "ac4cdb16fffa447b9fc246a9304a1543", + "523b1fa6ebee42bd847ab1a0d8f9e0bb", + "fa757fa2a72b400aa03f9cf5f9d00426", + "dfbb335a32c74d9e979a868baeda2ef4", + "4add2d48a927438390734379946ddc9f", + "2bbbfdb7e7f54b64a70c860f7356aa52", + "290b9e48cad843639bda09239193e59f", + "69d125d7523247c58fc785575341b79d", + "0ba40952f59949628ff65f19025439b4", + "60296c3a2aec4d1b8efcfdb74e8b1510", + "567bd57a32f74c008f595d2f62469bb5", + "3a39afc98c3940f1923d59130512be0c", + "818d8f4773844a40bdf43379de718f6a", + "fcab4a86262340a4ab7a3d9ea0585f85", + "10641177b18c412198371ecd25b997e2", + "f8ae73f41a6f40259d9d811f525ee745", + "3ef3afe527ba42d48f99c11531b4d0b5", + "11d0a20b961f4195a44d4b0f150da4ea", + "3407f35303ea44d8bd0b89187ec5077b", + "8fc455e0e4a24d2a950fced068eb4efe", + "bc5b61d68ae04ba59ffc2cfce32b8a32", + "b3e2849806fb45fdaa50ed1d01a34ade", + "fc7456ee37154e00ae4898e680781458", + "61a607fa847e45b8bfea58546c52971f", + "e5750324d6744be4a38ca11e8c4d9d6f", + "6ccb03f85f284aabb7d89de7eaabe76b", + "5d51a5e31ee84792a18046a2a8df8bdd", + "21b2515fe210423fb9191b4f9d7bfc95", + "dbda1db89136468595f9597480638d34", + "68ed35e49041474d80fb1b2d087b5d70", + "10511f3cb3f940b695c197dbde6efb0c", + "250a3008c8454eee8e4f8dfdcf446795", + "4fe2230f28e74b349fd8b79b52b38282", + "f04ea10301984e2eadee7c8456a54405", + "22a8386b5dbf49cf92c7300ede770aea", + "766ce7819fef4e96b74795e9b23a4453", + "02ecfd300c2745318952bec016c84946", + "928428f75c764eaa93017161aa6900f2", + "fc7dcd48bbce43c2b0b458a7beaec12d", + "5a8e355b192c4eeca377bf8bab997ddb", + "f7c4914e04404e1e85f1e5215131ad0a", + "c40cff99ab3b43a8bb1c628e6a287b43", + "f874bffa8e314743b4a7cb9ad4b9f3a8", + "fadc837c1f3946b6b87f5fdcc29c7357", + "ebfcbe8a80464f2aa65fb19c90070647", + "5645433aa729429f9b60aa33bb921bdd", + "e1d0173f94b841919b1d5fb6b0409abc", + "f01d7c975b1e4bafbff39729a9eb23c3", + "eddf3122062d4215b83cdd59fd1be4d3", + "35d9d3dceb9a4292ada2a7dfbf5dcd76", + "81669910c0b74f41a3a58febfd514794", + "43221ead48364d41977ee4e7ebbfcc04", + "7518349655634fbfbeab3a342f73dc38", + "5e384da966574a9a9a337d413dd37b9a", + "dd35db1524bb456f92f08c26145d906f", + "54bae8ffc884422498c87c511bbb89e0", + "5d3d861e381a408998276c95e655a4b4", + "2f97688375ff49179223195c2b5032ac", + "520ba807f97a48e3bebedeb7f44e9bde", + "70c5fe31e48743e5b36d739d6789ce2c", + "9562226299a045bab13c3d66f8593208", + "4b2427e240764a8b9db635d7e14ddf43", + "d3a23ab28eb0453abf56e4d61f5dcb3b", + "e7a2631478084e1485189e3b6659c132", + "408fb7a0597f47ad957db91d1821da90", + "98d4960bcf66471eb4b65b92f8137a53", + "a04dd59a7f1e4f02b5f0a02eb7e79616", + "7f7513f97c30462f9e0a511e0cd6882b", + "2087c1ce992e419f898ae1185162f5ff", + "e3c93868c50e4f189958ea5f28767307", + "11a322a4ca49429f8991d0bb8d5633f1", + "d09c31ba28994f1d953362fceb3df226", + "ea1b9673f09b4d809c90ab48b1eceb50", + "c78a944eef3d427c80d47153e6f8b220", + "b756483d57ca4b1ab0c3eb84ead1e075", + "e4785419f10045e8805c3cecae763048", + "46c8760116a342c69eddbe1c0c028b60", + "28ac5a4e0fce4d94a1a84a77139a74d5", + "e937afc06a1643f3bac57da9aec9e308", + "d9cab5cb94c24e169d59da6a92866b05", + "8aee8c79afe042018e4eda67403d12a9", + "b12a7fb702804cc19537047a033fe0d9", + "4c19ea76c6fa4dc3994a0d2564af6228", + "71a4502e9a20423ba847bf6b073a07a1", + "3df54f6f0d9a41ccbf9749ad50561d69", + "29ac53b1dc264b5bb82132f521a9f17f", + "87238b7b27a94332b0294c0f36443d53", + "aa7e5d9e2dad49ba8124faebeb8b9e4d", + "a17698c6c747416fa673c7a10e751262", + "4e8dec7f7e844a1e8661bedff3df4ee9", + "9e2db14911d7426290f6aa294d04fd45", + "5dc3b7ffa3c4479292f45cc39d667db4", + "30afb0dd7d714f6bbbcd4acc891214da", + "874609938e5f40738af0d656b8103121", + "3020862e9f884a6eabe362553a76f575", + "e6da54853e2a4141a9a82adf182e60bc", + "445b80747ea147eb92545bc881f2c0b7", + "e378199a307c4276898176f45156ab65", + "e7925af708214cacbc776142e31e274d", + "af15ea524fb7465c9190b63b71e91270", + "ea1ceda39b4d44c58b01745a105117eb", + "a002bdb64e9a40719857c653d1fcb2ad", + "ad389b31a38847f7b786a5079d97782e", + "e44a3523ad3d4db487c276d09dd40fdf", + "f60ff48866a94050a42be8aeaf376817", + "a9824884957045829211090035900302", + "49d97ca2fbf34f85b6c88ae8ebc7514f", + "7fd8ec4bf7284833946c9c23b91616dc", + "e359db2718214aa58808e1fd88a26cca", + "459db9c0633244fabccad44ca329d5a1", + "75e6a95b0dcb455f8fa82dc6d940add3", + "6b25b919a2aa42fe88f7a78f575c3a73", + "0dde70fe25954b3995711b23fcfd28ec", + "d3bd63036ab4405695f29625f8d9fcd6", + "cb5c705cc4bd4264a3bcdaa6355f643b", + "ba4994111ff24568861c60e41dac8815", + "92d0c5bbadec4a6e8fc9ddde72c18d4c", + "fb4202d9afc847eba660d1607a57f64b", + "c797974d7e73445cb22698260e3c78ef", + "1dc0fe17c77e40a9ac5a0c52462ecee5", + "177bdca95ba742548e5291eedfcfceaf", + "0c4754201b074ba980032e26bc9c7598", + "d5b69e67091d42dbb09686a33c387f3f", + "ecd70bf53b29493a84e21037e1c3aede", + "d04d8ac2c1ba47ee9e03351b4f08dd4b", + "03fc72349f38421eae0c55a92560e95b", + "9be0b12c582c4b578ecf889bf4b3ce3d", + "6bc9fd040c3c46168c1a2b80e2fc4b9e", + "e651e3ab11434ad48788065a4924905a", + "cd284a25f8114485a17d7b75d47235cc", + "5566ea4f906347e7afcc864ab241628a", + "e624f969b87f496db6fe555ddbaf1691", + "68dc58d3c198413489db07e9c2b9ef62", + "ebcd206c9c4c45979cd92e1af1a634b4", + "0a34dc814a3a44cfa76388e732c05376", + "20f5a6ebac4a4173a63cb315b280b284", + "9e10ae30b11b474a9c759d6a28cfd23d", + "ad622111edc448d1a349ca66f641e73b", + "890b608a1d2b4b55a65a2d56352bfb8c", + "15c719f4c2ca4d5e90ef076057794c8b", + "ec059ea5256148bd851cbbe100a0a969", + "16df9e0284124e109f79879294f538c1", + "b43ef95cd56343d8bcc1a62f728d5e5b", + "e147326b60954b94a72138443c16017a", + "aa0c76cb8ecd40c5a61846b83df143d0", + "012c9344518345a9abbdba622e393d0a", + "e627991380c6410f827ac7fdc8610346", + "fd4cf2c471834295bc1430cfd6e429b6", + "c99de34b3c9742ba8c42e4d2328a4760", + "a054e2da94ad4c5783a8e04c866e6c1f", + "bd80cf84a16e4f9c9eee13d373d29d8d", + "1e0630e55c4b4e37a0667e7f1fcc9eb8", + "1018cd118d4f476bb8051a121485d27b", + "f2bebd100dc94f9c8745a47dcf004661", + "fdf8f4480d874f4c8cc2841727051da2", + "09247d35f0e244c29c6b7f7c36a12d45", + "5f4141521fec465e9c48d9b20aeacfa2", + "66a185f373c944a68dc09ee3ff19ab0f", + "e37ba665f10e4c42ac07b682f1a21436", + "f307a980d98247b98fac39679fb47e0c", + "a24b02d3e75643eeb7625dec88616a30", + "cedbb1d9c25c491e948757c0a906c249", + "aed75e9dbf1346da9358bcf3ed0b5fb4", + "9b3d9ef33d82404e974962515048ab2f", + "e0368cec6d0c4d91b48960528f760b9f", + "2f2bfd7940c9467c90362ad2b3e80cf5", + "3bb60da9708e42dda0276d8c7c45c4c6", + "97611a53e3b846f69e0655b210f72b2f", + "f2a527a044d24072804f3661081e08e8", + "f317b73f79bb47e1b271e734ee9ea0a9", + "fa8a27c91dc04e19983e21d4954eb93e", + "59d7e2b28b8b45ec8b179fff0134ceec", + "cc6ce525111e490e93a2c32dd8f57c38", + "0c30a9f6b2f740b282b6a305accca96f", + "1aa94c9127004536a5f2b14f9743675b", + "f5847f80ad0f4a4da4684eb10bad6633", + "ef4d26f737fd4ce88e39387e419de1b3", + "b9dc4b7181a14f5eb3ab618b4db129c5", + "2b943071f899407ca403a3c65f016319", + "14df83a24d554b5f8c929903f2734e33", + "55c4cb3cb6384759808460587a731185", + "4079682cf06547c6bee73802820fa109", + "3894f67369b4464da4d4e95c8057db57", + "9a87c4971eed4fd5aa6e1e3441cd1e70", + "6b247c088f034d09908d4ee78c39dd18", + "7e87642c9805464aacdd8c5bfe36a323", + "625b0a764d0f40d48f3140acdd644823", + "b3f962419f5e414d9289f578307a7974", + "f5f0fec1b50b4f7290e9da7a004b4ab5", + "495f7b4204584b3199e8ecbc59d7e598", + "248f19938ab04761a15e35d9e24161ca", + "4200a0f4dba3414b89053633bed7a695", + "1e1c77e3898f43b780fa240175b7183f", + "e37fd979827a407a8e9b25c10e17991a", + "b36e0027d4a94eacbd3e47941f8bf388", + "5800b532c1fe444f92f9d53172b72c28", + "785a64d91a1d4923840df57ca1153920", + "e20daea8ee954218802c677a3a7d82e2", + "56e3d41fcab24b6699abf536419b7c47", + "59776b2fef0d4782a4dcf7096fbcf205", + "566cba1db66747bdb1ed46057b88b3fe", + "e947a018194745598df88444bf43de11", + "2c4611686c75483b995526c583481030", + "c4c9b498476542f9ae03fc24d2be2c98", + "29d864449f8040cb9fcac874da48da0e", + "c0ea5b0b7421464c9eb0f62577ef8eb2", + "8fd630ce74c54fe986a792c3ebb5d57b", + "b0bd00b700a3451da1cb4ad9b082c3e0", + "45c730d0e45d4fec98626d66a004bdfb", + "7c7a9affeebe43e0b6f32729c3c8d0d9", + "296da41f47534f98ae2d3b958d4c4f98", + "80e8478cc29b4aad91176e584ca67e1d", + "84c96689f7aa46a98378416ad7080219", + "ec0ee0b69b6a4400a59a7b1bd99c80c5", + "95c53161769f4c259afbb41bfc94f5f3", + "756e40dbb2494b6b8cfdecbad8832f83", + "3a6780be3d2c4a50bc19949e2156558a", + "f6037ddde37646af93249b1d4b863f1c", + "bc001ab61e0145a2b74fc93181171f0c", + "c8fa424e650c4125b9a080f633a21721", + "63f071b5c74341fcb4106c8975725f12", + "1be1cb560a934bd5a4ef6051b90197dd", + "0273352444e14e8ab4f484679ff21ebe", + "fca5e4efc95846718eae77dd1df32c12", + "fc655111af5b49bf84722affc3ddba00", + "eb8cba7322ee4827b92c539883638474", + "abdbeeb5609c48f9a801107c3cf01174", + "f1aec7284c034d7987681873bffa4f5d", + "a6615ac74bba49d4bb77092de480ba3b", + "a0b900d9de78485bad2534a88e2c19c4", + "fd8c3845db504a03bac25b946afdf9eb", + "0712c3b3f6484f1f86cb59ca6bd8f0bf", + "e13434a196e842b3980aef22835e4ecb", + "6465b89b6ad4499993c90a39d7c512cd", + "310addd9d480470484bad732b7a44bf2", + "7a1fc54af5804aee80e346b3f50a3fca", + "e767a862d98f43788c8b2e4da3f38a3d", + "aca2da24dcfc4a0b9091151745e5124e", + "1aa88f57eb3e4e36ab1c512ad637a366", + "1769a36326a04913a2b8bb0ca47e9e91", + "f673865741ff4a878204ed6bf28ea47d", + "ffc51622ec034f1db7c9d0b9a1e1948e", + "1fd66adf2bba4caaa2aac9e54c424b5f", + "9335eebb9e3f4cdebe30fbe0782ad8ad", + "f960f2a43b3d4539a2f797a560b2fd82", + "56f5e7a6e4fc43759cac4ee99246a98b", + "d08bf7f2725a4b938d6093344e841c60", + "b55517c209d74762b371bc6ce0d1e56f", + "cf3b18862d1849168c31f7fd6964c925", + "f07a603c3542407a926336fa5308b471", + "bd063fe114ff4208897d69fa1818a7e3", + "15d00d76890d458ea454d34ce08cbda5", + "84c4f27b8eb84938bfc2cf36944baf3d", + "c54a7f8f0d2048e7b3f897ec497c74a6", + "3a9a95549e8041fea11d9eff5a09c568", + "eb37bf62437c48f291831d9213ed0df6", + "4ceb76440e1e4825a10ff9ace48adf26", + "fd8e300fe0094f8283e0269686daa8af", + "d9ecc99108a643ab887296cb986be937", + "65bb2a14797947849da7160651d814f6", + "f31b9e74b6c34285af8a1f5ede6da95e", + "8dbe9bf2af2342e5942be8770f7925a5", + "4487ad10f7464a6c9bfb0aac6217a989", + "f1f9ffc006ce4b9c8661ef9a36951f83", + "84603358f4bd4851bb11fea66cd50cfc", + "a0bf7bcc50f04a109d5212a6da0c3f4a", + "65d9df0e7e904cee890892f6128f3de9", + "a4c9a503f63e440e8d6d924d4e5c36b1", + "0bb7db373532482d8520e8ac109394ab", + "8fd4c03663424c6594110639bc15c5e8", + "512e5e98e7b74de5bf6e23c3615c87a7", + "c8bd51746dba48c1b6dc014a50a84aa3", + "fa2fbbe8e8324919b7e8a532fab33724", + "61d188cefc7a46f6bfb58a8eadaadb16", + "4b8d86761f9440cfb324d0b4d07336ff", + "8e482e714930455691995d417c688791", + "b2fe4a77844e4cb3bbe3555d9cb53d98", + "b0758b57a3624166b08198537561b947", + "004746f9a00342298c89eab88c5203c5", + "8da66aeff1f345dd94d4b8355412bfc5", + "2b116c282f054383917cceeac221993e", + "dd8f4c5a104f463992b9d1d1bcd0c0bd", + "75e9b25b1d1d4c0dab8b4dce94dbd5bd", + "33d98be6ffc84acb8aca4d15fb6c1755", + "2eba66dcf9eb42a98f192230620ab52a", + "4fefc6a5fad443b88c795a0d8bdc440e", + "b02fe3f92dac468c9f2be8a88adf71db", + "95f1afb745b948fd9bac0908b6546d0c", + "6830e31c6bdb4829ad39c01facdd9859", + "29bf32135c594bf5958997d55c5c9ed1", + "91dbbad6be8a4c0ca0debf209df0d8b0", + "16f83d9187ed4ad2b15a15eea3ada950", + "4dbd31f8ccad4e6f8a9a4255d76448a7", + "f7eafeccb45948ac89f314f324e8c3eb", + "f7d2757432f94a2bb366c9a41503647b", + "981fc5be149c4c9eaaafc4abd83eea03", + "26d3deae44af450a8c978031a36b2b95", + "af7881199a5c43a499e668399aaa4a52", + "f04ab1e3e07f42c799c9415a4767fec9", + "b72c2a1e909a43a193a74827b214e718", + "77552fc8fc4848fa809dd307ee6f5ffd", + "f446f48653b8462fa54bc3371e7a15eb", + "852927bae6724ff9a9df05ff36de2dd9", + "812a73dff6d04f24a396f9c8e131f8e9", + "894c7d8eaf3f4591ac4d4efaa2b71983", + "9bb1437af6584898bcfeda74e93242a8", + "21b3bf90e25d4f07af3bea232fbc239e", + "1ec8b9126eed4323aec245a3406974a7", + "591f7d9f6337460ab1d93ef6c95e70e5", + "b1eef8d330434ab6aec83cc171084d89", + "e44aadf5ba8341aa81e5f807a375942d", + "23e04c6da9b343669cadd3553594cbb5", + "91cc585647b7453a81e302991017a95b", + "68c578fcc46c4dcfbd8658823a36eef0", + "7ac65580fd7f4869990e00a6957d1c59", + "65084cd519324260acccc6256c4d23aa", + "3abcaff1a11f4d03842f9c8d73bb0121", + "297cc08b20b54c18b3d330d2b569b0d8", + "530222b7fcf348fb93d895aed319c5bf", + "4204ebc430364660a336a3ba20d327af", + "0018d378a2cd4ad58fa8fcae42e8af9e", + "d4f9862c66144f16abb8ceb35bc8e7a6", + "4c5ff184b00d491eb569195c2ae17468", + "d942473ab5bc490caee4106c9b9fa5cb", + "b0bba8e98d31421a86f82875d15e097e", + "c5b130f54fae4ec7bfd4422b744b379e", + "71eec398f7564977a865dad19cd4fad6", + "c2c239b547824d6f9e4c2d38fa11bbda", + "9f1c8da02e6f4806a4e2ce7ff5becc3b", + "7b67b44cdaa6456aad0433ee2b4591f3", + "dfda6e71d079425ea07a55ea47b94da2", + "89f8295add4d459c86fb714d30341875", + "ec99489ed31b435e9533859b9dec49ab", + "298090ba739e4f5f82ba70d0262283d4", + "82fa6ca1a23e41c4afdb93382ee5644e", + "a3fa2e70a3ba45f98e81f118c7898016", + "03765a7e66374ec7b3fa18749795189a", + "5e4e99fcc9974549b14ab4ba538d1cce", + "deba2b49e2e14416831f0deb78117745", + "f0ee4c984a6942e5b8bb6c6fe7a0bfaa", + "fa4a4b55227e43b9b552ba6a0ddbaa23", + "2aaf15a6bd6142aeadd3897bc30e39b4", + "e6a7b8adca3445f2901c634952ac2b3e", + "b7c97df584824ca682d26daabf401f87", + "693d13d8128447b09fe15f624df1a91e", + "d81c7b2fd33f4b81892062d93df57b7b", + "0c7f53e9f79d4a8e821b83705e9546de", + "8de045536c7a4881ae01aa460a2d453d", + "0bf3ecacd69740e197803bd53302d1d5", + "ea9f86bb18984cf98dcd1b595d23d573", + "77d41aba53e4455f9f84fa04b175dff4", + "627ebce56f204ae4a4dafdbdc993513a", + "c1cc5a4cbdb2469c9781b395498d64b8", + "7981e8bb46a841389563e257f1234d7f", + "f3dc37ced5d548ef98c7ee8bd2ad5491", + "dd6a424807614544835c8cc4529d6f0d", + "97af0dda95fb4025905e9b134c3b1627", + "026cf4d0752e4a16b9445fa6793c1141", + "ff2242369e8640f48d65df83066845c7", + "daba6e30f78d4604b5167b2f83b0d162", + "047be21efa814473a477aeac79bbb6cd", + "3da94ad0a6f34bf684a1490634f1f9a2", + "cdb393030ef34e93a2159113a72477fd", + "9eefcf9a6fed458990b59f63a2870d9e", + "c5cc01a4d8f64817ad5f558ac3cd7636", + "d3bbd54ef1d042799c042a1a50636ca0", + "14b2db3cae484e0eb05cfd1fc0bd121e", + "f6050a143fe94555b23b5f2b673616c7", + "6024de0573a147ebb27395d5696fd0ad", + "2b1bd77415b64570a4f5f4554414be5d", + "8430a420a4754c2db233715a638476fb", + "cbfa6285b2ae4caaab5e7c2becf0ff59", + "4228b3aa43444875bcd1051276e67456", + "c54fd173322e4e8286e170cf85697ddb", + "a00f60192d1740f49902009c3d0aac05", + "34278684a4404c938b9dd91da0d4927d", + "e36fce74c5d242068cbdc47b0fe69b10", + "6e6df6348f8f4d0a8bfc2c6682655e93", + "5b4f3897ba78417d97a3c7f786a0bf71", + "1df839fda36e4adc99e0b22484aeacce", + "d017216e3f48449c87980ee2a888edae", + "550d5a0368114f2aa62285207ab1adc3", + "4d6f0a6aab8e45f4af131ac517c74363", + "3cb0c95b955747aea22476264eecf390", + "f10a7e5b1cf242bcac3633c324d023f5", + "3e624e2fb26e4bc48f9532f6f2b2a73b", + "67f88fd95e344a87bb9be157a4f73f9a", + "a16b74fa75084aaf9736f60bcf23992a", + "fddd97e7388f453c87400408c2012918", + "f15cb01acd4941969bfba8357292f96d", + "db2433b325824ff299351fbd057c0153", + "61cfc277da3941c8b19666345d622ae4", + "a38b6658117e4135ab0374cca4d745b9", + "348f4f73dc374df893c01c4942d89e32", + "3585ddc206b24c9fb2298eecc2573974", + "0ec178daec3b40de9d993b6a3b68411f", + "b0c5bacc3b1a4fe9b7f05039062e54dd", + "4b59720c67c74be7a95e59d9f52df88b", + "8831948aaa4449e5b164c62b10e4be6d", + "d01171ae9b9247548b592396a75ce1f5", + "76c7f49863384f47a6856a768c2d8d5e", + "8632380517a043ccbd364e1418cfed74", + "018dab01b31949318128504332f649d9", + "2826823d900347bd97b17708ee04c3ff", + "0badd2265db2428cad5033aacf3f7d2a", + "57c6a33fe3a949d3923e406465b3c91a", + "62c642a71dc54d36a6009c9119ac5b36", + "3522034382104c3aa7b1929852277e0a", + "6db831285d1d447997b9b9bc06a0f503", + "b741649233404cecb47cdba3811b86ec", + "d6af989868a84939a4f12db2e8334523", + "d3091630338141f3825a6fdc6adbfa75", + "f4a50b61cf154b01a184c117a27ec348", + "6acd6e2c9d9c497caea531cad01bb07e", + "f1f1d3b1d5df42138695fb503facd5e1", + "bd4f92758cfa4cec9031d262c0aa4b0e", + "e11ba068feb04c31b6b67d925f0f463a", + "44c454137a274c54934e45d7768d08ab", + "e6823583dbca4d219ac303e96cd797fa", + "dde4f952f90a44c49db8b10d47952de3", + "b135100c5d514f85841b93a3763c05b2", + "649f10d75f86431ea0930ba454d11c31", + "1da241d0c62c4e318baaf078cd0e3b89", + "9d21863b3a3f4397b86e2d735b95c061", + "4d56b3474e6442709bde68874b6e6fdd", + "372ddca13cf34765bdcd3af35fe77175", + "86b1bc0763a747d181489a7c1e7bd89b", + "ac2b50d2542c4f458b4ea404b8ed5e4b", + "c72f7a87d7c34b49ac73ccf235190ffb", + "543c9a06fc8f47648f440b2c36b354d0", + "5222cf9dedae4a31882281f6d7bada89", + "4f8beaf35a13474f9c655e169a439b5b", + "26a1c48f1a8d4e9bbd24bb0acfe2f433", + "72f1a54112144d0b9841da74ce30f6a4", + "f2537f2750a5416b9e7b9121878e245d", + "d03766ba61f2468aa95709ce84b5a4e4", + "83503c160ac3401bb2e59488c0155369", + "9cbf22efc459491db7aa295e8638b967", + "93ce115ac08d4365bc9a8d9e386bd166", + "153333cb5334423185c59d0abef9090e", + "4c4690ba918f477b829990dd2e960c21", + "2edeff57548c40978c3bf66b146ecc18", + "0f45a8874b234efcb59e3a3268f750b5", + "fa9c3aa591ca4724a3ab414d20f7ebcd", + "6a41bb71e72c4f3ab070e0a5a237ae53", + "8b034a6e20e6464286a532d2ba08ee84", + "dce8bc6f73b745e7827209527c52fa51", + "d75b364f42db47789f0e89047ea5651d", + "d300f72448f14589be070c955c7781d7", + "919dc2f2784b472a904117326f6dcf52", + "abb5588835f4455faa169b5d98c9c117", + "3c53be0431e2486da35f35b990c0f67c", + "4d0a4c8cafda4af9b4e617cac229e86d", + "2ad86321197a49feb54b7726743d7fd0", + "03f2af58cebf4256925ba3179d32045e", + "d9d84b1f6bed433eb69b6ab6d16c3bc5", + "623771273fd44848bd3e4e55dc358190", + "d6336cbaa64f4a75aa5b51b97a9aae98", + "14cbf975ccfd46338d39cff250d91c8b", + "53912ca094fe4de3b8468d133cc99f8c", + "24b4d9ed93e04d3d8ee83401196df405", + "1fca6fce3aba423b96aa2e00f004e9f2", + "0334d2d16bdb4310b84a973b9a696b13", + "f1d44a8c315041b3bfc42db81681c2c8", + "4fd49ea011a145c8909bb5e9a0cd2908", + "f07a458377b144f6bbf522ff5edcf23a", + "d5016aaacbc141a8ac4211e37e08e461", + "bb0076cb0f884c19ab0627411fb73e19", + "3396d1dad4b74d1d99a0b64391818b4a", + "85acf3d110314662b2f502d868913538", + "b10c785c094b44eb839994b8c018d536", + "0fd82365601c4370a25676679cb7530b", + "8f9c418c63364f8e93bc545288dada39", + "7999db7760614b7f81f3a8761e2992f7", + "255e172b92f145d2a43da188fe3ac8ec", + "3d1956be9e724235817f03a1d570f408", + "cd19839669604911997f34496da96bfe", + "222e96a82d3a45009ddea01488ef6ae1", + "0a122f8d1a954276bda739ea64b1d9c3", + "21bb3c10fec94d1083bcbbdaa704747f", + "d290abd04b8445099b4c603aa4c6fd10", + "784ba6ee58f043aa955826776b95884d", + "d7c705d3773d4642bee7bfea7820dc87", + "ae909c439e2c42d9a8cce8196513ec9d", + "47c6bfb547c0468dbaef0cca60d3fca2", + "13fa659acc61471e8fa4f57637351c6c", + "77e34b5b67b64963a67f0d8d5e4eacae", + "67c218710257493aa2e7f2e9d4e1e702", + "0013bdaec08345ec9fd03214030baeb2", + "3fed29b606d74bb2828dca8d30f1b9a1", + "fe1388bf67c94f1a91ce094b8a5cfc83", + "d10ab05314a043ff81602b59e0d479a2", + "3aa68d6110d5470588c7c1435a0d4d7c", + "f864488cb5d5482fb866844309f8195b", + "976b4218d01843e1bc0ac484712d63ad", + "3953c3f4bcce4e179b42e2b203788b74", + "74253d45fe014ec4861c9b5e1beec99c", + "e3f11957966b4a03a2aa5c8152c7f443", + "51616225679147ff8fc1702e3687dc20", + "a977729fff9d4bfdad487a59495436f5", + "0e8acc8ad98f4d1794985e4579ce18eb", + "ad3b24b0d191461dbc850059987c8262", + "6b7961249e1843639da30e88b7a6bc28", + "2e2c556c4ca840a994a21a33c9fcd47c", + "a1e98e91ea6549d9b07f4f0c69a179ef", + "6b8bad65c4a946e0898ec81af98f836d", + "baac63f9e9804eb89a34a29d9458f52e", + "c4a0da1c328e42f688ef54daaba9cc6d", + "c3411b51ee934f80a3cad23d808b4435", + "bd5b64b58f1c495192ff6f8bef2971d9", + "6f7c7477e7ba4096904b7fdba5aa575f", + "81e80a4e741f4995a4cb0f6d04f3e7ec", + "e40ea1a71c9048d1a2f8db02de6d4ae5", + "5e0710bda5984399a56aedcc7ab0174d", + "d40aa57bd3134878b573ba48cfa37f2f", + "8879720e7e2d475b818395f49f299845", + "b2fc4bd184944704ad43d3a31817a676", + "f5510c91f0ec4df5b2e5ac1a0422c68f", + "59b09646badc406b9eb64125f21da35b", + "c7dfb82541f648acae740c019d04a408", + "f34d2fd6d2964251aad9c0993b369ff5", + "ca36f4ec23a041a096037366cef5f274", + "a4b3213dc9034cefa99e35f19272f382", + "9bcb5cc753e4486ab98440c1a100e8ff", + "74c3f4864b1e482c8e5dc9529cb8cd57", + "745a7b4d7087433fa305754062996b75", + "f89c972e822f4cdcab48e8008bdb6f17", + "1a119b44eb854886a8b8bd5265d1b0cf", + "58351abc254d406583b120d2b2eeae37", + "b75046a6baf945a195fea09f189b4a8c", + "c77e4e900d8a4a488eba963a5d3741f1", + "547816dd7c1c46078309b01b9576f978", + "1f41a813c65441b5ac500a4408ad2dd8", + "a0a80e5afb33458fbc0aa0ca6d0636b1", + "c0e15706b69842fe8b192138bb0f0025", + "732c23ce6f074e4e9eac662d523fc42f", + "827df69d85de408c9435f26af7ded672", + "17353b094e7c4072b6f6544294cd194d", + "671bd73be07843079eac01f73f9420a6", + "50c9a0c6d1a648a6896d3efdf07f0c4a", + "4fe570cea42240c89d85b3b86b2a048f", + "332a2be4bb204a9f8e5278949ab1cbcf", + "e81c8b8a78804af88c5119946c7cda60", + "e00e77b6e88d48ebb01505d24acab9e7", + "1e387afc6d7443878c310756400dd467", + "efdbc2fa6f6548aeaeaac7826f211e50", + "dc639230642845bf8274b836cdecef93", + "43de4d030ae94667bd8b8a478dd371ac", + "e38d5972b3ec46a9ae0468435b5a9f14", + "a0299c58b4a34a88bba05b3489c28917", + "e6b8448619ab4c2c9b1313a0457ab68f", + "8fdca192becb47cbbf57386036327bad", + "469b34e0f2114280b2a58e399585dd50", + "f4160b557ee34182a33af737d2f9d397", + "5b7c03fa21c74489a84c9d2d65a9d5e8", + "efb7ca4fe4ac4459951a8be9a4cf6b21", + "f0dc46563ca947cabe47f6d2ef6e8bdb", + "e153f445e2b24646b2e2d71832758ae5", + "0516d855f83e4337a5d5f526e19b94e6", + "3cbbe9177ae24f1a8ca953ca7eb8bb86", + "a0e4a674f08a4faeb78e14cc36549c4a", + "13c99a031fd84cf7aa756006e7e18a3b", + "973b13ce7ac24e749571c3af3327bbae", + "ba597d172bc54cf7b2157883879c749c", + "e32e0db5baca414baa50b7b4ca5f0999", + "be5cb11a9d55445e9eb5f33151ac57ab", + "9ce4577b75d44bb983ee75d07f25cd16", + "c73f48027ae54a78885469c38e170fa2", + "6aaa37a04732404cbef22d8965ef9b4a", + "6b9751c018b645428ec65af737a4b57b", + "e2b2c437da8b40dfb32881352144bcc8", + "9811f127a39b480790d1beaef7af9fa7", + "b2a8b38e26bd4040802f4172a5cf6781", + "36e3ea657d3642adb7c1a05ecf6d4d62", + "3326222ad30846438660f7aefee9cffb", + "03f4c08b0b2040339a8423aa77ad1cfa", + "e7aae3c8264143958016d1a88d5af668", + "f598dfee0d22404983dc9d9c3f307202", + "a4d90a06d2984b57952cc0fab6d78c9b", + "3445c3528fb041aa9bb415ba1ac7ee15", + "b24f1980dea749f59eb8ace6946393ad", + "f1f57078e79e49289e14f0a551b5b60e", + "966a2965978c423eafc4b6efdee8fa0e", + "660641108abb49e3af3ef4addadfbbf9", + "e5d4d39aeff94542951815e7556546a4", + "512158da5f394bc79a844acf8fa972ab", + "9c6f21280bb84ca7897eeaa9974cdc3a", + "e9750e88f79f4e8da9497e6cb3dc053c", + "3eea6c64f2bd4376b5737bb09a3ac852", + "d8ee907bc99045d09772162cfbb263f7", + "ddfe9c089d6d425f8a83959443bbe062", + "e28162d6ccf44da089b9397612fe1066", + "2b814e91374444c5bcc2dd4bc002ec69", + "f7bdc4a7e80f44779c1893edae6a47a0", + "5b8c729912bc4643a8c8c8c4aa5fb8ea", + "e102e46a26154f5f9e77bfc07ce02f12", + "d44124e0b2b9435cada8949d4f445b3a", + "fc0b7c47dbdc4641abb4c2f5a399d793", + "45ace760c9694388af5c1f211b64ee78", + "5ed5fc8dac5e43639d881a21065bbe7b", + "ebdfe855299343beae2e5129c8788c8e", + "a7d105477772404daf5bad8011b6f1a8", + "9f960d99358a4b249cc8a6adf86e2ef2", + "20c65e01d9ee4e06a438d9523160d883", + "104bead7c04345bc93019490d075ea6f", + "919a347dfcff40fdbe0eaf29b3210f1b", + "440a31aacb614048a98646609a73b914", + "a5a169466fe64f6f97ac58dcadfd8622", + "c877e570455a43769758d151610534ff", + "0a3fa07a6c244500941b2a747d290046", + "b1191827a2ce4341869cc8d8a476bbcf", + "edda532c28154e169b1e51e1dbe16689", + "cbb8140178e54758a8cfeb9a90a7e0ec", + "8dd8f987f9d64dc3a6f17d9e880d0563", + "b5ad68523dc04634985267d2ed56e110", + "128f0e75afe94c6ea0ee564db07cb8f9", + "655a82c8d2a34e189e1a4418696c314f", + "aaa202435fa1456fa3dc18739f5bcf1c", + "e1b84e5b2f774b94a96ef8e5d8f39b4c", + "b4ab34f9e2104d12b56cb25c76a25900", + "63f37d0c4c7344b192cfac9284d9d178", + "ff9717e45a014315bebd5f88c3dbf70d", + "dcb8de6bf1e547d79528cfdfda7d0c89", + "bbc9f882493743ce926a293945aadc07", + "4944b4320392432a87fee3a1269c74a6", + "09a9fc4a0061464fba1bc3ba76848869", + "11c77194484147e9ac5442f4a7ecd59a", + "49fb5b927e35410db13acd490caf7649", + "4fab339a56104e21b684693889d4586d", + "9c4248c152024c1f8dcf8c8e802281ce", + "7835452d6d4f42a998b11bcadbed6c23", + "e3d89b92dbe14b788beed9e08f879940", + "6d8c8c2a8c244a9bbc0651b884afad73", + "e9f58587f4f241ccb8245e28fa10f717", + "3892a25754c7452eabe772ff691e4c6f", + "4dbf1a7a1a7a410c999bb39d3682e5e5", + "1b6dc44192cd46a8877a188886734f04", + "6234a9feebd94f48a8c907d92d9eb358", + "e243fab1a47d4427bff9de3ef44b1a15", + "98b1da4020c54f91ade327a9de2a3cd1", + "61a2c3ae82dc42f69bcd68adc6fc1a66", + "06d1b23952b142daba118ed121835a73", + "bf6da7cb248d44eab09f79685fc204e4", + "6ea3a5efa51e4b8ab72470c6ee475945", + "21b36ef4ac1140899763f6a0581a01eb", + "b69e3a5e989145eaa284a33612139496", + "1ce07fffeaf74071a5097e6a075d9e0f", + "e5fe8edb1e674e16acdf47da7c792e86", + "41de702c637a4c9886ba8d31c5e492c1", + "61f557ba982748368925e02c04ad80e6", + "b1aa9affc15f4fe8868f5120e16ed6c3", + "c638f55aad814156a9a9561980a78eac", + "cd78f5b2a2654ddeab14d92fec858907", + "09488b18d45a4eddb2d58b5cded077c8", + "0830e548a03446eeb2ff24ab82f5604b", + "2b0d1feb52474d808ae6999c81d42e89", + "560184ebf3f3449fb195f1fd829d25f5", + "f40f30aed6d84e69b61ee8981c599ca2", + "ed268f2127854b40afa82a454b7a6d22", + "45679d2bb86c48aaa798cbb1fda7e4af", + "b55969446ff749938e9e6c7598dc5f36", + "dfa1f70efff346cea2645dec57c64d45", + "d87cc4da7f0547f6bd3034d3015550e8", + "07d500944f68482cafcf7a1d67ae515c", + "5fab390cf6a04acbb6483ef96df7ba27", + "0497f5b8eabd4bac95a7336db3fe9f86", + "0ec4b1a8c71a4700a2005842e3326af4", + "65ac23e97fd141569be711fd875dc162", + "50bc0faba74d45519f63caf76ee9b4f0", + "09fd6b85dfc84ccfac7b6d3ef378fea2", + "c352ba6bf37f4af1a9d903ce1168f3d4", + "c8831bb2ad194e7381e419dbdb07c53e", + "e0719f5bb82f4f4eab539f64161ce0e2", + "907608f7e9ce4b3d8d3f2802ce336a9a", + "0c489a30b5474ae39b684e37b0c3ed4d", + "0048e8224b174b759771e39ff521ee2e", + "bc2044d6cfdb44d8aa6a6962b3a41a2a", + "f376bd06d35a43e9b09c61e3a1c39d8c", + "e3de2a327c0d43ccbaaef3c7277f7f51", + "ebdf3dc34c814e15b28abe626efa08c9", + "864872b1417d45d7a472aa9cec8eda0e", + "c0997ff7ad7a4f78b57258e502a42c92", + "66eb8c2178d24c91a792e487b241c0a2", + "a0d07123cd804c32b2b6299764ccf007", + "d875ffae3c6045bcbd8ab03bde23f666", + "2b38725953174b31abe1d1fd95f6dc9c", + "49152c6f61fd40ab9fd4cb370799a62d", + "eb3f46616dd4405e812c1de38a1aabf9", + "8c5a7920831e4242aca0f96e80b99492", + "5555de9eedb045ecb30f9039a7b17711", + "cdf79890c81a42e896efadcc5d2b96c3", + "01e5cf82289e43758867faf1f56e8162", + "eeaf49493e614f3682d5f694b7ea1470", + "c1db1b10f9b14717ba731d7f49d25443", + "2c3525fc4e194f2e8911fdec4691506c", + "5577e0c007b34ce88d04e2fdab684524", + "2fe3e52d805b4ad29bafad439471b6ae", + "2a0556940780487b86798cfbce4e1dd8", + "b87137a7189a46679de99a0b09fc9e7e", + "d01a6b0749534f149adc00a0d18a00af", + "d18692ce01d74c368ab953812e3b80d0", + "10e171454c1148be96e684fcf3b48d3b", + "818b98504d4f48f683a55631444e58da", + "4cc9c72932854d268551da5ec0c3bf36", + "21863a3b3a4243278108dfb325a26b83", + "46bcd94a813e40e194c2796c7418f0e3", + "541c38efcb4a49ad9d59588df6252f09", + "659d2e4e1752459b874d63f2a8302aa1", + "e4894c42af9f489e9a4f18328a44bde6", + "e0d4217ed43141b082361e9be071e3ad", + "7b5e1b554f9646678ad1e52eb6811452", + "2924224f899b43de93e9fd43c9a0a079", + "b7cebcfb4b1c4d4a97e22072800704ca", + "19a1d4c33c094fa2ae7aea81c47db225", + "e9a5e78e1afa4af092d9a4829a8db768", + "71bdcc279269441d85914e38d1c72d81", + "cc9ef646d4bc4896aef52bae07e8b544", + "3ef73be9f51d441c94fcde09e8e654d7", + "45ebbd70612c46a3a0abe7418f10a229", + "ab2d7dbc79f14a3f992517cd9f189f7a", + "80cdf4d7d9ed4df3b5d9458357b89000", + "16dbce6f08404f4d8b2ceea9eeb689ce", + "dde01fa566a14702a59deb92c844d7d9", + "b38c033de44f4950becc69aa0035af91", + "806d76af60dc45c1a45bd0eef3a17531", + "67dd8d1991b541ee9bb46880663cf6a2", + "aa96f905533044bb97ca639444c44597", + "a24bcb6b7a2e448fad661004f403ae12", + "6b710bbca0a04afd888804d476d060ac", + "b1e63005e953469eba9c39263e3edc07", + "35556c78b053496f87b4d4e3cb923369", + "c3af7308a0a94b4cb912ebb3bde8ad2e", + "f515990222cf4951b5c6b458ef5197f3", + "b7db270375934222bde922aad753c890", + "2085d2824e5c42129554681a8de4140f", + "f1f96738c0924534ace9903ee998aaa0", + "e0c17496b76849f7ad50e4a90fc64756", + "94b760a27658487dad23f2ed53c66951", + "ae3181c81cf34876b187b353291a2f96", + "2bd638a4490b4b3aa0de3e82a61df70b", + "2be1f3c8a0e54150bb61a438940b6921", + "d2153a9ed0d64c15911db2f53f1772bc", + "55441980b3ae44ec817167ec3871d35e", + "2b7d5c96159c42589dd970d81e877668", + "07a45c5d00664738a5dabe6bd5b85928", + "0098788193894ab49ed9ca8dc38dbd2e", + "c4b0cb4c231641a3a4c396fdf592b9fe", + "272c283e7e2d48e898d2eb5a8e43815c", + "f1a84b2cb8aa4904931b502f8e26a6c6", + "72208a74546e4e3590bd2acf43dc330a", + "32659191a62b4641a10c8fc591e8e949", + "ef5656ef5bae476b9d293b2b54d544dc", + "dde1c48231de41eb83a60c11aea01deb", + "6da221933be543948c894ba53108e624", + "b9579ca17c274a48a1e083da0e909865", + "db8205cf79174b10a56cb7f567c6a1f2", + "168e2ff924404046a14b39eadd4ef051", + "c6faebd33dda465db7a0419422266705", + "c2b702005d45416daa29d42510d9365e", + "43b3aa28587f49d8b320d27ef9cd2f6c", + "f3192b5891b74770a09ee628fc4f240b", + "a9ca7f7f96684dc3b7c09cd5bdea5f84", + "6dcfe567b48e4c9e8f6c78529f7930b2", + "fcefa84aafdb431bba07d92efabec5e1", + "2651a32fb4dc441dab773b8b534b851f", + "4a6f167707d14c9d9c10f994c05d23d3", + "861fa7576ad74ac78ed7798bafcf6c1a", + "a181b6f26ca74ea18ad260698f5c6eeb", + "b310ba69fed942179eef02e27c1313a7", + "e7a03de4e430450697f06884e40b927c", + "cc1a672c8c9447feb386c203f8396f27", + "1df6a16b19754ac1ad40a8c6b690d9da", + "b3e1553b0c104cbc9ebdb0db7d8c1cd6", + "858f975b32884d8a89d4d8d025fb5e9f", + "fdb8227a88b2448d8c64fa82ffee3f58", + "99bae43fca9049c3964d20099906d14e", + "e03f5fc00ded413ba2a08d3d32a095af", + "f43dbc1c67e44310aa9ddf7d037b201d", + "a8052c62fd6744ce8cd5321e28fb13cf", + "901765c8962740f581ec13dcf256b1d7", + "92a1f382f1564f199e954a05ed2dc349", + "1e4d5f1551a94e75b407bb5119fca8c2", + "c999333c40c54b50ac2e33fefc3df62e", + "dfeca8e7c7c5429b91d6207b3a3a9af4", + "e3a6fcf361d94351b2d3fe9095834b18", + "8b1981e3cbeb4706807b7f327fcc310d", + "cbc5b979f7bf423bac0b4a0e8eef39f2", + "7548a79957784efda58cf4d2d49d5a33", + "f9411ec107e940fa94dcde342368d711", + "db7987b1c47d461ea285c235ecc53d16", + "b95cdbc129924c2a8ee9536867c3f433", + "576f0b7ec5b84040b929186669558e96", + "25738fe88f3b44918096d54deabfa23d", + "f14d73667de646668982cac93d602773", + "f02b5cd7ff7d408eae2fba98062055f9", + "7ab6f804440e4a1993699ed260140dee", + "ed555160e7bb49cab85360e50f8bb6f7", + "3d90bd005c324876a49a19e694325173", + "095e633990084e8b812fc7270c47010c", + "7cc9e64d7ffd4e369595062abb3ab177", + "42f7dcc821f041c4adf400ba76c85ed6", + "546af06b942a4267a67d2e6838dd7220", + "bd980400cfd04ab9aaa8dcf3310c4256", + "0594b2e447f54aa9bf862a51e6db17d2", + "e6b725998e194b7bb770950b57b78a87", + "27efde463d0a44d1b8386a3f95aa6fb0", + "244625dadbc6452796e342271e12d79f", + "9e3e900295254b82bc144b3ca4333b80", + "c456bdc52aa146d4884306aea0088c06", + "0137fe739f5346a98bfdee5edb78c2c1", + "ee48890ee3454b15ac52cd8b84693603", + "15e368152d2b4e469ab6d33732d31994", + "0baad2ab0df5463fa55a4b03ba9caa09", + "b54b7a96ae04487081662e4ff5383956", + "5bfb40aa22ee4a34a190e22254589ba2", + "4f01396fb91b4f5c83a890381f2d4424", + "b8e7c778161242cebbbf012fc44e7287", + "3bdc783fb2ab465a9f1adc3e5f0a79f9", + "5fc95fddd9cb4038b767fc5cba588c4b", + "4c4abfe1b9184d5f957dee381c05767f", + "eaaf71d67a164b11bbd4b9c1d1e69163", + "cd0400cf0d2541e49d82efdfc0f0450c", + "7fcd555c03de4411a83aa5685fac1b5b", + "e022dec9019c45bba3e2fa7f616eff34", + "ef350bfcf48b46618e3ffd1048b6e8fc", + "9749f5ba1221476993376a3cb8fee1a5", + "6bfc95774d374c4bba728def2c0b2700", + "73cb248ad76d45ee9b638ec4bfea4128", + "ad1a6218b2cb41ff9bad1aa8150745a1", + "5424ed724a87417abece2d55ecbe5e84", + "f5836f1fadd54919be5ce641182fd386", + "db7f5471865543288af40550a265c693", + "be3559439f684332b3e2e82cc71b0c25", + "b3efcfe9a17348a5aed9fde7ea2697ae", + "f93d05bc2db144f7a50374794ef5cf8d", + "1d0c965ea0124bf0acf426de59034364", + "e3ffbc52b7794dee8a7fbbf7118bf69b", + "42b78950675942cb871904f69006783f", + "c07ed2f916bc49ef8529043bbe8b7ca5", + "6b3afe782b204dfba87a03ddaf222958", + "da596c9400184183b9b8fca70559c048", + "1578907a916245609e1a45f7052cf732", + "4a7ffd6578a446e6908016fcaae9784b", + "6eafabc7c0404197a3f8f993b78ebe8f", + "a595bb77f4784181830f74b5c15b4768", + "e99dc4a15dd94d05b1703781b988c8c7", + "ea5f46e8eac74fd5a828137e3eab48ae", + "40e786abcbc346d19e2304c028dbb4b4", + "541b94352ae443be8e2bfb9de0e80865", + "f984b1a4c18b46e2a654bf29fa312643", + "a25c6504c82f4851bf9bdcb0989bfb02", + "cf2af4b2b8c6420da69ba8d8f73744bc", + "ea45d396c3af4f818b665d1922a2801c", + "711e55e302a44095b336dda8ca4933b6", + "a24c02163ca349d886d32eead5fdd9aa", + "88566377115846a2a0d6398092bb6754", + "2c1ea4ff1a304559ab5c41629149decd", + "2c38a0d71fc64064b162b33154334265", + "6774eaa326794054bc8dc5812740f137", + "8aac71b4f48a4c79b49e8fdda4001108", + "c2ed34bbca494045b0a35ffd774364dc", + "48b073d405e5472d9fd7e0dbe45c973e", + "1850c472a3b944e0a1ad7c1da2ea14cf", + "b2c04e1980b74abbbf69cc9e002b3728", + "28fc142140654e948ab1cf28c461d675", + "e5c6cae2c71b45fe8fee9657af246c2c", + "9d68effe20754ea8b893ff1df039a07c", + "37bb476020fc4d578b7c0bc1878ca8f5", + "4203689ce2ff4a128302bddd574b33fc", + "e95a6f1226f44ecfa761b3ffabdde9a9", + "19db5d1dc63841dcb9ad6a7d13a60e5a", + "eda9d905b3f54609b467b557d5b4b31b", + "a8d7fd1391494d7d8da879ffcc826862", + "e45b96c6981e47478ce62df63f8a5b9f", + "f199f190a54545a3ad1f2f831939c3c6", + "a1c8580cc4ed4966abfb47d195c33d95", + "75ac5035d4c54eae8bc096ebcf75004c", + "11e0c6453f3a4881aa8d118a92787505", + "7795c11d23ee4a1d94ea3cfe075e5fcc", + "ee1fde7ec1514fd5a61790809ebd46a6", + "386432d41a0a4515a90f3f99b85559a5", + "40023055503f4248a5e11cce891f9a29", + "549146fdc7024dac94ba5eee5dfbcb54", + "6acd3ee42b6d45ae8d45d65150f26589", + "e3549d8f4dcd43b39c9bb1b447dc0ead", + "e5b01c717dbd4244b861168eddd67375", + "2f3e1db91150408288b7793582da4279", + "661c85f7cea14b7c81fb30b31d603cab", + "e4c82b66f3df4a6d9f7714a77498aed2", + "266fb75edcf94c249ccc81b67c793afb", + "de6af2fc859c4558b9c06d811db8dd9c", + "f9419365096c4fea909d0df8edee0668", + "f343508829314d3983658a410a8280b9", + "eee4d3bdc5734cf6891db41e098e7cd4", + "fea999c1d8d64eb4a9c2bb1fac1e7d83", + "6167fb73abe94fbda810020123d0dbdc", + "ca73e13a79404bcaacbc0c425e757d2d", + "558aa0e9c3d24232a7d62180fa0aa1d6", + "4159867faf63453eb2d45cb64f0cc51f", + "5f151e09f3394314b11f64ce929acea0", + "be6ff8750f64417d9eb55c1ff4762d3d", + "79c4367011ba477088f1e14cc18d945d", + "c63dce91ac214d56888307f74f98cc57", + "0c18856042ec43458ac04a4a0ed9311e", + "1d6cd1b21030449ea6711abdccc123ad", + "e03abb198f644cc083e36350769d7273", + "c389697d92ed4f1b9b942a90524574c9", + "980a0ef080ca4208ab4b9c3d2fc6aa9b", + "f372ee8669c041f1ba528cbcb883f644", + "6f4a0b64512f412aa46403796201ac1c", + "57465415c0d045229c86b003493d3467", + "06b77ad6945c4f78907d12ffdbc9ccba", + "4231c988122a4ba19e672dcd9ad1278e", + "5750f70ac6734728b0eb3ed81de9bb2d", + "a0ffb62bd8d84e18a6e0926e838f29ad", + "2718349782cd4ea38cc1c3035b8b118a", + "faf947997ac4410d9cf264a15dafab82", + "a0c69e27fa2a4f21ab0b2b4080e6ee92", + "fa048c4ac32a4d4988214a5e3fe70a86", + "ba68b7dd4cc34c92ab2745644dbc398f", + "fda12812ab1147b79c1a6c7aa3adc5f8", + "e4d311c0d1c843c197954c9c1ec23f90", + "cee94c045d7549c890f88f6cc1493117", + "eb6fe03160f943c4adc5c731a435124e", + "0a6e6c8cf2b544b1bb2c97c3f01d925b", + "721359a5c0cd4cda8c5a378cd1e83494", + "e5bc00cffa4c4aec84006affcad2cdb1", + "c4c987c8e9c24969964749f1312ca3e1", + "00987713fe994f4fb7c765dc82810ef9", + "eb29cde83f4b45c7aee94e37f307eb65", + "b0a9471193014762902799dea45fa52c", + "4ca43cc270fd42c78c9d0566dcb1a5f0", + "e79308f01b124bb6908831f9b2505721", + "47e3fc610c2d487c98f37d6932a8ae87", + "0d1ef6080f6e4079995f73a2600269b3", + "999599bba2be4d1fa7ed855091645711", + "1da7fd7aa7fe400e8ba7cd3deea7cacb", + "54e4d4102dbc43148e02f89926809367", + "fcaba41f8ec0430696793a384189d0c7", + "9f2a85c6b4694ddfa307df5b16bb821f", + "a728d4a3dde7463885d7a5889fdfee04", + "4ff4cf0cedd54b1aa63be8f376d9cb87", + "ad96fa619da940f88b4a9eb4c1013ab0", + "affd4ebf5fd143d98c1b7c76eedafff3", + "4bbadfbb42b841919c1b66ab3714d065", + "62d7dc8d76324dfea5591aa7b536886e", + "4a0a520b5c704c1996a84b9e8164c345", + "3e4e82e3f3aa41b6a83680cf5c0fbece", + "9409fe92cd484e538487d7bed5ff252e", + "c442c91673a24b3798065d76fda3b4e0", + "989d796409514627807378b1feccbac1", + "040cbb34282747d6a1711f3e37dca955", + "e02e53458df04a7892224d312e17541e", + "47b0f679a93845bf90a772859b48c76d", + "e9edbd0c027c4f648e1405df96670cc1", + "d1d0e427e6d04de493d80520c1fa2214", + "fa24ac97d25a4e20b93c7d317311fc8d", + "3c21f5beb34345bc834227d708e4d830", + "e0aaf0b7368441019b9ceed6ef46ce3c", + "c1f47a4579164a00acd1a0f7a51357fd", + "d96dfe460f9f4b71a14369e5f0d5dd2f", + "f880e385deca46519ba8fb5348c978f3", + "d73899c4b476436caf7070e67e44fed3", + "295b000686b940dea40a8e6090fe1e95", + "0ae0314810814139b3dea039a86d6504", + "7b2ad0c3e4f94d61a46d1e567f30c2a8", + "fa5e949f97e3479b8c389a445fdc49e0", + "20d2cd4a0ec3455aa821aa2f76ddb521", + "c2b8d73835134fdaabf18ef05a645221", + "95a2d518160a4a8dbcdf2f23d101fef3", + "c52f445eca564ef39def020a8db14ffb", + "e5e4ab0b38da4540aed5244524828fdc", + "dc0b4b97fb2748a2bff5edc5c0d7d804", + "90dfb9e99ddd4b4ca414be7599ea6469", + "9a572040fbcf4e469330c27c92463ad8", + "8dce6f56f6584509a6137f7e00925a12", + "1557f1fefc314cad8c603fbc6f64d0fd", + "bf94641134e74ace8b1735350f2421d5", + "796531a764284083803f6f8d6030d249", + "346f8647738d47de867b105fce5b983e", + "af1e03fb8b2a4bc79e9f774a6c03f248", + "25614319b28a40ab819cd33133b8b159", + "bd908c01773b4a0689e7530cfdd4f74b", + "f2b0222f35984e599bd6d5913b0b3844", + "377da8211b0349b2b13d2339eaffa4ac", + "eee7385ec3ab49e2b8e3f08ed9e38707", + "c2540fdbfc264dc8bb1f6c971b18366b", + "630b7d4aa7554d5d928e3bd35236f968", + "2cbdc76448e44f1d9b20e44ba524c270", + "28c7c30b5be84de290d43b89899ecbb4", + "e4f9d51f88264bedbea60ccc147ee79a", + "1e744cf9ae6f46c7ab67a211fe3cc7dd", + "d515481fb818405fa39b16ad217031da", + "39755b394ed24719932ac54e3584ee92", + "e730175fa6e942d3b42c00e8a0addfbd", + "b2db46a3cb60418ead8e87f312797561", + "091643a9a64044458e75c966225d2669", + "23e929c482c3483399fde042cf9e9208", + "99cd51a8f0c0478088296520c60d5c65", + "813e7b26e9c8409caec3a42f26d38197", + "b090482ebb694deaac77c33353b9a65c", + "9d1ad8b8512040f5a200bc3f72577d8a", + "79b4a0919f794283bb1aaa22361e50b9", + "6f333e67706341649ca91580bb51b066", + "87838fab264940329c3d66f3ed6ce30a", + "fb83e182d15b4b03a920ecc4dbe9371c", + "a8f584f6b82d474492940018109eedee", + "4332a99fba004e5898e68981f7fd9da3", + "5001c2a5548c4691ba665003201364b7", + "1a812a1d30bd4d6492a8f87f701a4d31", + "a66c812b381b4ac59774e24872719d1a", + "e1e4d1cfbbd048c494236380599dea66", + "ce810a7347024b6a9bbaf4c4bd6c6a2e", + "e2673aacf8554b098f3c2fca7fc4334a", + "36fcdd98f9df46fb80750a8faeb5ea3d", + "c57d5f12ec9e4f669c93536d59f96030", + "d806650595ec4fd5bbe90aaf1f2545e3", + "fd67f7bfe86f4060a3057d2ebbfe1a48", + "dfc071de8cad4821ba6e59a4268f693f", + "4c4bd6f21002482491b2717500a18ed0", + "f2828c5f3cd543f2a7659f0d8d10b311", + "af71d7fe4b87409f8d9b81452fcb9847", + "6bbd346a4aff4f7dbf6bb3755588f384", + "dc08af0e13314841b999cf57badde6c7", + "b4a2639acde64ce6a930c4936e1654f0", + "3e7a2c0bbb4c422f8423b89ccc3dd062", + "25c29121183740059bdec15be94b3ac6", + "bc8513c84eb146dab9b9ce7be3a2fe4e", + "facfb7d088504a0eac7c47d4f5ada0d9", + "ae19e601aeff4267b8aed4870291c099", + "53ebdb9be40c45d581a1c766dec01000", + "d1eebc8fe1974ff08a2c00028516ce50", + "2ca7b3f063284089a12225a3a5ce671e", + "eb72d308cfb44dcb9d2e0f7b4e503bf4", + "3e0faf09bf4e427ea7480397bb2ee387", + "290a824ebf9d419fa1e11eba60fb4ba9", + "ea06ce6c179a4676a1e9329f3b7ee127", + "28b570276b084cb2b0b169618e328bbd", + "fde824c094ee4620ab482a6f4a6a3afc", + "e23cc5eed01149048fbabd4244ca2850", + "2f6d2837fea045a1b5d976f51157a9df", + "a3adc3d127b04fc58a45ba5e5135cd17", + "f8d7f92c9f07415fbd29f327db5bc4f5", + "5345d37be48c4202b25ba2e2b5a8540e", + "ca6509e3858e42caa5f0227403b5c5c0", + "e6a2785e24c541f5bee78e1ddb043b6a", + "a03809443f5344d6a41a0533c5a74a9f", + "fcfb137cf4174194a382f84c2b2d0898", + "e642950d58964c7f88c9c25fd8c18072", + "65c1ca532f5b4769b991654bcdb51208", + "16dce1e474a046d0a5c95c24391705ee", + "f033545bb7d94595ac010d132f8761af", + "3d52780cff9b476f8600349a6e711ae8", + "c43801143ab6470c875a146210cdd8fe", + "c5eaee0fea464cfa944b0863061ba8ca", + "a8fcf2220c264a30aef6bd8fd51898d4", + "5eac1d12146b4115ba8fd8b7c23a1f3b", + "1450ccf286f64ca4882422d0751334ae", + "e773ac9fd3e04874bc20ee5d6a946adb", + "13a47f4ce7014779a037cf7a17fd4f7c", + "5838bf92b65149fba0f3b0fd93ad43f0", + "5e530e4e82f3413a9516b3cc8287c42f", + "a81888a64bf84a6ebb46cd770050b132", + "f0b56669cfde44019f9648955c12173e", + "7cc2f7eaf49b43e4b679fe3ecedd38e2", + "11ab7d7c48bf4a1ea4f44c9ad8279c1a", + "5309de66e31b41acbe0ea604aaa66da4", + "17b766de120d41e99c3fb17d4112cd5f", + "27d7bc7985ac4609acb80a4762fffe41", + "f14fe7efa42447e7aef859b1c3d0f59e", + "7e864a10617145b49e57c7223bffcdfd", + "eec19e0deb6046cf9f909e63c5371203", + "c58796860c764ae68082b4f752bfd84a", + "4751dd9ed8654517bc66b4d7443ada82", + "f299834a8803461e8a81785c32b4b3e9", + "4195ea18d45f4d7e9e2a0b66b1da3fef", + "6fc33cbd0cf54e0d9dfecd52da1b2418", + "e2d383792a75446b869e32464c7ea466", + "a91492359e664c3f8010a041b2d05de8", + "f0b8c79bc5104a63940020d5187654b6", + "82d466ceeaf4430482c9edddcaab683c", + "b1c7e13502c9490086ba95f1e181ffc4", + "a3823d40744c4c509309dd15d3c9c128", + "6d9ce5c765fb4f3d9d1808bf80dff824", + "7b81d73516774445a3dc152e2a9be402", + "3f673a5ce96342199ee709dde7f20a82", + "81c696aadcd74c5694ce676887dfa4e0", + "66ac28410f5c4b1b9ba1bf2f4fd284a9", + "514d448907b74ea093f136af0c706d3d", + "30a5522395da4a0e9e69101f2353ec5d", + "600bc99bc01040cd99180f555b5b3a61", + "491aecb4d6e04121be9dcd9bac6e9ba9", + "eae9d7e9cc5042889c1966ca387deeba", + "68ebf6492c9c45688661657bb6aeb320", + "48b23bb7989e4951a28e8b93b96b565f", + "60eb909694184e54acbe8b78343146dd", + "0a51db978635499cbce9cc57c434ffdf", + "e5c60cec993e484fa028cb16e8a03b1e", + "e658ed425b1d489190e3bc4ab9c1c353", + "ca937e7fe03e457f820eda8a27157b7a", + "0b23642b64294b06864d1b9cab8711ba", + "db6b7597f9d942b0bc221259692d506d", + "949a3274f02042f2b68d5dbc471a70f8", + "aa9673cfd2bd46038c3d7d703be1ad47", + "ec3ab13223184b53a31cb531883393e4", + "b60c397f0bd141fda1e5dfc8b6709096", + "fa24dafc04ef4d8a81e0f3fe22512264", + "6c692bbf57364804a68d4a6477e788fa", + "dd6423946f424934b7eabc5013fdac37", + "2d30a0f626f6446a944d9171a8cb557e", + "1d13b536898f4c449eb9777b8d1f2541", + "82f63a225edb419b990fd66655ea5d4d", + "c78071fe7eba49798a751fa07d0ee0fa", + "53f514139ace446cabfadf80bfb1fdae", + "e3467ea791e24a86a1349d25cf98a1c8", + "ca121fb9b7454fc18769d0d7b6e1781e", + "fc310b75f3944505829b3ee13ee608c5", + "e6b2c8a5be864ad6afba3bdfdde1aff2", + "fefe1eb9f4134f78a0eb1dd29aaf02f4", + "6bb92eefa68d4d4189837b90f43d6c2f", + "b90e23fcbb9e4f7c99564072c0a5612f", + "c872c2c0346b486c85e2978284841a00", + "f82265833be44943b6f2d7bbbc1e3b26", + "a0c216a7de774aba903f441d7899aa02", + "20fece387d47426fb0d105049920790e", + "b581cd5112214abb847796710b91671b", + "04e5f5f5959a4218818162eb4cdfcfc6", + "f669df2c04cd44c68f8a6c9239f5b3c8", + "dcf0e226564b4ec3b18dd5a93e6e8110", + "399b5aca63cb4b148019f9542a96ee03", + "3d9ef851f5414f84b9c72824e468c5a9", + "5cc2b8234ff04a2aa29d5f0a0393ed0c", + "0c770364d18042148f398a0dcc722d9e", + "c5ebbba0764a4a9c93fe957121893f6c", + "43a9646eb03c4ad8be56a2b333c13731", + "5c05836dfe984ff7996d44c1f484d18f", + "09ffebf34d6c42c4ac45999e790226d0", + "44d69f20e761400d93b0f1e72fe08528", + "793a45a116be4082aad5ca002ffeb5fa", + "af884c316bdc4b4aa4c61177ee32ca4a", + "eb7ba8abcb384dc0b4f86ab869e5da8b", + "f728858a202240588c6c2d14184f6188", + "e5f06bda3ea74a1f8fa75b1945cb5962", + "f7d5399fef1744b28a503f59437db29d", + "35f9a17c5c194885b729ab31f216ddc9", + "3978fd01d56e4706b52063a8ce12d26b", + "b15cf31aec72404eb6667efb22d55d0f", + "ee10a6e05053422a8e15ff66f5e33f80", + "1757576875664d9ab891168a4c01b521", + "f235ef113d47459895b2ae7407eee8a7", + "811e149588a54fec9514603c832acb50", + "9884f8ad8ff345c391c7c1c8b30eea8f", + "7d925df32b954d17a4482aee5a5ba6df", + "edccae41b1c64e38953cd7a4078f616b", + "af7d3d4ec80f441aaf6f9947d0813a30", + "9d7b896cfa6b4761b2a497215754eb38", + "04629445e5b14f93bf18dcd211fa3d78", + "1f16565d7dda45319e7094c4ec7af66a", + "ff72a80384bc4570a804215270b8db29", + "2734161713be4f97b9aa88c7c39e9e0a", + "b2eff5a26f5848f8a10a58aee420d0e5", + "854d4ae8ba834309ab7b8f1e00401196", + "356fe590f6f5478e99888fb59b7aa77a", + "c21be071cbe44b96abf7046507305c97", + "496335a85be047a494fbfaa8b4071469", + "8926f6be27704713980076253a78e057", + "b2b577977af04c43a44963e4f34d9631", + "4124562be1a74264b57b561e0908e69a", + "2109fa9ab86c42f081d0f629b4731b5d", + "340f8dccf3234b46a9ae48d23639d09b", + "b2ea1501b04f481a8311cf8ad03a8bc3", + "0060af6f4da24224a4770eea54685ecf", + "21cc98087f32408da021cdf99b28328e", + "e98e7fb33743442383812b68608f7006", + "a6b0c3de5a0e49208772fdbd73490774", + "e9942025312343b0b9f821ff5b5a26cf", + "c8e10e541ee44bb2ad62a571735070af", + "f368f1a17be24574a8eac33aa1a6ec27", + "9d1f6924a3f14ee2920176083a558dfd", + "15d71bbd00454e63ad7d23914dc70b66", + "16ee83e509e745998f229da44a8387e8", + "ecaf78a12d5c4fbc8175dce8a1617a45", + "c952cb79279c4b3581bbd00e36f376c8", + "71245a5c0c5e42fcba21e2da571a6c5e", + "e4bffd85e16b4c87b38e767c9f6dcc10", + "9c8ed8e91960404fa5f24b5599049bad", + "ed3591dbf22d49d88591f777cc64b905", + "6f762bd59fe04888b840f324c85d6e31", + "3e03fbff124f4a2fa366bd77b2efff11", + "e60f0e238c754652a233fe5eecf72c81", + "2d6489d925dc4fd4ad828b04c8553674", + "c7ace0b0d679475f912df43fc6f7158f", + "6935152ccdd84bb3a900853147b35582", + "eee3beabbfc24563b5046f290ac25cb8", + "6007efb6cefe4924b3e00095884c4e83", + "8ed0cbfccfa1449996ff0b06875b1863", + "b681993a7ef246568b819706f3e029e3", + "1e2825e6428e4940b6971e09929bae61", + "e2a4f0f4b36244a5bc076a89f897b132", + "7bfd7808243a4883b8a4cbd13406acff", + "74f4d37d87a847c0b1250c615d975810", + "2c3fc2f94cb64785b81088efb0097d22", + "41dace169ab1483987e1c46bc07e4384", + "10da14af6df9404da9cb4360db7d2400", + "dfe09c08557b4bafbfe47a54e840aa65", + "e40732b8fb06468596ec1623ff89d70e", + "f247c9e2280f4152b4e9256116b77aed", + "c2723bf64dbc42dc933fd2f8f30249c0", + "f0493b04de0f4bbcbab66c47bfbad9d5", + "6802359bdc16486083301bea24f1f3f5", + "108dbc67037240ab8d37bc5288595a96", + "b79883ded1ad48faa7133763b233a1d9", + "0785c3de269f4a99aa74ff360c93138f", + "f70d075ac1a745ecb5b1f295fc501300", + "efe93249652540128d1df1d5b21115fd", + "cbc154c33969481b8c04389b8c396948", + "f9adf0d8bc604094a6b9cefb09b1568f", + "05798697321a4c9fac353d8b1df94d3e", + "ed1bee5d153b43a7aa9eec30dd3df7e7", + "275a7f052fbd4ad0b649f7162b1b8e30", + "936e79f2935c4b28a93a88480d8aa44d", + "28b34d3b51dc45eb9805a7eed479af63", + "07aa5f57ff324d4e8785ded90d2e5c52", + "6d34d82e368e4850b8117bf512607a18", + "d4ac9ac4debb4c26b4aabada4820f986", + "3521f4c1efd644d8aba4cac2268a3fe8", + "ec43bd941ecc447e86a89b442a1f344a", + "0e1b3e2691b84d3cba174e239e52126b", + "548494946be94ee7b59784aca9d37d27", + "c36d736d644e4a949d1301fafdb65249", + "e54afca98dc44e5bad209f87b7c516d0", + "fa85d54cabeb419685924b853c7032e7", + "3857946000c048d0b0b880e5bb65f5a9", + "e3f21b66be924b5281ca2fa759212f06", + "17a255da05df4c19a93a9b67db698e62", + "80488a1047834a558e0d571dfdd75cdb", + "d592cd978bc64f158835684dccfcc480", + "fc1febd4847f4d1ca5069de39b99079f", + "166ca3b7a91e4644abc08cd0e322c2b6", + "0f00fbad821d4c05b4a49b80fce3c46d", + "4f051ab415dc4ce4ad81ae5f99da477a", + "65638e7c954c4f9cacfbb02f14122bd7", + "e8b334b1651249c29a54d67afb6f13b6", + "ee0fa270366d4b4cac309b9a790178e4", + "14a4745557e24661bbc1515ed3882dae", + "ea9d48bf4ca0408899e10fdd8bc91bea", + "9332a8e1e5d643b6bdb284e016627f57", + "351a82ec49e1444fab944e18ab251ebc", + "e1051fef094449f980adbb76e0c0ddfd", + "4387c530b415411fb885fcc30d3c4a96", + "b94d51ca30894de0a15101a22f96a8ea", + "50e3b31e6935484e829696094b54eaf3", + "936c15265f7e4674a2a3f8563e2d334e", + "fa87f31a66f24baebac12ebc7c4b4cb5", + "fa6635afb87f4e31930079369ae6d884", + "a0a9d9abd05044b982bd93884b189ed3", + "b81bc5c50d30490f8a015cb62cee67cb", + "f47e84c2558842dfae2acaa02d27f547", + "fa1f532e2a2b4c18a5d9cdc21159e26f", + "ca8f9202ca184ae2943c100ed25b61cb", + "680b5ba359ab406186cbe9c61feda9ce", + "e55c3adad31749fa8c78496048f7f191", + "6120ce6f49174414b981b183b815db98", + "4199027b32544813929a63d5e7944037", + "ac18467b45c341c384b2fbd7e3c6f745", + "14ad8882f90b43d7868afec5148a2d68", + "ac4108f79b654ec5b2a40c1b1f7c579c", + "acf8b776d3404ee1a681a721894a8b62", + "f3319f0853de48a0a2e946b290ef03c7", + "5e3e480f9a7f4ff19fd9fb329a100fe0", + "1751e91968704b43a0dda2eb53a5fb75", + "f045c03591fc4ce2bf8c6abb764cbbd5", + "ba384da44e144b53a0d8f8dda464e0b4", + "a5941e7f539e4639b6c54586fe1adf33", + "dd6c40832f1e464d8efc6f3e50a1d66b", + "218caabe4d1646a980b0f8c5584f5c90", + "b0b9a86db0b248fc8ac3d3320986c624", + "90d5a85e8e6e4ea9b0ac8628ce9041f5", + "eb16370e0b33439abfbb66ce8d4d0867", + "c5b082a6e88744ebaf2eb09ba65c8b9e", + "4de96f97ca814709a7664b1831a7c9c9", + "ffb8035c3434458f82df0408ffde6a04", + "33ab9ac87c7646eda6f0c6bba9dd68bf", + "f26d1358631643e09f89c3c857ded45c", + "92dafaefb8c742fb95fb8ec71c27b2b5", + "708b5014d7b34ed781878932a23dbf1b", + "f98b0ddb09e640fab6758f75ad9e0f41", + "5274bb67579c4238bab68ddac35042a5", + "095fae447c0e4f8d989c67ef2104df6e", + "6c16027c8c244358984a82677d768b00", + "f974e3e7c83d493ab8ed26e812567880", + "37d239396fa148858017dd63e9c01c6d", + "d30cac84d31a47a3a0860f6f4758eebd", + "f5752293425f453d8277657e73f8bbe9", + "58839241525c4818bed8b9c103f245e4", + "421e9b3fb95142a6b46c96408c45d263", + "cc6728f652a143e785f9671e9b80acb6", + "4237721edd044ec79c209770e1f90d72", + "96d7dfca30f0463da09ed3f42347778c", + "9a0c401dbc2743eb9a2b5ad5598e92e1", + "f91d3bde48924feba00b17f71c2daf50", + "7bfcdf2d13654b0f9f5e3098aabe4895", + "f162cee189bc450cb0bf9df9984ea45b", + "ff5d1c07cd4b4f1bbb7da5fbf09f5957", + "287738fd02734769ab20b648fa8537cb", + "b554058d4f4246e6ad237e9326532f2c", + "7b5e576348c54318bb05374136e34b1f", + "ad354f84b55a42f6a5b014879973dcd3", + "f5c620ce3c6845d198249220d082a2d5", + "ec964511a3ff41c18a13e9ef18765e17", + "6547ecc4f59c469791133d9ab06f67c7", + "616d4017a9a94f1a83f90c3e6f535316", + "46f65621f5264d1885097d9b432856e7", + "6ca43aa457c944c8bb5d9aa354b09d3b", + "8d9975ce684745489f526b4b2ccaf349", + "2db7e238fad644719a7d2d6237f4b177", + "39e96c79630347d89fae5f6e5417c4a9", + "ad4a281c460f40a9bcd88d87e86cacac", + "578577e4e6584b58b1072ab9aa40314d", + "824c4170f06247a99361717c40377294", + "b84402001e314a34b6ffe0a363f5feb3", + "34adecc3e9ce42e4be9befab36ae4467", + "ba435f0822f645459ba87840eef254ae", + "257512d4edbe4be2ac782d9ab74f8360", + "ffbf344a1f1b4e1788916514b3291d16", + "fee4160588ea40bca74e17785f5c3179", + "f2b54451866748f2a7c7d9afe2f2bee5", + "7b0b46fa543f4eef931990f02e210808", + "d7918fab9b774f10b9fbeffdfaf27616", + "d6f9ad8cd65b46e9b77e1b557b80086b", + "f8846e71faad44b4aebaa92abceb2e2e", + "5cecfe38606f4c9b9d8b33e43ebc1bb5", + "927592905950476eb2239bb45b5eb2be", + "0b96cdb89d75448e8f11ecd2a65e2183", + "dce5bb1f7abf4ed3b8d5ca2610d63023", + "f41e5cd3583c40e18a14df47287a43dc", + "3729b2dd716f4c89b87a192290295808", + "3d5a5d4daec8433ea2f258d7a66a77f2", + "1378e50dc7314a0a8f93a09091436bc8", + "29451febdc894682a36a5112fd13f054", + "725065392aad4b04b7a172f8cd965497", + "f3c14e0c58b14b808c2f2c5cf34736df", + "f2ef78fd6a5d41beaca80843fd9717de", + "07b10f607162439a98233c801a42ad12", + "c934585162de4abe81b151a2354217f5", + "e55af322cf8f43fa9b4fb2b368bafd0f", + "8da8a154c56c44efafa4d43b4dcf666b", + "b0d32690c63a40f6b6664349030293c5", + "1e7898f9502f4ac0a71e03ab8a5b18dd", + "f25e5865ff8746879c61c4b8158259f9", + "384b544e530c46f4be37039a4a44cbab", + "ccfd5c3f62a34c83b0e5d84fe2961d9c", + "cc0aafdbbbac49e99dada18cb3fd803d", + "13ffe1dcce0a44d4be335ed60a301dd0", + "624dd9dc5e6746e389f3c262df7a320d", + "2c438bd8848740f8992ef2985e3ebdc9", + "f300d0943bc44c45862d07639534909f", + "ad165ec4459045b1b6c2101bff620d9b", + "1f6f7318f9364456b8d58c1eaf71762b", + "ebee49fcd3f54f44bb083e2d803b793a", + "493602ea53554e17b957503cf31cd792", + "374d04748c4641dba2cfea7e29c6bd93", + "531dc9b727254aef9918e1d0b7c06e97", + "a12d3ae76e3944428f14e5b15d4f0efd", + "24121280217c4c9aae8b455d5516b238", + "c7f353d055b443b4a091b3947ead11c8", + "bd6c178fcb0345f9a857399fd5840353", + "ed005df8061d43038461c129ffd681fb", + "4e535b6097fa46218e85c3e0aab7826d", + "45bd80f76b294b4985b76f055b7f8d72", + "e69cb11d27464324a7728b080e728245", + "f292513de086471e9dffff684d130e4a", + "c7f224be0eb2481eada2310d3f7ce315", + "29e907cd254541c3ad8b42850e9ff504", + "f25fb0c25c124a91af8ee67e6776d6b4", + "0cd1353e9d644ebaad932ee48baf8ce1", + "64eea8d653f0488f93415ba5a59b6ea7", + "9d08bcd9c8664b1b97662691234a7ec6", + "c428a4e2e5bd4a098696363e1dd4f3f4", + "b6380781b32047998a3d02a6ab561cd3", + "a631ab27f32949e6a8f2ed94d040b9eb", + "d62e0b6f29de4716a250b55359e87193", + "10a19cf4a0e9418389e554ba6426dd24", + "d96d62c234724d90864bbfba85307e63", + "8e632f9680714da6b9536f5e6003c722", + "e6e34b501347437da690876bdc0ff7eb", + "4e4eeb01ee1a4a7bb8c333acf9899713", + "42ef95c945084551b92ae7f63ef34f4c", + "6cce0016ca3845c79b73b36a3208d94d", + "a25540fc03ba400faf012d4f68b7ba41", + "ff3b7016740e403f902a7ee54b07ef52", + "96493c107dc948969df4f184b6a2bcdd", + "2b2990912d404d6eb08bb2af056df3e0", + "ca53ad389b8148bc8541b78bc2d87b8a", + "e8af96a51d6940a2a550ed84132069e9", + "8b53aa66ee3346fbad65399a58e18210", + "5a79396e6c754077a011ac8fdb7fda35", + "93fd538e282d4d60b973b2179ab69e5f", + "5e8a5c521f1548378e17b462a1a21eab", + "d48b6ca668e84824baa31763bc8191ef", + "0b7e3ea6c6364865a083655012fad027", + "164b1fdb0fc34cfb8eed21bae32a044c", + "741eb08a5d3c4796b43ff726186acb77", + "6c24c80be5134db1968c80fa98b4e509", + "926951d8dbec408db448ffb6550418c0", + "ea0cf00f23574b2cba0eae147106b040", + "7f658554a3854ce28cae876c2a3fafd4", + "fc90c018647c4fd1a3a9f62559bf67f0", + "3a3ecdcdc3b94cc898f8e7a2a59eff45", + "de691d14a054487e871f89d052c06a74", + "3910e3cb04b04858a5e3df19b74c6d90", + "22cb55562c844320bab043ce64e8ab1c", + "f65611997883426bb7c56336b8fd4c36", + "e0aff657175a47ccb6f143ea60b4a48f", + "6d611e4dc5134b36a2249258e77e46ce", + "09577224c1ea4fadb86beb282daaf1b9", + "0592fecb8a124d598befd935159bd561", + "8e9067927ee543819d974f1d533b3525", + "fa23d26cd7a3447ba8b21c2667ab8a1c", + "1e81186f57414f47a22b726cfce011e7", + "f235e5b7a96b46489db4dce642742049", + "27234b8a603d412c903b156c632b4f5e", + "10c064702a7843ec898c85e51a9a50c5", + "41a3ce0e1b0d4645a81c5cc5bcc2a636", + "baa90088dfb8429b9bbe7ed8f6746714", + "5b9dbe6b48a745bc96a3673108a314fd", + "d14007b844e14d2f957f1d92f47253f7", + "90085243d2c342b49702e804d5a52767", + "ce47daaa1af84cd8b99b11d77e78905f", + "633a551c679b400ab258ed37dda0f1f0", + "11d5f3da2f004f15a32f18c0fc220ef3", + "39059edc24d547f393c91856606e25da", + "1355323d390f4daa8f5f966aa178037c", + "3a39f00e440148efb8b8d08730758ab1", + "8ea717f32b474682b747fd397b34a271", + "f078ec4957764c5daa43cc0105aaf064", + "e408136e84414784a142e40eb876bbed", + "6b85cbe851c74f26b336334abd03adc2", + "31eea862e4d74b35a5c20ae16c403c80", + "68f0ae7a7d7844779383d332319a7352", + "28b11e6934c24f998637ebbdc02eb769", + "7699acde27aa4b1f87f844d8465baf93", + "e50b50ef53c54997b432446796d67791", + "ef845cb048e4499ab2f2845d20cb10d0", + "68a9c0d117304892b12c1ea3fd63bef2", + "18326cd8315c4712ab5d880efe79b44d", + "1c78af4bd9784c70bdc920843ff54892", + "bbcb084ac7dd46e9aa20acad273138fc", + "dc4a1ef856b24492a2290f45c8156d4e", + "c4209af8104e43c1b59c6c499492b2bd", + "ebdfc87b2e104e51af6a7bc018a21d6b", + "4269b97a679f40da91da28a69a7c9f45", + "9ac7a6979f354ecbb37805b35e6f5432", + "c7ec86e7feb746489b30b4a01c2510af", + "5b4d477f40044ef5a95d0e3288518a2d", + "28a769dffab9481b84740f4adcf124fd", + "ea66c997677a49cfb4d880a64f6819b7", + "bd769a8792b9477a9de7b4cfb2d96c0e", + "d3f279329c034ad49288dee94b03fce9", + "de2e40e2e05d4146b37154d821772c9a", + "6251afafae2349e08204ea203aa4bed6", + "f73e2e1c8ad241ff859aca7e032ec262", + "fa28b1e74a5a41a0a96e91b6829e8114", + "2b8b51acc3964cf4baee36aae0989550", + "f98f6da7e1a240e5b1a3d321253b3754", + "3ae0b4e6a75a41d38a2adf8db048a703", + "5bef6c9eb44c4824b3644e911659d889", + "1e524fe8e0e546d69baff4d6e20e7533", + "3cd01b9f9ced4e509e3180378b666e22", + "230929231f8e44db920c9be0bc55456c", + "53a2ee58f5784a2181778d499afa8e03", + "4598f33325fb4e2b8e8b0744b75c8ac4", + "f30ba7d7a43b436587f8d9c57e1656c5", + "79a3902f37f2482c97520f3f19e419ab", + "f3b26b1a2de44a19926c7b829baf0d2d", + "1c357aa755ec4469b23e86f1b0c6aee5", + "6da2baf841e24d17a2cbbd08540aafe0", + "f3be35040fe94782bf5e3c0a88d34d5e", + "e77aeb66adc34c8495b6a8692055b6c4", + "12f1f70b679640ce8ce8295100f5e3f0", + "79d352623fcf4f3aa39ffae715e6b4a8", + "769829932659490c936ab574af87c523", + "1e9bd398e5a149a9860920afdfc0d156", + "9c5242814c8d4e689d000273cb807d73", + "4c85a7dcd4c4446dbb8d03a8bd311bac", + "d28690af06624a80b24bcf818666ab1d", + "078f9ccad62a481f86b3a42d040acbe5", + "7652a4e76601463ca8c7aceaa84d9bf3", + "f187160e1be34929ba3226dcaad5b0a0", + "ecae4a6a393b4ec2b79fd2801a3fc449", + "28bc366ba09447a89fe6b75420299a4e", + "f412d837631c4969884bbbee0e060909", + "a2b56b6bebfa4388a349eba131572a6f", + "2b2f2afe691143b1a0d9c56141b028f9", + "fd340792a4424819bbc3c27193e670e4", + "c387552cb29f4e2f96e9514f0dbb1ddf", + "5ad02ecf7bb34425a8c4a1be2b554be9", + "ba170cd84f6f41f494d2bb7a7aa53134", + "f818484ff04e47a7ace688faa5015a55", + "03fde10430964af396242d2a6ced7ea4", + "392a362ca6e6453f8c29ffbf3fc20608", + "987dc460c7ac4e78a27e237231576f19", + "5866a5b13bac4a01918d2b1eb80ad2ff", + "f126e15c0f904fccbd76f9348baea12c", + "26563b2166ce49d6a80b77d02983357d", + "6851c90aa4b14c3bb7df2cfcc0b1da4a", + "217a0c7934464b95938697376703f106", + "0a7ac1401be04c4bb3dff02d04681073", + "e4c9b6a856ca419d83501488d6ef64e1", + "4c9549644f6b477d991f16a26e442935", + "a6f13950fed74b6f912f2d19eae51b80", + "25076b00d3b94a1f970a05a048dca6e0", + "d0aad1c318e247ea856aa01325c863f7", + "4c2553601c9849ca8051a0bf39423422", + "f7563933f8f342fcb1622405c4ca52fe", + "cfc32d5db9094b7b8df48c8227b3d5ca", + "b25366a78f134cc3bab5d990a32bfbc8", + "552046e1874849cb925abf7650e7afc9", + "9b1fe3f138e746c1a69224856732a01b", + "61f67a262a8c4a22bcb2e9059636b6d6", + "712e1b9155e84173806bdae1868aa7a0", + "4fcf23297885436daadfedf917a62d19", + "3b9b92a5ef0f4bb99f3d716c5be79bc2", + "973fabec62ec4e53acd0016779bae37d", + "fde9b12958f44581bb4e94f7bbc49ea1", + "fcf64ccbf72340558b54dc328ba9bc3e", + "2f68c7ae32614c75874793f5de4a4cbc", + "69ec21a2adf249779d307ed55e5a3dbf", + "40c3fee5315c4ef2acbb368484a1fc7b", + "03931f6d4f38472c937cbf51d277defe", + "0a1810add9984f3c950c34b7b5462d96", + "d39eb03ba00a450287b830b6564a3e64", + "457947902e1e4b3a8b2606cb4b963e11", + "50412b64aa20474b87e2ed690464cfea", + "f6100bbfd32f429cab16975e08995aad", + "2f8ccd790ce74c00907b1b92d3b8c878", + "99602f01eb004a488ddfbd14b91f4cbf", + "82e38b32baed40d080454474595e82f3", + "b3e3d7ec50604e8b8024045828b22233", + "a5ed4c7a97b640de882058e071488164", + "3b16c260d38849babeeb5e0c3fd476c8", + "f5e81b754307468ba709fd297fa0be4e", + "c136eee85ac24891a00c28c345ef1570", + "26c4469c1fd94e899b5ded8b41da0b39", + "da0ddb490f214ed9a5c4afddad1aea27", + "924a3bf6e7b14c9a8fae4d3b514d2d23", + "e4215ac2cb74453f8c067149903cc30c", + "ccd1aae16ad34ed284677a6a1830b092", + "c0321f8846a74318a10c076e09dda5e1", + "88c1cc6d02fb49cfa35692b790134594", + "db8f248b9c6b4149ba1125f3174e90ac", + "7b3e7c7d0220479fb392a9a02a73ad11", + "7e5e0f5636f2453cafa66172358d95ae", + "f62e28287c594e19b501248aca1f3d14", + "d1f9c2ef80bb4754822d15e8db7487db", + "8937a7a99e0d4343b2bbdde0586d9b63", + "fef38b59e70b48c08dc790fd392d1b92", + "356031a2c4d34638ac2aa87a7f4302fe", + "f3de0a851ed845de8ec338647372d015", + "4864cbc28d5142448e6ea9a836b25925", + "66bbacf0c7c34f2cbb936654d9c79c05", + "e7da84be9a474e67988ddc9127faff72", + "91d46bfbc4fc47a7a7257851076fc3d1", + "1d5c7975158741b686518362d7b08769", + "f9b05840ff914f6dbf54f377e008602f", + "5f3b329be84649d683135e5c9fa84e64", + "5fe6a3cf65eb41e1834b1aca4fdd261d", + "16c34f670672466a93b7345b10004951", + "47476acd32244cd090e6c8b8decb2be6", + "e13f98a9d7364510a65042d4c42e7a9c", + "a3b6180f2d8d4655a7b1963c4eba00ab", + "111cdc2f173745688517a49acc6cbda8", + "8a6c2db4387f494d9a1e03cdc38bf2d3", + "e8aad827ecb244e28427864c57b18587", + "a1ee69e7687543aa8753ad054481d67f", + "7296f952f8894293805efab5753445f7", + "75f279bbfc6e4d9aad23a0518d2d94b6", + "747b402691154a048702ce7d9ca9914f", + "b3eac46b00c94b2d8f601ddee0150133", + "1c088324b71e4ede9b18f77be0880b83", + "c570abc36b9a4fb1bf5b1aaf4c9c812f", + "18b0083e2681443f931ca8e16068aa02", + "52119881fdf24110801fc01500ae968e", + "924254a35e69415ca61b0791628ae095", + "c80b9ba7152344d98980fd4b220b47fa", + "7333335fbfb046719b08dcf3d8d6093e", + "6646d5b51257425791e5715448547984", + "49ac55b411074641bfa9a7057bf74dbc", + "fc0d8ab059474b1188d0b8e6b1c3888a", + "75c0ec7cef5a468a87736a5d3d391d02", + "3227ac9dd92a449faa8b3f6533c65ff9", + "2cbf4edf7d1c47e1bed5070619092263", + "b7bbb388cc2745799ae6b915a2b23a94", + "5f94dd75cddc42d89f4a9d7402c72581", + "49762d0776bf4b8388c03e1adc5a321c", + "f6b76042dd444cd395b76fc73e2f22b5", + "b088d87257a14d7db6b490910b4063ed", + "f76dac28f45048a6871f6fa00b28b261", + "fc9bbefee35c46a8ad8fee352273b7bd", + "bf5e4d86b3884abc93add1a72fb1d2ad", + "8ea0583721724e6f9a51764f47f7775f", + "fca2e8395e984794b04184191a7d3a36", + "b037b370d78748e3a0778be61d45cd23", + "4f494a27d56f4e2dae3a20d2722df302", + "1e2f1be6900643308b16046bf930e3a2", + "ca8451d8cb234e11be3c2d02bf1cb83a", + "eddf350940cd41e986a6b9a788633523", + "f1db0ed35b844c728c42a06d008681ef", + "ab3681b2e3ab4c47b6d85369d0d469cd", + "fbcbac1708c54a44bcc2a1b5aac12bc3", + "f47608086fc141a7a2bf05485e6562dc", + "cc947f7dee0147b49b589998f667c19f", + "ea3d4260f122455285a28072473a88c1", + "538487c7b2f949f0b45ed438923941a9", + "1f2348e1ac184a2bb79b4c2f0c4ad48b", + "bb070e4454c9468abe953db9ea57ff4b", + "e7d613c7f26a4d1895d5d6a59868fa6b", + "78d474a0aa834ac3ba13d312b0b2ef85", + "7238acda0b7843f8b3fdfa2809af5750", + "21ec96c2259d47f4b6e95ff891abea64", + "6e0c10bb0be34bb8853e580f1d544129", + "e427c1aa489b4649895854dc955d479a", + "e75edb503f254bd2ba5439b71ed77280", + "0b04b81875614292abd7916d577776e1", + "2adc33a3a8c74a3c8759745c46c612ff", + "7688dcf5b87041a3bea09b0aead0f50e", + "eeca051de9314a119bdb1fd92dfbb8f3", + "ccc3ebc8e3964bae891d0e2550c33c5e", + "b06080e80c294565a0f0d978e4c30ded", + "85ad5e2e67164559907954c3ba3526dc", + "2addc1276bb14632bb515ddfc1be1526", + "a847a835995a4d91a61f45c9e42f7a1a", + "ccf94391d45747b4a3aae700c143df20", + "88be8ad75f274c7b8da4a54fef3aaac9", + "cbef0d53d6d54a678c54a2f2e82fd680", + "c10b5698e0f4467b8cb8f113d80a0d43", + "4ffa78d0e5504da5a1f75ff73a439abf", + "9431e3895d1642a6afae054a779d9012", + "eae478d4dd8d4a9c8efb955a0c6638fc", + "82d8b3fb158e45d1bac887cf2ffec43b", + "b55b0da1aec44a9e98731ca599c1edc4", + "4a8030e3d71d4b699b5aa262ead736fd", + "aab5fc38bece40f3a170aa456534706d", + "b7d498a138f343c7910ea169ed1c2a3f", + "9c131ae49d6e4a0abdf055ddc421bb71", + "b16076de0db44f7983d99250ac54eb2d", + "47a10d446a2942ca8fd7cbb0cc306b7e", + "61386bd3024c4475b9c22ca25301746a", + "f3521f3c4769493ab4ef3758d779afde", + "3a7112396c7642df9201094a9b3634b0", + "9b470dc7a2a045ca9537304ca105a779", + "e15521857d9b4f8bb9dff28d616e85a4", + "7a2d3f89c5d84b109eda95edb952d22f", + "74a7c9e4e0d240ddb27c420dda54a582", + "08844a5d62de4134a4e1fcf95662cf27", + "65f268f13b084845b33a3a0c66f4f6bb", + "fe19aee8cbfc44d68f2af6cd39eb0b72", + "d9dba4e568cc4f6786febf6dc1fef91d", + "e5b57ddb408644f89a16ca9b76d8cd2c", + "ef9780f0cd274c28a614f1745dad00ff", + "b82ce3af0ebd465f86960db28704abb1", + "6a9fee4f7e7b41a28dab59fd278796dc", + "58c7f4dc7efd49c0b927217e216cb16a", + "6f6cf0d96cbf4e7f8c639d6e2b7c0aea", + "fa201642a05e42c0aae8baa95fb43667", + "78d8abb70cee4bf1958c3128af24f368", + "645b4a2217ef452581428e0510d7e607", + "0efbc54a5a584494bf60f77698197f75", + "f2632d011b954b55910afcd473f5d204", + "d44d80f24b7d4f4f98949ad8fdaefdcd", + "41ffcfbe76244f3498d61af0d1d16af6", + "a30fb981effd439fb046a7318f0c2065", + "fa092de08b9d44f4a8e703cd2302c145", + "1790a520ea7646d1832327c934837a42", + "f2d2bccd73fe418f9bfdaafbd7fe7bde", + "14aae91ddd4e49918597b8150a1900a8", + "fb2e16d216ca4fda948a073ad5ee26a5", + "65a7d16efe844886a006214602fda2f0", + "5e808499e8d847539e1d326a024b9065", + "144c2b57eb4549d892e839ab76f307fe", + "2ee91354914346d69b12af1c37a9ccd6", + "9257780d71774443a02ad1eb8c344615", + "a7e8c94f1ae1492497dd1d2604d9bff5", + "122b9a58bc434a7dbec84ad0676a87f4", + "ca86dbfc734a49cd9c26c71c96961f99", + "f98286e3c31248af8645963bae4c7868", + "6739184aa6c74f0eb6cf2965c731416a", + "7915140572064211b4e4ebee9d9d5194", + "6b893ec7e2a8417b8438d3dc7a81a820", + "953afa3f7e7e4ad687a0bf19a05ec294", + "65fe9878da624a4c8f87e9bd761a621b", + "fee1811af0a048e9b697f2ba84f49963", + "9dc0ed726d784d9db1c7f9f3ed194619", + "ba5949436eda404c8600aecc28905f86", + "29a88585645f49d6ab1e5664eddbe380", + "76a8557e54524a40b9dd16ddd373fd4e", + "2c887a28840f47cfae6b5dee0d11b842", + "c48ef19cfc444478af5cb9e1fff3f9dd", + "5bda8ef98bfb4a908bd671b248ee22ba", + "6fbdf6dd75ba477aa59bf7dd82dc99b9", + "df59ac5e13844fd28c84c0c279015cda", + "9769f517844d45dab438ec17d32cb668", + "563593b9d3134fa68378e6fb1b80e34a", + "a24fcb0d7d754296802027293042714d", + "bc88e6599033451bb7b8631b090a1d55", + "4e0993560f6e4e7cb08b321902d279c9", + "cbb67bbbe42e42189931574ce0d4926d", + "253266bd74f24d09bce2655f0c7e9381", + "eea10af609a2469787bf25fb9875d575", + "392a16e37bf94a9ba74bbc720dee6b67", + "e97f693110fe472da620f2174f16b218", + "8165200d339f4f2389a000c42329ae60", + "afc8c9eb7029423daa20bcdb1fe87b3e", + "cdec6d2038e04810a526f99c764af0a0", + "99787bb866eb4490817332831cc486e7", + "1b6dea328d4141b3b20459b45ebe929a", + "74237b233df04f00b2c3aac39ab18488", + "e56a1a53ce204d2087b5bf68f4bb9300", + "84a8483b74014517a9e80fb9cb5683a0", + "01474f78a328473b8d99ded65effb2cc", + "27ada59b1f02426cae3d39ed0f845d4c", + "cae4c557c949470697a86975ef9fdbc6", + "7b38959fcec2434792fcead2ad3dc767", + "c3da86c19d3e4838a8c60492393be68a", + "419cd821cb6747509bb4a6528b21d4d0", + "79436d34fb2b471e8861fa9d002b082f", + "402b8a20adc7476194d8608798866d65", + "009e2eb4f0f44faa9fb79aead2717266", + "0c8d6b4973a9486f841477e4530f8cac", + "b46f808500ff4800a6a8919ad49df7ef", + "de51106ea8284e0cbd3866931c9698e2", + "a329c478088e4e47bdd26747f06da880", + "8780501f7ac64cd0aba44717c1d88ca0", + "384821bed6fe47b79fbb775b4f36cdb1", + "5437dd4787b14759a438bd5455b5510e", + "354c05cae07c42cd8ecf2b00373cc77b", + "56e42467f7924ab582985a60939d7ae9", + "a28333b1d3774af99a6c8e4c2854b171", + "e802a0af37bc41978ca31ba845dbaab5", + "80617f1367e140b5978422f13d564ca8", + "51d1341516504500ba8ab3c807ff8930", + "09ac47c5927d4e40a05f23e6caa36931", + "e3fffdb1261f48858a1cc0f96e10e35e", + "869960324fa447f780aabd4dd3da418f", + "20e9d6a9a102490d87980caa099ab9c2", + "ac6da28eadfb4b7cad9e4826a18b1a98", + "c6e25135475f4905862f79b05f890044", + "9f57541be21c4a4d9cdc5e927bca4e5b", + "e89ce52cf2ce49ab834518045deafc06", + "d596c9a34172459f84413dba6782512e", + "f8a101205c43481e86dd9f1f3970d1ef", + "42724d46046e4bba8eec9880890dc45a", + "b306d3d3e23a4eb2838e76fac3d7c097", + "ba0ee410209040f8acd173188de0bc1e", + "ecaa22bd52ee46b1bc56c8b366391b58", + "3906dcbdaebf421ab2a4143f474924c4", + "7d067512aadc42e1802e37a6a501689a", + "682e2a90a8724b7fba42ea0a19c179c8", + "c4cd974ce4b34b229f8627b647a32250", + "7e44cfac32754fe0a2ad096e42b45a6c", + "46e64593c4234183b3b00391fc960415", + "83ab10bfb21b4739ae0fe2edb9e13707", + "e3b24e018ebc42769c08819669ad03df", + "f40b694f9a874f5fa382e0a1ae37086b", + "5ab093ab190d4a85858e9366a6e41b85", + "a3e0e0686dd841d18cd5ebd013282548", + "94bcd912320747f7806132d936e47ea8", + "e443d31dc4de49e683f1674bdca468c1", + "fc1d01c96aeb48e48e4b9048f4a811a5", + "c6694b9cafe74e7ba46f5612a3e9a7f0", + "dee8c21951e14a47b8985dc8718f222b", + "3258c42b472a42a29f07a9ada311c8bb", + "8ae346eae2ea48858ad3ec3265f0b3f2", + "c3951fb6b4384ddb8b90781a24c89e51", + "19ef6ee8569747cd93833fdd3abe140b", + "dd46240daf1f49e78016b12ebbe4e890", + "f6974311272b46598b316a1065098661", + "61ffc885367b4b418b6975d138d94048", + "09966d101d75410e8341c0a04155a957", + "17cf0dbe4435434eb6e04394fd5bf7ae", + "f6e9ec5953854dff94176c36b877c519", + "f2a69ec3fd4845e8a91b067e8ec5c186", + "c6af148edcb04a2db207e08a179e40a9", + "8fda709c6b2646a49f884d130c0c86da", + "91903199dee5422484d0aa2ea266dd09", + "7c3bcfc6b9dd4dbaa9cd888701f36c0b", + "e3774ca0bdae459082f3bed37fa7260c", + "cf95ee01636443a2b5c47b6af8a84a68", + "e2edd31463a64db19cd17db50776bd67", + "aa4b8ab41c3544edb4d9e32d80a8b599", + "d1b8914c07514268b8d4111fc8de89ca", + "a9f69f227aeb4c96ad39af40df732428", + "ca9e7bd924844a9cb0fadf0ca7c62dac", + "dea7d3e83a2c40e9a1a567d543f69444", + "40903b09601c4e15b97f8e43ca42d449", + "acd11b98bf5f47309af91b913912c26c", + "21d1679f7d7449bc8d38da537cbaf72d", + "03a5f54034b64995bcce6291b35bff71", + "0feefa2d18374ecb91d3eba92747b4c4", + "23d3b25d47f74d7d9a96ee542914f281", + "200a6976e0a94c1f9c2ec4f64e0f3272", + "1d1906bee46842c997e56ae1317d8387", + "392a6ba320564797a66f519de0426dd2", + "0b9929633fd5458c8f234eb9d415ac06", + "6df08ef8a8504504911ef520cd870aa8", + "efd707e70a8a48e4b777664d6627b190", + "a8fa5df505e64cbc8aba20ed1ac6c6dc", + "be0b7e93e66a4d4c84c2d0a13fe1852a", + "5c8f46b1ebc546028556d620026139e2", + "7f943c50ad4f4b3fbbf3c2e1283523f1", + "d0b5aa164d44429b95e2e91901b7e4cc", + "907f998c388043779ce5a66096cb6882", + "04b13a5595fc467c8e693ccefb18de34", + "74f4aa5c5a9a40d1bc3d7e11820cd66c", + "c440d78639b74e77ba6ae375f9cbf5b7", + "e1745c4aa7c046a2b5193d2d23be0192", + "d15b90299cff493e81ae29ca525a9b2a", + "f2164204caca40a898b3366b17b0fc8e", + "22477916bcfa42b7a03daaf6085e5755", + "9f30d360cee343efb5a441978ddb57bd", + "d97b45b870374d568d24d4d879e3ac14", + "026ac7369717440aaab3012d9afe4bf1", + "282ddabad0884bff81c17bc6ef69253e", + "c8d49edb266c47779ff34b1bfe9e3518", + "83f93bd4697a41d887006f8310cd67fa", + "30792308605146eb8603e17f913b1ba6", + "e70078010e124ee89426dec56ed34886", + "56343e402bbe49dc929b118616a3ea6b", + "8d444320adba48039e486446d25cf978", + "087122bc1c7f4b8998b58b650605a67c", + "5c8cd9f1fdb7476d9528bdbc0e7a318c", + "e02616bf3287455f888053205fc7b5f5", + "f10a50a72443418e87a4087ef93d9027", + "0e11b3724ac9436d8ac77c029f2a9719", + "3ad05f9e89294272b9f4d8f3b005a04b", + "327aee9f75b44c9ea1b3d5029fd45c22", + "2517b867250643c482e0e316151ed758", + "9b898f0b2be344cfa07ba6b3a83708b4", + "773161905d0e49dcb0a625ca6aaa77a6", + "1d3078a8fa49496882a66e4e0a287152", + "4cad8b729f744e48867728ad6659ab27", + "06a63364525442faa946780136b73ef2", + "683242a5e8ff43d986ed82e2ba602c8e", + "cfc49bcb02134ecea34f4fda58f00590", + "78ce9fcb771a4187a61a08492338f543", + "a3a7e637802242cca8d6a1d2bd0724b8", + "44d32a1bb60a43dfb1d67fc3bcb27a28", + "7f5b4fc17a3047e18c1ed48634e53b59", + "e4794f6db9d941609ff930f69ca71bed", + "d343ce86763d4d35aef94c2c151eb36b", + "900fc693c9af4364bc7e38b6e60a6d0f", + "a3cc0a1c653f4b9bab05bc8497d89aa0", + "7c5c9dec5c2e4ff998c386410b0e3686", + "219e7f236e584837a20b3e21a057d5cc", + "dfa91788ea8d40b0bc61b13b141f5ec5", + "ef14ff6b4cc44fb8afccd7130978c466", + "bccf270cf88d4dbfbeb1f8b8fb0647f7", + "6bfb72bd89d14a8b979f727e3366e49a", + "22c0fa4190db425ca8f6b5318f9e162f", + "7994d3067a554e4dab14e88af242f174", + "ef8ced4cbe764fab9799113f7f700aff", + "8e8cbcdbf2ab4e2486f898ebc1fe92c9", + "f03145e303cf4f2b9c0a585564b44292", + "30134c11e00c4496baff2db222481142", + "3b34354f40824c2c99e8e6b891257685", + "1a1764e896e44cdc85f27222f9db8230", + "7fe159646f814184b927ce5fddbae597", + "d53ed9dc8f624db9be4c7f3ec22a8e8b", + "d161435954f44ed7b2c18915467f33cb", + "8202c8fefcf1434abbab9b2eae9a2c16", + "7416f0f3e04c48d1af25778171256341", + "c3db152d87cd41449085083c23162f13", + "5ebe6fbe73664e2f8ef379184d144f23", + "f4bdcfe475e842d6a95972211d68694c", + "934716ccd00d4f6ba9555d1cea788488", + "68d135abd71f400fa47f55a85ac3db19", + "9599f1489f71468ba1c057724b0a167b", + "ade2b59ff37c44059433414f39c94abe", + "4da1da94471c428d8fa007fbfd34e8bc", + "321c2770c5954931a491a619e40cb1b2", + "c70eeeafd37c4d8aa138b61a45821c25", + "a73854935d294308827c9f575c52fe1c", + "5b1a44cff3d34249b8feea2052ddd972", + "39d0231b4dee432eb5a86a1bf1c25ed3", + "cfaf0f457ca244e59c746ebdd6f3ad6c", + "926a7987d9b04160916dc4f2b9f0efe5", + "78629a0cb1564f459939be058303238e", + "79005845160443a0b8a175614cf2926a", + "dd61828ea85148c48b322402016b4c68", + "51b27f90817f40d4b5a34b630dc2b31a", + "9fa76511c2d04396a680628187392077", + "4eba49b0f6f54ade836a565d98247723", + "0033322379a24798a6875a5cb2de54f5", + "58d14538b81544f7992085e90232b338", + "14116da06a65420db32b585466061d31", + "08f40fd84cd74766989c99c2afdd6ab7", + "cb3d49a6261a4913817e8e00d6ab6e43", + "327dcd11fd214e6b9d44d029beac358a", + "5cad65147d704e79b047518f2ccd8c1d", + "39d8bb144bb04bc68f5c9ba4adf17273", + "b8f7f6ec414e442892482811e8630e94", + "a2d4d0fc855a499999c49eeb8053c49b", + "e38f5780919946aebf43605d41193c6d", + "7f6d38d1e9b84147b5a86d4f45a2e610", + "ce3274a82ee74249901010d93fce3853", + "c2db43f821b94759bc1473457e259172", + "6b5f40ba934a4e2ca3a6e8419e96eac1", + "cc90bbec9d75457681e56ce3e682913b", + "c51b8a7d88354d8db4501eb6cfb0485e", + "d6cc86b3e48f486887c366a452ac9ed3", + "2fdc25ceda4d4e4487697cbc7c218aa7", + "d18b2372cbb44c62adb627050af6587d", + "bac03ae66a6344cea37f5a661838939f", + "b7294b6b1ad64cc6b624f1185be8523e", + "64c1b93f2465451b920176b7ad676a95", + "f222d8c16b3740ca98c21a5df26c8b13", + "de59af6a151540f38ae352880c4c3be0", + "68252b8d76e74206bcdb266606c3f840", + "e312138c4b0a4375af5daa267213dc8b", + "810569e6151f4aa0ad42c4d6330fcf85", + "d9f4807850a34eb08ae635412dc5b3ea", + "2a2adf2851034a5d9647a85313d82a3d", + "0a9d9fc1e45a42719b1b215f59dedc55", + "31259cbbe1f047eda02c2189f428559d", + "acca44bccd9e4d82ba0e2ed0eb1e478c", + "7accf73c2b754ec1a969af691368c270", + "f5697200004840e499702cd40dedebf4", + "5fb3005aae9446c6bc12dd241194a17a", + "7cb872b9fc9e4ef9a6e0033fecc161d8", + "29d734a56a4340048a659bccedad73dd", + "3641a0f251ca4852a2441c23fa3ebdd5", + "b18d073b06d545c78940964683e28959", + "ed577ce3d4db49a283924c2ec27e65e8", + "92bb9f59fd9046b1beb9dca6b21489e2", + "29ecbb4d17c34375b007a3ca4f2f6586", + "dacb223985354355920e478b3809e089", + "cf168933583e4716ae79b142a569a4a1", + "e8498e351ad04d7f82283f029ba08d9f", + "1c51f972ffec4aaba54f5d04466d858c", + "b4b3e046469749ce813c95f144276640", + "afa525f9b9de4569ad72ee0603611161", + "4b53bb73e6ed455d979679b5b1d8c3d8", + "72fde976e8ce4ebabd7231661ba957fa", + "23439ea505504a458f403a53bb8d3de2", + "5a3f53a9fb9a4090a30688c591f070ac", + "ea9725ad867c42a684bc58d21039e8bd", + "39247357f19e468c9863f5370cc03974", + "2060a310cda64ca18db33b14b1c1d521", + "1b63dd4832144e89955ecf2f70e8af4b", + "01c7918e11c646b4886d43c45dc323a3", + "3b72e8a8c97d48e0bbda1bd488b1bb20", + "c68e6c50b4b040d780e3c137965a97f0", + "ea57a21eb7124457b13b1a9a5bc33625", + "6e22216e113641cdbd0d0588ae4dccce", + "25fe9c42f0f446bf95ef9594cccf9610", + "11773c2a6c494c3f80492e3c232ae884", + "8feb2d0355754e8489442abc5bbfa1fd", + "9817b60dcd404fddb5ce16112fec2fe4", + "5eee9d9172dd4738adc6a1916f53eb1f", + "8903ce6965504b1c831c2eb3a5e2c151", + "a21d69b84aca48e094df473cb5e879c1", + "18d738a49a2c474281a2675eb35de9b9", + "227c0e5245e24f46b700339707c2410e", + "f1a1360364434bd0bf91eb554e7852dd", + "5fb6ebd7cd6a4a959742bd36ef781f3c", + "9090813964814c8cb34a63c63441c631", + "3f2d4f5b962340b2933012e1bc634d88", + "8ca72ea7475241d2a47f568ce7d1b18f", + "ea9c0c4d033a42bab8768294b392a85e", + "cc284b0624a44d6e8318a275b9110590", + "5cc824a22935448bbf1c9f5d13249a7f", + "115d7246cd1245fdbcebafc8b0310626", + "b63f65374f0640f69b3fe7a95e2cbc8b", + "cd364083da2d45bf955a856e8e4a8cd5", + "44b45ae8126a4358ac49321c538e2c31", + "bea8441c08d94366b96b53775391d8e6", + "ea40e26803d045f1b93f225687b64797", + "8ce88742f3ad46c086929a4e303b5388", + "7c4a25ac913b4592927cca87792eaa11", + "1596b8cdb2ce4160a62556a2419e5b95", + "28ab910901224743a610788e99112025", + "0a597869a5fe4d07b20034a440384fc3", + "aed1aa465fe84ec5ab16d6cdad1ff78c", + "250966247c42462c8b69d6c9af668c29", + "884a54d5697e4026b69eaf1ad51f9c58", + "8a83411fe16b407a84fac1bfb4826221", + "e78ba0c19f204c778ff4c6306824e0af", + "9affa340947c4ec6a2712ceff577311d", + "5a15a88a9dda46ea8728fbb1a5e38f7e", + "ea87c9bbbf4f46cda162b104ce2849e7", + "213e9c4168c44f138c43671e5d62a2fa", + "e54ce8520d8c41f1a042636010e73de0", + "115202e0823540b0aa1a76b4f510a5c6", + "7a2bba14422d42549c1ab74de258425e", + "a5e397b1cdf3457a99573683198bdcea", + "a2153c35659347879d1ff9ce5b796100", + "78b8386266f74ce39e066366c95b069d", + "fb777ec92c2a439bb1ac45c3be550f7f", + "009795f69072466e9a71b70a560ed2df", + "750152f4c0604191ab9cbbe160252c67", + "efb1a7f8606b489da1ce48f09563b32b", + "559abfadf5a542f0a18b79252596181b", + "8804582d562944639552a8fe8bf0de50", + "dd20303e82654cbd91413da0548ec608", + "775e22047868419886c3f953f3d75c34", + "88be308975644de6b6d188915294f5c2", + "135990262ca441569bc76dbe13dbe6ea", + "fce7d5c2b90249f0954f70348d0fe388", + "5bc467cfa9d14408867db9af17e128c5", + "76dc9ef9c665487a97a5d993fd26c468", + "ac692295b820429d8ba562fa17c7b8c3", + "13ef8c3671204fd3924b0db9a05b21aa", + "418162498507467eba2ff5e9e865fef7", + "1060361948a049489e30ecfd98d0fcb0", + "7a6c126ee76c4c10bf405494a3e19d00", + "17e4ece66d4d477f942c0427ab45c8b5", + "f015f4de3fbd49aab0cdbb68245118f7", + "9a4bb1dacdd34654abc09367da5e03a4", + "4058a3ed739e4f9f89f49323c7db4b4c", + "50ef251d19cc4e909f8369aae5aa901e", + "fbfb1afedd524bde9c6824c6b94ed709", + "aa8d48a70fe04bf3b89fef4bd622d056", + "5b9c84a7fcae4406b9b4ec29bd6c4a45", + "0b5e5d259a344e6bad123a1fdcc4e563", + "df7e33c31d0d42d4ae7a5c7b009f39f8", + "628cc3b0fb2842aaa423e95922099c31", + "3308de942f37418e8f90f104191da0c8", + "15afc2696cfc4755a239df24690b2204", + "1bcfdc065f004f638f881b8f91dfeefd", + "f1d057e664dc4970bc7d52398d8fd0b5", + "e35d0a3a3c854692b7a41ebb50c6486c", + "1b06bf6196614c0ba75c80f577a1af4a", + "f3fa166ff6bd4ffe8133f6f6eed74d64", + "ff47bc6e5ac444af87f80c413170d42b", + "eea667c893474b42a16eb7a43ca28249", + "8f0d37fac13b4ae59f0ec2dae034fd3c", + "e3b8f46b36f84fde8bee28e3a02fa089", + "16e46e4c4d4b4ed3901bda03002ae827", + "de78294dd2714b99b68a84864bdf6354", + "fb7428af230c4dd890e73f54d2cdbe7c", + "286cb8ba408547b9b5290e543a01214d", + "168a74c4fe6e4b379906806fd1ee1218", + "c23be007c1a649d9a2082f54af6dec7d", + "2f584f889a0d46d0b81d26dfab5105fd", + "b80bd27b5c9f40e19b2d8ad6565907df", + "1c544dfbf2344889bb7b91edbf71502a", + "e68232e257834881991dd8bae5bd3747", + "42f2e5cf65a3440e8176873bc24d8d57", + "cb6451947757498aadd36b41ed8757da", + "227d07965b744bb181e33d1e286e1eac", + "ec2c6087d4824211abc827f2a4c2b578", + "e8ae80bec4884254823832d2ab2676dd", + "ae748d12ba0a4a618d27d11345d75a12", + "cc35ea9a4a0640eabaf21bb54114e76e", + "f894299417414214b87993f031259e37", + "c2f9b76e6b184138a23dfda89829fa8b", + "21d255f040b948a2b2af88de30c7b43f", + "4d105b45386d43d0a78d9f0291d14e8c", + "f8ca6d3c18f2455c8186dcae492c7816", + "c64c45bf1d804b659b37693d4284e867", + "e73675b59b8b4a6b818487622dc330c1", + "e55aff4bcb694de3b2d5fee812d8e462", + "dc738bd046474bcdb3ab71137d311234", + "feedba7ad7ad4416ad6abef2a09dabe0", + "133b0ecddc364b4d8a997c02032b47b2", + "61c37ba84ea0476ea39bd3320c771baf", + "f91c7d2ed9824ccf8b52f8e99235dce9", + "2ecc36c9c0e04db9a962480950df119c", + "976b4290ac7f4a6dab143572d457bbab", + "364f1208ffaf42db9da456e87abc7eec", + "7194f4ca9393451492b414b060980c2a", + "b6a3345a07774bf9a4ae41a0fd3bf449", + "ef60e03fbaac450ab664947ef72eb448", + "db83348d6d334155b031b905b1d9e80c", + "db215ccb1d04490dae6de8e2c8c9707e", + "1b13667bf6ef4ff583db26b608b0c50e", + "3217e8827dcf4e5f9ada995ad883b3c4", + "d40ef01e55344c4f87ee816b6e1fb6e3", + "e552e92f8b064ada9a387c259ae32c0d", + "e7b71462d0734fba998b06c1a33cbf95", + "d0d490b69fea45cc93151a4b83e055ad", + "35b1b9b094974418b4954d489970d3a5", + "e9b769a750b74020973211f39f976037", + "843000ec4e604edbaa76946cd1a89501", + "33a68c221d3f460cb1cb1f78b9fe0bb7", + "92718bc81004402f936c4e2b7d41bea5", + "636eacaa081b41e5ba35601626893a51", + "df1264b0053e454dba0e68f07f3c0615", + "a3cd551df1d2452691bec6c8476184f4", + "6937a8e542934283828fc2a553dc7de4", + "cbf53b01b1e245baa896d7c6af69f187", + "94f27a10cd3b4318bdeabc38f384c41c", + "1ac6a371fa734f77bb02e1d6cfd26cef", + "483878b469c545e98d02d06130874f83", + "47c0b4ceaf3c42908f96e54be3539392", + "99c0b4485e9b46f892cde91372c55757", + "aba19eb66aeb48abae81132fb3517ce3", + "c9405115a26344bb810ab1eb31ff73bc", + "417915f419f945c8a424b2a7943eb25a", + "5dde5a7422d540198742b55e0e01dbc6", + "4c702c17ac4949058ad47b3e13706e68", + "9273c66886cd4792a983263d2082da82", + "c604ab4e797643f88fcc1c899e8cd419", + "de4d37e433c0467c83e540717fd9ae07", + "5bfad520d63047eebae4559ff29b670c", + "5c32977055dd4ee49b19b179f212a54d", + "742d3d85328a4e898907ef39a6bf75e5", + "1052ae995374454f853a3c190d4b1965", + "f755e3f9e9e64c8db5ba49b0c821bf36", + "e7c052f0df7044569b7f89d4b869b13e", + "0523afd3e60c42119a726fc6c52eedbc", + "208947889c8140acbbbfaabbc671067c", + "8b647d638e7e4305be0ab948d67415c1", + "cd33432aa12e40a28a7058fb289c8a7f", + "c63510b103fc4954ad36a84d7e26e7ec", + "0fc69683beb74e6e87853e412d7ffe32", + "b92aa14cbe5848198ccdc9ac2396f219", + "be237d4f0c7f4b84be5966275efc5c55", + "b21647005ac64c9f8e9a79a5e75a7a0e", + "1ed96f964b9d4d3eb9accf2240dfabd9", + "4bf1ba29222b4e9dbc3ec0e2535c6a1e", + "262b0aecfb814c2abab3aae1d4138d44", + "ae01fcb32cc34896bcaa3827abdf36b3", + "059ddf8d773748a0aa32c778897e711e", + "fb867db8280f43a3baf4affd7a33bfa4", + "061e22e5717f43f2a4e5ee324d2c1db0", + "9338612e9fb54a79a42f9561fc22b697", + "00785dade17c470c90a14c90b75b896c", + "7cb78813cc7d43548a4023441e4eb47e", + "db6a01dde2a34070a3cd97f09069239f", + "3446229dce1f47528fa871cc7669136c", + "2a96032b9a3b493d84a039d3d03452a2", + "b3b13e26164948c69910119558616485", + "5b16cb03f4434727852fbedb86223a2e", + "e49ea080f49e4913aa02c48d096c45cc", + "f25cb76a65ea4d88a92dc4d994cf4094", + "a6ebddcfff9a4c8a912551530ebfdb45", + "df3c29202d7c41e5bf68e375ced35b82", + "9f38cf569e584667aca4c86c31e06711", + "ee81eb66006b4d8980d0cf9ff6304b69", + "0add92989216419da76ee607ec6e673f", + "b690d85c01b34e0cad6ad27cb582663a", + "9819dff941814adc800633952503dc4d", + "d2e28f4e3f48430288aad8f7dc3fc47c", + "98933b602bb4468d981a64279531faea", + "016aa8df34e946faa02a145bdabe4b48", + "7f7155d68356435e916fa4b80b4468ca", + "401df6b99a4142eeb6bb1c02ef09c18d", + "0feee3cfec1142499c2c6ae2b82e443e", + "641f57694ed34d93897713f71ac1b89b", + "deba60951da34a48ba91631c6f67b6a9", + "e2be3a9c003a46e192847e2b2e7b4dd1", + "5ebd3720da554fa2a60e0fa280c5ae7a", + "aadc2414af8c4e0f862bb18a9d81f774", + "d8986fdbf51d461aa1b71d16297d6b19", + "7760315d38844ea8afeaa5e51d4c6e25", + "8c564dccf3184669880b729e36541c3b", + "f32eb13ae3a345ee9f457561963dc0d7", + "f9dc30b767e74ffbaa8a5ea36d1f43bc", + "f178d4017b5a4000b92d37bc716b0dac", + "9912e15f89e14b8e892c5ad180ba6fc4", + "7b55ae54ebc94f108b46939d513dc484", + "7c18493e26df41b99cf4f5e350cc1d2b", + "7f7d9831de524660b6e2428ac19a674f", + "89038877d06448f398c066b1b93228c2", + "2f47ab99b8da45e2b343e28de4945696", + "5c590c42fb5e401e8add8528ccd6e900", + "4e719b26038f4011a59f4b901c10596f", + "c5831340f01e4c7b97f4913aa85cfd1b", + "9ca1b6d6ad9e49e88cb442f5ad66de97", + "ec8855a1281949109243392b04da0484", + "bc411f6919d8457eb953a65b7006c8d6", + "26e1bd2ea5264001bb1909dd183caf82", + "b4853f8e7661447a87acc16705f61364", + "f9893c3dacdb48a3bcff0106ea5a5404", + "5e449a73f9214903bbc77b03fc423b62", + "c0ad735d84e749fd80dcd2cc92575862", + "1b22cfe60b934d4bba8d256093d023cb", + "cf23a572a78d438f850fd273ff1b0c73", + "686d56baefae44ed96352b042c658bbb", + "5cc7a99302964b229921aa445a1fcbb8", + "f085813c5d1446b0a65e1c734debf8b0", + "7c25d215cb2144578e6665a7bb79be83", + "f9ca6bdb2af640e087112180bd1be152", + "695b9b8ae3354368952ad97c66ce3cef", + "2f69495ce4e040878237eb7f46e7029e", + "9252141c5ef641f2987be9ec21a51446", + "b497684568844c208a6f6b827b9eaa52", + "914d1dfc0d2b44c49103da81f230bfc5", + "370f39d807d94343a2873a4e55b35435", + "edeb4fef09454706a669282aa2c06a10", + "7229d7c7b24e4cf8a124456625a4d1df", + "e740b561cbaf472dba969724a0049dca", + "2d455ae454514f5fa6fb3bdc7927fb90", + "88b957c1af714a61abf7bdaef37f9e0f", + "0ecc7556fa024ebb93f29f571fb5dfbf", + "d2785b57e7da45858f2fe8bf4dedd68d", + "14531e18038a404c8653568975ef3e8f", + "fc4e87ccad02448893f86449fa95a243", + "ee8191c1c75f47389270cde684872a2f", + "a13662e9a21e4841982903644096d34b", + "da5be1985e2441b5a8d144127fe6c175", + "48a77bd947e648e8900533bfaf76e78e", + "7779b4ce78644c78bdd0ad7e4f0ee6bb", + "5849e74c343b45f887eb8657032574e4", + "1dc0ec53ab874bc99c5930c1a87ef562", + "c6d505d7002741bb97170d3c9462ebd7", + "1975fe81c67746b588dceee03b315659", + "c3f41bfe02274a8e91a82343603553ec", + "fbeb7c776372466daffa619106e0b2e0", + "5e624099dc3940508d3cea32efae77b8", + "1bf586d0f6ee4a9f80215ac9a4b11ecf", + "3d2c61e3e7ef42d4b926016c4c91aec1", + "3883d1fa36dc4030a9754366e6d35774", + "a05dbf30fe1d46b397c91025b075fe05", + "773b1341f6a84f7d99cd0700e10b7a55", + "b9cbffb2c34f4771a6490c65886667a1", + "1b6a3b856dee4d8195152cce1819a13e", + "f7ccbab194664ebd85593b9ff556b1e8", + "7fd564b3442f4e72b233b8810ac028ee", + "d7e45db19de041419b28f95df0bbc298", + "f5dcc79f9ce8448da69d1fd4dbbfc55c", + "0857f2ebd4fc46769a90e69225a558d4", + "e1409dcd76b54c0a8a5dcecb37998316", + "f2a5059dad8f41d08a813c864ca7c2d7", + "f1798d1366fe4d7392be90ab0af31143", + "b9f07394ae9b48c88be3b321cc655d98", + "17de70af186e4a35ac0efc7cc8d600b8", + "48557913856d48bab083a0fa05019f69", + "1ef567278bba4db68ac5488d6b4bc851", + "edb077bdea8446b89b9af51cbae345e0", + "7267e0e238744adb820b0f13dc0024e5", + "7a02abc1ec9146b3b3c3dc05f76dae0c", + "6e127bf8350c4ceb90bbc5eefe4d3e4c", + "f1c16f4f5400430097e004f4f59bac09", + "9166b13b6ae341f4bfc093edb71d74f4", + "898953e58e04438c9bb9c3d8651422bc", + "3a0d7939f81b46d5af0ef2c96553f3e2", + "bfece1644c5644d5bb996fe90ab2db16", + "10e6b7479e564950aef2f6b6bdf5fca5", + "18483cf78d944cf7a4b88986e71f103b", + "a7e3761565e54fd3a5c8890538c6e3ec", + "56d77628e4f8461cb47f3bceb610397e", + "ce26b3228816472fac46366a560b488d", + "6acbec139ac04331992e2b60e234712f", + "ff065f1169c94a81acfeb5f80d1efdfe", + "c649a680bfb24066bf53c69282f31a9f", + "b78442de2bc542ef9393608c40664aa1", + "296e30630e5b4b75b2fc5c530ce9d69e", + "4b50efc9dd5943a780b96d5f25b75699", + "2af94225d74c4d9a89ca1d1d5a4fc612", + "0ce3b89790954c499f9dc67f3e3a621f", + "6f44ef05ea5541eeb1ea8587332185c2", + "84b39e6893e84ec39dccce1077d694f7", + "98be3833c45f4b00ae244e2bad07de8e", + "4ec0d650afed41fdbb662e7b88b09d0e", + "801322110e974df180f157dceccb8ad6", + "ca627c57c58e47ea8e4f120052f007a7", + "6f91e6c9587046c5b502b01696e7bf63", + "2190b03d39804f34960aaf6fcacced30", + "b4cfcf8211494def845b1d00f2688e08", + "f70db0cc60374a54919a4f9c6ad1dfd5", + "fd87b71239304574bd9f8796c41de05d", + "710ed30db285407c9aa1dd56421e6f87", + "0df655fd63e44d038d0a71569886f37f", + "efa1c4c1f2a947659ded2e61e20eff31", + "4af7de2edd634b6596b167c56eb8b8cc", + "2e4c986248ed45c78cc751560bedce55", + "03579b4e630c461cb5136e57f321da6c", + "33d70246aca544cf9ddae738254bc1ef", + "eae692466a7d4cc5b494839e55dfd641", + "4cfe34c552db450993724fe25b22234d", + "a6fa0df7d7ce4022b7202a9334a59763", + "6ef95979598942cd8aa91922f35dc28f", + "74cb411e581f4de38ea45fb2ce4a5911", + "108c5ad03ebb453a8b1c064a6d9ae271", + "fad3c3c733f04bf599233bae74921ca6", + "955cf512b86c4a799aa3ef391d670e55", + "f3bfb333728f425aa67b8d20244c46ed", + "7b3cdf65ced047e496b672fb7560964b", + "b618ea230ab04d9c8804eebe766a6426", + "048e1ea3cd3c4903b73fc65f6d2489cc", + "01c263a259ed4174bb345afe24859584", + "5c42929b86854b899aa2a7168bede0c0", + "2d69761f6cf04139884b5ce96cacca70", + "eb8efa96966b481d8fd254e2c1379cee", + "9063f044c2c541bdb06dbd13e925480b", + "00d56831f9bc49f9a668f418c1af7558", + "e20aac44e5de4cbd8ac8cdfc4a78be3e", + "0483043dffe4441583b19642492a6861", + "1e21399e4c674ff79832f7fce006b285", + "fa5315f553564b5e937f224c8c2c1423", + "4125db0e838245a58f8a92bca125b856", + "0ac105eb165c40aba9dab37c0615bb17", + "fd31c0eeda8f42adbd8122921cb75f48", + "b542adf020a74c41a8cba1522cd2e568", + "e037fa6d608241d2bc50c324d81b88d6", + "1de6d3ee67fb4f9fba7a4f6e42d1af2f", + "b52a83d7ef684da6be0d4a0aca818553", + "176d61750a5948779b24d7e93f022b8a", + "4314b15066c340a6a0b39979884ef077", + "f76d0698a39548088d5192174ed3ac4e", + "25ca9426f4af4eb3b2f8ad379bb8724a", + "b07edfb826db4a37b0df3bfa3443484a", + "fe97d02daaac44bea0caffc4f1cb93a4", + "57b03dcc593448aca1d64c8d166333ce", + "4b27628be0804c0285d0b13dda025a0d", + "e34e512dbc304ab9b7addcec376f6226", + "fbdf6cd044234c30805764a749fc5506", + "82bf19f3981647c48f59d780779aed13", + "f3ee2cae618d4ed0b9cb9ab6915357ce", + "be365d4a32184764abc4634c1280e6da", + "1ded9f27d0ae46e9a7f4c871eef7ed8e", + "e213da3b642640b2bc34a9ff8ae318e2", + "031574a75f51411b9d73c386893ca7a6", + "0710b146f9e44170905a45a85621c02a", + "3e0903b811fb42e89fdec0fe24212047", + "55fcca49917a441282a22cd97299afa5", + "0636415305924d2f8f31de1b038c95a1", + "70176804007845359a9d17298c4cbb9b", + "002b5dcd1a7844b19c7ffa63a9b23c68", + "b73497d937774c96a92f05947c738b9b", + "2ec41800c54f440cb8c9393618b2a9ae", + "4d1735ef095044209e9ac12e60aec30a", + "4b47320168ff4057b5f441a2e37821a1", + "e72f3887c94a414286bf485f7139488e", + "aad9ec8b83f244499dad6f663f1f952a", + "eb2b9ed28abb4d05aa8e3fe60ca43f36", + "fb4c5d7b30cf444493062f4a6d24a587", + "e12e11f6fdd94539ba6215d0f3a684c3", + "d5583c4a750b446bae251b3a4f3fa88c", + "87d5bce4301c46d4b02ac318970b975f", + "ee5604b40e6740c29b5b67a384994d67", + "cce39de2c1354b2d87a6f70f358a8f3c", + "8aa5cf5a69264e07b2ad4a8f754a824d", + "1cd383e97d304d509109fe737a994e2b", + "56b12166465d4f18973849e7536cd532", + "c1f6de6cdff84adea0b483af8a4d4362", + "170730f3a34d4650b89ca6090c8b9c42", + "9939de46afe2412cb291eb313f26951d", + "cedae25d954141089bc46d297970e46f", + "91535afacf004ff8b9bb5db7c1641441", + "abfa138c9cc6425dabcbf6325d8d783b", + "7e7309da088c45ba9e1f72b75ceaf043", + "b81e2038bdc24e8a81a5a0e6e5012eb9", + "5fea3ad87a324c68905714115684fb35", + "e2d1acbdc2054a21a2360ffe03052fae", + "d3386f9a3a27417d975e6002bb2eef11", + "069fe37a0f144d8387db9b4594c501af", + "4ab861f340374326a9ebf9fe8b2cd2a2", + "25f100bf51094136b3b4d3787b2f61a5", + "5d546ab0efde48b2a292845b2b32dcbe", + "943a03495cca424694aea9767fcf3f83", + "b2119b2c326d4ef9ba42c83a9c711166", + "2e97657e4fd849529e6184558f9670cd", + "bf2d05741b244d34a86d0fa6ddff3cef", + "f58620b073f848b0be2099b0a382df4b", + "7101eaf08447436bb5d3b26fe15ce744", + "0420bf1e2ee446cd8e3537484713e78d", + "7ce9eb67a5f445c5b57bf9b4437b342e", + "0a280e2b64a84fd387667cca221ff255", + "e1bddbcc07f74d81b5555cde25e2017e", + "14df8bcc73e04921993371a0849ad36e", + "deeb1abf8a6b4c44adac7c7589da0df8", + "ef9ab39abd2946a29f94a1b670a9063b", + "47f1b331f0464a408afe100506115a55", + "991270e938174770bdb0bde23d9b4e82", + "8d50c19e138b403e8b2ede9b47d8be3c", + "5183846d201340aca58831bd2d3a0819", + "f8531000e3db47c88cb726c57b9d8fb8", + "a986ab66368f48539067bab12d8d2bc1", + "9fe6f8a40cc64ef8a84fb08e4a859ab0", + "bcf815ce791249b1a70f1acdf074fb4c", + "e7f6fa23b4a24fe1b752fefc00aacb78", + "7cbd44a3141f4a1f889249c3fb1efa34", + "052449f0d798499b94ee30c112eda403", + "23c778c563274a4a8f8b8cee580b212e", + "d81bcea0168440f486e67b0ba9caf95a", + "429536ff8dd84e538168c17ce6e82e28", + "1f1798bb86fc4cb383969bb1f0060341", + "85ac889151324c24a9b696a7b905e185", + "c2237b0373d146f3a06240e085d02dd2", + "9c127b07958343bba6d9f0fa41578272", + "f5008636251d44f99e1187f057df7d91", + "b2b5272e7ed5470ca8652b6923d9b396", + "1756a32a03204b468202ca30aa02e4d3", + "f658c352668f43529af6bb97973b3d5e", + "d889023d07e749fc9844bafc5c7cb2ea", + "dfa2855262b2424b8da810366bae9ec0", + "b04d0d9481e94c689da389402471a864", + "4174b22dd5234634ae9356da36b6b42b", + "a4863d7e05ce4117bfda48ddf6af8af4", + "02010e17a28845cc921858cc24ece163", + "dee1ea44d01147a786280b7fa2a4305e", + "50a023f83e8c434b8b908c4d41c0118b", + "ec184a627685495e9d0f3a370dfc1422", + "359d614e46fb44809bf6730a6ff92f2f", + "d44f838c48b748f3b51eab9c830193bb", + "5fae226e54d24820b5c62ac25ad062c3", + "4b6ea1dff1474d4a9729b916433ad334", + "fe6ee5b4aa584759bc157e2c8abb1aa2", + "d605550137dc47a18cc726ff4f2af2db", + "497579124e8e4d18917d836b278e5132", + "98ddcab19b4c4a31910217efd5c70592", + "729715b5365d468391b2fa5b98b63c5b", + "f51f1d33be804a759207152154ac7714", + "f295dd1a5b2a40bea76efbe8234eb0cc", + "b8a847d396534a00bbe2269894d19aff", + "cc77c6e2f0364c8abee4b411c579f854", + "e69e99eb82084c2cb45b35f21f929d49", + "e230d530ae1b4d74bb62f4d034b165ef", + "7b086f68c721467a935e7d58a89dde04", + "13e4e3da76ae4750b9d7e6df88530d44", + "60c006be9a834849895438f15d4927c0", + "883e4c1fdb0b42b48467191616b22edd", + "ce3c0bc29dbe4b07acdf068c18d4f603", + "d9bc98544b9a4e5a979df1512c269a09", + "fd1fdc80e8284306b56412e3261d1906", + "46dba319bf184aaa83352bb7d187ebeb", + "ef4d2daeecff4742b6b3bd92190f0adf", + "c808579607074ab680b6506b9b127367", + "c889035e87494847b2dcc0a02b824618", + "1cf0d8795cf142739de1948f30a18a43", + "e9bb977320834368ae71b10dbe913c0e", + "fd073296a28e42089e5e8a59cce8c65c", + "da957a350433461c9924faf08ec76dea", + "1b3eee421d92472b90c7a2d8ce33ce18", + "63c49ce5f17d4c4c8311f6c2d62a79bd", + "bf7902fb64644da3beb0ce1fce07f4aa", + "e90d9945f68d43ef9e04157eab355f8c", + "009fdf73a9c54e7bbd3a7d28496752e0", + "b6f9128ace03477fa18875bcac5ab469", + "ffa3993ffac54c0595bcfb5b1f5767b3", + "48571132f5e2443998e97fa3a498d816", + "889f4a84f24144c0b1808d4b59c04d82", + "0c79a8305c524872a6fd55f92425eccf", + "a39b73078dca4cef8d87dcf41623f3d3", + "3964e19915c34da29815091e1d7a800c", + "52e0455b23784d64a647b81b2db8f609", + "9e17d5737d564d2e92338c80c8324b78", + "f70bc7c1ed74430c867f320f2e8e3cef", + "29cd8378983040f2bd4f2d9c823c1fde", + "2852ac8cf5a04333906a76f163fc0a43", + "adc2c82a953c47c4b197a8a42da12460", + "f3f669cf39b5401d92a573dba91f591d", + "4e59e28f19d44d5f974f80f0a9ee354c", + "b65cba53888f46a4b3c363f1836d0851", + "a66f6c9eb3c24a3099894c4d91f68e0a", + "e60dca44482045ce90a71946888a53b1", + "5b7e913a186b416c89df9313c4f16c7b", + "56896e159e9c4a1380427fd0946b6a81", + "eaa08a9b86d745558ef18a0186766d44", + "dbe182eee98144ec8738b63802282354", + "b44f96c88cfc4cf1bc196971ef204ac6", + "0e820490bf3d409a91a0d409b2298290", + "e579fbdd53384c198f502b905a567614", + "c68b01fc33a7464599d47915cacf9abe", + "0cdba3bcda944c54817d0c2382be89f8", + "63cf54469f65453f8db374811a83863d", + "dec9e912d6574c71a23a02bf03022b27", + "0f4be86441694633b42c764a4574fd41", + "08a3baeb2e0847939d53027824de5a49", + "aea8ec106c3b42d0b421a799260ee15d", + "0297ffd148ff48c1b02d32457be0387d", + "28b7dcb472e5445ab944f1e40b78b36f", + "4ae15c384cb1446f86f0e0b3c019b443", + "06b1d64acaf14d178dd8b6e108a1e9fc", + "7c85cab92fe242b5a24fb2d766fc1e12", + "f049d3b5d81b4a87bb4f9ceec33ee305", + "9fc1cb45c8404517aa8cee3bb47c14fd", + "00124bcf3ca3463fbe05f28218cc0f5c", + "a27409573f474f14a97268562b2e0cf1", + "0b76d30d697d4488bd35dee187d95fac", + "bba3a744c7424ca2886d1e8d29cfdcce", + "d90fa437f67b4211a8231519e4619b2f", + "d1758f279bc54631b079733b6a4e96ab", + "dd5f87e5b8644111b8180515eed4c54e", + "faecb357a28c407c919ae129412fed99", + "6c479a2d5dff48ada02804c446561ad4", + "cb680d38bee541a5ab4ef331e323fa2d", + "99c3800812b4445d9f14c1555668c784", + "6f204b258be743ed8fb2171e1e65f6a3", + "e1ca1313c2734145835ccf8ab269b297", + "01560b532c574ffb8fbd74d99fbd369a", + "f8a4d1ba05bc46ccaf32ed6cd7e40ce9", + "fc6febe9b92c4da3aac0dd4de7f64e8f", + "59e74a6ff89d4017bb707840ee9a9d1f", + "1cd4eeeb72ab449bb1c835b6bfa85360", + "7f526263e0ae48308447f5f82e1df9f8", + "7fc9094e39504a5db0584cc31a626e2f", + "4869fef39a304c7696bb3683179637f3", + "11ac243d6f294da69ef9802e7b51fb8f", + "628c8f40cdaf49a5838cfa24503d7890", + "ffbcdbd186674294bd3aa0f7f249d45c", + "abb8d6205e5740918422e5bed03626af", + "9cccc2bdaeae48839e93691df30be3dd", + "8003aa8ce7fb4019beb09194daa87400", + "5fbb7784bc0f4775bcf2bf8ae2b47c42", + "d016234ed97247f6ae916bc386999d03", + "5c2d2c485ca647339651c995070564f5", + "cc00b5addb584d15ac27379b6e5d76c0", + "f323dc9f6b804e8c9b6bfa9f781e4241", + "0e21faea18a1471796f67de902818b8e", + "d342da714c19496391c651a663fa1927", + "41a7761ba5f14f20904d90bb042fd5a1", + "a9bdb32efffa4f7cb7f98d4f7a877b5d", + "a5706ca3647a4513b86662787cb9efda", + "ff4adac17905436c9f244e432e1200a8", + "f2536b8f11b84cf3bc3c5f72cd887aba", + "427c72ed0f034229bb1795faade5eb5d", + "b1133daef8eb4bccac700a17725f2c09", + "52f9daa141994477b68087bf6a84b823", + "56e2e01977df4650b75e0926ff235d34", + "075f4e0645d84bcd9b661750b253310b", + "d84b623ca339443ca622b1a414ae36ab", + "7820d3725ec94b759c633eefcc30aeea", + "b8309b5acd1d4530ba07c68fab826adc", + "21b5220775af4bb6bad570d6d19a00c7", + "6e890bcf15fb4c889de6ac1773327978", + "7352393b15e742518d4c1df28fffee3b", + "7edd4e53fc174cd292b1ba8a6fb1e871", + "06ab2df0a94d4303a97ced64fa019e1f", + "e3e832dd142d4bfe8ef18d33dd797129", + "e028200c278246399b15e7825f750a9c", + "ee48799fc98a45139d2e258537a9e1a4", + "996c8d78905f433183ac368086580f82", + "ca85009e578547c0a4f0872a0b3363c2", + "96a3fc052dc94c07b52109d71032fc89", + "eec133d3b1634a4b94a294671cf7879f", + "af0ef2bfddb54c37b7c3e6a6967ac05c", + "16a4e4f583c94fb480eeeac033fef336", + "4a2f69beac63461d9010e3b8f2b262bc", + "b7a0536506794bc98449419d41182e48", + "4ecb4b2226e24233b1806925897b66e1", + "10d9ec53b8a140c7a7785ff54a7ecc22", + "cfa7c84140294a85a10db653c89100ad", + "e8af1f52ea6d407397e901df40e0a72a", + "b4449d86e361479194c0b11e5b88a8a7", + "2be3740c17a54af2ace945e1d265f358", + "ab882baa73e64bc3b51dba5ca0742c41", + "8d6cf9bf4a784c0b91148ba6a993e2f3", + "38139f9121a54a7780fea927ee62f4ed", + "85061b53386940b8abe130f1a7b03379", + "4a4bbec3d17b4015940209c10cdb678b", + "5ea18ce9e35148d186321bfdcb87fab5", + "430666d7e43948e1b31b294c736754fa", + "8eed6f4763ea4f0b9acd02e066e6c277", + "9863ce9aa4c449758a304a92dbb03d6f", + "70db1c37b96c4c50811b68a446c0de01", + "a243b78d6e454bbc81e9aae27f9e783d", + "16490ee439a54008afeeefcf53d8d051", + "806607b62e6a474fa3d72495a6e1f6ea", + "0bf5a09fd6124ec4beb39830839b2c63", + "39c1c24d0e164585ae9d523b20c71e50", + "d5aa894255e74340816c5ba47a28d6e4", + "fdca58cddf0c4987adadf1863ebfcba6", + "ddd91e3c9bb7493aa890ba9383bd72ae", + "01a0487f34fd4c6598159d2c55259dca", + "1d1d7509952743e9b83456c3437d6fae", + "891942728c3143858f93071aa29b25d3", + "ef846ad93d734f7cbc4e55aeb81c0b81", + "aa6e9c363fed4fc393d56defb52006ec", + "89a82eac43a34bcd83a5a075b0e5368f", + "e52fcf2655b048babfe10e3ffe72a316", + "25d2e4dd016640139562a1ad23828ad3", + "9170ba9f384f442ba9977b48d4eef113", + "9b1834ac141e432fa8081e5bf5835fb4", + "d42aa6ec1ac04ac6a86fc295a99fbed5", + "d10c9764f22e4fa3959db48d3955f282", + "485b809b30ca4361be80ba37e715202e", + "4ed1cb3315b74e03a9ee1c51ac1e87a1", + "b2ab7e64eb9c41ac9b8724f6c8db3fbd", + "adce194e275d4fb0887faf550ec739c1", + "2b157cd62bfb4f60a95a0b8f9d767e3a", + "a24b4b74a40b42aeb083cd447b79683a", + "51ba21f2a392472cacf68f02a5b762c1", + "d1e3a58799b146e4af6496ca9b8fba41", + "cfcfa84fa9d441c59e8047ffe3d539f4", + "cbd6932aac874d40a340660dfdcfe64d", + "df09f51886824cd78957d92017fef972", + "e8b11aec127e4ce896d5cbd474702703", + "deaec3c63ac64e0ba43f24b57767fd10", + "58daa92fd325411780126c5c8ba84ca6", + "790b86c8946b43bfa93e626f7fd0f886", + "b12139f023934b93b06ae240e999b131", + "bd8cfd73b78745e2a3000e243fae0672", + "7506e9731f214d37a2498115de8f7623", + "49e0b2c7cccd407e93af1162e086c686", + "7207df141ccb4c0cb2db0a9aacada802", + "e19ccf3c45a94abe9bfcb2bdc4950ca2", + "5c1723090dd3487aabcb2b2d5bc35c07", + "0673975bf6db4e7ea9a8ad011a573a8a", + "2b1120c4b517409184413ed709c57a66", + "3e0ddefe82524314b0bc8eb0191950bc", + "3e54b8ce1fa042ab9a25fdb7594a0d0b", + "84020334d1d047b8b77152108844e786", + "ec124f25d0284aa7a41fdfb7af4b0a00", + "8be09b9d10ad4fb8a9e2125f1b6d69a7", + "b674fe255a6d470eab510a1dc54b86d7", + "f6b0a42876f946398bdeb9c916dea2c0", + "49add91ed5874ca590fa137ca2029353", + "c4b8b07d74764ca383e9806f25b6f192", + "39e4f4ca2b7a4d528986dee97a5b609c", + "d5a90f47f32f426e8b4e51c5a4f55b53", + "565e4ef4358b43a0aac9a123089a4d4a", + "4896cf9b3e614662b29eec0f87d9a44b", + "747fe7a49dae4ef6b067ec8916c808e2", + "557c9259640f4f41a273c04c35288cc6", + "e21cbbee70924977809639512e12209b", + "bf2b68bdcd7342a98b36efc03f872349", + "3a7f5bda21e1457fad843422e745b02f", + "3ab6ef0bf46e49bb84fc122640a521ea", + "6292c807b5074fb2a41448d8fd9e8bdb", + "5bc976c103f14f2995c048fae25feba8", + "cb887989b19c4342a5648b6754179779", + "ed11e4cd21124037af70dff7bb69a1a1", + "5edfb3471cf4400e99ace18446f924b3", + "6e7beeda7b4b47b1a4a64c82c3318be9", + "fed413356b80464cbafb2389ce18091f", + "29527175dccb4149b30a470e2cc6fbad", + "f500940881a243f88fe4850090787efb", + "a1c2262838724d1eb4c6427f04933fb7", + "e4781fdc397e40e1bf5e80e09adfe780", + "e70de4b8c5a642b8a525acb036b98bbb", + "3403b6f0f47d428eb2dd098f864d9ae1", + "ee4aee8bab7e47309fd6957272bdfd2e", + "0b726db918f94fdb9e7a44048321472c", + "60728cf9622947f89ab39e9bbf15fc20", + "c57269269e51426f837813afb84466fc", + "6d007a29c5a5445a8f0712253095e2cc", + "f9a72fbd857249febfafad5f844e6990", + "0cb168c5176047439bfa91cd6599420c", + "cbc798efa59d4d84a199edb1ffcbf547", + "fdb47e3496ef4cf5901313ea76ca23dd", + "aeb21d38f2274b04a940e0446431e502", + "5b2bb37f68da47d492df2325e464c397", + "ca533feee43e40099ec0a5ff2da5f4a5", + "fd35bebdb5c444fbb917dfd1979ab4e2", + "421cb6e21ac94abd826c5b28a5b39ee9", + "3111a9198a9f440d8116196f38d6bac7", + "887060bec4924028815be1e133da5eec", + "4204828e5e6d4de591aafa6605c13ebd", + "22e7c6f3dc1b43eb84ce081db6567e85", + "f4163676707944da93b6e43641fa534a", + "5d811fbdfdd443d9a4c2813ef01b6878", + "ecd1e3f2418246fcb4d4952e4317a123", + "e5aa03a5ac98441ebcff7b0270142291", + "842020ff8e474c15bed3b39db8298ae7", + "48738eced27746dbb8716a520dce2112", + "4cfaefe43ba44cafa4b4b695eee75f3b", + "01ec0eca84584d7c81972cf2672c9e7d", + "8565a55b2ebd42aba238fc071060a70c", + "d3d0b478357f43c991bdf4eea88d1853", + "4179ed636e2f4d47bb82691f7f536e84", + "6a7a8e3060dc46dfa3d9c83f2169f371", + "952c166d3ca540ddae7dd86c02c964ec", + "4f7d1fb61753490da5c5001ce23149a5", + "929f570129dc438eafe2cf7083fe98a9", + "fa4ef40a462d4f0994e77bd20072629e", + "ad7011caa5714a9dae06bfd54e220dc4", + "ede6e2c3c8d644b09d44e6c83f6ca206", + "16416c467b174bc3b487655e95318987", + "0bbf6713817648f59e98de8861ba3913", + "ea1800fb5ecb47d99e39041db34862c1", + "f0f5f83715ef48b081915d990c345068", + "a5c178713aae4cb6b19a3653a31b9fbb", + "5b194ba28e1c4efbbf0875cc313b3674", + "c041b5b11696408088c4229100b6506c", + "28274600c55a4280b2297f277c5540bd", + "ec2dc94e022547beadee622b1ff34a5d", + "bd7d993037a9473e99d380944c7bf5a1", + "f72642a034744cf5966f29a85eba4d05", + "f957820ce0c645f5a36d0e89350964ef", + "df145d381f96431d92d1ecd137d2251d", + "df10878c17b0410bb7984c0068b7eb85", + "d7454589e56a4e5cb4665ae56eb9ee3c", + "7f92080d86484d81b8dd30317bb28586", + "b93d03c2f8874bed87583a8dc2e53d77", + "33694952d4e54715a620ab4499d14cbb", + "b72411a8065e4c5688fe27e98f1bf497", + "5c6f14140c8f492391c464c308190c62", + "51dba5eb17c24e0c9fbd1f817505cd60", + "63630134a61b488fb95b6b83243bcfa0", + "74535e12bd4c47a98105845c114e2bfb", + "4528c95e2c0c425585fc3a3f49f6bad9", + "c4263723ebb64c7da734946ea5ca27f9", + "a2f041ab9bff47529d3555708701dd91", + "9f4e1b7572b2494c97e8ceaa85b41cbc", + "4009109c83144e82899f8d9bb80960a9", + "3291d6a301e548418d6d7cff145f355e", + "f58bdf8de83d46e7be542ceeec7214ef", + "dfc462fb314a4ca2985b6ed7090d1e90", + "ef87a40c8fff4fb5ad20ea62c0f93ea8", + "d690654a1dc644269f00855c69f508a2", + "17629c39c3474d199e63d638596c9420", + "1051b03086ba4388816a4b41fa96aee5", + "c0e527763360462985d305a7dfbb52e3", + "6abe7c3d35de41349d416e1941d74bdb", + "e5c62a05e35f4fe2bd0924b4b56b79a6", + "66cdb12bb3f34cfebbc95f6d82e53c3f", + "67c1247b7c1248f0ae696b913c555ca9", + "49e793ffcb684484a80b5f902d310946", + "e2db7ceddb4246d1b880790863921d73", + "ee0229f75b72438c9a858afe4f47ec8b", + "ea7da75b937847a9a1593c674c6e88d5", + "eb130fcd003b4094aef0b7ea127d41c2", + "1804be5931164fe1a07db120d8fa033a", + "8169c87768c2438e95fe1047516f3bf7", + "69f1c0489a144f3c98e66dcfe72b3969", + "9f83f5090b1d449fa69350aed9dce10c", + "a3f4b43dfffd438f90a985b7f0c28090", + "9c51e91a7a9641bba7a2e8d756ed71f4", + "35525efda19e43aeae566e8caf93545f", + "2e47ec5ca78e48cfa56fcc2e7c8a117c", + "f741994b7d404eac9966313ada5b8a33", + "4e479017b6c14399b7fb7a76d42e14a7", + "f71d7475ef4c465f89acdb1c18bc7ec0", + "092d998579834a32acc69cfe59cb4139", + "694ab0c46f874e1ba7e30d2f271b3546", + "f019ad2b4933444b8c8ed1b0f7f1d8fb", + "69a149e1d61b4a8da5756761c7dfdb24", + "4a6b5f41139f44e0aeb5b13a5ed96d0e", + "041ff9ca49ac4bcaa8e3f07417702c75", + "d5a085d0983344f2a98efaa651dbdb36", + "6de9ad46b6794e78a08af59ebeb04ffd", + "c6c08606ed24421f82c465eda33bb6ee", + "1cc9fe2b424641058db483d5448008c1", + "426caebd84a74fe9993bc8b0cbe6ada4", + "ff2344351c384ee4be2adb73c22250e7", + "ec191d88b379427f8ed4dd43efbeb051", + "35a72ff20a20463ebf63a412cf424157", + "e15e56b956784ad2ae7c5e5224513445", + "e13b0d848e9e4fd4acfba9b061ce2d41", + "8300ee896a4145a89aa3f18cfddccdbb", + "a2932987a8a941c4b5406d07cecf8ba9", + "fbf2ca604ced43a5b001879961987fae", + "f8a8d32652f64c9d9e1a8eb3fe263ba7", + "d6b0bf73a0d849d08c929f1f7af00805", + "b0a9b607c7d54d08a06204230f6da30a", + "b986b5832f934247b693bd9e91a28552", + "e67db84c8d2442519353afbae5220de0", + "64d49a1f60cd4acc9beb4b5d13285601", + "28cc79da0b4446bf85f362f18f4a6f9c", + "608431214bad4e4f99522aae86b77bb8", + "b49fe8bcb52844dfa4fd9f86e2a6bb7c", + "c057361b58f74f7888efa261d1eb3ac4", + "c1488f008d5243d29eb5a7acb41f50c1", + "9527ada3b62a49f583b9c1a86b21cc18", + "a010ba2dea0a41f49e7706176a62b8d2", + "710100865395435cacb3bcf6514cb495", + "a6d1e50c93db488eb91b292eb8ba7765", + "7d9697e32b8142a1ad6c9d3279883786", + "e0ae8199a19b4f8c9cb7ff05e5f94030", + "ef5b4ebbae07448a93e8078e87af6475", + "fc4777bad4c647d6a21637d68d5d40d1", + "84b153e8deb94f3ca54989ed7086f8a9", + "e8fd0c25765c4a578de0df1c7cf7b925", + "a4b565b1ca7e41078e35dbf679f1c356", + "4d6074af12144035a518e878a82aabb3", + "d0eb520347d449699b342afaaea2ac4f", + "ac0e7f6d41b543ca96f69b4bd21298e1", + "8e73c1e9c85645378f6294f0b2351ab3", + "a7793241073a48e08e92280f445a6a67", + "f229b75945bb47f1ab2393fbbda82a43", + "23d2d9791e2a4775b87e799e8089f906", + "924c9b0f3cb4457b9fb4712e02384796", + "7fba34f8b2704dfcb4c006d6abc340d7", + "e8f048aacfde49c8886fe72f72674965", + "01922143cd9a477d8f5ea5f805637691", + "bb1d75d971de467fa9f3c26f3d8b4eef", + "a7aa70a9ba014d36bd2661a261ec6029", + "826bc4f3c5e247ffbf81d98871b70b2b", + "e64ebfc6c0ac406c961d0a8a0e8631a7", + "f18675d0123f4d939f3035f5f335f5fd", + "8bfedaad32ae46fcaaf6ce2203a5ae4c", + "8f6f1a38f62c4c96b7fdb35bc4aeb78d", + "9a985c97964d4f368ce9a17916468e71", + "de51dc61ec7c45eab148d81cd393dd11", + "60dd2f84af874a6cbd335e36cf0abc5c", + "1b1554cbee9e4dc98b4e9f8282fd77c1", + "e3ed48a3a0814d8283c3458c539ecf8d", + "f7122decef0b4f7aaa3159f66876a9a3", + "254391f83622453babc6f0ab63947034", + "fb01a997ca3644e88cb6005627d7b174", + "1fe9b618f2d24502a0aaf73175829ea9", + "47919881e30e418f900ea5a8dacef14b", + "aeb0e4832f04463280510e550e2cdbd5", + "704e2b1baecd410fa04082eef08e97bf", + "e64a2023de594ae38f9a4e79eb18074b", + "400ce6fc25f54d149efd4cd429daa50f", + "3175f9b0f9e141329f05f77817021755", + "ee3b649aa5ad4cda9580dc3f4a32bba9", + "fb0291f77665442fb5e54473a8d12b3f", + "f86e98a4927444de9b184ec212c19283", + "ad368a89b62d4e67968d4a08b02edf81", + "18427588b7304181a6c2095dae6517ae", + "7b97137d2ce3441cacfb76ec2fecfb78", + "35328820cfc640d2a9b5eedb6d7b907b", + "fbd20f35d3194093a47e7a530e2aa217", + "b2e914cd6f7842278752aa8fb0b1a4c0", + "95b6485c508c4b068d683dda16a33252", + "141245699297480a92ce81711823638f", + "1b54d0a314954aadad40333cf80c2d28", + "fa3577bfb99e4dbf83d335ce75de5910", + "dde8d2aa26354eaba3d82925d833b5a7", + "08318294c24f4ccf968bfa046a327003", + "7c8451376a7a42e79cfcef5c0d7836f5", + "9b3dc9b1f27a4e6ead100ed4e641d8aa", + "ceb1f4401c804b638e57155b825302ac", + "0c398f7f15aa4527a733dfd7f4769265", + "d74e7913267b455fae10181ee77e8a1f", + "bbe937f9a0ea441496159d8f7821d07f", + "82f4d273bc2240c49f70fec7b6bc5fee", + "c12e3b933d77412c91fad5734645db67", + "609200b0c7af4f40815ea1cefe6f7e0a", + "714397383f014eafb4de216db99e851d", + "6e6be76a169343f3ad439c084d16231f", + "aec2924a4e9f44f9ad569717301e30ec", + "81a531bbe9d2448b84d161c6aa9f048b", + "ae327ae50a7946cd9ffb609ed136d2fd", + "f130817ddede45b5acd1d78f7af099d0", + "ecb01317a2f34926898fa43ed9754df2", + "cbe9d1ecf85e44b4998e205f86ba4311", + "a55e471989d644d3aaba92e117b3fc14", + "fffac5c39c104816bd76307f4fa4cded", + "45f941c495824cb583712dda57f58707", + "7f18c636d8ab4f62ba880f03ecc9755e", + "92167e12a3f04ca691a5126f25976017", + "e71d797bad504ba3a3d15923e7aa1589", + "e4a7ac2fe26443a4b9a786634a43f6e0", + "895a9d0aef344d7482b6ee545ae9267a", + "cbb82162cd4d46818e7815d547d73edf", + "eb364dedffca4de1a68c752f12f36e23", + "420b6bcb2c594b9aad189ab98a22e0ff", + "c09e054b25424ecebfb06fe072465df4", + "ec2cd8ba3ba8478186679745ab1bb94a", + "cdeff35b7a2541759a561bc921b8e01e", + "34e129782bd648a8afc47ddd4aab6688", + "3905f91101d14cf29525b9519748d92c", + "907dc3f6d55f439eb5a43a68695aefbc", + "3d20e12029dd4e279ded26eb6cdd8d73", + "f84beda470b540e998e8a1dcfec93336", + "f17cf7f2da59456d8d7e532e72b807c6", + "24f9bc38b64e4aed871dcf11080c5e8b", + "5db4a3bc2e7e4150b1eba1a466bcf37c", + "ebd106ddf4af4bdbaa3de413483ae07a", + "4f647aa45b9441dea2f79970959d8137", + "b6cbfcecbb044cd38b9f6f2c36b6d866", + "b51c7c0437bb4fb48619b7052dafba4c", + "e13212de348549a1bd3c3b7b18dbe7b9", + "419d8d3fca594dd29b50f625ccf9f2f9", + "fa0360111770494ab6edd9d3413162de", + "08889596bcba4a2ab09f3533d7cf14f3", + "e3d7f1717bb546c6bc875d010eadd690", + "a212dcd1c71a462bbc0705648515ddf3", + "4ab4ee46dad54ad6ab608d88eb19530e", + "6b61ed3f4de244f08a8cbe0534e83ff1", + "b0c00b0f224c4b04b4ecf0468445d0d8", + "a1853e688f7f4dbda9e5dfd9a9e9c840", + "19d9aa2c51414e76ac59a12c87e98acb", + "d5cb92f6e9b44a7d8f1818f701c31d7d", + "51749275659d40198c491f951a27b4f9", + "58738abce8c641de8dffd611c599953a", + "36f71117ba4d4dd7989bdefbc43c998f", + "f5aa336ab89a45ffbc9b7dd2119ff25c", + "b3d14df9c54c47d0940fb1094d20c2fe", + "d5f2b4b7d9874100be9c374d4b3eeca1", + "ed342f2d9a89412d80c4e273a963eaf3", + "35feaa052a88429a97b251f89be42fd1", + "87428dade9034cefac9eed6a1aeb14a1", + "ab0a3f25354f4c859fdbce10e5b51279", + "1b36172e3e254b46a973f0132c4b2e08", + "ebff999fe68b40dcb89b5bfb069100d8", + "532b02858c67410f9a1973544f25dcc4", + "c64164760318411588b90671b76adb9c", + "d9b022c5b0ef4f3bb6a1f5e1c4627aff", + "ae0d40ec0b59459dbdfde84138bae813", + "cfee66951a2d42af908f6829676cc369", + "99cd3901e0f94cf7a621c89dfde9e86e", + "fce56ff9023e413cb319cedbffd06f94", + "61a609a96d8a48adb9b6e218e8ebc016", + "c82e45e542b84bd191dce61efab5051a", + "5e7ca80a58e44c3eb6bd75a89be80d26", + "8e8337b83069431fa43d536a7a101922", + "2071bda681b642218b6829b82e4fd93b", + "ff10170d6b9447e794e8a4171e4f3fce", + "79e205bf89454102b85dbd488c3201ba", + "0c4f6b97f9f14e228299a46ab5a00468", + "a0501b0193884ceabbc7309952ab5f09", + "bcf3a4e49ee14eeda2faca7c7455161d", + "148cee97600c4356b82dc72ac0a25054", + "67eee79193b44b93b0ef1bc0934953c0", + "eac0d2c3cdbd499e82def321248ffeb6", + "8d283399dde7478f8aa977b48a427c36", + "4fbbdf9506be4b6ea0d4ce74007a37f8", + "b61e3045c32646ce89342031818ae5c9", + "fd2951e29c6f4ae499f368a35475a8b7", + "e0c6a24f9b974c97a89bb2f876680310", + "10b2191029b44f81a6dfe08955a7ff5d", + "0331d321e5e5498b9275402736b406e4", + "bfccc771e7fe42559e5742701ae9a908", + "e6270b9f9da84810a41ceb333f083b2f", + "27d97837f8444c9cbaea5f5479341de1", + "f90e2befebcd4088ae3cdbb8921a87ea", + "57946e0708f7425486d19903b3bd997a", + "535258125b254ad59690f08b4578ea30", + "c6f67e740d3242ef97f4e7a8d338de2c", + "f206c7140ab9469eba2a4c759eb7b23e", + "901284a4a0154d0f9c0d3177ad552320", + "e54ce0d44f1b4b07a51b81fdac130a89", + "9bb1930da1b24614a1b2f05350944129", + "80c1cc223503498fa5ed7f2bec2f96b3", + "7a09c75d40e84b10acfd4f8c40e08375", + "f209de0f9c7b490da5e4089241f4705c", + "c27f71e432b84353a245fb9b65dcdbf2", + "c6ea23d3e053419cbf7addee94f2ff7c", + "fe949f804d1a4f2b80cceb544220517d", + "764b0727c9a14a6186a54b99d553d339", + "fed2fac6be1a4e0ea225bd9001e88a79", + "4582749fcf9b4cefbddfb02f0e0ed1c7", + "f734d62f5184445880e73f7a64935c0f", + "d1a021a45a214dd7ba5c22a7f3cb561d", + "a4c0eaf66bf748c5a2a1d6bb595672c7", + "4a16befac30b417fbe9f0fffce267e22", + "57f74d6a8e334b78af143ad7eee99921", + "48a602e8671a4534a3db78e715c6ab9b", + "087b5a3601b040aa96adce426f8e685d", + "0002064ef02e46f9a10b4bff10bae805", + "0ac651eb518a4bc69873b117cc7e3dd2", + "ef3169dcf91a4d2b957ff4718d27e4e1", + "f1b4215ff6234c8a938018158713bc3e", + "804413e30a314fd0b0d9a307f237c7bb", + "d3dcf36e0d6340078c82b61a20b596d0", + "8e194394fb864e2da73913b89e240a71", + "020a2199c72a4f8eaea8f1212271a1b0", + "bffff45d3fda434aaba30eb0d5485d73", + "0e5e7c985b3944f5b84140990ec8189e", + "caf6d29f508a4691b56601c5dab9dcd8", + "8e30f525aa61481f8ec4ca22a3a5cc83", + "64ed1d20cb7d4cf2b36a00c26b61c2d1", + "cf860a30743f4fc7a849732488a9005f", + "42fe768d71e04bf38e1848d70942e194", + "f61f0e0bba004228afd31d3ed3f71818", + "47abdefdcdfe479a91e0cae48e70f8d0", + "67981a3bcd6c4dfca90f6d1a55104d44", + "c43146abb4804be794b78ec0aa4dd1b8", + "5eddf36af49d478daa7ffd382b6247bf", + "e81437f7bc974774800cb6470571b199", + "4439ce3762d744f49f0f45c76145ece0", + "1646dced57074decb0afbb4c6ee9a721", + "9d71488123cf48d69fd26ff9c9615225", + "f1a1c38cb35c4266be0efb43f1411260", + "f60e5b1a2a0149ceafba863c25ba74d8", + "3cfde705683940579456cbd0abce811a", + "f45802cfe890462ab5e11fbdeab646ee", + "dc707f81a94e48078069c6a463f59fcf", + "6e509bb275c44dc994d1e6bc694242f5", + "fb70d2c633d6405190fcd6a0a9733b6f", + "e1dcd19f297c4350b5acc355ae4a4e6b", + "a9d0452fb03047238283b895777e2e97", + "41415a2e3054491baa46da5d7a859dfc", + "363b63967982455e9ad749851bee1d7a", + "cff2d3483c4a452aaa9201b2a1b7d984", + "40be5a4ca73042deaa9bedfd98c44665", + "5363ee82fcd64424962324f9265fbdff", + "ad1ef89672ba41dca171b5b36e6a15ce", + "3a1136e0f8c94763814f748421906fd2", + "f164f8d53250415d9e57d92fd1191e5d", + "622202ab925f4cbaab8269237e2a3480", + "f8f5a766be9f4cacae1d6754044fe422", + "d90331faf5ef40f68c25a9d4cbdbb9f6", + "fca1a178324244ef9df1ab0cb54da4b5", + "17bc64af683149b981398591b8f2504e", + "c2d87dbdbdc644e89a96da153af4284f", + "25741169923147daabd091356e5ec078", + "e650d7ac4c61485c9f3f37ca784afa49", + "61d5ad6897954f2484b9ca8dc5998096", + "304bcb95e181499d93e1fd75551f59f3", + "7e0099fb40f147f28b6e60cb6bd49bb0", + "0830b75a1d164f459851573d37616e7f", + "a21bd4eed2c642eaa7e702269f47b002", + "c3e45d7d11cd4f7a907b9d28191a824d", + "c0e2bf89baea4383a0caf77e330c83bc", + "a1d2ef559c774fca910084b1136535a8", + "e5f6fdcd6c1f4d12ad081a3d42dc243d", + "e68820e2d14a46a08e23070e28c84b7b", + "ec5534eb7179436599d753c8658fad09", + "8aeacdcd0de84070b2ea64296ddba474", + "a144d6cffd0d427eaa3e534f503f5d72", + "bcdd96f72c9e4034a6fe2a5121e93a87", + "4c288e19f6114f708f758d995fedf80c", + "e38bc70eb5bb44d8b293397e2f9578dd", + "f5c9ad9d14514ce8b7b84ae65cc43003", + "840ed19399d34d8099b1663796b3773b", + "63904d0df09c4be6a09518be761cf116", + "5d801c03124e4fa184b4e3271abfa9df", + "478e23b384014e23ad98cc157fc3d26e", + "2ee2003561cd42789f6346ed1b65b2ef", + "2c55f313494849769f17ab44bd4d3fac", + "729ac26b84044ff8956bd484056efbdb", + "6b5cbcf70e944966bebdc102676cfb7e", + "d0a816a10d734fb8ba77d5bb37181c4e", + "a4aaae85b73043878c494487d806f7b5", + "32f1cf6a13a64742883282e90ef68c8a", + "7b8b481d58d54ab59f5f4004de4c6b27", + "bf2f4c168c41450fb77bd1fceb7aa43c", + "a7c7d39c461e457a811c8b206e178685", + "6d8bce057af54abda563bae1fd6ccc58", + "faa0ea95a9b74233a32013e381342d6b", + "25f6eb11e6814e0785d4f57b1ce6213e", + "e6fc1f3bafa141f6a322bf0531197ea7", + "6a67efee5d04416984d9bf77c222b331", + "a6ab06a3fe80463ca23d0cf3c14b573b", + "a62b69ee18cd477d92e4655c84a79770", + "2b9a9d4b2d624b8f889f9d7be4c7a14d", + "ce20e03cc42343ab96e65c364ba6c78c", + "b16f3bf656df4a029d869dfbdb5b390f", + "decf197fcdc54d2db7d400a8a7eea3f1", + "92601efb9e7d4021bc4ecc7250a9930e", + "38f6251209504ddba51dc3b0be4061b7", + "3abddfdafec3468d8d4a7e05020d4097", + "74611a68f6b449ebb48a62e617611037", + "b6d54fd1e9394a1f8884e833bf91db26", + "a57204655044471f84d2e00448aeb97f", + "77d1498b156946eea65423cb72cce135", + "dfb56c353e0a4bc8a6d795a23cfada12", + "b1d3d3a8edda4d52ae9019d2150e7bb8", + "7079a5fc5bd74143b36d3f1a123a4f03", + "f3d9535a0b014487b3171f68e2262e4a", + "45fccda8e74a4127b6a5c660dd1a86dd", + "ff814230abf44128af37ea768b50ff90", + "5a9ca3b40a02464fa385f3e95d4f45d3", + "77748f51f2d14c9fab18fd2a70175c31", + "a1a1c7d24e984dbb858d2f1bd63180e4", + "d76c2f26905440cd957de261301d09ba", + "6bd9b2614dcc44a4b6faed27951ed252", + "3bd786986e974eab9f90cb3f09e2834d", + "fefce37536b6407c8bcb80c70343c5b7", + "8e55bab46e0d48afa3c22c339a6b738c", + "963846a5496344559761c02f62998b03", + "e9fa19e6bd6a4ecdafd21a9b51e02447", + "07d5590bb5164ee08b7c4b9c11c44643", + "324208bbb2b3468082ced58f8b8113b7", + "42529aab3e764437bd73bff8eb6e3a0c", + "84bcaa0c9a1c4385b8206c0385c38b78", + "60d9fb6fef2c48628796a4d9cdcf34c0", + "e60f9b0745ac4ce1bfdd6b001dad1970", + "a36de7afb1c64b059f2386825411909f", + "bef2f96d165a4a20af0b84cfd1ad6df1", + "0a36d75bf85f4cfbac0896034e6b95b1", + "7ba9f879b3ab41f6a5fb6c1c7728859a", + "61df5683eb8248c08fcbb4773a887280", + "8388e93c6d6549228dbdd676c220ff14", + "fe1bd031df584950b6d8b06f1613ae86", + "eba71a3fabea4ab8a015fd4881ebd941", + "dea744f73fb940988d4cb78d3aee3dc6", + "7e6709611ce2431ca35aef17cc0af981", + "50e232096ee5475b8937742d5d35676c", + "c188b9b11eee4c788a4c51e0e71abe33", + "302c2a1a4d9342f18acf2250cc99c04e", + "8b2a6c17b6b640ee801b4048e8d6bb72", + "130e6644c4d54e99ad3ef5163481ed60", + "b06dab7a33ef4e51bc186272e19da9f0", + "274bf0130e5e497990719d44c498ba00", + "27e7637ff9c84479967618e9fef5d082", + "687e906ba84e45f5929d57d2b644f6d3", + "f2e9b40796e946518bc6ce1fbb31ad01", + "2f31db3d679446eca15dd115119371d1", + "582b841b0ad8431ab8d6daa2536f1851", + "1bbec1d9f9844c9ca5a86b78153a7b2b", + "ea77e76c3a2141dfbdc10ebe09061b4e", + "ba25d10d82a844b9af6fd135141955b5", + "dd9c1d0087ae486ea98232c799c05846", + "09ca11888eac4a47914ab95d95a8b1e5", + "3021153101a441989103550ebfaa2659", + "ad4378111a304560a38cc3b95d0c72a6", + "dff1090376c54c96ba6663139bb6e198", + "9bf7b9465aae4c61a2ab3ce07d0c3636", + "f1592cef6d3c4d88ac07436f1cc8fd0b", + "1f5a007441124311a99d1f6156cb17f7", + "f683c0dfc3e34320a1c4818891818021", + "b7a9a04e62144bdc85d5580e594b0b22", + "11651709717d491790987d9eeedeba4f", + "ba4ce43f7b07459b862eae024a6b0c82", + "beb3aa19412246709a7bcdc2812cc4d7", + "7c5f400773d940cdb2bc6884c990e888", + "f0fecb80afa243cda158bed844919846", + "6c34e43b6f01492b9d336e4228deee62", + "dffa451e9a70420e80662e52d23ccb1e", + "9d24aac8a4c444a1b440647aa6f96438", + "f69952ac65ab4d8391b85736453a82f4", + "f15fb86d99564454a9e34d8bf8998885", + "001d1b57e9df4273bede948b26429429", + "d6affe6e51354247824b8163d825659f", + "50faa76f94a3470ca68ce414c2c4eb12", + "467054cb138243298b97651aedfff0bc", + "803c646867dc44118210dbdbebfaf191", + "f0dbcaf76c83422c8890360fbccb7740", + "9cb753e6285d4fb19b41f834aa7dd9ab", + "959d5351cb5843d3ad2b2c169da63b90", + "791b5dc308f242e2ac730f7433e1d545", + "91bb386ac8984da5aee02d0632e4da0a", + "e38557286d5b41049dc972ccc5bd7e39", + "56281ca6acfc4eeaa4af6e9649c7ab94", + "f71bb7af17f541708e9121f5a5a5b433", + "5fefd235b77b4fb0a6bd5db14528d610", + "26587b743d2b460a865df2a69f4692d9", + "9bfa66328d274aa784d0e2eb26b4ddfd", + "988a6e8067f846fab40b898a30df8d61", + "a0b89558829b45b9bfa4aa4083270c09", + "f6f2c4d0531046c7882855f9294b85f8", + "e7e55a94f3ea428f983ca688af432cb0", + "ff5ff2a5b6784180a050a3c142ada9d5", + "285af8e962924feca3d1dc61550aa716", + "c8c26f18c26a44d89fc09299907a38ce" +] \ No newline at end of file diff --git a/apps/third_party/Wonder3D/data_lists/lvis_uids_filter_by_vertex.json b/apps/third_party/Wonder3D/data_lists/lvis_uids_filter_by_vertex.json new file mode 100644 index 0000000000000000000000000000000000000000..616a85c065bfb3a7be0b9598c266e366c99419dd --- /dev/null +++ b/apps/third_party/Wonder3D/data_lists/lvis_uids_filter_by_vertex.json @@ -0,0 +1,36046 @@ +[ + "5166f44ef6ca4d298a497acdf9b38a58", + "6c29bf5c59254a34b4879afef673323d", + "15cfb4fcbbe64f8db346824a52dce1c3", + "e65c6b45a4414b7990c9a3442271ed5f", + "309e36bfe42940128e72aa82a4d230fb", + "c3f713fc4e9045538f88a1179ccb2c7d", + "fe255a26057341099c7139b9d6648e76", + "71e499219de548a7a1be74c237b6a2fb", + "7ad240c094874e7ca1e0715ce3150c20", + "56ab0de975594288a00ec26e238dbc07", + "66beb25d4aea4a15bcff8d1af16f8801", + "54ee1f25a5ac4488844a4c76e34b1fd5", + "4b5293b9de7f4c3b92417e6a2674d184", + "a0271ab30fc9471ab2d91599e04107e2", + "ad76e854a7584ab88e2ef9b561c71d86", + "64ee92cebf5441629c4ed97c2ebed515", + "2e523d5dde7c44f891ae6dc8fbd84fe5", + "1dad6edcaf2f444fa6a526ae0dcc1611", + "d29ea01da3ab497d8c0376108c419c18", + "c9433cb2268f497491a3dfb5bab1870e", + "aa9adefc0dad401d9c1a40ac90cac1ec", + "448630965e754a4a9d2fa5c04b1db6fc", + "be3cab654da84e6f8a6ccdc20180a115", + "09af8624f011406c974b7cd4678650db", + "3588500d9a9e410497f8cd97d9863ccb", + "580615867c9545fbbba3176bf14169c9", + "6ec724289a85469abab17058af037fdb", + "14ea665b30104b25b7fe260e5369df23", + "a5e431d25b5e4aa89c5c729fbd906f06", + "69f32fd6456041c9b37fef8f254efcdb", + "e8a6785aecdf48468f38b65d4d953388", + "5251618b2a5744a99b3338fb2c099bae", + "11f795f4d68445eba47e4b3c3cfdb044", + "8870ef6ecfa9458b9cb383033f8f699f", + "4281e10a38c14998969e6a9130507dab", + "14940a9a3a0b4af49ba51e689a87e727", + "c9f44c599982486494bebb38d23474df", + "4b0743594aa04c3a98e0046f88863c83", + "39f9b772c8514dfc8ec304bf5c85ceda", + "5ba6a5759315437a85fac54749c46c82", + "539af081d1d649398a05e15b5eeeb35e", + "5e56c500173b4148ad6d228a403dad65", + "a9e826fe9bf4492fb338a8b5e2cac482", + "00642d469eaa4b8f9a86abd68e1cc769", + "d0f8edca337b43338674ca392f36c4df", + "b1e936cf2b8948ad877d0f598b69b7c6", + "f6f36f95bad24334958a40514e7a67c2", + "43fa5f8086334ef2b3523dc8e461e60b", + "39f9f70164f04bd09bca721e13cc3491", + "291c896c7b524ded94208f70927d5ead", + "e15fa5ac39a04695a4caa1bcf0a268ef", + "b5aece830f74464a89f239d656d9b4b3", + "060bbdf23d8b42eb915806499f0b4ecc", + "fcad66aad5fc479094af0da5c2a1bb7b", + "7e46ca9ebbb24affa9ac348886481dbe", + "92574e215fb94cc89cf4dbc9d52bf796", + "5c036a82eebb44b99f7855cc0b04ced0", + "94cf84fb941341e481a98c33b7f4d4e7", + "477f00bc987a499cb85b74ff1c7cd988", + "07c6d211698848f695e28afef3e23a75", + "0acfb2346cc44decadf6a93ea6ce940a", + "54daa7a355d64f29a82695adc2ac1918", + "d42c3f2add1b468684068bab179b45cd", + "b43f9098e61748a488e3bc194dc8c031", + "2f23c00ebfdd44e79c19d60d643d6943", + "f6e602800b5a427f89d9adeefbdb049f", + "cee4802cafe3483c9d72f27d6f3e06d1", + "f47f3f0762054e28835e20d31d05ae10", + "5e63fa0561404805aa7e437dba6d6172", + "63ae0999b11f455d99d78db69de7adc2", + "62c046fe80614cd09d66b792b7947569", + "606358954b0b421d85916e441997c3ef", + "a6e19d641a2642b4b9ddb68b0c5f3c56", + "870288d9c28a4abd824f1cbf0f25a9bf", + "f519892c383f479d9ca2431f66e0bbf4", + "4a57bf6615354c42a6d4f8fc9a1ac8a8", + "30b8f6dc530f4094893ed39367d3e66c", + "0acd00b0410c4600a910899bc277b039", + "a6e803a39f8b4ad5a68a7a2e6cdeb6a8", + "e23cf20d6f16409cb878a789bd1a8b38", + "36fab1070ecf44e6847737c546928c24", + "53053c677f9d47edbab3e14c9f07c2ce", + "33ed1e7b5e07417180bc2055e57e7d98", + "2b7d17764811472595b298f2b328760f", + "ce073996d95344a79d9ffef897fbbb12", + "2e43c950883c42408246997ac2a16d5a", + "892e75e941b5425d918613fda34e4d1d", + "66b83fb8729948e9955cac4754ccd132", + "5c992f0db90049559633663bfae675ba", + "9be9e102cd6b45de81f15aeb21a6c00e", + "527968bf436249d8b029e7707a8c3437", + "93cc67a6f23e4e468d80f0792b22e087", + "b0c3025929054f11af9b576363ca0f8a", + "2dbe18b7a81a4331bfbbd9cd2263e37f", + "fd8f14a7834a41508495c8c8a6a44812", + "42680c8a6be348c3afd40dd8ab8a5a49", + "ab564bc564ed401e9b0f6dc95072e2b3", + "48f2b91c32514fc591014933ffeff042", + "d5f9c98735a2498ca125f3c90410e302", + "d1e21953bec74801a4109dcca325b133", + "dccbfce73b8047a0a3157ae62360b498", + "eb3df3c8001b4778ac36156bd1cf79ab", + "584ce7acb3384c36bf252fde72063a56", + "93d0c62722a047a18e155c407bb71ded", + "a2a623cd107047caa11ac79451571918", + "2c315bcfa3a6491bad19d3b22d83c89c", + "e61b25eb6e264679921ab9e38f7a6050", + "716a867e38c94d9dad278c1befe1aaeb", + "613fc896899349e4911ccce2f94e63ee", + "fd9d3d073bdd4697852a07d8fca0d1f4", + "0456a6cd25df4305835e22428b2b57ca", + "30916fd87cbb4345a1dd499339abe770", + "3def0627dbfc4b98b5b462a2166efc38", + "8cb30e472fda43788ca754aac2d42541", + "24f027123ec04cd59f5c173f70c16aad", + "7ec3859752304e1497fcad1dbc8fd27f", + "4e83522f14c6414c83095365a29d29b9", + "704bc7fa4f1c4226908e3905c9730c22", + "8ebb8c08c9c041c38e279c0b1d5b5ef9", + "221449dda3b54ec481584509a9e12863", + "c1d6c8b90929452d9abbc530af66954d", + "ea3c2447dd1442a3bda1322b4b1001bd", + "20f74d0ddc3b458ea4bc3bd05fb1cf43", + "672f7cd60edf414e933a4383ed5506bb", + "51d928b33e5549898cc86cbdaf966d83", + "0ed899def79a43d69bee31634e03f300", + "a19f7112ed894a5ebab2382e3318d453", + "f4abced537f6473693f306729b096d5e", + "2f1d5156e76a42bf935dcae0aadf2839", + "81ae47aa25664054830ca39cb9fa071d", + "9433970d1b4a4888b73679cd6c8d43ae", + "38cb4ee3a65d423089a32ea4b89eb95a", + "7934c5914213431d94272b50f8b82fcd", + "9d02f50339204aceae991da3ae251869", + "b1d5123382bc4ee884769d282ea46dfb", + "b0f0f1fcadc641949f94db3abd7315da", + "76e1032fbba64563ba77c16f7e483efd", + "98c3f3ec677249359d8a61a4dbc79a34", + "8673cf294717420b929d72a488c8923a", + "36576ecb1b3648f7b74d5e71d3ba3f0c", + "2059dfe757584bcf8a480b56b44b855f", + "eb86b7e6f9194e999de9bfbcecd18453", + "0d4051e6c71d4d8bbf159563ffff754f", + "8a23c38b926d4aedad86c2f1eb57345e", + "a68b49030ac74b3fbd7425407baed09b", + "e2506f09a30b4a73b2543c0f32651846", + "bb112c3e40e1426586e5ece48f5b8ef2", + "a884bf6ce8b74648b6813564a443824a", + "72037fd5c2bf444da41a0220cc345d64", + "fc28c7110c15496dbe05d9cff4ba6a21", + "c0b8ff38acb14439ac2516b2b08dbd59", + "065a7612d4c14844931cb6e10eb6864c", + "7ea6582daadd4d6f9c685b5d1de07fa7", + "be16353c31aa4a168c11b4a58a79f3d9", + "089fb41566cd435895e1ebecc4dd3575", + "b82595bea32a46a18574cfd3e1fffd3c", + "2804957af87549f9b7050969a86c4ea8", + "afd405f8e703423b83a942d8f76c4241", + "79f30cb4af5a40c482e487c8e7c3c58d", + "d415ec55aec448f4941ebd3c6e2d35bd", + "24d8b2e005524aff82607e63e8eeb9ed", + "34122e3ff87441309d6714396d6e22d2", + "6bed02c9c99d4caea3f744c42e6317fa", + "d505a9af77224b79a3cbb2d9350f373a", + "bfe2926bfbea4616b007769c5d1e8b89", + "af00bfd4ae474a0ea89da81c128e4a16", + "644fb3e8dc134d8f994f4446bfaf1718", + "0f03bd5af28544f18410a341ff541168", + "0d381d2a89104f59ae500c4157aa912f", + "6e9108a963d547f8b83af09bd905836e", + "9b8c4236495d4e3fba5e71760d12ac94", + "dc0bb314a28d40bda1af9de1b012db8f", + "ec3e105d98e74ed4949ffe7c1cf1831f", + "f512afa2cbbf41e2802fb0cd043fa976", + "02c9fd6f586a4900b1e9f83e05ecc4b2", + "f953d29af9e8483fa3fe7bf950adca46", + "e3596888fd9d4a509c8dcb2a449302f1", + "7db992dd324344f8a818aa7cc24e5bb8", + "ca63db1db205476fa6f54e1603b7d15d", + "d8663f24062e4525b86568138bf9b378", + "6702d5d92c9c416eac5cc99ee383ff46", + "2df6fdf4d3d94b0a8f3daaab7326033b", + "8c375ece6c444908bf8bfe784c332d30", + "93f931b84d544aada33dbf6ab3a22bca", + "58de43d2ae934e12a116ae6af412ab50", + "dcc5c73cce1744dfa4d1bb5232c39d56", + "3a7d0075025d4abb9f9790390fdd5b07", + "8c22f94d87e343febbb30b7f4da87e8f", + "7008fc1beda64a0480b9352ac55a59a9", + "aa08a4d6aaf041a79721cc50c4fde9f3", + "9f0e47cc9790492dae9a83f1c86006e6", + "8368d0bca47f46a0993ac7c9ab56ea54", + "3a89b45a978347dc9567083d660cfcac", + "85578ffdbcdb4743b0c32a658d62dd1d", + "0f2d08052f3648a2a42d1ea045fe60a2", + "511451bfa1a74573922471430a98962d", + "126a593d1a86446f869a3fe920564958", + "074f617227ee41fb86f212ce086a9004", + "62c27454917d40db8cd6e28f12ff4fc5", + "ace4e5c7601d44ee82d21d372eb9656e", + "0434e614b2d946eb9ee72e2a50834c74", + "efbc56fc1bdb48e4b091d0494d6f2f0e", + "cac428295bf64df59ffad15bc3124b0a", + "f0b2f344b4a24141ab2f714bcbce1e71", + "786fc91339db40f1b7da2234496f30fd", + "f911a85438e34044bee12417ea361c2d", + "a2e4ec6c85aa4908a365c3ec909bf9e3", + "6e3d0647797547a89bfe61405740e5cf", + "d647a19a1ef94609a44e34e68677733d", + "8f3a450bf7e3414b89ceba7484d074e7", + "6ab495b21890493b9390c0b1f915713e", + "33dedbfe99e24379a422db4d5c809752", + "97033e32d0c04612b2c2420f574d218b", + "a5d54163a10043a885f7878f7fae0326", + "601fd508d0814d38898b7ff545564215", + "90d4a86595cb4825bb79e5b166854e10", + "139639e00bd244a8a794c866e2061dd0", + "41a47824db27488792237d223717378a", + "886defe4dd444200a863f9d11a4fa82f", + "638e028757994dc6a9883449d7c8c689", + "e93b720e48904e1eb354854e7501ca44", + "077f95c0c1b64e4fb9f02950ab098b56", + "57626ed78ab74ab2b0bfbab04a47ee9f", + "ce41e1a47aea49c0a83dc4bb5edb2c18", + "f3c6aabb3b2c477eb9ac80cf02bca5c7", + "74110fd064524845b8b005a3026f68a8", + "e1d276a9514341ef9871bd771c20180b", + "fda8f9c3326745ac840f7115e50a8ce8", + "ab9a08f342624728bee06d9444094695", + "206d1a40d4654d1e940c9ec05b2cc14f", + "631d44691024464eaf1eacc6ccdedd4c", + "2cf2af64dcf44fbe98a9990b86fe7a2f", + "0b817f64ae1f4be6829de2d099a42419", + "7dc8c30e10cc46a1a052e7a30cab8a83", + "a482fd641c3d46ce9000c2f1e7348b2c", + "2052bb378fe4436ba78d788755913112", + "572ab6dc598d47b393fb9a0ba146e8d1", + "6784e4f16a7248518cd5ef1118a2198a", + "f524bd3f08e44a4299e0f42ced91c6c7", + "95f92f8c535649bab48ec0efbd7c1ecd", + "4821a4f368bc4b9e8eec4533f270dbf5", + "d2bd517fdbc9454b93fd9a9551537441", + "f98bfdce5d88400b938d2c984f106945", + "efbf5b3579994a3aaf0fea15706afaa3", + "6000c9c630f848e8b516408e6eab610b", + "ab0c7e8475ef4d1da5cf06a5449bed46", + "aa43cf45ba7f42ab8b03a896cd436d5f", + "ab7497ab861a4a63b83d00f318e0976f", + "501cc2f8653a425d8aa7d7c7d011ac0f", + "3693fa4414f64a41b04be4aa70e35448", + "42840b5c292544b6bb4fb5778b52b01e", + "a82cdd603fc240b98e21dfdf3aba3245", + "a4448170224a4f47a389d377889a6522", + "fa4dd71ff8644c3c9c778b7456722ace", + "4737f9c898a047a68270f1db2ad635e7", + "7328dd0e91f24f7c903035a8ef26f944", + "2c940d298d7e417fabbb0bea3324f7b7", + "3a62c9769cf84eef82560b64f87f829a", + "1255af266cb644e4a1a2842535408b14", + "36e532ef9c454a9faa9ae3eb7282482c", + "309ccba7b2cb40a6bfffb89f498fc54c", + "999d2c3b9f234193802b0c55767a0171", + "da9675eb54df434584c38b35c1b6acdf", + "00d1be4411f848efaeb72b936d4d1692", + "1a11f7daa5c746cba6957c1897ec1442", + "d25f2b7d0b094eea960e7b6c5277e60e", + "1c7c1fd10f72468e8551ab33d48f72b0", + "525499e07e9c4400bd165ce35e897ab9", + "e37b1132f44140e78f63e54607347186", + "0e3e6cf6a7ee41e9af1f398da518c5ef", + "1ba1c6aabda2468b89e743386cfe5b51", + "f4d181dd05a24c259ba612cf68961445", + "67c3a313b7b94907a2df123376e6bc35", + "c740b8a8011e4c719ff9ed8043cb69c3", + "dd12125f00fb45979cb51e23b15ee946", + "5d903cf6f2b8433b9863f13959c04357", + "1f83eb2f77e943118bb589ff77253550", + "7646f7866c984898b7e5924025bb032f", + "2c9e62172ddb43f0807bbed280448710", + "c6e9f4585a054e5fb0a86b42c94d0d9b", + "b4453b01bd6448e1871699d3cb825350", + "dce1e86d180848b2b05e0359d767f344", + "eb29a8245a31409ba42e29f40c85a3c2", + "e707d48311ae42b19624813846b557be", + "49d1113fc0dd4664b4517b07ab6b9f28", + "c6ac9a23da824d7f9100ec2f801e5a0e", + "b0d2faa768474d0eb9f223d4ed0bc6ab", + "2d76d390d7924e488ebdf4f9263183a7", + "d85455b881ef405da875619f035bcd8d", + "63f42695017f4e389a00c33a3820fe17", + "e2ec9cab2c714feda70b39e71224e3a0", + "763cf27bf28a4a61b1cc9c4e8f0dd423", + "6480933f2c614675847c868b765a3aaa", + "91bed897ebf140208c576b8754f46da1", + "6de248c26efb4b61b0702c2255891c69", + "313d1a33315a48d1b8e495790a137f3d", + "fb8befba62114570953cb63f1e130083", + "124392d37fd047aea2c5cf61f9dd7750", + "12df0b75adc84fe58e49e602308dcef7", + "29642e0a9cad4275ac78c1d4f12660d6", + "60c96bc3faa54f6094ee3b8bf0b691b1", + "20ce10ed388d4a90aaeaaa08202e4d41", + "2ef5b079669c4c1d996c303b083c4f8d", + "0a7fb227e2c147178c576bdb6c1c5ea7", + "67010fac463641f7904c97a78629d697", + "97818b211e0b44c79f452333e7b79988", + "4efef883e04a45f99eb2fde1ed60e48e", + "337e1cf840e94d8cbd1edf134b4cccbf", + "6bf69ad84c1e44b8bae38cfca8da309d", + "99c68556d52b418c873afee06d9d9718", + "852cbfb6dd2744bebfa720f62146064b", + "8037b10b555644deb06d2cd9db9497c5", + "8e87806126c448aab98c71055a501921", + "8b99562d27d84a29bfad2c33306bd172", + "980b520d5c334abaa699a62c9492cf2e", + "2cf44ae766904616ba5ba85db6107176", + "35e4554687fa437b9a404abca1bc87ed", + "e8d518d575b04fb39d2581a757d932fb", + "ea5b270089d848a187942da030ef313a", + "543c8e12a8ec41548eb182960df772d1", + "b753f606727646b7af8c4f43ff56b6f7", + "f8f227f6a07e46d9bb312282c309bbf8", + "ab7d4447569c40f9b81c83ccd574098a", + "23a1ba1341af41fa9648f2a81adec1ce", + "e93f95b217ea4ba3be66fdc801d0e2a6", + "25ac233d8af44b3eb5a4287d1c64a229", + "358113e5921b4e86905db8ddb09a18df", + "85f535e135844d678cda6420d1579ef0", + "9ff11fad2f814c53bc88b9c4c8a13509", + "1dd090467398430191a9b5dfd2d0a9ee", + "dee99f1ca6c644cd8af0da072c277cb7", + "96e96772a7564df0b417244bd2be33f3", + "ab1b676239b44c4bac53d652a4147738", + "64289c570aef49f194e7cb74c62c3929", + "7a8f89e68e2c4f0d9d7e9e7ae384bd54", + "56147c05ecd2466b8d9f6c2e3760f445", + "df22b00f6ef942278aa2be7899ec07e6", + "602e7f80462a4c27aff5e9882419c0d8", + "3fe0a42547cd4e10b88cd7920dd413b4", + "3550625c19194ca7ba7666d6d414f3e6", + "a4af70b4e7cf4eeea18d26e7c84098a1", + "be7b493951554b0fb4e126f57eceb938", + "f51877efa703411092451b97bdbc04b1", + "6182e09fe0b84f7891be09d80f82e341", + "7824b6d021264d32a5fd7894021e9461", + "3b1bbe5f59134a369fd613d2ef28c821", + "8afccda6a86743368429e4271348ddc7", + "fd8af04e86b84fca880c9bdd1fe0704f", + "0bf499c436754d8bb7ee0fb0df2d14e5", + "7bdc3b3bcc62494f9cc24bf5dab535b9", + "1a34ec54dbf345a98afed993c2aecbed", + "b57fa59a8e98488a8cc07d26388b143b", + "310ca2d8d93c451fbb680ff877ef098c", + "219e25d6174745ae8d9c37f53aafea03", + "04866880dffc4f78b34229ea1285e9d5", + "6546bb20aeaa4ff091fcf6cd4cf50373", + "6d496351c8bf485287da727c31fa8ae4", + "2d40c8805443463283c1b1547e50e650", + "7fc92abc3b6a449f881c6baba58e5866", + "64eaba9e990640c1ab63894bece30376", + "e5edca069e6c41dab5178f391ba6c76e", + "412e0e9990d5464bae1173972a4fa38b", + "e2b8e628073e4416b54ba3fa91a09c1e", + "5e76452dfe1146c4878a0368e9548bf2", + "ba7b015bf364431a99cbce9c38c3659b", + "4eb62e5c8a2640e382c892e03372550a", + "8d379e0e7edf4b9b82258c024c634618", + "21e9c031f3e74612891befaad6e228d3", + "0e111e6228a349c3983ec7f9a7e3d532", + "201fe2faaaf7453b897ac14b4ffd9f00", + "e1fe51efcfaf4c0da17b9ccd505691f5", + "fba528bb5a1541a8961c6e805c473108", + "783c55d5d243491896b323ef0499d9d7", + "1ebedb1386d44f7eb0d5c3de577c4d50", + "2695e29966104034bcb0efb618c6cae4", + "5bfb43ddec994a21baa0eb5e458cdf09", + "fcf8dc63e22f4821a4006403f046eed8", + "a432cd8831134a2c8a8f0576c964d3b6", + "53bbdf285b2a46a9a9254a933faa7d78", + "4ab324b82c4742e69576bfc5ba53b1ca", + "26a47b71d54a418c994ec43c0eabfa58", + "f4a521903e854546b8a694bf582dc418", + "e7260037761740afbfa7af7eb5285522", + "c3132a723f434ce2b94e2e563420ef7a", + "94b7956d69ec478c8e6778ee126d347c", + "db2394b5766f4f2c8e464afadc912b19", + "8dbd18bc6c144d04ae89190f1c857c81", + "953d35b8ae894ca4a300a6127bb867d6", + "a00202e0f144405a9966e58bc7b630ef", + "8dd0d3d040d64126a9ab2d237a816436", + "546dda26e1c34342b61f6973603052a2", + "03400f3a6ecd45b6aace4a36174ffd10", + "ed4d1dca8ddd4801bf4fa86c30a6fac7", + "5c5bc5a44cd849998233294e6fb52d1e", + "519cf15925d14223a058705ced0d8919", + "469b83d2c190456b8e7f1dcb28c3f1d9", + "3dc0ffede3c047a48b9de5bde0dafd88", + "4dce18fafd3d4ea4ad39c3a06dfe4977", + "81aa28d5850f41a58b666d4491731e5d", + "0f3e07963aab47f9aa75a2c157acb334", + "a5e61e7333034e1ea2b5b9def7ec8dac", + "5d23f5626f324b8bb8cd634c90a8de8d", + "d5afc8eaaf6f4bf3a8672086ed86d544", + "6fd6b4bb05664b8489769706b49024ff", + "4d659e1b1f5246e9af65e93f21d08774", + "25aef0a02c3d4e59921b628f31e567b7", + "032c38a1a8c74e2a9b0d8bded3cf4bf1", + "94a0be547579426fa4ce901d6eb8cbab", + "a590d257787a4da78077002d0257d473", + "3fb4b128ec7646c08ebb5623aee58d86", + "4d118da1c0fe4325a33d8e87898c8d41", + "56909c8cb27a4de7a4c5273ed13e8a80", + "60fde1a809e24dc2b7afc6bfd9b016f1", + "0dd16fc4b3df4fafa79cfedaf7ff8f71", + "5ca6b82e6a104e71936ff1dff91646f8", + "5af10566d7744ebca0827e996ef1378d", + "ea6f501a74634a0b89ba68d3640da398", + "456f637084774ee9aca8657d8bcaa139", + "454d8a68941a401287b844670c0646fe", + "6eac0832d89d4628b8309f4796803561", + "127af08a23a34458b35b3a8a401502e5", + "a8ac93b172c9403cb25f979616ef0a77", + "b70d5e5b42b4464d9a87de009190a616", + "24deeb105683487eb54250a441029013", + "7f4630bc6517464e8e92a378b7d680af", + "0f085668e17644e8b29fca2e60eafbf7", + "906c41f4f3c44b4e8daa9dc890189df3", + "4ffa3d242d624f0cb53782451f43b92e", + "122d3c85fad0478199b8b895f35075ae", + "d176fb35083e415fa4146829912c4e31", + "efdce2d230764de599cd574f5a20b55c", + "30e0571c29a0490e9183c10b52f34398", + "0bc2011018e2463ca119ebce4e15a94b", + "7b6f0e9c91f84e419ad315f318ced45a", + "adc180c348214933a016f902d83889b4", + "4476410131f34713afafb0703f4a9f04", + "64e34cad33634a2fb09d3bf37dae98e3", + "10219fa96ec643359b946924a6e3f59a", + "6419b8a1fc004446b4adf705433b7f51", + "f0cd53796b1340bdb5a4130c9e591423", + "d8f92e96cf0b4758a4c9bd5856163467", + "4fc98176958f45dea72f0f000762d0dd", + "a34ecc8b700a4cbc81e887acc6d98991", + "ecaad147e96f49f2a2158bbb3e7cb083", + "8505977020be4fd194854ad3d9808222", + "ec6cf358c4dd4cbda7be67f7846cbc9e", + "6ed5f68246594b87b33c7504939b9031", + "81d3e591008e40e5a1bade11bc472c99", + "5b9e03a46de84bd58d3894cab9f40a78", + "131cab3a040142688e47dad37aade68b", + "2fbfe663605e46869daa591c08d81de7", + "034dc69ab0a7412f97368607f378c037", + "8510bb06872247cebe29b15cb00ed6b9", + "5bbdefa4234c4a6fab4e8de8b1ce6d30", + "db69d2257ed74f0ea176572a2ed991a5", + "1183ab5f9fd945cfbaf6a9f4f53ddc3c", + "e0918443eee5439d93e4e6bc67ea5509", + "d8c9c0c8a5074afda8ade56e5a6e8bf3", + "e74dacf54f4b4f0ea62096719d8f6512", + "f2debd76b076436c80106a0428f9e9fb", + "65a13a04056c4f51a9c324e2a975b9a5", + "22f50f6ab73a46718c9f54e0ced9a8f7", + "ed58faac512a4c199cf6cadd55fb1b5d", + "097fcebca940470287600e01673e0494", + "903ed803932340b19104cf5232c5dcc4", + "a586d04e32c240c192285b4f2d46a7d9", + "ce7aea56180643f28481c6512586400e", + "3b160b6445c340cfbca05da84acd86b7", + "5d940b4af2634153b14c9a0423402ed3", + "6c1f6856ced04e49b956468cac114cf8", + "4b7ff9b66a4f4b33b36f58c89b2e6e61", + "1be92918ba3541eb89c8e9bc0759394b", + "8cda6e3eaa30404fa650b47f6a9bddff", + "50cf7bc1f7444c38b8a89e4c516a4fd0", + "79da8c46d3594bd1b00700b205e0d0f0", + "8d13e53faecb4888982787bc681a5668", + "e1fb91a9a91b4a7da1d2d3363dd6f89d", + "c36387d3c0e04b0b97d5757bc8601879", + "2c14092509974e08a96245598e86ab27", + "531e3d2d93df4c78a20783de0abd861a", + "be07b36086df441291df751c6d528d2f", + "2210c49edd554bb1b95be93af73a1da5", + "80de25d60f6b4148bdd8e5e55baf0c71", + "8cfad14dc1cd4a418e31d0a10e52b079", + "69ad00f6688749de9934481f3e7ea669", + "73d21c990e634589b0c130777751be28", + "2b585eaa5ffb4117a58a29f52bf6a966", + "c22286ade5ea493b890b3269e57b191f", + "65d4eef2ea6d40a38a07c5b421d1bc68", + "619c004f87e74191abbafe9395c22259", + "2125c39434ed4b3696bdff0a0bdb6fb2", + "a3c1f9e067db4068be7ab18194f59bdf", + "818c64745413452296d03d32bd240962", + "f1bab970dbb541ae87116217470c1cb3", + "3f195a49fbb347ea9e5049bfa0998d7a", + "e6c16dbe9ac942aaa89f8a378df3591c", + "47558534407a45169544dfb5d86b8c08", + "fa44d55f148344169e195249c0981306", + "758cb6df456245888974eb34aaee310e", + "2da946af9bdb4569852789008fd57f5e", + "7957e646b140495089e79720e6aab917", + "185188e95bee4edaab7d5e255b509c62", + "e56196c72f9e4747aa33969f65046ff0", + "ed9502b8951f44369dc23c73c6894518", + "f256203558c24ea09385a861b917c75a", + "80cb6f96240e4db4896d2a3a1c118baa", + "331ed2a44a8b4c41a35decb9d60eb53f", + "520d70532512441696a02f3971f6dcf2", + "fd7157646a0d49eba4a03e17fbc1cb65", + "01c53767c1f84f55ad9f46eb89949cf9", + "6a3f750c5be74bff8082f68a5314e063", + "8b8726e390134ebcba42c5cb1ad8e412", + "38b3b0b7a46e49bd94ed16af9be83c25", + "791f5ba13bfc4d659a73f076587de66f", + "4c54c34b193b4fe78fe1643bb8fb0ab7", + "56b25c34c5e34f2c870516ce7af494c4", + "61666fc11aff49c2927a94c60873fcd5", + "54f11c39024a475bb99d0de92c98de0f", + "2ba80c2563dd4d03a5f719caa0bd1f1c", + "6dd5f17680b247558f29b4cf66e8b732", + "b58ed4e4f6a447c083f4b9f444e81477", + "12c6fadb64db4c78b55fba123de817a4", + "646e334dea5249708138b0ea2d6a6fdb", + "b1f84a10b47948ffa8769d48b3f3bec9", + "2390dfb117f148d4ab971fef73a293a4", + "d6c314a387b94f31bc7cb8665877dc53", + "6712e5113f4f4a60af61beebfac606f5", + "c13e3058a6cf4acd9a92f42184a59d83", + "78ebe1fb7b354fd8a000b55775bf9570", + "9136dd94137742cd94e124d9ecd46c74", + "242fae6fa0c346d28a4685118ccd6f42", + "c7d77c9d5d04446982852800242fae21", + "2fab5f1e288245c989798818e7d5e68a", + "11c5431997da4d5b9c362e819951a1f1", + "ff03127865b24b1fb55bf58c4ae698f6", + "a9100d0735734854bd1741233b902fa3", + "78b49c06cbaa4ba19365b9864bbc8845", + "ffe84f53388043ba8d4eb211457ca432", + "5b9e8ba19b1b454f82898ac4809f02b2", + "5b42cc3b33224e5b93ebe84f808344d7", + "5e3e6f8692584d67956cc501b869e02b", + "edec8e53ce6b4200868178a24f376282", + "3fa441ba82d34eae85f3b00357613dd3", + "5849544053924fecb1dee018fa815bf6", + "6edb9399eb4640e18d1bdf73fb0b1854", + "91d8fea62ffb4ddd9dbc7798e09190cd", + "104e91f52e174ea6a249d2dd21facfc0", + "46a1a1e9171f4b67a89ef1f6ece787a0", + "b9617543ef6041c2a557e909d2990f94", + "782ff2fff45f49e79c9bbc7e8cf49da0", + "5f866bb034614cdf950826cd9694460b", + "92db5e13fa0c4c27a2689b962fc6305f", + "f15a8fdb25ce42118c1bb6ab695f56ce", + "1567f5f71c1a40eebe487b1b8f570250", + "a40d9dc2b3fc4ea2a31124ee522928c4", + "22ecbc49f81d4f9bada84a7638effedf", + "91a4c332a5c34f7da8a932dc6d9fbf0e", + "942c41501bc64e4e8b4ead5031407edc", + "c29aaecdaaee44deaab23d0523d7b276", + "ae56922235964bdc9ce8f2b6747b4eb5", + "23a69d599a7c47318e9af642e5782877", + "b618b71cd43b4c36879e1365e4ee8ad4", + "5a7229d68d66455087205806af4b4558", + "4df3ef1a7f0f4c41844cef7bb19818c4", + "99d6bc041c9d4f56ab414b771e14474c", + "099f508befcd4ebe9930502b48978042", + "74400c6fc6ec4ae0b11e381de7de2c04", + "4fe5b4e1c32c4bc3adabbaa86bf43ead", + "6725fa757760455a812f4684474c150a", + "f129ca7ee93d4fecbe279ea8d0d70562", + "c0175dba479042c89c66fab958b0c29b", + "25fc9ff88e5d4622b4e534b6524273dc", + "a8716a40aa854cb9adb26852939ecf26", + "9d5ea98dd34f4e06a5229577ec53228b", + "471624bc7cd84b74aa93fed9361498fc", + "f1bee2e8f75948b09fb9985e17820a7f", + "0f3e87f7cc8f4fd0bbe0e9a4f92a9b93", + "fd13709c8de049928cabbb8ccb87d991", + "c887f92d3d9441b7b46f4ed25476139c", + "b08d8f5a40894169b851d269b18ebbbd", + "a1d464af3b0d45dd9d227867c006b7d5", + "6b45d334ccad4773b06e05bfb648c45a", + "a4b80983355d40cdae20eec3f49ec80f", + "de20a2592a2245a6bc94b3c10fd55a79", + "42054efc9b404576ae5bdbc6dce8fa7f", + "fb5e3443ac1b4e1cbc4099b84c75fca9", + "545f9359f8674ac0a18836cad2fb10fa", + "f1155a4e9a1c431aa5264f7450dd2286", + "03ce973192634d1f8d5ac3880e532f91", + "1ec5b57a8354446886a2178b6e4b41e5", + "03febdfb56cf419d89fe2d4eaa0bdb5e", + "b99d652f0a3c48c8bdca5444e5982c77", + "9228c67bc67e4396a4cf286d4b4aed50", + "04e19437a0464cffae8872a725d3bc9b", + "cdc80b4a96a04cad9c94827ab84575cf", + "f32584f4df9545f6a0ad740f10de426a", + "261076b1e9e94223bfb59a0d5577dd82", + "b1e247a0f394455aa12086b3a79c01cd", + "c3e637ec11a54c41966acdb8b5352cce", + "7a0b72c7d01944a8aafab59d44eb120e", + "fd71aec20f254445ac6e618182436fe9", + "9ab7bd74b12d44d1928c6b0b08a92b85", + "4654e02017d141238bce04c8ed4c5415", + "546f95f3ea814071a515a05b42585cb8", + "05ffeabe4c094f95a8611ba854e56e12", + "e5083bf139484216911e99d2f3557fd5", + "d96d5cd080e148898199ca775519b593", + "24208e6a58f14bb7a890489c8484051c", + "99a54a8e06fc4e5a83c25dd315f228ee", + "1eb9bc82080f4d9a98ad696f26ab1576", + "d2c7221ac2634362b29ba3b15f72aae1", + "2916aec5032b4196b89ea9a2d1e9277a", + "240d85422edc47a09c695e2d7fbe2bd5", + "50c6945e0f8c4f5a9735be4050ae6364", + "a99fcebf03d54e1b903bdf01b589098d", + "61d8de11775c460f943bd8f6d311d89b", + "850f96e4ad3a4b4d8eb38c631e51fbb9", + "3dc49a977873417088384f5ae78c5a6c", + "31263bb85c694ff3b72f51fd96470893", + "91d1a4eccefa4bcbbd72292c8a509cc9", + "aa996d92464a4d2bb5d84377944f6227", + "97f68a87886246c0af5a7e9944e71a16", + "231c465ba86a4a749b3336f0736865b0", + "c130a2b8c219469cb1e82ee190be67ee", + "2f082f75277d4e2eafb53272cdc86ac4", + "9b2f18ab1a8e48f8a9436fd4c5c02085", + "50dbbee655e24512a0fb127a502f010d", + "4acfe7111dd34bde9b2fc04490d432fd", + "5cf5e29fd355402ea576d44f232da717", + "97a01b34ff944f928e39fb947b1ed09d", + "d45c39547a9846a9a54840faee0f8990", + "ef7851624b794d0a8d67d25fd97e0a37", + "81ada0e24e1647d8a0d6d0708a696f84", + "a2df68e14dea42c79ab2abaf0b0f8443", + "5ef95438498a4138a6d57cdb55cd84c2", + "a78c1a93dd124f7eade179e74236f0e1", + "68e98c763c044d038d810d94d3378cb7", + "359772180f324b2da2a0b6b8d808cecb", + "b4af2a721b1645ddb77168d5e8fe4882", + "2a533e3f8f7f4c34bd4b414793d3f019", + "756da5ef6d0249479510e6bdd1856e42", + "074a4a23e33b4c71b7cd200db490f23f", + "1e43f8aaabd946eb9fbeee5b61d6819b", + "7a967d4fac69441ea8fd12efff8b496d", + "269e532c269e40f4be3bb8208e206ecc", + "b1dd6e4881b648039779b58a9c82d72c", + "2b75877c9ec84c8b9733eaa496e7b5e8", + "8f4019fde97f4ad09c45628fa2a253eb", + "ae26f37f22404719807b2e6f3b812606", + "4fd156d99362453b9592f6ace5344765", + "084edab3deea4ed7a447b5a7bae72590", + "f68cbc8638df4d06ad10ba9a91d553aa", + "00f665c4abc04d48bdcb430131bc5b73", + "e867291098e44a55920a1f59fc69dfd4", + "17e2e06bed994e70a702e592dc3f45b4", + "8dd79c785a4142e4a6e077567569e9c8", + "046f34e625f540a68e43cfc2fa22cf4d", + "bd07508604ab4d11a054fad8ec8a09b3", + "167f7a55e1c74d478c63c36b245fa751", + "867ab04528614d6581599e0e27684c52", + "c8754e2753a44033940defe8be615966", + "7af1578ab5d045f78f6c59b2b2b54a6d", + "82118925322647e38a6ea1a33e3bec4d", + "2cc5c44b4e67438cbb26de6b20e72c79", + "df40ef6782884eb99af8fe39f367fc47", + "802d3eeab42240839e60cdca6ff99ec7", + "2e26b877657949089c1dbb5264cb67e6", + "a2438e34dbc84e749c49bc6b188474b0", + "08f1dfe418d2431bb1a6f48316208e88", + "2970b9134a494f068c5f69868a43982c", + "82b490fd735e472db2220f3b12d3e47e", + "ce6878e55df6491ca4a227da5f858579", + "d56b00311db345e087f63e1f90f6dbcb", + "12386167acf940c7ad2b548293f01b0d", + "526afb5fcb5d48da961c0e7d0e0b65fc", + "712a551ed8124820908029199922bd22", + "4f3799a5a2bf4d58a6e623b88607642c", + "196ed80846d94df29e8e5464156d6257", + "46602814e52d47eaa86f8f73d9ecdc30", + "f354633476a840a1bf0d775a22f854bb", + "ac30b773e4ee444a9ed4a52fc3abdce3", + "da2c388cd499491b9a15a0dd58f10a00", + "c3fce21cff474c03aaf02834dd938e21", + "f1f4f5907f34459a9fb1a09ff189c3bf", + "a0f0544f6f7147fbb0a92cd189fbe1c2", + "b1b64047a2d94ed68864e0f6e9bf5ca0", + "508537073ba64d3dbd027816a20f20ae", + "7bf4fb4426924cf5b2f6740951d2449e", + "a224dce2b2614ad1b9f3c50fca505818", + "3cab709105184154be74c2bd6eb9ef9b", + "fb95c7cd06bd4ed3b056e2dde34d7295", + "88763e24fba84cb8b513379f59ce9c89", + "84625e10b6bb40ddbc12f411e75c68b3", + "4bf8ad35caa84f12884c6f5ba6ad79f6", + "48016ceb77654dd7af9cd699148afecd", + "bb2a24ab8dce4888ad34fd8ee6c8f1ea", + "71030c18f36740e3adb8985ebc11ec3c", + "5847669dfe3d4ba8b59e69dc64bc09c1", + "61e49937f4ba4a80a326ec1dfe850c26", + "dd73641e18964587a8ad7ef70333103a", + "eff5dfd09ae74881b03b5cb27da97e3f", + "8fe316b8474c4d8aa86860eaef2702f4", + "68e164f1a9414c29820ac2eaf6d8ac04", + "69ed74ff54164b05ac7b565c6aeacc07", + "877217db76bc44d8bffa38fde9982b31", + "fb0a0301abf6431485b70e497aa3f5bc", + "609c328f2a68463ba1cc5d1dc2a15857", + "a4884ea277164aaca6f98a9e8e6708a0", + "02e5bda4ab97441e9d0107b2625af4ae", + "c1511756307a4c63af12c67fef603dec", + "82e943e3cfac4da5a20d189ddbd6abdf", + "f9945610ba8f40679ff07c690d4560f0", + "8e24a545ed414e6393d1ad02f4395faf", + "5f98f66cc39343909370bd8f70aa1e82", + "0f35b95712d44704a5521829a5ebdb42", + "780876970a2c4106a98a838c4383a847", + "ee29e6033e8847bea0cc0d952b76800a", + "9534544e53bd4353b061acf0bdc6c8d1", + "a44930f9c14544a6ae6967d5544417e8", + "5369d70668b441eda59a5e1dba46ef1c", + "b08b925ad711464098f609887167f507", + "8ab62abc0450408d86c1caf6873b5da8", + "d3152fc451dc442b8f4a1ae87859d39c", + "a693449e49764a7f9e1a93d437bd794d", + "fea67bc5f8d0428dade7289d9f85174d", + "57f5ce7411924add8a11fd3350893392", + "bf2c6ccd0438403eaa5090b9b3e062e3", + "c6c0f931fba24903b6b480abf2be4ebb", + "aa77f781162b49439dad40dde14d2228", + "501b2931f04b41cf8e294cf000c67fed", + "e6669ded739e43b2aca0b375c2d0fd0a", + "ad89f59278e5408a8dd8112dc07929e6", + "7be0730ea025439590dc10ac7b4e127e", + "b89b03eb963740cc83407ac626a3855f", + "9347b02b8e2945398dc54d3d8ff6f5c4", + "777b929d33a2456091e8ebe9c7d0deae", + "ec62873d22dc46d1bd52244b792c8c44", + "130c604d3c0f41a6bd3e8783620b24f2", + "e0fcb39a40ae4a79891d2b743b073416", + "2445d22ade0e42eb9b5fc6a0bdd00cd9", + "454c2acddab24e718736183a2f979a9f", + "3e6446859fb84867a74d73468c9fcbe6", + "3835450f8f4f43e8879d55897f7713a9", + "6ebf56eaade94c5dbbb662cf434ea58b", + "7fd244dcd10c4489ad15ab29f665e41e", + "d0827a414b0540bbb9fa2d6ff3f38e16", + "824175c1876e4db9bb7dbe666affff06", + "2f2c3113cb0840f493b5e46d36628642", + "1e1cf17d40d947deaa25bfc48effd1b0", + "9e5d8b381821442f93c319607c12e18f", + "e7b30aa0ad754744bb5344bc86bf794a", + "909a985281c648db897ad1dc1a85905b", + "2f1c112f6ccb456fa633e9902056d488", + "eef14ac53ef142e882d0c961ce67ece2", + "8a1a854958604320b172d03e7cfb9768", + "245eda28e866471dbdc6a77d19d66a74", + "eb9354299d9e41b6a986ae9f7c3f6ca3", + "fa7e295f28494f9ba23c07ccdf54666e", + "caa93330b22744db80981cd4a256f5e3", + "2bd9c2ede05c48998741671e936aa9ce", + "c1ae384218d14636be6fdfe2ac8414a4", + "2ab903c108e942bb992a194efa0b95b0", + "5986fa3b3721497eb88b94cb886b3f1b", + "3f43fad9e7714788a81ee27b0a39a4db", + "97fcbcb2c47845c49485a271b10f97d6", + "cc1e1a66e7bc431487a05388c24b1449", + "61314c17bfde48ab911356b9f04ed91d", + "a2a46facae184965af4e5dd138f4f9c4", + "8ea6bfc85e5d43b881dec5d224583f19", + "8412b78b8d6c4f5b86c66f49d62681c3", + "8c9bceca966f4d47b2a440a1dc434989", + "e0c2951ac0ca47b8978b2a6eca426c3f", + "ad9e59ebeae9456796439d5464d7dd08", + "1e52cc305b864aec90f3eb5633e2eb14", + "48ee683c9f194d6c8a22f1c1c2425294", + "ab045945871144118dfcdc7a94d23a67", + "7d2fe8532a1742beaa6b15d22f8de53f", + "9c49bcd01350439ebecb0fa78af6bd71", + "072e3ae09bf84f2f9b8556e6e4f15e5f", + "5951aa2f3b584186b43e503be52627fd", + "bff537fb09b641c59b2ad123da0ca3dc", + "bdd7787d4615463c9b7e93237670d10d", + "7decd476a5f0454d8ffe9edc21f9ffe1", + "860935f99b5d49bc880c8b08a2f06a94", + "15fb7902d1b142d6996711e02ea7a357", + "9ded19c9334249188b060f989eb7df99", + "44c81c84860844fbbebbdcc558548420", + "528a4d8575ae4bd7b010224cc5961a62", + "4d18ba843ae24b94a5ffc77717256c8c", + "2622e68968cd443db5c082af71ddf5e8", + "68a593d7269a4d528ea6e412215e2928", + "5b4b1f24fbfe415fb18d1e9ce20d2d6d", + "0a8fd74072f8457db07182f7411bd4be", + "eaace4e2c59843198f0443243a1f26f4", + "d559f45b2d13437b9681a70fed5cc8e3", + "6c9753dd523747bebf9ffa89a81cbc3b", + "a0bb73338995462ebbdd4b11057773d3", + "a35b30bfc9d7420e8a7f94a7b2c205a5", + "4777b5f5839e47c0864dd6d8181250c1", + "7383de7d92614184b0e10ac7e20850b1", + "a2ad7a6716cb4cccbdcb17977c9702d9", + "16fa3d8402a84f52aa8d57d9a41f9f97", + "b14de644bde5452dbc73e0d82995495a", + "9043d7516953498ea001f74914e50db8", + "f7c762e84f18435fa639e20f61b792ec", + "3ae548d49256430eaece8eb6ee1d0bfc", + "d60610e421414a4882321cd9fa3c12ea", + "ee1c36acc61749f787be7e4a694e3b1f", + "4bb3602008b94a0eb75a704a90c00ea6", + "e79b5660d8c2406d804485257eae6c23", + "d9a7e407c64a499d812487043c4437e5", + "67d21a5b72a84aefa9a045b7fba5726e", + "928c257acd794839bc912a8df956bc7a", + "56c14e85298c431580176f5e66786442", + "013bab705a6341c687af37f7261fd312", + "c212b517cbdd4fa1930ed31a45670d39", + "cadccdc1d08648a7be5b0233ba42ddfd", + "1a05d820c3e54ab99d110922beff9be8", + "307b26004b154ef680b03474558061a6", + "7018d8578d6b4ee7af010d26eda1ecc9", + "f46ac1cabc404c54a86f15d4aeb58901", + "f23573e5145a4e5096bc5db4d50facd7", + "047462f5fdc244339511f87f4df49446", + "dc063dd41013484190304d68ba0bcc3c", + "6ca6bbf15371417a934e464b652f8ec0", + "67e00f242ed3408594a39d314892f741", + "1bc85d3575db41809a3e111fed2a8047", + "241f7eed6c9340118127b5dd05a0c237", + "fab401e6e0a14c88a3f3bc994627e313", + "6da9fd8b9d224e1c8a346f397396623a", + "beac0847c065485b96c383979bad3efe", + "041cee6b214f4366986e0b4ca1492967", + "ba7e9af9841b4747aff873c9b383ab37", + "7df1c33323ad49e48c4fc93a01873153", + "6e103a49c43b4fb3ad0086cc83b8ebc5", + "acb2bdffd12d45668298c23ab51efb0d", + "57d5b09cf38b4dab99c97e25bac7760c", + "5ef680a1f4f6495c9fd3ea4cc45b213d", + "de75f62fd597451d9121e970429a313a", + "945c394dd4a24602af03d75d5b762932", + "15dd4489ca3d4c0183b2920c67f96d30", + "be92edf0f81b4c8ea27ef110b4eaa04f", + "5d763e6c435f4713ace93fb9ad1b5bf5", + "c87b96181fd249ae8de1ac14575ec475", + "ae89e9c50db54a3bb52e8a72577d378b", + "f336d7727d87401faa972be649fe3cec", + "e1e631372a27498ea2a2ec8fb05fd250", + "97d56ed21a3f4a8b824ff519196ed2a9", + "2a929abff35444bbaaa868fca5d934df", + "baa53594134f4a4f99d96ce4ba25492e", + "eef888832e0643a6a80db6789be50541", + "48d3358906584e8c886fb087e39f0d4e", + "11a459d53cd04ff69da21d96ce848aec", + "3c6b18692028416cb21b29ca43eb600f", + "4025af156efb4e999e44ae0ed6546a6a", + "f9dd6799808741d5be7078925b89629c", + "0cfb4b98ab324643bee6c9f3cb98acc1", + "fd813c521a3d4c648806050b7de0da0e", + "a51262faf0084b0b9c302d6cf1a95076", + "f1a7290f39a44a7caa51ec87ac92cf86", + "6e815d383a2c401bb1ededacfe079734", + "690310e9ed434c7b8520c73fb419fbf3", + "a22e4c087fe14d76af6fffcfd0d42dcf", + "52f93d1a80ef490eadb55c53450e4330", + "37e7bbe10520431389479b7ed5bb16ef", + "c5921c1bca164f609b46ca14b032b2cd", + "1893b247c3e844cd835cbc1934595171", + "8f3609a949904713b692512b84f81664", + "181cb8eefacb4fd0b77c6c28209b82a5", + "f219f29dbd7f4b28be84c92e5c9507e6", + "36a37af9cdfb4ccc8e129910a35fec92", + "af51fb8b592746b39cfb0423c9d9b708", + "b088c80c5e054885a6c8f33cf4cf7726", + "45e3468808f844e8b56826655a2573f7", + "55c815ee24724611a0b58dd59cd482cb", + "c7ebf5a3f3264793b6f7e8d194c23cbd", + "c2d86a911115433bbc40fb1d96e7c727", + "d54e1c79c9ab4e409d2107fe7eb999b9", + "16e0c6324c0f4473b6c02bf9e58e03ec", + "d53d4663ca7943c881a9a6d20cdc7e91", + "12d0a13d523b46648435d9b29942486c", + "f1ad2a5893e7427cb4d7d18d582d8342", + "56e04a2391d943a38a492eb3300bd6e1", + "f8a25f8a4c5345e9a19c201da2edcf33", + "77c971f5aed6409c89e30f3719307adf", + "fcd63f39aa3a45fc98e7e4ef7193a929", + "2b82d90a50054a58a9ea607e1bbcb815", + "ac48f997ef5448729f73b36700336e66", + "720814e7f1cd40ffa5ba8f82b5357ae3", + "47259ab6afdf49f798f4b4e841c06ccb", + "4ae1f4b440684b7f835e34cf10729459", + "bf18bfd89efd43389781050230467d58", + "e561533cfea045dead0be4d3423625a8", + "4816ff67ec6b4c3497e6b28b7f04ae5f", + "8e1fddb38fa8400c9fcc784abe29aaaa", + "edc325da45b249a88cf3fa3b350769f7", + "f137c64c274d46ba8a7157450541ed0b", + "cd88e7a2de6d4ff7a26da0192f132dd0", + "a90c581065bc4816b3d1711b1d8b8a2f", + "726571b60a4e45239fca5756c75f0691", + "eba77c4126d2458a93481231c4831b3b", + "f8e29184e97541a18880d2a48637070d", + "bf99b14f3a054215a9d9cec9903b7ab6", + "c9e848982b4e49e893d2b9b55f2d01a8", + "cad444be44ea46eeb624bccf7b3bd7ef", + "2dfc0686a2ca4a868638a8850774d82f", + "09ddb48d33a64d6fa67ee82ac3bf8715", + "da7575dd48fd42cf9b6b9d4609108e7a", + "256e1fc581494709bef4bfb5cddea69a", + "51e350cb42ae4c8eb7176f21778196c4", + "440b3d9c1dcc46eca7702a30e52a851d", + "2eabf0a7f8ed4c58ae09da04929e5465", + "f911589e275e4c60963d52b31bc0b061", + "1207c326615c43a78e9944c33ba401a5", + "491a8f42d03c4af5956925e7ab91a1dd", + "a815f91b472649a0a5c7fa4b275579b6", + "7f20a97a3250400aaccc9af3eeb7f155", + "0dfcc1463c414239870ae34058830396", + "810906c7d15847c7ad082b211795e1cc", + "1ce91697022a43bd98fed14c8e1dbf27", + "3a7f33f6a10c4a8bb36a053a203a4eea", + "db09c5f5fe1f432ebfd02b45f7d1de20", + "750b7ec1cf8c4eccb29a7bcdbab15b0a", + "2f11377a2e6049049473f854007882d5", + "129028df34944847bd802f44e0d6b066", + "b4f684d303f3413fa1861e69964cf6c5", + "583e886eb2334765acab222cda7d2bec", + "982666c56fa44e1bb66518198e3ae9f6", + "8489b49a1636472ab0ac6dad84e72791", + "ca109de3e8dc4249843ecc2ced8436d3", + "4ea00ccc12524db9b5a229ba969038c0", + "5fe985508f124c788694cf61803ec3dd", + "56a91ee1e71a4d1ea8a5c8d0c11f03d3", + "962a1b6e639e4b1e8279bcf0280ec8cb", + "6d39153a4cef4ea3b38cc5ba9543b37d", + "5b46a4763f88446b98b43f63549f8e8d", + "86b995b879914b629af34bcefade3bf9", + "f323dd4bb9f640a4859bd8dd31ec233c", + "c4666e51e7664fe39eeaa7b82a766ef0", + "cce43dece37b4914a72c5246e58b35dc", + "48fbc9e640db4171b252ebd776a8da39", + "64bf4fb3d17d42b0b176af273ccf0bf6", + "cdc4064cab1947e7995598aedc17ecc8", + "7be5302628084c94a964cd703cbce9dd", + "727d22bc8fc44038a5a68827db386a52", + "fc7d79e6ce5a463093e24925c7518c93", + "c2c000d5e6ad48d995d6e27d80dd1832", + "d5ba5090dd034ac7b3dd5fc9847c7656", + "d240a7bf160e48418c2f16e91cd62987", + "5e77a057585d47309d2605934197669f", + "f88ab02d623a4bfeb6a11ccf285f1db8", + "72fa5a80cbdd4c07a59f066d9b6419c3", + "8f964a73dba945eca40abead9e4e12e5", + "05e20fa552964861a656a9fa9248f641", + "b60955319e424192837a2d9a7196eba3", + "a58a3c9672fc4fe9aadf7c6f80fe52c2", + "1fd4655a17964145bf800005dab5c042", + "c5efe3b185634107b5fa5117ef0a04e3", + "a92c8a97702643cf9a379e260a36fd69", + "e2a3f48382574bfba83e1ae8ba52860a", + "2c6ac7b3479b46f2abc57cd8d9632e1d", + "fa56c3d537e940bf98dfcbb43801d8f9", + "c3e6b6d63d7a4a0ab0e3cad09f9a082f", + "326423c8c2474960ba3c4bef4dc8eec4", + "2ce58fb8b361418897e2cb2f4085029a", + "5c5d1c3bb4494ed9bcad956b6b4709d5", + "b8932befffdd4992ba20afbd91e65029", + "4d70477854ed4108aacc98b1acf671dc", + "798ffbb44f334de79b6f7185d762cce0", + "230fdd8b48d24afa92789106d828e0bf", + "ffcd5b21fb21411d828c4f8a09453c4f", + "252236660fb647c4885d25e2b629386f", + "43fdf229319c439b9dd4557b7acbd0d0", + "f1ba62649a76439594d7ca0a20ca4295", + "99912aa35c08481c8db430bccfb264b6", + "24bfc22fd52f4a2096ea76bf3c759ebc", + "efc971c1e966434d803e733bc2f679a1", + "53b9bc12a01c4b1688a4b560c9f5548d", + "22e187363dd14bc3a3e1b4611830236a", + "15ff40eeb9a14a67abf76e2791527a19", + "e70b46a54b9e434589c843dca18d846d", + "a53d773a23384998accb5f88485e64f0", + "f11413f39ae34684ac6ecbbbed58621c", + "a76bd38f0af1422d96add0d9606e5fee", + "a7f5127362284174bb723fceae47732c", + "7133d16751574949b35aea262e2c7836", + "f0558a7a16ad4af2b5ee29cc6985a8ab", + "4a29a96da559495ca9ff2c06847ebbe9", + "68f8bb2d57a34002b9087a420ab8c39d", + "24a294b94176474a924282204da22423", + "5f2d693a060546c7acff61f9c39cdbb2", + "1d909b482ccf4d3f8688702bff9d78ed", + "21e51692f60e46ffb89428d8b4492f83", + "2cbeb94fb96b4d138a56a61f65789ac5", + "330346369d2b429e86c9998eda2e2e68", + "ce5c3a6781574d0093ee3b7b67d61851", + "47ad9cc7ac81423bad673e33a34ed81e", + "5a02716654ed41ccbcfa356c51c4851c", + "fc8f1162901a4e38b506fe1ab229f296", + "e74836a0171045fdbdcf341eecfea892", + "e59b9d14b7dd4407a94b0ef2baefd19e", + "4c016736d01d4718a82af036d08090ba", + "b5af0fe19a3c47078ad8a79798a79017", + "ed58014072a64680b0fe5ce4cac6234c", + "6ef94285eb3e467ebc3128110b325a1d", + "c1f5b4e46fee4c2ebc28737898baeed7", + "ac8332be15f345eab8849f957420e424", + "f49394be05c8468aa34690fc62bcea79", + "a2a6fa541b4b4073ae823caea04f9df9", + "6ab71f99b8a44e08a20134d32e9c8a59", + "fdf1673f1f6d41a99a90312db9bb2351", + "cebde8a7dd0a4f82bba900c8dcd3f7fe", + "460430af0bc941f09e48f556ccc28f76", + "298dff4d018c44e8af3d7209bdd36159", + "dcd980a74cd44a1dbde7f8ad4d5818db", + "00380c3f5cf548c9846faf3c42dfd6db", + "a14f9073c64a44dcb25994b567182a2f", + "0d8c23a7ee2b402bae6e329fcaafb880", + "c9a94056e33a4fe29ead7bb2464218aa", + "7e7c54f27f0e49528e31b43031605dc8", + "81b129ecf5724f63b5b044702a3140c2", + "3e5393bd35e34531a576e22d45611060", + "baafc6537f2c4b6696ff0829cc32f772", + "df0b24ee365f48db8a22569ada621e74", + "6df175704d624090ac11350b48476f54", + "c87376d985c044d8b3ab4e03310bd6f3", + "76417b1abdbe41f2ab4489f03f3d3b8a", + "fb06d9ee4d0e4225b97ad1dd387f42e6", + "9cfa1de8774843c491300e68ad96f10c", + "59efc2e75b26405b86969819b6cd91c1", + "3496c75ae3c34a81af7a54e50e95faef", + "441d04f0b28b4949b693127f75e113e7", + "b4b640a1b01d41098241c51fb5798d14", + "1faedc70b6bd420ea747970d7ae05631", + "c347c6f0357a4deca3a47299c1d6d83c", + "8bab11d8be40425fafee8560aae60d7c", + "c8fe4f012fed41e0bb629b8a8d20c316", + "d0f20eaa1b0b444f9e8dff8bf6498fe4", + "4091e2ef8de54644a5ab68a646d8d9ca", + "5545e230446944ebb432e73826aea606", + "d00b0f80275d433e9946d43a6ba01e4b", + "548c2d72088544168c7ae45b9afa9ed3", + "b1d5762b6a1a470ca9009cbfd368e9f5", + "d5a5f0a954f94bcea3168329d1605fe9", + "26025864a0364c0b9af9a4d1d6846d9e", + "1eaec68364bd49cb93c155132cc68add", + "b8c382798cdf473b86ed497a34770b35", + "f58e43eb40f244f2b1c9b399e43a9bdb", + "3e6b91194c6348c0bc0c88d8d2f83cfd", + "c8e19be6fd024d9c8f5b6cddee74d92a", + "55110a5563f846ac93c1c35bc6b80999", + "dfe66c9fa01d4d3782700395d2cd634a", + "a647bc9f973e46178bd672c7211b6a2e", + "c4a71f42dad84a6da03b35c200f3e399", + "79ca700e4c4b4b58a058df6ad332b3a3", + "a476e0616bc1419e92a187d3a7044248", + "06f5712fc32a438899eb6a2e24a92121", + "e92a4d57fa4d4791990f102f9152ffcd", + "01c430c211d742299ece389a2dcbf12f", + "e283aa7835664a74a4ad39afb26d2ef3", + "0489ffe0fa2742c18b4de1fdc8dd6936", + "686a821ad87d4d9e8fdcfe15ea58a06e", + "1250a980630e483bb039f2b33b03eea2", + "53e11060a7384144b1ba89dea86414af", + "9faf3f5ad35344b0a530b0f93dbe2840", + "ce23ebb7eb65459bbdbeaffd9a62584e", + "51ab56d0ca164927969792937db93a2f", + "61e84e04346241419ee6e33636fca3ae", + "49e749b81a8845f3840c4f443a78b264", + "282a990de8e24cdb9ba9d3aa093670a0", + "8acd10b3f80344d79202d8c2dbfa6e61", + "f0452a4970e04fc6960bb00bf02d5890", + "cc36e7c5445a4270b301f7ef938e671a", + "fefe61636e7e4670b83f38943cdac85d", + "63d36a28e7a143f8905869c06b2c3bf6", + "b9cbd98827dc48f48c0086f8f08f1c84", + "c83dc4dc30ac4116a454ba396edf6803", + "889385bf89b24564af1385bc0658cc10", + "cbb6b9dc27b54b3992e9255bf995c310", + "257f44c12fa948deacca9995dbb70e7b", + "30711b2ca5414752ab2fda0203557fee", + "6a049f880cb84d26933ddaaed1221329", + "c1ac2337672e4616bcb006876c6de599", + "e6b8de64e9364eb294b3b0a530080fdb", + "1bb41621fac1403e9c11aa45b349ec72", + "f3aabd68e95b473d9375d830e6f04dce", + "15880f6cd0f544889704fbacaea21592", + "23ddac5a352e488da455da7e6f3c3cb5", + "745e8ae2a77b43d5a45f3bcb8f438164", + "b9dd553e4d4242dea05ae437695f4d66", + "adad37cedb284f61845c831314a2b9fb", + "38140fe53bfc4608afdd684c46ac3800", + "b5d778728308459489ace2e98ae03e93", + "2f716cd34c4944188655b8d64ed05438", + "096263d8e9e0467490d46f9d8d419f5b", + "77687023f30f4784b8b430e728e2f166", + "94032d9c7b1746079828b54b5d02c533", + "72290e7174a24462a217027fae5fde28", + "9a33812786564517a7d644354131167c", + "ea9f3e4b09d048988864d6d373567b9b", + "ac43c76f818d461da0282822b1b49cb1", + "f825c82b549045b3b090af98aab40a60", + "5ba18ac80fef47a8ba9fe7e399a3991d", + "c3fd4e4842b74ac9aa194681b700ef85", + "f274269004d44b1ba5ac1473f458ce11", + "c149f9d83e574e72830271f74e6bb13c", + "7f665f5bdad243869e1e0c61679bae60", + "4f45dce0e867459ea0a545df75535d64", + "3598d4508c8c4568a35e2ed00e4cd193", + "fac6cb6cadef4ebf962a772feeeae7c3", + "36488daba956473086ea068102da7ea2", + "87782fa33bf343d3af8cf53f347a44bb", + "a80f4c1f948f459db4dc3ef65e41b6d3", + "ac2076c22a474f5c9b533727966d88e2", + "a93a6ff3c8c14bd9a9e6a00a7dbde62a", + "1e395b4a15254ded8a430e1bbbd4054c", + "3cf4f4f0d1704140aed771ee91489da0", + "7b8462c58d7043d4b8fe726c20aaa7c9", + "1e0d027371c8434ea2a336540c787772", + "45ce9c8bb7af4327a5b3736f7ffd60a9", + "aa793558285f4396890ec56dabec1d68", + "fd05cecce82346e5b85949a0e1be7dcd", + "7e90085a20a74f819ad8b94a9ef39631", + "7a9f67c3d0584869927fbbfe85194187", + "24fefce253dc485da154b6655bde8133", + "7fc17c66a5eb462db209abce6527671e", + "1c6b102d35234ab0bfc529d166e64c5a", + "4dad2cb4f7ed41beba55d6d97400b00f", + "09efb6669918437383a7e695e27dd2a9", + "bafc16de9a22439990f54709a68ff6e6", + "9d701b48826a44df831e7e321754ec5d", + "5847d39404af4314bd8af0b37bd12dfc", + "7cfeb5182e0e4c6a921667ca817fa575", + "2b7027a9753e4e529bb5da547a949b30", + "5d6119734e064d78ac12419e028a6b14", + "acddfc44b5874e22bebc9da084f9c953", + "26aa1218680449aa843e84da2cd36892", + "f66d327b7792417c9fa7a0b01061a9e9", + "7342b56116334f0c8289b7ba497050df", + "b88254fd0f5d4ba3908d1e5bb82f297a", + "e83968579ab84a4787a508a855cf5e27", + "5ca9d35f5a7544fc8cd6a1569420c322", + "89864132515245ecb1093f3ebffc03ee", + "5fc9b7f0aee446b5b8ff0c3a77950a1e", + "b2a393020cee4f54b61cca70ea95ac35", + "0a6b884fa93946278b1d9baba2e24a0b", + "c2520aa7627447d188aec6c002396244", + "b26a53419075442ca284cdf1d5541765", + "1d1e3ea959c94c1989083ac5b85b7a18", + "e7f45a56725c4ad8b1a722b23c252e4c", + "90f173ee66f343e4ac0058bdd3242367", + "333759bcdae74bb396deef5d35f8ee14", + "63f5b91a92f94ad68892faf489abce8d", + "f94d3cf8ef574b168418709bcd2155ac", + "132e02dedec648128bafc0979c32399c", + "28c7af955b8547ce92264df91c1983d8", + "8566e406c12d4143a1dd2a71e0b5fc25", + "a6bc0ad223db4f07b740ff91fcd766dc", + "f9f7ec3895d540e69e6671e0bd85452d", + "e5263e91e4154fbd95f424b29888be78", + "7473cdc686f04f4183ab64cb1e764437", + "19541e167655499b9e15dca3798b8b68", + "8b96ed9d18ee4341b13084658cd64c7e", + "09b36bf70aef439ea88350be412db5f1", + "6f00d54f5f234b61a7b7d9eaa1b2efa8", + "4037a5122c294a19bee0e62042ee77fe", + "9817719b5bc64e3ea015a7a1f9fe59a2", + "c4bf4ed4f0d744009b3b65a1bf81cf6e", + "c594cb43f36140c8a422b069d6d9714d", + "ad0f9220657c43fb89692dcf7a6b45a8", + "1bdb934dcf7943bcad6cea9a687d8af2", + "be9ea98f8fba4883aa5419efbb25aa64", + "9b61dfc7cf60428a834cae9f6d5495b2", + "c7eef8719c1d464780205e81b1d82c08", + "40141581e7154d65937ba4ae75284e38", + "af311b4c32fc47bbb633874f7cd867a4", + "faf4d744f7e84a1c88cb21c601b98ee7", + "a3a05071650347acba62ede058c89816", + "fa9f091f14124896aadb847091b0e48e", + "356cccb4136e421ea0cfa78e2d007bd7", + "dec837b2107944ef9211bceba0d12f13", + "b4f8f019018f47fdbf35f0119034e240", + "2a16154214014fb0af9c8bf4fc6ea1cd", + "07b31f18c791436d8f3d21659f21f83c", + "dedda1dff9854517af354fef0d50753f", + "ced850c3f651463b8c3d3ef08bf6db02", + "a6ab53749ee9432a9872564d2e2ab5f0", + "ebe62ed6dd9b446a9c9b7d7d6a8086e7", + "601ed78848dd4fa0a9db1117bf688671", + "7674fe6adda84cf08512b72fee4f0a8b", + "d6b2561de39f423f9c7a2e7944485beb", + "1a488d8012aa452eaae5ce0a2818c36f", + "5139e2b96d2745d19ba5148239197d01", + "673a0ce082ad42728f90f3649a6fc727", + "fdcb5d8fdac247a3be20c28f4da2b466", + "04a38745f1764194a7a4bd8ad5bec6f9", + "a7440e534ef6444895a6cc5feaf15a33", + "50d03f602bc34a398d7255e414dbf507", + "f73b67a17f9e4c698764fe2191803460", + "47a4c0af8f114070bdd74fd0e0b17b23", + "3b61e28b2af7473f9be019947f95498b", + "05366d30abc54c178d808f2f0d84ee57", + "f0478a8bb6b4419886c2817001509c42", + "9f705c85b42943f49603eeb739310257", + "c25171a3af184649a4ba2c30610ae9d0", + "a27ba021c9ce426b9ca68a1ff5c6cae8", + "ac4e710fdceb42b9bed56733f6c47e95", + "ee88784602ce42daba6824b19e87987a", + "4011fb8484074e93bca7f6b5a89e72f6", + "44479b53f958471c8067504edae0e130", + "4bf930218b60442bb3b2fcebb3ec4850", + "6099a956fb4c4a21b2957bc2e4874d55", + "705cd9de52814dd4b79e7dad46516b37", + "5426e6f3a789442eac69ffcb53710a26", + "e6ae56134408447d98a4e478ae012b2a", + "d244d166eb5a4e659f5264a536443bac", + "0289474b7e6c4f0882275bc1ccde6b5c", + "79d7d10b30b14ae09f2ef89872868560", + "d61242df068e4bf69cb86b5794e58b1d", + "9f8958d54d96451d911c75f65ff072da", + "50e8923c1d5e4784bd4e9ffd8e187613", + "3b4ee19c627e4fb4a3305621cf925aa2", + "3f02cff82a334e959c7d71f1c7307672", + "31aaafe7d95e4b548bb86a9445754192", + "9b095e3e435948688a1a9a832b9df756", + "6ee419b81ac2499a93237f9094c3b874", + "2f2a6a6f30f64fc38fca1c662903b591", + "af930f73ef304cf4a4a6d09841c7eba6", + "28653c6cc47940a8aca65745a700eda3", + "cf692e7bb80f412188778649b1a7d443", + "17bdf341fcc047888935f67a05dd2fea", + "ea7e6a8cd09b4cb3a3b88d60c7f22bf2", + "5eb9dd2080bd4ae79a047b06d4a4a0a6", + "67b0c5735cfb46fa959597e2448f61d4", + "89e7a4216de8417a940cc16fb83f04db", + "ba8b7a59eda34d1d9f86667594dae7b5", + "3d33ffacd1ac4b89b983ca18be2b80ad", + "89aa5f17e18848ca90e8c113359dbee9", + "8017ec74b8af45b69acb36f2cc084ad7", + "48b7012e722449fe9320471dbba6f32a", + "ffeac94c84d24c4aa5cd51075eca6c9c", + "8bc90676b9464068a65f324a553d81db", + "eff40b1550e0466a9c3273a519139143", + "a5b2875156214bd4b62e43db65c5bc60", + "324aade21fd84ae6b994418555fbaa18", + "ff4ce9d1854f40838745e0e25c24b946", + "6650f4cdb54b4be1b5a328c1a9f1e414", + "33344266dad14c4593a0ad37b140e333", + "b23dab375c294e958124bf82318050f5", + "b6e895f7dad54be4b103d97ee5098308", + "3ca3558e2b594758ab50c8fff8ea0b12", + "654fa56fcd98402081e8c2dc4b473f47", + "8f487afb06fe437ea7633fd1974effe7", + "836699c495fd44fea12834998da56c84", + "e791351ccfd543169030feaab5efd927", + "9592001ce91647fea94c554e29ee9d8e", + "4bd91490eb3943ffa9d7a639a55e19ec", + "6123d1406869491e80b18c8bccf38660", + "3e2eb53d58fd4bd5b8269e7db7cc39f6", + "07be4c07a57341c5b537cacaa3c7295c", + "113d04df1ee9432bade35fd6276dbc80", + "70ca81fe6f1546efabbfdbe5cfe81955", + "0136bc280f0d4977b528af83bd3b9642", + "04e1c4b024e64bf4a581e328cbd56c95", + "d098b20f4fec45e0889984e557728cf3", + "106ea1a841524dc49f652d5ce7c8b559", + "f7e8bbfd7d714490a8bdbb0b44e60c85", + "10d412d46db54e0bb1f2e8e84668fee9", + "e8a2859db612442ea141b4e3af48cd58", + "4f758b800ca54cd2be15a8755976dbf7", + "974e74f55bbd4dc9a85c4a48fc987a18", + "e7bf494054f545778647321fd9813bb8", + "8e12234f242d492cac7b1cd3f0347e42", + "df32141a7c66437e8d7923c7cf0758a9", + "e9ed215eb0904811aa56b0b526795bb6", + "3e4e78ea50844879a87064c6ee021762", + "b3a19dc30bd9492086b8d0035cb9a840", + "01b4a5cf456a4b4e9851ee24db9002bd", + "fb3b1c8073034d95927c3a91af195ba1", + "5a26adf518824b7f84aeb3367b07d3cc", + "f430adc68d34485e83b15b854b719481", + "7b973295fdc445ecb26a39c4bb6577b6", + "9f25e7c83840435396225970ba47b75e", + "634657b52db74fa998acfc4968b4c8d4", + "f84fa637826a4b8eb19d6ad4f9ba414d", + "60fa9e11fb954927b80af21855258989", + "e466fa3862724a699dbc094a1ab46b0f", + "fd5bf34b25d04f0c8b8d33b17619de30", + "1e5c21e32bdd447c8e89923a6e15ffb4", + "0e246ae972234b4896e34e59fda1e595", + "ca7a5a97ec934b2984bd0ce28a392cae", + "0b3dcb302c914edf8c06ed8a604e710e", + "ca54754dc83c41539c5d543ebeb0396f", + "220505aaf1a7408385547dcd75efb638", + "9840d5beac004d818b5b8b670aca4024", + "1d150c01f3774a08af29a0ef6255e2d5", + "1d18a5d05c9e4b02aaa993778211abd7", + "af42f063164e4035a2ba07438cbc17df", + "bae37c9a52d54e7ba4d60a0276b3ae88", + "86030eebb34a4ab7af88167dedab6140", + "03c53bd7f7644377996e5b2437ff93cb", + "fe58e81e5fa940319e79796e23053182", + "bac002cf45fc4c468d01a976cb04ff6b", + "78ed22024c844a44b4869a30e7acefbb", + "3d4a9910f88f4107b4539007de78532e", + "beb06d59c946427bac6bdb170db12ebc", + "0f19c871b8904e91bcda27b617414a32", + "efde7240c8024bdfa12cede0b9009d8c", + "64eb3f327d3e40b4a01df1f9538883a4", + "62535c0b7c0f47d9bf4673cddf8cc123", + "9f57c839da2b49ba9fbdbcf0a8868ab0", + "c5f8ada1dab549c3a1c77997dcea0ca2", + "7c3383a26abe4ff0b4bcf596b0f1be0e", + "2823ab7ecb514c7ead868f9cba9f6ff6", + "31a8aaef0f604c84bdb08f9e687c86be", + "f9a2b8a487d1416aab802cbb44c9d378", + "9e7af2dcb2354e98994758a9906c21a0", + "b212eb60f78c4d80901e061e119d3857", + "362706d5511c4250bc419c6f5ef4f2ae", + "0202ec72baf548bb957406ed2d88961d", + "f9a56a1bd4094bfc8b60117928d731b1", + "0fc7c56aa9374b9c8ac548ccc02ff4cb", + "4c0f44f3884648e5b89b3797c4dbb944", + "5bbc5ed173e44e4c8ee895327dbd0d91", + "0fdfe616df064592b8c5ea8ed632e248", + "07bf31bcaadd47359b30a6a00b618a35", + "f05bd62a592f4fefad0c636800708dca", + "6801a0e6738644aa8f3c58934663a5b5", + "29061e6e63e54a5c8b376d687689afbb", + "75b3fc82e74b49ac846f649487ccf409", + "45a0272235cc4f4a95d18905df3a3972", + "6ec22c4ce9394d0aa2d405708d2aafb6", + "2d072751d6c44787a98d685602810cd0", + "3d764c6c9ea549808209adaa9bc54919", + "33bbf5563eb64d2cb5d7dd7354d6bb2e", + "923aeae6441f448eab9ba5b278c26e6a", + "3d7bfcf3e91649e096a31661d387944d", + "90b2f4b7e35a48f4812ef9d35df7eb10", + "b5097eeb96b34ef3a3ead5f2561043fe", + "ca07336af587471ba16f2704e44b7eed", + "7b9f124340a947d4bc523c42c9936ad6", + "32b4b1932fcb4728a86e9734c2549713", + "08390acccfd84752bd8ec83b8ca07430", + "f150e9e0ddd148e8b0e1f2a9a14084b1", + "78b47132c6be42bcb664545a69b380d9", + "af525021a0bd4e489f7c886cf0f9c43f", + "ba96f32c3beb41d5ba4594c69c3dfac0", + "683d34e4f4d74192a7cdaffad5bf3c47", + "d879c2985526427b96a39733dc2a075c", + "c0c0070877144262a2fa20718cbaa298", + "f9562b9b04fb494aa15f58448f2a02ad", + "07b98a94818241349af431d8ab1a055e", + "3ddc195b71994042b32b96c23b1577d6", + "244a639e6ece4777b1ca836e40ffe3be", + "38b2fc37ad6e462da262b35dfa0880fb", + "184baa16500841ef86fdc94e62017e58", + "0b43af6d2db04b62a791282b1baa1897", + "d0ecf40321464ba0a8ece64322fb5dac", + "9b736d751762436189e9e961c8277b2b", + "362cbe01dc734766927b2f4b50547a58", + "c68b5a75e1d14ca880eb50dd924a609a", + "350f3337a3e6484291bdf29537b54689", + "093339833c8341628bb34fbd70225a5f", + "caa7f94ac32f4dfc96aebec8f0913c16", + "89fcd105c05849109695462b29762559", + "a41a7b63e86541b89a452e537e4b4e00", + "21b041f71851446c8b1a5eb4449d15b2", + "bfc8948a81b94a03afe00b4873f9235f", + "0d1b1ff7d7b54af9b6b16fd0ef349904", + "20fbb246bd19402c82e01d7541a72f8e", + "9ff054865d6242929bcc7ceee11fc01c", + "d45e1c5f9a9c4aaa8fa5b92b5f23afef", + "c9f0cf0cbbe64ba49001d644244b1d16", + "e9cc179ed7424f0f8961d5321388dcd6", + "62d7f89a88184d7499ec8ee07339d151", + "fcc0c0e457c74270991415750298a5a0", + "0657199531c5400e8e0bded9fce5a998", + "8b72e119ad08450eb8ad35d13dede945", + "f739e58c5f7641cd871ba04722ba67a8", + "7ad444f1a7d94049a2e3038b19dc8bdf", + "87210c1a114c47ecb6dbe9035d079be7", + "ddb45f99470f4175b4edd1dc2253b347", + "a77921ba3ce244739e838429eca9e427", + "89af79333eff4b38b4d2a967d1147978", + "ad2b9b0cee594673be81ec92235f010d", + "91f6cc06ebc14e968a24da0f64bc504b", + "9551fd583b64469685f674f40f580359", + "7ef1158b735841f4a3f3ecf43aa87c97", + "8be96cbdd2cf41bb90e54f37711fc812", + "8428f79d22a047d9b28e4920c2e68b42", + "a3a5af14a6ef47fea2e513140503df1a", + "b9bbac4416a44da4b4eeea6026efffee", + "5106f58927cb4cf4bc2f3c43c008bc1e", + "4fa462db54874abea533cd7e53709b5a", + "abcd5cc76c494045acd303fa56f7426b", + "bfee859734644f84ad12fc1b015a7791", + "4ece5a37c3aa420d991d59520cdbb9c7", + "8d22af983b8946a9843325dcd16bbda6", + "6beb8d90379f40578dce48864e73d648", + "33eb258d9873435690254cfbb0ea46ec", + "f1705040d8d44ed58381e7106e01286f", + "28d5f8f70d5c49258cd64381d0f6998c", + "543d585a3b744ec1a3d82b3ac0d2473e", + "d22c911c9964467ebb2ad6c86bba2329", + "ae8d2e995ea34c559693b6fef4125e28", + "95ffb026ebc1466bb1d4b20f59df53ef", + "a116571cddad4b0d97062f107ee833c7", + "23fa0b9a671a4f5396cb844801889d48", + "5ff902ec07244da79b9d5d162e3b54c5", + "e0304800688647d488200a993f1ff930", + "4a880b382059426b97e0d389f3ef3f35", + "8ea4feb323234287a80c6168fbd96677", + "f07c1e8d3ac04807af69def725ec1061", + "767fdd65a829495882060f45def86f41", + "2f13871237e74122bb1cf4ec21fe46cf", + "39ba87f0e3be4269a7e0d9148e1025fc", + "6bfd9abd60f5441fa9d07bfc6f56200c", + "ec1e7667444b4dbc8774dc54c2c3fc6d", + "d50b1a00e5e848a1b2505dd2972c3154", + "5e126dc212b3422e84b58279a8003b82", + "b8aa279de08942bfb0723f43c5bc9b72", + "d5e6b6a11da646f68a5fcba661dcae99", + "6384ce3d41314434b0fdb690eaa8067a", + "dd43b715d4414a0fac8477dd0ddaab3b", + "423502aad8564e1b9fe1b810e204b7c6", + "e00bf205f549406b80b1254fe921dd55", + "7a018e9a55084b0981d37ec41e2f558d", + "8ea0ffd2fccd41d79c5f1ac9d003e92d", + "017f6036af924341a358bb8a3bc0a74f", + "fd45bbe5177a465b96dbfd3095cad7bc", + "25550368378e4dba8d86d9be786b7aad", + "b3f85d00c64042b199c3302e7f7a8fa0", + "06afd2b44b0f4523a85a5824b91a965b", + "99fabc61118c4c489f8787d714f8ea44", + "93244198d47b420fa5b0d9a551545658", + "093797a8ea98481aa0d7f1062d48f8bc", + "2cb3e2c082f34506a5fa6e30d32c4ce9", + "ac00dd4042474b2cb5e245a8b72598e6", + "f9c6d59bb4094c788ef67ba388df2938", + "1e93268bb80c4264a8f8b82ee59f7f7d", + "5b08ececfd6b4e9ca93490b6c7abd6bd", + "80ae3e593b594e5fa5390900115b61b4", + "6d676e1653454b8aa426aa28f9fea87a", + "03d4836e66e04a5b99c994fd0b6a5f44", + "e2d4a227deb14e0fb77d1b02d44ab4ad", + "e400c7a42e24465695a12eae5de51b2b", + "ca819d77eb9a4ae795bb71a2ec316770", + "c8b9ce3fa7cd493cb2600026b887e792", + "4eca248627c6460c85165e835c4216d0", + "8acc7192f0ee47d9964ac38c81424bde", + "bacaa33407474fc684c82fe7929535ff", + "40e852fa60084fffbc45d91ab5cfd8e7", + "48b278b446da406c8b7ab88749e44cad", + "6898c4f9159343ce8cd690fc19bc9e89", + "08940e0b2eaa478cbaa312c773859feb", + "db46661c8a714905853e38ca88e0e971", + "06a5cfec9b87416b8b01a2e1239e62a1", + "61ba551451894a19855a6e9ac1c8ffeb", + "6ae3b4f8864e4174baacb350231c054f", + "917f876032864a4d9719a20c8fa5f492", + "d012b8f2523246499c04f794355a05bb", + "f5d7d0c6891a4772ae47120a50985f8a", + "698bfa9aa58f419c8297b93d3d454554", + "0b5e54e410a94adfbd736e30a7c915e0", + "aab6d5b2a3e44500b6974133134c64b1", + "a7d136ab51aa4d8291ace5294c90befc", + "3b3156919dfa4cffa6ced7236b7cef07", + "627f07ff02df45259f86ad74c30f6745", + "c9be59f678da47b3ab808cd5224dd812", + "8d8bd092c4294c55ac726666306365d3", + "7314e90200754806bd3e2bde64ae5d23", + "47f19fd492fc4707bf3222c697dcbaca", + "7e70858be7fc451ba8d54b60a52fbabc", + "659afc7b5cd84c91beaf3911888acb30", + "5a546e4f485a47a697ff2f27d1cba97d", + "5ebb6b41072547189da584d9ba1e217c", + "17e6280d7c2f4eeca12a8caac812b539", + "bc9475576006482b88dfe0505d6f6769", + "6772c41e98dd4660b6a2dfaa0426339b", + "7405f17de07d494990de5d5de296bbe5", + "792ce777806440aa846fa3c1ed77b352", + "f83cdc2ec0c947509960ec8d06b4fa62", + "426c88d1811b47898ca63a0e938cc332", + "ae9a1ea9c62340aa8da6cc14e2380f8f", + "fd1091cc07a842e285b92972ceab276f", + "df8a5a3f93f048e78a3c26b2bb098663", + "5fcf6ddd66804fe190389f0ae1585ccb", + "ae5e8008775c45f5abfce067f91ee6b3", + "b61f642e087b4f718c4cee048274cf05", + "3e9b9f7841f54577829c0a9167b167d7", + "562dc0dc5cfe4b54a9db01f6d7092817", + "53a6eb7ccf054aa2a378dd7ec08f88fe", + "422ffd55bef44db8831c41dca9091a49", + "a21eb6c8b84a4cfd87cb979bcaece64a", + "5fb7d184274b4cd9bb306387f702659f", + "f0d343ecdbcb4fea80536550a8a2fb03", + "5ed35a4df6324ec38e4b8806ee14a24c", + "24cd9876663d479fac2093fea173dce5", + "79e70a8ec7c54904a411eadfccefe775", + "ba33bd49e6324da9829317357ef1e04c", + "4bd88ffe2b1e4ed88249a86f4f6304c2", + "8769ace67ab844aeb72394587d8f281b", + "038ec90b56824962b51418e78af88b51", + "6145a63d33f441b6bc7649166d3b0324", + "7ed09e4f0ef54c47b5e2ef884f24a91e", + "488b8d1315cc4e2f89fa6188514ccc9a", + "fb6c56b1e12c4541b80d24b580d9106a", + "fe5b7e3935944c4b8ae48bc3e5f77d77", + "f9b405abefe8401888fd5ced504f9c40", + "d32128f4b85d452a8ea5eb2db150e829", + "b7df14a7d5c549e88800ef0fd96162e7", + "b115a450a05f4270a338a2ba280fa50f", + "659aca3137724abeac1722b309270f07", + "371011a1dbd34742bc0fa6ef72f335b6", + "1ac3789442f34d17a1605eb019eea9cc", + "106a182b1f95497bbd4c253c588d8e82", + "47a595d6c2dc419bbc49e35bbc2c951d", + "6718a71416714e82a8eb6157616e8d6e", + "6bc50370853b4a868c55c94e14a59a65", + "5657562e17f348b0a490ba31aab653df", + "f69ca3ba5a8d49bd9265de758ebe676e", + "5620efbecd1042f5ad32a6fbb30849d7", + "190ca827015445d8b4eb980b47c0462f", + "7852ac9958be44d5ae16b5d9834155dd", + "5c380b8448604c7682a8be365c579be0", + "36cf6013bae44dcea3eb606e6d636f00", + "ef59b9792e7d4fd99c26cf004e4e3194", + "4e411994270649208cafc6a0b66583f6", + "f0ef12ae364143a4a3e3649448d4e819", + "87b43edb22bd4575beb28f7cfcbc3eff", + "bb812edca066437b992f4a99d7463150", + "4eb60ce6a8ce40b78a7a3fc10422d2ff", + "63e0b7d1cff348308cf588a9d55a304c", + "d66341be20c54ac982dbc24c1a6a492a", + "28faa54f048a4463a48ea34d737c0b53", + "18b54804b5fb47208ee20064ca14d06f", + "c86b8ff0eb954ed291ba3db8a922b954", + "c3278c478ccd40f69da77ca76327bccf", + "a9f58735696e45fc868f6035d2477e28", + "5c7c05bf45e54847bbc6340c6d84c8da", + "335015fbbd6f469383e6f80b29d45cda", + "ea0cf48616e34708b73c82eb7c7366ca", + "5211e2f509a747e9a2a3acda5780b544", + "4c43723b4ee5461abef085afcaae7546", + "b510d5fcc4084a53ae9e027b8d4f2976", + "5280ceb251d044f0b0d445195d527977", + "e914e306fc8441f1973f9716a6ba9356", + "a4d37da48f794ff5b2844d0706c5e4c7", + "79913215b4994d95ae6ce2d0f1d02168", + "6a09bfb4032242898292932ee68622b5", + "61649cbfc6f74ecc85d62b1fe8126399", + "7752407caa7142e3b5b1e58bd2e60c73", + "8a3f51d301974cab8b5761119ead0ead", + "ec97cda6d0dc47f78058bea31e85533e", + "234f8865dd164f7f8d9739cc8f4828ea", + "a79ceb32d29a4327a2eda3b4805c6155", + "d9e6543850844578a93e4b87cef50486", + "eb2ae31bbb1d4e669efc990209438d72", + "4d44d08a03b047c8890d28d56e9eb860", + "eddd78c746734197a81613e10affed89", + "25134a84c07e420b93cae181731fd7a0", + "837dd873c735472b9fd09d8bb42b6b9d", + "e905affda3d94d3897bf89f3975d3b35", + "991ea3b9799d49e2b27713337c6ec4d5", + "b1498cae5d294ed392a2a430e2d2e711", + "9abb67a4a62d4089821af07dfdf57ab8", + "d02733d55bf24dbabe9e9e5791aff2d8", + "6b54d092e7854bcab978e723e29a9adf", + "ded421ba06fc432e88692f9078d99959", + "c5e836236ba14b32aa85d708dea55885", + "4968efa4a4c1494ead9a3a541351460c", + "5b6d0f3a343d4031af3046f5ca9e0d6d", + "741ed8274dea446994e5ee240ad61220", + "abd6292205884e17a4bfd15f3f408b28", + "b55289b594654879b6ac22891f86698a", + "e4b988f7671a4cd1a76957f7542afc7e", + "1582bd8176654bb98871b8c20ae94a72", + "19a3321b01224d20bfe06b210b74e79a", + "19039ee81e004877a958f4566aef9178", + "85ed070c2a1b44c2a6924a71109397a8", + "4073f830912a4224aea1a487e9939dde", + "7589e46002e141daacad5bffd0ee803d", + "5df3c782d2b64884aaef0877abff8cf6", + "009de5b694dd4aac9c5a760d544046d1", + "e3316e8c891843fab3eb09b87b5840e7", + "9eeca340baa24e6f969acd1d9999104f", + "8552bf76b9a6434b9219b24ed8b905e8", + "be9888a7a5c34c3c8e6377969ec78741", + "9ae15671f1144f7b8b20d72c2d6bcc79", + "d90beed47b594988aad9a0fd180f093c", + "0aaf8989743c4cf587710648ef6ed05f", + "c828bf6dab2345d88f6d0d562fb91489", + "8632b397579847fd86778b76d315cb5c", + "342aec05aede4137b874b2b4ccf3ed64", + "22fb22cfad184fb4ad14e572b3b18753", + "f2af053534e443ae8b391ffa036d1466", + "7a1d6d019851430eb6c594c56876a029", + "0f8a868fb5914e81b9e797cb17ad0241", + "4b60f54b19b843b1b5c5b752e74d1069", + "7da02269f3984896b8d9a73a111aee08", + "f3c4f5fd41f742668dd32611cca98ffc", + "0336333ea9f84e4b98494e74529e031e", + "3c22408ba46840d189fcfbdbdc044f72", + "cf3ed83c1b87486d90435f54c074e16e", + "e75a702742b045028314586105e1595a", + "e24f99d09fdd4aa0831d11c27c4f725b", + "4ab5a9d412ae4700bcda1c9dafe6def5", + "dea61a7bd5c7487cb74beda24c214d75", + "e2613341a1664ddfbaccdbb9fb8ee362", + "6bb1511500864030abde5c30630c5be9", + "1779f886209f433db69ca6afa8af055e", + "6a0ae028c73b4baa84fdc8b1cb64224d", + "447c8c13ff4d463793de744d4e3cc814", + "b6ef9a1621b241f2af756cedfa742f91", + "640b0c8287274629a7f4ff3ce74a5999", + "c314d1f2efac4e89a7277b63ad7a1152", + "becb8db078d948cb9d6f4b21c2a36c83", + "d6ec7ee9a6dc44ac9a8333d1f23b5e94", + "9e661d6ea83e4e1c99ace3a8c516131b", + "783db6c3134c46ecbe0e451d34e9b4f6", + "b2e9d11db44e4d6a94f049d94e5b96a0", + "f549d837776947de8ec22202fafd9d95", + "0bd9a8dfb526499cb75ccb67b6a7f738", + "dd345d3248a2497088ef76408fa8938a", + "15c54638a22d490ea6fe350e12ef11c9", + "2913b959448b435e9aed0fcc4897cf1a", + "7454d35729114dd2a8abfe8594891ece", + "4c7bb1c659114cf3bcdd6d2566c21dd7", + "66572c4c88b6444892f7f6245dcda914", + "309c1d959ae84fd1b4c48ddecf6fbb8f", + "c34682ee2cba46a2bd55cc4be587eca4", + "dbbad999b40242d2988fa7e95b5c5c34", + "b2b5599c6cc74c888fc0462ede629091", + "c5f5247389ff4badb18775b100f98348", + "cff0abda2b8f4395bd5d57516d9ea982", + "04206b246cf7419392e40881212a8010", + "34c1846e93ab423a974386d7b12e298e", + "272cfff0dc244bfd9c4ca8658a3013fb", + "bf02e2c57f3b4beba33eca34b720f86a", + "12c6ead7553a4541b29d7f6ebad4eb4d", + "4546ea618ca846ca8b0643f17a054d59", + "8bb08d987a83404ab4ef48d5d46dcfeb", + "b1a8fd887059417fb18ae8ecda2bc287", + "e272c70c23864949b234885ebfe4e804", + "c3dbcefe14454b1ca55bae8d1af032ab", + "fd2905eefcb446c08af5d877dad42681", + "49f4e93d6d0f4253a257c0391abe7d0f", + "9f6cd0dbf8104044a946864c6d06266f", + "ad6d38daabe74fc3806619f238a1bd26", + "5c29921a556346f09684eadfbc51a91d", + "24ddd62de82f4455b2cb25a9448bc4cf", + "b04a6fb90f014498afeefe1d33be3bcc", + "bef0f699a5374ca1a8fe8e27fb77788a", + "422820f79eed4502ac419b2fe9875696", + "afca0b1933b84b1dbebd1244f25e72fc", + "6576fa56e90e4998a82f55c0b236b228", + "b0ee36a6fece46b5bd8f713fc88efaac", + "5906b11989484691917e9262b4225db5", + "563a7fb115e9407cbca8f3a4d486cb08", + "04d150d363594b2d9a7781ed76340eec", + "ea969c0c10b944bb8b921f3b8cb59806", + "9f3ebb06393245f0a273e6e9baadd2a5", + "25942e72cf1c4e2daabb592981e2a321", + "80171e35124f47bb9bbb635919bdb4a9", + "631f3ef770bc4b8ebd1bb3c727d08813", + "d2e221daebcf4a32bf0843fe25b6c57b", + "072d0468bb97447ab1ca7e3edea25f1f", + "a599214007fa458fb46e35235ea1034d", + "e3140a8c501545a88f8d9d9b13c4ebdf", + "f9e70bc184da4a6b97ca4bac4b056f5a", + "723d2c91cdb248ac9a750a31f6671e87", + "ff4e2fe8956a4a17bc38e910e21c27b4", + "60f8a7e073e4497dbf638b51f101cb43", + "41dd3652813a4183946e233def4d3731", + "5f7233c10f0f43d882bf6b704c7530c5", + "7f3ed9f541f749aa901f0eae1e07736b", + "d688c1d6c0ad4dd7b3d219ce2c23a942", + "2fbe8ebf76284db0b3c0ffd47e33d597", + "398c1b3b8114409a89eb02f9b42f8064", + "e7172544d7984d3b8b7ac0cc6c9ae693", + "fe0d953112044d6893d04dbbec75ac82", + "6430a177632b42cb9531768831ddcbe6", + "e86e632d3c614a31b4f09b83997e5f0c", + "b526cb22f59e4c68ad288ceb8815a6f7", + "e378694413e6481680a90972bcf653cf", + "6ba38407b4ef48f4aac1890c2cc88b13", + "eb73d55b89044f6daa36932ebf30181a", + "df325cfe1fa24108bdfef58ba7e88b3a", + "e57e7d7b5c0744c4b24e21fe44567e38", + "59ed5e0f87c349909aa621ddf27c0036", + "d7955e29c0184bfa87f96c2927107c86", + "d367f2a1e96644c7afd46fdd47659a69", + "8ed00b819e944ef48f28267ccddd16be", + "4241927f4df24cf588da158c076cfe46", + "5820945088a14ba8937ce655cdb0a008", + "65ff77a1624949789cbbcaa315021186", + "9499783bed2d44b99112ec18cb5259d4", + "f27b2d3929d1471487280bea9df2bbb3", + "28a56f2794424422aed48d24cab4178a", + "9dedea6fb5c54b2a871204d7a3403760", + "5d505fdbcc594cb3b3f1b30be8240ad7", + "35d7f5a5bec54e8fa1002db547ed060f", + "a0af273dda424b16884a95c306d588cd", + "dc53315bc20f455eb6a0f1b650f8db41", + "f5a15ee9d42b4154b8e66541b9ae1a0f", + "dd1436c8136541438bcf131f0cd25d54", + "ea331e9ed7a94e749769598d8b8d6539", + "1f68710121e64a56a33c6c0d4d1f22c1", + "eed6f50b0bf34f07ac6124a9bc84e8d3", + "0509a0fbccae4cc59fe3643d8735846a", + "bf739ac106354b43acb41d0c9b4b59bb", + "b90b63c7f9ea468c81285b5f5458ebd1", + "67384b66a5eb4d72a9d0c18b76d1ed8f", + "4ada604e78854b118594b621087835a7", + "a9bac16586e14f0c85d19024aee93c55", + "4fc3500e04b14e73b942d85bc948c5e9", + "640dd3a7507a4feb9df3c3aec0b4e885", + "578c4c77731b43cab5fc014be8cae8cb", + "86af94f65403477f99acb2f413634ddc", + "0c42257deeac4d45b134a72b42abdf20", + "decb57b075ad4df09efa345233535340", + "5db338db85c7429a880fa20fcd2f046a", + "a3302a0c22d548e5b01b039cf8fc2e49", + "d750ff735fc44f949251e288567bf1db", + "8ba97f1802a94dd9b2bf5c59b11bc4b7", + "db56253857f24dd983c8eb8a5eba3ab9", + "4406f384becb4d53823fd19d651f9c55", + "fc163e373fb9476a8bce22dabe319f01", + "00b8be166dfc491b89a8dc5503e87d34", + "fdcbd368e9454f559364a4ee794453a9", + "2e0d2a9821df44ada9a2a3fb6aa40ea1", + "d2682097be654e8cbf341d3624662e4f", + "eadca353d41c4326a21bad3b0cc7f9c6", + "284743d09a574daba26d4f04db4031e6", + "f71bbb8e9b2346c499370cc7f407fbb3", + "b11316ffca09440e80f69cbc1505ef86", + "710ff1ff49124515ae741c99a87c86fb", + "bd2c039c8fe34de0a908f968505e5770", + "c03bd5c38e00494bb5b51f6295d1a092", + "1e80d8eb41394edf9452318f33c1dec7", + "97e60c5df3d04bc0a1b86a2427319467", + "e57e4847e659475eb7819e920cbd22da", + "c60420a840134dc9b4646f43911906d1", + "0750072969dc4e1fa5ff221df1b93c3b", + "19719eb93e504c60881a3205c7ec30bc", + "c4a92f9eafa64e03b8fe6e1c4ce462ab", + "3564578cde5c42279ead680df1619e3c", + "9950ca58ace54ee2ba6ba8a1c7e15203", + "e00fafc01bdf48939f6fb1909b247672", + "e2ddd47551554308877cc1177117867e", + "e9740d363b2b4873966d790b5c952549", + "13001f5d857e4d3fba693bb64ef2456a", + "faa43e3d8fc849a3bd5a81d8054d039d", + "4511d65b590c4ca89667a4a6fe77f9e3", + "5fec200c2fe2483fb85af10f55983a69", + "d73d8ad87329426883cce1dcb9ad931d", + "ca3015b2a66a405ea9105fae0aa3cd0f", + "0786542d0f7549208f889113fc384a7f", + "1f7b8a16a6ea4da49082b4eee85d647b", + "9cdc9a1cbdcf460e9d1a16c59d5b58c7", + "4ec9181f5f274cacb2138714202020d1", + "a6a7595c2ff44532b53a9c8208ff2301", + "9c7aef61029c429aaf0c6d241dd68f60", + "f4cd4c63624f4642b0e9cbb5f521894e", + "a658898eea824f92ad471a0afec24607", + "3356144cda7f4b10a38231b06d9df544", + "039679ae060d463192cccef9abaef8a2", + "3dc802d209dc4d1da2672284c97b0adb", + "ba57e5d4ba714c01acdc84cf1387aba2", + "58b83bbd84e14b6aaba941a00ac76413", + "0b52980cbfb2482cb8245ddf20e78106", + "7bc9181b2f1543a4adf048e58b35a70c", + "95198e3460b14c4db3749eb888a869b3", + "769a5fa758de449e8154a6bbd33e9220", + "c108593a444b4762aac8860a7ae3d5a9", + "f1505004b7f240b2b162c59da4ef2dc9", + "a6e69e07c381482baf86b59f0f4446f2", + "b3501c8ab955444da12be6b49ae449ab", + "0ef362e1b2fa4a77936531b160be843f", + "57778343e3ef4f9b8771374427edb189", + "b5ef3c040d084fdebc483f402491feec", + "f6dc2d3b77664e879f45ca4c9ec144b5", + "a5f3815707bf4a218680f51aa48305f6", + "43400d1c8bfc46eea64c9252275b8ea7", + "9a8384a28c6b45f8b5914a99e79178cc", + "57698b6adc504efb81478e1627f0a2cf", + "ae35ae9f063848408ee24e90ce797e64", + "d187c96dde6f4c90950adf622d1bc4d7", + "dfba07d9928d4b79939e529a53215359", + "115274aca8494491aa1a4c933d53ee70", + "8accb353704a45d19cfce3d6de00a70a", + "26c119f3cec042c8bb1daf5cf099883a", + "38a9cf12bb1b454cbaaf1ada13b91fbd", + "a4992d5a8837474b8cb2f9b8695a209c", + "d9c01eff2af745d3b685d3e2b61c5f2b", + "6c9dad5c781841dbae2dcbd9fc3e95fb", + "42176807bc7748d39b4f529c48bec59a", + "eef3bd8d77ec4b92834e730927b7be12", + "810124cdbd5b4a16a4219d1d052580b9", + "230eb27915684268a0262bdcbf97a1fb", + "eb9dc61965db44ba81cbd22b1f630aaf", + "d0c620986bf142bd9ccdae83bc83a59e", + "303b0a5b3c974cc586fe8ba7502e1ffc", + "f9785251969c41a1b22bbbf319d42d08", + "e823432c996041e29f1a3c48378a5743", + "83fefcf6b9b34b22824863e68d27689e", + "20329b3fec5d4e7cadfa325cb4058af5", + "d806163447c448328614d92545eef461", + "2723396ce03440ffbf3182139afa0d97", + "c5a247bf34164578a03cca7649e9b8a9", + "259f7cd8c86b469bbceaa81aae533aa6", + "ccac43b579d645c18ae10f635b779994", + "dcd767affcb54b35834fa5297f52f9cb", + "9f87b300c258465195b1e68b239faa54", + "cddd741895e6405c98de8501461c8bbe", + "a7fdd4d4ca904fadbab050762a30950d", + "5afa551b37c6401eaab40a371eceaaf0", + "3bb5a2cea99f4191aefe26d2bc5af4fd", + "9f41b6bc0cb84732b7dd46211205fde7", + "026f0fb0f3d64bdea19afd4f4d0797a5", + "2d3315a0bb7141db91cb62d922151113", + "0b8c873633504663a02572aa12c096ae", + "216b2f1ead574acb80f47c3f5d31288e", + "7f0e7e46c53146fa9d39ea8d1e80aa79", + "8a59160c8374412d981c74730101df39", + "13ab607699e240eb9a69be694b0d81cf", + "e79a07b4d48e49009d8ade1df7abc109", + "7917f3c8825943f9b8f6072cff5007c1", + "f2d196e0754547dbbb20375fa6eb91f5", + "746c0a8916184b14890df5900359c7c9", + "135964cd764e46ff8ce737fa0c160bde", + "a8a50790c4794b9a878d340c3bdae0dd", + "ca6b81f51c284be2ba8e714b710f19df", + "9a1d39ea71a640cea08cc62524444a2e", + "6eb27ec854f04a31970b247777420d13", + "a84fb46b851e4294a47a3f0cad1f2484", + "137f87454bac47c189bdc0c8ff7dc52d", + "24985764343240ecbc680545c13c28d1", + "6d7bf998d2374980ba9a08c5567fcf24", + "bb501d2c0f584e62b9efd44a2ca733d0", + "fdcff2c8375d4a528d0c11ea229471d0", + "6800e0a23178413aa393a4f5110b0a14", + "b6cb17060a3c445087a96a7b6b2f50bf", + "415089c1150f47829e6dfcc3f54475a4", + "c221b6baea234dc39ff09cfdc33086df", + "dce4e428a26245fe8157643110350820", + "2cc3c9adcfdd498c82fff3d6623d5c32", + "7852dd40618b4e68aabea2f712572b45", + "f9d1ac73857e43bf82ad2b8e82ff7002", + "dc6f3b42a2a24a30844bea4d1fc8f452", + "e91ea830e5be4111a045d674ac81f256", + "1347d88293c14f099a8697d619a5f228", + "c858b13b32a94b4f973e96966c8657d1", + "a6f121b7315d487da82bd3baa46a37ac", + "a19870d9871b4ca79bb0f0f7530cce5a", + "f480bfb777a046029f9ca77268989193", + "9b6d76ad41c44da8a856f080ce89223d", + "8e849092f0c440539049ad206ac2d52d", + "d02fc474b9334159875e7f81a3f477d3", + "b6f33df7c2e44687aae8bf452291989f", + "bdce5e3b40df48ccb116ee46bb40eb32", + "222c836c79c146528417409662571ed2", + "dff0057e04e64d988215a0411a1abf93", + "21fba3b1f29d4cc0ae13ea147db670f8", + "dc1e8a92f4f840f98a8513e28fc035f7", + "da8efc70f6f4411dbaca3928136d7bcc", + "d47f914685a84ad387af7d562344af64", + "78c2ceb1e51149698c6a8e6242d5dbb2", + "8464d97835954b7f9d4c35257f8f7bd4", + "faea71144f3a477ea295336ee0e50f22", + "22809785ee9f4226b4b89bbb46ec1a17", + "7dc7f8ae7a5b47c6a9d26b676f3ac42b", + "2a270a2021df444b926fc68aa0ea2136", + "7edcb591280c434d8a4e714d926f4b32", + "8779541cdb3a4af7a23a597bcac90318", + "4770895920594c7ab1b00cc36ef74ba7", + "05ffe73cf5b946b89ce81ed1a422125f", + "f1fcb8dafa9f4b2aba17ee85bce249e9", + "f7d9f366a8f9416a87719cdacd5384de", + "a674d3398a9f4598994c14aa2aefe3c1", + "ec00fa069f784e339c62a29b02df2c12", + "0581b5b1349b4431b6beae7306021ed1", + "1af05d5ebd334e36933f043355f54c25", + "f5cd0e0e4dd845c991eb88da17d9dfa1", + "fa849999a46c46bdaca951f9627804c1", + "4d98c602d2b14f1db312cb057ec07feb", + "909f0191c61b47df86824da5722f7f54", + "2513a9899d9c4fb2b1d76b341f2faf4f", + "2ed510f819b7483198db65f5fcd156cd", + "2a43e6e50fdf4d8aac6bccd9e4ba629d", + "8e7f843c81d14841a7c3989ef842f35b", + "edc35d45838b428081fac9fe6a8bc5dd", + "f9bfe0b1877e4d378551549eed8625f2", + "5fcb3f108f8048e790ddb27b1a4291b5", + "1367930e409e4347a5a3adbfe29a56c3", + "f3b47ab10bc745418ebe694aab4c07e6", + "36b33e471e0045e09c201f417f397625", + "fa291637769541dda0b940a3f826b9f1", + "9767f86330814c7abcb5c1820dbcd139", + "7d52600a15c747749d845d9f906045cf", + "00e9bcbd43c4420ba9bb1a6184c022aa", + "87cb0380b5c64e729474ad3a7c60ee8b", + "e190f65694834e2fa77e3991f1e16bc0", + "5501b45ae23649008fbb9b85a30ef39a", + "dd82dcb8975543658f4ee5097637cb39", + "d6b066a406df4c6980eca387ae481ef9", + "1195673235ac45f2aaafd62b3f823e94", + "c05c98f523df45b78d50913b4917e9fe", + "0334b8947dae46a0956b82fad52f63b1", + "3ecdd1dd47a8402391ded8f8ab27c5b3", + "e672fccf79de48fdb9ef4dadb67a292a", + "47d7910242904abbb0d630087b5ecfbe", + "d0c641cbd3e44fbcb66a3bc9febeb092", + "82773a4a1a4f469e80d9c4a43159d012", + "7a1ba72650df4ada814eab8b728e4005", + "bbd0840ebe8f4fbbb427af537f6ea41f", + "0a57f789c17f4c9ca98c6843db1e1267", + "e890caa3313b407496d1e28f8f386baf", + "94994e39935949b0905227a0f14c145d", + "89c82681f8a0452998f1325fe78454c3", + "82ef689ce285475191cede0332dfe959", + "29f58809b71847e8a8d0f96eee4221db", + "bf0ab52207f74b86a8fbbc2b8a670c13", + "2994278e274e48c1a3f720d70f54177b", + "bcdd24c905eb426f8c5268b824bb013b", + "84093c9ff75b4fe48a79b3fad099fdb0", + "50b9bcc9336d4c74897aa6fa6778edbb", + "12308ae5dfcf421f800889498d99c2d4", + "f8bc7bc415664c3c96f5abdea41945a0", + "7a46652dcb8341b0aba369318eb5a172", + "db48f3af169c4fc6b22174a6cdb300fc", + "860750e2583a4ec5a7595b21768b8f60", + "d0108575a4ac4fff9113652eeab96683", + "6fa2a9d40b9a460bb261db69a08bb113", + "8655b5bf7d4e4398b6cdd1dd90b0bb4a", + "71ab3427ad1142718af2ee8feb85c5fd", + "62d8f3b7739c47b68663faa3460c0f67", + "c7cb831b5f9f4b398ec6843cc6b75afd", + "6a8e6274737e40d982653efd5d53fad5", + "41bcb59567ff4d70a27d45264be06aae", + "eceb4b045a2c426da93ddb2dca81f94a", + "39c90b72a5ec4ceb99ea27f83e545c9a", + "077d27e0e4944e248c4aa60555b90621", + "d04da8a35ae0491a93c77e806dd60abb", + "08760070807b40b69875369b5d5e826d", + "0bd2f7281e094856a43330966d51a2b0", + "81f69012d80f42639218760c3916c876", + "51ac88b15a2548638b9490f78cd9b30e", + "85c0c24608ca44c9a77a7210518bb25d", + "f352ac67466b4b7c85f5c2fc69d52000", + "3bff1066fd3a4df08a45985be53e6047", + "1fb892972d5041b2995f4ae940edd923", + "7691ce12ca55443c96e633a158227d15", + "7919a991d60a479882e97e3753a69b21", + "42a959cdb2e94f05901946fb52c192bf", + "230264f6d9e045ca9addfa56b694e62d", + "09219d5a54324b0d82f5e809eec4040a", + "00130eea9e884209be92f68378a817e8", + "837171e3015b43498b087f3852f9b8cc", + "115a4de0551b4caa9ff726d263dceaeb", + "4d9f285756e645e2ae5c11a5c8a49786", + "3d8d342f8ad14130a85f3c9ca858d376", + "c91582372cc747759d4235fe3fa2fb1f", + "986050ad95ca444caa07026c033e548a", + "578be076b72f462799a751e0f32c5982", + "a861e53c515b4ae68249824d76c61755", + "12ee0a4474394a2bad6fa802d46b69a8", + "5feb04e6adac4ab7967c5097fe522f2a", + "36d879d88fb245e3a34e08ba675246e3", + "41574a23a9ae4c9d990ffe672af6281e", + "af249e607bea40cfa2f275e5e23b8283", + "8361aa8f2ac148d397dce51b921f0041", + "03d34765519a4121ac645f35ad742340", + "50a7c04a53c74bc582b82609fa1ec0da", + "4a88ed6d9fbd457cbefe816e22534ed1", + "960ac9ae4baa45b586fc5037a6e3bc96", + "51aa9554018342b0883de6e865a9d1e6", + "887a347705444cd093c4eea7acb06e1c", + "8c7f2110e5e240e08ace774094b0d843", + "cd2222861e8d4239baac70a32841dc3a", + "226ba71853ee418a80729aabb387c455", + "b7613f77107545ac9264807976c127ba", + "60609764ba8b48588c76e9604532cbbc", + "5a518840fd9e48cebfeae70a17021c93", + "154d951f702d46289878b56dc9f42a30", + "e29e51facc8646228f1f6dd7cca6881c", + "2e6d9e77be114535b01d7ef028c2f49c", + "eb77223ebfd946e69fb58ffe9ad32adf", + "4a420222ba03428fafdd5279ff0f3056", + "638c390e349d495b8fc9bdb43f02f719", + "758801b2181441e086f8e923d51c763b", + "f8b06a00be894bee9706c720e8a0bca6", + "4c9fb3a232f249a39c7d7cb76b64ca7f", + "67d17da7d0944c4da18564fc90028315", + "5b15b893b16743358a87221d599d0aa2", + "c928fe8af1404bc2ab3a328a71aba57b", + "512140065abe4ffeb8220b768f6d6884", + "c2ae194bd2564bb39abd79a45adb4744", + "33005d8b2c034be7bf55e8026e33fe04", + "5876ccde9a4b4a52abb0d054aa21b28e", + "fcde6bb3008542fb86a4e916c53a73b8", + "4a3c93c80bc84efcbf5434b162ac1c8a", + "d8da8a2e7a6144ea851a76e37e98eea7", + "df9306007427449693c303d1f85d9cf3", + "f79d8e4ee82c44b495ed623f14796b62", + "d19b189fe0d24704b45a084ad029ec5a", + "d8f0f9e4569344928d8a071e6c92a371", + "7b14d44bd6b04014a8b53cb38c90b903", + "eec78b30ad464f43a650b8dd853b8f83", + "fb33dbed54b54d8f9e3d1424bc46fc39", + "184f5c59cc6b45e8abf85b8d10257add", + "16d057dca094426e917e87119b4f4806", + "08a82d744b39481dbb40289faea1ba8f", + "7b2082e5fca045019d13f8e8c19e71ab", + "eb4deb76180944598be5a12f790f6b5e", + "9df38b999aef41d288682d652f5e7234", + "5d4cff41cbf5417e9b51390e8d279f66", + "bf8cfacb09b14ab7afbd7890cf1b2d21", + "9ef4c782e9074e79b433ae55458bc2af", + "7f25d5367b464d3283724d7fb3905eef", + "2d3f3f07b39a4ee9bccbe64c865c9f20", + "498702bf390a465893c21a6f9d7b7966", + "76b48860863048d2b2b9a0a7c6a5655e", + "b314794073c44ede838cf61627b5a3b7", + "7a34189f183e477c928139f3369852a6", + "dc490319b1fb4bba90b73467c1673a54", + "3ac81514068d4b5e979580d460fa6bf1", + "5e614fea3aaf4e78bd82cf2b6e0e5c7a", + "c087746c86aa4073ba7e9389eab4296d", + "1283ffb5acf74de7a2853390d3e39611", + "1893382c7fa24b78a0d464d62310ab7a", + "05a035c3347645b8a7ceb6d65f825ac3", + "7abbe51badc0445abe683628e3db8775", + "fd38da81ce0e41f29869c0dc7d051d2c", + "68b8e6802a244470b4051eb192d99a9a", + "fcafeb1ca1d84ad4bf71222a430d8c93", + "830b1864b50e4f7e94c7f5cee5b64b43", + "ba8a3dc8f2754176adb3f25e5e10ddc8", + "c6390154c41d4ffb9361ad78c371061f", + "3b130ba06f4d4e929cdb6b5f6acc1dec", + "a1303a387635413a8e6d896cb952df33", + "b27a303bd4c747d7970780a148b97a24", + "132a3aff49c74b20992e7473b2eb248b", + "91692430be4a422ca5f56f1247f4b291", + "dc1f8c763e8b4064b9b9c674aca4e85d", + "a30fc85dd7764b3bb45f509a38c0d000", + "581d861c05ff44209cd4cb925177cf80", + "609454d5168247168871bd422afec3b1", + "74fa123561744c32bff6d5ef60b88ad7", + "c4f7f5028d90485abfcd107442e228ca", + "0c7d19df3d3d4cbca54af48d76734e83", + "6cfa73de247b486087cec829cd525458", + "79a0e0dc02dd4df5b7f0dfaef7c3a05e", + "5655596f9efe47deb09df57a79b44e04", + "23405a46bd55450faf20617f15433da4", + "d86b8632da384514965b9d920815334e", + "ca37a688c511429ea6cb543cfb8627c9", + "0917c63e36cc45718b80a92dd5aa7b62", + "f53d75bd123b40bca14d12d54286f432", + "31276b5cecf8430db6f91175b1d95ac9", + "3b1ae1ad437c45388efcdcbb05c51c4f", + "021fb16e259741c9bbe9c07448e1f95d", + "3674e79090ed40b9b06e5b3fd56780ad", + "c8e14659a449413cbddc074c932a575a", + "c8961fec0f5049fb978b39d059eaf860", + "bc10ff32ac7343b8b0b5d71cece675cb", + "6f5480698a7a43c7a8c0a8b1e295e4a0", + "4c08526679324761855bece36a478dd1", + "63267108852243ea940a09f9dc32916f", + "50155edb7ef849baa20664431899c18f", + "b5d22010f2ab4123a72d7b2a7d6643d7", + "2ae4d0417bf94008afd360a43074291e", + "c511346461e84360b5bf046ca3dab780", + "1cfd3944c9564a0196fb2241ef2799d0", + "8dcf0048e5ae4befa57309ff356b413f", + "d2bb6ebaed634330b4292fc4c3daf919", + "a9e81d1bdbc14ce18e098ac3773e4111", + "273742eea2174598baf2ae37524706a5", + "e594db88e6634388a7526ebd1786e0b1", + "8e82b9517681451384a1fd845d6e77e3", + "1136b76b0c4b40ccbc0ba45824fa4d74", + "1c345764350a4fe6a5839842a6b9e0e8", + "ba313d2ca6064986a7e7f59c58fd945f", + "aa67b378bd9c4322a0bb1f98adab8174", + "b653b88efc7c452586416f1e662d9271", + "d023a3d87fde4b809e31395999535935", + "0241e66e7f93462ea3cddfb1f326d753", + "9744442e4860487b9b84cfa59f215d42", + "0f4cee2653294b3181dd4c900a8838bb", + "1f95b6d17b074bccbd3f9236039288c9", + "d5559c1411fe4b43bbc337b6e5150271", + "2894066bbf654b4fa69a66be62c40e12", + "93f297c8736649bbafa731d0859c738f", + "f155509637cf44ed903d8b3a671248c6", + "3c8fad41a4d240d383cc123efcdeeb03", + "cf0690389b9543caba4d011b0c7b3a7b", + "bced11a727cb4954a018f4053456d6e1", + "4016930e82234387b4a1fcd3c5bb0c12", + "1ad11254efff4f59905e09f1a9e8ed41", + "84182b0ee1124ecb9d546d893bc01cb7", + "3674ea1aabf9458dadd8332872509749", + "d5330c4de06641f0b2ed50f25a805af6", + "4df49ee038004902a7902afdbcb8bcee", + "142ca651880543188ce9a8c3bff274ff", + "cb72bb6e92c34c73ad0c3f8b12288543", + "29049cd6560040f6afe23b6c4b89da59", + "4dbedc82402f4c9fac945b1098e10bc8", + "813400e1884b4e8dbc00f29a7111efc5", + "60c5718a745d48978d757ad566041773", + "11b0455047ee4988b13e53e6d775d32e", + "d76c80a319f64b45b24c56954cdcc844", + "e83a068816b64c38b947abbee973b202", + "4fbb57124fec47d8b216101e19f5d385", + "65e9105d24314887bf8dafb06d3401d0", + "69c194cc30f24dcd93e822751be8de35", + "2d81c48fda8d4b05863c378e68042d7b", + "25a3134916654257a9b5d965a101fe9c", + "a606688f1ef74049b6a23d759721db63", + "ebc519b6e3bb46d9b204789de7b6784a", + "d2979d2c1316486c8c02f19e119b5675", + "636da326f0a94bccbe055859636e2419", + "aa008ea8ada94c6d97c345ed79f1a90c", + "92b18869fb7d416f8fdd00bfb6bce501", + "21e5615a6a9d468f88cb6bfaf853322c", + "38f399f84b9f42898b58bdd2db22daf5", + "f24c04715b874327baf86b74334c36d9", + "9bfa5bd092bf4d84a4e5a563e235ddc3", + "a444e83df72b4d41a26c7a44db929986", + "cbea02f813454fdb88ddf695dad0ba95", + "6e288a3c332e4191aebd591a80fca9c6", + "c93d24544fdd4f1784d482490465c00b", + "800d25d41e9641f7b349c564c3af32c7", + "dd2d47524cc04928b480d7bdbbfbdf9d", + "b28311e44a4f41fb99b91a489a637bed", + "5d3d3340bf2b4567970e5f16a3a94b8e", + "e9d0b14e9348426598b62f0ee2cd1add", + "43e1a1d0eac04f17abaf1bb80268e3ee", + "5d271445ab5d4928ad44f82a0aff28be", + "899576e8549443e38ae557aad9f0fb5f", + "e13c985857324b48b7dfa4092171d6b6", + "8ea24286904649fc8787a19091c66c27", + "e8ebfacfdb0f4f1ba3958a1e0c467784", + "440bca344eeb471d80527293fc1084f5", + "efa38bacc4d444c1b9dcf2cf4c28b087", + "a8f1890515cf458da8598733375d4eb5", + "a6668de2a1854db8992945973f2b5d56", + "8d6804f3f3804dba8425620eadbd2c33", + "7482e3dcb4a8495cb5dc87689ecd045c", + "f5ae790cf947477aa7f38830591bcb15", + "751ed3b5331d4c3c869f0dab880ac19f", + "7bd87ea90ec44d73867e3a91fe7efefb", + "9ac79ea81b1b475d873b60ccd249518e", + "854123627dbc44bbb0bd0298dedb3e36", + "39ae5039479f47c99fa64e267ede82ec", + "59909f9f4f984a26bdd795c789bb91be", + "a44544c27b6e47f190d7087c40c9e01f", + "de94359590d340dd9f60113fd657a356", + "9bb1507c07fc432babd9254289c0d7e6", + "ddae28c9cc9c496c88a7d56d216fe1c3", + "bef194310df14460a626d7030f41ea48", + "103509f334ec472abf5a3a4a7f39ed89", + "b2c714f8e0f641249e90d88cdbcad4c7", + "5df3141533aa4a2488296104d6a306a0", + "b8bc7286a876466db58775f44c806f99", + "db68c321fcbc49fe8fe4c54df5033967", + "d0143f13110e4f02bd3a8f43f8416288", + "c7d3e24c0362414f8423f02755e33199", + "0ded421f02754a318c265dd0aef311f1", + "2c19dba8f9c444f58a7b87d1e48ca4bf", + "1c8716f6621549f1b7275d4dfb840ac5", + "4e5afd0f0c5a424a88e5391f73402548", + "e35173571d3d403fa97016681ecfee25", + "8bb9c087abce495ea493b63d112f86c5", + "6e7ffb6c00e94f6485efe5e8a406e2c6", + "299c21cf70984fb98b33a5e4ce64856e", + "6a12041d84f64e6d9d626d6517dd17bd", + "f923538fe3034464aeeef036d2b6afe6", + "420eda3b8e6b4bbe8993ecc7548cb326", + "629c68ffe84040acbb3115ad2e5db297", + "c31b39952c164baab5b34a07c76d1e4c", + "b1a99e828103414a93e02ef2f8306578", + "19842492eaac4381b4a67f84371e945f", + "883d9a3f559b4f4ebbd994ffcb038664", + "8e689f15a8be4af1806c8165c6f0940b", + "201ab7e00f524aafa527532f69e73b4c", + "b6dd89dadb104bfba43fc399477e5a3c", + "673d7693f8884e039c3462a5079c36df", + "49e50e28bb794399b6f293add351fc65", + "df9f6717fa6c4df89271613c20dd8b60", + "b223a494c7d848428e37602bf0c2197a", + "4505b22d84e046a2813a33b8d8c2746f", + "2aa8947b216b4da294abe28ab1dfecc9", + "fdd27718d3da45abbedd15d4b2c0a262", + "1c60a8e45d5146ff9a698a23fd958734", + "bf0666bbc6184f5da9245a4be6c63588", + "cbd406d01c8d45a3ab2bc66855f8c955", + "d3fc2490cbe54e37b6d5b159704c787f", + "7823190220bf43c5a4a9ee28e07b19f1", + "1499c302524c49dbaa765a7c1b876067", + "38f90bd105e14f278000f77efd075b56", + "fcf202af53994465976aea36aa261940", + "3021280b11b1427cbecac9bb45d12e9d", + "552c919739284752b755751ab9a2befa", + "e4d2b88effaa4223bdb37afbfac54d59", + "605b458f5f034a2694d8c3814d075b54", + "69cad741dcf8417982265e9944230aca", + "d4ea4336ae64441ab353dd814aba72d8", + "89ae51450d324138ada40332b02b3f33", + "bd9616dcc4e64c03a4f066a12ab4d949", + "02dd46d99a98426c84aa47d2e2150aeb", + "03f16302c1a54c46b438dac78e9d7048", + "9233b529cb9d487e84849ecefc810c93", + "6ca9e3bcedae4dfe9fd9d639639447b4", + "5121b091d31f4b74a72d604bd53c5daa", + "3fb4baff1ad546d4ad76938f268ca2d7", + "42a911b7c5004e5fa493a1065f061477", + "2b0f15f41f7f4f958a04831488004cde", + "2005d15daca8424c9050955716af2fa5", + "c83c466cf32341fc866a9a22e6576b37", + "bf80d9243b0c4a67a4d568916ef69a53", + "d6cc11d2bcf94cee96cfb12ecb9d2b3f", + "6fcaca0103704783a880829f28194e55", + "c9aeabca5050495eba4b5cdc08768d8d", + "0b6fb2556a81434687066af8e65661ae", + "a988e7ea72974529887c29ceab7f19d7", + "0f9fc087827945b5ba88da01e5c5da60", + "84a440c5ad2440e9907323ed0f379845", + "680e090566ae4ae9841e6e3ae5a5cebf", + "cce3a987bda2410993fbc7a24db70eb5", + "d432c087bec4417097b0b72f19ffb950", + "8e088fb15dfc42ac83d39e31faff4461", + "6b9ceb79b10d42a3a810857783c4e6b7", + "ad26ef15cd8a4e798b71ea11e1e29af4", + "071b539adfd548818d94f7c7626b8def", + "511753d447a542d590602f313b7c5b1f", + "c7b2dbbd0b8a48e7b93656de8ccf717e", + "eb7931191b2048f2a77cf543fe2348d2", + "90f97e0a658d464f87dd6a478196b26f", + "9aa41f88b5094c20837091d3b9a26380", + "037539f91cb34368a44f70eec628db67", + "954cccb2bfc340d2a79d6c7f8a165998", + "1facc6d1c73e4532993e7c80c17d2cb8", + "405945594fdb4494a434029e75c4d00a", + "3049f8a37f3a4f51b49a16b7ff5c4da5", + "853c9b14acea46c8ab83cfc5358284ff", + "f2ea714bfa5d475daed6816a5f274ded", + "c506ba42e60148cc9e00a07b1ac7d707", + "5cf029f28fe5469bbbecd4b5852fadf9", + "6ef1e318e5e544bc954f02ba67654b93", + "a8d4d759557e458c89e5e01cc9a96917", + "7bf3dc8ff8d24d4aa37b669b37478714", + "e1d025e567624d69b762fe640adcc85e", + "0046f208ef8d4988ba7bb9d297f29ec7", + "092c6a80b3ef4498af46a29f8285d6f8", + "fdea34e69537480e969cd72bdb6b6781", + "9a57589787144da49d7272fb153f726b", + "3678d5fd71c2413d82b8891282945510", + "81ab6a12ef9d4e1ba070f51c57a3fb6e", + "9d5df16b87514d06bf9fb5e147509415", + "9f39fb0ad4034271a6769d352226b858", + "b0c6ef8cb62a41d4b6e4d94ba0040265", + "9b4655dedefc4293a4da1d8f530b78f8", + "6cefc1b2a28c449ea002b359781fbfcc", + "3f7c0551a34f4b0dbe60feebab893fc0", + "c80522fd9bed4d3f9b2a3a7c135dac25", + "bb6d66a3db1c46758ad31b6e12cc318a", + "ea8fa9c8e5b2410c95425c17074b7a5b", + "94d1e3f9ee6148189cc968afd43d61fe", + "9b847dab1734499aaf6a1893b0d63865", + "9a1c7a00013745ab8b79be940e77f824", + "3f6b7b02847e49d0892426b5d0abf317", + "a820c7880b49463dbbc6fe5ceeec9a9f", + "aa8ac4d2c7174f3f80f2a33fc9f4653e", + "792a7ea907ae496cb81b0063dfd88745", + "f23f8aa6eeea4dfb96b95bb4c36717e8", + "7cecb07724f44b23b4ae6117f3e21888", + "9e5bad1bf8b742b595ce22719e4acb16", + "69ac3fc5e765469eba06d1d235105da2", + "942abf58826d4af9a59f064d98098539", + "6cea809f7ba747e6b59a0e7d1e6ae753", + "2e90c725b2e04f7f808e33f949f3c8e6", + "f7125f5ec62040e5b8cd2719fb633339", + "44513b83c2254f5d853a816241b022b8", + "dfd734a9ae4343fc8f572b11fe09ead3", + "5b0613b9b7c0499cafc32c772f902d4f", + "a913c282c6fd4e73b825e0efb5966720", + "7951f3c7fe1d477591e0717275272765", + "c004e6ff052a4583b2088860b2806977", + "b9dd582c978341ea865cbddc92edb5a2", + "a8c54e31fe9c4779876085de74529d42", + "fe71ccb79a0f46909a259d01e8847fce", + "01659373a49d4ff29e6b99abd3b734ce", + "fa15b3ffa9b64b3daff2241b65b92ab8", + "ffd5e10812564f47abb94901be99d1be", + "dd034472beb1473ab94544f5acf0fd91", + "8894d5da5a494ebf9e42ee37b41e9aa7", + "7c0bfe2e800742dba8e5e6c8e36b0cfb", + "41a5488c67194a11965012514eb08714", + "d6da27e3d95f48efaa4d936eeb9d6fe6", + "cd2831e25958420d974e050aeb9d2384", + "cf7a84a290f8488abf6debdb058775f4", + "2b82c7206188491bba8306650782f6fe", + "6c832989ee684551a3a3508ee90cdda9", + "413d75a26c9944f7946984e10692d97d", + "974a60efe4c142a0adfa04adc9a10e84", + "f79090dd37d94deb82882104016c71d5", + "578d999f800346729001bccaedac9619", + "239325a362504d5eaafb60b0260a8880", + "7d353e95d8094f7ba3338e3c0cf76c38", + "20430683e8604342a5fdcb3abee96d0b", + "fb566fba4fa743559b466e6154abef4b", + "13b945e18fd543c5a3ed084e75571185", + "5cb530ebb2274747a89965f67097d161", + "95a0e93a8c1649f8973ca8db727213eb", + "8b1e116d758e49f8a69b625fc4d4f868", + "b90827fc3c774912a76b62c7c8344bd5", + "7e388e2d0cbc4bf0a3da43b936319b10", + "98b8bcc892a64973a1c4a4ca8af0691b", + "98cd249a8179442aa20799d88509f821", + "d9f0673d4f0445859b70892e416e293c", + "bd96a4cb636b4f29ae0102534ee2310f", + "1702a2275a2c465d8f7a6d4fb26d2c50", + "897fb52b1e994f8c9c0612baff72607f", + "3a40810c85cd4576af04b66e5a18e6a0", + "51a5be546a4443619e75a150d8ed082b", + "4e034c2bd8f7432f9970c6a0be3cdc0b", + "34c1665d16fd470ba8a126583f1cd839", + "bbf60a0c1dfb4181ab374b5260616ec9", + "9587de3156554dc0bb39cfdef2bf682f", + "ca845d03fafb42daa973019abfc1a013", + "d793de7c08d74414beeb8ea50f730705", + "9e7578af65bb4307a12fd0ade5ad2e18", + "16efde874c294c7d9b069aaa56632b02", + "97e50f021e47477c894cd73b63249889", + "4a2519f67a97499aabc1c2a228a69166", + "13f29fef23f5432f8e179118ae3c14c7", + "0c2ec0a278fc4ce6b5ad63a3aa0280ad", + "bc79ba81d120412aa93f40a05488d464", + "7789095425514b14936912bded8a28a8", + "3d3e6cd1ed9549c288e33de168e7cbfb", + "0ee4f66bc63e477bb81673d7e3e633c6", + "7a9ef6b9032b457b96a264c1b1b84bfd", + "da15a3e6a414448681db96743f522ae6", + "4398bcb5976945b08f195816340247b8", + "800cecaa060a4b9a8e94a1a2e6d1ee20", + "77eb557575c147708f0e07b487055690", + "7a9902eee08a4298947347b03c786021", + "577e9b769a0d45528e18707aaaae18ff", + "6f3a26af345341a39ed2af45437f8dc1", + "6ac0f5bd54574c2cbdead764045dfcb3", + "b262bfacec7b42c7aff6bf1f9e7cdc3a", + "ca2c4b34b90248f39add966df2ed8a8e", + "8a56cf63a204440592bc2c694dd63c91", + "d574d3b45b0e4cb78ef3fdb08039143c", + "fb3a51e947844299a9a1dd285a45b283", + "94d6405522de4c2895912c0a45332056", + "71542fcf8e83422392360789aa640189", + "5aaa3dd5d4624016b96412233e7e84ae", + "8c891444d62d443592d6451d0afeca27", + "87723236d2b04335a04428610b9752bc", + "f2643c116c15498e881d4dc97394b9e6", + "0d44f84ec5824261837ab03694b5a8d5", + "f62d2239a9874ef9b44890231e4a8f5a", + "fac6a210860e49789e48981dcab31219", + "473d3302496d4c62b86a5ad31f7aa374", + "6436132bdc1746668aa2cf2423932d17", + "4a0c3417d5654abcb30d3881f00570fc", + "2752d746737b4527b5d3285e18147ac7", + "07f62a6fb60a4fb0bc956b800822e611", + "febf4b4dc3b94c66bde6879fb3b93771", + "867d245434174664b533aa7ae0635bcb", + "d8211f8358854c429971cd213f5aba52", + "8e739f1dadd9476b8cc8405206dee758", + "b737399e49184eeb9a4e954828434a34", + "4643fcab808a4860b8d54f2688bff8f3", + "fd2ef60140334681b0b5cff622eb7245", + "c246a807312f448f81ef14896d7bb665", + "b2081a8c11344cefab18b38c292a7ffe", + "3f0350f0300c406581748105e81c3dc2", + "bea18366e9eb4e10a01ea38ed28e302b", + "5982ab03c0804662b47ccb49c4d55b5a", + "6f7bb38a14544f65902b10ec921fe57e", + "46c3b3ef67e24cec8c11fb4c811c1834", + "e6d6eb6f313b4e198f6089728bb21d52", + "3b2beb3418f34fd1ac182d968fda987c", + "24fd09302b824a8f9662584511697318", + "ddd34c84b93649e2b1de4b1afecb58a0", + "ba4e5e1c550f4402b6859a139f6ee1aa", + "4dadaa5050a345d9b362367752eb7c1b", + "478f1405450a4eec94016f5210b83d4f", + "6f22c1ad27604b39b2ee7331a9cc4b45", + "212d5d395ad14367aacac0be70922acb", + "7949dd7a33a0422bbebd194e2865c59a", + "a64cadefc6634d95a2fca54a105fe404", + "e776fdc2f30745ceba1e8dba7fe565bc", + "ed0d680fafee4458aa16720b637acfda", + "c713679d1374437daa08828c924cea1a", + "afb3d4c6128843f9b322de543abe48db", + "e6d59799a8ea41d581f323ba64edad33", + "11bc06418b3b424c8d35691ab6ff0c9d", + "6452680209734f9e9439b10704953441", + "1d5aa1c4711549dc9be905c875ba97e6", + "be4426cef1054b5693ffca10699e6f3a", + "dbd89fcc3db04efe812c8610906fa3c8", + "d02727a13d404f988c3689d76638138b", + "72d16ce9a267457680325b448853ff73", + "af389b9c83c146dd88c3f91246f1fb97", + "38f7cb1a7d964959b44d4a2c09b2a2a2", + "710e5b6f9d37465aa9558da36e948b05", + "69e141a9045047bab24daf43557ebd57", + "fe25295eafe54a0cbe4bad579e2f0aed", + "e114be7a4e104228a10ec1b604c9a04d", + "222a64990c7347778377f8a065e342b7", + "056d9b939742424db19aea4adda94e6e", + "3a23397ba86f4a2ca680196a0bd25f2a", + "85f670ad12fd43eeba1ca0fe8dca6554", + "9b0c3e5255d04159bb332fcdff4a693f", + "c61f8d8c22124140ae676ede1f69f3d0", + "ff9fb3fc5bfa4fa19a4e8f07141fa4df", + "591ac582089148778213915bbb41ab8e", + "715f1b7ccb7a40668b14ef1c9edfa7d2", + "90351208d95343ac8a17f7887e6c8251", + "4493da70aced49629bd7357749591959", + "62c8d984df1f42929427337c975ce3fe", + "cb484683659d465796ed5af8664cf58f", + "01f1cc659cb847a4a7366b84844641c2", + "2461c404fef444e186403b72e2d73c4d", + "9e6fdad4420c4d0ab6aaa9a50a309c93", + "430a2d149c49414ca66df5acfacfa4ed", + "ff58f27249194f7e9fedab5e3e68270b", + "7ba41fad8f1344eb88dce4b761adfd4a", + "c1c9ad20dfc7408ebb8188256da0e7cd", + "4eef3df05a234a36bc9c385be5284078", + "7f16c26621d4475a8ae4e2603286a3e1", + "85bf071656d342f9974005be81a5100e", + "e590553ebf174ab4963036f805e6d809", + "4b9fdc9cceca40eab362d3ee7cf421dc", + "0f8d49b1825748ecb176561039b12745", + "c0686894c7c64a95ba1b03a0db5a82e7", + "b03049ca14c3490a9949796d31562736", + "d356b7e88ad046dc8bb0c0f625ce01ba", + "1e2cac5238dc4168a6a2eb333451d27d", + "1d031ceb7dba490b879b6d45ebe7966e", + "e7d3f8fdfe5846a4aa2b8426cf216687", + "aaea9805edf143769691b81bd2fbabfc", + "cd5ad7440a364ff0b30e92200dff63a3", + "3ab0183cfddf40af88b2d0547a997e04", + "c65f5d6c86874c6ea406c2fee8640a21", + "8b032ff6ba704134ad1e125e55c2f49d", + "f0e327c8b90c4c66a4cc5326e848b743", + "65b7f57cdca34db6a4c84c5cea59199b", + "30705ef951a64da9bedd426d0d3aab70", + "d026d9d0fb3c49ba9b97a0ba1d40f9be", + "64d38ed4203a4a67a892cfa60c9a74cf", + "3ac556171c5c48678f45a2daa0e7091f", + "fa6642c122d14a728eca409ff2b8d2da", + "0bc473ee934f44c6bd124717cdf58c93", + "b5d9a25670bd4b06bf71be2f9841d392", + "795fa0620bc44db8afcb06720a4dadd7", + "144051ab17b948359dc413c5a74968b6", + "214adc33925f41899d8f7d63300bbf95", + "ca079c2ce1414d7b8a6364f4d200ef76", + "36b7d11c056a4e52a4ee83a0a021f228", + "0494222eb1cd46749fe9931dd6c4c30f", + "d9558c4a37b146bb847a907e48c7f132", + "e7caba92073d4adba3477c21aa25e91f", + "6cd9d9f74d614123aa9c10e85ec9408e", + "eae187d655db4deaa4a9d485e3108822", + "221ef05436294548aa792de2b9ffb12a", + "c94bef6f529e460fac45f6110a0af617", + "977f9efc21084dfab70a9ed35f66873b", + "84a8514571034064862b36e61a026b61", + "af28cc413ca943b9bf6caae24817f851", + "4df2d85295564987a1fc3ec13ec2984b", + "ddbe95af5a0b4220998a000b5e54f65d", + "da43ef76720a4cd996faf42242e51db3", + "29496edf3dcc4dbdb57565726a514457", + "5331670cb2b1418e8bcc7eacfafc10b5", + "99d6dce2e49e4ba185ac108ab044524d", + "b87a65917e494aa4b306aeb6ee961182", + "70cf47069f494c769b5e667565c1ae19", + "b51e82ca7a934013a21c243c2b9f85b4", + "59ffee7518884b809250bfd59ebb58ab", + "1829bc2edec44901a2f7032fe2c5090f", + "f89ef1454832489290156a8bd8ffcbc0", + "7bdb028ee24e473c9c44f0aefdf1641e", + "b11c22328b614c268f413b0e47348560", + "428d07274ee54873b5d140f08300874a", + "307c5e4477254322995fd5b9d00bca53", + "ab61fe73553a42edbb8bd0a490adf0b2", + "fa39b8589d11465ea238b5de2351603b", + "0ff94403111942889255f764cb97ba66", + "aae43d25e76c40399057bd1d8f2e8ab3", + "62ee76119f1c4524824edc80e2e5834e", + "0206790a2fe84bf4a2e4d46adfe2dc40", + "23db4e971876417582d5fdac2b252762", + "7e51da3a75aa4334bb0dda4c5b7b899f", + "ce265c3b62884f01acaece0a9c47809a", + "933c5e1acafd4b73990ea4c0eed831b9", + "5a0c81d951f5450f94b6ac32972dd290", + "e5faca93d8984c05a145974d86f7fb1a", + "0d2020330f46460483846da5ee0749df", + "b1b9fbcbbd0f4310911e1c20ab039aa4", + "fef2e74c23434993b2ae9ec0b31b636c", + "597f42d6823045ed91bed412e02a8ed8", + "6f8260fe6b5f4c18b767ad577c18c46a", + "cbb8e7af40c44b3fa7937d84faf56999", + "0e8155b9bf94494f9754901c53764942", + "72826cd5c17a42798a8e8e36c05c5035", + "5c00779400bf41d38ee501535aa7592b", + "678119818b7e4465aa21461d1c1c1c70", + "0cea33fa41eb49d3a8b00d9e4d325053", + "93d0dc6ff1604c1bb0f5a276f6a2dfb5", + "520ed23a021448f7aac926c49401d51b", + "5203e4056ffe4f62a3f4e824b1314d67", + "b2e14554b84e423ca1b53446160177d4", + "e8dad8ff07324ed5ab46ed37f808255b", + "c847a6d2912643cd96e1ada74beea902", + "0ca0ccee6ebf4242b6073a6b9f25725d", + "ba4064906552427a93e0b024eb1c1a62", + "13ff4a293e2d47089d5dbc49101a01b0", + "55097ee451624583acccd5ca36cc3f3c", + "2c8b491dcbfb40e7b82ee93cae0d1edb", + "4d26c963e0484e708835ca04cfa626fc", + "8858ee85893d4b3c9aa3bff245a5571a", + "85c991f5696f46f4936ab29d89b49fd9", + "e52d4aa9a9c44a10b8bc06e708f84285", + "8a578c65175a438694b1835b34e0fa58", + "61b3b54ef16742bd9854e3e7f33f3996", + "c268c7c7eeab424aa7d01a92b0e4a937", + "d2e1a57932b447dbab589284451e35ba", + "52e996a984254e59b0fe6fdc75af251c", + "04f8b099fa2244b7a4069018669a4acf", + "5340eb4804364b19b1666feef8d6d9dc", + "8111d4a5bff64987a45250004e12a0c0", + "ec50e888232c43cfbe7f8ccb9d2368f2", + "4bb4be63c8fb4b469e787c30e81f9e71", + "c055e535966741cc908540b98c99db5b", + "b90db0a968dd4ddd85e04eab7f15163f", + "89df6e9c76de44c09d44645382b094c3", + "e1abfe6bb6214cc7ad497f0395b28f1e", + "77ec5a1993214bf9a24170ed748e3b06", + "52a685c32314443e94cde43d9e0d6303", + "3a98284a462041d5b482996dfd848a2a", + "c758edd810344a1b9e61d08908546c69", + "da7ff2ec78634c838396ea2846dceb44", + "fc24cb34811b42f2976e413939cbb08b", + "4df819168907461fa8e02b5d67b3731e", + "a9d846aa86944911bd5f983a6c9f2faf", + "3f9bc2a0d4c04b548799c5a10ac08be3", + "55e93491b9b44b5bb6e91e001262d58f", + "a959ee8ce17d434f9fdbc93cad199a21", + "27f97e3f6d9b40bda877a88d0d1e8bba", + "0e3135374d00472b91d12fd1018e967a", + "c3da987e228747b690c1a979c41e6705", + "3968cb9c8c314815ad8b136c6561f860", + "5e31198bc72143599d4272f7598c0539", + "042767c599f44303857e76b57e76a454", + "ca2abfebaa144797bfcbb24aff11df80", + "1af231e71a214212913e1acbe5e92bf8", + "7CoQuqqEaSGyzBuPPOA4QtYW3gQ", + "ec78aff7132d48a98b7f84f89e39d172", + "b6ad5f6b9e4441dd9f74abf5f702fa33", + "40e48eb77df546e690ccf53b1ad9ebd3", + "652d57b25adb412c800247f18f1a7e55", + "5466cdd5407541d8a92287e8f33a9f5c", + "c7ea604b54d5457f9615caa8a827a38b", + "7df4b9ae20514b65b5330a68c8b459f8", + "8810a9aad4f546a28fe5cda1e429758e", + "4d2f4fc53bbf4c4bb9a1fed821e0dbf3", + "17e20dcc4d3e43a19483554fb79455f1", + "042d0eeddf20468dbb560c7c8966c02d", + "a3ec3f21113b4ee582e89f491c9dc67a", + "e17580d57faf429d8352d6d433a5f7f8", + "46e0b2e911594c699cff8a3cf533ff75", + "3adaa94863254f349a66bf70b0c90207", + "c1e4b11375a5466f8a4fa689b543cc73", + "38b6df67738544ffbbe85ea48fb45d21", + "ae23a2f6b7df456b90fcd03e3d8b2072", + "f279979d9fdb4aafab73a2c26557136b", + "d7a3c5b655194c2585e639762b8ba5b2", + "008f28b256ce4380ab3cfee5638744a2", + "5ecfc69eb56b4a108328f3a3634784ae", + "6a6bba55b0fc430586a56c6da9a7cb95", + "e1210bf5f92f4340b73afa94605101f3", + "8e597273fb6641b88f25d575f7019e95", + "dc250ffc3bf2441bae2ba83dbedeaee5", + "20cff8caaece41ffba8821701441dafb", + "5a8af945feaa4be396186ae61a53d334", + "cfa28f49a0654674aa640b30be3d9490", + "aac24dd940994c8c9d84931e44508fea", + "d351e74340e14ef09fb24b69dd4a6502", + "eb3ff9a63a554526bab6318a1ef28706", + "e72dcc58707843fa93384690e3f16d9f", + "154bfbd39541425c974e6c6ea6815a49", + "15523e171cc74158ac453fe328dda8db", + "f64c5eea213748458d28a927e0b1ae69", + "3c5b555331c0455895a6bac989370b42", + "95966053ee514557ac7155ac99ea9a5d", + "74bb2c7441cc4d078dcd5d82ca47da09", + "991a9917e5d343738d4d2cb7ff6536d9", + "2f0f66556ae8458d863215cf528fe41a", + "1616df3ef6494e00812b0abfa2809806", + "70c8fd82c8dc4dc4b98d6b962835fda4", + "fc16ebc7d0b14553bc617033b4234936", + "e7dc65bbf189461d89899b42082a802c", + "01ce620e70ff40708eb4a1b04f4a828e", + "8d21d1ff64584cdf83f2bac359062f3b", + "0484a45547114a46be39022b66726bcd", + "958ab8886e154aa79e7fad01cf0e3b3b", + "7e96dbb3daac49de93b6b0f31964eb68", + "3909d6d5c023462ca745da3fa6db78d5", + "f46f5558e77c46869342f015efed4f0a", + "cd476fedd600421791f805593d7c8d01", + "9d9557c5f3af4639bcacf468e4e5182a", + "f167765d60bd4238ab22963b8585ced6", + "d673aaf2157149acbc55b624df95d693", + "2ca2fc71dcbc48f49a4094186cde8359", + "07b07f7292ed41019a8b6aebd98a5c29", + "8d86c0da0a9f4fa2b4e4b5be830b7781", + "17c448629a0946a388076d18242dfc1d", + "c14548c4ac994b9981dbd31eb049e5a7", + "abe57386b98e46259dacf800da6cdb0f", + "a6ba4ee83fa84d11929a1135b8aaa4bd", + "c7612ca89efd41b991ac9fea6737567f", + "d8244ade389d4782a972bd6d7da6a602", + "f432f5ab498d4bbe9f05bd6dd3e93051", + "62cefd7899d6472aaf5397145db9417c", + "b84dfc98d44d470ebff1ff6fbe36f57a", + "27ce91e2f2754ca8bb0b00fe2644ae39", + "68a8c84c742d423f847c6526cb4f720c", + "0c2bfe4c137c4f3dbe69d08ec4fab1fc", + "b9540702cd7942fda59e23bf6109261d", + "09a4e785583044c782b43c4a18cf2008", + "05dafa582db84ae6a675533c73a3600a", + "7c18605c30dc426b9fe091c4da4b764f", + "072aaaf01e1c4157a5f3b5166d7f021b", + "0022a3197f9646acbb9041eff2d1f55c", + "a93d800395eb4b4ab2a447405385e4a1", + "e17af92232fd4c81828c56c2cc0a06cf", + "093cef110898429cbb9e9fa7067d0c00", + "a48b3b49a2c849e9ac2de85609cb6e0d", + "c5a2a51a2a1042c6b52e314be859c944", + "f9b7be8237b94ac0aa0f042c462cd864", + "1de9441cb0744c0d8459ce957b8d0a57", + "3fa58828ebcc4bfcacbb775f83d7e8e2", + "5c069acaa23647eca5b69db3417f560f", + "644836d3f8b34c5989dd6de0ea56cabe", + "dcb2153718f84286a5ec063049598fda", + "5d05f4996c56449f8c12034f327c6551", + "4b1cd8bf8d04426ca244f17fbcfdb8fc", + "fd52e107fa8647da946b990054d8283b", + "742a5f4a7bc84abe8d0c645cdb411cc8", + "02fa47e722fb4189b1c21c6d69120cef", + "8c9ecc71fb114d3c9d0ed1e8fd348953", + "8f2a04cbcf3741088978399924b46a92", + "d58db59dc0cb4d4ba9b3d5467c019a1f", + "e7ac7b47d28347ea83f010bedbd9e830", + "ff7b5ec543934e32b94d4dcd729aa822", + "30a03b4a29c949218e5313543ff7f676", + "7a3eb53dab574f5a92501ba1efb0cba0", + "313f3983b52e46baaeb35c15231ab73b", + "35c6f05c7ad346759b9f53db5fb8c48d", + "2dbe1277caf74deb9a64ba032dff21b4", + "60de8c5c5d7147f686e403d4495f49c1", + "cc1cf5c6ddfb402381548c5eb5ead12a", + "d29892a06fef40a592dcec3bd13d7d2b", + "a974b6d4742042b1bf24918256a333cc", + "8acc51a789ab43499a8b6304dc5f28ac", + "eccd13e2d8364c318116971101567c66", + "f957752d945e4493a6bd9a229353d3bf", + "4cd820652ceb4c36a480f62026e47137", + "d27387e0adad48de86e4d6bc8a5d6273", + "24c96b6714b14d98953bcf72ddcbe3e2", + "4c713330a531497eab09d7bb7b19f841", + "f472d9e2badf47d39815c2b4b59ce05e", + "5248aa117842442980a2a2bbb5f3bfe6", + "657e9abc1b564840a569bfceb1cd580c", + "341edaf151d44250964544398a6b2d61", + "992502e791184bc686f11c9f3bfef655", + "bfab6897007245ed93f31f354f47812e", + "354cf5f5fd40460092490b2e38e4884e", + "2f697bd92e06464893a7619231e5b619", + "81ccc2282aa541cfb5577dd24c716bf3", + "ff46d11d84544a419dd79f4e19c1acac", + "2f7ee8c7bf37491e91ed1dd7cc99cba0", + "c6f69c82912b4961a6b5b7df2fa37747", + "373851d3dd9641158f53e8d0531e271f", + "25d61b7f56554876bae4b72c7be516cd", + "0202478645b64d24bcae4eb58a2391e5", + "8d6355cf00f44d7b9bdd26330f486c01", + "d0bde09e97f442a6ad89b29168945a80", + "e91308b4723240d99de1870d4de3ef1c", + "1d2f3157246e4eb3818a50a6732ca05e", + "69643553cb794eec90a5d633ddbb504d", + "226cd5ae040c4ccca98e3bb08e6d72ee", + "ef7799bcdba043238c4deef9d2832730", + "0e21675682ba457ea4e3e78e16bdaaf4", + "3bcc0c28ced04e3abf7f6cbf004d46b4", + "bd384d46514548cf8c4202f1ae6ea551", + "e669c307e3eb4176958cc8c07b68f873", + "7e32a74d66904627a5053b1003973639", + "367a584baf9145f0b554e655722ac0be", + "b3d601881bfe4c90b3ce7a8e3758bf74", + "1512800cc19640c5addb7f469dadd7be", + "473577f6dd074c71b3cde9d16e357885", + "fc662503b33e44649d04f8d017c0b82a", + "b562dd40ba5a4becb5fb60eab176f401", + "884dced610624ff4ae2f08eb6fdc0107", + "43a64cd729954a5bae9a2d21e918cd93", + "d870637936c84c968adcb1bafd1c31c2", + "31d614f9214a4fe4830c6cdc0b688fa3", + "685e148a899f4ceeaf03cb36bf891286", + "b782621200834da5ba22c5acb2bc6d5b", + "c475c9510a2b45048fec0b67f20c9387", + "1557fd3289104918ab475b8e1e6c7063", + "32c0bcf29aee45da8a7bcf7ffe1fd8c1", + "f6dbff10bac748acbda37f4ad3318a56", + "b56ab6e2b50246c88c7f72a4f16fc857", + "a9917037f0c643dbbde0475b59bc53b1", + "95c2cdb3812149c88daf1dc8431d1e05", + "8b7c81c6ed72445b80f630a296625db6", + "d0dbe1b081e3421a866081e97ac7ccaf", + "8dce1efec1294b4ea4c5d4129b0824b6", + "ba37f4a7d77d4a358aab18e11a854706", + "68978b4eebba43719bfa5712b97e5bc8", + "600f9ba87a9f469c92e7e3b56be1869e", + "68ba07440e744d5697050446162bc661", + "b782768a5ec1453fb2587bd9d82aaf7e", + "c0a589dc61ba423d98476db5a319f8e5", + "09032fd39ff343a8900ed9969835151b", + "bd3ac97071104b64bc388a155b64f79e", + "ff28ce784aa04d90bfeec0defb2bcdbb", + "430047bd3ce643fcb93a3c5be65352aa", + "ba393ddb5e68429c9a45796ca6d92000", + "4600f978c9c5410bbb7f86eabf54fcef", + "cf8049b499b749fa9daea5e1a74f6cce", + "97802a0adf12404b8370a3b75c5b9237", + "b1339e4776284c2b933b01628cb5f5c5", + "57ccd61f9dbf4e7ea801fc816e2de0f0", + "11adc73e6d5347bf8073eb0b1f991bc5", + "7e8485a272784e6cb3b5bda68ff319fa", + "6ccb9799c3484aabb6d72b2c7ab96a8f", + "bb3f11a47f8c4301a8940b4156621a50", + "b555371c60fd4dc1879f6fb34cae240c", + "b41057bfd40741e8a844102958a8c6d8", + "01d23b3ca3d9410993d55850730277d1", + "dc38fb47d0424cd0adde9f82616e8bf2", + "72960d59365844aebc8b9c85ae7b4cb7", + "fb407b00aaaa4ecbacd63ec022f7b32c", + "76fab4ce1af74a2288fcf9f2a9ac8499", + "d72a69945cee44d8bc3b736e236c26e9", + "a2ab8081cafd401b8ad884d3b91ebf50", + "1bf43ed7628e48e7bceae6f6c5ac06d9", + "fb83cd5fdc114bceb9367dcbe00a33a5", + "42b619c45e054c88a3b3940f0b6c5665", + "2cd60800897648fb8c24c20a30047241", + "4d1a87ccb2024822a661fa3542b6fd1c", + "4aba936878a54041ac018267b754957c", + "2903d7855bfb4164ad6749c1c8c5fede", + "ba08b74f9bc243ac94ac256ceb6cedb1", + "1bcef93a72c74e9683720788716ed9a6", + "1e32e1334fda44f595b18ff5a191464b", + "110ba0ff4c8c414988c454749e52f3be", + "04c9a4a2ea5442e68aa4889e92b63d14", + "646b9ab87b6543499fc9284be87376f4", + "f04eab114a5a4fb694c5797f7db5dc12", + "90bcfc48347f4075865e438bd70c5c87", + "cb4d823afb8648c39985605a4e27ef4c", + "be638ded539c4964b1bfeaf82e669397", + "3896055eea9a42e788d119e89d63a715", + "cb43e2abac66494d81e1e7116eb47043", + "835eef6febbd46748cd3c39cc5a2f99d", + "afe78859d8444319a2984a000866f659", + "772ffde4a0a245ae8823b01ff58cf22f", + "2f5e0e395155408fb5a3726b61e52a12", + "1704ecbc09a24f358332fd358c818d18", + "68d5d71da69349c4ad785594bddd2110", + "1fd610388f614a20977d1de79d812ce0", + "d498c39e40974966836fc1140c263d22", + "996dbb04cebc4b7595ae45ad74d1ad99", + "74f3a391c70146efb80475c44387a72a", + "984038932f0d4586a3c619280cf89bad", + "7b2a96dc42fd43b4bdd56bfecc29d56f", + "791a73b17d7e40a4957e7c0df360e5a3", + "3572d21407c240d1a8fc5f2ec7bc8a46", + "81aadd826c85488180fa3fa2d5f7a0aa", + "4d85475b4d9d481cacd5a13107457fce", + "74c505dc7c554dac967e8bf7d9b89b14", + "f93cbc21279d4423986d6d84ca4ba74f", + "2a8254d16e1a4e329b4fac13d9ed656b", + "fd0a2dcfb518449396c1f0b578328498", + "5c332ca9f11742bfac2e65f2b7893192", + "c880550174f0445098ff48fd5e5f2cb6", + "81bc19b3bd934f0eb1d594e5f81994b0", + "700ee9a22271414b8775c35e3971b695", + "c7bd4d76afd741a0ac36bcc0861d4138", + "4f682b0b32204a2b88f1cec535e58242", + "9f2d291f0c5d48dea4107ad0e93a1798", + "d13af35cd3e140b3b78bbf995d333ec9", + "70ec1d287c554f7198ec46a438735fc2", + "6ecd27f7caa64beb9cf1f90a276b6d55", + "92feb879b1074393914e40b8c500488f", + "a4213159f0ee468f9c52e3e5b016f612", + "7b2840fa884346259ffcfa3f854ff0a3", + "22bb95b8fda7420e97be7a1b52aaf759", + "3e49682a4fdf4b02912edf601f5d66d4", + "6a9e1ece41cb40efa69dae21e9fe704b", + "2b924e8700034b5288a8aa36f69c86ab", + "666ff42967b040bd965e6771ae9bdda7", + "d6c7ed9bbb2a44e591a8c5168adfe362", + "d69a8d74eb72414aae505d4d51a3002a", + "4a6f80605e9b4d8f90936779240a4f48", + "bb06db406f8f415ab3ac597a3a202c27", + "aab2c93ec4b742d999417fae2f0194e2", + "60abc0f79689415891be128338f811ab", + "123f95eff33c4149a81231c1079bb6aa", + "b04fd558e574478d9acd9ea72077cb7e", + "2c7a80e3990e4d769e9b2b6ae00cb516", + "2fa30bc6c83c41f6b4f0af2f7c7c944e", + "f1c1e890de674fccabcad59e16e8e4d5", + "0f6331f190cf4a5ba09fbbe870ec2ec6", + "1fa75984e231488483182a29e2a3d859", + "a104c8ee588d4670ba5cd621bddb94c8", + "6a915904ece84a44b91abe52cd79db45", + "316cbfa55e8549d8bce87e6a8e884090", + "adc289349c3d40b68725f8dfb8418217", + "c04c370f2761457d88ab79abe75f6d32", + "c4114b4c1fd240f1b9aad57f9bb3f851", + "64e815972d294cd6b53fde0f056f7333", + "2e4578206ca04cd49256fd2aac34e8c5", + "a8755116b62c4033820dd278fc6d4975", + "1b12ef6f030448e0aafe3ca1157d1714", + "c05369adb63b41968de1cb242c22e51d", + "1e9bf67a82774713a09929986d15afda", + "6d73db6c079542b8abaf54e2e7f748a9", + "d03cc899ce1841938451f6c155f38242", + "c5b05cf16c994a39ae417aa131bf789d", + "effb043167494aa4914309130feb5cf1", + "1103d639867d4c98818bc86c97812171", + "3e5b44b8eac24e2dadcc158e7ae421b2", + "f2d29714c8e24a2ba03fdde5fc4b20f8", + "2eb180c68ac146989a8a3247ab19b6ae", + "46b72ffede9c43d6aa237315bcfc6443", + "91fefa1ec3324b1793e854d5afbf508e", + "2c90746141b94f0eba8bc1c379d4f4d8", + "1702f71e798b4cc794ec12f8219405b9", + "a8ec3aa1abaf4b84b144e64f9deed635", + "a037c00543ea4ef2ba3de2ba50f2d931", + "ebe8d1b25dd64e869e515d3eb47b9e88", + "2048f6bbfd2d44d59f92e7687e6deab4", + "f4f465e072af475bae0068c08c07dbcc", + "d023e43149234c3a92f34810624439ee", + "0bdf1f27bf5e4950895eaa899202ce52", + "7a3191e0ea864c528bd67b5bbaf9ae7c", + "8caf0067136a453eb1bb6305c2faa8e7", + "926be3e33c1c4cd18e062bb986a89b18", + "4dfa90f069ba4eab8e23167919d63e02", + "bdeadf60bf774adc9a39c744792c02c4", + "5348e229f87f4dc581cfc4dd84aff2e3", + "d816b210bf524123b9c3898fa1a89ae9", + "49139922d58846468c0a06e1e87b300c", + "8ce51b2e9d774ba28aa7d768171a0def", + "c6a248430aff4543aaa0e87b968c617a", + "07a1e91cdba44bda998ea2bc6ac1223e", + "f19b8b01ac31493bb89958763c00c706", + "884defbca8c8473695e5a5420ca89de4", + "019c5ddf853e4618a686feeb7c70cb3f", + "c28d838bc3f648009a7646c8f03141cb", + "b13ac3d99e4f4c09888639032e861631", + "05b1ddcf2cae4d878072886b0fdd0f4c", + "e544c0ab1ed24b4d84196fccd41c92b0", + "103c06ded85d48b68fc09c347e1179ec", + "a4c4e43e911e4a7fa0cc2617a0697eef", + "c8c312861f994d3ab10efebaef4a3d62", + "031f92d1e6b84f458024a9eb9f543825", + "fc93dcac82ee47ccb912491de9689f02", + "f3fab17153d54ddfba5eb99e3259c268", + "588278115f92444fab01aa121da0b244", + "a1a17b557c464838b9e770d3d5099d54", + "a5960dbba4b545f89a9c398c54cb68e0", + "622fc5f8e60442439ebb0d8338108385", + "e7cbcb10bd2843cf97786ee8266a3ddc", + "373231ad576a4809baabe6b908a14b1c", + "921ccd2090f443c09b13d74e4d276aeb", + "90c9d43d35d24cada6be59424fb59eee", + "568e73d81cb94e4bbfe8c3e0cc334bab", + "0ba9f399e79547aab25619a8ef3efb93", + "cbd974c3a0df4cc88fdf4a53b18a5400", + "e32f65b299c14862832ef9647df51b19", + "5fe98d86b1314c249ec635cbfd055efa", + "059a7936ed89419ba9eae3153753ae86", + "7f2daeea9eea45f8a9ef854661e99ee4", + "852924e14f2846bd8db8d94a5b417ec9", + "2a4e890cc8e041fca0d62e26209d81c0", + "d8bfe4d8bda84235a75797046d395018", + "2a7c5be3beef4dc0bde1d3382fd09f57", + "7c3daf651aa54283aaca355fc0a83191", + "f4fa35b36f6c4a5e816ffa6b1e902d45", + "48d69ed57f484334a908b163fb35b839", + "6f79dc4963a04634be4a05abd26e4994", + "d9d44968db434ac2a32caa38bc4c2ab8", + "de2bcff379b14db59be4e57376b50d9c", + "8bc7d35773a74368b1e72da249d16ca9", + "2c70ddabd58343dd9f9d97db7821e8a1", + "ce56d3a214aa4ff29b67f90fbc0eacdb", + "7351366cae2a4361aa3318f9d2fcb03a", + "5d9b864029084c6abca6c40489d75b28", + "af48414a52794e9294d7f326bb8d3479", + "e9d1dd2b28284bd88f02564b7dd2c046", + "2c0a2a2350694f7590859c4ac32b5366", + "d914d958f6b844f9aea3fa18208b6093", + "37e029ffd4b74baf8ae6441b9f54723f", + "804fa46335874949938b6dfb55d17820", + "b23f88b379224afeafe029642b62f899", + "e41c1a6a5d4e4d71a06f613cd396ff59", + "ad79e3b821e746c8ac58f72c2919c4aa", + "27983d7958b9467b8d7beddedca8c12e", + "803b3d12423342dca168cf845c3f857f", + "010b9ece8a3a49e3b73be0b3cd02c720", + "44f7223e15534f1494a164a9c9a28d69", + "826a236ea5fa4c0fbc8c6ee7d88df70d", + "ec16c92fe7af4bbb964944575fdd22a2", + "d32d6ee4339547a9bcd07032c16c28e4", + "31322ba4ba454ee7b1e867669effd0be", + "c113735307204d87ab6b38ce2eebb462", + "92dcc31fb7864ca2a232990fdc36fe42", + "7aba73c660a744f193388a9288deb859", + "0e541713f1144f039ec8e566e2cb9b56", + "bae65903908845c29e672b08dbbba80e", + "ae97977ccbd9452fa31075f6c0279dae", + "6d429f534a554dcd881d4157078c3e47", + "18719d59bb62490c99779b4fb4def854", + "b46fd0b1245040a8948564f35957e3fe", + "83aeccdc3ee44ebebe2c6a22adaa2977", + "e39385639fd0465aa1443d7ad22e6bd4", + "fc2c7fd74dd04e39935803b884c77258", + "81c7b048805741e6b53cdb396febc614", + "7187bae2a1944e2ab5b9c91b400558f1", + "77f578670b59423b98e5ad9965560b9e", + "c4c6397c9c47404cbbf09bf5a6edda24", + "bd04ae5d16784f44add01c0ff6bcf4b2", + "e2bf3efb91f545de9e9b5d0926ecaa5e", + "9061ee27feba4aa18ed42aefa3723e9f", + "480a866fbdca45cf8305d304484bfd82", + "f031c8de09764978bfec1b2cc9094f1f", + "63e2323f49db4793bd087e67b20ac350", + "f7b32bf8e85545a38c15c2d5f7735474", + "08d23d386ea54399bf56e5f01a392674", + "3005da6ad7be47cba014fc1e0e6e90ef", + "41f8de501701416e950811cf15cb0462", + "0f788280acd84006831b13b08c0f8bf8", + "83979fb138fb491398602dbe3e5a60d3", + "fbc6be2bcbb34d7d9d41113bb6c938ee", + "889d9348443446558ae7d9831e79e702", + "2dc08ab4103e43e3968ae45e59231c06", + "7272f055ce484be8b1588e139a6484a2", + "aa584c852bd647ca978d7f00efc72c5c", + "0d2b7c50beaf445d96f1ec54e1337ecf", + "93151015ad7f4c2fb40896ed7214de84", + "aa5bc1c5a4e842c4bab40cf08b9bcc3c", + "ac25c9f4aa3d4b459fd930eebc577c71", + "7b16af2078f54e48985fea38634a2102", + "cb3780dd61e34811b805ad31af1b2446", + "17d4bd4b851c47c4b0c823b785aebc25", + "613fe976919c45a3b7078789b0e86a16", + "632e082d87084ae984fdf600cabe8fe2", + "dcda2913a5d843618404f374b48be3de", + "e2485d989591462c85c4eced4a6cec4b", + "2aa050ea66254bcb811a00f13da64cef", + "ed0ea1b7dfd245b39cdbd2c186273179", + "d04d521bd0a049719f2199159e24d981", + "6db16794a695461685033677fecf9639", + "faf58bd8859744a2ac73719fefc5b454", + "557b448ad7b44870b8a2409a7d7e768d", + "8BsnY9VX9OkmoOARIPCqzf353xW", + "54d2c60a8a524844a33d0dbde1daeeb3", + "1ed3c88131124bd3a8de4eccf5e9d1c2", + "bc4f9e3319ec4a2f8fc6d0b5aa99b4cb", + "b84057b1e88641549f35733c1fd23218", + "6a59af66bf5b45a2988e575278b8c4f8", + "c2c5b668395a4e7b8ff67ad715e13084", + "8c3af1362caf45feb2e8eb2b6731926a", + "e46f3e28baf044d88cdb337a1264ad61", + "7b6a036bf0164ca7ab809b1b3ddf4926", + "ee618735fbfa4554952ef286fdb33a03", + "bb7e31d730814e97b882bee710535b12", + "5a31da20fee54f1c898ed0f2ddf73c86", + "8c3d449a43594c09a6289733c02891a9", + "2a49ce7206134ae68156a735c05651c4", + "d7169cb8a6014252abf05c8a6576ec4f", + "940781484cb64c6db6c615473bee996a", + "084e947281f04c8c8a0967609503d25f", + "3103821f38154c53aedd9afee825cafc", + "14897726f38f4b7da96bb4e9a72630f8", + "0f2ad11b9ad8445e87b7c6ee8ef61e14", + "4ce98301716e482793dfeb9aed5d1f00", + "fbadc209177641978444636641a6d515", + "8affaa3d12c64617b1dd04bc17152426", + "c591ac5a800846cea4d0861275e32570", + "9f79ee359a23478ab9d2cc0d0da3fc39", + "529c82e35aef4230849130e09e7f4522", + "e9e93176d37b4849a768e3a3e7341770", + "757961eb75a64dc689f2047ae8cdbd3b", + "11c751284a3f470b95336598bfbc8755", + "391223ac8c8a43b4a5fd6e0e05835bca", + "9a2c5ed79d634a61b1166836a8a5530f", + "8e5f7932521b460688c93c6aac79481d", + "f8a1269b8d564045af13b78826833a7e", + "ba33e9a52b9049ca8e46702bc1bee70d", + "14302adab4da4000a98a566aa2045872", + "59c298074dd744a487445284e6bdfa9d", + "5b98e6b4e98e4a2bb27bed44887de723", + "bcec690c4683424584f7ffb07e72b1cb", + "103e066a3c9545e4b3bfd2f176b38f52", + "93974967271e4c4db08efec0023d06bc", + "c38d573bb47f4dc4bdd2faea926c5276", + "2e85ee4291864ae4b43215f3396b6144", + "1bdfeb80a823450697f91fb26ac217e4", + "ccf5f68f59aa436b924ad41cce84aa01", + "2315667320e048b780099cdf79f1d814", + "b1de27e3981845369e48e9e8680fda3e", + "5ecf9d1175ae405a9a073db305786411", + "47be25756380445cb6e44eec2abe294c", + "4da1c40724254d9e80b0095c36b33d1e", + "8d00e925ebd24a9092b69d366ae024b6", + "dfecd6bf789e4aaaa7df7da5e5b1a19e", + "76a51825c1c944df8780c75eb14a9ffb", + "baf1ea30e7bb4790854619485d62b022", + "48828a3b571244aead33be214e7245cd", + "5d033c4a978c4efa8575e3012bc40c11", + "f3a115b5fc1e404fb81560dd5f2811f7", + "a17054d5f5e24c129a81d72e48e3fd65", + "f921c498d3fd4a33b600dbae0ad7ee8f", + "57cf7ca7fcb2493999d9153d7e338afc", + "15123ad4b807476cb1e1fea3c7906005", + "6cb1994ae58a40239ada19f705825ee4", + "0730fabb2c8341aaaf303351f2d644c7", + "58a48a137b03468fac88eecc6dacbaf7", + "9151102da3db4f2294748ae485ffd89b", + "23447a79169f49a196ac6a71158d4c4e", + "1a098ec926f544e9811a7a0b45e57e96", + "ed82ecb06ef9438fa83a2584b24d9f14", + "f31f1101f1a14b119b22496a6f8ce8cf", + "c394163e042d4049b191fbed941085c1", + "75c206e5f7854f169cc4013274e54c9f", + "980c232450304db182823815c7562b13", + "a9cb42717d294858a4691508df43d174", + "91b6e68c947a417dad03bca66d5a926e", + "2066470b15da42f0810a820163eb7bd7", + "a7f1da7d317c4d8a800b61213df15ad7", + "cb12d430d8e34ff6b51463a1750512ae", + "14c017540bd64fda812557411a24b0d9", + "7a38e7406ff846488a6e08c3ddd539ac", + "1d0066575968438cab7f9aa2ba893160", + "3e5f382200c9449cb41120a2fc977372", + "f78ad5dfb4cf4400a006a46ffe2889f8", + "e126eee03647445c92e44dfab049095a", + "2ee060080fe541e5805e48437ae40b65", + "4b144d343bb3462dacc5d37f3af5acc1", + "3296240a02274c3eafc4122ef053e123", + "2e8caf8eff2647759cc246fae68fb9cb", + "a7d9cf4993a341d398b4e626c1fabcee", + "fe6da61fcbed48fca962a7a97e0e504c", + "52f94ba7690446ee99df878f13d5247d", + "86be8ad4a17646ba98a5326aae12bd43", + "fbe6ee0468664971a661f75b6a6ab544", + "8a4f2d0baeb2481c8fa35a2fdc822554", + "9084895255194a3080d8bc9d610054aa", + "9ca345fea6b441b799f72bfe41e8ffbd", + "f953ec3d3204405580d54f74e4aebe8f", + "72ecd4deff5f4886adc2455581f0333d", + "bae498f934344556841afc86ceec6a15", + "f466a81875ee4d10b0c122d1d9838008", + "0176be079c2449e7aaebfb652910a854", + "ba76e2ce6a9349e8b688ed7dad25d956", + "4ddc29480d614eafabc8e402ce3e6fa1", + "7ff0bfb73bfb4a36aef31d8cd0ea4cb5", + "45cfb8b422984d7a8db0451d74022a22", + "92e3a69454e645229f0b1c374984fc00", + "19b840f12f67450b9ffc849165d46cf4", + "0c443c56738a4ba0b4b8ca1ffb337c8b", + "bac5fb96ec4345348ad530b4289c648e", + "6ed9e478c2774462afd8134f748346c5", + "ee7d42e76c174791824e59df999a5894", + "2f69e0cbfed54743a1fa40bd8bd5bb80", + "96b3653d589c4665b9560209ea285e05", + "94006c7196f840ae8e129a79ecb04612", + "0ab8c1875131421e9bb1c442fa3f5950", + "0227561c895f47fda3ff218dda809310", + "01a9b9241681422c9c21ef6d02c3bee1", + "f23a6d27f3c04c84aedc2ce7f17e64a5", + "9f6d03cf29f245ad97c51a56e9b1ca90", + "1fb36a3766074456bbb67cec452fbdbb", + "ce90ecea48f540959a5b580585f22d2e", + "baf7c311867744f7828e39108a936c0d", + "2b9064abd0d04d84a4aee64ad3d624d8", + "40190261dee14648b9fa5eb8c555916e", + "cee999f004da4194adf42b351306499f", + "f4d536baf41d4d1c80b89bccceded00f", + "f3a09aa627074470b6447479d95bfe70", + "eb42b12a68e24365a85c8832c3709e56", + "c4ecc0c89acd4c0c875ff8675dca7195", + "5644ddda1c2d43f29e7d97a2babc09d1", + "d9b25bcec41d4c1fbe04c869fd2c6545", + "642f7070f855479d88406de3e518d049", + "6a7254f24cb043e290f2019f34eb4325", + "05197c7001b343e183e561c66134c951", + "330bf3505ed7405ea9896c8214990538", + "bac4c4b4245e41e9bb76518871419ad0", + "7edd79c7145b4a228c5e6ecf7b2b259c", + "0550fd7147fa48d0863095d4d346330d", + "1ecc04eb85b14f46a398316586de6308", + "a360670b31d4446cab42db6455c29611", + "85dd813ac17149deb7b80e7e79905423", + "6c137d74d48b442ca8b482ddad8d6979", + "c31bf7a62a554460acdc243437d7ec83", + "bad8aa4988474919be8f48920dde7e3d", + "3dfe97bd897a40d48975b7f1d1b636fc", + "eb0f2125b09042808397993c24fdf965", + "981d39610fb840efa2a4a1913173b049", + "98830a78e8c54354a7fbe5ca8346fbf9", + "e1083bbb88ac4e55b31613f98bc39aee", + "5ac72b904b7b41deae78c72f1b0e0bf2", + "70aed3dc12274120809c97ee26e78fdb", + "765e3fa06bf947e982cd947cbfca7300", + "aa2996808fc24e4eb19c449bf1655c85", + "f80f09787b644975b1cfb3f52d8a1943", + "9eb9a00a95f14977bc2bb89a3690283f", + "cc16f75c4db54dfc8521735043534141", + "94cf8e9ecf43463c90b7f996e9ad314c", + "fff6033c0da34869b506233de7265d01", + "6da14fcf919940488e9b8c54ffff3f17", + "e2b9ee3b44c145d481e82f1cd344433d", + "87aa023087be46d78c02ab78e9da575c", + "410be9cdc3d84f6a9f139189309b4891", + "7467fd6d2ea044b191d2246e6fc7d875", + "889ef5336d414177bbf65d896ebd4d4d", + "cc92b578495942ee8fbca9049097b6f7", + "c22a351375084f79a47ecec4b3d78ba7", + "f537e142a592428d85ca7a940be221d3", + "d50458c651c64232a0beb301efc03968", + "1645702377054cab9b0d9012c6a2e294", + "0ca70c3b2e79458798d54f9438cd4793", + "fe566b14b0f64ee0bdb800b2c75c63da", + "428e94d194004de6832257a7287e4afd", + "ad5ee67dcd9540df92382ec4b3c3a378", + "df659aed13ad4d158481df6f61baeae8", + "15383aab42fb4643b6d099f64b3653fe", + "2f149a27338641b19e89f9de47253e55", + "68655c9cf95642efa50c98f895c7a449", + "7b1f172b5fd04f6c96a460140590242d", + "a97db25d23d74adf9d67dfc888f2d1c9", + "0de5f69c103e4d9eacf3dfd3dc14070c", + "23b0ee67f3344897abf2648f9b75fa60", + "2e75b800c76d49bc99010a89c6c328f4", + "84589627d9bb4faaad828970dddcba8c", + "da6d646358d1451fa751f1a9141290a3", + "48c7e5dff469450e93a76cbab0130a40", + "e4dfa6d204bf41adbc232f59b0fc6a3a", + "a303605a16804886a292008b89884119", + "b6839d41e73c4fb7b5ad3caa17a13266", + "f164d7cd880249a08367e32500f5b512", + "33aa56c96efa44aba978240659bd1f62", + "5f286538672f42d5ab292c7c4dee59ec", + "f8a12705a47a46ae968348de1ebe873d", + "b882cb6e4e7645c783ab856650c4df8f", + "17592eb4c67e48d3a13b36436b5b747f", + "f799e4a2db764626af2fc00dcd610542", + "69c8e841e0884f3d891f0c3b3869af61", + "46a294a3d35146f79b0fa1a1761a7d2e", + "1e63355f527748309cafcc85db85c3bf", + "9d51e2258c814560a89cd0ccd9c40120", + "028021b978664a108c8e1f2fe7d4bf4e", + "8e6e9418aa5040a792e57dc55131c6e5", + "eec2bde45a4a4273b96cfdee89a752cd", + "ef8e6a7a1adc4f659ffdd20495b72056", + "90f63881bce341b287c1124433c3790e", + "87e82aa304ce4571b69bdd5182549c72", + "61a31eeab12d424b8ab496f32d737c1f", + "085b9a4273ca43d8bc7093677666a896", + "4630cf631895489eaf3185b914aa14f5", + "d1147d567cf84d569c1abec10301cd29", + "39da0b3a463a4b7d87e829b77fb086e8", + "e9b92ee05ce44f618c9f374274a058b4", + "2bd3fcc82c9f43cfb0c8cf26c7d0107c", + "a4c500d7358a4a199b6a5cd35f416466", + "62a0ecdc608e4441b858e74ca649814a", + "7b5f0fc68ce34c78a98a1454597a8897", + "c003f02151c2479ea4ef975810009ff1", + "77a3a5bb2b5b497e9a1b97bf65efdd7d", + "cdfc1e37a83f47458539360e3a726563", + "d9fa3faf87ef4fd58f18046278f5633d", + "3804d6c79f26483485c01809ce388221", + "96f8d9d2728248008ab2fbfec4868b22", + "b8817926c0c74e43b6664a3fb0f76960", + "0c14d10726c4492ab15f592aaac1efcc", + "39db18dcfaf24ad183dcbf449698706e", + "eabdae85cce9456e8a194e89d42d0958", + "ac1dac6f444b4daf9173fd9908d5225d", + "1e9a0f0578434661a70056121f322f30", + "0721b4cc16664fb59b23b1a32370b13d", + "0d0d3f7f0ef744109a1cd7515b525fc4", + "71ef1d96970b422ba55d8e03ef8b0668", + "17385ac375154527959bef303a881404", + "fd7bb9503c284c60b7776c539dad934a", + "fcff1bddc64c4c9e98f85ff848a8a0eb", + "1da37b3d991a43a8ad9f58458053ac13", + "1b027d51a0b2474da5ca4f9ec0699c34", + "4eeda6741c3344e3977530dc78eb8242", + "6176a661fc1540539c981188987efe42", + "0dd82c3846b74e3dab39daa8a62b5898", + "fe4bee2d15084a09a599465e6bbe1be5", + "c21aa5ca52cb46a691c7d942b34f8fb9", + "c1fea49ff58f41458b2339c708c8617d", + "8334ff04c08f496794bed022e086deaf", + "c0951700653e4e978ef6199c38d07012", + "16f68961ae324c74a5e055e77f30ff27", + "5ccc72d43f0e4dc5ad5ef8eeb93cf3b0", + "5c1766b6586f451cb61df9fa29d3914e", + "c698d3e3f4564103a7bbf1ce4b9fdf3e", + "3a0a70f412e14b0685848748e0828138", + "cf6005949c0f44a9ad90961b9d0fe00d", + "06f579cb804e43f49fb47a320e6567d0", + "edbab39ce5fb4dd9a7ff9ce8933ea068", + "6d735c4fd06d4c159996d0c36aa16168", + "9fe3b3cbb19e4300893c4d3a1662c100", + "66830647970a47eab781c55c23746105", + "56cc5ce7665d4aa190f5e3818a548c15", + "a7bb63a8c1864953a214c350b6c92f93", + "f965adcdd1b84dc6b0f144450475e17d", + "693690cfb52d4559bf5d25b85b74265c", + "5a8ae351c0444499b83d131668260443", + "be7c6a1ffa164952afabb8e0eeb0abce", + "f0fbc1acea804a4ea612dc547d07d76f", + "17f0678bbd944c2ea3b63033e1f4f97c", + "03f1678351214e169ed36e05c7fe3bf0", + "1afc5de1422647bd879ab16ee022b42f", + "cedf99b8e91845c6bdfac05153e4a14c", + "de65428a6da846a4b5f05ea4fb667b08", + "116a11d0a88f4e148994f4197a5c8bd3", + "f73fccfd8d46445eacc4bfc2d6ca5c72", + "208a40369cc74270af9de03d12a72851", + "59e9c369ae7148378c496aef09fa7cf1", + "1141e55270af42309f4d5598a0cc17a6", + "3e249751cb3542468d14c3c58dda663b", + "15f9b57f69d642968bebf56ef6179ca5", + "230d900e77ea4505b8cb2447c4a7400e", + "90d1ad4c7a0c41f7ba53ac7e636dec0c", + "5cadf4e715834d1a9b8772591ddd1e63", + "f6ad9c9521814e5480606ed0d865e8ac", + "c3b507238f8846689447e2f59ba4a864", + "266b1bfc504a40bebb03fad1f7fd90fb", + "b2efbdb7322049ad808bf5b3ce327d09", + "dc797a35886940e19cc79edeb69ec933", + "d25dac7b78bc49fba3ed441811a7de7a", + "caee2ddea3f64380af5983448e6fed2e", + "afebd0f2418a4daca865cca0e485726f", + "61885b8e146747f7b842455c8672314a", + "f9939905b39e4c0a91da9e165a191f89", + "8b389d99a7da4e3499f0f84c2123b6d0", + "0276b7595fe44ae39e0f812b25727e54", + "73cd0f53b73c48bfb1f6897436d91a5c", + "a4c46087374a4a3e979092512f92c057", + "4cc32fb5dfff4f0b9432c2f1bd4a4f3c", + "af8f1c1ce0674fc38581ee39488b041c", + "b31bf7c6d10e493d879b902485c24daa", + "b1a7c5dcf8ce4c62a3c7bdaf8a4c6783", + "57ebf2b09f7745e2a65da9441e989437", + "7736320934f64381a0b9ebd8b6025ffc", + "01d685032bb7401a90a57d2c775d7cd9", + "f3a18faf9f264eaf8e69caea6a8d174b", + "925ccdc0b8d94d1f8250ac6faa9a1bae", + "5e5eb72eb4904dc0889971d97d6661e1", + "bca7b3a3b1ef4f978daf7a7265c583b2", + "f8f82b773fb94807a3284a5d5fddf579", + "fba21404c4a44db58e905e330586f043", + "3debe241ac7e401aa36ae944daa1708e", + "7461dd18799d4a7a90932910b031617e", + "f8f1bf5411e14a04a58d164fc00120bd", + "fd57d303020b432aa920bef6887607e3", + "22030c2da04540e0bb8c0b27e90b1821", + "650d7824ccc744ba9779765296490658", + "72f8601001af4220ab860aaf49bb575d", + "c03e397ecc9a44409733432b628b8cb9", + "46de6f5c28cf45d1bcfc2f634f921b5f", + "7cdf0ab3d55242858dc9e728501a4c72", + "802ecb616ccb476897b789a86e66753d", + "b84d4599058345b0b2c2ea4c5edd2aae", + "775a7a3c8d5047fbb1d0ec82bea8401c", + "5d45e58d77b74d3284a41604276ce72f", + "51d539f2158b4cc2b2bda9291c11518a", + "1522d7b6d8a14f4f8c19f996320fdc09", + "69f7f06a762745f289994d8066d7c57e", + "e128a618c91043678d815170f827bbc8", + "41c22daa59cd4767bff2b666e7c6857f", + "bc6ff205623e4720bbcf07a92f265100", + "cbc92e62b5c04401b49c356889325cd6", + "db946998f2074a2a9d6754a3d50da391", + "bb96e13d69c640dc809ea6148bb803e2", + "e2af833287444b1b9e675a8ad7bf9039", + "9bd81e34ac8a4f3f9406d0c05949aa56", + "dd70fc52babf4ff1af0418ac7c563fce", + "5ece83c92baf4cdf8d8383bacd9fc116", + "dc908f954a984b83b36433a3092b3085", + "d53bd92890934d249d4ea2e099ae0461", + "5a1ec9d7384a4974b6a17f6f05a0987a", + "1ce916879fc44f8d8cd6b07aaaf0724b", + "d0784ac4263d40efb74510bc948cc844", + "c551a3eaeeb8431c9ec6e32181ed2c60", + "9c4b4021d12e4b05b5a8992baab845d2", + "3f859435a4e24735bc10f5bd9bf85c88", + "d2132badba7846a29b9f3a4a5d80aeb4", + "4d8187534458455f99fa4d9b327aacd2", + "31ddf51cc5c84c3b81e7cfa85c072c0b", + "a22a5ec25ed747b1a1614ef0ee59725b", + "3f06dbb8db4347b8a6ffed1161689eb7", + "3ea2a0203bdb42de8faa11dcc81aa9f8", + "b68fd365187f45cf843e316d2ea23260", + "e25fd144cdb447968f20d4f4a6166d4c", + "9b04e85693604daea5c1f7ae41b85472", + "c277c4d1742b4f118becbfefd325ce71", + "6f6ed845055443589274347c168eeb28", + "656f83a4d9224c29abc82ade2207d2ce", + "f77ec2ebcf7d4a25a8ff08d6cb1643ff", + "087a0257a1064764ac57efbd0221ef20", + "4d6576311e1942879bbbd312cfc1d6a7", + "72f73dec9f794404b68779830b3583cc", + "ff12ae13bf3748e58f4fbd94d8f0a728", + "1c3dc1d3885540af83bc5246ef1d32aa", + "5320bf7bf1fb4c9cb0c0a410595160d8", + "c7e11706a0ed48fa9543b7286aa83ba7", + "b9b8b6aebfd146b8a11f840b2f8d0cca", + "c2b524996b9c47aeb7d7b48bb142b960", + "88949b5ee225423dbda36628df8fe9a7", + "72125b9457bb47419cdb7feca0a9a860", + "d1fc138d06d04ca6b2de4f6ee09fb925", + "cc0e8ef824294538857f0dfe11d1f74b", + "a19e79ff161a43a4abf2969e22707d43", + "03f6aaebc2d34ffe8040dff0f6bfc380", + "9c7956fe92e44f7b9c4582973203c690", + "d6c9c8e14edc4367b79280bfc16fa9ca", + "a9f7a1221b0242628bdeff1b95d2fe6f", + "6c0aad2ebcf44aedba8b0332b5f5ea5e", + "a23ae589a21e48688e39e065e8fa846b", + "4fdd0158c80c4de2a1b1bd5e0c77543a", + "7f9633ce2a7f438f9ec2f4e4fac2ba78", + "d499d237c88f494e890d828185bd415c", + "ab2380ac02474e678798bebb835c388b", + "f5307b774b1245d88845538d43ce1f9a", + "41d5ba704e154fc8889f5190fffdde07", + "c5121c56e5dc4f4a801eccb7d73f96af", + "529f0f57bd48470ca9d4922551cd78b4", + "ad608dabbcf04658a2afa0d18faa5240", + "4769f7f165c147a9b2cf3ce06ae6707f", + "57fcd8daa9ef429383eb533a240ef4de", + "5b6923b5185f4e15b9c16a58ca4a2d5b", + "76c92ae8920e4bd4b553122fadc8d570", + "6ef03a9e81e74b7ab8e98baf512e7e64", + "56f311dbc6994f93b5b5d14992ca79fb", + "ac463214548949a8b62b7de374aab451", + "952d2e8d5e01476cbdc539d5dd333108", + "bda792eede214739b5f55a65a4e7f97e", + "36f83cf4fab44312bd1a47efb6031987", + "d6a3307927254388a06b8d53aa847fcd", + "fc0b1187763741a08985a693cd010420", + "9e046bf9912841f8bb7f77c8fe878a63", + "896d4ec0a4fd46b8bc908518475699d3", + "bea0cb112eaa45dba2f89073cea6c6ef", + "ce316248e1994ddb9b47dfc9c2efaec3", + "1f0eb58fdc684c6f92541a7d55910c93", + "1e65b131074641d0845d3098abbe33d0", + "0f89f0e00beb4b57a587c4d01fabb61e", + "8f933c82cacb4079bf699f9fe8c3c0d7", + "bf2e74bab0e949d389fc1661f9554317", + "926e2afa1d5c4bf6ab1ab1e7460ff62c", + "3f1667eef68f427dafdadf9902ba1f3d", + "48d12f156daa46a8a9051b6b80a3ec45", + "b041673510a549fb83627b5689989f06", + "562f7696a58843cba62c794444b7b748", + "3180d17274e44a4aaf624239562a484c", + "ba21771aae634b62bd80284fa373abcd", + "87750322cddf4274bd5bb02a0c3190ff", + "d1bb68aebb1b4532b026d8eb824d4c15", + "f4652dd83c134e17a730e02a2cdd234e", + "8ceda28e608c450dada885fe63b21afb", + "7fd2cf441c5044ebb005e68893f0882f", + "6e329d48dfe34854b89eb40e5ee4daae", + "5fe299e839ec4d1586124a084811073c", + "a2db41c7b60a4823bff66e2c32143734", + "a2a9d279102c40eaa6e18d8d8e22dc17", + "7821a97af3b84737850b7aa52027a6b4", + "78a932a7fc414a7e886e4951435867d6", + "abc47f768dbf4bca92a3ae7ce3324564", + "8487824860ab4ff7b9c54665eaf2f050", + "f79f2bc987f94c9ead02a36844e7c48b", + "0025d57953fc4c8a80a44e59294e6841", + "8d8a9be757154b29872d959b598f059c", + "1bb47903bb2140f6ad08348662f51c71", + "7cd0ab4306f04645ab6443ea27cd8e28", + "2e6d6430686c4027ad4d86a8d711e3b1", + "7d6d8c6b5a4a4377823ef1b837848177", + "4a04473b6df44726864f3db3fcab30d6", + "4141ca05b3bd4faca7e249e10641117b", + "3dd6d435dcd24982b0a461e10237f06f", + "8c6ac61b545c4910a6d3f97cd59fc71c", + "85ad615c7f324095b5116c7ba66489db", + "e5b70b26a4fc4c19a610497f6a925661", + "c2629c0ed6c243b2bd92a48176cb10da", + "8657793385c14feba16726c0313db4a8", + "2f43dd2b45b049c7bc68e953d49ffb5c", + "d96e99a06e04475fbf0c640c2ad9cd68", + "019b60dc80184c40aa99b7d96a0ad90e", + "1d21c18fe54b4e549849e7e9eeb65102", + "b721e71976a54715b43edcced4731533", + "6d633339bc2e4ab79d2153cf4c925140", + "5767890161f243b3b8cc1ed4912059ba", + "1c2d6b04d438438198e31994f92a0072", + "1b2c7aaab85d4642809a5f34dec0dc0f", + "21bb429f13d54d3faa6c35ac9bb1262b", + "8b7831b323234d70b8a553b67de90ed2", + "ccd657ea77f247a88c579114b4690d3d", + "2bc46c45cb61498e9ff1dba26060452f", + "4ccf0fa531124ac29b4c8173471f8e1b", + "4e8debdfc7954e2ebfd93e0e228db9f7", + "841000264bd5438890bed25c2358ba9d", + "4e7c3cc5d517403db710385a1f82f7f2", + "c59eca2d6a214358b1b3b89628cc34da", + "be95674591e34ac9a566824dff1f5e0d", + "538e1ff6ba0f44fc9ff498b62d89f970", + "c7c9f3c0961e406986a0e7e3d5af3bba", + "c3e36457c888481b936157249079ffdf", + "8ea60759ff8d4cf6b953ccd2676d56b7", + "a84857c0b69046778ec0319a68bd2bf6", + "b983f3959db641ef8b2870489de95b04", + "c5090ffa4aec4bedb0db5d688e647538", + "9b89997606084bcfbb50082332dfe4ac", + "c42d069236174467a2fb536f7d42d7f0", + "dbf8f1da9e594937985b03a037501df1", + "6586e916ae8c4d27a0006987d5b1b49d", + "c2091146aa454765a5f7654dbad62d3e", + "3fe560a7da33420aa8d33094073e1684", + "e74df1700f64493794fd743af3dcd67c", + "aa31c43caefb43658c6c8aa88e41a926", + "ffd39b6fb0c2444dbdf4af2a3b106635", + "df6bd854d92845f2b409456456e21147", + "2c3e474dd455402a8ed3d72b24192da7", + "98abc88264bd431b8551ee43212c4121", + "444c3a478c984f339935b78180541370", + "0632e654899b47c484c7dc2495469c97", + "544ed0d93221467c812c30467afd8e91", + "992afd9f039b4773a5a7b9b89b91a244", + "ba324110e80b4ada8da103497040a9b0", + "70617d7cae8d4d67a354cb44ba7b21e7", + "15d85a42ebfb4f729fea05f421ea9202", + "ddfbc802f6cd4f11a58226c37e2fd4da", + "f9f2bf0d6ffb49848b34f15d0253cf5a", + "22ac8280c1434e5f8b41e2fdec45abd6", + "4a1267b0e6504829bedc74c7ba0a7e98", + "18944e30b4b7448bad8c79528f111e90", + "6cf41ee1a60143efb983b74c0d69a9a4", + "05ada823740f461c94456a68f1146ee2", + "027ac64798274c3297d2fe9b09ac7a09", + "3734ef58ca644b59a6ed8afbfb8c41b1", + "cfa3bb161fb6471b916a841686efa182", + "0195a8f730c040e8b54ab972550a0574", + "b874f4ffbafd4152b3f28868e2fa79f4", + "5895cab07bed47ca9defeacd935c55ec", + "8230e789f9214e5f9bd5ac3dab938667", + "392dcf37195e43948cfbffe099082108", + "b6c3662d06f94b9eacdcc311cac51587", + "62a2594229754c58850935fc625679d3", + "4a4d0b7f45f2479dbfc328f14869068e", + "de918c5094e9407388283c1e6aae6ea3", + "3f08823a3a8d408bb98af066b938c742", + "8acdcffecd6d428eb8f766d74b2ec7ec", + "192676e1bc78484f8a4120e1dbb35bcf", + "b2496a1228354ec3bfd86f83337bef26", + "f6a69b6ebbbc4f6baa151eef92213271", + "86e4ec5f8d124dae8a4f14cf56183861", + "4c978c49b3e949edb55fe41725f0df88", + "8bd6eda897ec4f86816fbfe8616b041f", + "e1177f28df204e19a62e1e5fbb76e42d", + "d83368c3698a4d9b8572ff212c03c047", + "8ba4ff3bb61945478cf58034ed39db9d", + "27c6ffde02594d99acaaa9a8d3656310", + "2c3b4613db884585938318e1d10361d3", + "9c6ca39cc8794dcbbd59de98fc1d88e1", + "5df23f426fd349f8b448cc2fbd34bddf", + "873053699e7b4375975aa234af20a562", + "f070cb9e943f41b9881145582b8076e7", + "2d7ee43180d940d1ad076ed7fda367da", + "8b3a66ebd56c49d5b24cd24c6337cda9", + "6b273f972c494413a2cb1e1e8d57026a", + "5632f99c65cf4f6eab6bde38ba99afa2", + "3bd45e3b76324f358cef8b4ec0df47b5", + "49bbb15e3a5b4386bd1fe27d37335d08", + "82ca6d4c273e4b6aa39258dddfbe2588", + "4e3561477ea04c93b793c8da253c22db", + "e2c70e7411dd496a9c54be5711e09f77", + "34ae6fccabe142358409f87e106cdaf1", + "a3185b14849c4bcebf5d416ea61de9d8", + "1f46425a6fbe47cbafac023e75df1975", + "da22b449bef044b188e854dfe46a7aab", + "964bb923973c4bfcb019fa320382c9c7", + "16dfbc0865284fad8cefc7487251ce88", + "e4bfd493951a435da340fceef6079d6c", + "a99873607078488ba37ccbca5d8b7dc2", + "02dcf7624c21467fb391e4303823f8e6", + "4615c80caadf49a2b695ef31811a861c", + "7c450f3d167443ef9979f6852cadacd8", + "e0f490339cb543f1894b60df92c036b7", + "7244d8d3849e4f589033a026c71903a2", + "3d9dd0b02300445fb0d85d5c2c5f369d", + "962ef5773bf04418a90294483a3f741e", + "56dde1d5fdb44867b5a48e232cd95b2f", + "5a59b3b6ac644c11a3621cc7d5e5f7df", + "5186770ffff244e885b211e1ddbe25b6", + "4eb072b2cdbd4277b63d80b98c9261ea", + "4090da9c2a304824982d8f17b5097166", + "8e18588b74404a18b5226953c427e567", + "cfe9b27eacd84ebdb1b8c1bebd85ffc4", + "1f7e9a8e7b2e40b6a60ee4099a122b9c", + "b768f84fcc7c4237b79be7eb317b826f", + "7a1869479e58422b84ad18533b5b4439", + "65d1720bf3ed40f085723b3d214f0f21", + "076d1f622af7417d8bb5b5f654fa49ad", + "066a5cbdbf194194847d773a1e339869", + "cfc4364c516544168dcc85096feccd40", + "c78b9c725db44324b3246cc59af1947e", + "47ada0835eb647219ee3e385a8fea1b5", + "e23148271b374a7699813e36af83e7c0", + "bb0ada380894441faac7c929787dbf84", + "aeccf29d3ab04639bc5e30090d43413a", + "410defc892de49cd8387459048a10d53", + "e63063d93b894b42952277574bb7860d", + "9f792e4666194853ac8a881834e74523", + "f8def3c5f656454c935fe3d626ed9fab", + "bed379559a57403ebe484566945d3c33", + "f94d39b60c5846148b63b523c8e85ed4", + "566492c26f6949ec8f082c0710ca93e5", + "4c093a58a84c475e85c01a27c34256f3", + "0eded1c2ca7a4cb0aca586a37451cbd6", + "dd4b4cdb343742b68982e746805b112c", + "1ff7542d6b34498f9dcbd1ed44cb2523", + "0532b56bf74140dea8a411cab7709e4d", + "a78e8add72184271b3334925f9a178be", + "d0e96151042d455ab7218617c0cd735f", + "2736ccaa65d7426db74f42809e3bd4cc", + "65649513903f49dfaf00eaf843186780", + "b946f87c9b7341909f99590d2bbf92da", + "e34b684db27443318642b3b6e9b50d01", + "c5b9bc57a58a43debee5d39efa6a516f", + "c821f5d2b11e49fbb62543ce4d91c005", + "dc429020e35e4fd88937d9e12614ea5c", + "31f4e52cbe294d7abb70893b48042f3b", + "c2e916b66c4d4bf5b93373cb43a85b99", + "bf02d1de6b42446d94e3ffc12c423937", + "de25321f950c4227bb04e2afa700303f", + "88701fb561fb4a2aa2fbc5d6353221d9", + "dd95e3e5cfda48d285982317dfb35c85", + "077d22b731b44216b26e43e4c62aa905", + "4a195689a3584dd7a6c40d39fc5d626b", + "ce61f81b34c747459f61b528d8967820", + "05990b201b514793adc8f609e302cf79", + "657b7bfba4b64e3289bd5aa5ddfa2f24", + "9c130e43551548d6b2f537d0d7b836f7", + "0bf7985bf5f94236b8b5c2965270e08b", + "9b43606d69a5494ab5cb75f3ecaa44c0", + "ed244ef789654bf19cfae6ef9e0c2dda", + "ebd8b09732dc4a2ab7f38e615c2a1607", + "7a75c224806a4d04a7a9ebba517ad100", + "c9ae86a51a7a4b688c67ef82f2e736bb", + "9237246f9a21433ba6a58782f5328e45", + "d9f647655e704c35a277ae052dda1b4f", + "758f72d45dd74074b58b8320997879a0", + "a615760dd5b049c4976ba13011e61e68", + "77816f1c617541d9b67c1ee4db9a0197", + "42e02b8cb8884ce09380943e8dd90372", + "f0a9fc8b51004680904f320e7133e951", + "5c933ef8b85040a9bc13299b3f5f5c86", + "5c20db910da64745abd6b4a7b40780f6", + "f85034b168854e0689a10e203801d3a7", + "e18afcee51404bca9352824fcbf5a2ed", + "7339a87dac884f1e8aeed3bf80dc0a5f", + "9c25b5b38a344667af6afb33eb8ac25a", + "81f7b0b5581f4e2b89b1c95259a054bc", + "63a294cd9b9f4b47a2c8da1f16cb17c1", + "9f165203a07e47bcb1a779479e0bd591", + "8f5f5abc75bb49f9aa2fe9a7c39b5872", + "5f988ebf336a4e6a959fec74a188b041", + "baf345bb68fd4f1a9eac39faf456682c", + "693f774894aa467eafe5c7d53dd3e67e", + "c626625486104768a6cab5eb4ecf9cf3", + "6614ffc5235941b9b274af113b0511b2", + "8863b1cf84bd4689a8b44bb2ddab6c29", + "9384c52c302f4ad2b9d718baf43dce78", + "a519aac644224af8a34f56b2440712a9", + "76f90f74e3ad4bd4b234c8846c0ef4a6", + "7f64c4535b1d4af4ac3c2bde282e4fc9", + "50f3ea9d6fc340b7bb6c47e5180b1ab5", + "07c3f7e48501443b9ef83adb13083532", + "0f2b97ffb3f64e11b78f8dd9f1b77b50", + "1b29010d87eb4f41ab81d054d77d03e3", + "d0d13ab34fb74e51984387fb9123b2d2", + "5b8d17e2bc1f4deeb4fe5e83a2ca7dc1", + "30d037c1ef774c4b87c5a2f2b1449535", + "8b289cacdd184ab49f5a7194d2658aa7", + "6346e560c5564737ae5eef7edfb6426e", + "bda89ea9c21741b793f219991eed4f7a", + "3378f67a424041f3acbc574b57bda90d", + "9246ba5533254bd7bf8ef046364cb728", + "8383655021be4b24b5e341497940b3f1", + "fa5718c649064d9195b3005ca4eefeff", + "5a739414f7014608a9f432f8749dd3f3", + "aadd0e6c42cb45f9982b0ce99a33bd27", + "2f513a795096432285e6b3227965f979", + "f3215db5ed3d4dbcb48c6cb40de0aef5", + "3146c02a2b5e41b9ac8481c66c8e1ba1", + "ecd6448e6dae4b93b60008913bdf8554", + "6914d1e81eeb4377b61af0e5321ede5b", + "3d66ee325dfa450d942e864b554d877d", + "8bfd039a8257410a90411b7f8da205c1", + "24116290afbc429b921a61856974da81", + "8ac4c06d24d04fc3b122e927a11690a1", + "ebdca24dec844defa1fc3f4954ca0a95", + "4127a49df7534d74a787f35a743dc87e", + "91c5283b27c74583900d5e26e2fcd086", + "26b0f7c8472741f4b85b889cf3b1d870", + "440d9b2aca8846569c41d8108ecda3be", + "590a030097184cc391c52929086848fd", + "85718c349a664e919e5b56aa06c97422", + "ed826285fc8c45d8a0c6d62352a3a239", + "910a9229768a40b59df9bcd58e3cd14e", + "d52be89d681e4d669e3c7f0397de470f", + "29c7f92167f3476a9aa13029796146a0", + "2799b49fe2284577bcc6b09bc8b71f2c", + "231dfc7ece6846fb87625fdf364394c5", + "e12005c726144f0081cccc09ec96fe6a", + "cdd861d7849440abb95fa8e37376d099", + "c9e1d2bcc5d04146a428b7ab4dc1d660", + "fd72e7845cf24342ab74b1c80fecb1e1", + "da2c426b7ec247d5aee0ab51a83f8e14", + "2e10a793298347439452bd8d99672015", + "70739da5a82149a799828a8751fd5d91", + "921667e8070444a68b0d7b95586b12fc", + "8d8de6b5deba42d99d045b984d67f5d5", + "094e79ef6fd844dd97f2389564b48bd0", + "2aed6f33ce554ac59e2bfa92395ed6fa", + "d5a5bf3014c24780b619580aaf8b0793", + "db4c6b62aaf04b2bb986f61e9a8d899a", + "67d3cd1be64f4bd398073e446b2455e8", + "dcedf982e8874a03b5df3a8c187616a5", + "85447e96905a4cc8aa68f68403eec62e", + "1c85f15fa094415d854cb167784ed122", + "342abd080b3b46ac893ab1790007ce21", + "c71f570d21634b7ab50364277e1badcf", + "82105cda3eb541debec026cba74381ec", + "6d95c79ab7d449dc877f0e5962e222cc", + "1c7064705d2f47b4ba0b7314efe9444a", + "847ad13c1bc648a69e2e0fbfb3fda997", + "fa809015f6854b978516741e0bc00ecd", + "844c1804c16a4900a317a7a1d6833c6b", + "fba45572d694408188924e9df9468cdf", + "6e5c625b03a6417ab21263bd180df837", + "959952e5a59c4ac3aa461e3c7e401f49", + "c7b7fa5ae4094dcc891e9266ebe486b8", + "8d829f900c61496baacb9785a787af7e", + "70d67d83de7a491aa8ac6ffb5d464a83", + "427da50ff3f54dffb63ed1510b743c8d", + "e8567a1ffb06492ca1b8750e5d61e753", + "a96d9b0f84664c3fa4be448e5f725949", + "b8a8be62f5064dada09f2b3ed520a38a", + "3677be38487148d489e0f8e13be93c37", + "83826b4fba9a4bbcae53e38c02ccbfea", + "e722bf80ce1149c5b97b574e58ab9d6d", + "4af5b7533cef44e599d00e7063d6de63", + "d9c7f3d06d2a4e4eae0fd0cfca9870aa", + "e8355b33ccfb41ed8d668cf4cf0dbd80", + "d669b88fe07f47548e4bca2aeb973b97", + "b542edb18a1d41f9bad314e01bf6f713", + "47aa0ad8b77b412eb266d2d37a2b5cc8", + "4ecf95f05078462aba00adbe05e03f84", + "3dd98cf970d04d79b07fbf6087affcae", + "ed2c74f57f2f44f78361bda1c0c0952b", + "c45145941d114c85a575681079c61aff", + "d1774953cc4d4a1f833ae33a4a188c33", + "4a3d504cdaee4cd2aafb617e9da5f259", + "319f26d959974b06bd4f746b4b736310", + "61337145044d4c14b006bf9fea4a6f4f", + "d1fd6c28e8c54860946a5847f96df2ba", + "a7accfa58fbd46f2b4e9a40093415268", + "454628e0165a4c94b04b8a6e9967fc32", + "ae4407f79ffd402a98d1046fa452f276", + "a500c503cc404c2e9acb624f1f8ebe0c", + "fb0bcbbd154f4c76b2fb389ea647015a", + "815bd9cee3644f3f8996b4a6d123c7c3", + "2bd168a944884e69ae1c0bb13489cef2", + "f86bcb600f04478c821802e1dd9d20ca", + "9e736e5bcee4442da616095015b96ee1", + "cf5558b8ac904c7b8b8a314fc09d2e96", + "ff61e3fe4df94a149ac197825d461efa", + "1fef2b190b0940b39289d3d656fc0cd5", + "34822be490d847059f91481ab91bd2a2", + "8cfa2353cb0f408cb1ec7badc455c193", + "6d30c06319c14340a17015db697cbb81", + "bb1e2c79c4244b538dd2c4127ef95f1d", + "462e946d3d424d589171f5dc6eb2f11e", + "90d5f8082ac2427d8540780a0cfd9d5c", + "a4e220e4f4c94b229d1944840c4a9a8d", + "dba206fede0844c6a9b33d6fc72ce65f", + "958421242ad949bc827c9455dec658df", + "f34090dec2d845c1b1ec436325f5a56b", + "d6332219454e45f3b27d834224238f28", + "434e309911934006933f987e60ccfeb8", + "9346f47705eb459eb4a20153ccedf771", + "ccbcab6432ee46f8a56ad4544a490292", + "27191d78da6a41ce847aa634ae270b25", + "8907f8c7c21842b7bf059b077ff99a35", + "f3c4029644064b8187bdd30c7671e8a4", + "30f76592697042cca38f1f05dc18b45a", + "1d118adc547342ebb67f6f888b964d69", + "ed49e5aca8a6445dbbe3ae88bad8e5f7", + "53bf56e597114c22bafed8c41c1fdc4a", + "45dbe855861e499396c584625e7e757e", + "0d06838c3c2041fe91b39b146c2c9eeb", + "f2d31eb0ddac4d21944df7dcc4af6d28", + "06111598a57045008e5f3367eaf58873", + "fd7f416d84d7414cb4ff4989a27bdb2d", + "70e364b143a24d4eaf85689be03e1898", + "02750bcb389847bd8e8fa4b5f63439d3", + "b3baaf8c624a4857b0b35c55677ef198", + "383bf7e5bc894e2b9a3aab61fe2db721", + "e3933a6ed40d4e9c87a9e204d6b049f7", + "564a3281703d43b0b2041c6b0e33f04a", + "26e7c5710ca5471d9f5f977dd1499ea0", + "b1fc1fa6b0304874acbbaaf3ab93365f", + "208f64a19478420e9b5874f70315b214", + "a5cce410728140c492855a109f219ac1", + "feadb91bad934c41ab9d0ebd6a9ee091", + "75de632d4300496cae0d01c5ad4d8d6a", + "2ccb6b62cb204f329eb35ac9c2621ea2", + "9fcf535da1094714b59f0fc4ab598622", + "aea08798296f4c0d99fcf11979b5e50d", + "b0360d1b964642d3b7502f423c96c3ad", + "73521941674543bfa02c70765ace80d8", + "11d8e1e33f544e5d85d0c5a6b8e2f29a", + "e94af9fdfbf74ea6b0737b94d5cf4676", + "2db4e72ee66645f9bf87a4887f181f96", + "3f38a8a2273441508889951f6e312ae0", + "1ee8dea6e1544460b0ffd050df164d22", + "d90e4353ae7047e0b4f37abc8bc58468", + "ed90666cde13404fb8a964749c38106c", + "22dfaf57c4654e72928c422eadb32da1", + "99049e2f92ba42499249f87c63ad6214", + "e0f835cbbd2040f2a4b9d4bf696b6bba", + "c80e2b05a1fb4d19937f2b7deb6ff2ff", + "03eb31346c794f99857b0c66a3930ddb", + "d9b5a2c032244ccf8ee63bd26ed8bb2b", + "388dc49d323d42fdbd08e53021c10e82", + "acd2d2f99c934741b1c2af2737d596ee", + "5df877728aa54fd4b35d54bfe2f5c39b", + "146817d85ce2447490c4fe9f0bbf6116", + "d0c176d08c884d5d8a4657c200a0c9bf", + "558faeb71ea04a5dbeb9aadf76430a85", + "7ad22cf0f1eb4c60bb4dc923018a7467", + "ba7ff0a176914c4b9d294caf7d7d0d31", + "27464644cbb4403baa2cfdc179c75c5c", + "b03b8fc3a5e343bab43f3fa81c024ce5", + "55b689d55dbb45dc8e4a5d7d76e54daa", + "8272ec9e01df48fa827918b876392c9a", + "03d35bbf470b48f3b28d54a4c6516276", + "74429e1800d1488899fa71569f2d114e", + "f1fcdcb729b64e32801b90614f4d8c2b", + "788616cd57f3481481e52172e1d4f5cb", + "27b8b5153257443d8f0a1e608f4319d1", + "6b9700f7d35e4ddd81b41a70a3c12251", + "a3b8866fbc0646bcb4d6dd0d1da59367", + "3f97dc47b0fd4b1382f169d2f1d3b309", + "18f3e9d66b2047b59af80d9ee90fd036", + "8db7c2fefe2949b6a4a82c6185e5adcf", + "37cf532aae4446c4b57f82d0031bb070", + "dac6cbe10dd44d2eaf8037e54e37dedf", + "85fc0625905c4fd4941dd08cbc37f747", + "1943b9ee974640ca80172d49dd388723", + "e68046fd93994b3e9c4e3b072d3cb624", + "643e3c77db9c40c5a90f5cb78e3cd6c3", + "1a9881bb62624ff78574ce773ecb2a0a", + "b10ee58a01b649d381598d899850176c", + "809eefe0c7514cb38b1a0a7bb910ab73", + "8fc797d63d574f8db310de3b657a41b5", + "2829ce5af5744b27b7b04cd250bace09", + "feef9e9f20d442a79023b232c38fb9b3", + "8be0320aee584613af8d2b52425b25c6", + "c913350fa1134c8ca4fb56843c2336f1", + "b872e2c3f4f7457796edebcb7c0a290e", + "d0e31dfed6f4438090294599ed5134d4", + "740b08ce6f3c4d3a844206b0622a93e2", + "8873d2ec7e4a4385ab0455e144744d22", + "2332e10e6745412aa9499524b656dfd6", + "f49f66f6e160498ca1a7b102f5b52f8b", + "813ff0eecb6c499286f15f00795f2ed8", + "e4c7780379b048bf98b21ef3858afc20", + "0c1ec94dcb5e4c7fbd495ed41087bdc5", + "bb9eb66d656545aba383bb0a0852e936", + "d745dd41428f4a2c95161444a1f90368", + "7099d659048f4214a00eb984deb66e13", + "ea37176639fd4c52add9371aee2fdfbe", + "b1817a0774ad486fae1c98a0db1d6d08", + "37e00109d5b04b859f7116742a9c3955", + "57ec7545f8704db082e784cc79b6a7fc", + "df26b8155ac84c57a10f5451a5ac1a12", + "f2027b2b27df4ac8a57648d165688c4a", + "745d0d185b49405694ef4e16cf78e224", + "fb0516c9c6954e5dbeb420aaa48059c0", + "d52ea5e420f540ad8cb1e2a77f7e9264", + "7b35843ab9364ca695f11224698efabe", + "fd206144d8b64a019de9aa0aa1203946", + "8c943894c0224654a11b60c4fdf89283", + "984e0d2c5ce147ffbd9df92b543b00d5", + "4e4e3474d964471984bf57a21f469479", + "640e241fec904e16991253ab3704e048", + "9a0c52d350634e419aaf0eea1e67d9da", + "50fd334123164e3eaeb95fffd88f166b", + "b02e258b63e948bcbb9e23af227e80a3", + "fac08019fef5474189f965bb495771eb", + "2ff3797559da49d5a8e43aa64cc05244", + "8fd087d7b62646c5b50db0dd00f3f596", + "df3f36c368e441bd979e0c149ff295a6", + "a2d6754a990c476c94f07cd98b12cf1e", + "e14da87949f249149980912c304d5f58", + "96f79ba5a39c4f16b1b70a51ced475ef", + "62eb766517024004865f3e80699815ac", + "931e2b1953304f2b88aa00776b5a3d36", + "a0b11cbd59e5435eadf1027927c85e62", + "157de95fa4014050a969a8361a83d366", + "87d061ccab964209953b1622dee66182", + "21b2a8f0d3c64459bf024471d0999fbe", + "d912256c534e4a0b84b94ac1b6b272ba", + "ada5b7de112446a0883c1f1353eddc15", + "f7d2340d2b3b4520957ae032f31b11c7", + "91acc6e821a74ed3a3c0ae72643958a5", + "fb712e616d724e03a7e034f1d5b5352b", + "6049f275e5d448679c29d29dc1aa9ce2", + "004fb4d72f6c4e55a15b9025a868d1a3", + "951e741587b643869017c5912248efd0", + "9e45a57b57fb4b4ca79d75a757aa3da3", + "3946106dc55c4913aa92d24e2b7114e4", + "dec0beb59d0644078572b65b2eef0345", + "71f421347c224f19b757f507be6a016a", + "7889724c7ca848f48a4c25347eac6034", + "1c7d62520689496bbdfc7e9cacbe4803", + "8344a44f7bb547c4882c20a8270b068a", + "05250fb6f22344d08160ee07a56e9776", + "4b3adf64384e450f9553ce3fba9882fd", + "099f78dedaab4792b81899c640358029", + "dce5a98e2e3c4d5bb6ffa09adc57d2e8", + "70c1759794534b79bb7efa9b40e79c9c", + "c5bc470c3c9b4dc190f654cd7ac1405b", + "2c4785f955bb4eedb825f2e655139cb6", + "2ad4ab1992c84b2084889c82ba110905", + "f7dfa603c0c241dbaedb6490e2866d91", + "5c26a86ff20c4df689b5fbd760337845", + "4ba531a854cd4213bdc34c62cfb7134e", + "35a10c95cdd34cd69d3a86808c2cb5d8", + "6b472c13b6194f8d9e60ae62101dd0db", + "a0d26974b8054a46a68a326ce1f1e79f", + "bc387203ef184f2dbd25b236945857c5", + "644268276422484eb24ae156e1d0ed86", + "1aff3acca92145b591082da2e6ef43a6", + "35cecc41cfed4c78bb31731b4db4b33a", + "adfb3f9a6b954150a894216c1c020a6d", + "02ef40153ca24f309d1f67fe42066cb6", + "adb078c42d0746798efaa3e4686afd33", + "d7edf834dd244952ad84d2bb34f54d23", + "152ea047c33c47ec94e15486b30e740b", + "d7c365148bb5403fa15aff16bcaceb67", + "66ee5c5053e44d70a21e3b48de0e4db8", + "6c2fb62146ed4c28bd40732609b7ef1b", + "a6b69fc12d8842f58df2ae0a4ef3ef54", + "dc14b3a6ebbd402b921fb0cbcc6e0cbb", + "4116b0b4583049d5bdf55daffb0693f3", + "545c4941bb7d4e62844fc60725780003", + "0a063e7f96754946a6719f3316ad10a5", + "b352356a4f394b25bc9c0bc37c52aee4", + "995ec373d380457e990057e6fdadcfab", + "63ca24d6d4224850a659d110f85d0f20", + "aa023f85b3394f6db6b88b08036e1799", + "a8d0d83288bc45a2ab4f00543bab40fa", + "6f96a00b102843d9b22caee1f028aaf1", + "f5bb6ebd8c9d4a5780bbc43155f2396b", + "509cf065f32a499f920b40b23d85c0fa", + "4f2331084ef24a759580091ff7575fc0", + "c1e243294aa44ffd9f63f964ac5c285b", + "a1ad2734fdf14d0b90e90aea8a6c1dad", + "b547277417184471855155ded759a85e", + "82fda2cfa8974171ae64d4e434aa4b9b", + "e3e30694cd504b38aa01c01b918f2e3b", + "bd71883bad9845389ef4ec2801004801", + "b5bc6b0023bf448d976a6e8ff699eb8c", + "3603cf85c49e4323a93b62db0258b36f", + "77458bde70b94001b6ecc5a8893e8d59", + "d2524f238cd043cdaca559b51f7611dc", + "de849052c70f458c9c1c4d65582330c8", + "91bcf402b3a4409f8dc0a64179963a75", + "e375fcb8793643119cecade89c43cb1c", + "cd80232e4ce145daa0d4c22045c22b55", + "5b81b7f478454277ab1b4630362e06b9", + "d298dbdce2884ea49516b50d0595a30e", + "dab1778875214c4f8e4a09fc330aaed3", + "c6b0d7c071964652be6aa900b146ed53", + "b7832cf1396e4dcc9513e5e1acef182b", + "75ca8e0250024a25a14b93ac7f8e0bbf", + "7293ebcbe1264f78806c695fe29a8b83", + "caf017136b334e22acc1b95d9b766bf3", + "e024e4e52c1b4995b277cb3c61ac8388", + "6145d25461f741ea952d03a85c8d0ca2", + "b038c39e626a4d28b7ce90c11ebc01f5", + "bd5708568d9042bf8b0e4893a416e92e", + "1067fad689ec4fc79c9e0bb2ffee9534", + "39273ba4b01648508b07e8f76fff0841", + "9aa1fb08953340b6a3f1f14dc4cce656", + "a79995916d8d4a2a903640edb92433af", + "6a035d2105c64cbe80970066ae36e058", + "f602b8aad3a749c8ae12d6a44ff062c7", + "54381dae288f44c1a0ab80dffae3389f", + "31d59bae140c4667af5162d44aa0fb56", + "e802d8415bd04da8ab404d226e548a3f", + "2d1835d41e7045c3b20099736e18c680", + "fcff3f35fc654c259e24710f89d1fcfd", + "7fb9962ef55f4680849035f3cf805827", + "d2d2703896c34879a59a97c123f77176", + "bb89b709772e41a58b6a4aef9df3cf66", + "0f77425d282c403e9cb8f4dc85bcee7c", + "6d53765d32f24bcfbf4c9081c4c2a558", + "4533a21c002542b2ae6649d66369991e", + "902ef5795d8c45cb9fadc35788a98a81", + "7650a398a5f742309cfcb66b7235122d", + "440bfda47c0f44b5a8cf4c8dde81ebe5", + "c89f01b2d4bc4a27981d26ddb9b0e49d", + "6dc7ad3cc7ed490eacbcf168d652d6dc", + "b35454d6bf504f8b99a3d1c705eddb48", + "3bc33573f4d040d8ba9e4c32c2117523", + "7887360333be4ffeb209f22a840dcb0c", + "19b2c1893f084653ab226cc3faf27c96", + "10ffb29ca0344addba8acc99414a03fb", + "9e82add156194835b892d67849cf37e2", + "382319dab129471aa4985d0f599bd48d", + "5d0dc95b0c734a4cbee9f6ec7e963464", + "fa2b840819ad4484922107c84f164fb3", + "581e861e33d84e4fa5e82695a610e7ff", + "c91bfbc57b8b4f6199fac8e5bbe59651", + "236675a2aff5435780e4429ab4300a16", + "5a649462ebef4028b6fee2656aa406d7", + "fea25ef07c5941ab9d7ee4f829d410d1", + "e4f44df62e974e8a8c09e2e6f4be0a43", + "e8032e3b76d14bf0916ec70a0f31508a", + "12a4c0703f6845849d68470d8da9a97c", + "faa0dd7693dd4265aaa509b3eb81304c", + "2b2f5957b5394da79431436f7ace35c6", + "c98c109df4fb4579b3b2e7d7249c68ed", + "3f2a6b3f9fcd48979f611eb59473f53e", + "f0736e4d64074cce889db48a6e2f051b", + "459c709937a44a81ba0d9bee266f82d4", + "204d8a22d5044262a6ba5d49d4628767", + "c7eb6c770a0e409b946fe4ee34996308", + "babd30b2446c45ed9234d08a1e32493a", + "099fe049c0cf4b219b0c9cd9a7361cb7", + "49a8eaee73a943e08fb77049f8b0d16d", + "50119bf08ac64250b715c6513f2c0082", + "e8a52be1754f46baba29a353888b1e1a", + "5a9b5a0ce4944cad97fc9e2d6ddfc6a4", + "c56948f1eb1e48bea30786ad576a541c", + "fcd4bea617444c818b026bb702b311af", + "fa01b6bf386d456e8539c49c1ccbe87a", + "3e8c37f3d701413897c6333446a76a6b", + "56d34315571f4523b71d3a74c1d4be25", + "6c20ebeaa8d24bdda0c9f5891c7ac549", + "e76da4eef4e84e1c959260a384fc1c28", + "73503cbadf004511b5c299e031fe14f1", + "25f5ee4216fd4bee9d2752705df21fae", + "a73426836efc4ebb86786f265c871875", + "5c6c533c1ecb43f6b8ba9db3f6eda0ce", + "01680c5bad224c5ba0b5dbf2b7cd79ad", + "6e13942ff76d4129b06e097cdd060adb", + "3eab4712ec7a45b28ede2f4b0de10ce1", + "02bd26e1454448e7b58964bc2d702418", + "6733f64d5d3143608ec60c04c666c1d7", + "8bbc24672430481a87b8a62186b18b53", + "07d2bc0ceda34626884c6226c01c5a57", + "775ecaaf8a4f495fa8a8483865f3cea4", + "21251fb8a37e4f96aedbb473bc0220ab", + "b0591dd6c09d41c3b787dc0763171a59", + "12322307581f496a9740ab1533a9d843", + "e98fef78c3654b148c1bb6033a6465c9", + "4dd64ee00ff94f7488ff7793c74a8cdf", + "c785fbaaed3e402989be2e7052d0a7c2", + "93a848a5b65f44a7b1c1ba2e19cc3677", + "0c0fd8cfc03942d48bac243f493fa7dc", + "5e2d540faf4142feb4722bc137ab200e", + "9f48d7f42afc49f0acc4c3705c0f8bcf", + "cad2ffa5d8a24423ab246ee0916a7f3e", + "6401c4ae87524c3c99f838d8ee21b093", + "e6eec4a18e734a9a9e580ae3b4a5418d", + "11ec73f295a6445d93b6a212aacc021b", + "7ec228e046b84b89bf1edd74598e55b8", + "384cfca19e1740e697e73a820f4b39a6", + "a0339aa975e54bb7ac65982ca3cc5802", + "83d0bd23211f4ca0815b957e15890bb0", + "1aa6739d774348efa691340e3a12b870", + "3196ea27c20e4da389cdfb3e5206e3fe", + "b68ca06a1edb4edaae1978fda36c6aa4", + "d2119364f0c849cc9ed40ab75d7e671b", + "a917736df3e24882af2a181ce5436ad6", + "812ed8c6fee44602a376159f7990a765", + "692c68c4f6374a3c8f114c11497fe1c2", + "6b93aa86ae784d4995777cb9322dbd35", + "9577021d0a9e466ebd42a98277a4005b", + "fd3a0d04c34b49d2b3163dbd4f1132c6", + "820e7ab9ec224193a8088b22e1850bbc", + "a1bf5853e3324d5c98d5afd44060f0be", + "e2e82a222bf242a29b15e9aa6e8e7ecb", + "ea15a659a739446890ce8cf04697cbb7", + "0ae3255707854840b7f7023ed93cc7ec", + "83191c1073b04a0f9b60d3975545adad", + "7f2afa3c4e8e48c9a2fcd81b3caa46cf", + "fcb451facdd94b5f82871ed231d45372", + "33ad50068d804d6da11c86198b743d0e", + "1de7331280bd4c36bc01b6905cc6602a", + "f4973ff6751d48189ada9b7b310915f5", + "b7d60407f41a4db5ba6f69320c5f5060", + "15562ed7b1d24a7a842d971f6555216e", + "d276a1bfce364a9ca34031beb3d02cc4", + "e638317e58c44b02a9aad7eb8891532f", + "d09b0ec0a5d344b5b19e3e6f7b77c3a3", + "c1ea534e564949869d91694df7d77823", + "1caf988005284be692f059e1872bdcf1", + "432bac3ec4404399980bc3565baaffc0", + "51111beb0db241e78832158cf7653e70", + "23197344dd544a679176e3a16fc8a544", + "148ab4d6978a4a76ab5e291e07d8b999", + "bf9e6f7de2a24d169f3e6236ab3096b4", + "106764cbf76644d48bc41ed71b42589d", + "eb08662d958c48be80bb688f2100a205", + "e1a832587e0c47c392c1ece3fa132764", + "18dc76d7505049c688303a7ae37fe2c7", + "16b2e75a41cb421cabbbeedae473f0f1", + "72265e59796a408b898456305da92b3f", + "e36749656e714104bb6c626096184cfd", + "87d995955f694ba789a5b553f35914ca", + "31d3c281316b4f6bbbac480517139434", + "587b1c9b68324eb38255572ba0d6adde", + "05f61a0cd0fd4825830749585cfa8213", + "6b9a687db7d04c4aa0487cf2c29a3edc", + "8cd4ef86c0914b95a181473230c77eda", + "e6f2808109db4a1193cf8a8959d90d7c", + "05098e2a7ced4cde8e95fc12893681cf", + "b8be47c8bcdf464ea650d1c312af2657", + "2f0ef6ad926b474189b6ef489d11954c", + "583b980bb3c4432abe5422d8a54ffe99", + "f265efb9398e49a3851ed7241acced41", + "6b7d97d28cae4f7883f7894598405f86", + "ed8b2d79eaa44bdeb70ae72c162539b2", + "e9f32a64a90349ef8f6cc97f1b5a9d98", + "f7e13a33e5d84045b87ba4911e1c9dfd", + "220f1341596a4de5934254260f7684dd", + "74723877ee174c05b8dbacf902ca6cdb", + "a220bee1b3a748c1ab0d1237647d7bc6", + "e3cb417fca3e458f809588b63809da29", + "472d646ce4a8402695ce79ae5cfff82a", + "1d7cf73ccf8c48f39e90f5d899b98d3a", + "919c6c9e899e4d68bee48dfed3ff400f", + "9934ea7f2406447cbcc48586009b259c", + "3f5deb82ff814a01b45cd247df1aac65", + "353b0eb4900944afa1790acee22e511b", + "33657ac0e044493daf495d45424ead7a", + "d1c9c3d129ba4fd7b678c3145aa22e20", + "bb9737f44ab042a6aff8f974f7b44947", + "03d6d40308db45a392a248d49510bddf", + "1b1245352f35414c8af77be29e1b2135", + "124a5901f48946b0a6fae62bbb26c200", + "0d81e062005b47f9b738fe187db86398", + "fbcbdaab9c3245de97df48ae6a19f789", + "88f5c56172444455bbde4a0cc921207c", + "2ce2f768d43943a7a83db5c1c13dc735", + "31564ba77f5a468c911c1573869b5f69", + "003219b0bec442d29725847969e4b6bf", + "5233dd28a284413aa23b24234eaf3f4a", + "083d674be632421b855681b371105ca6", + "4bc4176c10b94a9192521394045af9dc", + "379a1c71f7624d469c3f153e394620c2", + "3a87780ff9c9462db4fda9287f348f4c", + "39cd9a49f9f546438da0473e00ac6980", + "c7d79c5a304a476d87c8014a2f6565cf", + "22d0f22388264d2cb641cb8c20acc548", + "04db9a96f52c4290a0b6bb1aa441ccf7", + "8a193bd9d7944b5baf2031f5fb80a7a3", + "b92d13ca51ad405183eab8c125b39307", + "8231a91d0a1f41c88b045fe39d2bb7bc", + "19f1c00170c14dfa900f563bd05c5dac", + "336608c20f45447399f856197e513155", + "e760eb48798d468bb761e17109ec8354", + "a0a1eaf4185c440c816bc085f1af4bfb", + "2ed47a1e98604fa4adeb330e71158a4d", + "2ac3550946324e9ab9d78b271a60bd78", + "704452b82d8445c7962114a4aeec3fc1", + "c2a207678875416d8eaff99fa366e452", + "ac3085611fae4753b7a46af8f7dcb51e", + "37a43c8dc25842c7889952d804f09933", + "1cf7a367acda4ae39291fc3e46706c53", + "0fefa5a58a9e4c0c9e2ec51601eafdd3", + "d41e2c59eacd4340bd7c03b8bafcb4ae", + "8428e4b19bc6488db38fa3f18963875c", + "48bf0206b9724a28814d299d93b7602a", + "6822503876f04df79de2c3ab2277f6e6", + "2a11fb8525ac40809d722d0547a00366", + "54e694e3850d452db3650174a101aacf", + "0068a53f561d4dccbaef45841107a42d", + "f6c8386e76e54918b551ebdd276479dd", + "acac40848e1d4a719d189c4b906d1165", + "3fe5df6e2b774fa5830734818b8b2d1b", + "371090c279ff4e77a59acdebc25b5892", + "94bfcf57171a446e9144bbd76dfbf730", + "cff83693dae845f58695847e8e392b43", + "ff73d3a9ae8240f19205bc303c004079", + "433a785e17694d5bb0afdc5b666664d9", + "b9374074279f4f41955996ab81e2e8df", + "83adcce7c3d140748082575bbcb4d19e", + "07ccaa32f2ec4cd299329524e2c408a7", + "60e8241011784f4ba68abdecc2240b7f", + "a106d50a3bd34c978e9520b4efb2dad2", + "70e86f64ebdc453d8601c1bf4814941b", + "09f70e74f9e74b72bf931acbc9e688ab", + "ccbeb0fe3e1f405a82ec9c4538ea8c9a", + "6392c5c78f1442ada5083b4b7d19b54d", + "253ec28ed9d745f890f64ae7bb902cfe", + "b3b256e932104d1eb36f085a23fc1fe2", + "bfd8ab62a3a749628a982218b19c2d40", + "03dcea329c5c438aa2bd1b2986940baa", + "ff2589e974214cf0bba715bfa40fcadd", + "0535c51c82644f9e8ac9e3c20470949d", + "71e4ee5e07ea4f9cb3663cd199cce0d1", + "801a507fe503484aa903fb22a61b10bc", + "f46022e565ff4a75b9c7b2251308f423", + "3d6f9421a9b54fe18b8cf894b17b3bff", + "6dcb26b8e33e450c8307e5cdd3b06fa2", + "abffad596aff4180ad1f9399d494582b", + "7eb655072ffb4ca1b2de9b13c11f3eaa", + "983041da163d420da1f66a106c3b9f47", + "0ea95f5b19514611bb0b18659a16f7c8", + "ba11f0bcd7c44f4cadafa4a91f964214", + "6dd0eafabe514df0885ae54b1cea0187", + "78d6415eb12a4d48a7f2dcab252a5989", + "76aaf5a62d8a42d49092780bb7ca4c0a", + "848ad9fa849e418ba6510ef9f31070f8", + "0f560501c1bc4df69c6a4f9ae5feb2a1", + "9df256441c964d22b174568a953f0475", + "31df9ab101954c5eb99c526047ddb0e8", + "6ae2e1e424374dd5b635d1748f7e61f9", + "e6b23e29525c491bb1cf2f913ee9afcc", + "f54b807ae28644a684d22dc84c0542a5", + "23ab9aa534064d47bf06f09e8b34e192", + "304bdd9937b34a569d19de876d33e945", + "52ee123711c44fc9bd43de9dd984dcbf", + "3b819937b5fd45dd940882cf6c298cd8", + "db056da732714e47926ba2c28a8b7229", + "a8c8a1ad33b7475e99d6ce956e7e76bd", + "b4811706b0f348ca9c722d9782a36e30", + "5b87502ac41f4eb2b2ba7b0cce6517aa", + "a0a353c03a6b4ce39ef1f0c74c3df1c0", + "7dbbbaa1a4b346ffa82531580140f534", + "f2cbf61351e24e1c95a61bb20682a270", + "9e56cc9656ae4016b96cb4bb56fe3a43", + "4735a1a4d1fa4302b711fd8cd9fd2abd", + "98c4a9e2634148aba741da07d0ac3812", + "dd06817af29643ac81f4bd17f8176999", + "94771b44cd644967ac04a79e5c898d3d", + "f834264ded504800af8d307674aee303", + "c91c976f9ac14fddb902f9d655a8b2bf", + "070de1ca5d664160b3fd489c412f871e", + "aa239e8c34804aa2b89cbe3f095bc5a0", + "d49cbf9a118b47df9efa7e124753dc27", + "de35d462cc764df5837cbfa2f599d06f", + "0a1b083195a04ebdb4681cae57f77e33", + "ffaa371e3c8f4d918af69be84c39651a", + "2d2382ed02db4b4e962981114fcad746", + "e0976ef0e465417a816b142387f41765", + "a78540de7ce84a378a4e9542dc5472b1", + "d204621598054c4b93cef386f4bb24fe", + "a3dfd0b7c45345968c229b0e6f9867da", + "78873d11a9044d5d8d3e0f1bf538242f", + "e36f0003b0be4209b74e093aa5514b2b", + "7aa4ae3243604b80ab428fbcda9202fd", + "87fbd378fd404311962747c90b4e9237", + "da6c5b6425df42c7886690f6e587d940", + "706ade297ac94bf49fe132ed3784a8a9", + "1d7a9e1952fe4d4c9aed60c471f9a8c4", + "df973ad00b764291b5b77183854627c5", + "dae37cc4869a4155b6999efe26df710c", + "18f3810848254462a820fcda25dd7713", + "cb486920d18f4802b1f31bd949530240", + "1139ae9eaa494ae98dc39ab87b2e6eac", + "4fc14ea5129b4ea3b34a22844a6f1b3f", + "2bd4697eae874ec581981dd7bb12ae77", + "7189ae06b18347bebff566599bbd15d3", + "437aceee05b1458183c0df2d23dd3943", + "fd6213cae97c4acab79b9ade20d0e460", + "fa7abc1ab50c484db3323ccbf7f8514b", + "5b43effb211e4688a18fb4ed7ec06ca1", + "a571a531ea024ef9aff37f9346cc3669", + "907c81d33fc84ca88db83fda54ce4788", + "4a5dd4a14890488ea17e0d420c524db2", + "57ea5da0b3c449c0b89634fdd35625ae", + "b6ef6a2eb1024e7bb5aba7755568a074", + "e24f51661775435ba15eb26136b6a27f", + "2d012e643288403baa8f1c145779ba40", + "14280af6733147fca284753104d44124", + "c48f7003cead466298150e09b83684f4", + "0c8df5efed3d4bcf93ab2ca341cd34cb", + "ea47186e191743fea068b441b6fd4e30", + "a188ecf0ee4e43d9b7729d64f147c9ca", + "c564262cdcd34991b6b10ebd0a84badd", + "a30d5571018741439c99a17de18c7287", + "b70477cd4dc443d283130d9e9f469d81", + "0c0da2cc1b4c441dadc2510212c25fb7", + "c59c34fda54e475d9ad129f709d723c3", + "d0f2a486c109484b877d7779518365e4", + "71c931156b9e4be3b8545e9641c73888", + "8e1f85bb6386477da3d75b7b223bb559", + "7a3bae8253074931a05d45788dee5852", + "b95a001246dc4c00b69ef669dbab8ff2", + "e434980262d0440b939bc32a8b9affea", + "7306f0db4e824784ac90ec5de478253f", + "9d1babf173c54843aba740e8f912aa90", + "bc379c569b8e4c34a1f9e64e626fe66c", + "d0e330462ec44c79ae11ed74f2a1f025", + "7fd4c11b1ce3435cb1985606de264e77", + "73ebf2e05fa74f14be28720dc42d506c", + "e298799a3d5d4b87a15d1d4af52fc2a5", + "4c4176a3d1b34dd194bd580115ed71a0", + "4ac6037405274ec4893b7979a707d625", + "bf60a7c7c7b141ef93dcb9c56cc3de53", + "3d43b4602cee469ab6dbba54a00eb4fd", + "823b2f340b324f759fef8c0916eff2c7", + "80037f043d4d4d8581027ace99a5e2d0", + "b202e5ff0e2747c5a94cdc6e8856e823", + "14c7de64f6be42fea3afb98eb96ebf67", + "6931e14a96f64b158ac4cebcf7ae8763", + "503d21ef21f243c1ab8dba09329b5742", + "7fe5deb6632344d6a01b22b0cb3fc412", + "8358b47f171d43e98f473083ce55b36e", + "ea1ea4d5847b4550bc58ef4107df6f94", + "5b86aa664756441d82a4a9d9bd32ed92", + "24006f127bec456a945b6b971506d5cd", + "ee435def4a3d447596838518b2e35af1", + "024f1a4b73f9403cae040dc2ad1716ef", + "76a98aae56704c6cad909de049a827cb", + "3513ae49853d48609fdf8b26020d3c4f", + "8324040378854f79b15f39259404261b", + "363957301621438cbb8fa188dc344d9f", + "0c5f6748af964d12b9ec16928d452fa1", + "fef52ffd517b4e56a3df2073a8dff903", + "49fac825fa934efc84c808e45ffad4cc", + "eba75e89899c49519a8edf2e131df19a", + "24467dcf61604b098df039d7ae5b6454", + "45fd88fe287c45e598b4e3a89acc9407", + "c1e15ee7a3d64fb98924928fe45741cf", + "e1ffd1e1498a444aae0f5d0b7ccd9b01", + "9b624d414d614424958375a5a9b0fcbd", + "cf82dcad77e34c49ba2910451fe96f59", + "7fefeb29ae3240f4af3b9aa9697d7057", + "5b2a1815deef431ea9c34766583dec82", + "4886a2ab89c44f9fa6f92c377a562425", + "78262b7089d34c6c970d6b0f7dc0e8de", + "6cc2442301a14ff0ba5ab13ce67b0a8b", + "ba43c7bbcca143c8ad2f77f5841b39de", + "5db7c77a0e46426f89251401815dbbbb", + "a9c0e87846bd49e88c4ab446cb6d01f8", + "01994d08f4834acd9734f1a4281570d8", + "7ac1593042e047efaba4add0c6668542", + "ac418fa936fb448b8eac927ca99bbf30", + "a6a4600c3f0b45c4bd5bafe7f34b1f3c", + "822bd4b8b8f44390b8ea0edd4f453c84", + "b9acf8366cae4ab794a8331611fe3ef6", + "4eb843f1ce0a4eb780faa429d76c34b9", + "d2dfc5c9ea0c493a8ad8a85c9eb566dc", + "09abc3bea1d34827bab2d1eed703d606", + "82047c00aa0d421aa5834b6952d75938", + "89c4130de98f4de0bcf6d331762a6cb2", + "d796ac8f56db4dc78ed18be534939225", + "2d1a97de770e4ba9bf07f09a6d634408", + "8b6dc03827cd4e09a0582d4ffe2b8042", + "d8ed49732e73483286207cd15e5e84e1", + "2a1edaa43d61499a905f034640e2877a", + "465edfa6bdf546789bc26fa87c885049", + "ce3a7d17cc4a4b1f9109a02ba280ae16", + "262acf541c264d4ab864c022075e347d", + "7db8c1b2b95e4f09b09917b7618b76a0", + "016576dd30c1464f9115584748950ed2", + "1a85b4bf4d3848f4b053b54f090fcc5b", + "f4bd493e917e43f784fd0e0312cc83d5", + "bc3e3ee3334146f986324dc22f3d8482", + "6d6e6b81b1204e45ba97df35018d561f", + "2bbb50750f9845399f8948916986979f", + "aecdae3d17e74256a3536510d58b30d2", + "84eab42d427545fcab4cffff9746eddc", + "e29cf40550774d1cab924d435f0a5b5a", + "67a1081092f94ade927bc76ed6d67e70", + "479ca7daee2542cebf6ad25e7e8fee58", + "9efda05f8c90427bb608ec74614795d7", + "0e464ea48ce74f5bb3aa06bec605908a", + "d41bf6e274044c5b8d2646f7b489d5b7", + "31b7048a2fbe4a038a9f216f1a966bb2", + "ed127ed844dd4b6a8ff8b787c7028d66", + "5b64159df5624baaa369423db7235ee4", + "eb8f7ff9521e4ce48522f5125798fdcd", + "001cfadfb9204424bccc45501ce6b90e", + "a55a2ebd7b9f4c318fb5dda4c6de4a15", + "c1c2cec3e95c429c96a9e59b9b84d4fc", + "2e2d756836084bca95da64e60fdde7f6", + "66540f4d84354ee780101780f5baa70f", + "3ea0f9bc15e1459ab659ee68037a8ad0", + "0ce411ff44db408ab261640e153467a0", + "8757f15fb75040868bf8d944791d3bd8", + "a8f26bad50124334bc7321b646c7f0d1", + "4fc86d231e1f4f1fb32fcad11891a5da", + "c5ddc586f0854a4981638287f30c651a", + "dcdf5af8a5434158bb9398a34cd4ccaf", + "635548c432104fa493c3f1c2827bf94c", + "a784e23e3a45414d87723dd624e8a147", + "8ead5f5ac8284f5299cd23c09251dccc", + "6b6459d2480b4126b91842a41f5d6e2d", + "6dfc6c8bf6e44f729e3acaf0f5131d4f", + "f7e093719b7f4065a681311061537bc3", + "6ad4a11e5d9e4aada46e896f13145efe", + "2ac8623edce44c0189928b2e804e49c7", + "328675725a3048e5ab1d859d07dc96d8", + "55688f001d25496f9fd01476a5ced848", + "5a0fbe2305e04fa394207c75ce6d363d", + "18c324002b5f492c8edd2b0c21c7158d", + "3ff8b6494f2a44299b21cee21be2e9b8", + "f6563bbdbfc2403ba5efa1880a01c83b", + "ba6161760e6841e6aff2bfd352892262", + "df9b3a2d51db493980d68fa3b56360bb", + "60de5b14f3514572ae1fe0f69c08a527", + "a513f2e85bc94ae5b6d8cbd74909e3c4", + "5fb48b7e431148dfa0793a0879d5974d", + "09273dfa925643b4b44cb8a1d3a1b6f9", + "cd09a32b9d944b8383adc02f9fe5e62d", + "775c11780ac6434aaf733f7b1971a0c6", + "228b7a8abfae4e6a8dca781c0feb0a7f", + "6ad5bfa73f0443a9a3b4e7593618318e", + "bb0d4e90dfde4cd58076859edf0a129d", + "0e6e59ade8b343d38682fdcdd9f939a0", + "375b8c73e62b493496e5bfc2e7859a93", + "9c7c7f48f218460c81d0a45953c9ee63", + "cc059f7ae882497198f3d7ec3ddd63bb", + "a8750076e8d944c7a6b331c9fea09dd4", + "1f0f72563b6444738606014502d728ab", + "b812224a5c354de5854c82547e1dc4ca", + "57378ae9fbfc45c9b6e691a7fda43b6e", + "43b88b2c6fa6462aa4c9d2d3c5e062a0", + "db563b479bee49cdba904998ba5930b8", + "f379cf2c400645b8b22f3989cc5ff6dc", + "3f5b98117ce04339a3a6c27c479aa0aa", + "2658e390cb644bc18ce1d7991a65f272", + "e49d29f9a6f94a8cb62ca0a8e1cc1bfe", + "3cc04622c4804587a9af5321beba2725", + "f9b63332e7fd416abb800c913fe5f4a5", + "e0417d1e05984727a50f9ab1451d162d", + "4da6a7ae5bc6434aae7bd8eb87699482", + "6c4561eb4b4a403983b30e68804be2bd", + "6d42f92f71d84796bd25f35c360a4198", + "75f488cec00e4dc88b7d6bc5867cdaef", + "46d0bcbe191d432d82f40276e173077f", + "b7755e81af3f400d910e67050eddfe2a", + "7771c53cbda84acb93ae549476971d0d", + "6ebecb69f35d461bac7d2ced50380c2d", + "68bd0f6ba698402c9fe630a3db9f5d76", + "71ca2ea2b6334461bc48afe8da0ba3b3", + "721cbb48ab1d481282416a3970be80fb", + "70d78705ad7749d5b25d0f54850ccfc7", + "b7c296dcf70f4dfe869adf898f515f00", + "31dececa02c340efbbe5f3cc5cecb813", + "be17f3f93f984a9781792c4bb5e4d6c8", + "21983501bac64993ac09cdc7936ffdf2", + "2de0b46b8fb449e4adaa6ee0ca00b5d6", + "ea40259ea9ab488e8fe21eaf2fc29d6e", + "efd5e89df42d461c81b805c1febfd41b", + "f01ef223980444678ff4ebdb6783085e", + "e7aeb61f942c4c08aaba4ec2a4a2f605", + "81be958079aa499b9eb5a7a1cf438f67", + "3fd818df2fa740dea108ca3b8bb1a5d0", + "d0b886095ff442b491c790da8cd8892c", + "d1263641f34344ad9d794f95f715e137", + "a4a4f69a1a07445d8d417e1c96a57446", + "e2485852a5624624b9aac80d27222f0d", + "411c990e22ec42b29926275308abfed3", + "f1e7eb026a9041a991a478f7d4b3d30d", + "b09519abed1a4ee6ad1a6a17db34cb94", + "963a56c7201143eba6bbcdf2ad60c1c3", + "a1e07438ea334c45bcd620d2c1801bd9", + "185359b93eb3424ca73b5cd7719ccc0b", + "a8db1a75233a4394abc5b6093105780d", + "37cb8499613848dea45cd7d53d73c086", + "223b376823b54d56a783f7b733aabe29", + "fafcd79b60964e57a532e74706af6d16", + "59dcb731bbdb4680becb9a6b529b8da8", + "c27ada0a7f4e42f98789c4ff213227f1", + "3b20cbf258864b818439321049f53a18", + "70154629c8bc432ba4e3aa68851ad8f4", + "257aa671655d4456ac24975b935584f4", + "04fdc7633b734ccfb61fb1be7cd6a2bd", + "3576b933f3034f0bb81121463a023010", + "eda924f23ba04cd5b1e5160abf2320fa", + "b31fe4c243c846eabd4cf53ccf9aeddc", + "990c08d7445743d8897841f82466e80a", + "440cfd6ead814445baf4e3031efd7d45", + "ccaf84bc1c2c4afb82a208a84ec09dce", + "209ddb545b5a4805a17fa4fb87e966e9", + "9afc7f5ca9ab4a61b1be331ccdfcdfa8", + "ff8451ebc4c7439da6427c355a0beb83", + "19d77c14b2704058adcb064c30cc799e", + "cad83751a295463bbb8b823c11a181ea", + "e1f3a66552364b94af673fc9b88aec63", + "e52e5e0ebbd2473a89176545349dba34", + "9e8f92a215784f3d8aaaaeab1bef54c4", + "654d21dda8654a81b416fad43ce7d353", + "92fa765da6504d2e8ee2c0fe3f41f7df", + "f6176112538e47959cfacb6091f14598", + "6ac0575a12d7494793fad7ae8ae8f6fe", + "59d7aa3e1c4740029d47dc0bcd838444", + "46f5b0b882554dc09ff5eec960966211", + "48fd19eb272346a3b3c615e8d74758a2", + "4147cf2699744c72ac61d1bace258460", + "0720eba90fba40d3bf329e7cf01654d2", + "9eedfb865cf84cd59a15e65f7f2d393b", + "978cc1d106b04c6791ae45aab557f909", + "8ee437cd46ae4369b41980e9fe8779e4", + "91fc634dd3ff4accb6afa6183d0cff7b", + "78773e6aa9c34a14b94c0af25b71182d", + "9a3e28a3fcad4033889da82ed913650f", + "680da7cc1ef24b0d83c874178c6576f4", + "d2cb4535c07c49319ab14415f6b3a2b6", + "de2850e394424330aace7c165b4a0c08", + "eee7a5bda96b48618eb3ee9fac3af71f", + "ff8590a609684e3fa170ca9672e5c0d6", + "1497aeb5b82f4f9b85642721ec170ecc", + "e2def5d1ee0c4019b5f38604892f21a7", + "67a4c51ce9894a218dab77cae5187518", + "d0d127942be340fc8027affd912fdd22", + "e467c0f8a05842149e19187428f7ea61", + "495b31d94bea4d0b811e70e5c98de56a", + "7ef9d0673cc6423a9542470d435f09e3", + "18a797777a8a4da686960575de652d8e", + "61b43174742f43e3905095969442321f", + "e99210d90b08411fa55ddfd128977991", + "10d9aa2700494deab67a644d91e2a579", + "8a22f1a1c43f42249a51872321e5f834", + "8e6a8eb5015545c9bc9e6742d0d267a4", + "3bb721abe28e4b63937209fa9ef721e2", + "b84698fbd6614d3c8f06c37cfa860f45", + "eb353582e5174076b8245ed823bef9e9", + "90317e425fe9452c8c7482217828e686", + "c5bfdf003ead4c4793f4e9b93a9b1b79", + "ff52b849a1c84e7d89a9319977a6cdbc", + "134bd3b48c8b4901b5e3e53c0fe2ddd4", + "2c2baa9563db4f20ba23f869ec3288dc", + "3c017da821f9447a89a993d251cedb32", + "33518f08d8be458db19a60d8a584c177", + "0972c48a7e4548bca80975a47a823bab", + "0c77dfdf9430465f9767a58d56e8fca1", + "60a1d227b99b4399aaf80c1f3ac83860", + "b594dc66811c4a8baf2cd5ccd6768530", + "1fa73f748b54471d91e58fe3160f4898", + "8de4f08f281244b5bf7f77e8319dd91f", + "b07bda30277a43dc826014ee8dc34756", + "3cc4a5938dd744bab678b370d6bb52a3", + "b193b648824040559bbb618ad5a33a51", + "7f6f619838f24e0b91f4d3fb1ce1e3d6", + "7a034e47c5eb4afe95e08c2e7d74f403", + "5384d68eca3741b39efe6b71a663cc4e", + "413e48e3c84c43d6b3f68adefb0aac06", + "19db38f3fb684e91b758731142c24ace", + "afd10a0435184da58cb5f391c0499b14", + "261d9727bd054bfcbb6334ac2b516f83", + "6d1a66b916884778955a9d3f4e67ac5e", + "ea10f71087af43e69c1c63c4146a81f2", + "875400ce508d435faffd6844d7fdddf4", + "f083b05bf7374b12b42f8282fb2ca556", + "95da985c92914e3c92aeb4c018892ca6", + "64c01997cc884bf9a7d92dd51d7342ae", + "033bc40bce5f419ca162268cc2a7e66d", + "3186d81f317e41c9bb8257fbd114bbfd", + "4867e2a754dc4b30a1654b0a937a95bf", + "f7f1ec5cf5a64c859b254e8d4013aa37", + "265ec29b3a6e4e35abdf71c5d3ae4011", + "0f732c36ba5e4b50b7451de3b489006a", + "1cd732aee5564fd387959f41eb9540d8", + "f84d70e942e143dea51ad6490a081008", + "ca39d6f0333348e59e66cbe4258a028a", + "e1074677ee7b4bcc855f55508ef8920c", + "9cf0d4d9c380433e9ae04b05d2397368", + "fa0021e12f9f4ec1971345c7c9434685", + "dfc7ab09596841edaa5182734d316109", + "5bf5f5fd7cea41ba8d01bb47dbb2c0b9", + "486a2476c46940b6b09202b5a622bbd7", + "73b64c5ef8e0468583c84e1b9e1ae59d", + "e8819353e9684f04899f6e5c93927da0", + "9cef8fd19dd84684b91830f35cc54d4f", + "c2b31c7104554c41becfb0a960efcb4f", + "7b0b0c20630248e59dc63847eb0d754c", + "df4305801dc24c41926e0932bd7bd833", + "2371e14a324d4b88ac48defb9bdda5aa", + "60f0d8f3c88947a09281d46013812a48", + "0f89fc7be2c54d4b92256fe7363ca058", + "79b7e866211948c6b62bd603f14e55b0", + "51f264b132884b4bbe62423cf70e0e60", + "5241839ca80343b28480e09bf3f2663e", + "ec2e6566bbf340b59cb84a18e04a7b1c", + "3a24ff09948341ed9581b768abcd384f", + "fc199f5a872e4e668b3b956322f341e2", + "94f4100cb87e4c7a83d4575594b80579", + "bbbad4eaf57d4cc18f5418299858cf00", + "050d92eccdaf4832a50f843dda6b7c34", + "f66278f4340f4f488ed56f581b07c5c1", + "3d0de232fe264410a4dfc77203c985b5", + "6812bf2c9a47488a8ef249ea08eda67c", + "b9c46eb3c51d43b2a561c9dec106e61e", + "20c6eb43f5bb474289cb3aa370ce3121", + "3c4466dc157c40fc807ab3acd7a2373a", + "199f9be566a4481cbc07ee14ceacda77", + "728d645702484493924e368b11dbc914", + "7df4925f2c6941c49d944be8c93618d6", + "4d2be4d2e0694e98baa1ab5c072f1cf6", + "d605d191a09e470d8fd68f0eb9ea1a79", + "0c2133c77db74538b0be55b7cf37e65b", + "0aeac4f2d5204593a09a76febec05f48", + "215eb5d9238b4cef8d730cdfe6403daf", + "5be4442df31d4bb9bfed011d0ae8d579", + "58019f16d1784063bfb95a5bbc4575e3", + "ab66fd684acb4eb3a2194c9c04c1ba79", + "37c1baf6f19a462eb857ba3cac0ee45a", + "4df10c64589a467992367dcf859dc22e", + "170db25fff094f68b6308a8fd6a8fe61", + "f1e8cc5cf9584f7ea6c2570f66163275", + "67598fc87de14e83961816d681dafce8", + "cbb56b7055f34ff7b4e790093d1c3681", + "25b4ad6821c64781988aba2dfaa63d4b", + "de02b16a52aa4eb0a4280f2242b52b1e", + "341ca9a08d1d419d8a69e186abacce5a", + "b559c90ca0f94114a934aa2bf849fe41", + "d3bc668a6f4f462591dbab579c43f80a", + "f7461cfd7b01444d968eae27130a9d89", + "084e63dbbd9748af860c0e365ccc5176", + "2ffb917efef043dbb7fe98f44d2d9b2b", + "fb3202fe00b245c8a3022452ec859397", + "b1ae8f78cbc844019e76287da01359c9", + "f6a450e1a23b4abdbb82fdd36f7015f9", + "b88c3c8225a249f289b256fcf5ba8729", + "a846d549502b438995bbdb9c9226fdee", + "d5df1d1bad23474d8a4b567ac43d417c", + "5612acc3504b4645ad64bd2f7fe97ebb", + "801e8977a54a4375a790983de242c26d", + "82e7e52b34c64a7f9421dc071ce8da4b", + "e2a0a0c088a64ab185f948f87da9d7e3", + "2a542407ee1e4c9d94d466777082c89a", + "dedac6c955a54251a25b87407e8bb2c6", + "62067deba41041aaa565f72c0edb553c", + "0762d52942f94db485d1a6eacefeac96", + "f395579ab95e4a20a4e484d7ef3c6dd0", + "8a1ae7a856e145e78ccf882d6ceab806", + "081194da071d494395827b3f9a277f8a", + "173d0f14f1404bc2a3c1a92141a6ff54", + "6524beb4ffa7467f8667dd393f52bbe4", + "0c9b25af73464d978658dbf17c5ac4ab", + "f4259fc2c43d4c0f9c3b6d93336106e4", + "a6af3d23dd274f7b9f23f3116e7e03cb", + "bd44c05b4353483eaf89745feb95b059", + "967fe04da5154c6087dd1b834cb563f2", + "4c7042cd8451442383b2af9fb09836c6", + "d200efc4f0a7413e95e6a6a779f91623", + "d83903da681843128b4f8d9e92592be4", + "214671c96c5f49b2a1927d1638f0fb47", + "6628f95227c24e07ab786e2368171656", + "6f81bdd9e9434d24b614a628202733b7", + "2f585fa5a2eb47978cd8e5412de48d6b", + "efe65b3c28054f2399bd577d19c3e9c9", + "8a3d4b05df3f4fda9aa446a39bf984f1", + "1b22961cfa5f423196967d5062c3687b", + "6ee97010819742a8b8713605695ec703", + "80f0c4e5e62640f59bbd81ee553d69a2", + "d44381eb4a8448ffbc239e1ef276ac45", + "3577ed950fd1455693c0cd32cff56510", + "cf18e56bfdb048a1b648dd2c4d8acbdb", + "4825d2d251b648f583db7147a7fd8d63", + "40782e7b182b4cad847ee222c1d5bc4d", + "94545320d6964614b111322e5596e9be", + "6af8abe4ce9743c88f3cdb9cde85f944", + "9394db1bedf1471f9f78a631932ccb7c", + "86f3bdec18e048249149ea67e8e34f63", + "c7c711c0f5c648009516a971ecac95a8", + "ceb5c1054cac4c9a83f5e1fb878eadba", + "5b99bf1d3491408cbe7f2f337aab13c0", + "de9efa09830a40448af09972470726d7", + "8f7bcd0cd4474eea9005395457156aff", + "8bef81826ade45738af629e27da7c0d6", + "b4bff18066bf460d9ab16b6d790d03d1", + "ad505c71e42c4ffd9341bcf38afe65f3", + "867d9ef7c29c4e5eb06b88ede2198587", + "cfef1fdda6e1436590eec63eac16c422", + "62f6c6368c484dd6a85a2a162133d2e0", + "fcf21ed719f14eadb1a1b22c914865d1", + "a0cd37a98ff74f1eb1b12bce0b7da868", + "a92cf64081d649cb96966ec62d1eb4fc", + "51cde7b5f2b549e795f56883fa9da80b", + "eb989ade028f42918d772fefb614590a", + "657e8be68bfe498c8d40ee7e0d02ff7c", + "5a6c3a55c0df4b08bc4e1e7e4181e468", + "8ec530bb19a14820b97d6c8dfeeb3026", + "e4c60ddfbcf6411584369f6750f85a83", + "f98c5ee54c4a48f8b5eafd35a81dde4d", + "c68aad2d3fd04ad394e23a4031be1220", + "4a4aee2d02e348c4a9a3b9df87441647", + "f004f7515fc544788143f7c799d1c598", + "ecce7607953a44d29f7a6aa3254f7797", + "5b954fd27d184bdb82b911517b0e44c1", + "2803c3d1e17b4ca69b16670f73773a76", + "764cc98d17d24748b65f8c102b24c721", + "3a3c8ed4371f4a90a0f46a03119bd74f", + "e3c5414ed4174d27bd048716fcfa3f97", + "c28358d1992547099ead51a462562030", + "5e050c0699064a4dae8d32e030b46ff1", + "ab53fe99368e494ea1fea7084ba32b6d", + "bf1d1a63b109446eb20c2c08b1b56e57", + "9bf1c47fd6ee4cada4dc89a0f05f3aa1", + "b0b60c5ef5b24af79c9da46c745a08d5", + "467fd3bcc8b641f488cbb6a9d9e3520d", + "dc4ecf9e517044b296e8ebb7505b42e7", + "bd0a3801b75f4456a94ff4f7e7e1742a", + "a914847c44fa40a685fafe211e118d93", + "4e8ce1e067b6426494cf724dbe4e0f71", + "081ab230ad9c406a956150c779de59a6", + "117a24442f4e4550aa06c05f37cc6c4c", + "ed86f328dcdc414396c5f900004dec23", + "7e8d8f533dc944c6a212d5f20997c69b", + "cfd477d07e5443f28bcf6b72a5370a52", + "b1227d257aef4baf9be6ca72754ab32c", + "d3a2d9b960c24b049d17297d5878a8ff", + "bf96eef9ffee4e52a6f13483da9bc1c7", + "5eac4e57097f4d49ad9803a554b309c4", + "dc0a1ae7d4bf4cc486b9b1ce5906d91e", + "e00ccaac44684213be71207aeb7f1d1f", + "ca0b60de05094a3785a03e8d67a5adba", + "d9191cc1eadb4c989eb65ef701abdafc", + "49b82c8b080b4a01bd622538258540f3", + "74f22ce7d95f4b39a86b097574c93570", + "e11f3fe101f140119e655940e4776f08", + "e9dd71afc4c94c40ab256efdfe0bb1e3", + "14f90291f09148bda96fbbdd502cd79f", + "045d9ad885b749b1bb826e2e801b57dd", + "8288c1201b5c41509c12dd3b015303d6", + "aaa32a77caed4aef956a1ef560973810", + "61870a045c734b8c9420f24dda8ded44", + "6b4d27bc17b44af4a6653a6135e8394f", + "3671b1ae12ec454bafd62d8ece7fed95", + "0ca239ec8f9b4127a16bb4e8e6db1bf9", + "c55eff0309a14cf09423d238900cc7c2", + "e1ad0a110d984c6898a168eff62ca510", + "0032696f5871429fbd0549d9628f812c", + "36a75eb478c744c7a31162e5101ebc3e", + "dab93bda54de4470a46b07d5a520d0b3", + "27ea7742072b4c4e8f7717cfc3a4b1e1", + "67c1f9cb4a3c4375a85c03d9a60c908b", + "a7fc2463dc0248eca7b51dcd012b01e7", + "4475c12ae6ad427ea2dc3d66e7c5b4b8", + "a627549afa71416590085ee4f9285563", + "e5761d31a04d44f9a18b74f740b01956", + "5d70537cfe2243f38704d15fe3a1c73c", + "722be26079264550a508583d9ebf7519", + "cac740b07e9649e09988027d375c2db2", + "3c4373bf947b4745ba4058505d2a86a5", + "950534bbb0f74e8792b41efd176c9c67", + "6701efe87ebd436c9be16fea288ee268", + "91e9c4b64cca4063aaf58efa8f41be75", + "c8675e9eeb34404ca391f6fa915a104d", + "d9c07a512d6e4c22971367ee693dbf02", + "097bc64010ee426bbb505b9877feba6a", + "f1b7ffd6537946b49fa4e5a8aad6af2a", + "8a55c508ff334d40a44d11169ae9eafa", + "117e5a2117704c1aa324d122994d61de", + "c5bb1e3cc4804278b5342f3a53820b04", + "cab10f9eb7d6453db458046e3d1ce32b", + "5eed734fbd7f45f088688b7a50f8a70e", + "c3d85aaabddf4585b2468a5bca9f51d5", + "154c2a94275e44efbd9604c95cc1c81d", + "009059d29da14895b557112bcd43f39c", + "c785b55867114028b592d5fbf0089d33", + "40d3913f9fd34ff2b48062aca2724e5a", + "c0784d38160a41019cafe83d9dcb6fc3", + "bee50cc724a640328020bf31be85e91d", + "7cc59a5dc61b4208a62c26bbc5599bd8", + "095afd8045d94a39bf3ed0ec20e0eb1c", + "2b937fe2eb4341e5a6f6961568821804", + "3c0a9ef4afd54ff4bbbc4a73eaf65e9b", + "bac375cfa4484096b1a5a46b298876ec", + "b080707a31e648bd84409b98dd79be4f", + "d883793e53d440e095444979cb88ecbe", + "76bb01ac12d3491f8c32c0b1e5c8651f", + "0e6356a258d3439b8362644bc0dec88b", + "746f0bf46dcc41958f23691a077a8fce", + "adcd40c1d4a148bdb52db9cfe35ecb2d", + "2b4ed6a6259141ada645905678c746f8", + "77537462cf1c45cba9cf2cc087005b67", + "2ef9cf1a1c474826bba59217eab58b3b", + "48ab4e2c857f46c1b9b7310f1f28795a", + "b140f762f97d43f5b48d13997e0d997b", + "2499c640054f4ec0902d9a993b9d8b83", + "4390e3589d8a42e6838c001d697c79d5", + "0056880681c044cb9fe815a9eed0425d", + "edc42b3b030a48eaa87e9d1b128a1e94", + "c46e8ee246aa4863a2cf602cddf1bfeb", + "12b0d602619a494a8b61448194641d58", + "1f58e72897434513926bae262831f1da", + "baf6b704265942e3a16294cf18975b20", + "b0f168b52efd4644a34ab13365ac4a26", + "005121da5ed340b4aedd168e33d56714", + "1bd870512aff40efba5678a97e7b05f4", + "5b3a08994f9f402ca109098c67afa5c7", + "898660f7a7924b5d9767f96e6321bf27", + "df3487b8a37349a884129233c70fd163", + "0b0968b6b5ce4be48b849c1b50506258", + "2df67b7644d742d2b0c198bedfd7c3f2", + "94a350fef21a40cd808e20b44cde7f94", + "9d87fccee66d4e539e73acb700777b81", + "ee459b806d9b4532a327d7ad6ceae3f5", + "a19092b10c014390af133e841cccd771", + "f45a86be340a4583aa26be5abf22f873", + "1c5dacf79f9f4b5a96a1961c120a0aa6", + "a3f75371603b4d29a5ab2b4e5ee25e2c", + "04a98264e704488786030cf29bfe2a79", + "682b809f267448ad90a8719369f63758", + "215983be30c9442ead3d51214cce23fb", + "4ea15989895544589276967cb1f361ad", + "4176a01b6d0b4d13ad165c0df278a6b5", + "2553bf20c22f4400a827ef008cbe8233", + "8f34c23a071d4865acc4b46ca6ec3a7f", + "8ad95c0125aa424c919323930dd84908", + "d69478f0c5334e189e98f99e84bbe3e6", + "836ccbe0600f44ceb0c7b4c217843fe4", + "2015c029216b48f8872ae64b5452faaf", + "e8bfd53da4974957b0a6f662e6941ea0", + "fcbecf6de2304ff085730f1827aeb11e", + "9fdec344b69d4cc89fc18b7171ef2e00", + "f31179077c7e4733a7bc5bc2b0638cd2", + "91320df3b34942b8808fdbc631571d8f", + "bd7e987449fa4067890a402ed58a81f2", + "81ce2518808346918df6b370665d5d3a", + "407798efa2e7467c81a79d2e516a5544", + "6a25379ebb134d259bd35c09682cc4ae", + "9726552195bf4ccd93c181eecd9fbc9f", + "0a8490847f7440a2900c83e4f3755165", + "e1349e9e905a4587b816f327953debc7", + "26f5c451903d4cf19e5ad6aa5cc18ba3", + "0cbb784d430d4732835717f8481a01e1", + "97fb54c001f84a6896b6ce8eb7a1814d", + "0f07b43af2ec4d60ad94115da8d21c42", + "21b653ec0d7241d4a01735911b6bd570", + "41dd506baf4c44bb9ba17f244f24c5f3", + "f16b7d84113d4cba869412ee95769910", + "e8932a4a66ef462a8b6aaaf2ef550c15", + "0b98857657764b02b2ae2eddac987a11", + "5c7242819339487da18d064fa769eeed", + "fa80b566272647418694b8a05ce62fab", + "8922e3fa1f2b479fbcfb14f86c104872", + "f4cc6869c3404af2af60059eed5fd094", + "7b66f863f989420fb4c26f875dbaf9eb", + "5ac0b7c46a3b4de28deea071fc1e87b0", + "e8f2c774c9154481a7c9f78c88134178", + "e68622d45dbc49148ecf492c541b3d76", + "744a2da01dac469cbded105427bdbd11", + "3b5c830c77c7442a8c87b3c297c45c8c", + "3188e4bfa6a8454d953c666a0fa3990c", + "45fea150b01542a7bb35f16914360ba4", + "5cdb597428224eb5ace68a1128a0087a", + "14a73529b33d48d9990d030896c67028", + "3b314d0bac774db780c409b487835f4f", + "c7625f90fc4445978ad8183ddf11c1a5", + "f5ebe0dce49846e59b41fb5718612255", + "637cfe8730f44325a34cb8f34de5ced2", + "9a191b9a479a4ef9b9ef4794d19b6035", + "3f8f60916ae54f1faf7fe9b04215b148", + "e72d24607e2749cb973e9b269fd561df", + "1b99b250bced4666b709b6d911f1f152", + "b51fbe92f3114f8a89f509924daecc75", + "4c1fdfa1694c44ba9dbcba8550ec4ca0", + "ac1c48faad454b138748e975f9be929e", + "f3ea9a8ef79d4a5c9714399532b0f6ca", + "3b6e7d456aac46a18283a30c090733eb", + "d458595ebf0f4234a854681006791d2a", + "cf1fca4ccdfe4e92806229df60b32cf5", + "2baad0ad3e2e44579ceaf77153136c96", + "8ee3f06179d24078bf39a44e0bd9ae7a", + "2b183ca4a3984c1385856ca864c7508c", + "5c83bf36bea04b82abd4396597c5c81e", + "40fe46cdc4ea4c20a436f6e508d6819f", + "c1b09337b22b43ec86d1ca222e73cac8", + "451c8b48d3504d29a9e826f2e0246fe5", + "925aa367e025473a88f3588b02def70e", + "3efaaf7bf529444786d29d0fdadce869", + "267f8027512e4016844c4ef38ca40262", + "0a96f1f19afc432bb22c3d74da546338", + "9b5e18b3fdba4ed096e85626084ce12e", + "c54a374f085d4732a14351a5845dd80a", + "e7e636e16f36410f9631235a695b0dba", + "31260ec93c914a0ea7835850db66e445", + "9ed9a21768724eedbc18219e74cc5046", + "e3c58fd478384359ad37993780d96aef", + "4314f2923bc74e278e74fcd41e3aa7d3", + "85a6f0f76604489dad2cac5048aad9b8", + "f85c796cdefc4b75b9d5892055650332", + "e184a48c42914fb59ca92b093380ae11", + "f79678ee4a6c4c829711b14fd0d78354", + "1dc9efd37bf14d1b9d1e3de0ca90435c", + "c460666577e14dbe86a11c54b9a39bff", + "a7fc42a0751c4be6a4cc22775b9b2cc5", + "c3c923711dd74bd58a4950456eefaa04", + "708c7214aa7f4c30b5656f046be7ba1a", + "e912f2e3d3ee4070b1614489f40d6aa1", + "49af49aecfde4d638062f3479856ad98", + "4b90d207fa6647e588e93d1cbae32873", + "08157e22487e4cf6a319b6023e766a3d", + "27fdaf47cde84b6291df4d195cee8f40", + "91b2797e0dfc4bdf96ef45fe0c399f49", + "2a4a821350ca4527a9b702cf893499a7", + "4049f82b509a4adc8234529723255564", + "70ec1b6c749042fb894443c66adee495", + "6a526b42e6a34a4ba12136a40d9a686b", + "207524d73e004bdbab379e271acb9bd2", + "84b905c09ec546d580758ef234461589", + "08ed5d156fd7415c9e87da2e39cb8da6", + "fe4a582d45db4a269bfe634734267f89", + "62f95f8c60f84e6babf9aabe22808307", + "dbbeb2aed294467086a51988ba16d53c", + "ec8d2d4d5f544832b499af8faf5c2c28", + "ece84b27ca1c4816a565296affcc4f3e", + "194aa47f854d4d9983dcd57ee581bea2", + "a11558f27b174fdd8bc5c44502c6839a", + "1f01a75cd97e4f468ad7df9b7ec7477f", + "3f7a9c26fff14bb99c130bb52a405326", + "d793cfaf26e04dae9364f118c2fc58aa", + "2f68d03db2564ca9b7df301b1e4aa39c", + "322eceed80aa4ac0a3f3d5fefbf45984", + "8bf8f35acb984eecafd711b2b3b33e6b", + "de53fdef51e04fa29dc7e823fc8f77c6", + "8b9cf4b7ab214e23be59a84256005c01", + "82cda96cb1f44f458ab65bd0244d358a", + "960f6126edcc45d08de4254dc08edf57", + "207f823f6d124fb28ae1dd9ff42890b0", + "811daf3a66fe4777a2d26b2fca951528", + "69121ede52d94dec9c3a755cf8939339", + "d51fcd44b74f4daf8012c41e0400c041", + "576e2badae904c3a8919b2f1878904db", + "dd2bb2b0034b495385367529829eb211", + "2d89e22eaaa24f8f95b3205ef85bb4c0", + "2f20d23e80ed432cb5866cab6f0f1461", + "dce1b942fe7f4a878a7233ccb0d381a9", + "bb908c03334d47f493955f579fb4313c", + "cef14ca597054ad5abcd4904541968fd", + "77774d22076940aa8484e053bb14947a", + "fcff57f7c3124e4c8f885663281b9033", + "a5986a27070c465280d7419cf783de31", + "b83ed85785784f2ca78ff321ab671033", + "7f43d4bd5a6d45fe95b7f7077835f4e5", + "3a840207f026420184005478dea65f55", + "d611f95f854d439096346f02b2e2d041", + "7344c5580777428fad4a3e5c88251301", + "247300b3b51148a09fd4398a691d6297", + "36a060e40be04538afdb645bd8f1fb77", + "0c0fdfaaba9249e88c63c65ce950286a", + "0c6959334fad43f18f52d69a24c3d977", + "6709f217de904476a0b7ba1b5e641098", + "f1bd324be33042fcbed45b764c9a238b", + "8f795db970ea4cfcb84278c1093659e2", + "897ce33a65d04bb69eb3d87d0742464f", + "2cb60fa3b0b04dacad58bc13ad485dfd", + "3bab4f86771f4f5893c013353e96839f", + "174e9df0d4c94928ac1b03a972051966", + "18e7e719b43f463791181ffa7f48ec78", + "4ae6ac813d584d12a5d5d608a595bfe5", + "3bacb022e4464205ad227688d84ec5f8", + "f7467160c33b47e58695aabc6dca8e14", + "9e3400f575a541b88417e85f766fc773", + "f6b4dd71d8a241898531f1a0f70e8e65", + "3700b83e23e7418b94ccc4dd52114ff9", + "3a6019602c234c13a376c55a6c52c0b8", + "7edb83d1a0e843ffabc87727d314ceed", + "0739f70ef74c4678a4895383b9447c3e", + "ad6fbf4844504b4f8321a990fcc4d3bf", + "19c3819d047c4ea5b792d7dab5fb7a19", + "df2eaa6838734e05b97ead25a39c9be0", + "4f46b0e0e099439498f4e8a7da599925", + "ec334c6693124d3686665337a280d272", + "9887d68f35d24170b86bb6fb208b9c21", + "c752c932af1a477a8fd37f6bb0ec5f64", + "757b3b5aaf6d4052933edc329c4f5aa5", + "5198fa6b7cd04296987484d967b9cc47", + "f06ae1fcfb75409fa6ff8e0a6b6e3d49", + "9be29b5f41ae4c628a7e587c55040a8b", + "297e44a133df4a5e9b85a6354b5ed087", + "387ccb9bece54213b65e374ef3e21504", + "d38d1aa74aa6482ba574d9bb00088313", + "3660dbfe55fa4e2fbd731264ffe0a94c", + "f77acf98f116492a9f8bc927ba375123", + "a37b84b1c11a443cbe2713cf27f268ba", + "1097239bcdbf4e3cbe7d1c66dc29e483", + "f73b3bbd8f3047a2a91bf0453e3e7d5f", + "f94c75745f4d456abf6d5a902352d5ab", + "ef99bda946d24a2bbe7e9f41a63d8aa9", + "6569def8fdfb4d42ba529fd3d5aa8846", + "63e73114fca2471781bbd685546b4d6b", + "362615a0868c46549907664bce12b0b5", + "e0544293ddf14ce28147160be6b22d30", + "5425760f74da402b936a5778f5d1f3f8", + "51ea6a23d71a4a9aa1cbbee3d55283e2", + "6f91565d98da4bb3b32dfef69a7d056e", + "b98b8f64d935415aab0fe9b70074511f", + "e41e9ddbca1e46389d067b4d0ac27dcb", + "f48fd6c63fa248ff93e200beb9ed5b12", + "b4b004ae831741fb9e920be2096a5fba", + "8d15db8f8b654522b91b083c231ad710", + "8aac82b4ae9041ebaff9944e4d1bfa21", + "ede1962c04c148538887116bbb40ec89", + "b20c21772dc446ee9575c5269a867b80", + "1b37c4a5a0f342f289899ffdaa501134", + "232d7c5531334d17b7137367be2b18e5", + "32bf638254b142378c4bd1546cd1940b", + "dfdff5061b974695be24cbfaa429f46a", + "7c16c589b89f48349fde69e6a20ad669", + "a9d5d0a3655e4e0a85e1ae9ef4f88ce0", + "57fc7be2efcd4284a9514f05dbb51942", + "35aeea83f4f54f30b36214051e93447a", + "ff2432bd9ae34b39a248e9b45dabdef8", + "8040408b970745ea8cfe69a3154aaaa6", + "6a3dbb7d0a364fefbdab1ae262d713a4", + "1864864213974c57aa9eb55294a39c33", + "d4adfab902254c62b7b7d164151d0870", + "f4b822dbb3b342cc94938b465919d9b1", + "38d6d1c01caa499cbbe2c4b2a037b073", + "a6e8bcdb300c4a40b75e2e3788914269", + "dfe6f89d65be4a23b28abf07178efebf", + "9b76f4ab046744aabcef6713d4e08810", + "35537c6b4c2f49088c32648100d1abc5", + "f1a289c083244cc5847faf6b5ce3a45c", + "4813a6e6bea446f7a59597456c9a7e83", + "aedb5bc937364e2ca03d5d13ccd3158c", + "ace77dd5c39d461a99fce6704c7ea61c", + "a0ea4633726d4fa4b053f13c12b6bd8c", + "2e0e34afe2fb4980ad4185e05c1fa742", + "b02f0c3435d447258155e1b8313eca71", + "3b7fded75f2d411ca393e4c4150ba5ac", + "5ca7a850ec394eb395f17920054f2673", + "3e3cfe7a291f402899dbe46cc6ba963c", + "21fc2bf84daa45d79e483655997d58b5", + "d2246d7b899f4819b9d6f7f178a7b1ec", + "006d1922549f4f83a87158c46c8f8ea8", + "c153c167eff5428e867c38e9bfa7d732", + "b07dba0b816d4e94814c66e9e34822f7", + "a28b405a6e58472e9e9448aba55e0433", + "018add783a674cf7ac92a4c52291477a", + "73d45bdab24a41529f9509d7291ec334", + "5e32d330fb2e4412b5319f1b501b3cdd", + "6dd59704d72942429b304bf6df8716a0", + "21b7e85f54024a6888bb168f21bbb2e1", + "a9f27de045ff4869a48005dece8444a6", + "8742bcdb6ffa43a6a93d3c46516d6a78", + "512fa76569d34ca8ad4a9790b2625e91", + "a547b66210554a7690d45a0343fce913", + "696b288fb1074408b235699d6fe525bc", + "fe722573f73b457eab4de0c8e4f5d140", + "16ca6e80f9144b34a58e561f1a58aa36", + "e89db313cf0149a09df61949018389fd", + "817406c15f1f4f809f432b7bd06c3b4b", + "c1417e0979dc4735b4484895834b079e", + "d5d03e42d4d1495691cbdb7b46d47a7b", + "7dda053766ea433ba2cb53765ca54b45", + "85bcca447aab4b2285d5a30693af3d51", + "834ce9961eeb460f94fed92732785978", + "599676561a3040fd87afa42dd46c29d7", + "c11f517d18d4494c8907c5a8f78f45a7", + "7e40ee7acf9a4e6ba52c76a5bb280c4e", + "4ad79dd647d24b9da9cb9a1232f814ff", + "26fbb79c01fd4303bafc8d5884813066", + "86447bb411984aaea8a5593456d5aef9", + "77d73403cc154c7781897a660752c80d", + "f0162201004b4aea8e29b754459d9f75", + "c922aa870b0b492b9addd449cf79f5df", + "df042eca21c946a89b8df54310f28c59", + "89545a657ce243148738302a4843f339", + "77f27fc1933c4d6095eb8fb36adf70f4", + "61287b3da993463bb166e5e56c3af610", + "250f64b994f548d58a4654399c3fa0f0", + "1c8e0c944d7242448d40b6cbb1f4901c", + "9797a95cac50408d92c324513b21f226", + "afe4929b753d477088dc8566195e4441", + "aa90a0bfa0fe41c8af443300b19e21dd", + "3689709364d14cc1b90d42065974c533", + "0ec69f6a8e0f48e5876710cfe81643fa", + "f7e0f529593240008d0c63e38666a308", + "629499bb34974b89befdc0f8bdb4939d", + "7d4406b23e5e4525a7afe7f3b25d141f", + "49f7cba7179c4a44b4fb6b00f583cbbc", + "d524be98711546f9b4512393e99c1ff3", + "89c547e2203b4ba1ab118aa324feeab6", + "873545a97bbd4bf5b8818b9c2d62b54d", + "3d43a361f128499eae9e9d48e2237708", + "b7feadba78234e2d9c931d8181f47d11", + "632257f11b80408d972346b1cbcf6790", + "d54159382b7f4ec1a1152da8587e95ca", + "1d2a32289c944f558942ca4db3ea71fc", + "5c78f100eea749c895d69fe2ed728197", + "c0abb3db19d145a791d70d3533f2358c", + "33ad082fda9e4d07a0889ebe8d841c6b", + "376d5fed44584570b3da415848d33811", + "4bdcdb888f324c7daef328f9c6b84de3", + "1acfbcf607d343c694006fa4b158c5e8", + "e6b4fbc8ec404d32a67cc67d574adaec", + "3d997263b04c4f6ea2b0df05ff6c9bfb", + "a10e145b98114e468f9444445cc7d7b5", + "8990c7da456f47d193106aa1f2f2442f", + "ce421f10e46d415198d5d19c5bd265f2", + "e35409589216483ea179f11c02c20270", + "b3389be723684644b731483f31ccfc15", + "ad1f36995784401bbadc36e60354cd6b", + "5c8c1b1765934bf38d76b3fb6387a147", + "7d28e28acc424fec8ebe9da56fc2638e", + "fdbab0fecaf24d7e965666b69e8309cb", + "736bafbf63a045f080528e4f0b8cb552", + "306ac890a1bb4f5f88cdabbf0d95e137", + "be014c4f545246b4996db9789e1acdfd", + "9231e77e152d4e54b1673eae6686ba0d", + "a567181dfaf8450f80cd4a64fffabf40", + "608afae01a8a44ff9bcc103b44f3a306", + "6ec90b8d2093490e98cc03d302e039b8", + "a59b3dc728ff45d48a053758a153249b", + "72a864afb37046e3b5f65387d36d5747", + "73a7f825fcc0419ab7a185961ccfc40d", + "7a14a891609c455281380f1d2b328ea4", + "1f3b996fde954abebce4d4c4fc5a66f1", + "f51306c13cd14d38bdcd7a31d8804bfb", + "a880ac977f0f4508b24559d706e543ce", + "47cc2edab93e41d083cbfd9ebb74b1ff", + "25ec13ed807144d6bcab9980ca1cc320", + "5ceb84855a354989a30e342f43956e83", + "fe686076735042bebef264f3b9484b20", + "e45403cce7dd4b0e81eaeb840bdc24b2", + "2b787d1a02174d0bbca9eac34eb3a486", + "5f4653c9d3b14c8ab92c8ddfc405b50a", + "93fab0443ba44d55853a878826c4ca60", + "7413762d0651496fb5e753801f4322bf", + "70076df786934605bfeed510bd1d0cad", + "3748531bcc0f4b469c9840a00b61d806", + "49704737bf0d4fc296937d5ccc5711ec", + "cb7021f1ca3d4316b3714ca3262e6830", + "3a80e07ff6364b4bbe5252d9b532a87a", + "271f04e7b2e24e48968c70f23c0cf795", + "3331e1a05cad48ecb95d11e8d7930a20", + "a69f22dccbf540a4ba86766911cbb7e9", + "8f7dd5a6d58f40bb8b4aa690a1fda5fd", + "d5acb0a9e7754ed78e4bf6400af4ca23", + "58338d7667924dcfa509b3bec8c72157", + "7ad5dfd080b14505b5caf38f102c32ee", + "578e94244c8648d18ca7d0506379989f", + "5c3f4d1c558746808711eb84ec4b5731", + "1e5bdfc4b4cc4957add70e0626254cd9", + "c2d2c347864d4663a220b2b21296a327", + "06fd1c033a204719a73be3901b18ad4f", + "5f26c52bc04c44c8acb229bcc09a2d98", + "5f9ae9329a1841b499e84f9915045659", + "42bd32ba105e4c01a2679997dda794f4", + "5c170aea19674a44afede5f8d7ce1dda", + "2524396cebd7411a9702f30b41e2760e", + "7c188bdd8a8d4b9c8f5f6652009bd18c", + "255982a6d7fa4efab1e2c9c7ede33054", + "636816af68c049c4bc0ed31bc1493e6e", + "685660e09bcf4a5eb06be56cce0a6f40", + "7947114250634c919a6fc515c724ca7c", + "ad1423852375470e8da8c0e4f8f07e52", + "e2aa3e4cc7b64408b453fed0d9732a51", + "1ad51f6676bd436eab77a198dbe991c6", + "f5aa537d99834294a239d85ddabb3af5", + "57bd8d531ce844188f1e2b22f96a48e4", + "1a149be991c14025a6af4a11e8ed84a2", + "7f0622fe55df4d839b472edbfd85aa0a", + "1042b9b3532444c4bd17f7d25a68adc1", + "7b905addda2b460e81a4c47fc7b6b6e6", + "0b30d2efe63f41b0a812904b610fe577", + "789a13c04d584eff833733ef7270a412", + "97507caab9064024b9ce604bf83d0fdd", + "341490d82d8d430bbc4402d8ea827d8c", + "185d18b159994da8a74f3f48b360d93c", + "3039a94d5dc34429b13b67d6318f4747", + "edaba58075ff4796a3ff5c4a43a765a7", + "45c78648aa9147668106a0fb8ef0bffd", + "582983cf16864a0ea18974ba2b5d546f", + "4f834dba8a434209a7d1d9b39319ae77", + "3bf726bbaf0c420b97fe6dfaa0d32e18", + "fd10e7d9a4b042c5b6ba5e2d90ed2efb", + "280fe062ef5a408895071716e7f36b5d", + "3455ee5d1c1e4a45b6dceaa5e3d3ff51", + "5879031e0ac541c5859bc07def05e610", + "bd48b016c2fa453b9505b3e5ad7e42e0", + "e365d8cfd6354316b57ba7e312c7de62", + "1d779259b2df4ee7b9e7e9ee2dd56ac9", + "956cef1ca1af49f5953fc202b20dcfb9", + "82b92dbcdb194235b6bfc54cb9b473f6", + "72e4fe1b943e46a782ac7e1790630589", + "2b74e98be6834219b9e3cb533d558d2d", + "b18a7d6210ca466f9dd9ceb8e1675a58", + "aac71bed4a784536964748569dcf1537", + "35b038ca0c6c4c2b91bcd64946299b57", + "3b11769207e94767a56fd320dc58b058", + "d5b25d1f9e94416484e00712241ea431", + "42550274346745549c27f7bd4aef81c4", + "28a43cc3a784484b83ea8d8c186c909a", + "19ad9302ef634b2d8641aa87cd035b05", + "9addea6a4129438b83a1fc3ed4a784ec", + "0f4efa784a344082a25ccbaba282d488", + "c6618f5d3df8477ca2fc6808688deb2c", + "77236ee7dadd4a4d927978b0475575b1", + "25930d5259ad4402a29e84a00126c54d", + "48a5b45173a2418092d8dcb727396dc8", + "06a5ae799acf4af1846b1d4b8cea20c8", + "4dc24ce9621c49cb8d6cc50594b5e38a", + "64f4866b5a3f4785bdd5c0ffa6f27c17", + "bb702ae313d845968149c3a575b10d92", + "fd0e0e98325146359fe5f457d125367f", + "8f0142bd566f4e7c8e7a2823d4dd6a16", + "42eaeaf9c88c4a3f9a8a53ebab79ba05", + "94768884d4c940709d87a2862489cb17", + "411ff2fde43849c08572fc4647c545df", + "f92489a55882402ea3fb41a6aa5b0fac", + "6c5c7dc65f894a46af678e1ea1b0a4f2", + "792e44e9d6c043629f15ff34e16dbb2e", + "b592e9af729d4ea49ef658433b7253af", + "84825e8d58134cd9964406af562f46ca", + "d8be00ffa4414c1ebe57d4210f41cf48", + "c892edb592c14d1b94067da032c2e0b5", + "8148f2bcedb74193a3e851249df3a648", + "bc0e393bb0c34561968bbc29535ffca7", + "91a435a5cc98458591153bf38234b21e", + "47ed4c8b48a248d8ad2684e1f22edffd", + "b338923163e048e49532323e569357a4", + "184d5a1895b04b5c8f8fdeb6182b8d1d", + "495e9b9683d641119bd3f8f209db56ea", + "8fa9f20549c74bc99dc209ac795d7ca1", + "63f8a10e70fb458faaba4eb8ab1d63e7", + "0eb7364f34e546bb987fb1b098467d51", + "5de8754563254e34837ec4aacac8632e", + "abe28d3df0ba41a08375fddf471b7172", + "ec02a2b9aa524999a6dd1ac73ebd9d70", + "904a927cbfb84dcdb7ca991f28451890", + "bd1cb4814d724fa7bc3acc27edefa5c7", + "4867663c59f949bb927555d9abfb768c", + "ae0fab3e19b94a8daf568fcb1c9e883a", + "a039957727b24bd5a58902c8d13630cb", + "31a843bd24d740158a57a59200ba0ac8", + "87d113580b924b9ba67fb6695f8b45ce", + "328a3c9a6be7472eb217d755466c42c9", + "374ac29fd6354f9a922990b4141111ff", + "a007e6ebd5a64ff7b1aa7ef645b1df31", + "3a8db3b4460a476da1fec0da95942fcc", + "f5869077230e41329d3d06870e126e6a", + "ea40fcbb60a040c1a77d1ac0072a0728", + "0c5798b7ddb147dd9225ade86d5df169", + "3b38afc564c44f52afaca0acb9949c35", + "d7e9ba33da2b4a1c88b0100793f36e88", + "5cb53bef00334e9b9819b1d5d2a051d6", + "6ed021016ff94232a94073d5eaf1b756", + "095df5e33ab14a8c84ed1a0451154836", + "310f1d21cf534fd0bcf073aa9b08a740", + "d83b8386793848c8aa1d2484582aabb8", + "a153f36d0e2c4d3b8306818dd706762e", + "49feb4af7ad9484c94a13b6653aa9f81", + "ce7cd75d0df7496ea72c934bce1fb43a", + "9ebcb8dc02c340a78c2b30c1f60862c4", + "1bc6c74aa60a46e38095f7d47a5c831a", + "8fbfab629a474631aba7f80d81609302", + "dd99ebfc07e54d4fa674fd07b4bbef92", + "c08f39ce6a654ae4afcc925d7d11a6d3", + "da6e8f5d9236444b875feb67d0c77608", + "72073746b09446068ef9e166fdb3ef84", + "a8738c0c916b432ca4110a93bad28725", + "6a4bd5debdbe4c35b1cacc3c01723b17", + "f7ff53da276d433cbd66bad134b1e4e8", + "8d6818b50166443f9e529afac52204e5", + "b3b81d7e4df14979a3b9ca19bbbb1e3a", + "2c8832c80aff4268b83a0093380d803d", + "c95b90fa1f24468783004cc34bdf7878", + "c666d90ad57e44f1baf90e5ec062a152", + "d5625487abc14990af856f3e36490b4b", + "c9d9dc20498f43e69cfbbc7d576ebd35", + "1df4fe30c19a440286fb56c19ac8fd69", + "9155b2b4be5f452a98837459112a3b9b", + "59869709cfa145f18ad00e9418d9849a", + "9bdc1edc622042608c44931386f359fa", + "204f6d75b01f48a7810e00f58cdbfc53", + "f298cace43054f929cdd580e2923ac27", + "1c3bd783a52d4e62a472113f16475b94", + "2b79403df47d481191f9701600552ec6", + "53017a1b74634d19964bff04772beea7", + "4921401521064ccbbdb1e507416a62e3", + "621801ba468548cf903470e75956263b", + "df7bb906d75e41ada6ec5b6403dfb7a3", + "480e633e5496497fae60332ea50923a7", + "687667d848954107b4302ef0393f82c2", + "2cc26e76d457469e827c5f03ca21f8a6", + "0f7b8ea366654674b217a743959798e7", + "1dcb04cf15084f95aed9602313225657", + "d628850b03e44199b6936d190283765c", + "f54e5c6df5414ce48ed5eeca0ec9496f", + "5e892fc786db4ca1b36738ab5e40e64d", + "109ed75bc4df4400a308cbff7cc70f6d", + "8e85d1e8965d442fb7ea81eda1c37f25", + "2ace311a7fbb46ad84dee4b12575fc09", + "7df8ae89ff1f4f3c9f82d5a3e0a3f396", + "4f383fccf4a24b41a795deed8cc0d117", + "85caa4844d164d18a9c58f6b0bf5d3ff", + "94225b477324434f87005e218c0644cb", + "2aeeb8958bc64240962b093705abffdf", + "b821071bd5fe46b5ae130836679e98db", + "8b9df0c4e1af4f7f855ad5f4e8a223a5", + "58c2cb90261f4a6eb368d4f97601519c", + "5e9ad4f128cb489aa3e0846a1fa74ebb", + "5e8abbb3a6154789bfef01635ef689e5", + "bba7ec6f61584664949db25ca18ecd1c", + "c9aff3604ffe4809902911b2d2807964", + "1d9aee732c50495597611151c4798ab9", + "9b2a0e3878fd4afd90c3b50986832a40", + "05d58bc6964541a298032d24014cf899", + "e5833ce0e19044a6b3a95988274221a3", + "e89d1c566bf3458089dded788321169a", + "93a474cea7de4c44b3f4741e5fae4b3f", + "8ad5b3d93a7e4d1f903c9d933f11b3eb", + "508e5e6c5d04417ab36fa02c703e768b", + "a9af14bb4c314a2fbc857796c71f8d83", + "dde20601f2cb495f92554efc9843a5a6", + "6b19a547eeca47a18d2b0cb4bca18c3b", + "aacc55e455bf450e9c07470bf411496c", + "3404383e27414d658bcf1f2e5ac98745", + "c09a85928fa44d33ac02ed754483489f", + "fb9324b02d564d4f984f2394827e73c4", + "e9215fa88a83493685ea828193ccd183", + "deebba1c49494af5bf04c1f770b3ad07", + "8623afa1a7a841519d77449c1488160d", + "9f421abdda024750a42ff5932f3bacdd", + "d0eaabfa2c9a49db8aad7745cb753d7c", + "feadfb9d10434182948d4e3e80117e71", + "21ce12eaaede4527a9703d72e9bb5c06", + "9055288483244d228a5d183b206ab9ec", + "e05800f3d32e46698ca99a45e797ea73", + "3716f3bbb40e4933b470398e7a8284a3", + "8f5e0e55407c479ab3c05fad440cdb8e", + "0eb6c94aa40c41b480cf35de229e8e88", + "fa572293646b4bcbb1283fa401decffd", + "f28f781755a84a4e83e56e36d06c624f", + "f844ed37976c4be987907526a781f333", + "9714bdb006484d9eb3a26df864b1004d", + "ce1ad6c08a8c4e2f8c08eb910a0f8e1b", + "a39e86420f7f48d8b6ea4c8f80090635", + "493b70a6177d4a1385b6b0ce041a93b0", + "a7830bb1abc348bd9390d126648377fd", + "a9d4e134a68c4dc4a2a375bd1b227f6b", + "a4d50eaeb0104533822220a2f2637ac3", + "a7764c9a884443109e9d335b6d281b77", + "7576ab313087425ebf0ddc595e5040d3", + "10b7a0e221ff4a7783cf178e242a5ea2", + "6d193c12639849d9a096f4c35ad50209", + "9ec96134d8e34be89cf946226dbf4209", + "fe59d90ae79b42718095dbe513c1adeb", + "e6c00e216bb243a4ba05e73111807294", + "df7abc62458c4752800522eebaa99bfd", + "2f99e5323a204202a4533267cce06d8e", + "76651441d8ba467891fc1c1c1ef6f744", + "210680414c9a45cca5ad95be80db07f1", + "a6247837ecca4431a68ee391e4ebb780", + "4f6e6b0d481a48fab1cecd0700d9846c", + "2689655c6a94473caba884c3ba285be5", + "4a480769d48841618cfb371e7dd44eb5", + "f843f7865ae641819e302d46cac4eaec", + "78932b7ffef240379e83320660322fcd", + "97188bc15d6741cd93fcf58aa97cb015", + "a917f1bb22124b63a4ac2938de40c46a", + "eb98251fbccf4cdd8a3737362e2378e9", + "18318af2ad484641a2be603b41a94039", + "0f7c1ad13f114f2b9da596641bb47fa7", + "0f5f943348a44039bdafe002db4f85e0", + "cbe93b42cf9047e5b55a2767886cef35", + "61ac73177fe34cc4973ff98830e10b21", + "8d6be6f1ef0a4f2fbfba2b77adc0b374", + "b5f6166802614bf8b6083ddf2ad22c52", + "bfc99e2cddf8495f93372974ef5a64f3", + "fa46b58fcad24c1cbcd49005fa6ae392", + "40431be061a641ba88732f17dda19ae7", + "0bdcc7e8ba444beb971a8f514ed9b994", + "6f2e90d6157a40958a500ace8c454a76", + "8f1d77fe247f405283dfd51a90331332", + "38e725fbd2a24183a8f4563b68865e5f", + "82e9f112e43b4940b9ccfed14b7be0ff", + "7df79a6d21d3460abfdb8a93b768a6be", + "c0a475b5318e48a387e2f8a1e5a20f1d", + "50f812747bcc469b8216e922fdffb04f", + "940e996b136e4db0a364a88be43ef0ff", + "d5b17a7d672a4ad291e0e6359abee38d", + "dadd8c963821485ba198731008f566bd", + "0321b21b146546929495f7d2fa597418", + "726c092db62b4a79b31026e81e73147d", + "2262aa6ff36840db8d98baa986231f6e", + "e7be62bfd0254ceda76297da3fce7f70", + "f307352dc4a54b669f9d9cd3c93115c2", + "4a6cd8d53cbc423da9e33299f4263aed", + "e61d16e2c1d94b3ab75dfcee75569502", + "52c9fb78ff704faa821d193543ae2cc7", + "a4d4dc74c3d04053a4578f3b734aabaa", + "488a3bb858eb4929be657ed74f2d04c5", + "7212d41012594906a72d3b5adc260d0c", + "68b2ec30fdbf4780a12aa7333a9e5188", + "a8d970fb13af405fbd39a2c726ff2c38", + "f5e88b5040b5432789e147be28710d1a", + "60d018afecb74033a0bc36c38c6c50fc", + "b221ad482e084c449408c229cab380d6", + "9c3ea5f692ca44e0a28b46d86f810968", + "935ec26dae3c4e848ab57640710b99dd", + "d854b2c749a2481e912335511920532b", + "ee1b929bc0ef4f6189c10c0a7ffc20fd", + "fa7f2be6b2b44aee936ea52b3c4b7330", + "84f5c1363273479fafc15e73c7c83abb", + "45fbae98d08c4c11b5f1cee392ff7d35", + "63b85e11d9ce4ce4a764970a32be67d9", + "18853b42315f4fc1af6a982d730d4961", + "c935e4a7176042e5a5aff2a409c53b07", + "8ebdabed48ed4963887435aa05f0b874", + "74da8c63b95642a69f6807b9b467766b", + "5b8a34ec3e9d4d15bf7d868ff576c9b0", + "e48409ffce3242bfb2fe6a445e57cfb7", + "1e025ab1bf234858ba48db14a54f26fc", + "eb2437bf156d47cab3e791ce1d8fcfff", + "24d1bb5b02014ba8be693b6cca1ca752", + "7625966239174504b1280c68a6c1a550", + "1afcadd005fe4bc4974f8ee69fd0e7cc", + "39009d5b198c4830914fd7cdffe0626c", + "6bf3705b7a54411785d50ec81a3b9b9e", + "8e53dadfbcdf4875bc6190545f9f688b", + "e4c89a5628db4c7abadbd18bb407a2a8", + "d92ab9476b6c4223b9e942954aa58835", + "bdacd07d23e0433c9714e3c3c45f3181", + "55f2fbd4c3974467bc52b53608c331b6", + "f43c23c42e9f4fb49c46a761ec9d8d77", + "0a0f24544ad2459d97e5762bf8aff380", + "f79ce8f87940478ba197ca8694a1a71d", + "9f262616ae19413a97adfac0d4aaa0bc", + "f9b22b6e76124b4781198bbd06acd50e", + "47140dafc57b4cb387346ff633319b57", + "8e0e716eb52c4d8fb8b4519ce0e5b45a", + "ebf6a27dd3344b7ba23a02a18165cf52", + "1257743e67104de693633ec0f05c7716", + "17ecd53718774ca287fb3a56b6d4ed5c", + "6684c165507d495a805b3b62349ec712", + "b207512fbdff42d7b5dc0a58d5254ed8", + "90823a5572f842d6b037c891b9544e09", + "bf09c469e83045f9b91667fdbb277e22", + "04c322d857504a80983d4bf4f4b56ba9", + "63021dc03fa0409ca8392b1eddfcbf18", + "8895bcaae1614cd3b41e7ce06b198677", + "336d9df05c814b2a8044888e0a1c8831", + "ba355e12b7264777874e47c20d19d363", + "4005811722a54afaba3d0c29d58b657d", + "926c66525d50495eab76d7b915ce0967", + "1231d4a31e6c4e64845ca1fae0cf0450", + "04ae6c97835448d98fe5253875921557", + "e72a40a1adde489b9e0149f94eb7d967", + "01af78638a2e4d458e9838980c23c96a", + "ca59b0f7ccd940939dac845de4ac486e", + "b44e188c76e94818bfeb0fa136c4e1eb", + "98ceeeac76384710a1e6881c09766a03", + "2159e8b27b8647dd820145a128b9a887", + "1b19bd9ac878433a84765fb6dc0f10ed", + "25a90ce47f7142a9ae6918149abff3af", + "3c08d8a970c242399a9086bc439a7ad8", + "c6ef3982084745d2957f11b40712d2a0", + "486c58ff94504aa68d62372e4b4faf2b", + "2de8c4ec069b4687aca3031f39c1d3c5", + "d5086765363b44bdaa1f053a0c7bb83e", + "10db7ee30d594d56900a0b79086e458f", + "c38cc2b2ae3b4bd1b035bb61ca8ed8ca", + "4d1d0606e7e44a84ac532d02f35d9919", + "c82b305d83be43359c71cfab5246d7a9", + "4e05b99389e44f71b22e284c05d380d5", + "6a1419b7a698497b90916e9f21dd5264", + "099d520e4dbf4b6891318db85ba43cc2", + "0367336574904207b7386f39f631750f", + "67cff4a10169496593f8ad0dc85b9bf4", + "9eec71c525e349709e77caa342a2c694", + "abad65e039334c08b044734841a0508b", + "e240d2d1da3142008265d75049a60b71", + "e55f015272e747a2a0c1039559cb58b7", + "1af67d13b0f84060a6b4e721060d5536", + "fa78ca4e798c43f7a7bcca2751712120", + "c2d63aecc61649938d0cfa89daf017f5", + "e8de5d936d824862af0469eae3b2925f", + "c459459cbc734fb1899f4e65b5f13f0c", + "10ac5e64861a4cb4868a244d08496b97", + "103069c0267b4d238e54128a724fe979", + "1f32bc0b4dd740f49faefc1cbe0e5e45", + "73809e41208e473c831d34cf90f820bf", + "fad1b19515a04b4b8309c79490e7228b", + "6da9a1f9d1784030ba18b02349229a62", + "a0d133b0871e46bbb454d0dd58e3ac7c", + "6354119423d14471a803b77aa539b2eb", + "4f2d897023894715a44f40c568dfc755", + "50231c1872584e7db662e3e5d9783f74", + "4ffa71a0088e409cb111f33fbba75b9f", + "2adc430b322c4130bdaadc4f9c92886c", + "13ad88e449e143b69f8e6642c665602b", + "c64c1b8027e848afae6f129292e51558", + "064df4f8b04f42a0a1997b813de36c65", + "350ee502097f4af88163e332e32c0240", + "fa968bf5d57a4265bedb233293870dc2", + "a4aca11a2259462f8735a60eead33962", + "14c4dd4621df4a7695e7b56db623c69b", + "4768d6fef8734c7aa99321f6b6b3c520", + "0948b5dcafdb4551a3eb20220b82bfaa", + "00d1cb5aa82745228a3b764c97f867de", + "d8cba8750867408e8bffd62a00c97583", + "72bf5667f7e74847966105cdbc352ff6", + "890ba220b4ee47638dfb156669a37608", + "a7dc44d6760549e0b26677b2a587457a", + "33e09e4f17564ec08ebe34e4a68a854a", + "0264eb8f32b34855aba25735bf611a74", + "6ad051e986b24831af5eed4bcb319637", + "bb1463e4d2a54c2da28e5d199d0dd8ca", + "5a93e0ce8daa403c91a24cac852f82d3", + "380200cc67484c51b01b48caba71a343", + "c920792a90484e3a88f61a03e077c001", + "57203e19a1514e57929000c9bb4a10df", + "fa4268e505e0478c81ecce5ca4b228d5", + "667ef3731f114eb0bf937bb4f820bd1e", + "3e659afa88994ba7b76003757aec8161", + "93ca005f5bf64a70857c9b137404248e", + "9396a10bd8804811a14b58f50d543575", + "0d00334b4c6b4f9fa34cc215be9990ed", + "4b0ae97b316d43868523452d219acb0b", + "345f5c6cf369414798e31e1f089527d9", + "1dd9b373e3084cc0914a580ce5728cf8", + "a838f6c330594956ada7df8d75bbc297", + "d52590470d3d42649f4f421dd161820d", + "f98c3e7ff9da48989d743e718c69f335", + "77c6c8ce9199433d8f81cd77f99ba978", + "05e6f8ed25e74242957b34f9256ffc47", + "eacea7ef80f248da9c70aa1b5693a37f", + "6d7f2518e42b49baad0ad1f3cb2597af", + "76d7ad00178c457ea03de074726500df", + "ceb7dc27a8484b149fc93a1de8d67f5c", + "c82e4171d5c942698129106aedbd87b1", + "f0ce6821cca44d63bbe1ca6ff8f6913e", + "82ec70ff368744638afc7bd8290e7afe", + "063a21328f5a4fc1a17a3f0e3b79f8b8", + "ae252eac5e2e4299be268aa0b320cd8a", + "ad1257265b364ab1a788f0936714a3ff", + "d414c185293e46eab32bf539f6fff808", + "6b13f9c6b1384358a3144921af6f9e38", + "1e16255de32f474baefb51a7283f1be8", + "8908370a98644d09ad41e3545500f7e9", + "61d5a28260744d8e8c4ba24d5d33db77", + "2da280c9ac82458abe77ab1d1c710086", + "c42fdcc52d4a4cd4a2576bbbcbbba885", + "dd164aeba6f94d2d9d9d66844332aa22", + "357416df2f5740a183e26c8b4c74a55c", + "e95aaed8cf7241f78861cc96139701c4", + "76d14ed8675046d686019a770b21d8b3", + "70d185b09a154c799fd6f9aeff8c9579", + "cc9c8331b25349b7a709a9e5a85b2f3e", + "7204c35a9c5a49748a317478318ffed6", + "4bd4fc0e630b47d798314ecff829e0b9", + "7063c92f849144e3a7dbcc51ef96a517", + "9c72d883d97848de87fdbe74fb61c2aa", + "6f5eace8ea344efdbe87e73de66ea886", + "49e07d6a217240d4a69a81e22ab0f846", + "af936b0e9b6f46c187cee334e957519a", + "4f64dacffd70441cb3499030615fe66a", + "a24bac93ec5b4c79b006291612f60759", + "9c949ea098d041ba97a3b988d7d329db", + "b69ad0b5456249318982aec3e0aeeb6f", + "47c8ae5eea3043e3934f67bc5d345bd7", + "17ba30c2d85d43298d85b3367748df73", + "2151e81af03d478f918511ffb1783218", + "ccfeafeefd964d83a54fa16427fdc0f9", + "e2688126f09b444bb8f0dd4543499fef", + "b7ebee0ec2e44487b5b79e237a1afdab", + "ded559c9a20d4c009e37ac8f7a1034ed", + "26c4202196ce4adf82428684c88fceaa", + "e0bf720a565e45498b6a395f2a5a3b33", + "e45616f913fa43ab801289b52c6577ba", + "8a983b17bc484fedbc1ead6eb61b55b5", + "6a053ef489ba43e7811ec4a6a19fc074", + "e2aa707b672a400ca6d4bcdaf2fc9aff", + "b581ab5018df4e5ebfe5fb56333a98cc", + "b3eae6aa93ce496a888715d4681cb55f", + "0e41024d41344c9da9163b672c98d1fd", + "82bc891f05574057b28535662d0c6913", + "e8f88ec0a31b46e8b48c4fbf23e47b03", + "dc62162e9e30488bbf5fda311231ad59", + "bf4187ec36724f8b97f048cfaf7b07aa", + "3c2ab477da8a48c38fb7464a594bf906", + "ea5754be593d4f82a9dc6e1a2e06e51b", + "1d98103d4d4c4972a960c642fb6a28e2", + "62a54774980144edbd4314752c6f274c", + "2e24c83d4d354f90abf93148ce57914d", + "5c55a08f18954902932b17c83b9c1418", + "77c0313ad21144dcb904915d66a163b3", + "f00d3c4b33ac490292db148f1839bb65", + "5527727bf0c442c0ab45be57fe6774b4", + "bf3d13dcc79945d382b61d0f00bc459e", + "ea0080f2433b41578145944a3d0b350c", + "1895ee3b91ff46ee8a24f01cb6707136", + "2a0028d1f50b44a49fc148b575b40427", + "f819119405f546a3aac500f51f8733c1", + "5d1f694c4d754b1ca7ff30f4bacb6ca1", + "d6ee1a7166554559915bdc187d8d8cf6", + "1f7480b382d748bcb063c456e031f9d1", + "4383b3f88d9646c7b2f336266eaad947", + "9321c45cb9cf459f9f803507d3a11fb3", + "892c3c4705b54efd804377ffad907d0d", + "759e480d707944ee87b1ce61875a320e", + "34401b6462e3454189f292f2b03a0d67", + "2f1f291be93b4e09898a17f99e99d5d4", + "7a89051127924a2ba793a72d092abe74", + "541ee9c800b04a128d6b670f8c5fe6ba", + "387d9e29174e44d2aab2eb87d4ae6bf4", + "4fb61998e44540158eace209f9fa9738", + "0cb1f13858ba47d496f4946e79fdf29d", + "41d79e02b8ee47b7aa2549ae139420bd", + "ae9fb0d6de684331b3ab8514a83425c6", + "70b545688f9e4b26a7253250352b7ffc", + "44173e42c9e2414690f630c8acf97079", + "69f894047a884feb83fbcc0caf09b0a1", + "8d62757bbe0149d2b7672c1489a567d2", + "6b3511d87b074b5c9ded318720b0c87b", + "796cdd7952304754883288f373024849", + "044b951bc4ec498bad494aec7e977be8", + "ad9b20a87d2e4e08a3df49615ce76ef7", + "9587cf9b069a4826a0de01fe88500f49", + "54b83c8a41c94cd0b75b8a3a77086159", + "2d8da64ae6734d0ca08eba1a011a03f3", + "132c6e972c254c7593869bd216fd3ae0", + "5240e4eddba040818cc9de50df8e928b", + "52772a421e784ac591bd93587a751ab8", + "a50426d4b005416abadea5581be42e00", + "9c9b9d12eedd42a890cfdb5046125ca6", + "a93161d5bafb4d83a73c766aadb97416", + "89e23ef8fc6047d3bfbb7bf15d48d02e", + "a6726b68b53940a892927a77b6a8b441", + "14c09aef045042fcb2e89990e846b8ff", + "7a093bca3275487a901149acc18509a5", + "6b54f92c60e3437cba065dfacf0f8beb", + "231cc6abc31b4602905023479fd0df6f", + "555627427c054e3fa163a57f540e1b34", + "18d503652c964a0da32435e040741686", + "a11f63180d6f460b928ecfe85506d7b9", + "26ad5100e8374a42a2d50b6c2a9e49d9", + "267f82acbf0341ebaca1f2a7acbd75ac", + "1d0a51e94a34429e900c1fd43d45f853", + "016627cce41a42cfb48db34becd7cbd8", + "78185ecb137441e1a46ae766279de5de", + "effa9692c0b64245aba9c163c991b21c", + "b89a06e6e7554c5db7ecd1c51edd3bbe", + "3db1f4b37cf24982a353e52bb330f534", + "11bdd46c89cf49639227034f0da41a59", + "af4e6161f074465782f7aefe9df2c943", + "bf7360470ba342a1b9a2351a711542d9", + "1f1704601c2943ecb7e1aab814a69326", + "111da9ffadb647bbafc45e21c2c3071c", + "b1231ac5bbd949429a2b8455fe646fc0", + "5dad44f4175f420bbaf8fbe88e52a116", + "ed42b058fda84754b4a4ce96b17bc91c", + "e34246f2fcdd4c81b0d982a2053b854c", + "7e6a9d9d648a448da4caef0e29c814f3", + "f0f182ec17ba429caeb2a5841b330e02", + "52170a9e940b46239a033fff297c9ed7", + "60a14b52522040e98226e08198ec4227", + "19f848c62bef44c0a3cbe72fbcd44ec6", + "c83369e317e54cc0bd436555082e7f4e", + "23eea4471bfa479cbae18a5ee5c943e8", + "f07bec578dda4f7eb84008bdf74a6548", + "08280e9d6f024942a3f57a9b8812dfff", + "c5903e56c9114226be3f55f275449241", + "ba384922efad4ee1abc1fd8aaed321a4", + "6033965e70dc482f91e3238664d8765c", + "560b013c4aed4cc093de013c517b696d", + "6b985fa7b20d4b2a9d404661652a81de", + "0beab25d297644c6a0ab7508e45ee553", + "0c0fa23bd2c84fa195ba980e38df7e1d", + "62954f4d59c34c11b22c62eab8cfad57", + "0349c93a75174dce821f05648aff5aa6", + "26d68962a8aa42cd893955832af61a08", + "8bd197cbf401418ca78d769001aef161", + "fa776e8084774971b043bcb28ca4cc38", + "1d489db9cdc24161a7537926a20bb17b", + "c12909c5b64943d6a11a9f2e3dded93e", + "948411a1c6d0453e96faa3dfe32936a0", + "e98180d5d2344977a5111a5c0d5239f4", + "d3f2431b849340b98871f1dabc531941", + "95e1d142682c45d08bb42079e3653f74", + "ec291518d1cc4f36957bd951d80456dd", + "e78653b4e7b34e4dbadfd07d09a56694", + "18f4f3f0638f452086f221fc9805ab7b", + "d2caadf8ffb44adda573de6d905e8a90", + "8d1a02e110374e33b3b6b773b14abee4", + "be087ed2be034331a2b16d479c35736d", + "966784b16f6d4b1b9a85a1bfd2510d18", + "d55cbeef0dba44e1a35bfba53b0bec05", + "0c15bf821a7546e7af4af3567a0efbdc", + "66119785c4bc426d99a691c43c0059e7", + "d204c0b5d862426fa5c04b262d6b4cad", + "a826d4dc23ac46a3b1f897138ff052e7", + "8c8d1259150f43679a097dda0598f486", + "ebfc326562624d07b08ac04baec46d80", + "c754fc24504b4f769c386fd3f2dfb473", + "8ffce3a498da47c0930f41fa58371e54", + "16f756d366df480c9d75e8119c253715", + "114f819c01b74a6dbca9eb09dfe6046a", + "6f10882020a34a6e8d9e5c3001bcb9da", + "ee74fcdacb694abfb444cbcc5954526a", + "0542560deb10425a83096b57fde9c3c2", + "df9eaa2fbdf8484e96111404bbe0c279", + "663158fb9bf4488b878151ae3f7e5a78", + "9781244bcd1c48939b04bfcbfeb3ae85", + "230303add9e04a4399d9389d5e660c73", + "5676b179b3b744c0aaae53a3dcea2300", + "f2cfbdbf70cd4af7ab765232442ca91f", + "825ec0ea25204295a948615f5c36c846", + "b01950cf99aa48c1ba2ebd0addc8a9d4", + "80048a8844a748f8955ff029cdc7ea04", + "8225eace192b49f38c989d607f570aab", + "7bc05285946e4d0385b7a938939c7148", + "28d6c7d1096345e3b99119e5b6b9f5f2", + "cb36b152c73949328669752bdce6921d", + "dc42ffc81c86480e9e7f7752fa134174", + "1bf85fbd7417479791a6cebbf950cb3c", + "430d454ebedf4886aa363f18182cc480", + "a2f385420e0842efb354a25b72f05d15", + "f061f7dc78034c01ba77e63f8f254bac", + "476f8b64886f4edbae88e74f68d065c9", + "93e4d025ebb046aa915938f03a5f89b4", + "3935db5647c8476b9e4ca17d188bbb41", + "6174162400fb4eb5be0dc4026d28dad3", + "769f1d695bce4e1baed49747665cd995", + "ac4cdb16fffa447b9fc246a9304a1543", + "ec2a67b27eaa4255b5d412b53a64dc81", + "c64fd63f94e54e4b865d62b6721893e5", + "523b1fa6ebee42bd847ab1a0d8f9e0bb", + "3ad5b1ae58b04da8bb3f848c0f5d7af7", + "fa757fa2a72b400aa03f9cf5f9d00426", + "bb6756e38e2643d89907a11754706204", + "d2a79c02a5ad471d90cc975d0033b8e2", + "1fe74fe5352c454cb6d2c836c577e17f", + "708c31a78cac482eba35f576d54feb37", + "4ff86697ef694e948e8fc55971d4f704", + "dfbb335a32c74d9e979a868baeda2ef4", + "1524f04f2d8147d7a63d36bfee1c5458", + "7cf83f9b5a1247198ff9604b393ebc3b", + "c85d5cedb1d84126b01368532f0a8209", + "4add2d48a927438390734379946ddc9f", + "7bd49a69f4cf466183d998ca973d4390", + "619cfd5b08ca46589ed3ad9f6154179f", + "e33495451c08417ebc997c6454073cfc", + "de0259c455ae4921b09d7b3a5d35318a", + "435efc9bbd244fb5b73abd1a69da06a4", + "a4e5d8e9da1d42269d1e943aea52f478", + "596d5066205c4546981c191f4d013795", + "07aa112ed4be43f8ace4e1b0cb30e2f5", + "a984e18f2f00401aa594b7797ee074e8", + "2bf4905d458c426199be919209943ee8", + "b7aa7644a6f9481b89da16eb2b9ca39b", + "2bbbfdb7e7f54b64a70c860f7356aa52", + "ca8714754e0c4a4f82adefadbf1b2d1d", + "a0c142a41f084821a499b6111f71a6d8", + "264dacd1d9244ac5b3775a1f4591bf54", + "8503ebe843d6428183a340652e5c03b1", + "8a9e2cf246194041b8cd98e8078df9ce", + "cd6ad265b50f49a7921cdb3277526438", + "696205b5d3f847ffb3c3352c00b0de62", + "f8e13d5694464e8581907dde27bb59c8", + "a5b1cad68a0e45399af7071e9abcf6ec", + "dbfb6e3ca44c4e8f928bd0a478658cf3", + "eadd489814f348548828fab5824b8164", + "322a01d12e394711a54da11c1be15a08", + "2d70701c21944c66bf00f8e417487c99", + "1e36404f0b4b4f8eaa4e590c7f384d00", + "113196784ce242ee919f82a965d454b8", + "0b70368b44fe4e89b906f0d7eb55e0b6", + "faeab5ae48db457abc390b65f793e961", + "6fb6b24aaf744578bf16d20627a48958", + "290b9e48cad843639bda09239193e59f", + "c8c8fbb19f2b4b409ea13ee6604f5741", + "1154bef203ce4b499d7c94d1cd5e4460", + "8b220d579ee64c728d521b5da0eebbd5", + "13cc84fffef1437ba59f26902dc99483", + "ae3c6438718d43699c8cd9817740b0ca", + "a2216a321d7a4946a48e49c1e0b6834d", + "8778de212ae44c72a435a6dc2792a388", + "db9ef815f9c34c769896b76147142cbb", + "237e27d8325c48968009d0a704e730c5", + "a01b7fc797654102a84e3e17ae01c057", + "ac48a0b2efb543d39f1cd673beb020df", + "3a9f6b8c57c34f7f8c7af20835a4a3e8", + "51bf8a73694141c99b801d64f5b2960a", + "f951875f7108400ca887697a6fad1857", + "c19f127200aa41148fa97adfdb658387", + "53cb2fcf6bc64a1cbd04a0c592cdfdfd", + "ff2d841d2f15424689a851c17d452efc", + "69d125d7523247c58fc785575341b79d", + "2809f1b0b75847a889b9d74c3a28ddda", + "1a4346bd2d234f3d825faa17ad9f019f", + "0ba40952f59949628ff65f19025439b4", + "e97f99c0216a4cae9a8b11d044d2694a", + "ee37f9d93947429a93bba2b8ec9d693c", + "7ded3df1804a4b998b69224961b3fc8a", + "deb570767fda4f24a6700f9106a616ae", + "73860325145a47e09d473d8e7d2f99d6", + "8a7e221fcc434c2e8013a6466878a59b", + "8aa52ebaec02485dbad616338cebdf5a", + "60296c3a2aec4d1b8efcfdb74e8b1510", + "567bd57a32f74c008f595d2f62469bb5", + "1520e6bc869b4c0aa6c7f718573338ba", + "3efcb43ee0de4232aef63b7411c8de95", + "b74ba902e1de48d4b0625c3bbb0cfeb3", + "c4aae071cc2543eeb98bcf1a76be40e4", + "2cdb30045bf84c3a82c4defe2bbcc516", + "bf4b47324d154da5a9fca6808222d08b", + "00daf5abf6d44db9a310b8264ad0e834", + "628e979ee3bf4dfcaf470bc96f6a9397", + "30fbfe60174b4748a212bd4f3e5aed68", + "f1526584726d4e87a735d9732c227a74", + "f05ac10c730a47688f6c4a205aa8332a", + "00dc312921254846a2b4c71b83d02b08", + "078da6e1f86c4d2ca874e3f4381becb8", + "dab7b5e6d601462cb0dec4fb6612b031", + "4593753c66774b0a9f6db4c1535a731f", + "24ecc294123d49cf8634d25bdf9b4e6d", + "83c1c5713b0544a59534ba337badb430", + "19040f5410d545ef822776318878092d", + "60c209ce9c25446dbdb0e880dbf51de2", + "70c38d63785a4dc8a9f9a68aa30ab9ec", + "f15fa341534e489494140dda183a35f1", + "422d16255d984803848e489f3782cacb", + "5dc4ca7d607c495bb82eca3d0153cc2c", + "e542ab7c0c8a4a38a1f8d03df94f0fe0", + "b752a7d173eb4f2e89bec0b100aaa20f", + "96e4033e6ec64c1b826f9180a34af241", + "3a39afc98c3940f1923d59130512be0c", + "37619e03e9564143aaf5990a3a76b80b", + "db1a56f564ec4c2bb20b64e46abeff55", + "7dbd780b41b14dbab86f0912cc43cc55", + "c03374626b32491188a8c9e6a6ac87f0", + "f3f38e2541e34e73a061af13eb55382f", + "c4560059b71e4db1aca2facc2070b927", + "f5d250b76c8e4e3488587963900cbf2f", + "e819525af9fa4dc0b8238cd740f416b3", + "f33aac2e6b16471da17f5eb83f563c70", + "5dc8cc11062c4ce59b8e93eb24a11cf9", + "190ef7bc700047668cde6811f243d199", + "818d8f4773844a40bdf43379de718f6a", + "6a06f52061d84ff9951ee57c7c5332be", + "856b8c895af94fed89e9aff4e38bc8ac", + "17ab033a40b746358a46eb4fea2b1f0a", + "79bb384f2ed545a5ae8c2b9cfa06cd8f", + "e5b87592abee448cb7dfdee5cdb58946", + "ba4d88d496dd4bb7bd462be92a1d5fca", + "628be966e8d34542b774fc85496970fc", + "a74d7f9d98cf4ebfa6cb2302c46af02d", + "61fb8d4e16a54a85a8532073d5ffa364", + "ff7968dab663482881dc7fcc9d2ab10e", + "e5e89402f5874424ad5962d2b224992a", + "a7c0842af3e54c9eb385a71d71e93660", + "a73996cc8d074da691dfd71240b1346b", + "a7c13bd6d44741819530c699e1ff797c", + "e2c3a1bea177411dad535ccf3ddc2cf0", + "59c85ab9efec436fb017b4c7805f9770", + "cdd9a3e7c19f4e23b9a0634a72905ed8", + "1e9229885c034f549ee504da105dd993", + "1649285efb7342da91cf7de40a7b82b8", + "0852d07c58fa4c56aa2277e606ee996c", + "543ed80ae51b477dae9aae3bc94fdc20", + "3b30117fa5704683b71f88fee54004dc", + "ca725657da624228b3f0c483dd4fba9d", + "fcab4a86262340a4ab7a3d9ea0585f85", + "af04261ebaf044a38879a1af439ea3c3", + "44795759d6144f61990796c02088665f", + "ea5f0b7f149b462d93432daa040fe185", + "9db7111830fe469bbcbe8d3fb356c7e4", + "e5b438dac9454b1baa31c7b035a00126", + "f120ad6424e84ff3b962d40ee1be0844", + "10fcf145c71b460cb90473981ffb8ec7", + "10641177b18c412198371ecd25b997e2", + "12397c70ee9a40bebeaba9de95137696", + "f55671ec28d74e28b5f28e9fd906d8c8", + "1cc9dbf0c5c84a6d8d75465c21411cc6", + "9cb7aaa94c41468ebea6faa179a3840a", + "f8ae73f41a6f40259d9d811f525ee745", + "9afbb678842c4b968b8f6743460df926", + "3ef3afe527ba42d48f99c11531b4d0b5", + "eb235738a0aa448f84c581a13341ceee", + "5b1925d5e4a144e4814acfe80bf6e9e7", + "73e610a8c4ad4f649b78b47c7c456daa", + "b4de5710007e4f4ea4ee04b15380a150", + "8a5b92a5cd9b48f9b3c471b81567423c", + "27cf6b4dae68429da0a30d305a2953cb", + "f1ae551106df44a0a27766e0787254b8", + "6f7d7154ae0442a3b32d8fa694fc7838", + "3781314af1954867a5eb2bca6c18a955", + "cc812eaa7c9f4e81929d6697a03b22de", + "973e59c18bc647669f7f8af470b67b2e", + "f1ddf7c1a91a46fa8630c091faa33dfa", + "1b10b96e94634a7aa50783c4a99b8805", + "599521760e8646cc93585eb501f9ec5e", + "11d0a20b961f4195a44d4b0f150da4ea", + "5ac257aee23e47e0a0f91a4e07a40692", + "a0b237057d0045e0951435af3113b01e", + "1135c1a68c7a4ce9a547aec182823f9c", + "118e60a3091a4cc6b2e63bda5dc7913d", + "3407f35303ea44d8bd0b89187ec5077b", + "0e9ba282f7cd4537b694e01f40acd72e", + "4bde08ecf8c34561acd7d0ff0bd71376", + "d2f357ebff69495da27f68b9d449dfa6", + "a69e339b48f14a12a4d2a57a09708de2", + "afde31c8625943fb850f2da17f63b5b7", + "857e60a63bd24c73830d8e7b68ed216a", + "adb4cfcf2709495ca08d79b7c44f3ee9", + "1f6844f5392f406483e4dbf36bb1ba67", + "126ec2dfb13b49bd9109c9bc61871484", + "7ea41e28383245aca626b100d7f6f53c", + "933fdfca5aa749d19b0750dc08bb0592", + "d970d484b89b4c4f983684ad20147177", + "fb71a2fdd45342a88877f894d9919fdf", + "cd23bd60bdf14fd7a0de52044b147c59", + "511d44e5693549ca9c4002752a35fcb2", + "e04a06b040824252b21d1c8de49526d0", + "ea5691e7b2cb46c6b36c1fd4439eea3a", + "f1de76cbacce4583a7268c7f1b39c6ef", + "5dd49a59d3e146f8aabaceb76d3ba206", + "3f49d205292a4f33af0e9398d7fc72e9", + "0c72802aa7234741a3b8ff6b6c7ec20e", + "c14501f6adf345e8a7e3ba22d485d4f6", + "3f829fe16712442ba627d3c7e0801437", + "7b728da935a34c3c979a91e6b1c70a31", + "a55ab7c0c1ca4490ac674b9556129229", + "e34fd707532d4f55a798b9b3edc7c463", + "b2eee1449a214d209d4214a2079d12ba", + "e7701b3b91d340d6a3ac96e66cbe86aa", + "33ec066dd147462494ff1ab544bcc469", + "b30087d53f0f4cc4901014f4dc37bbe6", + "0fa6d0427b664cff884389b212d17302", + "8fc455e0e4a24d2a950fced068eb4efe", + "bc5b61d68ae04ba59ffc2cfce32b8a32", + "ebd3122affd3484889f5398f5a95d5d3", + "c1a4cf9e445045f3a512f676a49152ac", + "d27ffa45966949ec96c11b46235dc326", + "4c93bb0d4c34489984dcc7a72135f826", + "8c26e4c5d62c4354b44898c19f4bfff8", + "84c402789645463eacb8fbb081f0bb67", + "b3e2849806fb45fdaa50ed1d01a34ade", + "6fdbf160d2ee4e058da7b16d4443f33c", + "554f792c26b04058aef4ad7c7d7171be", + "fc7456ee37154e00ae4898e680781458", + "2225dea84eb4484fb001da955b2f0230", + "08dc1e1369b44f3ca45cc116c4a53bb7", + "f5ca6eff8f6741dfa44de5cda5fca188", + "2d58313d0a964d04a7724040dad750ce", + "2bb7b5a4da8548d896105bc238047550", + "83ecd3a305104235877d2ca1bae5c135", + "c1987ac31310458794ffabcbd8bc7a49", + "0b9c794a76f641f9a0338d1fab12af78", + "61a607fa847e45b8bfea58546c52971f", + "114b1d8e355b44c5bdf01f684bd8afa7", + "ff2875fb1a5b4771805a5fd35c8fe7bb", + "e5c50afa83604537babdec3198322fd7", + "b3485341f15240279c180685f0e2cb86", + "7ed892d894134524b94086589f5a0ee4", + "e5750324d6744be4a38ca11e8c4d9d6f", + "6ccb03f85f284aabb7d89de7eaabe76b", + "37c627ea328849eda0179a0f9dc7ef0d", + "978f0d98d6474618a4f9047d6d9fd377", + "615073dcc0cc4ba2b5c64366c8089e91", + "37bd9212d2a84a7684acaedbe8d0e66b", + "6f799e5d14dd4ca28976c79e40b53fd6", + "5b5f480b3bbe4988928a3c3e64c72b22", + "a93c7f27e5e0488b9584b58b6dc339fc", + "04eebb0543df40bda1034ddefe0047f8", + "f8ba7580d1954e1199b0b844f852401a", + "5d51a5e31ee84792a18046a2a8df8bdd", + "21b2515fe210423fb9191b4f9d7bfc95", + "d0f1f586eb8c4abe87e35273913f3d97", + "dbda1db89136468595f9597480638d34", + "3d0f9198c9e64d77896bb0cd4a2bd87c", + "c45144af966a44c4b242b1e2fdbfdb29", + "088fe6f815854b78a1b3998cf04b1583", + "4fcb68277d4a41b7ae430d453e817ea9", + "68ed35e49041474d80fb1b2d087b5d70", + "96985644dbce4045b0fc8636a9874bde", + "0fe6037175b94d25ae0b8068b0cdf854", + "8a4d1935aa7d43938bce60e832c1a774", + "10511f3cb3f940b695c197dbde6efb0c", + "3f7a12c2df124bdd9bc8546a3675981b", + "a30c874a645749108423449283c0ff2c", + "121b97a4aea44a5cbb47e99670c58466", + "5f217528cc1947919479d4551021394d", + "417e80d50f4c4cb7a153d6ea593de9ee", + "07b497a29bc3435ba2dd559eb68d345a", + "250a3008c8454eee8e4f8dfdcf446795", + "4fe2230f28e74b349fd8b79b52b38282", + "63ed81a563604a9a887ac51ae0514305", + "c5c009d8f7e6473c8eea32cbf5bab14e", + "35b7cb7698374921b336a0d3905178ad", + "9d5cb1b4fc2a4c61b4bc14eb92b7dbf2", + "34368742f07c48a8bc2404f7feef2fd3", + "d8e66dc4a2934d0887782fb1d4fe9e3f", + "b2e70e0d8d8b4224b407da650cbd10eb", + "2d92be54d86b4e6295a6b2234f184830", + "f04ea10301984e2eadee7c8456a54405", + "abc7705b46bd4e9fa7a245ea15f9d89a", + "d1c58f083f5a4ee0b40560390cea1439", + "444d3219776b4e5e8ae2b73a15090012", + "e30f830ab3174b30a142bf37f13670ee", + "d5a3eaf9d9f24288a977bdea97b160ba", + "01b31c7fb7bd41ac8019ffc994b22b60", + "043dc9a9464a4a09b6b1384777022a2d", + "0f1e001321bc485da2aa4a3f9879ca47", + "89591a21a3ad499f9178247b1ea78484", + "2721e946c7ac4ba2b1eb65aa99e2f77d", + "a8dee5818ceb406ea75513a0c4b6b7a0", + "fadf9b71585446309544fa2701502627", + "d883ae7653a7403baf3e14bde0deab24", + "57112c7318a8485f91946803429cdc14", + "2a77a1c27b604f038138e16116091ae7", + "0c03c040f08d49d9b401e29937439bb9", + "1175441e0d6c4b71a1c066916c8cb63b", + "2ed069355ea24bf0a995a978d56c5622", + "22a8386b5dbf49cf92c7300ede770aea", + "a77b3f8fe48e44c695748adba881d321", + "5ba4724327a1410e9d793e9bab34e1d7", + "42133f7fcc394ab89bb71584a946c6ae", + "3019fe19701b44f18f6c49603b4b89f9", + "2b7882c2408a46fb84f9a040edecb66c", + "a41505485d56456584028a04ebed46c6", + "766ce7819fef4e96b74795e9b23a4453", + "bd0f8d2bfba24376bec2b827a0cbbabe", + "37e0ae874e604a58997d16df6070c0d3", + "952d69c41f4f4c01aee134766b12d4bd", + "02ecfd300c2745318952bec016c84946", + "e126b0076a824c6ba63e4e4e8150f04f", + "a912b548d6054ffb8d2b4d8ed46f7d81", + "1c3f0e7bd38842558e7f96cda66f3932", + "928428f75c764eaa93017161aa6900f2", + "56eb5e56981f47f2a7ab4681c6636055", + "8939b47916ab4b2486a3fa2613eac54c", + "fc7dcd48bbce43c2b0b458a7beaec12d", + "fedc520b63c0422eace2b10bb39fec10", + "74555a6eb72543cdb5bd71ce98bf21db", + "ce621108a98b48b6b5a97c1144252aaa", + "ee0074e0761e48b0979eae887c3375ea", + "eb9b8ab2aeb84c6eb87be2ad3501705a", + "5a8e355b192c4eeca377bf8bab997ddb", + "f7c4914e04404e1e85f1e5215131ad0a", + "c68c30014fc54888b3ba0eb17fa46414", + "526bba8c0f264a59a28e9e152c2836b8", + "f91b1f5033bd42cd86b1092761aba3b7", + "009d250efa144b93aa6615a94d8767c7", + "c40cff99ab3b43a8bb1c628e6a287b43", + "19f76a0df81747369acf46406b36afa6", + "f874bffa8e314743b4a7cb9ad4b9f3a8", + "18145bc088cd4c0a9674d6f1d64fb9d1", + "78d28f9edffe41c9bc9c7050dc2d3fbc", + "7e088f1294f74a6a81e86309884e1df3", + "e888fe74c2984cd4b79adf0cb7cffdb2", + "afd49ad1b1a945a3a495edddf97553cc", + "d8bffa8ee8664a8a955dbba29125b9bb", + "ce535f14407f4f1ca01111d23a3696d4", + "9e884e487bf94784aa1e058e5aeafe61", + "7ee9b111c5b14e00bd7438578ee49d87", + "fadc837c1f3946b6b87f5fdcc29c7357", + "7f7f192c09cb4e4a9fb60369d5544014", + "8716cb4b92bf44e4835ed1d6da73df8d", + "0b168196d835416d89d89302548273c1", + "f6b42b83687d4a809bff6269d49ec9fd", + "6791a4ce3cb44c7c88b5713b5298d908", + "d78ccbe406f744b881aa2c339fbd27ef", + "0dc7fac90de148f382dcd36d499656e0", + "0e1568f48f744f4ba716ded930926ddd", + "106bb8d8e8964d0e92164e2554888edb", + "b4d45f08264e413896dd9645c9d90bf6", + "a0989f487f0e46e28794a011fc060fec", + "e475de17f7034a9ca2fd41e6d198b7dc", + "eeb043ed9c724e6f8ea6693977043879", + "159cea36f78c459993943b44dbfb5339", + "8963ad4edfbc41429825c75b07b0581b", + "6bceb4eba0b243409325fd4f647547ed", + "195d245f8c9c410b916ff8bbf4b63ecd", + "cea67369ae50485c9f06ea44cb608b92", + "e0f26192e71f411ca90257c5c2fc1b54", + "a83e6d62037e49338a2c7bc2cbaad531", + "0c51d4f6f0e24e29875aeb3ff2d65587", + "b54b110dfccb4ea3a8f5a06cc65edc5a", + "f84c0131e6f94eb59e00967728c26d3a", + "ebfcbe8a80464f2aa65fb19c90070647", + "984c7af3900448d3be56d7a6bb0ba75c", + "e96369b768ab44a39ed0e629ad6f2622", + "68be5973b6444d0f99a87d183525f342", + "2c88306f3d724a839054f3c2913fb1d5", + "5645433aa729429f9b60aa33bb921bdd", + "3400dbebc55d4f198f383d09adeaf56c", + "f46755cce790463f81e4e7d7b1f756a9", + "2a42d9a558ce4924a57308165adaf07c", + "49bc15ef22244c799d37f61f8c45f68c", + "257e82462ab44076a4da572ce8f9f3e5", + "a71c9c05480a4979ad246fb3e2a026e0", + "b5eb81d84b8943f8a7ef59b6ae312caa", + "1844319d768f4d62a25eb33babea5903", + "53c4339341eb4e40a3fc3872f0842479", + "6fcd293587514335801f845819956302", + "32960b17b51e4d488f9d2f68dd06fe45", + "1f7f03384deb436193ebae0e9adde2e2", + "11672af57b8c4aaf9f49193a6134dc52", + "28f7c0b0363f4502aa4184c4750a3e9a", + "bcf29e831ea64df49ede43a54b4889cc", + "ded99d102385494991b79663ee3d3082", + "e1d0173f94b841919b1d5fb6b0409abc", + "34a65735a898465ca5c8e930391cf0a5", + "341f059cde9c4486b4dc2d1905651f95", + "5713fc403f4f4899bbc10e8e3d0e9185", + "01314ed0460f4ae38e9652a01597e4e7", + "efaf89790d4f42debdd055595e4c1e39", + "4c656b98557f433499726238dfa8eaa5", + "7798228aad9b4500875eda3c4cf26b0c", + "0c59d74e69fe4ebdbbf6747db1b2afa4", + "565dad22fecb484296b678972858d394", + "442804060ef94473acd034d8f446cfda", + "0045c7d3543f467e808af1320f7fe252", + "f01d7c975b1e4bafbff39729a9eb23c3", + "7ac42c966c1343efa2e8b1012c2f4c71", + "968b58a99183496bb02d6757b209c2a6", + "9a66091543a44877a03016d8f472937c", + "c5a3609b970b4924acd102377b8ccb69", + "9ccf2fce68ea45e0b0861038d5aa035d", + "8c0870643b8b494087ac3c06799cf0bc", + "c36f2d41b28d4ba1860dc6621d0869f8", + "ed7707e79b774052845f90d12f44a729", + "3752f45780dc4b9c87ac541a334e1351", + "eddf3122062d4215b83cdd59fd1be4d3", + "40949184dcbc4d5cba5f115b1c0dcf6f", + "6261c100f0774941b5e6103e778d6c45", + "02452dd650774e8899a9c637973250e8", + "49ef953306874e7b9ebecb64093f09b6", + "36acd5413d90461c988c58d3454e2c05", + "7fb4d851580942f380df59b26e905942", + "e5bbfa708fce411fb6ffbd18d50c971f", + "4156ba0320ab4510b7416b7b019f0ba9", + "892ac0e281324005a32ad87adf78fc2d", + "5705d0adde414506866885157b95e753", + "979b7dec28df4db0b493054afbfbad1c", + "0dbdbc5f973949c0a5e0ae89381e930e", + "a2a074cabf7049869e7e6d4fcfb66b1a", + "4ade55cb29194bf48338cf12ca03a457", + "2ce197fe22c5404f8674aab5a6cb410b", + "ed2005ee49e7419e9c91cfe1d1c45dc8", + "3fc3c4911f0d4b539b0530d0bea340af", + "309600e4f0094a0b97f9c09075704651", + "a74451f3850e42e3b87cbfc08c680e19", + "4525f2a0ef7e4c66b6b2976e14d911ff", + "f09ddded553c4909bc2294b7f340b230", + "f4dd79b07b9c4754ad3d95a52224470b", + "a5c6f4dff8e848b288115bca839c3780", + "d0fa8e4755184155bd063dd17ab33f0d", + "6bafea3c607848f78a42239755eac8ee", + "35d9d3dceb9a4292ada2a7dfbf5dcd76", + "4ac179c3447f4636a273d8574a61a1c5", + "e20c75d76db347d993ab8876c1fddd49", + "aaa4533d27f04efda064a9724f8ad706", + "a022864ae7b642a39469652c3eda2b9a", + "f0b4a0131f784059b0b339d2911478f3", + "80e2599b07714d7c93f68a048c07c4e3", + "81669910c0b74f41a3a58febfd514794", + "f936446a26e346ac95eb79c6d7560f1b", + "1c548a57e4634340886943b76c7446ba", + "c0856d7c6c104b9397d9644c9b29c132", + "31c25f7042c340f5985333c405fde9a0", + "2aacb306a9d6488bb68fea6a1320a5c6", + "9241361a5ce14498ada7eb128b1f38ea", + "f64baa008b98490cba53e9e14efd4f66", + "186c3d0657a44e2ca04ea9544c453437", + "dccd0d629d704cc2bde905572b0947da", + "c5d23e21daef4fc2a62704149f5f9af6", + "8aab8c92b8954d2689dc76f60f2dff5b", + "4a51a6ec5c5046c0bac543dde6adeb51", + "ea16c46502394e9b8959aa146e77fe5a", + "61d5ca146e4443f2afe64774a63bc9fa", + "41428760d903437eacf2b4c73de73c75", + "8fe6ee86ddf4460c879e6214e5ea3c42", + "7d7e5a47f4fd40c5b102903cbb1abf3f", + "8cb2dd87795f4316b43aae17c3748137", + "a33244faa08a4cacaf4a2750b1307e57", + "1230444ce2e149f4a76061ab1010f56e", + "22b315a4ea9e493bb2665e0a34d7ab54", + "3765460b38944107acd180d9efa3fd76", + "734b921c454c477bb20f3e3b37ac869c", + "db761226ef2b41b5b6dbdae5a80e715b", + "04a577d2a06849a798368b1653a7fbd4", + "9c71ca5325014ebcb70abe80bbaf0492", + "23e952d905ca4bc788517afd9086edd7", + "faea9af25c584e8aa893b65103c16601", + "7e3668fb13f743a8a3a07b9eb8939e49", + "58a93d40f16e474fbc81df08198230cf", + "43221ead48364d41977ee4e7ebbfcc04", + "2ace352d9dfb41549f265eb69a537622", + "152647e7208e4da0a04b3508699cd2a8", + "30e40711b548419c97934965f7c7213c", + "cd55004dcab14b32b702c197213b297a", + "a3d2b678685248bebee00eb247a3dbfa", + "75b0f01544b0423aa998b09aba7d6448", + "a9bb1e020da64fff8f1f6ccc3266f4f2", + "7518349655634fbfbeab3a342f73dc38", + "ddc654718e4449f6a19c4775d6295350", + "fe4390b1fc444f74951b421e250b6fe2", + "80270537268f472fadf3b589245f40ff", + "c5604d5c4f864330b6d171866ea931e2", + "34d5787f909848d088baf1377fb1dc46", + "e76e3457253747318ba49f84645196a2", + "6bb74c3de8ac476ca5852236a5e04094", + "5e384da966574a9a9a337d413dd37b9a", + "12dcadaa50d64f15b64a6a5342beedb1", + "88fa74f76e6b4e389016fcef513aa9fe", + "87350c7e444549eb9f612a1aeff11a3e", + "dd35db1524bb456f92f08c26145d906f", + "44962bf5f51242a790551dc6ba423ef1", + "66b4fe511ade44a8886232f07608358c", + "fa80b79d252740b4a2d1d3dfa915c515", + "91a2a7611a5346029cd4e1efcc78db68", + "de4ecf2c5040488ab98d214a0d9362cc", + "03ba684b8bad4fffa1a8cc2da2c2c59f", + "9e4ab3769d7248fe8aa7594f4f7c0a5c", + "2af91001df87495bb812de029e53bf42", + "1e5454d0a0754b1a9032b44636e9a81b", + "15e1a5ff460d4f1ab090409239a47f4d", + "b7d390377cc54884b5e2ab40982c90a6", + "dfb3cdf1690a4c5a895b3243cd395107", + "56fddf35a2e2428197e3a8d4860ec7b5", + "6a8ee729cbe84c99a4cb96b25ad8d3f3", + "0ec03fdacb62498c83cf4f644ef1a253", + "8755f46074ba46d2b21dba17550c290d", + "4f30d3e65c45487abfa438c0368ce602", + "b6c70426be144507811705f9bf18c3ed", + "ff43c4b829644fda8822026e9a96b1a0", + "94c9f48d451940ebb3eaec1c249c5ea6", + "636d1bfc3a894e31ab100bfe35c55759", + "ae81a6d59b73468b81003f355518e573", + "390a5b07105842b78351c8cf94c854c3", + "768da275f1574b36aeac4ff3b0af9a55", + "301988318d07467782ac2d8f4d81e5fa", + "54bae8ffc884422498c87c511bbb89e0", + "b56da3df5deb4a08b3f9519be1971085", + "0f24d1ea66334d89bfe2125fb3d22f24", + "5d3d861e381a408998276c95e655a4b4", + "9c8f15cc1584410f8d77b069e5098b01", + "2f97688375ff49179223195c2b5032ac", + "ea94a300fbb149b3a8112a2a334f7f0b", + "520ba807f97a48e3bebedeb7f44e9bde", + "59f4db25c1b447f18fddf3241b5e61e5", + "9436bb54d0174212b16faa3ee4f10bcb", + "f6366216877541a3b25541377e4b496b", + "727fbedf464448c2ae648bc2ac268e29", + "ef22142bf6e94939bffd7fe74ca23184", + "d5816da876f14df89d4b5f0f65d19a55", + "0521d3ab35144e35a8c98515ce4f53f3", + "70c5fe31e48743e5b36d739d6789ce2c", + "cac1d5ce87994f63a24090812bdb6281", + "6ebab275b9574faeb8dfcc7d523a973e", + "a27ef45bf8a143d2b71b863d9a379b98", + "dd0d65a5c6f643a2af2e930c640d45f4", + "4befc0f57d414a76ba7a827f709a9f51", + "5ef5c68f05774d3e90fc66009122ba65", + "d2eb59f553974d8a9dfe7a37b785fd73", + "9562226299a045bab13c3d66f8593208", + "1878341a4ac34cb49896188da4169c95", + "4b2427e240764a8b9db635d7e14ddf43", + "d3a23ab28eb0453abf56e4d61f5dcb3b", + "1d11eee328c146e48eeb3e76630b6724", + "f43a41ce46fc4f4da95070cb765fa876", + "68ccf40fcf0848ae8317e61187090206", + "c3a81a5f13274874b776761c6e64716e", + "a09908a3910f4110a835f15e0f774da4", + "bf630047daae421daa375d1d92858e88", + "87b1622a80d64141a11721f1967f4c0a", + "702a423803444db59d4396c04f141347", + "17c796aeb1b8455d8f594a72490e11b7", + "e4673fcfd4764b8084465d65fb954980", + "49cda99f837146ab94f2fca1ea5cb198", + "4cb0c6db596a4d22a8c8d8778e3b8fd5", + "3e3fb2880a184a418dfa62581d07e12d", + "e7a2631478084e1485189e3b6659c132", + "017eaa0c64f749dfbf60e16c67ebd421", + "738ddfc31cd94e86b1e3fafe30dc6f84", + "e50773b1d03f49bea7da90f45fa5523b", + "53d27b83494f45a0b997029b65a6bf06", + "1c58319825d34790b9723ea18e48bebc", + "74984cf6e4fc4e9bbd52cd226bc0dd8c", + "94bba75bfd444c30ad6fac9d42887b6b", + "3e1b1c9e433643f6814c48e3f07caa63", + "72735d454bde4e06864a0ae819613584", + "714f271c306942f98431376a69de6e35", + "fbaab2ba11bc40d18132d94e56675e17", + "408fb7a0597f47ad957db91d1821da90", + "5913807043744e2782fc841d52ae6e7b", + "b4a8d2cc8187486892e6016d2cb9b600", + "98d4960bcf66471eb4b65b92f8137a53", + "a4e2cd64e3244512a85e6753307570cb", + "22ce6b6e9a9041a4ba7ebd9f8e30d063", + "ae6589db12fc48f78081a1c054354888", + "16c43e9c3334470eba73f5f08cda2686", + "48ed8e2cc02d4c8cba8832656fa874a2", + "e5e0f42aec4846a0bff905d0601fdd1e", + "ce28811d5c174f34b966b4fae3d2f5b6", + "91850c2da31641b6b38dbed98f116728", + "4698bc37e2094d69aab4ffb6d9d950b3", + "629e75fec89b4673a6dd676f46523882", + "b91b01a817f742fd816785a64785c525", + "0a5652c16e1a4575903dfc1696382502", + "37a029f9ea184950a62b309f62ab6476", + "5706ba1c08a74968aee1eb8f038109b6", + "a04dd59a7f1e4f02b5f0a02eb7e79616", + "7f7513f97c30462f9e0a511e0cd6882b", + "1e66110d80f049efa4f76f010417b853", + "aa773fe89c9b4067b7f3f9c29554e1dc", + "93404d54377a4049b08aa7aaa1522550", + "2087c1ce992e419f898ae1185162f5ff", + "a3a9543899bb4415b127b73b58e8da83", + "27e59017519e419ea8f5bd048db5b452", + "e02d2faa8f6a46a28e2bb4cad493f81e", + "5633ff2f729142bebf6b304118647f6f", + "07ab113a3849450e81221c44d3a36af0", + "9bce0daea34d47699777f50d71c6ec08", + "7ede9c8eca704635a6649eeb53a6044a", + "abe09cf8812a414b8a790a5e97920196", + "0d75351c6d8e42d2bd77f449c3e99b5d", + "30f383a4c61d4ddfb6035c931f6639c6", + "92a4f12f7590492eb70780aad495202c", + "cf09ce0755614429a382551bea5960ae", + "e3c93868c50e4f189958ea5f28767307", + "0fd1d0546f8e422b97a4fd5cfe959d2e", + "ce105cabdcd54cc1826494ce2fb6514e", + "11a322a4ca49429f8991d0bb8d5633f1", + "d09c31ba28994f1d953362fceb3df226", + "73e092e4ce344683b1347521e28d5df6", + "f7ab52c4629740489294c89557d8c52a", + "cfe4fe307d0d4909b69ae838d6d184d1", + "eb8fba8db0d34e0d8ed56dbdb34401e8", + "2e4699ab8f2c4c7183cca4cdbeacd187", + "362c9505cb314460815e88708aa906d2", + "ea1b9673f09b4d809c90ab48b1eceb50", + "b1155b5ebd7c478bb0d35747c2211e5f", + "f706fa6a3b54449297a7ba757bee0071", + "c40081238c7645009a1a883803eba786", + "f06790df90734b79a182e378ae602b55", + "c78a944eef3d427c80d47153e6f8b220", + "29d362e1972449e48851e4934b9b4423", + "436adfa552e2473390d47b6a2dfeb294", + "67ab02496a534b00b745398aa3b0c941", + "c931e2457d4c46598c3bbdde5efd0d10", + "3e09d59a091c452eb4eae299b0ce36a4", + "fbf1464ad39a4cffbd2b24c4e6d96aa6", + "d8c6ce395b3d4e95af8957dcf084f368", + "dca771ce34eb4d21879a489eca6c4882", + "137107a9a148431ea6bd255a5a5a4cd2", + "c1e69b274b9d4b05bcc2761993e3c554", + "f1d32469c10e42b7bab652d5383291b5", + "d2ce6fbb66674acf94ee2d907aac352a", + "5865959f730c4a9781aeb853b1db4861", + "b756483d57ca4b1ab0c3eb84ead1e075", + "a7a331aca0874096a2b44953270b4d9d", + "55d93e7b82f54549a54b9f01d61cdcfd", + "682324ddfeca402db477da3bf90276cc", + "ff4c8308932447ac9ac831155fb63992", + "13c8a69f19d04c47bae48a083b748103", + "5639713fea7b414e8df9180f78ee07b8", + "ad49496e5f5443e38665049c8b0b4ea7", + "080aa16c29ed4ddfb6da3c4ae2538a58", + "30a177eb777a48659f2eb4ea70375d29", + "12a8e9f12304431889485112123c5ce2", + "f02ae933ce934f87927b4f7001e4b4f9", + "584a486f880144f6a0485b5863fed885", + "e4785419f10045e8805c3cecae763048", + "e3c85f95cfea4e9bab4412a9cec6da61", + "42ac3d271a3a47da829a86239227560f", + "bedd61104d3b458b93fe2c78874ae8e0", + "c6c70861cfc84a2ba366b4bb5cc58aff", + "a7b2ca1de7f14b91b15e0b8a331955be", + "f3bae65f598f41d48fc2d27aaa7f3d05", + "0009a51366fb45e2876715bde6a574b7", + "080bd350828d435896af81d268785173", + "25f51b2ed59a4b0ba72224449133253f", + "46c8760116a342c69eddbe1c0c028b60", + "28ac5a4e0fce4d94a1a84a77139a74d5", + "7fd225adfc794cbc9dac1fe6b53e7cc7", + "1b34de1b8208495abb37b4b629c1f8a3", + "9154d84ffd47416082c119f5866035ec", + "3c3ec4a1c6034e07b419e3f529960ffd", + "37ae05c23fe34e3199ee6d2175fbe23f", + "95a30d3c00ac4d41a9a510013c3318d1", + "e937afc06a1643f3bac57da9aec9e308", + "4436f000d53544fda0579470a0e4cbe3", + "f76c502218884914a27148f656a9b656", + "97038d6aa2cd4a7782e6dac2c408b5b5", + "ca732007c5f740a881121c29ab8ba34b", + "a84cecb600c04eeba60d02f99b8b154b", + "a9e61b00b8534077a904d833514a2f26", + "37d8b9c7e2a24c56b58c0fa0e32fb170", + "b4c54c0469904512b14e3d9b8712fe1c", + "d9cab5cb94c24e169d59da6a92866b05", + "067d636263844d32ac4c8fc902f061d6", + "f03e5ba5e81b4562958645fe27565f3a", + "d4f466de30954aec87d5c629e45163c6", + "accbdcc76d0b410cbbbd616ae816f864", + "9ae4ab975f8942cd94a15a6880915b41", + "8aee8c79afe042018e4eda67403d12a9", + "c0b8074f7b154df2901144a2949acdc3", + "42bc88cd0262461ab28d3ebcb72e80fd", + "ef94916c83e441d483e6e3b9647d274b", + "5fea50aad8544532bbf50107505aa709", + "a6ca57363110496cae1826dc7f97992f", + "ac46c4d4d79740d7ad6c907ca3fddd46", + "76c068d30f0b463bb800c0beaf792a4d", + "f6f3af46a30542139cbf23b2efee5439", + "b12a7fb702804cc19537047a033fe0d9", + "cfad2e0388d248ccad1480ce784801f4", + "18e452ded8dd412d8b2002d7ad7f9b94", + "a5eea808dc20404cb5f9e05680f7362f", + "993befe23ec340ad8a58e01388f8beb4", + "3acec9687c754522b7de659802e20642", + "e709ff43041347c8ac9e2cc9bddc443b", + "0c8ddff67c5e4af3a3ae39547774054d", + "e573304fce364cf299027494fc1afede", + "71be9d781c394827a712dce0a9f9b816", + "4c19ea76c6fa4dc3994a0d2564af6228", + "a2b2fe2fd52f4a3b9830d3a54cd99463", + "e4e6232f2eca4904851236f3a9e8c3eb", + "7fddf5d339734983be77c4730fd0d826", + "a8099f18c8a648fcae7dfb4797630975", + "dd37f37004c44be0a9fc8da2c9d90e02", + "e82d5757ff7c431e8ab103278d4afce6", + "c3cc5a3e1b5f47cbaf841aee7125b759", + "91c0f9e543f04206b74bbfe1b2b312f1", + "5a4677f178764b0388de833ce4b501a0", + "f6494a408d4148039d861e106986dd68", + "0d64fffae0ec470787bb9f009e473d80", + "96fe8cd088bb493c8c62d318aee90aba", + "baf9545dfd08419e810922a348808836", + "67201464998a4c9185d2d67da808aabc", + "3b9e7e5b955d4c7cba9406cf70ebcee5", + "9f85c3d0b3e04f6786f64737ffefeec3", + "36a31490e20d49a9be66f90e26ed621f", + "0e23abfdf9cf472d99f204aeac552bf9", + "28cf19822d954753a9173ebc09f77cf3", + "5cc27537bf1f487daf64a192db80affb", + "780ee18030f34cb5ac2d37a5e3892fda", + "fd6eb6cff0a44166a4d57a7287182a41", + "97ee48d279f44cd4aaf3de85d57e91c0", + "f87d3692c8d14861b4b16a184aa9030d", + "71a4502e9a20423ba847bf6b073a07a1", + "874d6caf332f4afd9d9d30b43dde2de0", + "25baea74f1914aafb9ddef58d0106969", + "26b8716a29474e75a9de1790c96d6404", + "25fb43458b864c5d8a3e792e9cd218c6", + "056c4e7895834a4e8661c3e27b51583c", + "a8926f1e35e14f4d9978a5b01583b576", + "a039edc2c5624f7b873a533b170bc9bb", + "f92215936dcf4618a9d5d5ce86b7e2f4", + "5d7cd6e8dda0460c85f50a3c3a5127fd", + "e30dbfd4088e4967bf6551dab00135fe", + "31b862ca9d0e4e56902c641238fae396", + "ff7681eb896143b4bb77d8d182613192", + "8f5e43c3780844d1a991de153d0b54cf", + "a93db43f956f440b840b5c93708f0281", + "a42c42d9b3684b37946a45cd1a496b80", + "95223d14d66a445bb09083dc69f6f02f", + "4fc842ad2ae647fdb13bc2ab13897bec", + "95e90fcf35cc42fb86126bd7dc4ee769", + "83d6defd33734f2da2d81ddc036aa8df", + "94f1882c0dfd46369ed8e78ddabd590b", + "3df54f6f0d9a41ccbf9749ad50561d69", + "284542069dab46c6a1e90b43670cf5af", + "186fa0e5afbb421c9ebf1e18417f06d4", + "6fe90ba6752b41de950f23c445523d54", + "84ba3a534a4840c4a6e33e288093e042", + "fd336d24aa5945b9b640409b9a5a9701", + "efe2f361da924906bffd720777bbbf29", + "f183f7c392494ead9cae2654b6f1af8b", + "6ce0aef097014c00b153a4e7a8b1fb9e", + "ce612acd03664358a5841316e35e0db7", + "3b3e19800e76495b821da1deedb23db2", + "29ac53b1dc264b5bb82132f521a9f17f", + "eb0807309530496aaab9dcff67bf5c31", + "6b2501d710bc4487a2ba1c0b2baa4f83", + "4513f37e409642f085066f1470b09a25", + "87238b7b27a94332b0294c0f36443d53", + "b5612b4face04e0e9f6abe41b5990b28", + "5b8ee0242d4c4d97902d586801bd1ccd", + "c12de382488a4f93b7a7276af3a277dd", + "abcb70a7c51547429cbcb9c8930df941", + "aa7e5d9e2dad49ba8124faebeb8b9e4d", + "4b6e9edf168d4520b86e0738c09b3830", + "fca137cdd3ec4d52bb6686cefe867ccd", + "1cd3c2a963bc4839b5bbd653531fed8e", + "cef2bdfcc06044279e4ff364e5083b92", + "0a314c1c700f40f9a14aaad08bc59d96", + "33c91efcccf34c48a91a058c099d6831", + "99dd92ac95ef4775bbdad981fa6de64e", + "a17698c6c747416fa673c7a10e751262", + "8485da6530904916bdc99cef8d58f95c", + "c840b416bff544f3b7ffeab7723ca24d", + "af76e633cd8e40f1b1f4fb985e9194a5", + "b39c8663081c4c9e8c5e14dda1c67bd8", + "c11eb3d421af4a44baf13072fbfbdb21", + "8f57ec10b8ca4a16930bb55c15f46f60", + "ef967be111234c02bf67c9d6bc67fd16", + "85590b052efa4741897cd0ae4c021a8b", + "ca9304d779c144ad925f6e4ca3bfea69", + "bfc23635e6c94c71bb08f05c5d91c259", + "e348789bde904c2c87b99aae573637e4", + "fe03debc89a045f4a5cffe1974071347", + "4e8dec7f7e844a1e8661bedff3df4ee9", + "74cc2b0550d64e61aed0fab833ef407d", + "c84221e0bc74453f96c27c6440081f56", + "d21aad74be654d35a43b8859a43c0fee", + "13f300195c5b4abdb0c85a36e70243b1", + "7b62fa23c474424f8458087f7cbfc3ec", + "ade044fcded9437fb4a48f2bc817d423", + "a89fe2c852e943319904938586b4f5b7", + "a0a41bee2ff848ce811ecca47736466d", + "e109347a62674ef4bae6239f0662c10c", + "e458cf96b19e4b6fac25433e1808ac10", + "9e2db14911d7426290f6aa294d04fd45", + "76cd51452a734f209d52c259ff39d1e4", + "88d0d9b51c5049d6ab0a6eddb316c5ab", + "a03293cb4a80460bb30cbee9257215fb", + "fdfee5dcc8ed4b568bbb6b741520d49d", + "b23a20fac742454ca78ce80653b334a9", + "fdc6b2fd40974708a07f1717a433e7c1", + "f0a3a7fffa2f41ceabdfdc0b816fa662", + "ea59f85f57fe4303b68a69d1ef6793d1", + "378cd6e6f505493aa8e22f68db1cabec", + "5dc3b7ffa3c4479292f45cc39d667db4", + "3c782b0787cc41f1b5974dbd7a1f8f53", + "f510996f662447d597cfd9b891ec4710", + "cc82051d07cf4b86a8aa1d3982b54660", + "76651f9e8af5444897bb653ba28d7f2f", + "1625701880c54b7d9f50e77455cef39b", + "30afb0dd7d714f6bbbcd4acc891214da", + "9a3c796f1a1e4e6b989f5c8745d66468", + "20d4386b22d44ade878e5551c55d8565", + "d2306f0660464e47aa9c4de7977ad796", + "46b4a7dadd3147c0a842fbca38010daf", + "1eb719a00700459191208db7ca450f8b", + "7d34909efb9f45d08b9d680837e76b8f", + "94b5565d8bce4438ad3b2dfb6c7ec6d5", + "4eabbf7ab80e4db8910ece11c9fd853f", + "08be716d9cc94ca3998bc3b38d95cdd9", + "8701afc9445b4b2dacefcf3643382e98", + "874609938e5f40738af0d656b8103121", + "a239036217f7423185550713f0b28d92", + "79c72750261e4601a91995e4ca9490a4", + "b2664bc3168549b1b089c33be6729845", + "e8ee731acfb444a5ae087c74cce02158", + "40077b9f92c04ca8bff18ad8329494d8", + "4c108902e9e74577901046818773ffa5", + "3f5d969cbbf94946a2808c2ab3068030", + "f119a138add7447aafc27029d9594c81", + "1652032bbb3d478cbc009d84f7e31cb9", + "3020862e9f884a6eabe362553a76f575", + "205f661329c24881aa30a907bcbe2710", + "4645654b02934cce94dfb30a0c0a2ba9", + "2e203fb7a86d454888962687fa845212", + "df65e2b6c7b04354b3a6f9110b277e56", + "e6da54853e2a4141a9a82adf182e60bc", + "1509b394dcfa4451ba7ebdaf7fc7a808", + "0eabcd88d310476c96eb4cfeb3c7958c", + "8a1a2e0263aa401591c1e87d824a79ef", + "445b80747ea147eb92545bc881f2c0b7", + "e378199a307c4276898176f45156ab65", + "af09e849435a492f839af78e8b2d898f", + "7a77adbb12334e1388f6e1f7c79b91a7", + "3d8df6eadd6043b3bd0509eaa90cadee", + "12ff5e2036c44c6fb709abf49b2570ba", + "fa75eff7a67a460786c5ad7e8a55ce7a", + "9f10d6541f0142d091363abc4843d941", + "fb1554855d57463ba8f9563cdb2737f6", + "0612fbb3979e400aad5d99dd06305a59", + "63e67b020cd349e89c3a506a513c1108", + "6b6928f3094f41b38ab9941d0cc8f618", + "a0e2c49d17074e049c944296788b304c", + "6d443f619ecd404a81769c70f447ba86", + "e7925af708214cacbc776142e31e274d", + "52b004ca285a41f7b24d1a930f6dbc2d", + "af15ea524fb7465c9190b63b71e91270", + "ca72b9984e8c4866aac56ad39ea7340e", + "ef722e5e1e5e40a8a9e5d8141b37b5a2", + "e30be87935f94abea012be597f6c67a3", + "46bb9561bf23477aaad941e143a52803", + "f550f917394449578f5930a46512f169", + "77ce2991aa004df7906954f8d97715ff", + "bc52aa4d98744f999c1e1e5046addfe7", + "59a9055a9a294e7cb5f79e102606c181", + "9a729923591544f1bc22527a25d18f7a", + "df082139a9cc46c583089f21be6a3466", + "be6a5866f8584b08b17c8bc5d00b71f6", + "f45b8e762f434b0b9f2c76194b344a37", + "bd743321d7184ca6b2bfea874f2fb0e2", + "8243c74ac83b49359911be0ba24a1b7a", + "545d37a90a7d4c00b5e5bc551c71fbbf", + "7ea465a1489c4b12bb5a8ff33325cccb", + "46b76d98783a4bf1bb4f7dd2dd7ed2d2", + "0adf3ccbcbad4a389ced97079c4fa50c", + "cf05f52b5d364a00a7af3e94731055bf", + "c3a9503855bd46a4ba0c7ea3d918aff6", + "8058be93a9d14b35a2af0d8b218d650b", + "353425eaabde441b9b851f3514c8fdd7", + "57e2176e3b2b473db69c39a05b2ad732", + "f23e77a14d4a4b2eb885af2642897ffa", + "b65b3f90ac554033925f8b4a17c2a8f2", + "def38e744e744c6387ff4e29abfcfb81", + "0a1bf6660c91492487d12b712178df21", + "c557ddedd3ec4a2e9a0c0b993f371beb", + "56ab3ccae2c54a548bfce1244b840c2e", + "ae4982aad27e4ee5855d66d0ef3c46eb", + "d3f5e832769f45e39c8ffef1f17e73b8", + "5c0b2b8ade634237977a1db1ede5529d", + "8072bc11a64d4a909ea62a9dc5c10041", + "1a8a309a90c0441b92d078dd8435228c", + "8829df03139e49a6ab752bf82330b3ae", + "a3f7491d847a463fb1d6043239e37f25", + "b68d4393cfb9433e9fc926d5f7bb04e2", + "ea1ceda39b4d44c58b01745a105117eb", + "84a656c9a1d3402aaccd1b83289b7b25", + "f52aad2db25947c281a8913028e9da42", + "8b1ea56831524781a70b8426faaac334", + "4ad9b6a604754ddab28ad3021848efac", + "e6539a42c12a45488e196b14935cacf1", + "a002bdb64e9a40719857c653d1fcb2ad", + "50f3de6126ef465a965df8d5b050ac7c", + "b03bad58c5654898859abcbf3218520d", + "f6614af6bbad489584e9f66a6296f273", + "a71cefe9b7c746c1b2fef86e28c994bf", + "2cfd0923c01d461d9513f63464bcbaab", + "7f4bdf6adb164b7292bcd10dd14e4a72", + "f0bf366352f94f949576703019b1c202", + "041ea96fc6ae4839bf9ce16f8ea4ad68", + "6d7f3fdb005741979e11ef6e10bf7ea8", + "cf0c100d3ee44371ada969cfba5af34f", + "b5e15bb0ec0c4edd88ae18dfb95ba6c2", + "90f3ae1be712488991e6914d6e7bbe0c", + "454ed3d581ac4f929ff34022afa4c662", + "ad389b31a38847f7b786a5079d97782e", + "41e3cd8afb714ef78abb42a517c7f32c", + "051ac251929c4d7eb39a3372e554df1a", + "15129f0ea33147e8a738a00f28adbe8d", + "1bd71f8b45204cd8878883d8fa1f9f82", + "2c484a78361a432ca974589a88ccd9f1", + "0960594160594a09862cbb405a8d7c85", + "9fe669ee56564328bc8f4feb39437b8e", + "29d4135c8a9b4bb396997ef406e99789", + "0e8fde91fdb5413494e878b0fef85cda", + "a9ca6747427041c3aa4c7ff771933539", + "a858a0c78cf441918a73b789a15593c9", + "385492df8d0e4cc885f5f419962a1e9f", + "e44a3523ad3d4db487c276d09dd40fdf", + "5e9f107e36bd4e558e7b9868b5ea7e3f", + "df7023a272544bfb9434bb8b2f7b7c4a", + "52c5113c46e14cd69f27d1ad1628b600", + "280bca6886a347b0995b31fe11f01e6a", + "efea9009237e4ff2b6eb3f0aff868aff", + "f60ff48866a94050a42be8aeaf376817", + "ca73d830eb7744918025a0dc720b754a", + "dc9772326f9c4bc2b639a5a81f230b46", + "a9824884957045829211090035900302", + "d62e8a7d98134e1794d3a62dc4734390", + "73c2a42017a8411fbfc58783b694da9c", + "8cf8ce4a480e43dbafa390ae5394c627", + "c6f1ebdac9e446f4b1f0833f0775886b", + "8eece961682b44ddaf826fd17455a8fb", + "d77e57b59be34c3ea0ee30b0b8fec82f", + "f7dc5a03936640c3a98f586d0ffab3e3", + "49d97ca2fbf34f85b6c88ae8ebc7514f", + "7fd8ec4bf7284833946c9c23b91616dc", + "aea464310259449a8763003672c33a94", + "672bf82f5d6843988b8dffbc4d2239cd", + "8aedf051c5714409a1171ceed6543644", + "393254e136ee4e759aa0a0664d81f97f", + "e359db2718214aa58808e1fd88a26cca", + "f5d129892af5472ea3867a2342a033d3", + "9d0be5306e2a422491799ae29c7cb57f", + "cf637b83ff4a48f0a34dd80ca0e7eaac", + "d401ca5456a24c2db734a1deb04f931a", + "bfd56e0a13fd44648fd2f360ecd7cf29", + "94cc72f11d4a44eb91ca6bfd3ccb82ce", + "bd808e85508d4e7f92c08f732c41821b", + "dc9652c425194c8192c34874503df434", + "32c47e171fc54617aef4c5696f27a7a5", + "e5a650eb7c25420b86617cf9c86b4146", + "ba56ad0f0b0e45ecbf65eb9547c73237", + "e4f348e98ceb45e3abc77da5b738f1b2", + "810491c6c15e4772960be9fb39feb3cd", + "6b43e64a3353476eb3a96286eb0e00ca", + "a285c08834864d8881500619419a4194", + "fe24f4e2a1514cf088744316d7c7e0e7", + "3557760490074a0cb0fe7b97fa8edd49", + "057589dce19147cba5ed0ad4ad09212d", + "5a31811f15a242e3be948832b24a9543", + "3ab14e5ce84141cda62c3405d8086157", + "c3c6edffc8ee4b75bf842b9a86ec7b7d", + "638001f45d294f4594546895ab88ee9a", + "18032ac3769046ef91d08afcfef18916", + "6d84ee88a53640cdbbdd635ab81998bb", + "000a82b4e6bf4e909fbe5a3b0e6d67dc", + "459db9c0633244fabccad44ca329d5a1", + "57e9477018d244378302070a8738b566", + "b9d649e2bb8e45b5a5d6eea8f5abc17a", + "22aa8ea930ef4ac79b7bac03e1ae41ef", + "5eb52e8bf2f94c79bfa570e7ca3a573d", + "75e6a95b0dcb455f8fa82dc6d940add3", + "b0aa6d2278c94e29abe44e93d972f3da", + "f61563c447984024a478db5606b1ab3a", + "6b25b919a2aa42fe88f7a78f575c3a73", + "0dde70fe25954b3995711b23fcfd28ec", + "4c0557631ab04a86bbb92208ae9fcf8a", + "d39e8f677eb844e9a0496830981a3603", + "0144133a874d4fa9881d8947928999e0", + "46a9670af5554dff8a2d982488a9225e", + "2698b78a79204ad59f802f1b00f26174", + "7ae5d774bde448418e81b6c127021328", + "121310a3fb834e0791a35c95d5b5ec30", + "c77dff3110b94fc5a05f29c3a42175d9", + "74e8c924ec464ee8926bbdb7f6edab33", + "d914a0769dca4d85b05571d047cb674a", + "121c06e0021a4f8290d318a1a4cb59b4", + "2eede2354905407b9a72ab6d36964916", + "3820e91571724714bdb08f048cd93c3e", + "c0eac3720039454895db8107a42e2cbd", + "d3bd63036ab4405695f29625f8d9fcd6", + "89eed0b74fc14329b23304b95edc1819", + "cb5c705cc4bd4264a3bcdaa6355f643b", + "bb4347b450a74f8986482c713971133b", + "773d387e68c14127a0fb1101b0b9a751", + "f769c1ea1ce84566a3a9c0b5f4388c0f", + "790067c44694464491e89a7367cbc4d0", + "a236754be2354420adebe13885ae90c2", + "e8d5a5d300024a7fa981cd294e97ce60", + "ba4994111ff24568861c60e41dac8815", + "0585f28bb12b47faab316bb5db7d18a7", + "cf6ed4746a564dea8bdf96c2fc7d6344", + "031ec8b3708d40979d32e5fcc96a8c3b", + "92d0c5bbadec4a6e8fc9ddde72c18d4c", + "11f9d7f58bec486c8f3125e08f14d485", + "426c14adba6a45638752986c2f7d16b2", + "6330b75480b1471c8cc5f9a5ad59da03", + "80cfa4436ce34f0aa96bce0c956c5d16", + "fb4202d9afc847eba660d1607a57f64b", + "6fc443e0c30d4b6fa3eb6296137a6a09", + "c84ca8a774b142788dfd403ca139e4a0", + "29832125251a44939fae1a21a3288f88", + "38270fc8d593420897328cdba88ba242", + "6246f801c8274f3291f0da2d60410ed9", + "74fb83396bb3436fbcceb501fe8568fc", + "0871ea777cf84b09b4b64bb2ecd8e5c3", + "0574df9de0884e7da4564f37fe37e439", + "7a7202d849a94578a1d1828f2300df9f", + "09be27c7f2a9459082384bb382f8cea7", + "a7122ac6b55045749309db4cd8c5164c", + "78212eb338124202b4d12a932dcde4ea", + "00e242aa87fb4bd98c15c0ab5bf9bd00", + "a8cd700ac8864b03a4f87934669a1671", + "1f9d06cc32ac42d79f2f658327ade425", + "afa497e00dc7452dac58b04e1b9a37ad", + "918ee5f333344b4da18e5e95c2acf34b", + "2e28ccd62dc54a7889dcb79dd5a788d8", + "d2bd7596ef7d43adaa5017c59a280ae2", + "8e9ed5ed786e4c2c899742072fb3777c", + "8867a649df30422aa652aaf9034904a7", + "e12493a7481548129179d926b9a15b35", + "36edb23a404349709c9da94f136351e9", + "7406bf476d974ff8970e4edc60b7001f", + "bb1a41bb9d4d412c985ba1492985e90f", + "b24b26485a504199ac3192b995901dc2", + "5714c3bb38a2448e9644b2892956c218", + "fd6ed7720d974309a90723a6caf83876", + "c1cea9f244664778917898e95ab533e6", + "174c18f020af4dd08d353a3aad1e1af7", + "3c009bb478e24ecf80f5be96f88f22c6", + "1e85bf94b50c4b62b777eeb38b24636d", + "cadac3d14ec04ac4bcb8d32556de2f3f", + "b748d1de55cf432c9c36e949e4022006", + "5efbf6ea69374d3e86eacde7d3580522", + "83646e018c4749abb112888eb2760a29", + "2ad12f444ceb49919e2f6e0afa046e87", + "071c85f465214e988c59be3538bd8614", + "1ae202f921bd48e6863a01a93744e499", + "2a929afa12f341c097de09aa18327807", + "48cdb8e94cb3423f8913e794fc04b88b", + "100c8d7f4f0041e3af111718f9f68595", + "0de6cd8ef5224f7397b9b06083d191fd", + "2b10c401d2134831a45dbec2bdf2d0d2", + "1f53297b7cab4282a55ff6b91f23c82c", + "d20e220795ff41ce8da53e7874bb6932", + "c797974d7e73445cb22698260e3c78ef", + "cddac786890f4421b452bd495b9ba5e1", + "a28ada3a10fc48a4ad118e11d8e7c97c", + "aee101f9685a464a97a5a874d91efee5", + "3c78e4de48054990ae546e2118fdc1f9", + "bc71fb6ce5cf4cb894fa373cf3b42a63", + "dcfac118b89b4b8f842a6d521486f54d", + "082524a9ea054571bf25c453b0fe6993", + "1dc0fe17c77e40a9ac5a0c52462ecee5", + "0b07d4714a544a7fbe3a145ccda8bf03", + "c7106b51db9c461ba4c3ed40bffcf3ff", + "74ea610a92fc4c7d947dbf59549e419a", + "5b3443b6496046a1865d4d9f9c205356", + "7984152aaed34505b62111c881291b05", + "0d856c423ee5419bbade2416557ec549", + "de9e13e35b504fea84b51857adb2e8b0", + "177bdca95ba742548e5291eedfcfceaf", + "a3ce91f489c44310895ab12f987bd4fc", + "c590313610d2413cba2fe8a61f11ab30", + "2cdcce5cff3d4aca9cb8d939137f0539", + "17fd890f565643ad9d66f483aafecf78", + "814b0bddf24f43a986f68e4ee8b3c032", + "891e86850a80467f8b0dab2095bb2e79", + "6d91ddf591de4a00b6ff6751f0e58dad", + "5f58daf8fd66450f97d21d8da6865413", + "114de582455b4cb284511882429b23ed", + "b0c2dce5b3e84c92bf798ce88913eb28", + "e909875deca1431d9e9e81746f6ea1a7", + "c50614b6796f4357aa6d7825d86f188e", + "0c4754201b074ba980032e26bc9c7598", + "47d019b5d3244cceb63fd47e6fdf5410", + "a63b986464e0458ca5418d94abadbc05", + "22567398a36a4a4789750575a5ce2051", + "ad61062b0ba047e39d10f3b5fba1a85f", + "7a60e92f29694ed9b43d591788c9d0fa", + "d5b69e67091d42dbb09686a33c387f3f", + "c9d2c670a4da476b83dec89a75069d13", + "c48fb179431a4ee4a8f3836ae17d5bae", + "e4e73f5a6b174e2d8fa957d7b720c7aa", + "9f34fbf1bf6c4dae9ec69cc3ec133d70", + "ab462630d90d45e29e91c2d4180f3529", + "22d1626853964fc995cda04814792ae5", + "93e39c1789c64a8a9ed0a0b026f4d6bf", + "6e0ad7a287a340ed9f384dcb8c8fd81f", + "e037af98590b440f950e06752011a5af", + "6143f411dbb54f03a6e0273c23dba77f", + "f7f891b1c5f044098530a2f4746a0863", + "9ecba41efdac47f29bb180cbfaef03d1", + "8d37590bd006428fbc690ea597f3efa9", + "ff7d426729174758a59add57eeb7f6a3", + "ecd70bf53b29493a84e21037e1c3aede", + "208363697add4196947d547c4ed3ccc3", + "6862d6adcd8a4efaafad73672afac652", + "76d436d6fafb4bc3b5da646bd1f6c41a", + "57ded204d780415bbdae8dd4ad5bcbcd", + "222a5ea42903439aaaa344da26e7f9ec", + "a24e836909e048ccb9fc568c775a9757", + "20fc0680ea0143c0b7dcd66277eeaf80", + "f1aa36dbd7dc41c8a9542efc15def50e", + "a10e91a183384cc9b40c71a262766835", + "9fa5593a7a4042e4b7bbdc84c0375679", + "5ce27fbad31443f4af82353a630b436d", + "a2a02e46c64a4ef283fd97996fbe596d", + "794b730ae452424bb3a9ce3c6caaff7a", + "47a1ecd89f7b4fc2970c767f7d538575", + "3229c85a80374129995bc89f9ccb4546", + "306eca96d48b4ed7bf7eb9ed329f59ec", + "7b30bdb2ea7a42a7af31ee9122d75f60", + "ea77d8cfdbed47978a568c5b741910f6", + "e0da05f859d340ca8889371dba217499", + "5770a906c5004041b65604126e71b620", + "c143448c87224f038e713ed2f8daf7fe", + "2f45d745adea4078b5e05b697c588b5b", + "c256c7b11a574365a9cf52ab67f47e7f", + "f71d8f369cf7404c988081242dd70ff2", + "17c503afdbbb485695adf8600602a79b", + "9f47a26ae86b4bb39695d3734dd78ee5", + "cb34dbb8bd17433d94b916d7023e0d52", + "d04d8ac2c1ba47ee9e03351b4f08dd4b", + "1777cf946fef4caaa4113958fc0efc15", + "f461660b453b42a9b1d678ff624a9fa1", + "9590ca9bbe8444fab91b347fff0675bb", + "9d6d460348e6436f97b4a17864358d14", + "74a5d1da231d464b85dc51d63493c1aa", + "4ff9de0228b446758a2e8a9beb687acc", + "c5473591a55e4823beb4cf8ff86aa181", + "23c639ca701d4713a8c7f6480d0a8797", + "0c14187e152342fe8c06e1906f7688d9", + "40b55608bd974cf08039c8f553f933aa", + "7408fa7973ef4b19a5e21571b9dd7be7", + "b8e09431829a4ca7b119fa136e98b4b9", + "347e5d4fbee14e53811c5df2221be8d0", + "9a633eafd4ec41f099eea1b5a435ffe0", + "53eb586c6a21437398e18e911e9dfa0a", + "03fc72349f38421eae0c55a92560e95b", + "9be0b12c582c4b578ecf889bf4b3ce3d", + "6bc9fd040c3c46168c1a2b80e2fc4b9e", + "4450aaf22e02451199012358c3c61c98", + "3cd8d3fe52f942709d77ab6151b914b1", + "aae77f9bea544c569fa8831a1b305150", + "8ccd3f9f04614fde8fcf95d6be6b3713", + "1658ffe50e154dd8b830412a6f845b37", + "fb94ce07ce5b4af9acb2d54a262886ea", + "0849a8eb5c974781b94d05a35c5125ce", + "71fdd82bef144b3cb23a0c21d1a5c25b", + "e651e3ab11434ad48788065a4924905a", + "a596523a7c41447181608f84ddb72183", + "713a1d5203a1423285c789fa0531ad62", + "187f3fe1b0ee4a6ebe4629741de8bc5a", + "ee52dceaff82462496bf159faec10f29", + "46b641045c954194aa1f47d7570a719f", + "92e7a7e5cac2442285d99137c4f097a2", + "75483da53ce84a8fa5732d9af3a1ced7", + "bd6c9ff434c04a1aac5b5596e6c0f1fe", + "cd284a25f8114485a17d7b75d47235cc", + "84bd1bbe9aae4f3785362803d3ccc9c4", + "b1fdc624c9c440b5aec9c8705b915eaa", + "f5e97b7d5dc84c0dbcec18ca0aa16d90", + "544b5c976fdf4eb3a65c3d90fc99faa6", + "756b89a8929044f49008846c336f9104", + "f583d2be3ca6474cb2c32cb485656d7b", + "5566ea4f906347e7afcc864ab241628a", + "8347138202664397b75ccc39c66ac660", + "aaf9bd2e9df543b5b702147eb81e63fc", + "e624f969b87f496db6fe555ddbaf1691", + "193b1c220e47478698c62985bfdf0ab4", + "1c2e2eb8bc83439690387ff70bfc198b", + "308623325be8470b9d4bd4f349602c5e", + "84426d6537ac4cdc837d602ccabe7036", + "dbb3f5bcf7914454b283184c2b3c1571", + "68dc58d3c198413489db07e9c2b9ef62", + "8f5817f47f4a4f0490f9df3e3cf28bd8", + "515d0d953687472a96d2a890efaca364", + "e04250f955dc404ca21eeba3f27aa2f8", + "1eda3c27f669448897d4833052470011", + "ebcd206c9c4c45979cd92e1af1a634b4", + "439ad3cdddbc4211b8a3c98448e900cc", + "a222f23d0ed849fb8b663188c63c4211", + "a3141b91d24b47b4a5e48e51814ef162", + "52cd14f6b8f54bb6bb26d728c02fd9e2", + "3f48989f50894e48abcb1a12fcb70226", + "7a3f7e70f7054018919ad930ca586c62", + "869ce4aa38d148a8bc65ee19f781acef", + "eb42c07e79764c74aa5377e092f783ce", + "eb7a7147e72b48348dc5211c4af45f63", + "509f73dea7934aa6ac2661c446f06027", + "4b23093348dc4bdfb790e350b7270993", + "0be224499da94192b4c6a7fc61d21f95", + "d98a52d836a942fb9322fecf95c31ed1", + "4a81d008e366412db592a532696b3979", + "1af76876711a4274b9fd4f8b12d923fb", + "bc090f6f5b0749ada5d7faecc01bf3f1", + "a9f5b1b3fe1849adbf13a4d9ecc5f080", + "4772cf59da504661bbb487e15307c025", + "0a34dc814a3a44cfa76388e732c05376", + "d88317d554054f1ebe075b02c2dbd3d3", + "ca29bb7f4cfa413b932acd6b4e29cee4", + "a46804faa54a4513a470592ec9d8e24e", + "5a5e7ad3c52f422badfad814a8b12232", + "f63932b93b564ed9bbfdceaa88c4bea3", + "20f5a6ebac4a4173a63cb315b280b284", + "4be131d7a01749d49f42cce7f8c538ab", + "e2ee65bf1c8b40ac8b78fe6a1e392575", + "383328deb18f4decad379e372cc41a9d", + "4a538218026548c49551ceb5938eb39b", + "9e10ae30b11b474a9c759d6a28cfd23d", + "fb9b63acfa154b8681fa379eedfd6e9c", + "38570bfff3e04df2ac8663276455b958", + "ad622111edc448d1a349ca66f641e73b", + "ae2f2be104fd4fc691d016aac3daeb5d", + "9015c94c7fd3433f8a247bab6bb9cada", + "ccaefdb6c8b84b0ab018e6cbfcf33184", + "9b59afbf4a694e8cb6daa0e0235cff86", + "925f6917087f44cabf1e0fabeb2ed632", + "9fa4f50b845f4ecd96c88dcca941db05", + "0818c2f50c46492187ef6da98f527f3b", + "890b608a1d2b4b55a65a2d56352bfb8c", + "3a406e651e69409e87323ab42a214874", + "320376c00aab47eeb75ccd33edb0fab7", + "15c719f4c2ca4d5e90ef076057794c8b", + "7b912daa25a44162945e31d45acfc502", + "61a9ebb24be6462687f6f40985ca11c7", + "3633eaa6dde84ef192987c682036728c", + "ec059ea5256148bd851cbbe100a0a969", + "ffcf987149df4e528ebf1e2dec6a9f8a", + "f2933520da4a415bac61ed677275d2f9", + "26933ed5bd29435ebdccc9bfd58b9d49", + "022662a5e24e4f99bde618ddefe1c7f1", + "64edd65e1ec7492ebb7c1a8b0cb1f5eb", + "16df9e0284124e109f79879294f538c1", + "f68987fa9f92438e9ceb3d4a06dc0d29", + "fbbbed16ae794d89b17d941f666a03d9", + "b43ef95cd56343d8bcc1a62f728d5e5b", + "2f4a67595f40485a8a51536b6c16fa54", + "6949d44040b34666babc172c9c1fb9f7", + "5b38c82c712941b39cd0c81737730ce3", + "e147326b60954b94a72138443c16017a", + "8b1319902fef43dc904a257a377d9676", + "aab44519d56c401681c26861503ebf02", + "755aeb4bd2484d72935a5e435338a4b2", + "1837d78daced47449446437ea2b8d196", + "aa0c76cb8ecd40c5a61846b83df143d0", + "cef56cbb91a9424884d8a8461fffd562", + "290fc84660db41dba65e9f41c7c55f29", + "0115bca2d7bf45f092e9e93064ffada8", + "905f8c707506405bb0663c782ff4c6db", + "4489a6b448a74f6e93e3a721bcb9eb12", + "a72f51ce1b93435b8bd93669546a888b", + "bfa1801f2a7e40668953e4cd64472cde", + "8036c969bd13427f8c0b56b1ca0ccc74", + "a05cef5b3e8141b194d1b9be65eac4a5", + "3cdb7952ed1d40d0a68cbc364cd175d9", + "059021e155ed421481f82b0e33e6742d", + "ce994a386e18442fa46b4d7b24a1c141", + "221e7eed8f0647968f7cb713a71e0e1c", + "20db98f81da04a1bba33017f615876c7", + "012c9344518345a9abbdba622e393d0a", + "d7728fcb8f934eec85003a2ac48b32b8", + "f43de97cddcd466f93b69e59a56865a1", + "4825c60f72cc4bb6b24c6c34f78616db", + "e627991380c6410f827ac7fdc8610346", + "c5890a678d754ae1b7645f94381c94b6", + "63a7bb7cff96479f918bad28abd9b0b5", + "f1ed3f4cc1c140b6badcff21d54479a5", + "9d8325839ac6428a9c23924beceb8ffb", + "5200983a287d4b9e850bd11236629ec4", + "f2d4f12e33aa4b15898a20e75d588ec3", + "d1935e44ac724c62810dd4a6f89eeebd", + "acb6f67e793d409ea1a05751530bf712", + "929f056abe02416da19d7b1aa805d235", + "2520483410b94f6eb06f2c3ce06fb0df", + "8425ebedb9334fc3a1e6d7a72f5612b4", + "accaf450af284db7ac55ad83bb6dc00d", + "80deaae4d6744299987d68a4677684c1", + "ecc5df46ebb4458b81b2629cea18ccc7", + "fa059adf40334e23beef2f49d05cd46f", + "fd4cf2c471834295bc1430cfd6e429b6", + "0e7beec9d6504f00b92aaa63c02f7234", + "9eb5cd18c7254c2a89fc6a851fa89bda", + "f7089ae2aabf4263843ec17c18f8497e", + "5e399cfa83414ba69af3e3650c92986c", + "5d5e8d3259bd46a6ae1a63c8d9497727", + "1b6a4e6db7c64b6fa932b189aa694874", + "0b47d0a027bf467aa70646056f714ed6", + "44bc7551bf1e4c91acd3526c57b39608", + "08196534325b47a593e69d62a8871973", + "353c784b776f4c449f4b6046f96d18c8", + "ae3eed651ac6415a913e326ae3c3c223", + "2417f797d53c4ee78ca31a74cc774952", + "b7cbf91cb2fc4984b3778d1e37fbfe28", + "8891dc71ede1450b9d70ebde1b153822", + "11931f4dd90f45c7b05bd0694bb6e747", + "h9m9VF9Uqy0oTp1vLmb7KjEfQic", + "f15298421b3d4e0fab4c43863a7e72fd", + "9b608ca09b8d46fd8579986d22c7ecb7", + "2a3aba2c1ef041168fab0c595e2e5882", + "052c74fdfee14ae0b53db1eb768fa3e1", + "c22dd018d6d148d0a23e1e5007a3d763", + "43a96ae6cdbf4fe2ad3e7630c98de98d", + "e915c0da07ce42a2b5ba080da135a751", + "743af2970261449595a4295a5a736bed", + "c02d7e2917f741478ef0697fed489fc0", + "7806794890824398b7da604880acd7b5", + "094697a23146463cb5564ac8bf89e5c4", + "79af8a0bff0f48e7a5fe6932157f8052", + "c99de34b3c9742ba8c42e4d2328a4760", + "b157b443415348b29e9e7123888626ae", + "7503367b467c450c8ecb2789bef3eb1e", + "22e460afa8cc43889f081033f2dfaa97", + "4f3b5a9577b24ca6a4442a694380e3e4", + "bdd4181dbe334192ba5385810c9a58cd", + "35b264837a694377b009c6e2d500e7af", + "7493a4a2ce2b48958f46ef52ae13b60e", + "7060cf492b7f48909288323b8c9802da", + "e45aa7131e084849815c980bd3577e10", + "1bf7b29a4a1f4cfc9af2f2976a7e4d15", + "2d6a70d7985b4ea391fce54920e112d2", + "b80ed1e9438c4f87b82b2b2a3e364209", + "2a4c53a53721412da328ae6d9e4917a3", + "a77bfd7bbadf4bbb857258fd5ce155f2", + "15054c624ab34530a6e7422af81123ce", + "0ebf6fe894344c96a63cde72fe39760d", + "21b0649aba644fa8ba5b637f0c6731fd", + "2224cf03a9c44a2bb06fe196b28db0d0", + "0741405f9d9942e292dc1d0eb20fa815", + "0ff9a2e928784270b5bad69b79eb4480", + "1b591374cba9494eabcb0dd21dd15ed9", + "60f3fd321f2a460aa516ca4eeba0d2ea", + "a521087bf51c48f394e983baddcf9edf", + "62903f8a858f4baf9e6dda24d2a93c40", + "10d60b25c7ac4c0c9de056686ed01002", + "a054e2da94ad4c5783a8e04c866e6c1f", + "b9e63643fcb841698286cfb9f39b3492", + "153107e839e5408bb5003c53ad796c3f", + "c5505e2997a84d5d9a6afb922978e8f4", + "fb8ff119e9ee4ca0bba589ed6e7178fb", + "5a2e0fdbbc5c4122873988a15cbc0c39", + "bd80cf84a16e4f9c9eee13d373d29d8d", + "9b7f5b7b09c249a4a76857093bed19c3", + "724d93a7f3644f96909e8c55909c6418", + "586e9b8f4ea4483e87c70a3c45224c51", + "7579a5b6399343a88dd75e59865e3198", + "afc7108c2dc7483da932288a2cbd9bcb", + "119ac4478b3a45a6920d171cf8d6570e", + "998220ed34ba4edb99e0d8dd55843abb", + "9a974d2d3fcb423bb9a9854d2f0d75a7", + "d48a903d948345e9904fba6e19345f85", + "bf122cd0854e422bb94704552c64810b", + "e61c9942295042c9ac89b910eb922269", + "092d0e5421864f5392287624a619f3d7", + "5c2f3b5403464545896eda504aca96c9", + "3eafb89804b54c8e8cbe35e4d456e0a9", + "a9596681996b4b0fa316565dc0658202", + "772e92af9eb34ed2a708b32e1e33da32", + "e7a38fe05d784df79d64d88bf939670b", + "6df3fcc1561c4a26910ea52919f66fb8", + "1e0630e55c4b4e37a0667e7f1fcc9eb8", + "6884790f4ae54ff3920c25c7bb2756ab", + "87f51c328f854b4582eb55f54b644bd2", + "9efe32e739b34f70bb6a2cd8fbff8e81", + "e9e844f2f9364044a181ce8f38a83dc3", + "62aef320fbd6460c8b099486438714a3", + "b4a7da34cee346f38bf5f795d22eae36", + "0451dc8905f140639e0d081e78ea6b86", + "8ac03ddde0e349b18766e4dad7edab26", + "b45d9f4370104ee28a5d84652201a6d6", + "32ad2a78e2e14c1daa4ee8c4ee079fa0", + "98c6deae13d54e0396f76038123a7450", + "0616281841b44983b1c113b578c0f0ce", + "6251869752b54edea1616104d58035ec", + "3c6737c169aa4619b9a00e4ae90a9624", + "14e42432d7274945a4024aec48c3d20a", + "b791d1a470ab43f3b3b310c7e8451e1c", + "c39e6b7c76a449e6b2d096cfd0d714b4", + "c81220c9d37e4412a0293c22c2638519", + "1298dfc93c3a43f6bdfc3ed9baabbede", + "d7c26b14eba741d2bb0120069c5eac4f", + "9b850dfdab7b479fa2878d722475d796", + "1018cd118d4f476bb8051a121485d27b", + "f2bebd100dc94f9c8745a47dcf004661", + "8e4a39d3112d4f44953e39397326c8b5", + "2967583f627d48928f2d2bc25f163678", + "4fdf3ad3c88d4bb58ea7aabb9bfcffae", + "b668d4e063fa4ca8831297fb8a31c811", + "39e6c82654e843dd819a3408374da0a8", + "0f440e2b01ca42f8b3fdee8178c51f20", + "49d81cd52df6422a81132835c2555b2f", + "7867aa1e7d7041a3af665f329829a0c1", + "1d06ba8ef476420094ec09e818bbebb7", + "abb542cee2f143cd93df69f54ba43cec", + "40b8a909a45a4c4da9bfd50993c17cd0", + "f56152e7c8654e52b55e032907c50684", + "3865850403ef4051a1f132955b631912", + "b62c64de64d64593b7f325bf88eca8e1", + "9f7890238c4442d789d1970cead93203", + "32f8bafd9fcc48adbec217c79f8917a2", + "65ad095e176940b98a2458656d9c56ed", + "c9de51909d0643e1a67c86daa694d44d", + "40e25f5611d14355aa71e46bedd565ab", + "26ac9350d20340ff9466c500c4fa6452", + "a27a8dc5863c49bb8aa03756fb355890", + "060c25991cea47b792252e02555dcedb", + "86791378f3dd4b1789617d223ec5e92d", + "65cbbefb7774468e80ea4d815ce3cfd0", + "2cb1ab1a393448e1ace72808c5b1d505", + "a80f36392aa543258ccd85e1a877e8d5", + "50a651291ec34eef938766579ee0f746", + "854dbbb2ab994ec8a1b46289a333a9b4", + "fb40af8e26674b1f993ae22c31092952", + "782e698b08854d0691a9e61a923c3e14", + "a3467b35348244b6a26897d46f218f86", + "a389d54baa124ea0b89788d0579ad485", + "802989a042a844a48379916e7fc55e79", + "0116be00f04a4447a4e307a06ed5b62b", + "0f3005faf6b0469089680d463fa930cf", + "fdf8f4480d874f4c8cc2841727051da2", + "5fb6e07b6d864a4385c0018ed5f88010", + "2e3cac6877664b9c8b970cbbaa0bdb9f", + "bac934617b4c4410a4701dd501177793", + "08babe7fbc5e43e180e68c108dc45882", + "2ab000d19e7e4ac8a76811e34a9019e0", + "c6d73780679d4b19b67086382152a533", + "acf44ca1b3fe46c38368e53881a6be01", + "c7efb3b9611747ddb4e15d164540d291", + "dc8224840a6b43f08688db0ce45be476", + "f09d4774ded7420a8031b09226403701", + "ff8a765ebd94497ba575af810c61442a", + "3e6831cb4f2344efbcdb829cd34518d5", + "7bc2b14a48d1413e9375c32a53e3ee6f", + "8c19d6525acf441b9cf3c1fd91598ff6", + "1e23afcaf076420786d8078b479b0424", + "1ab0499f7a7746188eefe85c1f16594b", + "e149e92179364001be680fc39064baaa", + "94813043397749d4a4c5e2009f0908f0", + "4c11adab41894d68b8634eff0b011c4a", + "19b3cbeefba44ac299904f04b468dc04", + "37f5011233d7442bb9ba6243c13f9e69", + "b2f9c198e30043f09170fa4eef12733a", + "f588ff8ff01047e6a506a01aa8c439c0", + "15276a21fe2347d894cd3741cf644f21", + "7275801603244c30ab5b584627eb1046", + "3ccf0f0e8e2e41dd8e6f6b88ce278738", + "e19e7056760444bb80d0d95306c70eb5", + "61fc3a9c9bfb4c5ea08d8b789b1beb2d", + "c7d505db5f5f478f8abffd165361287d", + "b3b7e3ef70c548b4ae4c50c810ed2b5e", + "cb5c3b342854497e811a1234cb5e68b9", + "de6311900fdb4f20982d06e318ba57d3", + "8c5b991b4c0a4bfcb13e0eea894343b1", + "aacc17f3ac10497ea309d25b14a99b25", + "5f0fe7ebcf4146869be789612f8928a4", + "f8339a2f7ea849b8afbebb76a40e1759", + "16a58d3bdd724f478638078138155126", + "7b99ca95e4694536b6206d53554f3300", + "09247d35f0e244c29c6b7f7c36a12d45", + "6b8ec1b507964b4e820b3069e72bf167", + "86f614d94be444a99c688dec28a89a3a", + "15f227434085448e843bbe83d2d948c1", + "dcb247cf82c74794919cbd0732e41f26", + "834e42625fe84762871d311f05938a42", + "bd41c78c5d9246b08cd01364ec6ac8f8", + "60a2a2752a4c4b5f961ead8a305ea7ef", + "951419250ae44172aabccbb3484ce199", + "966f9c3ffac142adb4cca2f82682ad7d", + "00f6c41165624415b20445a1fcc38247", + "1237d80e466f4c5dbf53b1302ddbca1f", + "acb463b3910741b3ab7af89134e840be", + "ff974958778f41c286935f443cc708ee", + "2e2d4ae6cc80448f8b2430c384a5e104", + "4d49fc721d3440a98297cb3ccbf0bf2b", + "143285e1f12540ddb29394a69100cd8d", + "8b0e7d3a1b4d4dbb8ec788c3e4c5f1ed", + "4b64a7bbfc974893bd3a9c77cd3c9d2b", + "c08fa9c29ffb4233ad16ab82a79b3125", + "8c92175e4fc0419cbf9f9983c5dad057", + "5f4141521fec465e9c48d9b20aeacfa2", + "66d8f6b62a3a4e3cb9c9246a8c843a79", + "64a58b6eb602473e8579e716d8c33195", + "5c850c0b79584f3fa9bb18709ccc2c75", + "4a6230ecf8c64cb2b503123a254124bb", + "85ca6ac110174c0c853f7d8f9f084dc9", + "448e57880fa744e19e18604e42d64cf3", + "66a185f373c944a68dc09ee3ff19ab0f", + "24e4e2b2d76e4868a174ac18fc5cbb5d", + "a777cbbc8aff4c3cb5ed4dec2265fa12", + "e37ba665f10e4c42ac07b682f1a21436", + "a390303a1e8e49afa629aa047d6493b1", + "f307a980d98247b98fac39679fb47e0c", + "197ecc13f22a4b8081e329c35ba1864a", + "758dcba249944d88821eec226211c54a", + "3eeebfe1c863444e8d569bd3583db0b0", + "a24b02d3e75643eeb7625dec88616a30", + "19e6236a1f334717a06128e5c892be2f", + "b7f382dcc5094561a88ffc765fabe978", + "ea81050ee61843658b2b95d94161a2b8", + "cedbb1d9c25c491e948757c0a906c249", + "d09678347713483583a99831dd5aad57", + "e3080638d80540e1ab596adb47de6104", + "ba5769116fe34c1ea2712242c4f2ca98", + "6681d871f0324d2fa9cd1d3b80163952", + "0ea520873f0d41b08124b09585df60a5", + "345e7b4dce1c456db06df73ac42c7e83", + "40d8954144d143f9bd8be9a90edeb16f", + "68910e549c304e64a0c86e231e24de22", + "aed75e9dbf1346da9358bcf3ed0b5fb4", + "c669f39f4a924a8e9321f9a5d856a380", + "dcc3e04332ce4bd29841e4df893897d1", + "a07af3b8c6c045d89a37a3b3cde7be1b", + "0f03d940e6184871a0f38d429bfc006f", + "bc556ea3636b4fd1816e526319b426b8", + "9b3d9ef33d82404e974962515048ab2f", + "db618e3f97d641bf9ba04af3f84eb059", + "46743d3ca1f64dce8faee122bdcd55fb", + "c0e9a0ceee16472787a61dca1bcec3ae", + "1a5ef5dbcd304f3a984848cd26de890f", + "e0368cec6d0c4d91b48960528f760b9f", + "4bdb2790b4de4be88441769aac21a561", + "4fda8102812c4a619a8cfc41f7434433", + "2f2bfd7940c9467c90362ad2b3e80cf5", + "84df0986e19049b69a15a4f1db8653f9", + "94b3a3a353324f798c9dc9f92c0e8d75", + "b0c4b928c9ec4c3b997c35d9f7dd31a2", + "1570ecb3f99e46eea13eb6d5b980ae7e", + "cba4bcda468540c7a3ff843b08f22412", + "3bb60da9708e42dda0276d8c7c45c4c6", + "e61f784439c44e46bd838f75943cf6db", + "7dbfa863d15f4e1cb59b43e3249623b3", + "e139d62f3f7b46cda1ca2a1f1e67879f", + "568f22034e364caca4e450a6d534dbd6", + "0e6df765d30943bd877970b3da1aa90d", + "66a005c6edf44b20995251cfdea64a45", + "20f603f201c14f3b8a4f5ce150693c2a", + "45ea75466acd45f481ac0fe22beb4aab", + "9B0brgbLr6CUvnVowLzRzV58NMf", + "3ea799bbbaf5492b894bb4af11620362", + "30b0d95d5f0b4de986957b34a22cb108", + "97611a53e3b846f69e0655b210f72b2f", + "2fc0fc6ebe564a249c4617e6b3e6da93", + "1a82e3c24bff4051bb61dd7f737fe22d", + "f2a527a044d24072804f3661081e08e8", + "6e2b8e1ef0e740cab650a075896764a9", + "8736ed8c3162415aa8794e5d71c88c15", + "c441b81898244a9d9be04bfd8bef6192", + "a81d24f5be1a41b28db06d54a606436b", + "1a939c14e6f14a0981a2b2d2c1018a8d", + "3b321da343714e9597e3e86af8a0a7a6", + "92312f41d07f4b56890e170f62d27399", + "dd09d6032f674d43882f1bfe42d6813d", + "adcedeb324644d7393e3123ae6a60616", + "f317b73f79bb47e1b271e734ee9ea0a9", + "70548d02cf624ca798b55ad62e09382d", + "2ef0c41e12504884b9dd681c9be9ded9", + "c424492fd48d40a6bffa40a7a94296ef", + "447a504c173e47648c0325debf347887", + "85880af5c95e4be4bc00ce5a74565e48", + "82d4e55085044dc38828507612e9fe99", + "8a2a9389311d412883818798cf81098f", + "6d0397e94d75498abf9ef7c4f245107e", + "fa8a27c91dc04e19983e21d4954eb93e", + "59d7e2b28b8b45ec8b179fff0134ceec", + "4b8adf3292e1437387fdb5b90848642a", + "a14d471ffda04d38a1910b9ef87e8dff", + "0c3be66231f64e19bbc821d65d15264b", + "32a00e9c23fb4675a466b6ae3124424a", + "d64641adb4d748eab56439b1867987a4", + "44337ec77d5641bfb6e2c40e7bf585e0", + "7d490276b6354542aa63911e02c5f5b9", + "d48a4041a6694f368c67e968b7a2c00d", + "f567cf6300984cccb42cb75a81bcb248", + "75c95aed02324c799a9b4d9bbf4c92eb", + "e8443bb1a96d48aa9695fbbe9f1428ea", + "cc6ce525111e490e93a2c32dd8f57c38", + "9d05c8c4b1f74bd4a3c8840c70e8f144", + "3471a6fedf6e4ea288c4d465b232b6f8", + "31260a5b2ede4ccdacfdf2e19bad1aa9", + "d5e1b42b92934a9abf9402f97f9890fd", + "bdcc731d1bd246aea84673ac21421528", + "761bfab57e9a41d38b92035879211525", + "973aca271701469d89b546000d7705f4", + "bb2573634ee64cb3a82aa7285366bcee", + "bf8b700b9e2440ad8dfaff1d99e94137", + "0c30a9f6b2f740b282b6a305accca96f", + "d72efd4c78e146d88aeff93a721c5330", + "fba908414c164fde8320f202382f7633", + "516d8b88109f41b4b52e5712959f62db", + "7348ef4bc7da4540a28d307409106467", + "3ecbdbdd34d949338e85c7594f606858", + "c70225db3dd34e8ba2f53b13bf93411a", + "e55aa9e1ce0e48b7addce7056bd3529f", + "c33bb1328788413b85b164875747d9a2", + "95ba47a7cc8843839c87cf2ce6ad71ff", + "97787f3d265c4744a360fedd1a54c6ab", + "4158d954ece94af599b25811c3c09e66", + "7279cac4115a40e6ac345d68e17f15d1", + "a2b7204c6ec148c485d2c946295e8194", + "d8e8e17950a44b179d0c1ee61fb45b6c", + "911b309008d24829b65f72fd913b91b7", + "4919df7f695f4a86a8385c26d2533569", + "1aa94c9127004536a5f2b14f9743675b", + "4f6ba80449614626bd84217ec421571c", + "a9c7c4d72e2840d2b1a7b57a90f49c04", + "16933f17c995496db81657041d024da0", + "ca18d2c2c37d41dd94b2967f6d58c89c", + "f5847f80ad0f4a4da4684eb10bad6633", + "e179fa35340a4f24b097277f5aee0379", + "5e782203d690447ba601e49c21a5aef1", + "636ac882d98341108c1f39956f2bafb7", + "f089bd097d324aa2ac2e9083cf3b84e7", + "4baac09eefd4495e85a6b931d6437315", + "97325850d52d455dafceba65147f4556", + "f77936b09c5142f8a721279b3e9e9f05", + "ec121632cbf246dbaa3108cd03328b17", + "6b3020fed29c4976bc44ed1b7cb7e960", + "639a0f3c67764d0d9847ba8982de93b8", + "4de36fd537c844b5800d003c06087d17", + "c60c660948374590af6763d7254a59cc", + "b9cfba75e97f421a821d40d00a622a1a", + "93ccea4774854425a55611b72b750ca2", + "97bd7574406d4df38d54ec4ac1f18c40", + "289a2221178843a78ad433705555e16a", + "b547d67e34944385bbb9e94f3e5c392b", + "c872dd644f6847d8a968e5eb372b000d", + "f69ef12bb68b4fa382f5680fe039656f", + "91902ccf78034e34b0f7afed6781cb7b", + "ef4d26f737fd4ce88e39387e419de1b3", + "84643b518cae4f42919224a560dc9704", + "5d3af04431e9481eade93f94f739ed28", + "d6e218214e1a464ebfe0ff6b6ac36900", + "9cfb6d5121a14c3691bdf9c92a37c8d9", + "f5fbea47f3244a21954015b8dc4c3330", + "8d835f350c70423f8f0b8c28883ecef4", + "a513fc821f764656b62f3bc20f0b7c6c", + "14e3257b674d420eae1aa58c4a11bdc7", + "b9dc4b7181a14f5eb3ab618b4db129c5", + "0253ceabf9ae437fb885a74140070227", + "6da1c721dbc8466d8f45ac8ff91ecc7d", + "01810aab099a49569c550c646b3427cc", + "cd49ebf5f32b4c98b9b4b556c02d36ab", + "3ff09321a5b0462bb9d37d9958bf1675", + "3f1d703b20484d538fb194d0983b1f96", + "62e99b3760e84e4193857f0d7c1bafdb", + "4d9a3e7fcf9d479881b29c84fcdc0cd2", + "204b28c7659548c7b5feb0418871a48a", + "3ee1234ba8734641999b9ce7993f8b96", + "7242b3c0deb044db97639f7a6b125223", + "ee0be183b042441e87abb36683a668b9", + "5e0ac045516e41ba91b53de9d1086f68", + "645886761a804fa5bfb184d1ec8221b1", + "3c5c4892653144449265056f891b8949", + "42bed4663a1c486c983f38a0a0f36611", + "8486dec8ba204deaa98400593a14b9ba", + "2b943071f899407ca403a3c65f016319", + "00dfee50afad4153880d3a04d9a040aa", + "14df83a24d554b5f8c929903f2734e33", + "cb2e9ae5febf4a57b8ef655d52be576f", + "03cfe970578a4744be7bef464b9c8b91", + "d0261c8292254d18bf51859d7e2e7eba", + "aaa79bbc31a14398ae8f91dba24c3032", + "c57cc8961898488f9d4ef09604e5bd75", + "159eb0a46ece45f387644535fe07daff", + "af0f77af545544068793c44825af3d6e", + "f7fadf43cedb4f83a7edb28e3aa595b4", + "0e3d11ca36dd432e945495c0e85de057", + "aeae5e2622344e298aa586f8db9d2172", + "da67ff0a13f749bd88a924d14575600e", + "9ec5bbe588e84b36abb8ce600b23980a", + "8a8c54e6894845d791b83c4ae25b7a9e", + "e8af2ec9bc4a430887eaa75237324ff0", + "c202f0c8f0d64d8d847c54776955089c", + "55c4cb3cb6384759808460587a731185", + "dd2610131ae74c42a5d80dce3c4a4803", + "4079682cf06547c6bee73802820fa109", + "b56cc6ebea1441f0aab1c1cc36299ecc", + "4394800e93b94b04948eb997b138342d", + "8cc779fba519474c877920777c5c7093", + "3894f67369b4464da4d4e95c8057db57", + "0e63e3bbb8934d5ba3059cd2924701ab", + "2c46e958b57f4c8eaf1e9f283549a332", + "9a87c4971eed4fd5aa6e1e3441cd1e70", + "c0e0422d554a437083a306654977d1a6", + "5ea118eba048482e9b095b8c88e3a061", + "6b247c088f034d09908d4ee78c39dd18", + "1d99ac62f2174f86995e3a1fd8e7ffa5", + "4f2ab80b891c4b43a73b4c2a242b7926", + "7e87642c9805464aacdd8c5bfe36a323", + "b4489a25900c4605acd861e2eae782d9", + "4e5f458de0884bf8a5b460b2bfdf3c41", + "edce9973ca8b4862896179439803e3e1", + "625b0a764d0f40d48f3140acdd644823", + "843a5c4189e84c6ea9d46eecc1e1c6e8", + "561c39dc6fef4a2fbaae7feac18828c8", + "e77092787ecd48389d0239ab983f5a6e", + "b43e25f3f8ab4e7c9b3ac3850b684172", + "3a6cda16adee41ebbe3cbb8c6cdbf464", + "0849e24b30184cd78220783b8c185a8f", + "f9873843c895404bb8f27b6330cc11c2", + "ffbb77d78c964bf18fa1babe8d2b9a90", + "c7b8207727da4a2f9f22059a02f21725", + "3f818967cb6c4be4a86d7d068ef9c506", + "91eac5560b7b4a959dff530a030b645a", + "e22a7d919a5443de9736884cd69f2648", + "b514529788a6456687c133b7fb92e6d1", + "051d93b09c7e4de48e6c57f607a9bbde", + "0ae58b68696843fa89548626d5d5f674", + "d57f243d3cbd4f5498908055e7f7ff3e", + "b3f962419f5e414d9289f578307a7974", + "f5f0fec1b50b4f7290e9da7a004b4ab5", + "d9a913f6827c4337a666af1256cf10c6", + "fe88dfee23e14d179fba0e526251098c", + "c1f38cc43c694137b711c260445137de", + "71ec6a1de7964c1fa13e67c5276973f1", + "fcf9039e22554ff29ffc62cc4dfbc634", + "8678fa1466c34436be7eff7cf4938a5c", + "b39b97fc656c435c9da583f015ba52bf", + "350584d8243c4f0e9a6ca2b306d287a3", + "487356d4b9e148dba8d6b385a148e82c", + "18318634820b4fc2950d125788519f4d", + "f0ead52726d447c9b21faef78a795280", + "41af7f298e844db3a6ebe3b77d35e0fd", + "813ca6fa4c8c4d079f39317135578bb1", + "99fec76bfc96443984da060499d30809", + "c28bb9681cb143a7ab20ccf751bb7dcd", + "495f7b4204584b3199e8ecbc59d7e598", + "b6f6740f883b4749abac47af0045a9dd", + "c504cd00c0bf4dd08c62fb9a875e94a2", + "e488303f91344974971d31c7fb195912", + "64eccd680a254434b329a6a32aaa571f", + "37760a8515af474ba50f085d4da31cfb", + "20672907a94c4233968e4281bc2f35da", + "62302dd591614b869bc28eed8b8fff86", + "91761aa110cb4a9298ad28a0112b5d2b", + "a5764759637f4a579b56185dfb4607b7", + "248f19938ab04761a15e35d9e24161ca", + "32720b491938476385fb3243e58b6029", + "4200a0f4dba3414b89053633bed7a695", + "c0de407f17014b1b846dd6d9d50e5982", + "0f1ceb30652041aea96b9cfb40e159c6", + "0b5b53c652804d00981978f36dfc2ace", + "53ea3b41f92c475295367c1096538573", + "4d7132a60a174017ba7d0c029dcac4fc", + "69bd97e6e94a403a9cf4aa872907c95c", + "0f2264f87c0f46708e30f90dc501c674", + "3fb482d6244e430cacf68aa14f206974", + "ef1cadf302a740de93bf24464d169fc7", + "b2bbf7e5e0d74145933511fe71b9e737", + "66843616d49a40e4a758c4ea4b8519a3", + "be49d7ae041743cb93e53f6b8cceb612", + "e148c45d071541a0a58d1c379ed4e27d", + "82db1923a0874924b8537d2d78ee8216", + "158d45e79a9b449fbff24ddb7b36446d", + "f8272460c67d476a8af29e1f2e344bc0", + "9a065e92e96e4ca8b51e3bfe5a89ab18", + "c9cb359c89aa4ede842e1250d3e04b75", + "1a090a6a3f28463d96ad6461366b25c0", + "a988a743a9f54fb6bd688f2236084fa1", + "7228bad14d6b423a8624ef69e5446994", + "7f60ec770fee4402aba503607c087705", + "5f148bfc60f34a22813bc07d1fdcff0c", + "1e1c77e3898f43b780fa240175b7183f", + "e116c89672564c32975893a29d61bb74", + "e37fd979827a407a8e9b25c10e17991a", + "63af4c3ff86643ec8caffdd744162fa7", + "f870d9c7f18a46f8ae386ae94cc87121", + "eab176a4a5a644eea446114f3bc19403", + "cca7810812874656bea7f31ad521659d", + "6ca5ebf3c2da4ea081fd2593c7ff2cb8", + "3875499494054c3d83c838d98e87b800", + "b4ad53e3057f4922b273f86e7adb3466", + "af41819f8f464066a703a1c05586ff19", + "86881130d2264dbf8f3033d0e87daaec", + "b36e0027d4a94eacbd3e47941f8bf388", + "f19bce8c90ee483ca52b41f29e6390b9", + "9b115ccf200a4e53aba9b76ccd49ab96", + "6c06611cf3454b978c01bb98368198b2", + "5800b532c1fe444f92f9d53172b72c28", + "dbef08259e8040bfb74d827a04f1abba", + "c3234af45ac946f1b8dbcbde575db693", + "3a36605b00ac44ef9621f8b37b8b9133", + "785a64d91a1d4923840df57ca1153920", + "1383202bcf7b4d13af75f6f29aae7ed9", + "457e8081034b41649f6ca3172f6ade43", + "37a44fb955cc41acbf81384d6b1eea4d", + "e20daea8ee954218802c677a3a7d82e2", + "c464bb8bfd13417bbaf5da0b1ffa041b", + "7da77cb21c9b49c8b4ca1171e42f6082", + "5c512a0a5d23490399725b818f3d5aee", + "935a4292e9c84a51853efd5986876805", + "56e3d41fcab24b6699abf536419b7c47", + "e6687809645341b58d89a30a1d25acb2", + "59776b2fef0d4782a4dcf7096fbcf205", + "dbcc82f60a3c4483b1ebb4934c58261e", + "cc5b253fe42c483cbf16d0d24d5b6866", + "c79e0f910e234342b950fa5b1d14f278", + "7e45afd586a74ed99936f49684b9000b", + "89fb8b142c3b4452be9be654d9c0765c", + "1af04031fc3842949063050404787cf5", + "c1eb85c9157d42f9bc2ff527c4d8eb97", + "38b939e4f09b4870ac6a1495b917bb5f", + "a2eb6b3ea62544b984f90a546160499a", + "447866508de547ceaa17cccd39063bf4", + "84dab97d3b90441883bfda5de6ac0dc9", + "566cba1db66747bdb1ed46057b88b3fe", + "4dce1be40c3845dc98ea4dcf7a726d04", + "419396578e9f4165b38252ddec0b77c9", + "d4c6c8e0f3f64e8bb5ccc970e53a9891", + "a9ad524322c047b4808a79bae2f94c95", + "a13edfdfa3d04161849078be7facd99d", + "55a65a18296e437fbc3bd441f8456589", + "e5015b222a6949478d68bd6b38fc6ee0", + "c6bc4240ea974b3cac6f18f1d5d7eaec", + "e947a018194745598df88444bf43de11", + "169bda1b05f54c14bc001548c7224e9a", + "d7c8e02d53e848cab05f84a29abe1d98", + "0ba23e1b5ca346eea78fb885dd1a59d3", + "c289f3af1abb4084aa466476dce32e88", + "2c4611686c75483b995526c583481030", + "8b4c74e4dba746b7ba2f114590a52ddc", + "53ef79b8097248b3b77081d031486db7", + "e7fe34c4ed234ac9b0ef519c01546f36", + "a85ee1e73ca34d508d8acee03c574c62", + "2e1532fa668f46b4939c537d1a51f352", + "840f43edf14142f2939180b7d4982a33", + "e666d13b9bb445e0814151f5af4d4fe7", + "ed62e8ab9bd241038609d48a26388b16", + "210a6f607e5e4036846b50e7f783f842", + "a492765bdc0b4f46943be959cc55aecd", + "03318c6414ae477c92266a8405d78738", + "3de098cfcfa846b781aac7e2ce6ae6b3", + "bb15f5e354ce487f86a2d5829b21db08", + "c4c9b498476542f9ae03fc24d2be2c98", + "14e616e26823472c809a03042a94b990", + "7ef6cf38f71e4b0d998cc19ddd73859b", + "6af0d66a358f45469537e236348dd3d8", + "03e4ffa802654cea865fc8ebfc0d27ed", + "6c817ddb1c4f472bb4e0e6f9b056d961", + "f6b98543b5a84efdb88654af793a7791", + "29d864449f8040cb9fcac874da48da0e", + "27090e998e4947d69bea68738864393e", + "7840f800d754463b98044d056ed6b34f", + "c0ea5b0b7421464c9eb0f62577ef8eb2", + "aae5189bef93439380822b7e7dad3ac2", + "0c1846631feb42c7b9920e4bf4b13924", + "c4dddd5119e24f6cb6fd7bcc96c39fd0", + "cd5864107fa845e38d0c0449d29b73a1", + "6d6f6b2a918c4a66b954b68a08db611c", + "b33adcd6f07247d492bb856874d3cf31", + "8164cac189ce4b71a02ba479c7c6613d", + "458cbe37b68946d486731c7c50704b77", + "8fd630ce74c54fe986a792c3ebb5d57b", + "2418fa403fff41f5959f459085d2eb08", + "4ea8139014c6402284d2d6a063f62a82", + "1305f495d1f24a0ab5b05d2481647329", + "4686d7eec76f49ea91facbfa379d4061", + "cc48e64a3a0f422b8781f7454fc84a42", + "2fca5b9556674d9694d34bb9da17386e", + "b0bd00b700a3451da1cb4ad9b082c3e0", + "45c730d0e45d4fec98626d66a004bdfb", + "25054fa28e0940f7bb5366ace9e54677", + "eadfe8fe43124205b2551635252f9e8c", + "4b99fb410740400fa7bf127f5ec5a237", + "6ad5405dac4147c6931ff20e261bc089", + "efdf3cf3f61c4afa83d6a2ad8d973274", + "9a0e347e9b094039b7ef789062520826", + "627b2345d85c4625816330b60e7ea0e9", + "cbdf758f21924c168c1c3da1afed9754", + "8deaddb9b5b645049df82172f3afa570", + "55372cc6491d438db509bd17b016c75c", + "f1d9ac89b732426a91ca29d5e76b83c8", + "c72ab93dacfc4dbb81ea953173177f68", + "53d406f487fe401ca82566ce5babba38", + "be1f2a8f992443b0911e7d5b5cb7f269", + "7674012736d94c84891ebd0407fb4b11", + "379fce5503cc43ff930875b3e68e4193", + "7c7a9affeebe43e0b6f32729c3c8d0d9", + "5fcce30de3e447dcba22c6d0ad841868", + "46c555cb5dfb40288cbdb10daf5a455d", + "2307ebbf827848999b3579c3e541463e", + "72ad4418f9864bb8ab0d6c4bc517f0cc", + "296da41f47534f98ae2d3b958d4c4f98", + "ce4e12ab751245e28819e9c8d16ce4c7", + "3cfb22a556ce442f9570a64a6df31cb4", + "80e8478cc29b4aad91176e584ca67e1d", + "985415443c184be68e0e0c62edfac663", + "e2fd51f8ce0141f1bf3bfa2d7b1bf5ef", + "ab2af1976057499b91653563dcb59eb3", + "73e76edb90914783b0fd732ea53b2e46", + "3d16c309fcbb4ec488faecb209e4ce2e", + "a2bb5388c255454d9eaab4365d7e3663", + "00880e3095534192973a34ba730c45c9", + "b0afc9636fea407a88e11dfc77374b42", + "9df0c703101c4ecf8b1cb43868ef782e", + "ed87dd37c84e4a33b28b511e33213052", + "0adb377236c84c55be35878cc4d2a18a", + "84c96689f7aa46a98378416ad7080219", + "7e34337ccb444c3a9b382c451ced92fc", + "6260fe79ca464446851a284e219c994d", + "a40018de387741f2896ff58948b93c40", + "3fbb173debcc490bb4a7959dcb0b5c73", + "d0eb4829fc9242dba0e592d553786f3f", + "b3a99e956be64ab6958f7f5e1895f031", + "aaae2ec8372c48ddadd6bb300ed11ae2", + "ec0ee0b69b6a4400a59a7b1bd99c80c5", + "cd55852307494036ae51c36867d7ee57", + "a977eac533564fd5bf83dd0ee16eb1c5", + "c3bb117172b2403c8db450ff57f76d09", + "b6c610357217437fa0cee2508e329e65", + "cf88ef06f28d446c9c660bf4b6496587", + "50cf455eff9047aab0900846f54afd29", + "7a01461b8659459eb399d632b8e32916", + "2b3b92dc69b8456b84b78b3a584490b2", + "2d23c0bdde2447ba8a80c6e22cd9cb6c", + "16fe88505c4644bd8501141ee1299578", + "9b1dd1cbe57e4bf7a8a4b1386250f2d4", + "bf76ef97ff844d5ca9c0de2e7985544e", + "22a22bec3bc047088957e731f1294aa4", + "95c53161769f4c259afbb41bfc94f5f3", + "252ad3b345ae433abdd92588b2f6e34e", + "ddfd0b9846c24a058874521e9d170bcb", + "59658925b3ab4cd18af03bf39c477616", + "756e40dbb2494b6b8cfdecbad8832f83", + "18f92e3a7aef49428dfff3c9f6257789", + "9bf7126cbee5479a9b79564313a51092", + "cd8f49022da04835a309824029acce1c", + "3a6780be3d2c4a50bc19949e2156558a", + "03f68d5494924dd9bdf1d948ba873be1", + "b7f7ab9bf7244c3a8851bae3fb0bf741", + "f6037ddde37646af93249b1d4b863f1c", + "ba55d947880f4533a791b295f2606778", + "8b92e906dfd0480a98381cecb1ba8780", + "d4c7eaf7b1304e6ba2b2d28e2c7010bd", + "772b49c2554f41d78b4deb886b30159c", + "77ec82269caf4d32ab4a40f0c5fdcd5f", + "01c77468a1d04414ae24ecd1d1559f7d", + "564d8a247e034178aac9fa4358ee070e", + "711dc79e2ebb4090964f2bc3fe44e162", + "ddc43d4a100b4bc18598eb2df839a409", + "4fd347fd9f3e481186a7f167faa80ea8", + "aacf30223071418eac0484c95c24d46f", + "de5339b5ac2548e1956264281ff2ae81", + "c0b33a7cbd184b82943db196052a0f52", + "76c7e3b25a21457287247908d51ea705", + "bc001ab61e0145a2b74fc93181171f0c", + "959761b5ca964169a48593a54cc45f26", + "6210a8a2024144daaa80610d8f604e40", + "64402258bbcc4c99b648057f8bd2aed6", + "42563f454a784d2c9bf6c473e452e088", + "615f08a721a345e0b79e02c3e9af4905", + "c8fa424e650c4125b9a080f633a21721", + "63f071b5c74341fcb4106c8975725f12", + "a92e18aacf524014908f240c1ad2673b", + "a265f9af877443d3abb04b8adb4840c4", + "677ac24bd6ef43029856711f76122375", + "1be1cb560a934bd5a4ef6051b90197dd", + "5987f52bad9f4c3dadb0e4eca2b35b5a", + "4afaddf0129d4aaab7947116bb1c89dd", + "e29de3f42b7c4f869c4edbd0e9676105", + "0273352444e14e8ab4f484679ff21ebe", + "8712e8bdc8604d04a76ec43c22edaaa1", + "ec072e396cf44b329a983264ae6f896c", + "10f1047b46e345088f0823dca575e749", + "8fc32344d71342ccaa3b2e59a9fc0e4e", + "c29dd1d11bf84417b9f69db247abf0b8", + "fca5e4efc95846718eae77dd1df32c12", + "444eb7efb67b44968b62d920b0b1dd06", + "a5bec96e55d540ad8c17a3711dc5a239", + "56cf7ae89bc8454496c330e451ee56a1", + "008a72f0e6be408cbf90c81966789547", + "001559b408504642831e6c604eaf583f", + "475a9c6f93b84081ac11fc69ec042255", + "fc655111af5b49bf84722affc3ddba00", + "eb8cba7322ee4827b92c539883638474", + "ecc33fdd7146485eab310921c2368016", + "8f38fed275cf4617b3560909be4b07d6", + "51cfe336d19243eba66c5fac64a81507", + "f723c6203a564ed28ee1f186681485fb", + "710dc11a32d74230afa36dbf766837ce", + "abdbeeb5609c48f9a801107c3cf01174", + "70c2a47dce0448e788464b7bc6a8d476", + "99a0849e8dd24ecb82315bef50855080", + "21e1712c27b847e393ac39214f2762a0", + "ffb0d644238b4c679658aa0ee46ac6da", + "344393d397234baebc44c21dd18cd2bb", + "90e33fde18ae4c8faec22d16b4b9329f", + "dd0f1c4580ad44f3ba4df566acda4e8f", + "555da5d0183a4b13901999d5a58ae746", + "93c4d8ae7ab94fe7abe9a2fdc84661e3", + "f1aec7284c034d7987681873bffa4f5d", + "034f2eceb09c40cd9d559268412a756e", + "9a9ff69080c1464481bcbf12e7870d06", + "6555898f925f4e8696932f048ce4ead6", + "d3e4cf45c74b402583c7c6892261ff05", + "fe7a627ee83f4af192ca74dcf10e72d6", + "73e3fa8100a345f2a0c98259ca6c59f8", + "43906294a78b405a804e244a12da2f8f", + "0ac0fc2c5a434f54bb50260741d214c8", + "71e75c9cb3fe460c9549016297e694ec", + "65b2d242268344a6a3e64b8097995823", + "e7c2ddf2c5a0415a86b6079b91e5d225", + "163ce0c92f3d49528497dadad4e7ef75", + "a6615ac74bba49d4bb77092de480ba3b", + "e77268b46fa549d1b611d2429b2201c1", + "a0b900d9de78485bad2534a88e2c19c4", + "f112bf90127f42ae9bb6f06b45438789", + "3a49ec760a0a4c72b6308635f21e0d2d", + "ade09852fa834238b68f77a223946c16", + "9ab0dc4c98cd43c08b25c08066cf3962", + "81775cb63f7a492eb98d4fc352928cad", + "12541303f4454268a941b06ee3581427", + "ca515beed1f847619db60b5d10f6c8f1", + "2722dc58295540d8bcb73d519dd9e070", + "95df86860aff4dda995481ab7cfe0b52", + "2c9e9a7374334d55a6a343f2abf40618", + "0b0bd9f8dce44391a7093b5efc1015a6", + "20a57636ec0c44c996e7f36313792cea", + "13bb50338ab84ec7938c9230df1df550", + "fd8c3845db504a03bac25b946afdf9eb", + "0712c3b3f6484f1f86cb59ca6bd8f0bf", + "15a85ff13ce242318af466c9a1caadde", + "99508a5ebb704cd39a8b08c9a88ca54a", + "d1adae753d034fc7aba1a2f8300e1df0", + "62808a566e544968b1a0c2610fe47bd4", + "7f9533b92f6b419e8a924c52e87a275f", + "e13434a196e842b3980aef22835e4ecb", + "4ce98baa83ad46e3a9c7778ee6c47270", + "6465b89b6ad4499993c90a39d7c512cd", + "8bdd5976c0e54b4fb41fd8cc12fee52d", + "2ee564564e374a6f826bbdd24922ad5b", + "e1eeab2a570d4c2eb22d917ea9806d4a", + "cd39a79690924f15afcdad438ca737ed", + "5aeda66d1acf4fe0876ff80fd7eae600", + "310addd9d480470484bad732b7a44bf2", + "a8bf334c411b4acaa2dcfc827f28ebf6", + "2d9ab1e838634284a373c63679980e53", + "747fe8f37183402fa2f75bd5129c9d6b", + "631912edaef947f8a345a41f16e15aa7", + "155282a31dfb4972b4ae2e3072d281d6", + "e119e1d33cd3427a9b5f94cf1ae888ca", + "5968803b2922459fba85c4a7ac49347f", + "70d6d27b8f2c42c4802f7502fa7ec1e5", + "f5c8526a14a946cc8689232663e6392e", + "a02bf18332f646069e7f1ebaedec9dcb", + "422fb4ef72de4ce58a29b80944ba6084", + "f6dae4cbbcbb479f86c126db4a9f7389", + "67d56be999f64316b067acafd72f93a0", + "22db3637b9e2454397412aaf6e94706d", + "bbef506aee0d4cbcb1a701c80212b57b", + "f028f1329b9c4ccf87a6298e5b706675", + "24f040d86b254a5cb683fcc85576dbf4", + "7a1fc54af5804aee80e346b3f50a3fca", + "0d5dd4a2a8bb489f97acd88f0e88c1ff", + "878ff679e85643f1921552045d049672", + "ce5e5cb72f104030bf0c127dcc42a1a4", + "e0a0c576b0d443bebec317bed1e82a55", + "e767a862d98f43788c8b2e4da3f38a3d", + "94cfd6dd3f5d485386c230a7f6dade2b", + "0fa50cf622f44f2ba59eff6c11cb8fbd", + "0450b57c682d4454b3beb2f8724a73f5", + "f93b3897c6e2438aa418409482ae7621", + "f6c365dd7cd84a26ab125f0a5fae2448", + "43b48030208f4fa9888ede102c97a8e1", + "a6169c80ebbb42888745f73db2aac421", + "4f70dc3b5dc649c48ffd3e43faf0efb0", + "9cb02a87e85548eea8c6a46b027ffed2", + "aca2da24dcfc4a0b9091151745e5124e", + "c6efd7a599514ad28d61e826ae88ac89", + "9c8a1bb6967741008167ff3057563d70", + "1c4ceb980e174dc5b4cea84eb023983d", + "888788e1271144bd9232317b6d3bf92e", + "14f732cb083e47cf8cdd9a30f03ca8ea", + "ed916aaab0dd4bdd8c04ade1d16fd05c", + "c5286827e65f455a888968ed87eafa00", + "9c2cd3d3d14949c79cead951ce64261e", + "c50b853f8afa48eebc73e2421bde5387", + "1aa88f57eb3e4e36ab1c512ad637a366", + "b05e151bea8c45a2a4c8e92ecd2096f6", + "2a74e808c7984b09a13f4daec0ab373d", + "7b18c069265a4ef090f2b255c62fbef1", + "40b15a403d7341b0beee9b8132245253", + "1769a36326a04913a2b8bb0ca47e9e91", + "93f2f1d1fafc4baaa435f1a32870b7bd", + "fce249b02ae94608a3f2432d67b4dafe", + "a044ea148b064d22930b4f62f91df7aa", + "64cb216d407849fbb6ea86cb14d242e6", + "c7c0abe69500425fb98b14b8a7398259", + "d0bf0076e829471a8b7ea85dbc32b363", + "017e924d8918468a8c0def1a895b8f37", + "e14456d485ef4dff85107c69e0044c08", + "d570e51c348a41778f8f6d8ca88f2791", + "0f3749cd30f143f9a3f2ae50fd8237e9", + "f41e4adc95134845a92d0f38084bbe3c", + "e373032ccdd34ebe8213d65e2213025d", + "d0ca606a36584814a3464a7e82bc3691", + "3ddc447760594bc4a18d56c4916e34f1", + "e885250d97774e46b5883ebc59b632c1", + "4e4b8731493344fdaabafa2290e72faf", + "af4b617beb3f4c10bf3e005d6bc39550", + "f673865741ff4a878204ed6bf28ea47d", + "ffc51622ec034f1db7c9d0b9a1e1948e", + "459dc1bd4a904836b12856659841183b", + "143f5f4f00c043d8b18b53a13a85b906", + "f491721d52024dd084a942de34c79647", + "1fd66adf2bba4caaa2aac9e54c424b5f", + "7b1b08aaee1c43b99c2d6797a7ee9c34", + "e9358174232c4e5985d93a023f78f36f", + "e4e30d3dcc8a45a1a2d72bdc9d61232f", + "d65406a1c74d45c1a7e565382e1fc6ec", + "103b63c05aa240ff8d77e986d7e74222", + "2e5b2435af10441aab8ce9a3a1607c7f", + "1b99c507298a43bea0644669ef518eba", + "973507d6b4e44265887f8feffa6de13e", + "eb4c0f07698047f39b78d1bdcceece75", + "96279c51379440b48577869ef83ea9ea", + "14bd62d90f7f4a8ba85d5d05cb804421", + "df469d5206f341d9bd93804ff63f6855", + "578e2bfb9c8f415d932527a938e2fc64", + "b56cedbe3e4345cb8ea48f623c329eb8", + "4cfaa7840e4b4bd6ab812c051454be13", + "810f897e3d264f7a8daa4e047b40582a", + "1147c87f17cb46f6b0b2ee2e6f5dd6b6", + "cd9669b1922947ae8764c6fa5bae9920", + "cdf059b69987467cbfa874e4df00a44d", + "9335eebb9e3f4cdebe30fbe0782ad8ad", + "a9699ed151a5481ea8ba2893b16abf6f", + "cb4ad2c1c474446092973ef085562c1b", + "f960f2a43b3d4539a2f797a560b2fd82", + "0e5815d18235404ba02e3fe8059c2920", + "b63c076b1f2d429c82484cac793742a8", + "60a6471bad834ba5881d55e6125f8556", + "35ba4ec704144c079dec0fe914b34792", + "h8G3IqzmKOMRsOS2iiuq7Xs3wOV", + "ac650e2673a34d3d882b5e5e7b09616d", + "56f5e7a6e4fc43759cac4ee99246a98b", + "941ff92e34a74de8aff76f66bad1c4f6", + "0278450d1e324c33904e160e115f6fbd", + "825eccb3b41c4a23b8bc89a28fb95122", + "79fd371f7db5439e975242908dc8db44", + "a2db315fab08485fba53a2d2b790c219", + "03fa59009cb344ee9241128bad9bba13", + "52ee3e1df0994b0cb451a11b4031ef47", + "d08bf7f2725a4b938d6093344e841c60", + "aef09725cfc5489d85f0b3cc74b4bcd5", + "e08fc7be68cb4069977ba85135fd7d98", + "edcf56d8772a47868a6da8dfc1a42694", + "b55517c209d74762b371bc6ce0d1e56f", + "2cc0b5c6e18a42d7beb820cab9525325", + "663fe416f86c48dd97e301ec50a7c5cd", + "106241c92afa4f769545877dd35bfce2", + "1105316bd6ca4b13a9c4867519744562", + "d9675ab05c39447baf27e19ea07d484e", + "3900f4cd73ed4dcd8d7ab20ce3aa2549", + "326640737f324e3a9c68fc23ffee4993", + "27e8bb3a04ed4906bd75337b302db98e", + "eadf631145d24b7789b0fc82648833f2", + "d040d73eb9914bcca943d9062f50a114", + "8c6f5f91a5b94051bae5d3be0937564a", + "cf3b18862d1849168c31f7fd6964c925", + "e9f1254682ba4a4988bfef57b060bd5a", + "903d00bf8b7d4a338cda67aa82af3e4c", + "379a041a45d646cc94419609eefd2ab5", + "ef8bb402335c480ca49a37a859fa8316", + "7d22c31b7af049d69b827b4dc23a04b8", + "f07a603c3542407a926336fa5308b471", + "bd063fe114ff4208897d69fa1818a7e3", + "893bab3514bc4a84a580fa9d5dde9e26", + "ed407fa514b84be4a703569289d1882a", + "c5f9a51947ff46fa95c60aa2e5cbaf75", + "15d00d76890d458ea454d34ce08cbda5", + "1f33e40c27fe451e9efda612c69010ae", + "406ab7c30cdf45c3902a868c89873666", + "a19916a62ebb40d08d2f2c7cb279de1b", + "47d9170392dc48d48d520e271e5820d8", + "eacad791c62b46859a724aceb4948953", + "1a5a5dbdb6de43f7aa9dfa2f31b326b9", + "adc80938da134b18b063d8f023871353", + "27e65caad3b64e5189c7fe094429d6d1", + "84c4f27b8eb84938bfc2cf36944baf3d", + "943a40282a624a4f9fd3b10c0ecab603", + "46a74e2eddb64b0ea5283c09c8704178", + "0637543be6bc42a89d8c76b08395b6eb", + "804d6814818247978f28d12efcc38cce", + "ac8ce1326c604a7e87ad04c121b3c5a8", + "c54a7f8f0d2048e7b3f897ec497c74a6", + "a3cb24f8dbe6422082b4c1f6bfff8964", + "f5ba42c4d75747268b9883b7c57a5669", + "3a9a95549e8041fea11d9eff5a09c568", + "2eb8dfa311bc43c39dc5c00069dabc21", + "4dbf4febf1ef477abcf005c94746694c", + "8570abffad304f419c112fa3d5fb69dd", + "69f1a1dccffd440e91dbf89ae2c11ee0", + "040089295e3a4ee684d4562a8fabce9f", + "525fe3caa67f455d8f39605901163f1a", + "62ccf31cea504154b1facec0dc267a82", + "35534127707243d6a40ae3bbcf461d7a", + "6cb49fc6c1e14f54a746fcb969741cf0", + "6559c012155b4632afda8924cd3c8f27", + "3440371ac8ca4a9d821c649d7bffbd54", + "a6e2f8b4591d4fbf8a416b2b2b4fbd9c", + "03e84c43e4994bfcb851013c7d7791ca", + "5840ecf70ab146a39548bceb9ffb5426", + "056cfd8c9b984719b1f96fd7829c981d", + "424683ec7f3b40b1b5f6aedb557ba47c", + "960bc02f402d4a3b84083ee97decd923", + "1b89502851754885934d3857e0cda3ae", + "efa9dbd09d3d43a3b11818a436b42854", + "d750992c125f4b20b7ca6126d8210ab6", + "f2a920d5c2f7423dbda874f42ae17d0d", + "d759bc8c6c2544268f68e7db06d47f25", + "befe18817b094900ad2290654f655cb8", + "eb11d4ec4a97447aa949630e372f86fa", + "50d0933375b7451cbe87aca53223e154", + "6b452a27d5a34328bc687da9c4a44589", + "e7d86d674e934510bf8a228893729303", + "8429c06aa970491089cee1517ccf47b3", + "eb37bf62437c48f291831d9213ed0df6", + "9d49a81015a641a3b9f89d1df65da5ad", + "0ea43f7fdcb7411cb1123b987f297d41", + "8f5c8f6029264bb7b9064fd2fb491ae0", + "4ceb76440e1e4825a10ff9ace48adf26", + "fd8e300fe0094f8283e0269686daa8af", + "d9ecc99108a643ab887296cb986be937", + "f8a7c8c0e7b24404a480d893df8b8876", + "b0fea0d8a5a54777acfc99fe482adccc", + "6709e9e4cbb14dd59bbe57bca8763e61", + "2246c91cfcc1436b9824e56fd11fad66", + "04c00fc6f81441f0acf9a1d092efe830", + "223acccccba84344aa3eab2f652d265e", + "336724b1ea224461846623cbac4b6dea", + "97eed67575434859b1ac2b2c1f6a8380", + "a49fdc2052164f09868ad97cd4401248", + "46617e30864a45eba268c756cf53c52f", + "4525bacc7ab84869b3384dea028d3f65", + "65bb2a14797947849da7160651d814f6", + "30990ba94fa2430ea5973dccd98c0148", + "7ca2a506ff4e41cbbf753deab443d911", + "b1b610c7c588439d822e4af729c2f5bd", + "410249dc4e4642fbae64a42bc547e17d", + "8c7296a58c654a55bd6b80277f303e82", + "60fea268c6cf4dfbb0d9e46ac157f2d7", + "5882f74fb1444037851fb12c1572a0cd", + "c921c626e5d8417580d2f299dcd638f1", + "cfc2172e2c414b708d8eadcd38d27b0c", + "781a7688333545eb9ad14a358fac01e6", + "6f79223d321047059e1032c78b1b00a5", + "9cf4dc774cd44741b919a44461ee539a", + "c6a27922749448cb9e04442c32e49fd6", + "788da489fd18427390a30285cbb1992f", + "294e2950fae04576bfc0adc240701923", + "4059fe481e754d588cbeefd0182b673a", + "eb45f914e58f4e3f8ebcc26725cc2d59", + "f31b9e74b6c34285af8a1f5ede6da95e", + "887ce59d9c564670950c6d5980d00a52", + "e6a2678396b844f18ebc57c894b24181", + "53f747f6c74249c0a86bb19c510c4a64", + "776462432cff4d6f89ec50d6a3342eee", + "5276969a17d24f2ea33e57e9c78c8919", + "83fb7c6aa6a94336ac24d156f479c7c7", + "5af4ab6f66e5408ea907d355df8c1387", + "8dbe9bf2af2342e5942be8770f7925a5", + "4622e88fd9264b37997671efeb73af85", + "44425b945556456fbb25de1042f3e5b3", + "ad2546804e8845b09e5db7c6db16b704", + "c18d2ad9c6314943b32c4fda3dd7a231", + "4bb901d9c7fd4ac7a5a02e383361d3cd", + "6a7d355f7b214cdaad689f7f000ad1f2", + "3ed3c416510a4edeb03e82e1eb0d599a", + "2d27c6908c6d44cb8a624f3150ec1fd8", + "d325e4bc8755423fb4731a4ce6ee6c3c", + "0f2ec471c84949d681ac443a458afec8", + "fe88a013b7fe4a19970cc12d150d3859", + "cb11629761c24445a3d78806c9a9250a", + "30648d8d500f438a929ece1d21157196", + "983aecd197b742b3a61e7da0565021a8", + "d3d0df59d20d4452a2165a4c76f62287", + "e378a4f6f2454cfd9dbd9297a235c26e", + "b34d0cba655e46c99070fbfd1d4e4ffb", + "f1c05b3206ae4553a3180f8467ca8fe3", + "8d89bff741d1486398a3a1bab4626abe", + "04a319096cd1428a9c5af4dde414a7d7", + "d497d7a1887c48a2b34ed822f7eecd84", + "1e2b45735eb340588a4adecbb4bf5ef0", + "40377ca02ba74e2287f2139e92048c5d", + "12998bea16ee4bfba0c6b67de6499f51", + "a5bb7def7fe745829b18361a830d0ded", + "fd3cfd62673342f6bb7a460897153ad7", + "2ce176f569cf41709629e713ece8d1bb", + "c9cdde5ca1454ce784a8f278fbda90d9", + "4487ad10f7464a6c9bfb0aac6217a989", + "9f91b85548314061a7b05d59eee5f7aa", + "cc9fdd9ba026488e870ff7a7949a8968", + "dc688ff9c3ba4a8dbab7280c3653cb09", + "111fc5314dc64506b0a058fd48d67637", + "f1f9ffc006ce4b9c8661ef9a36951f83", + "843a674e45c84003b6c616c6a2bef715", + "155a93d394c14699bc261ae3fbbb3f08", + "db690e8aa2d44b8fb362422b8a242eda", + "ef4db61ebe434451b8addb4ae0f22b4d", + "0dcd58518f924ae3a3457151ff94e8f6", + "042691a0afb8497798bc50174f633e68", + "a77d9a22ca964a71ab23519cab124ff6", + "96e12eb5891a46fca80207b73263bc6c", + "d48422d3febb479c822d39301d1bd3be", + "bc47e4a25779449c8653c41c96772cd3", + "03c7117f045e473abfe5de90c5a8319d", + "933b943b67664ab692052bdceaf11f4e", + "e9d9f54942f64b6084fc9567a98ddde5", + "a6d79e13e935421fb09709cf9923c9db", + "977eeff67a6d41c39d0bc5dd96d71e1b", + "d0e07b22f1d54b968943e7a896235a65", + "e7cbb51fa34240c3b6a8ae0ebdbab1e5", + "763fb4fd5a9746b880fc44251625b174", + "84603358f4bd4851bb11fea66cd50cfc", + "71ee5cd84e1847369695c2f3eb6a5483", + "2d3e0f86b8524aa3a8be7f7df438f1f1", + "03660ffa531544339c8746504286fe78", + "e526e7e23e7d43b5bff5b579ad939e5d", + "8f67cacc8bf346eca9feea02dd56960f", + "292a4c1fdc8f49e0acdb1325fccb56d0", + "d4d822cacfa34ba78d495b2dde7551cc", + "9ba49bfffea1433a99ad0377ad57dae6", + "75386b041bde489a9f164be51791d1db", + "a0bf7bcc50f04a109d5212a6da0c3f4a", + "65d9df0e7e904cee890892f6128f3de9", + "324b2ca5551546909dfe74dfceaf31db", + "039171dd98ed45309cc62b7a0313fdef", + "f35d482c75304220b7fc2c60596683fc", + "e913c3d127e04b919bb9e9b416f47da8", + "ddf5b0d6b27d4df19c9a71570fcc32f7", + "9646813e492b47fcae126b2491554991", + "87409d43659c4de0afa1c23f04b8ed88", + "17a8134052ff47778a21cd3efcfbe916", + "cf869921585c4ab7ae8c85d18ce1349b", + "a4c9a503f63e440e8d6d924d4e5c36b1", + "b4ed18118f2249b2bb28af78b7fb7a1d", + "9c68e7f437b84f6c919be9f59ebb06ab", + "56f9038d53634c48a57195f5927d4ef9", + "80382232802446e09d91b452b5198a05", + "3e7a5c85871d4b59bae5e2191d975039", + "07fe989ba464464fae6943445703afca", + "4da95996e46c4ced8d59f6f4bd0b7295", + "ecfb6d71926948b38866255ac6c58673", + "0bb7db373532482d8520e8ac109394ab", + "63cb1eb1f26443be927185e9e0e49e26", + "d5d4e84c005f4f3fa69646d2e21c152d", + "631b573d26354f6abefc05f8f5d19364", + "99e1ab7d0823439e83acffc1ca6a1b13", + "765572af5003423aa4e18230c4620dc1", + "ba6bcad73fbc4da0a9de827d2a698c72", + "7ZA2tOVNoMbYbll27zJ0RWsMdxC", + "c21c6f6e6d8b4f718a49291e12f67b76", + "8fd4c03663424c6594110639bc15c5e8", + "a3edd70e72014d3fac5e0dc1b4495088", + "512e5e98e7b74de5bf6e23c3615c87a7", + "fd85de73103a4940a0335b253354f2d6", + "c8bd51746dba48c1b6dc014a50a84aa3", + "4e3015a1133a486ca595b356f79944e2", + "1d93b4117b014f6e882e0c0867ed9b04", + "bd22d0fcde954aeb8ac924f729f83a93", + "64a6fdc014054c60b7aa38935e58d23b", + "668e17c1b002416a8ab2df07d501dffa", + "8e2393754cbe4ca9b02e8731e9723371", + "b895a08ce1a44cdc97bd83b14b0eb546", + "be3df0c195494b539da8a33e4706292f", + "b5883c4ea9ce48798274f0500bd12d1b", + "2559b69c225a482b9539ccb40ce11f91", + "9c012491312b4d3fbe856a2d802cabc8", + "caf84f961fab412e8260be1d20734b8b", + "445e0f3ea0254925803a447caf37bebc", + "bdcb485bd6e74550a091e7a47eb87660", + "7ad429cc08984766a0fc8715e3029a49", + "1af68ba2e4ac4aad970612b6c6b5d07d", + "9099f14a50194c6da24a526877b28066", + "5b4cb70775424665a3b7e2fe061f5004", + "d871bf2f8294452294a83c68a6a04576", + "16816ef54ff24863a8b4384bcf28b41c", + "5e87752d56cd45bebaeac48ba934aaa4", + "fa2fbbe8e8324919b7e8a532fab33724", + "a995a9edbbeb4adeb697417c0f330c5f", + "71dce3dd627146e9a1e4776a490e786b", + "b6e6a061f91c477db1a6acb6c0637dd6", + "61d188cefc7a46f6bfb58a8eadaadb16", + "6a5fda0bdaae46c2819fef80039cde4b", + "3960097528924a83be348d9d59995ed8", + "3b35271f1fe84fae895a0bdd998fac26", + "f74b285829544e37bf463aee9ae0c1cc", + "bfc85c10545141bd9db10337f3ac26b3", + "15ff2ed44a8142c990ea369cacef9dae", + "0df9dfb6279444f19749b752b0a399d1", + "7c4ce8f97abe48b2abfbfa6e1c9e1549", + "63d0f45e4fe54653a1e0f738048d2937", + "289151e3e35541b4a3a7d2bb89acb90e", + "70b7081f32c94e169ddc08161648f9b5", + "60a53d04cae34dd2b10e29ab28e7b063", + "4b8d86761f9440cfb324d0b4d07336ff", + "a01169ed9a0c415aa383cb4bb9ed4c76", + "31139a065546483588ec923fe4e4361d", + "84ceed6e18b448bb84cb221805b3e085", + "dbfc1d7bff354ab9a3f4e786390a85d3", + "3a109ddd80bf4c479b5030c87e3e1707", + "83848995cbfb4727b2b85ca713363d15", + "8e482e714930455691995d417c688791", + "63b6554d951144d0be5c5ec11cfd7810", + "97192ce70f1e4209a0b7de05084a7e3e", + "84419b89ac4c45b1b2ac697dc6ecd974", + "bbb6de7d1a15492f870b605f2e13c4d3", + "0bffe315f4644680acc6ed07f9f7d488", + "85eb61fbe7144faf89117594ca3a5844", + "87b32d45a07d47deae6516351c656151", + "18d6d563555a423485104c638a5e3d57", + "b2fe4a77844e4cb3bbe3555d9cb53d98", + "93ccd8bac0ed44c28ecfd0d60d8ceace", + "e51c441a781d474d83b44b7dd3f6eb32", + "228e3afd6bcb4f9c9e9f16176c3ac7f7", + "1761baf3b8464966aabf22b5e48013fb", + "1c07b3ee4d69451faaa57cc49a64aed8", + "2eb74b9524164d418c16c2e5d40a27c4", + "dd0a255416fa47ddb9e5c179d86ef437", + "f8d34218f2804efc839e3707afc31bd5", + "59d240f56a7e49f18704e5a6958bdb2d", + "7b9e48f7a223455aa9adf5115e4975c9", + "cb7c881d8cb149ba86bd7ee3f3a800d9", + "4fdc700453924944912e87674dec95b6", + "4422afe841d346399e52938b929bb62c", + "6794751c282b43458a421155eaa14b69", + "aeb0bdfc5d014aef853cf20cb8a26f3d", + "25efa96c3840472b98ac7ab41a4686eb", + "0db14b0861a646c1ae206c465044752e", + "67ea22ca4cc74ab6ac5721db2dc598b0", + "b0758b57a3624166b08198537561b947", + "02d21cf6f03943a8af560813295b558b", + "3865646d6fe348a5a928867ed299ad8f", + "b4cde8b1c6a744b0a91e322e672020a8", + "7886c8713f39495f88b84e882592e0a5", + "48461e78135844b0abc51c2369644b4a", + "852110f8f33a4b68b548f77fab0505f9", + "834d4579731b48b0bf7df45889746487", + "d16f1d8a8c2e418fa2ae54075147e2b1", + "ea4038496c9e4cd2a72da94ff04f3daf", + "a006b01175bf41e4af88a059d3ed375d", + "95db56ed18d04d96a394675ae0c7d9ed", + "4729b1cfa5b74db68924190242f8ac76", + "7a70d85f889642d6868ffcc3f1cdd27d", + "8aa66be29de94480bb28e42330dd6d80", + "16c504d81f5843c3985d7f208c27b79a", + "72e737a82cc24b78b66b89b09abdb2ca", + "7bc76e4eef61474f970088eadcf82774", + "6f3b6984c2f74d64b08833b5f61c2253", + "861ceedf64914d849a429f5b49cbefb2", + "dc883f9b758347f0a83235c842120f6d", + "cfbcb02c981e4a6c92b6c86fb5ced91d", + "7f5794c8941e4e3d8f64bcb1a5e205f9", + "3f67f11540da4e4f835ffd97982a1582", + "b05862a2023f4c02988b3bb3004f6ff6", + "504c56d674564b90a0d0a783dc5c381a", + "a42165affb1645e8a63f523116c11975", + "1702eee5b92b4895a5991383b624df90", + "93f7603fbcf845078576cfb8ac7f6018", + "3a3f5be2703b412a83de78bb98b8561d", + "c4328357f068460d9cba2a286ecb5087", + "004746f9a00342298c89eab88c5203c5", + "3a51cfca26b34da7a8ac02af373cd130", + "a309b78e26f2483bbc50a78648d7b8fb", + "5f112aca4795426f99561fb92af995f6", + "8da66aeff1f345dd94d4b8355412bfc5", + "7c62c37ffa9145ddb309b1c60ff1f3dc", + "ee9ce6c896664ab6a86a0c3f9d52f276", + "9129e7dd1a864b1c9134c4224971335f", + "13fc708a29054e0c86f886cd8a36191e", + "d0a0d5b16cb04793a743cb5a21022161", + "fb1b6fc41f7e49adbf467e5e5988d190", + "2b116c282f054383917cceeac221993e", + "dd8f4c5a104f463992b9d1d1bcd0c0bd", + "c92881ee1087451ea5eef053ed77e77c", + "ca5ca5f269e74ad9bc36a1e35d910653", + "96b3161ee04e4bb1854aece80aaf6598", + "a8c4ffddfc4448909b48980530256c8c", + "0e3abba220e94d15ba42093c782b1681", + "3f08a53550354e99b991ec2d43ff2751", + "29a91650db644ef8a2f6cd48ec556eea", + "d83948efbf134624aa6533b62f095035", + "c2b65644ef8e4cc5a2617e68f4ad79d2", + "9a643939a34e403a9965bc1eb58e2c92", + "d4283317bd544b3e9a2b42a014cddf10", + "5728d84ab9db41f2a66d57b0b913e36b", + "72972d93856f432983e56da4ddcd1be6", + "3d9e8075978345a8acbe7ad2d0ecff45", + "fbc2566f648d46a8b28624c9cf9fb218", + "09a76b3eb3174185b76cb04d3338d0ce", + "4b7a4a3611144ea4a619cea2ba7bfc70", + "e38101831cc84befb512c4637a7d481c", + "616e18c422eb45af9e1607839c5d5b81", + "bfd7866bf34e492fb9674b73f9f0c959", + "ab949cc33dfc4c06a7b79bbf8709ebe6", + "a43e81a6edad473b82ed33f9c2dfd284", + "2e141e091c2d459ab4d07a8d65b1ca9e", + "1eb2a605dad84949bbb8d4911ec41359", + "6a62d098e0c548e384ae122d0947604a", + "75e9b25b1d1d4c0dab8b4dce94dbd5bd", + "ba15e56dd0524543b089439838e903d7", + "6e9a71be6fb64785b09f2a4bbf2abcdf", + "5580f7c37a33445c8aa1afa157b3de54", + "33d98be6ffc84acb8aca4d15fb6c1755", + "2eba66dcf9eb42a98f192230620ab52a", + "7b3bfdab414148a08cbf46fc105e280a", + "c0acb964bc584b529440e4c03a1df548", + "a2d0c23925354a23a229fb6a883babd8", + "5b797867924940dba3d2abe124d7ec63", + "6d24a8da0d684ee5a00f7d71b6fa74ca", + "eb7bff482d084c17bac645e82a7143e6", + "539cebec2d764beb9b98130ecbd2e524", + "9d3cb105a87a4cb4b79c5cfc093bd5fe", + "a73c177b572c41d49f260f3ba17fc757", + "4fefc6a5fad443b88c795a0d8bdc440e", + "9844e42e158d4938a70cbe94bba33ad3", + "e414718186d9486eae1fdd476ddc3151", + "a8a6874f62da478f8572554959d3c62e", + "43bd716c4667417fb315a73225a78469", + "b02fe3f92dac468c9f2be8a88adf71db", + "d923014b75ff413b998876929d6fb6fe", + "1d3ed42e81c248cf809d39e8cd1a55db", + "1b6077a0a88a4033aeb654b6cfc87224", + "c88127d8aa76405a9831da834c00e1bb", + "9fbfde79f5154d28a921b2d8a51b45d5", + "7232408612424923838e8f67176056ce", + "0b1b8114e4ff41c0802a901442abae79", + "feebcb78c6c84a958d07d5e3d0542e9f", + "62fc82ddd5fb46a2a0eadb06d493e194", + "f337235e23b74adf8dec003e883e84f6", + "45a9e6b3ceec4e7ea1d3d6b691c3b713", + "5db43db370394c7481d8b28a30b0858a", + "a3fc2ab724c949c5b38d2059782906e4", + "e2c1f3a3079f410a90ede41dba8c4b06", + "95f1afb745b948fd9bac0908b6546d0c", + "cf6c7f069ed24ff3a2500cc0d6673afb", + "c215384fe4f445c096c050dbf45f691c", + "6d4d4e9294a64d65870c401005cbc0f9", + "e1041df2af4949fe80dfd7093389b19d", + "ae274daf47e341a6bfddbb1b47e73f58", + "e826c513779149d7ab3bde944647573f", + "1dc9cf9b1e214359aedb021d1467f5a5", + "e4b78578e26f40ad8ccea282f182c3f2", + "d28187d5ff084832be45c689ebb3ac20", + "fc5504fd32fd4842b5cfb7b49a88c437", + "c17637ca11494004bceced81e1fbb621", + "6830e31c6bdb4829ad39c01facdd9859", + "9a915eb89d544ebd9a8ba06f5e56ecc9", + "50263d30b5924193b4a000ec7735ac36", + "2d2685a7e6a04a7888fa88ed1d6237d0", + "5d495c00d096428f8ab858d3145f2b62", + "58b875eb8678462db567694f9537b79e", + "29bf32135c594bf5958997d55c5c9ed1", + "912ff36b32304bf1a3b7ecb50e40a172", + "d8e22e7fcbc04c4db77edb9df353e0ee", + "a466c040962649cbb20a256967652c60", + "243e844221d6435fa3afdd2f167ea2d7", + "b79e43ebf03c483b834e8b493af0033d", + "ed3357efe63547e18f5798b273514923", + "fd4c07f6eb4f45ac8c2f9a29c599daf0", + "8ae7ce20a306436e92e5684161068c3f", + "91dbbad6be8a4c0ca0debf209df0d8b0", + "c8f10fc275894e088e451453a2cab667", + "27e8c4b38f7148e583890661eb9edd64", + "7358cd3d445a4ce183a98e1a9fdbcc79", + "85a79f745d484ec08d85b29992d7d576", + "16f83d9187ed4ad2b15a15eea3ada950", + "4dbd31f8ccad4e6f8a9a4255d76448a7", + "f7eafeccb45948ac89f314f324e8c3eb", + "f7d2757432f94a2bb366c9a41503647b", + "3f99b067fb29498b91bc4e5843a4c94f", + "981fc5be149c4c9eaaafc4abd83eea03", + "4c8194562e1249c49da58b07b1fa05c9", + "26d3deae44af450a8c978031a36b2b95", + "ef501e91ba6641a29e0515a10fdac631", + "af7881199a5c43a499e668399aaa4a52", + "f04ab1e3e07f42c799c9415a4767fec9", + "b72c2a1e909a43a193a74827b214e718", + "98c7f8fb0ea049a0bbeb81628cb133fc", + "77552fc8fc4848fa809dd307ee6f5ffd", + "cc9d3e0368124bf8a339d4f1fc85743f", + "60a75dfbc31a4c09832eb2d2aee28272", + "d25283e6dc7c4af9858db4b33b2cd898", + "e0fd16e172564b44a8b869fd68307c3f", + "b9f64da5b7bf4aa3b2ef14567f404ece", + "1ec6b400d8ee4ace85244021c1e371c8", + "65046419ec5243ff862d3408b71472b2", + "4acb1491549f4543a0433e58dd397d96", + "2a79482cf73f453381dc73a3908046ad", + "593ae0b4fde44ea6b172bb5bc1769bca", + "1f6b478c21244d0eb3562d986c7fb8e4", + "1bcf18a4172348359bb9160b8c8828c4", + "76e5c63c28ee46f8a08650d9540d1609", + "0c4567b1f9a649e7bd268b11f48c116b", + "b414f6da72c54cd2870e1a72292e23fe", + "f446f48653b8462fa54bc3371e7a15eb", + "b0072ccebfe14f5fa06af5256b98236c", + "118f2109a1ac45a0a217d23ee6ed80a0", + "d6b385a5b7df4e5991cc527aa4696e74", + "741f01b969da4f1da568b2744aafa3ca", + "a4677757bdb6481f9bddeeb8eff95341", + "262e5f04d7cd480e989192dc47134f88", + "bc0e90729dd94eddbf8ddfb3d941d011", + "bca1d727739a4866922faa4a6d649d4f", + "db5759d94887424dbcf540ed9bf6af09", + "da4884486c2442b1907ce838284dcaa0", + "43359be26f7a4a2493337d052dfe1ae5", + "06ff5ac6e7bb4c6eb478c8e036b1241a", + "e91b8e7f53ef47e0a6f90d6268a2e156", + "d1e36cf1dc3343f69a287075a69faa34", + "f83afceed8d1483fbe86efcef9265488", + "0212e6648fc84e66b2b33b2c652055dd", + "852927bae6724ff9a9df05ff36de2dd9", + "11550980025d4a36b476dc8aca373254", + "2689d75e460a423f94a4076dfd8ad623", + "a96a84406c2a46c2b26755bcf8852e49", + "bcc1527f2e684e95a5e8c3dc85ab1c87", + "c24148fe726a492b8eb37c2b6c303fed", + "841cb663e5324418885f5664bba0fdfa", + "9e45e03e727b47adbc2a68b1db5ed53a", + "039c30f9160e4ffdbc5e9157ca6ce852", + "cdb31c25fe094a11beb0861fafda212f", + "6ed3b867c9d647f8b5cc3d290eec7887", + "07a97f4ecf994f579ac4ec70d74c561c", + "7e6cf10fd7fe46169d25f272925637f0", + "073626ba1f0a419d9938ff1e1b493aac", + "812a73dff6d04f24a396f9c8e131f8e9", + "a022a15441ad401aa46ae442b7e440c7", + "b4dc0da100dd446bb20567808f4db667", + "899587f5843345649b1ee069d8922071", + "8ab47cefbee841f1a56ec8e5a6ba42a8", + "c0c718fb01e8452bbcab5e7058891372", + "894c7d8eaf3f4591ac4d4efaa2b71983", + "d2b5e837a8c24fa7b4ed68a787d3679b", + "2cd59181404c4aaa995a0ea55f89e212", + "b1a5549adc74497e9cdb068476fc1477", + "d674a80e8b4a4c29a4ec8dcfb11ae2f0", + "051c3db9337c412e947887477a28bb27", + "b4c3afb8229e4149981b0fad3226c844", + "de79a920c48745ff95c0df7a7c300091", + "16c3444c8d1440fc97fdf10f60ec58b0", + "f5ac20ab3a984cc2a5a9e4ee72567bd1", + "cdf2b718bb5f45fc98f1ab0dbc2b35c7", + "9bb1437af6584898bcfeda74e93242a8", + "474d5e3e80b344a4a2b64a15c7dd91e2", + "21b3bf90e25d4f07af3bea232fbc239e", + "9ef6c018a8ce4d41824ec40b9870e412", + "1256cc8ac24841e5861828689a7560eb", + "3a784add78294c4e861c77cbcbe1c6dc", + "2c4af597b9864865a1b7365c2087a638", + "04f51877ba25493d94d05f6086492f37", + "621662bcb60a442fa8eee08d3eba4fc4", + "39f4611db5fc494a85cd62906629bd0b", + "00b2c8c60d2f45a893ee73fd1f107e27", + "f83d5d5e73d84b30b355881b381ada7e", + "5411c6c928a449fd93e5ec8ac2942a10", + "1ec8b9126eed4323aec245a3406974a7", + "895759c681cc40f7b9b2d6ce159edd24", + "ed5df3c3f93745fbaf61e4d66c3ca911", + "b095a072c707490ba8ff798e7177748c", + "b366398abb8e4422a7fbdcf2177e1934", + "90e76d36b37e4b89abb6223f15a314d2", + "bb06e5aaba054d8f8d1fbd7a87e4efef", + "b0708bc73bea466e94e2eae8b4af1fb3", + "65586b5f86b5481abb692b94ee709112", + "372fa5872d5f49bc8c1964d58635e7ff", + "8c900496173b4b32b8f8990c2d97886b", + "80aaec3ab8904e8ab41cfb18b754dce3", + "591f7d9f6337460ab1d93ef6c95e70e5", + "f2aa252f7f444f42812335e15f40d72a", + "6b6fb74103114feba100c02fc5b284b3", + "5665c6e3bec14190b3d2fe8f1e4b070d", + "b1eef8d330434ab6aec83cc171084d89", + "6e53ddefba2e45dda8e4f1c73fb89f67", + "abfa42baf26f4e59afb584fd9f3a9af5", + "1a121ba643144d7bb36655d999b10493", + "e9f91c854e83470cb9852e20e24c80de", + "af8cf0d4963d41b0ace60f063e468703", + "4c10d4384d404aba8a8740a380ad7cb3", + "3969fe35c6444293af27b976dca085a4", + "4a17a0973f4444dc82c327fe374c4550", + "6aee1290c4094c1480e32284e41471f5", + "935c106f6b264b3f8d6a66a5701919a3", + "05ec110c6ffd4f87a3828c128b2e01a1", + "e44aadf5ba8341aa81e5f807a375942d", + "aa422c90af77408f85e04df090e602b4", + "697c29bc77a04a928e085a79262c91b8", + "9160b0786dfc40bc9b27575e831e3966", + "1018d8d3266249ab9aaf49ea6509cff8", + "4bcebb1586f44beb91033df3b06bda66", + "bff3a33dff32414e83fa57e650e701ce", + "3f2eb88877e24ce6a3aa01aeb59d8f23", + "196bb78e6e6343888d09f468a6a9dbc7", + "eebf5f172f174113a6ab7934e3156fcb", + "20d07381f1cf4a6bab7a062d180e8fb8", + "2835f3bdc79a4e46aaf309cde977861c", + "0eba4cbc46c0487f87e002fe23452bc7", + "b4384cd0a4e548d1a7c8acc538b47195", + "51b0d8180a2540fe97b6b514eb475de7", + "fed6c4a6674948c092926d88346da376", + "63825c41ee4e4f63a5f655b930b3e960", + "ae63a2b6575147c2b705f8ee96eab451", + "86f58475306947ab814df2c87ac86df4", + "bf06cb24bf724a2b82f4b1ffc89ed0f2", + "a89edf41218a43c1a16d00e8e242c1ef", + "f965065b1e684e079f689287e5913003", + "6b36d2db270843a8929ad72c8a8faed5", + "668237aabbf54beeb347bbaa7be930c7", + "b46cbc5fe2384436b07d17500f8e5318", + "95b7126966c9479ea992f27ecadf5f1d", + "a4618bdaf9314a9bb4690b009503811a", + "c5f6ab6504f44b82816a9917f8b80d0d", + "d3d237dec0c843c4a04a9d30e80d37ff", + "ea80a8ffde494fb59f015565e4c16e2a", + "93350647843a468b9f8ac8a481321639", + "ab42a8f0f4a646dc8ac0784eed873f23", + "3dc3bdbea2724a48ad2c843c8a34bb00", + "23e04c6da9b343669cadd3553594cbb5", + "91cc585647b7453a81e302991017a95b", + "878df3bb45804a2fa246034420d03cfa", + "3e9300d4e5da4e6ba09ad16a22fd4a29", + "1f6a331e21db4f919f6e448bfde3a090", + "70907da426384ab19ccf4e9b0537f1ca", + "8c15c5881ca94ecf83a181be9731bf78", + "ffbe6bc8412b419c826ac9a3248f5c89", + "c5333782f49e40e8bb4fafc5bff63b88", + "2b59a1815b1e47a298d4a3c084523d72", + "58934369266641b2a7be80e0da9cb79d", + "937be548c2374e1d89626ca722b9ea00", + "30f3ee70d94f42158f634aafeb832cb4", + "cd956b2abec04b52ac48bea1ec141d60", + "e37cc2a1af884cd28e7266c989112d80", + "bb8b8dab8b4c4fc1ac6af310b70f1b6e", + "251901e0776d4c2d9592df65d125d880", + "f2d84c9ebf7d41608742f699acec629e", + "0e89da693a494bf98c717fba30a3676e", + "bb1023a8c09141d29996924e425fe6c5", + "70a574ead25844a3bbee633b202376d1", + "17645107e5224ec5993f131fd74e5b2b", + "436f908c0464454fae31a72c4012bf1c", + "8fd7e8f7b2c843fc94dc39808fb8e57c", + "a0c4f306d5f543c195c2618552134689", + "42cf842f793b462f87b35a24a88f608f", + "0a2d39bf74694906a69f45a4b99cc7c1", + "9983b66730814d769c42a84969590761", + "680a7c8132ba4b03ba3513570640d182", + "dc4ada286a514d85b7476f139bdd5e38", + "e3780256aa164b4f8c821cf9d81637bf", + "9b26f4a859e64fa392e16d68347773cf", + "c29f81f74f114c8480cb2106ec27a238", + "ae84745c720a412dbe254bb3ddb93592", + "0baf38666f4745aaa4e41c0e38bf1c71", + "8a0a232e5b7940a1a9bd57eeda05dbc4", + "68c578fcc46c4dcfbd8658823a36eef0", + "d80bfd725a5e44b2abfa639ec2087a90", + "8f9f88c340ec47798fa5cf07e92312be", + "fc0b0dbee5e34ab1b926117f49f53b60", + "a6ac36e6a5ec452cad3012aa12ee9cfe", + "7ac65580fd7f4869990e00a6957d1c59", + "c426f52c4b1c4c5aaef166c62612b88f", + "aac1fff2db8e4b808c1a553f9146d261", + "81c4b185fb174bdf875ed88be6db2394", + "13d164c01e6d4a7899551cf7577c6b09", + "147f57282f7046b09bc540bab1370db0", + "5fa7060601d9455987080fd4a91b3b1f", + "65084cd519324260acccc6256c4d23aa", + "3abcaff1a11f4d03842f9c8d73bb0121", + "2aa80df980d1408f96bf90adf16d6cc0", + "35dc6dfd128b4158986c82d8cc030cdf", + "e68c2fdc267f4aa0abecf82e1efc03a9", + "875aa3ff00fd47309b6afb3c055ed794", + "c3e94aa9d22e4adebae4d9d30c2c4047", + "f495b575f87441429349810173aba054", + "7cafbdc90628431980c0c8fffa50dd82", + "1f124d5de6364378bb937d5bf7c9da6d", + "3c7a36f25c5f464e8b75d69e69ea49b9", + "079e24f4748747d592f2f9bae01de712", + "5ad0fbc167914e02b0c27f2e779e96fb", + "4ae093bb80914bd9851a85570686efe6", + "ac53955cc59442a7aa190ab950f9f12f", + "726b0790815f4f8b8cba4ef0c87d97ca", + "297cc08b20b54c18b3d330d2b569b0d8", + "f4cc19718bfe489090bd68ef0f460601", + "44c0231a2e07494e99a50037d1a0fb0b", + "f339a62af93d406caa64aad1c7851838", + "a6de52aed4a840a28ff95c7d97f79564", + "f1159a945e544e51b1db7398b55226cb", + "df1aa375f775420b90a20c1eaec9e016", + "f886b88744f94713b384b95e29f063f2", + "49b5d57469684ded9393eba871854755", + "cd0a18e6ce8e4b49b0e20e1a7c0e07f4", + "bcab82613d3844aaba5d7049cedc5104", + "50ffb91434ea4d978eaefe03220d36fe", + "63b9935a370d44369912fce664957ff2", + "c1d4c884202f4e63b63d841915fbbfbc", + "b43687609ad140ca87249453ab92d7ef", + "9dde72825ec14738b4886a9605354f1c", + "b1ad63ecadbc4c95b84ac0ac8552c358", + "fd19b487511b4bed93f5d733fbe5f1c1", + "acb8432dfd4d463d95c83e1b58f518a8", + "dfc3c0d86d1b462797f6ca2e8f67f7f5", + "7a4fc94a0a0e4136a030f925081bbde3", + "2da9df24e8ae459ca05269e130d15b68", + "cf9a4d61ec3443c89347fa16b8b0b170", + "92a9fab2c7e64bccbc0511be0096994e", + "bee48f52ffe5407fab1f0f8b206f4424", + "ca4ff3bb59f34232bf626a8839b36018", + "bfbf6cde4a8d4ca399df04f6862d5dff", + "9272682c0f714933ac59202500f8d6c8", + "530222b7fcf348fb93d895aed319c5bf", + "93929be2f96d4d15af7abae931b1d56c", + "f035c1ab5a6541c48fc5761dc8625bbc", + "5dbfe3c5798445a5bdff4efca0b943a2", + "bc6c5204b9374c17abd5e2ae97fe8744", + "5850a38d2bc34d84a8117d95bf41d83c", + "6f3821cba1ba47fa968fdc49a3a0cc9a", + "f5d9d526fd5b4078be3715359744a75f", + "4204ebc430364660a336a3ba20d327af", + "0d2c58e379ff47c7847c5f05e8439db7", + "2c5969f0fa024e9d9629bf91df6c8baf", + "c53ff2c38f6944d38ef691f50de62c37", + "9db75463231d4de686043b687cb6836a", + "0018d378a2cd4ad58fa8fcae42e8af9e", + "9df8a6e0ccd546eaae9bed25fdcd70db", + "8f4af0f494fb4a01924d53ee7c34fa35", + "392e2810e1e24b02b2fdbc1dd3f21064", + "08a6930d03a34eb283a4d6972a19fe96", + "e60fb42493fa47389195350fcf216ee7", + "e878599f034c49ffbd0aa9f2f346cb58", + "ac1064a1eb1d4af5bd1efb158b7d1f88", + "64adc2e5a4be471e8279532b9610c878", + "0f6f692552884e74a4edd5bd6868ea32", + "8c0f8088a5d546c886d1b07e3f4eafae", + "5191cdca98ca4b4ba961f00747029b03", + "6db77dc58bc741f7bdac12b830e2c771", + "40c94d8b31f94df3bd80348cac8624f1", + "d4f9862c66144f16abb8ceb35bc8e7a6", + "eee26aeb02e947008e3a258d99a0937b", + "45062a04f38f441e8dd626f91f17045f", + "50db8b27c1414717b1aed8bd48ecf88d", + "7befd65fb0bb4fa5bfa4633ad873e642", + "85ac70192ead48ff83396c4398aeb629", + "ee45b1a93fa24a349032afa6f3c9e16c", + "4872586ab5394c1b95d7c4705153436b", + "ff68255ab9aa4f438a8fe9b16d6cd1c3", + "842c7b0398f348b792611c06e73cc3cb", + "9ff1333690904e8db55023e3abb275c4", + "a4b3d26542324454b22fe060aac8a94b", + "2820ec40c4994e5eac89ff81a8e87370", + "e9696f0f630949a4b0360804a02d0ce6", + "e30bc438f13442eaa96988a4640e24fd", + "5cfedcc8dda541e284e5d8b3add46937", + "4c5ff184b00d491eb569195c2ae17468", + "3825d316bc544b98ad837d086166ab83", + "f01778fe87a74d6f8105ef18c6321d63", + "01ad4a8234ec42efa916ce0ce65e9a9e", + "273224fe5546484aaaa5de9860cef11c", + "741b7c07b55d4019aedab52b623b4550", + "83c04eea513c4a57a805a077df97d55d", + "ee8d0281536a472c9b0bf6ad4ce880c8", + "60f8a59081344b1c889141643425eff4", + "8f8c6813fd9f46a19c7d0e0e583bfbca", + "1cff0d0506364ac6b4129b68cb4e27fe", + "9f85f18f95fa435982be7e5988ea3776", + "71af93b1d15f4f48ad836d36110626f7", + "808beb7b67ab4f73b5a03f641ddec3e1", + "2d2502827a10497687f67d9cb58059d3", + "d1b5ed2f176f42ceb176d48ab262af05", + "d942473ab5bc490caee4106c9b9fa5cb", + "3d9f0a5111224554889ceaae564ae329", + "7d48b34f6f3b43fb9fd49ee3ddac7c5f", + "01a25ec4b5e343cba858a53cb8511058", + "71632d1abbbe47b6a6d3803908f839e5", + "7f53c16ce9e94644af896b93e8a73418", + "c01286b194044fc888302c5c78ccecd0", + "fba1b218e50e464b860514c0cef8f858", + "5c21cdb1255a4c0b8a5ba65d18447b9d", + "afd79a4ba8fc4cd18971e125c772a565", + "2dc619299f1c412c806cd5c190728523", + "53027aadf795411e9ec8f59e491e06ca", + "c43287d13c5645ed8889d85ea61197ef", + "7bc7b0678e6d49a391fa1e101fe2ad5f", + "6f36552a994c46fcb4624ed96246d1c9", + "fa45f368c7de498fbda39ddacf7b7d93", + "918b752a475a4a39b01517f6837e54e3", + "ff0dd18a3f264ec1bd4dc3f0fcc0209a", + "9ad80a7bd90b483f8dbf0e293251cff7", + "b0bba8e98d31421a86f82875d15e097e", + "c5b130f54fae4ec7bfd4422b744b379e", + "11fe05b1c7f94b39b4e328db70c88b09", + "b45291dcaa934b64965935b207856906", + "51f3e3ff40fe41c8a942ae99cae45c6f", + "9edc801638884b648804176a1ce48429", + "2a93f91b3bf9462eb4e14ee87db9b54f", + "29d6ff48918a49e4822bed668499dcde", + "a6cb1f5137174cb18e6f245cc72e963a", + "2ac9591b09ca4ef6bb4709568533644f", + "0b3aa18918be4df38265ceeb74f607e1", + "7cf85d94fb9a4c7cbd33e8776730f67f", + "f5537bebb8344c0ebf3830df2d3c46fa", + "1ab1718b8b7c4110b4cfc41d8b9eade0", + "76e04139da794055960b96937f7b43e4", + "d7963a23952140fb9306083654e2e0d5", + "71eec398f7564977a865dad19cd4fad6", + "d1334f0020d7412b9635314752b594e4", + "3aec4887da6441e29226f717ef9054d8", + "e94536cb920947d598764738c5474a39", + "5b7538e15e4c4abebd03089cc2b51bf6", + "ece545c8149a4305849171d27c8cb28e", + "236df1e91d6c4a33b4efa0502e50fa98", + "d689beeaef7b4c92b2f1aa18a8482a5a", + "602ed4eef5844908960e33f0d86e80b4", + "435077bef9dd48d6a5cee72dd1f4a4ef", + "3feb2eab325f4f33bc3e4ac871e7105a", + "0dc10f1d3a1f474ead3434a1499d773b", + "66a35234648c418f8b67ce1b015f525c", + "c2c239b547824d6f9e4c2d38fa11bbda", + "1414976925354613b004d3173ac6459d", + "c2831735f80d4521a03d96f7f95319fa", + "d73adbce122a4e21b0153ac77fdfe7cd", + "7e2c63b326564c9ab8a934515c9c67b9", + "9f1c8da02e6f4806a4e2ce7ff5becc3b", + "816db1932d6349808b98260b218726e8", + "430a040458ad4db5b4fcde4c7db15e1a", + "7b67b44cdaa6456aad0433ee2b4591f3", + "503de69b733146f6b9cc4da6a7c4e3d4", + "7bed8fa479dd42788d122f93650b6194", + "8a80dfcc4003402c8cbf1377d2e8be66", + "7d2b60f3324547a880f1069ecb24c5a7", + "90678160c76348aca4c4b7c37625adbd", + "0a8c36767de249e89fe822f48249c10c", + "e9478aef8065474fafa7af4bd4cf36c4", + "082c0ee66cfe46b4a191b4a3aa731fcf", + "27eb9b31af4a489ba2dc79a0117ecadb", + "dfda6e71d079425ea07a55ea47b94da2", + "93d57f0c4ae04a89b698b84a5cc28620", + "f13cbb13a3ac48f4bd7e1dd9187a55d6", + "44112469dea546f396dbb6d35539e8e0", + "46459ea37d6244abacd42cd2480bbc69", + "971f6e56ea1a4030bafec3a1937087b9", + "ff2cd3eff128404883fc40e3792f3b43", + "0d118b86c9f84117b32e2e85133e0847", + "e36950b9b76f427b8fb36465e06f7c9f", + "35e60221be2a4b2999dd5cb9eab2c797", + "75908be7a70c4cbf9d469a69e12acf80", + "9ac757f47e8f42e8a7cc82a9cfe8753b", + "07020a01030c40869ceece7b739621b5", + "9d46daabbefe4b4eab74d9da349dd015", + "d2152f81109d4d378b44defd61cff1f9", + "4a21a1d0307c4ee788f875caed993ffc", + "94abd34548514932a6b73304a9e512a5", + "d4f2c598e6be47a498af912f6baa6260", + "444e17f7be6c4231ac3c21feefbfe399", + "d9e27e854aa3427882da1405bce5de61", + "aa9c7800e7944ea793db18a832c7b576", + "68e1accaf93d4ed18048c2a8b2c4fa95", + "97e61e9cb1e44fbc9893135f4a8b0f71", + "89f8295add4d459c86fb714d30341875", + "60aef48a110e408887caf314360d0d38", + "1b10cff0e1274bba8f3d87d1faf7ebe3", + "11ed23dd653b40e9bc4c144039816466", + "7ee46e7422234dcc839366e85d010074", + "20d2c70c4e164c7596e9393139ad0b72", + "cf9580db045e4bd6818306d50f2fa2ce", + "7e482921dbcb4d239eede55ea4fe2818", + "6d291c889b014eae8feb610b39aa33d4", + "b81e6c505db745aab15b93c2d2f0024a", + "e5ffc82181ae4a49bdd2137432db9718", + "4e6b4a5f5b49481e9023fce98879b279", + "6ff9cc405b3748f18d4c55803d242c15", + "4f7af1c8787944b0b323aab4db29c520", + "ec99489ed31b435e9533859b9dec49ab", + "6ba760b777a1429d9274fa9093228da6", + "5fe11d5efac044a1a23c234288763611", + "b0c2423e8c5f41a586193b1e25ad7610", + "dbe012f1012e4942b23df9747405551f", + "60b5fae8d55e48f5bc3a554652d5d9ad", + "3a3d821048f0434f9223a20972325896", + "8fd013e4352d4aa591287799b452a1cb", + "cca59986dfb24be5bb3ef76ef03e6446", + "298090ba739e4f5f82ba70d0262283d4", + "ff1cc34bdff94517abc7b521234606c8", + "81f02df60c6241d994bb4059bcde00d9", + "604e4ea5a078467097d32984c7d82f44", + "13f7a5dd61994cd7816341a653071d47", + "2eca47f8e6d3411980690c343fcc0162", + "ea889f35c67d4002a8cd71631372a0c3", + "aebbd4f5b37a4dfd8e3556de9084bae9", + "42dafaf8980f4d2f852f2a15054aa3a5", + "1648379b01734c77ab248ed1bc81aebb", + "1e176d7d0c5d46c89efbbe483432d1c8", + "c2069ccf3f4247b28c843e480da3118e", + "5aa8e3db89e245b7908b3abcacad3e4f", + "55333a3f157a428b8f6c1f4c8ea2c942", + "8ad2c5cb23f247e4a5aee99612a4f2a2", + "7db0fa787ce34f17a9953b2e071aa1ff", + "82fa6ca1a23e41c4afdb93382ee5644e", + "f42e615de5634df0af5550651f7272fe", + "506d8417acd643a68e30b453a36dbc22", + "b1b578f40ea54e51aab36b5da31d6f80", + "5483404317454b7d90831c1351f3b4a5", + "1389004d1eb945078e9176a4b1818b99", + "f1d895fe2fbb44f3b474fac9cbb0abd0", + "58df2211f91441cc8612d58cbff56631", + "32643ff9d5994b35a8c6bb28f4bb1199", + "3612214cde1c4a3e96b18b7d4c05e032", + "1fab59b932464984a5bc535a7f67821c", + "b20887a16acf43a2bd102a857d67f1e5", + "7b9be5e13ba94f39be36112f2d254fb3", + "0b111367493e49a897907c0026d27e25", + "054738a828404745b7333877f6f5e0a7", + "075a4acad5e4495dba628ffdc875f265", + "783e6e237f3e4d6faa8538ce5001a143", + "6f1504578f9343d088643cdbce38903e", + "4b1855527ecb48488e9e81049ae03fea", + "c34b893d6e7c4267abad4b4fc79ff01a", + "7f2bb7f63bee45908919d54adc6e536a", + "0d83abc11bfa434a96cedeb453e308b0", + "074a2164ee564e408e33ffd2fada9474", + "7f4b851ded5645e3b3c381769752a4c0", + "e9aa393ab42e4bbd928965f2614688ee", + "38e39212e349468d84f67cf1852f7631", + "6ee29efd354e4bf291ee4cc06f97baa5", + "8568eaece8e64da39af80a84bbcdaa45", + "fdde37ab83774efda67c7e0b1783df09", + "a3fa2e70a3ba45f98e81f118c7898016", + "14b8ae60eae240ff8bf1abdf9af5e49c", + "a431aeb168a049f1879d3f1909433612", + "d2c1afc47ba54d4491ee7b55469d11c8", + "f6f6011216834a94aff02d05ccab947b", + "e583ea4d46b34e58bd3e1092edbd5c53", + "403bd381bc374b09a2a0c0849c0035f8", + "03765a7e66374ec7b3fa18749795189a", + "8a57a866af8b444795380b6ccc3f5359", + "1ee138ba1cae40fd9db1ff8b3a897fac", + "99218427e7a2424ea8afc9b8c668a5c7", + "d26b5168a7ad4358a48c0d18aa439fd3", + "dc79f4e55ed8462e81ee02c6a01f7cea", + "32be52bf7832480680b0aaad599bdd94", + "87334b3f6c4f43e2b470961a86d52322", + "36e7a82224264eedb79a79f6676769d5", + "827f39e4163e4872b5a0734d17ed65bb", + "5c48284fd1724fda94d71657a677ef6c", + "c90b62af44654d549be357a4825f6142", + "5e4e99fcc9974549b14ab4ba538d1cce", + "a89afec37eac4a91ab77c8fb89951948", + "4526172da4f34ef8bfb7483a468b504a", + "9a0305becfca4f6aaeb36ebfa2208c31", + "7d62fb8900cd47beaba916a13c1169ed", + "a11b0cc9957d4e0296c7cff039ca245a", + "40c4b1c6bd3c497c8167355f73ad4e17", + "5b84834cf9e846f1b289b2fe8909110a", + "238e26ee5b85425fb56c0a2f36bab3c0", + "7de3f1bb5ede47e2b2978f7b3b0ed65b", + "1a26aea26ff34e9e904350d9e61e9e64", + "f9c34aac9f594e8ca176e96cb0155259", + "d88321bd61a7449ebc780e9ce65c298a", + "ffb617395c6c4fa2bbe0b54ea0ea33bf", + "6fac296036f64636a76324c60ec0f249", + "94ec4e3118eb412da82f4238dd8fe061", + "deba2b49e2e14416831f0deb78117745", + "4a6a34dab56e43518141cb722d9fede1", + "2138d71939cc403b9e740396a79fb9b1", + "f7914d33c8964fbbb18fc9d4ac700c3a", + "d76584f2c06b44f59749a8e4f666d13c", + "5408583dd2b042dd846a54c4e7dc7c87", + "f0ee4c984a6942e5b8bb6c6fe7a0bfaa", + "f8a87e1da0d54ed285c60cf5dc3d77e7", + "0d1d16ee22814a40b86df5f96ebac0f9", + "39fdb3ee809d4f7fa2d4e4d686496207", + "ae700bdeaf034da980b4fac31fab7043", + "ccfff4c5f8c54ccb8deac282d52d6e66", + "81806976e40c4fec821d14c8a0e2b373", + "262aadf15fb44fb3938d0f93a2bff7d1", + "9b745955aeaa40a996999e03976f58ea", + "5f3afb15359c4eb38c070fbcde34203a", + "4f4f28032a6e48eba05e51e7ea298334", + "7c29f75f055349e492c60e4600496437", + "20856d9731014b8f9c1010f2867978dc", + "2563d1cf30ac42078a804ea45fc3acbb", + "4113a397deff448d9c0c931b4d07bca6", + "94d7326dfcde4cef98939973b670f817", + "6c85f8e8ef7b4f9bbdada909dbf7a32c", + "a1e1f4b5aa9c4fee9938fd96a88def6f", + "684440b44e984bfebc6395587092bd35", + "eec2cfa2536d42239b3b3c1ca2021c51", + "e8b32da76b8444c59aa13b749db5fc56", + "1dce9da025fb4987bf189aca9176ed96", + "16c2f3b8706f4fd7b64139238f5ab1f8", + "c44fd14b195b44f580c24809a38d4def", + "719469569287452f86f1d3568158ec8d", + "0e337f3fb21743dc9b9d58282cf940e2", + "d3efdb58cce44aa78446f8c620e49738", + "ffef2df2037041ad9aee816fe1f27ff2", + "69d2ed11e1524e5d82b89f5c61009778", + "8cdbd8890ed84c228191cbe6241b420d", + "811d4d00678349f4a4f330502e87b218", + "3b536d8029e943c2b3a338fd09a8b7b3", + "8a8bb20693674d4893f15bf004b16c94", + "d5c94ab29a3342b1bde11702c5b8e968", + "4c37518849f7447792dfd272ec7ec340", + "6dcec535c1f043158bd766de36040c5c", + "d2655c4255ae417cb7c00abd775b5eb2", + "e5234847b15e437cb5c001ed428c2503", + "fa4a4b55227e43b9b552ba6a0ddbaa23", + "6836901c289f4e01a8bd49852669f0d5", + "5a3b50e19e5342c0aaf713f9b3f33527", + "f6624fb286df4863bd58cf59a1d462bd", + "5127dc2571fd44629e5661cc239e2e6a", + "a9437b81317144cb8d2582b6205614a0", + "5d3a99865ac84d8a8bf06b263aa5bb55", + "2131f71349d747a6b6bebfd30456245b", + "7355e8b965b54cdeb924e529595b063a", + "62172557a2e949e0b0deb25e95a4ffde", + "75f8d3a012034f4a9a13f88d80b5c67f", + "ea97efd2bb004178bdfe14e577ada72b", + "4682fe0accb24ddcaf9673d36c2bb94e", + "3d3f563179ca42919fc8ac8bcc862270", + "98587ddd7f144805a7737ff3538cf664", + "8a22e6c7237044da9494812643897ff8", + "2aaf15a6bd6142aeadd3897bc30e39b4", + "e6a7b8adca3445f2901c634952ac2b3e", + "b7c97df584824ca682d26daabf401f87", + "f63daf968be34047bc513feb756b5828", + "34d395bfe3c04dbdb5c78f8197af94e2", + "09cc7c3403f9487ca0af0978f4e1274e", + "8c827f533043415496fd598718dde13f", + "2ab68590731040d7ad3f618469cb5f95", + "cd50c3ce1485436a9c3ae290af4d1303", + "693d13d8128447b09fe15f624df1a91e", + "0adf8acdef3f43a8ab84307bd0d8cfdb", + "da8d3bb426ba4142962243b0394a40d1", + "b3290210ad154e0ba706112ae5cd47c7", + "a3a777e319f54851b420f0da7e54b782", + "bb4cbf36165e47a2a1331be6a968c4f6", + "0652dbcaaa934562ae582aa9771951e4", + "a88707201bc3489da43d2a0fb934308d", + "2965de09e84845a286d8a2986d3d3c8f", + "495f0a16edeb4f2981cac53e23d6d0a5", + "98eb2616868d4671a451c81bc21ac91a", + "78d628831c3d473b9702b6ae4b6f4e68", + "f53e2b75b0294846a6d52fc54432ee98", + "51b3266bf30c4db78e9f15135a380159", + "a0b4a526405f49c894b5acbcf7d77620", + "9cb3a5b05bf8430c96a2a6cf9cadb6b2", + "a2f9d3e31f5045579881b3d671a1120f", + "7547b73ba9e54c4d89bfa47ba5d6f23f", + "78d9c88449ff49c09fbaaa87e23c2559", + "43861f9af252411d987afafbc84357a4", + "c6ba8350e0f84fd8b7bcac09f5cf6a40", + "38875d32338c41659dccebf7492ccf9c", + "4d3104b405894a8f808524331458adfa", + "cb5c52c48f6c4540b2eaae6852267cc5", + "18845f8878b54555b0a9bf5bf2181a32", + "7824f1ce6ff047c283401056ef4afd58", + "d3f23b462b6e4089a53f5e0579dbd5d2", + "4a90c5fa3d824d1d87cd63bbae14ca59", + "a47c4340a5c84f789c71ccea51b3f26e", + "a6827f19a16c4fa588b46f07eaf3b161", + "08743fb0f09d45e4bb596d337abb8072", + "87fd2e0ea7704985a3b0f6a8e586b22e", + "86c69a94247e4399b8599d254b657b56", + "848aa81f73364d2ab0bd39c5b67eddbc", + "7a8f74c239034bb9bf58c308dac08ddc", + "35bd2148eb6041088ea52b1b1f9aeb89", + "55976721c7584b2ca8788ac14d901f08", + "74b4e52f8f554fc5a247cd1e762297ca", + "7d55488c4cfb4b89a777c4e67040aaf6", + "9d35187c2a19484297b7d88a6399ef6c", + "adc1388c38884b67b17bbf976222b4f9", + "6fb815d117cf4bc0b0c4c2d465e2a735", + "ce0ae78b7918474b9073fc9ef1288218", + "604962493bc2430a817acad4baac76e5", + "7bcc0425058142c59255979a2b61f0d2", + "22eab7e614d14cd09a2a41147db2fa25", + "0d69051b3da345ff8a8f775e2127708c", + "912dbae7421b458fa723d72296991b8a", + "d81c7b2fd33f4b81892062d93df57b7b", + "89ad9370995c4707b077c746eb99075f", + "eb0182a470fd447c99e0282a3329d8a4", + "bb46b012c6134f86bc6639d0494b2b4d", + "b6adae02e47d4251a4944a8f2fd56608", + "cd78d72dca1748048c7badfbb2f4e06c", + "0b285c035a3f4dbfbcfc61a0c7191bca", + "0150994cb47042628dc086db126926cd", + "118f19a1e9a1479285a3141c0d1f9b3f", + "9fa057e3d8a14cafbb1df0749537850f", + "885f1fe05f924bd995a89cfc3b6fe8a9", + "d43d1e74315a46359a2e898f31fa94c2", + "61c36cd1799b43499b33d28496fd0143", + "f04ebeab61344bd6983108a32a7b3dd1", + "214e634cf57d479098bd012bf124bc8a", + "71603dfdc70643448552dbc8cd0f36a8", + "db88dd47c3674127a353393d6532bbc5", + "a33d8334c89c4ef29428b384506d1803", + "d02e753de0604da69e7c132c1c61a17f", + "4b9a5c4d5e20434793388325ec18ba57", + "ed0dbe7cb07d4d7d9005212511a4c974", + "09beba2fa834415f89734b21376fd886", + "7c00eea07b004402ac5b63ace4b2b78f", + "72752c0ec1af405a9932343b050fb737", + "4bfb5a6b0452458998e7cf28fd8c048f", + "5320bca3c2fc435ca55729cf2cfb357a", + "782ba25570c44072b635a1ddcd4d229d", + "1c229002b55148e99b144e58e4fd9562", + "fbc85cdc67964230aa39c646ce268ff8", + "0c7f53e9f79d4a8e821b83705e9546de", + "88bfa0c9b60a4892b0e14824fccd9e1e", + "b2df9294d530400e814165917ca89b19", + "59c97f3ea12946e390f498c64bbfec50", + "22b822c6520d4d49a50ecc1271233039", + "6e4b8c413bd44fc4afeed9d2c7fba3f0", + "2ffe382647cf488384c2c39aabf7cff1", + "265c0991bf82496ba98d7c4e403d65cc", + "1915ece903a5406d8b59b3af3954b943", + "3884b208fbae4915be69b6654da8e071", + "6294a91fc19b4b908948f8bf571c209e", + "cd7cec4d369846a69b5f87deeb9a8399", + "9fb7f5521bdf4217b67757c6378f40c9", + "e75d11fdfdfb496886658366fcd6a812", + "8de045536c7a4881ae01aa460a2d453d", + "5acff83f32304be281d6b3f13b1f18db", + "34380eb566034cd5b1877527ee7bdc4c", + "c50701af72334361ac7f50fa01945efd", + "1ff167f84cc64aa0a9aa55ae4691f0d7", + "1793bd3ab01b409b8fe5944462734674", + "5a0355ed75f042329699a22cc2698281", + "0bf3ecacd69740e197803bd53302d1d5", + "027b54e7c9b4405b951a8dff079994b5", + "eeed8ff8a7d8418fb7f6807e8353d1ea", + "78285fa9fc0b4e5a94212ffb065d41a4", + "d88dffc380904f1295728efa4499bcd4", + "6d81ef359d88483f9109734570becf6e", + "3c0cd4b426c7403c908d4d00d4bc4a1a", + "ea9f86bb18984cf98dcd1b595d23d573", + "944625fcc4244abcbba6eaca19c7cec6", + "5004d1dd89984cb38351b42963ff93d8", + "23d2476cfa48463ea8bb9f94cbafdcc6", + "01f33919650c421e91666908db8c421e", + "77d41aba53e4455f9f84fa04b175dff4", + "401ac6fd05dd4ca7b14eb8dd607040d3", + "eb4efe40bc60475ca7f7369925f00a16", + "0776052b361b4002aba142e6ec6bd01e", + "80317049549541b78ddc84f20922d835", + "ddefbf484ee443e9b9506769745e6f09", + "5d8ee3d4f1f247a4a1e6193b037ba66c", + "8985db5fac7b46e0bb9a31b0a986241d", + "c48ab56a229d439da1c8bd35b683d147", + "5a0ce5182f6b4a4e9f85616670ff46f8", + "a284966428304a7a8be43eb4a1eab008", + "67917947ff9249ae8d73bd5fa78f673c", + "7f51463f66234d9aa56731d6dd3ad627", + "390010cbc1a34c9e8db93fb3fc44b863", + "26e5998ebf0b418bad7d582913017f37", + "627ebce56f204ae4a4dafdbdc993513a", + "c1cc5a4cbdb2469c9781b395498d64b8", + "b978575bf7694f9185fcd906847bfd9c", + "b42796beb10e407b8eac779d83e1644d", + "ac5b149431eb46b593fc9e9601379b2c", + "5521857a2261482084a68b358618bfc7", + "a42fa0e9decb4756bc03095433919393", + "2211bfe7312348d795e1fce4f925dce6", + "adc0c8563f39434bb95d223c941bfab4", + "9e4f6c7c49214be1b98cf180e1c432ac", + "7981e8bb46a841389563e257f1234d7f", + "8ff6b09319bf46b2be253f51ca963cd6", + "9ac825106dfc47838e47cfffdab65b12", + "5d02b778587343bbb05cc2c03d395e40", + "e7f02698cb864fc98a6efec3e1253f8e", + "f3dc37ced5d548ef98c7ee8bd2ad5491", + "f0f8084ba15d4a529e76a3037b553070", + "516a1ef5df1c4fb288f1566c5c5525d6", + "2349ad91f46449079d909598db140528", + "6c40f717a7b84e4f8a4ac4473f658753", + "1c77bd376c0940cab3ec72b037a6fc46", + "a7014d2bb7f648bb9aa2297a326934ae", + "8a65fab5402d473c8fff58ad7d8d7ab4", + "655f785f49c74aabbc149fbd41c60d0d", + "efb07425b3744456a88b24d2c8636302", + "dfd4f863accb4758911fbe808941133d", + "f7a1da7dcc954cecb132d9963f2edefe", + "915df72510864d559a08a8695d379540", + "ab43f96da577493c811083c914c51efe", + "284d8197f9d645df801ac0a5852a588a", + "967b30db3c274165a37099ec4d2a589e", + "8eebcfb709984b349e16c9d0ad64f2d2", + "8dc4075c2c764870b45f037dec2032a8", + "d529aa542b134b0589fee1f67e2bcc62", + "dd6a424807614544835c8cc4529d6f0d", + "71a197a9d2c14c85867ff3dfe62b3e77", + "0567ae8c25954f43b03fc5b5264c3fcf", + "0c1fb190948d45c5a819f9538bb01538", + "24464015c15b4662a32be7625ae3f75b", + "8e273ad665824e869a4d6440cb426dea", + "79c8397f25d94aae92b8a41a272044a0", + "883a2fb67b5045598a94cd172c790237", + "8efc78eb989242cdb237c85951063b39", + "b74b57dda3eb43cd9b29d96fa23d81ac", + "26adff33d1474a67afd8c334b9450f03", + "ca31c4bb63104cde93de36a1d656619c", + "97af0dda95fb4025905e9b134c3b1627", + "747ec345ba164a8eb79c0beb4a25bfec", + "cd32494ec364469f966e55f690c5dd40", + "41e6c8bfff7d44288b40adf21efc4225", + "8806b403ed7e4e30b06a334db00d2329", + "026cf4d0752e4a16b9445fa6793c1141", + "d9822cbffc4c47f89e2213543103e4a0", + "3f38261ace5f452196d5d15c11e4db57", + "eb4615aacd4a4453bff8a41e91c843a9", + "9436ee7021d64f4b81845cffbc0d987f", + "bc6d9098ab2a43a2989d0334833e63b4", + "ff2242369e8640f48d65df83066845c7", + "ecdbc391a69a4ad48127a9d8d595f8fd", + "b687054a525f445ca1a6d582650ae474", + "df6096bd797443189756ccca1565e1b1", + "2bb9a12882154fbfa07a11861ff7e6ee", + "632781d61a6e4d2c96d19525bb21bd88", + "f42f17c611cd4b58bf9e475016e7e60a", + "c1b2afe08c6645dfb607e23c7b462161", + "0acdfc046a5149cc890c992da89b48c0", + "4ccf7c65e5ad447bae9de15ed0d53b16", + "5819c81a7ee942deac939ed7c63b792f", + "707ca2d72fc044e2b75885554dcb37b8", + "daba6e30f78d4604b5167b2f83b0d162", + "18fca4e421094c789c63cd78565e38b6", + "becbef04dbf04d58b32574c79b11e30c", + "06a4a6b9008c4f95ae4e89d260a19db4", + "35d80c2ff3214a59bbf8f1995f69b9d9", + "222e0a9f12cf4352b381dbf594f09b06", + "ce5e2eed8739457181d4b6709d3804b2", + "b8a40fd6390448688e4613d4aa6e703a", + "38cd0b9138c64c4fa5fb125c5f6796f6", + "b14338849a4f482ba9c5574d8c349a2f", + "28fa872e41264a8fae159c0469fc73ab", + "047be21efa814473a477aeac79bbb6cd", + "a17d910df7de4646bb9532aa6b5bcddb", + "3da94ad0a6f34bf684a1490634f1f9a2", + "cdb393030ef34e93a2159113a72477fd", + "f8efabf1941d40a1970adef04b28cb9e", + "0238adfcca3e4727b9c36eba3a9eb7cb", + "833ef9cea519454fb1d249154b830f04", + "c64bf5d0ad644ef3993087a81cd4d013", + "548e1212a3e248dd9026ee5aef2820a3", + "072f50ccb520425d859608f1548ceec0", + "9eefcf9a6fed458990b59f63a2870d9e", + "c8763050b62d4ab3a3ed9b175187fb48", + "64a7b5778049425c9f31fd0365212aa7", + "d85fe6b4d16a4703879f6924c0cfd227", + "4072a5178cc64a8d9a25b302a728707d", + "53c8be823e734833b982e96ed34e9855", + "c5cc01a4d8f64817ad5f558ac3cd7636", + "91f651d3f560441e9884f3b6057a526b", + "85a3fde09fee482abfe37a47b023ca42", + "d3bbd54ef1d042799c042a1a50636ca0", + "0e0b73b1eee34daa91757142d3260c94", + "9136553b3c2143ac93383a6239f52b50", + "f94cc938a75549e6ab7d6d9767961a4a", + "7ccc95a3fe004e56beb56ec73658402e", + "638ada0c5cf3498080b6cfaa72f4e4c7", + "4f6b919edbea4839ac5f117a98badd00", + "3297c67207d64233b53b390062c532d3", + "aa555c383d5748fa91634b61dc3febf9", + "1f87e20995e449cd8c903d8729ba875a", + "c97cd4e234ce4a319abceb3f8ed5a20c", + "44d4c7045eca453b9f225e20bfb0a955", + "14b2db3cae484e0eb05cfd1fc0bd121e", + "62039f6107524d0f8ea9f4754818f0fe", + "2ceee268be834c919babb9b851f60c18", + "4f95a2a5d901493c9a33956655881970", + "08fab6d48d5240d78fb14d8dd67954c4", + "46e0eae500c144acb4a26d31eb8f6d56", + "26f9cc0044d3408e862818142fbf06fd", + "669dc18812684254af14919d94a3785b", + "66b845b9bceb48ae9bc7ef401523dca4", + "98cf1e3ff1dc4064b7f5535aeb540f20", + "bbafa80686fa4c2c81f19f1a7e883be5", + "146209f3c07e4c65b16a0ae16616d27b", + "952df22d32b3406d958a5979131665b4", + "79a619a8e522469d9aed2f426cda3d86", + "ad0b974411d94ec2bd2bd62b701018bc", + "6b7184f7634e49e899c5bf5476a1831e", + "8e460c98b5364c55b5ac4260ece97114", + "914dc213ff2f43658f6c858e24c3da0a", + "23627a7c3c6f4b8abf092aa505b14326", + "31ed5bd2befb4a9c9ad157b35bfd8672", + "ea28c9d457024633bf47a55ba032e752", + "30473d9006904e358c068d01b5b5b91f", + "ce5e4170510f4530b9bb7d8a558ea363", + "20be3142dfac419f9c9be9c8aa8ea88c", + "c4f6141878534efbb2f0add1c4d99d27", + "eb763328068b45769609eef6f3255c96", + "c1f34428e7e3411b80ad23f6c6ad8607", + "c64d24f6aec84ea6a30a46c39d50de3e", + "5704fd30ddec43a2b114b1334a7569cd", + "f6050a143fe94555b23b5f2b673616c7", + "6428763fe8084c378f8b65afec48f592", + "e19bac6adaae49f881193af7181c88af", + "409624f89a75424ea5a2562018d5276f", + "bdc8eb3e2a10409bafdfa85fca906204", + "6024de0573a147ebb27395d5696fd0ad", + "3dc1e779dee34dc98bdbe06b51419ff6", + "2b1bd77415b64570a4f5f4554414be5d", + "1b1b223e06644688a7593b82eb37ab1b", + "6c04f9cc26974a8e97c9a496b56ef988", + "1ac706fe913547388493572df5c1145e", + "08fe832848c74d3a9dab4a87b66297b1", + "716b7cbf5639412ab4d4f91b5a9fc67b", + "8430a420a4754c2db233715a638476fb", + "cbfa6285b2ae4caaab5e7c2becf0ff59", + "3ac6dccc4e5b4ce2826d3391e31d153d", + "e50b24d24f6a4b9d9c44e6f051194fc8", + "eaf9f2b531064719aaf911c5b40d716d", + "4228b3aa43444875bcd1051276e67456", + "c54fd173322e4e8286e170cf85697ddb", + "2f5d1ab0f339423f90d3cb856e80eda1", + "4e15eff0ed2f4c7e8e5d8a07b01311e0", + "f9bc1e0b4e8f494dba71f7d33ee6d55d", + "a93177cd6d5f4fb2930b9c542549ca87", + "ab309ab0cf094372b6f1b26b91c35eca", + "cd32dfa73b194b01b1ee2e7777c123e9", + "b136ff21d67643a09fa9bc96e3f0fae3", + "fd47e62e36d74e8580616d60d935a99b", + "a00f60192d1740f49902009c3d0aac05", + "d74ea126ba0d4846b593502b9d16b9ab", + "be9c5de350804403badb82aef1bb3892", + "f7ade690a1f44d608fe0097156642510", + "4a270f2477344b55b359e2913f5530f2", + "165dd586aac84692b0c4362955a111ba", + "451aaaab47f846ceb2c6fcee2d1c1488", + "3ae3b153415d4987b171a08aec95ddc9", + "34278684a4404c938b9dd91da0d4927d", + "c1f73d85752749be8252622ae03bd3d6", + "49107fed9917435d8009e2276d0ebc65", + "4705d3b006694c2da3a6662f34060bfe", + "3beaab22c97d4be49621380eb34290c5", + "e36fce74c5d242068cbdc47b0fe69b10", + "3f32df3023964c80a6234c7f37ec0670", + "f049ea345b0143d084f7b5cd67cb8f1e", + "abdca2ced413486b9c943111621d6f39", + "bcbcd708223745e3b4eb012efcb63302", + "f7e5a12a2f22432c8f39eab29880e7ed", + "bcd19697785544c99f54f2e71d1cb557", + "aea2cbc8684c45cf885af4eb3b26ea9c", + "c00a869a099e42e8998f36c60b0cfcdb", + "e6fac27a832f4eec8b8ca49f4da26fbc", + "af82f700434644dfb6e63c6117695527", + "83e75e7b106f4e2089dc03a38562b7cc", + "3c2155a7253847d880b88b9921252400", + "9f4774b44e14494696d0e947c5ba38d5", + "6e6df6348f8f4d0a8bfc2c6682655e93", + "3e6f9b9cbaec41dfa411696177759431", + "5b4f3897ba78417d97a3c7f786a0bf71", + "0f0910d75ca9402fbfc6b66950ceb93b", + "1df839fda36e4adc99e0b22484aeacce", + "e8a7704b3e644523924a19d6a9f38703", + "e3b3290b8200475993a37c5c56b18ee1", + "4298195ce1054cf29b3341fb9b233777", + "1bad69c6afc444eba5cac8f06cf96faa", + "175fbd16eaa047c8bc3f0687dd01c38e", + "1dc27dac0a4a4a498ff59996838b1ee8", + "50d3981adcf242cdafa54ce7cf00132a", + "0d3f8c356cb741198c8300b4704f0ce8", + "36dc07c8e85c4b859d78ccd4dd60c63d", + "194fb61b75db4a4e8b6fe42eac80359b", + "b23d22a46f374f05a5da3c85875ca5ee", + "0e6df6c6ca5a4140b5ace6a957046ce9", + "2c260357359e40d5a8885dd5c22c57ee", + "1d0fe843aee943119c839f747acc7434", + "d017216e3f48449c87980ee2a888edae", + "14ee91ba8cb441d181665d488c3c3fd1", + "3ed0c8a70da84ee99816fa29e352ac16", + "46bf504ab10d47c9991a5dd57d1798e6", + "e100ef07cdc241c6a71fc476b234a892", + "88207e92e16a4032adb336b3bc5169d1", + "8fdf04d28bee4088b0a79aefce9ed302", + "3f1dd36d74a74f3eb61e07c5129e1f9a", + "dff7be715f90478282f75c80930f1c22", + "fb180bbcb5b6400495107db486d4249f", + "81738d582ab14b30933d5aab47314ae2", + "db76b4f8fe79426e825d6660dfac15b8", + "6dc9c6a4a2c74417a4411603d7a911f4", + "cfa4ec3fb60f446eaba4f1ab9b4adaf7", + "4f372ecf378c47ae9ce6cd2bb734993c", + "d70bd66d69e3402e873c82daf48309ed", + "5e1a3f6c2a074fc6a02953e12356b5c7", + "34d4e9d8837549199658133c36643bf0", + "550d5a0368114f2aa62285207ab1adc3", + "4d6f0a6aab8e45f4af131ac517c74363", + "3cb0c95b955747aea22476264eecf390", + "d48c77d41a5045bfa8ba4e7edcb3128b", + "b6cfaa69e16b46fe92b98e939642b630", + "3285064ced1d4e0c99490483d8f0f95b", + "107e4444065a45849a65df22c93050b9", + "75183b418412474ba234fac7a4c0538b", + "26741de9593546ccabdfe88b4e39e4db", + "49f6629262c6458694f4310cc98697a1", + "9173450a6303469fa0fa0c5fbfd9fdac", + "8cfae5ff022e428490dec84fc5dd1043", + "b199c6b0361944afbea19c0a68cc3c99", + "d695caf6372e43fbb1cfe13273d32c07", + "12d3f3dad62545bda030fff5117df536", + "2069a0d4429447c6971b4ee0783e3d83", + "cbbec1cdf00f4501b26141717b9f8588", + "ee3cfcf00b2841e0929ff8c560afcbd6", + "fb1790ba160f4f07a2b41bd075b76174", + "f10a7e5b1cf242bcac3633c324d023f5", + "aaaeaaff8f9b40569f0715471f30f750", + "3e624e2fb26e4bc48f9532f6f2b2a73b", + "6eb2f110f0b84359ad2e35b56e0fccc4", + "a7f28b037e624880beaa3e5259ea31cc", + "c20936f6e1294b189282d4afb58b7a94", + "b9643d6614c64b80a9662aeb2043f4b2", + "67f88fd95e344a87bb9be157a4f73f9a", + "1ab31d73603348c2bcf5ef0b10856730", + "a16b74fa75084aaf9736f60bcf23992a", + "250065271a1e4c45910dc4aa6c3ad735", + "33f6b41d95ad450aa07beea4844e5092", + "da48ec59c51b4f04a678dc1f7935f166", + "aeb586ea459b4a29bda5684eece577fa", + "97ddd7db0b5b471983db0d6526991dc1", + "0a5c38536ce14e64955ae6d2ea9cfc4e", + "fddd97e7388f453c87400408c2012918", + "71052e994ab043718c60408f2f6f4b94", + "f15cb01acd4941969bfba8357292f96d", + "d3ee1a643ddd45dc93695fcba465143f", + "db2433b325824ff299351fbd057c0153", + "fecff69ea8244cc2aef5a0ff2a78413d", + "47d8faa0cab740749c29c5f7f9a1cd83", + "733c2622fb954c8985582393c0dcaf25", + "1642ad1b51a049e8a5f23466cd8593ed", + "7b84349f3a1d4a90b6cc44af79842a48", + "e5bce83a8c4140bd97ea9eca32b4f038", + "66a2a5baf52d471ebc9136db7d794239", + "ee35b05e40ac463da7c8ae92f701cf78", + "61cfc277da3941c8b19666345d622ae4", + "fe95600a9c3b4a4eb40b62ac38e15c0b", + "1534c1b10378454697ea2f2aa888270c", + "3ec38868fa9947328e2d0f80a8be51db", + "62898588e87c4edcba25de3c20a8bfd7", + "7cb4d3334b2646df933df23c00a87c39", + "a38b6658117e4135ab0374cca4d745b9", + "3cb5d1c5aa2047c2b25104e546e1f3f4", + "6500a90ab1dc4d489385026448220157", + "47448797a2474c6f8b5d33b946bed635", + "b8bc996da0834f19a7e8c001bbe60bb8", + "348f4f73dc374df893c01c4942d89e32", + "860879349f0a4bc0b89bae8feefa3cf4", + "dc1e9529e48241d98e74b63b61bdefec", + "bf3d88c6d06341f9aa78a8b017f5dce8", + "9481cb3ea6fa4f058c3afa0a492b3a35", + "2c78d406b2a5426d975f0351f9759712", + "105da0b01b414fceb2feac631b0f64e8", + "1ae882312dc2430785ee4ac48bef35c0", + "cfdc13ab72644cf0bc3c5a04628b094e", + "efa2f1f33966447e8d21d605fecf5231", + "72fc2f9279dc4a5bb76652fc272af184", + "14af06cd758e4e37a919548fae755a1b", + "3585ddc206b24c9fb2298eecc2573974", + "1014ad7c8a4c4aa8ba5e88fc6151aa4f", + "66365495cc944181848b3db883865c98", + "c12952f233e942cba81cfe42eb676ba5", + "dd678588fa084e108b004d5b92328785", + "09e0d00fe07542169f13fd46297a2f06", + "db883e500495486bbe7f633253a878d0", + "2ccb80f669a5411a9930b465606934c9", + "491161758f5e44af813469facfac61c0", + "c58368b5f05849ed935ab5819b87b187", + "7ef16d15f5274ca3b2863c58bd5aed3e", + "ca91baff9c4a44d4bb05c9281b1138bd", + "a505344d484d4efa866c147808acf89e", + "b986d60d194246eeb0e02f6cf5e18495", + "f103ac43ea1f4398b19a23a44ecd85a7", + "0ec178daec3b40de9d993b6a3b68411f", + "e43c7b0b261c4e31bb753791794a9bf9", + "35b76b90614d49a3aa92eeeb6afec60f", + "8ca79d5982eb4ed7b67a84df1e38a84b", + "f10042b1603646deb1a015a3ee2c9c45", + "5e3eb675741d4b48bb4550e7d769af45", + "3155e5ee434d4705a161320269df30ae", + "c469cc01064742b4a730d51526458c78", + "8e5838871a154b63a1000310887b0062", + "0aba41f5d8e74b3aaee9cf955ef1bd6e", + "5ec32c9715a6433ca3626b8f74c2508a", + "5457c5a35f2d419c823052a0b8e9a0d7", + "62357db608254b13a5ba4910f4e07660", + "4cedbe0a32be40118a136244cedcbbb7", + "05f26436aa5b4ef595950137f8e80f04", + "e9d34a3af3c54910918b3221f9f770e4", + "c5163b50c1224757a8346bdb21fe09df", + "ca1b8c8150074daea810166ec5c86b78", + "5aef23e7d08748318c219da5a3257156", + "a6380b5071e34b908798ec97106a123c", + "317dac94ec404bdbaa6d41a85e04f51c", + "d8c1d7dc47cb40128826157775031dcc", + "7aa3640350c84c61a9e0600ae7b5fee3", + "52b2faaf84ff4300b64195757976509a", + "f0296ef0a4604b8195f7361320bfaa7a", + "69a7c36397914b81b853a910b5d30761", + "bdb663c8be5e43fbb23522e994ae52d4", + "fccf7666461e466c84b1cf24515726af", + "f139bfd0a8ab46b3bc759a962e7ee0bc", + "c371737143bb4e38b3aeed591c08b9ca", + "fa289390e7b34aa98e9b9a4d5b8f8cbc", + "a4834c2fd94246fe87278b6a9d72ebfe", + "b0c5bacc3b1a4fe9b7f05039062e54dd", + "7f788ba7ac0847b0a19ee2ff0d10da93", + "7f52b6f60d9f4695a4cc77d38fe883f8", + "fc341860f7b94257883cfef2a667a697", + "75bf3138459a44fc925525a4126959ad", + "c35d569ce2854a73801be61d8d917c61", + "19834e0488794aff9162abe697a862dc", + "e27442a7e8794a1390904ac8c1181476", + "b69f3a927f5d4cdd9c0a47397620c5a0", + "774d076e5ac64aa5a45f0018f18cd927", + "db0d103174c34fae8dcd1c0ee1a9e363", + "7a209dabe66f45d782ce3f6b4a3a7b37", + "1806b99f1cf042489cac792fa6c0149a", + "4b59720c67c74be7a95e59d9f52df88b", + "e4a1aafed0ec43a79c20f91dfcfe5670", + "0e1ed07bcd45477c93e2385f8557fe6e", + "8b92509204c04fe9ac5f71d216c1069e", + "2c30322d4a7445809f4bd88a31da5c15", + "86bf9f55ad4a419293e13284a68675bf", + "6da7006f2a014c16a60c6e383150f772", + "37b845a974e44cd2b119f425a50f31c2", + "4df589f33da6402b98a90b554c7564cf", + "e15fcb29b7c1449796a3fedbe063762c", + "2bdc0423a665436b8a1e4dd0c6253146", + "9c8483481a134ecf84d3864b45faca6a", + "a5bc047bb07e4fc8a025e59023455b62", + "3ce5c791f1204da0a17348880f8a7983", + "bc5407469e1345e382ff93fe4627bfa4", + "8831948aaa4449e5b164c62b10e4be6d", + "09649321adfe4a0586777e914262b8a2", + "5861155b706041508812bb83b76e0390", + "70cd18ea107841aa9c6c853fa495bdef", + "d01171ae9b9247548b592396a75ce1f5", + "2c9b9882f4ca439e89e68cabbf49c767", + "f85894020a4b4cebbdfd74f538a07dc7", + "41c5a2b3b0d5474297ff57be20312abd", + "d9a373d54b5443e29a3e21bd5524884f", + "2eecdd3afb24477981f75a8063610b17", + "76c7f49863384f47a6856a768c2d8d5e", + "8632380517a043ccbd364e1418cfed74", + "82a96bcbf8dc40db89fafceb3a7bb7bc", + "dc3024aa5e234f4299641f072558b9a8", + "cdf3b49e57154f28a149301e34bc0c8e", + "4234b9646b4c49818623a14651659e2d", + "9d2902a4d3ec4921b3bc9c4eeeb7c13d", + "930fe8641f25480cba0d44f9047d553c", + "e886b88c572441d59d99994addcd283a", + "b31f2efdeca64c999a4753f2789a1e67", + "018dab01b31949318128504332f649d9", + "d1bf6285f4c4458d8128a5ece3749b96", + "32cd906750e14e29a8f15c53e6b7e88c", + "2826823d900347bd97b17708ee04c3ff", + "95a83d7a1b7c49188bfb933b8329ebed", + "494ad5c723924c368e11ab5ac7ead85b", + "4f50e5d5a25849ee80b8049c4fdf098f", + "235473477d4c47fab26769aa89f3e529", + "abdb095ac525489a92236227f72631c4", + "5a45754234384c4e949144e0e3fd7872", + "2d66e6638e9a4e7387e2d5b724a64f44", + "539875c4f92f4a13a8e215eb460eb68d", + "9522d9515dca43349815855b30577a37", + "f0a9c037534c4172a2bd4ca3ad6f26c0", + "0148e4be70934f47931055925051e0da", + "41b074fe3c6440f49e8e6d7ddccdb3cf", + "27d7509f0b6d46a098a872df96e4ab23", + "7df779223b7744c89345ae2e4a2f3226", + "d86c37282e0c40c5a88f72f7e5d4cda3", + "f5c624361ae743e6b02e262289fd8374", + "b16d2b8158ef4adca2a0f7a917928ec4", + "0badd2265db2428cad5033aacf3f7d2a", + "57c6a33fe3a949d3923e406465b3c91a", + "7ecb9aa762da47dca9f10b708f6923d4", + "1d9c515756a04590854316759eb08b3e", + "fc8c0cd50b7f4e108d054c401b2bc148", + "ff9916c70f5a4d04a70ed2305ac104d2", + "f3785071e9244d83ba311b7da48a1085", + "b17dcb079c394235b340a612615bd104", + "a6808f5c6a184a59915e36e44950d659", + "132c4fe334ba4e508c07533a6a214832", + "548afec5aca946c7864b73695caec7c0", + "f3fde76f12a14cccbc1cadc0048b80ec", + "8c53c3bdc53c42d6adf7f0b415d6e7bc", + "15cd0e85b7d2472b876b7fa6cd09b8ee", + "62c642a71dc54d36a6009c9119ac5b36", + "2085dcf1423047d691be59d5faab4ead", + "2b271bc246d1405398be1609704a3e14", + "0d672a10acf94737ba672b4f747f9c97", + "35727dec23e84a24a8d2e8ad20dd545f", + "17c50676373c4dd392d0cab723e8f787", + "17c6a24dfab7436e927bffd1738b4081", + "3522034382104c3aa7b1929852277e0a", + "11113b28be364d93be509a012e6f257f", + "8884fea77e0247f783b6b84e0925f871", + "bf56a2b64dab4e7dbfa418c7ad0d6c60", + "387abe5244964f06bae65b60d2f41ae5", + "bad47b128a554f748af6ed0d0370671f", + "e66bbf01dbd14d15999296d8355f985f", + "1765a8a8921947f8a9124badcc28aa23", + "c78f13f842714863800899014754392a", + "c65e566bf1004f5385770a4f28eec736", + "c9d09cdbfb814211b888a183ba91ae47", + "7b3efb900f7b408c8155566815a0ff4c", + "fd3afdcd22db4ce4a86c7a1257850a15", + "65cd91f9319140408d38ce2c66da8a9d", + "64167bab103e4ffe8561b7583802b74a", + "5b5d5fc3fc944ada81d00ca16003882b", + "52e4948f12bf4ab4ad27e59d353ce9e8", + "59c023337f2341ee9936332b1ad2c6aa", + "a3b9b84dcd2f4051af25a3d87b71f7f1", + "df4bf911a9374ecb987a222d017f12cf", + "c42920de88244b2f8fdca6dd408b53b8", + "6db831285d1d447997b9b9bc06a0f503", + "52d15427b1cc48509f358eb241d5002b", + "161cd9949bc94e299b5ad1f2fa03a574", + "3205d319c5854499a02266ac2e472835", + "17cac1aa2d46404ab39766a20c5f2e47", + "271f05a23b6d415584df057b7b1da442", + "89027bd07cfb4856a7f8b7db8c955f25", + "9cee65228d8f435dbd6dfd6ef900ccba", + "c85175a3b66940069939cc35828b04ca", + "94828a7f821c4790af789f67a3ac0520", + "8c16a0107dcb4ebd93a5cd2e1470943b", + "f1aa479977a74a608d362679ed5ca721", + "878c1f882808477ab81c2fe86d5a3936", + "000074a334c541878360457c672b6c2e", + "e2da46f23af54a7ca5bcaf7581dbfa6b", + "655edd88cfa74d2cafc13c7aa387d137", + "4d4e8cb3f5ab4b219203b7757dafa5ba", + "fd612e2ea8e94d80ac3b8097eb2e5bbe", + "7178aeec9022464c92629af184f4ac2c", + "67d6494522b94a06a8058c5006c4caeb", + "712e0cf10fbe43b697bfaa25987c8d9a", + "7ea7b60be1a0412b87d330148229b932", + "83879054afcc48a39bd6978f4899cbc0", + "544ca52414a848bdbf33794bc04752e2", + "93b6eb454fc54f2184b252d147cb2323", + "4c15fd435ffe4154a3f3852d0820bd45", + "7c39a78a8c1f4fc5870e7975bc9b1fed", + "44c982a5367d4af8b845c7494ee55e6b", + "1d14b2f4cf864208a9bfb0479881536d", + "b741649233404cecb47cdba3811b86ec", + "e40bdc9f634e418eac01c64674812bca", + "1f64833ea97b4f3d8a60f9ecda09b1f2", + "a9691aaac6c8451bb50dfaa4d3b8d564", + "41bd4918a6d94f56b6806991855ce52a", + "8bc661e726714de4926b7d95ab30c81a", + "4ea1eb161ce34b3cad5b2aa50428d9f5", + "0229e43f0ad0488aba90dd7cbfd8ee24", + "f257c99765e242038583aa6b34e01635", + "349f07ecd7704df6b4e7112037f72af2", + "f1b122751d0b4609926041975fef2bab", + "41f7071e3e474e26a7898a6042123974", + "f7f291cd5c71424288cd7175eecd3104", + "0dd451f295d049cea20c17d3ffa87ee3", + "5982d309266d4654a01e01debe54d842", + "e0054749aa4b4844af0a4aaabe1d4657", + "efce8c21a9ac4a4fa33a336127007c48", + "4a780837e8494759b881c980e302aaa2", + "f6e9c6898f3e4b29b7b2b5f45a896998", + "73c7a3d1476143ca9d31aa3e515f5be4", + "579ff7f8f4ac4c23a54ef471f13a879e", + "8c8a9d0153d145b2aa64bf185c3f9d20", + "65a35e27d67c4a7dbba6b7c18c6bb476", + "aea6aec8741a424385ca378389feb73b", + "499b8e80c3d543c196e61844f7cda9a2", + "c18feec3dcce469596b5f7636e2c4db2", + "fa12b971c9bd4c9e9fc5ae386259b99a", + "972f084ea5b944e38fa99a56d1372b1b", + "57d62df35f4541e693addf45604f85cc", + "4b7a4d43ef5a4e8ea5d5daf709ed655a", + "5138e3b820ec40c6b80b1ee6cade4f48", + "207a8a10d98e4607a7fb1812ee132b4a", + "562d998d30d94e8c96856b68601b8614", + "d6af989868a84939a4f12db2e8334523", + "1fab9642522247c09dc8754709f84628", + "6587efa32615464099b0736f92336506", + "784169583c2e42cd8b4bd8667898da44", + "e46deaab889548948a31e4264de61e5a", + "ca123df978a04daa860c0d8e9d3511d1", + "d6006217de99465da78c9e5b08e1f9ae", + "9aa8d6f4d32a4d61876408a27ea4acea", + "5eea18bc43964bfeafd6dd9635f5d254", + "a17bfefbd1454c9c80cde4af908a6442", + "118e62a9d389429fa028f2de8fc3bb32", + "d3091630338141f3825a6fdc6adbfa75", + "a70ef303d12e4f268c5f6c7dc72f1696", + "8d91730c6e744a96aad5f08267de7013", + "76f1d65b3e1b496b99cf5fa3ee5417a8", + "a87e3b0306774d65b1c64c3d699fc5c2", + "4981d9bafc4146fbb2f38a918c5b4bdf", + "79f906eceb3640bf8729b903cdd47f9b", + "507590be54d44703819bcddcc061213e", + "7ebcb36dca0945dcbc7cf7dd6aa273a2", + "c1cbd15423b74c1a84517e6bc331d15f", + "1cb6264b52174424a9ff54f970027ff2", + "bb52066b2fae4d059883a4dea9a58d07", + "bde3a242710c4e63ab85a89404600607", + "2c6af8b437da44bca406de33510beeb5", + "55abb97f9a854f76a8bc574780058c3a", + "f4a50b61cf154b01a184c117a27ec348", + "21c67e417ffe49c79c358b43df690a15", + "aa7d98734c7644f787bff33a5a0e25e4", + "6acd6e2c9d9c497caea531cad01bb07e", + "b16686cb9b284cf892c5a939d357f73c", + "504fcade8ddc42d99a5e8cd46720879a", + "f1f1d3b1d5df42138695fb503facd5e1", + "af95b60825f34651a6f4e3f749078202", + "c408568208c4461fa9c7d54cafe4d1de", + "23f916cc790a4dcb9db1a1b959e3485b", + "347f0780a7a048b8bd32226ae2af53cf", + "bd4f92758cfa4cec9031d262c0aa4b0e", + "f58946a7b7304ef099c0275b1ac3ef18", + "74475cde29474c7683cb63bab6a0b94c", + "43788ea407a4464bb1a33e6319dec996", + "e5799780e4b74481a2d072483d7a3e2a", + "e11ba068feb04c31b6b67d925f0f463a", + "d40fdecddc254175996276153ea5ed7d", + "bee533e6c67d4c4fa34c23e79b819146", + "f1eccbd01c884fe28ec65ce699cf7b81", + "522bafb5245a4a07b2ffdab3833d1b03", + "3d6ad17050e7425e94a9441028552c1b", + "e46cac1656464743850e8add78f40326", + "ba348ad8e81845279317ddc441d4a101", + "cfb4b56e14304ad2ab4f211739104abf", + "1864ec8ab4704653b27e2ebf37ee75d6", + "a4c7126cc70343b1b05441e17cb0364c", + "ea80b4bd735d49458568093df857e8be", + "316a0da5fb1b49af92a51a6baf719098", + "1ea9d69c1e7d49d48ed804b7744eac3a", + "89ebea4991e34ec292657bca82f73f60", + "790ee621be764ca88d4708a89dd14016", + "8c24eb2bb8dc451f90ae23143b2bc31e", + "2892cc4cab4748cd865b7b7cf3805308", + "44c454137a274c54934e45d7768d08ab", + "eefd711998cd4e8da4adb7a80ff30968", + "e6823583dbca4d219ac303e96cd797fa", + "8b53d504de26437c8b677f224bf9d711", + "001f5b9d3b7d4210b0dee5139c664a89", + "c4423e51c2fb4a43999fd28c652e7186", + "dde4f952f90a44c49db8b10d47952de3", + "3b2db26a99584daca66ec3a0c731c620", + "9505179c04314ddc8728371b89e9a4c0", + "98347ea0597349b18b69040f7dd1d6b9", + "b103a1ec9bb549848d884a003f96b3fe", + "b135100c5d514f85841b93a3763c05b2", + "b0b3da3425bb403eb75f714d34ae14c7", + "fcfd6b9a12f3402b8edd867a0d4af9e7", + "215377ebdcd648bf8865106180539c1a", + "89d1fcd0ec0f486c8fc3e5d811a1fe5c", + "a0bbf1bab92e4dd19096e882c60d05fd", + "a210d4cdc7c944a4bc6c456e385a0bdb", + "8aa3d39c9c6b46d4bb39b0fde6204a8a", + "e2b0113a985b43a1acdea9e0c58b9e11", + "416a462593e7453b8d0df0d965967677", + "33310c3df38a4153b9f076286ee27636", + "c362411a4a744b6bb18ce4ffcf4e7f43", + "df9a7c57c2b34d5a818f360e679b576a", + "3c76cce1322948ffa467358ded7951cc", + "1ab2e4eae4f248ae8d6b45e8a12737b0", + "62dd61240ffc4e158cabcc32d2044dfd", + "649f10d75f86431ea0930ba454d11c31", + "81657d5ab53243e78bbaefde493edf5c", + "1da241d0c62c4e318baaf078cd0e3b89", + "6542db5456ec4489ae1c5ef40f079a57", + "87dc4f75804b4635949a4e8c37c79d8b", + "99ed138bb3d64d67bc9ddc1400b211a9", + "d8d6bb178d07401aa9c94faab14e0b4f", + "d85e8574d17041eda423cabafa18ab98", + "ef84c85d501f46949b9df0b0dd1b235e", + "ed56adb98cf84c5fb72ef315a0380ddc", + "19ffbca399304db3a04f7fb735deec4c", + "3e6004858508416293b536efaa2cbedc", + "844da43957bc4c8082d2c2d3922c06a5", + "ef4fef24c990461986a96f5462c5248d", + "3c96a2a3f207411987c6151e680b72d2", + "51be72dc58d4437bb3dfc408c751344d", + "9d21863b3a3f4397b86e2d735b95c061", + "c9c562d08b91405786285de43fcc729c", + "24a30173a4f94a739c99513645e0d6f8", + "f4031bb5f7e64ebca4c37d4fa5ba6e8d", + "305bf8147f004b7f8579ebe2507dac61", + "618ad10c9f414e9d805e36fd514011e1", + "3d75ecc475504bfb8fa146ddfa09e3d5", + "81b3eaf9958b444781323c733255db0e", + "7ff84e7e989141a6869c7afc12a5e398", + "42eec66827084ea6b1990c4796c800d5", + "bf82021cf0cc46808ec26f4721020e70", + "7bd9dd8a60b840439c68ec3e3562550e", + "f83d2745afee42eeb2b385191d99391b", + "02230deb5a8c4050824692b2ca4e9ba1", + "2533ef500ece4fcc804872c706df036b", + "3ff3eec0bf76429daa0b99eb981cbd61", + "418f684021d240d6bc69a0da1b17dd34", + "429bb251fbe844e78d03d84af8a38f23", + "bba49b60f3d94e8aa6ec0257fe89c2a9", + "8d35be41a63c4762b8cb5fe62e50fc52", + "76c69108ab894ea3a344b209c8f95db6", + "6a8e4c5e65d347738d4b821e211d6c56", + "7c6f8ba8621d41489cad80d426259f90", + "1f075567411e42eb8af3942b5e061871", + "9cb7beb4f12c4127b8975e18fa51fd6c", + "7e094efa6d184bdb8d0e05f5d0961f13", + "2c6e020ea72b41f589b0fae5b78ea36d", + "4cfa4db2d1d4451a9c08b53dd9e7c2ec", + "fc63df9772a4474ab070fd765bfbadd9", + "4d56b3474e6442709bde68874b6e6fdd", + "9f6326eba30442289c0f2d6c2dbd1dd5", + "beaa39ee91ed4a7dafd50910536f5cff", + "af981d4f47d5462fa0b1e16d72f886bb", + "7c42807127644030a2fa92e4bc326160", + "dbefa974912b463491dcaaa247d74e58", + "cc7c4ed57dc44576a42e85ca02ce8263", + "efd5e84da1004346980486acd06392bf", + "e54dce6a1f6a49e8a295faf8e2213138", + "f6d6a80c25ca4b8aa7da66763275d0d5", + "372ddca13cf34765bdcd3af35fe77175", + "0af4f2b80dce4b6ab6d6823acb124582", + "b430ef733f7b4052aff820ea7864c66d", + "376e251851b44ceeb2ffe737b5c22562", + "b1a0328691f1455a99037aa49352d082", + "4781e8d4956e416b89bbc41744ac35af", + "94f74bf2eceb43f48b72b06b98b57b59", + "86b1bc0763a747d181489a7c1e7bd89b", + "e6523b411d4b403ba3a2d018c051e65f", + "726a646234fe4ee59fcdff9dafd89c09", + "ac2b50d2542c4f458b4ea404b8ed5e4b", + "c72f7a87d7c34b49ac73ccf235190ffb", + "89afb4636fa44e37ad688f0563ff4723", + "543c9a06fc8f47648f440b2c36b354d0", + "b542ac71e229471ca18e2e426c1bbb55", + "8c2be5195952496aa71e4d396e3473e9", + "909b3f198d5b49cea3f68549a8f57b51", + "a755d0560236462faafc6ba391f0ba8e", + "82c003cd4d724fc4b21bc61cfe7168ec", + "1ae3077f108d4775afab873f99b2c44b", + "5222cf9dedae4a31882281f6d7bada89", + "bbca8c63b76c4371b75bef10a712b4b5", + "2a20de42531a4156bfcb388cae209101", + "bc12d3153b7d4148bc74d038dc5cd14b", + "66451cf5029d45ffa5616342bfd8c6ab", + "60e3f514f5e34c4086d0e7422d9f3099", + "b2bd17e90a464ee4a951807984f8b57f", + "5aa2c97228774b6bbacd48b5255b60f1", + "f7c99cafa3b44d1ea8ff4c28c3fb1de5", + "4f8beaf35a13474f9c655e169a439b5b", + "26a1c48f1a8d4e9bbd24bb0acfe2f433", + "375d4054af104d80bcdffa72e131fa31", + "eb44ebb2b5f54811b0699051147419f7", + "67698d67326f4e57a96bace4d57e3f0b", + "cdec8a3b9299474eb642509bc5b37844", + "82df114bcb8a4238a0c2e0bd381f2e50", + "a1a4493326b9418cb17ec6b871dcd28c", + "dcb878f3b24c44e099b1f51011cd432d", + "5b28b362e57e4e34b6df6ab2241ba1a4", + "76ed37e3b9554a46881a0cbd702c7c13", + "ab0a2921a8384680bed6f8cef5e20d0f", + "302c7f7912fb40b28be06a61faa5c723", + "825f8e31ba0e4864ad4b902aab31af22", + "72f1a54112144d0b9841da74ce30f6a4", + "f2537f2750a5416b9e7b9121878e245d", + "d03766ba61f2468aa95709ce84b5a4e4", + "4eadb7226f404c35aa3a506957f01bbf", + "ec7cb33535a6419fb0d03da03f8d6249", + "8f4c5808e25648a9b78a2ea39f7d271a", + "8100bb0054c84fcd9bd4fa3f52cd58fb", + "iEjmm8vp0s2TPcjq9j367AE43fA", + "c720409cee794553b6386c68bfede496", + "038d1eeb927d442bb0b8f9100ad7dbb2", + "57e4c5c6250d47c48f59c031b52e1f07", + "c6799b8841cd42488c40db4fc99dfc27", + "0c21f6ac8d44452197751910527c3b0f", + "1843e5b5d6d04de0943542c7dd3d5241", + "2fbb3739ebea4a68b7898460dd6445cf", + "67abff7459f34afca11e3effab62c761", + "d262db8c87e5410c8ebbd080138ec0c2", + "f2e66f07dac645f88a8464b790cfe751", + "6c7db00cc164467ebac356a5ca67368b", + "ceca35d922a147939967424c552001ec", + "b4954fa4806d44629a8848137c46690d", + "cac4273c81334a19b54f6ba02c79de15", + "3c28bca3e58b4448a650907c1edab432", + "31ae953de0f246c4a6279252289d3b20", + "2b23af67627c454681d8080e48904c1f", + "83503c160ac3401bb2e59488c0155369", + "9c1c86c41bf1467f8ed419c746ecef46", + "09ee0595169942e0aa2f6e7a99e49bbf", + "9cbf22efc459491db7aa295e8638b967", + "65e6e24d033a46aaa859497388f006f3", + "2b807dda52eb4235a0625f79c9851c15", + "b0eda7cff4cb4b42a30eaca71024af04", + "5ef8564938fe4de39fac93c3fd496015", + "d8a9e8ff1dab4566bae27a67a9965fd7", + "9caf40f129294b2ca264e4539044fe87", + "1b0619308be640a2b33a16cc898c8dfc", + "9424c015eab74a59841f78018024e016", + "aff09df52ea84c318ba591c0f70815e6", + "dfff87207b394ded97a7c7c2669a5fe1", + "466390ba903248baa31a3c0977666a95", + "93ce115ac08d4365bc9a8d9e386bd166", + "c49e9d6a91004a319a7415b852715f45", + "5186f04c177d4e1d991e87a3b4640b88", + "1891ec7520974cdca1c8e482f22535f6", + "0a741a4de126439cb8f2b6b7e3086117", + "90ddd00b03374391adab15353d78a3e7", + "60d3cb0210bf4c2e9c802cf35122116f", + "8b98b2f9759a4bbcb8af5c9d2890c91a", + "341ca375af784300a4fb44ee204dfc50", + "c13df811c8334f158d486ff15d1d23db", + "86a4e42f3f0e4847b58413ab69f0c789", + "8e112a961aaf44ed9895911856e57034", + "153333cb5334423185c59d0abef9090e", + "fc562f62ad134dd6adea0f134b6c1771", + "6fc20790cded438c88d4a76d4c2a702d", + "d6a1aa8573054336a24cc936cf9e6200", + "910d3a33ce414c799f7050f08fae45fb", + "f6b589d0577a4eb899c6c14fc52b1049", + "42abc5b0cf7f426eb83bdfede64bcbaf", + "f277191dbcbe48e594f0877240c9b20e", + "df6cfbcd685d40b2932a6d35c7ee9677", + "5cc52b3d32064c9ca6d476e1a90b634f", + "a7785ac7ce7f4ba79df661db33637ba9", + "535e745d7dd84701aa8ac7deb7e09c37", + "d40cae50e04145dd997cdca415cd72ad", + "e391894b3c3444ff8d2b1b0cee905ab5", + "19f68e57f79c40658b1c6bbe434a0386", + "0b1bd36f662743fc83a396d40bd75230", + "2622736aa0e84d93be7f38137110450f", + "e64b5fd0fde2419cbcba07279c4291e8", + "d9db0ec3cffb4c3a99a4b71b2644b586", + "8668a2b3e5e743248b3fd64fb6246a0a", + "276e5736a5ad46b18ca227d3e04eb2bd", + "fd9fac0fee764dd6b77a567be1221c05", + "4c4690ba918f477b829990dd2e960c21", + "a1fad496198c468f9674f148653f8336", + "d6507259030a46f2a21a58c55d45c67f", + "169bbcbc091747edb843d204747f504f", + "82ef0bcc6d844131b3a3deb1ea09f73f", + "81ac1ff71f484a48857b622cfec06b1c", + "09e36a58c2624509b4c56ca33d54d2ce", + "418bc9b5d4a04ffabdfc65df242b67c9", + "4bc699f995844d3394389e8ca8c64794", + "46178db434914b67a639109d4d585bc4", + "445f6cd1f36a49e8a3bb64bb218e1fa1", + "952f35a14f2e4fc0937325ecc09f8175", + "c7da540534134560af463fdd29ed209f", + "01d609eabd1a4f08b00d87c1aca2b4dd", + "b4738d0de0d642cdadd9809a887fe44a", + "f61298c6bd4c40d6aed082057177a994", + "d9496eb457aa4f09a6309fc6c88c58ef", + "0aa9882e169a4f228a27a1a88126ca78", + "e684c968e2c340679945651cccf600da", + "372cf57211e2429bb53e9863fc603596", + "c765ba79e1a74dcab9c7a208e7aa37b9", + "2edeff57548c40978c3bf66b146ecc18", + "49caf3bdcd9642a099ba077bf6c82872", + "0b3293889e654904b2ec4313bf8d181d", + "0f45a8874b234efcb59e3a3268f750b5", + "92b1bb0824ab4a238c5ec899729067b8", + "cc6be3bcdde246ab8efb5deeffe457ec", + "67693c102abf411fbe47ccf37a4fe979", + "fa9c3aa591ca4724a3ab414d20f7ebcd", + "dfd9a8c4a3e14888ab40f6f18b5decd0", + "9885a4f288c24135a7796035cbae6de3", + "f19a35db2281414d85452effcf32fe6f", + "bf47eea601784059aa52f2929a0c9ada", + "6a41bb71e72c4f3ab070e0a5a237ae53", + "a98131dd42c64d84a43bb58cf04ef532", + "516b955ad03a4657bee6bcf3c96f759e", + "8b034a6e20e6464286a532d2ba08ee84", + "dce8bc6f73b745e7827209527c52fa51", + "d75b364f42db47789f0e89047ea5651d", + "618b0adc2df1477c80ea3a27247ca196", + "d300f72448f14589be070c955c7781d7", + "4d7ae7033dfc49e9a3159edcf71afd43", + "16b4c314b1634e2ea035c97222483c09", + "1baa55a1af724ed9affda2623baa1714", + "a23868ce6be440ccbe771b6aef9fa8ee", + "596281bfcda140ff816c19694deca819", + "a410486fa3814ccaa2b7cb3bb76f7a28", + "7e3b35368929485d89df5fe9071afd06", + "2b358bd708c04b5c978e35f75f63d2b9", + "2d777903a4ce45b387a4bfb314bfc8c3", + "8360d919decb4f93a595914b131f0839", + "6612a34c526b457b9fef451bc4b37507", + "2ba6d1808d904733b9cd5a19dc9a2404", + "4718a61496e6481481207100e8b77ddb", + "5a6d088f0c5d46a599c5c48f1a9f543c", + "23310246633748859785653f03511d9d", + "542116c52c604cd7bcce50f17d286463", + "b547d81073b64d3e97200fd3ae9a74af", + "9586b39b49324d4ca045bcbc795d4ecc", + "3c867252612d4fd9a5d862066de8a925", + "f03c3032dd884e7aa49fe64ac2e8c3b3", + "87c75769f75c42f29c2c868e1509143b", + "56881c423cab436293fddd2b77e314d0", + "a228b2c58aa6490d9e7b5f2339977944", + "0a4c2dee37fe41a882321e4b4010c631", + "9539094e99df4246a29063bfa11a8f73", + "ee4d318b807047bd993f8ff2f4da7b3e", + "90fa309b7f3b41e9a3c236a101973b25", + "4524f72c721040229bc33fd190a738d4", + "ef62f89a04a2434d80ad077b064bb639", + "da0468db72b6469aa651259a1f812c1a", + "b03fc3b58957488692a2b3609a1c84da", + "e6bbcfd2e8884fbba848acdd669edb79", + "cda570a9a10e43cfbd0ef0ebe94c0eeb", + "f761f1b136144f748bc596dac8315cf6", + "9db89a2de2a4463d9d5b48486cdb3fc7", + "72924a6dddd245959ecea87845fe813d", + "8f85a6dfe37d4ebc86182a82489c8e02", + "3f20f59908884fb18a68fd5da22c11f4", + "d63ecfc224ae44368cdca10db35304c4", + "1f8fdf6d9bd74757b1a9cb11ccc138c7", + "ebd6b533ab8c46d6a4250b5d89c30d8b", + "919dc2f2784b472a904117326f6dcf52", + "abb5588835f4455faa169b5d98c9c117", + "c2651a434cff49e0a2e41a3828d38a89", + "551b3bf83c8a471ebd18398ae8ed27fd", + "d1b39ebed6ac4a2c9ae7d006bbb8ffa1", + "3783d883641d423b8e78dbd2784d6bc5", + "7e0e83ef46ab43ddb9d8715627451bd4", + "331af300e15946f3bc5870c58b0066e4", + "62505720a81e4fedabe0e72d2bd20b70", + "253f45df4f3848698d34893b000d10f6", + "3d4a4881c25b4dfebeaa6cc70588e17f", + "73fbf01d7573499fb6fd6c4fc0c6a963", + "f95b0f20749b43f7a283239a99217377", + "7cf3226824a94b0d909a7ba0949bb5fe", + "7f19cfe921144cd8a47369fd958c4c1c", + "035ebfe681e744b38b6cc58e2f551249", + "b40004677ea841cca02f9a8e9b6db754", + "779290935b8b4dedbd39c2259d44faef", + "53f6db7938454e11833559b70ca449aa", + "a77f888bac654f8191442e74f0db4e7a", + "44f41039246a4df59027c38023d5a576", + "ea215b2cb8c2408ea8a65500255bf766", + "63e3afa5aaf84935bb9245d94bb79c7d", + "0874ab71b54c4d40b32ce993e1106919", + "fdc6d98516c7469289038f44f68629b5", + "93c15997949a48b4bf07c816746fce3f", + "97c552b03c3343e783670de61e6d179a", + "ebd40b3a66934aa69d847b8e138ab752", + "57bca8de17ad4705aae74745ce73d5d4", + "e9f362c58d7f46159f2fd05d73667d8e", + "461d900478a34af9b4da478548efea64", + "9d5c53fd0fb543e2afbcd4982ff4b893", + "565f37f9d5344a459dd9a680a67b44f0", + "e4d1dce6c8f240ee8a8b2894a306bd1d", + "3c53be0431e2486da35f35b990c0f67c", + "65a0cac3e20d4dcfb97f71ca58888612", + "61c4ec36e30f4aa58e0b7f9ede324569", + "7d087d76cfc64ce7b39173eda2bde3a4", + "bfa9f7d0bde749ec950d17db9db21bd0", + "3f9438ff3bc4490d9ce4d1e8b43a09ac", + "6b65ee4b71a848cbab23f2026ad23bfd", + "9b1e09abe5e34d6397937ebf59901898", + "19da94bc606f46c7b135ab9155dd47a2", + "4d0a4c8cafda4af9b4e617cac229e86d", + "d2c6dbdfac514b01aac842d3f89a08e9", + "b7efe1d6d1784b5db62c974437b3da7c", + "2613c5f24bb3407da2664c410c34d523", + "a53633951e9e4dd0ab14bdc06e08984f", + "be45901e180640f6881fdcf189994873", + "5c03f6b1082a4decb33ae7511209271a", + "5cbb9821c81e4625b5f9dfd5171d3f1e", + "b691c4c7a57b450dbc5b7f04855c414e", + "fa83302f5dc7470bb199d48d2a1c8085", + "c246565eb927410486c7cf27b138a2e2", + "5f642bd6a08e4990bc951e2dea254296", + "4ed1c284ae05448cb5131c20286301d9", + "5ff4270b4f0b4017b34363a309f756f5", + "2ad86321197a49feb54b7726743d7fd0", + "513621a3eab84736a4dd3910363e7a98", + "ab89c948efab4b9eaf12d9f0e72acab7", + "a26a17d7213f4163b731efe224dc8ead", + "0419bd8379344124bf29cf488da98528", + "7ed0516cba434c8ca230f6d9645ff0f3", + "9b2530fa45e347a58c4fb7ea171d936a", + "82268b0aaf6542d885f563a0f5b6c578", + "951cea7c961541d6a27a9d1abca27ee9", + "03f2af58cebf4256925ba3179d32045e", + "237a028363c14a5b89462d248044d4df", + "a7ff3aaadd70477c95d472f628f9236c", + "e009982029d84569b653614784e0457d", + "c801881f25e34327bac908af98051914", + "240379718378404f8efb2f2e5544c00a", + "dbccd6718dd446ee8c4e7765ec75bc5c", + "06716b143faa4992a6106e91dc4cda2c", + "a7fbaca019f943b08873e596ffcab495", + "8849b04a347740848c447c213daa335c", + "ba8a9c396da64205b38bbf350741837b", + "d9d84b1f6bed433eb69b6ab6d16c3bc5", + "140dc25d6d1e4329a9a923c2e9b81fb4", + "9a5d683196224650b76181239d648d05", + "8763b698b58549e0a6db84d2e32cc8bb", + "a4ffc856eb504345b0eac42d891e7f8b", + "4b77509259e746fc90bf6dc06875a194", + "a68bfdc7043e469e8479b7e87bbd8071", + "b0699e20ad764e53be6f7c54a911d0b2", + "9ac01b825aa043ca8a96921e11d58af5", + "c9c96db118264616adce39b362eae928", + "31ddd03174d64d019419a44984daa3b5", + "77592f9bf3b7413291b4e322e8f3fd6a", + "0098586123fc435f86c7f5cb3d3b8a79", + "29620ea7b8364bdda75c9d1f66bf68d2", + "623771273fd44848bd3e4e55dc358190", + "24981a260900458399176bf2fb2b99a2", + "322ba3a159a845c7b7642467e23fcc2d", + "5268dc011d584b17acc2480052325c5c", + "c30fd75d12a3437fa48d1b2385055f85", + "38b08cda681846b988b92a9eea95083f", + "cd005d49b13743139c0d24b1648da8ae", + "bd691bdc45ab4f91ae9304df4190e2e3", + "946bca019fac43e2a04304dc27898024", + "f82277a43fc649f296e4c59063e78593", + "eddcaf883d4f4051bf03ee3bdc714b57", + "f6113eba1f83456c80b36d8d4ff4ee9d", + "d6336cbaa64f4a75aa5b51b97a9aae98", + "55414356b280452ab636f9d7abcb00b4", + "dbd6e256d4204ac3b78cbc1e16269198", + "c808b6c4239c4bb7becb3124c4b3543c", + "500b55ef102e453ebd4fddb2f3c8b3da", + "9a7b472a236f4c22aa85d790dc40b796", + "14cbf975ccfd46338d39cff250d91c8b", + "181c2f0663664d2eaf444c0435334296", + "5773656a849f4af2a965bfe2c9bc2539", + "84145cf4a3984ff59867f8abfe9138ad", + "23d22ba864ab495f82ea6efba5d3d1ee", + "ee968d0c974744c2a0c0c06c6a86c8e4", + "38b7db04e49e4cd996ab1e55b9af0b96", + "c89d58d38ad04863b490585a709d8523", + "071f6fb8ee4c4ab8aac5520f82e20c9c", + "5832ef06058b4e949828533ef511c33a", + "53912ca094fe4de3b8468d133cc99f8c", + "e2fc682ec0814894989334b06bc351db", + "24b4d9ed93e04d3d8ee83401196df405", + "d36bea1f26ad47ea98f41e402d70d9b5", + "9cf701a0db76411294266c5a3665458b", + "e1ef0cd124134ab9a2c75338c8a9b955", + "d9a6b6fa601c4fdfac80c2665f00b7a7", + "bb298c6a88734bedbe5d4822542b9224", + "a444496f15d143beaca6dd24bd0852bf", + "9c851f51ed824ef89a82be587dc3f9a7", + "83aa9bc0ba404af49cbeba8fdc0cf2ea", + "53b9e73599a74eb292c86ef1a219229f", + "bffa3036f5e24cb28cc8f98532783928", + "9edb72613ddf4a2cafe82cf844824d49", + "9a122b5d958046949d07ff580799ffd4", + "1115d0518b744af7afa213ede890ed03", + "1f563de8b96d4d21abf9a2d8ce8c96cf", + "f60e41fd53634021a470c045327e2bd1", + "16ea785ea2764860abf0883eabdde25c", + "c867c76118514deeaf3bfd8d08babd03", + "ab30df1b79c64cdb927e8edd3227ae74", + "d468df5f301a4b098e6521d883a817da", + "3320d2ee08fc4cdd9337754c8fb34886", + "754a35fc531e43f5b3d1c27ccf35a139", + "0a5439cbbbbc4f03884e82c49a5d9666", + "1fca6fce3aba423b96aa2e00f004e9f2", + "437334fe23ab4e34b7e054b84cc8762c", + "25c6874d173a4f6ca63e150bbd505686", + "ee00e4ecbb8e44f2b483dd6b092ff817", + "481dec023faa4edd900784f7862e9e1a", + "8c1485f88cbe48688a2d14c793a632ca", + "c7f79fbc547b4b85826624566739d85a", + "79dab0ecc4dc49d9b41d86c62871c5ca", + "0334d2d16bdb4310b84a973b9a696b13", + "1b14dc0571084740844dea2e0f6b3bb7", + "f1d44a8c315041b3bfc42db81681c2c8", + "215381b800c5496793b4c277a334cf04", + "89df181bd04341caac549ee8dbe31283", + "ee50e01adc864ccc880caed9b5eb3bcb", + "8b004ccbf98a4926937cac33d16041e3", + "c027cb3f85414b7caa59e31432686c1a", + "cdcecae3371347018827eb6838e403c6", + "4fd49ea011a145c8909bb5e9a0cd2908", + "8d0fee842f1f4ab596aec44c6a91ca04", + "9eff909d56c74282a94551ccf38844b6", + "77df82f5ee344900aa7ce99dfd176e59", + "eaa0a0cbce964b2099b955f5ea241eee", + "4e43eb29aa144bdbada1ec500d218a81", + "ad516c53aa2a406fa99140aa52ed636c", + "c7c4bf93806c4861a995b0182b2ee211", + "dcc1b54a9df8473a9857ec8997e378cd", + "0f9fe38a1e424a47a77f8b1f8a3e4efb", + "01e28caba4a64c408413e5f621a58365", + "6d5284b842434413a17133f7bf259669", + "93bc5a1c73f6445094f552029dabf4f2", + "482e8266fe5b41609a5567196370ff79", + "e5d2f0d496f8451b87c08c432781eaf3", + "29551ec33f7b487f9ade7c32f089e786", + "a1e5f86f0cf84ae5a79d06bc8826cc6d", + "8609cf7e67bf413487a7d94c73aeaa3e", + "64e61bf3cb704534bcaa3dea5fa2516d", + "736c071876764ad599ebaa6235a1e236", + "476bdfe46cb04c069cc5a5589deaa0a8", + "4df80d6f07a44e45a10471de3e1e8308", + "3f0bae38d9a74ff6bf9ac5fcfb9fd176", + "deeb41e3f5f1480bb6f79f474c9f7ef5", + "bd4a67c182db4fe0a2fb82a70b97f470", + "f07a458377b144f6bbf522ff5edcf23a", + "7ef0374a132d444e998a33089da5f094", + "d5016aaacbc141a8ac4211e37e08e461", + "a63dccd75b7c4107bb3815a9db63aa86", + "84e8f248d94343338b22b530daf4ccf9", + "71eaecd581bc4aeb9fca84b4914566a2", + "a3829121efcc4cac8f432a5b4581c82b", + "a078eb0775c24890acd0ec3cb81009d9", + "d133b97771d84bcb93642fe8ad4d22db", + "fe9b39e004c34ed9b953ad2e91538b68", + "12f8507c2eae4ce6a73b322a78a2c0c6", + "b1c7655511bf46f788c0ef97c4964254", + "4dc4fc2f96dc4dc08228f9d4445f1de0", + "38347ea815fc4cb4a88ae3d0a3225efa", + "bb0076cb0f884c19ab0627411fb73e19", + "32b8dd2d96844c7db0fa0c5bf4a1214b", + "c00900cda58c485ebec08791cf490873", + "18ce415d0e6f437bb6e78a31ce5e2242", + "146e704d169d453c9b41f48d59652039", + "c8202e14dcdc48b899c4de779f771c5f", + "843a0f7b72424db282b92e112be6bdd0", + "be866b8f03a14965981f5a74dc1f8df0", + "5efa916bb4054e15838bcdeabee683c6", + "38415fb7fe67425586ab2e0b4cc8ab12", + "3396d1dad4b74d1d99a0b64391818b4a", + "e2f3f8d608c74f91aafef2637352aab3", + "84607458b0a444da8817c2c47de2d735", + "720bd64aa963457da4340fc7830b7aa7", + "370928d8346e47a2be52cc8231902443", + "651fdbf468124dcb93f98541d6c12706", + "0b420d09aa224062ad6c8031c382661e", + "867dfc95e96a49878837f80428918ca9", + "0ec729037b4e4eb7a9df8e865ee40b09", + "ca22ab61dc1e4ea0ae0691cf09927bb0", + "9c70cf2cafef4cffaa45cf46fb862a9f", + "ab44344f1f0a4d36a0cf3fd720d875bb", + "9c89f5c7427f4e1084a1ec29419f92fc", + "3b5c8cafe4724879bd06fadc28ec556f", + "a5ece341020b4d169de462585acf8396", + "61cdef0a49aa407b9b409d7fdc2db78e", + "85acf3d110314662b2f502d868913538", + "65248841bd914884a837ae3f3bb6137c", + "33d1d75841cf4d25abacb051b8fefe66", + "6646f7209bbb4894b5feb2b0bc8c86e3", + "379ec153fe2a427881ddf8be093253b5", + "dc35ef4a3c82475e8dd2b405a765fda1", + "b10c785c094b44eb839994b8c018d536", + "ea39fde0274d48188b5deae9e07ee179", + "b2a887e7af0d49b0abc6287b4e619ed1", + "dbac55fe84c84a1eb8d4602e83967617", + "49e06b3cb50a4a6087f5f64cbb3566a3", + "41a8142416f14665bf0cf82304d02b68", + "0fd82365601c4370a25676679cb7530b", + "8f9c418c63364f8e93bc545288dada39", + "21d81a73dcdc48a3a4de947e3e4cde2d", + "6fb99a87667c4bd0849c641f2fdcbf30", + "abf32f095d94465ab3a51f0a696eec22", + "a35537a5c61d4584b8d5baee54d260df", + "c6c14296f99d4c0cb482d5f544704815", + "ce72a5fe0f7a413cbfbfc765b3545dc8", + "d048f7bd322a491cb270d6312962c2bc", + "ea80f20b0d074343802315c58980b594", + "3b8f9b47275e4942a64920387c82240b", + "f5bd8065de084cf297302ed676f4da71", + "cd394f0c6d7549f4bbd8dfbf98629523", + "1e1a09dadac84a70a330b93ca500c84d", + "ccf72d795dc14d739888c4750c9d1804", + "4a763a1c211044089b1315f9f025b027", + "98860fa5504344ba81ac3801f59fef1d", + "85c459d1c24040f3ad67178d6de4a0a9", + "7903499ed5a741cd9e4faa447013057d", + "239e17db7ed94a699cdf3677378448b4", + "7999db7760614b7f81f3a8761e2992f7", + "255e172b92f145d2a43da188fe3ac8ec", + "febe0018f2d24629846b92c093ce4e2c", + "3d1956be9e724235817f03a1d570f408", + "385a49b096de489c8d3c544687e9b69f", + "a422d22e0ff64b3f87bd8c6fea8cd3fe", + "8c55ad5096094014999f68f706b2d233", + "c6632441a5a14ae89c873b68706ce2cd", + "cd19839669604911997f34496da96bfe", + "fb3ff27a30bb4243b8006bc997f4d8a4", + "61e3bbc68d414124863b1dab10525216", + "22f7121cab3a4d1eba0dd05db5ad9642", + "082b6deaa6cd4aeda8ba698c72cddb59", + "d8e24ffb9ee44d5498bdf9af505fbdc0", + "ca6177a826504119a7f1f0420745db13", + "69a5724e28024abca6e844fbd5122962", + "724e2da65e0248c9974ec864c65c45bb", + "54a0472b77c84658a8be0a4d9b53817a", + "222e96a82d3a45009ddea01488ef6ae1", + "0a122f8d1a954276bda739ea64b1d9c3", + "1e439c8c11a3416aa5e997a8e24dfe84", + "a5623167e7e44615a06414865128fe74", + "ce27e3369587476c85a436905f1e5c00", + "7d28879df294422ab729b6adde64c485", + "21bb3c10fec94d1083bcbbdaa704747f", + "084e557285c24d129246e8bd875959ec", + "4b8540708e134046b755f6c4d95b631d", + "d53966f767e645199592a72d9897cce8", + "28279274a7ba4320bf862bd0360cbb7b", + "0e5e674706974836bf792c7f4ab0bb76", + "390e4b951de6465191d46aa1b5e1c920", + "522c042aad9f4348a74c2985ec3f99f9", + "561954f322f94c79b5f930ac00dfce2b", + "5b72b7f26be747469ea60fdb74013b9c", + "e8c0b696c3a94010b716331ba23d1aec", + "c440b291045841abbd90cc3ab603a0c5", + "de02363e5b084234b0bedeb0da5755d1", + "32a201a6faf54a92b22bec4611b87e43", + "aad08d888ae4498da59c47faf149208e", + "b36256a5d99941008bb1a95be62bf741", + "b91918f32ea2475fa69c73d46b997844", + "af36a169ebb64d0cb1e387ae5925bd0a", + "eecaa5e279bd433c9fda24ed7e4faa7d", + "ab51eebd3c3d447d9e2968efd3085bce", + "fdd26e2f4be449c19d4d1c9f0c390cd3", + "259ba8af81484d19861fd5d70e9f5fcc", + "4900df561f094b6199d923c338cf7273", + "8a7fb24c8f444b6b8af17f31245ceee1", + "bc6f833fe3b440058b967375c25f28c1", + "42ee6bdde3e74c89946fbee74d72aaba", + "4b0e613fc16a4f67ab6bceb27c295456", + "f68d80456dae416fabab3856272627a2", + "b80a2a5fbb3f4372a0bead029428fb96", + "7223f972a1b44194abdc8f84b896086d", + "a08bef09584b490898b0d1c7ac2099cd", + "e8b022bed8d9416496512cd2f9d65a28", + "63ea7be8390a40938613da78ec736038", + "3001e42d65d3486ba56da3a36d6e5219", + "98e3113adb614bc68c8a493837a03327", + "946d829aa76645ea94027e156e03fb17", + "961f5362ffa241bc9523cd5609ac308f", + "dd8ffd134d3a412e90e90070d9eaf9cf", + "d5cac0e6355a49f3aa7cb502bacc73e5", + "855d54f1e67a4564aac7871b30ef687d", + "a128ff9bf7ef478991ab4ba8c95d38bb", + "892969a88e71495d9e869f96c95f0abf", + "6c6f657a31d64c3281067f5c5993af4d", + "37cccf4e5a2141d6a901b04d17074b7f", + "956a85340bcc4efc8d12cf2bfcca45c5", + "070ea6eae4bb40a99e799ed6d94698eb", + "c8cbf474d6dd466c887f01095b417a80", + "acd6397a7e584955970365de51ebe365", + "95ea6bab413b4b2bb76bfeb57dc6454f", + "9ea86a0b47f5437c95851a60ab7a7d0d", + "d290abd04b8445099b4c603aa4c6fd10", + "dc117aeb4902472a952989314aa75d60", + "936704d29d1b42f4af8cb558f4853c43", + "784ba6ee58f043aa955826776b95884d", + "d7c705d3773d4642bee7bfea7820dc87", + "b7c4c73d8310406e84e78bff89a5db98", + "a8813ea1e0ce47ab97a416637a7520d7", + "ba705749a39d4f5382b265c7b157e962", + "d19ab423e02546beb0c23719660fd1c7", + "493ccd4e2b6a443c87ba4264fe7cadfa", + "73c023c90f8d45fb88294bccade836c0", + "7ac304893c654d3daed685f795247711", + "3b63c5b6d6a94d3aa3eb026c869b9043", + "1fa6b89901ca4b7d9673f7d93f07def0", + "086645156ed248de98aeaef83da77ac8", + "71ddc9eb324e46efb10a7d3a040af6f6", + "f996b1c1902947caa506d56e565de77e", + "ae909c439e2c42d9a8cce8196513ec9d", + "408b7abe4449421caa9254b9c9745e3a", + "d025942952774f50808e0511dc918556", + "47c6bfb547c0468dbaef0cca60d3fca2", + "7590ca4ee92047fea87a5c287d3fe22c", + "765de21c345842e38468d321ebdb84cb", + "9305e4bfbb3f4224ab8fc091ffeadc80", + "19d1a8e4576e4f65877d6427a923fd41", + "9965f6b6789c43509e56db922141769f", + "3f94f913d04341cdb1e1c8dd6ed94fab", + "13fa659acc61471e8fa4f57637351c6c", + "77e34b5b67b64963a67f0d8d5e4eacae", + "79f559be72e14c248940ce5504162b5a", + "67c218710257493aa2e7f2e9d4e1e702", + "5bc9e49be13b4803aed3c25e87bb4486", + "8311e7e4233a429ab7e70c451d9c0367", + "674dc1556dac485585fb0d80c6b24727", + "7877d497ddcb45a5ba501b91e5e15700", + "1843ce30f1d34e4fa886b11449d7e6d4", + "c6ad2d2710b349ffa7b9057d1b611082", + "05308bf4da874a63b040399dca39489b", + "2e1a6b040bad4b1687d4305c2bbeec56", + "852ddc543f7c4d578bc893d6baa10cc7", + "0013bdaec08345ec9fd03214030baeb2", + "056d2c6e4c214506ac839faa644534c8", + "3fed29b606d74bb2828dca8d30f1b9a1", + "a639e9230a2c402fbb72136b43dd1427", + "ad0be0dd98384cbb9a3a2ba48f5028ed", + "fe1388bf67c94f1a91ce094b8a5cfc83", + "8af644c2f5654e6fba4aeec1e245e8bd", + "24a92fce6f284fc5adfe05d5e84de2f4", + "dd23c7d47a974ee0a10454f731d04335", + "216e6878000b404d9d905ce75f6cdb32", + "2f77a26ab3ec4cbb9e8f0b17f2af2786", + "0093866a726d45408c8935f9ba7c83ad", + "10f97ec1537c4f049c346fe1fccb9b8f", + "9ea5cc0bbdbf4f4b98753a9c71b2bfec", + "8b611680277044e1918e7880098f75e9", + "0b1f2c11b0ce4a85910c35860813213e", + "e971b701ee6f4d11aa22f70a46c54e52", + "bba822b058cb4bdea025510d2dbcb727", + "3c40aed20ab54b308a92b1ae2c628573", + "bfd65251ac594fb9910c44ca7a6f8c42", + "76b5e2b5f6e6420aaf70fae98089015b", + "2056be0ff83d439cb88a1712fac56f07", + "126dd75bb32a433ab38293de8a19353f", + "dcca5c46c2284767ae15971cc9ef29cb", + "78e47fd0e12c4401aede24e4f70853f7", + "a16f7c6675044342b3e07693f287fa6d", + "d10ab05314a043ff81602b59e0d479a2", + "e70d96d889ba41ad81465f2f4c4809b8", + "3aa68d6110d5470588c7c1435a0d4d7c", + "66f6d7fa610745ec94ef4b988ecc1724", + "b4ee64eab1824a9296525a91c5b5fd05", + "921c4d5289644c1aa25db6ed9f047c60", + "a951300ae5164cbda2567e22902642f6", + "36ef9c80cceb48909e11b358aee00223", + "d9c2a4e2a88e496289934f63e2968c40", + "b6d8a40632814a91bc9ce62bf8a5e100", + "75d7af9d205640da8ebdf789b93ab9d9", + "f080300151034ade99d1151dc8531eb1", + "948faf200deb48c0ac6f8225dfe1d31f", + "57346e17a9b84a2f91e5ecf27243d94b", + "edd00eb7b1574b80a4c9d9e218d441b1", + "fd72abc750e0469889b471aa1a67004c", + "f864488cb5d5482fb866844309f8195b", + "c3b6975ec55a46bfbe7bde74bd830cee", + "57929b16fed84be89ffabae491a3de13", + "b831f699de284f4b9b2a30485c2b8b75", + "b0600a51d13b4cb4bed00552f2b7da55", + "b6f0ab9d5e7f495d9f034a4d0cc1071a", + "5f6fe846894044dfb8d5fcfabcfb1ebc", + "d7efe01f8f51469c821407c9e248c519", + "9fa218a4484742e88930bbcb7fb444f9", + "e00f9be84145442987c3cb06fbb0481d", + "f26e7589e0124c9ab24ac8940d6cbbf7", + "f926b7290db44b77a66d5c72a35f8b4e", + "c2bb470c8b7c47ac844dc6731b9afcd0", + "48a4cf76e3dd41e6834bda88ad360677", + "4d293085dbea4d0686b304b88bffd6d3", + "68ba20aeb8fe4a03befaa2db5b429758", + "38fc38c0499e4e9da19155d1b52ac176", + "fa711666ac094d2c91d21018b8c9b421", + "a845be1db4c141be92ceadebfb5b38f0", + "389074a57b354deeab1afdf56853158e", + "9e3c7a51cd8248febdf8a12a9b5f2af6", + "8b6502af6db24c9699b5f2a2f8ef98fc", + "1dce00b5d2444462b019744035950112", + "ca023ce7e8184205af165034ac1bf19b", + "35388e3fadfa4fd2a453d36b3ce2af4b", + "0b0ee0e7f92c48e5bf8a18e162868d67", + "976b4218d01843e1bc0ac484712d63ad", + "aaf52e6af734473cbb9c2ec7429cbf7e", + "542376de78494412a2c1e0f0bf982817", + "46cc1ad784d54003b15812936065a2c8", + "2b63f788ce7944ae8f29aee20d98d7d2", + "ee52e314d71b4f05bf1b4d99ad8cfef3", + "3953c3f4bcce4e179b42e2b203788b74", + "c41cc6cf539840a79a9e86c904d75665", + "74253d45fe014ec4861c9b5e1beec99c", + "523aa445024b4768a40145fa79ef9eda", + "11972b0fc5034ce4a50636d2a02b18eb", + "dadf363c84314ce0a2598a4ae0f800e6", + "6bac7ea154b24666bb1268eea48dee39", + "50df941d234045bb801dc30f0c41c41c", + "a1fdfe261f69461aa5893dad4eb75e64", + "f08b85ca6bcf4ec0ad9a8610a7196563", + "e3f11957966b4a03a2aa5c8152c7f443", + "7b14d61a88114f86a079235a16816949", + "d16e69b830af41b19489ae7a51bf3671", + "ebf89ef157c54692a5e72d07986c618b", + "77ce9161326f4e4b8615bc0d14754837", + "51616225679147ff8fc1702e3687dc20", + "b3dca99f978149e6a902397cdb30867e", + "73bc5f5503de4782b8425fbbb8384f72", + "fb509f0edeae4f75ab4368a8133f4ccc", + "b1d620ff625b4a03aac49d17cbb1778b", + "5f7ee0b43aaa4e36bfaa7e25f5609f96", + "99bafe10363e47e892f0033161b898bd", + "a977729fff9d4bfdad487a59495436f5", + "ee5f0ce47dcc4cdc9126db3b28ae49e7", + "99ef536b8f174b9496516bed69368f46", + "ef6c07a0857740e5b725077bbdb03dc3", + "43906b2487d54d4bac8bf216cddf7387", + "4dd35f8f8c604aacb9500f78eef0fdfd", + "bcda2cf96cc6433ebd36c9eaed629588", + "b1e106d8dd8141bdac3297f57e61652c", + "b069fbeb341741779f5fad1abf56e322", + "93e8a67ef1e24d59b42185ffcb4ff7f5", + "eb9c96a5b212475fbbdd8467f8f73e4e", + "42e097aebea143b69beb9276ffd1cbc2", + "690bdd5d6bfd473889e9eaa6d8877dd0", + "695534e6f1de49a783ff1343449e3ba3", + "0e8acc8ad98f4d1794985e4579ce18eb", + "1051dd9a3b154006a944a47a9b510dcd", + "af666c21157e451388162df8ab90524f", + "8c0d285c1e6b4ba3b5ea777b563c4c80", + "decbcf17cf454551b930a4cdad09075c", + "25bb95639bee4e2aa5c4f7a7e7f36b38", + "b2596e7b857a4c89ba0d8754bc5a07be", + "af16623741714b90846a1a1f9e4fa19c", + "d915a22d1d9f43529f23604908acced2", + "24e1654fe9744a97928a1e03e375a305", + "fd3beca9386548d185d4151e51325434", + "2a7ccd62d0db4b138a0d56d579e2ca22", + "45233a0e41ac42198bea11b2090608b8", + "e53475f5c5ce4967aa956a9c7aaf86d2", + "df628669a400427d82498e4a1aa92710", + "ad3b24b0d191461dbc850059987c8262", + "43c333d026e14409863e3c5693c36fde", + "2aa7264393544dc98f7b2e74857e6952", + "28c56facb0a94453b6a6e86a29f938d8", + "409d1fb2508d46b18ed5689cbfbbba53", + "f1d196fecadd46889dffa94749595a89", + "9ea3da9f73c445a5b63130b0c1b90d4b", + "62392d7ff04e453fa2dfef12de8b8a41", + "896e7ff5903b465bb34e7ed4b918b3b1", + "6b7961249e1843639da30e88b7a6bc28", + "8618c0eeffc1497fb267854d1e25e717", + "9d3be49270b74c2797c3b6bbac4a3722", + "c8afaa20b08c4530bedcee8bed544f1f", + "ebfee94b75c64bf293061e68ba58d5b7", + "a0a35dc6e81944dab56b9b117fbf738d", + "e95846329ea04757b889426b8642a604", + "5be739157f1b4f2d8eeb352ddce4481c", + "b44dcb3d1893406bb24e8835bd21e8b2", + "78511525b5b34ae8ba0add4f38025c12", + "c3c837b5a5d24e7fbe0dee73dd6a099c", + "ceff5646761f497ca32e258e79f5338e", + "6dc27c2da9f8450fb278fbde8c468a98", + "f84c35be43aa423585da752baae0d6ec", + "22cadfd9aa6e46cc9c3a2131ea19ab9f", + "e835ce1275d74fa5aca5287004e875bc", + "fbd5a48f6b8c40888d4286d7fc56b681", + "7d8debbdf9494316a889c46ad2ec87c4", + "94d4fb18b7e54635b9fb97c862ff990e", + "2a0a78e6c910418e86b81bee9b3d12d5", + "075d61e6e604478f95dc710840b61930", + "19d70a642a934888a931d816601ec41b", + "94d10b9747dd4982a98e327b87609624", + "688ac508961b4bf8ab677ec4bf881b63", + "966de49fda4142678f9319c1c9ea69d5", + "2e2c556c4ca840a994a21a33c9fcd47c", + "6c3b7f42886f47f1a59725bfac3640f2", + "e1d2eda711e9492c8be09b22c21fb4c4", + "a1e98e91ea6549d9b07f4f0c69a179ef", + "fb1d8d60d3354b7d888741de33090f23", + "3e91980a22da4c0da975cc8ef776972c", + "84f0eabb482d46e1b39a3d559130a664", + "bfd76db93f3c48289fa6922455677602", + "1c33bff9e6614181adc5f2c2657afff1", + "9da061dbf64e4a5a8cc6f538a84a373e", + "6b8bad65c4a946e0898ec81af98f836d", + "251e0f75dbc8475aaf2faab9e72fe15e", + "baac63f9e9804eb89a34a29d9458f52e", + "1b763ca9aed0435083784b11317f6871", + "5286d4f69850479b99a1f5c8f908ab43", + "a2350ca84e6541a1a010e6dd2db0314e", + "9749ffdc1a4b4d38a6e60f48ffee4e3b", + "cb9d503f2a274d799cd2cf2c60c3fae5", + "c1a16e82042943a8893013c0ec35843b", + "1c5b01f4ebf14c4c968e3afd4061e001", + "02480fbc56b342bbb20264104a72f798", + "daf860020fdf4ed392f07933977ee89b", + "e4e29f337fab416ab4fe11aa1d656cc0", + "aa9e0ee2c9b64f79a2cf6c6bd53a1fd3", + "41fa8e131cdd42b1bf371a620e312f22", + "b57c3bbc442f481b9fc9e47c80f3ab9a", + "f59d7b83860b4ef7891ea4753e9d2a02", + "ee6c5b5255ca402d9cfd95ec6438c50d", + "08df70392658445192550202836a33fa", + "a10b2017cc9f4a08ba22b7346a8ba724", + "0d32aea8744d4611bc32e4b08c1fa80e", + "9b24c5e2eee24eb7a1d0386f22a26350", + "36c25d2118bf44488ad8d6faf7fce037", + "e568bc1734aa40f082536697642687eb", + "55c93bf5ce5a42df82b4da70e0f77c7b", + "103d99b1ca154045b058f552385a28e4", + "6bb3a786c47b419493b90dce2a74231f", + "044c565a818a48f4aaa65125d25f9990", + "ab02325e744d49aaad85c95f0c73786a", + "6aad34e9d1314a8c912aa43158aa039a", + "faa8c0eb078c4219b845143aa181cbec", + "2f9d407689c941d993f3d112a2af5595", + "3eccbe9ebc8247359040f38e778871ca", + "f4c2fcb0219743c2a717461882df7f7a", + "30a4d0f1c0754b8e970875be2e2e11d8", + "c4a0da1c328e42f688ef54daaba9cc6d", + "ce4e5766b3724944a83088b55b19b1ec", + "c3411b51ee934f80a3cad23d808b4435", + "31818220c7154260b680bb360062f64c", + "396d67176e4f4525a2a97a59a5f71ed8", + "bd5b64b58f1c495192ff6f8bef2971d9", + "f5da73b8050a4e7d9fce53b6171ccbc7", + "1f9eb125fafd48a98635b12454466880", + "6f7c7477e7ba4096904b7fdba5aa575f", + "be8eb8771d3440cda01a8da1b6ff1eb6", + "508a68f48cd640d1a0f036a7776d5ed8", + "e49dfb061d51494d9ac1952130c5de0b", + "3ed408980a9b4f9396a7f7c48ec50aa4", + "81e80a4e741f4995a4cb0f6d04f3e7ec", + "1116089f08a844248d87f3d51bdf1adf", + "cdae08c447df4f04bba136075570f021", + "866ae6c021b84a579ea0b5015a2c7b2d", + "e48809045dfc41a7b1df7dd3ac370189", + "05fa5d437eb24029ad00831a7abdeed0", + "f0ff385edd4f4a9ebac56d755c2f6634", + "74941cfdafaf4125bd14459a640a75eb", + "bc8c5ea7ae7b47e6a2d7760740ab560b", + "8e51b35078d7458091d2c2455034113f", + "ba3d9e3b939446718c40d0e169ba6bcd", + "a5923998c60547c7a7887f11f2f2088d", + "b0dccb6b4cd94b6ea22a3555dc11e4fe", + "912b855b12ed46719425f94743b32cbc", + "92d6c1e43d744566bde8a1f7e6742157", + "adc66cd19bd5410ebfe3e2b060d83df6", + "bc57dc01b8dd4eb290ebfac01eb92b9e", + "17178469a639453491ad907195cd443d", + "b0e77ddf29404251aef996406e3ea70e", + "10de91400b454d0fb04e23f699c95cf3", + "3ab87a00c4d34afbb92dd15b5b47f892", + "e38b00deacc446fd8960e46570c4544a", + "18d937e0bbc44b298e2593676f4f2eda", + "5907e9c9d6d84c6ca4df3057b302d95d", + "aed7e822412b49f4bd75a3d1e80143b2", + "e40ea1a71c9048d1a2f8db02de6d4ae5", + "b01d81c8f6d341c389b3f4dba84aa3f0", + "1da67f8cf6c8438b989dd5e62289a52a", + "3316c1f3fc4e4f95adf05b1ee5478813", + "4966e7579fa44ac78a9781a15321ff94", + "34e27f4b89504c53928b3cec8c1868a3", + "5e0710bda5984399a56aedcc7ab0174d", + "8126807d282947d496a7090bcef5dd55", + "9d1725fa4d494984b25974fbaaeef041", + "1eb6214373d64d63ab6770e486040176", + "b8d6c9706f0746628cdf184d268c0e56", + "2554c38364d0432dba69bf721fb14e5e", + "a3970f8ba0784ccd8beefd8abdab2068", + "d40aa57bd3134878b573ba48cfa37f2f", + "1d38a63959044c84856b0a13200e99eb", + "36a1a63993f041fab9644fd71e1994ed", + "16e4fab1858045f5aa94da96afc9b649", + "a6651bdf90454307a22fd697ae8bd107", + "8879720e7e2d475b818395f49f299845", + "5921cab512484fa780c34f418ddaa2d8", + "c981030f0d744ea793f093d676ce8ea5", + "95f6145ab9774d78bf1d05f72911b673", + "a324ba0bdf95402ba61f153852dc3312", + "d3391a5a5e9a4512babbdf148489fb88", + "678336fcee8643bfbb3eb3e49a800798", + "90158152f382484c876c56ccfba3a890", + "4153ae4c6416484aba088a66401ea583", + "d32f3f2eedf2476fba8c6b4dce14cbc5", + "e81c12b73b44472cbcc262069c03fc45", + "40c7a4f11dc64a29a7e42ca77a0a50d1", + "accd8ef3844e4c168f8d950b99a80482", + "de516e7330e1491fac4144e3d2f458f1", + "22536ec10cc2462db661e5279d83ab7e", + "9a07e1a9a4bb4d268926a8111bda8c26", + "63a1b16501c44c55b5afc3cf93600467", + "6d71a27af7a54b91816742c53b8b3de6", + "b44063d100b64d65b63c193d4cfdf40d", + "152b0c49e46f46589570faffe7bfadf9", + "0a50537f3b2d415cb4bc46aa84ca039a", + "0f4e615457324281bd0fb5700a944fcb", + "9aa42997e7f745e5b5158b07e690ca9c", + "c446a37205f04786928dcd123fd4b263", + "b2fc4bd184944704ad43d3a31817a676", + "089778f21c0345c09069707c2dae945d", + "850b9fc020954995bae9509ed312f317", + "431e1b4a85d14029a8a4157ec6fc83ae", + "02e71acb4e8f4b8ab159f81d0021b925", + "7d95660645834760a0a638775e5fe4a7", + "f5510c91f0ec4df5b2e5ac1a0422c68f", + "e3f411a7470a4ae4af6b6279bba85463", + "4cd15dfdd2b64b5695e940f4f4609087", + "7adcc8376d0c43ee87c40a3b70b9b1d5", + "3a9d89ec0d6642ee8a8fc42a1361c701", + "7f0b6d3f7315438a8fd98319111455e8", + "59b09646badc406b9eb64125f21da35b", + "c5b7ba13492f4fc39aeeb49a4f3ad298", + "3d3751c5040a4b44a2ec2f6edd1f9074", + "ed58c7cf06f54647ae9080d9f092b5a4", + "9f88fc155fea4eca858c8c2a459fc045", + "0f074fef547f433586d9ae6f970285ec", + "31bc449fa74f467b901fb8fbe0140113", + "e4f1c395626d49fa906b03cb5e31de18", + "5dc8b1763a4542a89558590b1e44ee0f", + "a3e3805be6364321b60159793feb2f66", + "9e6e5ed071214a0e9714a09051839f7a", + "e555427af39f4e82aa204bd224371b27", + "c7dfb82541f648acae740c019d04a408", + "31be7c8a61844c0796e96d6cf99e9776", + "4e8243af45ea441894b35d303edd4a34", + "e7c8889b3bc84c4088a0bd71ee49ecb5", + "5235126da6d74a5a81675cd2abf5d6a2", + "4d9107d7c30c42a3868dedd6e71c8005", + "f34d2fd6d2964251aad9c0993b369ff5", + "16f136f3d4b44154816d7ffcc2b8c8e2", + "2258ad546c434096aab2822b8cf4cf27", + "149a7ccdbf26454e81c704cfddc3bd53", + "0b85de1a9fbe45d393c9e812472759b5", + "721c9f0afa084b0d9a505ae4500a7f06", + "533a6c2a58b040de97a12da50a1d05b5", + "2ad357476ea14818a64e2876d33b7c0d", + "ca36f4ec23a041a096037366cef5f274", + "25ab8294e60146e58aba0ab11278b4ed", + "9dc6696eef71420aa4114d3afe95e644", + "1a41218e823c4cba801bd2b3d71c9dff", + "eb3da58fb8bd4408a7901823387d29da", + "0bdc57ff6f924a1fbb863ac0d4511fa4", + "d3d735e368624641904f4472d4e92bc6", + "0a3da81bfa904cafa446ab97e7a62cad", + "950242f8b6a043aa9794cdf09be90b17", + "ebcbcfc6b4e84cd0a85a110ad26e4b95", + "0b5d75b65a594f1d8eb70f5c5439bc34", + "e1ebf58bb90d4ea6b2a9643bfef9ecf8", + "f32ec9229a8749d1b79245813fbd6c31", + "b9aaa2a6f1b04f47a10ef0bd1ab71be0", + "7f95df5204854bda883d01ee136fbef9", + "b058f773d3da40a6b718d63cd4714b43", + "c2959e0c752443afb9b821d888501715", + "e04f3d2808c046d888d1de0e46b0a604", + "a3a2d6300e954690acb64f93462526dd", + "5bfb3a92bcd346e9878140733aaba4c2", + "ff2998a43d4748619e1285b8868af24a", + "38dd2481ebbe4ed6b9d494cd2d1cfe30", + "b32ac9d9663a4214ae9d444d21e9b03f", + "cafe7d385b49457fab07b3322d0693bf", + "2342f5af61484b3cb9b342ab5d2e30be", + "7edb2967f4d34269b316ae3e40d44dc1", + "e94b4b2bfa8d4f80be64fe9d71790ef3", + "b3eb949fc4184ee698a768db932643bb", + "a4b3213dc9034cefa99e35f19272f382", + "9bcb5cc753e4486ab98440c1a100e8ff", + "2880e5402eff46c5885cbed3d0a7128d", + "fa44ddeb72614002ba960b85f4237a2c", + "8084f30382034d3099b7b3de82fed120", + "f70d715f687f48a593b8780c18dc233a", + "07b6a06735db46dea37bc28b83c2d884", + "0dc6d0a2595847169e30454a80cf20c4", + "b7c56101ba964a05a56d4cfe907e2be0", + "d5e6b8be218e4441a44eaa1aa72c27fe", + "50b88a2361374aa3a8f8fec1447bb93b", + "74c3f4864b1e482c8e5dc9529cb8cd57", + "3fd154299f2b4ca68cd826195c7ade20", + "366b50081c884690bb2ce4df6dacad59", + "5bb862c4f5ae48e4894e37e8b3a7a874", + "742efa7beef24cbfb2ffe4bef1d2cbc1", + "f623380aab274a2884f2ddf1e99989f2", + "b6ac760f0e624c019becdfe986d01352", + "e9615e1cf2bc42f1888515ee52cb148e", + "626caadfc8e34042805f9eb230fd7246", + "571ed5e0bc574cba841b954f77e6b0a6", + "ebbd381ff003415b8ccf863ee49e6d78", + "9fa225175a80485f9cef7b8b85d3a961", + "745a7b4d7087433fa305754062996b75", + "176a54958a5a41c2955fde2a0b252a10", + "9ded3586451144869ef0845ed099f023", + "78fb8285be55432aa5874955576ccb41", + "b8ab1b856a554b47b9ef43b6c2e89b7e", + "4da56e7f67664c5e966320b4e15f6453", + "cfc58389cf1e4f3bb73a18fe94862835", + "cb6ddf30023c480fb0476fc96af00504", + "0d17fd8873914713a8ddc08791a00ad1", + "5a54ef7253274554aa70654388c8cca5", + "d5d543a334114795a7ac5276827b2708", + "f89c972e822f4cdcab48e8008bdb6f17", + "a0df91f135d447acb9b69b1deeefbdcf", + "305863cd3839482f8fdfc1b799ef5029", + "1a119b44eb854886a8b8bd5265d1b0cf", + "92eae2aed8a646c1bd757eeb08fd2f0e", + "b094e881ecd54027a4ba869351499f3f", + "9c37ee385901414f944951c8c5097d14", + "3cffef5a53b842428dbf50d95726011d", + "01146261d288473f84208b818579e3c5", + "1d0dc79c9c504079a1d9e33395f6d09f", + "12aecefa782c4e15b94920cab9f4243e", + "47ce3eac47524efc85363cca7513751a", + "e46df03ac6ae4495aa6ac6ab8815b42f", + "d419b5cc08ac4b1ea3304153944de78e", + "5ee9aa73c0344183ac2b14355b32e5ed", + "7cc86bf9d37c41948e7aca65901b0a93", + "a265ca9ff122441590eb653b2e248ea8", + "1980572e146045ac93f53ab83f89b7cd", + "29f78283c38d487aa8f34497d1233015", + "cd52e1b5299a40968f44c209899b4597", + "18c081f765854d249bb8dc580a1e9f7c", + "28bd5fe1fb4744918f493536b49a25bd", + "2916ee023b204aa99bfb8907a02ceb63", + "f270150329c44ddfa402faa206048b81", + "00ce4eefc9b0441f8a86be845e6ac51a", + "89ffb36f56ab4e279a6165f57204958c", + "147ebd486f04407d8a4d0825ffc2ebac", + "e4ce5f53b2e24323b77aae9cd32673a1", + "58351abc254d406583b120d2b2eeae37", + "a273497c03494d7bb962c7add0a7ddca", + "7d71c2727d3e49119cf4cd2126e531fd", + "949e95ae441e4c29a77770bb89bced88", + "0248669cbdc140ab90d55ad1d346fc96", + "141a33d4e78344cc8a62d5197ff18ca5", + "9650bca5d02244368983742ff2e44cea", + "7d49f8c85e6c40b9859dc378d270e7bd", + "f73eb160bf3f4689a9ecd504c3994f4c", + "fc796ca671ea48a98b0e51ba44801f1d", + "fcec3aefadd54be18d67574014c51ed9", + "b7c906b7e9ca4733b82c2924e766903a", + "f87cfb03224b4b32a979c982ad0583fe", + "138377b0ab2847f081e3a6a5210516e6", + "46d74a922b4f451eb0efbc3f44439b4d", + "0e787681f08841e2bab60f4f318ac784", + "b75046a6baf945a195fea09f189b4a8c", + "3d78e01d40cd4532932ad8180bf9137d", + "c77e4e900d8a4a488eba963a5d3741f1", + "54d77ed2b16e48848425a9f36b69bb8a", + "af5ace26f930451eb9469e1dd08c99b7", + "223acfd933fa480e96bc45e38dc1537b", + "6c7dc026af314d0f81c8a51242ed283e", + "6985cdf53d3e4fc2b886b9f2f0f8081c", + "365812aed83d401ea62b77d31df8c375", + "df0a7eb8cfdb4d779a1e920ad194c9fc", + "aec6709c445f48dd89fed14c0f1d45c9", + "2d71280c4d234f978dd0c1943e43ae1a", + "6fcd4ae9f82844219ec465b49d4b69e0", + "547816dd7c1c46078309b01b9576f978", + "e6ad1e6b980c4868a0325b8df32a0ce0", + "dfcd6f9d7aba46938912a0f68d0ce676", + "d6e71d9c8204485fa6965369561b8491", + "be3cbcb625c54902853c0d78ae3b95eb", + "caa27a9a97254f2281e932f5a79fabc1", + "97947476d0754ef8af1a7d8bffec6e00", + "0fdda2322d5c499d9b90debbba5eb78f", + "a788ff7615d54d10bd73eefc8360a82b", + "8ddd8d6309244f629b5ee3eed72d94a4", + "42493d4758bb4f128168ea9cc09f3266", + "46fd5c8f70444800b53ff91bee47ddfb", + "ba9c67b09b1240f6988abc0b61aeec87", + "5d171aad72ff430487528e0f796db348", + "76e4c9afe41149558c07945a8a60a548", + "1f41a813c65441b5ac500a4408ad2dd8", + "7180aeef2438452092195683b7ad9f43", + "a3c221e5504d40a8ba019f8f1bf5ab0e", + "9e896708ad99490da7dd962ecc047b06", + "77b75758cac54200bc9bffc8a74e240f", + "f9bfbf04f4804d988d6e3725f17ea72b", + "cabd5910411b497a9698931246faa95a", + "ca8dbc02573d4463835df01e43ff998a", + "a0a80e5afb33458fbc0aa0ca6d0636b1", + "c861646295044f7585824c827a524248", + "6c8815e2e7c4468ab7c8b6a90fe932ef", + "e58bf787309540e49140a33baf4322d1", + "5fdd33ab71a94d1382566dc330215c52", + "e6a38b9785b1457aa353aa2933211b16", + "53409613b45b42b98b979f12ab8faa12", + "b825856d20034abd8339c66f4249cbab", + "f87312427ff9465eb9381c131cd09320", + "7eddf98b49b147b18681d9b9bc149193", + "26c05b15487b4c9792cd4d8b87ee4875", + "48e834f645df4a4ba958a03e2eb23d5c", + "ef56fceaeccd4e068236eec7ad55ed39", + "7f460877380349f8886280a596253034", + "fbda6f75c10a408e8401de9c0a56ec62", + "67d79532394c433b9d2e5291c7d9da22", + "c0e15706b69842fe8b192138bb0f0025", + "65091d727c074ecb8170953dbcf2af8f", + "b8e0e3185e5a4bfdb53439c3eb686fad", + "732c23ce6f074e4e9eac662d523fc42f", + "7db2a3bad21b485c883dd306c443a53c", + "edbb7502a3f54d638f7b66aaf3716b80", + "f39a6e40a61447c69a708f7a3ac38a3d", + "e6ecefc487554fe3ae689095d425a6d0", + "2db87772b2b446a3af2ed0cc427b93aa", + "8c89d04317cb40a4a977ae3d10c7ce94", + "5cc6af098e754d94b49ca610def3f3d6", + "73a1eb92153a436e8332cb42bf0d4d9d", + "6741e7e2623e42a4a4e0238025860b90", + "7ae163ec140f48279722ed6daae51460", + "8c92184b5a1645c5b9fba8de332d28c6", + "29f60fa077de45df92f84711cebef978", + "cef2165d6688417c881c021304cef57d", + "99be78357eee48069420ee38af0eb5a7", + "146562854c044056abb08de66eb9426b", + "30e4695227c64c26a7eaaf48b7750cbe", + "827df69d85de408c9435f26af7ded672", + "17353b094e7c4072b6f6544294cd194d", + "75fa365595564d68bcd42e6141b68a78", + "c34615edc056446e95ef87fec6073611", + "d21a338b81b94ed99193a0be5a7adb65", + "264cb00bb0944ed887d7353a76624e2c", + "be11c0f4a7af41bb8ed8a107c5ec2ca6", + "671bd73be07843079eac01f73f9420a6", + "c411160aa1624631adbce3941a57e863", + "249fb621434f4541972be2fb10c7fa1e", + "33784f6c6e9a440f9b870838847d651e", + "ff70c9393f33426ebb32d8c90300a342", + "b14880e53023400cb4781f8dc06d078f", + "50c9a0c6d1a648a6896d3efdf07f0c4a", + "4fe570cea42240c89d85b3b86b2a048f", + "805083c159f14cd189a37ad28c87e545", + "965ea1540fbe474e86717cbd45cd36a2", + "43ecd0c1d8444582853c7ca23a492d1f", + "7f00fe4678b34fb2b1035dd4dac4a3df", + "49a6c4b2028e43899956ccb7aa10f420", + "ea09ce8bd3554d6ebbd61fec548bef7c", + "ceac388cb5ed406a9a728c48d6cda71f", + "256579b353de41b5a90d9d42cad6e8e8", + "a1932b57521c4aa1b0148d1e6ad6b7aa", + "8d44c667ea43418c85aaa4dede1d58ca", + "625e45f9aca946ee8307ae335509822e", + "83b56452e0b64845b6fcc094690240bb", + "73d7b6f9a0b7410b945205338b090566", + "85a2964910cc4bc6b58716d0187c3f16", + "c1fa7c935337414d822c1cbce8b7380a", + "4db405ba1fb7470cb2b9d43fd64a1d72", + "332a2be4bb204a9f8e5278949ab1cbcf", + "e81c8b8a78804af88c5119946c7cda60", + "f2afe44187c14ddb988676e418b0052f", + "f62f20a6ca0d42f785ed927652ee8e51", + "919f4e79b11d4feca575fdc9213109dd", + "45de993950c24e879eb641510e89e752", + "35d3cbd4113440d8aa246037ad6e6bbc", + "b9f12c4f8efd4137ba05de0fd4820116", + "476b23ffca3f43b2a8cad354a35072eb", + "5edadba1d396423fbd1ed1bdf5a32668", + "f54db6b8e26f427b9ba93ca993dc234a", + "728aee572a5c4d548ac59a232d659b2a", + "7458b901eb0f40a0ab4065b12140a1ff", + "993a1aeb956d41708b5aa30c993df276", + "cc5e3d70ebba4215890504ea311252ba", + "e00e77b6e88d48ebb01505d24acab9e7", + "88e4cb41e40d477eb8edfacce721cfc3", + "5d1544f61cc74047a2453d55791882ba", + "e80103292d164dd7b483ce4049640467", + "775adaba0f56457aab4564e9f6c01dbb", + "3ea782225cee46269006d9b85838ef54", + "1e387afc6d7443878c310756400dd467", + "9feda98dc9b6497db8332ff46d0b5c44", + "c83963eaf1bf4b38bf2e10c27e97898c", + "56a5d4f4da8f45f284098c8697f9719d", + "35fe3ed8b5b6462f856dd62b9caf382d", + "b46c145c453147d9bb298e3a36c06fde", + "66b977817f6a495f889cdb87e79335cf", + "d4ed2c23bb1140a0b5540ff3ac7fb504", + "79c250ae659e470095170269a5fd487b", + "3113acd4e90b4b8198749b99c704e72a", + "26063555c841414fbd1bab9e204d34c1", + "e219778f802f40a59f87ca92d2c5be80", + "9a131b2dfbb04b2aa5c06ba9667d6221", + "efdbc2fa6f6548aeaeaac7826f211e50", + "fa0c9dd491bf4662b4a8b5754f600324", + "dc639230642845bf8274b836cdecef93", + "de93559b3b75462ebfe9504931436abe", + "43de4d030ae94667bd8b8a478dd371ac", + "30e3bd1ea6544900a6e38d97da2748c1", + "4cabff429ac84eb0881fdebb4b202f68", + "d215bdb9b8204f899a78fb1dc4b30f72", + "6686fc601a484d32878db00a9b426ec6", + "da3f963385d84c258b85f70b44f3e16e", + "335ea4f5a368410c9c2646062aef3545", + "376453162e4342dba2c07b61f4abfd8e", + "bc0944e3a4fa4dac8f13172a71a11302", + "e38d5972b3ec46a9ae0468435b5a9f14", + "5de6f8a50e1c4718a3b5152dd0f80889", + "4ff91f3dd21d4e6ab2b7e6b79b979050", + "a0775f3f3ba54be3a6e72307ceb69c73", + "e72be75e9d5640e78ad27c24b31614f3", + "2f34c0d825e84b289880b21754b9ce36", + "a0299c58b4a34a88bba05b3489c28917", + "cdd3ab524f35418fadfa9b1975f10fac", + "e6b8448619ab4c2c9b1313a0457ab68f", + "f5bbabadb7b44645a7fe9e0e619d555e", + "97d5ad57fec54d94a2d8d182a7967f42", + "d4db11e69036480a9847bb62d80ab2ae", + "3f0a8c0b6b6e46ce99da4db863fc754f", + "03cc1e92bbdc4d448701ac8979a6a4f6", + "e59c60650c6a4e82a4fd8a92548ab9c5", + "8cb19c3ad9df426ebfa2053d9d8ac1f8", + "8c08d196fb814724a97c120d33cdf466", + "557864422708428992251ae358d39793", + "28d6719b829145af8fb54adaadbd7621", + "5d5b431c2e534d408976c713a6177ef8", + "4973ffc6f37a46a69eb8d545ae7f3117", + "e198f7e92cfc4802a3bdd1a10a9a44de", + "a1b271479687423da1ac060c4afd6d78", + "47c1da3925ee41a39befc061997d8291", + "50eb97832f134a1a801cfa78f2d28292", + "8fdca192becb47cbbf57386036327bad", + "5147de9b18c742c688715a2ab3ce7c39", + "469b34e0f2114280b2a58e399585dd50", + "14de6e84822c48d290482acdb295921c", + "0c24c5f32ee94906b4ce35dabaf05ad9", + "ddea9b66b7bd46949316a38ad677efa7", + "443d0adbd0c641ba8ed7b33e7f42e572", + "02eeda0b18d745819e4b990cf7b8000a", + "4c75613a5af84ee0af87512dedec47d9", + "8ba0d24f3a1d43ffa5410d45406dea57", + "a3257df530464f0fac388583081b177c", + "8b2618ae09ee429fa45bce42f0b2f3ec", + "f8a7f086e0d44883ae3b2210466a2dd1", + "f4160b557ee34182a33af737d2f9d397", + "238162014a0e48f99b1b278e237d812d", + "985466172dd34d4ca3a9b555a09ef1e2", + "db358e2fde414de997f69c0984f54adb", + "1d8cf327109040c6b9f9b848ccbfceeb", + "ccd0c91cdfcb4afc9140d99f7a69ec60", + "5b7c03fa21c74489a84c9d2d65a9d5e8", + "efb7ca4fe4ac4459951a8be9a4cf6b21", + "90e708b380ee428cad064afb880df01c", + "3ab147acc5604ed4b76943cf99504a55", + "a484b3ea93dc498e8a4d9e71d70d1fbf", + "e574e90cfb6d4e6d95df3083b40a7911", + "7215e3564a2549f1af0dd57797970358", + "c4f0adcc1dd840fa9f4bbd8a440d643a", + "aa82baf218104070a932dee9a1db61ce", + "e761496eb1a24b1e89b27bb22a3a8a84", + "4084ab4424d54411a3ecae635395c5fc", + "f0dc46563ca947cabe47f6d2ef6e8bdb", + "e153f445e2b24646b2e2d71832758ae5", + "05ab63c372f94b4686b20c8930ffd4c4", + "dc12313e97434133a6279a458d0650c5", + "0516d855f83e4337a5d5f526e19b94e6", + "4a8cfff678454a60af839590606c69cf", + "0295f923f1384c1089dddd697ce71f11", + "3cbbe9177ae24f1a8ca953ca7eb8bb86", + "eacb143364f8405395df78e229aa7f12", + "ba0414d87a774088bea1b2a5cbb6d26d", + "ec5d27a5618e47fc8f2b0c48bd26a690", + "e0fad92bca3c4e1f84ab88d297b352a4", + "0caf7d4def6949de83299a140022aead", + "4561e45110044d5f854f1301a8a1f0bf", + "40c7776c79d04366a7f9361ef8ab9558", + "dbb8dec952c0450ba58fb4f75abf86ec", + "a0e4a674f08a4faeb78e14cc36549c4a", + "09a9122a294648b0ab7f1a28115cb743", + "1003f6c9547e4db8986b24376286a4ea", + "81110f71e7d944c5a159bf354e977721", + "77c88a3524e6479488caca3edb3d62ba", + "103989411047470ab9f86341fd016539", + "a4d92dcd462b4c5aabc7a61392632314", + "9f94540e2e91456280b025a75af16f6a", + "9274e00392f9404b932d87235d2d0d08", + "ed9385b69b99461c8a081d4f69a08362", + "99a29194552445c99df5fc779b8e831f", + "936b56c42f1241e2a1bca01f4a388e11", + "4631b4c0b4294f96b7fd207895d0530d", + "0a494089e6954a05854a51e9cb473e4c", + "6895bc3ecb3540b3983f040a2b642110", + "4f62d41dd44b4a4fa4010a991f8e2220", + "b312c05ff88640f383c4133981f659c5", + "13c99a031fd84cf7aa756006e7e18a3b", + "b4d50597ef97453fbae92d276ba2de4a", + "a759034b3abd4d19b41d0fc1dff8d07d", + "55fc25d20bfb4ba58c2957da32be0b46", + "17f2e9139ea349faafbce7ad851301ec", + "3ba75a7ee4914c5e8276e06d00ff6b1c", + "921712309e2d441ea8332f471ade2fcd", + "973b13ce7ac24e749571c3af3327bbae", + "6f975907ae99438685ab65884ecc266f", + "8080339947b24801a80a8e0022fbc52d", + "53b079e0957a4ffb9f93d8a1bf5b6784", + "1fc9b210283c436bb754ca8b6376fc5e", + "c79680b6741c45ec9752a3c5eda4c127", + "1d3178230c5d466ca6c1e93b643f3a2a", + "3af84c6fd73f49a79fd04d3f62cbeea8", + "e395fa630c5741519792617b1b2db67c", + "f0b7373a0b4c426b992af7a83e4193ae", + "578fee32fb314e199e6804c4990cc892", + "3ee1bb1430474a029e3ea8dfd8b9666d", + "6280693aed984238addd6225120f4b11", + "83b2087f380d4365a459e68bc95ef986", + "475732573baf4476932cb6b145a904fe", + "990a9903baf8477d9585b229111374cd", + "ba597d172bc54cf7b2157883879c749c", + "808978edb69f44b8ad27623b359bdb4a", + "7930b40f0373448d948ee7c3bc333bf1", + "49f8c88f40654f60898fbc36343a52b9", + "80585a7dcf614cb2af0499553fe54ad3", + "67a2240611f642068a8896b2df3dfca8", + "f068f347aa404aa5a9795c17fab66346", + "992b05bfec7e4c4187aa1ac5f6446c68", + "b59197bb48314e539cfa834d3db37a22", + "ee806705a85f49458816effe5a65a4cb", + "d27528dbf5464aa8930b5524c2a0d989", + "feb6d77f702b4ee2b5204e07d37373b5", + "684df453535b4ec28c4d5b64dcd60f59", + "9f278795d00c400a84b4020cbb21df9d", + "21262813724e401b88333d381c4626f7", + "e32e0db5baca414baa50b7b4ca5f0999", + "2adb29a6a0804da9bb617b9b86fdf54a", + "cf408bb49d7948db8d3237d27a1b7c3d", + "c5cdc1c706564d3c9f34fca10813304b", + "507ddc56479241b68bac7b48a9b14a91", + "146b780acb0940069f58d7cc7e8684ca", + "8e10b3acb81843f39a22c4ddd38c5f26", + "6bc360dfd3a842c4ac7830f41e944fa5", + "be5cb11a9d55445e9eb5f33151ac57ab", + "9ce4577b75d44bb983ee75d07f25cd16", + "3692aa6a2c1b4b53991e6cdbef731351", + "c73f48027ae54a78885469c38e170fa2", + "27c495c9e968411f9855ef7a379fd65c", + "6aaa37a04732404cbef22d8965ef9b4a", + "73a349e6ed2446ecbbdeb83065519dc7", + "aa265dd3c99e4336a3e958cad567f856", + "139e5a5886e74fbe92e3b8804973d6f1", + "9920ae029f80406c99d413200dcdaa2c", + "6b9751c018b645428ec65af737a4b57b", + "8d7e365489944960b8924d2fefe392ad", + "2190db3fd04844f88543787a913e8b4b", + "ebed0a3af94242a6be6bf0f8ed6cd49d", + "b924ce155c374de198f199a2f75d6718", + "7a6e5a855c8544dc897e6c5cebd641a2", + "153466aaecf84be6807eb1ac0852be93", + "0f250edee2924a2bbf2411943763fe19", + "d193887f6151412f92f33ac3ef91f783", + "f603a716bba84a1786f6a5d1d3ea60ec", + "856603cd84264151b2e28c8f6a716464", + "6815a7e99dd54e91a1b2a248bfb672b7", + "59c526267b164f828082d4cd39c10bb6", + "7d04fd3100df486cbac3e1ec69ea2f92", + "513597aaf0bd439dbccece499d97ef90", + "6acaac9c73214edeb4145bb3d4d75906", + "ecd84640bef44237b1794d01b0f6d78e", + "d35d4c4065494d1687d06aa7353f6d79", + "149d47c6c27648a6af26d6c912c03826", + "8497de30e5564a0a94b03e62c3c4ae6c", + "404abcc8b80349e0b6971b73ed360fd7", + "7507b9c798744c29aef2fe09fef97ab6", + "e2b2c437da8b40dfb32881352144bcc8", + "389d5427a1f344c4aa4883ec5a6aaf05", + "1e32e931ffc34fd5a4e839cb6131347c", + "70cf8d97d8b54ff8971bee59ec23505b", + "5ac641426d3b4ee8854201f2f6a77a72", + "44a79d5b8dc649189179d3744768c0b8", + "9f33e75c53614271a788e3a5e086cb2b", + "cc2b9e63ef284a9cac2e3091b52a20fa", + "8de2390c67b84532bd2b25318f656b99", + "19673a7291344ca59b85711070996c64", + "c1e33c689040412ab32c4922f02b522f", + "a1b5d5c02c184429aded90b0c931762e", + "7c16a2039b954637b4a7764f1b9f64b5", + "af4b086db64f42ce8749bbd989838df4", + "a47c2640adc540fabf6e6708c524bb77", + "800b21fff792444597b2424ae19f3452", + "a8d0ec0764634b168c0ba8957e6bd2a7", + "1139b853280b4dc1b3691396c7b9ad3c", + "ec225182826d47469694e880d1b97ee2", + "1c1d54e9958347ca839fa55bbc393a76", + "8221c7b5c69b4eaab276156e8f9c5c6c", + "0bf4013527064475b4c7c41203e3b759", + "950ce6642cc64475a0a3c1df3a5fb13c", + "f9ac5185507b4d0dbc744941e9055b96", + "5e0b0e29d0b64f398ea35b2a51e4c5b4", + "091401b7fa834b4fa360f90f34058016", + "a3994e8b236d441c9775b2669046bd29", + "3e3df3928bf14cfd8d47633e088ee17e", + "fe40ed1bb88d47209e7577b06033a763", + "33fb4b71dbb4421a86427d56d892587a", + "82f8a9d5cff74aa2807f497ee1b1e961", + "ba9407ad7d9c4f39b27b52a5972522f0", + "2b4b29e6c0e6435eb50de15823d97276", + "1e4595c2b8804491b7c58a042609bc97", + "9fcbf84a8d024ed5b088457376bb53ab", + "2b9647630abf468a8b69a91c1fd5a315", + "ed556ff299ab42749bbd4cc1f23aa482", + "d616dcf7ed704b7c9ff10c3f36cd1a2f", + "cf5278291d3b465c9481bac7759756eb", + "207d1a882f0d406c92ee5d4dc522b7c8", + "b8cade7891284711948a72613ff5a97a", + "373b8890e4e54c20b1affa089ce91026", + "68d4c6fa8d6746feb168cab25dddf4ac", + "0af38fa8948a4df0ba7a7939c31eb204", + "9811f127a39b480790d1beaef7af9fa7", + "91dbc20279574ddea78cbab278bdfb90", + "342190210bca4a18979c799e6048ba12", + "3f45605e4d99475c954730cfb4c2a0a3", + "b2a8b38e26bd4040802f4172a5cf6781", + "cb1b6006dbb64f5ba321abf27e0f97f9", + "48a469fdd4464fd2b1ba86206f7ba2d2", + "85dc946bedad46db96eba9212c930c46", + "b166e9a1c5d540c19a1075b7f064f42f", + "a453b2a175ee405593b7fc29784ebaf0", + "f9b6931a200147f99779034142c12199", + "80cc44761a294682bd998b5b17287c8c", + "1f30341c5c414bdabb6b8de9432e3a5a", + "f53f358e46ae4768a97a3ee772dcc314", + "9520ac8ad3e1424f85cbed8af58fe722", + "ff7fe95e57564cedb3f61bfcbd7e683c", + "9f2a68c678d24de6ad187b04b2f92b7b", + "7e799ebadd6a42fb9be301df7da69ace", + "123096fa63924cd9b7535816dc3f7ff3", + "665ce053043047c48ada64329ec4bc11", + "992750b0df674378989fa915b0688ce1", + "c131a12840214149b296b84a9f39ab1d", + "cd018f99b2a045bfb9bde33c191ef1b7", + "08e14b4618c444a2a4ad6414e73ebcc3", + "48197b174e734dbebaf04e6ea0ea24f3", + "122abbcbd0fc49d2a0b157dd63730da0", + "f50b3382d67a479f8654611cc748f20e", + "b5337ed2243e4ef0a0d669efd4c02891", + "2996697866e34d4d83740102d982490a", + "36e3ea657d3642adb7c1a05ecf6d4d62", + "8a6e4f02523d41bea9d126085f3eaf92", + "8ebcc1bbdf2741cfb4eb2e3460525202", + "e094b3a705f94e91b7c869fa200a51a0", + "44895b008b8a4546920d385b10f47c16", + "e278943cc81449ffbffed19e5fb289a3", + "c46af6c317c04f8b9b05800debca29a8", + "d9d7989ac61848a09eeb60708dc0d941", + "fb4b4fe24a354eea8cdbc82da78f5cb7", + "4754f1bc1d6341d19b313ad6a51417de", + "830110b3d34246d995aec0b6f5f16910", + "b4c523b0b00849aba5395d6f28bfb0ce", + "4dd6d2a49310481ba0717a71ef76f100", + "3326222ad30846438660f7aefee9cffb", + "85afbcacafbe42b893f1d5aed06eb379", + "03f4c08b0b2040339a8423aa77ad1cfa", + "0c32b5e717bd4a76a0420120f919e003", + "e7aae3c8264143958016d1a88d5af668", + "57e3a3a19833452ab253996b88d4e266", + "0c2cdc35530d4b9e8eb8cc4373f369c7", + "f598dfee0d22404983dc9d9c3f307202", + "1939d6d2524147ee9858ce0f96ed096e", + "b79fe6f0eadf4b5a9118baf2fa46415d", + "d274f36005274b33ba92900a403dc81d", + "2cda50e73f69438598eabf8259e27cb7", + "307a4f5a12fc4f799468bb6139a1be09", + "53f905d5add644e9b9c7dfdc189e9a9b", + "f3ec7049c1414c58b90aa3e45e9c755d", + "2cc9988bfb09440f9b4bc4931f531971", + "758f9c854fde422d8efa3b7f99858660", + "34179f58570045feab328b17d0173a4e", + "073eef14ae3c4d06808498c3ba895e67", + "a3d687b243014a2eaba4bb4091e9001d", + "cd59a3e9fcea4e3cbb6918c1268a94e3", + "d7acd639133f49fda925bdbfc38a040b", + "3c656da9acc14dff85350d6ef125e367", + "0e06763d63f44733b99c06ae18dcb13d", + "bb742ffd1630498c909caa4b58d8de4b", + "a4d90a06d2984b57952cc0fab6d78c9b", + "e9d4fdb2b5344aa5a4b37566e535e991", + "2f2aaa1420ac435ba7c2b9bcd658beb8", + "3445c3528fb041aa9bb415ba1ac7ee15", + "03592149579946dfa921c23c05304737", + "1e5919f8a1ef4618b4dea274e028f857", + "b24f1980dea749f59eb8ace6946393ad", + "caa7105de6534f05948c248f6876b194", + "5ff64a70fcf64d1a8fc0278ac6bfeaaf", + "88fc39bb6b094ecb99eb2bc4e51576a0", + "382d0f26576749b2b497e84fdcb7c242", + "3049fcce9cfd4bf4a164398966b3fd7d", + "ab346aeda5ab4c7882999f491d974619", + "2f762373b046451e8924a08b5618cc95", + "2723964fe02d47ed818373fc311a09f4", + "e0447a01302047c2a18f88096ff63abe", + "5ef792aa16ad42bab3f28b72026e675f", + "11656915f8fc4d4c8b5e3fb50ca5cae7", + "f61affe06e6b48cb8ba40f60139fa0d1", + "e5493f66561b4b7f8a81599135c12455", + "90853681645c494092323583f1225a56", + "4f39b8be8c6141849d324b72f5d8ab1a", + "a67015b5b2bb48cfa15eed7b20e7f195", + "988e8aa36f6b47beb4fa85b5076cf172", + "7c98e97b66c44a1b8c5020ec4c22db3c", + "41a66f9f225a4bc384c00920bc5e32f2", + "788fdf94750548b5914bbaf0b48581e5", + "7c8b2bee6d7943329b78acf84b991a78", + "9a3484de337a4028b2d49140e9f1fdfb", + "93069fa0e5184ca0b649f5135d805a90", + "3c6de8d50fbd45909cf2efeb6d636113", + "42a1a31ea80a402e8d5a7a1a4320b8af", + "a5f57d3736584c44b221a181d558dc39", + "c2a6265a7dfd49df84847b4b1e7887e8", + "2a81186134c549ae8c1009d12fb3edef", + "90009fa6fa0b4d4bb1a1203431954097", + "dc0f70cd60ca4c428432e873c36fd062", + "56414f33231949beaf58e05095e1acbe", + "605ea5ffc77845cd8b5ffd32b6ef9e77", + "59b402ebeb7c45fcb5f80fd631ddc106", + "a3e9ab84264d4e368e6635dc7f6e5312", + "f442c20ca7dd4a988a17a12604556672", + "c4e26bd993ab4d8ab17d1fdbe9431367", + "19711ae60bce4ffb9315074fa7ecc94e", + "59efbb7b8119410788acf447ff658180", + "5fd164d6426a409ab3f4130c49e2d418", + "ffc2cc4575464dd5a9d8b813bd227023", + "f1f57078e79e49289e14f0a551b5b60e", + "c639e763b0f346769414c7c05bc38c60", + "966a2965978c423eafc4b6efdee8fa0e", + "1b2a17ac46a649eaa72d624747c8fd97", + "95efd27a7f4e46edaf7e599ebfc8fa10", + "df20a205f05a4878a24ffd72d745bde6", + "5bec36e4ffb1434e8136088a6314bb6c", + "cf64d04d3c4e4fa18e0eed26af665aec", + "44612bb17e7d43e4adfbe57b7649027e", + "c1062acbad784aa5bcc42836c305585a", + "473b432ef7354d94b489de208749e711", + "660641108abb49e3af3ef4addadfbbf9", + "c384f15c43ca48c29ba8de8b13229759", + "fe63d70a5f5145788cb9b1e3c47ac3c2", + "90f5205c3bb5417a95069f89257dddb4", + "c80e0e2312bf420883b82f8c121ca812", + "b302d2bbcc3d46ba80f6ab808fe95b5a", + "fa6edd547e8f4d6291364fb549688f2b", + "27114c32e8364a65893c9746fc1aa48a", + "a63b41bf6b364c9f9177c9b1e3da049d", + "4af6d90d49ea4ebf9aa5f3926ee607a1", + "e5d4d39aeff94542951815e7556546a4", + "512158da5f394bc79a844acf8fa972ab", + "40294ffab14b4802bc1c0845d30d6384", + "de15e5fbc38a4ea8a367e3c4b49b9080", + "37070a6b1e8845b0a67c813b5ed445c8", + "3efb9e42f49f47c6bd1d36f86281888b", + "06f92d4d488d4a048360eb19667e231a", + "933ad3c84ae74eef86761774c3536a4d", + "9a3c5536f58944f8a64d0e7d9b64e205", + "01c803e133eb4de6a99feb24bd490fe4", + "3833b8e5c9cc4edea62ed5bef473f8d6", + "02a4ed8629b64261883419e7b5d8041a", + "9c6f21280bb84ca7897eeaa9974cdc3a", + "deac96d06f3547078c72ce423df5044b", + "ca4bca236e72483ca07ccd79bac59eea", + "e0bc8c1d5c8f4be0af37ea852d42d6d9", + "cf7304e277a5465a821d1091a67010cf", + "e9750e88f79f4e8da9497e6cb3dc053c", + "db066d9c0c4e4bf98e6fdd8f94ad4a6e", + "3eea6c64f2bd4376b5737bb09a3ac852", + "3accfe0e63534040a6e69d25870caa7f", + "e65a4ce9a71d47ce911d281a66a534d9", + "d8ee907bc99045d09772162cfbb263f7", + "bea5524a0768437da94e2ed71adb2d50", + "5291772a7a114a3384c5fc9248b9c251", + "e653f678018c4b5c924d9d725dde0597", + "2d166d5b55a549e585acc13f35a57545", + "144ad4d46a284511986c60796966f201", + "ddfe9c089d6d425f8a83959443bbe062", + "773cdcd8e85d4b9cb7fbdd16d50621cf", + "ed56f46d99b64d29ad7078196726625b", + "ad25654fd52a4e6ea2196cbf84a164e0", + "f05b0c2f9bcf41cea188a4b4c848068a", + "e28162d6ccf44da089b9397612fe1066", + "20b641ec3fe0452e8dc6535c77a51fd3", + "88b3a65ae4294b3892d5751a1587db8b", + "22398cff046149a29651be0fc3cf39ea", + "3bf4b9d4bc2d4e74bec8d9ee5721457c", + "62658b70d76b4f499767326e98853e50", + "a14878d4c90d4e23bcb4445da825d09c", + "3843bb01c619455cb78d720898661216", + "e6899c0b45524f64945f874e2a449961", + "397ad6222cf64bf3b6ff5eee4a1f002c", + "f43f4f4f9070467bb127e45fed7ca2fc", + "89141c624e5d49a0b567d405781e8e72", + "9e68a576b56b4cfd85d07660e5df752a", + "7d4b5f0a0be1406cb80e53f31f217fbe", + "f5ccda1a705a4f68a360060bb69219c2", + "89f5bca8380d442687ccc0c1e970d75d", + "1d0b59fc8f0446239a95efdf391ca084", + "b94b684ce44a42aead014d4df47b55f3", + "61a8d41d5f6e41698d560520a8bdad9c", + "2068dc4e737a4bc49d058ba4c156f48f", + "e109b84f42e74e03a42680e47bdc2e8a", + "2b814e91374444c5bcc2dd4bc002ec69", + "60a127f246604fbeaab143d34049d537", + "04b1c0999a4842118c82914ab37f07d4", + "f7bdc4a7e80f44779c1893edae6a47a0", + "3f04daa9365a449fae5e800b7c2f9374", + "63cf2d038a37433f97789a2b5ada8621", + "cd1942f6cc5c4239bd12e028592d1bef", + "7f3849dfdbc44d4b9a055ceddec22219", + "6b74cc88f5ce45488fba3a98a3fa41a8", + "044f3af671454a619aeb2126fcbfede3", + "f9161854300f4d8cbf452afa1e9b371c", + "5b8c729912bc4643a8c8c8c4aa5fb8ea", + "5f3e10bcd4a540779881e012789c155d", + "55f695dca3f444f29e07314634fa1b85", + "bebb9f4cd0554f139556ef5700f99d00", + "34e312f0084545da8932cec3a1116431", + "564091a1148040be9f31e8d3e0706fe9", + "7b5afffa5dac42adb4a5044c99d43bbc", + "bd4c17d17c394c688cea2294bafc7594", + "524d2fd1aec848eeb000e8a5177f0db2", + "24db25ee17234dab8cef37989a214da1", + "1263c4dacc1b46a0822eb5da85e6c38b", + "566323fb276f4fa7ac2943b38bb4e98d", + "1a64d62a328b400b836dd029ddf4f3bd", + "490659ad59034d189124eef93ef83b4b", + "e102e46a26154f5f9e77bfc07ce02f12", + "ca85ed451d4549a2a3885831a27a2315", + "6b6c12070b5a47d4a29b420918fa5626", + "fdc3b8cfc7df4fe9b1ecd1ae1198270b", + "fa6e0f0571a04db1a10eba21ba4932d8", + "5b6a33958ffa492a8dd96c12322156f9", + "96ebf942e78b474ea1018376b5ee5fc3", + "d5a4054644534737aa6eaa40ef693c8b", + "fc5b21a9b16b4fa6a6803bc5b967e0be", + "cb15efe40a2244848c7426ea3219a47c", + "edca5a087ec143b9bfe4fbcea5ffa1fb", + "0307be96ba5748df9bc359acd68eed3d", + "eb870106a5894238ad01ea6805f5905f", + "ec80c013535a47e199db8b429b012e32", + "79bd4261d45b4577a822dcffc0897fc5", + "6a3afb2d4dd14e7382a5419418003abb", + "f15cfe5cedc34408a84f41c42550580e", + "25726a8d0d514c90bf83f30c2b985ee2", + "229c3e79701b4485b33bc93e2fa6156f", + "fa31f0a004ad419b85f431e462543d3c", + "85522191fd9841a6849a0ef2e9670d8b", + "c6c1972b1f454f73995eef43de2e5540", + "5cd01ea6167e4b7d9d97e62ff529bbbd", + "2a48c1d30ebb47fab89fc9868ee1d263", + "c1d1cb3a3e874b6796dff574e73c849a", + "5084519b07f04a9b958f61d8b7c2626a", + "f8a2cdc9970846da95585a428697d173", + "2037cb336566458786ae3fc5c91d8ca6", + "be6e8ec3d90941a8b33ee40701224768", + "c9b9c316434547c892e7ac7bde27a74b", + "78dd6c8318ee43ff8d33687267707a54", + "9a9a351cd3e047d3b86bdcca20e61e06", + "b5072b1616f040e197ca0b042e7f7a0a", + "47994470b8704b309dee48467a58a2fe", + "d44124e0b2b9435cada8949d4f445b3a", + "f3dfd9bcc4454b8082dac726d8b0fce1", + "10c8653be7944df78d1ff77394e62d9b", + "733f971061ba4b688ad098e44cf64a6c", + "6da2e7e8066f483c89f9c98a2b5cb371", + "14670585f48a48738134523d6a5b17e6", + "b281514344f14915913da72ca8b4d89f", + "660cff67e8fb4bdda64e2d3e0c0641a4", + "182c78a7176b4b52ae1e90858de0cccc", + "fc0b7c47dbdc4641abb4c2f5a399d793", + "0b5a8b81aee24e9fb556cfae5f00cc92", + "347a5f42b24648efb7606a661ac71a3f", + "ce0ac25e256a408c9c2d005789db4de3", + "cd6f9016db8644129af1b6026f9e46bd", + "bdb4d3ed9af541b9901b722913d79604", + "8e23ab2bf1af47438399316fd66aa0f3", + "5152d57b8e384e1d9497a5fdaa28e6dc", + "d41aaef0caaa4d44b42bb8bb130b36cb", + "6db9df35976346c9b53f5290bff15778", + "43ffd9117b9b41199f90f009fc17f351", + "4c09371b69f841acb79b240b2cefaae4", + "a1ec1e0d08d1441dae73ecb170056df9", + "2020a7a4caeb4cbd836d92da1c6b7de6", + "9e19bc36beef4093a067f6cc1f1aced8", + "85716cca8e644c3a9b7c7772923f5b5f", + "4b336c8b8cdd4f6b9ecf5b6aa724482f", + "d1e36d9d7cd74e0389bab5a8e5aa6402", + "876e268cbe6846c4b4d9ce8370c21f6f", + "0638011881db4a2e95235b63e70cf416", + "12af6318ee9d4d848bea7fa0750c714d", + "9306e08555d947c7bacd20b78b765fac", + "1a970e6456844320b3247779f68d5f2a", + "c94f3f61ad484e5f86a4628797cfea52", + "1ffe56b55bc74f5ebea41814f51b0831", + "f520912e94a24024913154a9eb62e6ea", + "b59052f4855743009fb4ddc870d98750", + "b3f6e9bf6afd410491017364994c7767", + "f7a0bf72401a4497b2e5399b87f7dc0c", + "5fd121e337164b41a1aa23b34dfa2e12", + "4aeffdbd8afd4a38ac35e4927e2bce4b", + "3ff006d296224ad1b8a85ea3bcfc0870", + "e99c2e4c5de64ac99b20755c7da2572d", + "d04047147375415bb4b5ab32832a8d23", + "8481ac383f5348529d366c99cf86ab8e", + "1a5db996f6fd487b9390fa23ea3121fb", + "267c18e54ca248098422de08347ca49e", + "02f0bcfb739e4a0fbb3d8e84db04c920", + "eb0b5f7b64fb45188a04e050537d3195", + "3b0059d9c6534289af845fb36b942cdd", + "8084e9dae0614831bb9724c61e94741a", + "45ace760c9694388af5c1f211b64ee78", + "ce678a4b9e8f4b96a2f7dd39fd79bf33", + "eaf4a00ea3e54fe4a31806cbb7f91261", + "5ed5fc8dac5e43639d881a21065bbe7b", + "02d84a6901584cf9ab42cd07c1514731", + "7d8266ae0e764478a03c2477dde6629f", + "b031f65dd5cb475fb00fb5d9ec229b87", + "b809e5698e3444a3b62bb58654caac75", + "60279aff8aae432a9933b9fb6374c2f1", + "7d31a8d461ce451cadf0fc81d7a0aeae", + "a3cf6b9b70a042fa85474c5a5f025e6e", + "0bfd91e18c5546d59021e574170c2bef", + "685946b38fc54fab93f1454c7709d49f", + "c8d30b44f1e042e283ea3eb47f7e288c", + "3d7912f4613a47d881df590357c58a94", + "9fadf8cf832a490eb7c6910b0da2ba8e", + "4bbfe00d36d647608e12081fc47879b8", + "fa7f3bb3be7d4b19bbb49fd90f547d43", + "b95e29b0b4dc4fdfba81d740b6d5baf2", + "3f80e4aa0bb04d739413b1d322e1de9c", + "f7e0d50afedc47f4b21348088c6c0572", + "ebdfe855299343beae2e5129c8788c8e", + "d96e52a67c42478186139b19374d503f", + "d57dbaa95aff4c74ac12d5bcf9b29cf8", + "bf7a538e572d4fb3834801eb3c86f8df", + "3665a2b8c42b4d8fb4512a62d80893a8", + "decdce0779694898b8706c7cd6602ca1", + "376690ee19d24138bb6de11d197141a6", + "c645474193ba436fba3154521629692d", + "5cdf4f469f034c58919d662d28ef16ab", + "a7d105477772404daf5bad8011b6f1a8", + "25f6e6a9b791458da09e75dc60e47a6f", + "280c07a63da04facbb08e45308bfe4a4", + "894c12a93c3f454a870e68868e6d99b4", + "2acda3ed2f9046129897f0f1e36092bd", + "fa671dfbc7b6409ea6e8499fb89a2f03", + "82978d2bf11845f49c0d4dfebd78b7b7", + "81c328132a674a4a940749f9a80d3b5a", + "596ed6a565d145af857952064bcce708", + "a30779e1c97248fda9cda16a613bd90b", + "ecdfbad0f8fd4cec967a09f19f1556c1", + "9f960d99358a4b249cc8a6adf86e2ef2", + "7a1e3e626c9f4ef9bad7e9ba0bb2d12b", + "7f4a2e4d5d434450a67770f03496e083", + "99c1c97462054b40876827a422675ca3", + "1131e48f0fe145a9bf4d5766ccea6344", + "575cf94b8da4484195dbe45303d1ab03", + "8aa00644caed4e57837b2deb98ecca0c", + "06ea30fe0e394fcab3b1793439c473ac", + "2a8d375f2aef42259c6b6814a3ab72a6", + "76f07b7380d947a2abad4f64c75bda7e", + "e096a8e12daf44768cdadd7aae36be49", + "9415f57b6ed042ed81cecff7a981a0e0", + "4d7f3c58a09c4a899e68ad837edd2b6b", + "6585a241d8bb43b69c840329a27b8a41", + "6cd6bc33c80544f7b843801050d14a6c", + "ec30843c5a89489992b9f24cca9313e2", + "8b0d64278d504c508d02d33e22ea7f12", + "f1c67907a3d847f6a9d8a578314fc8cf", + "4d4225912d0c4564bc70f2225abb73ff", + "eaa92d38774a420a850ad60eb5921055", + "41c445ce5f894d32928a0e4b7a7c67f6", + "f20dcef78ec54d3ea8ec18be582273a9", + "acafbc9831894ab0a291f1c6e05584b2", + "ae44a25727c34933917457f1a677dc9b", + "54562cfac54049538e9cfc6a5a56c3bd", + "bdec6d6cbf2e4284928ba93effa75e24", + "044fd1407ba2472fbec638479142ac22", + "20c65e01d9ee4e06a438d9523160d883", + "d1f4aa651d9d4953a5a2742914b84635", + "104bead7c04345bc93019490d075ea6f", + "c13528cb6aa4497eaad832124ef2986b", + "919a347dfcff40fdbe0eaf29b3210f1b", + "0e2d79b42d9b4147aa4414ddd1cd61f6", + "91492741c1fe4b5b80c89d8202664cd5", + "625c012402074e91a1a534b771920a17", + "440a31aacb614048a98646609a73b914", + "fa74a39529f5462e978b4f5dbc0b8add", + "cf72ebddc2dc4beca49280e55f90a6c4", + "3ff33f5baae24b9eab100442fce797e7", + "f1c1134ffdc241bebbd6ee4a889600e3", + "7941f0aac98143e09f85119638b41b12", + "a38384a0fc40460e9cc75f0762b8cc52", + "1fd7def3b2a540a0b7a00bcc92261018", + "232362224c8f4d12bc0196e68e3f7bf3", + "438269450f57484596d1a7c8529d4505", + "67e70e183487464cbeacbdf25c34ba46", + "cea63d418b41484399df819a0bf5e281", + "ecc03f0875e34a0cb2e66c40b22383e5", + "ada7c35a1a5742f1b4c528eb3daee35b", + "80c272f29b0f43189316ede9cb3f148d", + "92f751dab03e4a2792348a21b3673ec1", + "26566d44a33f4b5eb42aeebaa37445fc", + "9afbfb47db7f4ccf8696c5587f01af7c", + "a5a169466fe64f6f97ac58dcadfd8622", + "79990b80306c4e13be88319991e0e220", + "3a9f9c38e50842c6a7695f5f8e8119b4", + "0b63793c9cc44cd589938f940f9a0df6", + "5fe2984318204445b000aed810f523ad", + "c877e570455a43769758d151610534ff", + "58ea4c1ceac84e19aa9c2863a034af1f", + "5b29a7c3fe6e43d7bc2924a2f87330d9", + "3330182002e8463ca1d50e6927ddac32", + "ab25dae4b11943a8a2ad2287a0c4da3e", + "413da5acd4214fcc9c4752a048c1fe56", + "6430cc007e17456e97f1940e1641cedc", + "208b7dcbe4cb4b4b92c3b460424fa30b", + "3bfc45bc729c434aaf7c782ac12d66ca", + "fbba5e57707f4e06ad6ff0202dc18685", + "021fc6dda14f4801a8772a9a3380caba", + "7faadfc055994d4198d0a4d1ce18db04", + "c046891f4a3e49ebb7885b685cb400a2", + "9f2410626927488295cf269af13cfbfa", + "929d718bc14f4959b7b4629e3a98aba5", + "fe3b5a37bcc042bd9ba4e3ec67d52ef5", + "4ecc9c627863497a9cd94e39ebe30a17", + "65fe1034b180420bbf2eb00e87092ad5", + "414c5775e9f444b4b280fff70b9465d6", + "89d6353a72ea463ea4e45ad4e160bf88", + "ebd6f15553cb4351b532925907262a8b", + "e05a357ca0a94e4db68e5bbd0758788b", + "0c5f661a51b6459992c94438f7dc4590", + "b2e3d6ecef4e40d994066416c395bf0a", + "cf56e0dfc9e049c8a94f57aa0baa356d", + "4a185716211446a3b02e77257065ab90", + "2656adba0f6d4f0585a60094f51482fe", + "7e5de66b10694898ae9b60cb1927a361", + "05d663c854724296a527c8cf53976f34", + "192518f463434dec85a926037ad5e9b3", + "2674281d2e6b4460aea377314cf84416", + "e84a58f7558545c4b7b6d460b72f8340", + "34c8ff48374c4b56884811868e5b43ca", + "8d7469d6f0744edebeacbd5065bc68b8", + "0a3fa07a6c244500941b2a747d290046", + "90acf44b95154a219b983befb3cec998", + "93ad19db34bc49a0b7acc24e7a5a22fd", + "e1807383f936415795021dd051ec3467", + "a9de4519ecf84395a16f0852fbc1f058", + "b74f01b2fb4b4e0d9cdbdd93ad1e838d", + "8477a004d7814ea880483bba501f78da", + "0179cd3a20f34e7d8d0e7b61b13ff958", + "ef682dfee3c946fabebefb616c3bf8c0", + "455f85efa67e44ca893a6c3fd01289cd", + "27abdf67827e4811bcb959942fd1cced", + "387894f112f44d82a0dbbe6aa3906454", + "41318ad65d944af68b84aeb86bc66270", + "6e859ed27b8c429b97be32f41f871b7a", + "da628d2fa22a43919f6ff0c3ab23ac49", + "49e709497f14462dafc21c18ffdc4727", + "dc99dcf5b8dd48ec99d3c01b514972ab", + "b82f84f2ba9b4f76b7717084f02a55ef", + "1737b6b9d911454faa170be52e8f784b", + "b39c78a6a2ce4ff3805c4c1c7f165919", + "a730a7bcef48485eabdaeef866db989a", + "081e967a3609471f8e0b384f44f3760e", + "84b08e6ed5a94051ad78345d1c694ce6", + "6ea3e02e76744867a26320b7a7e68e4d", + "6df9eea2a5be4f8fbec679cf1b34c059", + "5948873c2c1e4c6285e3f3d18a9b991c", + "62da94bdc70547db92d8596dd59f5301", + "3bf865a8ab214ce1afc91dd1694e1193", + "b1191827a2ce4341869cc8d8a476bbcf", + "768c6f65e91d4d0e94efe4cc496e6eed", + "3eafffa90f564ca6b4fd517566c5d0a7", + "e47ec90c961c44d1901c1ffcfbeeb975", + "7664695f05234c409e27afba756d3a1c", + "a94604849bb14ffcadcf8a9f7d1d6300", + "1f8abc738d7e4d74909522e06d342132", + "f4c59c3813a04a1bab8ca0e1e9ab7c35", + "9531cdb48b8e4f728fb88eb24e17e027", + "5a9434fade0d47dca6afd6adedbbba70", + "2dc2176b1e03435abeb4bb9f116dbf72", + "c37f8a2ac2064ef2aa2cba1771d8c5f7", + "97b09c13d2fd4f77a39b9a5a016d2f14", + "421ea7ac27ad459eb2e05df49dbf7fb2", + "c0ca5a0aa9a048b0adfd33864f738718", + "3a345f16a90b44dc868772dbfba411d2", + "b9458e04d30e4b6284d46d35880a9b95", + "3902551f1c5a4156ba67b9f8a8f5d59f", + "d94638d6c6ad4119b868567cf8e9fe2b", + "edda532c28154e169b1e51e1dbe16689", + "02f82d69871941859c7cd594bb3fc0b4", + "b9f516c5f36e4f51b2c007a4a6b2625a", + "899f97d8c92342c0aa8c1d4969cfc0a6", + "ffca8bb09691443384e6fab09f2bca90", + "05af6e9607db43268c1cb35aabe39d02", + "508f09d635b14e2cb066e81d564f34c1", + "2917156edabf484285d28e522a3f963d", + "4d1b8b78f77845e3bdd18427ea8103c8", + "300dde7f9b114295980ef7da782da86c", + "9a808c7af51c4cc99d976fac7db52ab7", + "ac8cda77b83c4b62a059224f382c04a1", + "26d52ce7c2d2461eb0625875bffbe0f0", + "626c976266064f5f842fc7186aa253d1", + "2c68d833f26f4fe78cf8dcb179a3025b", + "57477e790a354b07bbb319588992f06d", + "cbb8140178e54758a8cfeb9a90a7e0ec", + "546a398c655943dab83d0d5356e44405", + "690afb5cd5114368939b5fb4728ba516", + "e9f172506e914e3c9f1f958839a7757a", + "7f434bcd52a14bd48d14b46487c02e72", + "4b6abe46e68940be872dea3daf3e1c39", + "241dd821296544f9a2507e53351459b0", + "2311fc1597c14168be9c035f4f5427cd", + "826b947e0d4f4c9f853150b034b6c5b8", + "7d1983cf656546878eb0dbb476304481", + "712f9b2258f1440897ec369951188ec4", + "ca2084ce43a64a809be5ba0a0ec6cfa8", + "8dd8f987f9d64dc3a6f17d9e880d0563", + "b397ab0c39014961a71b337805e91923", + "2d917cc2f9a34de78858ef6f24147bc2", + "f0e3c872f1984cf7a467645d9e0d3abd", + "89195c90fe4047abba2925b938a035f0", + "4ece6ce3d10f48c3bf6774a317bd813b", + "c70286a5cd02424792f0bf1c11742510", + "3f3e204cb66b4189a3c6a7e66b4d27f1", + "7861ec8a08b34a8db9761fb80f786220", + "a015df83aa154fa5829d2e5c0416cd3a", + "2edfb418a8df4051ba7258acee719e19", + "b424adc1f8824b6bb2d287b587cf8ec3", + "7adbff4089bc4a27a8f1922d6240d6a1", + "b1f4ebda2c3d4e75b1619400dd409c12", + "90c9778e68e54a84be1a9ad773d71d8b", + "582c0ce1ffee41179ab981146ae0ff87", + "3490102dac814280b983f9ac95da20c9", + "0d24279daaef44a98b4b86dcd7d1525c", + "0b7cdd53398a4c1cb29913633ba565c6", + "2e1faaf0656649e8ae1d6555217a11b8", + "ca0c929add654ba5b22bdfc61d2b30c7", + "2df4d844df8a41ba9b01c0a9f81739c0", + "129cac21a35949508b17c6549959b38d", + "1432fd64a4fb44b5bb1c03794f7d0a46", + "95ff48f069594f34878b5df32a8f861c", + "7ac7e1d92a8a45108916d1ccd0908caf", + "8face78e7f2c4975b46b331198aa5c00", + "b5ad68523dc04634985267d2ed56e110", + "fc6dc70e60a0442b9a818c3e190ed244", + "42d8bd38482b4218a62f7cd3c5aedbc1", + "4e1953a04cb44a61929a569bb868c090", + "782a9f01175e43d9bd0c2c0a2dd6b442", + "99ca0cd55e234273a589ebaceb5f0c93", + "b9840f05ac804984b528104560383f5c", + "aa3370e0b7ef4e1f9569a5d94c40f516", + "96b53d18fae64d428cc8a4098be30700", + "225b6c873d804589946039010f801c73", + "686746d2e4f44de5805b55d60f727f2c", + "128f0e75afe94c6ea0ee564db07cb8f9", + "aa2eb2881606467d8176c360f459a9d4", + "655a82c8d2a34e189e1a4418696c314f", + "aaa202435fa1456fa3dc18739f5bcf1c", + "5f998c0df25d4229a17e33cce6bfa0c4", + "ae9d6190c88145099e089f7c51104b20", + "4e441ef576e648768229966efe7a03b7", + "ef68b3d335d945929ba9746b64f178d6", + "e1b84e5b2f774b94a96ef8e5d8f39b4c", + "016faf19dae1433193b2792a34e6abdc", + "5b1e483e1f9d4d3d98bda551b7caef76", + "b4ab34f9e2104d12b56cb25c76a25900", + "82ec2060f2b0431699f57f1b1782ab18", + "7ad37a39f5534d57bfb68f34fe0fbd22", + "91bda979471548ebba9a31300d5d9c6f", + "9007d32139d947a1bd97f5e8770d44e1", + "930d4e516e9e484f923cba0245c561f2", + "674daf07d6cd4ade8ad8dedd48bb9fe0", + "218071be4ad04809a9da07e86a7ed4d3", + "a1b5ac526b7a4fefa178fbe84e2c4045", + "085f6e7af0dc4093bfcb8e55c01e2e55", + "31df366e091a4e64b9b0cfc1afc0145d", + "1decbc44830444b484884835ec7f7c24", + "a4475b81ba7b4d589faeba319b58b30e", + "e8b4a3e02d274c448d37b42c0894b9ec", + "a7f60ca3dc264eee9c3206d8c7b038fb", + "63f37d0c4c7344b192cfac9284d9d178", + "f4d71696649c4c49b3e6823fd41f5e1d", + "1f0fa090d56a4662ba4b58ab6ebca761", + "f6e6bac42c114f39b07f918ac16a355a", + "44e3d6ebaf1d497f90e41b751241e5e3", + "86c2da6d42364cb3b3f5d732fd01b9c5", + "7838304674bf443cb7e2701e2126f65c", + "4d595c5dee47445994b53c218d1f55ff", + "26aa4fbd272849ce849b428e646d6082", + "a2784d7b873242878faffc2bf6c4db7f", + "e308017701094d859b9f4bc52d4fb620", + "d99606643dec4b1cac043dfec036dc2d", + "fc37d39ceb264b68ba9383c79babd01d", + "9d1151a63aa94b90a8f2552c2be5b1f8", + "ff9717e45a014315bebd5f88c3dbf70d", + "8db91efc58a0434781d169e1bf4b3e8d", + "ea320c1693164d65b12322b478991efd", + "5ffa3aa646cd4387ad6f60f5f5fc2172", + "a33223313b554338b0dd395494bbd808", + "f77a7095794e460a8ba0b2a55f20a27c", + "504248ed68e3480a807aced6f002b2d5", + "97c94c3796ce468faeff2b11153998e5", + "fe10f12853044affbdc9e835eabc2c81", + "bbfd013280ad4daea483f65bdedcf824", + "62a09b0a7c094e5585f2057d64ee31f9", + "da034278cb1c426ab0aa6c15b2cda81e", + "ae7680893dfc48099a5b28c1455bc88c", + "3abb3e01b4734f44a312de3f7953bdd6", + "58206e3485b24e3f89e1d1ea61607189", + "b537c2c46d6847cb96ab68bb06d7e6c4", + "b5d38432f62f452da57deb0326a1588c", + "dcb8de6bf1e547d79528cfdfda7d0c89", + "48b72421a4c7420eb201f893f3b6f4e7", + "bbc9f882493743ce926a293945aadc07", + "0b6766c2df0e4901b8c387283d544027", + "a35b9437e8814f54b2b7b77a190fdc1f", + "77e549b22dee48b3b7a5841e88ffbc67", + "901718e881cf4a11a61cf2f810e666d5", + "4944b4320392432a87fee3a1269c74a6", + "6f8523cc25e3436f8ed3be5f822e56aa", + "90b9768659cb4ff9bd0bff866ef127db", + "a16e15ac424d4056a5939b9cdac13c8c", + "98152e492164485f9c476715c3477565", + "09a9fc4a0061464fba1bc3ba76848869", + "de2d0e3416224e5e807bc794eb7d0d49", + "e47ab9f8b81a4432a70653c7a09b8274", + "f3d1ecf9bc324a96b70a0dc305300ea6", + "11c77194484147e9ac5442f4a7ecd59a", + "a89e6f5e85fd485abe64f9b26eb14a57", + "fa931921a8864d029adfd642b13776af", + "3ff441fdf285443cbe4542be0f8b5099", + "ca1f7d67dda34644a50729b95fe17d18", + "7e51304475cf4d63a14b7a54832cce3e", + "962cda5a75b24554bd3b3c53b0828ecf", + "fe04da572c474ac1b7e82d5a88d005bc", + "1038b32756a8443397bc55473d404958", + "49fb5b927e35410db13acd490caf7649", + "4fab339a56104e21b684693889d4586d", + "76bb1e24829047c096e63f3322b2bacc", + "f69488efaf50489cbaf05de717ef35d5", + "dcc4336464ff4325bd78a4bfa6b9fe98", + "01472d12e4b2465da7c681ee97605cc7", + "9c4248c152024c1f8dcf8c8e802281ce", + "7835452d6d4f42a998b11bcadbed6c23", + "4390e2e6a1534c329f281c84b951af15", + "463ead51d6254a12bfd623f840e5ca21", + "acc19a79473b4e15a4875f583fb12762", + "74ee535a11dd4778ba40eb121f00818a", + "24c8384d85524627845fc7a25bf28393", + "d4297ce41801483181bd50f3d516dd6b", + "e3d89b92dbe14b788beed9e08f879940", + "17e90c40e76e432e82cb68f5ff3342b7", + "55d0e295c53e43219ba68c6d911299a0", + "a8a4b6f1c851491ba79c84706ed745fa", + "5c12ce55081046419ab39aab06d69bb0", + "a073561befef4547a4edd426d9e0eac7", + "2e6183a962d9447ba37368993aca785f", + "8abd2fab09e741518eea0bfeba8499cb", + "bbee8a44206f4fae8f672f3f93297bd5", + "a42c16ddc04f4da386769637a09d3479", + "ec853716d1504e91aa3b74e14d93ffb8", + "ab795908c0874284a01556b71ac8f34a", + "b2e37c5341b94db5a5e48fd4b2573f93", + "73fe9da4a34c4eda9118caa6df8be27d", + "7ece989075a34708b69bb98b221173a3", + "1271987b3fed464daad412ebce14d33e", + "d262d850c849400cbebcb41cd8cb5a8c", + "14e958fe6d104a02864433899d3079b2", + "5cf2199634ea400292cc9ded55a2ad29", + "4f911a8fb9654cd19305542d8d78d489", + "fb9c3b70ceed474bb0e40717a6ad8ec8", + "e6323c2c8caf42fd9f7c841be84647ed", + "e4c3153dfbc642049402df3e15464a06", + "6d8c8c2a8c244a9bbc0651b884afad73", + "3031fd7b1adc408ba27ab3515a5c34d8", + "e9f58587f4f241ccb8245e28fa10f717", + "6f054321e329476d859df23b608dc7f6", + "bd7c92058cd143709b585f6a1411eb23", + "e3fbc2dee3ff46b5b4dd42fa16867eaa", + "3892a25754c7452eabe772ff691e4c6f", + "24a8cbec7e244aa5aeaf9a3ab0b50d38", + "248cd9a417ec4e56968388d4db97197d", + "129e44db7c2d4a4da951dad12ba7beb3", + "a19f140d3012463a87a7c08f1ee6d799", + "02bee2c9913d4eb18c977bb7f09ace35", + "e9f89e7be10f49b98b9871f0c47e95f1", + "8fb0eb2e4f284d2fa8575159527cea7d", + "bc297fd86f2841ccb9a4f9d6b4c529c9", + "1dce7b028a634036b645eddcc5aa2c00", + "a3245c6fbaaf448180066145c658fcee", + "9f04dfb191724bf287ea9c42ab29b233", + "776eb1b52e18447c805e4628219d3b74", + "fd00f63eda5b451a8e617e15290d6e94", + "f10af0b912b944d189bd4d8f96c7b414", + "6b60665acb9b4399b418be035389de9a", + "cb973ddaa1db485c824437d10aea2fb5", + "7f675086fa7145dd912f272218f05971", + "fb6380cbb98547b0abc14f2771e48374", + "b4def16f4ab541c4afb413d14b142687", + "4d32ad54ac72488995da9474e3436bbd", + "9d96a976248640daa80cbeb8165aeba6", + "a4967310b3fa461ebb5ff3ff414380d8", + "55273849a9394345b777d9df6438b26d", + "3837b45508f84399820b8bad3d6c2520", + "c2a670ae3e1344c982190b6adaebfdf3", + "7913ce56e15249a89641e304dfeec67f", + "914eb8ffafc04db48f45da88093e0a68", + "bf4f2c6afa0e434fb105586a3f360728", + "1e1264a68c3943bf93405b4ffe88e4e7", + "4dbf1a7a1a7a410c999bb39d3682e5e5", + "85e2ca99acf94cfc9acc325027207f38", + "18ee0212a87f40218217e6dac1c79927", + "fcdfbe63d3854fc983bdba963d1a160c", + "cf523bcdffea48f3bf01e7a976a3b11c", + "1b6dc44192cd46a8877a188886734f04", + "710419f948544e6bbe895198aab6994d", + "e53e12ad33134875837c49c9bd84c740", + "a68544fd4d124df5b08a6f34d0a3c718", + "4181d0137e0548f291396cf7f387d932", + "a8d5499be15f420dbd1379c33ebee4be", + "3377107e093944d094336fe9e6555ad8", + "8decf90bc6b348ffaafcc8eae8e23b3e", + "87986ccad3734266a50690d5b35ba24a", + "c56a233f4cbd4d308aaef3416bacc3f9", + "a861384658694b9f94154fefa89ccd32", + "6234a9feebd94f48a8c907d92d9eb358", + "43d09b6ee00f41ccaa4038f14f59294a", + "f24171aefcbe4541afa1e3d958366f7d", + "d4257d92a7184e8c9f111e81ffdf3576", + "c335732772454197817f29606b731655", + "d82eda5ddb9e4623ac06d8d888b6f466", + "8a4ab629e80f4f0c856dfbf3ec958356", + "9244cf7991274b34bf36289c89db5b1a", + "e243fab1a47d4427bff9de3ef44b1a15", + "88b0b93487b74132b50e6dbb250aadbf", + "9926c2a955ce4529858a57fd0f9d60d4", + "c96572898363495f85993e7e0411d7be", + "a11f0119bbf34a7f96050a2524f50063", + "bad5e04d290841779dad272897f384e1", + "e0c20469c46344ffbe37ff14ae669da7", + "7da36ddc2a28494586269bca7d4a7942", + "6b85ce0741944f069cb7bd6c06177ba2", + "8346f89943bd48329b98629ddf510430", + "98b1da4020c54f91ade327a9de2a3cd1", + "79c8697c03dd4b43ab4925f90b55bde1", + "37050b9e700348f0816ae649df326f40", + "e050dd76cc114581adab3c0f8caea016", + "88a0fef863894ae3a7efca99b36e53a3", + "26640d041edf4570b396c555efd4f818", + "a8d8dc70affa462d86345ba9f513d780", + "fe6b9d884f8d48b2abf98e13686298be", + "e43e4e9376104945a158eb039d590789", + "1e8bf0d0d47247078facbc64b6e0198b", + "0e5d6fec63714df0b49b3399c59044c8", + "05f311a4318e4d1d9f3062e6a553dd31", + "6601e19714d349d1892eead6fcc509da", + "61a2c3ae82dc42f69bcd68adc6fc1a66", + "66b2ea9eb6e5468d91d814395036a537", + "d6ebad7ae6e048e483ea54986dde9fe7", + "7f92127194344e3089dff95221082e84", + "ad0501050f0d4781aae97215dfafcb78", + "5d35a6a8e39b4c0a89b53be0bfb57ecb", + "0aa13b8ee38f471097bcd5de12e1ae87", + "9df85c89503744b5963ef5d51109630a", + "120fd69494994dcaa23c95e499ebd6e5", + "9d912e0fedb44b619fbd2a083bbf174f", + "4bb7ef9802f64bd693df0f6934cfc49f", + "46813c9124d84440beb13a0078702779", + "b15d7a05c8484f92b3a7859f536c0bcb", + "2704a3eb44f349b3b2982580b08faa15", + "e3ed0446c2dc478d8f29e89c6584fafc", + "06d1b23952b142daba118ed121835a73", + "bf6da7cb248d44eab09f79685fc204e4", + "710760eaff244282b5f324906147130d", + "5615b16ba2e24f7ab6cd26eda7946ae8", + "51582c42a9b14526ae7acb33f536d1ac", + "b57706ed26c44dedaccbd99996e8d807", + "5d6cd30f9177407ba5f3a56f7a7ceeb9", + "7fe87a99a1a648a7980dc07bf0e65293", + "60a09f18626144aab4a67b8826cdf6ae", + "6ea3a5efa51e4b8ab72470c6ee475945", + "8ea51554eeac4cc1a8fd078fa7024936", + "80a443a0f64a4ba0bf4800e10dc3a37e", + "fc35ea02b05e4b1dbd1774361b7bcaf8", + "4809199aa426497daa46aeee398dd387", + "5f04e2fe311149afaa3e59871a465c65", + "d2663d7899c04e73a43cc34ec3e14ee0", + "ae0c3996ee0345aaa8bbb717db7ffb25", + "68df6a442220474c8c697df2a6d3e94a", + "0a1e010a89324e33977f2961d6af6465", + "8598aed982b843b9a0e5beeeaae9999c", + "17540961a58a4d2bb29b800d63bc58bf", + "f1f3132a87854e688a2068a079f95e75", + "21b36ef4ac1140899763f6a0581a01eb", + "1dbe9e6bbde94b2aa2e78d7258378ae5", + "e14a4471096041adb9e33df44651e136", + "e6d08f3e92f243c4a9ea3a19d11f97b7", + "42b4eac58446443cb2988fefc418682b", + "2819c6fae8ac438eba43a35c2347d097", + "c5d80712ee2c4741a5f059530e523a7c", + "cf012f960b7a4b3db7ee45cee6bfe43f", + "47f8cde331054e6eb7a67b0e35390e02", + "c3aa9744242e49efa50b0c5c977a4f9e", + "7784f88d66ae414ea5db2126bc5dc20e", + "70752f2d5d5840e1930c20ccf46d8ee7", + "05a94083efb94c0cba5b36a17eea57a0", + "eee70cb7980a4ca7aa0a2f86c492283e", + "f347d0126d2240ecb2a3eafa4f96c160", + "b69e3a5e989145eaa284a33612139496", + "1ce07fffeaf74071a5097e6a075d9e0f", + "8dbd9cf630b34a7db505565547282172", + "ac80420759844f65b23aed1ffab467c2", + "e7a0d50c1781403c973d9bab4390a2fd", + "9334e4f73d7d470681688c3c09fc8edd", + "cff2c5c2e8734568ae170027bc736968", + "904bca0fecca474fac5e5cd45fa2592f", + "f0299a558be8424da4fb917c58658779", + "18008262b60d42b18d127666da64f82d", + "e2ec7e74efae49a49f7092d3a5222c1a", + "dc6998cf30c848a3bb20c837d1857e15", + "21af1e278bbe4fbaa5aade6295d45c7f", + "6ee63765c42642928c61510dac7b3df4", + "808aaeb2ccbb4ac29c356890bae9f892", + "dd1a2e7568d34c7081ca04987be3ad80", + "975683f84bdd446ea1fb3c705459665a", + "1b48a3d913474e6890b8b8163bb5407c", + "430a5481ba5d43618cb6646dccb26e91", + "daf2c867ae0140eb9368cc522dd17e7c", + "714694c15fc14e2197fb6deb251cf07c", + "f51de8ddeedb4826af4b0c32e635758b", + "e3422158ba1845feb23ea7272ae4e208", + "3b25ca2501dc4b22bddf8df83f8c4272", + "e5fe8edb1e674e16acdf47da7c792e86", + "e4ee3b89c73046e0bd0c8b5b3010b12b", + "07ad5f34a2c349a0bd1dc1bd46cb8424", + "f5960b02d5f94925b2271e795913db02", + "2ee32fdb0e6743ed971f6bc143ca81de", + "d3b8294ce8cd467981cca4b1e9036acb", + "91a82a11e9a04589b3ba79a104f2cbf5", + "2e22e1cbe0be4da2a82a79ab76cb64a9", + "07d75b41712548908f7a24c7282f38f3", + "41de702c637a4c9886ba8d31c5e492c1", + "b636c0b27abf4aa79e6a04748d1ebce8", + "b5605d9681e14949b000a74750a056e8", + "10891952bdd0488d9269852e0a42df78", + "c143f3a5099f47eb9c1c4039dde57628", + "c7c7142b289f40f4b23ceeb97b8c6af2", + "b380864d0f9a4f83bb2c7f2a7ab06f4a", + "0f12b822714a438988ac949e28e11f4a", + "0bf08af99acb488f9cd5e39034eef985", + "be74968996594fcf9de725dc7591b865", + "93247d5da0e143faa8f4c16b39c782b1", + "7c261ce99883450e961ad40f9c814291", + "fe72cb4ca29c4b3fabe5df257fd2feff", + "d75965a9183345658c0b850c0d6b61ef", + "2a881b7a4931412d9fd7e5cdcc2c3128", + "b1b452fe764a4cc9af3030f69939f506", + "f5bf29193be44caaad2df1db3db44871", + "06262f163e984fd79a287a00d48ba61f", + "132c790ac74c42a0bb1a5fc7e3d43d7e", + "023e3d2170f54b219d4d44bea2075f36", + "52d33d288368461cb3d6e8e6c7730165", + "2b5fdb4154fc4fa7957d885ab45c2a15", + "701c17a1a77e469ab0d833e3aa1b1847", + "35426d17345e4fd3b0532ed0fee951fa", + "c915ec6760d0478e89a5a49a956c5c14", + "5e52b176b573484ca31f709ec1c441a5", + "549c4dcf534841238c25d3b10fbf3370", + "f312ec9f87794bdd83630a3bc694d8ea", + "b3a90b66b6ff44e2b10dba2549ac892b", + "fa855687500b4d6182fb3fe0a06fc908", + "4e7600fafc8e41fca9cb00f3fa1b3f8d", + "6fd9348394f34bb4897e7b6abb5ce825", + "d301e870e59d44f494c410ce1fcdd60b", + "e863537b272c4c389cd0e47f37c2a049", + "61f557ba982748368925e02c04ad80e6", + "a2703a8667cf489e9c439c368fd89493", + "90fbd4f247b444049b5bc64be3200678", + "f9f7a920d24b42c19d87a2d569e27436", + "f0fafe31662f453c845bdbb3d4e58cfc", + "5f5a6ff122c64b4e86a21642dc6ed391", + "b1aa9affc15f4fe8868f5120e16ed6c3", + "c638f55aad814156a9a9561980a78eac", + "a11f593600c944cfad8323b3d2908cd7", + "34084ee85fdc437eb6d91d0d963e073a", + "205507f9b63746d8bf304e30b3007239", + "cd78f5b2a2654ddeab14d92fec858907", + "c8b5cb9b83404c69b667cc043098a241", + "76e4af37bf424495bb4c195229168914", + "ba545e4993cb46f5961cf4edec1ba139", + "76beb95d0b5b41a3aae0d07c3eae99fa", + "e94e66553d02432eb69233d1936d7f8e", + "4e10012f0d5b4ca1ba7dbb2571f06e2f", + "a6104fc36b7c429b9b3eb43369481992", + "77e0384786d84a688ba3a3e8ba31f697", + "09488b18d45a4eddb2d58b5cded077c8", + "032ae3ee496b44639997ffdb9c97c5a5", + "b5272154f9ce40d88483715674ecc787", + "731960026f8240b1b5952dec3ec339fa", + "87f446798bb544c6b0dca2504b1f9d50", + "266af5b6ef0548a0b574438d5a56889f", + "9ac8f34dff9f467dae32fd8ddc686b47", + "fb4e2af758a8426a975af18fb0bd6677", + "cfd55cef36cf4d04a30417d59921481b", + "33b8a04b72484302a1a1739677658675", + "f51a4331b8314f9da5c76e9139ab4f41", + "2e370295f3404203a662ed5df91b291a", + "3623d7ff740e4b969539008999eebcf3", + "e736a1e7cdcb48a5a4f2ca4100d52d28", + "0830e548a03446eeb2ff24ab82f5604b", + "b92be47157c54e8293927232b985b5a0", + "2b0d1feb52474d808ae6999c81d42e89", + "0fd825c764c14c888d37228984823ab1", + "560184ebf3f3449fb195f1fd829d25f5", + "64fc8375cf954a6c8460a1fe428383a0", + "4939d1bca386405f9cc22c48441b63de", + "256ef6e691624a42a18a3946fa72a28c", + "e06d06101cc8434e91034b97211d5dd5", + "0a46621504c24197b5653608f474f73b", + "09063f37b7bd45aab9f75addb60a5cc4", + "58efd7183ff44605a5edc5ccef40bfcb", + "03c190dcf15e4ee7b9398576313b4981", + "e1372c9d42d34d78bf03d98b744cc147", + "f40f30aed6d84e69b61ee8981c599ca2", + "0083fa5f10a442408e0f3f88df19c8ad", + "172f7b2cddb942c4a6867e55bea4c47a", + "2e5faea64b4841c68c01bde24674a380", + "57a9f57210654739a9243996a926ae55", + "c158361c7f804ed3b7e7a8edfb827297", + "577ffae1bdf84fefa7b62ed4b91a6949", + "0ad165ecf7264702b7b805b1d0c3967e", + "ec3d039cf5aa4f19b71275a2c66536a7", + "9fde607d57484bc2847f9d65a1538330", + "964bc8cb4cda4c44955493ab7af25e44", + "b44b22671b464574be1342b2f21d98ce", + "d64895d7ac2e466dbf836674bacf5058", + "e3bfc0046bcf4ecea6e1b291311b8280", + "c198c7d48d1546c39d98bf40738bdede", + "4a3902780dd04d38a951a3c69efdf430", + "5129df55cf16458eaf747591b009eabf", + "ac8cd8c6758e4449a15f3c4147df8c5a", + "5b608772bde3411d8bedf35c576d95dc", + "2f3a0e7183ce4bc693652628c18d0027", + "118aa1a874f948aba8bee8450bb38b1e", + "d8f393b1fda94bdea9f1d33ee1c6531c", + "a55205c219564a9584fad60e0f8b8820", + "b310935556f645508f49323791feed34", + "ed268f2127854b40afa82a454b7a6d22", + "1e1e611c333042ad817f32f961e8f2fb", + "f92bb2f1365249a4b7620fe38e0d04d3", + "93c4a32cccf44aa991b05b94db6790c0", + "344d9fe4bcc548cca31bf1fac927a07d", + "86ef8aa3e94a41748d9e0698bd0d154e", + "c6208b577e6b4d83a8bd5d5402ee485e", + "5e6f4ed5aab347d7a4bcf3dded0a0207", + "b78103ff5f22410cbb50bd35c25e8910", + "f78ea7447a774847bcec4dc101098906", + "11e2ccf4fe834b25b02696f563fe770e", + "9fcfb4575a0346268cf2f567d5b06a56", + "45679d2bb86c48aaa798cbb1fda7e4af", + "e3701cbf405d45c6800b65974b4d99e7", + "26444bf184ad4fe0bc3591edbac0420d", + "638d2a0a7a8a4d4a8287cddfaf1bee25", + "518f42b92f594b3fb5f4820b286b2551", + "a857ec8b963d45dea703d3bec04b3913", + "5cc72926d9c646cba8141acb19496da1", + "14280a2619b547649ccfc22440c5bfd1", + "b7bea04856e1401898250f313131659f", + "a49887894381400dac586e3a7f21c4b0", + "107ae1a7290c48589a23b965b0a9ceb0", + "942a6c6671bd4c44a8704e28566d5dae", + "478c11432a50470e9d6cb18cdea559bf", + "42c95b9d43a548f1b7e2ff46ee4efcba", + "280687e9352e489b9ab980ca8e5a44d3", + "619563fb2e33466cb1286b5732da59f9", + "ea69be4fc8aa468c8ab35314f866d793", + "7baf9ae9e38a4a43ae9c7fdaa1703625", + "8d90fe24982c42719f22fb3033371b85", + "177b3adcf9154a8994d6b6b953a496cf", + "2f7c32f5b197494e8308956c3f2cc4d9", + "17df66f940274e8583c2b0011ae958c7", + "458ec9364613406b916da8d617bb783c", + "fbb841594c55412fa24e8cb73342265f", + "7613d14a507b42f7b83a227e1dc772fa", + "c6abbb83c7b14acfa39859900873d8a2", + "6b80d946a3024479aaeb6d0e41e534b4", + "b55969446ff749938e9e6c7598dc5f36", + "dde3f925f84146d4ab8d6023251d8ee4", + "89bfbe6008b143819a40f9c57a131fc5", + "49855805dd124418a4c3f440ac60e8b9", + "1a1cba4f5858437ab05ce00d15fdca3c", + "b2ffff2874224bd6ab62dc2ef37e0e4a", + "40844f37adb6440caba01451cc64c94b", + "04d985493afd4cf8a2ac6133116d4686", + "e162e6533b224d769edb54cf55f7a62b", + "9212ef9e7655478d8b31b46198b49b56", + "a6d34c9a1bf24146bcfbd91886d7df30", + "dfa1f70efff346cea2645dec57c64d45", + "aebd4c8226ee4c7883649de15b856e22", + "afb862ed1cf241debe7a9fc6086a91d1", + "b5dc17af6a84456e895e557b52c8fff1", + "d87cc4da7f0547f6bd3034d3015550e8", + "d85a11cab9ad4ac5bdc2aad2014e45b7", + "07d500944f68482cafcf7a1d67ae515c", + "0d5e75130f9c4f3c9714f10884cf2321", + "32861158993f4a31a8a8f73e932ab225", + "1b32c678cb9e4d14805e48e77891c459", + "5b9b2c2da2474642bf72393c58f3b1b9", + "950f1d50fac64c3a918b260deb108479", + "0733ca3da7fc4250ae98ac1b61ec1b9f", + "cfee8afd67c94b2ba72842e8939a8a6d", + "536d687777f0473dbc79f00ea4a17917", + "dfd3875d8807400dbab04a73b08ccf35", + "9aa37ce8b18d44bfa072bbb7767d1d41", + "64de31be3c8c4fffb1a3a1e4d1d5b904", + "f95b82e7eaa34420a10b064dd515b13c", + "5fab390cf6a04acbb6483ef96df7ba27", + "0497f5b8eabd4bac95a7336db3fe9f86", + "1cfa99de7dc0402e94a5ea72d6d30acb", + "30aef1629c094b22a8b80444de4c4d59", + "cf703108d5bd42f0ad3970ea23306aaf", + "2f664bf777be402e94500b6a77c1e553", + "7f0597c6f53b43beb263ec477a1d30fc", + "e45ede8d849141d49762ca5d3390cbc5", + "03a45d6d62a94ed9bfd308e2ac96cca3", + "0000ecca9a234cae994be239f6fec552", + "235725b81c1042468029169520374c24", + "7b86328990534ffe9c93b55a676bd6ad", + "f96a88af2f15407ab9ac89f10910a78b", + "f7a8199aeed1413cb785860f1d4e3702", + "a8f48711ad794604a35727788db7fdb9", + "3ef74b2ed60c4a6a808a595618908aa0", + "0b7b4f4ee4ed4031814d62c526ab23a8", + "0ec4b1a8c71a4700a2005842e3326af4", + "3878dbe176654c1f984805deee25aca5", + "3be817cb06f5412e87015c8460edc51e", + "eb6f448904c44e1e8082b5afe528c82b", + "0a5f52a298864b20a290fae141c2791b", + "44f3d713ef0e488eadbff8895520ecdc", + "b6d7a6e9690c4aabad51c83b37435282", + "65ac23e97fd141569be711fd875dc162", + "23097478a32046e98b3804beaabe445f", + "53edd634914a44f28fe9a1bdd5dcd973", + "3ecff6036a1e4afc874dba9f1a6218ce", + "88a53187eb424f4c8c24542438ed3731", + "5d1181c610414c1c9d4a08c65971b355", + "bca02fb2be994ae899727704f3daca4a", + "0cfd4b6c4ed741d79b444e3ec7f5b0a2", + "3b05f573850f4558a590569a56a4230f", + "7a6ccdb34fdf4a15bf6998d348a6ef24", + "10367ce0fcbc45279f59648e80e26139", + "ba112a588e804424a1f4cd497500f111", + "d7cc2b585ad943ef81274e014e6f745b", + "5209b250a702487684bbf84df5112a90", + "50bc0faba74d45519f63caf76ee9b4f0", + "d42f2c22796d45e0aa2ded45b8e89b41", + "c66d804313c549818cee3e795bc73aeb", + "313db418155743dda0f834ca53dc4316", + "d70e1d9cbef24eabbaea329896ea08a7", + "d4d902a56c8e4b5eafe80757557f0491", + "2fe6812a60cf416c8ec046140f85086a", + "d31ab63dbbe54c49a4c698605c23681b", + "703654858927479da6d5bd52c76d1411", + "ce8eda2ef00344819c809a03c946ef8f", + "1cabd76a4bbc4288bbc2a4633cce1695", + "6132c68594544694b753b305b50bf66b", + "4dbae635a5eb44ba8953b68ee5b4c88e", + "47de6f92d78942259f90738b194cef9f", + "a6239e9278964d7085ea26487cd70f01", + "8fdc644e107147a1ab280f78c89895e3", + "09fd6b85dfc84ccfac7b6d3ef378fea2", + "50c6cc33366449be873b785c3b1efab6", + "ff77cb8deb8647fca89fca4707ba1cfc", + "d5a7a206f253428da32dd184bd5eb26e", + "2baee3f8cba540e68b7aa3db47b419cf", + "780a49322d8e41119fef0f33af3fbfc4", + "0b77970f7f984ce8ac5c0a03ed1fa1a8", + "419a105395644219afea37b78d5c906b", + "ec9afcb9f12c4f0286e92c77184675a4", + "64ba7451e11149a4bd566a9a8976fa86", + "07121d29537c4c70bccd4d02db6a6466", + "6a2bac9e48c246b5b08b798e1d32354f", + "d9b5e022929e4f7098b14fd53ffc40e9", + "a3101697171f414b9df6fe8298654108", + "b6bfe1c7bb3b4fd691f24914e430a2b2", + "c1856fb0fd1949589a94aca036274a70", + "bb3f1b2ffabb4e358c6234e061874abe", + "5a6846f469f5426cb0520fff1680ac25", + "439c950dd1f242868dd9d8fc0a2dcd57", + "c352ba6bf37f4af1a9d903ce1168f3d4", + "1f88f7cc096643ba8e364c2b0091a7e5", + "bee2982219ac4b59a4f2bc4773761a90", + "844b147c0ee14cb78d133770ccc70fa5", + "e3c9e323f01d48c7adad038f6085fd98", + "c8831bb2ad194e7381e419dbdb07c53e", + "13f400024b614c489caa9c1119c7d967", + "d218b0cb51764d4387286b16b9f2bd5a", + "3b12b5a5f067430b9c7a2d4b7d1dc467", + "2189104c64c149d6a6db6ebf1a2903c1", + "c6a68c2e9a7143e4b3a36f8dcc4af8cb", + "654cc646a2424f7b8f2a8c5003be23fe", + "43ae5660b22145da818381568dd19757", + "bbf5c9aa04c24fbaba328728d955777d", + "0cb0a6704c8a4fbd967039998a9d76ac", + "63e357f3cd36465b85abae897e1696e6", + "e0719f5bb82f4f4eab539f64161ce0e2", + "aa701db7f39244898f0d79391950c539", + "7330d379778f40c6a0fcdf79105778e5", + "907608f7e9ce4b3d8d3f2802ce336a9a", + "5763b27fd1b04726b97cbcca71ed11a8", + "a6c732bb747a464a98b2ac2ce0e90509", + "399e199d27104285b27e05785e88d3e4", + "0bbe1fa4b2024ec88b89a527dfcb74be", + "0cf4c7e293a1416ebda862227870f1fd", + "284849e6aa594b57a76adae68fa4a854", + "ff2eeb8659264d6cb1ed76e89c0d632d", + "b2211caf446a4c0394ab84c4658b0956", + "0c489a30b5474ae39b684e37b0c3ed4d", + "e2f631c75c83440887d2613fe4aeb84c", + "9085d6e964a64880a6af9c73af6d1777", + "7ec9273bdf95403993da4a5962635da9", + "e3ce5ff8d950442992c6f728c7807cd6", + "bc88355e2c334570aa1792a65addc4eb", + "bf1c12ae53b84d24b0fce21df6913079", + "fb00fe823303424e945ca4e38611e1ed", + "2b27f3d96703411187aad64dde3e1f05", + "7bb2448c74a84111bf157b6ab1642dc4", + "f232b9882c084ade97fa4d47e3c24839", + "b45673fde9b74522963ca5a4148126b6", + "611af78dbb4b44ba9593c84531e7e94e", + "0f39e4bb43e546de8ddf37bcc21e8727", + "0048e8224b174b759771e39ff521ee2e", + "0e2598df4f1a4ec186df704c4bfb4338", + "d881a723c4704a61bb468a111fb647e0", + "bc2044d6cfdb44d8aa6a6962b3a41a2a", + "0c47bc57d02a410cb5de011931aef56d", + "dd034b35949f4d0182b576565e54b52b", + "3e85ee7537834fbbbfebec9a68150a33", + "d76fe6df084749e385f688c477f9f661", + "abbc90bbd5474f73b16482ccd10e07ec", + "bac56b3310ce49a3a862da59a5d61b07", + "6ea379ddb2a242b384c2137238f46e04", + "03ec67298100408ea87689059a45d865", + "63ac173b927b404e9582e817361c583d", + "fdc859edc8274342ba00a47f84c148d9", + "87b185a15151462390acd84f706310af", + "c0867b481d1b4701b0ccbbbf6e27db82", + "689cd0d635cf4906920dd3ba435d991e", + "f8e824a6234c46979e8c087cf7e480a5", + "648eed9d59d8472883cf3d563a3d5ee8", + "040f59db3d424af3b0c0c9e68176623c", + "ece4577916614f138fb470e373193bec", + "1d02a7921c564c7fbb893ca1143bf196", + "3b340277441043fbb7f1d3e032d94e1c", + "e780a2a50515460287201f6019823b26", + "7c5516c76bd441d998af76e2240a2b8d", + "a8fc7a9994114519ab4ab177777d52d9", + "8266863b372547939d0bbee60e85c544", + "beb71125f5a54b8f835c4d0fc7eb5057", + "f376bd06d35a43e9b09c61e3a1c39d8c", + "38f0889da545459093cdc411a0e7ae99", + "15997fe949024e51b4a2cf8df3fe3b5a", + "9ce8ab24383c4c93b4c1c7c3848abc52", + "e3de2a327c0d43ccbaaef3c7277f7f51", + "ea50fd7841b94a5e8d0f0b6aa171de2d", + "ab220f191a88494aac55dc854e51c420", + "4caff3c560474f8988a37d7ceed5236d", + "ebdf3dc34c814e15b28abe626efa08c9", + "321a2fa8b8c2403f871014fb22708e39", + "29637003e3a0437cbe2836024792cebf", + "08129621ded8409c951bd1ae9a260127", + "d60d5c6488f340ccb4d5bb67ad11907b", + "5ff4f40089104fd59a1204de9d6162e9", + "864872b1417d45d7a472aa9cec8eda0e", + "fc203fd849ea46f0b84d4843ba1aafcd", + "343a88f0654f4a5094546c592032f647", + "2691691810b440b996905ec5be9e1ede", + "be563066c230495abbcbdd962ea60652", + "daa6ea3a66c3418e80b025c015626642", + "00e1490bb12f4ccab3bdf8973d165b04", + "745c105544784b9a80bbec49cccd1580", + "c0997ff7ad7a4f78b57258e502a42c92", + "58eac0d1e3d641cfb89c29b68d1da6c8", + "d02ece714c8b4f2ead4b27bbfa98d515", + "ae4426721f1c4407a2c944e5d22697e3", + "41530b0f32594dd49ef7874715cb5807", + "66eb8c2178d24c91a792e487b241c0a2", + "b01facd8c81546c2ae5cbfccff8f2df7", + "971bf873926a4cd7a2b466edce3d8589", + "3d3301d5945e4151bf26038070f42f4d", + "c425a758d1a64bef878da358e66c2b92", + "825bffee6cdd4cc08915d520a570b4b1", + "d8c00a03f1f540d398d8a4dbb5dbb996", + "a4f9de5cd6d04ff881c906ae5d0a7ee9", + "bf603827d8c3432894049976dc9f17f3", + "11d6314f1aa449e596ee1a08038afc3a", + "05de9890bb234a6cbe04b19ad0cf643b", + "92af054625b8490ebfb5c08d13781b5d", + "1473f199ec744e86bf34008ab90ba58e", + "792b24df65204dc1bbc3124bd1ddb8ca", + "7bf6b5d016da441e8300f3c4d12f983a", + "5f272f33cd8343179b7b75afae034cbd", + "d8546803ede3453a8ba9f9e14237fece", + "921bfd09e37941888da7dd62d982df41", + "1443565b845d4f639e07d6d6898158ed", + "fe03f887b06944b1bca6e367408db329", + "a0d07123cd804c32b2b6299764ccf007", + "85e7cd0d4d0f4c99adf9dd0ca9761dd1", + "f3769a474a714ebbbaca0d97f9b0a5a0", + "136368db06a044b68ea8a5baba5d6efe", + "f6a6667cd63240639a4ea9598ca4d8fc", + "4a13c0429e35454391c9c79a1361caa1", + "652c8e96613e4ffdbf1398486002f788", + "fe49ae7a8cea442e9222b7ebebfddfc5", + "c0af7ea87389433cacff5d0f90c7ca53", + "34bacb976bc94b988599a9f5c63b5468", + "dfd73a55acac4517bf06b673119d205a", + "41b87aee97e0456b8275e5397ef6db37", + "5c47b26f85eb4659af66c10c568c1df3", + "5689a9525a2c425d93f7d483b93d8cfa", + "d875ffae3c6045bcbd8ab03bde23f666", + "1b94ca5f0aa14e058df21c58f2cb0246", + "6cad5161351d4f949766cda7e4030329", + "acfaffed7696404ca8277cf9fc2f17b8", + "e83a1b69bd204e4187f30ffccea456d1", + "faf9f46a49364f9b902a7e7c196728ab", + "41601a3f942543caa191dc5d96db836a", + "575bb8d1ea424fc5a3070a0c3efda620", + "5b08596fac96400a93071791bb5cc93b", + "f03eed5909e345d3b551097e9c849fd4", + "26137866131f4c638ada57d85caea01f", + "7db8ad6ac71d4c0a8df13850d6d01338", + "181124c146e94ea7a03022d0c9b0c8d8", + "bb2c4be987fe4f5b910c565aac802a35", + "f853a0af65d34699a1f3e202aba0400f", + "305f2b09e0de48bb919116026aba8f44", + "db56721845f441d9841c82b31cfb71f8", + "3f8f4f2ee4d74d5f891ee1d7946052a2", + "9b5f6c0f630e4436a39f736f0d7dcbc9", + "426bec4978e84abaa1009a6f30686319", + "420d5be345904567a51466259c9476a2", + "e77b1e9de29b4ab5b3a20c3f35dceb67", + "fd36e971980b423c8c99bf1bfd679a89", + "e0ed61a74a4847b5b40d05b0b554321c", + "10355beb06ab40b4ad2c05381a8eba6a", + "e27ea21047714428809ec3c2509d15a4", + "7fe61fccb8ea4c65a8e2870deb1341bf", + "e26aa20601cd43fdb6d56197472d07c1", + "6b339f68554b49f7ae956e4530c5c22c", + "e2e5ed563cc340e69b824784748cc4e6", + "ef1d02fe28444991837aa1af862469ca", + "6677afd4de0d4fbd817f8c0876dab69c", + "ed37304c61ec4c9abdba68fe8854eca2", + "7608bde6437b47ffbcecd1624c361c79", + "b10270c90fbb43a3a70a9e3f1c27c073", + "b43946cb77bf4b9fa44be1b3af76c96a", + "95f76beed697414c80e0771010c6e194", + "ab62a287fdfd45eab8a1f37dd803ceb1", + "2b38725953174b31abe1d1fd95f6dc9c", + "257b95dcd98848ac9e9d1ef87bc356be", + "49152c6f61fd40ab9fd4cb370799a62d", + "33dc7bd753194ae58e1715397e090f6f", + "c8d097a56a304d99b12e8dd3aab3b81c", + "fa913f8999434a198fe3b4d6d636b207", + "ef33c35629054ea68fd5b7383ca43f5d", + "9f0d6acab78e4a84904e4f8ba573118e", + "aa51af2f1270482193471455b504efc6", + "851f2c9c44384cb383ddd27059aba524", + "eb3f46616dd4405e812c1de38a1aabf9", + "8c5a7920831e4242aca0f96e80b99492", + "3d3db8631e4b43cd8d6c63078a9f0cf3", + "c5d7c400f9514136a26f24ba5f9df446", + "a982b9a143e540639d48988ed3662703", + "23df23edda25472994f6665b612e7ab4", + "f6c08881622744ccb86c0385424e6971", + "c564bf7f265b41cfb225a1f65214d6fb", + "e0d5654c715d43ac87886fae90f3ce51", + "5555de9eedb045ecb30f9039a7b17711", + "f1b23bd1614644dfb748b8de37bd07d6", + "c9f2a2a203474765976269110c8e2c68", + "8b47d6615d174d4c89bdf68f3fe76ff1", + "839832d0fe834379855166c0677941da", + "51e2822c9d3a4c9e96171553f96bdf04", + "db5c377562514835bb983c6e51f94db2", + "c93f1ef0267e416eafba5c03e2f2f511", + "5946f63acb3d4113bcc6d87febe30fdb", + "242f66ea0a454f5cb4fc174d1160b60b", + "27264d84a0d24e6a84337b09e4395621", + "937b7db3cece4037b4a0383d35bf3b37", + "59fec10a91a247118ded6e2fdb906946", + "a697b1ddd06d4862920160ca71803473", + "d9a2d600817c43e2903c6f4a5adff5af", + "4732a9f750094c5f910710ab10bf8d54", + "736e3ea67480426da4013dbca5fb8d20", + "b8cba8b5a69543ce9875c40028261490", + "5b6f25eb897d4f0b80d19bc5c4cccaed", + "e8a54da09d964b3e8abe951d5d83fb59", + "eaa4a0dba652460daf53aa51bddf8ae9", + "29ee91e1cb6f42db8cacfa713cc8da1d", + "0afbd92ceee74327b2613284f6dcfaa7", + "cdf79890c81a42e896efadcc5d2b96c3", + "2228274a55364ba7b668acf7ad7508ac", + "c534e0eacfe1486e8eb652f94411af43", + "234e6bfc7dd346e9a0f821020a336ea1", + "9492c5a4f5654ed3936750e27807b587", + "9a179f9803734a3e95630727b9db3477", + "9bc147a06e7b4c26ab985f695a76de3f", + "32f9cc11f3f24d34ae11e5da74a7004e", + "71ff597228264500b3566dcbc54e5a8f", + "01e5cf82289e43758867faf1f56e8162", + "00b6f70f3f9e43eca3d5c08f67d4b1ff", + "aec69c979166446eb2c8e1503f570d26", + "6f26dfe6672f4c9f9780aa1e6d16068b", + "95726b8c91cd421f9454f71e02b331b8", + "eeaf49493e614f3682d5f694b7ea1470", + "f5499ab7648a44f287649c02fc3fa027", + "b4cd616deeeb4072a5de7013faa2330f", + "72e233b48d39463cb3d185a71485368f", + "7a4da493e80b454e826e6db6f5cb28de", + "6a8191f334784ee9880f029c82cf69b2", + "8de5d8f3c31f45b997feea9067b69f45", + "c6f6d2bc33d94a0f82c3edc8c0aa2a39", + "c1db1b10f9b14717ba731d7f49d25443", + "8971f0746b4e4f098c2329cb6b8962bb", + "1e9f54cc9f7d42a697c3caf0db04c27f", + "af6fdcfcaaad4a3a937f5b843f6efb31", + "d5c5529e69a44dc69e534dd2c5e0e97e", + "c54ae790425648638f844cd448628929", + "2c3525fc4e194f2e8911fdec4691506c", + "00a1d892548542c7ab83565070737d6b", + "55eb947c070149288fe0ac2dcdde9f9e", + "0185bd75f3b44931b894e61d50caa5e1", + "7275d3eb2e33411399d12e0ab14fc1f0", + "e51b432e19814a9f877f90d96d6347e3", + "8d071c61e24f426e8c2a5b80b451c885", + "efd5b3bb9a284ba0a54e3a128ab81b1d", + "e33cfd54333049ad977a9d784227d3b0", + "5ca7c51ae0544ee88a0bdb8a1bf8b3f0", + "5577e0c007b34ce88d04e2fdab684524", + "c3868debf7d34e5abee8dc49d6369ee2", + "c8f05718424a4e29b07be535524532a6", + "d9bade93f764495c92d2997b3be05ea6", + "fd6e07cfccef4b5aa6416183cb54c13b", + "0649fdcb431c41a0ac2529940f86c7a1", + "96a561e75cd040e7a5b9e1ded8fbfeac", + "bb554ccf931041629f710d4fed6edcce", + "04fc4f2c880340df871d8a0eee310cb6", + "3bec7dd69338472d8b4563c15de094e6", + "2beaf073b9de4d499d24f799865a59d0", + "9793f91454ff4fe7b23590c53d451130", + "2f45a71206fe4a4eb665b43c69d407f7", + "9ef388cd9cb947f48957a497e8b8184a", + "c0255eaab80f487991971dcf6a7f1b99", + "a132fb245d624274b218338c77376cf9", + "b66f118b4f46416484cfaf0109cb9181", + "92a9a0213cdb48d3b2d581454b798f09", + "06e1f7f25c8f4676b354690966d53b13", + "2fe3e52d805b4ad29bafad439471b6ae", + "810764ab68f24db5becdf54d5be2737d", + "a1e36c54df3d4bc49c0a08f5f00618fd", + "fc9b4bdf4ecf4613a0837d4d15c85c6a", + "8ab0dd710f0f4372bf53a2bd944a783f", + "6eab492592f848159ebc6340aad3057b", + "d2c2036181114dd789a0c651ef66ec34", + "e4b65ba340124ac1936ac9e689f9157e", + "2a0556940780487b86798cfbce4e1dd8", + "b87137a7189a46679de99a0b09fc9e7e", + "84cd8adb9d104010b10f3fa89e5f6a70", + "e5007ccfeb93487e8f3c56df4a8c5ed9", + "224b2e1336b641d4b8f3414260dc5522", + "69dc3bdc70f948f4a7b1944dbf934860", + "27a3e813ae444f3ea1e2258b9e6a47cb", + "bb182cd70cd244b291ba0e3020f132ce", + "d01a6b0749534f149adc00a0d18a00af", + "96b925daae4d4dc89035123053d3055c", + "b6ba1d39d560436289bc6cb39e0c224c", + "9922d5678af84adeb1c9b479856446ca", + "57ba5706c58a488e80f654980cac67ad", + "5fd13a5303af4f3bbbba993dad35f788", + "57bc95b7347d4cf3a1702f195d734c09", + "d18692ce01d74c368ab953812e3b80d0", + "d14268e2c68d4cf9bfe4e3bbc39e2669", + "ff4b00b7ebb24fdd98fb96b08f2c43c9", + "a0458a0969c8482d95ed22f4c0f1fa4c", + "80425f5e117b481087f04c47f55bfafc", + "cbb8524b46e34a218861f30a3997f954", + "8b5efc48831d464988cae024f4fac021", + "4aae5e1de10f4627a737d3a8a215cef9", + "3f4c5e992fef4eb1bad58e576ce197a6", + "8478b888c45b47e6a6bf2bc96ef2f88c", + "78627050a0e54896b6e37285951de3fc", + "b257c8dba2154bbab0fd1d90ff4f75c0", + "eeccd33aab144e76937c1ebdbc1faa74", + "6763631bfec342c8840675dce2e9302f", + "27bb543b71b94d3db39c19fc45fda67f", + "f92d4353392448e6a736a986f5065cc0", + "50924c09991448f58681103aaee1d830", + "073534d7bb5d4b90a86c44316c0f112d", + "f8785ea8df6b4de9ad47832e323449ac", + "4a2aa976e29948168169f6da77c3deea", + "5cefd413443140f4a9228ccd01c875f0", + "f38f404c2c9c4b6f8bfc0f0356efd353", + "10e171454c1148be96e684fcf3b48d3b", + "3da200cc47a3462b9f866ac864a58499", + "63678f3fcfe1438f9271c85c987572df", + "7314784698a641fea4031ef583f1009e", + "59ded3135bb54c3a942b1b3df0450351", + "ae574613e0b1473682ba99a3270f5e82", + "c743bb0fc5a24a3d9645b4f184cc631b", + "ae67ea1f5d0b41b1aec22b422096f923", + "801b4b81b9374f14987ba09aee7af925", + "20a64a8d4de8469ebfaae417a6d4a187", + "d791109018d9476e9b26420e4c7e7e81", + "827db024440048db838d373aceceb8e5", + "2a3a9eaccf634f4887648cb36864dee9", + "af554072b35a4234a2c13e2d87e39ca0", + "a6e910bc1dc745389ee2473d9a9ac794", + "818b98504d4f48f683a55631444e58da", + "970c2fc52bdd4347875dd48d8cc84ffe", + "db76219d73b14ae3aa168160551fc4ee", + "7ae72d29ede943798623e11231b70109", + "623505ff005947d79fc6417bc7b35264", + "d09f222c97274d7f9789eafc16f6e7c9", + "2adca8fe5c2c46c79f22544446ebc736", + "a125085ee3244e759407882ec1e0e12d", + "af907f4642054686aa5cf9cf2e7e35ca", + "f625cb638048416db055a92ff1681532", + "8e140fbe354f41a88511c50edf165db9", + "f67448936fb34ba6b1d03e5c227805f5", + "5ffa9b9dcb124fcaab91fa8f43753384", + "5c7fa159c094419f9e11178456a2ba79", + "21df7f234e2e4a139e0b06632083c937", + "a176193349884bf6912cca87bc11d955", + "817c6e54217f4277b6711fd5b217a609", + "639b16c18916422db3bacb49edbc996d", + "4cc9c72932854d268551da5ec0c3bf36", + "5996e7a42fb14ca99715906e19fc511b", + "21863a3b3a4243278108dfb325a26b83", + "b8a0fa9ddd234f6695c1a130d8a69b47", + "4a2dbfb86b2545d69e1a10aeb7417fb9", + "a911adbf46d14001954e6b41d4f52ff0", + "c4304814dcc441b4a6ebb5cf99081ffe", + "60099a247f3548edb38c551e88cbd06b", + "46bcd94a813e40e194c2796c7418f0e3", + "481c591c358848939744ae6c3f47ac07", + "34f92922bdbf4275ba5c98fe0ae11e3c", + "bdd8e06d184a4b48852cddc5020ebfb5", + "4f19436380134ceeb370bb0eb0b7a41d", + "ee4ebd57bc32467b8d627336852f18a5", + "6cf73613dc5443e8a013f5f8bb941e6d", + "0cc9580e49a641f59f1997490826ab8b", + "68da6889e31643feb00e9750ea829fd1", + "a648ae2bf2db40e7a88a7cb6526245d6", + "4e88b15b8e494099a754814ba0c10ba2", + "bedf29674a0048a5bb628cf720f6c96e", + "90a7684ae83049fba8b5e79dfa9a6779", + "541c38efcb4a49ad9d59588df6252f09", + "792240a76bb94282b31494fdef52189d", + "e34aebe630df40a98ac41b16c7ab22fc", + "2ffd3c11cacd42bf83a09cd2734c2209", + "c4de39793682473aa808eb5d9798c669", + "c13de9d85f6a4ab2baa15ebc138db0ee", + "23f4d04849ff4e109405b869dcef69f4", + "cd435ed9e944488da735ae01dae98a31", + "659d2e4e1752459b874d63f2a8302aa1", + "7a8838b45e964977aeefd6bd7ca795c3", + "e4894c42af9f489e9a4f18328a44bde6", + "c7c0ffb1943d44ae8fe91387870cd160", + "e4c90c5710bb4062870e64933d86cecd", + "52799b0cd1a44912946baa331958ce3d", + "e0d4217ed43141b082361e9be071e3ad", + "9681d78524fd427daecb14403c320c8c", + "7de4250b31354f80806cd3e88bd5c3a1", + "4655f87dfe2e47aa8ecd3ddc2443c240", + "ba1e726735424b4d88f3e210826b9aaa", + "cee5478c69694ab19b8c785aa80a15c2", + "e34de4c3a89e4c94b240cae7b6c611af", + "c5c2133684f646e9940ddb2ff7f81334", + "429b4599b3374195abdbfeb4e6ea1016", + "7b294e29e59843a1b02172d176e06a61", + "9efd9b435a8d45e7b990b2ab897f7de5", + "7eb397d18e854c21afaf16de860bce66", + "dc0c1995690645a4b7016b1c50636bb4", + "2046dd5b34214b52ac5169bd061eab86", + "096eb5fd9b044b7688a026eb7f6c892b", + "c58df40e5b62490e8d59e8035e4826d2", + "390132330e1c4b07a5beb527298b3573", + "9c67ef3f983547319ea27cd40ec30a48", + "805eaec17fd94af3be9f404d764da6e1", + "b14840d1fe7a42b592807079df691f52", + "e82900b6422f455c9e241dd6c58da5d8", + "a7d16cfb303a4b688545ecd8614beb8b", + "7b5e1b554f9646678ad1e52eb6811452", + "9f3a031f0d6e4d39904014723614ac43", + "2a17bf7d6ef54f5f873e62648aa5c03f", + "5477e8a504374a77b001b943e9b7b4fd", + "11705eaaae174eababc45a53203f59ce", + "356a507a5da348fbb1119b760dae286e", + "fb4caf893f5041e4a68d0562e5fad8e8", + "1cb01af673d144649823d6d4076abe7b", + "8330c89e8431451db3aa9d15c5836ddf", + "5a9603aedba74e1a9b27473179af1a0b", + "112de0a85e7b40d8ac8d60afcbf2e1b7", + "2924224f899b43de93e9fd43c9a0a079", + "4af5836ee55a4cabb7f30c3ce2f6cfef", + "70d2687b6aab40c291d2d453c3f0afb6", + "b7cebcfb4b1c4d4a97e22072800704ca", + "eeefe5b0c3534b96ba6c692e347b94a3", + "ce93654158f14651809b0a9ec6a1ca6a", + "19a1d4c33c094fa2ae7aea81c47db225", + "64fcd02030d14bc39325abdc94413206", + "6c5bdf224a28495bb8de74c45300c43e", + "d2f2bbfe5ba144f8b76b5a24909196f2", + "f6be688c2b3941dfba118f78a76c64ec", + "dc812d0f885f49b39bc583bf12ed9cef", + "400a34584152445bad00530e7e693798", + "b0cf6517af894b59a25ff95aa6e83aa4", + "1ca4e736a7184b628544f07f7d614971", + "f39e820fd1dc47d8ab1b44575dbb3dc1", + "5f5940f6ee524df9b9c27aa59a7f613a", + "648e364f806d45018bdbf2c772452d79", + "7ae04e7f345449cd8dabf6e78ff687e6", + "03e9310faa2c42e2988e5dc6bceea04b", + "0b9a44cb896d4076913e85b3782b81b1", + "cda269eb3c984d03bfd978d61693fed6", + "fad3c78c87454f3296ba6fac46a69dd4", + "ef8346241b284676807af0335a12c405", + "c47502ead1e94b5eaae8447e512cc772", + "d4d0771627574123b10b64f2e77cf9c7", + "f354a051748b4f6db292df1d363e2d07", + "2b33f63aa12d4201900657961b5472ca", + "bb782326932e4c179e34f3d6c8e36b86", + "9d451987abb749038e073ecf94f5536c", + "afc93c1289d74c80bef1b7d78ef1d412", + "be46b9d8a13445ecba889449b4c5003d", + "21f6dccee186475d962a31e2bef9a072", + "b857c8e816c7486d9f7ffaf9d6665350", + "72d915ef196444f1b68c911a71970f51", + "27abe84ed89345f39b529f09757c4de8", + "5dcf9300148243b1b95f3d1c3769f307", + "aa064f3c81904774bbb4ff1bc56e2d18", + "e4f5d474029943818f536718d80d81ea", + "9540b760aea545c8a5595816a9e32e5c", + "ab86d68dbed74f21a1adf85855650640", + "d975ecff85c54f6cb6c6a01787bed3a8", + "4400d37f005c4dc098106a4e4a3531b8", + "99291913acaf419d8067183b5a7296ad", + "e9a5e78e1afa4af092d9a4829a8db768", + "134d50c115c843b6867b15bb5def3f1b", + "09751dc6d60c4e0680b4942e9ac4fd36", + "f2d84c0f31fe42fe9aa2054ef3e9aea2", + "957352b3c37c45d7b95392d40235032f", + "5cf17083bf0a4baa978e20a7e8197a0c", + "a17145104f5e4492b48c8dfd2c23677a", + "056ccf898f9e49acb6e3e370deabf184", + "4ffdb3a3d02f4af5b3da91d897a196f6", + "ceadf967d10346be9cfc37e8adf8ec74", + "0f90e7ca30284e83904f8c11826efdd9", + "72420e3bcb174abea9f744b0415b7acf", + "3e0ce2a765b24ccaad8d780d84db9170", + "c1b832e8778a4ff695e51b7caa8a1649", + "c5d2ebbd65d946bda1211945aed5888d", + "2ce6e525975344a58485e8d8e192844e", + "cd14b616da35470eae6894259697314c", + "b7c151cee3494ae39068c1c103549d34", + "2e89c2ab489d4fe3a308084bbe3f8a00", + "0284db5b1b22483ab21433c5716e6fd7", + "5ca607a931514e2a9d2c2e8d7da30b02", + "3e45a58781694b709e3f3466f1ed30b2", + "f23c612a59d24a5c967ce62a9d0b1984", + "27d5994e30994a6c95e6cf53305d7a09", + "5fdf4a70414d48e3b2803b8784a216a3", + "ae0529d9da834820b8a9c30ec0b6228f", + "ea58ab864fc342c1866ed9ff36ad6fab", + "7d43e0c0d060427094d7b193007d558f", + "a2fbe74abffa450aa9fec1f807b80904", + "f9fe6b0c9e8d4fbdb281dd991f05fa34", + "eb3d6519fc6644d0bb660cbc218c61c5", + "8c18d26983f2457b9377ebbe66a4c8aa", + "38aedc02c0b2412babdc4d0eac7c6803", + "cd2b0592bb85402fb9c85d1d1779471c", + "86d43d0769744894bdcf946f14f91bd1", + "778331cd602140e7867eb2667d8680b2", + "e2102cea794741308c99cddfa2773d98", + "640c89d8bd9a43839fc9b696bd3c85e1", + "c6060cbaf7a84c3982072a618d18ed0b", + "57da23761da74217b80f4d8c62d18f6d", + "6bd564e520994c568488a685750d67f0", + "e843fbcdd9f746e2bca65e54f02a1845", + "82854a0ae19643e3ad01f79e59e67568", + "64d111cec3d842f09cbb8c68b1e49c8d", + "3ec4459f787d4872b263496118c9a9e0", + "14e69be7554e4f74a14086ad06250c3b", + "ccba4426eeb34603a1de87c1ffcdd878", + "eddb6dd1c0c34a68a1452a0cc8446bc1", + "b5752003aaa14c7789cbaa744097d0c1", + "00a66884dacb498b85701acd1cc77c5e", + "a6ce8ae18a914d9cb1771108a58c2604", + "ef1415d1de9f4008bda5631241808c35", + "835b5198d5084b6cb2c8a11e322ca58a", + "c11597fe4a2c4b41961b672c2827c7d7", + "71bdcc279269441d85914e38d1c72d81", + "84edea6b691346ad994e21c374782ea6", + "a9deaf6a7bf94ad083f4d5cec02b4e0a", + "a37e20eb85564e9ba21d0569198b20c8", + "03e706cd42504955b08379f45633c9ef", + "7961ab35937046e69b6820a018b03118", + "f59740ce79c94107b77dedfc2e870256", + "02d482391a374f34b3dbc6b2bf19762e", + "31df1da7f21748d1836186724833b189", + "1ec46122b8e745639df767581598e1f8", + "cc9ef646d4bc4896aef52bae07e8b544", + "2df97bfe17f14cfe985053582cd67e81", + "f8f16346224045b6914b83e02c35e0ae", + "10bad7ff4c4347a0a96e378865f87f06", + "91902bf766224adaab7884b6136f75f4", + "14f036886e984c6cb8942f7a86e2a96b", + "a8d00d5e6f6f4703ae41fd146025cd2c", + "29415280edd646c58a58af50dad35e86", + "289cf2bd644b4480b9a57e7bd2e89cbb", + "3378aace9c7242d995af734294f73275", + "3ea32be2d0324a5ca831f2b60e4f8bc5", + "1e7f6a00a82f4c9483ff4a8fa8d3ad0b", + "32d5faef157f488fb146f46ec4a7ffab", + "e7f2c9ada1304c26a2909b4d4afe5412", + "19cf952615cf48e48ed5d2128eb8b23a", + "8926486211e84e7299fba16e4fbfd576", + "2d363470ff624bde95e989aadc734245", + "9265338621b4427fb34b741651f9cbd7", + "4bc60007e59a476fb01141f72bbfc825", + "3ef73be9f51d441c94fcde09e8e654d7", + "2a4d893071294f82929399f1fd156fd8", + "d9c9d8f795334aefab4442e380d20d5c", + "29d1efaa456d457aa505759242a96f24", + "86c65d515bdd41339e321a6bea424bf9", + "0e676ec8467e4e40b5f9163fee85c31c", + "fc05b694350d40b5b3c16af37561d24c", + "c5fddda6865f4f3ba840c714e6849251", + "fc086ac59a5e41aaab32a0cb460e3bf2", + "a991699c4a6f4d969af4eb46d9296957", + "c9cbabdbf1d548c49309b0c6cc2f255c", + "45ebbd70612c46a3a0abe7418f10a229", + "2f4ee4fc911c4671b565a6d0b99abc65", + "d5d96ae5d0cc4c7cb83c2a2c35a2092e", + "495e9fa32a9f46948a2dd87845fe4835", + "312a5543798d4daab7a854d64d5d0808", + "51b880c976b34f47a4e0e0c122b6d000", + "03eb535e459446aa8ee4c0022a248db9", + "d2f06b781b3d44b9b49fd1f88236386b", + "51149a8e7ea045fdbe6aeedbf812a9c0", + "41f06d5b8d004fcfa7d214117398e6dd", + "ab2d7dbc79f14a3f992517cd9f189f7a", + "c1264fc4cfed4f80809646ec39f76d20", + "80cdf4d7d9ed4df3b5d9458357b89000", + "da7084026e5246148ed054037a6a3b71", + "16dbce6f08404f4d8b2ceea9eeb689ce", + "7bff0c19ceba4a809adaa799b323c97a", + "eb2de2f0434c44c9bcaa9ddd76bb8acb", + "280f03acf3c447d184f8ff8116c0ccd1", + "aa2a7dfe0a304a5da0614b96319a9159", + "1f2d69d1011f46fc92ac365f46ab258d", + "dbf3b267136c42f780416c0f2494a8b7", + "6ab617cfe1aa4a86858863680346f53c", + "2df864207ad248589dcaa149e445d7d8", + "8666cd97a46d436d838479905165be60", + "beea3a539f144690be327a5e233df509", + "d25c31c0d4654606bbba59bf142f7417", + "4ddfe24465c24769af01e5971e82d509", + "c46b8a42615b4a3ea4e0343ef68b0f23", + "9c10ce62bfac419290f5ab20c070c503", + "6267771326ec418f892411c4f58a92e7", + "eb052bb7c5ee4cffba520b19b3d3c784", + "dde01fa566a14702a59deb92c844d7d9", + "0a7b8a27d72240a0ac2a60accc4ce81e", + "b38c033de44f4950becc69aa0035af91", + "3e42a60bca5d4a38937b12f8a5e6c1ec", + "fdebb507cacf45caa67ba468c8a041c3", + "2709ee3458884f8ea5d50630df12323b", + "ea1fdc05acc84e02b5030283f2a8bc23", + "08eb01e7379444f9960bd5512f3f3324", + "45fa663b17df4aa8a90a52962fb2b0be", + "852a67421cae461d9c66ab45c60297e8", + "c3b08e6c355544808c8f34de3a4bfe35", + "8f51f42c5cc54931b073dccaa9015f3a", + "baddb68ba030434fbaa162e56f11edf3", + "a60e263c563f482093c4b1deafe86b30", + "ef0a922f1754439dab154d33d18b034f", + "3bf37ebf060448c8992550c0c76b23dd", + "e493838af1d64800bc2008c231925f11", + "9fef8726e49247c598e623dd14c2769b", + "f354289583da458eac29609b86d51b46", + "78c769436f6f49e9b4d906bb79d4aebc", + "88a0984ac20b414daf8d1fceec1f0baa", + "7dcf441ad32943278ac838e0018bd573", + "a4bb5d311a494c7888caa74b9286be7e", + "9a511d27d3e146189cf85535d010c145", + "5df38e1b440d402b910fc5a986108ac9", + "683c3c8f598342989fe93093475e7310", + "3fd283d224f94b55b4d4f8331d79e329", + "d08e7fdbe549402b8fe08ede21f9aadf", + "ab8f80b8ffd04e21801bde322a7efc75", + "591fa396a54f4941bf50b451b99a6de4", + "6e790164235d44a58f76f17ef9bcd5cc", + "e3968f4233244d818c67a0205ec9567c", + "c33a102b4efc47ca98b31e56506fc564", + "5b32d39eef874ecaa0aeca5f186ebdae", + "952a1373fdcd47aa9d4b2ba6f4abf42d", + "577bf5d9510e4f9b937414543d05c675", + "2005fc546e224c9aa283a496a175b806", + "9895cc5f6efc4af8a9f6bcf1ec76e88f", + "46e4cc034efa4e56b1a262b7d507db8f", + "ddb9d814a39e4bab8b9ca0c3675564b2", + "a27aa928a6664473a0ebfbe2c7f72b23", + "d225389de8c24d1c9cf7102c740eccf9", + "92713f04988a4bada3b72b7db87fe058", + "c22bd73cf8d247b8b8e4ed6fe23d52f6", + "82e23306fe2c40e098e7d0fd2a097494", + "806d76af60dc45c1a45bd0eef3a17531", + "eab682dd4a834a2d8c318cbcfa65cb36", + "c0beaf97cf1d4f8b819ee3a061fcf65e", + "32237ac2c8204d13b741b43409bb5cd3", + "b00e1f89f7734820b0cd4b146eade1b5", + "b0642bac7aea4d4b9def4bd4ff7fa7c6", + "62d51fd078d846ed9c9c0158b71fc94f", + "11663c8b7efe4fdabe76e42c5db4ea78", + "3173e9d9ec9e4bd184bf59686d08c373", + "c340838bd38c4c9aab9010c36fc4fccc", + "2a5c5d81f1f54b6692bd04560f34ff11", + "e3b4e0d9e3864fb584adbacb7a8adeb2", + "46351dbd59384d30af52d8249b90650c", + "d81fb3c8790d42b3b14463814568d771", + "c377223198eb40048e14610e71bab3fb", + "7826fd32098346e6b4534bd20b8a3011", + "b83fe8684f3a480dbdc35fa9f2e7bef6", + "2dfa849756dc45f2bf6c6b2d8100905a", + "16263758dbd04da9a03ea27bcf2b0333", + "060f77b5d50b4a1d88da928d38b1d2e9", + "0c1cbd5cbadf4d0a9ae02f98a68b453b", + "21d30beafdd14c7aaedab5047f0707f6", + "0316f2811433420a8315a6a2d19cab93", + "04b69c34c46a4c69834144ed33804180", + "d9d9420f36194d35af1f866d9724848c", + "15625b34fe114d3faa31dee3636a1349", + "c48b9fb0530f4e11b0bb0352752afb46", + "32ea63905dac448dbc3378062da95641", + "ca9f04807f47442fab1e6e53279d7193", + "fbbb42068b4649139099e213db039531", + "0a222fb933e14f92b14f872d08200cea", + "0436298b8892486ca5392603bed14fd0", + "5c315b8dc48e4ac4b4f7775309240080", + "cfe7657f86c84b2496dd60cf9e8bf4a6", + "0963ab8654b24dec8130202f877a6408", + "c19aec34d1bf44c2b390be568d114448", + "b463d72bf3a84d45ab15243656023d84", + "cea266722325474984c2205a88c6fd52", + "ea0e67f95b7948328bfeb353245977c7", + "c2dba135bab4451486b099a9bff1bab6", + "a262cda9af1449839ecf002265969d7d", + "05485469a7a840c1b91aa1b213e658ae", + "b2a3c997ad114902ba02f74b375cba6c", + "8bd6af15b49f4abc8f539c1ca4efeb2d", + "592e4f6fb38944aaaaeba40c94815e11", + "30c2f124d66d480f9171db3bdf684dd5", + "c3634c8e985b412abcdfddb85c5fc8c8", + "7769f93273b349c7b4f0cb1f420cc502", + "895f4288ed8d413991db239dbce3199e", + "a77c38a190204ace877fc62b77f466e1", + "00820ef5fe4843cf8beef97281048215", + "7ac053d6bcf94ca5a6a6b93058aeb21b", + "389e6b62c5fe45b8ab883a1acfdebd59", + "c738fe19a60b43de982dcf29b6574245", + "cd471b55a205468ba87a2e8494a99746", + "54adeeca54d44de688b94dc948f6c3a6", + "5e5d2fb1c8ee47f49cf7019bd1ea4b73", + "2acbd60101f4499d83ad5b708651702a", + "8833074e5ee44923b0457fecf1cc4a7c", + "65c61cd8b9be4d7eb66c201833cb7765", + "3d10d36fcf8d4baaa30d00be23106115", + "f83790d0f6cb4060aed165bdcbb2f42c", + "fa243c31611547a38c07b54339d70716", + "0e70c34b4d984442ae39ee20e56bb31b", + "787eee9d47f0440ba9491b9e9ed14606", + "4873988f0e79415a86f6a392fc25d270", + "d9354ccfb0e3424392c81a83dba36655", + "0a5fb5f1cab44726bdfea1ce928e6198", + "7b3305e3369c4b5ba004d5747cce233b", + "e2c2e1a04f35427c9225745080282a97", + "260d3873be1542038715b0c048fa4dda", + "4b4340648ad5446e961e1907b952c044", + "ac59c8b27da84f34b91f47187d819601", + "9454ca47b3014acabdc5c930681715ad", + "d578d3c03b2243fea0f1ea72f7fbdb31", + "55c0a624d211469b849d44a59a691f57", + "5b9f9de219384b3e9edf190789128987", + "67dd8d1991b541ee9bb46880663cf6a2", + "f21a2fe135c14509a7a50ca98b50fc84", + "28398dd72f6f442aa2280bf4db65f977", + "0ddc5b75bc3941fe8822e79aa3244ab1", + "94fbf6f8452d4c8aaa082409976cc4fe", + "ad28dc69173140a7b39e6c64cf403f57", + "50f098a9a8a34549a81bbfd0e8ecb649", + "384b524481694c43a1e02c453e0554d9", + "586396cf11524c919cf2ccde694ad954", + "edfa32a261664f88babd91433d25e5cd", + "c5f1f57882fe47d89b701072c5d18a99", + "25290cec69eb4154b7c831f76a5c022e", + "ed30ac4045a14086bac01316768b3dc8", + "91dad749d692446aaf712b725d8a99a2", + "355a1580d4414f0c84d72d7634a24af9", + "aa96f905533044bb97ca639444c44597", + "e1386f645db7462a81d6bbee89607642", + "f342f50a8eda4e6fafcdb4f057be5792", + "a31932ebf678494e88184778e8b2ab6c", + "85b1168249c14be2bcad61edd3e9bcae", + "641ccf55ae80479691f2a8f01f97819c", + "00c5e142e41740a18d4356259862709f", + "78c2e8cba66e4f5294cec5aa05c9d431", + "585ea93403494ec4b68e00406586acd8", + "c17c934df3a246f0905ae3138ceface9", + "800d3b0870e244b59495b835f464ff9d", + "7239efeec7104dc3af46a8842a66aec0", + "cd113bc83baa479ab96cd83c304bfc08", + "7c91bd719e594fcc930f3646db843265", + "ff329251af9c47b9b6d8c5953a53323a", + "1b5328db81514a3b8813b465110de208", + "a24bcb6b7a2e448fad661004f403ae12", + "6b710bbca0a04afd888804d476d060ac", + "5f7143f9e92147ba88c8d524d9244492", + "5e7e82221f674b09b649b0a890fe3803", + "8c8cafaed9c04403b40982abb81dbe04", + "7a7f4482763e457ab626db7f9981f4ff", + "e37e1c8174c34befb40ecaa729f8687a", + "1675cc74e29f49379771a1799d1bb313", + "ff839dd419bb4770be14549124267583", + "b4fc5f9e411c486394ac30c1843b5c6b", + "0eba111d0ca54af19771a164ee1b54b8", + "4327de211c5f4c82b65726a3df787578", + "259e5c2c3ff14da186a84d386a00edb6", + "b1e63005e953469eba9c39263e3edc07", + "a6e9e670115c467c8899414c60f05d85", + "c50e844108c04a45814303e8e7be3bf3", + "1410096bb2304973809b99d0e1fef220", + "96de257a4c7d4721a6428580b2ce145a", + "5325402eeba44000a1bc9d34a9b043b2", + "a3cc4c845ea44e21873e6d5345a8d531", + "e2f33ed05ca848aa8f09908af7f1dfd9", + "f6988feef75e42b7acf028cb310407c3", + "35556c78b053496f87b4d4e3cb923369", + "d4fd76d0790845eab54dc5bdbebc47be", + "15ef730c856c4ccca5e0c59fe69beffa", + "c3af7308a0a94b4cb912ebb3bde8ad2e", + "3452d8b95bdf4d1ea890534e1f82d8ea", + "ddd382fba03b4732968dc43256a69201", + "b81c7c7e6a624976b10a9be1a7913e4d", + "9c680c88b95e433e97cbfe3b37b4a3b1", + "691d0e4cb6a1409ea72d960d0ab144ea", + "f515990222cf4951b5c6b458ef5197f3", + "75bd1fda860846c49101e0cc236e2c2b", + "b83d576ba9f848ebac79e2edd6213233", + "8f04c4894cbb47e290e53f6c77b6e2a3", + "53abef84940f4e1ea8bfef4c4e2b04e2", + "ef7be8efe82947c29290a18ef94a8c35", + "0742747082804e1bb1ae49f44c5d6eb6", + "ad071f3fa42c44b1a239bfb80d36003c", + "2ad4d1839bb74c81b12b242b3ef34428", + "61e185ae00b640258071c581ab40f749", + "6b6b25bd629a4ae48ea20018900f9b56", + "13b73d286d1d4db785cb56c7d472d6ed", + "e82aa19a3f8d429eb351f00742da9bc2", + "e0f0f391790947f593a36fe735426d8a", + "a1bfcae534604c2588dcb49c9598f979", + "62de642b5cb640beb769d9f328371ae8", + "6f24a17465f741ddaa14d066f0c31eee", + "b7db270375934222bde922aad753c890", + "16cbda059dd34718a63d029f50333515", + "8cb702a0f818483690c6c73093fdff66", + "2085d2824e5c42129554681a8de4140f", + "9c617106f68f4e00862bce68531d36c2", + "f1f96738c0924534ace9903ee998aaa0", + "5d535677b79b47feac2f1b1e49b9ffe9", + "8ef4af2e4d8b42b498a2cf6f3a843dcc", + "6f71a325143344a4bf0751be5d703444", + "494397e3d7c9444e8f86440b4c00fa0d", + "452a0ba229d04c07aff64a4b5ebfdcb0", + "baab8a1f43ec43c0a0769e636755d217", + "71e7aa497fc84f638851767a3aacad8e", + "e8d121d8a25c4e469ae4e6b0db66bbb5", + "9e10330ddb3d4527934d54cc7b716a10", + "3b755e02a4454f9bbc66d1534db75ae8", + "26db2460912543e8aef9b086cac00fc3", + "ca9bb8c8ffc640c6a9be8ad5f341c9c4", + "ca0f242a4e21499bad2dd7974e6204a8", + "e0c17496b76849f7ad50e4a90fc64756", + "a283f9709cdf425e8f0fbb0098252418", + "94b760a27658487dad23f2ed53c66951", + "e6c4858d34f0440394c2aa772ebaca38", + "c635ad4172c14cd1801a29bd81c2fd3b", + "869a6646b2164e9c9bcab048a714a789", + "9ee586f16cda46669156b252a67ddba4", + "e321a9439efc4a3c845d296e589f5be5", + "e0578b70b5d748f286757ca785522430", + "e08bb2e734004870b1ed4c21f111a854", + "b28776c4f88b410a971f118b6ad07e32", + "903558c9098943aa87124283ce93f393", + "4e80bce5dc42498c8b8e0ec5c9a987f2", + "7fb4298d5d8f4185b25bb2c43d7f3787", + "ca6ca83b83aa4d9d8d55834fa3cc9c8d", + "88d82ddc607344ce8fcdbd3a1dc3d6b5", + "264238d81649461a9159c1f112192fd3", + "93d7c9a0f0ba45eeb16897931d636720", + "ae3181c81cf34876b187b353291a2f96", + "ccd7a316ce2b47f99023d677a99ef681", + "2d7d267a686b4ddc9432b10463cec1d3", + "03a05076e4fb4d00a17ae2a31380a8d7", + "c1f5ab1afd5b4eab916692e1e7dbe3d7", + "39551948552d438499e8694b7d3691c5", + "ca673585e3df4dbcb3bf95261a8af647", + "6b0c4b3ca0554d02810cddc400e26f1a", + "926d42895ef940eab9f1dce84d96fa39", + "7d8bf4eee041473e806e7b41ea7d2de5", + "e3a23127e0ed466196517b7733d6978d", + "2bd638a4490b4b3aa0de3e82a61df70b", + "c9c679d465a84738b0380aab8716fe6b", + "9b5220a1ba104999832c11dfcf3fa01c", + "2b07765da4be4fae8862e71efc77ef3a", + "a2b2ef140ae34b74a5b7d6d7bfd1c236", + "8b2f400d48aa41ebb1e7398f19af8b42", + "1519d1c0999940e1a51cb10a71348f83", + "f91b2a2f182245ae8cd8914569ad499d", + "02bf18c597f9421fa43127c11cc5fb97", + "26528a95949a417892b0b7bfdbd51b3f", + "78d6a35f0ecf4cf69ae9271f28f5f137", + "832456c04391432b80bdd0a780de1f71", + "d0190dfc1a91459e82388fdeb6633191", + "778e3d26cc8b4de18135ae8fc48206fa", + "2be1f3c8a0e54150bb61a438940b6921", + "e158ee130ac54392b4be7c09fb7557de", + "d2153a9ed0d64c15911db2f53f1772bc", + "d683f90628944d81a017c58952414f96", + "218a1626f9dd491c8814b4011bb8077a", + "3a99690fc35a47c0b275b1254b921997", + "cfeff228086c4beeb46d3b900ae2f78a", + "55441980b3ae44ec817167ec3871d35e", + "6c4ad3bf062b4905950a410f503a8d92", + "0a64625d5ba04833a4d9da63efb6c6ee", + "53a6e6817c2c4c2b92b66783d48af4aa", + "776c21864f8341de9ee7454aa5b220fe", + "120c6077533d493793d99e736a26db06", + "53a53517635f494185eb19264f1b19b0", + "fb0111a1d4b64066bf3d59f38ff815ff", + "f7f8920be569488280d6403acaa82511", + "2b7d5c96159c42589dd970d81e877668", + "36c6ec20279946ff9432d5d1cc456206", + "0d950a42cfe04dc6bf7e94d6a5144d38", + "274d4da5d54e427d966ea81fc2a69b03", + "ba0b911fe0e0463992ba5cdcc90f1fb9", + "575cad5c36714af2927faac37c6e8e4d", + "9ee0d2b706544e8eb9504b1818049760", + "e65692b390a445ed9499b4402c35f3e2", + "e16617aad7e0489a973cfc6bd896d0c5", + "d0c428c2e18d4680aaa34d8ebb1cc055", + "dee17c12fc5e4462ba48b9aaf76932f9", + "668f8f1a408845fbbee93abbbec9abd7", + "aa1aa9b931634e1f9086e6715676a242", + "1af024a1f0f94d1d855abe03fbef7125", + "f47fc9da2afd47a38186424be583c0df", + "ff088b54a51743a69579d331841f04d3", + "1871970a007c414b92d4e77c1d38ea7b", + "655444d3fcdc4eef9cfc993daeb4fa37", + "6be8f9bde1bd4977b07c6440e4a5c51c", + "d6aa292677f94890bf05dd7ba1259049", + "27cff3716bf84fedadd282b23c64a092", + "aeb581e782194e70bc3c97123c7e9078", + "fdcf9d47997048da826ffaf7d84024b4", + "09ec320d583a49b18dd657b89b774238", + "6f238f3e810c4a90acffc93b08f55d6a", + "327e3a5f569f4775b271aca0cb117846", + "48f47dbd9469443d840af6db926d1da6", + "cbaea52a561a485985187467cc4cebba", + "c748c558e843426fa8cb6e8a11d85bfc", + "e6cd6cdd1d1143d2b0379742e1be49f0", + "4e00d9d910ec4bfca10527e3c3fb9b73", + "84c6db3662f948848619613c146a707f", + "75904a4969884448952e9e01047bdb65", + "07a45c5d00664738a5dabe6bd5b85928", + "3661b71f9494405da64f0dbdcc1a4ae9", + "0098788193894ab49ed9ca8dc38dbd2e", + "c0677ca12fa149c180df495a12eae0df", + "959c282f25714baa8d6c16d810aee199", + "345e3b564cda42b5ad88ba7860de0219", + "2a5bc8245cd048e78efec5f1838f08e3", + "1adc97c8421c4f6da647c77362796327", + "c2e96dd0962240d2ab81d0b02d698216", + "c4b0cb4c231641a3a4c396fdf592b9fe", + "519e7994b912402cba806825e844ca07", + "272c283e7e2d48e898d2eb5a8e43815c", + "da0ae24a2f2943c298f8c020ca501e3a", + "fc05a8aa264b4905ab032f4860b2af27", + "8a36fcb9485d4071b43415b595bd6c9d", + "f1a84b2cb8aa4904931b502f8e26a6c6", + "7e96c47b5bdc439b9c1c5a20be62e9c8", + "1f6ee73edf1b4dbe9ceb40daae3951fc", + "ef6e151655ad4d64bb55aeedbff17b63", + "72208a74546e4e3590bd2acf43dc330a", + "56717487f363489da344ff8079a26317", + "9bcb6f80754840d59dc92d7f9bd7e171", + "f1852103f68944b680ade1592ea50c1c", + "a2d1c4647c764bb18575b1b24452053b", + "84d37f86089d46148bd23a87d1c99488", + "5eb868652fdc4531990e9e5454e00d89", + "16930ec31f5342a08e1233eaae01b2c9", + "35cf2964b5334e4db53649084137d477", + "08cf90e320c444358867af5bc5f91fcf", + "ee404b76ff34479982385a08441bacaf", + "798f80b7c857482e8e97d6748032c362", + "1d46da5bc8ab4d21b55d479410bc748c", + "58e9152b3fee42f0a0e130a1327aba2d", + "3e995809ef6b4f0a9bfbc89f84566c67", + "e3bc33b7ec3e44a98085180832ed2cc3", + "cbbf9ea2a51940b098a3c8a367213b30", + "d859eb1b182d46dbad4e1cdefd8255b4", + "a2d039df6dd247d08d56d52db13bc2d8", + "32659191a62b4641a10c8fc591e8e949", + "cd97e1e0d9e347afa9ee4f88fab19650", + "8bd39f148aab472397a68930839a9aac", + "abd291070e0b48be84be070d3c460c8b", + "bebf423c0eae4e16ae1dad71e268a298", + "dc443b7a878f47e68c4d446ab691d0cd", + "02ff6520d3d3480a834db1a5da124150", + "2353c11119674786955adfda7368df62", + "3d2cb344a1794efabca9e196fd1dc428", + "ef5656ef5bae476b9d293b2b54d544dc", + "c5ee84d7f319449b9dba1495d701df11", + "d746c8d359204de2a8d0c991cee677c6", + "12e13653d75a4f8ea91db08d2cfc8630", + "5798e024a3eb44b3beec875d8439c752", + "3a4df884aff945eaa44e31d1b3a16f7f", + "6014d7d241fd489d93003500709f3e5f", + "d995ebacdc304433b39cc9a1b9e2b13b", + "70111539882d4f60bed3de53d307fce7", + "540db7d882cb4d7aba339cb79b33c8e7", + "96eff6462d1e430b9d162afb145d2473", + "d57286112de04584b02284724d670f1d", + "dde1c48231de41eb83a60c11aea01deb", + "6da221933be543948c894ba53108e624", + "2abf2ca0bd10437db2e4fc8d08dc8368", + "82b453658227429aa8eeee6ba5e0df0a", + "b9579ca17c274a48a1e083da0e909865", + "3cd35c64e8c546c5bcaba7bee49cbc81", + "08365bf9119445a2a104833bad68a951", + "cc46444d28304d98aeb8f2fa2693d177", + "0c0f21264142495fba769234e52a2f71", + "db8205cf79174b10a56cb7f567c6a1f2", + "5aacdd08e4f649dba15402e546c41614", + "068f17e7bcf74d04bacf5524c4a2079d", + "2f495e17db5e4bc090a4e5c0ac7a5966", + "4ac2667fd2b54248b400d5f092d3636c", + "a61eb8e73dd641f98a34b720850c1055", + "d794569290fc4f0d98e577f9d5ae77df", + "7a18d091b906475a9d36ad199382d4d8", + "eaf9910ab1e14d498c7d224932fd76bb", + "9607844ef89f4933ac934dba62ccd3ca", + "60afac65b571470e841856afbfa4d0a6", + "35408acb34b74ca1a4fd23d2e6df2f47", + "4ad47c6172c84ca88da0b0ded8f99429", + "eb017be06cca4ab3bb7008b7164063e9", + "227dced38b1e427bb2bc70bd85050047", + "5a8a799f379943839eb00ab334e55989", + "4eac596f106342b8816afae4a79400bc", + "6b45bb61de71488da8e6bae472b967ac", + "45a86fd4b50c4228b5863709266246e5", + "da134b636d36485ebe87b284f5f87b35", + "17f1c71fbd7740e4903a5aa1f0e86f4f", + "e43342607d4e49c8b33ff1ec03248bcb", + "168e2ff924404046a14b39eadd4ef051", + "2fa004a79e9c4ebdafd0268d47e36052", + "4a37f0744b7043c0b52253d9cba02fbc", + "799d4fb2489e4386b0d5254cae3cb704", + "c6faebd33dda465db7a0419422266705", + "3175d88bd6b6480ea54378a9085b7a67", + "e65533fa0a004c3ba960c47af78dee4d", + "e073bcbab25b4849bcd9985fea14c3c6", + "6bfc709351b94a69a876d885a4cffde6", + "a530bbe03c5c4a3ab6fce31481a6a4ea", + "8707652737a64161878d83eeed10e554", + "e347f682bfd54b3c84511d01a5e5b71a", + "98dbd0aa2f734bd68246025e74463097", + "61b02d725b5c4f049cd1bdc0d7b9c8dd", + "4865bc2c03624864b779e61a685625b3", + "a4d4ef2f17c843828cf24d538a9edbd3", + "38aeb725fb0b40d1b1fd5af2a21e0c31", + "29ed8275e7c24d158faf7c751baaa9c0", + "a4ac2f193e164487b30a2b8042e7336c", + "971452d0652c4fb984bb92151d0c4307", + "c3b30fc4e1c741ab936d8ab74f8b686b", + "f7186597c70646e484ec53a78fc59894", + "a1307b345b81407aa0654b72d2a4d196", + "4cfb8a1570404234b8044ed9eeff71ed", + "c128afdbd8174a3f9be2df3ffa071185", + "96559e5e447e4873bd862e8207e66dea", + "a01d9f81e26749aabd7bdca3726236f5", + "b97c9e994c074cba83d0c00814f59dd4", + "918bad4d31ab45d695c3bf08621f4ccc", + "c2b702005d45416daa29d42510d9365e", + "fdf3de6ae225421ea78961b897b9608a", + "9816819af90e4f28a7ba853d48516bcb", + "90e5d7e4fbc8487fb5ae17e21818ad82", + "f1eca81dbba4459e8de2d80575f53191", + "68714ad096cc4d5b8a305a33374cf81b", + "ad8019e436ad4d3b89e4042461c6b6c0", + "aefebe80487042a8811040e71ed91599", + "06d370001f6a42b985e84795905425fb", + "af57fbf7fbf44b159fc790060fd16a16", + "fe701b8dac9f4f048897efc30ba83c9c", + "34b4146f71d64617a97d3bbdb8a7682f", + "bec20f3649c74cfcaa5a6fdddd7dea80", + "43b3aa28587f49d8b320d27ef9cd2f6c", + "3164d92d88454f48b244182ef198fe97", + "daac2cf0dd914b9da81be71296a792d8", + "f3192b5891b74770a09ee628fc4f240b", + "a2bbee932e12446caf1a65e06e271907", + "808576397a6143f695e84fa32194066f", + "afe4c17b12e84f8190e142db758f2311", + "1a53231bee5d44f58cc2c33b76ade1d5", + "c5e3db928b984f7586d6acad70976596", + "ca30c85074dd4dd38bcdb447f1643a8a", + "43a5b7247f484595b496c8bf1c56fa75", + "a79c9239487b4bb99bf6b8f8f85ca162", + "b0655ed242bf4e47842936543fc1594b", + "8d6cbd2cd497460d8e7a94209c3ea582", + "caf7db0414454cf4adf7e8598f4954e4", + "2e90df082cfa4728b5aa8330cefd9812", + "bbe54447c7074b9bb32645c68fee01b7", + "a9ca7f7f96684dc3b7c09cd5bdea5f84", + "80bcd0dc25c04c8a94383e0dfc49fdcc", + "6dcfe567b48e4c9e8f6c78529f7930b2", + "21c2ba98da75467fa1957baa01b27300", + "6be02784e3bd46379091bd0369d16e79", + "28af38de4d2c401d809148c7f63a73f9", + "ec3694ba07cb48c98ec749d40e6999cd", + "9eb8bde2b59f443d8454eb4f17543489", + "ae6a2752a2c14ecfbbef1914b6c00205", + "e46b661ab1744b03b9f89d38d186d5d9", + "6fbab432c8d74eeb82031d91412e9805", + "04d8e009a64347509704072987319440", + "0e381145b0984aae96e110815286da60", + "4c02a1bd51af4d5ca992a2a45b04eb70", + "e3bcc5dc38484eb2b54abab279fa1855", + "412544b36a81481c879b0420c513da6c", + "834b6b22df6e4925a94b2517201fe702", + "fcefa84aafdb431bba07d92efabec5e1", + "bfa9f09680b74465868ae4df72541a57", + "2651a32fb4dc441dab773b8b534b851f", + "1a10ecd4e72746109ee29a8631ea4d70", + "4a6f167707d14c9d9c10f994c05d23d3", + "9b3d5631d1e844ddaf2ab3f388b5d4c0", + "929b54a0fbbe400f9ad0075205a014d7", + "7ab7e609af67482e8c61c5f2410a20a3", + "337c9704139e4e0e95429cc7761a3dc7", + "fb10650ba5084516b4bb2e32bf0096f1", + "861fa7576ad74ac78ed7798bafcf6c1a", + "70c51e0167be4af9a6d5bc268b149f5b", + "6fce663938a24cb99d19dd28f946ecc5", + "9bce6e3391bb485e90c671cbb6e7c52d", + "fd3417f969ca4256bfdb1125f32b9daf", + "12079c398b3a4e8db2d1f9a4da6b29d4", + "a181b6f26ca74ea18ad260698f5c6eeb", + "5d1ea0ec43a14ec9a38e3a1572b1626c", + "1bd73c9a74d14ce29e45c277570990e6", + "0d2826e456a84c798f61f625b1ad30fc", + "182cc7092d17474e8cc791aef04a8fb3", + "c9ba4062c51b4aac929a9d0f3c2cb5f5", + "b310ba69fed942179eef02e27c1313a7", + "ab501450fc254917b497ee719b0bde66", + "2b59fc6a3c1a4c12a7b720202ffb5ca7", + "e7a03de4e430450697f06884e40b927c", + "79d222cb22b244858d0e5694d19bf640", + "fb882b00bd864d0abb808635650cc59d", + "cc1a672c8c9447feb386c203f8396f27", + "6d1e6f511aac48c286c83d5004dd9e93", + "0ecae4d93e5a4de297b62f9fcb7a127b", + "5eabc8a4e16a43a7a5ae37d0b0548354", + "62ae011828394965bd85c199a629c313", + "989dd76b37aa40c38a57cf6159e72a55", + "80aa5db40c7e405ead5c3677737b69b7", + "5569d97509f248d4b587f1bee3dc20aa", + "35b52fb518b84af98361a5b44f767bca", + "b4eb973dfc4e4deabe48dbcc944627a3", + "e1eac1e5e67544dcbc7775b5d7407e19", + "a00a50ecb26842b29c445d071ecc672e", + "b034b74cd7884b418fb7395b01c5a394", + "18ad3d69c1d34fc38533f7bfb2b33a19", + "c306e6d3f168490a8c9078345880540c", + "c53f8ed9ebac4444bccc3b2435e9f13a", + "617edd940bed42159139736f6a20abae", + "d7ef83a345a145c49824a360f26142b1", + "4d8695370aa94d68ad73e1ced24c107d", + "63738e27ae8d48f3b046539a54516abb", + "dfea434382554526b04635013a59f13e", + "8305af9a92e44f9db0adb446d8752fb1", + "818c5f44b9314ffa85d14beed921d886", + "3903cff2a580403fa54b648a502f0ab2", + "5cadc4472ef145678754698cfd70e332", + "b3afce7367c74c6aae355f7db4ef2ac7", + "7e27fc0c53744e009b642309776c4981", + "045e3304139b4db79918972ce228c933", + "757b47717f1b42f1a00b7262f4cf646c", + "8e94b2a618e74c3b8a88d304e7bdecf5", + "fca5c69c5635489e8b7bd4790dfbc9b6", + "d42a9769a1964b858993a17a0732b581", + "2d8bf19f134e4219b542d52304b80728", + "3f71baedb7424ac99bccda9bf4004fce", + "658aebe16090468688807be351442a64", + "b08d8a55ccda421d953f46f2274deeb1", + "a5e9dfa969eb47e886fb0063d7209511", + "5847113c458f4a2483aedd663376c7de", + "0db165441e2f4994aebb90ceb4fbfab9", + "1476c6986dc44e7f96b550d1f321d9bc", + "1df6a16b19754ac1ad40a8c6b690d9da", + "66ff33bd52c645899d08ec483fdce758", + "1ac9bf684da3476d918fd086d554bd5c", + "c3d42b5b89d141b3b33c29bc34b44717", + "15e5a96ea28246e8aa0948fecf49361e", + "5d81bcc38969431e9d18764e2c72d285", + "b345e1ecb817408ba2d30649bfe5cb48", + "563a01e3d4d84e078eca33ec7c2d1479", + "dffd4f97603c4792ab0f2c34273af1e5", + "23fa151346304c8bb8c58f58a76e6407", + "bf08219819b4496ea9f7bd9a61c16f88", + "fba084f031df463596bb2d67ede38e56", + "3c9bfb8914d043f6b566688bc46ea216", + "cdd9a9b1caf84b98a506a21d0e635c6f", + "0ecfa65cfee44fcbb48d3aeca1128454", + "b12e03ed59304b1b9dbd74d1af97b8d2", + "ff50337de505456bb9d1b4b04e1c42ce", + "af29924a0b6440c786c6e5cbf35647db", + "62b7661faf0049449934786fde7e25f4", + "c36c7b9207dc4df1866a1a53d3543d2f", + "769eddee8c85445fbceb85580dc9a3e8", + "deb7a94e0e7e48ff89cf2911388176d8", + "ce335fa19cb141ae8467bb8d4320f56b", + "301283d396814d3194fd231d469610d4", + "ccddc454366b4a8a8459e7b726307828", + "da72562d27944ea994d8198f714adcb3", + "8c335104ceb74c3bbb77561a0eb1d443", + "a7e6402b6a904afa963faff3812f9d8e", + "b3e1553b0c104cbc9ebdb0db7d8c1cd6", + "625d7786760146b087824a085cd6bdd2", + "4c22475aa32e4fae987d9343c3ce1cbb", + "0341835032024be3bd7022a64038b0a4", + "858f975b32884d8a89d4d8d025fb5e9f", + "380ca0a10a4a4c85ae00c547b489afe2", + "885ed5a58fb24b9cb7e0c21248d37b11", + "e7b99e157e3a4a33a7d054a4542544f7", + "d8ebef3d836a42c2a8b00e7974f6c9df", + "ce16d057336d401b8037ee31419be30d", + "05f2dc1d396a482190143daab5ddb618", + "ff6a03e2d7ed4fa8bbece2ac54020ff2", + "a090798626964b369df85d3f78f67741", + "6c409a59f6784d778d9e844b78e7501e", + "90e9ccdd97f74104b5310772a984ca49", + "bcdba5f7681344cf9b01ec8638505107", + "fdb8227a88b2448d8c64fa82ffee3f58", + "74718eb7fb61494793f03f317e9fd2de", + "418cd976b0314e49ae1b5d57e01bbeb5", + "d600eb8281854718a65d3a9bed9cf0a8", + "feb365045ac341f488e985e81aacfe6f", + "2d29a4c48cbe49208363a5a9feeac77f", + "98a3a573af9d4c23b95e5ad38ce0b5e6", + "78339a3e989d4720a317dcd59ed0f881", + "99bae43fca9049c3964d20099906d14e", + "311335cc506a43aea3c8b7e0c85a0043", + "9d0a3da65ecd4c0d9337eafdbd0096c4", + "48c09a95fb9a4ffebf6b45fd3b9f0c7a", + "e03f5fc00ded413ba2a08d3d32a095af", + "a8369ac955684cb68222d4b7b5a0d885", + "578410b9289f493cb634903cb5207a33", + "05cceb371c14447c86a0910703c18b15", + "e8c6dbdec8cf4b71bd72da63e27ee104", + "50decbf440da4921907eb852e69a46ca", + "716ce97771cb45a1aeda9ce9adf0a30e", + "5a7d3b6c69da48dca3ca5fed7fa9e882", + "fc8aa399d6b64584bb767e18a2b43f69", + "cb2a6e17a1264f1db8ff7bcd7905398f", + "2ae974bf45a3436c9d2a6d5e4bdca385", + "12e83291162d4d63b22214ef9e0dc115", + "f43dbc1c67e44310aa9ddf7d037b201d", + "dd2d5c0ede1e49738b616b1c6b6e8c25", + "acdd50c334ae412f86be25d5c4f40daf", + "5ed61d20ec7d4fc7b03c966d57e48300", + "46376f79fe094112b639f06c6661e0cb", + "ae725dcd33174a718e6293573e0a70a1", + "3af6d9d8a5e648939298a9c8cdbc0bc4", + "a8052c62fd6744ce8cd5321e28fb13cf", + "eb5cb664d78b49fc8c99a1a617c185c3", + "c287f9c262194e119079c5d67a53ada3", + "3f8cd7ccabb44b91966e2ac11d310cc7", + "156d311152924c5b82f6ff0d8cc9156c", + "901765c8962740f581ec13dcf256b1d7", + "d7fc643e570545fb835e55d810cf597d", + "471cbdf77d254e30988c8998a0615e44", + "92a1f382f1564f199e954a05ed2dc349", + "07141ec4d54b4485be1819a52e8ce7f6", + "3d341f0c1f5747a1909a099fbfa798a0", + "5dd87a342bc64ffd96a4fd1dc48e89eb", + "1e4d5f1551a94e75b407bb5119fca8c2", + "e04b202225f644f9a02e95d88f50888f", + "be20ae3b9a48405ebd67a4cd530b8908", + "a564a11174be455bbce4698f7da92fdf", + "18c010cf7c36497b98a24a9b11bab6a9", + "bdc4982297854c49bd2e856649c7c4fa", + "2a04602fc6d34dbeb8c534551eeba658", + "c999333c40c54b50ac2e33fefc3df62e", + "f5f729f957584d10b962e40e81b98393", + "62f1f2436c0c45dc90b7b7d2587a2300", + "b3eaf60f6c4c4f56a39e491f1e606ff3", + "38a9b928560e4ad5b9e7c1c4dc2a0369", + "af77c5d66bce4bea969f0f673204b182", + "3ff325601a5c4de38b90699c4f73defd", + "d1bec7606e604e1bb3e0b00e7b303162", + "a6f81ec460434a4fb999a1e201c6fa22", + "bbf869aa654348bfaec30adcb26a181e", + "845c215786744c17a20c38a738fea07f", + "3690f5c5b27748a5a43fa7085e6a6320", + "3886f505abe5419fbb774f6ef2d24717", + "d2fdabdc9cd84b409fc9330f911793eb", + "abedfdd937c24c7d83b0aaa5e9f11efe", + "7c235fcfdad445d991e50ea69b9f2136", + "0705ea8dbfdc44aea5b2ab8fc1654ef5", + "5203281c06f34ef7af567dc69351d459", + "e4dd06652e0b45d688570f32b5f9e0a5", + "a28843f21d784fe98cc220ef0d1df478", + "dfeca8e7c7c5429b91d6207b3a3a9af4", + "eaaa04d38d3d4db2b53ab35653659d2c", + "9cea8555d8374beb96275aabe574be84", + "b9031717c4254b24b7d0c42152dd77ff", + "aab4b8198ac141f4907f89e7a89de8d4", + "a8b57da71e9549c9bed7425043408f91", + "0161624e84684e988bf3412174993e27", + "c41bb69a04df432bbe43d220796f7d68", + "97491086f9c743e197534eb9042c66f6", + "acb0950d593b4a228e207c253b59971f", + "959291591aff4c8fab3f00b0db055932", + "03cba69a2c3140f7abc013d42d455fba", + "848c102840fd47ca940d93f8d0f70d22", + "9b1161c5e56e43218d42c639e3511fe5", + "e3a6fcf361d94351b2d3fe9095834b18", + "204e1c6f6c2144489e510a16ff2fe8c0", + "e30b4da9ebdb41e997fd8bc455d43e0b", + "be6ef0a613ab41ad908d0deb2b399925", + "0972ddcebed24084b47bab5eee38748c", + "abcbf71d5a904a1d9abd21f6063e3bf9", + "fb2eea00c6b54befbfcc7bb08bca961d", + "6221ee81976b472ab28f8b5e8b2015d4", + "1e96b1fd3d3c42f3aef4f3cdb6051746", + "94dba5bffa344e09aec68262673a25c2", + "95c5d6515ff04092987d698ab2c8442a", + "88188362fe7b4263ae0fce961af14a9f", + "6fcc25c69a754ab09ab08d75cce06279", + "1675f0d7c82f4ab59dc3b0f123e5737e", + "a95f26e606ed492eac4d8f5459614a77", + "730727dee14a41fdac2d40e015444b9c", + "d0d5eb345ff7420bb7f5c5239fcec637", + "86df3fe2c641432898680cd78db6cdab", + "b324a8675955439fbc88cf8340ba0bd5", + "df15298d3146457f82f82eafa1407c79", + "818d7994915d447bbf05be34a0b122fe", + "6e666a764f3c49be955c5ddbc6c24bc4", + "d6e2017f3bd94c629c06167649910234", + "8fcae78fe899467da8885cdbe04a139b", + "c464fb60bc134c3db590a6a3790d6675", + "fa34d7bc019944ccbf3595cc586dc682", + "37e80e6bb63947fabddfc9d5e5d921f7", + "8b1981e3cbeb4706807b7f327fcc310d", + "db7887bc21a241f8b8354eeb5516446e", + "e59fbe8d7ad64c0bb72aeebd75bc75c5", + "7d82e16159e141678b917bd1e01396ef", + "e70c19f7a5e445ef97214f95f42f2a4e", + "829c5b62755540b2ab099701aa1d3ee9", + "b3a9c7bb62b84e42a5e06e02f9e84b0f", + "991e20de27754df9b4f05bee954ebd84", + "3fb85943c20248079bca650c9634fc6b", + "32a513a313144e6aad91151a19c85bb7", + "a026f13cdd6c4e7f9f89c82731d7bfa3", + "147b546598a440729ab545a9cd798c5c", + "cbc5b979f7bf423bac0b4a0e8eef39f2", + "78a6feab02f44a6f84fd6cd62f06ea7b", + "2a0e016f3deb40d3aebec797f3ac2bce", + "9ec7e03c7df7480b94a62563a60a7495", + "79efd1dd561e4c7891ce3818340406aa", + "7548a79957784efda58cf4d2d49d5a33", + "06b6504ca987450e871f64c77f29ab34", + "7bcf8626eaca40e592ffd0aed08aa30b", + "8a3bd823f3274784897aa077a76329f5", + "a2472c273f2d4cb48eae31378898ea5e", + "e970b13897514109879976706967e75d", + "8a8b0cefe5bf45b981b30f7a4a11d082", + "0848f85ac1544cb296c2d14082700200", + "1bc2987dfc054796b5ab09f1bff1e569", + "fb1624ac3d9e4487b4baa6acb2493e51", + "d0bf77b2953d4ed39056660518d2fa21", + "89247d41551c4909831b61bae5726d54", + "24692a5bc2bb440c985fa430fd383ec8", + "dc5b365ea5814492834e9ed8f8953306", + "0febe1e7ef9a4e6891245689d5e16f70", + "61a7ee4d5cfe4c62bc568a30e8c74b8c", + "ec65400e36f8467284f6cfbeddd3c7d1", + "aff5c52c293f4b6aa73c33388f2f1b73", + "f9411ec107e940fa94dcde342368d711", + "cbb36818144642b7b8183cf1ffdce407", + "db7987b1c47d461ea285c235ecc53d16", + "32d8fe9aad0c4a8e92694bf672f25bfc", + "8ab16a9c3b284cc8a3ba7c6165065d27", + "42300704567343479d46bc465c9c40bd", + "d8a0fb1dc6d04c81aa1cccd1eae9cc06", + "5b20ca71fe4f475e8838420fd66519d2", + "1686e3215a15418ca4baed820d4334e1", + "aede1a7e6951497b8bc9258a713c791d", + "92c07eb07c134106af3e0c2bfcb4fc7e", + "11c8f9fd13374173b1c13dd11ed7bdbc", + "b95cdbc129924c2a8ee9536867c3f433", + "10ab099817134649b9f708d5f3fca4de", + "51824919f5264e429b75d02371205064", + "98428f7919ec4ddb994790f4b2af339e", + "6fe52b29551e4e27bdf4e2a830fb90db", + "734c7a8da4c44094aa3a2482ff3d8a84", + "678365f62e8b453399f186aa598a97b6", + "c37d22acc31a41c5aa353f28a8494c1d", + "a031287e7b684c2a9fadd8f16e6adf91", + "2d1bf7963cc544cc9c12fdbdc6f03e24", + "4637b6977251421cbfba1a6b1aa2dd59", + "2f1b16245e5a4ee4886506ad9f2d8945", + "576f0b7ec5b84040b929186669558e96", + "fb4ace256f6440139448ecc1a46f79f4", + "e733bd2635704e1fab36598d0a4c1db6", + "415d5c85262e4716825dce73e061a8b1", + "25738fe88f3b44918096d54deabfa23d", + "a0f1329d6c6d4787a6be9008d4f356d5", + "ea7a7e0e36fe4d9f8b7bc12ab78f1b81", + "60407a98754344cf8d23a33280a8af3a", + "d5ea47a7d40c4afe9b2391faf783a305", + "b6ee65e56fbe4d8798ee34c96837a0bc", + "c9c7fe9b477a4565a11fd2eaf868c23b", + "eaf671ba9afb4485922f44e268a3c715", + "f15c7f6fbf7d4c4a88217b32dfd39eec", + "9293fb74b2014f648c3b1dec28d1fc80", + "9350b711fd70433cab72831fed058d12", + "0701a4213dad42c1a3c2947a0cf92abf", + "dcd691724f6b4d29a6d16def24d14e6e", + "4f590098666a4d7598d8aa72c0380b92", + "8cf02cdc5fe544b6960d66d70193a86a", + "5b862d56c15646c48442da6421b56f32", + "d17685f988c14b3ab9c9808a516e4834", + "95950c70053f42e0b5ee87077e8599cf", + "bb46f193682645f9bc714cafadba5dad", + "0b02daf91630407aa38f8ab21d2039e3", + "2612be461f424810ad1b1630d466b5ee", + "65fe39b119a94d3bbef1b044908ec5f8", + "93c0af979ed04137a39e1d0d9a9a4c72", + "8afccf3a63944cf5995c678858762723", + "b926b3af0f364423b5b5e8449298ad9a", + "0972e51c873e4956a5da30e7668cd5d5", + "c1d062b3ff1548e3abfdf7bafc14254d", + "6b6ecc33993d49939bd4c7633c795577", + "8ae1030c47ed4d3c9acc8f1360aa73de", + "6c00c79f40944ef4920613ae7f1b0fe7", + "a7c634f099d344a9a33ca040462163cb", + "cc08afda9f27432d909b1160b52d8bbc", + "874fc7e11d674f51a4dc2082d29c9b9a", + "50a67b795360417393625f35e97e2331", + "62a5b060acb9413cbc42746fb34f9e94", + "553b2499edee48c18089c730d72624ed", + "7de8bbd813cc4387b31271826706b123", + "9af9bbb468ff4f65a40da5f1d51573d4", + "49186937cb474f49aae7bf483204f23c", + "d2d63e52c8214f9fbc2186612fd068fb", + "7b4caabaf5f74d769a6b6a90860512ce", + "57ef1cd0112d4aa882918497be0eef50", + "acd3c24b438948b7b352cc1b3a126c90", + "3e32897a225f4cfe93ca7a02d51fcd30", + "3b65b7d0e3af4b99986a199d3df01517", + "f82118e3dacf475089009efe2b930ee3", + "dfdcf768fc8b4b20b0b2d0c00e505a8f", + "8a19106a7fae4fc9979540b61b4ef954", + "862153aa6df74587a71c6c3b33c7cf03", + "66624c84a4d94559b35914ee2ada4c4b", + "fefcac338607453f975595da44f0c7a0", + "9c44c44b447f467994b10b6f37aaa078", + "1641a9561ae24f49ab8524a7da9ff5b7", + "14084f216e834241a7f152cdfa4e5d59", + "beba5b2965f4445fa279aa2c4fe9988b", + "1f9f1e9d04f246afa02469ea71317c30", + "673dbc21651f432aabf7788b2d0cb8e3", + "e6049b321128440baaebdb4a2b0f806c", + "7f8af574ebe04b02841a230b141d2a37", + "8f05abb87d8341ccbcae60892b83acc9", + "a015bbe15ba640eba0867a1317042dcd", + "114fc64ac8064daa8c9053f4602d6f3c", + "37d61dcafe4545c0bbfbd7224ed004cb", + "497e4096c0bc4828b611aa8063157bd3", + "c65a00ca4a174653beb4c59cb42b9143", + "d68b73d0d19c42769ff49216e2f2126a", + "f14d73667de646668982cac93d602773", + "eb8faa54b7684e18abe6af39e1526b7b", + "f02b5cd7ff7d408eae2fba98062055f9", + "875a64457c5b4e738d6897a44c9fd279", + "7ab6f804440e4a1993699ed260140dee", + "ed555160e7bb49cab85360e50f8bb6f7", + "98fc33b429af49e6afcf35a513b25efb", + "ddc05284711b4132808bcd187bbcd503", + "6946a0316c4849fc8fc0ab3eacf52f78", + "3d90bd005c324876a49a19e694325173", + "dc21b640a55c4d03b86c0f61b50014d5", + "439c61b8881b483688be86e7ad0cbd1e", + "f2b3a71f48d040069fb144f76a1180d9", + "39a2e152c89d4e72a84494146704f82a", + "7a6f7e5365b6491ca8ec6631381e78d3", + "bb874f644df34816a6bcd141a59c87e9", + "ef972bbc359c4c69980a854c59b36004", + "ca9d03af291b45d0b2a77e739c713754", + "16c995f47f28463eac39183ff3d5d7da", + "2df262e6815f4c2eb7572607ae5e0321", + "2592cb40eacd4cafb35187f963dc889f", + "607bc6fac59b48a5b4b534eb104ede98", + "9ab63ddd36d44c87807534e7d9bd7c61", + "603a9af46a8449f0a81754d1db76e163", + "2894efe73dd340bd844646c8a612fd15", + "ff92f513c58647f3ad0c3a8882927f76", + "d0492f06831c400baa64940764fdcfac", + "d6e6c098d67842dbb71fbfda8ff8c2ca", + "d26c359c9fbf427b9d76f6ba625281f4", + "6f938426fe3a4a08a04d22907cb65838", + "de0e92c5df07459c9da81d7ab1231285", + "6f0aa5aae22b4f5397ea9a640d1d161b", + "aa39dc5c45904e179a8c8f849f2c9cc1", + "83455db5eab84bdf9ec5f0df6975f938", + "3bcc1e221d194ba49f8ebcea7459b853", + "79ce99d39e554fc99102b56d5e786bae", + "4cc80f4579244407b72c6afbf13e0979", + "d8a1ffdd367143f382c618663e020605", + "e9dba085303f49c8bdfeae3d98c55647", + "e48ca09a737844d48d74c5f0034312dc", + "ecf02296184a4d8f99185f932c65dc28", + "134e654bfbbc482c884c5bf7a14e1da9", + "eeb3c72214a940a79310ea77a89a09a0", + "6d30ed5d244a4bcaa9deba4133ff6372", + "2ed38b429e1e4c889b35cb8d7041d029", + "095e633990084e8b812fc7270c47010c", + "a5ba0961640447e1a25317e6df4791a5", + "50b6e50751754a0d9c0fa8c6f950289b", + "7cc9e64d7ffd4e369595062abb3ab177", + "05df5fc57c6c4e08aa7a6a413bbd5ece", + "0e30fbb962d944a7afe27401fa05319a", + "d022fc3857104da59e286822c20868e1", + "41f273a644414888aa9e4db4a7ef994d", + "63f27ae01a164941816ca9366c4062bf", + "9d9e575a2fd24739ad854ac07a3d4b3d", + "4081ef75f13848019b70f00b01639bed", + "8b5382c7ff304e4bb986f0e3930079c7", + "4393c09681b44229bdfae64582e94272", + "714031af7a4e4f92ab2b463f4180ee5c", + "bf31f7249ce44634a6c2f05491d3078e", + "4eb1b7ee75844ac392400a77c46bd310", + "ee78932f134240dd9ba97f37b0ff6515", + "42f7dcc821f041c4adf400ba76c85ed6", + "546af06b942a4267a67d2e6838dd7220", + "144fbe76874541488365d3ca35fb7be4", + "71bc97b4714e43418b469c57dfca330e", + "e20d0d51217a4536b9e3d7a5c1d79551", + "8ca85840a9bb41288a408df836f9c253", + "686c71ef72f04b50aa522325651e3222", + "8dc244d4e06a4e868c6efa796cdcfcf6", + "168ca4d0cad641f797fa4edba00164a5", + "639a89472cfa4794b848175bbf652136", + "418074a1454f4128a9d58daa05bb9610", + "36a9ebf2c3584519a8dbd3b7e8c2a348", + "e84989aa397c4bdfbaf6629e78eb3ed8", + "a395ec5acbda4466bde237482b16e0a4", + "6aa37d779961463e9edf0ea771420907", + "809f3456a353498299d508c171aa6274", + "69eb09a84dbf462b816482f7f3103b10", + "5df89d991d3d469b9ee6d1f35ffaf554", + "f3dd3064db4f4e8880344425970cecad", + "bd980400cfd04ab9aaa8dcf3310c4256", + "1f0a7d30a0354d559515fe9dc6571bdc", + "62aeeb7d51ae470c909c3b7fbdcdefb7", + "8ed2abcc7fe14e47820a71a20988b69b", + "4d6e4d3dd9194633ac86285ada1017ad", + "a03df271d4ed445ca5e80e24ba72f6e7", + "0594b2e447f54aa9bf862a51e6db17d2", + "a85e7b29c9ef4fc5b7635c45e0b410ef", + "9a4b89d7ff5c482dae835df596fdcc2f", + "3f96a590f1644b55b83bd4053a665043", + "5ad2253133d4433b8b3970aed913c4ef", + "50a5cf176a15449bb3b5417c49fec47c", + "b9389a2c49e14753b178884cf486f495", + "e6b725998e194b7bb770950b57b78a87", + "3c22d7f115a0446c8111e7bb8d45dfb3", + "4a2fe98254114412b73b6b831b1a38a4", + "2d94ece999364621b858befc999ebb37", + "e7d33789de2b4fd286cf9190b855de28", + "77e8b5ee3f774a969681357a0205e2f8", + "27efde463d0a44d1b8386a3f95aa6fb0", + "f7ba72403b6d4342a42b20907ed37dfb", + "4129518d0a5d41e7bdab5b42ffd8faec", + "5ccadc20cccd4e38a5a9965da8054a85", + "d41ef98dbadc4d1fa49c2adc715c3fe6", + "888f15c535bd4eeea3934e235370941d", + "244625dadbc6452796e342271e12d79f", + "6e699f6e9d564bcda8afa3a1b26bc43c", + "225c0da247c84f889183f4912b87774d", + "3ca284d6b066484893c650987fe49345", + "2da7115195654972b95faa7018e9a8c6", + "931b534b02734a0f8307d1c236504202", + "86364373a3be40949e4a6a863933a25a", + "da8f719b60e9406fb16c84a0bf404297", + "dfb7c3b51e264b5083dc28450e55c2a0", + "44d4c3e01dc7479c8225ddfab3dfc8a6", + "68ec5021d347475d93e0ed5835280fc5", + "6ae9dc2da51a4f858eb759d6d2d7a9dd", + "e5d24d29a6c44e91b51359e9a63f74f9", + "07a54ba6def741159208d613773d0524", + "d8eef1546773469c951dde190b508257", + "f97117c1ca21458881c1b058f177a6d1", + "f678ca59b9704a83abd0737e0980d4c4", + "edc8c38a80f5419092f72e8febf3598b", + "a6e948b67b0248a8ae4157b1775672b3", + "c244f7e2d44e49e096d0eec440fc90a6", + "f723433582e1405abf7c3950f781f898", + "9e3e900295254b82bc144b3ca4333b80", + "a871dfabec3a4eb1a0c9b8a4e6cf02d4", + "2a09a3dc75364c8c84b25d2cc235cb9b", + "515df9cbacf743049491ee8b5e4b7012", + "9e0a989a5aee4ecda68e08b62552a799", + "c456bdc52aa146d4884306aea0088c06", + "0137fe739f5346a98bfdee5edb78c2c1", + "9fc39591fac94d5eacd692e74795cf88", + "de3b5b5a112748439557191f2d7afeb2", + "ee48890ee3454b15ac52cd8b84693603", + "ddeb06c9dc094a31bb4c777b2683c374", + "4b1fe1d9569346b69bb956bfae354dee", + "3724de1e56ba4f4bb0be2ca3170e39f2", + "40b7570f0cc74ce3958df03f87d77c86", + "2be2342163c34c448b12e5d5aa5516f6", + "798812890dfe4c6eba20d3df5080ac86", + "d36bfb3f96a7424cbbb348bd66cdc291", + "8bc4056fe78b41c1b7bfbbf08a93a0cb", + "15e368152d2b4e469ab6d33732d31994", + "9382585b9e5c47999f83ed9658f82dcb", + "b17eab484b2749a18cb39a09abcad147", + "a06ac84d848242c58c3d4517c189f8e3", + "5515900dcd88497886b8b32f41a2c8ca", + "b9bcdce035b64bc0be19e917903acb59", + "530f9b2171954dc481f90c2bbd781f57", + "7acf463941774484bab3dfe500cc198f", + "0baad2ab0df5463fa55a4b03ba9caa09", + "9832fb26ed7c44d2a1f7570bc1d7ba99", + "b54b7a96ae04487081662e4ff5383956", + "583a67982908427298dd3e9204bdb4f2", + "c423dbcb8b0243d584fe96544f649997", + "5bfb40aa22ee4a34a190e22254589ba2", + "87eeade1219c4e12a9c446783b49ad11", + "de7a8f843afa4439b9296d3fe40e7aee", + "69d4d839822e4e658ee95addec9fbc37", + "4cfc4f9eefdd488ca5adc30676bdf3b9", + "5acb640a90384c95aee4a7ea2f81a546", + "f83a6cd3f3534a78b35e1a3490a3ac18", + "8c2dd7c421e2494b8acd73e9938a426c", + "1765302c984a4bebac2c81084efc096d", + "f88382f18b934826bc8d06c8d862fbb9", + "6cb480ea01744894a0c73df2bd20f480", + "b279e479d8354ea684131361f0876b69", + "4f01396fb91b4f5c83a890381f2d4424", + "9128289763b0425d9472baa661028336", + "9796bcdd0869446da27813947ecceb8b", + "998bf1e44fef426ebf6c6ae33eb8e246", + "ffee6a0d36644584b8933e06900f4e34", + "b5634d0df70742bbb1cf2eb2eca00133", + "89a530d9954b4003b112ffe2aa3b3b92", + "425e8e6e72c34c29b0832a897852f2e5", + "7eb601a5502549f9876a2eec0638b68a", + "ca087939dca74b6fb66cc66e4142f249", + "5ad5799f83d8421dbd101be6835fed59", + "6f4065870fc74114ac4604ff1f3d568e", + "1918d469225147a89c6d337610a08aa9", + "9a53c7293d914f8ba2110dfe6a4d2ca9", + "c87799d0ebca4d939112bcee151f80cc", + "b8e7c778161242cebbbf012fc44e7287", + "809bb454267848aaba83d4d7ddc8b90d", + "3bdc783fb2ab465a9f1adc3e5f0a79f9", + "fb83e05ce81940cfb07e650a0560f1a3", + "5972f3f5f0d544829ea6c7fed807fa32", + "1d916cfb3a1146f4b4d0cac44f542859", + "56298d9c30624704a6aef678e08d3010", + "08820036c2414736856bdef67efc62fa", + "5fc95fddd9cb4038b767fc5cba588c4b", + "5111ea327f8e41afb177121ef86b8461", + "4c4abfe1b9184d5f957dee381c05767f", + "8771813e441a4f34bfc80db529d943f5", + "f2c0dbecb4d74e5ca8dff06e4fd6e969", + "e21d20c7359e47ae9efbca5ea008c96e", + "28f3a08f5611411188bf84cec13adc6e", + "8aa0a3ac43364e12a14769e8555662de", + "c0e5f00e1f3f47d2b19088ced9b85932", + "4189fb8e955a4999a268b071cbc7098e", + "eaaf71d67a164b11bbd4b9c1d1e69163", + "351becd8707f485c89aa218d53c4af50", + "a49f959353754987aeced2b9f3cc400b", + "defce5da76fa4b19ace3ca7777e593ea", + "b80321e2503142018b42b8a331b63d3c", + "ceec28bc7b8b47df95671a470e9e9b65", + "b832262a465f436abdca0b7a152de6fb", + "7f63dfb1ec204175b69f774293c46bb0", + "62f39f6c2a834260ba317365a544ae22", + "f94119d2dcf049d2a507bdb76eac9fbd", + "cd0400cf0d2541e49d82efdfc0f0450c", + "e3c113c291c24088bb2559b39d48b778", + "033acae3977a409db84e270dabb6774d", + "140b248e8b284423b71805d4d5401352", + "c21e2a4d650b41abb3b24540494ea71f", + "c5f9e72edf7d4b5eaa2ec9b95c3b099d", + "ef7e562a80f24d698a337db0aac4f042", + "7fcd555c03de4411a83aa5685fac1b5b", + "e0e4b761e22c46c2a108b98abc88b95e", + "86b2348241aa48649e2f68526aacd053", + "ac5392ff0b52414a855c0ce9b05cbd50", + "286cf5c53b5c49d78102d18e11f13292", + "7cedf5cdd7894f58bf4cae7f5be9d6ca", + "e022dec9019c45bba3e2fa7f616eff34", + "ef350bfcf48b46618e3ffd1048b6e8fc", + "15e197a919574a158f51a6f0e39ce067", + "bce220731e57403692e850bfe6851a40", + "37e362e113994d1a9e977496c5001f93", + "0478a5ae37d045ba8263f6c727401e5a", + "35cf4575c10c436eae7f13e9ae894963", + "f0f8fd0862e24f95b0044c0423ec1ce2", + "d09f470a3e0c4a30a7611f6fc9edc08e", + "b37db59c7cce46b2a3e40969e6797117", + "851aaf35f79b457fb62cc693b6e08518", + "1be0f09f70cd422d87cff81073b3c2cb", + "2a52287cc64c49749ac03bda533d7132", + "be6e4048ceab4c9c8ef9181f8affd481", + "865a12da7eac48f5bc483e090441ccca", + "ab944e1b70474fa5b54e1403bfde3a2a", + "28a40abd0183488e918191a98aa87330", + "2b66d433fad7419d994eb2b098293577", + "ecd9399625ae46faa718d6838f3d9570", + "665aa05d24e54e3bb5d0f01ac52ce9ed", + "577ff7950f9d4f3790bad37b8ddc6b86", + "2b595c801e114eb3b3def91cf9a20504", + "62e5584cb2c64702a00800214a0a2b26", + "088d569b94724975829d56d6ff531d04", + "ec261c81dc0b428d867a9836116e2326", + "e4ce372b7b7f44c2b1ac991c65b47aba", + "f626dbe609b54078aca0bf676047f30a", + "f81271a178734da8953e49e5acffe334", + "3cd9c8ec6d914268a8ebb87a135af44a", + "d6fdebb1970e454f8104647f1eaa3a1d", + "21e5cd7abf56439394fa2f310d697de0", + "986e2bbfb76d47cc9dbc1d57346ccecd", + "5fdd10083f664eb7b18bf71c054bfafd", + "b00b13c3d51a49b4907a89845a32cf9d", + "cac640fe074847a794318b42a2755008", + "9749f5ba1221476993376a3cb8fee1a5", + "e3c0b9b16f634e7791c9822ea987d96e", + "76a75a4cafb74489a3c5385834058f0b", + "c1ae123c3aa345bdb4c4649ba0efdbc0", + "2b30f9b848754e7bb55093f3fd0e6dcc", + "a36820f7ff30446d89e76a05a68d99ac", + "dba6b750fe1245cd94d7aee1ce887f90", + "346475955af640c5bb66541d0d76484d", + "5251c39ff8f6462faa49f14fcf5774ad", + "4b676d5593cd4349945c7dc7b9f4ad40", + "9cd93b871f6b442d96b7eacec7326e6b", + "a8acd6cd99a3435ba5ad4bc5fa2407d7", + "b642670e0c3a41b6863762c8545079db", + "6bfc95774d374c4bba728def2c0b2700", + "4d2721bcb6e34b6f9e2fff7ab3707888", + "09986328dcba48cba717f4299ac928f4", + "ace99cbf2a6f42e2bfe48bad03b92199", + "73cb248ad76d45ee9b638ec4bfea4128", + "dfa38e385f6a40c19d9f4d8034ab5836", + "d20c2f1b62524c6780647212a55e27b8", + "6de47e9a4ce747aa92293f347bc9abc1", + "a4332af4f7d5425890abeda048209ae9", + "d34f1dc5ccc744b293b2c96266f0e64b", + "040d548a18b44fceb518b1b57a62aebd", + "c71ee01618c248b0a603f0d3b6414fed", + "ad1a6218b2cb41ff9bad1aa8150745a1", + "caef7a1957744472ace263fbdc343b8e", + "75b3522c868842048cc2dde9001a00f9", + "6d81e5d2d0ed43d089a9a9ffca87cc17", + "bb2e0c6de4a84bbf908e7ddd053e1fea", + "ab606fdfcb2a4cf482c60dd6dee81df4", + "6e38c260393f41cab7908f1c94b59732", + "9a66736e293e45ddb23edc2afec73e8d", + "d3ae871584d146b681ff45a7915a4f32", + "bcc3b206b4554d288e8eae93ed08c38f", + "ec74e02ac1ab4ad191f7e4b9fb1de09f", + "791ad3f831334d14839973ed4d27a2fa", + "4786c095259146b393dcf903ca6c519e", + "5424ed724a87417abece2d55ecbe5e84", + "e2b4a7374f584924a74b60e896bb1567", + "c2926d2aa5014376a87fb9ba72c64e48", + "b7abd02598894adbb848847f7b397d09", + "e7d0f33b4bab42edb0ec1623fb1d2010", + "c17a610a6ff249d8a5d99f305764de11", + "ee7c6835d6d04cba832918a58a69649b", + "7b13b36ba2304912afc9840caea731c6", + "5cd13916f89e4552a25efa27e03170b7", + "a86cfa0b90014c1c9cad605080b3987b", + "0fbafa2f474f4bb0bc6506d2f0431469", + "e526597dc44c4f50994eaa73881436ad", + "aac6eec080db410a9200452719cb16e9", + "80085ab67b7844f6bf6c83a23f71aee8", + "eea15a596c8847b791b78c0861dc1a70", + "4bff8adea43045a5ba9ac44946ca0bd5", + "d239cc695bc34fa0b9441bf431ce0787", + "d061b6a017e240fc873966b703483f76", + "f5836f1fadd54919be5ce641182fd386", + "9b0cd6fca3b14438961f21aef7288e8a", + "62b3936ec8514a04b237cf66cfb15995", + "2cffd1685e794ca087b0f2774cf11984", + "86076a337be8462b9c653a0d3fc598c9", + "db7f5471865543288af40550a265c693", + "1f1ace6eeb8642258e346bab45b0a243", + "c2ee2dfed3ad4a34bd535de881badecf", + "19d60b254b9e4275a35e9fb359c0df4f", + "c4c36da309374d88afe4a751b78d02f7", + "e219c344517444c5bf3e3efd7b2c4b6d", + "e300f013cafd491f980bf091423c3e92", + "9561b5ebf0644ec7be89285f1e986681", + "6f06e9a207534adb9703deffedfa3ed9", + "84297b1096934f8a9ffa1c0eb16934bb", + "988423abf0a24da680ca21e615173bee", + "c26df783a78f4b0cb6818d12f9a203b7", + "5a9a9eb0144e4b758b8656e28ed610d8", + "2e778682f8584353bc78e95e91ce8530", + "be3559439f684332b3e2e82cc71b0c25", + "2c146683709b44dca0fed8ecc62fc639", + "8e3ff2ee1e5d4572976b2385d9b502af", + "b3efcfe9a17348a5aed9fde7ea2697ae", + "473321dd7c824920bb39800ada18524e", + "3cc4bbdc3a264ecba544ce46523741f8", + "e0aee5bb029c46c4a7e0d8576403debb", + "e85f2e4751e74a1fb174595be1c32e9d", + "e37ea992fa744f79998be179a1c12e10", + "1245a63b6dfc482bb900b6f40a4d0b8d", + "bfdd04a15273482694e7319ca98fc468", + "9ee66510a72d4ba7b5ef4b0ac7a22373", + "6b59ae346345405290e6b4ab8912e2fa", + "c9add858e6f14b44a2613cc3f3237ee4", + "f93d05bc2db144f7a50374794ef5cf8d", + "05590035d2954909ab287208a42da45a", + "ad7df56f08034680b4f94822dc7b0a99", + "1730a158d49b4c6b96659cdc9cadefaf", + "4acc9d61b5794aa991b29759c5b0c798", + "b3baec9295904001874f8458ff73068a", + "5bfec4ccd31445bda0e582afe3214862", + "5a7ecef3d12242f9a4a9b4db971a96a5", + "16969cfef8de45eaaa73d2560b100be9", + "f0ed2da987674fcfa7c0ba53d98a8a5d", + "4231ea4a40b1497b858958c54842a642", + "b12f45fdde4041b6bc76a35c3ac769a7", + "ee39e110fdbb4664af18fb1bf0b484d6", + "450e97b0289e436c8930cb17221a1a51", + "ecfc7f4e23704d84a7d7b4fed9e059bd", + "57ab28eb0f21472ead1f5dadf4e73a27", + "d40caf43a86f4429a5a9648b93b84512", + "1d0c965ea0124bf0acf426de59034364", + "e962d32beaea428ab1481ee63a20b130", + "59e66731faa24a278a86a16650ee6b79", + "b11b66f233df4818a70f7f30919c94e8", + "1b16c5884c404087b7304c36d91b562b", + "011f2cd821e94596863378daa134cf0e", + "8786cee0a1324ae2a961f534a5a4840b", + "158b67543fe842b487b00425a65cab5f", + "34fbc834a75042a9963f711bdf0ffac1", + "3dc1d573c3fc42ecb53dc533d844b460", + "f0864db153a3416695e681c575009daf", + "1494ce0d32e04ea88040cbcb3b8dbd96", + "05a3c7955018489aae83d5f516593ac5", + "e3ffbc52b7794dee8a7fbbf7118bf69b", + "cee8337683584caba85d970727500db0", + "42b78950675942cb871904f69006783f", + "50dba05c6ddd4cbd941e6e8e4412954a", + "d50d61ef119b497094c4b155a6e50570", + "2d3257b9366d47a09abbdca213805fbd", + "d815c3cf71ed4c279955f06e62a82197", + "c07ed2f916bc49ef8529043bbe8b7ca5", + "1615c1b99bb3419cae1913aaa5760aea", + "81a899189a2546f982975a7c19e10b9e", + "73c22fd086b14ec8ae476b20f22d67a8", + "414118f373864247b74640e09b342a2d", + "e9da4b520da340b9a34128822aee1586", + "6b3afe782b204dfba87a03ddaf222958", + "9aadeeb6635440af88606903a06950d8", + "280f6abd9c7c4b5cb294abc89bd659a9", + "5f59503760e646759acd1002ec585b44", + "3d109ed87f3845829069c63e02978e1d", + "0ec4ea7401f74d1194f75c9dcc5f42d0", + "4330849036a744b5a9c0876c049c62b8", + "e979b358b82e45c3a6eb25ed1537429b", + "edc8a7c4d58b461db769b046b5297687", + "513e2a0370a74f31b569ac77dc7c6451", + "345655b592e043e2a14a2c4cf8083512", + "d9d5ed5de83b4d899ab93f55bdc3d0bc", + "93c41cb33b444b32982d737e08afeb2f", + "37a8bb139b3f42978c8cfec280df3019", + "43683b70fca24b8f8cd9583929a533bd", + "860ba6b1083243de9cb8a4bd6748ab3f", + "da596c9400184183b9b8fca70559c048", + "905455b40c12417f98569a20206b6577", + "a332e9c6f49c4d92a00d466b1a923506", + "91fa7ce2ea9e43a69d723cc3bd08f306", + "b4cb920d8f2e4dc9b714062577be81e0", + "5d2e65553ca34c94ba2dbed0e4194a70", + "bf76a9f3fa604c4297161af894541c95", + "83546fa4286e445abbcaee30fe4e1f11", + "311dc25570c041e5bddc151a327c69ad", + "2681760bc7b245a19a719bd000583577", + "1578907a916245609e1a45f7052cf732", + "15bde60b897b4850816bfc8bf229cd7e", + "0d089f6385db48f6b00b204efb6c0307", + "4a7ffd6578a446e6908016fcaae9784b", + "83d5617c421040fa9179dd72615baf11", + "8a5df6955aea41fdaa9484d7bac94a57", + "f2197c472b2c475e8136741e7164443a", + "cba02c194a22402cbc3e3c4c3452c776", + "6dfba42794e445719010caf0a1ceca7c", + "2e760aa7464b41949ce9099ac714a2b1", + "6eafabc7c0404197a3f8f993b78ebe8f", + "36e93eed8db74cc0bf1ff4a9614c6b95", + "29704a99b15148908c6099ef535a3483", + "f830aa10c0274c3994f47ca0ed990681", + "240e8fbfba5b48148ae6bda2a3ba04ba", + "eb014aee22bc42cb863096b3314d7b95", + "5b72a76136d547bf9789db41ac2323e2", + "c8681df07757457d8cbe61174fe8929c", + "5f674ac6a3ed47109fa598fd6ead408c", + "36d68eab2641425c989460badbb79c0c", + "26c9762c120f41efbc905bec09729f61", + "9ebf8e7e34194f239f3b03a19f5ebe73", + "9eb9d52b34f74e2c81925de28c0ef68d", + "a2e2c16fe1b542fd8591f20742eaaacc", + "aa1db9feca8f48fe90e1b38f60cb5eb1", + "ae2d1d85b1a34466bf64810b85050a33", + "51226d166ef84bfcbe5c63bfd389a152", + "14f79e288012404cb7ebb21df3acca2f", + "8870b9e07f7c41fe9f4ff44d27b95cbe", + "b4881db642f74f2b9f47be02e83caf67", + "a99916c035ef409883324fae6a86b5fe", + "0025c5e2333949feb1db259d4ff08dbe", + "f8f4a3bbf71e4300a2472c82bc305de9", + "a595bb77f4784181830f74b5c15b4768", + "300ba1548ad14182a93c48a670b0b809", + "575e8a87837246738bde2d4d375c1c11", + "0002c6eafa154e8bb08ebafb715a8d46", + "200adf1d019d4897982627f949b08f32", + "5f4c74fe57ad428ea6ec4c2412faa816", + "e24595629480417595a252700cbb9acd", + "1ccbf4317dad40458ae84f2224eafa72", + "e99dc4a15dd94d05b1703781b988c8c7", + "ea5f46e8eac74fd5a828137e3eab48ae", + "7177d1c798d042aaaeb543e5bf7b3911", + "24bae7f3e42642ceb3f08a78085d1288", + "26afc1d67fdb41b9a971b243a3ba846b", + "d6a5427888b8413fbfcbcaad14353af8", + "32a63cda1edb428dbd0387c74c106cb8", + "7691cb7427f14e219678b8f1f3b34875", + "40e786abcbc346d19e2304c028dbb4b4", + "f3ee5acf741f4c73b5d48568ad33618a", + "541b94352ae443be8e2bfb9de0e80865", + "90a0093f27f04ea19e33591f22910741", + "ede795f1c6f74a99b6952183f340fcb8", + "5eb6c3c527514da1bb294e4796bd63c6", + "952721393a9d4f5a8bc9aeeda3fb270c", + "cdf1488a07a14bb481569f6c7690764b", + "d01852b9ab9249748b6ddd102bfdcda0", + "04c4eebf6c894efc9b627fa453c4d917", + "9f881201ee344b0eb5fda2ab22197bcd", + "3932389d516a4cbfb3644f40922e542d", + "1afaa69215604838911ccd3221e4a6d6", + "32febdbfb69a4b378aa9ae950677118c", + "58a6c7f34c32485da095a8e942b57756", + "a7fd32c748b24462aca2fe61c46d9289", + "fc2dd2c7b51e4ff5b38d1d3611da1f93", + "6717607d062d4c708fc386b27613ff16", + "2f4e263885014a3fa12e642cff873fba", + "08d4bf632019457bbfb87c3a9b3b9803", + "a394b8eac4aa49fa9d47dcd286788ea4", + "923472983df8487790ef5a90d467cfd7", + "87a8f3f885f44ae18759afedf3c0a960", + "f984b1a4c18b46e2a654bf29fa312643", + "592d31f4896948bb9ac5e53ac246d8c8", + "1406f3c8be814022859539e3eb29cd09", + "4337933c22b24e2596baf89a3f121d02", + "7114ef335ef74420bba552599c4f20c4", + "82f23295ecc542acb2137d9bfecf455b", + "ce79dbeaf3b54dd686b3fd04d50fa6d3", + "35002d28d3fe4359be492bd444569744", + "930a5039b28c4858a2657395db3404f9", + "78aab521e9474ea4be8a76332cc93540", + "e0262d52dc0b4124bc14814e7c1f689a", + "21a4bc038cbd415b8e09566148c87c46", + "6502f2d7760a416cba0c28842d0beef3", + "d647b91d6cf94de9a11c9b80ae4bdb00", + "a25c6504c82f4851bf9bdcb0989bfb02", + "38c6d1391e2d41e390c9f8d8d0ec36dd", + "ca85e1fcc3dd4fcfaace02404959a2af", + "cf2af4b2b8c6420da69ba8d8f73744bc", + "739b014bdccd4993b94037057c96089d", + "ea45d396c3af4f818b665d1922a2801c", + "f99551c63ac146e8ab67439610092b1b", + "0c5888ecaa4d43b880a7cbcc564bd3e1", + "59e342de144442cebfb035600e9ffc2d", + "42da0122f2134a189767d0911b401c1c", + "816c99db3a9745be8deb0b716be822db", + "1a54f80644c64f598cbb3b1d4ec17b02", + "3fe13164a6074993a8670a22d8feec41", + "de46e20e79b247238b8c374ae42166b5", + "86b0c9fff81e452cb67e10f4bf5833dc", + "b2a51a01d28942fea938b5f7766e324d", + "72e69a423723445680118348c03c1032", + "dfafb80f177f41d89aca04d7bf3b8417", + "487ce2538b03486eb34933c40bee22b9", + "595d93b528a64fdf962a46ed800c7125", + "f5e139a22c4f44649f5a653348737320", + "aa9c0e4426924266bbd12b3dc80ed413", + "6d3842593fa04267aeb38a61d57e6f9a", + "424974dd5eee46c5b5e28bb2d3e494fb", + "f46f4038d27c4bfda52bcac33e478cb0", + "62e2b3e9db77443b88a7341ac0032e3b", + "c6b2600e065644dbb1fac6858b7b5c61", + "60d65f9215d74b4dbf2efef4577403ef", + "d03f50ae268f436aba1da7eb5ac307a4", + "583fc05c9c2c4725848efdeaa2e0bf1d", + "889587a25238409d96fb88ece5e72d69", + "457c34c9297d44a1a5d4e5d093c6a712", + "06128e48037f42b78fddb572a884402f", + "7b396a16065046eb8d1bd6f528e82914", + "f7a97e1dffc5437db44771bd261090f7", + "73df39be82a142389b0741d80511132e", + "9488609b11c244b1b4176fb4dd17b718", + "ea91bdbd359843df936ce40f63c1e40e", + "0195d3e483e94f68964bbfa1ebb5c6f5", + "f6a11db5dac448c996a4441a5570f042", + "bf4f4e0882f14710b568773d07ea4083", + "4238acf07e5247f4b8334999159eeb37", + "a04d789afd344eeaa029b72c16797a99", + "50eca44a12d84a39b500658f2f8d891e", + "43b835b4c0e847388a96c9bf27cd8d7a", + "ba903f7ac8424699b6c3112815604cd2", + "3f0b63f78c004821bdf73aa7acd2e917", + "5b889e682437418a85e9237dc6d66d82", + "940c5278bbb44e8f9725c0228556e493", + "e386f2abfefd423b8ab7cb967d79a200", + "276a01e4b8484fcda02061e073662dc7", + "a5d2dd6a6b964974b8ba8d88d9a38def", + "711e55e302a44095b336dda8ca4933b6", + "99fb4b3897f24a4c8e774fbd7cdd060e", + "43a19f580f324bce946860cb2d61baa7", + "c1149039868e45d08b7084b8011bc5c8", + "f44a1dd456de41cdbdbc73efddb84cad", + "a24c02163ca349d886d32eead5fdd9aa", + "78f9cf9616ac4dc2a4fd7547fafde942", + "d833c29776d94bfe9cbb6e0b68dec39c", + "654225b07dc044628d3e675554eda91f", + "88566377115846a2a0d6398092bb6754", + "47fd70d2b3bb408b8eda632c53d86515", + "1c5668905d014211b2c0a9d123e70563", + "2c1ea4ff1a304559ab5c41629149decd", + "2c38a0d71fc64064b162b33154334265", + "f9ec1e8cce62458db5c89c6d1825a307", + "c13893680b79494bb9bdd3c39fb9142f", + "36f12a0c9c9149aab3dbe7fb35189fee", + "fd64a2892fd249c888323579c36ebfa4", + "6774eaa326794054bc8dc5812740f137", + "e254e330d9d0439da7367587ddb4d085", + "8aac71b4f48a4c79b49e8fdda4001108", + "c2ed34bbca494045b0a35ffd774364dc", + "e61015a6edb744e48c7c6dce343560e5", + "48b073d405e5472d9fd7e0dbe45c973e", + "008daeeb47284a37b467cfed9e9afc52", + "d85cfde21860407eb974c67c84dd0392", + "3eb1fdbfb0ca4e7cb8c3e4f1bdf5b28c", + "8aadc69e14f84fbdaecb5f990883518c", + "9ee31874dd6b49108ac1435f93d2f113", + "ce642db7a44b4cbb9bbae22b977df0ae", + "338750859a814c8d99e45095ed95a2e6", + "98da0ec599ac44ce84804e875ece3159", + "3ab3d50afd35427fa1ac214f56170367", + "bc5fb94cdf2d4e9bb7803f565daf600b", + "020accb62dc445589f4edc3ba9c9ad07", + "185b37482f3842cabfa67cfcac62fdc3", + "174c95d9dd014d8a963c92d6db1ad058", + "1f2243cd9b024a2e92f7ba07548e01e7", + "01a4d229631e4aab866e236968881241", + "383923d4412f4b66937d9c1779a9a0a2", + "d7309f0f6200411ab872aed55570a13b", + "341eecd25e7f4914a6d321e71e5629af", + "8e6be3d334f84619a97eb90c5b20369b", + "1850c472a3b944e0a1ad7c1da2ea14cf", + "de5a1d8f8dff49eda89a4787c841224a", + "407e488680a7423082ff32d0d538f621", + "78e3bf338a9b48de97c85af32ca144a3", + "e23586f2f3bd410cb463f05115de28cd", + "b2c04e1980b74abbbf69cc9e002b3728", + "1232037887da4ba7a758c387fbcd6afd", + "e0fa281b98c44f098569706566e8de02", + "f9aa595acf4048e5b71238e7851c6ce5", + "557971d30f8f4e5a889810edcc85cef5", + "1c7e644c56f04dd4aebc8775dc327941", + "0fb02107a2a6443781c755e3cf52da7e", + "0981a5c30fdf4416ab03bd6e32a77d08", + "b91442e818154b54b507fc915475fcd9", + "c600b853268249bdb9dd59bac7ead0b9", + "87af2bcb0ada4a92a70a9347753d50b1", + "fba26df1cd3d437e89902181641b8d1f", + "e3550f31da9f445d9319e889d614d4ce", + "e696375b6645453d9696e3728a959d3c", + "834ed98a1a724c3f9a9d6d6afc0ff5c8", + "b212585f6642467fb933f3ecf7c7293f", + "14a97d00755d45c6b369289989e1e198", + "8a0192eee6fb4140bb3e9696b3dbae5a", + "69a2bffb744248598ee21c61039b1aab", + "b6ba1cf44167429f8925b5dce367a745", + "476c6852a9cf4465bd6f125069d8a38b", + "1404ce42aade48e480f22179ce41caf3", + "4b9683d86ae44ad5b2edfe17d850ac68", + "a7690401610f4c1f9b8b2f022ad3eb28", + "28fc142140654e948ab1cf28c461d675", + "e5c6cae2c71b45fe8fee9657af246c2c", + "23c52a98648948738a11cf7421ae1b03", + "cd4e1bd4e2dc4db6a65bb60fa5ee5b86", + "d2d7cbe46af542f1b288c1d6f0b9261c", + "653c57247cf04ff9b099eb2074b6bab3", + "54fb7a15e03e4c1abd60432fb6129e8b", + "95fe6a8daebb4ea5846ace8c0806d108", + "adf23fa7342b45cfb18b9dec03ef2185", + "92c8f249632d4424aeaa57944a5ffad0", + "98dec21894e14ef1b4abf1ef233cfb8f", + "6ed4c3ba94794e819084aa09a836f015", + "aa340ae9bf2b48a391296d5b989acd17", + "03be182bd1124f08ba6320bfacfa59d8", + "6a37f1655c0b4a6e84a42ee26ec02be2", + "8cbc2e814ae642abaa938deb4f6f245a", + "3ded283182614210a48ce29c4a2e0de8", + "d475cf7453874e70b631cd16b95049da", + "b9b3c597f1eb4d1c916e7d7d0cdc7754", + "5a15c6466a254147ac4324b853b1d65f", + "366878b31b014e00ac598757a6499891", + "f2f0c7df12d94f4c8fbb758b1635cd35", + "910cf7e424e6433abc8a7763bcf9f323", + "a5f7a7d4a7984df9a1b88e3e4edbb985", + "b4d2525b58a54717ab604aae8ca2b900", + "71df3a6e3c624ba483d41f51774ea7eb", + "589b3a49a1f345d58dacd6309cce0eb6", + "9d68effe20754ea8b893ff1df039a07c", + "9fd91de5b1264429ac5e78022d2867ca", + "17da41600fe64bcc9c5c79d4550a7cfa", + "6617f391661b43588f95183f17f8386e", + "7a49a0485d8e46d09647834d200c33fb", + "74851cdf119c4016ae17d22984aa38c7", + "37bb476020fc4d578b7c0bc1878ca8f5", + "df8aa1da415f4c0b94746afcc377a092", + "32427dedc61b4fd0aacd976246117fe4", + "42c85b6e79b949eea51fd5d6c37a457f", + "79eb859310b04ffbaf0e842caccde71a", + "4203689ce2ff4a128302bddd574b33fc", + "77ec465b45574d12bf527a26ece473e8", + "658abff1dbf640b9a128c580aeb4f359", + "2d44a1bf479248ffafe28285995acb80", + "af05d9e08899432daeb185362a9dee9a", + "be38157bd0b2440983c2da950bc63bf8", + "46c91864ef384158b0078e20bdbfe3e9", + "64ec494ed8e348fc8cfb95bedb23030e", + "ff232ad25b184de28c8ca5b3b80db964", + "3131ea6f0f43420a911545efd7f495b0", + "5e6cfe2d5543419dad355550c01f79d0", + "e7f4c701048f4dcbb2b24a57c357ffa9", + "2c78dd65f2d0483f8ab9a97151d840f5", + "cd9fd5e350d644fea18a1b4942fb5b8f", + "1a767a727c484ff6b82c0a80f2f8649a", + "95e540c805ac49b4ae171c907118cdcc", + "36fe89a5c53d469cb8d3b0558ee6f0b4", + "704d83ff28c84dd487ef7dbfdbcdf2fb", + "621f6c1de14045b0a017e5bcf51b1e02", + "50ad43bae77448149a89d7f547ee958d", + "c5cd206abf6443e2b6fe8b1fa6cd625e", + "2b35d77a9d1d4250940400f231f083a9", + "f75d0b6dcd214b489751c76858979f2b", + "b5b41bbc26a14da196880ed0d8d7285e", + "1f49b5c9e32e418ab519f902501fd6df", + "92126e1aee8e423bade8def122e6c3bf", + "462ed0b290e94690a19238eaa63d7852", + "abca7ce88e104b9f9d3958ab34f9228c", + "80659d45b56b4b9bb7279c146bf0c615", + "54372e592c3a4342b705111fcbc4caab", + "325490cbb6884de5b2a3997ec1690b3a", + "7c249277f3ce40798ba420d9977c5149", + "0fdca00224624d089651853a09c165b1", + "f74b45ec393346ee95c74af5a36357dd", + "f336b5a0a7d64f2e93adc14715744b62", + "4dea8508053049789a98de63471d0a8c", + "e95a6f1226f44ecfa761b3ffabdde9a9", + "17f40d0ee47f442d9b9091d7a609e812", + "b3478092559b44b39cc1529985499e87", + "1fb985a5d5974bdcb412e91293d817f7", + "4997e6572a6f4de7aed48e800ebb672d", + "29698e1a487349f2a89a33bf1577f859", + "6016a94e56a046c2a3ad77792527239c", + "6b328f44ced14a09a4ce785a7f85b9c1", + "19db5d1dc63841dcb9ad6a7d13a60e5a", + "a9f4ecb19d4f4fd6810bee41494f7023", + "eda9d905b3f54609b467b557d5b4b31b", + "4bcef2f7b2854659bb9a0514d44436a9", + "4e91cf4630614b94862fd66b1efd1991", + "a8d7fd1391494d7d8da879ffcc826862", + "dec45a28e6f346648c3d6585426157b8", + "f63b31c67e0f433abfa8649ee6a4c64f", + "df8e4d7ce33f4aa985f1fe15c5af4646", + "0d4e574cdf6f48d79b1fe1337fed5097", + "9232fd7a693f47588745baed76c90910", + "e45b96c6981e47478ce62df63f8a5b9f", + "4b1730c3d4b040caadda0fa57d0d2e60", + "668e76b828014eaf8851ca2cd87901a1", + "5d3d8c8d4aa14d9db070b18c4c128864", + "0dc6f643c5aa4a22a8a81f0cbf3ac05b", + "eefd61b2cd1c4165a1848fce57aacd33", + "d6be8deca5904b818a74493612221e85", + "755175daea384176813e7dc90b2245a5", + "40949f6c79ab413e8f47ac74e7bc4c21", + "14fdec73c83a4207ae06313dab325613", + "11c5efb7f6514cc28b7df1c6b148bcd3", + "71853da424aa4b208e14f6cf430339ae", + "d03352a2df7448c39536223aba844d39", + "3884980ab7dc4e6992728947df26e61a", + "f199f190a54545a3ad1f2f831939c3c6", + "5963edced1504a09af5d1a5bc5d9dcd5", + "a1c8580cc4ed4966abfb47d195c33d95", + "75ac5035d4c54eae8bc096ebcf75004c", + "d796cf8784fc46169e3ac70375e0e8a8", + "11e0c6453f3a4881aa8d118a92787505", + "2fbb8f56b1ba47bdb6746d95b6fc2242", + "31ae4708a6bb48cfbd0b7397f480995e", + "049c234ae04f42adaed9b2fed13765d1", + "a0a775a17e8d49cfab294831ad05bbd3", + "3f44e79c7bb04219a782257eec0d9334", + "2ac6dd5ddea74e258f65c79de7f47558", + "c0fa4fa507074ed7b5f4f2b557827ded", + "21181daa25364e1d90d186edf113b82b", + "f89111d31af74ef5aad77cf283731c0b", + "1b39273ef9fa4da290e8af0678e304b9", + "a2b3757dd4544a92b6b5602bc5bc65c6", + "f5d4b4e89c3440249722b503b2aa3e35", + "ef95ddfdecda434fa90dad1d7e560709", + "ea33d1d2147740db8f28799438b3298a", + "20d62fed128845d5942720920dd1e441", + "a40f7f2a9f2843b38ac9ee7b26365b13", + "363889a835534d758fed0f9c70c86ddb", + "4ce243a811aa40c7a4ff2e5a6505d88b", + "7795c11d23ee4a1d94ea3cfe075e5fcc", + "a4f91a798b0f4a7188ec8379360e1386", + "f16b07e60e8440aa848db6f9610a138c", + "0b7dd58d7c22469a8583dcbb9b5d4c36", + "f7f352b61f954ab5b8c6086daa72c060", + "f8b6bf5626914e1e9f05d784e7cecc19", + "de1f77087aa84632a8d113dacafdc860", + "a7cc2764b1fe4cab91f358e790944c5a", + "a3db17aa31074ce490e288cc97d9fad2", + "0e9861e2a05d4814adfefc93ae0f96b0", + "e3e85978a98444bdb483ea79f2395407", + "7f3955b789b047a4abd29511941c3f90", + "858147dbf7db4b9e8f640fec74ccaa24", + "6f4ccb0c7d344fc9989af1f62cddc266", + "37a18af36f3e4d6384a37b2d3fc4049e", + "f49a08efb8a544efb98d4d806b0d1c27", + "e7945f4a49f3491380cd547e9c0b5195", + "bdead7a383844203b8ea245d464ce36e", + "0f2ba5e3a05246f48abe54f87954e034", + "3aa23ffa68cb4cbba1acfe983f8f4b4c", + "ee1fde7ec1514fd5a61790809ebd46a6", + "5252ba851ec44491a79a26c79a2827ad", + "d7bb2fb4f20149eab367d6ff90824f16", + "77db9590a6314582ac9504e785449785", + "386432d41a0a4515a90f3f99b85559a5", + "e0fb48b67b8c41c091e0bc2e636d0d18", + "f611e8cfddc940068758190fe9aa1d3f", + "9c7af6d33b8b4a33b778ca37131ecade", + "40023055503f4248a5e11cce891f9a29", + "a853f349137942558e114ced3bb38a58", + "79a43c562fd1402b8acd2984eda5d260", + "319e97220c7a458383fb4ab17551d95d", + "64d138851af44e2fad075dabf2039453", + "dde01cbb74db4b5299bac55dc74a27f6", + "b2fefa6f7af04c18966655d68a458974", + "549146fdc7024dac94ba5eee5dfbcb54", + "9ac7a85e1b7b4172afb7648ae270b7ef", + "683e2043a99d4bddb750098a934e3533", + "8745efe2cfc2425491cbd8a1aa5cc945", + "b35ed42afcc7461f97b5e570bdb99b27", + "0a1f4dac81604cfc9be40b1b237b4025", + "b802a7bf274c457a8f3fdc8b474b8c27", + "7368207bfc9c44f4ad874d0383bc7815", + "0d1eccf1b8de4722b3735e733aa3df93", + "8bf102698ed34cf2b8824865d54a6c1c", + "f8ccacbb0ca94ca69b436f80c504899b", + "658ef22fa0d64963af728ef45efd3818", + "6acd3ee42b6d45ae8d45d65150f26589", + "774914583df848b9949addacfe61881d", + "073746acac87484a96609d3b029fcd40", + "2b6c11be9dfe456cb64eabb4b666dace", + "798d5a5ecc6948c6a9b542520db9b4a6", + "6d6bb2a538c3423089077ba0559477f6", + "e3549d8f4dcd43b39c9bb1b447dc0ead", + "03bd1398d4fb417dbd1119b8d2eba072", + "26392f9f9beb4fb3ae16b6416ee20125", + "0224e1fb5bbb41a38d0b3d18aa58c607", + "a71daca5560140708880b9711fd9df4b", + "e1fd08d2a4a54f2ba56e445aacad9edc", + "c13f4ab22c7d4ab0814caba9bbd0c830", + "e5b01c717dbd4244b861168eddd67375", + "170f5144a7544fabbf203199a72e3cc8", + "8b7f97904ada4974b52bd6ad290e54a7", + "7aa9002b63e9405e81d9985790acde36", + "7c7b7cae6f884c9c9b90787389deef6c", + "3d79cc9684bd4c6094e1c0778e334ce4", + "a28d0e34d39b47c59d599bf7bc790fb2", + "699e7c7800434a8fb656d44adf27f83b", + "51600a9a53284b18a9b1623ca54d9a49", + "b6bedd6209644bacb5941d79cfc4a3ca", + "2a3c480e033244578c3bff0fdf9d39dd", + "867118c06fdc49a682c8f9cfd945d82d", + "adde1e2669d14286843bc9f1cff9ae45", + "9007fd1dc2694df89b20c36908b3b566", + "a0f2a58ef4484ea1bbd6d2ddad0a0979", + "2f3e1db91150408288b7793582da4279", + "a2986b0656e349ca8c4960533b99fd23", + "661c85f7cea14b7c81fb30b31d603cab", + "127e434667c54313b9a9300404f7f8bd", + "b46803ba0bc64e12b31f832fb761c4e0", + "6e765eddb3934d78b92ed5436fc84da1", + "e4c82b66f3df4a6d9f7714a77498aed2", + "db890a90256e4057b009023db65aa95b", + "05e1359c8ae14ca6965db3e7bf2d1e27", + "e2097054f3254a829b1f3857c20409af", + "35103e7f38d843cb9ba64bd66d7f0c91", + "7d3ab592920e4e98b71df547a8666091", + "609aed8d9cb84df5a139f276725b9b53", + "b89408effa3f49e68745d5b2a238c092", + "7bcae5766790468aa46dddee691b26aa", + "668a84366e5543dc8ea1ed8cdec16c12", + "237f35f1f37e4e3da20987e90229d6f1", + "af3c587256c146baa928c71ffe9eff77", + "67fd0ff6d64041759b89d4d093210a2d", + "0c35c6072e2c4447a94be5fe1f7eb615", + "4faddcf2b8df434dbd159d30e69d2983", + "b415d9ca46b74104b68f1967c7f38e23", + "259aa9dd98a74a1dac3f5e73aeffd723", + "b833d90258134deba1f59a54ca295f57", + "ef747c3b04974c0e89a50247e57553f6", + "4b43e1aafc9147e282a7ac34580d62bc", + "c3f33e2592e047c98633cf5c859bcce1", + "15771f3ff2434117a0c1ad2788207c75", + "73a396c7006a41cb94c756f44a72672f", + "94ee9b5b53894cd593462f18b2d71572", + "535910c6ba5e4530b4eb48382474b72f", + "66b1175827b349d183341514e3659ce5", + "e56eb6d72e564435a4204089a7dea774", + "f2eec72e7981438ea1b0ae65f1297fbc", + "d4a37e00cee941598d8158f712bc8eab", + "2353e9b40c4d404db33d18677848f68d", + "b2f7b1de22a749b5a52e392b5fcb97a4", + "d696e679e85e48bc987ec6df8116ec21", + "31ecdff2bc3747d19a51d49507bba740", + "569a71ccf4d94c1585c9573521fb998f", + "4dcb9fcf35764e4f96ed74450e0fcc36", + "0cba1db0c1ad4b469553972ac9132a7b", + "fab087c62fc3459a8b7664757d980c28", + "b8a709a4b82a4fb7b545fe178f8f46df", + "80c655fc179a4e068b03868fd4e2c708", + "75f07e6cf79c4134b4db95676d62d432", + "bc0e180aa9b14421abda4e665571172c", + "ff2781cf60ad42cda4a59359758687a9", + "82db6275c3f344f2a25b71dc2c6f0af7", + "ebbf3b4edfb8481f96f8e737a46d1fbc", + "266fb75edcf94c249ccc81b67c793afb", + "de6af2fc859c4558b9c06d811db8dd9c", + "81d01e6ce8f745778e2629bca80724af", + "76c21237d8e142729aba9f80194cd73d", + "02b2e984f977439ba549c65d8b3ad975", + "5dc66a375b9c447fabc6efc0a27eda4e", + "776d44b2465f4c2c856fbe74c21d5927", + "1fa7b593b3a44e3d835f7f9221cc5443", + "2c21f18251184d5091f7f03b429834ba", + "4f310c5e1bfc4561a8bb278f5d0ce7ea", + "ae716fc3bfc3441482336e57898f1534", + "59f5e54839aa4128bdb440a7c039a320", + "78a0fe5048d44c98987c08b1a1ba25b5", + "8d66a96bf8de4bb1b65c941b2bee65e4", + "30178d8ee92949499854f6edaac8574f", + "c8b7b040ee4946af8d2bf9b52a3936e7", + "cd9ef47d964d4fcdb170718cddd521d5", + "e304748a4d704299bb1c37bb6f8cf40e", + "22081620065e49828b7cf120d96331bf", + "ca0e357931da46bcb19eb9401924876b", + "343915fbdd0c46aabee09257e724095b", + "a6c297837fe74bea9e86bab3fa2413f2", + "5f84f8429cdd4b12ac3be5e189fcefe0", + "10b1a03ed9c445ef88b1a0818996c8b3", + "2b9bb9af2afc4650a24539d5fe9ce48c", + "7dc14c37570f4886b444f819f19e14ae", + "f9419365096c4fea909d0df8edee0668", + "ed92cac6b8d64ea48ea4f91ce9bf350b", + "064acd866664472496b99205b64cfea8", + "e5c13fa39f9e4b83baeae7f5e18107be", + "f343508829314d3983658a410a8280b9", + "5742a9ea0f57437dba7d2da6c6f7cd86", + "547fd15df95e46fa9786cca309004aaa", + "72df9741d1254c8f8e30742a118d6f1f", + "967d4eb1f46e450eb993a948c766431a", + "5c416044a05241728e7b5b076e1065c3", + "8c6fa4e7e596447d80cd4f2ac11727b2", + "7b0f1626f4ae4764b8859cfecb5ff3b1", + "7fa6b107be4b4c19b683c6dda6db3b10", + "aa97f90e44664441bd7023abb290ba78", + "fbfb59ffcdf64a708f4caef9c6d1afba", + "bf149f8c21e040f9a69fae8e35e68e83", + "5edd371a120d4a40b1248e79b79e5fa4", + "eee4d3bdc5734cf6891db41e098e7cd4", + "6a1c3ed6920a4c1a81d1a995f62fc11b", + "f2a8992ae59c4696888ab0fd35a22ea1", + "8274f23ad7c540e38734f9eaf048c40b", + "fea999c1d8d64eb4a9c2bb1fac1e7d83", + "3fc10df45a534661944db3dd7dfac9f5", + "916a0d7844074ea5ac9a60b1f21bb6ff", + "78aeb85f59224bf3970b0f7a734fb209", + "f50a1d6bb7e640cc9f03596fdeb2e0ed", + "35ddd05927d346a09ad6c76911530c6d", + "a3af48ddbd224bb1bfe7e5b96f7530ae", + "6ec4ee91d6344924ab7d0fbf36e2a9ab", + "6a6a154724fc47b08ff0b7ed76260b4d", + "6167fb73abe94fbda810020123d0dbdc", + "de017be6ca374a5bb35f652f48d841d8", + "d783caebf9654933bcaa63641fbe223a", + "639955874f824bc381702faf7684d779", + "d6b42202060e4d23843a2b87e786807d", + "f5dd1fa1e66c4754971d0d35b0bf2107", + "ca73e13a79404bcaacbc0c425e757d2d", + "ef4bc2b9b457445188f619a7befedfcc", + "a8f930b0bfc442e7b4e3d9fda1d12b4d", + "3748e33f7b884ed1be58704a73c064aa", + "558aa0e9c3d24232a7d62180fa0aa1d6", + "047d421fa2044bdba0193c2222a2b8dd", + "4159867faf63453eb2d45cb64f0cc51f", + "1eb7d441c3964c6b9d467fd8a4f530a5", + "baabf607c4e044179f16835f9501aa05", + "5212c56e65f648d48a92526dc993ec11", + "d8ec0f4d69fd4d8a8b42fd1affe19a98", + "3957490cbadb499cb69f8404ce29bab8", + "5462485e71ca41f9b6d25b0eecafaee4", + "5f151e09f3394314b11f64ce929acea0", + "b45e9f62b3c24de5995935b59dcc332d", + "be6ff8750f64417d9eb55c1ff4762d3d", + "4af08e1e8f594444ad79765332f299bb", + "c34902c474b14ed6a927f67d79e0cbdf", + "f857ecf2fe3d4113b31d6be463d8d645", + "87126aab996b4aef83aeaeae238a02e6", + "7a383f39b2ba46129284ccdad3c1c05a", + "516c343dfdab47b3bb042ede6164c405", + "eaee5c918ab74563867f445569eb65bc", + "99d1c7b4f5f74b4e995409e748c7ee59", + "c6f31f3925384a84ad558e67f556298d", + "fdee35447e1f45c490af19036f57c36e", + "e3e6c10f4d0d418ead167df69c583ccb", + "14e1cf1e810949da8b9b5f1cecf834d8", + "f1a6275d011c409586bea27362d83866", + "0675f7176969428a9f0acb2b5cd49dc9", + "0a0c7e40a66d4fd090f549599f2f2c9d", + "79c4367011ba477088f1e14cc18d945d", + "b83f50a2c08147efbb548b62bd4df830", + "3e38e8351c6e48e786cdd8bd181a09db", + "a2a202875da94dab8040e5e78198b989", + "7689b0f5bd7748ffaaf378ccf977699a", + "6671c5021ecf43ee8090646df1db9935", + "b2d30398ba3741da9f9aef2319ee2b8b", + "5bd2cda8deb04409bd0b4272966be972", + "cb9e69ff974944ba92395e30fc22016a", + "a68f0d31a16d48248fce52f6a14f68c7", + "3d56939899344873845881b06e41776f", + "767df84ba8124538a9a5cacb52df558f", + "c63dce91ac214d56888307f74f98cc57", + "598306d7b9824f3eba00c1adaf225d6e", + "e55a855a9185490993b56a69ded8f310", + "6cf2b68f9dd749ed834dea0f1a1c1204", + "bb8962a66bfd4e8ebc0148c0f30922a8", + "2806a8295c81461db7a638c8d65f7014", + "e32d1862e0294f90bb645bb81719cde1", + "92cb84778eb546d39cf57676595a626b", + "3993424dc5224f14877464b6a656804c", + "0c18856042ec43458ac04a4a0ed9311e", + "33aed51feb14402d838060745731350b", + "e96157df7c4b42eca68e2706bb3b3436", + "3bb35766260f453abacb88379684d68a", + "93d9991078204bc4921269c3c8fa4576", + "c1dc6cd22e474ac0a8f4d4b854aaac37", + "410e6857d64f428ca2bf698c156e4929", + "1d6cd1b21030449ea6711abdccc123ad", + "96063f5197ce4a30adffbb5bc052c809", + "e09437bc2191442285e0a242d2b80a8e", + "f913bf792d5f480a8786e1ebdf704c4c", + "9149df9577b5475f8a9be58751ef56ad", + "8a213c84ea2b48bda0f9dbb41baf5041", + "ac7e638e8d824192a456f6a792eb9e6f", + "01ce23ef2f7f452393d7c52adbe1e7a3", + "757c9db98fc74368bbf5253d2db649a2", + "e03abb198f644cc083e36350769d7273", + "8462eb40332e4967acc2009b337414c1", + "53f1dbdaf71f488d9065dc2d4ed26d5b", + "c4d037243de9441aa5aa7e8f30cdae39", + "357d2f25e3a34d16beea1ac295b33091", + "4010b64c855041eb9ce0b8989ec4a6b2", + "b7a9b0e884c849d3a0b93a3a6aa85bf3", + "c389697d92ed4f1b9b942a90524574c9", + "0283a4e6c0364efc812e11ac5473137c", + "cb2e60edf56d45e8bb99a3b4af05d514", + "21739197250649b59e5a61a0afc12d42", + "f8274dfd12274d2cb0224a2ac5faf987", + "978e8a84ecbb449cb45999c07bf49e37", + "7ce5f0c169a0433583e25b62c624780d", + "bad26cec6af4420b92b203bd949bbf11", + "89853a54227a45da8f4cc067772753cd", + "9477467748ca42078e9d7bb82bd0c4a0", + "980a0ef080ca4208ab4b9c3d2fc6aa9b", + "3a84dc988add4959bccb3630e5649f0e", + "53d103114d73491cba2e9bd695bfa096", + "bf96f1edf4a34c3d8c4a16399e9729bb", + "f372ee8669c041f1ba528cbcb883f644", + "6f4a0b64512f412aa46403796201ac1c", + "8c262e6fd86d442ab0fa4b37ab46223e", + "bbb9a990516144c6876e3997f39584e2", + "6894262234ed4fb480a75039aa84cb05", + "d8fa031363904202bb1ffaad296a9988", + "46327d1128824b0ea30207de66dc11b0", + "e9f24d0dad3c4a8c92707e3b28870eb2", + "dd04da681eb14840946432070d59fa81", + "a6a829207d4547efb9d7578016d44332", + "b93830a175f4466fab6bd4350fc8b444", + "5785199fe2f849c295cd2b40a5cd6261", + "a1bc54d8b7184609b34a0b44469e6fb4", + "c1b0df74db66467f999e58066f3c175b", + "63e2c5d8fc7241ffa9b03e3f0091c231", + "00e1541b9c564305991941ea67596264", + "69819f011a8d405291f2d3450ecbf38d", + "94f2b4c2a34947819e3446c7dbc169ae", + "b607773878844cf88e4f4ad26c9aec30", + "19ac15dd0fd840ba9c27c0ecf9575c4e", + "0017fed1dd804ec1ab2e06bbdbebab16", + "6e22f0a4099c448c80ab8dead3a82155", + "9355380b20ab4be3b0086c57afa6b766", + "2fa777c32afe4e048ef4067635790c24", + "315366203dd14506bb215d6cd97662ec", + "08d02c1c33dc44cab79abdb14175eee1", + "563540b49d2e4033a29b829595863fbe", + "efa711534830453f8420f84fdcb8a85b", + "67d6472151714f539b28601592f0ea4f", + "8e8b342613f0477182ec8586876291cf", + "c73a41d4fcb8493aae327e039dfcc67f", + "8626ac141a2547e685f337fcb8aaae1f", + "acf6497a3d274d90ad3750510348f07a", + "957ef4ec8f954ecf8c31e4ff7c5868d3", + "5e7466230d364a6d82c05ba985e6e767", + "de69307eca7442f88c9f3bfe99300e9b", + "0b0b32949c754e58988f1c26023e1077", + "cec005829c0742148afad726955f4f00", + "a7de61a7e572462dad81c0dd0c1e5f88", + "57465415c0d045229c86b003493d3467", + "06b77ad6945c4f78907d12ffdbc9ccba", + "166d2bf05b1341b38d67466ddad292f3", + "71478cf86a164d31b4b41ff6aaf4a43f", + "4231c988122a4ba19e672dcd9ad1278e", + "03c1fb786c064f1e8dfc5dbb245dde20", + "fc96bb126cc8421798c9e2be278d1b5d", + "67a63e18584a40d5a5d63a9c3639e83f", + "1315415fe2c7459aba9555c31fd68b31", + "e2a4c49d95234571a1e421e34de0ce06", + "f7fc563719d74b3181ee200cfdf7f4bd", + "5750f70ac6734728b0eb3ed81de9bb2d", + "2a0141217f9b4ae99abaf1a1a01683f1", + "7c713e5e80684f7dab36ad5339302a45", + "a0c5f4b61f9247239d682f314a0ecdc6", + "a0ffb62bd8d84e18a6e0926e838f29ad", + "2718349782cd4ea38cc1c3035b8b118a", + "faf947997ac4410d9cf264a15dafab82", + "3ef5b607164848f995fe6b5071ac2192", + "a0c69e27fa2a4f21ab0b2b4080e6ee92", + "6b837773d0c0406f9532d858a24febd6", + "baec7257198e4747964ae0b291af23f9", + "7845bdc92976450db551c1e2098b5826", + "5da936d387944bb89d4d1a76950abd41", + "03c16e1367cd438c90c884115b208e16", + "4c520860a87e43b095050b120eef7443", + "1f60399f99304ff087274e0e39352389", + "8fa970254c0f4246a740cea6c0df008a", + "fa048c4ac32a4d4988214a5e3fe70a86", + "f873d34a30784bd6b64176e3111e4fac", + "f25f1d5b761d4e0b84305f1c467d1807", + "2dad32be0d884b5aa7be75b1f3f2663b", + "7ba2a00a9cbb42eabbc57e697dffed95", + "65e18a7f558c42b28cf090858071b744", + "09fb5f0c73004aeaa9ab1b119673fa33", + "a2dc5b4ab0eb41c49bb2190e9f6f48bf", + "3d1845c62a6e415498e8097520d8b3c3", + "71243ecf771e413199b9103b5a444b9c", + "9d87a96ad2484cac95bc54d88a7627d4", + "c60d0446a61d4558972929a45209b9ed", + "f9aa5e60b29d460abdcf6fd618297621", + "0351104bf3bc4f91b2a6955a2a23d7a4", + "ba68b7dd4cc34c92ab2745644dbc398f", + "b10454cd501d4d7187842f471de153b7", + "52383efb54cb41d49d1e13c4f6d92da5", + "a755d424dd1d4a69a854ac02f7f86f83", + "295d60432e3e4e269412002f4c316f9b", + "89135ee7dd864d83bc3b2be77b53fb1a", + "f4ab0103956b4e9787ebaece0fe574b5", + "34d438b4d0d94e63b8ffea3ef0398d51", + "b1c09f43fb1c441e87e652d67d5fb5c4", + "8493a64aa0f648c1bca44b6ea141bfbf", + "fd5bb0d5f7c843fe8b9d2a44d9a8d755", + "f02c038597824d2e8ddd68b45078702b", + "fda12812ab1147b79c1a6c7aa3adc5f8", + "4b4519ba5f1744f4be888d4053c452e6", + "e4d311c0d1c843c197954c9c1ec23f90", + "cee94c045d7549c890f88f6cc1493117", + "4dbe23827e054bac9277d2ac7983d52f", + "eb6fe03160f943c4adc5c731a435124e", + "7c7c839a76c44f36be942b1c87b040d7", + "498b84a5ae0943e8bbad6ab2cee6874c", + "847d1cbbdb794e3d861340c8d5f44ce2", + "0a6e6c8cf2b544b1bb2c97c3f01d925b", + "721359a5c0cd4cda8c5a378cd1e83494", + "8a9031ec320e4ec3b25f79039fae1886", + "e5bc00cffa4c4aec84006affcad2cdb1", + "0b5c61ad2f574e28bb98cf00db278ce6", + "c4c987c8e9c24969964749f1312ca3e1", + "e70d92d72a004b2dad7fc31870ac494c", + "38e222a6358d4b1dbfd9b0e00af1b6fe", + "11de2b21ec264c0a814ac024c45ab425", + "5966083fea14434895ca6e0758843455", + "8b6d6ee79d824b33bb3bdf11f80973cc", + "35cf77272b1546a3affd2a544cc0c576", + "00987713fe994f4fb7c765dc82810ef9", + "884a58e5bc1243c285d126a07aa76f02", + "7fbe323be68742419263845302645be6", + "ea777c5753e1412bb7b7b93e813d7dc7", + "aa1cd41249774e5e8105f5b74b0e0769", + "d525ae1197d142f4aac2bbbb8f64a171", + "b2509c183e404a2d89c406bc0f40243b", + "db6f9bdf3f2f48828e2236052a4154b6", + "c5da9821e5684103bf0e6897c5c69b1e", + "0d00e19a512c447b8bb9a7b1facb2791", + "415631f4856f4348a584a01731a79fd8", + "c5b79db93a1d41d78025b65b0d102be1", + "415f69c1e91f456f8b4219f25d7d4c16", + "fc1c8024060849f4aeffb5d2ee1a5234", + "f531c888a2c648e5b10be6a7c6cc67c0", + "70ddf004ecb7474883d26cffdc443250", + "c0e11012e5054fa889b937cd6c7dfb7c", + "503fd41365d34beca9fa18264f7878c7", + "da9da86e081d4298ab0765ac30e67717", + "c217b91b31874729af7bbac5524c4b64", + "099f7ee70c7d4716aeecb05329009702", + "e2b56c8d16364930a8afb80846ae84d1", + "583dc574a5654b34a39b6deb11ec535d", + "6b475ce70edc4399b4364cc36afe3c9a", + "2ea82367c9ee4256b45e78bdfd83f199", + "1263cab3a38942a1a8d6ab2dde6bd524", + "e88e9a2ce9a94cc188c6afad074660dc", + "51b55989fbdc46e1bfaf7ce66c2e955d", + "7f18296ae3fa48efb3b22f5d4b1351aa", + "479541eca11c42bd886793db88ceee6c", + "2eac97eb3c6c4675bf9ecc8436f11892", + "31fe323db905406e96b3cad6d817512d", + "7c8c94ed8c324cb6a7dfe6ce9fc084ca", + "0648e61d41504518a79b027332e67540", + "8a290792c0a44febb78a8ec0c7e4e590", + "528e34393482454baa45e0e9a09c7e51", + "0960f8a9850e44f082cb7da10ab0d036", + "c270282668134f41812d5743bad2889b", + "caa582bdf5824596925d7be27f8b349a", + "b58584132d3f4a18a0be6af1741f8970", + "6e31419378ee4ed799c00422c3c3fe83", + "4947a747442a4feeb12af2ea53e01d1c", + "67e0ff55d772445db4f55b91f0afc6fa", + "348feed6e4054b4d8eee1a3ed85e8a99", + "866745e5e2ae470cb19fb36e5b74af4c", + "e9715aee26bd4e03b2740547b5b259d0", + "2e4dbee39f534f0cbd5e68657979fa86", + "0187a1bc282745d9990758bed96b6df5", + "64947d2112e04f429884f7293f0d552e", + "cb145eb6068a43bbbb50672350550f7b", + "d3307264b4b14e079ba5c861eeac839e", + "cddbca0ef489488398388a6831b47e1b", + "59abffa7876340cfb2e0dcf12fd4587c", + "bdbe20ceb14c48a2a28ac26822d2cc21", + "eb29cde83f4b45c7aee94e37f307eb65", + "5c39125c2a194864878ba816ce6bbee0", + "32c5f698e4f649b5875830ed6e10ab70", + "4ca15b1ecfc7488aa1eee308c2167641", + "b0a9471193014762902799dea45fa52c", + "796b03afe6604fa0891ebc06dc0e03f1", + "939d2bc7260d40a3ac5593d88df1b823", + "514998cdcbd94bb781df40e8b09ff57f", + "8c452601c52f40a79a1fa2fcaa144524", + "f555018527344d4cb0ed43ce7d744e07", + "57331b4986414fe5b4954c3ee81112f5", + "0c8fd12242874a259289ffd22a2a7654", + "4ca43cc270fd42c78c9d0566dcb1a5f0", + "e79308f01b124bb6908831f9b2505721", + "ffddc991690446d399adb67792063d60", + "745c1c723d26498e9681cc0d7d065b3c", + "1c74372d1aeb4bf2abb90358352d4282", + "679354c151984747bb74310ec5af8995", + "364298aa0f7c43daa104200ac70b199c", + "2e304962bdcd455280433a4a8eb971c1", + "ce77ffb41a4c4ddeaee066cb6855d715", + "690711def6994d419a54a6371dc8dfe8", + "27020c400f534b9caf83d09e8fb4d5d7", + "24204dccd16c4508bd0cc291de6980b6", + "5776fc6d68684c9bb9d19bc950ead580", + "0c8da673ce884bf9baa588dde30e690a", + "aea7523d6d5f41d7833b1f4a0ecf8328", + "83bf154f7682461581bc6ce066fb11f3", + "1572e083b9e64b52af2d3e76e20c027f", + "9c241819e1e64f1e809f9e1d5bfc0d63", + "df772d5a4c2d4f849f44969a4664fe4f", + "47e3fc610c2d487c98f37d6932a8ae87", + "6064b009396f49048882cc26a007d991", + "2440d24c883c46a4a6c21e3cb1b6f323", + "9454e6c9dea245f08ba88be96c12f126", + "111c2b04ba6546d89728d08248b08a53", + "46ab248d51954068be28e4be30c83ebd", + "039c6026571943d6ac45c6816bcc7ff1", + "bbdd92e8b4e24723a4b3a293ea2dc577", + "0d1ef6080f6e4079995f73a2600269b3", + "d3a5f8daefe14149b9c6163ef9f42f23", + "3492fec73172474da3e10cb2b682d6c0", + "d450768fadd546459c31d900c64aabab", + "a35e1cb1d0fc4befb288c0d93e068edc", + "999599bba2be4d1fa7ed855091645711", + "162f7255db1547c1a541eddad32d14c7", + "5debae48de7a48e0adb1cdf1dd35eaf0", + "2df64ba27a7a4a0b8d00230990b970bc", + "464537dcc5cf48c4a0ff478945cdf6cf", + "3da7ca9ccc654a408c7b97216e945bba", + "d4f0d10c9c884dd084890eb895a84f9a", + "b51576d61e654517a269dd9e478b83a8", + "8925787ea2a44f238f0c4ca745f2bcc9", + "83baae4b0e8549939465307d694a97b4", + "18b2160d27d54850906d4dfe7e90d63f", + "23428abd790b4df4b7506d653f563905", + "59d409193a994ed9b3369a04b7f3ad14", + "11e3537a91974cedaa7dd3222c9c58aa", + "39a05ec9dc3b49fab9c6114ecc6c06dd", + "0aea26afc5f044a6be7bd20be75bb911", + "46d9c322e32d4cb38baace9c1ed2933a", + "d1639a54c8914994b09efd4fb00ac885", + "0beb78c11c0f4537a27c53f8e46ddb86", + "013cd050d65a4e828610e4755c659729", + "9bd8f9527dbc437abcfb03befdaf1f6b", + "e5c9e6632e2d4807bef920c0b805d2e2", + "1d18955742df45e9875b28d382a33ef3", + "e64166631f324ac5abcacad21c1bf033", + "2fabab9066a14c029992d32431c6a753", + "3af23931d6a44fdb8cfff1d381562220", + "212f2713f3704907a2ca16c1546cb8f7", + "e2c01aea6c3d439dbbc57be1f059b424", + "6c8de8ed57284ff19202e778d3cdb330", + "d498651cd446456793ad3475ab16f12e", + "b108ba7884dc4cfcada005ec52b49684", + "54b03a5b14994d76b5f8a0f24b0e7f32", + "a3968c83f2dc45509712bc68ebbe95e4", + "92f5f7ee6a8046bc982d7bd7d76b416e", + "ac1be06d215d4428abec190f08156ef5", + "491b5d0ab76b4951a535d62da8caa466", + "1da7fd7aa7fe400e8ba7cd3deea7cacb", + "9acb0b1a53964a8e906bc7425e43a6cd", + "a72d8d894d314232a67504a56e3864d0", + "e7dd6bcb6ff141d6a62a0a9279bd88fa", + "3bcf2e379f0b48bab7969c6aa4f038f0", + "c8db5a6b6e0947c38888f476b7e4bd23", + "9ec30763ff05447aa89b0e9c781cd083", + "0b3813b60dda4ee3be416fff9166f794", + "22e4b3657c5d4e8fa429c4dd14d0c6d1", + "f0916a69ba514ecc973b44528b9dcc43", + "6a53dc2e9da84da69f709c3e665f4e5f", + "54e4d4102dbc43148e02f89926809367", + "a813d59401be4d3986e066505ca8e2c9", + "4b6af44cf17d41eeab1076c3b99e4f5d", + "07f8d7482f1e44149acf81c8fbbfdc0d", + "f2afb8bbbe6b4e489b096627c88db8dd", + "910c7adbb78544fc8c846f62a7052749", + "fcaba41f8ec0430696793a384189d0c7", + "6b5ee48e336648729e7a82f3805a55a2", + "9f2a85c6b4694ddfa307df5b16bb821f", + "df446275558a4dd3b5e46fe5ec23b647", + "8f711295a47e4723b7c89e837e843b85", + "01a259e3c4f34e56a33a4e076bba8458", + "cafa12d984664b4e96f6fa442faed938", + "5440c587e9b64ea5b9ed70c131698c37", + "94400495243d49fdba409876deb590da", + "d4febbe416104e9ea90cbe3e73c64250", + "3ff2ab8f53de44e6b74dd3564598645f", + "09203263a3154b4283e1158a7abd63d5", + "0fa49966a0ea48f7a96a57feb167aea6", + "600a996f3b9e44fd912beb8129b5f929", + "57972124483145b4a4bbf4fd4caca6e7", + "087f976a313f401da2d38f0df73905ff", + "da436f5030ed493a863900b5f157b3b4", + "77a7cef9019c4a50b982e315b38a90df", + "3ae3d0a680ad47639672cd126a681af7", + "a728d4a3dde7463885d7a5889fdfee04", + "2343abdae7674f46ad85071858db93c6", + "4ff4cf0cedd54b1aa63be8f376d9cb87", + "1a55ff246d0240f19d8b10b06f93d461", + "57581d6c2799478ba5a2592eef055b41", + "d3418042e1214ec9ab693aca7ad70970", + "67ceca24e6234eedb0ce7db7b3e32489", + "6c77dfc55d34470991f77ba78fc2bdf4", + "d16b62a128394374bfad53e6469f4b0b", + "ad96fa619da940f88b4a9eb4c1013ab0", + "bd8e92fcbf4a4a5ab7e96d89cb3ddc6d", + "aadecf1629c54703911b7007e5ca9042", + "6e4844738ea04abfa200cb5ecf5b912f", + "c7533cda6cea4adab86561c7f5e2f675", + "436aea34bf0f43d591362465baead3e9", + "4a6e764d56f2496e8406e162e4852e46", + "affd4ebf5fd143d98c1b7c76eedafff3", + "699d0f6476f14be1bd9193cb16344ed7", + "4bbadfbb42b841919c1b66ab3714d065", + "ae83bed96e414beea7abb0e823d60616", + "7e18ae2c3b574b20b4c86e50fc96cc6b", + "682141ef5e4f40e5b0608f835de49c63", + "a7e54e9b61b946b28722632582bcbbe2", + "62d7dc8d76324dfea5591aa7b536886e", + "f83cfd9e3edf4b4abab5ca14b0b28ec5", + "d38ac696de7f4506be4af16a9b364bfb", + "8ed3b61a67b741d798f6d842390e984e", + "3204d1a914c04f949fa48f7ff84c689b", + "52f79ac9ff0b40baa30feb68018fade9", + "833149db44c9422182927e1bc278240d", + "a759edc5f9af4ee0a08391d2c5049c0b", + "938a6482de1e4b00859d26f3bcaf1d90", + "08c13168bb094895ae5a2fce6d3a8e11", + "fc5f7716bba54284884136ca1403c59f", + "c803f1e61acd408f86cd7f22e66fd3fb", + "480cfc5b09ce4a1bb6b262e3686077c7", + "cdcb0fa332344a32ad9f6ec81936acc7", + "7609d5893dbb4fdb84a6190d49ac37e3", + "684f1c02ed6c4c3aa8571d8d2addc737", + "ffcdc8ec5cb647b3893a2746bbea929f", + "b6a6865d41fa44649b1db7841255c2fd", + "378d0cabc6a34e339640721bd7c73a42", + "fc085c8a49ba4252aac5916bb2d43691", + "a686626332e2471482f4e8df4d4a1bf9", + "efae5821496a4e8a898b5915300acc6b", + "16e61a9555f4486e90c0256b100b40be", + "ce76aacbe3d240228a2e69812b1a5a7b", + "cc9bface960c4e7c8c0f14245f985eb9", + "3289c148eda54700a379685262c62480", + "3eff436e33ce4db3a54d4d8edc43528b", + "87930f0080814d65b5add1987327e122", + "7ba258bd0f214106b4067d753aa518d7", + "9d494e4e32bc44dab959c1ceeb7b5a9e", + "160ffb9d7baf4f7fab4c0e828e8e8585", + "e334ab27591d43d3801f1f80733fd51d", + "59c36e80c6874222a6e70c21c34671bc", + "e83c46aca4bf44c5afaa0b00f590d714", + "fd77489fe5054a0e8a1e5b2453154d2e", + "98ae66863ff744c6bde8f74fd2a3ddc1", + "10e836a1ef464011810be12f9c94324b", + "0c33fde02258414895253effb04404c2", + "466f71e295014c5d8d95363d4e28f5e8", + "8682e434fb5748309e7dc9ca453ac69c", + "2070615c282a45cabaf657adcfd825c0", + "f1d64e2782fa41738b314ac12bbb1ce6", + "86903f719a9347e6bd1e6c1a2e07989c", + "2e7a7ba4e45e48858424a62e4b1490ee", + "5fc166b5dde54a4e908da332410d3cde", + "258799ba04874be4a972b13eaf180fa0", + "23eb3ec772b94a83b985f8f1a7495337", + "6fef8debf5f64a478b2fff6858d51201", + "f802f7320e6445648d49a7f48d2cfda1", + "bf25f8f14f5c4218bad49f50e2aad000", + "c4723331d1a2400d942c00004d59e1cc", + "536619c65a554351908a02f2c82139bc", + "4a0a520b5c704c1996a84b9e8164c345", + "96c9dfe0456847a299e75f74e76b4bc6", + "3e4e82e3f3aa41b6a83680cf5c0fbece", + "978a8795190d4e7e91026d43be4b525c", + "acbc64addc98410582d1f631dd9b6d5f", + "55c427ab7c554a13bf17f26dba37d439", + "0f213ea073e745e6b014cb7c6a26880c", + "84908780ca9b437ca979c050346b63cf", + "1da7eaa2b1db412ba5eb3369d6b2f18a", + "0d2c70bf8ec14d9d937f518c6d3b416a", + "5f2e244f469642a4aa603ed121b06328", + "6deb4cfa403441778d7bff062999c9cc", + "5c18cf20f0484d76b44ca31b57198820", + "beb3a53feb5147259c301dbc437d1916", + "d1fa52427e0e4ed9a678beb6dba2bc4a", + "a210744073da4e289c24f1c2efe361c0", + "0e4facde034c48f49268db9af51ae3e5", + "ff70428886374665bf737a332cb251ab", + "7bb792a75d524954a752adc9c75c5329", + "c28fbe6267974ca19cb1ac755a1a981b", + "9409fe92cd484e538487d7bed5ff252e", + "80154e53679a41f184eaa14ac8c103c8", + "47a3abd6f9644477ba7f25e82c9329f8", + "b63378bbd98548ecb00c8e5feb70fc79", + "bf4a2edc7202496fa62b2029a6057b1b", + "382363ce5b5f458d9332eb8002326c7b", + "9fa3bfd86d404d70a91f8fe126f9174c", + "3efb27bc2d694cc982bb076cc017c674", + "e2ae7590759740708e6f2f5bf01d531f", + "bd598bb78e034b0fac362dd3f1fd0344", + "859161b7ace44f44a3fd9fe9e761639a", + "efbe891ff4904a9db85f959299143d10", + "bd09405bd03549238f69b34d43340d13", + "c442c91673a24b3798065d76fda3b4e0", + "187b8c3f1bf14305a96c056bbcd29b46", + "b4889cfc22a44e09b2c25c538413b92a", + "498f16743d0c4127abad3b933f011ecf", + "90e60b55f99c40dda4c9901c950b194e", + "7ce5fa13c2f44d0399d4d238448400cf", + "231af8e4f0b74c5195062cb2fcc4eccf", + "c15bf550c4204805ad848c2dceba99a2", + "989d796409514627807378b1feccbac1", + "367917a6948744de966d887e7f803b23", + "a60e10dc03ce41b88c504781108e2279", + "f5afb7a324cf40f9b61d006cbe09a2ab", + "033c0d7ca2bd4236a72de5f9ce7ac110", + "54fed4e3d9414df491b0788ddfe96580", + "de241daccd4b4f8883c7b2dceb320ec0", + "a965ef61e0f24077a3de4fe2101e8acb", + "493fb514801d453e8482f52f6f6c2d89", + "2f9e7a1893674e01bc0d4f8ed425cdf1", + "2a82621f274445ff8898bdb620465f07", + "01531de593f3468084dab12f6515e8e1", + "b4bb8bd7791648fdb36c458fd9a877bf", + "6010ec41025e4fb78593a2b47d1ae6eb", + "040cbb34282747d6a1711f3e37dca955", + "e02e53458df04a7892224d312e17541e", + "57be766363f54139818de1dcb1f89160", + "b9e73f29c3c54b06870cddc6ae4bf03b", + "8d6dd9025be64fe4aa64d79710a7a26e", + "af30b6a1f86e4438b7a877dbe81255af", + "5505a440ca4e48c28d1134199a2d54aa", + "9995a134badd4551a356a6e258546c4b", + "759ec098a2c74d80b92f02eb1e61339a", + "de995fa74ccf4a0db10ca697e55985a9", + "d7d59bb76a7640c99bdccf4dba341a5e", + "a3b27c7977964cfd95fc52e179b6e978", + "f16ccbacda724e27ba5112b5b6355558", + "7693673f97534564b8a14968ad5b31d4", + "80f37a9fd5ef4d4e8547347b6a352be7", + "224d642a9d4f4f7084d4099659a7caa4", + "a12059a9ff8f45e1979bd1af6fc1b8b2", + "5590bf4ecf1c4c6198bccce96c225b11", + "6cf47eab249c4ed7a476341a9f4a6758", + "480f46fcf87348de80a3c9791281824f", + "7e98e7cbaa75492ab11599c26f13f3f9", + "cb0a873201044b8aa5e4c3212fed3b19", + "205a055ff47d4845b91d473b1908bae6", + "ab1fc61c834a4195891e102698b09b57", + "84a1bf68e96f4b1fa2cae12182d09579", + "7f5c98f90a5f4328a4c1769c4ef2b8f3", + "7848f43625c44f66aaf9ce5f180c6fb1", + "47b0f679a93845bf90a772859b48c76d", + "6e54a7d3b4cc4917a6e40aad4ebeef05", + "6adf7d0fc9a249d7943b1d55d613d0ec", + "f6fb07e9270241f8900d89bc24f1b6d0", + "3b3e4d1af0fd4a62bb0b628d358fe492", + "40e7a56a66a446e0abe605da4a2ea454", + "6a29261b38e74da59e481dd45e6d32ac", + "8bc14b7bbb1644ce9c3318998448b586", + "296b31ccc3e241ffb0c9d3e2a4d6c037", + "78f56308852b4a5a978585f00dc33538", + "45381c7f838540d88ed85cd2f00cb35b", + "f389c30071274bbf9a80214f93011c31", + "d34e37b92fcb452ea2f1ffbc81019210", + "a0d66f10a850469c9cb04c3cecc62a05", + "313d87d0db804ff58ded52027608a0b3", + "18f8848d06eb4119834ace3ccdfc3d11", + "94279078f1f242a3984954068365573a", + "e9edbd0c027c4f648e1405df96670cc1", + "d72ea381caac4711948ab868220a4322", + "9a79954b804440a3b4008ddc4032886a", + "b2418020928443ff9949eecfff8c7050", + "9ad231a5335b453e90bda43c3d35e1a4", + "47a0b404e6664be0bb16efdc46a0b883", + "ea9b05a36232472784c6cc4067cb93f0", + "20c89dc0f8c64d89bcbeb55d11840ed9", + "5109d5c4fab04719bfcf37ae153e14e8", + "0e44906698d74142a58cd90addbba927", + "70a41b78fd874b1588a18e0d106018bd", + "6dba40d87e2547d4b6f764fa36ff2bbe", + "57d2db27bf97475dbc1fca6b1365f961", + "d19afcc9bc1e41b6bc9c67693c04104b", + "d081a5003bc2467bbd12f0c5a990ed92", + "dd9c3e237b514fe5ba0ed825d39e40d2", + "d1d0e427e6d04de493d80520c1fa2214", + "e20b4ef5131b4d81ae013e4ff5c13da5", + "c2c9174c2ade465b80f82cb2d481a7b0", + "3da4121117424cf69c7304e1d06b17d1", + "fa24ac97d25a4e20b93c7d317311fc8d", + "95e44b7b6a694ce48e4e1e2eb561d942", + "06f2017fee444e5f923826913a862d1c", + "f73c9babb750479d8f76b3743c80f72e", + "c6a7c73a08e644988f9d2163dbddb0a7", + "8fca912e2c96495e9ea669257fceb51f", + "9f3755f4bbd1432f9819c9ecaa800491", + "15926885c602418cbae100dc9646cb75", + "436df87f858a47c390771b7a87a1c3e5", + "5aea27c2078740faa9e586410e723a4d", + "ed19baeab2d54fcab07afaa73376f94e", + "3c21f5beb34345bc834227d708e4d830", + "b53fb9b3547148d7afe84a073ccd99db", + "db31a6c16269415cafee6c2fe7377fb3", + "d701121f4c564cb0b4de821d5806987e", + "8bf8b18c2fea44f1a37f9c6af2a7d96a", + "afb7f736230448b085927d4e3c1a0c3c", + "7c65cae0690a497ca9e21d914c4e0ae7", + "2c54d1c79d27428aaea4d0909cae0635", + "1b41570c71164d84bc9e426eb51069d8", + "794b77a3e4654a669cf259d20dc89ec7", + "e0aaf0b7368441019b9ceed6ef46ce3c", + "df5924e3d0ff4e78b0b87cff74dd3e1a", + "4321403fbdf44850ba2a69a568e79697", + "075324292fa94ca09118a11a59121171", + "742fbdd5bf314a488494a4afdba92b25", + "9faddaf3ebfe4405a8fdfbcf1a111206", + "81fe61e043ba411c951e4b3b80e82ca4", + "b0ab1751605a4415baf206f2bd9702ca", + "49b4fa6bb3bc4add924191c8035073ee", + "b33e2ef440504da1852011b74bf5625b", + "f1946f7e1cf1456086c9a1a63f9f4f84", + "177ff2ea25214145a708301b2657c529", + "3d043b85f1ce4b29a3fbb03763c86203", + "84a44a5ed52f47188c8ec347fa58f971", + "e18c3147f7084f9096c6b54b094f08cd", + "534c7ef382f34700800f72f3374a10c5", + "a1d1c782e1c14d29824a8f2983198e9c", + "8a0f0c2fce8c4a98bec307362e254435", + "c1f47a4579164a00acd1a0f7a51357fd", + "d96dfe460f9f4b71a14369e5f0d5dd2f", + "0a6d26c4ce564f40a9e1d75a2ac465e8", + "6cdd6964383e41778e517abd6d11b3a7", + "a5ea47eb11f24bc6a4d4e47caa30b6dd", + "55f16de75dba4bf7adce3e1ff5bdfa46", + "62897c52e967469c85df9c6abdd09d16", + "d6aff073561a4a9f84c9d12472f17002", + "947997b3bfff45ab81f1f8b8f60ef147", + "804c8cae9b2645079d98822e3dcf9746", + "c4ee70d74a7843f8bc89ca8d86a6398f", + "a29735b52f4245b19211a4e238c4b328", + "b03c2f947d5741d9830305bb7f38a5a1", + "0ab2ef32d5664516bb513f04eee43f03", + "bba8f4448805408aabc5038e2ff2fc22", + "d8a7829253b3474c9912b578f50ed124", + "964e418c7a73480cb935680ed9d397db", + "f9f2c474b4d44b868a45bf4bd00bd846", + "5be9012283c340de8d48a59bcfa0a39b", + "5c27d3ad6b6d4161af2459de16dd2308", + "c441f1249b454165815c523984953cd7", + "491cc61dd2b841a380220525c28db4f2", + "b1937273e63247c29080b87e250cdf03", + "63a3ea4f23624a7f847c75cc8d68359a", + "5b15e014a05a47359ced2318378d4cef", + "3bb4f120d0df42fcba3dc4f550aaa9e5", + "a453e90d47b74260b5e5ccd5a965fe3e", + "f880e385deca46519ba8fb5348c978f3", + "0b0eb4aee3cf4a558f6d4d30ebfa18e8", + "f8853612da5c4c558226ced5f5c184f2", + "94291db4b36a4eac836b6ce85290164c", + "87bd7d269c7e4c82a1ab1521c13683ff", + "c7e4c17e948b42ed9bfdd6b8b7663890", + "035aaf61dfe54e0896cc519473fb5326", + "2202fd5e261949b084b8f4fcdc65452f", + "79decd9b09d44e04a47219011547355c", + "efa6038b5c054b3381333632bf0e9a55", + "652c421271bf4a05a97ec80063f04919", + "d73899c4b476436caf7070e67e44fed3", + "8225f2f58a9c4ebbb57fa967ea76e4c7", + "4be0a443bc5342ecbba273ce93ab75d0", + "295b000686b940dea40a8e6090fe1e95", + "6a0a93cf64ef4cfdb06fef0641286a06", + "f36f865650a34f578780e0fcf95be99e", + "f726fd6afd104ed18cb4bbeedbe7ff2e", + "6e6984811b3c4e9ea5fd16e1fa47517e", + "6c650de87ab6419ab8952f7235c11ef2", + "a0ae41c430ac4f1190fff89a3c565b4a", + "abf96a604fd9410b92a523b90239f8da", + "5824bdd7838247a7a319b3fa75a9feca", + "091c13376ab444db9ca72b965fa9df2f", + "f4053c234ce442d7b1d29d50f1824a60", + "5519c4c436c54946849d298f0dc13744", + "359df41859394170a14ba8bd2d2cc58e", + "ef2b63cc98944c95840cd6c8c522b340", + "1b28ecdc02f94cfa8bfca5c774143667", + "83525b91ca114a2586eb4ffb95a9318f", + "f190c41994ba429da60e259788e761eb", + "f5d3d6ee6d564038982c4ec2c76c4443", + "725de9fd2b784fbd9ae995fbea498f62", + "3160c6c53dc64943bf107f7567c7dda1", + "6f782c74ea4d4ae09499da4be2e6a2e8", + "34c44be877a8445587caff24fd3436bb", + "da9d0663569b4354b3aa9f57c3ab4f3c", + "751c51a2901148589d373a973c348f0c", + "739e9503bf7c48c6a73efdb24197ff5a", + "b6e77162f78747abbd85ca4a5c5ec487", + "0ae0314810814139b3dea039a86d6504", + "02ff51f84324460cb826bf2a618358bc", + "680bd6dd918b4834ad309d892ca5533b", + "3af3fd64bb204529bf14694598b076fd", + "33b272fa3e7345c783e4ef0e9a0add76", + "4ffc8ffb491f4db49308f4a730ae24a0", + "636d6a9279e24242914799709502b258", + "0d4bbf9da3a44860b22c3451c7c94ab4", + "7b2ad0c3e4f94d61a46d1e567f30c2a8", + "034ddb9bc4544023989f3433a613917c", + "15e01b41d44f412a842cf393d4eb73ca", + "9572ce7f1ea64768a968b600827e39b0", + "fa5e949f97e3479b8c389a445fdc49e0", + "2a89aaa64c974231a48bea839a21c879", + "1cdf3d7b17ac4939af684007978b613b", + "b6f9748a612f41e9a5927df500c3ddc3", + "3aa6b75b5512461cae6dea9613be60e8", + "f2be311255b649b2a2d5e53e058c70c9", + "917f8aaadff04833a8601caaa2b76d95", + "20d2cd4a0ec3455aa821aa2f76ddb521", + "cbd8cc04489d41b08c1416c3425cfaf5", + "6e29fc211b8442dbb0ebc9dddd595ae3", + "94fca8c5ac9f4974bd4a02e8f571f493", + "32fe2467659f46c5a5709f8f4f0be91f", + "91a6ed16c2e64df288f140d56282aa44", + "eb4a9828d3084b34bfc4275c9176c176", + "5c5a6601578346aa8ce974453909f175", + "b87d332af8094cc495292f6d711422b4", + "2aec8d7d14a648d998e8e49a4f73960f", + "0b1cfd062ae3438883d9ee59d0e592bd", + "353d9e6667a042b5b086302f1309ce8a", + "aab131e254f24e2abefef68ba774688a", + "a32716b79ef9466e8eb51746573c520a", + "3ed05d0386d745ed95ae6ec7f4ee86dd", + "494141ea32bc4ddea488dffa0f5910c3", + "4b88c4c4e94c497ca39f831f374e89fc", + "c40d358a515e4c66a506e5d8d6530e8e", + "2e7fd233678f493b89c01ef2caea0444", + "8433e4d4b290427881443f02f68abc39", + "c4e48ed13c7040759b269e645a33aff0", + "c2b8d73835134fdaabf18ef05a645221", + "7d3ecc2271b743a78c33b7c97aed0a9e", + "dcb1415a4bba49a682b313eb9cf88e76", + "0e3a24bd38a5430ab7bd333bb95afc1a", + "e9711685eaf84b78aaff96427871ef54", + "b635aa9db17743a6958f0f79211b5dee", + "95a2d518160a4a8dbcdf2f23d101fef3", + "a059adca68374be684d539a6620d9a47", + "c52f445eca564ef39def020a8db14ffb", + "e5e4ab0b38da4540aed5244524828fdc", + "e57b4f6baeaf4d8a86d054b7e02406c4", + "f8d4de00a0e741bd80fbd50cab1c9397", + "e443c0863cf64608b68b18e76c83fef6", + "bb774df5bc1040859d93fa9d2f28d9a9", + "7a697a7690eb4befa603897cdc21c912", + "c5a122c1cada4410b1dcfec2b02be30e", + "544270f711e94f38ad6e5763a0be9043", + "da8eee14e6aa499da34a93614ab38733", + "2f0598cba938424688cdd048a90b8339", + "138289aa08a3484399d45bb8713e1afd", + "b68ea4b74a9f4a0d8c9d395f964e48bf", + "23cb7434839b4ce889d3573b10a735e6", + "f2670ef082da4d818f3c44635dd1358a", + "64bced0aa85b4723bc398ea579b21350", + "090f958eb69549c99510fe8cc8a65b67", + "482d68a13dea495ba8f15fc7c13f47cc", + "32c421ed129d4f4684a2a82b3742244f", + "9529be282f2d4fc7a237168d365cb64b", + "c18644406e1a434688d13d84d7356022", + "0e5f93240b6c472f9ee1bd9c86d1ec8e", + "8dcb53d1b73841ddb6a1122220870954", + "e0b72fb2bbf64e4ab03bc3408753a236", + "f57bb579c5da4b9c95f1cb874ec558f7", + "4bd5fc7619044334a4517c82832e92db", + "b78ac5ade0104cd6a85c51e60565aa3e", + "ff79f84eef294f46a68cb86836a9efb3", + "4d7a9d11ddaa4bfba28f2e73b3880ff1", + "5bc1e53cbd044057bfb06dde2d22904e", + "a80a4073a4aa49c78d5da80bf67cf715", + "5afccda2b78943eb9ea667e95abf1e10", + "fa91104769ad4bcd8e244ca2d22c858e", + "dc0b4b97fb2748a2bff5edc5c0d7d804", + "6696691cb494481192452f4c255e97b5", + "6d93d9e10b204e0b967c02a08c6feb6c", + "3cffb7c3028548e689f26817cdd8a6ad", + "1a4bcd31c5a2408aa93ecdac424e9e4c", + "1dd9473a4ccf428bbe4d3f0ef9fd2d0a", + "152ca55383b2491e816f5ed5ac127677", + "277b1be2dc2a4ac0998e86d7ba3781c0", + "90dfb9e99ddd4b4ca414be7599ea6469", + "da670284651f48658e468f4a93684877", + "4cb4b30b98cf4d79ae792ee3dee671f0", + "9a572040fbcf4e469330c27c92463ad8", + "3f182e0da86c4592bacdd693683b0232", + "8dce6f56f6584509a6137f7e00925a12", + "03352d911acd496e9b53968961234d5d", + "f4582dbfda394f32a5677efec5a1501e", + "c351112891524961bf3288f11f5effbf", + "444277a220bb45f1bead2fe4973ba671", + "a8dbbefdcbcc43728407c14b2a7608f6", + "ef1ce271896c46d39ce97a0350a0210e", + "1557f1fefc314cad8c603fbc6f64d0fd", + "a061628e766240afbd148d2bd1719dfb", + "0550851c03d2440c831f82bfb27d0f91", + "76c11a26bbb540c0aa9960272598c1ea", + "4fe8d6113f354715a2da2a5552a72dc9", + "ba49973ae14744a999a53749667c9092", + "1ba5627725fe4d4782ad5ca6304defb8", + "4bd0d6250de94dbc920468bfedc53fcc", + "24985d8633fc4a999fc18ca921fb482f", + "bf94641134e74ace8b1735350f2421d5", + "26f516497f9f48caa7c544026bba8593", + "f8e006b05e2c4fc5ab47db65dc4c70df", + "128bf307e92f49af93c6fa10b450b32c", + "796531a764284083803f6f8d6030d249", + "f394f4f7f446474fa65e3217923bdaaf", + "a2040583041743bba0088c906bd9ca8a", + "f046a38e397c404e999c75b546236d9b", + "4ca7bdbf4a17487a85c24160f6cfd6ed", + "e0e9f9f7b70e4be2b150f4627017ee4f", + "00439fe1c7c24522bf408af0b2c155a9", + "d86ab3f2c9934fb79bd82458fcd350a9", + "374a3d2f72364ad9bdaf29197ca2f843", + "bca97093abd74ed08481c5acb7d7cd90", + "feb91b2cec4d45288af234a50fb71fc9", + "495b1cb96b1b479da86c8ffb7e513ba8", + "bc0fe39ac458416ab28be1b4b58827d9", + "11988638b3104689ab1f4275598f6ff2", + "346f8647738d47de867b105fce5b983e", + "c93d4294ffb84bb4a106df13c395d0d4", + "9f55423e94c4416895ff8d58a33c8317", + "5d98c7ef664141fdab4ddb4e1769888e", + "61efc01dc0ad4ecdb82aa0d0c96ef565", + "41a38cd6fbe24388a13c5bcdd58d4260", + "27bb4436b0ab45abbc2a152198b7b885", + "af1e03fb8b2a4bc79e9f774a6c03f248", + "e37125dc47654359971ecf964272c564", + "ca2a115469524c4ba15658c2b1535dbe", + "9e0f91d1cfb54804a0ea67ad6a96f5fa", + "0c83005b0f9741a48730a4b4d2e45173", + "25614319b28a40ab819cd33133b8b159", + "0d4b9df784ca4598b98ebfeecf71bdc1", + "c79b4fb3af0b4ea6be16e9d973077441", + "621e66026eb14c7194646b8ac310467a", + "362d90fba83f40418a165ddd9d2d9eb8", + "2e7aeefe0ee24b478126af50ac8a20c5", + "c0c65d7ef38e4babb14cebbde7bdaa0f", + "bd8d97ccfc3d43d09d27034e1a9edf31", + "ee91cf6dcab740efb0b04449a6b5b20e", + "8abe0e78fc644fd2806d228355c2c90c", + "9ba6aeef039f458eb998cbdd672b3952", + "ce52621fd0a44c019a9369215df8f593", + "c63e2dc9d7494ecea070a5ed7e427639", + "f151006fc2f44f4590800c219a022e0a", + "1b1e585503d6435dae2dcb0d74679712", + "76b4b96296a9449798163ec9ed455604", + "1880032c6a634cf18b6e58e0972d4e90", + "97bf00ffd982411ba3e2a60d67e828ba", + "db5a7d5bb378480bb40da086aab44c65", + "3957dbf8d80d44cd8a450c803a048c85", + "9b4e163476bb48abbc243f6beb951150", + "bd51773c52e54812a88c38c14935ae98", + "51bb588d4cc546168478231e25729200", + "28d004c0d320423d89b6b4421c23df2f", + "da9b588f7a7346519f391c3eb9532226", + "b09c4dd0706c4943b2841e75b2d6da69", + "0c9957338432477bb6eb6f0609bc3062", + "f79bfd54e45d4c06ae51a533a60103dd", + "625869fc843b4fe6a4009d5871130650", + "bd908c01773b4a0689e7530cfdd4f74b", + "10ee955b62d14841955a5dbf9f9e6095", + "90bcbd233bc84ad399f7f4312e4c47f7", + "e99ad810413f4baaab072dd41b6e348d", + "f4ca8ee7da6a4b34952f86ef26274d5b", + "f26063c8ca6a438d9e328b28434d1c44", + "49bbc29f9be84c55bdb53181d74a4acf", + "7b2cb99127ee4179862b7c6e11d04e9d", + "3ed91f860fc6461cbe95361f3b80e1c9", + "b959a8e48f1a4fad84d0a9bdf6d1bdf4", + "4422df496cf043e89e059b39f763d709", + "c05684e8316a4631be60fb1ae92532f7", + "f2b0222f35984e599bd6d5913b0b3844", + "9f0de396187d48f7aaac0486d12f1a37", + "377da8211b0349b2b13d2339eaffa4ac", + "eee7385ec3ab49e2b8e3f08ed9e38707", + "c0140b76cee2449ea527feafdbe141bb", + "9f4e65d9773b4f80bfca6ac8a9c8b952", + "7c3981520cc84a0d9a914e445c2d054e", + "9d2b154c8b6348ca8a59ef45dee347d5", + "5670e755313d46fca5f4db1293228921", + "f78e6c976e8847f0a574c69d3d0ed256", + "e90e3cf7446f4c0896b67dfcea9eca0e", + "c2540fdbfc264dc8bb1f6c971b18366b", + "af8a5e3c79b24be1bc69f9891d95868e", + "a1197fa450a3428e88e13df8219e423e", + "e9b75b70e22b49f2975f9fc9d3691af0", + "64960b8c8576499790f0cb2670b37917", + "ddd2962f03ee46dbaf584c8f49e5fddd", + "d5a2ca06677b49e78868350344752f94", + "d3c01db2df584a95912a2e4f9d49d128", + "0fb58ca488b64298ab8af6f0372e66b9", + "630b7d4aa7554d5d928e3bd35236f968", + "ff6320c916a9400586893fd0494413cf", + "8409e64103fe4f1d829f90adca90cba7", + "7f6414166ef6416fb546c0bcbb1f4616", + "9626b82200e44a5ea4a0ac5cd8020e3f", + "e64020d77c43497ab77b9848809b9222", + "b6108cc585c94c75b7ab4022c3a13533", + "38f7cf3a785f4c4e8e5c51a2952045b0", + "05b5a5da1a0a4c1fa60a9e5edd5c3424", + "31293307f7a947a28a4ebbbd1e0a81f5", + "c372447be4d442d99ac0efff37f695e1", + "4ad94e7f0d2e44b1bc4e2766503997e0", + "ab0ec6f2bf8c48929543ee65213bb1cf", + "aa22e5ba7a474ccbb135fbab14b713bd", + "8f4abf0c719d42109f316ecece72dd75", + "f68f4306256f47cf8c3bc45748edf8b0", + "2bb1195ed0f64af1994816e0b091043a", + "edc6ad9455734d0dabadbcaee9f9a0b8", + "675d89b3227241ff95797446b49bfdb0", + "a03242351c6f4bca9f4fe359ab27cff6", + "c8c8e123b85340b1ba425f77f275d59c", + "3e8816e5e60949429f8e6166b9b004e3", + "f44fd3d626a1402c99baa0a971f8d22f", + "2cbdc76448e44f1d9b20e44ba524c270", + "d8f970bc64384f64b5846f3cb1344d40", + "388d8ad3f60b409683ec9bbc741499ae", + "f123ef50ca8d499f8692a66a18fda6b5", + "e2bdfef0f4154c62929d4518d30c81c1", + "d53b49d528a64d7d958a0cea0db534a2", + "addd8acd41c948afb8dbebc0e83ae6a1", + "b77c631e3794478d8cc5e603cac65e0e", + "2ce349f95b78493f8fd15c103d84e5f8", + "ab26773159c14c42b63c556323559c20", + "de32ba1d09be48858e22ee9395fcd814", + "d9176822f72f45f68a3f65e369fdc9d1", + "aa2b985797b447f39d25cc4ab18e6e87", + "4522a16d4a1f436894eff3e00c7a11eb", + "28c7c30b5be84de290d43b89899ecbb4", + "b37f526832a7478c91c866434608e414", + "9249e4a1c92e405da59e0f869fecab98", + "175e4e432e6f4304af73c7fff56be773", + "108c4ca4251348bbb026b59373880a8b", + "8011c858d8544b338eab4c864f701916", + "cc3f2e306e3c46ecb96bf47631bc76cd", + "0a135fff072846f2b27a8152dbd63eb9", + "eed46e56a6234eb18d5603f8e399cf2d", + "705933739e2a414084beeb01671ff7e1", + "2ea7ce56d81243a3bd5aa3c69cd5e093", + "b6b28aa8ce634df4ae992cc8154f7368", + "5a3083e835ac45c6b8fdf66ffa9bb5c0", + "587c32d50ac0448eb0809fd8d4c2314b", + "65e5c193702e4be9beb5ec783c422b5e", + "7aa2f0637fde49fca76cd0651936dec4", + "7a725e6108e34c4ca11315171e87fddb", + "545e62b9b35e403ba92f71bb19d8c74a", + "44457c8007874907baf0f4cb1d12fe6b", + "b89c9db0a6bb4ae3bb745bc3e7e4fe9a", + "a7652a3d813a479ba93cf880e466789c", + "5232ae2dedce46b58cfcb41171e7c1ea", + "c9fefcc588754d6d9f1b9d9be4247631", + "08aeaf270417443b8698a44af7bc55da", + "1ca5d1ff541043ed81e289068f46ead3", + "88d21787a85b464c9592472d0b62051f", + "44734b4051d84aa0aeae7c6dad4d8c3f", + "3e575430bac047c6a5f064bca40b5065", + "b3bbf1348c1a4c699b5654704a848555", + "fb74e652b3af43d3831b86235ac799cb", + "af61433d65c1494cb227fba1de935e28", + "3d780f883c6548b2849f98393e466388", + "8cd40f962f2c440c9caf1db1a505357f", + "7564358b73614881a1e838a0827f10f8", + "a63d5b273ed74801830522f4b4c9fb81", + "4f4fe076fe624d2a8f198588c64fc6cb", + "5dac8e8bca5c49d6b85b6e4515315884", + "0c1a7657bea0421dadef56e2080f0297", + "af6ddb4f17a54d74988aa78e4c98b51f", + "00e75d990dbf499b8f6ddcd09f9dfdf9", + "4b63af7c8b4442169c6f99c061085173", + "ccd6f54f7b254ed59e866e8e8dfad326", + "7649d45e7d6f408b9b5929ab51895dfa", + "6fa6ac4dc24c4802b51d05e4475bbb2f", + "db36ca0fcdba4343a0b0ff13e840a121", + "dd8fdc8d682e469792d432389344a49a", + "d8563064e64d45459b86281613ea4732", + "fb08eb8a6b944b18aa54cfc7431d8809", + "f4f0fd05ee884db1898fd7c0aab57711", + "a59b9d2e4dbc425580bd5c4f6bfce60d", + "11c46ff362254a23ab3e241cab1606f7", + "56420652b36f41b1a42566754c1e7099", + "4d700de3fdf84cd5a6e715fdd32fcf35", + "561ffaf55bd441feaf10512052289197", + "a6c86e1745dc458e8724f54dfac2a760", + "d45823db89ef485a88788f8c0a03bea4", + "87b4aecaf25a424a81f76d7c5da5b701", + "ce527189c1ca44d59b24a6b6118ab21d", + "6545f20ce7084f4e8d529afae5951045", + "d05cc75aabd6450994fab229d59c9fb1", + "6ee71b1571464747ac92b5a1d0c781c3", + "68e4c9f55c5745f99cbec22e816026d9", + "0892046f3c9b4d8889e09d9d1723addb", + "50408e40786244ebbb9392d9ed1f4313", + "6afff5c83f1f4f989b53573c26072828", + "90f3ef440b4740818957fd5f4b44abd7", + "7fb40ec36536459b9c1e6d6c344f806f", + "36b8cec90a834e03a2bed6bb27bfe800", + "0da7a740994e47418e6bec9010fbca0a", + "f801c2fadae34fe28b429024d146e524", + "e4f9d51f88264bedbea60ccc147ee79a", + "e8d19ae2e41645dc9eae55c9f948b34b", + "acf277b9b5794255bdde428f08803721", + "ea7b55a86b8e40f495deaa72b445c323", + "46afb19e0e9c4f06a15e027503665aad", + "76e550147371413ba11fba13ee712bf9", + "52189db28bc744d1986dcb7e49ba4dfb", + "0aacd964a119468889ca3fdb29e3fa1f", + "3396e5219f4649699bc3b357b21e72a8", + "76c33dfd6f5e45718197206d23f1fd76", + "1e744cf9ae6f46c7ab67a211fe3cc7dd", + "8a2ffb84162a4af2ba3a6560d10bafce", + "d92b146e697c4376a6fb039a1812741d", + "af37576ba7874147b3dfa5de5f94e35f", + "d515481fb818405fa39b16ad217031da", + "85fe5b8c70e44492856b5ef37dd87e50", + "79ca700ba2664018bc7811f4bf549bf9", + "005f5630a54b442291aeb0a5d487353b", + "ecc5a1833a6f4d21b32177796912efe0", + "c6278518c51e496a82687982f545ac3a", + "390f8e71038b46ceadb86df1b173c859", + "a57c5e0607c0416ea43df0a68fcd2c2a", + "59dd69d81d5e4a408164a523a11d93cc", + "39755b394ed24719932ac54e3584ee92", + "131f3fbd70c44e58b965ae2d92c66302", + "d41d5f32fd8747d1bfe4b31d302d8e65", + "e1907c831863496bb6f86eda076525e6", + "789fb1d496d54218888ead2fffe05995", + "edb0d24e92834f0eb3dd1e397a7de89b", + "b6d5e398382a4f72b22a898f071a194f", + "28bb1ccf95834df78ce479f59ce0249e", + "0825562485d8480899a289d941b473cb", + "6f12fed83e6145b6b74982c804eaeaee", + "7437ba359a5d4eff8dceadbc1919f976", + "6ff7cc2b7d674c36ad22dcb366d687ff", + "d21894ed7af24cf2aef2752ad5026dd1", + "cc31edc74a7949d7b3d35a092cf5ea09", + "cfba13ac9ad6440db68d6a65c22a01ed", + "9ee738251ebf499ca1b64909c816e6ff", + "7cbf4aa231594b7681ed6badb6905207", + "e5db252dcdc74bdf81cc4d7be5c03160", + "22fe649c27174c0d801646a75c40d54d", + "f45017f01275462bb7d8dfd1aa979a65", + "ddd491e7210744faa0aa7dca03a0bc43", + "0e88f25b5cb1487786ccc2277629d16e", + "aa02865509d549188c675d389b97e2a3", + "b935aae74fa24e6ca778f4b48d287143", + "d2206995e6f949619ff50c9d84ad02f4", + "a56c0691cd0f4dd0a046fe35c3002486", + "d3b46595287d416b8da57183776ae4ce", + "f32e2f4ae4a348e3bbb3c97753632e6a", + "38ba247199924158a8f84a6ba88ce487", + "b45539a475734094b4eaa89e5174b3d0", + "5dee033716ce43bd9d5d17f2d072f88b", + "e730175fa6e942d3b42c00e8a0addfbd", + "4c0f32f6c51c441dbfccb40d84738548", + "b2db46a3cb60418ead8e87f312797561", + "f1eeaf4e00c84403ba8d34111b5f3941", + "e546dd854b744467b0aa37bd36bd499d", + "3b4ad34125c346158b00c2123a2c4ebb", + "c0ec4981fc8a44e3a3ca5fc80633ebde", + "ed4f893a583148bc9573a273fe7e3e7b", + "bf851a4a22034bb68b80ee21ce834011", + "bfcefcb8f6c644b785ae555319075e3a", + "2dd0cc6b57dd4042b5f28153022e5810", + "76a0fe4d91324b9891d81faafa43e8b9", + "e569c4763db04a32b2bc23361b82b3f0", + "fc53dbf2b8954f12a1285355cadb4f99", + "73d71b0bf2dc4beda4e156dc79b53c04", + "7333990bb2ee49c9b677487f7e6ab1bc", + "091643a9a64044458e75c966225d2669", + "5a134fe54c3140b093c0660e63f0880e", + "42abeb524ecf4c099c427edd2e99b121", + "ed24a23acf7e435db103d161e3229693", + "04563f114c6e4205af0d34051314f876", + "23e929c482c3483399fde042cf9e9208", + "99cd51a8f0c0478088296520c60d5c65", + "fa2f80dd8b20433483bbfc8accc10af5", + "9945e1eb5a6247cf9623506025d92e7b", + "95c6132fafcc4f4aa1217ecbedcc1170", + "db7339a98f464ff38e3c3e32c924ca65", + "d8c234eabfb24f6a913cd4aca0f4f85e", + "813e7b26e9c8409caec3a42f26d38197", + "43c8c807b35d46978658c564d876b0a2", + "c1184fb4187b4bfc95b27ab3e841d457", + "08cbe7908a6d4332b280add48a839b08", + "37c1b68a67d44385a435ecda1281f708", + "a1fdce3add9d4f4783b9122b9239c100", + "f3028a1392e0434ea32d318458dcb99d", + "d77a46bb8f634cb68f2ed9c6f2ee0f7b", + "436c3a375dbc48da9ade6ddc3d86e0ff", + "1f3102a661544e6698cf8880e69fec41", + "b090482ebb694deaac77c33353b9a65c", + "5c08d95755954e109ab63fbf997b818b", + "33ba899b46bd40da80a92e4594639937", + "752a244b086b4822be8e7b39fa63c5b3", + "c188489f4a3b4148b399239f94b1ee42", + "ec978083c86440279af2f71d7c3151ca", + "f1018bef8ced4fd282a8b94ccd2a91b2", + "162d252bfe6b4317982ed3436486f02e", + "2856dd3c61f940909dced9a5c0379484", + "9d1ad8b8512040f5a200bc3f72577d8a", + "16ca102e1e25437ca4362dde60e03204", + "4ea243b23ba54884be1612641f20d6f8", + "fae0a272f36846f2b2e80b8c318ebc0b", + "79b4a0919f794283bb1aaa22361e50b9", + "ccad57a6f40640248a023dcee3d5cf3a", + "c93d61ec3bab4ed387c4cd80d2b332a9", + "94286b5575f64bbb901d26ba63669d80", + "81da5adff2dc4157893f59f85ec2fe7f", + "6f333e67706341649ca91580bb51b066", + "4482ac8c3ef64649b62d6f89369239dc", + "87838fab264940329c3d66f3ed6ce30a", + "16cd5c8bd38f4934a5b65d22c599b83c", + "d4be9b208b1b4f238692875d83286a58", + "99b8511cbaeb423db9a0c1c785895218", + "34f011fa3f0e4cc3b01ba603dc6e0d20", + "794712e7d8a14367bafbeb2864f2695e", + "986e6f1ffedf4fea876c61ffc189570a", + "d8dc05000c26495793203d0323bca8cb", + "bc50fd5186ac41e19e5ca3248b64edc6", + "e12699a3bd4149f0ad113fcaad8775c3", + "9ded2a6e40694a3aaa855801727e4e82", + "47b60d15269e4bf196013aba2fa2a7f1", + "b397436a707940459c553883ccb5a00e", + "6ef81c26d9f541bd8ec9bc76e2855d2e", + "e8eb52e846114e16b2c121143b8ceb8b", + "fb83e182d15b4b03a920ecc4dbe9371c", + "32361cecf3fd4e44b7313b69b17b0877", + "05ae3b8566454f3ea749d58417a64820", + "a8f584f6b82d474492940018109eedee", + "23ce25036e4545f88d60d1d6bb758ebe", + "5ea65e6a2f0a4ba0a0e72b9f5ad36139", + "283cd9d821d34bf198be2d0f4d42f2b9", + "86f3695a2b2945c9b6428e094d580c33", + "4332a99fba004e5898e68981f7fd9da3", + "5001c2a5548c4691ba665003201364b7", + "0a7ec762364f45dc898d116d22caf70d", + "ad65fd36ff284655ab9331e2e8a5a8a5", + "a7764bb862df42ceb3cdac2c611c9449", + "1ec8c12f4fbd4987bfde21696d0c91b3", + "dca97787b1b24fd8a0fb6bb536e383e3", + "24f0c5db0f4548f09bbdc57cc61a4353", + "1699128117be40d9a0b2b7437510ecc0", + "1a812a1d30bd4d6492a8f87f701a4d31", + "f061ec7b2e2849a192ef97919e2c4f26", + "2f1d7b4938354282b48675d1ba9d8781", + "efb74c2eadb5416695f3c76d59c97470", + "e380a379439d44c1bbdc9b2628ce8867", + "43b9a729fed7414fbcf5510575e1a851", + "b5a90e8c6a0e45e4a52b5f81c9771c84", + "eb2d55dabbd440eab651dd7085fcdb19", + "a8cc0ca704fe4d7884a73a8d9f8bc797", + "5280a3f6ee4941c192b38076f3e8c546", + "14f5b8ed45da4450b5c3f606a59e64bd", + "6eb9a282a122476b86d3650b04f7417d", + "e959f4481edf4ed68f5b6067e821cc08", + "44e652f9f89e42b2b40fece12aefd303", + "47536120b714418485fe5740fe0ca810", + "e0f809c14bc74e028c1ded8297241f2b", + "f026592a945d409784985b46e3876cce", + "b412805b19c94f8283b8721138c6869b", + "24113eec279d488897a4997d5dd1e128", + "37ba192f3b094ba6867713477e0cac58", + "090a0766293d4bbabc731c151178f2bf", + "cf71f2d412a5491ba70ef8081d553272", + "51cc688ae4254e30813e0bdc5997af1e", + "0880be4c17d34b95af74efde0dea22c3", + "1a8cfe144d114c47b23424dde443a775", + "88a6d3f214b241808815bfcf45890dc3", + "58ee88f2433f4476bff50628b11fde71", + "b400ce18d4a54fa3b0b434d184e9d4b3", + "a66c812b381b4ac59774e24872719d1a", + "3b28f114b60d4fd4b74931724666ae55", + "84267382977845f190cdc740e4977f43", + "5e6edddf49c0419c990f68a78f2a2a22", + "e1e4d1cfbbd048c494236380599dea66", + "ce810a7347024b6a9bbaf4c4bd6c6a2e", + "45216e1f214441fea910b60c1eae6f64", + "b7c8bd2cf3a44192b537028a165cc3ed", + "3c6f61a6436c43639ab6ef5c1bbf2b38", + "cc3926d95e094e08b0912926fe4a9502", + "ec1a1391646a492f907615c661d7764f", + "47463f100d5840b2a180d1a94f6cd481", + "a6a158611dbb4d76ba876d0aa14146cd", + "5744520600de4934b44cc3e5005da2c1", + "e018a680df4443d29cbcb28b9050ec1a", + "a43d52fc78cc4d08b1242010ea9a20a4", + "cc4bf1104f2840ddad4b3aaa68fc3f74", + "1378402e55334b199fdba96e66571012", + "2905736062c043d8966df18cd5910978", + "9c02ef66b6ad41889b324bba06805c93", + "66de78786f44425bb648c3c4491e66ae", + "ad1bc5b0800047f4b08db424eeb78437", + "578cbb400b884547bd1c34a14b1076a1", + "fbd238669a074875bd1709cf60de25e9", + "48e98b9f3fad4e709f608c7a89a46317", + "9a0f05ec5b684f96b37c49767a569da8", + "adc573b9e44448448f63eacd0dbdbd7f", + "b130128dc6c5446790c782e900d17afc", + "7b142df10734454da1fc8c98a2ccae89", + "812121b9dc8043e2993685c4e3149179", + "762984f66eb34f9e9b04959a755d190d", + "e2673aacf8554b098f3c2fca7fc4334a", + "c424eaca72e6480399ecb22b9f76e75a", + "2e5e3febe02d4cf4891ac045101f4ae1", + "e491afcbbfbc4c5db639218730297d01", + "dcd16c31187d43df98a7480b8b2b63bb", + "a612e935b5024d22a8afe143e8041afc", + "5ebb20b9014e4b9c803191c7bb43395f", + "cd23b5ffec794899acf4b36c6cee8a13", + "830981b958964bc0bc36014e9d49ed0c", + "296b7d6b6fd24030b31b1041e877612b", + "9bb1101fce9748b68b5f24c0f48bc0b1", + "1965f86a45a3480995df29e14d5aa73b", + "5841ce4a336f452981206067f08448c1", + "2f7728abd2ea49dcabee0e838be24588", + "2da86b2c453745eaa1e01a4c9f623092", + "2fa4665a57db4575a6b4a0208fd5fd42", + "490a5cf17e414841924a2407e50787c9", + "4b9c75dd6b4445f485748d95a85eaf5f", + "ac47aee373b3488fb6c2175823320acb", + "fa99fca27aa54adaabb03473616ff117", + "e90e9810ab8e4e08843f57395f5fee59", + "283e03dfc7cb4e48b9e0d7c3664052e0", + "99d53b44586c418c83953a7b6d889a46", + "f5fd28e6723b474ca1fa3f61de01af12", + "36fcdd98f9df46fb80750a8faeb5ea3d", + "e1efafc9fbea4d40af9f1aa5e27e693d", + "e82188b25188425a9b03bd561dabd08d", + "0eba4ad785674d3586aafc82854100fa", + "be88dfbe6125454d84233a7bfdb53471", + "d07d3bdfb250443d8c2251eeb3c40735", + "684c2067c4e2425a927ece2acd11107c", + "33c93ec8f852471cad6270f1c089e5fe", + "9c9faf8544ec4ecdab625f7904a05777", + "09e408f7c1534fe3881c010cb9330ea6", + "47284b76795d4f58bdcdc386146dcef4", + "044f2b4efa034b4ebbd46ab9b77f018c", + "56694860ddf34f9daee3547ade1d95ae", + "33fced7c840f42539e699ead09a68517", + "f45b0d0154ad4abf814b05e55ede0c60", + "90f39e68feb64160b99af3632ad88e08", + "3548f130e77d4da5b4cd38df5aaf354d", + "09eb01f6fe9743deb23e35219ddff2ed", + "2382790f69cf4562a2f9689526e24b6d", + "f6bec6d0fed14a7aa914f6981478d033", + "a3457e1e0d3748e48486dcc4e4bf5554", + "c6bec657b24c407b8e1dd15d376b83af", + "9a733f9a50564d0c9fe849fa0f933944", + "a10b06defa96443d86956dd84a573241", + "c57d5f12ec9e4f669c93536d59f96030", + "b6d728b57c8846f7bf7d1722d456c574", + "79fbce980dff4aa5ae32e1b95676f564", + "0b088d83e5f9458d88ab923e126f519e", + "9465276706b444bbb06065ddd42c72b0", + "a07da643c2b246b8bd5e704a385bacb9", + "d806650595ec4fd5bbe90aaf1f2545e3", + "b6a0ac936c6041708d9478f1d5120004", + "2da0cd17ef9f46359d29776202c283db", + "78b38e9b7fc1401381c1c5f621cd4537", + "55bc519784474b7db6baa08b6cece835", + "351df1c34c724196a75f6dabb6ecbd74", + "8d175261fb584c1eadb772e5cae0de89", + "fd67f7bfe86f4060a3057d2ebbfe1a48", + "40bae81948a8425a80aeeaa3904410e6", + "b4342345041740a7953f194361fe8e39", + "f1c26612bb21430a9ed31994597c35a9", + "1713df67f6954b6ca2b1fe94ef70f0ed", + "2ec713b40d8e4f718f03bc301641b78b", + "24cc5c1c6b9b4a62a06c9056b3a2ce61", + "dfc071de8cad4821ba6e59a4268f693f", + "4c4bd6f21002482491b2717500a18ed0", + "e603b63bfc604c6d9b0b721311a32fc1", + "e4961832b20c4959ad059fced0fbb529", + "76ad127432d14abd86387c668965bc29", + "5b8095131eca4914b6dce4e96b290a3f", + "8cba1fb2d0b6442cb0b7aa903025676c", + "f2828c5f3cd543f2a7659f0d8d10b311", + "fc2b821ad9714ed19e17e834450ac18f", + "25efce9c429c489e8a276081226b3872", + "bb0cefbeac234c268ea43fef6974d42b", + "39541d5daa7a4fba9614ad9847c992d5", + "6a227fe2736345919250c9bd318cf49b", + "a8c9b2a2d4604a68961c599c6e04db26", + "c69921857e864a9185ec6822876f0244", + "c67f61fa444044bcb88ec3e28f0ca7ac", + "bcb9c73793c94974bd1ee58e51eccef9", + "af71d7fe4b87409f8d9b81452fcb9847", + "3b64801b3a7e4e55a71d552bf8f03af4", + "7628165de20249a088f13b0b85eb8d0f", + "4cb98914614140529e3c08721df539d1", + "8087beb1a14e439ab8e713ab4326cc83", + "e85040a9693d4c4983cea1e034d156d3", + "39b03d18881f4ed393611ae7a6da742c", + "c69dc4b462db4b09a75c14e0977f216d", + "a02c10bf6e104e4eb592343ce53bedd1", + "eb2d9978ee8e4cc3a66a40574be824a5", + "8de3a0ecd46646a78006f0c38340066c", + "9b7999f2443f464da71b1b73601c025a", + "23cff152f2ee4512a568c588d1e02a53", + "bec1aeacb47f4911b853ba6f4b6dcf56", + "f3010f753e1b4a4eae1295a7fa55ed30", + "f4ff238459a34795a088e3cd4ceb762a", + "6bbd346a4aff4f7dbf6bb3755588f384", + "e7d391f97e404f519fd7a871dbaad302", + "c5cbb7b2fbad4811b8df0cabb290a619", + "4d29f717981e4477bb3b71e712ea4d12", + "f676081ce3a44b42b7dd7cffce96bc66", + "d1eb3e8ae2a04b0dbcfbf87d0015d974", + "4d7ed627b1834922bdefafca91e54796", + "dc08af0e13314841b999cf57badde6c7", + "b796c052c6fd477799ed90598ae2467c", + "8d4cc4b4e23a4563ad41703c07d5b906", + "b71d80c276a94e9194301f0ab4893b00", + "a425533dc6fb458f9c2ed25ce27c31d1", + "f490a125ffb74093a66bf9d6a4920e17", + "60a084d76af1455b98f5a259da13430c", + "e20ebbfd0fa440c38a6bd1bb3f22a2f1", + "68bc5563e0d94362ac100275ce9b5ad7", + "1165c0c634b5468cabfd905f24f1f9ee", + "b0e9b7df6068489da7d09a065de065d8", + "e92a3df021e84de2a67443d2ad4af9d9", + "2c8d1c35faed41bc9af2ba70318a08d9", + "eb7ce2497e9c4f49b8facff6c9ba02b2", + "ad409625db7542a88cae62e20202d399", + "4a98b588fbca4710acc327ccd7805ee1", + "e7471193f73a4bc0a26eacf144735b84", + "663b5edc92a543668c1b602981e724a4", + "b4a2639acde64ce6a930c4936e1654f0", + "63952197ebd64211aff7d82d949c760a", + "3e7a2c0bbb4c422f8423b89ccc3dd062", + "f802fa8051c643a2a4cd6995319a5715", + "a664caf21dea4bcfbe1592b6abaea3d9", + "301e7a45c07b49fbaaaae26fc6e3fbc6", + "897bc8230df54a1cad474492771880d8", + "6045d275cde049ef8fcf7c58f2807a9e", + "cf7d8b3d323b47a68e3c91605be9cb59", + "5d8c92a2267f4818a73088929d18d81d", + "0b7b526d60bd401fa3deeb765d1f73d0", + "78c531b540c84e9db17e095dd4dbe9a6", + "09b89f75697c476ca9ae560ded0176fd", + "be875ce2075d48fda14a9a30882a51fe", + "2cec81ac7d484c8890ab28cc04e4a3b3", + "d5dfb1c58f88422bb7c26d15e10b4af7", + "925ad46b0f54495aacd6540ae3e4bb21", + "25c29121183740059bdec15be94b3ac6", + "fa2c41a7a6c84fcb871a24016fa9a932", + "d518e2ce054541e6b329dc2343307462", + "bc8513c84eb146dab9b9ce7be3a2fe4e", + "19df061c4b2042c6959bc411a3ca100d", + "47b4230a324c4390a105f656ff1210b9", + "ffd35d2f516d4bb7815c97810dedc2a5", + "56814a55b82d45828675bc60c3947c49", + "720803dc59a54590be644537b462befa", + "8958ccb7b55c46249c256ec0b56ff765", + "cede6a606c024d4f8d92431213a84158", + "feca271009ca42f3b5572cdf48d030db", + "3cd932bcabf54ac5838f23e35fc6fb1b", + "98d85b403ba0426f84636b575319e4f7", + "40fee272465042bb9d91788c916e9502", + "5b20c2af480140ca8770c0a93d2e77fb", + "facfb7d088504a0eac7c47d4f5ada0d9", + "7bff4de965f141399c852831f66ca899", + "ae19e601aeff4267b8aed4870291c099", + "d952b5f2a9f14fc1b2ff78e709a2fcd7", + "ae2b15c6f139439eb8b8add8dbf9bc9a", + "64dba6a697494803ab48e7676c5cbbe3", + "8e36985fe267413183f7b35f3e421bdd", + "c317f334ccdf42438f612b9178478766", + "f4b2252bfd1f4ef0afc2e895867d5b92", + "1154c61009ee4dd28a52c06aaae2596a", + "7c55eceb98564b78a0d24d9208c9ca71", + "23e9db6d0bfc4ff98ad902e64b317a8d", + "0ecb3119b8894cc1baaacd0830b55b3b", + "8db33631ba4e4ac19393aac9721e8d39", + "f4fc1cd448c04a809d106975cfa7011b", + "6d88456182294edeb190ad21b9847257", + "74ace6194a2849bfb3b21719aa3faae8", + "3559c2cdc0a84c938847250201d8ee0f", + "92d4d41e0f1744118a84a04bd4e8c8f8", + "50727db65087429dbe853c30650f1bfe", + "3499aef8cb5f4b61a2f96b976d9c2b10", + "879b5e4bb0fd438989dfaaff1e955acd", + "ecb6e632f06246d4a058fa69cf65304c", + "85db477fc5ea487797c449deaa7b1835", + "53ebdb9be40c45d581a1c766dec01000", + "5a6b924ca99648ad84390da1498cae5d", + "291588f79b3d497cb0587249f3af933d", + "96350d1e978048fb9d8866c215eb904a", + "2e4f49f6b18943e6bb0b0ccd2b14312f", + "bb2ba70c18704a88a784d67ad68ec19f", + "9dc66dc10bbf4fa6b4566a886d8a763d", + "e2f1c33deff644488e436601fae278c0", + "ef50d0542749471bb36c404d82fc47ad", + "918b82a923e644f7890788e5920d2061", + "0727beb974be4cb7b9c7f9adf15a6d98", + "3c517c07fad44b75b60f0b817b23e60e", + "15f59272a388445d9a1a4123aa9e7de2", + "d94d4a66566147179144c88da741525e", + "2907647e9d8c4391aa9ff2602e1bc469", + "d1eebc8fe1974ff08a2c00028516ce50", + "2ca7b3f063284089a12225a3a5ce671e", + "eb72d308cfb44dcb9d2e0f7b4e503bf4", + "b1bc8de2e44c4b49a4b9ca9b3f185ed9", + "0a93129f133b4d3ebab88f0a6566cb98", + "dd9db3259f804a7ea2dd5f89b4077183", + "d16afc21f6d6486da1f7b274ddf52129", + "e462a6a0c1ac490c9efa9f2290bbab6e", + "2d199878d3d24d57b7624979d3ae1837", + "c60494ee265246bcbe38ee2be3036a14", + "4f8a7f58e55847d7a7062885cdc2d7dd", + "4593c25fee6c41d0919cc94e0a77bed2", + "4c9816c6f1c04e2baa3bedc449b3dd9d", + "42b468ce9e724d7db7c8c1a7ea41157f", + "c776dcfa7c164b28a9541cbc5b86be51", + "ce5ba4f821934269973ea1f8b9a8539b", + "a82d9aad1af5413390e1212e415ff7c5", + "3e0faf09bf4e427ea7480397bb2ee387", + "a3ef7a173a9c44dcba0cf639f618e38a", + "d77af1e61296449da833e24b46076dc0", + "660f938476444ad781feaa2aa4ff456f", + "c6bab90fe05f4bab99dae859c4aa7d7d", + "638b297a82fa42678e29d49268cfdafe", + "3d04380080ff4c269fe0ddd9b6924a3f", + "60e698ad26ae467e9300158bdf83a6c5", + "2daa226265f443b39ad7e5b950b06432", + "f256f98eb3684dc2a3ecd13a424c3c55", + "f48a7ed36c8240ee8b6610bf5fb1a9fa", + "3279fe171d12488083cddd7efb143fbd", + "b7859b4980a840248db03df22799a962", + "da029397ae5140b2ae98f54bd1d5f82d", + "87b29ea6d5974e5da25f45ef4991cbac", + "290a824ebf9d419fa1e11eba60fb4ba9", + "8db81f535ced44b0974adf6518b54bc6", + "fce412a0472d4e798ded2a13c0dbcd71", + "62ad203327c84589881849a97129fa3f", + "ed1423c2d56e4f6d9f61d52cfa3bbd86", + "a8a6f31816544dc08483db7399088bcd", + "496d6c4c2d0b4f8794708440e39028b3", + "ea06ce6c179a4676a1e9329f3b7ee127", + "d01dad33772a42bfb6400291cefcc535", + "222ba81cc5f1494bbc052b87df829f49", + "cea782742273430e82d2874624ab0dac", + "1d7529c4c9024c5cab246286bdbfe30d", + "efe465b448e540e4a2576c65a6637f27", + "a3fe0f5ce664467a9ff0ce0c17933316", + "d5e474d0cecf4688b488d84819dc8790", + "3174abaad33740ce83debf88df53f5b1", + "9d02c1277e7542efb46409d02cffedf0", + "0f93f671ef874e378591842a84a9eaa6", + "93fece05b5c14bb68a1da0bebe69d051", + "270b9d405fab4d0fbb6fd29b43e237f2", + "28b570276b084cb2b0b169618e328bbd", + "f7338f63211b436c930f695dcecf0183", + "919d58adb0884c8895fc140455169ae0", + "bad78de713f04733ad22d9d3605fe631", + "85db5ae7d74c4d0ba690db265f28ad72", + "d504e243c2b240919fa582869fad12c5", + "100544bc355347d1888ef470193215a9", + "4ac4584387fd42fba25086c42148fd6c", + "a71c7c8529f246b3a3a5fbc76c33fed2", + "ac58cb3a28cb4a0d92ce1016f74fa5ff", + "61875706587d44b4bb8122f68c9cf61d", + "9dc5201b8839467d82064b2acf64c888", + "ac0f972547d344ff89618ab3c6e3818b", + "bc1f3dd452f544feb64b41bb9a092173", + "775a10863f4b4819a409788ad183e2d5", + "a7852c063b484df6963e1b5f649e7fe5", + "bee9ec58623442249c2f531e7f313177", + "01a9d2dd3c184268abc76693458bd5e5", + "d26b667147a34c90b70fbeee399499fb", + "30e234683aa343798c50438af550d863", + "bfa9fecd9884450baa68192cf44ee9e8", + "966235cef3f34f40aa8bd19063c6c411", + "9686227ec9154624a5bd7db66a85ac72", + "e8d39d9338c84c9c90be27003e0a4f9e", + "f0a53b38eaf948b59e0b650b111f644e", + "28d33c1592e14d8b895d36a1e0dfaa5d", + "233c4548c26d4b66a54d69db0ea18da4", + "e95a8cfe163b4cf9bfa01e34b5c10fb0", + "cdda6a4b1da043c4b44f2f5abd6a952e", + "2aa3eda5dc9c4dda81905e0e451901fe", + "92251bea8da84d4ab36105c32e5bc8d4", + "1ce74ac683d44784afcdd95c4702d239", + "15e51b665ab34dc19b7f96cef1ac1ac8", + "a8989077813b44e8837fa1b283d3c050", + "8ca2cc2c39734528a219875461718668", + "52de419237fa42ffac21b38c4b13bffe", + "d20d1d78836f4c37b543da288035f2d6", + "74091fb35399431ea179b3dc13e74c5b", + "02bccd08cc51480c9bc00afb7e17f164", + "189887e394d34408b7f30f57e2de6606", + "9f349b6b1fad4e7e91531a863961cc21", + "fe179ab2bbea425f8fc898cc75d4440b", + "203236844a29458786ca4cad8557103a", + "9a7cf8a3f2174c5581506527fa2b17d9", + "8c5c01c0e2994c1280ddde22dc095004", + "af3743bdb36c433ebf71a2135d3fcf60", + "da39bc3a29364f8bb4bf45bccf856bdc", + "0b1b92d6d5584284b59aaab57b1009a1", + "879b2a2797f74119bc31617ef4b742fa", + "5086b9cd585d451fb4d53d611a99fc32", + "eb2f87f7efc74cfd91167bbf91be186b", + "84683791c7e74992b8f2baeb52595de6", + "868ae9f9072a4f8a8f7c1a83c765e231", + "28870a80130847f5b9532b6fb1a7c690", + "c1e6ac573c37485f9e7acaaae418df30", + "217a445ce2ca4ccba61aee563f1713d1", + "45d96f2f0e124ae8b06293add20991de", + "3c2ba2d3b7aa4cf7893cf57cbba2f2d6", + "a854eacb9a784cfa96f49c07d44402da", + "d26483419a9a482ca95c6a1d122eb798", + "c665d3c997e64828b24e5dddeabced8e", + "9f1bf5da014f461e92d678a9ad3cb3c1", + "9caa1266f2df4ac7a379f5c2c304bfd0", + "040143111d264848949bee737058b83c", + "66d7f208cbd94ca5bc0891968b416783", + "ccea7e2e68c943b6b85cdb93fd9898f2", + "f805731bfb1c400a910397a8fe764357", + "86d85d8b18bb4d668332553996ce2480", + "042d2d9e0dde4a5cb580d87540d9d643", + "832083da4adc4817b3d1e966dbbaf685", + "e58503a145144470be27e38f014db153", + "9d2c7a71d10442afb919acf853bbb12b", + "1f0920eb333f402f994a4f7c39c2944b", + "ea9fa63c6e514d72abf89dde240862cc", + "9c61ab86b73740ed85d2d298be703a08", + "ee5476b5928142a9a579404a331528c2", + "0d112fbabd344c8a8297d429f5f471b2", + "94b74a459f9d4733bcb90e687dbcf5e5", + "5856ed19a9604c63875f7fca06b50d40", + "e3f0eb2c7da74561a694b4132460c00a", + "26ae79bc6b5e426981a049ff90d8b8b0", + "3fee3d9c85b8468bb18833bf9521a87b", + "651c2501316046ea94249335a9b7f4eb", + "1758ad5207d943d597db8ff2b21bf827", + "332a4fb450ae455286a24982317a0b60", + "221e70566ad3468f880694520506365e", + "a02a7d2d428849a08becd358a5687613", + "6f804f9373144dca971f32c97e228ef0", + "fde824c094ee4620ab482a6f4a6a3afc", + "d7ea2d2278f74e49bf089ea531e63fcc", + "1ec220e0d5f74d82896b703f14c76642", + "58bd57f213b7433abbb9cf0c77d53731", + "e23cc5eed01149048fbabd4244ca2850", + "c0bbfc838d4e47e8b85cfdabf4e67f60", + "284c71d94e3e4d50a152494129f56d1b", + "8f0180437da9470aba7eb45a97c60744", + "f8ecf3f985d84be7b1cb5501f45bc688", + "18ad95eb42c7465daac64ca03d177f34", + "4a89e049402a4053baea3a6bae955d6c", + "b30316ab32824927a64fafd802eba182", + "0d51b5b5444c4f08841dedb5cebf14d7", + "5e38bcaa4c7b4d3da21a726bb7d0ad3b", + "fae3562a5e564fd9ab315caf07be5818", + "2f6d2837fea045a1b5d976f51157a9df", + "aa11b3d1eece4a7f8ee07efea91d99cd", + "d8f7e48d4c1f4d70ae2864ec21812605", + "74669fc47ba549829537455ed4b6de0b", + "a3adc3d127b04fc58a45ba5e5135cd17", + "a214e538fb1846d2881547dcbc9afdef", + "a1107b9e090244db974717681d00ac1e", + "42f3763775aa4ed19e5d080029253383", + "f8d7f92c9f07415fbd29f327db5bc4f5", + "426fa957ab7c4319bffbf058da22ecce", + "abd9f475ea184432ab8ddf964489bde5", + "da26989a147c4fe89fe6ffaf8d767bc2", + "63f67ba1fd614f40aff93c5b3d8b77d5", + "fe230ad740ee4907bf2dbc66099096eb", + "e76cebbb6cf74cb3bcf46c7ff35934a2", + "ba8cbb85a8774c8bbb2de5eb6cba1927", + "5ae212805ceb43f6981243db2eb8c501", + "5345d37be48c4202b25ba2e2b5a8540e", + "db3920b942594294a3b4643a0ee1ec0e", + "822a9bbaec8245be890d83986f3c57d6", + "7c912cc6484344caacb583ef4cc2c2bf", + "3770d46e9ea8408d87965bd52da4687e", + "2b52fd4e8bf64d4aa46f606c109b52e8", + "6362d3e9b11e4396aaafa854c3aa6f06", + "7d83cd5458f04930b6b962645079b4fc", + "e308b3c816dc458e8b79a9116f8c106a", + "c52e70a12dc24793b5b13c2dfcd002ef", + "9cc9eb3c6e16440d95f2df2e84112b53", + "c03a4202245b4fb790e55ff5201a0731", + "fd85f6ce0ab948afa17c37d7a3f9ffc7", + "d2e412c5eb11485fb41223778b607a7b", + "a9a12ffb690a43b79c4412952654e87b", + "8bbec2eca09e45d18d4e43e47d81b728", + "a6f89746f95b47248b4858dab9138994", + "62461a516281492f81f1db9ca992450b", + "7859be7c8a8e401a9e108b7c3217e94c", + "ca6509e3858e42caa5f0227403b5c5c0", + "4f8003c35c13451eaf176ba3e44de20b", + "d8bbf05dae0f4faa9142b3845e4a86bd", + "c35ca3d7094c494caa16570a6b7776c5", + "f75caead1dc1474195eb32a7f4c71117", + "71e9895cf75841f2a1ab1778861f1a89", + "e6a2785e24c541f5bee78e1ddb043b6a", + "5e88595b20004658bba018f9b6878920", + "a4af94af989e474a98b6ff1e79ccfe1d", + "ec97374d7b89442c93e3e82bb7185bcc", + "517da23d3e434a8bacbd5cc5be178683", + "ab15b3ca2356422eb463c3662e6e0321", + "a03809443f5344d6a41a0533c5a74a9f", + "c820ba2fb4e34f10b5a9541b3972692d", + "e836eb07dc6e4dee859b920acb6d31f8", + "f73a98c541a74f3ea90f27262fd3219f", + "c0b77d47832a452aad1d59e9190d3142", + "5ea2b00e5fc34271b632eb84f7d98aad", + "1687c93ab6f743a9907bb7d56495a7a0", + "ddf090fe8ce242b498d4ed73cae4d0c0", + "341382ccefee484b9159a08ffd0e96ba", + "46c230958135402693822222dde11ed4", + "d951740736a647d5917e3bf451e34195", + "d184ccb82d1d4e698ea5545a1e79b4e4", + "3df6e89550b747a79458f197889607ce", + "66323482c46f4b9687f16d5572934bda", + "fcfb137cf4174194a382f84c2b2d0898", + "e642950d58964c7f88c9c25fd8c18072", + "19382675a537455086f3e4e75adeeef7", + "350d7bf705f745acb6630dc016840118", + "96dc535c87b342499cf9a542881d2103", + "692f8369b39740cfab7feb962f1693c3", + "85568de0bae74304901701384e1c3d5b", + "187452aba2d64e1db12c02796b103f00", + "774bf1ec4c8f401d86c470010b04a855", + "df71272df9a745f8b6ef0e032caf5148", + "834e4be579584431ae0173c9a89a2b85", + "19ccbeebbe91485ebaac67a0e352a703", + "91fb64afeb0f4799974ef8fb628f9407", + "8d10923b08514869aa57dd3f51ebaa84", + "24d282b7ef0245a49ed3e508724828ae", + "d9f8a0c160124f1f8dff7ccbb6b4b9a9", + "829f591452274982998f95e3be807baa", + "4a9fc7a5896242fa93cf94e4adeb8dde", + "e31287fefdfb444aaae36ce68fa5ce16", + "30a614e79b2e4c9b8f2b50419cb47622", + "1b10aeaa977346c3b38bb2d724703c6c", + "1c75c94dbe15458db73006a2bde8ed0e", + "f80d955d56e44e358b92f671229420dd", + "65c1ca532f5b4769b991654bcdb51208", + "2dcb6582841e44acbc7a1d7601837e27", + "ebdd8f5a15ba4d55a19662654864a4a9", + "c6c37a6d80bd4ec7adef7740b5ac2776", + "2d74d996b42d4cf4aa23ea0247207da1", + "759c2774396a45bcb0e04a1ae787346a", + "6f1a18469568422ca5a15c0deca1aae9", + "4e9c3cccbaaa4adc947ad8e8ab351d0d", + "18f409c293094545ad3b569ac9088995", + "29392dd175444772881f62436af56397", + "241c95dff58440bda6c74a491b35b3fe", + "70005f64dc8a4250bb3017515b83f878", + "ee7f11ae509f41b1ba6ab07853a2e2a4", + "18187a038045445594a7fd9160ad70e5", + "31a60af75d2c4ca3bfa9898007cfffaf", + "a39ea97eba1d4e55a35ab7fe7dd7efb5", + "4421768a05464242bcea4516ee686458", + "ff75867adf374193ae3ab083e8df660e", + "abbf1556a020443c85fa5c492508b78d", + "7a137d7496014da99f29bf45f6ae030c", + "8a9edd2804eb463db1cf8a634d058ee1", + "850e244791574894a9b8c5134468e64a", + "16dce1e474a046d0a5c95c24391705ee", + "3a8d707c2536440d8f89649626ea9df6", + "e11ff20503854fa18f8afe3742a4a847", + "6b5629bc0d954e10a068d1a0c87fe795", + "5a754cb30f744403b22ee12c20d2147c", + "f5c1446879484addbc606233a2d86ab4", + "679cb7b84ed5404598630363a8b9a8a9", + "eb3521f5a3f44752af14e75c006ed6f0", + "c8b4d7a3bc164e129513c8e2b97e3567", + "96c8538782f94a468bb58b0ce0a42f8b", + "f0d9cf1d6efb41728607669d03b85b2a", + "7a8dae0520a445049a9487b1950d838a", + "f033545bb7d94595ac010d132f8761af", + "67e718a0fc904487a9f735892d9834d3", + "21e6bc59d0264e43a6eb0e8df5d6b868", + "7a302590b032442fa4d94cda3b8e8994", + "5aae5116f65046c8a5e087b83f47b70b", + "3d52780cff9b476f8600349a6e711ae8", + "b1e2175e571a48d48c25f805545576c2", + "4be3573f710044a9a1e401cf8374a852", + "cbf916cfda304e2d80225f690415f9eb", + "98c29f77095b45a9ad0a4e3014d111c6", + "654306fc3ae344c7b9e7a9a40faca45b", + "08708444f40949d697340fd8f9d7cbeb", + "a38e69bd31874d609d9f47ae6679e897", + "6a83113968ac40d5848d10e5a6536982", + "c43801143ab6470c875a146210cdd8fe", + "95c65289eab9470c9b74df95e5dc4b86", + "02d7b885896042af8e1cd16d4f5022c8", + "f9520cf976534fdeaed301334ed3824f", + "a8654f95c4204dd48ce606b8d612c7fb", + "98097909abf64521b87e43d11d4e1839", + "04d0553202d34b299bc0bf43025b6ef8", + "4d41e9adc6b444a383b7990b9ed6c708", + "916ee4c40aa74b54923ec5b20004c577", + "aa191cdb735e4999b066b2f848ad9acc", + "73aeb50753f440d0a721305c7e8deaca", + "4b42e21c567142d690bd11ea314e433f", + "ce195c7adddb44d2bf963c526756362a", + "c5eaee0fea464cfa944b0863061ba8ca", + "eb60c1530b5940088c5d9d8826c772bd", + "b03a0664c7e34b91b93d617fd08cc3f2", + "a8fcf2220c264a30aef6bd8fd51898d4", + "5ecd80e632b042a2a5e19af41d643286", + "19ab4b99a33244838e64406affa3fcb9", + "3ddfc1d67fdf412aa2f0ef9cab2f2323", + "5eac1d12146b4115ba8fd8b7c23a1f3b", + "8f03299aecdd4382a04783c472139254", + "9948c089613041b1abb372d7b7e1d3ff", + "61f9ce1853dd454f9c193b277e58c048", + "d63f28d78a1c41449ff17169b9994465", + "63c3595a0f344820b2e1d7d0b8a025b0", + "3b5ddd7b35f747d19a1cc85d7c07e64a", + "e33bc4cbec84431ead4ea830ec6969ec", + "c2ca972ad18045fd85849414d24c5813", + "7a35202825b446879e9a208e73ba18f4", + "f027be5d519b43b1a3fbf7f29f22d0f8", + "f31daa00bbf54bbe81790c3f7d9016aa", + "7b829577ff5944a080c13e05af8af7ec", + "bd8784cff717400c80a0646a745c3d31", + "dc47a8e45d34435ba3864a6510cbed54", + "82797367c2b94fb1981e556577a3c898", + "7d3a25c1e14246ef868e2422b5fefe40", + "233383f78d0341f7aa2d3776e9d6eba3", + "b4c755eab3d54436b7ec8f9d2fa772dc", + "cfcfc1a5ba1e4a64a21c97725c56c26b", + "3af628b2e93f4d1389ee67bf114d3370", + "ffff460cf32140e9a2af3e5d7538cadc", + "b52c66419c3b4091835cd72bc17c60d5", + "7e9e83d1abc24113adec8b9c1ec3a7bb", + "e8b4e32db5bb4f698543882e75ff3876", + "1450ccf286f64ca4882422d0751334ae", + "e773ac9fd3e04874bc20ee5d6a946adb", + "4ef3179268ee4de8bf12e9f4905bbde9", + "b82ab8224b084e2bbee1f0a59865139a", + "e7ff0a461bd34502a113920fda64f642", + "6a7a77caca23487d8020fcc688bef662", + "13a47f4ce7014779a037cf7a17fd4f7c", + "5838bf92b65149fba0f3b0fd93ad43f0", + "69fe679b60f04f17be3fc96ab9ef25c6", + "a7930393e1ca408bb5eab9377b5873dc", + "6738327269c3431aa2d2c208603c18b9", + "9b9be1f8347349bf9283a172615416d9", + "5e530e4e82f3413a9516b3cc8287c42f", + "29ae2784728b4b91aa452fd694171ddb", + "19d436c8acea45cd914c035d2aff9b54", + "d7907af6fe0e486499d5e0290b426d51", + "a81888a64bf84a6ebb46cd770050b132", + "ebbc2e22b06844cabd6c59ffa03ec7bd", + "17ba4c58c5f24a79bc5ad1e4205e4352", + "717b843ba48e40e0b1c3a8b6ef6a1d34", + "df41afce1c994fceb99a7f117d309ab0", + "d06243f4c2814664a50c5659f6e2087c", + "86f1d737bc5642d48893c0329302a6a5", + "a6e99776c35645c5b11e03a753f7c3e7", + "1dd1ecaa236146769c0f231d1c3bd9ec", + "2a8632e9355948ad97c129f957c2ad09", + "ad010b988fa44a48baaf9bba6bd97d9b", + "60d3ac53be8047ff819ad624079c9400", + "5760a75e9a8047adb8bf0a359c7eeb2a", + "cb9fc8e6de3d43889fc333030bcc83f8", + "ce75423677124680bd307a4311575980", + "402f71e49c874c7693b6205ee04023de", + "ee055a380c094669b8c732c600cbbaac", + "2ec079d528f24cd8b94c53779fee1835", + "f3348ef60e414f088145a0ad70fe2d1e", + "45db143ee7cf48f4803a5d7be9d9b865", + "e05a2ed7bcc9402b827d85a588115bf9", + "4cd9d4a7727c440f9b1bff2384bac433", + "d8ec9bb3dfce444a8dd8a34d673c6feb", + "3dd1b1db55954151b4c8d2a39c5c7d28", + "f0b56669cfde44019f9648955c12173e", + "a77dd867e8d54eeb9785128d741ea167", + "442f355461854f599e5a1a979cbdc59e", + "cb08f60390414cf399aa2fd7231ca7c6", + "4ab4559a9a8e4c1e93cef0259cb3ef43", + "7cc2f7eaf49b43e4b679fe3ecedd38e2", + "d123e21adf784cf0a436941b1e38956b", + "d1b7ef458cf942bab26c49888fea6c68", + "842a0b88eb5f4875a1ccf2cb6c9f6f36", + "11ab7d7c48bf4a1ea4f44c9ad8279c1a", + "594224fd64a04e848f7154a8d88dc384", + "7bdf6e4f9f9f43b2aaa6befcfc331abf", + "45e9d996e0a84a558e7b41afface911b", + "0f0d7a4b7cb041a3b63a5dfd0c0f995b", + "a26c8b185911421aa20cfa12d3176f39", + "6ba693789e4f4aafb70c6661d5c79f3b", + "0c7f27ff5f9f4160806cf18c09b6d5ba", + "34fe7fd87a924cf8aeff89ea6f012bae", + "40a83149a787444b90ef3b8f2064444e", + "0036481f67544ee79b067305af33ea4b", + "cc93110a684743e3853e20e94aedffd5", + "4ab84cf4256d41c180e5b080350cc817", + "5a0900dbd71542d082ff7b32a78205b5", + "575bb83f8f03456dae21ccd06d67d19c", + "d542a0ee1bd848ef86a62223c8483e5d", + "189e02ef2303450cb798d44489b3e7fc", + "d1fd2f75903f4d57b50e0b37e71fdd1b", + "5df981cbb7744925834d66fe5a6e8504", + "4d9e5cafc8164ff1bdba1ec4ddcf7296", + "c32f7b87090d4ce4b10c76e844dc86cd", + "e107705a68154eb0887417f34bbc2055", + "5309de66e31b41acbe0ea604aaa66da4", + "ea60e33437f84341822c556805ea74c7", + "a1fb3ec987264287a2d7d6e999b36db3", + "88563ad41f3049a6a48c7339a74d92d2", + "17b766de120d41e99c3fb17d4112cd5f", + "0a7b87d8b90744678766b2e6a0a09a07", + "9c1e10c3488b44a7882878f53221d0db", + "1db13e38d29444cebdd65509e15ac7c4", + "f7d22e5427174a9bb92d1e43e95acf0a", + "eb46569de6004995944beb8016edcaa4", + "dc6fc960191c41a9a0b97b46c1cb71a5", + "bdfaa94b6c9348808df53bf088f151dc", + "3003b7990af041bd9455817889b7e1cd", + "1ca95881f2d14421803246cd9b7c9a1d", + "27d7bc7985ac4609acb80a4762fffe41", + "8654c66cfebe43f4a14ebd24eb446440", + "de028c94ae87414e9da27b294afa97ac", + "34d6e003b6654f428855d3c1c79e7f67", + "3464f46a2be6498ebe0b08a557b0f983", + "ba6d134ed911447cbce61c3e65b2e386", + "a2c57f38199346b3ba2ee9f73a81301c", + "3c5815d78bef4ae3b2a8bf6603e44807", + "db4affe7ebb34fe7b67ff302436dd549", + "34657bbeb0ec40ca89cea6775c550e0f", + "89469fba09de46b0bf45d3593bff7cac", + "1754d6b3255f4ceba68efe68a5c5efc5", + "8d9b27f829e04575a54c231c8e8151b8", + "678c310aa4cf445889e96e3298218bfb", + "f14fe7efa42447e7aef859b1c3d0f59e", + "cf3f14b48f7b4b218b1df2a19315f3f0", + "77da362c4cb44295a838fd778f70f31b", + "261f62e5e5fd46098cc32302e1402108", + "6991adce213c4d67ae8fb81037e65d99", + "82dd1710a57b4e6182c8fedfebcd3ce6", + "9ef270e08e5f44efaa4e26159acc7f3a", + "9b7e56c3dc6a4c6f9a43ffeb87364613", + "7e864a10617145b49e57c7223bffcdfd", + "eec19e0deb6046cf9f909e63c5371203", + "30444fb6cd624e9c8947d3c78cb8199e", + "ef7fcbb8e1414af5b0ab8cee8e17b8e3", + "24a3da0e190e453587c394fda2a309c2", + "5d2938a131b64cfab85eba2819ef218a", + "06d1702169534de8bf6fb797dcd7d471", + "a0e077140dda4c4781159f5ac14f3e5a", + "b4e82eeecde647b0bfb8b07ed8a319ad", + "840f7c226d764e56b04ef98ba522e055", + "35da1d1edf734b98a698e7c1c5278533", + "2c7171d6b50744fb9c2de5396a535957", + "2cb5aa34251840eda20d2984d26eba53", + "e800e73471f44825b12479c57670f6ad", + "c58796860c764ae68082b4f752bfd84a", + "5ce655ef5a7245fd976b395f41182eb3", + "98ecf24550e34039a916a3f5693044ec", + "4751dd9ed8654517bc66b4d7443ada82", + "c12ecc2d658e4ce98d3d719fdb09edd3", + "1d3e592e28224d239ef77e03923c563b", + "22e00bcec8e44d7ab10a6707e9fcc355", + "8f094196d83e43fb9865df4c7501a930", + "79ba96d1de0c4bfbb9f828d0b8590fdc", + "7661ec0d555947af8f7b5279f5df8bd5", + "a15c23f99687460b9a4763db10f2659d", + "8c017871063047c288f57b28372eb50c", + "f299834a8803461e8a81785c32b4b3e9", + "097842d4ae11445f872d883cafa46b7a", + "96e8b4d7e20c4b2c847524346a94bb86", + "51e55396ab0947c48d5daefa42435979", + "17b1d17b26794b5e94cbee40b836bf54", + "93b56a66331a4490b71a17a158b352a7", + "347770adfbaa4962ac98c58bbc51b23f", + "93b14c97d75b42f0ab103c37bd4de22d", + "de17f7368b21417599e975cc7b38f259", + "0acc5836ade54aae9625b3341305932d", + "7571f66b907f49f08fdd0babef5800a0", + "3be9a6b52f7c4a1981db2b01be76b33d", + "bef1917591e245aeb0a7700e33ff0b90", + "4ccd381b2d9e48bc8dd7113ce444c030", + "37680edff3514304b37f277df42017ae", + "b4af74fae3cc46df9a1d38f6bfd996b4", + "088c1883e07e4946956488171e3a06bf", + "20afe3d907d745a2add9a4b59a1aa29a", + "5331d831fc7e4cd9b8bddb9a0ab1a161", + "a48be596661a4381be6725b3304623ea", + "130363f070ad4e0bb8863d965b7f2574", + "fb56bbc1e19940a68c2166d13b3c65c5", + "7d789534c58b4419aceadbb6017d2dc2", + "31b7a51433ce49c88bfd0006a3f02d29", + "3a076319712c4d50b3120ee371a9b1c7", + "86b0a503cc5d44668eea1215a8dd6cb1", + "a4ca1a1764e841cc9ce9259e699aebd9", + "aa9013a57c4e4cb787c037b5687e0bcc", + "c163a94a1ed44b738d8d8abb10862966", + "0fb029e278b144c4b9a5d933e5f49167", + "31276ffbcf2042f2b420b6a64e45789c", + "84e8837c1e294a159fae045f52610ca5", + "3f33f2ea4615456f9ef658a9ad432f6b", + "79bf80e21e4143398d089448cffabe60", + "1158924818704a6fb8f3aa48649186ba", + "1e23d9b649a643528ce00de750e858de", + "4195ea18d45f4d7e9e2a0b66b1da3fef", + "c19b16e5ab2e41a2ae1578ab25eae144", + "950135a993bd41878b7d96a9273df459", + "bb8d20b556a64ba4a8058d165e0ad372", + "b601649de568470db6e9d8d5c9c76b73", + "e4fdf08238dd4b38a2713f0eb3f14c73", + "be9cda8dd60e4378b316e4933229d501", + "668e210ec85441db874b57105b216f39", + "6fc33cbd0cf54e0d9dfecd52da1b2418", + "410026f520dc4e6999006b38cfaf5eb5", + "47a27a0225ff4c1fa2e2fdf7d2cc918d", + "61f2a899394c4f1a8250362e1043e338", + "2c6db68d87ab42788622e35adfc5e5ac", + "aa0bc2a61bcf4fe88aabf32d2c0e3dbf", + "e3ee02557a7d43a59ac030f5292aa2d3", + "d38460faf7c541668fa086eaa4d0b613", + "84ffce6116784c82b19708986b6b015d", + "5ec9697d85654005b27fd29bd6df987e", + "8f7df859a8374634a5e83ce396076e78", + "bf18d6bffb22406c85e2bf136ac227ca", + "423fab6060ef4d12bda58e99e6f76193", + "d0ac32d6475f46469df63df93b1c4e23", + "9ea3d71b452946ef89f0ceb24af852c6", + "fcb869fb1464475c86933cf471502a54", + "373fda1045994c07aa3a5e8b7a6d57b6", + "67bbe07dc9c84e0da4260974651f699d", + "8bde00e0ca9540fba7d1d42ed76603e2", + "115f7d5116d240d1b623a630d63f1609", + "0b75c3536e6d4488ae3a87114696bf60", + "c105abf20f8942518f5ff859e8ce163c", + "3ee733bfd37b4692a7efb7719ba32626", + "7bf2f8cc2bc54dfc9809c2245b5c775c", + "2f2a8835e5cc40f98a6e6bc14f58a6f8", + "e2d383792a75446b869e32464c7ea466", + "6841b2543cd14efa8400dbf210937553", + "17fa66f2280043e6b34e4f93516f289c", + "a91492359e664c3f8010a041b2d05de8", + "b350456d5fac47bdbf73e9dcc3a6ef5f", + "3a257684cf324517a284f40dd3143d47", + "19255fcca4064eeaa1ae0e2ca940f18f", + "8676570b5f384097a33174ff100261ee", + "83d077705836402eb86e713d3396f9be", + "d7ff98291fe047c98ea3be6f70276e27", + "b8e554d94e804039aef35926f505cab4", + "bcb39abdfaa74f4a92838c008b904393", + "c50ec224b6fd437b94f4adcacc916d97", + "67de7ec7fd064debb979b8b00e87bc1c", + "817f0bc1aea843e68e0231723a18d336", + "73521a4eaf8d44ceb267ad6e8303a152", + "4373e0516d9a4f0e99cc95b63df2cc3c", + "f0b8c79bc5104a63940020d5187654b6", + "82d466ceeaf4430482c9edddcaab683c", + "86e121f89c1445de8d1e97495e53da93", + "391efbfbd8ad4ce9b41c71c349f89d7f", + "4f7f22ac72a9470b9b4f5bd1e202e598", + "3c10ff21c9b84ea8a067cf8b72ba3f2a", + "39368256c6b047ed9112ed94d0538f6d", + "b4ff786c82c04223b01d9b9d7c421eae", + "8898b12687f642d89d260244476df92d", + "b1c7e13502c9490086ba95f1e181ffc4", + "06953629592f42e5a21aab9ec82e7790", + "832be807365c49d5b6cb9844c4aa66f8", + "a11b544f2fac4b3592b91fda9765ebc9", + "05d89057c5f74801a1f4557fe3bae843", + "ccc27d8bc7134d94aa7a94933ba04ace", + "c4b59b5230f143a1887f17338c3efdee", + "04592aadd25149b49cb72d86f0d1daca", + "24531e1143904ffaa505db85df9abaaf", + "842eca60049243779f4d435574259f45", + "adbf990ab0aa44ec8c1f3a1cf38075f2", + "916dde37ea224f1fb83f74bb75341317", + "ab6393f2bf8148ef867b051b0f844515", + "1f499b5cd3fd4c8392e81231e7def77e", + "bdfd694d01574cf28b909975ccf98db1", + "a3823d40744c4c509309dd15d3c9c128", + "060f3f8bc7de4e6ca2f348d414702e9d", + "6d9ce5c765fb4f3d9d1808bf80dff824", + "367f27374b8c453889efc9b2b8515536", + "263b6ac8073542a58769c7688de1e139", + "7b81d73516774445a3dc152e2a9be402", + "2e8bca775044446b984aa085a97fe97c", + "0aa910f8ec974330a9a89a5c7cf4e3dd", + "6045e5f168ff4406b33d6e33643b0c29", + "6c2b00b8f9c443228d9ace3c67a034dc", + "156f342bc2fb43988954a35b932f01bc", + "6543aaad61124f99a2296099a7f56748", + "80c69e8b972b4639bd9d05cda028e1ab", + "685fff1ef9084fbb85e748fcecfa8206", + "62771a21b17646648a588b223afd6692", + "7553a10ab6cb44609d6e2b6146563d65", + "142dc666e43045dc82e4ddbf58b0d381", + "6fbaa2229c4f4a53921e15825ddfebdc", + "db5ed86c820f4d45beaa8eee7f6ea4d4", + "dd5588c4c18e442892d2e7f306e8d01e", + "562956649e8040408cc29a9377127666", + "17edabd5c78e442eae45fa7f7bf26c0f", + "2d5479e9bf5d4b07a3b4b486cf092bff", + "fc3610ba8caa44258e3047f533447481", + "37cd5168919f478489cd818db86f414b", + "fe643f106a794fa09cd490b51eb689d2", + "3f673a5ce96342199ee709dde7f20a82", + "e8e0d1c5c1834644a25b63980bcaa9ae", + "7fa519370312408fa882e1fc8cc9c339", + "24f46b1fa0f5456a88e715ad591adc57", + "866bff7858b2400bac59d05fcbc078d6", + "9001a2976c2545dba6afbc92492c850a", + "be7ab00cce174ef1b6045017493591c6", + "93fa114375a84e61a4d0993353183137", + "9c7421fad3c9482e8af52adfd97c5a5f", + "b10fd730b60a4b4f904db3834f92c83a", + "68f71e6ecbec40aaaee4da563efb0194", + "59c81aeeb0a241509936eb06f1146228", + "d020ffdc8ea0408ca11986a8e0ccb8e1", + "e91f0a52b99a403eb0b8626e4c25a37f", + "7537fb9b87f34db991fffd18119d0865", + "ea410c2c1ab54f53837f23ee9783f0b1", + "fcabee72a3a44fba8c94583d56a1cb06", + "70c1469b4ff4437fab1d66ada329dadc", + "0c1f1f7b39d7429fb2a3763ba488fbb0", + "0c7e9bb9cc2b40f9ac99ea1acecc397b", + "f7cb50ebc82a4eca94b2db9d94ee7711", + "b7e854a1fcb2494facd7fa602404c5d2", + "1ae7b7caaa074ce9b9adad17d67d72a3", + "9b7d68bb7ef64c97aa9a8a46effa040f", + "78ebae28e4004b0ca62f587a8ad8a5e1", + "f69f527c033c4c8781f37d27a63b1dcd", + "50fda8d9ae5945579d02ed99a58a402c", + "fd04e222e3134fcda58487819de0f51f", + "81c696aadcd74c5694ce676887dfa4e0", + "b77ff389442745f399221f3c29e4f427", + "b08de9a1056e43a09320072a943e31db", + "ce4efa18d90a42599c61f52a3e995c88", + "f69d75ec88ec46888619dd48087d89a2", + "c8959296a83149b0bb0707ce7b16e387", + "885b4a83ad1a4db792715ba24c7a5d57", + "6336f84919f94953aa41c5e6f70e4e47", + "66ac28410f5c4b1b9ba1bf2f4fd284a9", + "0cae68e893dc4d94bf2013a02789efe6", + "c95276929eda4cfb842f73d29b071893", + "514d448907b74ea093f136af0c706d3d", + "3cb18b0abc31414d99b9439009e14549", + "9bf986e0ca924aca92462c5bf271e3d3", + "8a8ecd1fdb1d41b9aa9d7da1c75f0d95", + "45fc01ec3b14488fb43f47ed245ae8f1", + "67b2639dfdd345a184817670f932dc47", + "9db3bdc7354143e89129ac650ef0ad09", + "eb644c3c1c3c4d129afb0677312312e8", + "759b8cf5f8d14a5991bca2f7e16923fe", + "b85428f387ec440eb3876ea47ceae7fd", + "a8fb6a8f2b5b4727bdfa31af41fdcc30", + "6b01d76f958b4fb38eb4674ee72e4d88", + "81f3f93d59c04567a1e343d7f9acc39b", + "30a5522395da4a0e9e69101f2353ec5d", + "1acac8dba1ed46439a42d76eb97000af", + "9fdefa464e9044dca5fb5ce5d2aad4dd", + "23df345a11bb4fb59f583bac4837f94a", + "600bc99bc01040cd99180f555b5b3a61", + "491aecb4d6e04121be9dcd9bac6e9ba9", + "376ffb482ff441feb7e11188691f407f", + "f81d863bec684b00a9b1ba4c2d844001", + "52284e7547884a6d864f4308ae03a107", + "3042d7bdd33c4a7d8a7df045e606eafa", + "634736e76cff44ce818470cd562c53ae", + "eae9d7e9cc5042889c1966ca387deeba", + "66878d980a364b2db1a5cc44c67bb45d", + "b91f3c0d62e449158228fa7d086d46da", + "e400bb42cc98410cad96dc611d584666", + "7104ac3d843649f5bef81bc100becb80", + "35c4e6defcea433aaeb2be4aa0e4d0fa", + "bbd739a130c54e478d49b92262cd6500", + "20733c897e9149e69254133e0c21230d", + "46fce676fc5c41b8801309c3dbb3aed8", + "41509583dbae4facb6cd996bb77a87fa", + "68ebf6492c9c45688661657bb6aeb320", + "e93c2f81e708496e8f778a48103091dd", + "339098311d5b4728bcd275f708f00470", + "bb0eea1979ca4ee1b9002915dafead38", + "89cc806b25e347da9723b27177bacdf6", + "a5588c0e88cc47f38d21d6d345f891db", + "8faa6ddbd0454b678399739c641f4292", + "90af5d4457ac46838bfd9be441865e09", + "1bb879ae012947938ad624249086df95", + "48b23bb7989e4951a28e8b93b96b565f", + "4a0b5d0473234d68b1cd94445c6b436e", + "0995712a05a64d5b9b41ba3bda9da63a", + "26777415c0d14c9f82bcc95f062bb377", + "0e38ef02f3de4711b47937ea81870f94", + "824ffd9227004b52bd99cf1239e666e5", + "2436661a640a4f199f088d2920c1131b", + "1f925d3e397846aa8e20eea433f47e8d", + "a96b428d0581472e9e7ae6e32b5a171d", + "4e62892943474f0eb3658325c6a3f32f", + "f17bf70bfd114a8aae0447bded2683f8", + "705e1d09e2fd4f0797bc540b34561e24", + "a5b937e11f4942c48fa31a3ca19c2f0e", + "9f1ed56c02a04fd9b6acd2aacfe3d5cb", + "944c307f31694beb8739d788c80ed786", + "426fef589d134bfda8d7f379cb234c9b", + "44f7c6fffc0c4061905e4cab73953a56", + "d8a31e7f87ea409086564218346b63bf", + "c86aa2d4c24d43749040b7d3ff667f7d", + "ec8a106f32e04f05b722f20ef4b45bcd", + "d40acd93eb9f472f86ea1698313e6838", + "3dc331f7a47441a7a08af2abfdb6fc07", + "49fa6115be81433b9c49d822eddc4c76", + "aaa9dee5e3e14ba3ac464401a24467d7", + "cc09098999ef4d2daa06e4d4576b2f1f", + "23b2d0e81d414836877c555e5b5fc18d", + "fee6f8a30040418688c2c2111ee09179", + "60eb909694184e54acbe8b78343146dd", + "0a51db978635499cbce9cc57c434ffdf", + "bf711e537ff54be3b14eb6a767ff0896", + "3455acccec4b4d8b994e8391643e761f", + "2b83e4197ceb4998be15be0ea8871f5a", + "79f66456163749c0a8ed733698ca5a16", + "2241ea5594de44a5b4f97daf97f70b53", + "c0b8353e54a54fc0a9349e77ff936768", + "76ce633705f04272b30823c428952a6d", + "6017c29fe2a34e90a8c39c7383219881", + "38a262b29d714cd3bb9fc45baa74e1dc", + "d159eb02dba640109a41be31a2e18128", + "436f6844fdf64364bb96ccdf6703fb2f", + "3ab26bbc62644e7ab6a08bd6ec78e5c6", + "e5c60cec993e484fa028cb16e8a03b1e", + "c300a037b0e24c4aac12e1c5ec2caaee", + "e658ed425b1d489190e3bc4ab9c1c353", + "21091907075f4b8e8438c3e0ba3510dd", + "2a7b233a593740ef951c3fb5210f671e", + "1cc08254d7554aaa9fdda45d42e5a7c1", + "e6c321d47483484d9828d8ce058cdae1", + "75f6a8f79319483cab0f61cfc45d6f5a", + "ca937e7fe03e457f820eda8a27157b7a", + "683d244e9f824687b9bfa47a9d36b81d", + "75d37daaff31413b90cf27918d84f9be", + "24b3630ebabf4c96b4d19d527efca2dd", + "0f26f15559b5421cba32468fb1b84878", + "24470259e1b84421a33cd905091e4709", + "cdc09904583d425ea7c5232abdf4b8be", + "e705259c8dca47bfadb1a164565af7b2", + "05eb4a68e56249c5b3db4ea937a57b6e", + "0b23642b64294b06864d1b9cab8711ba", + "db6b7597f9d942b0bc221259692d506d", + "4e981994b487402c92b5a760b46aae82", + "8c0c8c0684c74b68962b212e6e1161e7", + "a914a855633a4185bab8f37b996bc690", + "1b8f2dfeec24456c84b7e10bb7bd5030", + "d8e50ffcf376460da718b0d9d81bce99", + "3bcff2746b5a41058b858c65ed82de66", + "d83cb7bcf1e34c8da8b08567020707a6", + "462498b44e9a413ea94c58724b69ded5", + "351d798f9cc3451099200c5235aee352", + "34022bf9dd9148e2a3de014db888427c", + "88c0bb51cf30455d8f66ee7a6b7a45de", + "0157b39c4b434ceba885ddace4f5b9bd", + "5a95a3afbf164e26b538de19cdb74ea4", + "2855c6e2042c41a8af0875eceb829702", + "d170ef75c0624c20abe212ae72099dce", + "a28198f79b9744009a3a0f94aa978ccb", + "bf1367c61bf14ee98bb3675a548835c5", + "949a3274f02042f2b68d5dbc471a70f8", + "e7554c25e05a47f7b1dda39c48ae2a06", + "aa9673cfd2bd46038c3d7d703be1ad47", + "465519acf2ad43209055b3b6e8787849", + "8586f65bdece4ebebb008735747b451e", + "97c96623b3554f11bfa7941a891b9c5e", + "7a91dd2508d44405badf7eb96e2e32d4", + "a0df60746f1641ba9c60559077703533", + "cfea46e743944c0aabadac6c2e6df990", + "0228981cd37f4a21962403b936f54629", + "59324d9721f94df39589d1c225cc68be", + "ec3ab13223184b53a31cb531883393e4", + "f5a3697dbb024d33bca2ba914479c147", + "6d95bbb705984942a130313c80ef7f97", + "7e74b12b2d094b11ad54c3f3949473e0", + "23d81fc03c1f460fbc636dc21b03870d", + "1136bdef8ce448e5bc9e199db0f1aead", + "3d83b3e4c8214ffc95867f35992e6180", + "08cc55fc36994e04ad24bf36b9aef6e5", + "a17f662734b74a0a8b8006db49f5a3ae", + "b405d532359a4efe8fba1185c777860d", + "3adba192e0dc45c29e37356776cbc228", + "f2ac26d3788949bbbaa49e8fa7059748", + "963a9e5d288c42509886c5efd4fedd3c", + "b60c397f0bd141fda1e5dfc8b6709096", + "b828a4e728ef418ba0160dbb048b1104", + "3e2b5b7d362c4dd5bedae92de2fa548f", + "a67bcdd39f524491a086bfc606be8011", + "fa24dafc04ef4d8a81e0f3fe22512264", + "b09f9388983d4f9eae6e0d6fc3f75aa6", + "3de9d35d897c4fad99946bb1fd8aa965", + "69de621a1f7a41efba3e7b982054835e", + "0651a218829a4d348b5e6d0b0ad8626d", + "6c692bbf57364804a68d4a6477e788fa", + "cb2e63cd55b54b8f8df5c83196834a3e", + "0c74700b13e74cde9c43ad6c7ed41c93", + "1cecf0565ea04e97988bc219c4cf579a", + "99b917b5ed1248c3996ae53aeb67fce5", + "4cdd2939434f42f2925419aec5eded49", + "afd7cf83eef946a1bebaad77e3a37384", + "71ff83cf547048cf8b3b4775f9df45fb", + "608a5332c9d848db9e22ca189aa0ed7d", + "3eaed6b56eea4e9d896d4be05fb24853", + "aa71a88c6ef1465eb6f232b3263cd7f9", + "f609dee009554b3c9926504eb80f8029", + "cdce7c9c2a17473cadd03ce4746b4f13", + "c0dd07bac757481f8d29404b001c482c", + "c6a9f5c8182e45fab908f210d53525ee", + "bfc5ba51548b419c94ecf632c0aa9960", + "9b5f5901aa9a403fa418dc3ada806c06", + "55bed065c7d343458f76c22c5fe37266", + "ccebc76ca970421a954f6953c66dbf33", + "55c292a5bbda43058dad396e8e8fd476", + "d20d4a01042845289cd2149550b153d7", + "b4618084aa7d49e8b8d04fc4544ae093", + "60e4c8e7143f45b093d79ac99856a335", + "ba022dbb1d0a461cb74137a18dbd4cbe", + "0872b511d8784e65a483bc3e7b8bc61f", + "e1e3d62daf7042c38bbf873a6fd8fbc6", + "346d74713027437992db6afabb768694", + "c66c324992f441cbaa79944e88aa596e", + "b5cf962766ba4948b42607d0a122ef40", + "557bad085856482dadc14e430a49ac0f", + "7cf44b40887848379112ad0c9b1baa8e", + "dd6423946f424934b7eabc5013fdac37", + "961ee6ba573c4844bdd15818ea43b42b", + "2d30a0f626f6446a944d9171a8cb557e", + "c6be53b6203042bca827ae3d934a057f", + "887879fa3a7642c4b1b68ef5dbacbca7", + "527bc6a2d9c24d969dc940ba4e5d6068", + "6e3f3ae2d3404e11871cb6f8c8d692a4", + "61a3b712a03d40f38a6702b97155cf4d", + "b0bb3f1a09ce4833b3067f1ef78cc4a7", + "825cbc3f3b4c4862820e1e20c7113eba", + "19429f27ad8a49cc97c99f2d783ad459", + "cd1ac4d72df24eab9f8b2b140e249e44", + "60af814d26b54ab9b71a97279ad0b7c7", + "a18eacf25ab74cfa9d2097755ae52c4c", + "04740704967c4b8d8f05d2fa81b2cd52", + "1abbb454980e4e45a531756edf9cff4d", + "7847011972fa4e4b8be0c1850ae40837", + "b70954caef624015a7ab415189c7088f", + "7816316002f1426c94d4c9b4c59e5696", + "16658cf99c3c4994bd005f4fb429c545", + "c5b1ca5b8492426199932f6b1a64a4d9", + "ade09b61de8b4a7d9e850b710d3eb151", + "cb72a029445445e4a9fb6cc76715d11d", + "26cb34b5b9aa4d8c85e9e888fb470de8", + "fe8eef087d6646fabb24833ea6af5550", + "8cef9554ec9b4d43873fc63b65553347", + "14d73356e0484cc1936680b4b2a87cd5", + "8290ade523514c73984a3e7ab3316b3a", + "6356291610fa4b7683494cd8d6daa4f1", + "c64b88208d2c41ebad9cfbb8e6ec5317", + "482c5168f1694911b597c81f3d0c73b1", + "bb4441c1d0a6423581d06c24f9cfee75", + "01ad91221fed407b80184c0e28526418", + "482e5e616d644560bb42bbd202404315", + "665ea4f3f3934d4e8535d8bafd8e5bbb", + "b0f3ccafd4d04d7d9bd4cb247dc1a34a", + "834fe85ae9804c078ed7b5aae16d7231", + "11cb8edf0eec4a2f90e65982bbf1d1b4", + "c20ff73f6713422591842e29a698230b", + "4fe9650493664a4aac49da9827be7392", + "4e7769c6e659411b9068629eb907244e", + "953d9d9bf39647a48391047afa03f36f", + "f50f5a133d3a48e592c58cbecc32baf7", + "c6468d98a719470a98d5bbed77b2acb8", + "1d13b536898f4c449eb9777b8d1f2541", + "124208a44b1340eea1ff5572b37ab715", + "82f63a225edb419b990fd66655ea5d4d", + "7ed507b6bee3494bbfa6bd678bc9d214", + "5b757b80f41b4d2da72928c6f36f18b0", + "860911c447744c0396b618db994c535e", + "c78071fe7eba49798a751fa07d0ee0fa", + "a7665e0f9f9c4b1fb3cccb14a5bbbba0", + "9bca64875950467b884003ed531d59f9", + "709e7fcc150c4843ac7bfc15d61f75bb", + "ea2db1936f2244dfa179cafb33e3e443", + "7ccfc4387dc242949fbdb53497183bfb", + "f69abac8cc7f4458ac86f525d1a65f4b", + "40ed7e89b92a4bfba04b9b82720d6523", + "53f514139ace446cabfadf80bfb1fdae", + "8f4ba1234f5f4f6c8c0a831c75a65247", + "f638d18097c140f489cb9d65ec4ff4b7", + "2ffa30f8ef5c4e19af9ffe6c6570fe30", + "0f5cff9fb78b4657b26ddefff4e10fcf", + "06507b19ad684dada147ceac71dc2668", + "777de89152e645c5ae25d9f11c4399da", + "0eb601aa649c40caa3eff35a383049b9", + "e3467ea791e24a86a1349d25cf98a1c8", + "238930a5e57e49109dbb3350c316db62", + "2aa4fe87cc454b17989f4aa4d4804d3b", + "d959c0117ae94c8493a3b02b77c0900e", + "9fb7c54715dd41b98b3dc67b367cf81d", + "74868e16ced243c088207e5d7da8c750", + "7f45d17c14714474803446e017965d33", + "69fdad701cb14d70b20f6062639af126", + "da21d5007d2149f6b558ed53ca430783", + "b6b718b827fd447484025751e7f7ea2d", + "25cb3b0549d049dfb4f180c81e43be90", + "ca121fb9b7454fc18769d0d7b6e1781e", + "f3f73f5cac9d49369f8f04632e1b845b", + "8175ffa9116840928a09a63bf40888c5", + "d39c906029df4837a9a0538cbbacd234", + "ce005ab4b5b447ecb98d50cd5c60f094", + "99565b63b54d429f99526428639037bf", + "6d155e8051294915813e0c156e3cd6de", + "29199bdb166b43bcb9e184e312978098", + "7cc6c57715a443c68dfe591f98cc4341", + "9b49bad1efd04679b8e7c783bc47ffc7", + "887092793d0b402e8571eda2d1a47cb4", + "13b9b033c35247209bf07ed158a50a1b", + "18fa961d691245d48a3bc1454538bdff", + "7d1349aba9e346c592a4f91bfd422a20", + "f2c544a02de94b6cbf4f04b61c70dc84", + "029dad75b4d349b1835c960c302081a9", + "c7f7a78ec67d42819bf33dbf82dd1bbe", + "f27c5bccb70e4b49b7b1ebed36553836", + "45597ff885684a29997a9b031225b385", + "fc310b75f3944505829b3ee13ee608c5", + "c9c4e705bf794cb88d5d8726095f4917", + "0e8d40755bfd474d98daceb58b792fa1", + "4ca063d2c3674ad5bbbe081f9d12da0c", + "0b9867d98c154737b422fa5afacfc178", + "bb23f68b48cc4530b4a36c4975290fa7", + "a615b94d69124745a6b13a662366ffe7", + "7cf86de294374575894ed1afa0a2f8cd", + "a2489c54c463486c98a575cd6172daf8", + "4cc04b1efc7844a2b14a87b3b4add58c", + "381ebf452fa74d12a2eac1bfa332d5a0", + "bad759879a334cbeaaec8b4e751b435a", + "15d6d94735e14e73964deb7ffb8a4354", + "76ae94ce183640f68f0fec2f135521b1", + "7e596619db6e4434af091a40a43d9d30", + "70559cdb8d9a4fb2be56fee096805ef9", + "3fdace43d9de444997bf7cb3950dd7fe", + "5ad7b20ef1df409dac02399d0983adf2", + "0386202b085940c4a2f51bd374f17bd2", + "4645844855544d749ef6841d3e5d2a8d", + "a699bcf2a46b49e1bf014f0d72c30dbb", + "a5fa7bfdbb024495a4211bd120e014b0", + "67423dda87d2472b9dd3e84e7c6e388a", + "cee0e56dcd8d4b73bd75380913d79161", + "39457cd0e75e4790a1c62a25e2246407", + "ad86cf92069c4e55b3c5189895316569", + "8ef7f5715310451f9115585033e5fd65", + "18c0a575446048a391c5c0634b5dccac", + "3b9f8f47a2e94c71983ef4cdbf74a190", + "e1ad06e684d147e3b8c0228fa01c288b", + "e6b2c8a5be864ad6afba3bdfdde1aff2", + "90ff81f189e6459a9f23d8e9cf0c236d", + "477a3e0268974083ae89516feb89f959", + "5dea28f32d0b47b6a59a3031ac9e0eca", + "956a47ccc1a54a40a8711f3852d54433", + "873890bce4554942aac0bb05e605c29b", + "7e4696fef0bd4f81ad7eb840d452380b", + "e808a44eb85b4be38ed2d8074e9c4ff3", + "08a028cc9024482ba6ebb423f813ae17", + "fefe1eb9f4134f78a0eb1dd29aaf02f4", + "40d6a071eb5f48809f115b8335228557", + "1dcc7e5293464259ace39515dbbebe75", + "bda77addf88245d69569bc351b55b3b3", + "d345524901c7482393c2c93560f2ed90", + "6e92159dfc9e4273a0694b22142fd1db", + "66b472fee75a4f2eb68859f7d4d79de8", + "a8bebb0d1a2646549ef42b60e1e85ded", + "14cd989153704922b7b0673c24ea4681", + "dd33fad87aec468daeb0398ea4a6389f", + "6bb92eefa68d4d4189837b90f43d6c2f", + "485af512e9844dbdb8543a1652792890", + "100fd458cc524410a60a4d9ff9115b17", + "c6999f442c4e4557a0f9dff8ad760e55", + "b90e23fcbb9e4f7c99564072c0a5612f", + "8d0e20a1374a42d4b3e1b282112c225a", + "d24daba80e0041999d92e23eb1be5710", + "af7730ac43514bdc84249d4ebb2f8ee9", + "215cd872c8ab42679988fe7ddfc6baca", + "c872c2c0346b486c85e2978284841a00", + "d5023f5fb73243179092067efb3c9c70", + "efb5f76948714689a43d7e41f712555a", + "c9ec2dc5bfec45c693e7ab52027a8a9b", + "1aad4ec8d14c43e08924a52d5910a284", + "0e8e13de412142ceaad8bab60ccc4273", + "1d5c4063c22a4d00aac4ee3613382322", + "48b2ce1eb4c94d05a5299451ec4ffe4d", + "90029d3d459f4570866f15d73628993e", + "100d28b5075941e986a98080b99b8166", + "94c36df60580408ea582ad83c55cdca0", + "2345e56662504ece977525901a593b43", + "f997468c67d24927b24a927e91f893da", + "b4deb4cecd784aa4b7d02f361f868a26", + "9e6fb46ca4b74f45990c5f7f9ae44cbd", + "c3145007481840a0ae9b77166ea437f0", + "3a9514b8df044abe809432201b8f1c6e", + "b183fbdf5f9b4930b35912332a6eca01", + "ae491f7dbd2e4bedb9bf4de485a81eac", + "f07d483b876f4ed4adbcf81d8b0e7123", + "fc278bc5b5f2488180fe501f9d4e833a", + "7df41af8732c4537b68c1c5d1a7e493a", + "b99071b8e5ba4163ad6c441da8cff4ea", + "f82265833be44943b6f2d7bbbc1e3b26", + "2fce67e5e5a347619fa791d33b1fb47c", + "e21063cc530b4687a4e095c05ea35781", + "71669f5079874f8e95d27bbdaca0e4cc", + "4d4b59e8293849a3bf79486a171b187a", + "a699c070dc864bdd89e9f3accc1f0c0e", + "35eb45955e1d4557be9e31f04b446344", + "97e0755d0dca43b48e5f4f84d03d0f34", + "a0c216a7de774aba903f441d7899aa02", + "72d2e934e47e4e0b89fb0038ad219dde", + "66d6b50db1ff4a8aa8b0e1fe75d0f761", + "9fc58f987ce7439eafcecc22fe44f4bd", + "20fece387d47426fb0d105049920790e", + "90ea20bab1aa41c9a537f80c5b9ea287", + "d2213888b4974bd8a58a8c82e70a79db", + "9e17a9fb77ec4bb483f68f492c92a2db", + "0c5a458e7b754fc88afdc93b79a43b96", + "b7e94696cb9c441dbf2c5debac325d36", + "9f6f9018f14a4dbea1ad1aea0ce89e7c", + "c908d72071c34298b54fdecd56423f04", + "ced5d54c132c4ac697d9d37f0e7732db", + "01dac0f367544b28a32ef3e276e3106e", + "ad523d17dbe146dea005c479363465fa", + "6e16fa9f2d3944088913ff5e0505d192", + "81d13143d53145bda142a1711dad4cc7", + "f444e45dd9bd48b0871d650f36600753", + "ff84f806650b48108953c52a7307d13e", + "9d194a5f60cc4d478e2ccab40e007dfe", + "8b6b1487054a4a1b9a640387f5b819c2", + "b581cd5112214abb847796710b91671b", + "3595a8cd1e0a4170921cecf974da5029", + "146a40662a6e4f00a50a4cc585f7303f", + "04e5f5f5959a4218818162eb4cdfcfc6", + "cf0fc54bc6b2404698bfb995fc887cff", + "f669df2c04cd44c68f8a6c9239f5b3c8", + "a194cd3bbe0e4e89820ac158d103c02c", + "dcf0e226564b4ec3b18dd5a93e6e8110", + "70dea595c5164a34959582a19c44e8f8", + "512e5c58293d4eaa83ad0ff9eb5be8e3", + "ed66b5fea72d467c9bacef6ddefc542d", + "da67896db37045dfbd88a468392dd8a3", + "c3f760e21f5f47368347c1b1354485dd", + "880b2c44718b4e9a89754200d58a92de", + "05db74e7fd8341bea6b1cb1324bb9a0a", + "7f99b79041634a7ba6a01bac35173fda", + "2d0bee1113e942bf97ecb0a3e5cad43a", + "749ba33db8c243d986c864afe3955731", + "905307d945314f3f86ece85b793891af", + "aa978898b1594fa49d5a63470acf6f43", + "d5e784aa92464572af37264c3b3d2fa6", + "9f21ac519bc3429aa7e4e72cc9c057e3", + "0b0298fff0ec4ebab0d2edec77291f3f", + "db14fccd8ce4439399ab85c1eef0292b", + "41bceca6a3884a6fbffe1403b57b42ff", + "2d203d8bb274442fa6698af002fdb36f", + "18278d96dee944bdaeb875d55d863792", + "241fe550f61f4a37be945a1dd1b77041", + "399b5aca63cb4b148019f9542a96ee03", + "c51d7df2b23541759bf8156913e945e6", + "5c87a966e6a047d49b5900c0b9107f17", + "1376748734f34adc99fb06bfdefe50ae", + "3d9ef851f5414f84b9c72824e468c5a9", + "4b3e3e9ad42944adb359bb5014e0c23a", + "fbc50a68b5b84abbb6fa67be74b39369", + "5cc2b8234ff04a2aa29d5f0a0393ed0c", + "3f3b93f2fe434032bbe966c6602ba532", + "3175a691aeb2421f881d8683ea06eb60", + "818e088dc59f4a89bfea14cb46a4beca", + "0c0c6cbd892849088a9664e165800939", + "8b196cc56aba4c69911a554205553b49", + "1ab67bad49c7415daa2c763ac476da96", + "dab84cb8737d4cdb81afd578134bae02", + "8a46ed7b806541459be7600b77d6b406", + "16c9489805024bd2a1cd2e556fb62add", + "e1fc2e71bbb84cb489bd6bce11979c2d", + "bcfae6acaa254778921933e9ca0f52b9", + "4f7e2045a4a44ec2b52e78b653f91b11", + "4690d156377e40c88ab7dc5bbeb53745", + "7298c99444704c3da07851bb28a8cf51", + "0f7366550f694e1cb9efddea214a3c33", + "304253851afd493d958fc8e256c189df", + "fcea40b6148c47d2bdeb4802c8fd6408", + "227c3efa8fd84efdbe6cbad56fcc6e38", + "7df28e36733d48cf80bea6e42a626523", + "0c770364d18042148f398a0dcc722d9e", + "08a93ccc711c44d89eac6a845c927b4b", + "5cc2ef84ef3a466babe4e315035a053e", + "2596a7c6006e4a8c8bb71037a039cb9f", + "17639e8d26e344bb89dcc57dda32311a", + "6eef6bec8b4b41e680082690e19b221f", + "11979e93cff24c33ac142bb115301655", + "d50f554707f24584b988e2feea162cc5", + "34fc3d43f6da4f088456c4acbbc33288", + "ec1352ff44754308b602f3d75eb32acb", + "338c3792188b4182bdb0b6ee846f1fc7", + "e5f8272a046641a9b9d5a3cbac727883", + "8b7e0bc2035a49719c45e4ee01114527", + "c5ebbba0764a4a9c93fe957121893f6c", + "e90bd760962142e48ef6641fdd41e761", + "7a2aa634ff50458285afbd9540b45567", + "43a9646eb03c4ad8be56a2b333c13731", + "153190fb48f84db294368378c3b23fe2", + "ca19b75bd5cf48b19b02ffd11d71f5dd", + "ad1eace0afbd4b128ebf403ab0edde8a", + "dc2c6e0939b2473f910154d668e818e6", + "5c05836dfe984ff7996d44c1f484d18f", + "2af0ecc8ec0b4d2a95df4204d51181b9", + "25bafa6241bd4246965a39f07d4b7a0e", + "1dc2c857f7614caeb6c2aa0559ccf973", + "09ffebf34d6c42c4ac45999e790226d0", + "2b98ba1d96fd40b1af2ec6bf4706d85b", + "43d50116a2af46c9b391a8549212681a", + "095a5ef18cfc4642a0def29cbff15d26", + "7685aa243cf14c3b9c5c443c62fc3bb1", + "354c1eb5814542759428d1db0b0a40ba", + "e1f0f404437043a995b9bdd073d8318d", + "8ce755e91d1b4de587409b442ec224e4", + "22fc3b3ff33b432e918ef159876dc555", + "03d9e1e3f20a4e3a98d8016a6765b220", + "0fa8268dc6d6425789333cec21a24c30", + "80217edb139b49a787a16e71ffb1da09", + "6abe62bea98941edbc6209fe95ff0f43", + "d72eebbf82be48f0a53e7e8b712e6a66", + "c4807f7c0f2247e697dc93daa915a188", + "7912970e3bce41e3bf40c90d1950f485", + "4d59aca8d6404321934253e00cca3b6e", + "236137f5279d425496270e30de088e61", + "ac26def69ffb4e52bbbdf576066bd0e5", + "c301c954a0cc48d28294bf6489c3a552", + "c5367c078bd6468191d80efb041768ac", + "170683a4e5c54b0e9e202064fb53f52a", + "44d69f20e761400d93b0f1e72fe08528", + "793a45a116be4082aad5ca002ffeb5fa", + "2afe5f4bb73343a5aaefae178c8efa8a", + "837e03d1624d420abc3f448da3d0900e", + "544250be3b3a4bf4b8c541c4a6d9de48", + "ccf0420eec274052a3877474908f8266", + "881e233eb56a47a98309ad68158494cc", + "ff91f534b54a49278647be854c5af631", + "af884c316bdc4b4aa4c61177ee32ca4a", + "5f44ff05a216407495733a908c5e7e15", + "ccb10ac01a294672826d1ccc438bbcb0", + "daf6859d23e34d40886412998ac0695a", + "216c927d15204f7b81c59556fa7ebc57", + "97566d5600894625b984657d508719f5", + "3e55138942054890820bf3abaac481ff", + "7241d57cd08e4508bc9b4914c7a27a4c", + "eb7ba8abcb384dc0b4f86ab869e5da8b", + "6554891b758246348b682dfff4e4b462", + "64eef88d87c74930b7fbeac968f24527", + "f728858a202240588c6c2d14184f6188", + "45f687a6593d4af5a38c51664a8f8520", + "c73d083bcf034a01a1c47de7011f40ab", + "fb95ffd9b17147ae928286545efeae1a", + "6a8df6c3f3aa4631b6934e42c3090f52", + "a2276712ad7f48b392530a62389668d3", + "78ccc70000e54687a57c334026dee21f", + "548d5ad1685348d9bd0c5c2912f0fc8d", + "05874623f9c34a63984e011579b29394", + "6452cd738a1a46c59f45d2f7d20bfa77", + "163be3188b2d4030a859775f70a4111d", + "dc3cfee034d248e68cd37d0eb49372d2", + "7674116150804999aacaf4c7de50e0ef", + "1b3ce0d47a7742619e959d729918a6b1", + "ed39b0d0c02f4be5b406314afd9c89a9", + "a58ae667aa1b43e789211047b8aae27c", + "ead031f3394548ca970e4b31b071d64d", + "052e699d724243cd98f76efcf847b39a", + "98fbf87c116e4909931ee76c6c8816a1", + "0a654e016f6141e582a3ef76a1eedc09", + "6448881e5eda4ac5a2cafacbeeb9bb7e", + "fab5262adf224bb6973222ec4db3dd76", + "ac74e4ea9658464a8f73355ad1e84c61", + "d211583ed67b4eb3846f43a8d9ec6bbb", + "9234d8196b73434684bcbb8092cc9e2a", + "c7e812718cfe4c5abcbd5099a8e3f538", + "9438abf986c7453a9f4df7c34aa2e65b", + "e5f06bda3ea74a1f8fa75b1945cb5962", + "64383f6d9b32443cba3a6f5270d62293", + "9a3c1a9c5a3a41f199ac720ece8f8937", + "04ddcde0040c47d88fc729d34a09f39e", + "13c79b8a4f35426a8d12bbf578b04c4b", + "ad918e92c653464f84acbf15f959f708", + "a03705f073034b0eabf9d6eecd9456be", + "0e31066f7a364cf8993a0b3c08daebf5", + "4a2d838b90a64380a623362c3dc6be59", + "bd1e4a2c1d884ea59b16181ccab37573", + "a44483bf93cd482ca92474620d405a1c", + "b8478cea51454555b90de0fe6ba7ba83", + "a9ed84b06e6549e486aa585129a1cf48", + "f7d5399fef1744b28a503f59437db29d", + "3a7ff8c34baa4caaa6098ee8ad447679", + "1f4dc36aace943328acd5337f5446aba", + "e63a90e0c4194546b275d6058ff1f080", + "3039dea506c44acfb7920d135051f4d2", + "413fb19e6dc64e49ad64c49043694d07", + "7f9aacd42aa84224b5f92f4ad3ea7511", + "a67a47452b344a51b48594be3fdd6592", + "121d3ffd7c274f4492f791241c81716d", + "a331b3d7b0fe44b89cafd9f8821ee8a2", + "eb41c6490a5546269055916029e623ee", + "cba29782a7d74e7db0dc6b3194984639", + "3544298bc80e4b658f1f91d304a6eef9", + "d9efe71a39d84566ba8dda862abfa5b6", + "ac5b67af3ede4449a971355b60b3228a", + "f561dff7acaa4e828252b3f3373f1059", + "e752a734ea7b40f78f2b9ee57a76e1a9", + "a25aefa12d0c460a8d181912e5dfe8fc", + "f4ba01a6a6de45178c36fe60a4eea1e9", + "17cf46a64ab3444ba4b780bd50e669b0", + "1d3687a764404fc9a2ff78a06b873ecd", + "93af393ea38f4ba3ba2db8c9e26496da", + "85ebb06733654cb5bad293dae518c4f8", + "35f9a17c5c194885b729ab31f216ddc9", + "845b08a21baa4d29be5c46f2b53d897b", + "ad2918dd374c486fb5a09f47038a67c5", + "cb172bfc6d48406ebe87ad4fca359ea5", + "d9c7e19aeef940fcac65efc964534a9c", + "2bcfa5f7396e4524ae1669f77bb8de57", + "10ece57b33d54451be9b02cc9d85c942", + "2ebf6f0be9b145ea88ecd557bade48e9", + "3978fd01d56e4706b52063a8ce12d26b", + "77c8995e6fef4dfc9744780fca98bed1", + "5a97a5d97bda43859452ce3b3125e4f0", + "b15cf31aec72404eb6667efb22d55d0f", + "63fd8712d8164f29bdfbaf6fb0fde238", + "ee10a6e05053422a8e15ff66f5e33f80", + "1757576875664d9ab891168a4c01b521", + "69b55039590b4896a24b53fbdafc303c", + "f235ef113d47459895b2ae7407eee8a7", + "a38872d93d8a4a73b0940ead7f074709", + "31a25f4eec454e04b54c7d4e6f942b96", + "0c1aee3e9ba044d29e3ebd1699672884", + "acc5620be91a43b09f884292bd6358d0", + "c79c20f2af0046edb567f6b43cba4ea5", + "07c4feb4845d40459bb9bba3fd439e79", + "a33f6e51b82f48c6b5e318d48ad1e2c7", + "8d193f5ff00d47fbb75e9f0a9a53c7c7", + "dc76cf85a7cf4829a4694d6ba4a570b2", + "a6792027730c4ac6bf13accc31f717f8", + "5479adf1797b4ab693b899e8f77d1423", + "545054662bdf461a82ba8458bd31d31a", + "addd5e1d4df74405b166aa48beea1b53", + "13f186b788e54d4ab7f35611e79d2e71", + "4a338b31acdb4186938ef898fc4fa47a", + "c96528c451cb4a4791ea3d6aa4f456cd", + "6534994bf1cf4f28846424479e41570d", + "811e149588a54fec9514603c832acb50", + "1f69ab976a884866850c8449abb6636b", + "668cc358af5f4ee0997ed28c2996ab2e", + "b7ba2a1f3b834db988aac54139e3ba61", + "c57b615960184f0c81e11e72ba1f46bb", + "499b3473ab424586b7a74408855d40b4", + "00c86cb620a743cc81d9cb87ad4d8696", + "7e1d9444d5424fc4b054713ddef74450", + "e88417df67b843e0bfc629a673a22b92", + "76fcdf15d166452a94ec5fec385d907e", + "863f20dcd6324b799b69e6a583909a6b", + "9884f8ad8ff345c391c7c1c8b30eea8f", + "62b0cd50ed0d428d8fe60e65d62d005b", + "b6a04764e3ea42cc9021327fdccd45ab", + "00e8884a27934e67b7374cb018f3001a", + "8db69750b0d84b61be689f1454d9e31c", + "579a894150d648bcab285c05eed7c800", + "60257875173141bba3124e4a209a2c32", + "cd5aaf2005fb40d49a422547cff3d1fa", + "a3e75ee0a8fb4844b75ad6c88eb0bd32", + "7d925df32b954d17a4482aee5a5ba6df", + "814781ac1f334f1e915200d30374529d", + "d33522b94a11432fb8a43364e684207e", + "66c491d4aff24f1e89778fe6c733a553", + "e24db0ad3c0a49bc9f7297f695d9e079", + "bdf2563f714544cba5a63241c1b6ccb1", + "1ee5a51ea6e74f42a9292c7321603da5", + "fd2b4c7ca9b34d6d946bb32b4a4e1d4c", + "11ef0a2e55434bd68367756ad0d7f63b", + "42b9941f24db45af94d97e5e4802c89c", + "b1e50932b5bc496daa1f52837c844556", + "33cc7075401a424fb60e8c32e3fe144b", + "edccae41b1c64e38953cd7a4078f616b", + "19e20b22fe92443a853f3dc65d2d34cb", + "df57b9ca44394d1891a1278bfae9cf1e", + "2b14055dc8054ec79b4d0d7e8f00be1e", + "36af1647d51e4a869af42b7127d64558", + "58e856cd176e4e60908754519a22a1fd", + "278d7637c0da43058ae6bc06b0b99bf2", + "ee5edb945f33416a9e63f3b4aa665d56", + "c1740035c73146b98f220ace2a7e2369", + "b916735ebc8146a48ed3dd502068c591", + "2d5fc5306e3a4134a0cc78c9a7f32f99", + "49363441e87644eca32d36bdabd2e18d", + "89dcd45ac1f04680b76b709357a3dba3", + "585464dfedaa4095a5f0f5b3c1d15cb6", + "cdd269a997704cd58960232f9c1f2c90", + "64dc78144ca4444a9b7e1819e275fdd2", + "1038a482155e4281a611269c9e59fa7b", + "3301331424bb4dbc8f06e2d3717bb067", + "1abf6fc0db0e413e909a48728e683053", + "d6caf34a19354df890e60be6786de20c", + "098f5adfb58d40cab5a8376ff4796c5d", + "dfb17841ab1e444080382faba3930efd", + "6d62ed07472e4e0ca4ad132b60a18753", + "af7d3d4ec80f441aaf6f9947d0813a30", + "9d7b896cfa6b4761b2a497215754eb38", + "04629445e5b14f93bf18dcd211fa3d78", + "5736985d6deb4af0a4e2c0ba885f72f8", + "28dccdf655c14246b07dfca7c70f33cc", + "e4fbfc1835ad42519d30983ae6c0ca6d", + "35194d20a2824a449d3fac7ca511acd3", + "542e372feb6d4124a0adeb589b316096", + "9837589c6b9c43919c8e944754745d09", + "228abf73a3a94a108a4b2f44e339fd50", + "15f8ceaf052b4152b765f84610c0054c", + "5f235f066a9a416fb7177496a9117ec7", + "2e3bb11be47841179f31e820ce3e5333", + "774bc66d11c24855bf722e35249fddf7", + "12b9545d618d4d02ad38e0262fba0cf8", + "8dec3aa6447243b1b449cb6953a66b95", + "1f16565d7dda45319e7094c4ec7af66a", + "33207568a3f04499a921e95ea7c49532", + "8257772b0e2f408ba269264855dfea00", + "10f5e564955741949779f2d612effd19", + "58c2e098a93744148bc1e83fba6a4135", + "ff72a80384bc4570a804215270b8db29", + "7ea984312db64f0aa77a40c305126953", + "2734161713be4f97b9aa88c7c39e9e0a", + "4bb34b104d0f42bcb367572b44af4ec9", + "ea54515ed6f84a6780ea786d3bf60ac9", + "b2eff5a26f5848f8a10a58aee420d0e5", + "1e14f7452deb42b5a5cb78d4c152b99a", + "212d4e9ca1674f33bbb40f5056c6993d", + "0995a326f06c48619604551320215798", + "3cafd8e77b6e402ebc84c19f6acceb3b", + "5dc5ffbdedbd4ce8ae8bb34fe4f2dd19", + "c66c5ca931344e44ad7232153727519e", + "abb02be176d64b388475b6bead22649f", + "b495fd474706417e99c6bb87068761b3", + "c9db0e3f1a4d4171af144788fa77484c", + "a35230380ea44282b0f71d13b89a382b", + "a8506847000e4c899358e91835f4aa0c", + "ffedc1b62f8d485bb19392c6d33fb71d", + "534da3d37c284d6980fd967acf2047d4", + "2a7dbf5f9a1e45c299bc8dea451f9039", + "06c811cb16df48429e74456b74514f60", + "6bf10914c59e4a38af24425af8be7eda", + "50cef26436b949198ab80e0664de15d4", + "854d4ae8ba834309ab7b8f1e00401196", + "f027d6138adf44ef974a9aac44407cfe", + "62a7ecc7845e40fa986e65495d59db87", + "911fcbe1df084b58ac03d405d1c7bd94", + "8f2d3e44a30542559a5d09ffe577be39", + "97dcfb19b4ac4fdfa4228b8920131c3b", + "0333443d2a93433aa99c8d7bf2f8c9db", + "183f0b6ddcac4216bebdc4c56b415433", + "356fe590f6f5478e99888fb59b7aa77a", + "7081c9c27df244bf84774361888f58a2", + "33ee4f1f77244a03aa6bd0d6458ad759", + "fe80eb65469d4eaaa6c2186f4a672406", + "6d04e2abfb514eec8d6de8c4982e1d3f", + "e2a46ca91dca442789af4386cc0febf2", + "1adffcff237848cc9d866330fffafc7c", + "f7e30214d97143d1933fcc699fd6d1a7", + "f7562dd4f11f4cbaa2cac58c38a85e1c", + "c21be071cbe44b96abf7046507305c97", + "210cbdfe3b254964816edef01755ad7e", + "496335a85be047a494fbfaa8b4071469", + "b5b09a67ba1b40b48d6f35498f41f75d", + "d20147392d174208bdd62bf0053552ee", + "8926f6be27704713980076253a78e057", + "e82a2d9de75646d185fb5b22f4fc37bc", + "b2b577977af04c43a44963e4f34d9631", + "29e5703bc92f463bba5004a24fd04e95", + "1706d29ed79a407b9a5347ddbdc3e03a", + "b7a7e3e9194847a99aea5828abe57c4c", + "536fb33b71a448399c9c48d985d755e4", + "5d796486542747d6adc8468f2d0af01c", + "4124562be1a74264b57b561e0908e69a", + "65dd1127f1214b979a8db26b3f26ff75", + "9aed0a7944b84705b8c4b2063493cf51", + "22360b4290d14d6598e5b917244a4c74", + "2b303b564d2345eca614387b7c44b88e", + "1404fdd7009e457a99035d19bef06657", + "b82e4d73accc4db28e45c9cc0d87a69e", + "ccb1f5791a7341ed85cb767bbddda2b3", + "810e56bcad204acc9b43040d1765f2a1", + "7186ebfc24fc42c599f81713cd28d55e", + "1837f10d9b064fd88a607a3d391a17af", + "29eb6a4e7bf8403fb05cc2495bfc2dd9", + "101dba022a874617bc6070dad742bb47", + "236ccf2dae264fc3a11cd5be5bc4e280", + "5b6f721fc1ee4e15bc48fc5a74dfa7bd", + "effd4a3eaa0f417e806becffd46a08d3", + "2109fa9ab86c42f081d0f629b4731b5d", + "55b2e0ec477b45debbfa9bb69b2092d5", + "eb8c106e7dd14b7eb18c390aac5832a4", + "340f8dccf3234b46a9ae48d23639d09b", + "950f6f4e17c94533bb62b588f2a39b84", + "0b22a2f802214c28b88edb17606492a8", + "3cb5a2385c124614ad4482c5d7e1a3d4", + "d905bb89d4c248038d06b42d18fead99", + "a976c9fadff94869919f4210b887586f", + "7ba7af1ac0fd4b38b019d689fc7088fd", + "f5e6adc41875410298181a9a50296deb", + "fd40add519e541e5a9aa882397e25997", + "33d01509e1fa4deeb23ccd807b686ad3", + "b2ea1501b04f481a8311cf8ad03a8bc3", + "ab49453cdf3645888469d5ff02b522d2", + "cce5e3551a204124882e7d8c4b1286b6", + "2e2c6e8169b7459db6f8f00163225adf", + "0060af6f4da24224a4770eea54685ecf", + "896063c3f9a1443c89ad227649aa85dc", + "59ea19c9ab4e4f92b9a7d8500cad62b0", + "0f5a6f5205a94b66a73b6fbef923f4a3", + "6edc9b08a06b4feb87ce09654c460a2f", + "8da3dddf0931464cb3177f55701b46d0", + "621cceadac024b498ef7047e958cc336", + "21cc98087f32408da021cdf99b28328e", + "0bd89d55caf9413a8a9c28e401fe2ee0", + "0bf75a6aaa9c42b1bb565cb12679cc6d", + "f7c195f58e2b4a5995a4abc1a3a3adb3", + "f80e4241bebe4a00ad57b0fb8d89b671", + "69ce877c820448528a02800c8e7933a5", + "c6ed7aa518ec47dbab2f7a03fa454613", + "9db0be7342f04e12b8b8341941412def", + "dbb854e7c6b840d78ac4b2db81937789", + "8a6016dd59d244c08a243db8f0e38a93", + "e98e7fb33743442383812b68608f7006", + "40c0f7519e83429883ea0d9fb2b69aad", + "209c56eb6c36418abafafca259a8b818", + "1423b93b3f3d4e9eb7e255d21ad0dfe6", + "b206746a780b4f44abfbc1f91c4356dd", + "0ed4312fc8314a85a99fae56e5f0dbe5", + "3e58813af68e4a7c99538e1e7558eace", + "6b77d17ccf304ebc9e576d1ab9c5f94b", + "2a0a93ff48a44734bbc393084fef9ee0", + "c0b276a179ef454491de3ed491c86e6a", + "aa940faf5dfd45b8b6732fa4fbade536", + "8dfababe1ba44691a05a23bd7d7c2703", + "dcc258fbf97141b88b9b3f0e91b9a61f", + "848e8db6ec734f06ac3920b58905b176", + "a6b0c3de5a0e49208772fdbd73490774", + "5319ac4845d84e6d979933c67b3c7374", + "f9d2ce65f26a4892a4888ffd495a54a9", + "7810777f8c0941a9a03fe50689b11e7a", + "c6498b9aec674265b6b828b287bc8512", + "1a38a86296524f35904eafb0289aeb75", + "6890a9e38e314b8c969093749f13d61a", + "a9bf09f4f333493580d75b4bde98f9cb", + "3421e492257f40959859104f46128304", + "c9bcb782e5ef4d37bd8671f1f82a0fbc", + "c915ab5d449e4773a9a58ab84636d690", + "f1b34ddc53bc453282e17f0e6bbd2117", + "3baf7d8e62e040f9ab54e1f06870fffa", + "bbdcc16a4f7f4bb1a4d93061bfb6d0d5", + "da511654cd9e49eeb812af93b1117a31", + "b8b046af916a49edb9b4854232a7e55b", + "619aec68cc334da0990e87c8b8fc7cdf", + "6ad3ffb2b84a4e1d8e372b08c74ae88c", + "e9942025312343b0b9f821ff5b5a26cf", + "97d43294370d4e8399d2eb449883c0a0", + "147aa33aaa684853bef880314176ee4b", + "e2c6a19e13db4a5a84a2ccf3ed41dfaa", + "6436d542531343c4addc9e0b96c5b059", + "dbb906f876754c878d184b334ba5cac2", + "6168b4a2977640b7aaf289b4b9072b63", + "aff5e7e9545a4bf3b4366fc1102a20a9", + "c8e10e541ee44bb2ad62a571735070af", + "088819f8ded444479348733c5207a1cc", + "b69b7e87558b489f955ad7fb235f1c23", + "f46a009e33234d0a8dc42863b441b25f", + "f368f1a17be24574a8eac33aa1a6ec27", + "15b5caf2761447fc866fe365f39c0a61", + "53c0a1229a1f4272a18dc210327b8293", + "bc5102bd3369436a9e1a52e3ff4fc555", + "9d1f6924a3f14ee2920176083a558dfd", + "85f28f613361473b8924fd98690d4fbd", + "713bc77008434576a65e31c18c131cf1", + "adfe0b76dd1744d7a5f2b12aa0bd82be", + "f8275823c6b94f33bbdcc1d857b1d983", + "1e2d3fe0b13b4653a87cd1e0bfcdc011", + "024f2d475867491e8a172591b27ce129", + "50b8c5a80825452f91ad30f900c14d1b", + "320c029e234c4afdbd6008838bd64db3", + "15d71bbd00454e63ad7d23914dc70b66", + "d014b5d74e654bd3b09a1e29b8c3ee84", + "1b69326303a247d1b87c49f54ab82653", + "16ee83e509e745998f229da44a8387e8", + "6d8e8b0dc4f04022bea0617c0ef074fa", + "7bb94bd2fb1c4334a782afe3cc895951", + "6f669f70f123449ab4d73ea3ca3052d4", + "ef7e34822e60420ca3a3a6d4a4509a95", + "252c69eec4ff4fdcaeaee1b709d42012", + "ecaf78a12d5c4fbc8175dce8a1617a45", + "c952cb79279c4b3581bbd00e36f376c8", + "9a96cb9e351c460b9ecb10088be7d0cc", + "d7ca85e96d944a1db88bd8391bdad345", + "71245a5c0c5e42fcba21e2da571a6c5e", + "f2b9e0a9c402491d84d124b6898854c3", + "d8663bde3e124dbaae359768b4f129e3", + "9514735916054455bdb644854fb78f0c", + "7abec8f4bc674537942d12f970d4971f", + "0b871ded46ec48f295daae79cee8f0b4", + "8efaf047e51145d7babd4ee0cdc23539", + "4b547ed14efd460a8ac2155be7130097", + "37fd1b66b8884c1aa4fb0356048720f4", + "fa3e5f2704904218a0e971e4edf63e20", + "de485d8f87f64932a26f910282034d9d", + "e4bffd85e16b4c87b38e767c9f6dcc10", + "544b79fac207496bacd988c07b11e679", + "d766481551eb4ab69ab1b26cc2518e33", + "177567caa7d2499f85477cb5391ccb7f", + "9c8ed8e91960404fa5f24b5599049bad", + "dda9d74c8c0345c99355248a57410b98", + "0542e418234e4f93818ef567e206bd7b", + "ed3591dbf22d49d88591f777cc64b905", + "ee029d8abe6b4c689d2bec6c4dd17cbe", + "f3a61ad607194ab0aea1df7a14578af0", + "c8dc1a6b6f1849228ec603f3b341b2a0", + "b3413168356c44f69bdcc8381177ff2a", + "a2d899dc8635478aaec3baf44c2037bc", + "5a76a5f0d436421f8dd3e4e99aba311e", + "1787fb8e12f14318899702ae6c502de5", + "6f762bd59fe04888b840f324c85d6e31", + "68d8094d390341a5a51bba5f1ba32bba", + "d4eb2f799e104911930bffba2f7aaad0", + "967d19d0704b47c0a12d2a85d44e30cf", + "5b6bfe1564894b768d6601caa8bd8576", + "d5d882096fda4248bb5ff5dc6c37300e", + "1facb9555b64423ca2bbd00338e10bde", + "3e03fbff124f4a2fa366bd77b2efff11", + "151650b9e5d54f0c931ab85147155eed", + "e98f3cd475654539a4d27156b307925e", + "adda2904496f45f2882f363c48a0c0af", + "8b3ce66694904ed59f39579de784f0a6", + "4587fadbd1194844914797cf86aed394", + "3836ff67877248c2a820e6a969984aac", + "7de77265cd6c4a07af7eaf3896153ed7", + "4ad93300b4744545b07bcf57f58f8020", + "6819b524d7a04400b80e31f0bc5f1824", + "44949449705446bc817e96dc5056f0eb", + "6e69893a8de944278617539977258b45", + "85eaf9ad00124684bdad9e7d3f1ff880", + "e25cf19b07e84656a9a7ab71b72c8e3b", + "f8052beda9344eba88c5692c6a29a2cf", + "d061d2b1e7ab4ad38e3fb9f681769bf3", + "ae7ac2f9f32142a4937758e11197413d", + "4c1a869fb8a940e5ac292530926b6cd4", + "c41292560f464b1c8948747409f140f6", + "c1d72577d7e14f8499c7af0195e89ff9", + "2c3f8190cb374f6cbc8aafdbc4eb56e1", + "640a427937804e9487d4e4e6838456bb", + "995973df0f0e47a7bde5603500bd4027", + "295c7210b9ab434baff7e1949652a879", + "13c4db052fea49c0842d990603be7d37", + "891a170bd9b549d6a1d3d8b6f64b9529", + "914735b189cc43f18c11b423f57f2128", + "58d9accd2cfa4328a385c9a3ea2075fe", + "23b964a20c8141c985a811351a07afba", + "dff67390ce4a4d83ae58eff74f6b8a21", + "382c7fdc309d4c10b22a8c26614b7f0e", + "9e118a65f7064d7e843dde3299fb27c7", + "9f449697ee8644c0910cdf0931f406d7", + "97d1e546731940cab115b271bcc7f690", + "ba6a921c95c6450bafe82f2886e0ec7f", + "ddd35916c5d84fd8ab4c38380a73fb5b", + "6ceefc3cfafd45ecbccd9e208599d0c1", + "776ab5704f96440481018e2ca89fa84d", + "e60f0e238c754652a233fe5eecf72c81", + "1e1a2a7587214031add2766799fe98bb", + "2d6489d925dc4fd4ad828b04c8553674", + "13dbe30b0e45408c8bfaddfe6a4e8786", + "08fab39eb0b34836bd21e5142f4aee31", + "dc2d392279f842bd8c2e701244d5f9f8", + "0b121221a12742398087068c1f4ce9c1", + "c7ace0b0d679475f912df43fc6f7158f", + "fac5992e8e18405bb09fab054a248ec6", + "321b591c82be47829b0ebccc522d4236", + "4d98eb2571734e2ca004bb3c16af9d2f", + "e564ad7c078944b1934fb9d2a63a770f", + "62f3eb623b244d8fa37b171bc6fb4a60", + "fc4d69c3688b4340bd2c8aa7de6f6eb3", + "30794482751c4c7fa90da7ca067fb218", + "98c3f1c40a6b422dba76bf5403e0a3d8", + "74fd4b3a54da4841b34b26970bc33975", + "5e125327498949a59bcc3d0e6998f5aa", + "f23335412345474eac20709967e25e21", + "6935152ccdd84bb3a900853147b35582", + "48bcd1e430ae4441a7024a6e1a9adb4f", + "eee3beabbfc24563b5046f290ac25cb8", + "16a80a9f0375413e9f752e493ff24341", + "685d34bc87a643289d31c0c1e4072029", + "8d799c7c87584ba2bf5bf032f82884d2", + "a4290c10749d464296659c34b5e109bc", + "1ae46d746599479b82890cb0b80afed4", + "c18594c29cb24637a419da4a221f6a33", + "41edb147672245bba0bec1327c38d2b5", + "5d946f4e8f3f474a91139a2f7b86d85b", + "47680a5dcfd14cc9931d5b369b81358f", + "b65c33fbc9d5459485ae0176187f9e06", + "d26e9bfce2644bb7af6710c6511ea718", + "34089449ff5f407daf6014b65f7e6040", + "7ad81da274424eff919615bd546825b2", + "b9c654a534e1436ebabb541042bf5fe8", + "3ed9ed041bac4b82bf83552cf55e42ad", + "028404734f534a1885297aeeada997b1", + "6007efb6cefe4924b3e00095884c4e83", + "f3f0116f5ec749959c8831dd1074771b", + "471bba4aec104eafbc6beaa343d9ec67", + "0b79d014ddff4691a235b55cac00c593", + "78396a70304b412d9bc8e3955891f6cd", + "8ed0cbfccfa1449996ff0b06875b1863", + "eaf89f5bc8e94f17a82d7dd1afe003f4", + "7218feba753b4b4bbdac135af36ac4a3", + "b681993a7ef246568b819706f3e029e3", + "ac469ebf4a7841eeb0e2997825ea46f5", + "1e2825e6428e4940b6971e09929bae61", + "91a91047fb2d417e869bd0e652524ed0", + "46c305b2605b4d30a5377d9fc9a36465", + "e12031e62692414a90f023b43bf29774", + "f4ee0a91d82c4e17a880c1052ca4c8d6", + "e2a4f0f4b36244a5bc076a89f897b132", + "d0fc5ee914c64e12a730f751df2a0f34", + "af99d40eb9bd4aad80ff83b92e955631", + "750c69ba487a485da85800010687ca51", + "cb6c2dee10f74fb28d0d0e43e3a13d75", + "f0b276f11d214c3794769175346b030b", + "c95d153b6b204cbe80afd2d9426e5e8c", + "79b10bf00f0b46dea7565bfb39d884c5", + "a2ce58a7c4a64a42bfb13af2350d18db", + "e79acc08dddc4440a7e1386099a6e182", + "7bfd7808243a4883b8a4cbd13406acff", + "960e6f177b134d008307245d8127b9e5", + "6fbf8fc861c74578a6aa137ec0495915", + "ada1afb1c0fe44fda96f85b60672981e", + "17710b6d0a2b4e44a2968a2b822b65f4", + "a449c098692748a08898326bd71b68ef", + "98d1d78722044d6189741ddc5f32b4ff", + "28f305a07afe455bb2f10553f47f204a", + "b2a553ae36a8452cba40a6ba1ce7c363", + "945f76c5f3f44262bec6417d19677a34", + "468a2035e0d84ff3865724063296f651", + "f990c2aef575427d83c17850b7fc6df6", + "553ac81fc0a747a989e76b4f1cf379e4", + "eccd66922b80448286c256d68b53ed4c", + "353ac8a56c6b427592666eb01dfec65b", + "74f4d37d87a847c0b1250c615d975810", + "ad8ce5f803a049a89c685b3f911c10d1", + "f3d8e925db784591ad54ce18a27e540d", + "ada6073b9492404193e618b41d5288a1", + "fc9cc06615084298b4c0c0a02244f356", + "0326c0bd90ff4d7c996eb1c5c9de68ce", + "e4545fa4b1664a0282816734dccdca30", + "0736019ecc674f049a06942eb97c2f23", + "42ebbc013fae4437a68133f0811f94e4", + "90d0c49db71a48ceb3b37c30ca55cdbd", + "f7ef602b19214debb0b350db9af55ff2", + "50a702db822c474688714cb1a01a752b", + "70fa7ebac26948429888c6d70700701e", + "e4e56487513d45e18bc2dc8761962aae", + "5e502c286bac462cbe2f8b37c351c1dc", + "5262c35f17924ef5a292abd6dc6e76aa", + "0de50d2480d146278e95c3525752eed4", + "ed60054b71ed430891858da8cda16ac4", + "94bc85033f5544939ab34a2cbe01dac0", + "5ba444a224244edcae89d58b11161b4d", + "2c3fc2f94cb64785b81088efb0097d22", + "41dace169ab1483987e1c46bc07e4384", + "53992e31e2ad46faa881b6c1490d8f1d", + "dc4b8bf86d8241c0af020071f9f73b2b", + "67e0432c7bea402f9fe6a8bd4073146f", + "10da14af6df9404da9cb4360db7d2400", + "df8abe83906b4bff9ac6d866344e5c71", + "846040f430834ba5bec8bd493a49df02", + "dfe09c08557b4bafbfe47a54e840aa65", + "6c2b3f8e6d574361b7121968f9ed0b73", + "9e90713cf05a44b092cd022d055cbe79", + "a08042ec0d6d492e8c2bddfe20fab855", + "e40732b8fb06468596ec1623ff89d70e", + "8ed7f688d9b4441e931c45545043cd6e", + "ef103acfc23943c382d66963a3869c09", + "b30f4b599b354838a83cb32a14cf933f", + "0bd15b3d37114738809416b839f6f190", + "7dd892b57467405dbc015f49d1270fbc", + "ada758c1d56d4a74883ffbfa2421637e", + "99be4d96aefd4a7c94bb3c92de11598e", + "688b42afa2744485a0cc38070b1bb008", + "f247c9e2280f4152b4e9256116b77aed", + "a6cf0247fc5a4ff5bf544b61f01e3e44", + "7ae0b797a22d4c8c8defacbf11a55370", + "d0be4f93e59e4d4c970c9f4e37c03fd0", + "618377179d944f7f9281de48d4a259ac", + "1d4864672d7a42a4a0073ee31d5bfbb8", + "8c6c6356a7a648d79c1e4c050d9011e4", + "459ce5b99da947438d3ea11d7c0d4225", + "5e55846a4e724a3793ba21c84325b2e2", + "964005fb5c064439b779c23c2f46f6cb", + "98f275039abc41d885068838df78e74f", + "529916f4db56489da9c73cb59e10be07", + "c2723bf64dbc42dc933fd2f8f30249c0", + "94d2b8d301484a8bab236674fb53bf7a", + "f0493b04de0f4bbcbab66c47bfbad9d5", + "dda4c8bcd0674f8191382f9f60aa6cfb", + "85e4d11083e744efaffb4411307efb7b", + "8cca6439409c4bb59dbf26e525910e61", + "26af80179971467ca67a3edd8ef91343", + "5e9da73665b34fb39839b81c2908e338", + "0aef5e1b2ef446d7a5663674e75d45c8", + "48155e8b129046ca9f96f97affc96742", + "f68569fec6704c73b05e7e5eb472f638", + "fcc83a44f9894457827ffb110571afff", + "569c551891a14f8ba70ed992670e4cd3", + "6802359bdc16486083301bea24f1f3f5", + "62a6c59760b84653b7a341635e8aa7c3", + "8abbd6cde4f74d71bfd07356b6c523d9", + "108dbc67037240ab8d37bc5288595a96", + "76de7241865a4b0cbf9fc6c0d16b00c5", + "b01cdead9e2a440aa1783a15a64939fc", + "efa6032f252c45d5a41cc570d64adc80", + "b79883ded1ad48faa7133763b233a1d9", + "0416f30815d6422791746b379f802405", + "f0a106e66e7243fdad67ea79ea29f2ff", + "bcfb61aa277d475d9c9ebf18be950178", + "a491ef8d85a24b7390a9b05840a202f1", + "6b54028607c841e4814b7d48a97257dc", + "0785c3de269f4a99aa74ff360c93138f", + "fc8ab4683c034f8ab873ce28d531a8a6", + "2296b05a1e494c79ad5ea8bdc37a5fb6", + "f70d075ac1a745ecb5b1f295fc501300", + "53eb25cf34b64cc1833a3507efcacb63", + "701d81bae20840e28df2e79a5c0a4c08", + "814c8c8ad9324aa9a326f29a945a62a5", + "9559090e8f5a41fda7a9eb8e9f0c472d", + "6ff9808e734644b6a925e25aa87ec17a", + "d298731943b24909b75fd439c6fefcbb", + "5761f82d00704f3ea65e90b94ffbbe25", + "4b2990b08d5a4ca69d143595594716ca", + "edc344dcc65440ea97b5eae84f1957a4", + "7ef22083747845b696838f2412fb7652", + "a990deadb759463c9da96f134673ef39", + "efe93249652540128d1df1d5b21115fd", + "0b5f059d4ad346a79e7360f5904cf7cd", + "e90c14b7a4054c9ab2a3b7fc161cc85f", + "02ab281f551a402ca72bda6531d26430", + "cbc154c33969481b8c04389b8c396948", + "0eb3f22a24e844e5acd41f64218cb8db", + "966e1567b1e4421e8de70616cba6420f", + "c9e54b0c51a8424e8f05b774d42c7f80", + "08162303550a4089b1eb98f13763c92e", + "232b7c4a39ae4a45b5e1b908ee2e0ba1", + "af00776b667842968a2b63992fb584df", + "f9adf0d8bc604094a6b9cefb09b1568f", + "dbe824bbf315454cab504639fdca797d", + "18a1a0d5b70a492baec2b8858b8930bb", + "7868ea956e79405aa956f4d21fcb45d0", + "23063b3954ff49ec8b5136287e4def2c", + "ea055e4fbffd4a60860a2a9482e98b49", + "05798697321a4c9fac353d8b1df94d3e", + "56b71e48de3d4ce2a3b44b80b64dfd69", + "2dffea891a8a4121af4ccd29ae9aed18", + "4fcd9b8fac4f47ca935c698827b89621", + "d228b257090a4bf7b04e6603f22e4a80", + "05f91295d43f4a3ea10708c2524e9cdf", + "a4a32440f6554a78bbebfa63cd830d54", + "12991440b46b4108ab83ef2bc01ad35a", + "7313a909cce04ce0943c2a78f76cb817", + "4e9a40bb13074339b2b1baea925136a4", + "1f815313cbe44c1882712549607b1a2c", + "ed1bee5d153b43a7aa9eec30dd3df7e7", + "8e511ed204444bc3a19cb76c653a63a0", + "18f06f808ae648c5b2536bdf93091238", + "b282e6d00be04cf1ba4e94f30f3dd458", + "289ad84c38364a73b75e3b34b6e4f896", + "83b0739cd4d440ab89901e092c6ac3ad", + "4c89969b0caa4d3eb30de9bac7ca1565", + "f71c1d4658924489b9e85f033236eeda", + "e214a0869b6848e98fab75b067042079", + "d8a603206e6743d2b22db37a728ff369", + "ee86052caf384ff78a6cbf272c054015", + "275a7f052fbd4ad0b649f7162b1b8e30", + "936e79f2935c4b28a93a88480d8aa44d", + "3618fc7f6847410f9aae342c21bbe98e", + "9f84a4a96a824d129ac302cdd68bbd5c", + "71f63bc6510c4180857349204de575e2", + "7e18ed62e98042e2a358d91611a9e8c6", + "1417a4fccb9d4a728105b3a3a45f6bb1", + "b57f8db50035400ab91b633c6f9f775a", + "6fecdc84eb0a4098a843cfe734af1336", + "2c417d1e328f43b6886baa3abd55df60", + "f8b802d758e34515932620450ce467e8", + "28b34d3b51dc45eb9805a7eed479af63", + "c33dfff904d44f4cbca526186aaa3fc9", + "b43f7f47ead2494aa73bdcd5eb5c4298", + "9290c5e47dd64b7991120be98504b304", + "dc3e3ae3adcc476895765bec1352392b", + "24a19f9c4fda40288685a4e5295c7561", + "d36b4ef6700d4123b5329e59e6db48f1", + "f72747715883480b9555a75558b3e9cd", + "c5d986c0b14146f99119fcaf5b0baf06", + "fde560e9eb35415288a4be6464f994b6", + "07aa5f57ff324d4e8785ded90d2e5c52", + "6d34d82e368e4850b8117bf512607a18", + "a66de12f14c54e58adfd9abc19e902b5", + "53354ed7f5f34b79afcea170cdb6fb61", + "4bb7b2ced116404d92eb1458721e8b47", + "d4ac9ac4debb4c26b4aabada4820f986", + "3521f4c1efd644d8aba4cac2268a3fe8", + "791ca9ff17a947a9939931ffb80326a1", + "f8ca2b9c4f9a4d94813901e9685b8ed8", + "1935902c177542aaa8dcf5f0e40a4305", + "c848036e1d5f455797476659dfd12b06", + "488802f3c3ad405f8a180bc2f67f04ce", + "481213ccd95f4f5ab16fe242ff8f30eb", + "414589ca777643ff9037857760f9ea92", + "4c89b72896194bdba62083649248e657", + "ac04df3b02fd45a19b0ee6e1502d4d23", + "22d13b14e0a4455db9e4fb37cda960cc", + "6b076d2d49ea41c78dbfb0188072f097", + "57893a2b5a8e4f43919c425cb4fd51d0", + "92b575f875144e70b241198195b6e252", + "4c039ee498fd42b396e8ead38751ad44", + "0a51959d26ab4b1ca1c63400d387394d", + "6ed4c53590d44eba95482dd9ba4da346", + "8779e3c59b7848459546a56756517880", + "ec43bd941ecc447e86a89b442a1f344a", + "9a29c54eb5bb40a1a244b1e1ee29eda3", + "c924ee98c4324ab0a5f4a1e3a11c5eae", + "7efff9ac17f4474c8b6fbd519b4e62e1", + "83036df81d05423dab94d4d12b3166e5", + "8345f26e742a453b9a65cf9a97a54119", + "21b1445e34ec4d0ab75758779e502137", + "1fa63bcd5d8344c1acd4c8a4e2a669f9", + "0e1b3e2691b84d3cba174e239e52126b", + "2d4dfcf83c6d43039ba60389b6e3dab3", + "f60e5954e94d43318a0d270dc00465aa", + "72a1ef08a5c341b3886a4c08bd3e4184", + "f80ff01911ea4811af89effae580765f", + "16be6e9528c743b190a4b2ecb91dbce9", + "4c22dd9716364485ad172283e6bcec99", + "8e514a97a36f444889d5c7a8df64d30c", + "892e724659c44d6c8771252523075b54", + "30d456f3fc854fb2bff1bc73f85a5c08", + "7dd1242005dc419ea9b05034a5f1fcb9", + "27b07e0b5046416aa86384edc99cce20", + "b0c0d21fd7cc460693e872e14873b457", + "8a20e56e69e14851bb157a3d0ce2eb9f", + "6c7aff76b2ff4aa982748430344217f5", + "cb8dbd22a66f4c33b62187189ce88e04", + "b2b68fc8b9614657b5755d2f16876baf", + "cd67db27f6904600902b6a4fe9775400", + "23b3d2c733764a6d9917bc46cc88c822", + "548494946be94ee7b59784aca9d37d27", + "ec3071c0d56447ebbaa3f665664ff072", + "b664bc16a1d14b1ca504432ce0667e95", + "0e7b49db55da490abe06b010cc25501a", + "8cc4336395c64a95a8f986a575f0b5f3", + "fe666fb4082848f88fe815ea0e83c0a5", + "b1825deef0ab4085aa8832435a857ad8", + "6f815b9822dc479eae0a17b8dcab9c75", + "193609eb79874c22b45bbd9534ad75f0", + "88024e9999094e2cb74ec1bb9d0b8c06", + "52602f74ceff43a493b97ee032897a44", + "c36d736d644e4a949d1301fafdb65249", + "5dba22e3d810499b893a52a665866b56", + "6261b5907b194312976168ad4ba9495e", + "ec880a582a77461e9c95c639a06cc376", + "13f05ef7e08a4605bb5ce290c69d1173", + "1d212c374aa04377869a622d28b9a9e8", + "f1af8e0452e94db4baf3e591ffe117df", + "4198673fa7194a81a430510a71b35420", + "2670043699a041be822607602ba48e01", + "206c60c7a47143b9959e3cff1e6ad404", + "69d2dec1fea34fe2945f539d96632160", + "2e738dfccbf34ec4bfbaf2c1d1203911", + "2536e6eb87f94e7195115c551db52e76", + "a8efd688ec4b472f90558331d59c0573", + "0fb0c4ff0d3f489288caa0afef723230", + "b3cc5d4948414fc38d1e1859df426f88", + "ad399a15ec484cd18fdbe4f96c65c7d0", + "43c1e0ea8b5942d6a3eedda55f78ebbe", + "15490024c156480a9e8bbf86753d0e58", + "66a000e5dbc747578e8bed269168313e", + "d880b744bd4c40fe84516c8b0306aa5d", + "e54afca98dc44e5bad209f87b7c516d0", + "e1f96691aaf648b885d927f5c3f5be61", + "7220b6283360440fbbf8ccff08e25a7f", + "acb7d4569b52426a8f0cd9266814ae9c", + "81cf81b2b49c4126b2a14d831866d062", + "b96042deae774f45a81bbe60727769cf", + "9bd041f645834686aa62d9764346fd85", + "f533087557cb47549c5e6ab5554005ce", + "a637940238584245afee0085f9e9464b", + "4f8fc3c05c2c4985a17a9b4b44d27e4a", + "fa85d54cabeb419685924b853c7032e7", + "9ecb77b349884efcb4c161cb701dbe23", + "51767449badd4da79992887fe692c835", + "3857946000c048d0b0b880e5bb65f5a9", + "e3f21b66be924b5281ca2fa759212f06", + "28a48a65d0f8440bbf85552068b682cf", + "cecf6aa3276d42b6a7c517e2d0f63b4d", + "fde4061400234cf9a6b0bacf2dde2325", + "92194258235e4359911ca60983b66063", + "60702d5f661048219e17138ccd4f9416", + "8654fbb33d544e1cb7d35667f3859c89", + "b652c476dfeb46f283afb1b471bff652", + "ce436a509bcb42d597b897b79cc6b02e", + "93e2d04acb5541e1a12a181f8b1addc4", + "d7beee9e9ed348ebae7e3b9fa09b7136", + "68151d9b8ea6413c9b6f2eddaf599873", + "3f0ecc594fcb40999dc5f12064b9a592", + "29cb594c39904a17b0debcc015495a98", + "bfa425f313004d05b0cb114d422c9522", + "f30e00c8992443b2a44db471c812fa0a", + "3ea1f0012c7c40ee98457c94dbe94a90", + "e2258433d1134e30aed8ad6b8a01bfe3", + "0d1971dfade24524aa4c3307b4104def", + "17fcbeb38b7047d5949df0b95d2223f2", + "3941b1c6743348ceafbaa3af4c0a7b0a", + "5c093f791e1645028e11f8cca609743e", + "6a8fc97303814b8fbf467c2d3ae060e3", + "253b3ec67afe46e2a1377726507475ca", + "6966de534f9d4e4ea1d3ad0dd0c91dca", + "3f7be769c796490ea28fc72c29cdb76a", + "581ae874afc948049e76bddf00f7c1a4", + "c90e1a1f73a94d39a34260539239018b", + "3077f5074fb14538b28baf80e65e52f6", + "c4b27b7056d54b90b78056bcf8a3c45b", + "17a255da05df4c19a93a9b67db698e62", + "c25c114d1be1435eb9aadd0f32edc1f4", + "ae81468e59404c9bb18333bb42114488", + "49d7eda516c544a49727f0c92a9a9725", + "9737c54341a749078e3997469382e68c", + "80488a1047834a558e0d571dfdd75cdb", + "79c837c560eb4ba9b074db479e8c0e70", + "f5014b2827b448cf94d7c2c96f2cbbe8", + "df0993ee21e74a759cd0519f6fc51cf8", + "cb7f33b244994986a4270b561f57cd5b", + "1de07cede7b64a2791f74cea210f8c1c", + "c03d9385a87040bda4f4fde8a00e461c", + "2332ab4e2c4046f487fd89a840909d5c", + "61fa68acbd69489ab6d901eb33bd4a55", + "0cf1ec678ead417fa14d43c89c46608b", + "2983d92ac4e744f485492580ca7629f2", + "d592cd978bc64f158835684dccfcc480", + "7b491fc2d5d748dd8587d2ebacdafb07", + "0a1ee08e669843928c1f0caeb9971f85", + "c18b73277d924fdbbee0cf28e6d9565a", + "e205583fe1234598bffbe494b57dc2d8", + "520761a6b8dd4895b502d2a02c79f97f", + "fc1febd4847f4d1ca5069de39b99079f", + "166ca3b7a91e4644abc08cd0e322c2b6", + "78a2afab899842d69630a7c9546c768c", + "40b51a12044943338445fc20f372ef38", + "1504783608094958a762f788038a3ef6", + "6e9da42de04049ab8ce952adad4b7592", + "deb84998fae54c9394720f282bfc582f", + "64381df8247e444899b7356f34ddce0f", + "0f00fbad821d4c05b4a49b80fce3c46d", + "4f051ab415dc4ce4ad81ae5f99da477a", + "b7898d2e04fc4f5988a32c5e0e54a4f4", + "fc497f8e331a4a82895a2d8ee62a8ef8", + "65638e7c954c4f9cacfbb02f14122bd7", + "0312bd8f47044ca790231904e9868329", + "d10828ad347d4e21b9b3d1c6a5a415d3", + "e8b334b1651249c29a54d67afb6f13b6", + "31fa6f1856514ec0953ebeb098c7c747", + "e12662427483470cb750c1acebfd7309", + "135d9d148a8f4b388b5c915f42b1abec", + "ddce0ee2447f4812bd9bf448582aa5d7", + "b6c404b9a7814023a4cccd91403e8472", + "f6ae724d763646dfb09cee2e8df935da", + "e451c15161684f3c98eba02e9bbbd987", + "6c6279ff246e4d3fb46d609fb3faaaa1", + "67be9e77389c4ff99d5ed30e1b6b363c", + "a7258219829c4a14b37b711660ce0c81", + "7f775fb731e44cee88e8361aa7982388", + "5e74285b36884c839e78019ca804ebc4", + "cebc2857ed204001a48c35d2cedd4a20", + "62447ab6e02f4f0ca039389a1a89d65d", + "9979bf07e68544609cca853e2ddf9b04", + "3a5018c5b2e04da5af5e9a30d3abf6bf", + "cb2d1794d0ad4557a8aee26f1e6f2dcf", + "847932da209e4f5e96f0e3bedab2f756", + "af52e08feebc4d94a244692212ac25bb", + "2149d4ef4b3946e6813a9f3e262d214d", + "b318d35d11c64c91984f55773cb4154f", + "ee0fa270366d4b4cac309b9a790178e4", + "d3ab7cf794214a4ab897774d9507af98", + "d8ed11b43eba43b59635ced292d916a1", + "6acba1689895492eaea9fba5fe00f587", + "49a6b6d1e9754321b8d35277f7c5050e", + "d0eb8d23a95a4a3bb5cf49069f830d55", + "1ebb7e724fc64d7abb6279c63987e512", + "5c1fbd5bb1fd4c3f952293cd5afaf4fc", + "72736cf36d1e441cafe1f953ecc97499", + "b59a2fd7dcbc439c9607103ea33c36ed", + "f397d7e2f05f4766b0589309339f8747", + "14a4745557e24661bbc1515ed3882dae", + "ea9d48bf4ca0408899e10fdd8bc91bea", + "6b486ff516d64a5a89339e39624f6323", + "e6ba3288948f4ee1b3b2dbfb70420e36", + "fb71f28a6eab4a2785cf68ff87c4c1fc", + "8e4106a856ae4ae5af4fbfb85665c33b", + "f3db8d79ecdc4615b01b99987f44eb4a", + "bfc31d7150374b798440d02c477ebf37", + "0428fa83814544c3818426af1255c4a8", + "f3d0c128e2554489b1c1c3afab974283", + "abed516f19254b1680fecb0bbc9586ad", + "d5790e5b165343ea9a0b6803dcccf41e", + "2f06edc7e5544f33a40492e497f0f111", + "9332a8e1e5d643b6bdb284e016627f57", + "1d39e7ae6b5748acb2ffddf420893f5a", + "136448f5c07f477ab020105515e97a25", + "44e30921ff5c476c883b8063d6c293c5", + "fe13862b9e3c4dc887d10e297d86f17f", + "0eeb66771cb24a8784cb3f73c18a2ac7", + "eb3d02aade5d4632a57a2ae2464eed52", + "75d11d363e1c4884a714a776049ea4a0", + "351a82ec49e1444fab944e18ab251ebc", + "faf3a63b2d2046a5a7ce5ff553adeff5", + "739a23b9040e4baeb60ab61ace1121f0", + "8a816cc6304942a9829f567ddf39ddcd", + "d8c450e049fe40b29e9d7e2d8872d2ab", + "e1051fef094449f980adbb76e0c0ddfd", + "d1db47ea02c24240b7d38ce6c2358eea", + "b57fd80f32ad4021bc39fd5e74d61ba8", + "c3c8b8b037354369a3f9892530b346b0", + "038b4934a9ea4f8bbc8854508bff3217", + "52708513aee2436dbc4404661e697939", + "7c18e7ede4394b5598ab7130a12427b8", + "e44b828de1dc4db38afb387aefe836ba", + "78bd88b3186546cabe946206c0a0b9f4", + "4387c530b415411fb885fcc30d3c4a96", + "f8a2ddb686bc47bdb7395f63bbb5d428", + "4a92cfef5ad244b88f86c16d8c01ab65", + "f3512126d36a4630893585f1ee2e44d2", + "82567d5d10974cdb89dcce70640e7e31", + "f165f665ca0448369c8ef1320678194a", + "6de8da73af884582a87104cc153af326", + "e6e666938d404aae881ff4d21c43f3a9", + "354b6549e6f74c18bf8665f4990faf8e", + "e647e85b7a284578b508437cf0f07e69", + "f06a196aea294b0fa05dee4be971a12c", + "0bd9facfd12a4e4cb08fc5c1717d9cf4", + "b94d51ca30894de0a15101a22f96a8ea", + "cb4f204b7caf4c20921ae9058c8bc041", + "960dc43d8e4848178c81201535f45be3", + "038108ec3b03444ebda00e7fc2611bdd", + "e5e7a2623b2b45b1864dd7af1dff8656", + "ec72d8a6ccf4450d9925b0d7d62b8afd", + "c7edf48644e346b2b277f87df2d6ab22", + "50e3b31e6935484e829696094b54eaf3", + "936c15265f7e4674a2a3f8563e2d334e", + "9be89ce98b9446aea4e956c7ca7213b1", + "65e767e30858489990ccf38e1c05779e", + "10f788e4da8842468c68efc1fe3d4890", + "6a11e3a5acd54b118166a9a55c672f51", + "fa87f31a66f24baebac12ebc7c4b4cb5", + "caa667dc9edb4754b9c7a04edc0ff6e3", + "dabb763ced0b4e92bff3c48152c2080e", + "7a0c2a659e2441b6b568a9d2acf8419e", + "c54ead3f464248f9bc6d04ee8bcc7f6d", + "766ea004832e4586a5af4055ae4e3aeb", + "d8caad07019141a0963aa66abb0efbf7", + "a820c3cc463a4ee49b87e1e9a4029abc", + "fa6635afb87f4e31930079369ae6d884", + "0884112ca7264ad88c10efbe0f470e86", + "2678ba288c7f4131ab1509e0c27c1c7a", + "11376cc0384f4aaba8d85a56f9740afc", + "cc321249e32b4161b8ea1cf8eddcda63", + "da1809b00acf425a849feb7ae91eecfb", + "fd02124a5cfe46f3801f9a3e205fe686", + "a0a9d9abd05044b982bd93884b189ed3", + "b81bc5c50d30490f8a015cb62cee67cb", + "f7783bf8a13847e589d2cda9590178ef", + "283213c2976c4865b9a01fa35a4e9bbf", + "21d88413da6545cd9a3159ac346a5d1a", + "69e4410cd50d4bd1bbd83cdbe442dc06", + "fe534a3cae7c4e66b6131da9b5dae6ff", + "2c407fa958aa40aeb499a7b9550ae0ee", + "ba13f81138ca482d8cfe1cee50e30cc9", + "a1820865303141a885357e3664066980", + "94a4eba8ce784f95b726f7bdfbd086b7", + "8a84c4097e7147a7ae99ee24937ad802", + "b1bdda9895c345cd808907caa1a555f8", + "c4e5a8becd514290a3aa37721488a435", + "bc6dc947f27247cb8f69cb6e7f3dd266", + "1145d066f66442b9a4af629c039d83c2", + "f9ee3a0618b94f94ba822238ed6bb7a2", + "9d54acd6abff450cbf58a8238d66a178", + "be0c2264afaa496f9d2c4f09c528f14f", + "6b5df16c0d6a4ca3a2f3ee0ba2a20fda", + "86a47442bf054621982c06760ebba2eb", + "55ac94888eec4e7ba41851e9543fb079", + "b8603b3641c64b0fb473cc13297df19e", + "56682eb214214102a00a5e62b391670b", + "8d1c092f61ac4e239d2010688e170085", + "7a38ff20948b413cbf2019e7bdff1521", + "c0cc6f50a16949c09c3264e300f4ec6c", + "3b9dfd93ea0a404fa7ba224a4f17d020", + "795fed5bd7634836a668b06d8c8501e3", + "4a056ba4d1ec48e9b4d7f30646f71052", + "9ec94cce993245c3bcbe85b43798ea0d", + "81cd003c9464476bbb6caa756559d8ae", + "0d3d9314a7714c6bb4be6539f0a24427", + "faae6d37ef744cdf9e6325977313a4e5", + "e761a2cde1c2414b9908b3a238e169a0", + "916afa8413284e2c8c5e524fb1e2458b", + "f47e84c2558842dfae2acaa02d27f547", + "db4defc696c349f5abe5a99d00abc9d4", + "2e4395b51f8741dda1b604d1c393e45d", + "fa1f532e2a2b4c18a5d9cdc21159e26f", + "2cbadb89676245de801b4d68de8201ec", + "7c1616c054214a2c897aab648e22bb57", + "ca8f9202ca184ae2943c100ed25b61cb", + "680b5ba359ab406186cbe9c61feda9ce", + "7e977388e3914b75a43c03687c589f53", + "f389bc7421f941c7b7085fd5b18d5a25", + "049d41e3b0d349439cc26f12c0beeb2b", + "4883133a03024351a8d4bb2231db9b9f", + "006c3cf0236e413292d9c2180e1b60ba", + "ae1e1c61f419495aba43fa50d87d6949", + "a066f55c926544ea9c10f325bd9aa1ba", + "f3daf79ea4e843c8a159e8ead7af6e74", + "635282dfea7a4b5297032dcbde237d37", + "f64b5035c0ba440396b17ef73963ccaa", + "4df0a66583774d7ebc46ebe9719018d0", + "bed23dbbe67b4d6db6fffe9e656917fd", + "e20277f803644eb4babe3fe649c85ee8", + "4dfd41f577e34127b0981ddfffd070fa", + "88a540bdacd940648223f517b9af9452", + "0a3dc72fb1bb41439005cac4a3ebb765", + "7ee6c03ab0b24e0f86fbc1017cdd897f", + "c0d4f02e333d4c8b9042c1db8dc6a376", + "69162d0f819a4cb4bc884e339cd8760c", + "8c5581a8e6b94a7f8133d9eed2d8df5c", + "0c7b15ee169046c9a3f07329a322b578", + "364f91c2d74744b7bc4f92f116e73352", + "19c3aa2f4749417f8d79115be1f32456", + "3784966feebe435b9a1bcd99d17800d9", + "496244e610f340179abd8360ee185763", + "902a5391e09742b285d28df96d4151c8", + "e55c3adad31749fa8c78496048f7f191", + "7f996bcce4fd408f9c0db72cfd2e7e0e", + "65f16361919f4901a3fa3679e7ca9e09", + "6120ce6f49174414b981b183b815db98", + "d75ac08cf8224dddb9ccb75789177751", + "015d02aa38e04950825ec5f8dc3d533d", + "4199027b32544813929a63d5e7944037", + "22822988a9324d9dbd18126945e18f02", + "b55d7c00511748d089fa665900ef6cc5", + "a9c9893da56e461980911aa5a753833c", + "cd46cf3067774836b20ce14a6390d082", + "4903e2d3d9454fde8aa478972536b492", + "05fe9235420b4a0798a19b09cd9d497b", + "a535c727324349258644d6fa4e7acc4f", + "d7811e6bc132478b9ac9b3ba21365148", + "a5e0295a1ad74ecea016e0ba50871d7c", + "8a0c9d1a4da74f52bf88703d0e7230fd", + "ba394828546644b0a2d5eecca4b9a3f9", + "ac18467b45c341c384b2fbd7e3c6f745", + "0d3086601c914ca19404ad30a3fce593", + "14ad8882f90b43d7868afec5148a2d68", + "ac4108f79b654ec5b2a40c1b1f7c579c", + "779771270a1945d1a141a0d62642b448", + "acf8b776d3404ee1a681a721894a8b62", + "f3319f0853de48a0a2e946b290ef03c7", + "1a80d3c23a734a98b575ac2e7ec104a3", + "b9483dc9fb1140c7bdbf20923f8ec4dd", + "115dea77972a45f38c8e8d578524f259", + "25392b75045946f7a4c9a03e3bea969e", + "7b9c8b1b126440a2a090fd7f9429bcac", + "c06130484bef426f8c970b7e899dce15", + "2651aa6a55944f34abdd12f29dcf99a2", + "9543fb020fbb4097ab1f72a87b5a170f", + "f175bfd13d874b3bb3f129ca8c73f9eb", + "d8bab16d9c3242fcbdbe8e2f54973b6b", + "768d1390b60747c0bd7bca897ecc6a09", + "f9c884a44a324572aced0f2084ed8f2c", + "8bd675e4479c49b1ab326d1c2aec56c8", + "a9c8e3c680d64fedbe5abfb43c9708b5", + "26f1e0144033467b97d6990fa90e6f79", + "5e3e480f9a7f4ff19fd9fb329a100fe0", + "8719886cf8f645ca9d53d766976baf9c", + "204f3a9fc02f48fba5cf9cfda8d5310d", + "aae6c9b7e03a4e7982464a31c6e0811f", + "991b78e6d39049028f98b8a8a6d1d9b4", + "d3662c2908aa4f73b5ea0917a8002679", + "8f0c86b33e0240b48287498dec4fb2eb", + "2ff6c43e30da4878b063383865649914", + "89e962fcce80418389482855f48778b3", + "3da333ade95d47919ece6934f84cdccb", + "5a31191d03244f899a3bce5e1ef71e02", + "d774928d546144019d0103f9c63f3d19", + "f01f4881d58248a7b0ae6d2fbf2fd5b6", + "e4f1ec2b8ad2492b837ddaf4c5b17342", + "790ef1bf24ed4354b6c626caaafe4a81", + "020636f1eeed4267bab94f344854a4ea", + "2572753fdc244f8590d079d126dd6f91", + "dbcd31e6a64f4c4d9567af998e5e2451", + "f895bb31d5d244f6828608f438189993", + "dccc3772dffe4daba458cf5ad75f6752", + "cc7ee8c5d3fa448b961b9042b61dbb68", + "3aab20b9e6364bbd8730c8af6ebf3587", + "1751e91968704b43a0dda2eb53a5fb75", + "f9408b76068b4b3e9699aaf83d8658ae", + "9c0ffc297a524314a6efb29ceaa97fb2", + "70cc94064c53499f8c793ffc221b0165", + "242e061bb73b46fda6ede3be17ca1264", + "f045c03591fc4ce2bf8c6abb764cbbd5", + "ba384da44e144b53a0d8f8dda464e0b4", + "a5941e7f539e4639b6c54586fe1adf33", + "5288f12eb87f4826a73ebedb60a1c82d", + "33e015d4910f45b993362919a3787d0f", + "019900af7ef14e07b66c3e74aec43d35", + "4d734a2b31c54e28a05fc94a2745047a", + "227117ca1bbc411382f2e8fecc008750", + "9b7ebfe829a74b999ae30a1e3e8afe6c", + "81ca3a8b52224db68cda1a14e46f1857", + "dd6c40832f1e464d8efc6f3e50a1d66b", + "6aed75fbbfa046b197ef497541cd489d", + "de02148574c5434e80187d35378d1b8a", + "590e3261d2bd429ba3e5d4a0dc5bd384", + "76f077cbca9844518cb282f12b1d107c", + "4de6e3a6fdf7466a8290130cbff7ac54", + "c8dd0c421bcc454b96b67f747b18cf4f", + "16be596eac514da282eaf8976398635c", + "b7f753028d354b419de1dcd966ab9f60", + "1b277d9fa2d7472ba5ccc9f3809c96a7", + "dac09c92cc82445994d76c1083ca8888", + "6d649b5496824294843e2dd512af4830", + "2e53ce8ed59f41b8b63432496266a446", + "bcd15948e8124461bb811e95bf848552", + "d50b445e1e0b4d0d963c18a3a0912abc", + "c9abeb537dff43c2b01bbdfac3913f55", + "606bd19d8dcc4035b7f6a250cde38ff4", + "a63def1ff7ed40b8bc40e86adaff6b91", + "5ad79e7737b44062978c7c39ec1445b2", + "218caabe4d1646a980b0f8c5584f5c90", + "b0b9a86db0b248fc8ac3d3320986c624", + "8f51072b74fe456fa35bd1ac48e038e8", + "0ce1ea1943dd4027a36390d63164046d", + "2aaa078b4a84437aaf302ccb2d855101", + "e41f175521064eab92a9dd2053047444", + "ae026e6c877a4d5da21fa640ae25b467", + "4f0c9e3fb6c9400ea943b3202af6775f", + "4ce462bf14334aeaaa3ba403f07f6f3f", + "0c60e89749454792820b04867aaed414", + "7754304cfbca435ea790114e6f6d8fed", + "fdacab7310cc4ad7811cb7eff95f486b", + "5e2fabb63f2046e9a44c47ec3e702495", + "6d3106346520472992c7a46d714b62b3", + "b7d882cb1790458abc58bac105e01a4f", + "e4ca828d65bc4979bcb1cad750f5a496", + "e871f8e7bdee4a958293e4228baae3f3", + "cd2f2ec6af864451b4fb205efc9bb599", + "9792f6b415c540b593866e226f5399f1", + "9a4692eeff5a477eae032f8c15fc0bb0", + "828ba833e011427abe6d4d053087f861", + "89b9b0ea47c04f42ac3a3598db835341", + "0da7d387a5f6460c9dfc0a6700b103ec", + "ee73983474cd491588c013fa9505dba4", + "e2ed7d0eb0524f9a919d316e8cd4fe34", + "43796f76ffa648aab3477538aba1d79a", + "558c6158334e4e59be464397638d16b0", + "1eb2d08c71e54248bea1813e1bf0bb0f", + "a77d9fda8a2e4dec975913d795fe6ab9", + "fe60fc4c73bc4645b3120ab20863f817", + "3c3796309b8641feb5717ec910b38b58", + "8674b41effa8406caff2c5a92035e8de", + "7b83c3e4504e4fafa5375eff97abcc23", + "be9b034525c246cebab3620acb5a8027", + "f8f17f86486d4a15a8404b345fa76de0", + "d7507a0caaec454aa6ebb7f0d6d5a261", + "9c5794f8db28439e994ca2e77fab3093", + "afa46d8967644c0ab790f0a2caaa2fbb", + "9dee0254aa6244bdbe7a5a21e5e40ebd", + "002be48987e54ac0924772d6a562eb51", + "6b74e4c9570e45df973e73f8484c4cbb", + "117391a3af7c49b59862d984ad976c60", + "415772a0e5954fe5a210353915e96445", + "ee2b20b59075408da2629882895672b3", + "db9e29cbed184539b01eb1047c0170fd", + "43fa0c643e5d4030a330104daee86ea9", + "de4e5f9a1f554549adc02f205b0f1f04", + "618e77d38f574f94ad4fd3219daf5011", + "fee2d0d9099b44fa9c399436c5dfa35f", + "2cab79beb5ff4ff8b206220800e877ea", + "90d5a85e8e6e4ea9b0ac8628ce9041f5", + "853ab309a88f43dea30b37ef538b76d2", + "5513e31ac13348dab310dde6911eba14", + "eb16370e0b33439abfbb66ce8d4d0867", + "ce2048507c0440f28d0e2de2f8b36b98", + "1b2792e199ed472ba2d7e9d62b1d3565", + "3190310c1d454895a48df8f71be3e39d", + "c5b082a6e88744ebaf2eb09ba65c8b9e", + "694d018d3e224b65a02eb1831b666911", + "2e95cfb4208a4a5f8229dfc4068e6068", + "4de96f97ca814709a7664b1831a7c9c9", + "0a7e0ae8315f4fa1b4444b34a947f746", + "3d94c44b36564ffcaea1d02dff6a4c74", + "03fa6768245446f4bab866db37a6caec", + "19376ab6ef9e4a3aa33d465614cac27d", + "263267be77b44390bf277a0c4257da14", + "57cfc1d4ae8244ccaa06e2ac288d2c36", + "d8484bd4a7ae4c3993137019c6fdd182", + "4584f3bbe15f4aafb103b210a35ee4c6", + "b14a2616f6974abd9870236fcd9d6b74", + "e1211c160a9a414a9c4788a1bd4b0c2c", + "b9feafae8876496c81503f889a984d5b", + "d96596e0c7164189b80888af2a02d10b", + "02c3f299435247c4bbf2524243bac747", + "84d7765fd30148499edef59415bb8dc0", + "13f6d5da886c45e1b15bb145777e3773", + "62cec3e98caa410aa6db57b1df683941", + "d455044d1b554a7bbc9b5a5c9aaeb50a", + "4ae706aa53c043fa8261ebf40f580303", + "2d3b5a9ad85244f8a9e861d0305d9a60", + "2e18c6e3cba04a01a42dde6e26da833d", + "9413521a8e1a4ba3a59585b4660605d9", + "6e12ceb244e74cc792941362fabf7f54", + "a23beb65a3e84c9f878265b47585d1de", + "a64fa1262856414b8aa4bd9eaa1d2a7f", + "a55c8b4a6af942ab986481e003511f0c", + "ef0c4e1df32b4cc39c25697d55d3588d", + "717d8d5fa9ed42dcaf4ea59d5a495172", + "866d215989bc4d1dae1d50589dc3a7a0", + "9ecff54aa535471b971e304fa0cd66a3", + "a4e5031e0ffb495c83037f53510defc0", + "6d9fa140a800420f8c71971eccd5d1f5", + "bde31c48a36d4e198c49f0d2aaa758e2", + "3b09e1d365be4f069417b2f54ba4e7c4", + "4c23e2622a8749979f49ad1632cab94d", + "5c4ef7a0506646ea9f42a88addbfc567", + "49dcf64cd426469898e891bd63270fe5", + "12abfebe42664f19b69a84b5f0a83448", + "3c78b210bcd749f28b89e859586146bd", + "fa88ade285a94eb5addfec93afcbfce5", + "f80e07f3fd4a42a5912590b2d94b2c32", + "780348ee7ef1499ebff0cad026196d27", + "b53bef31d45f40689caf1970cc689423", + "dc5bff50734947eea49451ed5d1c966d", + "4c63873087264787b70ff0dc14994988", + "c78f20d5a3fe4baaa9240335740c9bd5", + "76c11a5e35b942c7ab707aa84c5cacc7", + "33e1e5146c6c4e1e8d02808cfae68717", + "73d244a9d14f4d78bdc8b0b6bbaca4e8", + "204fd66893db4e0aad77208ea93d4122", + "dbada35f8e8e4268967cdca0857bec03", + "2976934488a84a9fb84e9cfed4555d58", + "300ea0299b9c4b0881cad9b639100801", + "2fb3c8c315474a6caaccc63ec00d0536", + "95a77b226edc4b4a9e03167ec676a393", + "21db80a5e53c4af09c76d0b54676e89b", + "08833f1df2794a9bb40d01cc13640e3f", + "ffb8035c3434458f82df0408ffde6a04", + "9790ac195b1649b9bc3b5132bc0234b2", + "909e1134b61c442ba60d7d2747fe2209", + "237c379451fa4edba76c483bf7e6d08e", + "a625bc7cb2cc4ac2ae4c214489fb5f84", + "85c3d3b9cfd64c108dc548e525052c4e", + "ecd71285dec94831ba6ab7efb6cef7a9", + "c3a2ec0b2dc2432581093e4948d36160", + "e1ec29a8cf9544a48258c6af32778c5e", + "d79a32a512c64c5e93dc856864789a7e", + "78339c366835415fbc58032e99268590", + "1fc1828ec1904802ba39e31209c86ab9", + "00944cf00144496dad2e14b5e2efc852", + "d0fe5e9a4b8d40faa8386859ee5dd63b", + "f2d60736e50849deb7658f72f1bdbf30", + "bb52c144e79f47489b05a859b50f1656", + "28a183399ea14d5e976b5f80fdf2bbc5", + "6f22b5d3c99e427694fe276f96dda032", + "0eb1d373ab604bcd97981fe8244da71f", + "1a9951a5da9d453db978eb01fe08e4ab", + "33ab9ac87c7646eda6f0c6bba9dd68bf", + "f26d1358631643e09f89c3c857ded45c", + "1f85ec195a19485d9ee9f68343e352e6", + "404dc4d7d06147078b3bc00a82250e0f", + "7e37bfff5662488aa10ca58a2ef077da", + "854b96db1e454fb6b9cacdaaee3f3502", + "d74638fca155470fa2911088414fbf27", + "218afbfff86044a984d70e804bfb5ec2", + "a6d92daf52a44e6db5955506846953c9", + "0b2aa45abf1e4d36851cd97b6b8e99fe", + "3132aef4f917454ea9c9c2caa688e841", + "35ea75fe18824cb49ec8f5c2ce3816e2", + "92dafaefb8c742fb95fb8ec71c27b2b5", + "3bbdc49fee8b47cc98ee12592288c091", + "2dbbc1914a484a71b90a58585387d9a7", + "bf7654a274f84ca4a5e31a58cf73ae09", + "dd84cdb121754138a863d29d4feb5248", + "7f607b4b0d514789b97270f83a6f4a93", + "ebec8fefb47d4363b2aef47850da0ebd", + "04f2c34a3df94e58be97c2830e7e462a", + "5c127eb5a193408989a1f48189cb2207", + "8ea2235340054945858b9834a60d5b0a", + "fc2b5dd09f9c4dce9a3190d47f0e82f8", + "b32ffedac5e14a2c960e03185f2f89d0", + "314c8d76959440e690de3856fe97ee96", + "2fa9ab187c754b85810d743cbe003066", + "9871e9d1e6734ee4bac48fd0e088041b", + "708b5014d7b34ed781878932a23dbf1b", + "782c61b71d76414e980d049dd521a848", + "b0eb1d60ac644bbcb8188a6fdb775e56", + "0de1a85878f440138cc84e187e5ae346", + "592e740e6310420e957657c16d830102", + "b521c9a1162d45d2b4f138206e114fd2", + "7a285b70d618435598740efe0b6467aa", + "8f057b46a63847a0ae1b589239c9c97c", + "31218bce18d548f79531431ef50ec2e6", + "b9e39562f929413dafe2f65d5a8e56b9", + "3f90a4ebbc3c4b0397de76dcb09c96a0", + "b07fe40e15334d65884e51c71c8099e0", + "4dc65614da13403fa45a9710b4b4d655", + "8b224b9be2ec4874a3f20c3ba982fc47", + "3f43be57afb54b778cbdcd0d62d09c51", + "617962b709cf4401bd0381410c072aca", + "31e5a3a2fedb4ffd9f06bf2f2fd86bee", + "436fc74f046947b6ad4f5607c5817a96", + "6781c0c33763406ba9b95d640deef936", + "60881fb8e28d4f4ea8bf91ea8bea43f8", + "37aedf976c6c4264a122f30562ca2aac", + "f98b0ddb09e640fab6758f75ad9e0f41", + "97ad3933b62a4d0b9077d0186d3b082e", + "1f1362d34a084841ac37f72d8f8a6c07", + "5274bb67579c4238bab68ddac35042a5", + "4bd311032f364db18dafffb866ddb9f3", + "54edfaf5faf646f69968086cc0c24574", + "ca8db7533b5b4f58a70dc48e58fcbe9f", + "3473a738d2ef47eebf085d37db37c15b", + "37512f5003164cc09d3d1cac10f7ccac", + "5039119bc64a40c4b1fc9799c5a077ef", + "095fae447c0e4f8d989c67ef2104df6e", + "729a6873bb7d419ab8d76b47a75446dd", + "f630c5e89c5949629418deee8320d20f", + "08b10e0176bb48fbb319616a496ce937", + "90e846bc8ba84c489aabc5b5c51040a3", + "9ba6f54f1b1c42f3a2f636a165294a36", + "c60f3f75ca214dd69590d77fc0fd76e1", + "7febd6bc6e824375b6a3a53256e56800", + "15fb293dce6c4a9294d3eff4d455c9eb", + "12e296976e184090a6d7d8f22b19b4f3", + "d7d22b25f3cf48d08f570532320909d6", + "a302627b20ff43ddbaa4ec35b56b45d5", + "6c16027c8c244358984a82677d768b00", + "e376f374aabc4a468f033ad78c3eab14", + "9f7b9a27b9794141a676e763542f31d3", + "b67c73427cd64754852f66c2bfab6c83", + "83358848ab0b4b7c8cbbe9d6b0860468", + "725d20cd7d55483392d5f7d60215f5ec", + "6fa3f6a894d942b6beabd6ae139ac835", + "8980127fd98845bd87a5029116190657", + "96462cb1626f4b51ba2b0a5cb3dee1b8", + "f42a3961fa7d451ea1a12727de67234c", + "fc71df6bb1c34cbb93e16a1a81e8b0c8", + "4b217c16f3e84b43a13bb68460d0ce51", + "84181c6828384934b1df0f2120d9f77c", + "96517c1c7be642c78ee4645f0fd741ff", + "3b3dc074ec614209a255dd2f7b84f145", + "9cb2d56e42844302acbf7620d75602bc", + "44647e6a6db74a78bf757280ae3a52ae", + "188af7078f7b4d6cbe44e37a3a57386c", + "dce303282b514bf085fbea14172d56b4", + "cb9298397f6341a8b4a547613367bbfb", + "66e162a4c38640789598d41f923ad722", + "54fcd8f8efdc46b5938be5d07b8b9274", + "683753046c8441f1b825a013c52fa1e3", + "049d0f1a46fb4d50968de6984c736932", + "fc7d291383a94b48847a71fe9f3fe1ac", + "b21b62f911e54b29863d37b2912105f7", + "7e2fa860ab9247f983657aa39a658726", + "c0a05946dd024c2e925bd990eb178f8b", + "27b4e8ad22e644af8c5b26bbd8c1c6fd", + "5b60af5a2d094c38957628a14c75d5ff", + "43fcd34e1f3f4738bda33a8222ad631e", + "88175353fb03431a9acfb4f6ca6e63bf", + "8ef7952cdeba4177aabc97bde0479bf0", + "153769c2ae6c4a09a01a25fb819d1cb8", + "4ee454c08f5c45a7ac12ffd484c6ec14", + "d38c2baabe0645598041666d47b1969f", + "672b34e22ef542dea0a900ee329e93c3", + "f974e3e7c83d493ab8ed26e812567880", + "af915a32b088402f8b22e31f93af09af", + "304218dfe7494f7cba6d98271b46b0b5", + "37d239396fa148858017dd63e9c01c6d", + "a9b48fd95d274cafb0a08896709ebce6", + "5d01b889bc324e439a01bc99be1515e4", + "02c4ee90724144fba9cb896602318f2d", + "cd51597956bb4ece8bb3dd02a5abe840", + "2113b139d67f4c62a473e8b48a68853c", + "bd78942b89474892b34ac361223a9905", + "10ea339235c44707b34511d4dde1e025", + "e08e4b03381d40459737899fc1aa13ca", + "b1eb4cef55f94a11b767dc111a86e669", + "dd02470afbb7406f84560810b0de1841", + "7057c0cbf1e547d39aa6ac8d3f8810c1", + "d30cac84d31a47a3a0860f6f4758eebd", + "56445ac6e23b4386849c72feb6e990af", + "602241fdaa124406b8b6db220a062357", + "00725d07417645c2a488a911baa51045", + "2807c0032b494f9dae0dc9db3823db49", + "56b7b83dd08d475e894bb478cf4125d7", + "f5752293425f453d8277657e73f8bbe9", + "c3170bfb1d0945f8b1c647afe1448904", + "5e1afc2f555c4eebb41705468c67223c", + "3447c840759a423d873555d060b4d2ae", + "b751333a517f4a819b7f23af1b8fa0f1", + "58839241525c4818bed8b9c103f245e4", + "421e9b3fb95142a6b46c96408c45d263", + "4e7e47e5e6a84cfd9f7560cabe6b7018", + "e2e02abe2f6f42c5a2b2501b5dee7422", + "f5fddb83f03246ca827ea10d218aea8f", + "a59dc25995324fa38cd54b7d71526ebc", + "f31d425a1d984f3984def46052dd3349", + "80f77eb54a574354bcc1b91dea28300b", + "5349da0846a94864a3117f8643388aea", + "cae2c1c03e864260adb18afd8665a6fc", + "48e999874aa94429b31412c9d8f8e6b7", + "41fe05712de64658ba5be2ae35a0396c", + "f26f9eda6bbb44d7abd947e39f1db4cb", + "b3a8b0a9723d4c8da86f753d45184759", + "c7d55d8555eb4bc396cb62023fd80e92", + "975bf43d39fd4440aafa511aa85c4693", + "dbf0dbcf4229429088b0a984e8f05666", + "0a5013605cc848e89ae5b2e3396504da", + "b81bb7d5b23b410ea6d91774a5f3136a", + "d6607f6b5a38436e88776171407de421", + "cc6728f652a143e785f9671e9b80acb6", + "71656228538740be8a9d8779eb109c49", + "5925aef2b8a64539a6ba323242da4db7", + "5eb658f503854de1a23943588dcf4286", + "c0165f18adf846a48ad803fc8f4d0f87", + "aa7101bfb0fd43f2b5c8cf5b670f314a", + "3dfb212bd7cc4bf7973e58b1f8d43e9f", + "9d19862bca0e435d9ffddfe75253b046", + "7609bd23a74f408694fb4847ae69b3dd", + "61d529683f904328ae28871ffe673f72", + "b6aa6e7f91d545f3bb5d4027a83e2da1", + "ce5192e319054658acef1d8fe45e9eda", + "f8a604fb3ade412191b03dad177a841e", + "7a5b5943ed76400d9f2400f06775e20c", + "61105dd854994c07beb66e5f8782895b", + "4237721edd044ec79c209770e1f90d72", + "a76e67aa94ac4a63afa59cb00e027139", + "3964fe9da2b243939f8f55765a3b0380", + "32e3cc62466b41feafe1f1585c9c87bc", + "958bea47f15349c5a2b888f5180c3023", + "e44b4e5fc9ca429388cc1d4fb3cef797", + "ee91ba8393f24074a862b5a8a8a6a1a0", + "a5def4decf18404cb999ca6b9e22fee2", + "8bede92081044e219e9cba0b5e3753f9", + "48fefabd53734af781f99128f9a32eef", + "3a60506a2cf04bf082c618e289e95a2c", + "8e1a9b000bf64b3faed962da7062c9dd", + "7caa4ad33f2541b2b606728f7331923f", + "1ba635669254461c957570a41d15616c", + "b277acf8d7874dd6b7cf2184654c4f0d", + "ae10c7eb86984b8eac272c39778fe5e7", + "978be96600a0434e853c938e93b9c893", + "e2d5b3b748e5416b825f43391e7d90eb", + "ea52f1800e814b7eb9df555d8cf46725", + "8b4ad3705b544f55b3b01f6fbb3fd577", + "82b72a54d62040c6856773abe6da726a", + "03f6cf1305794ed3b2e8f259dbe94714", + "64161445a879461792aadf95d95b03e7", + "e99f7b2971b843bebdc0122bc63f9d95", + "d3fc0fa08efd4786b989bd8d2d3376a2", + "c2bd80794a3947238fe610f5733be9d2", + "59ec6f10d16f4fe9a683462e3c780386", + "96d7dfca30f0463da09ed3f42347778c", + "42868ca164eb428e807b0697c23c4800", + "696b2b10cd8f4d38a7b00028029d884f", + "309c9156f9c049beab6813a2b1ca5b46", + "80f8d9a6dadc411e89ca366cb0cfb0d9", + "9554eb0597ad4d0dad8a4caa90141329", + "aafe44319b65425680862f9a50d35bc3", + "9a0c401dbc2743eb9a2b5ad5598e92e1", + "77350cd19e18435c9718cc76e98de28c", + "f91d3bde48924feba00b17f71c2daf50", + "34ad55182bc0444f902d301e12650a71", + "7bfcdf2d13654b0f9f5e3098aabe4895", + "f162cee189bc450cb0bf9df9984ea45b", + "554579aeec3141fb9d591fa7c0127b4e", + "052aaef6c5c34c5bac94607bcc12d2f9", + "a1335f1604b84ad9acda9177743bd890", + "268888fd930a46dca8e3e62f2f743618", + "74dd3cfb132c4f0aa2c1f128ac8fc0de", + "e87a01fb9a604c4794c82e0197233f99", + "9db7f69324c748e6bfbed697c5afaa1e", + "467f78253a974f7c98506a85db5eebb6", + "39a813c157e94a3d9d1f2332134a47bb", + "5c18444a1e604592b1f72cdaebeb570c", + "8f967d1053db48ce9edbf8741e376f4b", + "7fbe7e469b784e8884eb07389d990a01", + "eee4877851224f068af45a00c7978248", + "c380debe912d4e14aab032c00a7af0da", + "dc4eda56ba334e3fbc5b79feb2fe91b2", + "176e4cf301c94641a4fb6f8fdbe56b42", + "c5792e9c68464dc0952a2ac9c463e1dc", + "7bd76fafb0e04c498fd1a764ae337ee5", + "ceadf5bc19284ad89a60c2ae787d6d06", + "f7306387666943a3a53852fca4a977a2", + "9db4c0c2be104b12ac0ae669888391bc", + "54c4941347d441a7b3ec8341491382ef", + "0b36571a18594f9d910188c261f7dd79", + "4994c7dac1504b538ec8f30b453fed6d", + "af998661f9d5407d90e60ba6df492463", + "7fd81f080cc348bebb40df06c627b26c", + "2eedb12ca07b40ceaf7865bae8207077", + "641a07aad0c24fb1a5013f74d5c3828c", + "66313f990b074bdca66a24f49148d613", + "f7961f80c8864bcfbbf15f5ed5a6ceba", + "f011cfd101b24342b76f5bfc3e38ba6b", + "cc124f92fdfa4742970de4c67489b521", + "fd4d42c9f8314288bdfb356eee9149c8", + "8bdac8c7141c4992aa1a5caccaa5e4c6", + "b42eb197671c48a3bf89d3d4f54366ea", + "aa3c04e297f042f7a0d5d10683784da6", + "f60e67989a6a4be187f2c6cc2f5ff07b", + "47b8ffb61de242c8af5690ec595b831c", + "5a9c7c1899c84a8e87fb3930132cf478", + "4907226f07604ee8ae9c98bae470069a", + "ff5d1c07cd4b4f1bbb7da5fbf09f5957", + "19dcaf51372043718054db776c2e55e4", + "287738fd02734769ab20b648fa8537cb", + "f4807cff90194ef5a17107cdf8a30641", + "c254e045aab6488e9d617ea5e14fd773", + "3edbd8ffbb34480ca4876aa5b9e6f0ca", + "66429f512d0747059e177f1c319e2ec9", + "31e0899e65f74cb9bfdc9df8e71288ee", + "b554058d4f4246e6ad237e9326532f2c", + "fa359326d8c84db49772b842aee09f15", + "a423b59b916446d0a83405e208181c52", + "da6dd9f25f934ec3875bc5e42a8d428c", + "36b38a6fdaf049f1a911a262b714d2db", + "790bcd5d1d3e4047a2177167a8fe9f4a", + "2e0bc4dfa796479f8766a252ca11cffe", + "cf8404e8ca7c463bbf50e700355bbc89", + "67c96616f3e7450ab31166512a9290c2", + "43ca47cd6473442cbaed866fa3633278", + "9daa7e197807443cab2f1953372f92f2", + "882fd2908fc8419d96d82e753fb721a6", + "b6a95fffb86e4c09ad4fdb254b1580f0", + "40f477d4d4b24d9a9e9f15f0f8e351b1", + "e2Dy0ShZg16Cv9SgWvmaHc5x38l", + "7b5e576348c54318bb05374136e34b1f", + "8a22c390b97143548de89a7cf646d9b9", + "cfb799d935d24119979302e84851608b", + "8d7a3197489b4067ba25a56bc14bb858", + "7a64a78ec54b4df387f8fb6ede3ae0ae", + "e46f7f814258411a919220e33c8b4572", + "94eaa3d25028483b92bce8b4bc3e6e6a", + "32a4f80a37104b8480f5679f08816d59", + "ad354f84b55a42f6a5b014879973dcd3", + "f5c620ce3c6845d198249220d082a2d5", + "56139b42c28e490ab4b7509bdfb203af", + "446288d25cec466683aa2910fc270826", + "1c18d985532246fcacac07437dbc4b70", + "56c758c5f05549e5b3eac3942d796bf0", + "ebfe7e99963d475dbf925acd959b613e", + "18e2dec114cb49d19153d0d1e2dc987f", + "0b49bcbfc5ca402888c24c0ed3fccb18", + "d7af8c6b83824fa2b70d16dd85e30382", + "93168ca432e046459b9e2c98cd9324bc", + "ccc624d8515a4e2a8991256807d0e46d", + "4127eb5bcea44daa81cc591a75cb6f49", + "ec964511a3ff41c18a13e9ef18765e17", + "ccaa5fe52ebb455e9709451e2545f527", + "5d40fa1205df492d887b5d7ac04b72da", + "ce594691279644ccb366dce0658ce756", + "4a0987f23c9a4b9099c63d39dd061ab4", + "6547ecc4f59c469791133d9ab06f67c7", + "306bd1c648924ca98f22d1d4f1dfb7bf", + "616d4017a9a94f1a83f90c3e6f535316", + "3ce131c1ece04e908621d8b72fb1ccf3", + "ffacafbfe9e640e39af162be077efab0", + "1230d9f2086e42479bad0043fb0a89a9", + "70a87ad33b894a5eb5f49d15d534be9b", + "690bc97ee8b34e15806cc1a499a7a21f", + "4139cadb34e8433a881b8380fdf8ed51", + "7ece1ee1b602436dbcfb77e4f58ba8e5", + "5c9113bbd9d2437da09723bcb8573778", + "46f65621f5264d1885097d9b432856e7", + "a075f9b382f24e4e85363a3af97fe0a9", + "2a6bcfe1c1d848bea7db428ca06d0ef4", + "45076905be154f43b7964b325ba62417", + "21654948bba44e648306208603fdaa82", + "c1e20fa3e181424588ec632a4b62d923", + "7684a1c08dad4d4b9d0ff76343a68247", + "88dcb09a90c741c480d868e616033121", + "aca6baa7f4dc455eb1aba1819e3bca4f", + "4c11f50141b44f34ba3755850d6e804f", + "c0d64fd38cde40d08466d00d59455e22", + "c9ae74203c27437e8b80523666e6561e", + "16b019daf966406295000f4ff83612b1", + "921e5f26a12643d99cded65621985a24", + "b2b821b31c054ebabfcc0f6df2bed260", + "279a0f9732ce40398220eb36244a8b19", + "25d424df0e5d4a2fa69ffbec4d1c8648", + "e7c0b5ed29364a4baf82b9872adb0b42", + "67b04f8e125e4ae4adacb3fc42d0016f", + "b8043a6925994d1daa3d29a2be22d5c0", + "dc0325eeec364e89af485821637bb03f", + "73b3e6d4fd35432382b9b096754d38f6", + "6656586a17db4590ab4d843224089357", + "17faa712d1134d4493667afa3c39f274", + "479082003e3e4f99bf5d36039164a7a7", + "8784b8cf48aa490797cd13c33ccd60e8", + "88f78a2329084b9a8a2ac827b0e198dd", + "22732575b0644cc9b65cf21857288189", + "54a8c3b2389346209919b86847252ebd", + "a2cdf40f331a4cb1a3722f995df5f293", + "98d7adb2286e41ceba3a6992f1604813", + "6ca43aa457c944c8bb5d9aa354b09d3b", + "d76b91082fac4d4484619d9fbe4742a5", + "cdd9fa988d5d4a78a8ff95dc93fb5fb9", + "b948f573ae844cc1aec5872440fe1fba", + "ada8abd5afd843abaa4b9aa2654b9702", + "b59a7634e4ed43b0a5f7ae309253244e", + "8d9975ce684745489f526b4b2ccaf349", + "2bc979ff7db84e3fa26ede4f5b0cfeb4", + "7c4236ccfe854874be675c548c7e22b8", + "f341522dc244493d842c0f61e61c1f0c", + "a5acea083aca48b98056917a53d91c4a", + "1ac6f72e36e7493d88c75cafa10e249a", + "9fa0e267fb3546388eae1f6b36df2f48", + "a3a17b679da64cbf9f30e68336bc7af5", + "df3578dca7f844ab8b7205a1fbea5ed5", + "0964ad0c8f09472f86712a752b98e714", + "513258ba2c2a4592a77ac1913bd83238", + "14fa7c1f2c694e5b93622403c2f38ddb", + "e4bd5860d82b4baa970d3574f0c1f35f", + "2db7e238fad644719a7d2d6237f4b177", + "e7c90c3d242b463d9f7346ac39742105", + "aad866316e0e4af7928dfe38b465c858", + "fe87bbdfe4c24b26a40542bac106baea", + "fe1ee2ca85c0471ab7bf675cc389c08f", + "576daeaa281840cfb3ece4850cc42469", + "c4c9add7c8d143f686de29d5af82cadb", + "39e96c79630347d89fae5f6e5417c4a9", + "4902255e21d143bcaefda91270e3dacb", + "33619cf0e6b94714bd611fdbd1268cc7", + "ad4a281c460f40a9bcd88d87e86cacac", + "8c07e2864abb4ecf83c4eb5ed56a8344", + "578577e4e6584b58b1072ab9aa40314d", + "824c4170f06247a99361717c40377294", + "b84402001e314a34b6ffe0a363f5feb3", + "a7acbcb9765c48cb83d70c6ee5829561", + "f7f99449b896488fa6d468e70518b21d", + "8c3ca09b43914ea1912fc37baea2d612", + "fa1d5abb62e9451fb236f94be393c174", + "753efdb4234545a698343661c59664a4", + "3abfab02e5d645d6a1409c7bc0567fb1", + "2f337e1ed3e542958106900c59c48199", + "b1a6eed00f1246d9b8f8f08003c59362", + "7c0ba25cfd4947d88b34f7eb488fcf1b", + "9347aa1119754f6d852e8c4c8c209ff1", + "34adecc3e9ce42e4be9befab36ae4467", + "a648f1a079674e92a1a5bccddbf8a76f", + "16e90be4f064482fbb718a5c44111603", + "56d7acd7e9eb46a9aae4b048cf4bddef", + "60e287ea45f045a1865bc2821ba53058", + "75bf49a757fe44f28a0ec980747d5f97", + "0bb4502d513e4fc9aaf4e231732605c0", + "c8f071466cd149968a5304b2267f270a", + "1bd1cc8fc7504b9c80786623cf7f85d2", + "cbfcb0e1d8c74f02bde4cfa7b92115f9", + "da75627c09064d1883a1828aa8cb9720", + "ee3f18a9e8d54650af3b6569d2119ccf", + "c93c1dbcf7e944eeb5d85ef78052ef4c", + "f3b118a1699046bfa851b6eb2d213ae2", + "ba435f0822f645459ba87840eef254ae", + "db7970d542994fdfb9088d021eed9232", + "1f26f834704c452d89cee72ba9e5e02d", + "c672510bf36f4208bea36d26e9839323", + "86c5d086d460497baaf4b55527331c85", + "65d3f968def74c578f095e910984f59d", + "257512d4edbe4be2ac782d9ab74f8360", + "4ccfa4b5c0064fbeae7b802ef789faf9", + "ffbf344a1f1b4e1788916514b3291d16", + "eed294ff80bf46b1bfb3a2dbbb69428c", + "1a1bb7694481411984a810bcac275115", + "b5f029a587ec4c5499ba13ad0a1aa88c", + "4281970c9fe94a778df26fa6f0c58a96", + "fee4160588ea40bca74e17785f5c3179", + "41d7a4b0881548b197a36cb810023b07", + "3980af8caebe44388e9f5cdbb5c54bab", + "f2b54451866748f2a7c7d9afe2f2bee5", + "a14b0fb5e6044c3d9143c9e764a916d7", + "c5dc6954cac64a91822ad618c955bcad", + "7b0b46fa543f4eef931990f02e210808", + "336574c433fa40999108ce40a19e7177", + "3d316350a1fe4401a2b55fcf2396470f", + "da154bb403b64693aa3d76f9a935a5be", + "b435ee6285cb4074bb36e8e7eb5f502f", + "b3a0df3eb55c4f41b57d37c498b7a6b1", + "11d7c77bfe804f448a516928adf3f05d", + "de8ebfc9e3704da5bf60a2c242584e80", + "bfcf7b1990c14e849661a00bd8b55620", + "af3fc082f6e74f2a888eb6a5a85a8b5f", + "f36612f3fb7c4c47a4973a8c305263d8", + "5a113f8624ed4404b5f7da708afed7e0", + "628d7fbd4d184796b51c4364114c5c10", + "6f3da1f0a2ad48ebb038e186702ac183", + "8b70001c63874a1892f19efbf541002c", + "d7918fab9b774f10b9fbeffdfaf27616", + "a10d3269ea37452fba09d91e97b36367", + "d6f9ad8cd65b46e9b77e1b557b80086b", + "0d6f53251bbf4a63a166c6e3d8afd80c", + "e265e57bf45f4dab8c8ba096c530fc62", + "edfb87590e8443e0aa0d2ec3a000bc52", + "86d4292baa6c489ab5fab374bf803106", + "1725e3264af442189e080894d9c5e74c", + "415990b9b8d7434099682efbc9993132", + "f8846e71faad44b4aebaa92abceb2e2e", + "6430f9d2863f4524baf56f9b96ee837d", + "0815eb999f144886b882cb5e2153f6c3", + "426f0b2bd5e8400684d319e537937197", + "926e2a5d9b7a4ff883f8957b3d5b3dc4", + "a0671f81b7574c619a8d22d8dc5ff7a1", + "5cecfe38606f4c9b9d8b33e43ebc1bb5", + "5955227c35914cc4b7cf562e151013f1", + "1759b50bec9b4e5f95a3069f08bb129c", + "7b1c1b63fcf645b48aba908aa3e5bb16", + "fd5039a460f0409294973429cb5d2d4e", + "3a2a7c597431416aa7655da8f747424b", + "74d64b35a3dd4c3ba7b6deb35685ed8b", + "f0e4e8ad54e14cdbba7bc84b1e871ae2", + "8108e576b26a41efb2d10d24439627f5", + "6b6e386e8e8546a2962df268c90f969a", + "927592905950476eb2239bb45b5eb2be", + "6ba95918a2854e7ea4213609bd965dfb", + "9f05fa536c4b427089de9768cc64a5ec", + "4c5a08de9b0847859c01284f2b83a290", + "0a336eadc4fc48b4b12cac03162d5195", + "9427b864e0ff44609543163b8716db0c", + "43792309ab8347d383fecf459d8365a5", + "01f74014d40f436e91fbf60e7f688057", + "500a64623ef1441db994bfc50e278ff6", + "1af52d5fc62e4aab9fc547259da2ba49", + "35902d53a7504dde83dd097f05696818", + "bb28444c224e4a4e94898e42bd50851d", + "38dfa8d01cbe42d8af890e21b29e665a", + "5a3db93a4a34435b94ceba1c3389b555", + "a0e315abdd82496791995e2ecb51abff", + "ae7142127dd84ebbbe7762368ace452c", + "0b96cdb89d75448e8f11ecd2a65e2183", + "1fb35ddb0493441d880b6b47168ea19b", + "9db9943054454fa19fcb2ed29cf26a68", + "25165076b9714999b14ba97b24ede3a9", + "1e8298cf521e47a9b3e3289fe4c190c8", + "dce5bb1f7abf4ed3b8d5ca2610d63023", + "682695ed62224411a58cd4ce76025a89", + "40c2bb3dd9884b3b881d5d577d7d9746", + "adfd231ced514558921e7fcb7a6f7f51", + "5c288986918b429fa5fd04edad5cf60e", + "c47f0d68a38c4c1e9a7c3010b0820528", + "5b930661644947fd8b5380c251e6904b", + "18a7bc41962748aab88ace9c70b90c31", + "3e3cb1a30ad84f3db40f0d6baf613f11", + "f41e5cd3583c40e18a14df47287a43dc", + "b0f59aea79634f2ab5a5eb0467e0926a", + "3729b2dd716f4c89b87a192290295808", + "b0971a91ff204b6fa8d1ddc5725f2f54", + "3b706feb53764c1c82271e02c10f25a8", + "cadc1e7d00f54cbeb14e0beb3b1a2e7f", + "3d5a5d4daec8433ea2f258d7a66a77f2", + "4dd6c5f49c7c481f8b6a5038760a3b88", + "ff8ecb3583684711981b02d83bc721bd", + "888de04c27a2480ea720f2a914e7052c", + "57d406eb5b904f36ab13b79932cc9984", + "657f2da8d75c4781b0f3faacda7561cb", + "1378e50dc7314a0a8f93a09091436bc8", + "aff60c9971ce4379abbb9f70d779be97", + "f444d6ea8ae249e889340719045ee555", + "2ee04e40790c416a8c4d8f598e5b57a7", + "2a725ae04a33493fad2ee6dad98a85af", + "0fa6ab1eb17c4e64be43806b2a7092f5", + "3b68aaab1d7d4bce889a2803b131a375", + "482a8b696fd74b3f95afb06c6bf72c1f", + "87c86eb31abd472083f7fe2d876d95e2", + "bc204ec140f94cd3b4c9c22855c3f0f2", + "cfdec705db9341b881cd95147793892e", + "ae7f73580602427b8352cedf8aaec0fa", + "acb82c319cc14ae9b77e73c41f9a4f66", + "f7d9c98b2fbb48e58ceb7b63ba1dfc5c", + "3d9c4bd003aa43f286ad81c9a5b86070", + "f0b1f7c17d70489888f5ae922169c0ce", + "1b4dc73c97c043e0be33c6beb3ccbbec", + "f1c3d0d283aa4472b411853bab7d8a78", + "64db8b5ade3e4981b6d507d3808743c8", + "9872735a6056471797a6fa349db8a830", + "07161ec7fe8d4bc3b625efa33c1bb23b", + "a739fbc9d88c4daf9f730dd9f6778c68", + "30f1714b3e9e48329b37d1a401875870", + "10fdee6e988046e9bfa6344e9666cf50", + "a51e4acfdbb349c7876d7c37d2a0ee87", + "28dbc43651294813b7ec16f88a4a2628", + "fac31ebbca974f3597f12ca083ececb9", + "43a42b1afd564df087b81a92ff4624d0", + "c5105c850f5242ebbeed012b648dc15e", + "bc8bed05201d4bb380ce1ab96ea2d4f2", + "9ff12795a40e43c4906558267bf8581a", + "29451febdc894682a36a5112fd13f054", + "1fda132b5f514836870f0eec4589f2ff", + "e1429326fa5449348f0e0693f44b4b7b", + "d7461a81d3b3402faaa1c9eced87c8be", + "524fa6dcbf81417cb2049e15ee5f7027", + "cbe6e0dcc10a414a84acc5cc08171b87", + "725065392aad4b04b7a172f8cd965497", + "924f0f90d14c40eb86b4a985875525a9", + "79a64236f0b74d78bfa2db18a1c68887", + "67ac86b4022b403dbf0dc0c66dee0ade", + "f3c14e0c58b14b808c2f2c5cf34736df", + "73046d56fc194b17be904b3c76d09585", + "45e20493a88c40d786df8584e63efacc", + "216c3f967e0f4895a9faf6fec328024d", + "2e0afa27358f4223b658e8351002d19f", + "cc9525c43e364839b706dd564692267f", + "4e1a4eb6b9854983b66098d989dfc91a", + "a17070d3ce224e9d80bcb4cebd10c42b", + "287c3f62c2b04a3585e2efe26678b8a6", + "48a23ccf80d54be88b9f7e39f10573d4", + "1c606ef8da3d4881a87b29087f6ef4a1", + "82d8dba71b624d0cbcb62c0e7aaf001e", + "1837c24636634148935c922e49892daa", + "d06106f340f64e26af8f0d6e6723c459", + "f8ab2055416c4a8c9d4e9e9377b3bb85", + "a37a0ea77f654aee830920ed148ec0f2", + "9937b74270244602b0e1e9744683644a", + "904231517fd644ab8cae9b78544ea029", + "2371d1aea7b647b3bbe635d0db8d4fd2", + "1ae4148047c94a8d9f2d7c8443c29c5f", + "6bc2c5e0de894d07ad6408e91e20b99e", + "f2ef78fd6a5d41beaca80843fd9717de", + "6fac7eeb54f2474296a0c473214d44c1", + "a187c344220543fd88152b35c3e28079", + "07b10f607162439a98233c801a42ad12", + "57ad2e5534084bad8fa10f858d4cfcbd", + "552994f9499445fa899c2f223beba46e", + "8439e9022f024dbda814b6876c130ded", + "0ac34c3eb29f40219c554ae8445860c9", + "659d124e115148e7b7605cd1129292c4", + "5dbfd6be3c7e4c8788c3eed8b4cf43b8", + "80e6e49864974c529798d7fa7ca589e2", + "6f83d025c0274d149dfdf8be910b75d8", + "c661b482f5744ca18a96426b9a41bc9d", + "81d76af8774446459a8afba4fa212da3", + "9b526e5788a043a6835309ac2b64ddaa", + "52b81c6795274dc5ae0093c068e50a4d", + "7db7e771881044f98df1f3ffcdfa842d", + "c17e8692f8d141b39ef30ff643163c42", + "10f03147643849b99acc31551af6c09d", + "7153ad2bff714a17a17e10979718ab14", + "c934585162de4abe81b151a2354217f5", + "5734d355fff1444ab57e3d9228f956d7", + "9a154672d9b34b50b39ca1dc26cc45e0", + "30c09497391d460894e7915a580fd60c", + "6666c98dc39b489bb4b22e44776e8204", + "9f7b04b6973f4684a4d7392876bce696", + "2b6e59b4a4cb4a49955c3dca60a63992", + "a24bb621d3cd4ec8890b8e8dca9f2c15", + "de93fcfb54c740fdaa405ce3afba1031", + "5d2fa3a3260d4a4d96165c4b29880e24", + "e55af322cf8f43fa9b4fb2b368bafd0f", + "215d9f8b0d0e4bada8c0e3cb65e37a35", + "c2ae2425966c4d15b6ed40184c334020", + "8da8a154c56c44efafa4d43b4dcf666b", + "e5e0396f288542919acc133f9bcdeafa", + "a064b7b98bba49b0a6744327c1119232", + "e69089e90c194318a3d2932557c8d3ea", + "a815ed8fec774767ba18485a12d5e102", + "efd6c0746ba94f26a53d5d820ba635ff", + "0b795895343b44b69191ef9b55b35840", + "1d9cf098cbb844d0ba092d0f8f3be05c", + "e7c14efcafee4c40a911d792aea3decd", + "b5d51f385d394ac292770b692cbd47e3", + "53bbfb2314fe495bb9750c3d96fbe29d", + "e892d17a63f847fab97f1a73e31a15b1", + "2fdaaa37deb142c289405997e004c061", + "23feb380870c443cac18afc6e26ef074", + "f3d4dabeee9b4aa78920ae0e27e6701e", + "998ab19ebe4447468753686766f9aec6", + "cbc20f61f39945a3bfa5d33a21b0c468", + "3f7478d095e74e3083a1169cd20c5856", + "a3e8c51f850a41ff978fa517bb5a9010", + "f28927f1ff7a47a2b5c8efe5789cc114", + "6720540ed8014c219aa14ff00caced01", + "248f4cb5b324497888b97e4fe7f84964", + "a32d200bd3b94ce9adb0f986d94ccd39", + "2fa5e80feb2140a795d1f98e7909e238", + "094130b8514c48e3beaa011fea272c5b", + "5bb6dbefcd5d4926975e33a68612bc1d", + "b0d32690c63a40f6b6664349030293c5", + "1e7898f9502f4ac0a71e03ab8a5b18dd", + "9db7356a148c4321b6ab36f067025585", + "89f2ff51b5b2431a94e57a5c11002749", + "ea8aee54a84346fcb0d303b2540b4668", + "b4da1f80949746c99ca637de9ca40786", + "f25e5865ff8746879c61c4b8158259f9", + "22970f61752446b7b207c3cdeb8b1203", + "81c8356529ba41d19f41ed91985cd532", + "fb3d849c6de346079d338251533a84e6", + "8554e0ea4ea24c6d94399e8785bb8de3", + "a8176d5e9c994343a8800453e8769905", + "b167e8b457cb4cddadbe5f7925504d3d", + "4a6e2b1cf5d54ed5b97da093ed1e74a4", + "c1e465c8a30b4fe7ae14451f71c92ddb", + "cd87813cf97c4b138132e42d0fa0fa3d", + "50b502b883204528a5ef6db4ea2778ef", + "5b115c0091a745af8a1f2f35fd44a4a8", + "c6259bcdfaca4e5cad3708af0af1bba6", + "b173574f823f425fb0cb710cde4278ca", + "0045e87262664927a3298f2ed0f640c1", + "7732924f5c244632851e3dead93a186c", + "998d8d17a4334167a4907f780491dff0", + "3c5accbd85cf464ab8d07a2c30feeef3", + "73d96cfb751d4ad9a8decae6082c1a07", + "d1a772d68cef4db0ac72958c86ed99e7", + "1df829ce622643ce874b31cad96fe484", + "11c741bcc14b44e283eba9e588d9eee0", + "c109cd389f594c2ab0cf8fb2eb80070d", + "384b544e530c46f4be37039a4a44cbab", + "33f5a90402b14060afcfbbc7627f9cd4", + "f19d6a3e6c6a4aa29c1d8ab2766a292d", + "e75c407050594952a86e95ce8053bf53", + "2ba7be14beec4385a5b8398c5e8e22ef", + "8baf60e60e8b4ed4b765e44e435692f8", + "7426364684264ca69c159a0c063120bf", + "4a5903968870448f8b02a0ed561c6038", + "c4f5ec5e2dad45dda12b1124b068341e", + "32fbc3832eda42e1aba2380dc074a96f", + "3c6f04b0a330419c9b94e5da6248bb3f", + "9c09445c62f94d68804d3c822740c69f", + "646098778f434b6888f1ad12a1cd0a84", + "288a572dea614508a86c1742e899f917", + "217ecd30faa54f20b03d8f0ad9ece9ee", + "ccfd5c3f62a34c83b0e5d84fe2961d9c", + "e4def86857cf4ad7bef57092b02b3d59", + "cc0aafdbbbac49e99dada18cb3fd803d", + "13ffe1dcce0a44d4be335ed60a301dd0", + "14133736e62949d0b1da06ca15aa1506", + "d9083e64d229434094dd91159de9bfd1", + "ca8f4d8f0290479ba3253a7b75e44075", + "0e630473c96c44f9b37074eb925120a6", + "4dc6168d7d6141139a0edeb8af6fec24", + "d11840320f6e4ec7ac74de2595c85428", + "5946eeec2e314e8f8c3609cdc57a735f", + "e4659471c596418dbe64e2f6801ac1c2", + "0afe33cb89514278a88f626a04c3e546", + "dc1fe22f12f94049849654973a833cd2", + "8a3a89158bff4d65813d5fe5607c5d14", + "28163951eac84f599415846068c1cdd6", + "bd2c3192cee442ae8151da50693d87f2", + "c041c4bfae76413485e5b221872372f5", + "b4103c80ca2649ecbdc328d0d64da1ba", + "227e09094f7e4ecea04e589e0c02b841", + "6cf216e7c4b44eeeb8c32286c2ad3508", + "08aa8c9b10fb4ba189a030582b942b13", + "ba25f1c2b1c5442c9a5a1710643cede2", + "c32526fd977544a98431b489a84a3f0d", + "4b90f6769631488b9b85c1dfc860d38d", + "829b388b683f423cab51d4e1e621ce8d", + "1720d2c5bed94fe2be8579a51010b2c8", + "75e1a9de3028440d95e146223e7ca66f", + "9915f322de534c38a716ef9c2bff4ac7", + "db6515f7304b40b7bbcb84fea0ec0a3b", + "7f5ce90e3e7f4a78b596cfef3c6e1c0f", + "47c05d03f665490bb337edff16a02a3f", + "07d3214101664660841602ddb2f2163d", + "899d3d74a1254a5d93a16be4f7317b3d", + "624dd9dc5e6746e389f3c262df7a320d", + "a4d58331575b422790c3947be8aeb51a", + "1d0d5466d8184ee5b2e887c54172f063", + "52bd292f53dc4906bd8ecef168832b79", + "7970fdd20e194128a84ed8353a0e4826", + "986f0f69f2e2435ba1c8e40d2b35583c", + "2c438bd8848740f8992ef2985e3ebdc9", + "4c30437c274647e99a5638675516b653", + "f300d0943bc44c45862d07639534909f", + "f99cc5d1e24a479796e8d0661a600582", + "ad165ec4459045b1b6c2101bff620d9b", + "fc634bf01f0c46e29136e944dd6894e0", + "f0f4773bc58149c68ef48d5dec42475d", + "509561c9de194acfbb009f2efbc8d945", + "1bbbfd79dc3345fc9e7d6d87eb6902f4", + "25aea220337a4d69a867c6da3edd8bce", + "6fe45842b1924f6fbf9e8bb021c034c6", + "37f70f563ada454f8d356649e0ae052b", + "4df0a054ac72434ca2bb70b49d6342d3", + "1f6f7318f9364456b8d58c1eaf71762b", + "9838d845604f4d55bfe327433009962f", + "f16473e05e164150aead07d174f407b0", + "3c4e617b995544638d351fbe544c8286", + "3308f98df3e9434caafd77c779c5dd2a", + "c8e7c77b08bf42859fb6b5af90c8ff43", + "04e09e3885634132957a041c80499f8f", + "9ddb37ab928246a2acfb4e50c558c49c", + "75ca0a0eccf2446aa2ae66b5645bf786", + "3ebbd29fa7a94959ae684c0cc4345751", + "2207808a6e084b6991223e8a5cc4ae6b", + "b81ba5ae27ad40a3b726f8dc197a5071", + "2132d036075f4e12a8759c947e5ae71f", + "b56b7c237d5a4204ba117360617a43b5", + "8eef8f10ba56485aaaa6bc8756944b41", + "9a9c06edf41c458988572675e1f7444f", + "9bd05ca500804c1aa7ab7922dfc060d2", + "eec42e4c8e674a4a83e414107fb0642b", + "512a7e0c3c714e1ea1a5c83f90f53361", + "bc00a1bb133a43d1a2bfa2b2cb4c94f9", + "e1f5c77975ce459eb0913d2ea602cac2", + "6b4580b23d07415c9baf2135f5865514", + "5a55cb61df1f4a5da29a985b2dd96105", + "5afa160dd2334a058849adff68bb0cf4", + "c4b7f8e858d946bdb2f6dbda9540efa9", + "6fd594fa04c74e128b523a6815c13bba", + "14cca1a7fe114f6e8877b8236f9aab53", + "4a387cc30acc49e59e243cf192ec2870", + "d8cc158dee83439db9e64505e760d479", + "f72dbd34589c48ce970e2015cf856018", + "4c63de7b396c4420a30655a9c649d90f", + "987c54b69e7d4fb0b3a66b17b9c6bd31", + "d843a23884734a4ab8ec9a7c4cbbb38f", + "57ada5a88c7743d5813634d92e9fb14d", + "b9dcd9029f1b4e91bdd3cbdcb45a18ba", + "d9f66b1e0f774b8dbc9a2f00cc0d1fe2", + "34198221cc4a425db5b2f95fb13e6460", + "d71e48b8398e4fd5b4f0aacf812a7758", + "8d90c1b562724dc3929659fa97cae445", + "72796a0e02ea492999ad33e226331a00", + "cf6d4f2e80c04a5da47d76f862ac4183", + "31ada63d7e654c088531379b97a81cc1", + "ebee49fcd3f54f44bb083e2d803b793a", + "ac0c8969d3164dc5bf52a6066478ceab", + "9733523ae798418a9d2a7055c3d10b2e", + "9f9d7e4c53d64dd19d82a7afc099f94d", + "49883c6c218640f1bb3e62d7bc2280bb", + "493602ea53554e17b957503cf31cd792", + "a5ec7346d918433d890ce66f5ca4e148", + "0e652993b636429eb2d72f60f8ddee34", + "141f2d0e4bbc4e26a030f8019fd317af", + "3aa0173a864d4f349112cfe836f1a591", + "bfc230e57e4a4fba87daa8fd3664d3c8", + "a0991f0d16e140268fa1cd3067e5a276", + "0e5d578ac7b14170bba121400bce0b53", + "374d04748c4641dba2cfea7e29c6bd93", + "abba80511e8a429480df241b616d25fd", + "7e5f044ed9e24048b12601f8ba9accb3", + "ab971de201d64bce81dbd51d4054eb74", + "9547a782d4a94027a7d218b44f0b5eff", + "f6f186c5055949b5b1730a1200de26fb", + "669a9ec9920743e4939903d8aa3c7526", + "3e2aff5658f644d9a3289b27e755cf83", + "531dc9b727254aef9918e1d0b7c06e97", + "d559d782ee5049ff88a46f7747f3e8b5", + "c6def62679014904af023b4ff0f0d65b", + "0e26897911d94e7e909c7533fc20c7dc", + "3cc1b049a8a9485fbb8772af8ba95cb9", + "485e5ce9d8724b68a02dfec6236406a3", + "a12d3ae76e3944428f14e5b15d4f0efd", + "9481bf1e6faa4d4a9dc2e5d8caf11b93", + "4823dcf53e804619a219c5a21d11a18c", + "ikcAlbZ2YXxyKWW3r4iOMRW9qR2", + "68873a9c21854e97a94b18c80f381dd3", + "fa0a40d23f8c44d8989d4bcca11ea7cd", + "caf23406f4fa4f52bdf41d59fdbd70b9", + "da28757a8fac483aa4aa1205e96ea0cb", + "d3239337c2fa4477bea78944d08a8d83", + "87f85f8e70974d8c8a5cbcdfbffeb176", + "f5e8252067fc4fa5a1f79f4e3d7b7c45", + "20a8088cf7724ee5af9e6c18aa0b0e2b", + "8b393c1de0bb4cb787ad4db66e0af765", + "5a40e8ab0d734e55957453a2e927e47a", + "57d8fcf144264a309feaabd5da831da0", + "568b4f1434784d179fd07022dd4c1469", + "2b70993763034bef8587d3730c7ca8ff", + "8551cccdb3174f4baf4fb977592aee9c", + "3cdbace60b00400ab8baa1dc481bd632", + "963e794792af4ae7bc8fe02a2028a97d", + "9066ca33adcf4b64baf0f09157e08ec6", + "5ce01ee7147e4b6fb22d0d0b2732c9e2", + "33f8aadbf27c486d8d4efca0fe21246d", + "24121280217c4c9aae8b455d5516b238", + "36bd9b78f9ad4429bc3d799c26413fb8", + "57010d97dfde48bca2c072a6cfb9b6d5", + "4763cadb193a4018bf3381c2f21ba396", + "fb89199357374a838cf2d36354e6b5c1", + "b38da7174791485792f7dcc18749654e", + "f266dd57a0fb46f4a6877abdad2bbe86", + "c7f353d055b443b4a091b3947ead11c8", + "691a48c370b2415fbe4fcaadd2a17c32", + "f100fab40964464a99103ffe53e6b8f5", + "b03a2ce01d1a42c48c735f0cc7b480f7", + "e23978f8a7c64447927cfdc175cb9312", + "b687701c8eb74ccf856935859d72da2b", + "1e833779b9f842c486ed5048b96e98d1", + "f20c056dc94c40cbb13ceb40c222ed1e", + "96dd6c6d1010416bbb19eae4c8f67cce", + "f7b5e46465aa4214a7c5d389a517e925", + "bd6c178fcb0345f9a857399fd5840353", + "ed005df8061d43038461c129ffd681fb", + "7b5467f79bbf44e48e74bc15b21706c7", + "c1cf347b22334794b88e25df2ee88708", + "407d81b508e244908edf9421a7e3f2b1", + "a73d111dd871418dbb9e2126181c5612", + "18be8d9d50bf4ca4b24d81e404697b66", + "787542624be648b1b55e453052df8e1c", + "4e535b6097fa46218e85c3e0aab7826d", + "b1f70147994249f7bec09c836deb28a4", + "329bbcc440a545539e2ca4a98c9d5fa1", + "86ae105ddc6e442fa1e8509d6b4e328d", + "c0ae5edb08064ce4bcd1c7d88e68b30b", + "8bad4ac75423461ba8101c53c934a585", + "45bd80f76b294b4985b76f055b7f8d72", + "bb6396c23fdd4b078c8564965dce71af", + "16fbadc669454c26aa0927445b3c6ffd", + "3be546411ca148af8780e69151edd69c", + "011e6d02b13240ac94334d7f4cc5cd96", + "f977085d87064fa6b3b4aa4a5858601c", + "25b3d02769a44d8fb653c5f89f03747d", + "e69cb11d27464324a7728b080e728245", + "8c12dafa63ab470a8c2196a66052a0df", + "f292513de086471e9dffff684d130e4a", + "20ef523bee784e4a939b4c5f8734edfc", + "37f7c6b207da4b669ef7a5d6e7dfd2c0", + "7b1d00fa252a4756bce74aba70a8b82b", + "c7f224be0eb2481eada2310d3f7ce315", + "9f067b405463412883cf2cb5a478079c", + "3d85e608d2c847c58577074faa134cbc", + "e480dd0ac63f4043b4c2cc43aa8657cb", + "e8a03b14310c40239365f166d325d671", + "1bc919e3966d439dad1272dbfb72b69a", + "2a252c00ab8a41b4a23d89d6c232da2c", + "29e907cd254541c3ad8b42850e9ff504", + "054458467ab8477a99400979e826a560", + "f25fb0c25c124a91af8ee67e6776d6b4", + "b5c5b759e12148e78ddbc9b014f07690", + "33ef610e7084422cad4a2327760687c7", + "32d662eb07da44448816e0107e6e453a", + "049a95c55864426da8e584c0d5c40b64", + "0cd1353e9d644ebaad932ee48baf8ce1", + "b973b88b0a0846fbb1cf1535b56c8cc6", + "64eea8d653f0488f93415ba5a59b6ea7", + "3c0a4febce5f4c189b25e3463ac18c66", + "c048d51a2e9a4ee99262dc27058d8b9e", + "7e58a1f39e444a3c9263ac6f2f47991c", + "dd28da079ac34fef9eb1ba4a261083a8", + "e2889f4cb4e64729b00e2cecf1425d30", + "eb6fda005fa34b25bcd65c5c077d0b55", + "9d08bcd9c8664b1b97662691234a7ec6", + "58647d0517d34b118a57da6dfa48ad37", + "99a67144dbcf413e9dd3aecabc9722fd", + "080ac3024b6243aead9171030161c95c", + "f0b12153a44f4f048bfb05fb593a8b4f", + "69cd0639a33945ec824b33ef3bf401ae", + "c428a4e2e5bd4a098696363e1dd4f3f4", + "4fb3bab820de495599b2987e82c6e6e8", + "836aa5c61155474fba05ec15a8a29410", + "ac718cd0d7f84574926106c771dd2308", + "8cd648997eb14534839d2d03f0a7678c", + "b6380781b32047998a3d02a6ab561cd3", + "24e28ef6a51e4dd8ad64963f529e73eb", + "e11f7e3ac45f4b139ce5e2d36bec8b4f", + "eb0ea87925764e78a0854439fead928f", + "a631ab27f32949e6a8f2ed94d040b9eb", + "89e26f8f166e49468c4606d917f90d03", + "1749e9f7223640c1944101edda958d00", + "c718746e7bc94a75bc505134e4d2c4db", + "a60bc5692c244d96b052e0bace19682b", + "a4e6cb969a80446cba9f17ae921f4272", + "797fdfccc46546b1920d936cce04593d", + "695995c32f194a81811c5e53fa872392", + "4db46afedfbf450c9a19b04ffe279c3d", + "9a9060f938104d259f01454a2e461627", + "d938c3e3206447c496673fc1a937131e", + "ca875610880f440abcb0604c1552e2d5", + "ed32e368b77f4fa88c1f0eff73e8bc55", + "742051f5b90948adaaeb5e75c10b0c36", + "049244b637ae4f4d9548742f0389bba5", + "d62e0b6f29de4716a250b55359e87193", + "270db66c866645c4993f2b6d64b71a81", + "7dab0b937e7d4a7c8d01ee6822c1a37c", + "d584a1c6840949a8bad9d55e527e219b", + "76d1eb497c5241bca27a96fb0083e40e", + "bfdc0641523343dba5e793c30e02e411", + "19ed58b1a695469b98a10b9557568644", + "c9c5648e16fa4ce18b80499ad8f4d277", + "e5e0beded526432bbef106c73bbc1f1b", + "eb664d2b46bf4c18ab466ca44c69a747", + "49142b8956aa4eaeabad9706532e0e75", + "3f8f5ecdee6c4dfb8fe0575d0d552c31", + "9ef5e164315b4375b207b0102b0cc288", + "c463d24259b5420fb16b24f0ea7e89c5", + "60d2efa2bc084a76a824119f41376092", + "7f85f9c7b3ab495aa097023ae8d9dac8", + "429059e430a84556a6706b9ac1d58488", + "54127d454edd4e3f982a46f58dd6c816", + "8a059a1c1b4e419d8fea3020fb00280d", + "353a648db4034239b131b77c5d55186f", + "dc0d58d286ad4efca1b1d68c278c518f", + "1b4d2c8a37974720b2abfc28169fc28d", + "84faee90e84542b5b9e1aac1c843b16a", + "51bef98fad83423fb47b9f1b85a0dd28", + "40cc72ae63c94ef7bda1610610942a0f", + "8912d944b0954e93840a3610660d5aab", + "eb0df79f44d84ebbbec3a7fb92f53503", + "a1e5e2a37d6a42299dcd5cec06cd1ddc", + "14d61457a9344bf8b4397cade98b926a", + "9cbaa626337a42fa8299cdd4a0be8477", + "22d097107ccc41ae873948a76825ca61", + "d8143872de8d4c6b85af59cb3395e9ee", + "70fc9c4fd0754719a0b39c79ed7e1d86", + "674c5467894b4eeaa191ea6fc11c842b", + "14fe03d792914d51b6c6250b393c44fd", + "a5b9de6b340f4527b4d99d579c8c844d", + "b1a3c42f6fc94fe89dc675d2bc129c3f", + "ef71a9d082024c2aa83205c02943af02", + "085dca6d7eaa49a2bc459adfe3357da9", + "c1d790c39dcf4ba2a9a47b4c0dc8836b", + "3913f071e02b42a181cd8b793c0e1cbe", + "8cafbab7a73e4fb7966a00659a4e31ef", + "3bc7eb1864314b8da5b1f277ae0d3889", + "a1c905e9ad284a17bff3920af7dd605a", + "f53055f87bbb481a96538df3a504950d", + "b0b86391b71743b3a0763f10f44897fd", + "60e93498c4ca47d48af8b7c60e0916c2", + "a295e68bbed344bca0622a792fc8d7d7", + "18ed671cc9274bcda023e63c68586be8", + "36d8dcfadeda4c939bd92b30bfad6d1d", + "42552e4ab8c241319e9ec91dbb0d6de3", + "f2b357dc313b4a16891b34354a681b2f", + "c7513de586204b7abda6219548489518", + "10a19cf4a0e9418389e554ba6426dd24", + "4b41c6d29e3c4af9890d62344a3106d1", + "7a3f9b9ace0f4d9490ee05d7152c5980", + "d96d62c234724d90864bbfba85307e63", + "4e80cb5cbfea4390b8332e2239e769ac", + "93ef3734029743f0a3a5fa6969cb9a8e", + "e6f66e05418f46c1be70f59b866ae87a", + "8e632f9680714da6b9536f5e6003c722", + "90c9c4191de04730a38f3d1cb44cb92f", + "fc042d9a11b44df0af7ff4acff9a8ff7", + "3b1033c7d6c84db8b0850121363b65ef", + "d9ecc3fff6e2402d9d1ad524ab635808", + "01e351b9603f4fd898e3e2ffbc42af92", + "9d570b2268f14a708936a4d7137505f0", + "c2c0504dfff248c8ac5c30afc0abaee7", + "07607092dffd429e8d07eaa050f79a7a", + "bf38a87d03834065a5f25c29a1cd7273", + "e6e34b501347437da690876bdc0ff7eb", + "4dae36c0831c4ce4a66af78b8f2c4d9d", + "3019c070516d42b494084cde1a35c3c8", + "b143c2bd61ef48779b25da2114cfb4c4", + "d90db5cff6344a04b45cf95d1f32a8a9", + "231f1fb0e9c24ab998b1af640404fe7b", + "9d5c6b51571841f391e40f85420bf002", + "4e4eeb01ee1a4a7bb8c333acf9899713", + "8a3313c4c4bf4d98a4874005c40026fb", + "5d83ee828e9b47d9b1e01a9602b1bed9", + "ca4ed414fbfb4facb48ee72b1e671e5b", + "0612a6d6ff794628abb96a650399daa4", + "42a0335c77c34ff3bf08618a168f73ec", + "dce32ef7606942269228d96568f83c4e", + "32248c4ec53541e18c5487e7273887e5", + "f1c30970559146db80c629774131ff68", + "d06d152ebbcc44f0b60f37ae9350bf35", + "f513c2d96ca74042b07373c672138442", + "655237b93d464cdcb499d3390ced7ff5", + "7c2a791bfe6a45eea78da716af00e3f3", + "dc9445bda945492685cdb19a60db9ed7", + "2a34891d4b594aec9d65dbf9f48a4b8a", + "123f9c8a30884f91b34168c1375ae987", + "0b9b4d8173b04614bb9cb40ef2edd240", + "e0613851ca1e4dadaf605d401c460771", + "a9948e60b45d47c6847e52e588119a23", + "96ef35ea0f4e4a5b87e8e91722f2c36b", + "d601c2907f114376bf9826272d686e81", + "a898b0883f14450abaa808023afdf5e3", + "7757bcc247364677a415090c5f29e1c3", + "37b10f9c92584dfdb3d1337697dc8843", + "b0196cd55f394ba4bc1b39ea4d4e5620", + "1b98b99b6c374df6beeebd9dc3332abb", + "42ef95c945084551b92ae7f63ef34f4c", + "13967f91e1524e58bb64bb47dc992b61", + "0d40f712496c44bba4b008b74d5e1764", + "657319b426564107bfa47b5db3b49f15", + "bd50d617c3bb44c3922d9633244ec738", + "3d154ca29b1443beb9f8eadd35694737", + "ac0908f9618348c6b80810ad29721676", + "ecb300085c73499e9d1b9f168faa7484", + "6cce0016ca3845c79b73b36a3208d94d", + "d79784074f084d18bc6cf52ec2e5f6ae", + "29a4ccaa809f4196a6e947b763d93e82", + "5967a2c18de44cdfafe7dfedb8d47f99", + "151c2a4f217b49dfa4207a918e865d8f", + "415584bc3224484fba20a482592e2157", + "fd30810e3fa84866b1b4f767c083ea6d", + "1417f33525ba46dfb3826c12a0d356f2", + "04a5b9260a71412cb860357610c80e35", + "fb99aa884587417c9f205f848611278b", + "2fd6f7dc02d8413da9af8195cf5f8239", + "4e3fa4ffa1b94165b76c9fd50ac2c2d0", + "51010c5d6a0f4689b14cd7e999616ce3", + "3c240b7314da4c00ab2a357fd7dca6d6", + "abbdbd6b5d6544378d8b4fd09e53fa71", + "c332a64343df42eca94c05a4f36a33ca", + "9358e58612664ca09b4be5be1bc30252", + "5cfdc9a812524f4e9bcb5907a3175530", + "f8bbb49681014e239f79fe6beef523b8", + "74dfd9925fde4ae5882eb74c77c3c663", + "16253d91b6fd42c2980940a83f976e67", + "5d6eb03cd47d457face2d692ec056424", + "4cffbf74c70a46ec9d63f33552319215", + "593d9b663c414c0c8cbe48c311dd9878", + "2b84cfd2dcb74c56b1715a44766ed325", + "a25540fc03ba400faf012d4f68b7ba41", + "acc9845b7c48479c9b23d93d3643612f", + "7f3c463c314848e0a01bc4a77b664f49", + "ba627a42f6ef4a8ca7c1c91011465755", + "fb56f8968a9c443897498a9ccf5c46d1", + "7fa65ef191b548a6a2e01c485bbdf55b", + "55325e3b09ac48b2ae3803bccf804741", + "c4d8cd0a027043f6ad6694784bde1eaf", + "63cdb278c4984c72bc7c65431e6130ba", + "67d4fe7e54104c6d90fd61ffb669d921", + "9b50a3b59a654210989494c9e456b473", + "25874c2c9e6c44c3a7b5d728c3dec4ab", + "74e217b1521343e1b72b044f4cca865c", + "6724446ce310413dae9a6bd75fe0f573", + "ff3b7016740e403f902a7ee54b07ef52", + "e728b8c49c8842c99efb8b971e75c939", + "8ff20045aea4402bbd864e75f4099cec", + "ff6dc83c818c4e2aa722cb89e6ada577", + "8ca6a96233db47b79b2955e7f6d491e3", + "96493c107dc948969df4f184b6a2bcdd", + "0e2dd2889082479d9b323a6cddfd8018", + "3164c3ea0e3f4ae0bc2e843f101cc207", + "f00f60bfc27e4f498467f386cd559503", + "b315d5eee12642efb67b7a75c9a1de6d", + "2b2990912d404d6eb08bb2af056df3e0", + "02eb49fe9545406e83d8904605cead7a", + "ca53ad389b8148bc8541b78bc2d87b8a", + "311f271153c64bd29486689b7d6f5116", + "94aa63eb26684465825f86062d82edea", + "16f957c7a1d54858956b5ce167c71129", + "512bf164aeb647e79e2fad406d11a982", + "6cd4c51f23fe47049b78fdf1de5c8c90", + "3079f5cc61ea4acb9bdc3d304025b3e2", + "9c97e41b7e4345ecb3796500e036eae7", + "07b981b3b9584bf99236f706484fc193", + "e87d88babdaa4c0f91c558b1d38ddfc0", + "734528a2b3a3421a99f3642209c85d48", + "f880b45cde9f41cf9b4afbfe25ce9887", + "badf95951a0b4ee28e66b3e585a2957b", + "ad397ce44cc548618367d58c69e3400a", + "f8b3398b2ab44eedbfa2aa9ce3ede7f2", + "584c35f70b7c482596ffcb27c281d72b", + "70e12a92d4834dd8ba25c688a3f411ee", + "74fd2496e44a4c5fa91d5c1aa4eba64f", + "76f6eac0c5a646faa102eff8ab8835c9", + "e8af96a51d6940a2a550ed84132069e9", + "4d07a76bc1754ce0811e5d44fd4b34aa", + "6c3be6936ffb43c0b1c3aaac85fb84b5", + "cb47470aa59b423eb381b1e37376508c", + "98d0ceed536541c59b1a180730a0b2da", + "2fe1650ef89247a58fddeb07e47c43e9", + "d951719747d042d7860a7cf7901da37f", + "8375a670f04d444caafe4479295ade0f", + "d1d93eca5ec34f7483aedb9c27611152", + "ab828e3bdd4b4665a77ac8ade85f2b27", + "b1132a4198f54427a93b887260b6c146", + "4c23ef1cb8d2476cae143f3025be9857", + "8c404f3b7675490cb1655f0ac56d9b5a", + "e83c1889c59145df878f7984fd7dcaf2", + "56ba87e6d1224dbcb2408ca6c5461942", + "0a2140ad0b2845d48f2611727eafcae1", + "5430d891d903468ca91b667e08f074a1", + "febf4347e29648108d2201a116d5422f", + "8b53aa66ee3346fbad65399a58e18210", + "fa000c2d4dd84431bbdcaf22bd022a51", + "e603a0d6a62b4577b354fd699c6a57ed", + "897500582c5c4c81b01271a7f0c2e322", + "5037b5bea4bf4bd7bf53d581d478bd90", + "f0de887cde3b4c92b50fd13876a3f285", + "c40e2c6fca8648b5a608eec60a838acc", + "84d49dc0a9214b17ad48eda985f80dea", + "ba83df40e48743b7899fcf14ce6ca016", + "f8f9773bd1ac48108db724f42316b0e8", + "ed7f1cb93ec446c89b903daf247ff051", + "854f9e42e5c7421fb93a7f4a26418be5", + "0002e50309b44e409c96f440202d90b3", + "478d053a749d455b85ef3f66447db0ed", + "6e0f63f57fc844019e7a05542ee4a1d9", + "3e1be8151025462685a6fb6cc23d0381", + "e56c715f81564b1ba5455c7b914b1349", + "393fb4399f704bc49b8d82be99785ab0", + "ce11ff0bf3be446b939d4b01db9e1d43", + "c5615dbb0e454a37a664b2507215dda8", + "a1602bb5b94f4f0ebc2957893d3c679c", + "61a47d09116b49d680cb466f26e402f9", + "febe655ee6ad49f89467dfff293233f5", + "369af9883c03449caed6b3e06d4d63f7", + "5b8de4b88ab4493c8554a8ad3ae5d07e", + "1c2a9a7e360b4d2892654f3f8998ef85", + "9c7d73d35822450689fcf1b1710fa73d", + "9fd4666fd5284fb1a578365d4d775a17", + "5a79396e6c754077a011ac8fdb7fda35", + "69b44b50fb484439ab880c853ac95a3f", + "4d2901216d2d40ebb00b8b76ee057e4c", + "01ef5233779b474983a4c1f552107a45", + "add3ff3c6ece459fb0ff7e66b9fe14f8", + "8ea23673d5314509960f8967a45ea761", + "44ef2ea4b50a49e395e5e3ebbdc99f98", + "93fd538e282d4d60b973b2179ab69e5f", + "5b0f899599b94cc5b5709e72a46ae51c", + "8b160a1b0b4b4b1cae9938402483b110", + "25437ff5ae0e485bbb4d9e0c8b371888", + "5e8a5c521f1548378e17b462a1a21eab", + "e524f74147f24684835c7469c9d9a572", + "de0817a4e96142c0961c4d1561a8ea17", + "07b215740eb04ef3a6f1382f8c6f7993", + "881ed78db45d44fe9db1520249cdc956", + "1bf20d2de7f749d889d69c42207ca669", + "a3fd9d01f45a41c1a9b8532c086941c1", + "8742a216667d4c0b83bacccc71aa0fef", + "451eaec7fe4e4513a0e6da8a0cf0602f", + "544745d804a14ae6a4d22d5b57dd9847", + "d48b6ca668e84824baa31763bc8191ef", + "a938d9527eb14bdfb9efe45073fa9c18", + "a5b86c0fe54447268994e56967230f80", + "0387d3335d6140a783508862d645653d", + "0b7e3ea6c6364865a083655012fad027", + "109e0c832cba471fae6387c302eb1088", + "1006883bdd9e4fb5a7321e654d4046dd", + "3ba8c70384dd4e42b8f22750de142cb5", + "0f81453b4d6e49fea0cf56264698016c", + "742f06047a3d451e9c61951ef598c6ba", + "f3ff2952707e4659b96628225a8d8b46", + "9c35e17e69bb4cd3b5fffdad8b92c2b4", + "744adcb50c884cdd91c8242efe825a32", + "3608313dd1f64fcfa185633f34b092c0", + "164b1fdb0fc34cfb8eed21bae32a044c", + "1095a05d184b428199b791deea8b9724", + "daf4801f72ae4f9eba9c338afbbb2926", + "741eb08a5d3c4796b43ff726186acb77", + "a43064cfe3094636aae6c084bdab1a13", + "1e72165edfe14b689b2021dc4557a2ea", + "bdffb7d32a8b4922adafc025349e998f", + "72522ee353fa41f1b4c40b5b14c1e77e", + "3bb434c9d1d94912a1a7f11225d330c9", + "8e9bb79e8c204b93836b7196cb9505a8", + "4253ed4b9fc6484293ecb0be4aca26d7", + "dff411b2750c429fb761bb4bd5c64a96", + "6c24c80be5134db1968c80fa98b4e509", + "926951d8dbec408db448ffb6550418c0", + "fa8b4476c1b14c9d9aceef6979d21428", + "ea0cf00f23574b2cba0eae147106b040", + "fb93a6b2c7de40138723c7baf2e48312", + "cce68f42b316473cb92e5f18a80c38dd", + "faccc1db122443c8b9c437f3690b2f6f", + "8d2faa10a166486fb359bad4ed3088b3", + "4eb66e5c0b4f4e60b8e3e2e8e2c8b84c", + "bb15db3af44f49108442bd6af9954822", + "22d0965baf344085b8ad8f750b2052a5", + "8c2c405bc1be4326bca2e803d0f3dfd5", + "7f658554a3854ce28cae876c2a3fafd4", + "fc90c018647c4fd1a3a9f62559bf67f0", + "3e225cfd07624c45bf94efecaacf4b91", + "0a6298cc21954fd59609834bc55663c7", + "ec4630c3a8f1435dbc13576258f73f95", + "a9325cb916534c72b6441aa4fa2a83de", + "03cb72b336394c8c969f169e10238aa7", + "85d828420d6e4d6385088a149abfa368", + "3a3ecdcdc3b94cc898f8e7a2a59eff45", + "24386f34f68146feba7fd44f056c7775", + "8750b8098c6d421ca9f125e4685a0d64", + "deece4938ab341cd999e419cbd0dcac3", + "efe008d8da0a4d58a158a191d713cbc4", + "01d49e77147a4b57ba3f10eccb949803", + "db935aad8a314805b973b5f8591261ef", + "915a2a55c3644f25b62c447488b76f26", + "61c2ded1b4a2454aa4d7438fbeea8b41", + "bb2d52721c394447904afa41f70ca56c", + "c3b02c96515d4e259b467a3453950e83", + "50ca91489e6f4844904da36eb48159ea", + "c7dcdfec1bb2415fa5e54703337dc15f", + "6517ca54e1ce49c1aa774456e466003b", + "26643044210742859726b0cfa36cd11f", + "c192ebcddbee49668d891b8e14c5f18e", + "36a231c7af324000b0ea55afb6a1bb92", + "30235ebaabbf499bb692eb3b3ef0ab99", + "fb208e51d71240e2b9269e62085e3c32", + "5b18711616054a44b025d9272b745a6a", + "9b50fe39df9b4cd89fba0c4717ac267b", + "88174b10475c4e84a7ef2b989571fda8", + "ed7ef9ee74194732af7ce9cc07e4661b", + "de691d14a054487e871f89d052c06a74", + "ad3f2d78ec4848c9ac85bd9808ab304b", + "a67101d84d634e23b4b9841a17e8ebfe", + "ebf6ce97280b41119310668a66359906", + "f77c43a407244009ba49d16540a03515", + "9f01983a23be4780928b41127ffe3528", + "ee5330b48f5642dea0fb8d6dd434f183", + "502ff900e8ec4612acdde695650dd3cc", + "ce6c82f1f7cf4b04af854f8f53c55c2d", + "3910e3cb04b04858a5e3df19b74c6d90", + "ed00cf5ea92741eab1d9ce1371681618", + "be18a2edd8c94f39b8a233f7d16f43ef", + "7b623365419e40dabe722b5fad0697a5", + "e7335fffcc0e48029be5679da26f1b32", + "71c78c5251004ddcb8c3269de719fa06", + "8e0203f796214cc08ad504139bbe8715", + "457cf1ce9c254830b59fc113371e5820", + "22cb55562c844320bab043ce64e8ab1c", + "f65611997883426bb7c56336b8fd4c36", + "e0aff657175a47ccb6f143ea60b4a48f", + "5916a75d1db34ba19f506ed89ad18ce0", + "73884e277e004c99ae4d5711e7969558", + "147ded687248466aadc5d0ced0f06367", + "98a4a52a6b84431f819fb8beb26be79a", + "61a06fc8e6974484bb9f0b3bbbef92d0", + "b98a30007e3a4871a0486bc83e9cca76", + "bb2ae65b9c3a45468cb63e3c4b3c324b", + "4caaeb95fc694b81b7dc264dbfc668ae", + "cfe0ad26828a42cebf49aea928ea8a15", + "10dfe487e2da4fee9b37f4ad23d4e87e", + "b4961cb10c6b4485b366868f379b035d", + "6d611e4dc5134b36a2249258e77e46ce", + "1c41d7d358804a8085ad167d44a34e48", + "794c039978bd4703aa6fc1bc7c0cdc8f", + "596c1e4851a240dba38b6291aa978e70", + "09577224c1ea4fadb86beb282daaf1b9", + "8275d4f8cf2a4ab3b9e3b59724c9f0d9", + "6d7e6e9e42ce46ef8e2361bc419d211d", + "cd2ec82cb798412eab45aea255c6ea07", + "e3c9238c87bf427a8343f685d0483347", + "3442fd87d62b483ba7574bd3de060a22", + "0592fecb8a124d598befd935159bd561", + "585e3a518b434183a4c1f799d9f0038e", + "0734bbd46adf4c188ef4953e8d71236c", + "21b8fbffd30441729228c177e1e9c492", + "7f2489e1e0a945be9b774761a1b745c9", + "8e9067927ee543819d974f1d533b3525", + "573801ef1f514db187fd15e13a42fc1d", + "9a6e0fd974e74bc588a9fdc86598d7d0", + "26f8f79fc5d14e31aa0e9cbe3303404d", + "0fcc3e9e55174ca4896f955ea3806fc2", + "6b92338caaa84b8da3311e1043b55880", + "35c2b77568af4caea603679ba85f4c7c", + "6df15d938f184b87af96fbf7a793248e", + "4dd9287bc37742518d7443f310287039", + "6fd57f807cae479098c5a116c2e0b0f0", + "96253bf8392c4a4f9e84c851e2ba137b", + "169f8fb7dcb845b09b8258ee0b6d6dc2", + "2fb05d3ad58245478a1152e998a5fba3", + "10899474b9bc44c2be069e84d083becc", + "b5adbee51ef1445893374ed09ff3e118", + "d5d43ebf8f944b2ca0d6534714e2bc0c", + "c9a0eb8e65ba44bc91e49972809a9e16", + "7fed88b9da584b1a95c8cc1bb176c169", + "6e9adfb45e3248f6ba3a9ad735b2caab", + "851a56298c9641998189c0d6cc1d2dca", + "898366645e6046838828d8637d6fa3c9", + "f4783633129a433abf0d2b313db86f43", + "473d0ab58a594ff7aa7729ae1b816fcb", + "fa23d26cd7a3447ba8b21c2667ab8a1c", + "5a51989fc09a42e38a5f3bccbb456609", + "ccd47f9847b245449d8e03c532670a80", + "09242ebb27164edca7c84991bcb16ae0", + "47915a64e6ea4de6bd5a747e27b0af32", + "6ef2e4a19ece4c568698e298c925bd3c", + "27ef8b1c9240430e9fa851094a134ee5", + "1e81186f57414f47a22b726cfce011e7", + "f235e5b7a96b46489db4dce642742049", + "71e02a21a6c34996a3def1726d29ca1c", + "6a047f8f55214a5dafeed82a697314e7", + "afd8ddf280f14461945a18c4ab236859", + "ef7eb9989b124364ab06c390e9948421", + "fec0a961dcf2456c939c2379f4683f21", + "27234b8a603d412c903b156c632b4f5e", + "bb8ea04fb536463eb6b03a93a17a7689", + "7a94425ceb6d488a91c835885843b77a", + "10c064702a7843ec898c85e51a9a50c5", + "3498937d1d2e483b90a5d306d20b631d", + "522de1d948004544b07cd36a078f49a6", + "73ad279aa1744086a90399c9e9f4d643", + "3c2b6a45655a4ef4b692c5b131298ae2", + "d558e635c8c148c588d5afa7ae914b3b", + "6f74762c2a864e75bcba510e21d9ba05", + "0ecc98014d684f548032eed7e89079b0", + "7e04a30c91bd4affa9c1420ddfe04008", + "cbc2c2d8c1fa4c9196a8cc09e876e26e", + "f39783d05dec49e49482c407d656e0f7", + "12e6d0ea1da049afaf3fee3c517ed64d", + "da7886cbd431414496b42399dcb04956", + "5c4a8c42277649d796448b52027a83cc", + "340090a0c11b451c835c26c4c050abfc", + "baded4f3a22e4d6e9472e925e6f1fc12", + "6826d90c0cff487ebff7282b1adc691e", + "0c9435f33688497dad9808e29fa8d199", + "f7bbf62689cd4fb4a49e3e5bd91ff7cb", + "fa0aa5bc2d1b4c1d9ed6de2f0a645a5b", + "831e07135cd14d938f367786335786c7", + "c489e9abec2447c2a5273a2ba62b6ceb", + "d4502c7e72c44fa2be1257ef7b78cd58", + "1177e55fd250431c8a19dd403366c0ae", + "4ae3e3780d0242b394fcd1a610fb5d58", + "8dd45092d0d34a398d1c0d8b1591a0f2", + "fac8c850cf5d483699d4f4047059115a", + "a5659b7cc9524e51ae7d0e41c4d00392", + "87af0524c71b48179c1cab34cf0350be", + "fc9cbf532b6045969b9f7eeac339afd2", + "f017c73a85484b6da3a66ec1cda70c71", + "5cd3ea8eb94c4f5597cc086b2df40e58", + "937b33e8c2914b788909607fecc334dc", + "1d74e6c3d0a1417fa0b45ee8baf032ae", + "5449d541f2954577a6f3e983fb2d00a5", + "424030e72ce0411ab511e35ee1e52371", + "db4de4db4ba14c839e9a69b2cf846f6e", + "b39b032769ee4bdfbf42c137d5783806", + "accf85a9369e43faa28ad10e039bdc44", + "1befcdce295742d08e2f64b6c19b14a2", + "1e97c897151946f58f1ae24dbffdfa95", + "778d0334ca7d4b2f987b7cb12e71c071", + "2c086bb5b39a4e7688f363334143f3c2", + "22d789c645db4f0b908b66e31240638e", + "41a3ce0e1b0d4645a81c5cc5bcc2a636", + "baa90088dfb8429b9bbe7ed8f6746714", + "5ec82b191b4d44b299cb1fcea0308296", + "989ea7f01b924859b3484ee27103e8d9", + "e403051d77f84c1ab359caa0866106b7", + "d677ab175af14499a17240c41139bfab", + "d35bbe2d662b4e21b00b6281ba7b579e", + "d6814ce433f64d0da49f4a8b1ca3bb00", + "4688b6a39b6f4c99a88080a004cbdf77", + "54e8a5489f3d408986a319d58f172aac", + "5bea2028c71c403186f495e35cd9b874", + "55aea8e66dbc40e9917fd92addcfaef1", + "9ac4e834028241cf825421ff77056e1c", + "37ebdfda9ba24ba8bb1e8ef2f188d7a7", + "9cbb4db4f5374e8daf3010ed613a8d04", + "5658ff8e398240dbb4548059abd10773", + "d9aba8a915bf465e982d6f9092ede32a", + "1b966be9e3fc424cb4bb7155549d3f22", + "c5ac7eab218a4b50a5ffcbbf09d34363", + "7bb4fc1414f245c3ab37f63e68593c5e", + "f351b2fd72334da8b4900277ee0d4c45", + "cf0ad35c672b4ff9a98c8627ea6bb55c", + "7d441f3977b1432f97b6ba2846bddb1a", + "5b9dbe6b48a745bc96a3673108a314fd", + "b081286782c944f7a3bb3d8b93a7daf8", + "d14007b844e14d2f957f1d92f47253f7", + "922991aad4894438a1075299ab317928", + "a730a2ffe76448d5a39d71ea5d5d5d3e", + "9ceb14ec1e884abda7e30bcb09bca106", + "1883273bf37f48218e7f5c1d8f6609ea", + "6c2a6d08791b4858b14ed29c09e69533", + "09f0f9801f354224a9c05b993a78ca0b", + "90085243d2c342b49702e804d5a52767", + "70ff658259bf4e4eaf0023a01497afdb", + "77161168dfb342e59a36436cd4953442", + "c53229548417418793b85a176ddf1bb9", + "aeb46a14b5e44f63a879e8733b4f0dc4", + "fae08c03cc75437c811f50426a81ac30", + "5beec398511945678132661bdabccd17", + "f2f774b44930485b9506e1438b41e390", + "70020436290f46e8932574d34210c212", + "d2f132d527ce445dbd07b335e0aa020a", + "7ffefa7b78fc46b384f9f911c75cf39c", + "ce47daaa1af84cd8b99b11d77e78905f", + "dcbfa579c19b4908857b92428922c1ab", + "2dd435d6b4a14517a387ffcad084a4e6", + "395fe8bb564142bda88b841f2aceac97", + "fa17a4e948ac4d4ba1ffec8fa6978615", + "633a551c679b400ab258ed37dda0f1f0", + "a0622f109c144a299bca74234895826d", + "c2f9667d6d7640f8b2d35f7d1ee75d4b", + "b55bc56825c8469abb8220b23cb7c8f0", + "11d5f3da2f004f15a32f18c0fc220ef3", + "3d4d80927c804175bbff838c7de4c7da", + "9dc073990b874cef82a5edfeb168a3cd", + "84a7e6af6d6b4f1ca5f81cfd0059be6b", + "6364b9c475a64195bf12b794f0be4912", + "b4a1be634f81494a8771249eeab4a218", + "5f06884e82394845bb1a4706a7ef548e", + "85229c525ded401ca3a1456e1f238758", + "de1f1f8e6f774b47b8d3e3dc7c1a1af3", + "cef2944921d84deda3570f39749bb73e", + "5971be37036848c6aa745ee41f4802bb", + "8fb01cf82ed9434db309e29af2de8bdb", + "6734e6f2fc6e4f80a887e6cfc9c92cc4", + "23d78cba6db24808801cc9e8d280a73e", + "32a6534055564cfb8e2609e4ad6dd856", + "beb3d37de8cc4e47aba8b5c2df6a5b6d", + "94aa850d29c54f0d8e8dc9947f4b37fd", + "39059edc24d547f393c91856606e25da", + "9ec5bdd5993f4cec9a99aaa8dccb5ed7", + "851309d1c6c34c5ea0e453b218b9b54a", + "1355323d390f4daa8f5f966aa178037c", + "95c4008c4c764c078f679d4c320e7b18", + "6fbed6b70a5a438d95a9ddb68a252b31", + "df587fc2bb7a4c8587604583412c131a", + "5b8d5bb5ecdd4d8a80f71eabd4d08249", + "b9141491f0cc4d0294b767d228b0f7df", + "1e2e309b7899475282f633fd800cf462", + "08534edf650d48c68fc19bbc5ce4157a", + "62082b40500740e1bf14449b5f004f79", + "dfbb3e7a1c664f198b7bb1cbd77f756f", + "6b971a7d4d8645b0b2eff23d96909182", + "50b7cf68173541c1a16b0dfaf39911af", + "c981106da536417bbf2248a80cd2e9c6", + "e13114924120441d862fc221ac8a4c03", + "5680a17f941743f3a56fabfbd8dea3c7", + "c994f981028e4c4187d666e7c2620e4a", + "ed981ae17d684d06a13f3f3b9ef0cffe", + "ad281b77c1164fa0b9bda84e6de9bf5a", + "fcd3032a73014ffdbbfe098f7f131a8d", + "eaea69d39c2e4c7fb5ec047c72753428", + "d7d02a4337b64bdb954a72be442f43d5", + "16d799890d6c499a8762677449b9e179", + "c55e69e870624639bb21edcea867bb47", + "cc054b30647b485f88675142295080fb", + "fc0de03866ae4bce9e213087295626d0", + "c6a90117cc6c4568b21d77a36a9295bf", + "c1a25a085a4b49cf85e9dae653d6d9f1", + "8303a2bbc0d146f792c623c25638a8b3", + "9c2e859d7a8146dcadf9014c3885fa9c", + "20ab5a367f20474bba8140d4cc706acf", + "7c51d385917147168fa3d2bba2563a4b", + "145e4798bb7a47fe892cb1f11187fcc2", + "006373e3885b472cb5538fc570235fcf", + "3a39f00e440148efb8b8d08730758ab1", + "e7f6ffc0546d47d0862fa3afa1ba1004", + "9baa161056964895aa72011fc528c406", + "d2e482a4aa374bc0b55c7e7849c8c852", + "e42ed3a0ae184045b12a9cd75e15b73c", + "576e6bcadb764bb5ad91bf48d93a95a5", + "52a2e5bff5c4441382b17fa0ffd4831e", + "3824ff09fc63472d99a3f8b78061bb58", + "0466ac2193a84f37ba6de5fea6186df8", + "913b9945ea964caf965795fce08368d1", + "8ea717f32b474682b747fd397b34a271", + "15d280f41a034434bf01d6955ff093a7", + "f078ec4957764c5daa43cc0105aaf064", + "5957f2ed2fc74cf28b9aa8dd5f3fddcb", + "ca82c5aca3704bd5a8a81296b9c34ad6", + "24f3f2176281407ea551a53aef18948e", + "a6c0f1a26f70409c861a1f6d0121cf2e", + "e408136e84414784a142e40eb876bbed", + "beced54230a146f6a83012d2dbc4f490", + "6b85cbe851c74f26b336334abd03adc2", + "0de9660d90a24839939b1461f840eb36", + "7ff9af367e2c4d26be44e6123f589fa5", + "c6dfb019a1d44157963eca4ef5e5e06b", + "0aff86d35a8b4abaae3d2f5cde03c314", + "b8a85ace01444026a6218358fb590177", + "ca7489f425c14cfa810efdf7d6b9cf4f", + "1c9866a995084b7ba237b8bcd36f68a2", + "c56c2dbec5fe46c198d5dce35f796ad2", + "9c349c2ac75645dd98fef36e0487c646", + "f7bc7869b58946699ca324cf2987df82", + "df9c3cfa98bb40598cfa7b96027db2a5", + "31eea862e4d74b35a5c20ae16c403c80", + "aef570243a09466e818dd97d27cbd9dc", + "59b71b9ae89340a38d7b1a423765ba0f", + "73237e73f8c34eaab22194b4c594df34", + "e2ffff89ace144509f689a1b20b8f35b", + "c37f571bc43a4614ac702d9f3c774b37", + "ee0e2b6eaef242d0b3d088dfca4759b8", + "2d5a9e8a5954436cae975569fed0368d", + "e29548d790ee48c5aa3eb0bec9be0f7b", + "b09bd813f93c41218d97691f31beaefe", + "b1fb5b82ab694a8e8316693fa9fb37c4", + "675337be39c449c89fa46fbc6e34e54f", + "b5a17878c0594da989c3f02101db7340", + "f3cf6f7443af4ef28799a1780606a976", + "02931523be024174a9ad7fa209c4c258", + "8dd9a0b3faa84aaa813431b44c716a6d", + "944b6c4785f8473e847f156338ecb804", + "b460ed9f13424f51a76a45f0b025e3a7", + "5e8f3d6175d24aab97266f0cad5f1b7f", + "2d89f86c5af845abacec24b6203c873a", + "e735f59247ec4aa580c0893369d17abd", + "1b3c4bcf091840b986c88c2a1740739a", + "f6faaf8983324fc992f58616ac84b68f", + "01dd0246b0344c7cb1a28820e8e31114", + "c633aa1023ce42daa7380711dab53349", + "bee98906fe6c44c68b7eb0cfcbae8949", + "7233f32afb9c4297bb8df91734ba410a", + "9f6a9d1843804633886dd850d281678a", + "b0a2d8c6424342b1bde523da5c9b50af", + "4556005c389d496a929e47f008283c3a", + "4c7f4bf2735f4ac3a328288c1b275b78", + "0015413ed8b74ee78d3b45c73148f647", + "febf6f67ccff4bcab7fa98bc3f47c172", + "efbf3e1bbbc34145b5f0abb6598b0185", + "84a87c5e5a9c45b4882e841885d445c0", + "e67f5d257163448cbb8a5ec78b38aff4", + "4ef149aa061c48dbaf7d4507214d4134", + "4a678fdfa1fe49739fd5497ad4253dd9", + "9595ccfac3314ee8abecd025ec29bb3e", + "739f1a6be838419993fbc79f79dda2ff", + "99a3a792278e423cb573036adf91cbba", + "e46fab2176ba4fe0bca2a105412dec24", + "451daef26695425ab1b751f503f182e6", + "4618c8cf89f44a59bef54abef745ea33", + "55a2c35cc2f7467ca36847945d04ce9b", + "115670d120b7496f983fb7579ce14dcc", + "84e8fe47ea02466aa7276a79ee27e6e0", + "e549600391eb46b1aad1099fd39cffdc", + "2f668a4195e74c81b9d8e0ccd48838aa", + "f3f9c9afab474d34ac9f0b2d57f41d93", + "dfb91696499d44499eb3a9863ebdfb37", + "bf473f9268004f6e929ef3f4bf258126", + "cb7538738c27449e94aa65bd70838884", + "5b770fed90954aefa5ba303ca77019f7", + "673e146e6f1c44ffba87696823623dae", + "df7ea68fd0454418850a3bdc80109615", + "a02bece11676428eb2f4bdb4d241b120", + "42421123cb7945668c8af752e3dfa8ce", + "68f0ae7a7d7844779383d332319a7352", + "03af8be8df5946229b9bc30b6dcb2c54", + "ae1249168e9343f5badcb102faf3800c", + "c0ae7e7dc85d47cab2cb8c12d10280c1", + "c62dd108af924ef3a1d611cf4c1704a1", + "bfe7d70e5cf14e3e95f4081be4c0e658", + "c6cef5b8f3a741e4a619e3441bee54d5", + "a7558507c75f46b0ba06982015792e62", + "c6cfc7e68cf14dfe8f5ac3bf7ed47fec", + "445ef1374660421a845b8fa5399f8780", + "28b11e6934c24f998637ebbdc02eb769", + "600da5e64c2948ee8cb8bebfd6444b5d", + "b5ee83754ffc4f9a9204f3c72610cd60", + "e14f7a696ad94a7a89ef421a1bc753cb", + "15621a3fc76c4c78aa27ba48c7fc4fb7", + "cfdca048680a4d799f42cacacc8517d8", + "7699acde27aa4b1f87f844d8465baf93", + "04d9964b9fb04da7b77f05ad997efe1a", + "cb8d85ba8b2545e6863fbd5463eec5ce", + "518e3003739d42dda3b20b2a87b59d4f", + "b6747a9de29a4dce8f34bb5efa7ab8e1", + "197dd882a69846e0825e80566996cbba", + "a06f14c1445f4bf592db12de9ffe63b0", + "500608fe956c45b1855b3a839639791f", + "05df6cd05aa6426a8d6240013905e9f8", + "f3a39c3ff4dd47abb9a04cf1ccf3e823", + "c7cb694adeea44b2accb97946fb5d5e7", + "e50b50ef53c54997b432446796d67791", + "6c13dd979b074b9facd5ea6648597a59", + "645c8afba91842ee85786a76e1c78033", + "e54cb84dc88144f1ba40c69c4cc6a5a8", + "a94d6230cf1840609de7019ccf6209fc", + "e2b0bc9174b3467da5ffaeddc44fca8f", + "4038cf88cd384c6f98ecfe670147fc5c", + "eb0760b4aa704901a6a4b487bf182147", + "5d769db79e314af0b2e58f67739f1483", + "5e10835be817425ead47ceb993cd8d75", + "998d641ce1c74e44978a91fedc849905", + "ef845cb048e4499ab2f2845d20cb10d0", + "2010d22da4fd4b02aea43354a4497a8e", + "a8c0797a4a07498a9eadaead25e5e3e8", + "072a84f8761e491e8803bcb2bfdf808e", + "aa9ee13ff6b4452bbc5bf6b4f7d45cd8", + "0b3325fad3e740b1ac86173c90b56afd", + "43512d163d6a485d90fddff8013415e8", + "68a9c0d117304892b12c1ea3fd63bef2", + "721c70b175674aad93d742ff8812b512", + "18326cd8315c4712ab5d880efe79b44d", + "c5f0d914545c4848982de765e6bf12cc", + "e0fed5c2a4494911b91105d8f9b8d477", + "6d1afb8bee79475795b4c70f7630e6ca", + "cfc503ced33948e1b494b52978ce3c4c", + "b573b1c4cf5d42778e701c981de426bc", + "29a5c09102044542aa48a44e2391951d", + "1c78af4bd9784c70bdc920843ff54892", + "20890d9c8fb746f88141585026977110", + "b3f86ea0972c4358a764225be1ef069f", + "bbcb084ac7dd46e9aa20acad273138fc", + "a36f26f49e8842c7b14ff8538398c205", + "dc4a1ef856b24492a2290f45c8156d4e", + "5303a5dc9b604dfa8131ab68aa5c0a3b", + "432240caa4304eaead0ac04d570c3c90", + "7c2ea854a61d4c7289e36649bb4f413c", + "857b2346837f4e4790cabbab2e76df1a", + "72e0e0b03dec42dbbb67ae0d5b9ff0b0", + "1fe98aa872364fd5ae3e8019695783db", + "8ffcac418d5a4cfaac40e477dd874e01", + "c447f77307a643649c6b19bad3be83de", + "d634252e1a254057ad8861b6e7786f1f", + "db00bc4985f4432f98d12d39c03ee009", + "c4209af8104e43c1b59c6c499492b2bd", + "9c4935439367490b8039a3cad9c46243", + "1f8dd1f5353942a190bc4654336a0ac2", + "6eded741814747329d1333ffa3222f99", + "6e59f642337c4f29bde09a601d14b146", + "077430ae3fcc430184f66a64f447213b", + "ebdfc87b2e104e51af6a7bc018a21d6b", + "cf373495a56049f6be1692ca6463aa2a", + "119914f66bcb4c22bfdd7cbd7b569550", + "0659bfdc168e48b8b33b541a33a7ee15", + "48ba5a6d926b490c99ff5cd6b6a02530", + "374f7f4d5f8c4e5ab2a6d13c4dd0c320", + "d9a1361bb7324e678ca21169533093d1", + "2975184cb1284d51b40724cddd0261ab", + "c28b2bea77df496698a373358dbb9bca", + "e9be94f83a3c47fbb50ba47aadd3b3d6", + "fd926f8c3cfd401d869d7a6d5d62dcd8", + "4269b97a679f40da91da28a69a7c9f45", + "41b460fb56df49b88dee6d20da01ce99", + "d9d785d3fc3a4e71a4a7ddf5e4968194", + "549a9ce85b464ff8b22f8f70c533943f", + "4458c3eefdfa4235bb7e915b944ecae7", + "15234873d5a4498d8a490647a10aded3", + "9ac7a6979f354ecbb37805b35e6f5432", + "5ebd04ad8a9647e999c04ae92dd2fe13", + "36b3656d60d44061926820c4ffdbbaf5", + "a687a8e68902424cb7655a1a3b4e16c3", + "c7ec86e7feb746489b30b4a01c2510af", + "344f5845929c4f0e92d10c3a97249bd2", + "5b4d477f40044ef5a95d0e3288518a2d", + "8f72114637a14f42bf8d6dbe8ff23368", + "2003b568becf4b1dbf14925a1904df56", + "47ad9126238545e99eb4fba96c46ff2e", + "2b3a049aa36a4849ad77d0d2f633590c", + "39ffc3fc2fa54d28a5de026cb5a73b3d", + "28a769dffab9481b84740f4adcf124fd", + "6284bbcc12564c5f85d9677ee80d49f5", + "898f2a90a22d47b08d974f3ab2310e63", + "4fd6943807374eadbe1f066f22c9c7aa", + "c94d567e301d46d3a4945f78cc647d53", + "458e54a470fb49aa8cc1887e50aefe6b", + "e420b7852d8e4dc8a3da1d27622b62ee", + "9bca231b88304dba8f5115a8cbc84cc2", + "864d6e11d4fc4c809cd7e89971230191", + "5816ecb4bbd642308e9926b6a1b51a95", + "1923aeaecf0b45e6ae808c72fb7c93a4", + "be00015328c04abda562357263ab4bcc", + "439169f29fba44d197986101f4ea6398", + "143f4fb470054e348d01faadfd2ae41d", + "cfc0f9718e254ea1969a26679948e1f4", + "ea769d7a3ada49048454cd0a58fa4c52", + "56bc325c399e4a67a71bdba6b48348f2", + "0a05b735bd904101b7d0bf62fed5894b", + "5d2692dfcb154cf6b62f558ef5b2a829", + "ea66c997677a49cfb4d880a64f6819b7", + "a05c4e6659b344bab94ee94703cb2462", + "1df6f3e239ad46d191b6d51e04fde3b8", + "bd769a8792b9477a9de7b4cfb2d96c0e", + "694a8e5ca80c4d6abeb10150c69e7476", + "7680833bb1af4628bb4716fe0e0878f9", + "95929ecb75bf4d42bead6d0989bf3dc1", + "ddeba12c5ed0473b8f99b8202b2ef714", + "5f64439a1f3f4ca28bb95ce24b8b2b8b", + "e3f795277d5f4e0c865bd540dcb616cf", + "d3f279329c034ad49288dee94b03fce9", + "57ab23e35b784a1db07f2e20ebd65dfa", + "e22390f629bc45839416cddb7d56d00b", + "b6d02e01fb8f49d6b9486db48b50a9e1", + "cbf26a0df9c14729bcc82017675a43e3", + "b2a917737eab4866a8fda30fded72d1c", + "a6183fce20744af5965e89ba2bb21891", + "68ee82fd97bf45eeadbeeaa556fa669b", + "e4f4fbf706a54b00af0382f0deab492a", + "c4f593c774c2464ba9ce7c3a3a2c824c", + "7d444cd245694f9a8da42e6c8bf7d72d", + "f22562f0e0ff43618941d02542123196", + "5da6277aa5b841a09614d98f521c1d96", + "332f01ea98564ac083369bd6ef0934b8", + "e6d865691b644b3b93114a0267257f4f", + "342ae0be6b324616915e7bf2d4cc06dc", + "c94d08a3c24349bbbbd7213532cd05ee", + "8a168b107c7b49e796b8c1be0487ae4f", + "43dfa2813779487b9d1bb36b7c1a321c", + "39894611110c4c5db4f989510a6e494e", + "f590daf988f14981be7134ef2ea4ef84", + "f9d7150137f8404c970b98849c85ebfa", + "b3aaedbb44ee4776ae7ea8f2266867db", + "90ea2a7c23d94c4abda00c08469cf8a4", + "c9229ff7afba4bfb94fd1e9ee126d3d8", + "e1a4187f2ac24ae384a244c0b8370170", + "6fe6ba6fce554713bdf4291c184a2320", + "b30c6f978e2444b2bfd67cb621250a58", + "78680fe2ef8b441c9d257b00af90c986", + "3fcf56927ec44ff886f67a17be2538f2", + "7cfe8cabb7f94e7db4459dfba38122f4", + "a9e7ff47a1c442c9bd97b8fe8bfc8e12", + "f3e6f744d88743039b101b4305661665", + "9c36c8e2d75b4f0bbaa884fefa0cb5ff", + "ab981db0eb63466ab4246f0bdfbb33db", + "32abc12d4fe44bd0b116b294194d9615", + "a2e4d83e8c694524b79a3c76a5696cf9", + "73aee2e1cd8d472491c0b616398773ba", + "00e9e6b9dbc34dc1ae691529688ab000", + "adce1c32d04c4c1cb1936e0eb9eb200b", + "558a28477bca4d7599f82e5621e41daf", + "cf26e1f9a7724b7ea449d27921f25cb5", + "d11039526b3943e6853234295571057b", + "e632fe253a7a48468d1acba1156dc225", + "f281677eb6114d539c8eab72febfc5b2", + "a3ad6dbbcef04d4b92953695a2aec219", + "de2e40e2e05d4146b37154d821772c9a", + "1b256f6ce7924f59a756fe8f7ba69416", + "13dc5e2aad2e4d00af57e8d99d7095e9", + "c93acd5558564d4ab2c2c8b5a3cbc73e", + "20cf3d57187d4f8fadb45a5e808eed48", + "9a4d1c954ed446d9a8d436d5be6dedca", + "8a5a4cbeca614457a2d839a62ec7403c", + "4c7848d660cf49d69322f63636a71883", + "6251afafae2349e08204ea203aa4bed6", + "f73e2e1c8ad241ff859aca7e032ec262", + "14cba64dffd3499d902de9e9b6c67107", + "20ae12a084ac4310ba2be1b067e66d75", + "fa28b1e74a5a41a0a96e91b6829e8114", + "def627b01b0e47feb4aefb55e0479c24", + "0056fa33ff5941c295e30dbc70be20f5", + "ba89d9fed0dc4677b870501948ab7332", + "40024be7853c4a0981309c30f1b3369e", + "9ac3804f84b84c8db8cbf39cef76faf6", + "75b13759a6e84978b41cb52073031326", + "a495d7f4d76542cf8cdb176e0da0f282", + "6f3f880ed56743f9984189a79720daf4", + "2b8b51acc3964cf4baee36aae0989550", + "67c5cbdfb91e432a9b3eacdbfe854b12", + "31979209a7c54cf3ad570a4a0090324d", + "e49e3b59481749eabea1d4063df8e489", + "f98f6da7e1a240e5b1a3d321253b3754", + "a853c65116e5453cb59cb00eab0dc878", + "9ca3efaa91cb4082b3d89907a536a3ab", + "3ae0b4e6a75a41d38a2adf8db048a703", + "eb5fd505420248d7901da8fa13cdfc42", + "535871f434f2411c9e8e939cfe88bee9", + "cf41fd31d472487e90d34dcfce966b4c", + "7cc3385a12304eb29a5c98380a01518f", + "78c54c463c1e406abcfd228c5a234d5e", + "a334cb10ddaa445d82c3cb5026f33c35", + "5bef6c9eb44c4824b3644e911659d889", + "e8f94dc4787b499ab9c4974b7a447415", + "3244a24ab56148e19a3c55d17e5c1d71", + "eefce9c88a3a43278a3b983e5b82d2fd", + "f0c69092cc4d4f1d9c88738258dcbf3e", + "991a4c60e7d54d74bfedc2d489bd71f0", + "7d86e3e5919e4468b93d116cad8b97fc", + "5abfc42baad4474cb8676b5cb709abdb", + "f189445fe1f54c069e27f82060f8b9d7", + "1e42560adc8c4da381210540831ef8e3", + "15d02240aa9648cfbc27b64330313f8b", + "9503ef5a564b494ea581ebed0ff65dc5", + "9c4af2420c2e48f58887e296180d88f7", + "88448fe608f0435c83e3c6a5cae76186", + "ad97ddacd915422e8aead0e64b9ff465", + "0149261afb9040a18d99c348e2e13d62", + "1e524fe8e0e546d69baff4d6e20e7533", + "ef97ad96268144de99f87132272cc0ce", + "3664f42ab5d346bca1a7fb7c7ebad895", + "3cd01b9f9ced4e509e3180378b666e22", + "071e439aee854058946e537949bf665e", + "3a02912e5b974e7589fd5adb0f46347e", + "15b2fdcb50b046b9b6d4def1835f346a", + "7d315a4a870c4be0b1981efb0b95a3dd", + "230929231f8e44db920c9be0bc55456c", + "53a2ee58f5784a2181778d499afa8e03", + "39356a1d32c2407eb7c2961ad1c5fedf", + "df4e58f178754b2d8a2a1a08be320eab", + "05046cb405cb40f99bdeb7108d8f69ba", + "0120ebb40850427ca7e409ef2ad26ec7", + "b423150f22584bcfaf4ad681295f5663", + "bbaaa148488d473597e80ea99f80c912", + "191d841203624bc5a249460cd2679bd5", + "f03f8dee943042d388c32fd720886b71", + "018b358c037f43489f1f2354685f6764", + "84777cfc806f40fcaa567c90b0ae8585", + "301fdddb9cd9420faa1174e68e0b56ab", + "4598f33325fb4e2b8e8b0744b75c8ac4", + "9e5cb26dab254050aa371f12ec63e566", + "f30ba7d7a43b436587f8d9c57e1656c5", + "4dc0a2b51c224f8c8591cf9f27767861", + "79a3902f37f2482c97520f3f19e419ab", + "a943dbc320c44a03a5ed683af0887569", + "296a53dcaca64681819a43b8a7ff7db9", + "9368b7c2929842ddb0e77df592bfb960", + "a148270bcf8e4847af08fc6d8450db03", + "cf514c6edd184ebc9db92bf39515e3ac", + "974100f394a44e25be5f3a67528c012a", + "f3b26b1a2de44a19926c7b829baf0d2d", + "17870ffdfe024c36b2247716af656f05", + "9166cdc0275e4310a1ea40a5afe95b5d", + "8a8187cd39d5430ebac15c68f334b399", + "9fbd8acf27914256bc2e673352b0e07b", + "f97e542ef1cf4907b128e80a99a900fb", + "0e9a611b6cb9431cb952ff2b7b2d7a51", + "7baca234c192439abfff15e747d77d11", + "921ea963c74c4d71880d49a37eac19bc", + "7e55b0c0ef04494a8812d201fa317279", + "549d314896eb4009b1c5b631eb1c1c14", + "8d1656825c724d11b596eadbc75f5a21", + "df627630a1644645baedb331b97ee584", + "1c357aa755ec4469b23e86f1b0c6aee5", + "6f0e8b216aa24776a8ea7a859afa980c", + "4157d1fda49441e58f8cff094297508d", + "354bbe1a96a046cf9412046156973803", + "99081d46e2614b0f851318eb06d21d25", + "6a230582e9144b72bdb3559926d57e86", + "dab2073ee4084e5f8c5f8bfc53831b74", + "a37f550f259940a7ac6d6999ef47754a", + "61699f9b3187407eb33ee5035be19489", + "6da2baf841e24d17a2cbbd08540aafe0", + "bbd515ec9e5149dca308028b4ae1f8b7", + "b6f302376a174891a0ff8b91f12ac37e", + "460d3e2a21ca49939da8a0c5e4b5c459", + "aa20f44ed2344505951b89ab8ff59328", + "19003077f2f44480963234a32ab30c24", + "dca69f083d6849e5beef3526a2f9953a", + "8406bf230b7440c38b6a5c4642cbda93", + "eecc7216ab704bdf9c7fb1ef33c23889", + "8af19fab703c458cb7e14eb5de74e858", + "d79fa51a9ce54f449212199fd37199a5", + "82a2b787c3a646478dd182b490dd3053", + "f3be35040fe94782bf5e3c0a88d34d5e", + "b4fb782ec7134b9ea52c1d1ce11e60d3", + "b0ff1559539d4a4f88e325b00eb581f5", + "08d3d7cc1bbc4835973e54ced42902ca", + "fb015ac74edf4ed4bd51a1e3a62fa475", + "6c40a15db4594a3296995776c71c175c", + "725273fbdde54a1babaf6ce1c95b96b4", + "4d9627d6370f45a5aa186263858a6a55", + "34a3ad1f5a1947c5a07cee4b252efb00", + "3188e466f8f44fff81264ff64ceaff82", + "925ec5acd9204040801f69a85f4ab315", + "75464dc7d29d43e78a3ff6142ed911e1", + "58426b30f2d14588b4464d5e860b40bf", + "b2d48d706ad84747899134684f66bf06", + "09188811da08451e8cb37d3eaecc7351", + "80c4b769405446b2b07e1ff6ba07289a", + "3da866e97fde4f9b90a5651f84b6bff9", + "3fa6a662e24b4aea8dcc21015687b721", + "8dd98fa186144792bb9c9cf91a66e8c9", + "e77aeb66adc34c8495b6a8692055b6c4", + "c8b7761685094d2591c05cec07a4adc5", + "b58efaedc77b428380eccede1505f81b", + "8b64ae5088bd4f7cb806927262403809", + "b0194336985e492fbd10db0f78ba2ddd", + "12f1f70b679640ce8ce8295100f5e3f0", + "7bdbfbab23f24e048b2ddd8e9d33438b", + "bfcd1f32b812414bab95d3e54284ba53", + "fe5d9844332447b08e83070e2c691957", + "b6efaa71d12d4c7bb16b90a78de27daa", + "79d352623fcf4f3aa39ffae715e6b4a8", + "e82e5ff7ae9b49d9b8ff09e7067b1ada", + "699345e2e6af4dbdbb21b333ea9c999f", + "26ca8d4db5f24a2d8bc4f567085bd5ab", + "769829932659490c936ab574af87c523", + "eae4c90cff974dbea1b0d5c613d1a0a4", + "9a13e1cfa6cd4ecb855dbea11877a52b", + "6c38dea39f974b1ead50a76568a8f32d", + "1e9bd398e5a149a9860920afdfc0d156", + "5c2d19a1e632495885d12b377d693eab", + "eed0588360284db1bcd4af720c258c10", + "9544dc9d7f064c1c993f2cf17e858334", + "e1ad319270e84c1b95003d3edec4893e", + "7914020e993b48ea8385579ee35b111c", + "9c5242814c8d4e689d000273cb807d73", + "4c85a7dcd4c4446dbb8d03a8bd311bac", + "a287e2b85d8d4d0b852cc033072923fc", + "36e9611b1e094b09bf20719f95669973", + "7cef86bade2b447d841c333bcab9287c", + "62ff0ef979144541b07bc8bf06c26582", + "95f3d6b37a16463e9d47d20f064af3fa", + "c6bde385889548bd8046fef802c748a2", + "d28690af06624a80b24bcf818666ab1d", + "27adb8f296584f0399c63583a1afbee5", + "d563b12295ed4eeab3330c212eefdd56", + "c230649ade1b475cbbe427c8d5a9b2dc", + "078f9ccad62a481f86b3a42d040acbe5", + "9f701549bf134f0f8b733a4b30f5f1f0", + "0cff3c7154bd4583b4f9df709144faf1", + "1aec175ca4d1439a8adc0026b6c3ba4f", + "45a7e7a2e2404d118ee66d59559de5f1", + "59fba50057104b9c9322e4827813ab05", + "7652a4e76601463ca8c7aceaa84d9bf3", + "c6f97125d3c34334a5652c2d56897cb6", + "f07e839957784ea390d512eab6fb61a8", + "777d2796645948e48b112c27218344d8", + "b75c55343c904f11b7eab40191fc57fe", + "70b58068fc0147f2805c2d5bacc8b484", + "e8ca4149b2bf467ab19753902e230a1b", + "f187160e1be34929ba3226dcaad5b0a0", + "687db903294d4f9c9b44e6bf147e6757", + "f5c99bd1665a46c4acfb12531c0064c2", + "8228cded38314c6183dc708951e0ff4e", + "1d3b28adaa824db39845d609d13a6b2c", + "d7e736bc8ef94ec0b699a2fa0c718397", + "56d9ebb40ee4490e8e683865e4aaa566", + "e1326c176959417ea8d55c5db3139fa7", + "abb2916c07214d9d95cd70bd2dafa8fc", + "1bfe99a6fb8a4ddc8de20a800c644bd3", + "f87ce5aebde04be4bab292db2d30327a", + "1fa054d12a084b7786d1185e0dc8787c", + "74982f2364d84750a482e9a358bcf800", + "ecae4a6a393b4ec2b79fd2801a3fc449", + "3b4dea4f05f04ed7876484d25c5e396d", + "44c886e980324c16bb5e32e7c517c170", + "61ec1fa948e04e2eaf87b44e03ff7da2", + "eb46b3407c67491f98a13df1b86950fa", + "175ba2f0949e411d97ef701db3bd485b", + "73430fc6d81642b7a53d8abe5ecca297", + "e80ad34c81044e499eacb414b5505c84", + "023ad6658397433ba96427dd595f537a", + "1c5fb857819e4022910b8fc0ef409318", + "dedf9003b63a4d38b9ad1934225c3709", + "7076495f9b5946c596dbd3475972a1db", + "28bc366ba09447a89fe6b75420299a4e", + "77acae16af38486b961591c1cb628211", + "530b970bd2074ca4b98c9a8965a98d38", + "60f449619c76404498cbfd9957034664", + "914a57e5f4614f718d85dafb0e82ca95", + "a70d783956b140fc8ab656ac69cca00d", + "c661b38bd57c4668934c60068aa4156c", + "f412d837631c4969884bbbee0e060909", + "c271718aff2b4777a38c76c5a040f91b", + "83c7586454d24b82ab7fa697efd4b9af", + "68917d0ed4be49a2ac77880e06854fdf", + "4c665517fcb64b07a10a1854778e7870", + "7cc70b76e35f41dd9d8352d7f8210bfd", + "71e67efec2914040ba2f17ae42929dbf", + "f55cbb2fc8784a3d86490248bc645f63", + "1394e830ef7947c7a688a8aaec00894a", + "e317dd0031794072a86e1e9fb7fb0f3d", + "06351a567b704c88a5a79a1d518e2173", + "ef7b406812ff44dca514eb7e2a7627d0", + "46d80876968241f4814598a71b3dfd93", + "1de6daa10a0c442aa64ec126ffce7e2d", + "3a00f75b74ed4202b2b1551add2aa620", + "a2b56b6bebfa4388a349eba131572a6f", + "35fccced96e84be5b5203442c7e0f994", + "7ab75054dea04187bca4da0917f501a3", + "10db74af64c640398abe0dd681db577e", + "cc2ea5ab53b447d0981e2f52edf08752", + "3262e21b3f524cf1893bcc25f45b3630", + "92b1f052b94a4a4aaea3b5cf512c33c2", + "ae36ac6146a64aebbc3738b376179620", + "23fe5c7a79c04df483d11d9b0fb43611", + "2b2f2afe691143b1a0d9c56141b028f9", + "6a2744b34bc748fa8a42998ac4750567", + "eadaa60e025d465a92dff7db4f3d184d", + "a21fa343f6a34ceebff81bcf6766f091", + "5e8a63ad82944461ac280ce5ad8a10c2", + "3d019feb83fd4ead8db6ef082c712d08", + "957191f9baa844a4b14e795c5c23f8db", + "195236c544f841c1b460baf215b19c9f", + "1b78be3a0a0e46ebbd7c0c12ee676ec0", + "b946475a70a54c719dd9091987c60980", + "07c301ad1ff84897b2c90e52eb318a21", + "334a3ab0383f49d1bd34575a36ddf4d6", + "4a0c523206464e40819f47d1770453dc", + "44ede42a38484e5a9df26dc8c9d9ebe9", + "7347b2d9b9794a5d85e75f494efc4c71", + "f2f13a8630004b1c82730d8b9ffa0e1f", + "ef4672490d0a47e3ad47e512207d82c9", + "981cf2ebbf5d44eab0500c4e5abaa0a9", + "349aa36f7f574f809c706937b93682bd", + "b2ab96c4d1424afea71513cd0a4dcd7a", + "d5136b3c02594f53b5c1adc8c123d5a3", + "2d609d3adf9e49ac945b62b5ce98573e", + "6e471a860b9a419d9c1f0d24b417c03a", + "425c46b81b114eb0b5dfc4881fecc7c2", + "385c09d2ebb2483d96a78918c665db51", + "05cf3c841d73467d8c59cdfbfd66229e", + "3fd311baa855474496f87d5e0d99f088", + "ef31bb08e2ab40c68c00a38206d9044c", + "92e36afa506e492eabc12b6fd34c45c9", + "80841fde978642fd9e2dce69731d8e89", + "01e35903910841fdb2f3c4dc41ff8b74", + "fd340792a4424819bbc3c27193e670e4", + "394d63b0102f4da4a7128a71cbf84d40", + "74ec5b7d6e3b46319c4902595a93bcc1", + "ba69fd0799284d13bcdae1ef801eae21", + "a35c18272af64e6db8188c6f1a15136a", + "716dfa11eb8f4020833584a3c3d09d5d", + "e02123e2b43d4092820c8e78b4a48332", + "73a7a4583d2744a6892708e3ac1a643a", + "9b04c655b5e64f57b5f316e21a98d4b5", + "d859d8d32a59413481fc38464511d33d", + "b5374f4efa7e4658b914bb90edf0f7e0", + "24ec0d2be06c42909185d287279ac42e", + "c3749ed9821046889b3b289ec0a32238", + "079495b273584867b3767d05aa244bad", + "c952be79c6b44702b4a7b83f85ee6a56", + "bb02344137fb41c982c3135338749feb", + "b95b68673c824c8ebb15e16ffe5e1449", + "af6c44c9ed334e2494798c31cac12f80", + "777e9e284d504b939281e927745b7f69", + "08f0fc1d37d74831912c7b9c59c84d5a", + "b401b7ee6127461bb338ec1ab2c6e9c9", + "f52615a329da4908a42f5fae1d0f37d1", + "c9f68ee69f9549b5b089e2ebf1418f4c", + "c387552cb29f4e2f96e9514f0dbb1ddf", + "394713df518944d2aea8b43097b444f5", + "f201fd09af8e4f048219917d6c7eb38a", + "2af2dcc7d1684a40814309d04ca62e4d", + "f54038eeece24df095ca1ba2f2aab040", + "881284b7079f4731a98364ec95a7f0aa", + "23d7c85ed1dc449fae20b269fd798cb1", + "c4f2c045d106453980b704a2fc84e68d", + "43dd26e234e042808532b53e67c5eed9", + "527f0ad9f3b847e4baeb2217c0907876", + "e6ad659e1b8346799180a7be9bda5795", + "5ad02ecf7bb34425a8c4a1be2b554be9", + "cfcd5581769f4785bb12268361d9e36b", + "bb7e9cf4496f420c8d825d2e507f124b", + "a802ecd67cfc459f9f1060f188ff6fc8", + "53984f3881a14fc595478ff5342e59ee", + "ad187b48edd24196bbf2ab14435c16d3", + "b6be1f59174d4a10825270fd805f21ba", + "029daded6fbb42e4a0f0e8bff11fd674", + "b70a5d186ddb4e5fa2289f52a93db635", + "723b227b63bb40d4adf89f265d79fb16", + "ba170cd84f6f41f494d2bb7a7aa53134", + "f818484ff04e47a7ace688faa5015a55", + "7fe6509abe104fc29c9257d312f9b14f", + "9cc9a05813d84282bee8cfd91fe6e03e", + "5f740bf3f52d439e8e9f8bcfde7e09f0", + "97a0bebee309436dbd19dde35a35a392", + "e088615fe2934a92be6316782d25f93a", + "50be70931dcb4a838b906382233a28f1", + "03fde10430964af396242d2a6ced7ea4", + "a64708ecf46c4f98ad588d21fc67480e", + "529b2d908c8840209c578dd25b67b977", + "36b3c0e2bd5547aca9fadf220f4e0051", + "b8e81546b3bd4b7199883277f553b6c2", + "392a362ca6e6453f8c29ffbf3fc20608", + "987dc460c7ac4e78a27e237231576f19", + "0cd51caee3e14b2d92efaef53c7c0196", + "5866a5b13bac4a01918d2b1eb80ad2ff", + "9f95b2c1dd424685964f58618b6265ec", + "0b272c2a4da140d38cdfd226fe750ae2", + "ba3117d847ef4ad6adfbbd43fd68b3f7", + "29d5c2ea3c8e43bcb44516096db4f3f5", + "97c1c0c9ec6e49b993b37efca14fa830", + "b2c020425d444757ad491af696cbb66b", + "a8afa440b54248feb39ab78e441015d8", + "59b733cccc284fd7845db3ef660880b8", + "079e5856cfc24fb9bb334096036d194b", + "f126e15c0f904fccbd76f9348baea12c", + "6fd59ded45e04e4bb0fea6c9e73c9496", + "438be30ee60843dca4cb8050de942435", + "333668dd21264de788698d6eceadad5e", + "46999235b0dc4f18bd30264656a4ae35", + "26563b2166ce49d6a80b77d02983357d", + "e11d52692fa64d89827c4b2ac5dc33ad", + "1370923eb3cf476b85d2798b558acf79", + "f21e495f008f4c959d4974a3707a65ac", + "925ed87334c743328cbfd8ff46de338b", + "efed137a7db74ca99eca90218ed14563", + "6851c90aa4b14c3bb7df2cfcc0b1da4a", + "99e4d1337c904b549b4ec97f6ee56aac", + "7b99acd30a1a4b54ba6bd92db4c4cf58", + "849e2d7080fb422faa6568fa43af1ba7", + "d0f27a597d064d9098d33d43de223fdf", + "ea548e94e5924a10b0fa0225d7300802", + "9bd569bdf69c43e1939d7b9c1747a81c", + "a1d755dc91a24124be2cfab253664601", + "217a0c7934464b95938697376703f106", + "9c5cc128e6d744528179b7807447260b", + "f4f2787d2f8947f6b93c5e90c10db87e", + "af371a83b24648599936caafdef8506b", + "2c142ecbb3ae4996b4989d1184c9a832", + "81b13b63e1ee478aacfd91f91e5791bd", + "a50e21424e5a494191bd306dc4daa267", + "0a7ac1401be04c4bb3dff02d04681073", + "9abb1020ee34465cab478616ece693ac", + "42fae0e826cf41369f4b67fc10ee27ba", + "4d38ae5edd3b4abcb2ba97400b65a98f", + "249cf5a048724b678cfd2bad8c3be831", + "87a9f5ecfd7242f1a829b22c2712e207", + "f8564545b9f449d9a796fbae15649e42", + "04d4543ecc33417885a437d3b2169a4f", + "9e7fab94d8f44c5da10128b4f8556d20", + "e4c9b6a856ca419d83501488d6ef64e1", + "d5689caf08f64b1591603c34db31e7c5", + "4a904f21dc2543acbe7bbb46d6340025", + "3d319ed27646467fa35cb2efc5c26564", + "39259b33b5b24361b91f2211f3e71691", + "e72df1d4ff5240fb93ee0ac0565dc443", + "2dbb0935c44a47eeacd13fec59e088bb", + "10b80e7d35564f25ad2fb9b3ff0275d7", + "0323b1df8d364c5e9227489b8c0cbcda", + "4c9549644f6b477d991f16a26e442935", + "59b932c6bf7842d59830e1b45bc9c261", + "bc8fa17135b54d20928c4a12213329fa", + "f43a6bcb93b84f98b379c252274ee5ac", + "5044961b5ccb4affb6f9b8d1cdaa834e", + "dbac7c1a1a5f4b79a1cb8bdacdd42aff", + "720e855e1b7c480c897b39b600a45284", + "209cb9da0ea64cba916182f29393ca1a", + "04949eda2fbc452e9159d088a994336b", + "b02c560d80314668ba3a52a004860d3e", + "a6f13950fed74b6f912f2d19eae51b80", + "1d193a8e438f485aaabb8ed759ca1bca", + "890567f125dd4469a87b3330cad10b20", + "898a07927b7b4e038662864268a4a4de", + "f1e949dcd4f14ffba2c8fc7da83483a4", + "0f49e27fe9c54065b9d1d1a08ff97f46", + "1f577fff540c449f85cb29d91bf18d07", + "38296318f6234054bf849608ed7ca3b8", + "5f0db0473d4f4d0cb327009e3a243efe", + "84f961ce13974fcab4d65dcfb3ce0e26", + "c20b085586fd48be98413696b2e76291", + "80ed3d49bea042799234fd45f0cf72ad", + "e62ebe03c6854248ad19f4aaf727c3ef", + "bfb6d044406e407eaea58f214b139d7f", + "b00ff03a2ab1438c95e1f34282e03545", + "862d64f546e2449e9fddfcc4c0aa02b6", + "e1badb6d32ac47de8ef38e9f4dad79a6", + "3ed56e01a91b4988a473451002091701", + "9c8a9e27bac14685a3c177056bf420b9", + "25076b00d3b94a1f970a05a048dca6e0", + "1486d72b4fba43acb829b5064cd4723e", + "c2d0be1d829044be919771983b617aed", + "e5d42dd9b0b94439aec2ca547c93a56e", + "43359c7773ca434db063bab9aebabca2", + "bbf5db75ba4745b499900c1fa7d0e55a", + "fff87ccd24464db1adb0995b5415b2d4", + "057ed726c32c4e0d8912d04343e7bf5a", + "06eb5c9b0f2a49dba0c99207f053e048", + "75ca3b6282c6464281fcd01ea735181d", + "5df0e70cb0e1466399b459f5fd0f91ab", + "e2b64f5031fa45e8be661a89baeae3f0", + "84eb32f27b4c48c9a854de8f9693c463", + "6c46435c39dc4a5c9011d045221d124f", + "e88da952d8ad4eb4a4be489c45a343ca", + "52432f571f904785832062171cca0f9c", + "c49fe9a654a444648230d73b7ded05e6", + "9601bb26aa0c4ac386f624498b9588f0", + "f35d62dcb3aa4775a0027e3e7a034908", + "a41483b4650c42eea2df6419cedbfab1", + "ed27e8afe5cb48a093ec52aacb84e19b", + "d0aad1c318e247ea856aa01325c863f7", + "4c2553601c9849ca8051a0bf39423422", + "0b5240a41dbc491c83432b75b1ca4510", + "8b18013265524e108b4e5c22a131dd6b", + "03655628d8154d5cbddc522c25e6ee50", + "7d5367e51dca4a50a101b1089149ccde", + "cd6cbdf835564c91bb74a3c80a21b862", + "d91576e59a5a41059a54872b2db0b03c", + "543d4fd971d045e4a296339c10082bdf", + "c438e81e796d41d9a6ae4cc147ef8d4f", + "856b5eca30b7438491189a4f3f729b44", + "f397144b498f4b84ad18fd2efea88c11", + "b7659eb02991433a98a60e0df0d363f5", + "7bdae48145d44a4cb29c559ba868f97f", + "c46c5299740346a2b0a3c778cdcc140e", + "5b1d40b2fa8348ec858431a1a311ad61", + "e2597b4355ad41a19017dc9745bcdf5f", + "b51df96bfe9e47429006966d7af0a259", + "f7563933f8f342fcb1622405c4ca52fe", + "3c45e0be1c134e1182be081995064b81", + "343edd0babf743ba9fd43f99182d998d", + "48c03ba452f24951bbe763dc03104551", + "fed5612d78e64f43a74c9b8330d894b8", + "fd0ceac284a5446f98dc2a6f27316060", + "cfc32d5db9094b7b8df48c8227b3d5ca", + "9a092f5d0f3a4373a21fe30bafbe5488", + "b47dc21973344b779445f4e1511a8042", + "fe1a3f59c9ff44c19cbf82cca69eb219", + "7b29f9159d774b8185a787d0f6070e56", + "c01b7abbedfa4e49bd25f14c4b2a756a", + "58103ddeeb294efaaec9455fd63259da", + "a5c5df38dcc5428abd89a74ab824995a", + "f0a32a7bac1b4ff6a62475099dbc9f12", + "33298eba723f440382a7a4d936f8441e", + "7a545709aa98429a9b30f812f70193f7", + "629e5dada20a4bacbb5ada4b5fe17e08", + "d654768b0a624940a8ac1f0be7319a8e", + "36bb9a6e62ab4b88b7154c41489b5f41", + "790fe3da984a408da1c18086b5e60bb6", + "64ef2a52613041bfa7b34f27a2dcf377", + "f9201b604572460284a327cab6b4d34d", + "f6466eb0534b4efd96d8720803ada26e", + "9860c0037ea049eab5503975da06d9f2", + "e48257ab06174d5298605b04d51a56e6", + "b25366a78f134cc3bab5d990a32bfbc8", + "a4ecfbeef9c446c88d69fef8f5c2ff2b", + "a6cd451fa7a9428099429ad5225b1f77", + "c93e5655b94343afa12c6b3a1a81823a", + "b74c6eee48844ac395de267d373d73c1", + "552046e1874849cb925abf7650e7afc9", + "48f0ccac1e5d4431ba9e03ad8ad0d589", + "9b1fe3f138e746c1a69224856732a01b", + "e88e7f1ebe9d4972b55cc05b45994c3f", + "1d3f306efb4e4b43869b986c0f428b8f", + "a9b75ddf1a2645bcb985effc0261dfd0", + "77fcb9e657714fc4964688488ccbf0e0", + "16cfc1219ace41819a7f4b3292207288", + "6073902dde8645a5b34ed9ad9679af1a", + "c7038c990ba34a268b044839057f2a05", + "af36f7b675dc4786884df674d8deafdd", + "f5a7b3ae249b46caa0efdfb30d725246", + "3a77c506eaea4e08a10f1d288d2ce45d", + "4c5e1845990045e0a5ad238bafbe353c", + "2709f6ce4e6249798d1502d7b22c61c3", + "61f67a262a8c4a22bcb2e9059636b6d6", + "63992b8328754d7ba78f0c8c07852d6f", + "4ea8025cffa1406a937bc457f71bfd20", + "20b3bf74562140d889f671dc994179f5", + "cbb83561e8b84704b55a9f6a597cd8bb", + "ba7a67295df242ec89f4fd23558bd79e", + "712e1b9155e84173806bdae1868aa7a0", + "b7d02f9504394185abe7fadf56849553", + "86c9057e2b78440ab78b66ec4cb5d41f", + "d5a5b2c4ce994bf5963a2714dd71f1ff", + "c9bfe52cf3c9435286c354c5f3d51ffb", + "45aee654bbd541d18c9cd1a6c951f72d", + "2037d88dfee0496e8539eb91d4e22926", + "fabe3515c09349b28d127202d20eec36", + "23de68a2da0d4bf2a3fb087270148694", + "fd8d344f83394987aff12a30d91013fb", + "7d7194c2eca748929da17d8ccdbfa6b5", + "b51ee2d17c04491db2e5c6781ddb2f21", + "e71ca4e6c33e409e8a06743ed21f474c", + "1ead1e6397844de4ad94f3c578255a04", + "760da98c1f9643bc900b806f6038ff75", + "844892096f6f41a7b68fa71cdb5522a0", + "ef3832963ab24d129ec88fd4cac4818f", + "758eaa4f4cec4d31a41964a330bfaf46", + "2c8b8737e70544a1925e69620b2c0ce2", + "90d4c9fb8acf4d299ced82bb4a8360d5", + "187d6eab4f1a469eb506d1d53ecd09da", + "256bcceef0884737948ea585c1561b7b", + "12f297af37e9444dae34a02e86c4d36b", + "164e0198b3ba4f06875374032145d18b", + "9678e12f2bae4445ae230cfab9b653f2", + "1093af0b9cad4a46bc19c02f79dbc226", + "45356277d64f4bcb8df290bc98f46f0a", + "340ff33151384032ae843811df48a688", + "4fcf23297885436daadfedf917a62d19", + "5e40bee711c041028e19585429e7788b", + "3b9b92a5ef0f4bb99f3d716c5be79bc2", + "c81aea8209b74e12a82f8432d805ec39", + "47b3e990541a4e07be8595742f85df2d", + "b4a2c7380da24adf8ac7777870088983", + "a224de0aa49748c882fd047ad87c9d8a", + "721bb93d169a4d5f9e8dd15ad45a367f", + "24057c211d0548f79031fdae979364ff", + "6251708b41514ee6b4fec0e3955c4b69", + "ae0f4345cb2b4aada051856a7b4a6460", + "a8fdfaba559e4f9899944f8d50f2bda6", + "4502d0bef442476d816d082e13a2fecd", + "99c48e9728604478884611612a39c0c2", + "0325e0b8a1654b2dba849b201e5c6ebe", + "c37c5babc99746308e902004a36b3351", + "2b93556557894e9fa9431731aa6f1a31", + "8c306994d4dc4bc0891e3fd0abd6d2a1", + "b94dae0fb1ec4583804e1afb71a6f80a", + "258e9fcaa27b4b4d8c30e9b785dc435c", + "b6ef3e36e316448dae263c7d51e3b499", + "9709dbae6c1e483180229c241ba04af6", + "b55eebabfa19475e83adac5839892391", + "1d101ec0737f4a1aadc937adb8d2951e", + "d7a4858165d6442abcb47524bd15eb61", + "2a8e0ad4bee94f7a9e5020aad1864fc9", + "45e3b8b81f0444c68fd4bcb23ba9251e", + "7dab9a1b3c1a47baa98b63ee42517f73", + "468cda443ba8441cacbb74c7ba00dcd7", + "b4c88e66eec743a2bd2aa620f161bc0f", + "e9c4eb98d4144180b85c6d78c4ee9aa3", + "d5782c1920b8420585f20cc67a15ddaf", + "789ce3b041504943b4397ab0a2bab1b8", + "d9a33fb3804f4c338a41811327a6a6e2", + "3c64c2aedd5e4eb589011d146db6a282", + "a225264a80324db4958695aecf72e344", + "973fabec62ec4e53acd0016779bae37d", + "b0b5682c7a5d42fcb32faba1a55c8334", + "0ce1420f5d3045bfbbfc7e3683761e1e", + "bccd2c5221764c3f8e57763ebdaaa4e2", + "d5a7d3ecec614226bd1a805b3f93c633", + "d1086009a04c4a06b7d02bc0d6dc3731", + "7565f8283ad84caeab80f9e44ad2c215", + "214dd5630fd74a99a98511e756ef8dda", + "101493e7f87348fcab1736d968d117b5", + "d9ed588e40a74777a9c81df3d93dfdae", + "7f3a6919f1ec4fff887b85f9cfe46fd3", + "d257039737d047c9a011542597b347f1", + "fddc6b76b921419da88c5b8951adbb1d", + "f487f0dd80574474bb4227228b508d8d", + "997e14b915804f0690e5c911cb3a979a", + "fde9b12958f44581bb4e94f7bbc49ea1", + "832dd9607d044c8580b6f24d974010dd", + "d1ebfb01ef4d4f4ab5dff2d89ab21518", + "53dd2968b6c44c8abc925907b6a10d3b", + "6fa42d5c5f504c78b2bd0ec1b595839b", + "6ae3fcb6c6ea415a8fec05d2e82f5505", + "e9fe70b8fc094d26a08bb4b8c1c37518", + "53720baedd98448a8c71395a0a23cc5d", + "426be11817de4c008c99b9b4ceecf736", + "4863d1f6ec594d88a81e0bebef6ab379", + "96877e9d2423485c856b08baace1dc22", + "60ff62fb2b1a4f5c9da90d7f0e915637", + "79741aaf3b84417992fee60c3615ae3e", + "b84f307013d347c693a23579be7a86af", + "d5cc618b12714b2aa7481887eeaae740", + "0732e0dfee7747e49cef95f3d179d880", + "a207315b73124521bd3895c1f4d320ac", + "cc96165eda374800a45f510d98216490", + "4f4764231a5e46e9a201219aebe592e7", + "99f1090a85b045efaac70ff3301b608f", + "1f2cec9b7d5041189df0eb071dbd79ab", + "75fa93a4f80f4d069cb617849fe35eff", + "513f5aa3d42b4aa98c264f50e8900a01", + "07ed32ee7f554b019ed54eaaf23ab99f", + "f3bdf660b937406e97f3fcd4d54f6195", + "d74fe57bb6e04a218280415d40ad34d8", + "334020952e6d47d6b781612b1b270730", + "9b20291215674e2b8e304f50f33b10ed", + "57c8bcfbaa8d4b7d898e74671da510cd", + "7738c0f0defb48fca4736eff54e21d93", + "fcf64ccbf72340558b54dc328ba9bc3e", + "73b98b9a1e664b60b4f614fddebe8bec", + "dc01c7c96ec64f6bab213fac36043fd1", + "4fa7ebf1f33e4631963f98224531c661", + "4d93486014384b63af3b59b2b9f6fb13", + "c700f944b3eb4604867c4a52b5ebfbea", + "7180b81a88cd42508ced471062cb4c9b", + "c990fff8a1c145acb00f7d0bf6d4d708", + "2f68c7ae32614c75874793f5de4a4cbc", + "8ca6793de7c8469397036f0f09cabe26", + "b7d174561a974ec39a709f6b0e9112eb", + "69ec21a2adf249779d307ed55e5a3dbf", + "0da6104a838a4c32a067fc2d0a8b566b", + "d88fbaa7a17b4c19b8a3c370448e29d4", + "55cfd78f9159467f98ce58731e31979e", + "4bdb6863db964ebdabd1e19d665f410b", + "b50cab2736c04d128f417f05008605fd", + "40c3fee5315c4ef2acbb368484a1fc7b", + "062f7cf613304d4db0d130b601619a4f", + "0ba9866287744c97a585105564416640", + "dba0c8ab83174c87938844575fded9e6", + "7fd18af9af9741cf9005fb99b9a51323", + "b81af869f7a84e088181c0862cce73fd", + "38f4afb122be419fbc7c921f6ddd656c", + "35e48613dd7a4dddb27e7cc2e106fd5c", + "79be0b8b6278443a85b37f82ab426753", + "e32410d4a1204c10993e5854d6a5a46b", + "7f650d22e78941aa81d0a14a4c501180", + "3736d43a804b41c29579cba3cbe6286c", + "748a81b33e2a4e21856615250e0541c3", + "8c03afd455304b8bae71c44b7005e694", + "b8b764f024984f35b6f98b3b11f6c51f", + "28eaa9ce4c8d457a87e1feaa4711fcca", + "ae720683ec9240e580885bd6a4aacf9b", + "d037558f2c4647a7a4fff1875f677579", + "9df57d2e623f4a4091787f4aeb080634", + "c1a8e1eadd1640c1adbe59b41576e1aa", + "885b71f984ec400a8443380a6b6d5551", + "e6a846a1ab9149d3a0614c7b82bcc8eb", + "03931f6d4f38472c937cbf51d277defe", + "e1eea0ff1b5c4471858d69292357a7af", + "0a1810add9984f3c950c34b7b5462d96", + "e4399b7dada04f7ab837420d8051a965", + "c8c3f307e93f4c829d579d1b369e6b02", + "1d95c634ec8f4a30ab43363b4de346a2", + "b464ff8d732d44fab00b903652c8274e", + "d39eb03ba00a450287b830b6564a3e64", + "ec9c547a71a5441d8a066abed15ab62a", + "457947902e1e4b3a8b2606cb4b963e11", + "d111b2412fb74366929d222ac6fbe359", + "0702225ca7e449c9ba85f3a142c65bee", + "d4d07bcca6d241c888849e04d6f98cea", + "0e44575a36dd4a709604269352130572", + "cdf56b3d94724be4b6351ff6e9355d07", + "59d9581baffd46f7941a6188b77a18c6", + "908858e3cc5d4341bcbfcaa42cee8a3b", + "fd93e10678864e2ca7fa4c9c272745a0", + "04150472cd1d44369521cd41964e1abc", + "d3ef1567ae7d4cf296312263064aed23", + "6ffe74e0ce504bccbc3edbb8408fd42d", + "1c090260738847c68e045e6d3f16a93e", + "dc72ca1c9f9a403197cda9b2d74518ee", + "bd15dd4edc6047e8adcfb51972b97e7a", + "c747e79a65ee4c6ca51b6a694bc7b400", + "07cec33da295472b8c078f20ab03808d", + "f2fe4576f0634d0aacde727e2a33e9ac", + "6659d460a0924f3aaef320961a419198", + "948d233fa56346f6b7f7c1f60fc57f93", + "0fb5dabd6784460881bec41a93dbe632", + "8f3b0cc184c94690948c996bc87c7d64", + "14f196c232d14b4d819c9377463169ff", + "b495045700ec4b10bfaf40d3ae713fc7", + "8d23019e11a64894a8cdbb30e36bf1d6", + "7a8d8b20d6ac411389a521454ce74f40", + "51a65d90e9a141f480ba38939ec9a050", + "50412b64aa20474b87e2ed690464cfea", + "f73581e1b3c94d51817a864eeff14417", + "2c843f62365b42feb94137f70582d7a7", + "b98f3ff38b2647eaba1a297c6a04a289", + "cd1e63b16f804638873d21b822a23617", + "0577046f049c4003bbb7963cb17de06b", + "7d840006d0184ef496c9860765023f52", + "f6100bbfd32f429cab16975e08995aad", + "669323bcc4544890947260a45f91dc4c", + "7bd35dbd3363425db41c9e6a391af2ab", + "33227f57c1964b9facc9d48f962a0f2f", + "670ef4373d544ea5ab577ef00161ffc3", + "eb242ce1cddf44648dc9277a601b728a", + "09365adcb5de4d9ebcacb161e46e93e6", + "4db02a025a4f45aa96a43e1743c3f4b6", + "f44378934988466baba8a146e3ed5f4a", + "5979a6cd55854243abbd5554d309f073", + "256deb96817f41188569226e75129acf", + "98cc948d6551439fa4a272471e5b7e1d", + "51919699f7af49c4b21e26bdb5eae412", + "cdb190c53a7c4507b51bd36d00f674aa", + "5fc71d0cc5b448118bad5219063c6428", + "89a750d568cc4817b163daec27625dd0", + "40288101af1b4f50888f646ccff7de2e", + "2e67af60601b4673ab6323574e26838a", + "868f6de838154a53a1201dac14f04244", + "ec9a413d88f84cc7ba9106e476276409", + "33dbc4f081f243b78c1ca6dd2332d2e8", + "6779fd8621ab4d64988b93a95094084f", + "9a22db244b074563bcb732af0213e440", + "be408bdd24ac49c6baa907a80d2d6777", + "2dc9a47c956945fb95ad438c79acf2d6", + "56fb5d352e964269b0263ab701dec0de", + "90ab05dd0f914e8f989c4854a052afdc", + "a7f3d93447934fb48b4224e132dd623e", + "8a54852e97eb4b7fb9d8484d16fa9b50", + "a140c93275cc494da94da54f8233711e", + "82e16f7b20604481b0c805e4b74b42af", + "a362168e6de6429785c4eab863b6f516", + "261e3990dfab43f5be3f65ee197af603", + "c3802314587c40a4b705918346aaf622", + "59224cc0351b4ae39ce2c580f9a01463", + "79e96df9d4e34ae3b2277b9730cc64fb", + "61c3f9ddde03444e820ff978e2622050", + "84d5cdc68a674e12958f41500e988502", + "f8a632aaa0fe488c9b197bf611624b47", + "47500b2c58704b929216a90c8c087567", + "5d3ff2b3bd6d4be48784d04da0649b66", + "21a30f3d38ef4a289ef2193fb8f9e511", + "8e9a045134e044b58495834f87101ee7", + "cff22047e4a54f4a9b6166e6922ede80", + "f174ed3f656145cdac16ba95f30c176f", + "c27cbc7744b94bb1bc96f5edbb6b634f", + "9ad4ad07292943e59ccc25c127aecf20", + "6bd6a9cf8bf04ba187d85981c0079f64", + "6df03b9117e84030a2e8693899a01d3e", + "8120ab4c7d214d77ac34220c10397fa8", + "6f3e2c34e587485183a83dcd862171a0", + "56643611c2dd43ecafbc207287338105", + "930f77af675b4a72b0d63b50f25fd37d", + "5ddc0e56e9224e4a8461cca6dac2caa0", + "368561a819984ee3bb968b96d71f0006", + "ed410e0846754f12a50440f17b19e992", + "c11293e0e2654ca3952397e0e3b7be4d", + "efdcbcfe058e40bfa5a6cf85068660ca", + "8374edde2db34030833379b9784325e9", + "d73c6d5526fe4f97849e2a691ca2e278", + "98fb87f4107b4239b833394c00f525f6", + "d162368956e943dab5b95bdd97a10d3d", + "bc17a8922ba24280851f5bce56e36126", + "e929f07c86f1435f9ff51808892ce9fc", + "2f8ccd790ce74c00907b1b92d3b8c878", + "99881ef3f7674d9db204fdbb69195a65", + "8a486cacf932449497d790dd7be22bad", + "31e839cf0ec2485c80d495767d4ca3d9", + "a06d8af625a94434b9c35a9be70c441a", + "3c1f7d0c2212476da83b135ca14f41d7", + "54b0f940863348b9b92f485cf778f99e", + "3c77d58c59ac4220b086a88cf75c117b", + "0d2786bd446d48caaf41ffd43dcb1450", + "d732ef3bc58a4bfab81613c364b5fc4d", + "03715d7247d1407c87d84485573983bd", + "3cfb1f683c324d7b99bb3d117f8a9b6a", + "78d7972d52c54036aaee0d6af3d07d5d", + "99602f01eb004a488ddfbd14b91f4cbf", + "cbf4a6dd8d544417848d8bd07fed5c07", + "ef3e7aa9a5254faaa2a612afe0cd92b3", + "f4ecccd226844c88b2c05a9dcdc1825f", + "51f56db753844e949d251e47c8406c9a", + "ba652714bc514e3888f94a606985f79e", + "c45475ead1024e42b6665339544791cf", + "bdc91e0363c140f78afedb0bd1ef4cd6", + "ce4213c45a864884acd781ce657338f8", + "721b7cec78ca43c390fc7eed47683f8c", + "82e38b32baed40d080454474595e82f3", + "b084c5c6a01749a0b957a6500a89c1ca", + "7a35d0c7b80f4ac4b48b87f1e04546dc", + "3dc23c3e1d2141d189d8581b229ec131", + "84d839f14e034fa0b33000d119db5fbc", + "94d70baf5c5b4ed8ba836e36c1785258", + "8255e0f68ab24f6a8656008612eabb63", + "10ab0817519343ecb21748b0a8e3542e", + "b9367a8d28a84ed297da850f67e9b9bb", + "b308d8dcc03d428dab297ad6690d9abd", + "7a1de8e4e9ed43aea81ea8d12c680948", + "b3e3d7ec50604e8b8024045828b22233", + "e9e1fc056d864bebbafde0c3419ed514", + "a9ec83449cb54f56852f6090e45c682a", + "a5ed4c7a97b640de882058e071488164", + "3b16c260d38849babeeb5e0c3fd476c8", + "601380b7fde84bd09748383a38199106", + "31ec52f05dfa4074acab6a98a5acc398", + "a3718bf6b6734c8cafdf7f74ffe0f3d7", + "ff506a87b6fa434ebafa4b1d5f2e270f", + "a5cedd5926aa4de0a366dc7d5f920631", + "497251bd38464483b93ac9e7cde0dd05", + "2d38711e23d24369bd0f84faaec36a2b", + "f5e81b754307468ba709fd297fa0be4e", + "c136eee85ac24891a00c28c345ef1570", + "e4f1401a472e49e29fbc8d3afadce6d3", + "d820c1b9dc154d4a9c5d2654d8086991", + "8a7ddefc6a1e4ccfb785b6c239e10994", + "f5d8cce624204a0a8c232c081eb05e9f", + "26c4469c1fd94e899b5ded8b41da0b39", + "c989a6f1f123404791f86f9ede48cc07", + "4503c0643c6e484785d13fcb142ec8ec", + "74e0e422a665475d94ddb3a62a8140b8", + "091b3f2ddf114ecbb84d3bea723fd9cf", + "8b374aea1c214d89afb6c74b4a963b55", + "383a63f94bd3496a9a821da234fab8c3", + "da0ddb490f214ed9a5c4afddad1aea27", + "924a3bf6e7b14c9a8fae4d3b514d2d23", + "7c6f89f1556c4b5aa159532c9f04038c", + "e4215ac2cb74453f8c067149903cc30c", + "e406fcfc18904bafb7165da272ebc5d8", + "0d5f5baa97754547ad517b694ea8edc7", + "1445ac529d0a41aa9c04508b669f41b9", + "c0ec549c914545a8bb29620b70491afd", + "ccd1aae16ad34ed284677a6a1830b092", + "f7d7d4fa90bc444ca095dd71ce6f4107", + "42a3686022014ca29adff471cfb548e1", + "c0321f8846a74318a10c076e09dda5e1", + "a8a1032c440646c0b1fa40dafd3ae1a9", + "1f5e1848def2426389fc1f10bb7091ae", + "9cef7e9592984d01bcbf17ba20ef18ea", + "356b9a9688824f9eab97d5e837a0a0fa", + "88c1cc6d02fb49cfa35692b790134594", + "3da99d95bb1b4555b06f1ecc7e4667c2", + "2e1138b6296b4f518d8a128c51df04f6", + "53d5d5e7871b4ef290d40a12b941ef0c", + "8be64e99663246e0825ab1ead146968e", + "64bd72851ef349ef9cd24403df1789ad", + "0d6e9e60dc6345678d08f8fce1164b1f", + "db8f248b9c6b4149ba1125f3174e90ac", + "d1cf57113883443c950ce7a1bb191b12", + "9a2e0e42cb814438a949a6f265b9ac2b", + "59660cc5eda14db0ae4be27d3b5af26c", + "d3ead6bb072c4e67a4e417ef977ce731", + "107e0185fbcb428584da42905bf094d3", + "7b3e7c7d0220479fb392a9a02a73ad11", + "7e5e0f5636f2453cafa66172358d95ae", + "dcefb9b908ec4ba6a4e74d5fb14989fa", + "684aab348ec44c2cb4f6a36e5fbfe726", + "192eee83851d4fd78531beccb81cd267", + "1fa51efeafc44a729e86e9bf6f7403c5", + "4b5f1b7c562640369102894b6abc6197", + "891123203ffb44d0a34cd04bc06cb04c", + "2940346cc97f4ff9ad1d5284827398ca", + "2f38d75f18bf4e908cd83b4fb85b522d", + "0f4646ca873d486fa9f2e383e0267c4b", + "9de59aaa95ff42408b9869a72f3a89e4", + "f62e28287c594e19b501248aca1f3d14", + "436f4b95f0fd46d0b8e71aca532dc16d", + "b77da5b9052e4ec1b0eae32d9e07beca", + "d1f9c2ef80bb4754822d15e8db7487db", + "f7b60a469d1b4d7da916b463b882828d", + "d93b1785c42c4752a7901af7c1fc3fb9", + "06012dd795fc4511b33aa9317aa7793e", + "8937a7a99e0d4343b2bbdde0586d9b63", + "eef556e177c8438d82d8cf9cc76e9729", + "97efae7bf22842139ea0eb3c2a0bfefa", + "e53c551b2b614885b998e22749efdd75", + "8015ed2937b6422b9f7092a096c9453b", + "c742d6ef0bac48008613c9a959d85fbf", + "9ce593f45d3b4ed9a5edd35080eef9d9", + "544df22f823244fcb64fbbb4436a1d51", + "7ddaf846feaf4646a964b6566113fa42", + "745dbfde6a2e40f88d08dceb94dfe97b", + "bba997540ce145cca41e9c814aa0e2e4", + "53ad8efeb5e9427a901fc669b440e3cf", + "fef38b59e70b48c08dc790fd392d1b92", + "dd693dec92b64fa38322ac6ab6879d77", + "9a682652f7c848049e77a9d87c8dd999", + "39b9b9c8bfb44a969b82fe4b72a48c10", + "ceebc5cdb527419291eebb388f23866f", + "f4e9acc7bf0b458e82951a7c99f960e9", + "356031a2c4d34638ac2aa87a7f4302fe", + "9347250c551d4a82afd0bd58f96103e8", + "384ae2f1edf44f76849cfbc0321aace4", + "dcdac8cd23494a7780e767d8b58cf6d6", + "352f853f03194e9dac551e2c8afe7d1a", + "a4ef6127b6dc450ab927227b891ca23f", + "00365fead4044f2a8ae896a68159625b", + "85bbb5013c184400ad8e9dff892c5e46", + "46b359fc3ebf4412917b915415d59e05", + "9a2ffd64041a4fe9baf1c8dd2d47cd5d", + "4b277d86dbde4b538abd74266d0acb73", + "0694f7a02bd6435c8886881207fc5992", + "f30ce33ad33d40a6b2b70f5cbfa9d683", + "5750c153e7134812b28511edd18930bc", + "569a225d73c449e7bca5e9bd1875e90f", + "8291a18d30d44bcb8944ddaef826686e", + "e88a24a6235e4eeb80173a879d2eff4f", + "1d717faae4024e0da81794f25bce68a6", + "1a81ebcf822a4eacb2331fe7951a23e6", + "e91fa48f862946708e62dd43e172117f", + "4631e22e938940caa841d632246b3f66", + "d1d8a64dbaf647589993ed2886c0c806", + "6c18505bd6be4ae9b1fc8b04fe96f026", + "aa671137648c4b049bd41f8d0d35cc2f", + "567e92036c31406d815e9b5bbaa74b6f", + "35b0a011814b438a85ae8fae5961fea2", + "aa51dbfa9cc24755b9382be28fc59ad5", + "e3d00c2464094794b4b416159ffe01b4", + "a59d227991764b6f92664c98a032abeb", + "5e254e9328764ad0bdd933b8cc6b78be", + "88efa7557d7345c0be8ef11659452b74", + "da29024b72ec47909693c84cb7061020", + "fd63948ed7f44c24869a13eb77ff5aea", + "c0ac84366cf246db9d3ce4a85b4c4d10", + "f3add20f119b4a8a99d7e685d3a94d5f", + "7357ab059f744223985423eb9cb01eb7", + "e3bee7511174466a8ea3aae156ab7fb3", + "e3d0e29f31804070baa9b9c6976e0738", + "72d87e3df2894d12ae0e9dfac80b7978", + "2e8bc78df7824bd4bb89c5e839fa4238", + "a243598d57854dacbe61eec2e960eff6", + "b22dc5d40286483c9f52076757b0b527", + "ccbcbbd5348643298fb6c6192f722da4", + "90bcd9f34a10492e813ad6e3f106f10c", + "394e72508f4642b5b7b438ad7fa74de1", + "8849c72d7f434483a88541f4e72bc065", + "97ef36387a114ec28e8a476db0481ee7", + "2d376e537b7b4d0a9dbea0856cf0484e", + "58b14729159f4845abad5c735255eb93", + "9fd4896dc1fd4ff69ce855ba3d47298f", + "18d3ab459e104d1c8de13514a8270724", + "dcf8545a20cf47ad88d6018f107a1700", + "332ae64e9ad44bc5b9b53f12373aeabc", + "f9a6951917a6446791c6d8b85d0e870b", + "c0a5a32803c2462b897e7a5ed051d604", + "42f2138659614587bacfa3c02270c9b8", + "f3de0a851ed845de8ec338647372d015", + "86bc7207cbe34ab787bf5a0cd66b988a", + "cb864a3768bc48938496b1923a752665", + "b58983feb216409290fcd53c6c0651fa", + "b2ff4439edf84d99b413ae5aa8fd46c2", + "2ee23bbe8de44874afefc35d376c6bbd", + "29b8057ccbe34e92848ce364b3a555f6", + "4864cbc28d5142448e6ea9a836b25925", + "208d633e262a4e3bb94599ea25042d4d", + "1ed333dc22e74cf6b4aeb2c9dabd469c", + "0318ad51a7294885b452ff4f408353ba", + "81bedf312287496d8c30fcfb7784e959", + "65081d8caae041b08a9aecf582dfdade", + "8bde6991ce9a4be5994499df9aa0dc89", + "db9817bc2d9b4d22887c539ab40ca4ea", + "603cc3f4cddf45bda054a885581c3ceb", + "23ff15bc69d44c21be3fb5a4c3731527", + "04bef8e589524b8c9d7a3bb206b206a8", + "ae3c1b7df3be411b81bd9e2945eac9a6", + "3aaf97d27e574291b35114a33346d3f2", + "12fe08903e82423699268f3193abde4f", + "66bbacf0c7c34f2cbb936654d9c79c05", + "9337ea6cf4e942359f290c69c77e132d", + "03883aee33084ab0861288582ea76d6b", + "5c7a3cbfb625422e8087090b9aa2c628", + "e7da84be9a474e67988ddc9127faff72", + "8cc54d9aa90e4c249fd8062f341e3f39", + "c38f909edb6e4186a05aa528fb046d77", + "0555e3e0c1be4080a2ba6731b801f8da", + "e327859b5b66470b9607f57af931646d", + "91d46bfbc4fc47a7a7257851076fc3d1", + "9b4ac1e7593246159e65e4362a9c5de5", + "ded99670d56f4ad099e88508faaa7aa3", + "fece1b60e2074f88a8406ba0476f91e1", + "f0857110021b4689bb767a83311b9466", + "d1f18c7eafbc46e4b7bf17cb205557b8", + "111b1373370645519e57622a952b1d29", + "55de9ed5554640d99fe75d912bab8687", + "5dfe7d704a1d4ad6be5f4a77fbb488d3", + "2cf6d10d703f4315859916ffc0e7a923", + "8ef9c50ce9e646099e6e16774966a82c", + "2bd754c0610e47db81660ba89eaa488b", + "6b92b74ccd914d38b09a541c0acfaeb9", + "ab2c61765bfb4081b05c51a54087ddb8", + "1d5c7975158741b686518362d7b08769", + "fc0e43a0de334f04867cb8c0521c5881", + "f9b05840ff914f6dbf54f377e008602f", + "29f7d53eae024e4d86d0d1360d32fa5d", + "c523d1ef93f34b5ab4db0e7ec1bd3247", + "d903282ae1324da5ad6581ce544da592", + "8f0e0e368fa9401ba93e5ae2f7703335", + "21754d03af3a4202a6d4e48a89b92888", + "544714a813ec4050aab5db09e5afb17c", + "4a5ce43410b9460592182a872ffded74", + "0d2ff93c988d43ab919e58bae1cd72f3", + "d0cc4b886aa9480186486de072421275", + "ac123823ea7c4bc383fc07efca43ddbe", + "d41c6cc181d4423187841c0e0a68979f", + "e8be6d9e97b14e12a489d4b312a4bd68", + "5f3b329be84649d683135e5c9fa84e64", + "edc20e62ec3a44949ba28eb5bd2445b3", + "b0e5ee8710b8450fa8c01b2bb390a8a2", + "5fe6a3cf65eb41e1834b1aca4fdd261d", + "f87c4873073d49ada0f0052d0617a579", + "ba0de8ab340c4c59842082d3f3fdf2d3", + "c85ca0cef2c14ed593e1205e1ac7020c", + "1dae31a7fa54440688eebaa0376c56d3", + "6611d47130564be683aefd71001991ae", + "495972f2b088486082b31db7c115f82e", + "1916d1f6ecfc418cb6e47db148f9eb66", + "578d3232032446a2a4692a9bd670c1db", + "16c34f670672466a93b7345b10004951", + "aab0d1db0e6a4224ae4675213aeff4aa", + "47476acd32244cd090e6c8b8decb2be6", + "e13f98a9d7364510a65042d4c42e7a9c", + "a3b6180f2d8d4655a7b1963c4eba00ab", + "e8b38df736994cf8b4f7a3a9d2980f6b", + "111cdc2f173745688517a49acc6cbda8", + "5c71a2ef43824ed182c81016dcd58cfb", + "8360fc332ed14cb7b87fc06d442a159a", + "a406b6f97b794d67b039ecca323bc8f3", + "a337046823fc4e41a3cc7187d263d046", + "b3ce6d803aa74929b5317a4771780b42", + "8a6c2db4387f494d9a1e03cdc38bf2d3", + "00c3da4c6a054847b5c220f75d065f0d", + "5240f9af9d244146a4a25503792598fa", + "9a72bed7fd424f809ff904df12de3172", + "b719b1e056694de1b38f8e2548712fe1", + "827c1ce6cdd44c30b05dfc16366fbeeb", + "ace6f1d2b20c4e2f82750cd7c7c454e7", + "56b8d634826242abab14162feb895cec", + "5c2496c27fdb42d09cd2d4939cf12b03", + "8f79bae18b2d467a9b3d1cbaab5bfe57", + "8cb4a28b0d70474583aa1671b5b5f599", + "e8c88d1bb95148ac8ae1fea9dec091f4", + "420a031560074d9e99f331aea21eb523", + "e8aad827ecb244e28427864c57b18587", + "6bc7060fb3bb49acb77720f7ad76a4d6", + "bfba243df6a84234995b9f53413fbbc3", + "653f43ff658e42d9a8084ace2110d715", + "b05bd1e7dba24cfdbe330693d67c12fb", + "e8868227230641279cd6a3c58e1c0e5d", + "8e94797daedb48178f324ffd5bfa729a", + "7250ab221633469b94035d0c9952c345", + "3212b8b1fb254371888daa55f5a5724d", + "df0c28260f9d4417add600afca6ecf59", + "98bf55f327e1412382b80a42b1116b67", + "3fe1264287384fb7a5898022619aa543", + "a1ee69e7687543aa8753ad054481d67f", + "00646d6f0c33406386a56a82b4b984e1", + "d71e0c931e85416b86419ea88953da04", + "f33f5416fa9747df97184502d71780f6", + "5c04fc1be0854cb5917fb66120894233", + "086a64c935b4455b95dff8026b488ef0", + "7296f952f8894293805efab5753445f7", + "1baff1810bef4dd09e968aacd17ac1cb", + "d5c861b423b84e13bf99550fec40d1e9", + "e1bd054f088e4c928740c4989a4a3a41", + "4f185228dda44dcc9aacba329d8edbc1", + "2d7c91d38b634f36a3628a77d1cde19c", + "ba54be49b0d349d68d7a0702adafc888", + "c566976a0fda4f719f6ea9445bae89a3", + "953eab03e608463197bc3665c2c35c7e", + "475f90ea52a347c992a3b06534a898d1", + "b7e1268b133c44b99e7f6b6313829d64", + "0a2105a5cb9e4c99a62867e89dd9339d", + "e9242cef53f34830858dcb84989e461a", + "94e8a30e011a49a7a13910139d8daf8f", + "3fff55045dd64cb9b5277bfc0ebd1cb3", + "75f279bbfc6e4d9aad23a0518d2d94b6", + "b811f79494b048cbb91b17a7387b0dce", + "2ef361391cb4455b9dced66544b4b965", + "747b402691154a048702ce7d9ca9914f", + "b3eac46b00c94b2d8f601ddee0150133", + "32f726f65d0c49fe928785cbdead8ea7", + "cc56cfec243c48c494355ac947f530e3", + "755b8840d6b941819a4366ca15c94879", + "cc7dd2fd60b54d089cb59e98fd9ea0c9", + "119cb34dbbfe41aba3288c6893d1b314", + "0318b84b37804cd2a9806d0947fa459b", + "e9afdd1eed0141da9e981953da135187", + "5465728bdb8f43f290e71cebfe2b7e18", + "58ef6dba3b9a4cab81a64a6edb2a9aee", + "5c117bc0be8b44a6b569e2e64e64e667", + "f56d8998e8e9432d847bfbd18b52f673", + "ddedc7528fba4f16ad9ac2b85c7b5d22", + "32d5033eb7e7435696369ee300ad16e7", + "d997a83d24e946a6a90c1806c46e8789", + "8f67849acb6444978de8cfe9d6d2f761", + "4fe5e63b33074b9892285f452820307a", + "1c088324b71e4ede9b18f77be0880b83", + "ef565ce5679d4ce693e5669ad13f020a", + "6e516c1b7a9f40b19caec424829066db", + "395d619aae4440308b422ed8ecf08f8b", + "1f73189efbe8443e9fb23ec5382b113e", + "c570abc36b9a4fb1bf5b1aaf4c9c812f", + "9a3b61c461ca4d7ea7429b550f2f7f13", + "57d0a2a0d0f44e659b589c21fa48f6e4", + "a69b7b9b000041bc89a9e076e8891679", + "d5d8d799f6954334854dba12bb6a1b5e", + "d9906e8140ff4cd7a4aff179eade29d5", + "bdd2389be3e34ba19bb5b3022b7488d4", + "b5c1657d74434d81b1c86b442a6c7177", + "9e344338f741427aa5c5809e04b8a979", + "d6d3cd6d2d2a4a13bd16d0667410cf1e", + "2170f37105414678a835ecf085ef956c", + "99e25f692d9e4237a76d994704c98b1a", + "125287ad7bb0428bb42757662db03c50", + "98d96a9ba15a4789b96af0bbce65c270", + "a40b369b82844e57af5705f113432113", + "fc4426fcbca847cc97607f96c9802dcd", + "f6b9a886d7ba46f680632ea18cb83da9", + "2a972cfd726847618d7fb47d470ca4a4", + "2d194e2ddee84834a929c3f25da58da5", + "e741245864614daf8170e615e4694c8e", + "5b1878a78d2849a494a3e8c95238d727", + "d023c4dbf9c3428badf44ba1aa3c43de", + "e1c268ca45e34c889d2f10398790fd9d", + "c17223df6bc64761aaab67a0a68296f2", + "052d76ff8adc4887b818bd06899458b8", + "9fdeed34b80545a2bff242e90d6a9613", + "0daa7ea3a143403cb8ec44462c341f35", + "61567313e06345cfb42e945b10cf5405", + "2656ffb5112540e884ad7346929905e2", + "82b530a913624743a6754bdd37e119cc", + "b2c1fc509240456894c803a7d77dd549", + "488908ebe8964bb38e78dc43258808ae", + "2b808687faa541dcb5a1987cea250c73", + "5ae4a2ed446a429c8ad13f54a36599b5", + "0657a328adde41ef978fa181c09955f5", + "90b65fc61a5b4fc5bffb13c951563951", + "18b0083e2681443f931ca8e16068aa02", + "25766ac81dca4864b25476dbe9200ba5", + "ee3fcd31a33d476fbdd66275552e2d85", + "a5bc01e1e999440a9e229796b59d9681", + "f9d07bb386a04de8b0e1a9a28a936985", + "24cba12e6d374539b533850de337eed5", + "834406aad22b425b8dcefebe05ec58bb", + "980abc395d744207b89999989d11fe3a", + "36a874c792ca401e851faab0fe747bfa", + "773e3525c68743b380e1a3d674847682", + "52119881fdf24110801fc01500ae968e", + "338d5278e2754d2ebc26a043d15ff372", + "b2b4fc6f025d4de696c2897111edd3dc", + "cca62f95635f4b20aea4f35014632a55", + "f61b549e1980446498df40ba6f21999e", + "57faa0f08ed342f6a0d56464f06d1535", + "bc0d0d9ea7544c0a84e7dc9cd72a09cf", + "8c70a119d1f74f158b31c07b349d824a", + "3b14b4e4566e483f87f9c7f2c7a8cc6f", + "7a769a1681eb43d39a003f36522802e4", + "eb4e58abec394c67b22ee6081e84bf86", + "815d12fdab2a481081365247c2f81bd3", + "4e729467967b487cad6f27e5de1b71f8", + "d21ddd9b309d42a0bba1fc281ca9221a", + "a591b58c546d43eab26763a294088094", + "8fbc2087b1254376b9afec839f59d584", + "029dc4b1a74d4e3286788c8b565b0330", + "64ddb36a8610408eb40466566f5da167", + "1379bd87b588495fbc1436f46dc72f6e", + "e5a6262588814c91b796de8b44b7f757", + "b9bdce6fe17444be9c851c2c1d345e32", + "705052b54da546c7a79864fc76d87f87", + "924254a35e69415ca61b0791628ae095", + "128d42205ad64fa5be7218b51acc43ae", + "30700bc210844bdc991a5ccf16b6379f", + "439812f3495a43bbab3528ec75111d4e", + "3bdb9a685e834932a7f3ce226d7bd247", + "cddd1a1d6279464ca359ae4f75a4e754", + "ea6c3fc222984aeeb312f5e0a80f144a", + "d22d36e8883943cf8733120fde611c48", + "005349b8ece7424984e8b1f224a8dfe3", + "ea1d51d3c10b4fb5b122653d68b5bcd9", + "af2ac66229dd4429953a9e5b9fc2fdc1", + "edabe7589ddc4a128edd16ed76df24e6", + "c80b9ba7152344d98980fd4b220b47fa", + "97a7243c1f304159802473331ee17071", + "09b0ec9c1e774f4ba418e0e4905ae010", + "9c5138069bed489181c24c60be256705", + "51b1fdccb6bb40a181df054fcf8d2e31", + "defbd463e037495e8cdc20f843c670a8", + "427eeb5f405b4800a237fc2d4c81cd94", + "e682bf0064c94e56868f084f39ecd5c8", + "9b4756f0c0f2464786032a5c4f666e38", + "a4e5a0d6c4dc44a98e4c15adf2e10435", + "66e0576260124140b52777d8de5824ab", + "8604291c8b0f4714b464b2aa2e4efaa1", + "cfbfff197509468b94534dbee3e4a287", + "7333335fbfb046719b08dcf3d8d6093e", + "e9854400c0c1410db01c8db897ef5359", + "b2760d856af0437fb9f2b232ebf615c2", + "df85ba4998d841f7837cd7e04cb39f90", + "2aa3256dfecf440a8bb26fdd17fa73c3", + "1e70b26e426c45dcb9ebbc9e062d6113", + "fff952be5e404a1e9882fc4879728ec9", + "f49cc71f50f541829a48bf55b6cc8565", + "9699e054a1834d57bbd80376098436c9", + "fdf39ca893a64368af45f82a6b6d68a4", + "6646d5b51257425791e5715448547984", + "49ac55b411074641bfa9a7057bf74dbc", + "0288e8376e514f929f9d7615d5cddd0f", + "d8a64bf6320b489ca6aabc02001722cb", + "335cd677c2014ca19e89efd65c7ddc55", + "cadb3080662941e391e4977705d9244b", + "829411d263a94025ae68002daa88a8d5", + "102ae42bff9940fc8f0b12c8a53d2675", + "88092301a90f45bf8e31752fc8d28797", + "73665de25ab24f0b8bb334f2832da6e2", + "5c642f6327064dbe8a6f0f8ffdcb17d6", + "fc0d8ab059474b1188d0b8e6b1c3888a", + "40ddb3635fe5462ebe83244d66751604", + "8c8141711ab84308950de9054ad498d2", + "bf0b77b88ece4400965bcbde346a1c7c", + "caf927547ea540b7b495160a99e5178b", + "dfbc4d8fe0364272a6efa6bcd4878ea0", + "8fc4b0748b5a4e0995dbc9376a42e392", + "8bcef5ec348645aaadf4cd0a2f58d084", + "d5aeb3ea0de74d3f989a1649da50aae0", + "4dc01d84c784405eb50854a6b177c869", + "866aacce4f974ac3ab5c43bb981af3e8", + "111a77ed1fcd4b1e922b3033c175cb41", + "272775f66468461b9653307e31d9810b", + "5f4497f476404fb485e228e5f70fcdf2", + "75c0ec7cef5a468a87736a5d3d391d02", + "6977120a31234b0f98a16d279b102936", + "77088ed10a6e4104a25f98121c3f4742", + "670ed19b6eb5436fb9a5ee8435ab2857", + "3227ac9dd92a449faa8b3f6533c65ff9", + "a3073cb8ccb74bd28be6c8e7d18c4a81", + "62ca1a7445ff442286ab2b397d254c36", + "2cbf4edf7d1c47e1bed5070619092263", + "fbecd3d497594041a5170e24d2d6bf40", + "79c0f5d111324264b4c6fea9402df88e", + "afbf8e6be77b4386b73cafe7e83b4efe", + "ea815ef83dc4462d8b90c4b153e51ae8", + "9eb895af086a4cbb95f86bc2fa773b60", + "93e2849f69894083866efab3278f009b", + "fbfe002d0ec34a819046c78493ae0178", + "3e2ce66a2379417db8e110c239c59f34", + "a2c797a8f65c41d298d616f7a4110eed", + "3c0d35f41da0454b8d1569b895bd607a", + "b7bbb388cc2745799ae6b915a2b23a94", + "5f94dd75cddc42d89f4a9d7402c72581", + "4e402d8ef67a4403a6119e7707bc7af7", + "1d6009449fe84fd79454c4081eb743bf", + "5aa5c78dce49418a995fb5abcb3601dd", + "929ad0104a9443a5911865154a7d3c43", + "4d674c82e4d142129cef5f390d5ff22d", + "11523012f4424ff9acc9b9a3a7d46603", + "6f89055647a843e89143e52c5560a482", + "46d82043b859414db7832fa240568fcb", + "ef60cbb8828749e5a4ceb123ec1c6d42", + "08320b83a7344141a3ec376aab20c9f4", + "2f2047d7746e4373bb7a925066b37f42", + "20b8f2af1ade40dd8c4004196a048f8c", + "d6ed3f8ad84b47b5867e2addc3ccf586", + "c8d22098ffaa47af91d525c8e2e95e68", + "0591b55eb2994a3e91a874993eb205ce", + "5860d67cf13c41c9903a7f7de86c7187", + "a97663b2ba004f5a881d3adf67083c7b", + "e09256bf6e4b4f0b97914dca034aecb1", + "be132ed9f3f040748b7800606aeb1929", + "9043192c58994a9380d38b665790f8f5", + "80b511cb62994475aa11d46e1cd0e94a", + "49762d0776bf4b8388c03e1adc5a321c", + "96da6745b3d04b0fb182e5744c19702e", + "f6b76042dd444cd395b76fc73e2f22b5", + "758e1a26051f4298bb4d9173b301b69f", + "ffbccdfb9c334ebd8f719f766b2bd765", + "bbcd5ba505c541f59b3e286e9abf3f4e", + "301272e8d5354461a20cd7cdfb3e2f16", + "4fdc6821397142fbbc5dbacaa2fd4051", + "901435dd6a2a4f49a46a8c596879d4c2", + "572d17bbbd6e4e7e8bf34c507c347dd9", + "1b3d199a690f4a58aa39f45c9c040c77", + "c12681f6188a4201a939d46d5fef323f", + "0a419df57f944cb890e5e1c781e2708d", + "c99cb8139fc6429ca610660e5fddca2e", + "62d84430af884405b0d8f2400de44ef6", + "494505dbe0744a9e9cd1263cf1054139", + "24ceded4bbe64dedbfdefeca8ce73141", + "3de7de1d7aa04832a056f596a6174e75", + "3e839ee4281e402987bc4f26e9f62815", + "883d6b019b8e47f6b9dd5c7b709cc536", + "db9a6dbc22484def8b2a1b0aa6dcd83a", + "b088d87257a14d7db6b490910b4063ed", + "f76dac28f45048a6871f6fa00b28b261", + "d8ede9f25f4f4b36bdbe95957b5a8ee1", + "fc9bbefee35c46a8ad8fee352273b7bd", + "b998ef07bd064100929c48b2450ade45", + "af96cb9c14624ec5b88084c7b854709f", + "034e31bc4b8a471699c3056b671b97b3", + "395987a7deb44f82a12b18eefae474f4", + "eba59cad60684ebba2925e35eeba7940", + "d0b08c213d0f48c58569ba375d4554ca", + "afdcc67923964f29a643e1b15d02358c", + "bf5e4d86b3884abc93add1a72fb1d2ad", + "deecaa5d26af455dbcb12315249fd38c", + "20b9ef2a6579426da3a2806fdbb1c981", + "5ddb1a9827464f1b89596d59a0eaa5f3", + "e7971d14e311432f841817786903839a", + "82ffbd3663d74c62a1d7b0f16029cf56", + "8ea0583721724e6f9a51764f47f7775f", + "a8885471fd424baca0493d1eaffa10ae", + "2183265ad754419d8402ecec94b0144a", + "ecfd0150837041c1a2e9a3c209ebab99", + "c916baaa52044a53bc1ace1be6c1458d", + "c4c01491e3d642b68f4a37c3b39e24d4", + "faf56b3ec1d04473bcd5ece74b258fdd", + "e8fdb7065c684239aaff56e5553cc461", + "8b363c50623445c5b76be30f100364d8", + "f89df1bc75b54fcf9a03b7bad87e0f61", + "fca2e8395e984794b04184191a7d3a36", + "78f8a5430b6f415484ab666b64e71c8c", + "cb991e62069c47c1be91db98d29948ba", + "e02f6ec8dfa141949a8cdb244090c2ab", + "20c37270ae314ee9af0f573f93b67a2b", + "e05461cb1dea4015bfd01e9d39edbc62", + "179b4438edfc4a43a27a83784f38ff4b", + "e8d4c95602a74ff09bc1c62da48dc788", + "4876d1a00a8d481fa714850d9e0702a1", + "9645cd0a8e084a60bc86fbfff7862c34", + "dc2168c920214e90a83ec09fac29f0a9", + "b037b370d78748e3a0778be61d45cd23", + "fbe5ef1d09cb408c9c6dcdd7c0b47d9b", + "d182b8ab86ae4176be6a0d2be144392c", + "696778c8478343178c1fefa45c6b3da9", + "4f494a27d56f4e2dae3a20d2722df302", + "5ff6ac2f9192423db8b3d9464852a3ff", + "9affcdc2582d4a73991473ae34c4393c", + "effd25a508d7400b96da30391db448e6", + "a9b9af82e36b48f6bffbdaeeb74a5f63", + "070ff896923945df9f3983fcbb9b4b1e", + "9b061aa01d1a401bbb02617c954b8778", + "60de5641decb4d3bb80e3039e54c9626", + "e60ab5e5d40a45aa8f6189b28476e535", + "4ee8be1342d34881a85ed85edf83c403", + "2decb1aa5c4948609e539cb357b63f78", + "ef64ff2b81b446d488243d48c3d2871d", + "28a812686c28461da065c29119860395", + "ab30351d594f40fa92ec4e98fec412e5", + "89e667d86eea41018821fd7796d09903", + "5dd321dc17774aeb830876bbb588d188", + "aba40571f00b4a65b778c36933510c1e", + "16fb27f5346943899986a0cd5e6522ac", + "715e7c818f814ca18b83c7f255b6b4e4", + "e30380ec13d740719b7de6e3113add72", + "0d66479a4c0b44babd475da3e63e77ac", + "1897a2f4dd554b9d959685650d2be0b6", + "1e2f1be6900643308b16046bf930e3a2", + "90233ff3cd2f4737a50ed95018cc5477", + "d0b894bfa5844bd98108b75d0d1166c5", + "a30a8ed14b9346deab20e6a3bcb768ab", + "e169676dcff64d588da211ae0265cbf6", + "f889c3adfc5945dcb10c1a594b35957b", + "1bf0a5e504584e2ea60ca6eedc4509e9", + "948a560ee9ba4f19a8b1265affb6861a", + "ca8451d8cb234e11be3c2d02bf1cb83a", + "a87d993c197749e3a243fac636f23485", + "43d82abf482649ac98a51a05c6c95737", + "01854fec03744ba98d56811ceefeb77b", + "a5083e2fe9ac4685a129df3eefbfde1d", + "7bc31069fe754074950ef7960fad6fb2", + "4ab91bbdd7e84ddca649031180d4da32", + "4a0c0ed1248c489182fad4b75c4fa1ca", + "4498a8c36d38426699f19dbcf6256b62", + "926a552f387b48a0ab391e98edbc6a40", + "4f95cb46814f43859b80172c9f712cd7", + "75fb17d3598048768893c96cedd0a5aa", + "16840cd3f6dd43f58e2d4fd0223659ab", + "f51db55de0fb43ff834487c11ce38215", + "eddf350940cd41e986a6b9a788633523", + "3f0dafeca37e479399f2d90011c1e35a", + "94462929297f42d3a663c2e67a6c4f94", + "5fa1ad42a31f4ce8b2cd548a33656edc", + "440a18e6aa9241c69eaa5c61c70fb816", + "ab756479140e46dea3530bed7af8c1fb", + "7b10478f3f234381992b821991f64bbf", + "00cd8d7fba924ff4861936d32baef310", + "5350e6ec2afa48ca864cc216fa4af76e", + "f32d26f7d7ae49f3a9e994f91015f65a", + "c6b565642dd2460eb3442d2614a2931c", + "4d3f1c2044814320af551030c3bf0e9d", + "be821e4657fb4b47aadaba3d6b0394dd", + "9169664e54b04b60a1f3265901b23c2d", + "791b545479544d168a5d9e744517dcb8", + "1d14570a943e46aa9da2ccfbb26d2baa", + "f0b802fb8446473ea328d33060f7f5c9", + "89aba26d17ec46bfb2d63803a38bacf7", + "2a9e10ffd5b0405eaabfe496d61de0bd", + "eb9b47bddcf5412380178455f0c1fb62", + "53c2cfe6f21940a7a3b4cf59465acad6", + "a670a16c94e941158541d959a5960891", + "e774329b14124cc18a87f484b58cea02", + "88e52866006342818700cb658e00ffc7", + "40e2289362014f6196998cb4d9f67099", + "de0545a1c3924479a4fa1d3b5210a2d5", + "8b259ecce3454873844dae472168a137", + "d549a0f12c524adba3720470c4954d6b", + "562acb4e5abb4f5f87ff676d1908464b", + "e3a5fd374386419680a26a3acaa18728", + "096a3d10bbbc45f0adfe6f3e8bf48cb1", + "a30aab65d235438bbfc6699faaea762d", + "01e3c476a3cd4d1db9dc8ded131a6d13", + "a0d301249f9243ba9bbec30a99873f57", + "c048fbabf7434dc38cec01d95897577e", + "7a936528fe154261afeb89ca132741b4", + "3af71e6dcc464d06ab264ab4085fee21", + "b9f4c7b4fba44fc09f316acc216890dc", + "a84e630e96b54f3f8e32064bc9dd1256", + "d2769b5a86b546fbad6540409d4d6d2f", + "a0905f82056940aea801730c91121db8", + "d08a67fb34964cf7be0049b63c0f5e17", + "302a5d1194464b71b840e643b6abb0d8", + "ed2fc583b7f348058c579b2580829a4e", + "370fc716c1bb422288646a630ba6d9ec", + "e0110fa5458d48c1911d8b569417109d", + "79e11163006342cda4ce0a3d41140cfa", + "2e24c954890d4616adc990ba2fdf6c62", + "5cf5250902354990b758cdf6b8395d1e", + "d84e5a3e4d9a48d8aaed93b7183235e2", + "25b65c5b7abd4cf78e58dff08fe58602", + "98a1d5b2288d49d993039cb161913cd3", + "1006040cce984e60998f51aea08f7a29", + "e3c719662981472f8479031a074bc727", + "9999197bbac04e3796ce1f4f04470490", + "e7d5fd361dd64769a25ec3c8d06a6c0a", + "27fd1f2dac244a6da5cbd7a113c0b6ef", + "7d4e67b7dbb84d929e88db6eec38328a", + "312e48b44344406c88a23cad59773d13", + "39b092718d1b4068abba42ea00cee691", + "ba6ac4aa5e94499f97675708419f406b", + "75f6dbd34b8d4622b392f57e23e352cc", + "ab8a2eb808d845c792b3487a7305ce2e", + "7b8e849ea0c945e09a2d34faef643a61", + "e3206a63a96a4419b4bce297462cb05f", + "834be506a56c4880bb061bd48decbc31", + "4049849e40ea465187c952a9a716a59a", + "f1db0ed35b844c728c42a06d008681ef", + "f046e4a5176145688e14ed922126f617", + "4a78392d905e48db9d12777c8b12f2d4", + "0a782cf62bde4206999bdd83021f082d", + "d812d579d0dc499ca49cf2cd6acb40e9", + "da2aac19bc914c87a1b3654d7f76e7f9", + "a3dffcdc779b4be0a2075b5d4c3a45f9", + "49543e34ddd040a7b1b428490a9a2ca0", + "ab3681b2e3ab4c47b6d85369d0d469cd", + "eb219212147f4d84b88f8e103af8ea10", + "fbcbac1708c54a44bcc2a1b5aac12bc3", + "6649e2a816ab4229b3a876a63b7f3ef2", + "668663da3a14453986cda1fef0e6cff5", + "141202eed32747b7b1259a3efeba9c96", + "1b34922ffa0248b489c6c0fa54890e9a", + "a835a95dd00445608d2d52b26dec50ae", + "73ce953592384ce68aacf472a93fdc3e", + "a9e5ae9c2a02418ea0989ed83befb261", + "334e599a874f46c7ae4ab709da53dbad", + "652160ed18354695a2906fb8e7653483", + "f47608086fc141a7a2bf05485e6562dc", + "df139869b8ff4fe790304ed9137dd1c6", + "20b0d715334944feacba1342856c03a0", + "8a60954eccad433e987bbcafc7657140", + "f1ae3a5ec7a14ae68a274df2e72a012d", + "d388ba4449c44321bee70158569d6909", + "e269e10b71054aa2a876e9d9519abef5", + "ae41fa78e18748ab89571113754ea59a", + "d557073223684759856c7d73cd5a07c9", + "7ad83b29ff75452f99415fee5b99d993", + "c3a671d13281417aa5514c2d297495a9", + "0e5451ae286d40088fcaefa2b6fb5e97", + "a2dd83a8487945abb643f016c61154c8", + "c49cdcb3e8bb4851905f93ab8dc4f7ee", + "a5985da6d8544226a82996d9799bec1e", + "42efa7c82d4144f0b0b2154b629a3bd8", + "f5c0e9f929a24f4d9266394c10695632", + "8d7b1385f9274438909d105a70871be0", + "cc947f7dee0147b49b589998f667c19f", + "6010d990c39b4f778f8d246af74b4dbe", + "ea3d4260f122455285a28072473a88c1", + "b17f1179fa6a4934bc03a796cdc4c8f8", + "8203e7ea9c7646ba82cbb190763630e5", + "dcaddcc9fdb54ebe88785c425069044e", + "9137162c3f9b44cbb15a9c2e3320d184", + "dd0f0bfbc3524063af20e2fd14ae846d", + "9ec022e6f6bd4ac489e8853919358ef3", + "030019585a6e4f79bbc3d7c10a3a31db", + "fefb3d5b25cd451390eddc6ac50b2fa8", + "4dee68cd3ab34d8da7be96e1ea9c3d45", + "fe7584c24df046d2a52a99ba7269c835", + "f2f85fc7c4df416e86fdb701901466d1", + "1749ad163235411295ed3342d024f1ac", + "9b46e54611c543f3aeeacd2580994c34", + "7331cd3ba5ed458782491474c2412733", + "538487c7b2f949f0b45ed438923941a9", + "1f2348e1ac184a2bb79b4c2f0c4ad48b", + "fad641f2a73e4924b8118acfe1bde2a7", + "b787519dbdc64f30bb20f499811dbdb5", + "f0b032268e4e472aac0eb0636c580ba3", + "216d27ab6ba8462aa51a8ab9cfd20405", + "71b82a14853f49a8bc1587a58bce9087", + "9df198b0e0a7421a9b8b54185a5f6887", + "038d61501656417aa1b3979c26ac3243", + "65707f83605e404c9d54581ed79cb0ee", + "8914d4196a524411ace8dd1073534a17", + "69c704a4679642dc9090b7b1caa1645b", + "0d097d04f0b04eb7adb0d6132dd910c4", + "c6ed2ba2a5da40df9c319028e67d28ef", + "bb070e4454c9468abe953db9ea57ff4b", + "ee7660359dda4c90990cb7440211b873", + "1a4eb7ec11bf44358f5cfe2577a0fa49", + "aa578d64a6d247ddae18cc2cf73c1a06", + "c84828f9ffe14218a0028a59bf6fd4ad", + "afbcd0424fa7475d8d24141c6d88c052", + "cf994ed3d772405eb71eda599c9a3282", + "fff92680341948349cf60ae8d46a66cc", + "1b1d889b183a47138c8304d288fd1392", + "21696f2141ed42f68436565f486080fc", + "20fce574ffe04b8982ccf67f2685cab2", + "717962c85ba64ecc901cbfb415ba24ff", + "11813d0c3ec2498a92f1e58b28c66f4c", + "ce7c285adec44cdd8081c2c158c309b6", + "2af28aa2f6e0449d80e7e2ddc6e70999", + "87d8da377ce7435182e49e5a07ffc583", + "6548d4c478c04d50bae6ab7719a6deb7", + "65cebffc7aea42eb9488b6c6891a64d5", + "ee3d603485514669b81a39515e59a036", + "338a323b2f064622a1a09b9e3c3f116e", + "fedf4214d4364e98a7ec8ac693428032", + "48dd3e9e150347e3b80e33af977d2993", + "e7d613c7f26a4d1895d5d6a59868fa6b", + "487edf06f01849d5a2c685a4bad23b42", + "13956b540bd8410d9139c99efc36844c", + "c58d624418d54df1a34431924c1a2bd8", + "ec7d14abea8e408883875f82e51fb29d", + "e11d3e8a68374c81acf79d1a021ea8cf", + "b110a32f87714dbabc431410e47b9cab", + "d9d16e8f037749d5ae1af3e0b45bc6a8", + "6b47bacc58ff49e3abd897528560eef8", + "5cd2a3dcda6b4394a3bf12ab00970f4e", + "78d474a0aa834ac3ba13d312b0b2ef85", + "2e0a2bb4f1af488c81e79f9edb21c261", + "27a6775c51e44bfda8e1ac8725eb3e9e", + "bf57f2572fa34fe6ac3863d1afbc651f", + "dce63cbd1b084cf7b5175d0c9f52a92d", + "7238acda0b7843f8b3fdfa2809af5750", + "21ec96c2259d47f4b6e95ff891abea64", + "20b75e6751344507966b057422438104", + "f8871bc542b142ebb30a1d296c329fe2", + "b20e2f856acb46848711bfaea1c6acb9", + "1e72faf8f88e49689810b6701ed19f68", + "971482f2119e42a08a3da428ff5b3a29", + "8e2a4923a1064dd5abf1fd93e4878910", + "78e3472a230243089c252fda0398f995", + "edb38066d4d44f61985f96410c2be723", + "f2d0cce3acaa4643bf6a724d16e6feac", + "c4311a0b918643af97904e10c7a34efc", + "dbb8f79e62904810ad47db92920be94c", + "73ea6b2b57644cd0aaedb115dbcfd50f", + "7eed92885d6b464e9abf82535e4999d0", + "26a2a51d1f764f2e9570f72c2199bd01", + "211b1a71fb674e65a263674c8d22de4f", + "725b18f495a249c483de9a635de66f56", + "3077db6302614258b3f1b77b9f1001b7", + "612736f7659d451e811c967c8fea370b", + "ffcacd74792a4134bbc6c17eae110e71", + "829d47b009ed4d42901a7fbc8a10aa24", + "a349e1d3445e4a1fbde98dd7e3463a8a", + "d5516f52ba734bd381a7c182fe4f9082", + "6e0c10bb0be34bb8853e580f1d544129", + "0772bd240afb4595a6c61e8ebff4541d", + "9088fdc12c7e4b3ba05613adafbea8d2", + "22b7bbd105734636b9fa92b52aa09d2e", + "5d730194b8c14c2ba083dd21837cd1c9", + "48f5d073448f4941bc2501a9c22d0f00", + "fef37151a5504904949483ad4312cf91", + "69ef1ff3ef26482fb32f66f80ffbbfe7", + "e427c1aa489b4649895854dc955d479a", + "a3dd0371ee754faebad77146d7cb2302", + "e75edb503f254bd2ba5439b71ed77280", + "92372d8e682d49c2a5e209d31f92aa98", + "6c4ebc76d4fe4bfc837c8a7d8b32c316", + "bab93acb3990415783b9b6d9b2e178ba", + "0b04b81875614292abd7916d577776e1", + "a0e7fa322fac48f9b333234b8ccf433b", + "ca1155ccdfa04b1f965ad50b6f67a7a9", + "825df1db56154e00963819bc8c393069", + "2adc33a3a8c74a3c8759745c46c612ff", + "aa1861cc93c34797ad3f4c276698a23c", + "43114d1a617c40c5bf45ea0b8e075809", + "b9ff31305049415ca6c891da9683c711", + "7688dcf5b87041a3bea09b0aead0f50e", + "9f22e43b4a9a422bb233ce1caa6f69da", + "ebb58f8fc46443d6929e7eba99d5f178", + "3945337ae7364c53b8df6dfed59ce26d", + "40d1ea2932954cef8fb8e109ce3535a2", + "5c06e3329500498aa98fbda4178a1757", + "1bd4e460815147d8b539a0c158c0877e", + "97b38f168d2e4235841803f2f90fbd0a", + "0213a71af3314ac0aaae25030d565d44", + "8017ce1cbe06458aa77a3c7b18df28c8", + "6ca0d62287c2439d9b24ba3179aae960", + "eeca051de9314a119bdb1fd92dfbb8f3", + "cddac835d6eb49eb8d815708cf37086e", + "f3c0a45a870647769bd0e84f1c0ba7f9", + "48ff148440734e4b99465d899cf80506", + "d549c16638f04abeab33a48bdb272c22", + "cedffde11c0045aca5d267a57ca6a2a1", + "cd382cced38748238da190f7c9a90bd0", + "774b96ace3ed4bb9995aa744651cddb2", + "904e013d57e9403c9d2b69b072e54ff7", + "969221a44dee43d892e95b495623bd18", + "619f8da783b34797871a5b1b2f1f697d", + "d0d062e4dbbe47f8bc32584845c1ab2c", + "26ae14bd0d2b4650b4bf878ca85ad06a", + "a8ad1bf89f6c43df8e4dca7237b306da", + "d4050a2ab7814f4a83ef4b065f007f28", + "c99aaa2b602447b5b893f273291d987c", + "d120fa520d1a439aa396995921ab251e", + "d2fc53c079144e6cb7d4770a3e8e603d", + "76cf741354b94868938e5958e066043c", + "5f6f9115d1ae4d5c994fb348eb8e70aa", + "ccc3ebc8e3964bae891d0e2550c33c5e", + "dbfb19290759455db5fc75c23a878249", + "3dbfe22766a04d1fa551471247d55fff", + "4ec16cc77edd42c990f473d3bc7998d3", + "2544cfd4cb5e44d5b02a42ebd28b367d", + "7e5f290cf4474aba93979b6c7244f142", + "e995be764bde415aa9c80b7171271671", + "c621a1ff4fab429191b320279114db39", + "9028c1cd5d7a49fdbdaf4c0512ffafb3", + "b06080e80c294565a0f0d978e4c30ded", + "e0eb9050274b479e84006a601c9824c4", + "5d08554d639840d8a48cbaa2e6115d3b", + "6467eae771d94f4e8224f57f83a2a8c3", + "7f637ddd62174380a6318d51d4b195c2", + "67cb54126dfb48f6a74d01095865b2eb", + "f1b05ddf1b634481903e353d41b6a654", + "99f8e23e8d38459eb75a82d5092251af", + "056e0c896ce34f13b92dca2c39de44d0", + "be119e3c891d4b19981692b019af9026", + "fb2e4061a2d24d989bd7423020bec414", + "01fd75058b974750a799ed5a9069527b", + "7f95e3d7b2b94873abe749d90cd5f8de", + "05166b03dfb745f79179d57d06d6c43f", + "49d8617a99c84543a96282b2545a599c", + "05528d3792b944309e005d36652a30c4", + "871404404f6046a3afca5b3fced24d50", + "ffda30903e744bd3b5bbe22abbfa453f", + "ecdb50c46a444c889736aa7938c2772c", + "85ad5e2e67164559907954c3ba3526dc", + "d0b10676de63490cbcd032f8d82d8b4e", + "3c4ba0da6dc0439a9161e2def1635d21", + "dc8ea337322f4170855c6162b5c2ffdf", + "c4060934d0c241feb8c7ff738db61398", + "7d400cd6b3e84b299bc325942a2cb6ac", + "a926d5a38d4842bda586c40ad3d482ac", + "2addc1276bb14632bb515ddfc1be1526", + "09a425963fe84282a7e498ee9bc534e8", + "e160b6c0d599465fad70d3e3fb40ccc3", + "4ffedc9bffad4a549f6e0a46b0f92b05", + "234de9a0c21142cdada11a6d8a630949", + "19c989a6681145bc999c332699eb852e", + "a847a835995a4d91a61f45c9e42f7a1a", + "ccf94391d45747b4a3aae700c143df20", + "b4f70c646b234217b091fd97bd39e70d", + "b891198a35a64b2c9c3c1a26338b1a48", + "4bb70d723e384d32b7ae40a210c373d9", + "f52f966aca6c40b7b78880a8e00bc22c", + "8c96914507c24227bb90cdb40a30aa36", + "42f97fbccc9c45f393559e59596b0ae7", + "1d6bf99a3ffe490f82f5c2a148d18625", + "1c956f80530b4f568f23a34e892c42e1", + "8e09e36becc84eb290697ec49a1f3f15", + "b146147d4b274cd2b9e3445acf6616e8", + "99da49bdff244ed5b0aa7c21804a76a0", + "a0fe31afa2274bd78a13bbbf06f30aaa", + "a640575d4c224ba3ba8e427a4421a28a", + "d157bfeb30244d43b7da816c9d7dfa65", + "88be8ad75f274c7b8da4a54fef3aaac9", + "d340160993764e7db76e66047fd88412", + "1dc7708fd7bd4ea1b035f4c48dbd7868", + "33d4fdde1bbb4a6b956fdc6ec2b3dda5", + "36c8998a6cd64895a75a14232bb6f434", + "5601480d04ed473296dd3d6a56d5df7a", + "8928df76a37e45a2b3cdddbe696087e4", + "49fd8648c99941a7b4dd5b32b3c7b355", + "70174aa639584b2c855a35de464b2605", + "8b099a2dfafc4436890eeaa7e928fd9b", + "eccf22e082b74764ae96ac88ef29bdf7", + "8506b2861e734c4083db2e96a717dbf1", + "3b46e34782734bae9aa6a8e26fca44f1", + "32858afac3a1453d96d2feaed6f67b7e", + "fbcd13ade50a4eca9e01909bd9984c7d", + "475efef21b514d33b40e8db9385dd144", + "11724c5536d146f682b701ffb9c8fbe1", + "922cd7d18c6748d49fe651ded8a04cf4", + "52ac76e312b946a89c0da2517dd5f1e2", + "e98f41a1df2d414ebd1b3ca84ff0326a", + "d65bced0bbf646668da42d10de36d58f", + "eff6e370ce5949e5b7bb613b306df711", + "614fec7b2ee14ba3899597da704a1c3c", + "729e9f90c0d24396aee0975a18c2a62e", + "5c8f46bd7a06484f941bb2bd420c87f0", + "33b3bb845c3649f9b029946ad2b4ae0b", + "639fdccaf68e47c39bd7769b4d10aaff", + "83d87df1b937482ba57792bac8830d9c", + "3f5e2489f1ad44b4b7cb8b982ace152d", + "75b22894a8944304a039b6bc22294f53", + "3d625e357197454fb4503ca1a0e7977d", + "db4cf8d2c50c4bb7bcf9f6a6b8df3d9e", + "154598525f904aae82c4ad29cf495a56", + "cbef0d53d6d54a678c54a2f2e82fd680", + "3afa2f3e1b334366a988f6cce4fbfd3a", + "bb7f4908308d4ba5bce1b07d4d730904", + "c10b5698e0f4467b8cb8f113d80a0d43", + "0b19338f63384e428e018bb89042ecee", + "b03070581d4a417f9ed6e17c9d3c5e4f", + "bca4312eaeab4ff58f1c665158d8445e", + "daf8a84804454041bb7e21acc60ba008", + "089826e5091b4d9cb6ab884639bb4f92", + "5c7dda8576e94eba8c4cd4709b2f5385", + "4ffa78d0e5504da5a1f75ff73a439abf", + "fd9f9c95567e4727bc897eca9a71d71b", + "f84fb37480754051aacdbf4572142cb1", + "50549a7af24f4ed68fe75a23bbf0c98b", + "3db19e1dfda9425d8f52e0d835a6a537", + "aeb85300d0734071966c379d0c173527", + "009d385eb90449aebe78ed9e6a0ae03a", + "dc17980757b44206af6ad13e9154304a", + "dd7f1d2b5a8147719cef11a331176fdf", + "be84e35cf7a0468bb6b9591275627b67", + "c8e1f757e11d4c9a92996196a1ea448b", + "ab4664db1e0e457aad11ed568807e078", + "36efa57fcfc5410b9cac8871484cc53f", + "585f6fed9393480c8e31ab52fbee36fb", + "b2a52b0400ed4719ae1376734cbf0b67", + "da37eb57368b49bdbc120b5516534831", + "64fc160875ad4d71ae1cc5423cea8222", + "b18e833dbefd4cbbaca5796924ebae73", + "9f44038502214a38a2e2e1dee33eaac6", + "2676a62b12e1425a892bdf1855638921", + "1ad2a34e60894d08bf7cfb928b02efed", + "70033a7ee305491eb9c67813a3395c1a", + "b60b4974c3724f478cfe7899a4896120", + "77e910d011464ca9bc04916719211acc", + "040ac45698134ff9a4c79273bc830720", + "d32372f93ded475f9de2e3f9d6ea727b", + "8c73bdf9f6304a3899b406483b5a6834", + "dedb4c81dac645c3916b585468c97ed8", + "c118da79a044487180b983180fef07ca", + "9431e3895d1642a6afae054a779d9012", + "157e691ba8bb471a9ed5a31fb8614153", + "ab05b18b715647a3b531aced0bddbf77", + "5d0a63c2e123406b8a88a854745d7768", + "e92f00ea8d6a48d38d591215142fa576", + "eae478d4dd8d4a9c8efb955a0c6638fc", + "a97c063e52d14cff8bcaa7d7cd97e622", + "d177d39f02504a099bd83b7f66ff284f", + "a31a0d25578249f39cac9d7bbbf279ec", + "5c4c713b9e2841648762800f677856ce", + "89bab7f26bc7418d96beb3ac0059f607", + "d1dcd88b7a1340caa8f8784c4783d526", + "5198c7a6817d477abba262bb327a5d47", + "86ecd638c8f841f799562900b8b94a51", + "82d8b3fb158e45d1bac887cf2ffec43b", + "9af75079750b4cbe8012a64c40a03396", + "baf9b8057b5e4f2fbb4fd9299c624fd5", + "27178a89bd744a65af64da4089d1b2ee", + "6732042e258b469a84262c07ec5b86a8", + "8516625900ea4d24b252e110cd7a6b38", + "f060fac648164c6ba491841a1aff035a", + "345bdc99a5ba429ea2f806a5c3712d72", + "50814499f5184d2d988de5c56cfc63c7", + "67ebe2e0eb4848768e71a4c582f95877", + "3f92887511f140b99f2e296ef90d4540", + "5958996dcbd54b829826c198d9ee2c7e", + "2faa80cfd86a4af785c25ef632dc4309", + "9183b2ddc72342848f8f69ac3649a0ee", + "4f742b7262bc4a2ebced61073e66558d", + "d47bebfb30a944379e51d03f57339c15", + "fa96a964e94b4ee49c0d042e2bbd8387", + "5ca1d2c929574046b60fb04a041af2d3", + "3d3ff931220a4035bc1fdc98ef1f3655", + "1d8aa893ef974efca23209d70170109f", + "c1a0fdb7c3b546e4b846c8a8e1f710c5", + "04c6b0d6e35446d2a42d4033f4e286c9", + "ee136487dda54e79a1c8e6027c6eb3aa", + "28916281018645e1a805a0a416bb2192", + "3e489f11f182434c88a3ba3de40a7a24", + "cc618b1d5fb44a748e4ef31ff59d8caa", + "4b1b3c55979543578b00a6e4f5bae84a", + "dd490f0219074655a8b08a97452b8b28", + "dfa314a5b6bb4ec6b3fdbdc2ab59cbad", + "ac100cbc729245ef91580206eef2e4bd", + "f0b0ea89f20b4f10bb583c449ae04d9c", + "b55b0da1aec44a9e98731ca599c1edc4", + "13bb74088d9346f99b80ff46b4596f7e", + "7ec7475639d44056a7aaa998c07745e1", + "2c8d1ff84471461a9c4dffc9caf80719", + "6eb857a564f841208d3468aa2a0c4452", + "730811e3c39c494c8ab067967380a0dc", + "db28a99578734e40aebea0e65f8679f6", + "aede8475ffc7456db913f0c340696453", + "c582bc6fd8684866825bee8e9c09789d", + "14a02f73a2a44eb5aafc8bb623d95451", + "4a8030e3d71d4b699b5aa262ead736fd", + "92ccdbd9c39a4416b6fcaf4bcbd7ca78", + "4565942629194e1da2965d3fe499d0e4", + "57dc3919998d439895e800ee5e0b0c64", + "361ede74a21b47adb53a812c6e2c6770", + "2902ba2bdee644dc8067a32b67fd0995", + "3338cda4fe694bc8869b7c587c078246", + "2bbfa4c7c546480fa1f7855aabaa10ad", + "7a800c6a59a746a2be6f976a3df5d3a1", + "6b53c8d1ebbc4629b145201f375f3f27", + "aab5fc38bece40f3a170aa456534706d", + "c3037705d3ef4f9f868bb78a237332f3", + "de3919b3d23f497595cb668c7aa65173", + "346927e0ef4f47baa0b2d69117a21c1c", + "6dcc0df864ef43fdba0e40af7f083802", + "322b83dac7d84e3cb7848868e7ecdf5e", + "30cb2201125c46d98281f6f7968e6666", + "849c7ccca2b840999f7589f81c38de76", + "2ef355786fb64e5a909aabc4bfbe83c0", + "dacce3ead18d429a859c59c0d0f7a92f", + "9303a9d30d86416099bdf466c17350bb", + "6eb0b6ef28e94f5bad9e4ac795c1d85d", + "64ddb31f6ff546cc953498862cb63034", + "b7d498a138f343c7910ea169ed1c2a3f", + "3fa45c3d774a4132986ae2211528186a", + "63687a28ef1f4b4aa02130cd1566b9bd", + "dc30134363c0460195e0b5b2df9c9518", + "dcef0b555b1f40a4ba388aee47ad4e3e", + "4a5cdbf2d7264a90b3f2fedcd146fd5d", + "a6ef4494070e457d89d418b322e2f8a5", + "6a9875e2f57a494b92b70ef9635a4fe9", + "2fe397dc515f4f27b3007891d0799f0b", + "6111eb8442464acaa71f9ecdf9087c06", + "2a29954c94b445d680bd5692eedb24a7", + "9c131ae49d6e4a0abdf055ddc421bb71", + "0cdd429eb08549ac954352169de5c8f8", + "90f28554f6d34de18f5df866e0ea8ff6", + "f05759c515544ea4abc1f61c718c516d", + "8e1ecdb8c34e45389642d0af43f5c67d", + "ef58952aec3b4a93a514f5fff5607d1a", + "c216f461f2de400797dfb2cb9cc1232d", + "7df995c96c6e49bc8875e4d0e0698739", + "1c822108c1a04ac18fd3bf540d6d3636", + "373221542e6a4dd7a1797d603f171f4e", + "3a3082728e72427bbc8d50f8f8a8e8f8", + "58170dffb40e49c4a4b8217fad76f5ed", + "bd968c68d7b74629a7e062af0842082b", + "a94e6192075548b68af878e57db2ed38", + "b16076de0db44f7983d99250ac54eb2d", + "4743e076a5154039b5774c299ac45ae7", + "1cfe3f7eef2d4af3a65063d976530977", + "5fb88b6b848b47a4b2f1534a1d7600f3", + "47a10d446a2942ca8fd7cbb0cc306b7e", + "fb78e587f28a4ff780ba0568e44df274", + "2993d88897574d5598c266eacaf4a7e4", + "66ae6c732fef4aa6b781246442b6616c", + "2527cdd4e465404a9e049171f506fc14", + "61386bd3024c4475b9c22ca25301746a", + "f3521f3c4769493ab4ef3758d779afde", + "3ead948ed4b448298a8762e912221a4e", + "0fee5eb011174012ba889fa3ab92753a", + "3d17b06570034048945a5118c7149a40", + "1c183506652e40d494e8ea1dc18296c9", + "2a372102552c4006a260a6190eaf4857", + "eb2d934851b9496591fd0c1d3a08093a", + "06fab6d433534f46aec99839b6c87721", + "8443b28516b6416fb324d8c2bbd8729e", + "de179cfe187542e79bc352f6ef72f2be", + "b919fd6f4203443ca224679b39a58b48", + "42d00280c75343fc853c53a6207b86ef", + "45867f283ac5476a9b858d1b9c62efcf", + "ad0c974f18514b0a8ac976d9740e094d", + "41dec153433f4cd5826fcf444fe1a8f4", + "3a7112396c7642df9201094a9b3634b0", + "c4526bf6c2ba48f8acaad9a0783b0d1a", + "7441b159f92e469d96401bbe1756f8b9", + "88fbc2f657134c12823f1a5c082a4d4f", + "1362fdf6c7d341a48efc217b71b69e1e", + "1667021ef9034d0595a46a342a3bec12", + "31b03d906fe94ca58f623d6ec7792f58", + "9b470dc7a2a045ca9537304ca105a779", + "a38476530668484b9cc902c12e8adce1", + "e15521857d9b4f8bb9dff28d616e85a4", + "a8821371a98a4ccbad0beee12fd4f3e9", + "7a2d3f89c5d84b109eda95edb952d22f", + "1768ad36821a43cda1c6fdfaf548c06b", + "fee6362e5f164241b7c8839182be8da4", + "3cf1e7cc92cb4e7a8ed32961b768190a", + "bfc927eb5b9a42a3a80d0d9f4af6433a", + "82c0b6ada2924702a561101339ea3250", + "ac17230055d9463d84f23d398014310b", + "bfa95a4d41464438a571f38935e6900c", + "057932f264fe4f84b070fc3d9104fde8", + "86d43c1fe20e4205a0e433d363d0b24f", + "7511c04cd6ef429ab354520485dd2bf4", + "728943c38fc845fea9e257c3e4adcec9", + "b5b2012b2e894095b9ce21cb2b446cad", + "74a7c9e4e0d240ddb27c420dda54a582", + "b41e0dd536b24ed1b298e7655c318373", + "22153c3ad0374aaf89ceced9a904283b", + "ec9970b956c94e09bac26b5c806e68c6", + "08844a5d62de4134a4e1fcf95662cf27", + "842a893dbde34ef397b838869ef2ad35", + "e886ef51f2e844ca8df77d041151068b", + "f4d7a66c61bc4905802577b65cb83523", + "cdb6864ead124de3af8b4d8d0ede3255", + "2ecfcb2bf3d842dba639f2b7ea698855", + "c836b24779d94670bc814ae751189913", + "35dd8973f22040e9886b6dc8186d2ce9", + "447a6fc3783c4191a5bc9d5995bb7e17", + "1bf9bc9c320e49ab8a6a50fe4c03c933", + "65f268f13b084845b33a3a0c66f4f6bb", + "3360b4a9f11e47f39c17b680a718619d", + "51423fcd3b9f4168846902a7d8cd824a", + "5a408836c8d7405a816d9b1d2f8c597f", + "666b7ae891ed4564bc3ac3988d854354", + "7549ebc69f78460192cb321f401b3036", + "51486cf2f5034c0c85289a1e43fa790e", + "82bb619702da4d40b8efb747cbc63ee7", + "808d6f532c5b4b28bccd4e7a21003176", + "b46398a573f44d07b5ea2c5a92042399", + "fe19aee8cbfc44d68f2af6cd39eb0b72", + "d9dba4e568cc4f6786febf6dc1fef91d", + "1d8a0247db4548858fcf8e27fb5de07f", + "696ac60d4a2a4efcba04e9ce7a5cf6cd", + "e5b57ddb408644f89a16ca9b76d8cd2c", + "9d9d8f98f41d451bbed4a22ea9fecabb", + "1c6d3625b6f448d99c95498b5675c404", + "ef9780f0cd274c28a614f1745dad00ff", + "46ce10b4de204956ab53323078caff29", + "e47231af16ce46a5978f40a08c571ad3", + "b51271ff9855493588d8f675e26751d8", + "18f78ccf07084b658e61c81b6983617b", + "b82ce3af0ebd465f86960db28704abb1", + "25e15b90f1da4fa69216636f48bc5455", + "6318cebd7ba544399e2c7a1fde02799a", + "2a34cd55d10a4b57b920fc27319eda51", + "59a1dff4ef9847c6ac1b0b799e04b0c7", + "a3918cd8d4204836a4cd84331c61ad5a", + "442a6a19b1f94a1387c6be0924e15e92", + "6a9fee4f7e7b41a28dab59fd278796dc", + "104313c44e0f4e94a4d0221a94d46a32", + "58c7f4dc7efd49c0b927217e216cb16a", + "08469acefe724b7faf5ccaf4c57aefd1", + "767a395d901d40128eb6c18bc64bd202", + "3c16824902bf45618458e5e28c2ccaf3", + "76ce77a8c0a446dfab0459d390839f70", + "e511faf3e40147ceb2c2c4555dc11658", + "f635e9f788854a53ba2b3df034a27d0f", + "6f6cf0d96cbf4e7f8c639d6e2b7c0aea", + "e2389b65271f4a57906fe194dbd0e56a", + "01610ca1062d4860a24c4f59413936b8", + "bf1ef1e7852a40ef82efdc73311103d0", + "fa201642a05e42c0aae8baa95fb43667", + "275998275d194364935ca36286abdb2a", + "78d8abb70cee4bf1958c3128af24f368", + "2d8969d8aec14639b71df94596583ebc", + "9651174d092f476a9e86fc8bd4c2b028", + "5fd3ca5f056c4b748265d08f6c6ec765", + "9e548ad560bc43e7acab5fc18557506f", + "1c25d4bac26f43d998fc38fbc1e305ba", + "392d77009c7d422d9240fc98732e5106", + "5ca52fd352f7419daaa2523bf586f64b", + "97092415069a42089f82a0b4683edeef", + "a1c79f4daba54123862f995b443abfdd", + "efd4ba50d0734615ba224f9c0dbd61d2", + "45e8b256ca2045deba73231c49e7d73e", + "6cfe19c7198445d4946b534187ca93e2", + "c6cd39ea5e194651aeb6d960b4c993a3", + "065d1418cc2840d8ab594f214b1fcb3b", + "f8e946b18179458cbcf8087144b7660c", + "645b4a2217ef452581428e0510d7e607", + "6c15637958824fe881b6c69987849673", + "46abe3eb9112443baacc443d85a49e98", + "c65edc8723354be88d7242ee53cf521f", + "49b39158e44e40c68f91f7ead92cc9ec", + "ca45e0d5ae394459b1b51b256b18ff20", + "1120299af488432887b09e660abd7821", + "f6ed459c48ae46cc92440c79382604c6", + "033a61d66f7646ceaac357b502a5f5dc", + "8ce213cab51a4ab793c58dbbf0de9195", + "33c58640307b4dc0bc0ab01d2098a5fa", + "08149058f2994774a3580208ca9dd238", + "4eb3ba34f50b4348b74a3f9a78793397", + "b34d8e42a6b84158a8b377a35a9fdee0", + "43eeb9c97402418ba0e5902b3a22980a", + "7f39b77440c4416cab9dbba79f3262a2", + "f3c4623a34ba414c973d8d07be98cec6", + "2ddb6a3739454d6698cb55c466622bc4", + "c5dfe6059e034e75af3f527286eb38d6", + "6c818d3f813f4865885bad305a46e3dd", + "f2e0666d9cb149468cfe6f29cfd77322", + "bfd94071302f439485520566ee5228a7", + "7e3988e1afd342418a05f1efd9128c31", + "2061c7b762474b22a1796d1eddf3d0e5", + "e6808ec3a56749e2aedff618ccdf2c98", + "096f3a6f0c11495a944fb7cf523318c1", + "a6773090ec184aacb8239eb0050cd34b", + "9c30a2ab33964b5dbf453e33d8fd5fb0", + "0efbc54a5a584494bf60f77698197f75", + "d3f3be29ed864080a0a1209dcbfa03d7", + "a69c357fe0ab4c28bdeebfe6671c0e7e", + "4bee949d883f4005a8774d09ed3e2273", + "b8d08fc37a864225abd15f094bd78a6c", + "f2632d011b954b55910afcd473f5d204", + "04d48c6ecf9c4a7c97ede0e2060f8177", + "d9fbdf700a094172adcaba24df70b777", + "4a1327799c864a2581c64e062d5f4be2", + "c781bc5cbcc546b1a593493cfa43953e", + "7c2da5fbe14748f19ce893d4de560989", + "518cc68fbf0e4aad946286150c8f88bc", + "f7dda85ae19b489aad0f7620641047ab", + "59d580d861a44a66b2f6d28638e363fd", + "dea662d7eb854e4cb9a93c41c83e0026", + "08bb78e6d7344a5cbf339123bd138966", + "234a6f22fbab4e37bee53f0e9494afa8", + "6a88d4caa17641b48534216759b204ee", + "d44d80f24b7d4f4f98949ad8fdaefdcd", + "09f6fe724dd1496dafd242f3022209be", + "41ffcfbe76244f3498d61af0d1d16af6", + "edbf04e437ac4e73b97319304d6ae725", + "43e18ff7b1f34453b5045bb7062c9904", + "a30fb981effd439fb046a7318f0c2065", + "f141ceb9ccca40d6963a62b8e883aa08", + "94d5f526587245c4b8ac1f538888aba8", + "615aa16e2f1946f48bc3aca64e97b618", + "9996c3918c014384b9c471059c303ef9", + "8b91908ebc3b4fecb4860203076c7976", + "a34e045f54bc4121a5b02f44f06654aa", + "fd69280489f4464aa9e39d77d96b40b3", + "fa092de08b9d44f4a8e703cd2302c145", + "885bdbd6418b44cfa973fde3d418c5ce", + "62d32d217bf244faacf598aaf5ef17dd", + "2fdaa56bbd85404cb4206dcaedc16658", + "259af4bf6b1341768e14dd7cdf246dc4", + "1ca1aca0eba24f168092ba357b7507d0", + "eb1bf63cd0cf4a3395a806e6af81861e", + "debbd8eda54d41cf91aaa7670d4d17cc", + "c1decf1efcea4e9b9676cef2ffbb7f99", + "1790a520ea7646d1832327c934837a42", + "5bdec4dc3ade4a4b93d89e68a982d86f", + "646295292f4041d28cc213bb9164b022", + "26b2b30e0484494b92ec4534bb7169dd", + "cf91916c0f424562bf5fbd3d9da5d9bb", + "2859a3fdb9a9423aafe0b031af8ffa81", + "130ecbb462a64dbbb6372b0873c4e227", + "b208127823e54203bae625bb415c7bb7", + "f2d2bccd73fe418f9bfdaafbd7fe7bde", + "5718fec0c54f42bcb87be258c39b168b", + "0695ed36d4aa47c2b13c8adb9999e0df", + "29d2c499939a4c8480e4e10f4247f500", + "1ef4b2f6bd784da89666b8e633ab112d", + "d9951aeea7ef481bafb777ea54198f02", + "09095656ad6243c08d4efdf20e43de8d", + "fab883897b2e4523b56a167111e78346", + "14aae91ddd4e49918597b8150a1900a8", + "c475c4aaadc14acc88311252b6200a4a", + "f046bb99985347fd8ad015b03f6ce10c", + "cb4d425c165a47f89aa8478537f2f364", + "d361a461f05d4c5e8df00f6b8df9686c", + "cdf9789a20a8449d9df80b7c7638e4a0", + "96ce16c9193b4192bf3c08e6c58cc137", + "36c4b7b8daeb43e594164d109029266a", + "c0154b11b3774588b2d0c32c8776a0cf", + "a718744443134eab8c5e009060f5f564", + "b76cd707047e4ff8b5b46f9ec2b761cc", + "f74d7d05f12a4cd68fc2bf592be6842d", + "16cf8f3804b9465aa98ec296919bdf43", + "22992533a4f64905bde3627fce98fa82", + "b3d1ab7790954d18a46ad83c8c0c3594", + "fb2e16d216ca4fda948a073ad5ee26a5", + "6813826f9126436fa1248d7eeb792f66", + "cc3e11dfa80144719a3092370991a7a7", + "b19f9ed0639641f7875c391e66da2e2e", + "fd2f6bb1a82a4c4b9958b683d73828e9", + "e5b8352d87444f5d8294ad68c724300c", + "7ec2fb3bf0664da5979a55a86f5cdbc5", + "6019b13176834307aac6f45e2fd476a7", + "acf8d87063a04c7b886a4869f9729c2e", + "9809e2893c7d4e9ebfca2d884c5e019f", + "af48286fdc524f6790acce4d851485db", + "19e5c19d811b4dfa95dcec728d3ed8c2", + "3f64480e3b1c48139919a3da331f8c5f", + "7250baeb03e940d08aba4a03b91e081b", + "69573fc36c6f4ce1a151a1f5466b881a", + "150711525b484b01b25ce5d5100692ae", + "e59ba47ae6324883a584da411693e237", + "09ef57639ff840f18f31c461148f8a8d", + "3b955af797e140eca0947ede57f412ba", + "ff78cedd87a34de49e9633233dffb3d5", + "d14289b68e8a4eb0bb227b85cf382dfc", + "9b71ad5fa8ec4ec3a7d0dbce24dadd0f", + "9d97fe5e551d4adea7f5f95667b7d407", + "65a7d16efe844886a006214602fda2f0", + "3f6b4ca2af34466a81d286c0bc84c4cc", + "6f2309ef36b34a7686cb62de0e2dd005", + "0f323614b2464939aaa137b3d0abc8fa", + "e342b1cda2d040ee973b25503acbd3f8", + "ba2dccb476b64730a0bf997855245d22", + "ae6d85933b3745fd9a8ac8f2aa5a1a9c", + "5e808499e8d847539e1d326a024b9065", + "34b15cc2e4a343268e287ea1f32e2a54", + "5c7400ae0c59468fae5a5e1b4a895867", + "667faea14f09429db5bf4ff0898e5493", + "728d17781c464189953e2d9482373b36", + "622f57d0e2924db8a2a0634ce5d29607", + "6b7f0660ea574d6cb179693f294b8679", + "eed10614b28d4b9692fc3af550f05890", + "144c2b57eb4549d892e839ab76f307fe", + "2d67dadaf60c4d85a77a5e2acfa81656", + "ad39ffb22b5640aba2f4cadffb5e0320", + "db6ad304929748e284e4508fe7463fce", + "2ee91354914346d69b12af1c37a9ccd6", + "45d7f4727a8c4ae09c5a6730589ef545", + "9257780d71774443a02ad1eb8c344615", + "4d9478e1b2b34d7a90c04d74b3e859c9", + "db26c4344a284e79971b37c584872404", + "729b999130854067b54edd3d45fd6e1b", + "5d1b2a881d264c688c092df821d325fb", + "dd37ba0c95eb4cc080ed63a4e8f691be", + "df3faff262414e5ab2997def4784af52", + "db9345f568e8499a9eac2577302b5f51", + "408ff45637bf44e4bb1dd0927c45da2d", + "427be76521fd421dac0e3668c072b210", + "20417e289a854da9923038bcc1b8343a", + "99a2578a85c3481fabad91dd13f3dcc7", + "e619738ee34d48a18ed61201184a877e", + "8992acdda2f1471fb64e925d3f558296", + "d227f1a717c34eec8394738c598def3f", + "a7e8c94f1ae1492497dd1d2604d9bff5", + "4ec62ed9b3de428db25b6c25417b7897", + "505cd7c1f05442b1b5ba6fd2a8ed3dea", + "9677308598274571b4203b0ea8be5148", + "122b9a58bc434a7dbec84ad0676a87f4", + "e097362e18c646afa96e90ec3b4c111b", + "ca86dbfc734a49cd9c26c71c96961f99", + "e17c65e0c8604407900a93104b965ce3", + "cdd5eb23165b431dbf9fad48e757019c", + "2ec169b62e09407b9ad4cff38d6ae858", + "68c4352aba1c4301ab409c15ce41ac66", + "819fd7304d124765aadd6f7dea9822f6", + "64c4b2642a3c4de5a95fdfa44e7a5fdd", + "f9c8c8ff399948d2bd0203642e4e23a1", + "9ab88889b9f84d7384c6f3bbab7982f5", + "c534e37656024a9fba79be2c4386d626", + "f98286e3c31248af8645963bae4c7868", + "3bdb32166bfa4bf1b8294fc680ebef10", + "222b416357a04a1780815ce4fd7beaa5", + "355043f9aa2647d7b6963ba64ae949e5", + "4f27c0f45c704cdb9858c073fe961ade", + "a330f31c57134b8fb59c93a033b6268f", + "a94edcc12f1f46f89da02b60ff43d976", + "2303628f0243427bbe81c51dda60aab4", + "b5706172bd35440b97fef2407416f45f", + "8c121413fdb642788e25ce6d4a22cd17", + "f33fb37937a34aca8aa8602820460e51", + "450c10d77aa34a7baaff7212ac5b7a11", + "141178918a044c8d8ed6d9399a39d340", + "ab00012a6fde4fee9de684f914702bf1", + "81fc76de8bda40a890f828e531e31e88", + "49e83a6970214f7e98d961bf95b866b0", + "4112e07e262842c6b7070aa1505505c3", + "9457285877d442359a64b8e42a00093c", + "3c0c16d6762740eab0aa539bec026771", + "f2b0fd061ee941d68541284616d16ba4", + "b67e8b6a1f67471d96900ad5cde5dae3", + "2f298b123a5e4f2f9c3012890db2b5a3", + "5cf21b38ade84ee3abf700f57cc6785f", + "3047f1177fe745819d6c832f31204a4d", + "3211326aee364a8b840c6425b6d4e7b9", + "3faac60ed14e4da6884ba53648695ef5", + "9835dac44cd94286956357c21f17bfda", + "7b2ab6b48a724f56b2a5fb9a38c5c74a", + "a8e346ca738c437084d61140dca7ea79", + "6739184aa6c74f0eb6cf2965c731416a", + "1f1c3832425c415d9300465d2a5d6a1b", + "7d4cf08c9750498cabba8cb4b4dc2c7c", + "c0b796c8756d451a8fef4e5c12cb867a", + "2d7d7c77ee6749ada408b9e54d582287", + "7915140572064211b4e4ebee9d9d5194", + "55385aa2ece44da89e871864e8d20929", + "2c413066184c459b9ebe958585dab2bf", + "aac70737c4f5478ebf9e14387a123214", + "64e910a193dd4a4a8c4e3dd8661928f3", + "680f23f4c5b441019b81a0acf098c273", + "27120b66ac4e4385889f5542df0c2038", + "6b893ec7e2a8417b8438d3dc7a81a820", + "0ccd662749bb431da57a622bec30ec71", + "f632e59e1b4d4dd1b5889c3f24f5da78", + "e9068790993a435b95f53588ac00b32a", + "5316212c90b44f8fb8950eb7d8cbdff3", + "8a2b07c519b34c4289da7effaa70f5e4", + "e8977020b5344943964560a3d6bd724f", + "529da364dbdf4bcb99f027c8922bc83e", + "c145ad80740f4f90aebf1f63d301ac73", + "953afa3f7e7e4ad687a0bf19a05ec294", + "7698651d136d440b8a2de35a4ecc2ffe", + "f898f82f60d44316ab0c1e913cb350be", + "5241b863cbad4d2d8d6780fc9af0246d", + "a02a994c8cee4ad3b5a4ecc8fd3f64a6", + "03c5eb65be354c8c872d4a358f99317c", + "5483beb389cd4837942e8f53aad09257", + "bfdb4a5ad3d042e2a449d004ea9d3436", + "1cb6e35f483c49a1906eeb4125d379da", + "325d638cadb544d5bc143be1989cc47f", + "66d2656f9eb44aab84248f262a0b1228", + "2923d2d399c84b2399aad9b558c39a96", + "23886548f77547858d5c93cc3d0a0939", + "b144f92d0b1d4145bb84e0be0be78b95", + "65fe9878da624a4c8f87e9bd761a621b", + "1e4bd42c423c49a3918c09907ecd0034", + "1bd0a38e18314d9f974d51ad5473ebad", + "091031aeaf3f41b7bc0b9d8b682e5f54", + "3bbc31e9ea704195b747045440ec43e5", + "dcf2e6d8ecec4e508072ff9ff73c9af1", + "02faef86ddd441179e6b9d85a546fe79", + "c397cffa1be7497b9a5be6d3278fed80", + "6751ae324fd44195903cb0558580837c", + "74c7791c8ac64c55a08704202b8cbf38", + "ee1843c4778f4ca78fd2b116c20dd9c8", + "fee1811af0a048e9b697f2ba84f49963", + "9dc0ed726d784d9db1c7f9f3ed194619", + "4c1ed7c7790444afa96de8881a65f04b", + "8a0cd3a2261a4c5ca7415129d066f18d", + "3aab0a64b603430380860e8151c2fe1a", + "b366e23a061c4fb29b10c9bb2814786f", + "ba5949436eda404c8600aecc28905f86", + "9877ff3358ec47ed8d997803807920d2", + "607d6c0e703e43dfa62b0781c5cc2752", + "5ccb735caf5a4cfc86b3c49e5938b840", + "c61d2366e5854f77bec1527e3626b979", + "2de3f52a3fb94a8d9e8d967ffb89464a", + "dfc0e6e423b34c3f923124a1bf6aa1a8", + "e0fcbec02e78484085e86963126a7989", + "2a7f950652db44878a34d274317b78c5", + "d241f8b58a304f788fbddec1c314bc8c", + "df207d9734b24484a40146be898b4254", + "a4a94fe3fdbf42839aeff23831fdff39", + "25265877c669464786ce5d7688bd7fb9", + "58fcc949156b4092a2b575fb68b3c1d5", + "ea37379003e947388fb8453614cc0e42", + "2807b1df093e496d9385aba617be6d83", + "73edd34208ed43d28534f75ff56cacd2", + "63d06c6cf5c041cd85bf710245440b29", + "afaa70e4e3894d2683afc625c755d69c", + "85d105a7589641a5a239d49db0e36feb", + "c43d7365730c4d15ad20181b31d4d363", + "e9bc3d3838514df2b7767c4f58e5460a", + "a2c689d32cd84aceb5e92921e55c4680", + "f1505f8c7ffb4f62a08df04f936be49c", + "ac1e58afd7254f128a09592f940f44e5", + "160422dda78d41e8bc6d3611f3e98dc0", + "7be9dae9ffb24bf289bcc2a72c880992", + "29a88585645f49d6ab1e5664eddbe380", + "5038686b3c074ebba576b85f0bb48970", + "9771acfbc2dd45f6b8740f7d81b709de", + "31b1d8a21fb44c1ca97fad867a5306fb", + "4b1eeac388e641b9a6b975c32cf41439", + "d17eaee5b2954775905bc974513443f5", + "f29055aeb5c34b6fb6fab6a12a2eda2c", + "297bc9310ed046708ee071f9f4e10ac0", + "76a8557e54524a40b9dd16ddd373fd4e", + "0decb5afa4ec46ccb9ebeb941731a53b", + "634d4d567a9e4ebea21a36e3a6328230", + "2c887a28840f47cfae6b5dee0d11b842", + "7529a61d0cc043fd81ff986b8a8ad784", + "5d7913a1e8d0400facb40514b448591e", + "87cda81b50d745ac8d2c4ab1ee5bfa51", + "628ebafb6ade4c20a193fd51d88c037f", + "48f5e50534dd4ecb8ea486460f146269", + "3f5c6f6b7cbc4325be2f58ac50ba47d3", + "3ab5f94d4f3745a48c7b8e5023836f8e", + "9627feedf519491bbcd7c25149fc80ba", + "6af3fad344e442228afc84decf9dd890", + "d8636156b5f34f3fa5c3ca83d6841cbf", + "d9fd5e64f2174769a222bdebac115181", + "04425ab580f04d70a87290ff13c7da4d", + "b0221d4072664797b6650080cd7acb40", + "7b2425e871ef4a278cde8cc01cbc8ee3", + "f54383fd0700414589b0ad689fa65254", + "c8f2759149604f818c2fe1169945cee6", + "beec98230c8b4c66adcabbea825f4878", + "1cefe2649fb546f29923ccaed833e0c1", + "4c9d9bf7df2f4af1aa3d48f61fb7d11d", + "bddcd0aa774f42cc9356a6941bb9d656", + "4b04a97d38544da3b884fd2e7b708c16", + "535e4ca30101418f8398a2bf35ed6346", + "d152a5266e76416b8a0682b520f7c067", + "48d65eb7fe5d41b8b5befcf1a41b9cca", + "c48ef19cfc444478af5cb9e1fff3f9dd", + "701fef9a2fd64676930ba306aa1fda5b", + "81b98c35166d4f75b559438a93843a71", + "5bda8ef98bfb4a908bd671b248ee22ba", + "6fbdf6dd75ba477aa59bf7dd82dc99b9", + "0aaa38c156414b159207789705ad369b", + "df59ac5e13844fd28c84c0c279015cda", + "b83a6e3fc0e14c33bbebff7d98dcec28", + "626c1b64d09d46e9a55504b684632451", + "b12c7ce268d64a6ab32abb5b76bef5a4", + "4187c26ebd76413181528663df783a26", + "80d8019d47554e61ab96668863fb9a81", + "f28b98bd9eb14cd58a2ad25494b2476c", + "47b1db77c4044766979e3cce55ca8506", + "01b79647e6e442989fda47ff20cabdc9", + "a915d9179fe6422b9d669a3a0d726b8e", + "4f6f2f70b0f744019d3ed2ffb837e382", + "f4076da3365f47e08c6979a01964ba61", + "9769f517844d45dab438ec17d32cb668", + "f993473352ca4cafaa5202c27e0ecd28", + "d09bb4d72820439ca6cc14bc2befe3c6", + "474e014d7843408189fec04a0d71c6a3", + "d7187ec3c7c54621955821a09d090423", + "d70b862f383649cd94901bc04f81da58", + "37dc9ae154784a999c90f6baa2ee9cb8", + "d64f26970a7a489d90811e1dad4daf9d", + "824b341826474fa483dcbc0fa3b15fb0", + "2568b63db4c9410a863efe11467e6851", + "5d1fb333230e46f7a1090304e4b39536", + "2ea9dd17e2f346b3b2abcfbe99af75ce", + "563593b9d3134fa68378e6fb1b80e34a", + "14eddfd59aff4c3689d3f16048fc478b", + "5feecd536f77452e9f5cfbba97acb975", + "eda91f75faae470e8d6461e0e6fc86fa", + "eee1b350071b429db4d29c94771a6360", + "eb6396369e8f4d518d9716596914ef37", + "b363f8f4f7394ddb9d5b3a337f2f7fc7", + "cc7bf5c7a8b647c7b8f10701c4cd620f", + "36cc04ba105e4363a3835c3505496bfc", + "97719ce4cce447dba96c85983af27013", + "d1f6601e36c64a01aaa7465d629f22ab", + "e9ff4aaf1d3d41338851bf22481db4bb", + "5a288e211fe647bfbe27f5564eb3ee87", + "1cafc56dd18a472597c9928eebbad208", + "c699824e4f3a46dc87e65e4f07fa3a79", + "7ba92c9b49aa4a3585d1db694462f918", + "94d400a7aebb4c89a5fe9a60ca3b2405", + "31b3d48ddc8f4b40a4099647fa016305", + "5c1a07b3a0a64349a1c78201b272fbcc", + "688855d765b84371b52e9f68ae5593e0", + "1f6d5dd9a2d9432c87e626fa0a88c5d5", + "0f3c07a8c23c486ea375856614802611", + "3a60acfbd68243c8a9afadc179afc92b", + "65dcebe837d34f13ae6c7dc2fa3b79fc", + "56ef603e301f4f4c81bf78650b3c4c24", + "7dec326bba8940b0b4de9d5a0e69e1da", + "3c1a0029ee0f4301ba017b3bd28c82bf", + "edbece2124814b29b31b0718fd913e57", + "fbd44ba223ef4567adac771de6bac346", + "a24fcb0d7d754296802027293042714d", + "03f935f1c9174cfdbcc512db947395ec", + "48926d46aeb34b1cb0d9c9a8d5269cbd", + "bf2eccefcfd1452ea100442251b7ab1c", + "7192c2b3d0f749549d44e6b4e0bf274a", + "ec7ca19df70b4b9e9d56f2a2c91dc401", + "caf4b801a11a4b7da82515c758a6bc17", + "b180b79e98834a83bf6dd1c14a588796", + "b1701344f07d49f1b9f7cf0ff61f9295", + "c39ba035a6c143fe9d10fbc9d9c5ffb3", + "a2448a561901428ba571752068ec89ef", + "b37cfcebbcb34928950ba2906f47919e", + "156ea3323734461ba0835f71daeac20f", + "ba4e6505b62f44149117c5090f651ccb", + "bc88e6599033451bb7b8631b090a1d55", + "5e8240e270c64c83a8187506ac064575", + "fb9e95e0f34c4c46bcd0e4af070314ba", + "df664af748cd4e5ab5274c0c8ef93da6", + "33177fb8529643b5a263653e4f706e4d", + "fd336c06768c47e4a8f915fdb3b7fc8b", + "2f50fd892fdd4baabcc15ebf888d2284", + "46452458db2147c09c8e4a6aaf8b3614", + "943f75e914064e1f83e24b3fed4d9d54", + "356704c0e8524d318be4deb1d7a50934", + "be257bdc35584fc7ab9bab21b68de84a", + "0684851262924daf9f1ff70c54e94b5e", + "49617ebcf2824de3856d4fa59d402538", + "1ae1faeb301e46bab6f0d6fd3de8a171", + "4e0993560f6e4e7cb08b321902d279c9", + "cbb67bbbe42e42189931574ce0d4926d", + "9cc4fbb68f8f45688149150356482382", + "33c4622dfcc04685aa86c8b06abbe11f", + "253266bd74f24d09bce2655f0c7e9381", + "705ee3aa18c54aabb8eafa3001cc80e4", + "42c857fc49dd4f3c82d9b1883ad502a5", + "c62ff270518645498927808d2adf9208", + "5acb1f0afe9543eb8f99e64751fd6533", + "d76980fa818240178aa8aa082fc4ce6a", + "f9fdd7c631b246eb83c81b50febd78ef", + "4ff0e8ae2f994bb7bc4de8105febee70", + "fdeed37ffb9e4cdfa40e44a5f2ca5c53", + "d3fd9470e5ad45e685295b1ebd620c55", + "ce58e0e71de048a98eae3495be60d76b", + "20e01053fa0a4933b46f8ea00f8c6e1d", + "cc4781a456f34e708de0b5545d340bb2", + "eea10af609a2469787bf25fb9875d575", + "392a16e37bf94a9ba74bbc720dee6b67", + "e97f693110fe472da620f2174f16b218", + "83dd191f82f84b94b8db0c77692729fc", + "0a1b1a5cccdd4d1495cc0f01d9b2fc73", + "898f08a38e43448a81f0ee84a34beeac", + "5d5b2a197c664856ad17d813934d2c15", + "4ad3ff1d9cc04163be00391ef77c9cd9", + "2620bd3dc9cf40a19f7aa30a733f8cef", + "eee419e0ab7d4499a33628f006db0934", + "c66f09a20a9146ab9b004685a5a93787", + "e7863bc1f9f24db1981af1171112bc7d", + "8165200d339f4f2389a000c42329ae60", + "aee7e171083d4cc38282e3a194917c2f", + "ff737ec0c534475592938a5085fd2e99", + "eebd97010dc947ab946b7e90d6397bfb", + "bea5e60a2a3b4c9c894fcde722e988b7", + "9cedd2251f9e4c0d9b42e623b525c92d", + "aa80118e89ef441a9ce47effabe24730", + "afc8c9eb7029423daa20bcdb1fe87b3e", + "14442dff0a4d435dbf83d8b29f817f80", + "cebda32042aa4159afca6a1638d00d40", + "9e7168858a8d4dd7a32374b854618859", + "f936837098bd436585153cae05c47e6d", + "bb2896720a1e4aefba3ab381d4b4554e", + "4f0e65caef354319b10e3d78163af76f", + "55d534750aa941a981896f8c31d50d16", + "cdec6d2038e04810a526f99c764af0a0", + "efbc8da1b1c2411d9162df959904e0bb", + "99787bb866eb4490817332831cc486e7", + "8e877e1b22334580a2a79b0769a1ba85", + "7a3dc12d96f741ab84d358fd2ac3df28", + "9bf72315135b41de82896ff16f381066", + "4d403792f4dd477a9334b600a8ba17b7", + "04b270a8666348b8a78c85bccb84e59b", + "651a731d4d494d8db733a18272eb8cc7", + "fee3686d85c44a69b778f2fac7c1a289", + "861bf5de961b45ca9636bf9b66beeea5", + "a373f7f69cd6454aaa69502a369f2494", + "1b6dea328d4141b3b20459b45ebe929a", + "36190037aa2a47b6bd82bdf59840a1ec", + "6a006afce57a447baa60c7a6791f0086", + "54bf68a512864d26a49d38ddbb5aef53", + "7d2666198df94a12bd297d4e22f8d22e", + "d8de93c489d840a497aa97110e42c31e", + "70d40deb92bc4aaca655a438278c73e6", + "6735874adfd64e229414f958b8f1f73f", + "74237b233df04f00b2c3aac39ab18488", + "e56a1a53ce204d2087b5bf68f4bb9300", + "120771dca01f44539491395b8daec730", + "e4cdeed8b6ad44bcae5ec469bf4751e8", + "2884e7f790a64d39b3a9f680d8bfb16d", + "ae3079ea24a6489d9defbf4622daa943", + "706732962b4846f38863bd28c8fbb1f9", + "0589b1efe9044be0b5953358878f8dca", + "99d50b8b9c0a4b83aa38369abbf07e57", + "b19ef2650b4347348710eb6364ca90bd", + "2f8cf49400954961866ff97e4d74080c", + "390d8ae3754b4a0da35c85cc33e20104", + "f53b55dbaaca4985bf8f544a439de750", + "362bb60777094cbcb98e3d780aaec3c9", + "3d9f2c89d3b34869a57550263ad01339", + "af878290c9d34bff8d998200feb87b97", + "4b62714e0ab84d80a2cd1c1ac4fb02b0", + "45edcf95ee30490f9e93abc133ce55bb", + "2a930f7ec91948b2ae008429856318d1", + "cc738f7712ff4a1cb39704f634521444", + "b850f3dcf2b746769bffddd8f20ef5d4", + "f87ea30d8b0b46ac9cd97382bc5aaf96", + "b621c64d0ed74283873c8c2b9a949bd3", + "84a8483b74014517a9e80fb9cb5683a0", + "32e3c01da59c426b8a259aec48c59761", + "dea5557997d74b75bf651de920891480", + "6fb1187a443047e0a2408d4bcf7b9496", + "d1fc40b1c91b475e9d444a96f400be48", + "4a039e32bfcc4af7b30732f7a53df9e6", + "01474f78a328473b8d99ded65effb2cc", + "709e218b242e418ca3cc77e82cc4039e", + "b625c3ccda8145fdb011ca9d0b00a5b0", + "27ada59b1f02426cae3d39ed0f845d4c", + "bd32b6a8cb504eeeb75748ab9e40acb0", + "45d0a3c40360447aabb5da47592818db", + "eb9dcd60c4bc4af99a3792b1686a4096", + "2f549172424a4b8b8976f55511b616e8", + "386aba5ab8cc4f048e5742a6b054071a", + "7e74894792b2461b86b5dbe0a3a706df", + "89a987bbaad04beda9955f70a8c12d90", + "28da032b1f1047aa836787781cd9adb8", + "17d6cec5160949cbb6ec5819907e70c5", + "7df28d1b8c314a9081dcc7c550b5ae7e", + "1539299921cd4b1fa967a33dc0cef4d9", + "8ff792ef859942d4963ff46d71dad628", + "4d3d229cc3ae4ba895b9898c8c73cfd3", + "4bdf53e2a8e7489f912fb8d3c8c5a0ec", + "3afcdf683d1b49399257952ff7ab33e8", + "c5aabc541f4a409c8fb97152cf88cdb1", + "951a6c90207e4fe68162b231d918e3ef", + "240796c1b98b424381195e8b4c7f83e9", + "285e4ed9a38e4966bfe14f47dc6862ff", + "0124889ae0b740f6ab55c65650109e11", + "019011bbb2bc4763b47b95ef18b09abb", + "562fb778e7764dd1a1ec254a823546c7", + "32c84725859042cea7bb532cdab3cd57", + "a4a078e0ce9d48d5bf11218bc22c2306", + "cae4c557c949470697a86975ef9fdbc6", + "b82700b70be14aeeb5514ab92fdf676a", + "7b38959fcec2434792fcead2ad3dc767", + "6080b7f9e1264520bc70478cfa952307", + "c3da86c19d3e4838a8c60492393be68a", + "9de9e07cf92e4ff888f4e26d636a5f9e", + "f19297379a494ab481a1ee882feb81a4", + "0305b7bf2650453d8aca2639b9a3c5ca", + "f935c127c11a4892aa004631e6b0ca9d", + "42cc7bcd3c8e48c8a5dec0bd36c18477", + "2265a6f058574a7388584b34d2d35f0e", + "3c2af16f558d438eb397940906f99495", + "2dd809a046d443a68daf28b50fb994f7", + "1318a647bda545748225594b90d10787", + "1ea3032768c043b7bf4ac0af158d30d3", + "131ecfb6c3ce4ee49752daf2837b211a", + "ce8af2be4fed46009a2116f0e8bd08dd", + "cd441e51fada4644a513e73d521a6f84", + "a6f2dbb501974c8eac4978fb4ee9cf36", + "a80cc0557213489395d6ff1fab0a1daf", + "4e4eb016da0e4b458d8ecbe57048243b", + "b3f2d2309afa4431bd2da501aea51592", + "862d6f0b3688471bb32f4bc95107ef4f", + "7b93e171b4914934aee65ac10d56d94e", + "117d56b0f6b94836b9cd750a9b23bcc7", + "1112a0dce84b41bda958351346de477b", + "012189cc00f24ae3a6197a31824dacaf", + "0dd0e116105e4daaad459d03f3d8de8e", + "434f381271f143c7a5a7175170d4f0a2", + "1f7154b30f7b4137a6c92d831db9d7cd", + "a7245b0f4a21492fbe8a5330c59590ad", + "e008a9b4cc1545a699157430ca7ee566", + "d3c4f7a1e0d6484a9b55cc7d8bd50108", + "f1f58518a9c2473693eb8913404efa66", + "ce926d5532834f1c810d09869e898645", + "3eddcd6921f34dac828db54ca9b6f318", + "3e428716bf6b45dcb993b6cd41bc3e27", + "2dfbd4806a6349b29012406e9dfb3b1d", + "419cd821cb6747509bb4a6528b21d4d0", + "6ce8e485da724a24ad63ff9047d78c21", + "5ebc68f521ce411587e7d359245c340e", + "79436d34fb2b471e8861fa9d002b082f", + "40d8a6d5ad4a4887a2ab93d782f5db99", + "402b8a20adc7476194d8608798866d65", + "6e2e0b63db5b4a6991511d97d5834e18", + "fae415aa8e9a488e8994f618f4f42c76", + "bdeedbaad80e41f19d6a50b17cbe7051", + "f9ae85ffd35e4873bd9e301afc8b478e", + "3637977058574834b9541618ca1a4d3a", + "23f75dd13d074f5ab08aa4f0db5fe648", + "8445d7c3a16d43d1837bc8a07ab82d0a", + "009e2eb4f0f44faa9fb79aead2717266", + "30eff37d79e7408c87cc0c8dcd9f5265", + "b09fe7d9503f41d4a77966c48a5db04a", + "1fff04f8715443f6a23455e54f2aeec4", + "9fc13419b7df453d8dadd1437381d390", + "decdb2c636e64a919f1f61c5e2636a93", + "0c8d6b4973a9486f841477e4530f8cac", + "e7cc557fd77744b79fc2cac3762aa6a3", + "b46f808500ff4800a6a8919ad49df7ef", + "1a4e4ce0d3aa460484bc43d705edb3a8", + "f1d8575a914348e49790930a314305b0", + "26225729dd4d469fb7370c344f432329", + "335c1625295544df98584bfb5c3664e4", + "922e0df32fc24a2a91d25871a515e0d4", + "de51106ea8284e0cbd3866931c9698e2", + "0680623e5d4d432fa1732446e609fb8d", + "24a09072987242458e2c1ec19915e32b", + "46ab1b12bcd34eb9b091720b1185c4e0", + "6d242c84dc12461192bf7a317ddd914d", + "a329c478088e4e47bdd26747f06da880", + "68cce42515f04a289071c2474f2b1652", + "7013da139fe14b70abf5742767110aa9", + "c077d30ffebc4e179a8f2a30caf4317c", + "3a97e7bf7c8e4717908c0bb764618de6", + "e9f40d803a874e84931192f09dedd58b", + "298915e461f84c1b93b9e61633076553", + "dc40632cb0e14460aa280df54d1332c4", + "206b724abdf2486db5e8556853274cb7", + "e46e40253e734c89954494525b23d787", + "9e58f18c064a48c18b60399b1b341a48", + "4fee7d4867b0467aabce9e07754afd8c", + "e6dd0a7668064728b2e34d71c7a994ac", + "1bc03832223943feb80c49ab7f4e0945", + "c5b20505715244fab8e171576d075fa5", + "63337087f4ef41c297e737ca96219b43", + "080bc55e978a43f6b969614c02335811", + "112e8e061c3a48f7961d54106132a023", + "fad9c3dd6e454831862e773a28a9538b", + "9764210006844040ac9b250eb382569e", + "bc6ab1edf3f846f491b84f9690bdedc1", + "a8a26f771d5845f092e71371a6e30566", + "1912014cf2da4dc8b1c7fda382206a36", + "19123e0abf254c4e9e14d1a6368c80ce", + "6178078a25644104943c4aafb698ddf2", + "9015ca554cb14c4982856012a219c977", + "78fe14d4e6f3431686142a9faa75af49", + "ac26a259f5b342b3bdf73782dcc35b46", + "20a41658fa284141815977b277a08520", + "cab3272b30354865bf7a650496401ff3", + "98d51bddaa724cedb1cde13483513063", + "3490c4f44bc3483b99ddff9be8b308e9", + "e5cd149f7ca34a94a2704500d4d1bcfc", + "4e87929f724d4083aaebb99a3db71cbd", + "1467f79dc22e46c49e68a688865e9f70", + "6bac0beae27748899ef260a8bac3e4a8", + "ef31d877ff6e4aa4af565cddadf7a4c8", + "8780501f7ac64cd0aba44717c1d88ca0", + "439b7bd439fe4bc59d8a569dbb61e2c6", + "550527f7563741ce9aa40b7c7d9add0b", + "f173eedc45904558824415d09646753e", + "583bbb9797d846dca6b5e3e68761b94e", + "edcdafc4b1184255855b6a1195772093", + "39aa6117594a4e29a93eb840e297df7b", + "8168ee85cf044d7ab0f7b5164da98460", + "52b7d1e80fa94a14af45cfc3b811714f", + "06ab35ed6b8a47ff9f572b5419026dad", + "384821bed6fe47b79fbb775b4f36cdb1", + "5437dd4787b14759a438bd5455b5510e", + "c573303be1f04e0c94cfa245c2f2ddcf", + "354c05cae07c42cd8ecf2b00373cc77b", + "70442fa7ab914e7e97cc2974ce47bb9d", + "56e42467f7924ab582985a60939d7ae9", + "a28333b1d3774af99a6c8e4c2854b171", + "807f6b034dac4f2880566520dd67c186", + "f2d34772149d46fbb9fc4f8ecb644e77", + "76b43343e280494aa581ca01a138f4c8", + "153cd8b6d4094e9c95a4c3addbeb118c", + "dfcbcf0b86244603bc3ee78a515260bc", + "5fa59e7ca42f407eb5cfc5721d337160", + "e802a0af37bc41978ca31ba845dbaab5", + "80617f1367e140b5978422f13d564ca8", + "af77f3a0ec684146a64ef0e5fcbc078f", + "51d1341516504500ba8ab3c807ff8930", + "a7ad27e61a914319ac9973b79f57cea9", + "f11e246f501e420d9fa6abfe394b94ff", + "8c094187ab104c83a5aa27454063c15a", + "94aa774a84db4d5481999145f4e5d0a0", + "0d152302aa7848ebb02ed8ac83733caa", + "d79500e7bc044c2092868539eb535e67", + "03c075bb284840b1bd3fb2a28c910f59", + "eb545fbd84fe442ab0706b8bf5be1bd1", + "c3e25bf4d6a64a698976e30bab8cb017", + "69994077fc894249b3c9dc4c0dcb87da", + "bc23e281a8fc43a3a59ec6fc92c1d855", + "09ac47c5927d4e40a05f23e6caa36931", + "7773a9d469f1497aa078ca07b137798c", + "5fd1a7dfa3924792bdf883d7ab330885", + "bc239ba8680749b1b5fa5911325e1994", + "4e2c181f9ed14dd7b7bf40dd7e871fe1", + "2c127277cfb94736b6c4051b61f9968c", + "5a8b5bdf2dba4adf99c37e630167794d", + "358186a9ae0f41999b97b75e5bf72ce8", + "9a191b1d1dcb447688e8485376a41b1b", + "902ad095fca94981b6156fa49a21e495", + "f0f438adb40a431d97e2891adcfb4ad8", + "1ff6072d65bc4ea0be5f8894f2001a0d", + "8710fd71b4dd4c49be6d54917756fbe0", + "e3fffdb1261f48858a1cc0f96e10e35e", + "a17de88a9464410fa2c8f550ab04749e", + "e5cf430d45434aa78516a3f64c940e41", + "eeed4086f6a64fd381dc37f86ab85a69", + "9770e5a091e94eee9636b5284f8d3e4f", + "8508e4d53ece455180428280cbdd7fe4", + "57958c14eeab409699f7907dc4760b9e", + "15827f3c56014bec9ed1f1aae25f8f09", + "469ef8fb47524bf692f286789fcb9bff", + "cb6f558c4dce469a824fa54537a6753a", + "869960324fa447f780aabd4dd3da418f", + "6dfd26d4c1ba4e26a9c3dc19c6bfbc85", + "af0e2e4f677d45aaa901dd355545f57e", + "87562962d47e48b28cc1b874fa46a47f", + "e0966dff6bc340959a87bc5c7dc448f0", + "2fc8e30ae72d4d968c44bf953312d62b", + "668b4362c7ca4f07a7e8740c886ef322", + "08f7f65edfea417b8ed9ca748381e507", + "310520c0d47044a9b6012a1d97a1ae97", + "c603a9922c6a4e77ab2306590f536ad6", + "3da0104169054829a2edc58f275ad978", + "b410c4820a99456ca2a1bd18887eb93a", + "11649d3c4d124bf29b41a59ca1903933", + "5bb40f883aa3456eb8bc42080f63ccb0", + "e04326a891f3407b9f84e4b8223ccf01", + "447e705daa514615b4d6dadab722e8e1", + "b565a618eb5c45c3bebde69870d207b4", + "c6473c98e21141399e10606b064febd0", + "a98efcce0b3244c1a22d7013aab9eeb8", + "5cdc4fc134e84a8d97fb2d3ffaf5c5fb", + "452b336b44174c8e8257eab5eaa8b674", + "7f501e1200434bd585f1dce0681edaea", + "bfa718fff3044541a3694863c3bf9c89", + "4d396a70a6b648b189cc65142e06ac99", + "20cf1856ba224a348f35be355814d61e", + "d0be290b8ddd46b689a53bf94c92cd0c", + "5809f034270947ecb32b597ed9e80afd", + "7f6e543144fd4bb59472d90442469363", + "33d13523ca594aebb62f4c87e400854b", + "e9af14841c0a490bbf63767c844bbe96", + "b00d3c3a63084436990cad484bf258ec", + "8eb56daa051f4a42a74900932180199c", + "f92f1a8a1f5f4f8ab955d4e7ea9398af", + "db49335b96b94c4da10892f09ff6ee0c", + "20e9d6a9a102490d87980caa099ab9c2", + "6c2aff20b3494faf8017ce2b909359e5", + "0c8b5bd7c7974b579665c0b67c169e50", + "9c2a1a27103d4398b3f5395ef3872c09", + "2c8311cb172241a9b25568b29e009907", + "dac86ad27610458789f973aeeeedffba", + "777e4e22b73d4c408b2b94845269c87b", + "5b19b3bb03ed4a0c846f208b708bf24c", + "9f1335d8cc9c4d14a5612abce5c836b3", + "ac6da28eadfb4b7cad9e4826a18b1a98", + "c6e25135475f4905862f79b05f890044", + "cd2bacdfe7124d68989b3b62089ab62c", + "24cd8c2a2e26402f8e1ea207658e9de3", + "19fe8076628c484486989dd8b490ce67", + "0579ddf52790473f99bbbcc4dd6b1a31", + "2d4d3d4f56d345bcaafdf60a5a19741f", + "347c6c706e1840efaf07a83b793b7885", + "a531156cab3e4d86a0385ffc0c0adab6", + "0918fd7ec53740c1944b122008ee0e77", + "3d7617c3c244417aa78393dc30928fbe", + "63797942d2674b6da5c94ce19672e6b6", + "841ac46c2932424f9609acd1c332159b", + "bcef01aedf2e4b1e9b9db10cb4eb9e76", + "0f3e4ae2e68f48feb459aa3c0c22805e", + "79882ac780dc4aff9a4904dbd74b485b", + "2dcf8ac0eae145eebf7ea780c9ee8b77", + "7a02a161c5e146acb2c75ddbfb0474d5", + "fd6a1f8c96da4d889cc99ef52dff5dab", + "66f9b6a5787d49c88b87bf01ba069a0e", + "d502bedd0f9c4642be06fe4f6a8083c2", + "f5461e046f6d42368ef22f36382195a3", + "0e222159668549fe893fbe9491596f21", + "b864380dfe96422e90f030203d110421", + "5c38957b0da84440b197c61b75cb9c2e", + "4328fe7e5c154c419161e2c18111ce52", + "35735db6d3ba4492844c562913a17c44", + "3daeaf6bf7a2454faaf1f97131bdb664", + "7c3eae14aab24d94afdd1a996d81d967", + "dcf23435c3d14370824e5b2802fc6bd3", + "5f7176a2ae284d6b99fc970c9d265c04", + "8ed403bae1394c62abcacf2a524d6ab3", + "9702c1f49821454a9a8ca8228793df38", + "d1b773dc943241d3b888b8a5dd1441e7", + "6153b4ce082d4ce08db452fde2ff55d7", + "9f57541be21c4a4d9cdc5e927bca4e5b", + "f4e0213b6591451c8d1d03d4983c796b", + "4f72eca722a740408258920b2449059a", + "0d26d3c8abea4be5839d8e4969984a1d", + "c5bd8cbfea19467ab10d6ed3b1a7310b", + "0295a6d5791a4285bb9923b9dcc60146", + "e89ce52cf2ce49ab834518045deafc06", + "2a86252f235744afa728a80add4f35a8", + "b06eba44b2e1466b933e3ee1c421df62", + "7ae05225fbb04e22871d9f3310d1daaa", + "9d655856f1194e6f984deb27a3fe2ecb", + "ed6a25f396a84d808977aa6d074d610e", + "47526b0806cc43dfb304e9cb10b3fdfb", + "f59fd41011bf4a699cc309681bc26f58", + "d42867abdf0a48dfa4f938addeef5178", + "bae775567d574635a9661f028776dd51", + "e8e5c483b3b846d5ab6ca512278176f4", + "59008114839b459e801b2833a24ba485", + "d596c9a34172459f84413dba6782512e", + "01c7785620d0449abacfb2b34e5dc4f1", + "a4dda5be59374f9eabc8185a43e88611", + "f8a101205c43481e86dd9f1f3970d1ef", + "858fd2535a9b4f4ebd69da6f958d0b21", + "452049761827436592b001b9094ae407", + "fe0ceb2b8037457baf986c871078fa42", + "258373b08ba740ed9feeca977af701b2", + "7ece828f9b704930b4497fc002682e9b", + "78fabfabfbb240528f63ee7609120f70", + "1b635b0ea6e8471a884694f95e48d945", + "21b53105b2634ef187a2228d34a7a497", + "1e2b4dc9efe348548b681a1fe0a1343b", + "d489864a70c14165bb526afe79895391", + "b2f3832446d64a499ab599c65b66a465", + "381f77e4fb844ebcb8494bbc32c8cb9f", + "c3603763da7c41359f58f7943bf06ab6", + "b47b487fbbf04c3fb0efd779184fc9f7", + "1bf49e047db04dabab8a1665e88af5e6", + "f2656927d6994722bd5a84d364928eb2", + "4b32888874f842dcbec22dafe33a3d19", + "c594e11c44e24b76974ccd454ebc173d", + "78b047730cd34d90a018d1976fc5d5ac", + "2a1d9a65ecc748559993dbb0d413d1cb", + "42724d46046e4bba8eec9880890dc45a", + "912f30a9ede4475fb65c2792a54bcda2", + "2445d248fcc54adaa9dfd01734d21947", + "b306d3d3e23a4eb2838e76fac3d7c097", + "0f116808d3194ca79255a0563eccf939", + "eafc4a3437bd46c086a32edb15178110", + "6b1c2ab367834ac18e6aaf90765dbbbd", + "e7f79ad5dc8f4caa97fe9fc037008fb2", + "81edb063ee4f4a4cb844b71894a85bf4", + "32cf33de834343caba3a160b7d26aee9", + "dd9986feaa144141b6c8cabc8cc7faa5", + "d611f44bc9ec4dd1bb8d74505453bfd5", + "9541e891a96444d4827360f3f6e1eba0", + "7838ed8612c5496095e78aff45970c1e", + "ba0ee410209040f8acd173188de0bc1e", + "424120a0c9e042889b09eac5095476b4", + "d97ed83921aa4e17a6bd89cba8a47d20", + "8d369bf078da4baea2abe89414accb55", + "2ed3994bc6ff4a0db53216e1cea171b2", + "455028add66d48e7ae391beda0a6dae6", + "d89adeb59f6f4f449c06284be12a9bcf", + "ecaa22bd52ee46b1bc56c8b366391b58", + "b03008f9c79143b7beebfd908d413371", + "1d381152ae61423d8bf493fd7ff00e74", + "fe43d109c4394cdb88e620a3c30fcd3d", + "a1f355ffea18473a99f04c3009ae48cb", + "3a4c4e3fd81241ec99e2a9dac838dc31", + "1eae55cd80e146be8993d31015804219", + "844b6231123c43cd858019422f5a4611", + "548be29c770a4b13b0e087a586d025f7", + "cebad57a254f4e7d978107064b6017ff", + "df9fa07ac2a644a2818c16a7b97cc5ba", + "f7374fc7f5554473b134d3b2d7aac0cf", + "d8230f06e9b74316a175e9b618947423", + "d622ab7c84f341628b6dd516ce39ccad", + "547548c8003a479a971727aace7d50bd", + "f4da8ee5b2dd4695978cfa14b33fb8d3", + "3906dcbdaebf421ab2a4143f474924c4", + "cb278948a28a440d8e26573bbc8483df", + "108e2769976840738db1515c6346f1a2", + "e693a7b4f7dc49a3aaee4048f986ed14", + "f05320715d3b4eca89b4bbc5fb8c3d39", + "3e1642e4f8ca44668131895223b245db", + "7d067512aadc42e1802e37a6a501689a", + "e202323db0264ef7b1bc278ff73bfed0", + "f5fcd9ab4e66440587c3f4af48eb6891", + "93cf76c6dc444a8fae3b1a06cac21ad5", + "76b11180241542babfcb9ed92cff558c", + "9af83288f33d4460a831228ce680f2ba", + "c1c39f39df7946149afe10b60b36eba5", + "f98b9b49be904dd0bc0af35564154542", + "c6e3348739f04e6fb21e76086e3ecd4c", + "03123c98faad46faa39cb7d5158624ce", + "682e2a90a8724b7fba42ea0a19c179c8", + "be29cfba5e4e481c97ad66f3b013589a", + "b5c3fa8c6fa04972b62a4bc69127908b", + "b14201002b5e4a22957819204be935d0", + "cab4992bbda440b187200749b5ec78ad", + "ebdafe6738cb4fcaa926cdd27eae74bc", + "0dda55d0d1c4483d9ac2c892f92483da", + "12ba786f8bea4abd958b1ef28417bd20", + "c4cd974ce4b34b229f8627b647a32250", + "1dfa6e3029084ba997892a176a2013ed", + "7e44cfac32754fe0a2ad096e42b45a6c", + "520b167619584f1ca14ada756e6b4981", + "05fc589d06964e5799152241d8308138", + "567058de5d2c47df8b77e9c45a5a95f6", + "201fb18d8cdf49039c8f06f958b22e7b", + "b14995995c10443cafbb8b5b790425b1", + "c8c896a1c0c44daeab7387a5f3e64922", + "28e028e981604aacb25766852aa279ed", + "2ec86fec565d4c329ca66fb36c840111", + "f467b90c58bc489f97326bf6639cd427", + "294155db077b4574acc066438141b37f", + "2555ca0bda09497d9caf277c1d9e228e", + "08c963100b6b466f9613c61925284f4c", + "6d656faa5a1d4309a43cb5763cba002f", + "16146eed0026466684d50b336e9fd29b", + "46e64593c4234183b3b00391fc960415", + "5cd91fc557c642e58d74bd4120534aab", + "6890f5b34af947f4b416a23cbd4e56c0", + "20e79a93f1a445a7affb64e7055c03c1", + "97667fc6211849609d5f8f589765e3ac", + "166b1129bd774641a148f999528d4e23", + "a6a5f605426840bf9c9428c8f5f405d2", + "1681865c1a414f3f8c473a4e47774571", + "83ab10bfb21b4739ae0fe2edb9e13707", + "e99b422437c64cd08ee8c3293733be2b", + "ac47df697aee4834a2b3ff24c83eb180", + "f9a01be31553463d958a46e69211fa48", + "ae52f5f6241b4759b9cbe48226a9db48", + "729c3921025f4e2297a2068b9d21a1a8", + "baeeca4fa2954a94876ffcfb7918e7f7", + "8c42ea688b5f45e3885c43bfb82ba1bf", + "64c0cd8ce5e141738a4969787bd6a1e7", + "77fd2ab363644e59bb93325837c61d8d", + "817ba23d2e34484fb1cb3c59f055cf23", + "de7ac4d62c054baa9ccec734f6a8c093", + "ebf7be4822a64ff88302079df70e2c9c", + "7addc22abd13432291d98f1c3187ade0", + "caa065b78eb34f1b9f5fd400c9fe32c7", + "87a67cae04bf4f2b9ac11005c09b77bb", + "a62fab23515b4c12998ab3f89c2d119e", + "0ca8b71cd0e742fc907b7f336b119954", + "a0190c099edb4c378f0b3f8779ab3702", + "64958f22e6e64a99b707241677753f46", + "9e769751ac3a4b6a893a5719349b78ca", + "5d7ba0f7cebb4f958aeeac274d4137e6", + "faef1d8061c34cf6bd8e0f2a508d1d69", + "18c9781b883846fc9eaab6b2cfa8a654", + "7060b83978f340f8af1230bd487df200", + "658e9ea4a55d41d28085417949b58064", + "3cab4c95c8384996933e7a1ff7b9839c", + "e3b24e018ebc42769c08819669ad03df", + "a96241f8fbcf400d92eb7ea4aaaa37c6", + "f4f34692c8af4a56a4c7bcbdc780d9f6", + "a9f09f7bf2ea41b9a969bd32cc41e5c7", + "3aaad2ff33c04eaeb54fdea68cad8c90", + "423a05e278474daa81019e6099082a77", + "59e0754be98f44539e842fb26d43acb4", + "85e13761e92345418f83d11a23157faa", + "f40b694f9a874f5fa382e0a1ae37086b", + "6ff126b9453a44dea9125c14aa766a2e", + "eac715e9aa034efd9f7ef3a584503041", + "ce07bc73ca66435680e227767725f3f8", + "18a474c6ab0842b09e3f6734ab551174", + "c2644b133b554bc084e83d1217663918", + "5755066cd3804f76b118166598b2b249", + "792295f9b1c347a09d776edab55f997e", + "64f14b1d4edb43258bb3104f4424813e", + "1b501d0e024c4ac0a44eae8a39e04d3f", + "582cb4dcceb94d8ab71096f1ac8f5329", + "5ab093ab190d4a85858e9366a6e41b85", + "016e93bac3c94a9fa78caf9630553b6b", + "81acc3b3e79c44188dca5d781f37df84", + "d586a1c1311a4e7eb204fd9c994f885d", + "a9be812bb15f4dc1944a4d2add0c909e", + "1e31404f5c7246fcb99d53884dd52503", + "cfcca1f4244d4318854f1a5b7e6bf758", + "a3e0e0686dd841d18cd5ebd013282548", + "07dd49275fc84617b5c6d3bd6a7d30a1", + "6d771706055241f281460006ee4f5a76", + "b9542cec56394930be21b61f1df030dd", + "94cbef1b098745679ce76b4fe70048cc", + "860e1d94bdf64f2f98adfecfab845242", + "9b3c791b3b9c462a9604fa866d503cc0", + "be4412de9f684767ad5859d851e5a255", + "e55ce2838c6b4ae49149586af72124fb", + "14791efb33314b02ac5ac74b47c36d14", + "575b69e4b20847bf9a59c10345cacc65", + "94bcd912320747f7806132d936e47ea8", + "093e3c0c786c469f9519d7944d062d8e", + "6e86eb006f854c83bed8f5071c2da4ec", + "f0a6f98137364c0ca5b95880d8c32b0d", + "170e195979d54b4fb4a084d3448b57ea", + "57185ae95254443c937b69de5c22af97", + "6b1414ded37c4fbab40e4b47a9912ed2", + "a7540fdc98a144a8a6b1521137baf455", + "e5b9efefd9a442d0a478996453a15a36", + "00a776f578304cce8c096fc0034582ef", + "dc8185e4e21747fb8b394e40d3ec125a", + "c4ea42b0c5b745fb83d095281df54a5d", + "4c1bf808ae8246438d743928ad0a16b8", + "7cd94bedd3354660a56fcd2b7380769d", + "2e40742ec0c44cbb80f8d3ac27355cea", + "169fd08a58b749d4ac43446689fbd288", + "e443d31dc4de49e683f1674bdca468c1", + "f0a4fb1eeaeb4c48acb50b54b7df5ce5", + "fc1d01c96aeb48e48e4b9048f4a811a5", + "be72af61c3314b539500b16371fe7184", + "c6694b9cafe74e7ba46f5612a3e9a7f0", + "38cc23735d584a6cadef7ba92d76473b", + "ea1acc7b83674dad8e89f16442b1522b", + "7973ca7b0f4b40d1b6aa62473980643e", + "98bf659f134e4039b0f0187d1395adbe", + "9e587f95696e4830bd1e9149f76f919b", + "5ec36e995dd94222a1fd26b112b65cd2", + "01a3363ff6d141fda8f8a329ffde153b", + "b084b9ed0a104b59b3ff4ed6e9ed0593", + "061241020d7c42deacdd6b9ec5073c0c", + "6e3a46b6ae5f451ea8e629dd55efdd67", + "c432ff776fa44b33a00100cfa8ba4df9", + "dee8c21951e14a47b8985dc8718f222b", + "804d7baa4f69496dbebc08e74753b977", + "9820c165e450447b8b3d5060b3f5194e", + "23ee8c55da7143d59f1e0aad1b20be8a", + "2070a8deb23c4df39c9c5bfd63345135", + "ef49dbd0632143a38d3a200c8a73a844", + "3258c42b472a42a29f07a9ada311c8bb", + "67f4626c68074ca68568cdf29da47192", + "8ae346eae2ea48858ad3ec3265f0b3f2", + "d3e8e9667a144e9aa11b0713b7b321ca", + "c3951fb6b4384ddb8b90781a24c89e51", + "ebb890feb03e4053b93dfd3dbad8089b", + "b5d4e86964954a7d988ab1fb601aca91", + "a175d9593e764b259d690221771c5011", + "f810cc698a8842acbafb401d09540751", + "a98feaf5731b48feb0434896a94fdc4e", + "2cc2b656d2124c2db990ab15425753bd", + "00a1a602456f4eb188b522d7ef19e81b", + "9024c86d9f474db6b379ca02932d1d5d", + "19ef6ee8569747cd93833fdd3abe140b", + "12eea4405f164c569b883e4c2e61f782", + "c512d5c1d036418ab2d173ba0f8f3ac3", + "0a98459ea48546b480eaa3c80f8bc748", + "f82264218618431d81b8a280076a786e", + "a1fb239134d7477abec3563403f8585b", + "8d2e470595b3459ab57ff8b717a7679d", + "dcddd50460ce4d1295733d32369683a6", + "10e85386efc1421595f07c7a4453d45e", + "ec82ac312c014bb2bdc5f17eddb96318", + "19ea6f600fe346cf9baacabebc644fad", + "49ba72b1c2bc4f40bb30fc42d6db4cec", + "6f84da06d7294d53bad576a02abd9c57", + "68a23aa70dc84a9a8d27f902a9b3b5e4", + "7ef6dd0bdcc145609dbe4f71ea91fd75", + "08ee2c09286844ed9abf84e5bfef9b3e", + "a4f65b9be66740dc85b1e78ce4a1919c", + "3127160fd6f540c6a9a53956dc467889", + "e72d01dd310a4e3ea7ffbe2e9a74b9d9", + "db6bed238e6f49c498c1e6e0c2d06224", + "33b2debd464f465b917736873680a050", + "9d65ca34fa3d432b9372c9cdb60a9a00", + "0a61021cae7e44208585d4c738904aca", + "ac1c4e8ddb334d0fbd464fe8370e5aa9", + "dd46240daf1f49e78016b12ebbe4e890", + "a73f4d393a0e4b86a582c5c8088bd313", + "ddfbadbed0db451c84185fa37c1d5e97", + "b9b2d4d05d1d4c039245cb216d07f5a7", + "5c93f6a79ee447c28ec421258612a254", + "c280c9bf4a3f479990879a8fdaf71b87", + "376d2b81ec9643d49c82f6bdac2488f9", + "d5aa77e6835a44bb90a28cbd5ea64249", + "ec1b8dc0b1d545a0a1eb2abe5faaca3d", + "f6974311272b46598b316a1065098661", + "cba0908a220c4703b65fba6d094e11f3", + "829dc1d22b58409cab0165c57955b7cd", + "2e5f007e3e1547598c75f0c399e9970a", + "edc08a44ec3a489da7850b1af2a37580", + "b489f06859f440a7a6506c58e5b2e149", + "c30c7e5fe17f48dea888d2f76b7b7b3e", + "65063e71454340f0a9058467258572b2", + "03b1b6703610447584b5eccb0b56ef7e", + "1d05951d994e4ba58247613cfa118abf", + "6d7a838d4885498c8b38f7c2cab03e86", + "17687db0dc1e434f9cba6d5aa71cd030", + "35a4d3eec65d45d3b6c971b187b4c55d", + "8e7e458f80434b87961d563143f2baf4", + "61ffc885367b4b418b6975d138d94048", + "5405ef962b9447a99dc35c98e28fad41", + "699da984a54c4bb7be431f11388e2048", + "0b0a1a9146214d09b6840773c1da173b", + "92af54ca2fc54f65bde19954bbfdb3dc", + "1b6bd188c0d149339ce618780bca9b6a", + "c7c98d92757d425f967e6e406589b46e", + "09966d101d75410e8341c0a04155a957", + "059e76a35fb94c08b0b4b940f934d331", + "17cf0dbe4435434eb6e04394fd5bf7ae", + "f6e9ec5953854dff94176c36b877c519", + "0fc4281624ec4fdfa8cb8476b6b939bb", + "752f4c1f4ea843bba5d29104f76d3f81", + "7599248afdfe49c3ab07691b658ba857", + "f2a69ec3fd4845e8a91b067e8ec5c186", + "5e0d899bfed9431b8c1e59b9b541dc90", + "c6af148edcb04a2db207e08a179e40a9", + "b37929fe34f74ea5af022dfece52fdeb", + "ddb421fe378e41b1bdf848a47093ca48", + "a02ac7fa63c346c8adb9f647c895a821", + "0d5b389e1db142b39dfc1794d75a54e9", + "8fda709c6b2646a49f884d130c0c86da", + "8ac3640fb8e348a4b468527964a05e78", + "7bae9eb1d0664018b4d2bbbd96ba80f3", + "82e1735729fe4ae4a4e84129f256d674", + "e6ba0472f3e548bc8273674f73a51a3a", + "11c0327617354389ad923c0c77495ef2", + "0b5484e92d7940abb2bde1b4aaff8d9c", + "301a6b7a8bc2487fa5e10465b46b3184", + "9c7a2dd5503943b2bdfd0b612848ba9f", + "bbe7d1ce209942568387cf243fc08c3d", + "95fdfc08d9d14fe4a31f2e5f4d7d6b33", + "91903199dee5422484d0aa2ea266dd09", + "d395532c07d347f9b5cf6544aaf96c56", + "81e6de082e364b6985346657c9b2a096", + "69b219bbef914153a60a00fa6379732d", + "f060379cd25d42f398a96824c503307e", + "c8940dc63ea5480f830440d696a72f18", + "68f6b60c7cf94fd4af27ebcef371a86c", + "639a0f42e3a6400999ec884356bcc0c7", + "81d1252d7eb141d3b62ed47a779b508e", + "ad43e7cb927c4c2ab9951bae44f5d1f4", + "924e37086e964a459ffafbc9e11ef5cb", + "2bb198ea4f0b4b08b81d8092d38df7e6", + "b87f88bf555a4492bbd0aeaf494f26cf", + "329ca55506c74283ac7f6bc9dc5e1015", + "4a1c8d3f9ef24eeb8c4808b68f953c80", + "4dff23e7a6d04f53a3dff42fd319e181", + "ce4929c6ab96465a929ddaecf762b6ae", + "4cce081cd8034b1d80f1fd85680d176d", + "f0f04ab6f7274cfd82d95fb345e19c51", + "92382dcc01774696a70b2d1e7888a25b", + "d52fe68029fa44cc9367da6eb227b007", + "665807dffceb41ce8f861db2c654e7a8", + "c3102b14a15d4dd896f5ace117a422a3", + "1e04e9d2bed3410e8569c5051913b354", + "f3994fe7c36948fb8cf5835e571b14f2", + "4c308142b6e146e892582b9c6025a92d", + "2ecc060e9a3c4615971a07aa4ead359a", + "d763a898b3584084b785badc123b8e2d", + "610e117860ed43d4bb0dbca1099eecdb", + "3c2a955704fc485fbe104b76a3806b9f", + "8372b6f98c324552a2372847c9d11c68", + "22bed08d490f454aaa6f29ae62241f4f", + "d418af94493e47fbbc8fe17cf65b46fd", + "12652c6e0aaf44dda32aab816f433baf", + "3f8645b0da054c258a11e6a0db8a66ad", + "fafa250459a046dcba06308b2e8f8a7d", + "537fcb235511433a8a53939473bb5d60", + "7c3bcfc6b9dd4dbaa9cd888701f36c0b", + "f14c4b1f3d64426e89cf7f211f808b10", + "2c4dec67e0344109a285f3a4cb17f9aa", + "bc03af64a3cb4af38771607b284e1ff9", + "78ad7f3c56a8425db589bc10f0b2f70a", + "de05cc497565470089d49299ce1bbabc", + "946db96fc4c34d3691ba542501448caa", + "550db344f7674d81be9d49e550f668ba", + "72174e0ccc1446bb939661a694a6ae19", + "48864fdf167643e09be7a49cba4b9065", + "15a06d5b503c44209aab85d579f422d0", + "e3774ca0bdae459082f3bed37fa7260c", + "bfb029c7cd044080ac85ee3508a68246", + "a340314ddf6c45d695422764579b152d", + "319ee0cc94e3486db3a14cc23d1039f7", + "192f5fd242b146b8bad547518029137f", + "9fcd653f689f4729a4da45e10f8b06c2", + "efb9d1c5fb274efca2c91c03e2791347", + "c11e010dc7aa4670aa952f0ff8ec59d9", + "89672d75840a47108eaf47f61acce046", + "fc83afdce3414c9a8aecde854d4f3c78", + "6ab6d67d66f64b68bd42559dae707d3e", + "695de15b8fc2448fbb599a35e5384605", + "39926e9feabf415ba64e9898ee68c476", + "801dfed0f3b04d619fa8cfdad756aeff", + "959fc18f5a1e40c6abe3b33fc3e3cfd5", + "ca0f91b3044e4f0ea315ae9ba64b49d9", + "f10f55ac03ca4cb28f641ae50fd513db", + "c3e501df5a024d9299cb34c3aaf51e2c", + "647133311005487c865cc33423c45b67", + "b650d390186d4524b93f5fedf2e5067b", + "eab21bf368fa4abcaf1b01c5abc4d8ea", + "237e58299e06470e8d1b49bfbf6e3bcc", + "40bc83637be642d19668e0fe856b2ae0", + "cf95ee01636443a2b5c47b6af8a84a68", + "e2edd31463a64db19cd17db50776bd67", + "9aecdbb725e84a1ab77642aa7767b383", + "60992edb4e2640b2871353156cd04d7b", + "97ee5b77987b47d79e474d0668dabe54", + "aa4b8ab41c3544edb4d9e32d80a8b599", + "4996b045c7924ac69c2a1dbc395517be", + "5ae174f9d26f40b99eebe3427153438f", + "c83c09f67dd64617b816ae4053ca0be1", + "8c39da73ffdd40caae46e45779aa74e9", + "0e61ed2494314d80a1ce1bfb3d64d304", + "105c17e25d7a403e831764ac8f91a916", + "5822d8d5d7c542368bbfad252b0c26cb", + "3b3c48751a3d423f80585d38c55b3f97", + "c0d363d197ba450fbef08224d3edd3ee", + "07f3c0290fb040bc9e31ec894e50b1dc", + "d1b8914c07514268b8d4111fc8de89ca", + "325ca51ea1254529af04305919a580ef", + "8a33c0bd94b34d99a125f4c23c6da524", + "50fe48f14baf49f6b03a317ec409f925", + "6a3f6f5c3781452684d25e80d8c03d04", + "a2c7c8916c234d2aaca58423fef01c5b", + "e23d79c1014a431bb913d15fc395b4f0", + "18a27b0e326644a0b47887d07e0d0f99", + "77a7f180a4b449e1bf7a47837b5f3def", + "5445555e0b844a16928c1cd114969d1c", + "e8241c085a6841ef85ee6671c4c0bc5d", + "d838fc2535c64927a817da5a84d83a2a", + "2a5a1160fa2e47a5b193014e54977702", + "0c6981ec2067481cae6d87c2021f6442", + "187e234b63ae4d9f84f49af9b6045db6", + "a9f69f227aeb4c96ad39af40df732428", + "d9943c3a36a24070a5e87a1b8750812e", + "6878ca05f50147b0ae43217b66cea764", + "0fa9786e50a84b0481e5f436db794d89", + "ca9e7bd924844a9cb0fadf0ca7c62dac", + "b6eaf57de8f14b97b876bea2935d86b1", + "5b415d529c774c01aee94eb09d86c00a", + "81b1724799d64da597eb9b312078996f", + "dea7d3e83a2c40e9a1a567d543f69444", + "b24c917246ee420aad3262b03db38ea7", + "40903b09601c4e15b97f8e43ca42d449", + "acd11b98bf5f47309af91b913912c26c", + "1bb71bf5ed9b4255af7f71d8b8d18275", + "33d1ec20564b47b6b9ad363a6de06a2f", + "ee8294efa6344586a41efb8a8e05d88a", + "a857f59bacc247728ad6d5ea1c3be736", + "fd7bae76dffe41bcb6ebdebeab67293d", + "5b177a1cf63d473c90271308fc961970", + "995ac5d09d944d31ac587f0f90e36ca2", + "00ad7478cf0447f3b3494c00e7037177", + "abd0fde38a494cd7831df8438a8ff610", + "a835947bdb514fe29446aad5bf223973", + "13407a0758804fc09ec4c7e51e9f9d0e", + "9033159bd5ad4737b75d6a81f0a8301b", + "acfa52dc286041f1aef53634829583d1", + "7c2a12eee81f4e81a3399f7777b427e4", + "0db215f28ef94747bd44871cf08f3d9d", + "eed34f04c238471488d8209da3896e0a", + "2aa14447ba0449988255ca240d25109c", + "5fd5dd9fe5854161aba5c65d8866b039", + "834eb24ec474482db9a1725cc9fd6dd1", + "21d1679f7d7449bc8d38da537cbaf72d", + "c4c8ee02e74b4a1a825da6daedfb6a4c", + "fdc3e88a736a4bba9baf9ac273a90ad7", + "03a5f54034b64995bcce6291b35bff71", + "f8a63f7abd7141b88488f2db3523de27", + "ab1bfb776bff461986f8762efb6b1647", + "7e7e31fd7cc8478297ff8e74dcb9cbf7", + "b31993aa548d4cb388848acf3ab43980", + "9a9ef9dbd7294d439d329c33484128ef", + "01ec7658fef64e18b69d68cf8b06548b", + "fa0a1b14ea0b43b580c55e5d2478f9ce", + "e5abc2ece9ae4a80a047e7a7c5173a0c", + "8a44869c542347fd8616463c74e0bb59", + "0feefa2d18374ecb91d3eba92747b4c4", + "9c32eabef3954f488427d71a8f49c583", + "56e227eef06048c593ed904a0cbe291e", + "23d3b25d47f74d7d9a96ee542914f281", + "54a58ee03b2747529a3079226763c1e4", + "032ccef2632146c59f1db8f55d3ba88b", + "5bf10f720fb14a1d875dd7118b3714d4", + "51b6a3efaed14a438a081bc69abc3398", + "5443d2042c7b4b86a1cc736ee6869da5", + "a6cf4260ee8149938707d3946b7555ee", + "8042498e80fc4a9282c44c4da4c30141", + "fd6a48cc80194eb3839cca1975cf3f06", + "760799da34734f43bd03457fbde8764b", + "398bd68323674532a8dc963bda9584be", + "d044c7495830494fbb9d35e2373173b8", + "1c7c95b52b704129bb0ccd613faad9e3", + "f2d30a742e3243b5b702512246376ee8", + "642ba4ea8c9e4c50adcc09f9a7462514", + "f5b6d7e24df74963ac0af09c1f435143", + "48ddd91aa4f44321867d9d991b77699e", + "51e296a3daf84b17b9541528358eda39", + "9507e87b71fe4092a8531e146c503f85", + "ad0a9385e5524d9bbc6b73ef5ca576c8", + "ba8557c211ef42cc81aeb1103110c422", + "200a6976e0a94c1f9c2ec4f64e0f3272", + "0b700c7689024b7da9ee70ed1104041a", + "af8a1b8b0a76485b934160bfa2393ae8", + "c2a3f2ab906c41488b64c368e8049bc3", + "1d1906bee46842c997e56ae1317d8387", + "f4bcc7b47a8a4285a1066a7ac8a3dd2a", + "05757a473c5d4bc69a6315fb1b31371d", + "fba6b5a8afdd4eb0a43be29aabceb3d6", + "27827636f0a54440b7223f792bd8306b", + "78331d5e09f1445994c0ce4e2c8a53c7", + "a293300d25724ff682f600f44d4620c8", + "d6059ba4a645470894f6996dfa778ffc", + "420b54e055f445c6a988296c9d2cb0d8", + "3a07d98bd1c74dc7966345c53de7f725", + "1e21fe13256547eeb5cd4d89255ad09f", + "1fdc84a7be2c4348b281490c89d76062", + "91685a40fb0b4c63bcc751d8859e5ff0", + "8327cf2e178f4014877d4c6e64b1b73e", + "392a6ba320564797a66f519de0426dd2", + "2f64382e6c664df99b0aa2ca55c760cc", + "2ec1ab458bcd4ea59236bb58bc3707dd", + "f0415214a46141bead9aa8316f68d095", + "496acb4c1d10446baa3b01183fd329a2", + "063b4b0102214272b572be91ea464cad", + "7477b6432d924c2a8243cc7f5eb0d8b5", + "f91e012840494cb1b60fe511f95716a2", + "0b9929633fd5458c8f234eb9d415ac06", + "cdd3f8ac36ef46d8871d1b0e217f7729", + "20aef99255c447d0b55a4c073b447b33", + "6be9de75c7724f28b68d43871e37d6e5", + "b0bb8b1ab0e54270a0696e581b20d80e", + "5bca086ba85f4a31b56762ef1947a0af", + "3535fb4ac14e42da8ac71ee05a594167", + "07bbf4c6cb8e4ea59a9afadae21f82cf", + "c532273884b0455b8e65664bbb91f4c4", + "af09472376fe4fdba06d99ea535c7b57", + "6df08ef8a8504504911ef520cd870aa8", + "68cbb104126543f285191b6dd60bd564", + "4568bee1f3c64645a3ef497fe0c4b30c", + "7527129b42ec4f47b070b0f91dbb1f57", + "78bcc90112894c3f8436fa9bf76ce14e", + "b798d07afb134d0a84f647cdbcc58cee", + "efd707e70a8a48e4b777664d6627b190", + "99d333e3b4e4470a8d7d38436489c001", + "b3c309beb89d4188b68aad324f60b338", + "47f357729c5748b88aa3dfdbc9babd88", + "85b4b4f0a6ed4277a4ab33a50a1b66a3", + "b0d5784d220a4c0cb209fc72ecd8434f", + "cd8d9960db854042ad1e26408c58ac47", + "1004dc38dd2043a39381f1b343c2e717", + "95b89115dac740fab8bb13c2c51e732d", + "c141e600831f47768acb5fe5a585218e", + "674770a31f6340fa9a459c66a473c328", + "c0353ae3304e499891ad57b5d5dc5f08", + "a8fa5df505e64cbc8aba20ed1ac6c6dc", + "330287dc3a334d6b934a72274f277c71", + "94555fb8cf9e42ab8d514d102899ac6b", + "be0b7e93e66a4d4c84c2d0a13fe1852a", + "997e3950b4c24f0d98efe963b5076203", + "587550c8960d46bcb1a5e4e3723fcdc1", + "831e51aa43424c64a9d13501c60c0c10", + "5c8f46b1ebc546028556d620026139e2", + "7f943c50ad4f4b3fbbf3c2e1283523f1", + "1aa185f5571143cfb8e2da15296a9958", + "641e8a73066041339d82539860fd5c29", + "085df0233ce345438f4147e448cb0dda", + "d0b5aa164d44429b95e2e91901b7e4cc", + "5493b40fb6744ebe9e5e05feead9b79a", + "411c164757fc4de68dfecb35fa858223", + "ba963019f4c14344b922c1cb1d24e0a3", + "c056df51fcab48cb8aae366b178c9537", + "907f998c388043779ce5a66096cb6882", + "39969b5d66fc420da0367d7c17cc3f09", + "a64c5648417a43d7968033602409bad8", + "00d835ea93204b64bd3acbc80945eb12", + "c084108185384160b10acbabf4607c49", + "04b13a5595fc467c8e693ccefb18de34", + "74f4aa5c5a9a40d1bc3d7e11820cd66c", + "73d29b4876954fd5a4a9c4a7a1523ace", + "eaa63cc2a3124501b7221dc667f22375", + "fdea2fed3b9e40a0a339e30fa6e7c675", + "4911919955ff4f788b60950e64c0a61f", + "1487f1a5d5ad446d8ed3095bf956d25c", + "a10c86c6ec7840cd89e3c2b9642a03a6", + "73622641d52648df8bdef5da81f6f4bc", + "af90a3acd4af40a2bab4ff1f923d948a", + "422cb41968af4a3998dd84fe3e26858d", + "0ca879cd17b444b2914c1b9ffd55ba03", + "0b2e66c4acf649ebacea1e15c77e3b59", + "a65122a7523d473e864daa045193e8af", + "f44a1c6538684c94b128e23c8a775ca9", + "52c6db9c2f924352a9d35c2cdc881cde", + "4db0ba558ebf4978ae925ca4b1cf9477", + "107eee5085634f86b8d362f6b5674687", + "f7b3464817774d54822c58cfe354c477", + "c440d78639b74e77ba6ae375f9cbf5b7", + "72ce292e1bd945aea580d223c75a870e", + "111b45e33a8d4e39b1f37f269e8a2069", + "bf5e6c6adf3346fe9b8425be4e200c26", + "c55776fd11fa49cab1a42459f4b29b73", + "e1745c4aa7c046a2b5193d2d23be0192", + "555c83201bc2415e8e758f154eb406e3", + "8e97b62a90f44ce19ea9e3fd421f55b4", + "508f23aaa6d7469996aace1463d9653d", + "d15b90299cff493e81ae29ca525a9b2a", + "90acd78096bb48e4ab97a2eea4139bed", + "82b7427f7779422c9451efc13130e997", + "f7848ac0804d461f9493a87b412bc011", + "51e76c3ee31149a7916d2ad37cc5ba7c", + "9c32479be0f440609fd96a83e8033c97", + "0ea9b956131c444898d830b18df9eab1", + "c9ed593f8752403396734c06f3fb1425", + "f2164204caca40a898b3366b17b0fc8e", + "879a32a914cf4f848477819965871d87", + "9fe9aa14a96d4f5f8e833992ca38c1e2", + "70d7a6a685d04ce7ace7092b2461e1fa", + "d731903082f446f49a66895676a26a09", + "22477916bcfa42b7a03daaf6085e5755", + "481c76e1424148e6991b6f8488dfb637", + "8a27f42a0b1646d6b210db9ab668c54f", + "20a235aa7a804d3694b8953839db579f", + "d149e60429574bacab6815132824c59b", + "66222f22998a42bcb86ae9b487f642a6", + "9f30d360cee343efb5a441978ddb57bd", + "05f8a0dbdd374d37b97f72f4176607e3", + "0f2592d5a67f41469a3b79e8cfa14ab3", + "59575e7bf8b74f4d8b3d38e26b34b603", + "eea8846fdeec47e0a218d7778513a74b", + "bf6700a3203e4bb9a544c3f04b81c244", + "d60b3975007c42fcbd95bdae39539557", + "abfc7ac218264566a82ba5e5fb30a351", + "d69b7576f7ff4ef3a987dfbb59139cb4", + "ada3335b784c4f3182217c0362906193", + "19487b5c0f9d474e815a2f6e78960840", + "10ff59eb67a84619ab019d98e24198a4", + "6da418c06b52440ea632a766a7489ba5", + "8f905d9289a14a31a0a7a75214e5f142", + "7ea84bb92fb144249cc7ef20704c7f81", + "7e61094b068046e0b4e2da4135961896", + "74bb3999f04242d89c53d01d90e50720", + "1beb5cc59f734f24a3800a1888f529f0", + "d9947bedcdce4cf084f4a79abe2e4bed", + "c0c9df3ffa4348fb8372e081be3dca23", + "d97b45b870374d568d24d4d879e3ac14", + "b58d68059c3c41bb836786df97b6f5f1", + "4b67b1d642b442e5b10114930cb90690", + "779672af032141b1ba56ac0586f941fe", + "70805454ab3b42619d38c7e662dcdc96", + "32edacf73ab9492a92afc69333f84e3e", + "a5933d4069414f76bf3e6f8135db7bbe", + "c2491d01807640a48a893207528f65ee", + "7584fa7413924f3593b037248fb2c4ec", + "74c1ec968a194981b093e1f8d293b035", + "cdad3f76bdbb49d29c120cb251970742", + "bb34ef5d5eb641de973a88d5ea5bca66", + "ab1eca756f4441f09c940196e1e82ae4", + "ac5df73de2c54239833643423a152592", + "8c63e5e160064cd3862e4b5f8781032b", + "3cc4f9e7e4a4492082430d1bb117b0c3", + "79e0499328ca420783c8c98695732930", + "a2058b6bbbbf46d7bf4811785febb669", + "60db48dfe11542739b8f3ada96fd6122", + "8a4ed17bb63847069191aa254f3331da", + "3023e02145cc48e88d2f7d792177634a", + "54c0f25088fb4e56a493496e490cfe5b", + "9d6d2da350644d779d429ebb17a49efb", + "1ddc37a27a0a4fd3ab14213c9fc7efe9", + "67125d725ff94a9bb5b368b7904f8d79", + "a261df98b73740aeb8b93caed543f730", + "a8cd96438a584ce3b697d08615634a5b", + "a1a159f78d284cbd92754465f03f21ad", + "f349f85cc4624ac1ac1b97062cf6bf77", + "c1b9ddfaa9474c9abb38f46a007ac63f", + "991534dfd6cf43d4a3b3637aa3ff8c8d", + "026ac7369717440aaab3012d9afe4bf1", + "9cf6f4bf55514f09b807d8a08609f26b", + "e14796f079ce4c6e82532e1ca3aee28f", + "20880b3810a7458e8e5257f249ccb65b", + "2701f53b0b1e4b7bac6e551050bcdcba", + "20ccfe3985ca411da08f8e0021cd0f18", + "fec95c6bb8b546be95c62aa7dfe01c1a", + "6c9393683031449cb884445e6751095b", + "f25b9a40828c4508900e1d26aa9a88c7", + "a44ee197b3524aa58f54898759940822", + "282ddabad0884bff81c17bc6ef69253e", + "e2a276b24dd948e9bee80d6fa65cc0b2", + "ba34ae6d766048a18b234580a515fad0", + "119d5abe285545559f2a8b25760f7354", + "c8d49edb266c47779ff34b1bfe9e3518", + "5b667e6797ba406a83d9440fb58468e1", + "3c4c8c2408fc4ed5b00d3f8f2f290fb6", + "478a1bf5c9a94dae9dff338fd5dad148", + "6f97ec6e83b04fdfb973820d725dd2aa", + "2e83bc092a7e4dba9c7eac30243ecb19", + "f5dfd5cf4a9c436cb03b2132e0f9a44d", + "83f93bd4697a41d887006f8310cd67fa", + "13aa3e52b28d42e7b3ff966003ee8ecf", + "8efa91b9b83249feadb49787c1a35e80", + "8841b809f2124606975f504f4f52a9df", + "ed8d17407c75443d8ad6eb4045cfafa4", + "a21b0397dc3e4a60883bd03527070264", + "f89e397029064849be915b087f7745ef", + "43f463875a7c44a6ac6862dd10e82e2b", + "30792308605146eb8603e17f913b1ba6", + "a6995104b99c4399a20bc4e0031fbf8b", + "cad29468e5b04ebc8e4703496a051d9f", + "308ce9ac88904d128dc3fddb440af712", + "b577ef44d92342ef8df8f01c926db0db", + "59949b80aefe4a41a71afd16a0cbe67f", + "45179aa65dfa4e3983f34bd403c9b528", + "e70078010e124ee89426dec56ed34886", + "c8990092ef234f5799c377464eb8fe56", + "56343e402bbe49dc929b118616a3ea6b", + "15b103f822ef4d92a386e95746a9aebe", + "8d444320adba48039e486446d25cf978", + "2b83ee4069a346f29fda9069a3a5253e", + "482c67c45711443ab1d91c4459d0574d", + "fc739bea1ae4441f95a464e94ba49ab7", + "92e3f48d57814fdd9db15171738d9b39", + "93189d4d74344474952256c666537d7e", + "27425c1e783c4210aec2be5ee61a73ad", + "f8d52b6ae9424e859108f4db0ff2c2c5", + "c2c8476dbda14263b01e8dbb88b67f79", + "e4a6e3a9d12a4a609c490ddd96c79113", + "087122bc1c7f4b8998b58b650605a67c", + "dc6a7d667d5a4b269356986633983d77", + "f02a510759254e5584eac643a36f8844", + "0531a9e9c9ed4485961bafd157a13cf4", + "2bc579218fbb4c4ea83c541c8486f48b", + "07fe8f8d13ad40fbbf6675aa259273d4", + "c0c0f2d8b980400cae6045139244c3d7", + "4ee197c07ff54bb8a5554a4a1538bde1", + "8519ef0c9c10444b91014eda4c9de30f", + "313d47b8120d4e43822e4f98ff318873", + "21ec2765c6b44c46960908faa4ba84ed", + "79e0af6f7e93426ab5fbfd2a7f284e80", + "7b07838985a947fda70036aafd46b3ef", + "c04e4fcece8d48ce903e2b44210dbe17", + "158970a7d7a044588235c2e73793fe41", + "5c8cd9f1fdb7476d9528bdbc0e7a318c", + "6ef7605a83534b329e66745f1f920817", + "ab0e803676bf487e835995c611df4c04", + "693a655025524c8aba97b0890c2ee016", + "2110860cb48741a098f68c6d5009e705", + "e171a9ea1be34318bd8d1f785f648300", + "fef4f3e831e64861b94d5e25fff93f35", + "49ff5037af0b45fbab69680fcb3228a2", + "4c6aae2ee5f04cf99c9cf417122c4b91", + "ac3847555e62428fb21221a318e2e684", + "f01518b76d8f458f8ab7fbd9c71f107b", + "0e1b13fda06e484d8387ce5557b32f76", + "36a862a20e1f4eb9a1655353af4924b1", + "2c94bc1386cd468abc55afcb6cfa18be", + "11c329b74f8c4b1a95e44d8c475dd452", + "1e09c20b37e942548b176f0a1ccf9dad", + "8d301875ea134faaa5a8c9cd2459f956", + "a9422fc585ca4433a198f5411e157091", + "c54d935d25b74047bf1d53f12fa410cd", + "cbef71e3235e4b99acb81d452cfc4019", + "a58389f94ec047fd9dab83e054dcbe23", + "f9ed3b934fa34ca1847994470ce5bdc6", + "4dcf61939c924f1a8220fb589fbe62f2", + "bae987c869f644e695f100f28cc38dd9", + "8746e3755fcf481f9916c84d9b37a70d", + "697ee2742e234188a155fcbaf803f17f", + "2dab7a2ecd454c3d86e7afb2054687d8", + "aca2a3b47d894fa29d0c9fe5102c1357", + "0bdd72038f394b0e99a983465f1c367a", + "1bea7def2bc54432a983dccbd0a72d7c", + "bef14138813e4ebaa289b8a0a2868a84", + "e02616bf3287455f888053205fc7b5f5", + "07b31e4a08044459b746555c7bf3b19a", + "d3fe7b67a48c4fc89f7dbeffb3c6cc3d", + "d4810efa0b394467a0efa989687e5351", + "f10a50a72443418e87a4087ef93d9027", + "0e11b3724ac9436d8ac77c029f2a9719", + "3ad05f9e89294272b9f4d8f3b005a04b", + "921fa0069be74b1d967ee57b828ef4d6", + "e74e5c6c6430401c9bb2da17de264a65", + "bfa29f9964a04a49bb1a049c3ff8383a", + "0bddad71f2b8402887aab34dd9c226d7", + "4c27fd0640874d13aeb9023d5c075531", + "14ce2a5c954243dca6af040745ba2455", + "fcf8a31165834f83a3f0e6b36563dc4c", + "51533706e49749f0a2ea7175a02cb4d5", + "416f4870df6449dfaf9533be8aa18701", + "6592c60e5caf48d0b92458bb9e086bc7", + "28a1fc7c2b5b42b1b26e072d0c171885", + "88e084fe401a4b9ab08cd287d25c34ec", + "a886da137e7246d892f38189507e83ef", + "4540c1121ac043d180188d0b260e7e3a", + "b24e7ac674354249a0520462923f53fa", + "811b15416aa240a49cbb287426ffc73e", + "c1957e1339bb420b9d2d1a27125caef5", + "4a379c0cff1f42369d49c56300c4fbae", + "919d746a04c149e8872d3deb78c438b1", + "2f6d6c2b56fb4d0cbc0d8274bc0f0730", + "bbb2e0eeb0b34247b8a70655c780fad5", + "f5b9cbc9c76d495cb544572dfa511dcb", + "828c8edf056d460faafa65870e8ffbf2", + "e0d04cfb29a54c0d89fcc102f2773af1", + "a7ff74de323f4811a95c3495dbe05f40", + "70ec785a5f0041dfa29a6e1833953387", + "c4740b53b1c447ea929bd13b2ee49017", + "36889c08436941d087b9ffeb9922f1d9", + "41e58efcf647494483f9860df99acf60", + "072d8e95a5474946a162a40239e991c0", + "9dbc69f89bd948dabf5612ab6e19a896", + "327aee9f75b44c9ea1b3d5029fd45c22", + "2517b867250643c482e0e316151ed758", + "77e4424d084344b78614697911af658a", + "7caa2b1d758247068a5b66a1fece10de", + "9b898f0b2be344cfa07ba6b3a83708b4", + "f060d455ade64f91af744535bc7a3109", + "f117b0c64b534181a967b9a9a681a237", + "b865c92c3ba943c4823de05ba15946ef", + "ee5ecbaf0e0147e8a35b0382cf1a0c6e", + "773161905d0e49dcb0a625ca6aaa77a6", + "4df5c828df0b4ca9b6ce73ff494e371f", + "da93f352bf434f108dfe5e6460a99766", + "1d3078a8fa49496882a66e4e0a287152", + "ed295b0261434d6b90a71ea85b7ff9d0", + "f7aa8a46b13448ec9a986620a01ead1f", + "bd2c6f7167b54a7aacf184b01e64fe74", + "89e655a7ef994d5c8360766d59b5921f", + "b25151793ce744f7b56f9846c7d1c2c2", + "5b1b414827c6480b84fa83bcdfae8d41", + "4cad8b729f744e48867728ad6659ab27", + "695cf729f1bc4a848f29016d07d35292", + "81b11403177242ea9d1242dbfe214432", + "06a63364525442faa946780136b73ef2", + "683242a5e8ff43d986ed82e2ba602c8e", + "335d95c24ef74c5d85791ea0fb05d366", + "c9cc2ad5eb4547bfb923d50d230f4f8a", + "2fcbef3cf0a54e3c973403749de5b69c", + "641b3edcbd984497a0465dd35bfa730b", + "cfc49bcb02134ecea34f4fda58f00590", + "0df0236e131544b4a940973c05137370", + "a354973dd4104388ad28d4c0da7c2f2b", + "78ce9fcb771a4187a61a08492338f543", + "a3a7e637802242cca8d6a1d2bd0724b8", + "abb0b2c7e9604de9b5a02d7e647a861f", + "f3bf7e1405744940a0729dcc491dcadb", + "ff0c8ece94c64c8f94329142048e1884", + "44d32a1bb60a43dfb1d67fc3bcb27a28", + "4500b31d30404211b3ca69bf0d56a054", + "d5018e50d3d645428542c035cfa5d25e", + "a5e82f6918774779811a47a73c1b2f65", + "710deb40e2a04405bcb76e43efdefada", + "72286e591df64c2fbc75f00f085f3d64", + "453ea3fe76b8495b9a9ceddd707a3ed9", + "858b94cb79904f7aba82f542d2b3510d", + "b8a7cc0278304cf0882ddf25040af3d9", + "7f5b4fc17a3047e18c1ed48634e53b59", + "76d15556d3af4bdeaa8eaefa1264ab50", + "8ac136d02b5d4a0cb526199bcd919439", + "35914ec269a94e6da2606ea57585d04d", + "ef5a311bc8284e86a4516a3b5296bf1b", + "a0a84e5e72c74a70af9c71f9302ce921", + "efec825034c64eac85b285d906955f17", + "08d237ffee3d4898b000ae0878a15a5a", + "e346dd27ae8f41c2bc8d0e756d2d1913", + "d3b3cf9bca394379bdb8e203f1c6930b", + "63c4d6c3bb0b4dc991ed4cfadc464742", + "e4794f6db9d941609ff930f69ca71bed", + "131e1df07cf140b89859fab071d3faaa", + "86c972a09b0d4111953b9f8eb28ce7c1", + "46ba6fbc8927452ba8a4862b2c4b617c", + "f36b44925cb946f6972160865d01101c", + "a44d68b768b74a63a1080d2dbaaadf4f", + "d343ce86763d4d35aef94c2c151eb36b", + "2b8ca11b4b4647b8848cd4920c8384c5", + "fd4851d6bb7e4738ba9dca10029e4f7f", + "23edaa0f24ca411fb29ca7947c10951d", + "53b5353b12cb49bbbb21141257043fb9", + "cafa78b0a19f4dc3a437810132eb200b", + "7ba042eb8c5b4703b0f3cdab552f3564", + "92b57e3e4de646b8b31e5415163b3fb0", + "bbac19c170654c55a64bb3806320d53e", + "280606599f7744a28898b6d1d18f879b", + "149abcffdc0841f6844174acb7286c1a", + "d726514a97f74f168b104fd6ba538331", + "0a7e5fcdaeac4f0f8d5194f42f4d4492", + "6ee92199c23341de8a8458552b505e89", + "bd1e662f253f4e1f821bfee4009034ab", + "21bcd49240a54f2b879dd3f91de4fca3", + "900fc693c9af4364bc7e38b6e60a6d0f", + "3c18565d29eb46929b84b598c8b47aea", + "4d0c9568d4c84024bf6203e0a3126110", + "b69d6538374642d3a46f6129691b2b3f", + "903a7c076e7c4751b9579ef5bfc3c727", + "b968f1d2833c467294d14be0d340dcca", + "cc0dcccd616c4d00a20a265803dd8c76", + "0162dea1b1044cd281c57af5e5fc2046", + "90425954be6c42c2b469e032b4ae07cf", + "e96738ba83044e82a0f69963770481ef", + "a3cc0a1c653f4b9bab05bc8497d89aa0", + "a0874b3213604c79a5743bb57d30e432", + "c8ca01f1ab5c42728480328d02b0b2f9", + "789e15b7cf234d59bc53cd81ef0f9d11", + "ea19e8b075d44c2a86cd369d85ed77ee", + "49d0b382def54ff1b544cc6293ea1b22", + "b67ccc84a7da41faafb0f948eea8c1c0", + "38d07cea51d04e9fb419376d1fdaa77e", + "9279045ec7044e1889f17b02fbb013a5", + "9d8e00d2900f4929bf121c2f867bcd74", + "963a1bcaae9345738440116ae7bb1ff4", + "59988fdf28f843c68e7591e4ee1e5cc7", + "6d5f9ca3da4b4b01909f2a611762a1fe", + "73a3d11f59554a1888b4e681db56d7bb", + "a055521740d54d118d8c0aeb9c62a8c0", + "7c5c9dec5c2e4ff998c386410b0e3686", + "603d972228144b1c90fae734a251c659", + "783913c7b9df441ab99ec666eee4e052", + "219e7f236e584837a20b3e21a057d5cc", + "3967341c1c7e4c1b8bc9346553157a73", + "a1a8bb454cac46ca9b3e6174ccb63e6c", + "dfa91788ea8d40b0bc61b13b141f5ec5", + "ef14ff6b4cc44fb8afccd7130978c466", + "a35bdd1b77124e28a5179715ebc39037", + "bccf270cf88d4dbfbeb1f8b8fb0647f7", + "c8926231517b480a91567e5113fd496f", + "6bfb72bd89d14a8b979f727e3366e49a", + "05b7974e98044bcba1f586eef3fe4a9f", + "4fdd427bfed9482fb16b6c33056ecf9c", + "46da0e25122b456b9f52930e58ce4bf9", + "edc9119eb19e497285c027ff7a6657b7", + "cf09b650f05147b98c05417531110766", + "22c0fa4190db425ca8f6b5318f9e162f", + "b5d46802166d4201873fc90bbf318924", + "d97399824e874d89819bd1308d3b84ce", + "f34652448daa44c290c7b315d0c7d29a", + "7994d3067a554e4dab14e88af242f174", + "4478d3dd074b40ee96fcbcb227e5a732", + "f1ccc55a65c744d7be201bf11b980e4d", + "aafe19f747d84c7089715b0e9e40ad12", + "6839a82c7c644fe5a99fce0bf11be727", + "3c3f5bfb98284924a70cf410ab532bc9", + "ef8ced4cbe764fab9799113f7f700aff", + "8e8cbcdbf2ab4e2486f898ebc1fe92c9", + "b5cfe1cc7e5f48ea8c6c46e1cd76a4bf", + "83573f8bbf824ba2ba2966cfa0e7423b", + "36972ecb0f4240ed80650dde59dcc88b", + "ae95b9c543404c9da64563dbd626e6cf", + "f03145e303cf4f2b9c0a585564b44292", + "ff8d8e5b38d64226af0abf1f8eb8ebce", + "c8f1c28bfef94d89ad148c48bd62361f", + "f0edda0b93e146fd83c7318d7f1bc695", + "5f7332013e4a41e6805b33d5ec1d7cb3", + "c9268e1cd93f4786aa6f48e5a777efaa", + "1f6e4d451821462894589d2ea7d39a9d", + "58549fe473ea4ffa9c1788c1b21b8a84", + "c4c967caca624115a6ce629d28266129", + "7a179f2b4837457eafa66c2f7094d280", + "e60666a29ba547ba90ccb7c48389dd4a", + "8207495e36704958a1bfb9b0cd4dd1a3", + "de05fe8a0c314eeeb8f7478b92032f1d", + "46e6d32e39f7406484da6f47b5bbac80", + "bfbeb4132ca540a8b0bfb42c9a155c65", + "4a143fc43a234425a1b912df89dac355", + "30134c11e00c4496baff2db222481142", + "4af048cbd3fe4cb1a52bf14c2299e3c6", + "fe3fcec21f3643f38ece8413bf9a8eb8", + "434f6bbbf54a4a7482ba0afea619861d", + "62cd61b638294841aa616ebe33a203ea", + "e9bf3485b7634d90809c26365493894a", + "50bd4cc3a141400cb84ea66fd8dfb2a6", + "9e7a80b01b774e5d9515e9c1480e78ca", + "eb99ef1910944f7a9c85e681d8194914", + "dbebc9fbcf2a45c1b983d91c416fd87e", + "d2ed14b765d742a18f05e75c231f0e5b", + "e5fea53c70ad4e1c90cd0fcae7bd078b", + "153ad530851a48f1ac49dac79dc443e9", + "79bd16a8c36a45c78ccd13b84b7ca99c", + "182169eeec334fa4bdcce740422ea5c5", + "f88fb764ab5d405f9c0959da094f1a25", + "6bda4bbea89f43bc9128e53ae350aa6f", + "8568d2ddf3a04aa8a2d3edaedec4b14a", + "82603b14014344e3a451d0242c095d60", + "7cf2120784bc40bca0a97869e6eb09b3", + "2166fbecc064479fa5a3e07c36a36af1", + "08024993b7174695b70e0b8df52f31ae", + "c6c5b4a8f0f04a94a91a41d0b4e9806a", + "de23a327ce1a45518afd80f763d2c549", + "74e13ab045404c5fb727b70fd7fd6835", + "74d67a23b95e40adbb38187afd335ddf", + "e607cac1413a45e499bffa50f26ea00e", + "27f7cc9385f64f29a6fc4e00d3fe0b9e", + "1215fcc4e8ea4f51aa1978bb15b6de34", + "170e890a4f4542dead948b6218ec65ff", + "00fa1623636640d7a21e5a465de4e496", + "14b504f7c3774ed6b48d318fa580146f", + "8568f8a081454979898fbae2dcbe03b5", + "fee1a23be3294bb694dafd9584bc4e7c", + "754ff778bac64db5b6f92516f8259974", + "7c553c19982b47f487870ce2aae647b5", + "3b34354f40824c2c99e8e6b891257685", + "c8976802708d45c39b695e50a0648f2c", + "ab3294c0d6b84ad09daafc9fb433c2b2", + "0552725d1610478bab895ba489b2317f", + "308cc67e2bf44a61b14e3b472cdf08f4", + "4dfb95c72f814d3fbe32e7ada8435fa9", + "f3209a6a45b844df92560099f982a508", + "cb35450a7e2e4a69b8daa7910b03151e", + "c61570f2c43a4a458d3d744aff0afaab", + "595ebe658bbf42b088dc45d1906b44a5", + "9cc3ed44649e4533a0a057f1175e728c", + "bd41ecc23835416bafea042d6a01a07b", + "954c17e22f944b5c9a3f409827c50910", + "4926464addc64a0f9e281ad749f69c85", + "ded403c85dee45b7ad8a6bcc8c3b2754", + "cabbafb1f9794543a465819135594cb0", + "2b1ac7abe2624487ade51c180bead840", + "a88463c894a44575ba4bda3c13ef31e1", + "06f9f74c0ac542f89912887eeccd2015", + "d7af6fd7724d46b092d9c15c2ecb8849", + "d8bfbc48bbed4d73b7e21eb26c96990a", + "afcb0e5720ad40a98797507861aa371f", + "1a1764e896e44cdc85f27222f9db8230", + "90616961550b44b58648d95ef3efbe54", + "8bbefe57330941c6904f4e4618756553", + "da3a78d46abc4abfb699461b3421ff48", + "2a2ef290843f48778216fcd499f904e2", + "22a260ab208745988777f36c3a68dd59", + "11401f2a73274b5c9f232e70ba03bb62", + "55a9c9ca6c234f9a82d340be29c45b3b", + "3e5f3f637aaf49b6b028d2c5d7581b60", + "7fe159646f814184b927ce5fddbae597", + "ee9ffc7844b34a57996219fb6528608d", + "085c555dee8d47dc8f016ea9241c34e9", + "358b781386de465caf543959d83fa956", + "0bfc697c50f447668b6f831a16f1f7a0", + "25813585b5c34454bdcff843d6962ef9", + "2111125a590f49758a7bf64abadee047", + "4bedaea868b84e33a8b6b7ddecfbb51d", + "5e98b02245f6400bbbd61bba816db2d0", + "07b10956418d49aba2981b0af74cff6c", + "0836fce981954665bf69374053e76713", + "d53ed9dc8f624db9be4c7f3ec22a8e8b", + "c74ccc573fd144729bd9bd33144782e5", + "00a57bbd1c894a7cb9e45ec396a8f660", + "9906e5863a89474da4ee4e178a2daa28", + "eed56295d62444e09430a006671cf25d", + "3b7c0aec4a664c8d8ae10085296f2c73", + "52005ec1141549cbabe49fd9331b8d59", + "1f4f0bb77ce14ea098755c71fa5c0308", + "b077971cff46463b8334f8cc510acd09", + "bf60890d6d194b449c12c27c76b32cc2", + "f7bd10224540485f939974f7a3c57fe4", + "69d498ab12b14d63b30c9749a50b03fc", + "d161435954f44ed7b2c18915467f33cb", + "9cc3c708a15c44f085f9a9c9b67a2f1e", + "a78a17eba65b45cab925fa01c7a91380", + "44626765d6304529a5e0d7190db701e1", + "2e2af6de1adc45f3bd56ea9b07be781b", + "edac81a42fa94e1cb6031337b8851999", + "8186e2b966c641cba743cd3e1a302243", + "da81dfb3c49c49f7af336d686567265a", + "a5343a9ea9094fdc99e5602c3ce9d501", + "2d1585f525fd4ec18415b550924acd1d", + "16a00ec6d0c8453581daf383dd6d3798", + "0cd590cd899548e4858010f054a29dbd", + "5d233ea04ee940e59125bfe9880a77b8", + "8202c8fefcf1434abbab9b2eae9a2c16", + "ec65c14e29a64b6b900d73e690898844", + "0c90ba77c3684886b859329b1ca2e6d5", + "4b7a1d998c2c4c068eb48395f69c1ccc", + "ead53728d4004a6686de6cb323d39007", + "a053e652057048d99b9543af619f3a6b", + "cad7b039ea734aa48942fbef906376e9", + "4530d07e89fd46fcab248e855cf5dc0f", + "433c602fb9ff4913afc8d1a4678e6942", + "b9616981f2a54dacb38d3c45b81f32c3", + "57d39e8ed5094e89a0e0940f970a2cff", + "ad1f86104e5d4133a2ac3d99c0bc241f", + "3f2c42cac5cc4df0af22760b65bd23e0", + "e1f09aff499f4d9484e6b8fb796348e4", + "c0262529e44e4a30bd6b2935d8bd225a", + "66167a28782a4472a531436b59ebbe40", + "7416f0f3e04c48d1af25778171256341", + "889a8657d84e4a43942d8ded5f715930", + "bab5e87d3da84efcaf8b62cbf2e4e730", + "536b939f5b7246b8a3eacb2061de444c", + "7808e25e62ae458db8cdacfe8fa3b4f5", + "06ba42f61a0f429b8a8e8c4a58d2d972", + "e3632cbea4cc46d18f9724a3833ddae8", + "c3d50c8ca98b47c1805d0e23ec9e6f33", + "15d783f3af9448de86859e99d22d9291", + "29e24da317c34d639175f6966b7d310b", + "617af96f7a674fc6973ae3344892b4f4", + "cbb4bfc4e5654500a70dfe72ffc0ce0a", + "4ae0d0e9e2644a1c86d7b4d8c8626280", + "60f0b422eaab48e89c5dff0d81f11116", + "0628e42dc7404dbc89e4a224f0bb9459", + "e393be9a47a24a7cae6142e13f5686d1", + "a78c6690278549c29c4959c467d58f71", + "95125384e43546ccaadcbfffdc771142", + "4ccbb5d870ea4189a5ce53291ddb7921", + "b11f5e775bbe451b95744060859ae5a4", + "3ee00f7e14674461af4241f5ef7ed039", + "46cfd846b2124854bc893a9e2d5a0476", + "c3db152d87cd41449085083c23162f13", + "95236390077940e0826bb5b8789e6400", + "3539250ac5ea40ff8135efd41a070136", + "15aaf52d00dd4c78a984bf97ed9d7967", + "974d17751cb7497286baa1a4819458c4", + "4799088a279d4836902daa6e26530699", + "56b2b875a4184fe5a86e64839c0d9bba", + "2050ae5eb02a447887972d77ae6e31cf", + "289ad47cb8914bed868e256d5ddd348b", + "cfe6d514c97c43aa828816453e435c6e", + "c3946d1fb2854361bc7ee42ee4ee9590", + "703600c8d4e6400aa965b87edf37736b", + "eb68e95943f648eea15c3956edfe6701", + "a0d0b01f22d346629306bf316d539714", + "0c55f179b04541e581bb6973c5e1c994", + "a565930de8354e3e8cebfea1713a051b", + "5b8387c9c73c4c8795df14edb83280bd", + "5ebe6fbe73664e2f8ef379184d144f23", + "a7482597c23f4ed79e16581a4b0ef6d5", + "a06b6613ae2a4f61b15a66f6c8b8c92a", + "f4bdcfe475e842d6a95972211d68694c", + "8e2be4f8958246aea77c868b42bdde6b", + "934716ccd00d4f6ba9555d1cea788488", + "7435f8558e3d472fbf6973e20b76567c", + "9f9689d284cd41019cce422bc69d612e", + "b5f151e73b4f4fcab08ed2268057c5e1", + "2b8368d2ae914d2f868d3fafd9377423", + "55c831f756894a318c7156c4efbb75d7", + "90d220d0ffcd49f2a705497bdb371006", + "d4009c0097d34809b5e27a5a122241e4", + "b37a3d92d35445f3a8dba72a0b7c708a", + "02bcfdbdca964989861d5e7a207ffcf5", + "5618f08879934b3fbf96e949166108af", + "68d135abd71f400fa47f55a85ac3db19", + "8eea5c9eda6c4b959912a66408275807", + "65b4086c9c2e4feb8d273e48e146d786", + "1599259e9dd644e987025a66ba535cf9", + "fcff049c431041a4889b836be5e93c93", + "7e1789d1fe5e433491a7c4052a018f3b", + "dc86559181b54202b8c96c4d0b6e0d01", + "35dbd8a2896a44e080ec1359c02829df", + "01d5fbe1cfb748569ae3c2ebf1f1abe8", + "88a9b32e1d0f44fbb5b8560d47ae7d6f", + "ab4de12c94184bd0b28fe3b952caeeb9", + "829b62c1927146d885670482e6963af2", + "94683604d86447aca2355facad973405", + "069a1199526f4747aeeab80faa31bd33", + "adf8f9948f05429f9449e2750eeeeef1", + "ce8be79e40e444709e31d2151b8d11a1", + "808866ce78a24354ae871c0f8721097f", + "25a67a986aaa475fab6efb1a6b2b0518", + "8b2f5f02be9f4ee6adcf35db711e287c", + "d944bfa696014fd0b1301e83a31226e0", + "3cb476448bb049068ee7473694bd349c", + "2c23a943c53048a3a7991d68ed3cf069", + "d3655bb9762d4e55aa0728fbe4d0a31e", + "63b20235d5134bf1877168cb2e232a0c", + "6c8c6ab079c7498ba7b723df1e3494ab", + "ce761e37e048474d8c40d3c2deafcfa9", + "9599f1489f71468ba1c057724b0a167b", + "82f6c9d0e3b0489caa7b884e21d1e970", + "a5b8917b2f8847d39a0dd2196a81084d", + "251dcf9f433545a29406c5a9464e4421", + "a7696665972a41d4bce1f658a0ca14aa", + "ade2b59ff37c44059433414f39c94abe", + "e29346b8eb0a4919ba24115619cc02ca", + "6c816c2eb3ae42a38faab5cb1434658c", + "f1121a2715b643fca200e1a7047c074a", + "98dc3a40ca4743f29ca31acf6da5d31f", + "e11eef1e733e4a4480c79d33a355628f", + "657e3cf03f3649908fab291e4e17362b", + "fd9f83319ec845e997293647cf4a3b24", + "b4778ec8024d489a8ae5422e5b3e0df2", + "eeda09a2600943ccb5ee28bbca6ba868", + "3625ec3eca404669b124d2852580c4a2", + "08d73e1168504bf2b8706cd838ad16ef", + "d26c329d542b424a8d59d794cea3fd97", + "e80ee150823f46298844c4aa075ca531", + "b5c16ec189884f998057dfdf77043a38", + "ba8cd12090ce40ca8a649cf6d8cf8096", + "d0eb9abc1f724003bcfb26bad66b30f9", + "01aa135a058e4d9396c234294d1691ea", + "434b04afb75d4525ae5eb272282d736d", + "727aee60dd2141fda9a26026a772e387", + "25acb61c86de4a19a710ab494b89fc0a", + "a42dd5963b3c4d71811a19c51df647c7", + "633bd6eb599b4e5c8494bfc0c3c12cd5", + "9f5942f7c92d49b8a608903c556de37d", + "07c512edd91d4793bf7161599ae1e6df", + "8f2e31c39d6c46c483dc518a4017913d", + "60b347d669fb4d0fb9799480f6638b38", + "8350440dc5cc432d93e47692e8772f08", + "211fa2bb02804b5eae411dc6e1ca084a", + "d0de22a6f34e4694b089bab2aebd59df", + "de4043a4c51243c494c317c5a9d66208", + "55b7b356c25a4bfda49302313d6cea60", + "018f683e86ea42eb8e98935e890eb9fd", + "f74804052fe54f14bd5e2621e6a85505", + "45de76aab681423ca9570b6cddbe50df", + "8bb5c3460b264951a045be71e7315c1d", + "3532d56ca306437f8460700695172ee7", + "c71b73dd44dc45d58bb2f7dcb6a29997", + "4da1da94471c428d8fa007fbfd34e8bc", + "c94bf64b33e14a729315ee3da5d721d2", + "050adf8979da45a29ae1dff03176a28f", + "8f56a64e780e4274a8ff72236540bb84", + "0ce76299ca3642b2bb804aebf694a6b3", + "d2404e52b2d144e18f0621903c98c06a", + "321c2770c5954931a491a619e40cb1b2", + "5a5687b3e3114db59f7b15357ccc2bcd", + "c70eeeafd37c4d8aa138b61a45821c25", + "63a955a9b54e419e89a670a0ff37ccf4", + "5072a6cbabee47d7b2d7b74865bbc03b", + "6e0206af1e2043f7abac110731178aaa", + "cebf7c41aed843a094126dd862c2ab0c", + "c7448070b8c544608976f47b43a063ec", + "88740a4b9acd422c93686ab186e4ce41", + "4cebaf3fabb54460a218740b0c4ffcef", + "0d28a4d945754a289ce4c35983a01523", + "3db86693ddb54e5984bf31801f9f1597", + "5b1bbcb42f4544c892381acdcb57c0de", + "253e8e3b26fe4c2495d464e9dd36c7ef", + "2490aa1120cf4db5aeff0ea21bab77ed", + "ac33b2fcd1524da8aa3d07637412093c", + "a2a9038d85bb453f8278134992ad57ea", + "d210f39dfb3746e49fa7ed14b039560e", + "a73854935d294308827c9f575c52fe1c", + "77c709879ece47859e913f90672a9ed5", + "8265a807b0914fb9ae4afedc7eb6d462", + "2f20f58d1c8947baaa2c15a037fba623", + "edcc4b6f843540f09a185d7b0a48b1af", + "2a80bf7b6d494e42ab626d66cf49a944", + "fd97deeb094c46a7b0465fba1e81aafd", + "6575ba56940b4816a17d4dabbf2ed25b", + "3592ab04561a4acc935a144034b51857", + "caed7fd65d0047299df9a4c3dd3882fb", + "8a5d08c3818f4bd3a704944647e2d5d4", + "d80d898b54d44a13bb150344d0da0004", + "f22cd9d7523c4c85ac81faef9eaa9441", + "937909ed882d40a3a8c6872253ef5aca", + "d0768d1475d74e1d829fc8db74326ce6", + "02143a61358845fa8d42d23037f0b08f", + "02c81d18c4f04b9b9275fde41d0e715b", + "0c900780e2b8407e8eb1e13a7ce02bbd", + "195c84cd622749fb8fa283674da654c7", + "d41b44b66efd4833abf5581a76d60efc", + "5b1a44cff3d34249b8feea2052ddd972", + "896424358015482db0a9253f5cec4202", + "b8fbec68d48040038397540c32121b30", + "69ec3826c4cc4eed970391aa55eb9006", + "105f109b47994e4596220bcf44cceded", + "ca5ad243982441948501cd5df63a5634", + "29c16de667d14712992c3b5258c1f02a", + "61ee77f5688d4061b3d7a975ca218146", + "b1c02672937d4f2ba7124639c0781039", + "08ffb3156ec84e5dadaba2b13bcdb3d8", + "2c32127e0a354be9b588bbeb8f9ac644", + "cb37e9a4830a4d6290c1134efd300b4d", + "39d0231b4dee432eb5a86a1bf1c25ed3", + "89964403eac1478e9f0734d7b470bc08", + "f5beb76618cb40c9adcc4b3a40c615a3", + "bd695b3f7ecf48dab7898c0a8b9a9840", + "f2055d758b5644f2a08225338bec33f3", + "cfaf0f457ca244e59c746ebdd6f3ad6c", + "b306e280c35540f4bfa844631f596d07", + "38cb8269654540c4865a7a89832f4824", + "8b6f793c5bba4b788859290900db8577", + "5ebdb127eee2413e990e769b305a1528", + "50f9b9982885403396f46d5f46c7b4be", + "4cc4f9f4c0254284a2d043d593265863", + "4805080f141143388f100aeef8b2efb5", + "21ec37b286474fedb43307f6f289269e", + "cd04322124754ea5a6c771e304976edf", + "926a7987d9b04160916dc4f2b9f0efe5", + "b5c646604c7d4a33bed7d92c6764f756", + "17fa7ee6fc6d459eb14657df1d459a58", + "1fe2e400f1bf46cd875fcbbfc9f3186e", + "61b40bf8aa0748da88849a6336bf71de", + "4ada74f745184909a012f9018183f1d7", + "fe82c7e6699f4dc18ea37450ca61a1bc", + "6c5bd43da4164deb983a78d87281cfbb", + "15c2adf9af7a46fd8eb059ff053bec6a", + "78629a0cb1564f459939be058303238e", + "64ad49b1a1ca425480a28a23dfa151a4", + "b62dfc66750a49a99119a0b821ab7aa0", + "fd841e1452ba4eb199dde5601eb2e4c5", + "29de2a74036a45ad8abe8efa6d77a13d", + "bcaaf6766b1049eeab7c63aa463fbf5a", + "58d15c2d67b147d09bc5e46f0fbcb0b2", + "8c1b38fd35714adf95f20c9c3ccd8912", + "80f10af6cb604d7cbbd141050d093b2b", + "8d8a605ac22e422cb14c0c38abb7db44", + "62a5b3964e5d43cab322b54fc5436c0a", + "440be7eb5de8469f84dbadefec1f0786", + "a47c3ab11ffa49448fb38fa235d6541c", + "4bf34c9bf74c49b7923ebab6042dd443", + "ceff8c05e13146909e648cb2e2ab6701", + "622a6275e0154c92969795ea4d7ae7f0", + "38f4a786031240589bad0bbcc9ad949e", + "79005845160443a0b8a175614cf2926a", + "c6f64380f0a946d4964b62c3a64b698c", + "83ef1a1ea3ad4a2fb6c5c18c8454fdbf", + "fd42746284f343c19183fa2376d8ce25", + "3528f0dfa6d9454d99039deb92da3fbe", + "6d1ef046e9d544ee9b0d4cca48471bdb", + "52f826bd16024a33b300580fb5c5518d", + "83b15d8e2b47424eb76a3340ab1988c9", + "3692f90ebefe487689ff9064e8167eb7", + "dd61828ea85148c48b322402016b4c68", + "e361095b9e434b1989aa6b4957c82d94", + "059e3d998e0c4a9d88185a2ae19e7ce8", + "11b6ceb756a749c187b4dedc213a2ccc", + "6cb36298cac0488cbab694bd476dda0a", + "d527ea272ab24cdfa6b6d9a8a0fe55e2", + "51b27f90817f40d4b5a34b630dc2b31a", + "9fa76511c2d04396a680628187392077", + "4044dceb998046f692d7063d3a9d236a", + "5842dc1fdfe34ac9817222bf6a9bac17", + "15fae6e4ae89480c8bbfbc7b8a6678be", + "4eba49b0f6f54ade836a565d98247723", + "ebab3c3800554ecc992205159a24479f", + "2167413de7e04899acbe05698af56f41", + "cdcf1566419347e88bd01000256ad602", + "0033322379a24798a6875a5cb2de54f5", + "58d14538b81544f7992085e90232b338", + "14116da06a65420db32b585466061d31", + "b4623f4127c143928b75ab839442f070", + "89fcf118b9164c7c9ac240fde6a82fca", + "c5961b09dbf24f56a2752a04b0517af4", + "3c1b19edcddd442baa3a8d128dd9bb8b", + "08f40fd84cd74766989c99c2afdd6ab7", + "ee972eed622d405a91586906536fc19b", + "0ded6b1e9ec04fa6b7b1a40a99abd31e", + "cb3d49a6261a4913817e8e00d6ab6e43", + "b1c0265a579a4d39b84406ca49c7b5b2", + "327dcd11fd214e6b9d44d029beac358a", + "cf4e39599cb94eb0acfd070e367b47ae", + "2ec01ec1eb874f6fb11ef732fb575267", + "33304ead62d64efbabd179e94b9b33e1", + "5cad65147d704e79b047518f2ccd8c1d", + "e209a97ad4594e188c2140cd5e8ef582", + "32d5b9d4db3f41d8a0f9b7380e8ef2cc", + "ee801bec93124d479ef2d41d4592d78a", + "e8d10d0d23564af590b879853be27782", + "528e0d4231ac47a180253652d28f7812", + "852e8d7eb9c4401f844fd889f85a45a8", + "072a06f2900a4807865dc9aa90f28ad2", + "361b4bb0dfac4c72a4bd6ec8fc7d71bc", + "950a3d4beb9b4392beab4e5e4b93f69b", + "e1e3a74aaa4c4dacb3ffdac4dd119830", + "104d34aa17e648adb50231219edf8665", + "aa840004cd12489daf8d8f5ca0fef013", + "b27ffa86d9e94ec689f982e048f3bb08", + "438fe451f5ea4d719c9c246e1ab3905e", + "339b0e78809d4bee97d7b1dc6ca8762a", + "c274989766c344ac97817f77a046c0e0", + "8e92dd7490484eb3ab615f99a414bf55", + "112204b2a12c4e25bbbdcc0d196b1ad5", + "0c87bb81838946728e2c3270817d67c1", + "a4cea22eddbf4e3fa7dd8d622642e635", + "e820f124728f417091eb6be6517e2279", + "76a5986de5ea44769349d5d2273f2c04", + "e6da9aa79ad9423296e4a3942a7e6332", + "39d8bb144bb04bc68f5c9ba4adf17273", + "e66a171f9d8d4787bd6e40f378d42191", + "1d7b005b0cf241d9890739a549769c86", + "7a91611c0e5d4f519c9e7cd1425d066a", + "31f4ea45ab034f33abc9715791134feb", + "6bead16346974abba15357a2d1adc0d9", + "b8f7f6ec414e442892482811e8630e94", + "8f3650c8731d4d4c9809be426834ab4b", + "d6594cf163044fce92e4e8f539257391", + "4fa5a5e2775545a780c1193cf68d7051", + "2f2074a9f0104714abdccaf983568447", + "6cb4e7dcfc944bea82b879e69eaaae0e", + "f05a25da4b2c4e8d889db888cd3b2efe", + "4d6810fae48b49928d765c4bcdd06f29", + "c3780129733f4b72b643704699c9fe4e", + "19612447cf644f559e5bb2341ec86153", + "16cb358be674479c8c5dfd4bd670a700", + "6e4d3a8b32214a04886ff5f1c0f50596", + "075c34311f304394bc77430bf29e09ff", + "85a796997c65490aac88c6ea6a06f787", + "d301e8fb9bbb4c8f91705a379a194fc7", + "d6f13319396e4f9ba232f492f9e7dccc", + "a9fbcfa6fb214e508cc8788baa099d5b", + "100c1031bd244896ad8dd7c156ad6e7f", + "f5df7799760c4452addb66854facffd7", + "a266d67f35814a21ad0d2d63d94409ec", + "8a0c7b9a58f44b0393efc253a94d453c", + "a2d4d0fc855a499999c49eeb8053c49b", + "5fbaf4ff3516412583bfe4d366fee2a2", + "580f8df75f4646f2bde77e49e93d8cf9", + "bc22cad43838433c971654ff21a12003", + "b0fc8efb90554c7b8c7a0abc847822c1", + "cf6852dd9ea94f3c9f5226a8e3ffe60d", + "a6dafb544f764f7b911b19280b3be48e", + "a9007d4daa0f48a899152bfed3c654af", + "202cbb2a22ea4dda80160ec89a77dc39", + "12a2635efc6a4318b912c751bae32371", + "ec443099fd2a43aab3f783da6986a984", + "f00f456bd8fa49b08ec36508fc46b5f8", + "052abc6c433440fda6dac5123c4117be", + "5b4f6fca82d84e4983396bda882573a3", + "e38f5780919946aebf43605d41193c6d", + "8186e08947664545be29caae9c9ff01c", + "30faa9f06c044f7dbfe59a01e880cedf", + "3cdcea7b797346e1a072ba8456492b88", + "efa4830b638d4ae88dac2e15daea7f55", + "7e944c6208f9447aa0bc38d329d9ef76", + "d728ba0836a046a4a45c4a9d9f1ef885", + "c128e7d47ce94b6498ce06eedfe78786", + "d6586557f85d42db923001321b76063f", + "b3cd2cd415a34bd6acedb40cc3fd2aa3", + "7f6d38d1e9b84147b5a86d4f45a2e610", + "541ad802e9a54902b762289b40116848", + "e70e0285fe1145228f5476f387129abe", + "08809b22f6604461afc38a709d910120", + "731124f11bb24279b20dc3aa4ff591d6", + "7939d36e8fc544cd9909efe27e39c48a", + "4e1b30d8166f4824b798b76ed74ff387", + "c56cdea9385149e4a265ac818be8c4c8", + "9d17119cc0f041e39b2a11211a677366", + "1f726e02c1b44a2bb89cf2c2139d1b6b", + "a8fad80289a44e21a58d8a3ccaaf751d", + "91cecedbf7c34f5d80d034aa6356057a", + "3b99c3f912b545558f5e65736cb32bb4", + "ce3274a82ee74249901010d93fce3853", + "44bd836ae91f45ac8cf8fbfde32b1b40", + "d02cfcd14b7440ee8dec5d45e29df6bf", + "028bf0930f374b3abb252dc222ba76f2", + "c0a789e10660492e82bd8eb058886ad9", + "91852dca70874c3fafdac99e5be6bd97", + "c2db43f821b94759bc1473457e259172", + "0833d5cc55c043318dff922f785b93a8", + "f7548f3494c44baebfa30a7313ba79a2", + "504d01d34d224c208b31004428404442", + "0db01abe3f89440393d3454e16b61f7f", + "6b5f40ba934a4e2ca3a6e8419e96eac1", + "239ee36b12b14ae796e65639e2818a34", + "cc90bbec9d75457681e56ce3e682913b", + "56aaf0d0ea924f2a986a550d78cd3cd2", + "768843209e734d569d1b527c1f3511a1", + "d065b9b1ae2844c0a0f2941be4830d02", + "c43a66561dd34db8836178ee6b212846", + "0ddb55142ac94514a7f6359cffff692e", + "214e903522fd4fa4828f5c001fcda641", + "593d23fc2dce494a8bfe03f6d7757050", + "b4fb5eca8ce64182a4124071111d3130", + "0fa097564a954363aca9f65f91479a41", + "aa0be973535e48c4b3b15d50f1df176a", + "ce5551f1fd754951a7d620e9d7128b63", + "0bbeae4fe59b4e44bed8d06f5cb415bf", + "003ba3e54a524999a0fbbf446573d589", + "e4b7056b2eb247dcb4f8fbe2786838b5", + "85a31cd6663845389507fdf35a981a4b", + "8f02b2f4ef124a5faec2661dda1d04d7", + "46da560eb4ab4c5aa83a50b6c88875e1", + "d4c560493a0846c5943f3aeea58acb72", + "75ee6d34bd184e3ab92b5383c781dfa0", + "7cc8affeefaa4e708dd0fb1dd36ef654", + "c51b8a7d88354d8db4501eb6cfb0485e", + "5d52e1d4199f4ed3a49224f967bab7a4", + "b2066ff7d6434f41a3a9745afd6b054c", + "c00eb007075144949097e9ac78d483c3", + "1da10a94465e47edb8368f2da091d0ea", + "55ff02e48cc8496fa919d827b7ee3233", + "4d406299153c455f94564b49b56bd6a9", + "868d9065879a4d1695ce10a6793113cd", + "897b5e5a269546e39add395e57c73628", + "b781f8cb073b416d8855b2f538dd47d0", + "7c4fc10c6d854e6397957ff21668d2ea", + "48b86820a1aa48ec962d45d7590e79f9", + "67895be55d9b47ecb2b6c532b1e03982", + "6ff3ec85501e444db8d0161c0dcfaedb", + "cc7460534919447ca6c3d8d8bcf16ac5", + "49b13505943f4c97a12b797772458ecf", + "42f0a41639a14d62ba6ccd77846ba7f1", + "f7c4c898f1c94264ac0108ae0a4f28ed", + "d6cc86b3e48f486887c366a452ac9ed3", + "3605575081e146fbb846eb604f33a604", + "f3167ad3e86d418dae93827be63541e5", + "2fdc25ceda4d4e4487697cbc7c218aa7", + "0f28ae23b36e45f79bf1ea212b4932cb", + "664d5ecb84dc452e82d658b05aaf59e6", + "f1cf30545f144aa19cc48655d9910870", + "a4df52206ffe4d1296fece6a1c226c99", + "cd46d738c59248ab87278bdd1e8f0175", + "e41ce871202547039f5a7a13f7b0d6c7", + "d18b2372cbb44c62adb627050af6587d", + "0e48887c739d470da68320da318b7b5d", + "c42623f9463043cf8fb380d29015a13a", + "e0d70a2ebb2c41c587906f7970292b99", + "5bdac33eee764857ad58d66903c0b194", + "ce4b4a2389424946a3cff266bc5d8cf0", + "b88bd1e0b1a54f728eacfbefb51f4517", + "1b1b5f7840074383bef7c7cfbbff9e2a", + "a26a49ae14d947dbbc5767155c82b876", + "bac03ae66a6344cea37f5a661838939f", + "566ecb1412f44137ba6dd7a3c8f5a34e", + "b7294b6b1ad64cc6b624f1185be8523e", + "8ed724fee9cf41fba6920cc15668265b", + "7a331446a653436088bc3b558501583a", + "15d82abdb77244c893429428ff5c9898", + "bcdf8a1419e74e6093df6ce21387cf74", + "64c1b93f2465451b920176b7ad676a95", + "146a40f1439d444eb2ae9bb553995d44", + "f222d8c16b3740ca98c21a5df26c8b13", + "c77abe86b516417c96bdac3913f880fe", + "e4b0e4f04ac84a498c4abdb3143eba41", + "9e0dba29de734ac4b20060ec873dc36c", + "cb5a4125a1ec451485085de830d0f137", + "8a606429628842d9a1eb05a506d1a47c", + "de59af6a151540f38ae352880c4c3be0", + "0f2b2014bb0945ea91ab650934ba6a49", + "326b88cbd4a4473aa7e624ae00c29856", + "244e006c51f94c63a95d501de5b62360", + "68252b8d76e74206bcdb266606c3f840", + "f33e2b58a6864cc68dbd6b22f9118108", + "04efa2b17050432c9452056bfd36af44", + "9783d77d4f2449feb27f9dc2d53a9727", + "72fed167ee4a4ff09193cf59f30e5033", + "e312138c4b0a4375af5daa267213dc8b", + "48d9517b6c8f49d0aa4588f1d4d616fb", + "14a283046d4d41f1a7dcad35f01ade65", + "0ac01c42928e40b0aa77861fcce68d95", + "ce809486c02b4271a5ea2370d0f695b4", + "810569e6151f4aa0ad42c4d6330fcf85", + "d9f4807850a34eb08ae635412dc5b3ea", + "023111dd9b9741628094019cd26085e6", + "824710c060ef4b218026ceb8515f7cff", + "a4f61071ea6a472684b6dcf281800c35", + "4123853f54a040c6a24ab9ed97f1b841", + "cf443036d07547abbfd1c1805225b04c", + "300ece91863242649e728e2f8d2a6bfe", + "5a4be383a62c4237b0eadb82f1ec9f8a", + "0e082f77965d4d2a81fae003f7962423", + "1a1c45db7e3c4670beb83977cb7c1ec4", + "5a5804daaa9345f48058b4b60d7a2da8", + "c9eb1731c35d4f1bacdb832fcb51f775", + "167cbae7c74d4689abbfdad0aa53d26d", + "c6483785fb2f46b7bb323704cd799ea0", + "aa1ff58f50ba4286b4e0c987824ed571", + "c061a0712df3403294d412dbee770ce1", + "1d7ccf5cf71744a694b77dc7276577ee", + "1842dcfbd32046718a7809f68b008cf4", + "86fb737b2e49406f98e0e8022c7635b4", + "6c038d4e66634fc4832be5b2d8697a0d", + "107d43ee934b431687fa659a857b5072", + "2a2adf2851034a5d9647a85313d82a3d", + "b843c63d853a4b788a6a6b1aad4b2c15", + "bfbf68d4750f4a1c91eee39b0a4cdbac", + "91be501188314db69e32288ca00e97ee", + "ba0f22d250694788a9e7bc32c5a197b1", + "8c21a49d8a7346b9b0cd6c25a0455ae1", + "ecdf0110c17a49b79bed826df14b1804", + "820130ea2f594a1dafc5b6942ee1487d", + "eb5aebdf527d457a8c815fd872babac6", + "27a3e46fa9624da599a868eade2dc263", + "0a9d9fc1e45a42719b1b215f59dedc55", + "0e8141f0200c4127a1bc12376ede86f1", + "ef8b3bdd350f4803af98be1b3fb2aae1", + "05fe4cb04803498e80ac5aaf6179cb30", + "1cdad3cea6f64a0a81e02a7aebf4bdf0", + "31259cbbe1f047eda02c2189f428559d", + "b99e094dbaeb48d58460d2a1273fecef", + "4604a7b93eb64f45bee77cca53138b86", + "cd0e6a816e6942b587846dd1e866d59e", + "acca44bccd9e4d82ba0e2ed0eb1e478c", + "2f7c073c03db4812865aceaa34440fb8", + "68baafb344b2445a8e7f4917b6fe8a63", + "6cc3855fa5474bf0a11ccd66b12ab513", + "71f34fffd6bd4f1bbb2278fceba686c8", + "38bf95fde0fc41ad8518fe33504536c3", + "74fca33df78243a8b6e38fe788d54239", + "f7b5904680cd448e964650b019930155", + "f13494b85f5543abb0f9ec0720caf59f", + "bb0b7d86c0634761b2b14f1053cd796c", + "df24e86d3cce411a93c08ee458894bce", + "5c829e45d783463aba308e1a634c5590", + "298bbb3a9bb140ba8d0c0a143b3e3890", + "ad28003205884841a028e80edb4089ef", + "ea7765a5886147aeb5f8f12edc51c421", + "e2d5eb47994c442086c92a83c60ef303", + "21558c36a39f4f8b80eaf727aa5727fc", + "1adfa1f8ed3649d58f7b4557282a9fae", + "956f9e09fd694f0c8c3d42c4e9e032ff", + "ea2f77aeac0846768778a114706eb92c", + "4da772a9a88c42e4b4fc24794c757e91", + "7accf73c2b754ec1a969af691368c270", + "f5697200004840e499702cd40dedebf4", + "5fb3005aae9446c6bc12dd241194a17a", + "211ab764986c4da9941bec956a134345", + "0256779d7f5d4aeaadc15f89ab24fb0a", + "8ef2078713b64532819fc7749fefc349", + "d6ffbf44bf3846e19528ed7cd3503012", + "6b252521d8464a6e86f9749acff226ab", + "0afc58416a9e4678bd522bc9eb477e3b", + "1cbf712727954d78ad98d67a819edf67", + "0d36aa81e1a8482d894421ff24ebf3c0", + "a9c86b73958844658ab8494a18f8af40", + "2c8c7cc2aa154388a5c321c284211236", + "c257043bc3c44a77a381a924dbe43e5a", + "a274837b742f43c9a39efb4e609579a0", + "49a931a453484cdba1e4e9403b996b78", + "ff1c862d48dd40c788446e4714d8cb1b", + "a26cd365a53b4f4eb923c5e186a255fc", + "990c417836e44d0bb0001bcd1c851e55", + "7cb872b9fc9e4ef9a6e0033fecc161d8", + "4e0cd828f3b94c21b61a7de473533315", + "2d5e40e450524898bb675f6bed7a5a2b", + "6788b9acba084c36ab40748631623f83", + "29d734a56a4340048a659bccedad73dd", + "ae75c00eff984a0a9f4ef7840a4221f4", + "3641a0f251ca4852a2441c23fa3ebdd5", + "6a275f8dadb746529edd1556ca9b6267", + "332831127f724ae8b55245abafe1306e", + "120616b52caa469597f89bd0b90e0536", + "5ff8f865811a4bba88903b2995da1e13", + "279e0e348245404bac45a358f0c30bf0", + "c5633738f2ae4a15bac2b351eb932e14", + "365bd8d9eb4846faa81118b1f7587df9", + "b18d073b06d545c78940964683e28959", + "1c74a3e3c90a4e41ac09fca2cadd8b8f", + "d384a1861d1a4e8593ed6bd7bb1a9241", + "5389a9a2b42644e49d54ca7a89f2c1d0", + "5ffe31a324a6452c8c4ada71daa12da9", + "bb6fd213034b419e9bd65d914b098a5a", + "14d4adabb2564307ae69838eb4cac51a", + "ed577ce3d4db49a283924c2ec27e65e8", + "98c7b684f93146ea8c0e3acfe8284ec6", + "6ebc71dc1f3441059910b90c04d92541", + "4979e70504904c219dc8e0713656f944", + "c92f74f868d0480eb9bbdae15d9ed40e", + "f6c249f24c504538999499c64e409f49", + "fb8ba6812b6847f8b7f26dc319c07f93", + "8a0481651bf144ae9826c3fdb6515aaf", + "ce0603388ac049d4a80500af5e808a36", + "09711bbf9f884c44958c9dd37b764e00", + "337e1aba96b245448e3ba95a5fdde348", + "c46ffa8daf9049e2b854482d3747c14c", + "44a2080f3d58431fb73a0279b84a487f", + "3248db9b720346ccad870b92b7d47e91", + "816405f909264b318e678999b2eef5d3", + "4c0fea9cf9704772907bbf07eeab9561", + "92bb9f59fd9046b1beb9dca6b21489e2", + "2176cf4a289b4c259c6cdd3c2c6ee8d6", + "6aee0ca57dab4e33b93bcce375d0ee43", + "0b7a5bc3652c4d04b40b8859d275d2dc", + "47b4af5820934ba1b6890627d9a4e105", + "a682103b00384e48b5d9648d39c43716", + "5a1593091e5d40d19ac3b842bd4aaefe", + "e820a4a0deb445669c817b0b6c57b7d6", + "75cae91a716140c3ad472ba2d2663e78", + "29ecbb4d17c34375b007a3ca4f2f6586", + "8b408fc843c840738ace44e96141d150", + "dacb223985354355920e478b3809e089", + "d4ba24895a324321ab7438e8d1d87a39", + "cf168933583e4716ae79b142a569a4a1", + "fccf56cf28384cce8ac9e7fca423f9cf", + "b503335114a14ff0943e7db911227c7d", + "09ca07e8534d4cb2a25f074ca9bdabe9", + "fdf932b04e6c4e0fbd6e274563b94536", + "3fde813eb7544f06a1a1ac0a944347eb", + "56e47cb814494e4388ba06daaceef332", + "e8498e351ad04d7f82283f029ba08d9f", + "ee9e5c89ef07454199212c4ac638e91a", + "764a9cda40d54d8cae704415cb99931d", + "0bbc5ab0e093438d8461d93afc5b74f6", + "1c51f972ffec4aaba54f5d04466d858c", + "6cc9a8fc29f04adab3fe8b008e498e50", + "2563b0a41edd4a7f9990ea38a04edbf9", + "b7abd8c78d3b4933b043115b2d4f82d5", + "58256fcd726440259cb72df8b3c36ac0", + "7661b329d6eb45c3ab6fde9581a1e633", + "b4b3e046469749ce813c95f144276640", + "afa525f9b9de4569ad72ee0603611161", + "4b53bb73e6ed455d979679b5b1d8c3d8", + "72fde976e8ce4ebabd7231661ba957fa", + "d986c02d7cf1439fa582ba3a436ec26a", + "f13afbfa6c8748bc84e640bcd18fcc99", + "9f21a2634347402888ab3930c78d23ae", + "5669fb9a087d434bafa9bc127aedf006", + "01c1d0827e214229a1057bcb6ac3da9a", + "62a41f67c53144d29f644b93bfb5ec61", + "d19f348e381f4ffebac97b1296aa9a23", + "e4b9b461115941eeaba8028a1398e97e", + "3c2191a4e83d46979e57512356187482", + "71bbb09829ab48fabe127bd5a857db78", + "295bc0c1ab4c4153b1117ee31a220b84", + "f98b0ac1146e4217ad60d626c43ee64b", + "104b4022e5a141efb9e1cde9fe9fab51", + "6df8f49f68f3417b8a759a6ebee7f79c", + "ff93e1ee1a964ac9b0d3a7b5f08b1019", + "9b7422a20f7d448b887585f59bbc9773", + "07a7bb0587774d00a15414b5126a1889", + "3f9bb4ad017f4384b474f32e150430d9", + "0342db1829f041eabc6d639747cc1862", + "23439ea505504a458f403a53bb8d3de2", + "1e477b7d7a1147089838f34b33acc90b", + "0b1f35e7a069479dae60af033e2c507e", + "5a3f53a9fb9a4090a30688c591f070ac", + "30a3a9483e824fefb8f59d5ec09d20bf", + "27d03b6a571f4b509cd44a4fced77dd7", + "b3163b89aeff40939a808b70d0d4a54d", + "b154616b35724833b8915fd2184fa5d1", + "ac4b9060e779447fa934fc4cbc8053f6", + "bea06c34bd73434faf6b66b1318f55fd", + "71b622c6e4aa4a848d9b6fcdbfc27ad7", + "da394e8c38a84529a3b98729f1868c67", + "5370268604124a978b558a5044ff76d1", + "5f4b971ab0e34eb582f7642ecbcbfff6", + "f64f5a3f80f444a88a6b341f89e8716c", + "20960256583b41abbab7da2c22de4478", + "07aefdcb6d6e41feb2890373caf83c9d", + "ac206c0833694797bdb0f4d5e930cb50", + "7f76c7992a5c49f39aa76a0794687981", + "7e331e1b5f6848a0a296eebaba555936", + "e08b0f7828054291938d948f9a874d67", + "e67a264850ae4043bb69dad7ae3729e1", + "407e232c1de64afc837cd57c054f533d", + "8013555914d5452c850d6bc91983deba", + "53d0ae77a5324c3b995305f122c20cb1", + "8d2aca4eebb04a81a1f3bfedd28977f1", + "a2f9fcfa1b414daa858616bad5bc5198", + "61b448368b3b439a80937048b3f9bb42", + "ea9725ad867c42a684bc58d21039e8bd", + "87c375347bf348b0b22297da4f85c07b", + "8ddc7865311c442b8d122fd53dbe742c", + "e9ecf5e168c0425181f4e917c43e75d3", + "e1eae1ee03a146abb703fffd3c2cf4ec", + "fe09d52222b64b50a84df30386890a24", + "39247357f19e468c9863f5370cc03974", + "f2c677828cde4cafa084f4b64f562f74", + "e265fb3789864037bab682fda1003dd1", + "2060a310cda64ca18db33b14b1c1d521", + "831dd489b8044ba8bb77f0ca253dcfde", + "88ea9335400e4d41affc7bf29a5ab0ce", + "6e4321cb0d534debaa4f959dc83bae8e", + "f3e28c3d4a3d4e03b3f64c215b5bc145", + "c3b8510cd4644f8b8a51b313ac44cb99", + "ee666f48c81146f0a5ddf9e109d2243f", + "4ad7875fbdd24c58b8d0a197a401d75a", + "c6bae6042551416790ca7af87f501eb0", + "86b5a7b0a4a348129ebe47f65e80a526", + "a6c1133849f7489d8fc8694006d94565", + "04964dd85dd9427bbfe319b17cc26eff", + "fa7c3f78928440a5851f2f6b0492603e", + "69b5dd8cd11547a08bbdcf9a0eaa61ef", + "6645f663e7364e9aa249f59e34989c5c", + "b39fd711f1c44000bae69871cf30fc59", + "4192f40b54684934a11b8bbe7833fd8d", + "e1f901eaa02f4165894b355d5947ff38", + "1b63dd4832144e89955ecf2f70e8af4b", + "ef6e1987d2bd44709ba08e4a0175df06", + "32623191dc3f470b918f8bc59b09c134", + "c0d817615b3341cab4d153422c97d52f", + "ed63306d38324b6d886c330204d34680", + "38036b2af8ae46dc83351fd81b3af1a5", + "fde97aeec6d84eda9ad6c15d6300b701", + "12764f6bee6d4d64820ec117b791d6dc", + "967f95cc38a445488fd5861b2ffe3512", + "84e0b1cc83f84b7698532cd982f02b4f", + "81cd05f3c461428d80114bc2ed6872ea", + "ed8da506a6024305a610848b0cdf1217", + "3904652d6f844298b6a851697d3f8345", + "54b78d37edc248a380c5112935465dbb", + "4716650057ad40cc9610998ff7dcc725", + "555cb39acd4d4fbf9801ee82feb7fa37", + "9c470dc0669c4eae8fbbdcdf00ac670d", + "434b2d35850d4a16980dd79981d28443", + "7d12f133d9044a17aacc33d16204bde7", + "f5ca70f46c5549b8a754ee1abf42af68", + "0d208886a539477a8e871586f2b56a95", + "6521efc833d64f44a412ea1a303806e1", + "ffab08d869334ea6bb4ddbca5f902fb2", + "39ed1da3a6f147a798442ec8bff58bd6", + "3c6b9e478ddd454cae78b598a70bcaff", + "fc55e924e377431dae4c3bd3b9eb0197", + "85611a5af04d4a848c3efaf3661716fb", + "db4f1f8f757341248818540ffcf87364", + "5eb55023bf544014a11203adaa8ed9ca", + "88364d4f76bd45048f6c3c7e2ec5f752", + "21b5f921343d4078bd32b721e9d95456", + "912e06625feb4a38aebddb636b604a04", + "01c7918e11c646b4886d43c45dc323a3", + "7bbce918be1b434ea5c25655e6eb3309", + "f6f0abfcbde8425bbeed46abd5c51112", + "e2a97d89d83e4639b53cd2b4b2676bd2", + "2d953b63c4514617ac0fb10d3f601a41", + "1418f746c19948afb20fb4e0fe52348e", + "fa37cfb2764f497ca0b07e27870eec4d", + "b9d5c1b5497a4395a9f13224307f20bc", + "52c7076d511c47b8b30acea6edf47f78", + "f029e2d321ce4686b5490616ac265fab", + "a877896991064296a66d461a8e62e62b", + "c936331a082d4a17899522e6b050bebe", + "bc2da71f58e24612b609a2963f9472f6", + "15287565369644f086a9b5051a6082ab", + "bed87049026640a59f3f8b5844614253", + "45a169ef98804f06a9b7a4af1a04d6f9", + "9fe0f5f34bf8416bbe5850a8d069e2fb", + "60750153857c4559a59c761da40c69e9", + "8182a295ca93401b8e3006da7174e198", + "2e7a4fd41a0847d7a98f9c0ab55e8652", + "8a092cc5c02042318891092cb531f5f6", + "1ba2620fab2c4433b5184a0514d46bb0", + "5bab6eaee5db47b79e0bddbfe50eb0db", + "48a50fb5d233497eb5967a23ccec3d9d", + "e865bf2af35442289d39bddc362919cc", + "58ccb06f1a664f79a0d33b28b8e63578", + "a1de8398597a4575a9c9a9f0a6e4dd2b", + "8f91f94beac24f1ca6e2778c7f6e9899", + "e74e2e3d22a744dcad7c944118ed76cc", + "0adcf1771a3c4b5c922c47dd09d149b0", + "e17f4ab5adcd43a8a2e88601fc21f4ee", + "3b72e8a8c97d48e0bbda1bd488b1bb20", + "c68e6c50b4b040d780e3c137965a97f0", + "18b53b6f404242b7a680b2a97649ec7d", + "b809899671d043d3bbe76d0505ab1d88", + "b2a4383526264bad9d87e5bab49e7a50", + "4f6c81b0b3654f3e9cbd1fe2d29ff2f9", + "0d121ca99e3e48ad943fec3166c94975", + "1cab4b56966a4b49bd2f3c6f32e5021a", + "ea57a21eb7124457b13b1a9a5bc33625", + "f7654b3f336249d8bb6ae12503e6b543", + "0ea33b6617174530b97d6b7a92c275fb", + "947c7e0c834442d3b63996088434efbb", + "d5f185b1176a487fbb58e6665a66c868", + "b005d2125a1545ad9e0994e0deb5e82e", + "592660a89c2144bab3b39339300d34b7", + "6e22216e113641cdbd0d0588ae4dccce", + "24cc42ed1dc64366a5146ca4665025bb", + "25fe9c42f0f446bf95ef9594cccf9610", + "a53a2477a11243be96462e9061f8315e", + "885ae84e85ef401ba0f7a07a81adbb06", + "2820827abdcd4e79b7c67683292416aa", + "42385f476b2f415595296a0bf6eb85e5", + "85a7db9dbc334129aa7cc60156082fe9", + "e408c968b0f44a9d92ac92ad390b608a", + "68f32b04c7f142f2bfe87365f9832fc2", + "56df1826f18f4669a99fbbfb1204e706", + "827a77638bfa436f9aec49bf851fe00c", + "f7476bbd8175430f9266326ba23dc47a", + "cb300fee30354525a4c8d9164a099c42", + "4a0f306ba95144fda533b329818d0680", + "11773c2a6c494c3f80492e3c232ae884", + "1bc786bf78a34e7cad0b559fb7391a47", + "66abd679b8934298ba8af35db56d8106", + "eebff658809147f6b1738c7156dffe08", + "3928451863cd407488dca50179b19ffa", + "b9ce3cd0680f41aeb056b9e6d4009157", + "e3b478e193ec4c2a938a9475dbede98c", + "0e9dca5f9ee64979acc14122fb43cb1c", + "93dca1aeee7d4ad28005ed9afff280f1", + "9bae7e7d44334b9bacbf0cbb6d038cd6", + "ee2c9fb3fbb041eca63157ad3a22e98e", + "4981429746804c8a93732dfe32afb397", + "fe191919c0f34c318536aa1d3a3a794b", + "35794214c74b4198ba11e9612b280863", + "5c36e77b9c61462c8933f553bbe63410", + "6170805a574d4dd68fc0680947d8ecec", + "f00aaf90dc884a1492a8077bbc2e699d", + "237ebd5ff4404cf3933b34ef43738994", + "9486748dc89d4aae887a48503bf18e6e", + "8feb2d0355754e8489442abc5bbfa1fd", + "935533fe2ccf4fec84ca8760f6add3ba", + "f1b4f7a525d24ea9a49b80c5d5969785", + "c09f99e0e6944209b5ee4eeb52731c84", + "a9b2069741404f6ea68c3a00b2a231d7", + "74c33d16b31346f1a46a55c3ec8e8a78", + "b7a91603be1b466b8c28a16956a264ba", + "335097ccff7e42adb5932711f4009d6b", + "9817b60dcd404fddb5ce16112fec2fe4", + "2809ec55e0774a02b457030173debf3c", + "ed58301fd5854d9ab6341f9c86c97008", + "698909fb744b4ed6b708b36606cb7e98", + "e5c153eebdb14589b8b22126435023f0", + "33732781d11747f88b1f37e9976e79bd", + "8a451338b2194387ae8cd6140ae51c97", + "c507cace6e444f77bec6d940adec24a2", + "8efdf2c4df22485a93cf14657111a1b1", + "0bea493312b44a74b6cdf70b76db5d8e", + "ca0ba4fd910448b5818e0fb74ad5b412", + "953deedf5387474daadff16a94ad14d7", + "ad837c6229fe4a82a1a60dda23c8a1ef", + "f9648345dfbd45419be2fcdc9705edb0", + "2d44fd75427e4d7a8c029137b0b0d6e7", + "5eee9d9172dd4738adc6a1916f53eb1f", + "1f97d868ddb245bb908342267ea316ef", + "af6d1a5cb0c642b6b60f5df70418c331", + "ccfec74015ce407487891074e8d65a50", + "17a53efb74c84681a8a45429b7486fa7", + "a255a76978e345fd804c887fb2da626c", + "dd79fddb754f47caa3145e7d184e3e58", + "08be0df170b44c44842590bdb3ad6f9c", + "d86c81354a564f0e908f4406b9d2f2a2", + "a9ae7bb81e1b45d6855457110ef6d3b8", + "9270da7e351c4986b6f3a7115c1319ca", + "8903ce6965504b1c831c2eb3a5e2c151", + "9e3a5d1d13324bdc9e9dc5a4c384d978", + "9493e95ec7cd4a218ee521acc550bc45", + "e85310002a594da0a459a37589b346f6", + "a21d69b84aca48e094df473cb5e879c1", + "7f06e4427552437ea3cca5c4f067a155", + "9202fac646b14e849eb290fa000b5526", + "0bf35c07e9f54d9db4bc13d189df1e05", + "8b0f6cfdefce48489d49f4700c5550e1", + "b417988c73894f6798e6ad503432ee20", + "0284d6ba1b13415da4be3c7ba6a7a622", + "3dba2b6e4098420c86be2a45c14f1ea9", + "fc93c3f26afe48b9a94c009cd8de9aa1", + "743f8b977ec24c28aefe40aee81586f3", + "adf60e42de904d3abb1d45d3ae2c20ec", + "8a7682aed12346c8abc9a5735a966410", + "aead6bb3bab344eaab541c5ac52c657c", + "ec9be69afd8e40d2a92f8f7a3854d13d", + "400b2f945fb24beaa5e3ce576670144e", + "ebbf71cb537c46228d7e8f220b8f9af9", + "48e4219341a4458a83c443fb3f0ff8ac", + "9840188c3e214587b97b979a0c5b1263", + "933b7b4256bd4a10a44343419bbae2f2", + "5fd275ab07584e118289c7cc28a6bbac", + "18d738a49a2c474281a2675eb35de9b9", + "a303ea0d14f04d75a32f329f6ebe3531", + "2cd1785b05cc4a70b8b7c5f6344a52f1", + "44f8899569284a22a283dde8abc4b6d5", + "2f6f4c5799c84ce1b05f6de2e04d5a21", + "cb7b2c3673c24d24a9615ed864735a31", + "7a06fa90bdc1481282c5d388fdf13691", + "e1ae66946e6a4e07a670767c8f141187", + "6acfb5d8ccc44fa285121e45d4b25bbd", + "227c0e5245e24f46b700339707c2410e", + "930d7e4ee4af4b8895572a79b4ab6b2e", + "1436c0030b1a41e69041dfe5bca52e01", + "bfce6e6485744250b75615b3d97c88dc", + "488971e6916b471a82faeca36442883c", + "46240f7b97a1467fa42532490a58e0b8", + "3914ad05eb9342208bac51b1b280bae9", + "f9e0e8d51843410daec8981f10003b1a", + "c88c3221f0b9436293a69a641948c36d", + "f1a1360364434bd0bf91eb554e7852dd", + "e8d85a62f2c146ba9e2fdcec3cd4e6ab", + "54d881742c8a4e2ab58c9c013a46dbc1", + "20d9815b99a74ae78b2e4d39c924f864", + "62805680de084214b42b4a966076dfc7", + "1f0d16d569a442f08fb5478de09cbd3c", + "cf4542cf2e074e54972574b24768acf0", + "27fe72e584fd410caa7a1cf513dcb8a3", + "05d390d260054519be59659d5404d940", + "9eff77e9c5974c0d91418339eedccccd", + "d5e75ca7946e4b5c9c54fb9fcdba705c", + "aff2339066e145a78cd7563fb495ffb7", + "db3b4773db17478786595286215e3061", + "5fb6ebd7cd6a4a959742bd36ef781f3c", + "e8b031fccedc4d03b5b2e6ee0112c0d1", + "02f13c9007ae4d5ab6c861f26341f441", + "3df7e953110d4b079cc3e00be5a4fc8c", + "378d86a1d6b5456dbd8756e41b140455", + "d02f31c006024021a7427339b7d08ec7", + "39c3ac74701b43b2af526437902bb98a", + "00bb9a6f4a4945c8af95de4e6b9178a0", + "f0ed46d723dd441bb592d715db241097", + "eb1f64ea5a124883b14b9561b93d50a9", + "d62cdacba902477ea16ad2268627fdf4", + "8bae3f0ef2d34f388f677c479246e2fe", + "fe17f6e666554debbba5b04ad7a51a0c", + "3c4656e7358a4b809498aacd32625d08", + "be6ad0f4c4534eafa73b1269852615f5", + "0c78aaf693f44865a06384e0c6a21103", + "44d825240a2e46b09b34d97b080808eb", + "c82089b44d8e4eb9b8bae8a347ce5d71", + "8096984ae8734db9bfa5dedf89c175a7", + "591744644cce40dda9cd78347947b624", + "19adf963579543cc969f41740d18a2c7", + "59783297884f457db1b8fe7362b27a59", + "314a281c6c7b471caf658ecb9b251cb9", + "b2fc25b82b5247efb864efec9899ca54", + "3ba52a41b4b248df953684861d9e7a20", + "7189f8017bfa42caae56cfe1b1d5d193", + "2127d3e788b24e1ca35c8f24cbe2db88", + "c024fd9af2dd4aa38e3821f7ae8edddf", + "e9f40d35ed2e4b26a3bea2254f64e200", + "ea61bc6d27bd460eb328c2672279eee8", + "9090813964814c8cb34a63c63441c631", + "b926f529275c497a970dd8e95c2460a6", + "3f2d4f5b962340b2933012e1bc634d88", + "0c790db61dab44e3bd7eef87771c78a7", + "8ca72ea7475241d2a47f568ce7d1b18f", + "6f1ac304029143b79f038536d79480e6", + "30937c9a9a54454d8390b050122b14c5", + "bb8e91efb9314d2f9f139f1ff565a1c3", + "a4d6a4618f554e5986fd94e04720488c", + "6ae2bf4d943b4e7eb2df4e21edc8c513", + "e3d033434e3843e58a62b8ba998a9849", + "1bc5925b6a9c46bdb979a62c93cffbfc", + "afbbf96ff6884bc3a73a183a4774c8aa", + "4d0db60c85104d8880fab712f158b0b4", + "c3d08efd7ea74cefb89c0af9d9332877", + "127f498b23e14b779bebcb1c49e8ab82", + "17010038595b4702aa697289a7ce89d4", + "0d7499fb40734911a5f9b5aca700d03c", + "e86de1f3f4e14bdeb2535cc476dfb1d7", + "ea9c0c4d033a42bab8768294b392a85e", + "0539d9218ee645f2a21e79c913f1aad9", + "defa3859b9e24c40bdd24fa6447e34d3", + "0d6c4d23bd5642a1bfcc995fa8448ac5", + "ccd28aa0c67c46b0b9f918a58091fcca", + "1b79c965ba5a444595ac395f6a8270a3", + "02aa3d2180c64a95b990a8b89d05a552", + "452cd113b13f4be38c75a43532713058", + "0921bb6998d74a58bfeb35ae12660eb5", + "7b25c3e8b503472f9229e413d2e8735e", + "f12cc13dec7b4b7282a51afe432ae808", + "1d6f87444d75400bb9098c7c3b5044ef", + "4e284b8f8a8f45b58850636efcc54075", + "98972a311e6042d790e095c0dbbdb70b", + "40911c863c8b438fa4e03ab0561a2472", + "cc284b0624a44d6e8318a275b9110590", + "5cc824a22935448bbf1c9f5d13249a7f", + "650b5892cc4649d8a6649a8b8d6f452e", + "a1b7c76f69a94b6b809646208aa40d85", + "38232c0c87d641ac8632d846de3821a7", + "38f89db1ace845df824bd72ff12ee10f", + "fadefc1eee3246a189f6b79c7c671343", + "115d7246cd1245fdbcebafc8b0310626", + "b63f65374f0640f69b3fe7a95e2cbc8b", + "cd364083da2d45bf955a856e8e4a8cd5", + "3ba1d322cdff4123a8e5e379e6fb7bcf", + "13f792c9c4a548819a28422780ae9bf4", + "236fcc6d88ce4906afa3a4f577e4631d", + "b2b3622f96464f23bf3c3c0b10950194", + "10778fa3aaa2462c96b5ec6aac50a80a", + "0c904d20b41b450e9f9225e226cc9eec", + "fbfe5855b91c49899cf446f52a7b88a0", + "8899c8a210494d9180b3fe18ed478282", + "f1d328dc5d49429e8b381ca3c38a25c4", + "f6065012e12d4cbe9a7dd00eb7511d89", + "a28b786d5dcc4374b15cc4d04e38ddd1", + "2d5c6f35931c4202bacee5742f732f2d", + "af01ed1575ff41dfa5dc54fb991857f9", + "ee2b3318a6c1477d95471effc2f8d38d", + "c20c815f51f24e2e8b7a3213c1b73051", + "a9098fe82d7e487c94fce5f861432768", + "388c3230515848cb9c07724f2230af43", + "aea414d44dbe43c79deebc3e1779c9f3", + "10bc1bcc7cfd46e0ba4d109ec19b8c68", + "63d17fbca2474017b9d2bc5031aab649", + "7b4cfa7ea96f444f8941c14af9e57844", + "c40379cc02d24defa9ce324738153930", + "9b48cd99f3d846beb317b29af3f36d5c", + "3aae6d64f58443d98a879d525b166f46", + "12e0873aa1fa45c88a6640419d3da99a", + "0dd620043178479db6752ab103b1e04e", + "beec3e9f2b074b7f90e965e2a03bfebb", + "9424b9ed7e26414ab2871af263a2332c", + "b4ea7af8484c4c7e98704585b70002e9", + "2f1c0f91ee594223935adbbdc9acd663", + "33c32453fc834a51b35d87c483283ef3", + "44b45ae8126a4358ac49321c538e2c31", + "bea8441c08d94366b96b53775391d8e6", + "380489de654244f2a255bca0b4f810b2", + "19bacf81f304491f8f472824279e5d66", + "a80875a2054345aa8afa79f20dcb3ddf", + "80270b80e9d84d53b22aa6d300c5e4b2", + "f39ce19b92e246268f4c501b72ea7d0e", + "07c5c681dfa04593b9e64cb85c6b2876", + "736cdc52e3b3484fbc201c941a88555b", + "8d56e83387b64684ae7a1b4a20040d67", + "272ce2e41dc4491987e17ff476d50b27", + "13f420e3a345428fbb538b16564138d6", + "664466bfb15e4282a8dd4955b1d11e94", + "008e9eacb9044b11b358a0c2bdae1934", + "e46c16fd3f5e41e3813caecaacf48398", + "ea40e26803d045f1b93f225687b64797", + "8ce88742f3ad46c086929a4e303b5388", + "59ed9da27c2d419b959fad13027a0dec", + "7c4a25ac913b4592927cca87792eaa11", + "1596b8cdb2ce4160a62556a2419e5b95", + "a77f8c86090042c1973db829e3fb8b1e", + "2e18d865b85941e59304719cd325322b", + "60c2a1b0a3004c979fdb1ed1152ac018", + "236f4744f3934242993b0d8288deb185", + "b036f90734a74ebaa5a16c089c08a1ce", + "5f78323b23bd4062ac87bcf811066e0c", + "a52703fe238f47d88e87daaa3183b0ae", + "e83dc29e69e94ca7954c0b25d52ea3b2", + "1290508942554dd596c15ef549aebe34", + "b7ad81c62950477883d3c2e1e2c12287", + "30abd707af3e44c2993431ba7ed697ad", + "8b51a94040254d5d923a32b203d94a47", + "28ab910901224743a610788e99112025", + "3368e91fa2a8404996b81244036be4ee", + "e282fa5aaeba43ae9c1edc7ca649cd6e", + "b63575aa9d3441ac8992a4a8fc5f0917", + "2179f56c4d4645ffa2c70c8e707b9065", + "66e95a962ad64383973ba6fc0013544d", + "7a9f2eea6069460793f5d3aedcb28663", + "18643998e46241ab9fcd34f9189c1e2e", + "181a0a6601d14af0ba5b9de3f5e398c7", + "0a597869a5fe4d07b20034a440384fc3", + "5fb750153d634fa5b16914c34d78b5ff", + "ab60b69424b242bdaf63b0857415ec09", + "6eb4212e70b941a3bd2db196a47828b9", + "ee749848b94f41a78a13b5efb6019d5a", + "ee70a460b9dc485f81eed2dc0ebf8619", + "d82a2ceda86640d79592ea5ca5544cbf", + "64db37183cdb4660907ed279a8f90705", + "b729bf790a7e45fc94cdc6a159442e85", + "581ab344e5a948ac8a9d109954851038", + "9ad437c7bc0b4a2787a425a1e78c3548", + "7cce16ad3deb472086c9997e01884115", + "aed1aa465fe84ec5ab16d6cdad1ff78c", + "250966247c42462c8b69d6c9af668c29", + "884a54d5697e4026b69eaf1ad51f9c58", + "e9cd5d1e7a0849ffbe37cd5cccba974c", + "3c82f3aee0ef4573a51a08c84382e9ee", + "f0f2acced9d54081a9f225558fb58ef5", + "b791cb3ebcb347c6973d0ee82a8a4cc8", + "6a48d848235f4dc5bec22d22e25080e4", + "6fe82a439ae8465e90d5d68ee0420628", + "1f4e5ea82d9e4e8bb6f4262f0355c7c9", + "52f6efc7a7a540d89f3f3eed0922c1eb", + "8a83411fe16b407a84fac1bfb4826221", + "ed28409333224611b31a89efe0c7c940", + "0135d63c4b1c499d9f7bfe103e1cd2d0", + "de5b245bdc464756864fda7754fcfffc", + "22798b1b718749608a0e729d576727a4", + "7ac01f6a83b4439baa4a83905add294c", + "2cdf0cbcebee4a7cab7d556c00d3f633", + "4ee2bb503921448d8b146763c9ab96a7", + "8a9b14f2660947e68de1a42687bb708a", + "c25119c5ac6e4654be3b75d78e34a912", + "1c17e217e6264dfda3d343a311e1167d", + "d5f82831026b4285ab0bf60da9b91fb9", + "929ac6fbe0ae4471b3a4f71b748a2efd", + "17e0f62253544acb8a369a0122fb02ec", + "41cec47f5a354e15b8ea8d82e0e3a2fd", + "8daa31bb8f80438e8287da51d110a6d0", + "f1de4fc390db4266a509b9739350512a", + "d781b21bde0e4fcfa7d46b68d6df99a4", + "85bc7daeb1d74df981a828b0c232895c", + "c5d028171d4043859c4f7f73ea470691", + "8d026112f0bc4917bebb5b24df726abb", + "a51751c9989940e592eb61be41ee35cc", + "bd8a50ef7f4848339a02371edc07e5af", + "f6dba1a3f3174cb89b4ec110e150c07a", + "bdc9ff9778da47bdb04c61b7002d6672", + "16e57998c4854547902d2fa9ddd8663c", + "7912b324899541aabc80ab680ce32350", + "e78ba0c19f204c778ff4c6306824e0af", + "fee48809247e41de88dad130ab9b339d", + "5b8e0438053f4f65b6d4189f23c7bf86", + "8cbf45a2faa447f08b6244388726f3c9", + "e205fc3ff5d84b65a4fd89c68af6068e", + "84fa9759a05d49c3a7e513953686c322", + "023b4424847e4d018636ac9f9512e273", + "9affa340947c4ec6a2712ceff577311d", + "24e084f8ec9a45dd81e2b920fb4f05d4", + "83fbf07f457242249146b2c0964723c5", + "5a15a88a9dda46ea8728fbb1a5e38f7e", + "7b151941772e41af956623b5e768f3d7", + "ea87c9bbbf4f46cda162b104ce2849e7", + "18d5314420954151a3dd5f9413ba0ae1", + "77e50d3e45a04e63b2c2fc989bfaaf81", + "cc4826bae86c4ba393b4147c75912027", + "213e9c4168c44f138c43671e5d62a2fa", + "59bc3d3f46a44d5ab506bbaf7ef4acd2", + "ad1943a863cd4de690ebd1139967c0a6", + "57f55dba6d81428a8672019aab2509e3", + "a8d11ec939064c009b726de5dcedbda2", + "a8271d31463944f7b2fee83143ad814f", + "223a4df9f3d84f63a23575ab429e2ca6", + "e6ad3ee7167b49228d9bf7d74899ee91", + "e0d993974f054f0a838d43323de8140b", + "6fd99dee17cb4af0b7474bff3114d039", + "346c33840e27461f869b1f4443b45926", + "755189bf58a944ef9c246598ae31a7b1", + "77fd9b44d011439db767c9c24b99f187", + "8b6875c0feb64b79b4119de7531494b6", + "0ffaeb577605464ea57c38d7157417ab", + "e427c94cb6ae428fbbd22a8054934e67", + "e514f7cdb20545e892774897934f5c97", + "e54ce8520d8c41f1a042636010e73de0", + "cedf44b8e6ff4323ace82b7ff34ecab7", + "4f7cf10593824061bfe2e36ffd823cde", + "115202e0823540b0aa1a76b4f510a5c6", + "667f789657074af1be75061cc7dbccd3", + "c2c1282dd510447b8cd0b95f6c4ce44c", + "67a5956349574fac8431b9b12aad8b81", + "eb9eabb6ec0b4630bc28714a097c9c9f", + "fca3293dcac3417ebce7625f5261275c", + "f6754f708abc42c7b976b99133fba037", + "7a2bba14422d42549c1ab74de258425e", + "033a28e3c13f4c24bcd3e24d99368faf", + "d076b147c2214633bb1e821895093039", + "5c516f5a81e5465e8bc530fd11c92bb4", + "b2ba89f4c1ab4062b94eb1ec61731ac8", + "a5e397b1cdf3457a99573683198bdcea", + "df406042e86f488ebe67a107d376695a", + "1fd36e30960e4aab8ef6aae2daebe451", + "3fb4343374304f51ae190d2a3625a302", + "7de128021f884e4eadfc5e797008763a", + "b899bf4692754eb89a10abfd79b10ee6", + "900102bedc6240b78a9cf779935fc837", + "a2153c35659347879d1ff9ce5b796100", + "6a7b6a34cd2d4822bea3aebca4746b78", + "d01c047280964c0291f4afb13de864fc", + "f096f7e1488d49ea821aff5d7e211374", + "01d66f741763454bba51835ac31a9af4", + "ce8b94b8bffb4172aa6fe63499d47568", + "793973cff95441a184ccba99df5c7c3f", + "842343e7989b4a28b36914d6849b84d8", + "120227461efb43f48777e8fc13b512cb", + "3ecbb2c1de924ae58f4fda67b3d160ad", + "38716613af0049e6bf0e54e71005e43a", + "4d9773f49ac94864bb0b1e935856d392", + "b0774e904c284e349daa0c2b8860e811", + "f7839b56dfdf48f5af95fd5053e5c7a3", + "bd45bb0736e14a2880e7299f11186bb1", + "29239105002b485e99e02090552c01f0", + "ae0002dbfd2241488a8d0a586925aae0", + "78b8386266f74ce39e066366c95b069d", + "5d87131def87474883f7c7254d6ac313", + "dcf445285b474facbe1bc1104f4aaf9e", + "0306b42594fb447ca574f597352d4b56", + "f981e04ed88a4dec86807ff1c005f91e", + "440afe6af0724b5e9c5ada5a754b28d4", + "f8abd9079f194334ae9be4f0a9f8ce49", + "fb777ec92c2a439bb1ac45c3be550f7f", + "f6fec9539faa4556b70a087736491f59", + "d67ed4cbbc0c4477ba5d89413e715c82", + "540aabf3688542a1a151169b786d4696", + "0de1fdd544c3438094edbbe1b01cf391", + "88d595c0fdb641e2b880a2a3089ac061", + "009795f69072466e9a71b70a560ed2df", + "a51be15d59ae4bc6987ac6d6b8c094a6", + "738cababdc3a427a84bd50ee441263a3", + "d9232d8cd4914992896854058199b961", + "1e06b383b41a420cb980ebc8f23422b6", + "6154520a963a4bb099642482a26aa9d3", + "45a59784bd7d4a7bb503626136d39879", + "f93bb826f374423681a4772a3c49c1df", + "4b629f3bc9a54fa487cb3f62eea759d2", + "f86b892662bd4853b415d67d45f83db2", + "d06965e6712646328129388b32c47b96", + "f9c822a080e74c4ba4f58537e34d3c52", + "9aa18b0d8ad44203803c95dc85b3bd7f", + "ba199e44ee6044feb59b8a369f795213", + "750152f4c0604191ab9cbbe160252c67", + "a278bfbf2e5c4523850f1c992770a751", + "bdacac78cd6e44d5844d1d7fde3b08c0", + "8ab20ab8b3e549fc97e48923c7f287be", + "d46e8e7c53774dda9b9f84abbd07cafe", + "efb1a7f8606b489da1ce48f09563b32b", + "e6892b89a01b4059b505975cbde5c2c4", + "427cdf4fa9f54b4d90ae21ce135162d5", + "9eb45ccbc540440b8308001b50b5e321", + "5f9475aeea2343d29605c68aece4c9ee", + "3d34b2b8c97242b3b5075cfb0ae2ec94", + "674b6c07743e4f569d4b745949d1a0f1", + "7a02accdd3164eeba2a02cb8e9198148", + "7a46ac92f9b94da6b0a0e02a9e537f4d", + "89671b7362f8418d9ae32c17a01c22c7", + "559abfadf5a542f0a18b79252596181b", + "e1cb73bb23be4e159c507010394bda48", + "7db0f8fc51614db4a2313d75154bff6c", + "3fa0d01bfae045acae2ae91eb2fcce8c", + "0bfbca941dfe45c797dbe9224c9e3eee", + "0fc6bbf6b6a849bba6c4027382e83e6b", + "f97f99da8c5140b1bf8ec9606cfc3bf0", + "287f0e4df2864e63a6a4ce05eec5f938", + "8804582d562944639552a8fe8bf0de50", + "f6a95133bcfe4e0c89e6240465f07e5d", + "defb1b6416d14eaea97f7d79c34e8fed", + "da8e2322f9e24659bd8236bcf6bea05c", + "5eb529ca7d8a46f5832c584c80b15f00", + "b0e6394b0d4f471385836143444a1a8a", + "580ae02e1dc44207bb8d412e520d674b", + "2ff9d99775254cc5a393936f13a0c105", + "bc0fb370e8e342ddbbe144b428fd1dc9", + "2387e678c92249d09f673dc87eeba108", + "da6ab3a8f5554d6ca485bfb5698fabe9", + "ae6ff29457044f2288f9b209c5c38c3e", + "e15aa38efe464b7880cd02b10d0fad71", + "2a5f52245a6b42e59cd184e84d662ec9", + "69e9188b8ea64785b39f397966a7a94d", + "cb4370c2bce047cca979b176bb4becdc", + "ee58895d55c94c2ba0a2e4b6fda67f1b", + "6ede129be11e43cea5c279e34a7eddaa", + "d6892307f73d4959ba36def29430389e", + "7e44ec220d0e4c8b8901aa16e5523bf8", + "dd20303e82654cbd91413da0548ec608", + "2a20442dca0843409111f0fc6dedb78b", + "b8124524fc7e4c5a883d8263759c996a", + "6d52fececa91486280d57d7d9d101b1e", + "b8736912c99e47f2ae635c9609a803d7", + "fbb8c1e6beae4b559c4f12aff3189df8", + "3efba4a378ef46a19ae667ac0073a001", + "1656d70baf7f431da59b6b622b1f83d5", + "eafaa4e2d3e648b486a8df83a188aad8", + "6b2862c241754f5d81690e8664e41091", + "562239d70cae4fc2953aeb5c20535325", + "47e49580cbb54476af742eb36cf9e8ac", + "f9a8cb4c7ba346b7a6ebe49de56b70b8", + "e3d3ba790b3140c1a67595fcf6f84c0d", + "775e22047868419886c3f953f3d75c34", + "88be308975644de6b6d188915294f5c2", + "cffc10e705634c6cb3eeb23ad5d7309d", + "0c58250e3a7242e9bf21b114f2c8dce6", + "8358c7e52d1a47bb8fbf80f543f96a0e", + "236d43744d2e42db923b0dbd7ee0e911", + "135990262ca441569bc76dbe13dbe6ea", + "dd108faff010488db0e4eebbaaa2cebe", + "da8bb463567d4f39abd0d5be860243ea", + "a888a151fc1b4272882a46a3d0de3abd", + "5b07b536c93849ed875a837ed8bcbd6a", + "e203bfdeb69d48c98b89ff75256da460", + "fce7d5c2b90249f0954f70348d0fe388", + "19377af687894641a07f8dc9b4871137", + "5bc467cfa9d14408867db9af17e128c5", + "fb01aad69315400daff108fdea76f361", + "76dc9ef9c665487a97a5d993fd26c468", + "2059f8532f784242b40f7050a9c07db7", + "cc05187d1647454585f3ac0871dcc8fa", + "2f4380b489c14efe8ce585cbb45cb161", + "541843465aa847e88e5aad30826359e0", + "8262743abb7f4f759aa0b3bda08551e5", + "b7a63454b7814967a460f97ea2bbcbfc", + "9429dcc709e74c968cce2290a377534a", + "32684986ac4548978035735edbf63709", + "d9e06516940a4cb3a2b1b95f1634f381", + "5d300f7c06834fe3b8f11b3c8817e7a5", + "ac692295b820429d8ba562fa17c7b8c3", + "ef539820b65d45adbab3708609e1bcc1", + "bb0a8ec8d00444d8a9956e0b1aa1913d", + "dc5a0c0c439942d58d038a10d7064c91", + "c084206bbadb4a5999ac69c35be0ece5", + "664d68c3d6b34ebda722e93b0ab2b058", + "6bbf702760ee4f4dbf33c02cd6f35adf", + "7d572663201440f29ee52ae87e1a7bd5", + "2d677e5c0469456f9303111638f1a8d0", + "55fed44f625840648db149a97ef52f5d", + "93e44ade0d8548d3afcd5c2ce01203c8", + "13ef8c3671204fd3924b0db9a05b21aa", + "dd4794ed162a4fcbaca147beeccc9c96", + "07b934766bd84c8788ebc1b36d4ee5d1", + "7160a9958a5e4f2cb3f6573c37d6b558", + "a837466af09845cb9b182e98dea872e0", + "3a0feca29d0140b89621cf80d1d97a09", + "f08dada8b253466daff7bfd6445c9e41", + "418162498507467eba2ff5e9e865fef7", + "7953cf2a6bdc4e6a9eefca86ce5900dd", + "684d6463e09e43ea9049e63b628b1721", + "3532b642348a4b88885e8f9e802f472e", + "0852e06cbfa74b52b6c6c913182d10d4", + "b584b056b9344fe091d7dbf6c124a406", + "28fb62e117f94307b30562497d49fc73", + "0378f066b051434490640aa4ccc7fdd0", + "1060361948a049489e30ecfd98d0fcb0", + "7a6c126ee76c4c10bf405494a3e19d00", + "19db2a66d51e489981f0113842627b0b", + "5171200a96f84b3ead5761bbdd3dde33", + "cca5f25e7e084df7b8c132d7708a71de", + "e1dd297afc154b76a0fadf06c2bc4dc5", + "e715ab67be934a108d0a952d90c07210", + "52cd472a53664b89a56aabde996a4a2a", + "6a4e8c22280b46eab35336a842b1515d", + "22353ccdad8a43ec99698f89b1d7bea7", + "ce49933eb26e400a82b36e920d79c22d", + "22ba30cf34674ff4b9b48f0ed2c3358a", + "ee4e02d868a34a7f87a83e45b58132b2", + "f757090ed58a420e94ae5454dbb4d43e", + "33ff3433cabd4234aac2927e55a0ae0a", + "db2bd53ece4c43e087697847f19ba36b", + "322f856e70214a8991ad8a5c0a05b920", + "97c6a7860ce549bd933f55b4255f1162", + "99ea55da77dc4441b9e66c45c2496e6c", + "667bb1e274cd4d9aa49141d7d5e3ed04", + "17e4ece66d4d477f942c0427ab45c8b5", + "ca1962844c344c048d5dd90d5750a610", + "4e039f56282e4eaba43c607dcd83e9c2", + "5e18f410ea20470ea1efb0acf6b652ea", + "f62122712d5f47b3a6b67120acb39f1f", + "6ab4a3d94a524ae78fcbdf811eea9b88", + "38f24c1eb8ae44d5bf2a4f9b940c96ec", + "4bcb32f952e940f68d74635f00aa2205", + "615d65e63fbc4d62a3e28e6fd781ec49", + "c9f7688b9b0d4e2ea8e660c2b08de980", + "82c85bd968404837845915a534e6a6b2", + "f2cca00a043041038234363e0d6ea684", + "77f00280d56b468381d75bf9392496be", + "f0acb761248b489689ef87c726d43959", + "f015f4de3fbd49aab0cdbb68245118f7", + "4e37b84aa5e1487ebb71c70f5142a318", + "c573fc6820fa41b0b1397a3bdce3fc0b", + "422c33bb68b5434e9b43f634964d911b", + "983fa8b23a084f5dacd157e6c9ceba97", + "462fd6084b9349a1aa97bd19528f54de", + "0796e23ab5c0448c9bdf3fe5c3b3e362", + "a2f6fc013cb64b2b9151fa40f84616d1", + "b47930ff784f4377937d51049aae380b", + "a5667f86065f45a4a5721bc4429f6d39", + "437380ef2bb14d7bb63e41c26d4d1362", + "9a4bb1dacdd34654abc09367da5e03a4", + "91bd399ad59947f8a232c66f4b5d4a12", + "4058a3ed739e4f9f89f49323c7db4b4c", + "38f73127c4cb42a68f1d4d65f1e592a6", + "0b4c70c0d73d4f259998d5898e542104", + "f3369c7e0a9d45fab722c3f5bbb9c9bf", + "a958f0a830574d079a8bba15a6ae4ddf", + "45d0891706b3432bb8815658a94542bc", + "21fb19cd873f4444aa4788166d5a8f07", + "3fbd758e949f4cd19c12677da6a7aa40", + "7f6f60f1ed344ff1b0811b95fffc6f0c", + "50ef251d19cc4e909f8369aae5aa901e", + "b07ba2d2a7884b90bab98db8c2b09bea", + "fbfb1afedd524bde9c6824c6b94ed709", + "8877681a05c04e6082dd50e8abadb9a4", + "aa8d48a70fe04bf3b89fef4bd622d056", + "796e4d17b0ac43dda78c3a3a89a9bb0f", + "7f068aa71289489c856d2918b534f7b7", + "f304e177100749f8871d487076d554b0", + "c01ba67b53614ea99adbe53e52b302c3", + "4a76b1f3c15e41d39267bf22782ab6af", + "787cf7b5a94a471b8cc739c492aa1734", + "81a2541aa29a4183a626ed1103533a8c", + "07b02a429907414f858cb947c6c0664e", + "87e42985816741a5b94c2a927264caf4", + "53edfd7ad3084aa1967a328e51eb5635", + "33182480373c4c12a120b45d2d612155", + "63c774fbf93341e4804c124c1ef90f0b", + "33cd2ac74f624f9795a8672d6ef2f229", + "044fecfbb974460fbd29ee7541745501", + "75479a3c31384f93bf423ebbcd3e631e", + "048948358cf94472bd0946621a653709", + "eb8b6ec93ad4479c929d6d355b41680c", + "4a961d3cb44d4cf3a008480923fa7d89", + "9e79852fb7f04bae912fa6a3b549856a", + "c70c38ad22ee42f394d7274c38ad5010", + "e8b11bbd44bd438b93bedb2e09716710", + "c0cf301884b0448198d41f73e511ae4d", + "3de2e575e8b941dd94ae08158636b20a", + "2d27c357a8f9454183e9c157165462a8", + "a5c76ae91c1a402eb63aacacf1216be9", + "b967f5684a624fa086a19d52fe387052", + "cb1bacb6260b4002a37d1b78a5763fe3", + "6945a47371d04afba1f3b91c8f04cd90", + "2b3717f437ab4bb89796d6fdd44db9ea", + "048d6d58981e4b0fbedc9500419719c8", + "1422444a7f5047468a27c1fc45787801", + "54a72a5212d142f0b73b1d6d356b756c", + "647db6bb1a13494eb685da0d4ebcab84", + "941cbf9f814f460aa97d653f7d637378", + "95367f12085743f096f0679abc0701a2", + "106a7193625a4472b77beb3f3efa5bb4", + "3bc876c9546a4bad91074928453456c0", + "63d085ac43ef4b97be0202e1e7836104", + "66739a7b7270425badbb02529e512dfb", + "f32a7136b700447ca70fd8abd038e550", + "7e3924420f8f4754bcb28ed0b6964b3a", + "5b9c84a7fcae4406b9b4ec29bd6c4a45", + "0d6d7ed00d4b42daa94b76efde94b9fa", + "84cc81f79c3840b28bddecc68cd5201d", + "0b5e5d259a344e6bad123a1fdcc4e563", + "df7e33c31d0d42d4ae7a5c7b009f39f8", + "e5c93f760031405daa6c5688da044474", + "628cc3b0fb2842aaa423e95922099c31", + "d51ec58d8e7947bcbc9627c3e1b0d808", + "aba66af78b174259a7fca90ffdf1ca50", + "0cd54226b0eb451784badcb2ba968467", + "8361ad3d183843e885f58d1c68720771", + "28103790207e4b1cbd67a900c4a2d0c0", + "72865245ea7240d38d2ef575882b35d0", + "61b41ccf0c514614a9aef40358bd50c6", + "8712580755e742158ad75bbba82063d2", + "48d4737e33144b689a31da00a3811a1f", + "3308de942f37418e8f90f104191da0c8", + "97f5a286fe504b79847f5741851a50ef", + "941f63bfc76c4560af34c4914443f5ab", + "66fd712372f14a8f8d83d4d1e4ff6dce", + "8ab650b3982243f8b661142de50f79c9", + "15afc2696cfc4755a239df24690b2204", + "1bcfdc065f004f638f881b8f91dfeefd", + "8de1441aa4ba450abf9a63af0a1e55e9", + "ece9b0b818004e738a634294cbe1d2ff", + "87461a8418374d79b38dea90e3d6a56d", + "074f004040ad4542ae03efb889c00b14", + "68d69bbf7a454a09a2536ac0762532f3", + "f1d057e664dc4970bc7d52398d8fd0b5", + "36d38e329b424d929c5efad81cf387f9", + "d93fe36ef62645b99d61c8c10fe673de", + "d265074377ae48f0bbe1b97e206ec80f", + "e9da83df31b3424a9a32fd75c0b8b853", + "34da5ec5f70942d0afd5b362739f972b", + "b0b56a5adb1049258d6bcd0ce9b19866", + "28a91e273a8341be9918deaf0ef6baff", + "eefe2ecb3f6344e18ca00e5ff85e4874", + "4213d80446f240ed952ae7b17d2ba732", + "a8e5239b1b2445b8b8e97cb1c3e3d60f", + "5251ae2bde074e7a8925fc38141661a9", + "3f572066117e4ebcb53ce99851cff719", + "e35d0a3a3c854692b7a41ebb50c6486c", + "767f17503edb45eabfd876771ffed9ed", + "98f167e89c6845d0aa7e53798f654607", + "3ab2eccb81fb481096066e27bd8d4a92", + "72ca268333164e59ac152cf401570254", + "1b06bf6196614c0ba75c80f577a1af4a", + "30a7d315b75048fcb92536f82840e7da", + "f3fa166ff6bd4ffe8133f6f6eed74d64", + "76fa0b88ca194f6184bcff0144eb1e69", + "f6ef3e86156948de872c6cef819da6b3", + "9c4f19635fcd4e2f8eca309f02fe2cb4", + "9ccc2f73a30f4ff7b4612ac30921e38e", + "ff47bc6e5ac444af87f80c413170d42b", + "f9b1003886ef4211b7de70cf5df0bfb4", + "452f105f49f24b73abe5edc728a8d17a", + "70f8a4f4db2446d3a282f82e451215de", + "6d8fbfc1d5694a6da73ffd93ec75389d", + "a4d258638d684f318d3f93efcfb1b699", + "d12ace10f4c141e08948240389c15f59", + "222643de666b4dad9924bcf03fc7260a", + "eea667c893474b42a16eb7a43ca28249", + "0f4fe85e2c044bddabde194665739c5b", + "0087dc01648d4cc792a7d1e49848b825", + "0269763acb7a4ab880a09bef35217e79", + "8f0d37fac13b4ae59f0ec2dae034fd3c", + "737f3b1d7c4b406daedbd66a1eff2a53", + "18f84f3e9ad94bb69f570a437a719aa1", + "f43199f19c3142c68cc672db55d9a40d", + "41c181cbec8c4af4ad4b32b90acebd51", + "87eab647ca624962a7c178c0105643aa", + "409eaaff39b24c3da252ecbd4abf8151", + "2712c2ec1ff04f05a25f15b12e27323c", + "c2786e2c18494cfc82ff4236074631e4", + "d047d8a997cd4061b6f63c687800b7d6", + "605a2c7ebd1b4cd1b47bac9fbdb4c98a", + "a4d3475c672747a4924a543c42141b8e", + "e3b8f46b36f84fde8bee28e3a02fa089", + "2e9530070d5a42e58e2c923154adbacd", + "0fd6f90f9a604d22af9e5d674cc999d0", + "81af439a08254996b023b08482d58502", + "c924b0d4ffa44fa88e8a8db6bd25c831", + "2706ffeea54d4b2cb6a33220bd00abac", + "0e7f5ccb3d2c4177b806a67cb9fc5107", + "3576b3e274ea486f8ffeeead0259ea8e", + "16e46e4c4d4b4ed3901bda03002ae827", + "5097ebb62feb4d5e98532ad71682f306", + "5e883726c95a4536828109d5b94483db", + "fa27c2fd712a4e8d857f16ee60dea7f3", + "083667a9aa0b4838895a701861616887", + "180f1c0ab5f64b90ac17db9f89c3eafc", + "c06d6248b9d64173b376926ee212fd6f", + "b7cd9d66f1fd446ba47bf43b9b2fb9ec", + "ee3dbdaa122b422bb4aea3dbbdd7e643", + "ec5fa2338ae34f0682f6974dc3190861", + "de78294dd2714b99b68a84864bdf6354", + "3b73d7d53de342c9b38bd802844bc989", + "ab29b0d3386549ea948568a07fb18d3a", + "0b5b51b578ea43f7b0429db362e46267", + "ca8d526966a74d5ab796092e6e4531a8", + "14decedce1b742df81366e3a5d203411", + "ed7529c7b4d54d73ad6fb6d1d3e1ad0c", + "f11824af7ffa4e0ba012fcc9cda3dcab", + "34ba28d8a5a24f4ab67fd801ad74e1b6", + "c25308e36b3a4c6d9745e01fb34a93a1", + "fb7428af230c4dd890e73f54d2cdbe7c", + "5f0eb4603edb40749eefe3a464f128a1", + "18a8287559a94722a5789d80d6eb8b45", + "ab7ea6f57ded4c27b5db922187ef20dd", + "9c242421a7c1447f941f72b57e7473e5", + "cf88d3c2e0da4f6680d4f84596e16ab1", + "ebed102485f54839b28089344caf3c86", + "bed7cc2208ae481f800a1d8516839be5", + "75f06f19c7ff43368034cf736bcb110a", + "05d9d1c2ae9d4edf8f8c7d96ae2f34aa", + "d1f6785445c444eea645bb7491511b80", + "ae6833510f8f4e14b09477472ddbe3b8", + "e624608c7da648fbb9bc6dcd4081f78d", + "0bb34bd380aa4330bf1542a9045d44e7", + "286cb8ba408547b9b5290e543a01214d", + "168a74c4fe6e4b379906806fd1ee1218", + "e725a56459c2418db0a7c2fc5733ccf0", + "d06e1e3c353c412482d66559c085f738", + "5f1524f9d311404d955338b4c072c7a9", + "499db4b47e5f40308ad8d071a9630d1a", + "149208cba1be4e7c9f64e73069a005b0", + "c23be007c1a649d9a2082f54af6dec7d", + "2f584f889a0d46d0b81d26dfab5105fd", + "faac771f17e74231bfb35b8b81f2eb0c", + "b6dfb19988674d71a2b3fbc1b502e6a7", + "65e304546cdf4740b7d86b35755242c9", + "a55aa27f5b124dfc8391c6445c49b23f", + "b80bd27b5c9f40e19b2d8ad6565907df", + "6942a31aa2e143e3a55d4eb11b5e6ac5", + "b8c8a28219464a7fa947effca8580f13", + "1c0e71069aed474d8cc544cc8e350db1", + "dd8a9924a46e42fea499151f98a91033", + "600e1e7db1cf48479da37f997e6c3448", + "4d8a09de354c43f29ddcbd64a1e23001", + "09b8de84eb8e4b14956a482cf9de2ebb", + "06a24fedb24d4114848c5b2adbef6220", + "f75268190ba14ea9ab7d12ecd1e794b6", + "04ef6175df934739b07094a339e8c892", + "3a8f57b6b9684cde8f428c1ea56741a4", + "1c544dfbf2344889bb7b91edbf71502a", + "b8bc290b0c3e4055918ab332c8747000", + "5d9dffa487494e57bb8113a5fea4d2a2", + "2624ac2ce2364930ba2d5f70eb7aa1ea", + "0ac2e7f320d44e84a2647cd81f250107", + "a9643e0991d544eca968de7a7f9af140", + "ef4b01dfce2446fda88041bbb195247e", + "76e6fc2a5d574a169c1241942a663941", + "a00977e464e34094b8a55aaacb17bcfa", + "b2c21f7c7c0c46f28b98967dd55a8865", + "64232f4b0dc14e8ea40b2ce34b3f6534", + "132a8ee2af3a40d39d270fbed3d3666c", + "8f53709f9f41453ba11961174bcc7569", + "e68232e257834881991dd8bae5bd3747", + "42f2e5cf65a3440e8176873bc24d8d57", + "080019a994254303a35fae30cf6ebdb9", + "8fad079ec38246ae804982a01cdb8d03", + "d09143c8b9894cecb8b934db411d5e14", + "68b7d018f43f4c47922d5059bac9ab8c", + "ffb96ec22d27472d9a89b620fe2f4282", + "7c505fd28d464cb7a2fc5034427992e6", + "1fa57770b4ab4581b65638e2ef31d66c", + "8abd24a101d443bdb34a876a23e3c49f", + "cb6451947757498aadd36b41ed8757da", + "b6d9e934c7f34cf5a382ca8e4109142e", + "e10f3563bf174aa0a80385e9840bca7b", + "ae14bdbcb5f44b2e98fd31d64adb2086", + "fbcaa2e44d784de5b8f971ee130741b6", + "2381b495c6d34165a182eaea80d3f8f7", + "061511fc89a944b08a514811b51e0433", + "fbf1b58032f64ec385689623c6b5c036", + "dc97063e68c345e8b5ccda88b13ef7be", + "0d8c95eb3acc4da29543dd8c8ced2688", + "7c9a6fa73c2446ec947e7b5562482814", + "34a2ea422c5f42b4b49081b3a8539e06", + "3529e97a616241f480a0115d74f97e80", + "9fa27bd2e4e04b38a4ac4958243d1b59", + "4ec89acd68c04420bc5878f58c40bec9", + "944bd46b8bba400fb942a7145a16bba6", + "03de8e908cbd4c138f210ddecc10555c", + "e8c48f47d2f540618a117265dd7b9374", + "e3976ad400224227834384d8d2784f5d", + "2b86802e55fd483e9498bbd42ab7073a", + "2497ab54311b4874a7ad1bd5e81a9776", + "329f0b6d71f245e89ff6cf8371180025", + "a8e0b7fe0bdb430988876c53f87c33cc", + "17c4643dddc14797ba3ef6fe6770e4db", + "227d07965b744bb181e33d1e286e1eac", + "d1678c4d33e946a9a26c07042e7f9074", + "203d6f3e9a2a4218aa9627aff948cce3", + "da88fc6eebe04985b2d69347d03300da", + "85c0b43592a44346a0f1ef26f9d66dbe", + "ddd28ceb1c2d468d9a3fff08fd4c0f04", + "bf0af14559d24294b495df214c92deb1", + "2816054c2fbf4b91934b82dd3c31f8f3", + "222ce23bad174017a05b97e5a88abbac", + "27a2bb91d63f4f508457383bb58fb105", + "bc6f5b109b7843ffb068c04bbcde980c", + "f992f2a23baf4eb49b13995a128f9775", + "8cc60d44baec49558156ac767839c2ed", + "d3a17ef8e01a47dca84d44f543c97f35", + "ea92df57027b48859719fc1545d9ced4", + "9bf2a804d3d24fcb8409be7aebcd7eba", + "f27d48d3fade43e884a50c844071233a", + "aa1c88c9217f47068a070fa815af4471", + "2b2fa3b8357741c6a40758958222713b", + "294ad9f9f0bb4223b8a71c2aec6f7104", + "f47771d9c463458ca2310307666021ee", + "da4f808afd264f20b9ae7bd8a13d51ec", + "c5cea1daa953448ca15cdccb885031dc", + "63171b7f228d48db90f0b4131d017067", + "b8ab0b7e24584f05affc70d69d9cdb13", + "ab3a299901b841bea1040c4f0079d283", + "33377dbd4bba4d6489a1165b25a90fb9", + "5377e2fa1d904a8c919341c6b3e0f182", + "d43841f7163542e48ffe6cbd02c072e9", + "22296c115d064f89bee065d5d6082a90", + "fb0a11f22a6544189d357c8dd11c5664", + "14802e7717ff4149bedb0569b93fd5ed", + "a2d29fabdb554c3bab217d157f32dbc5", + "720f9de6144448fb834d12ddcfa40352", + "5be2814eaea44101a8c00419b73c03c7", + "1aa6a053634648d58f5309b583834fd1", + "69fcedd9d66849f4aa0b47f880de049b", + "ec2c6087d4824211abc827f2a4c2b578", + "b6cdf8c56e254673aa7a2f668f3bf05c", + "083b867926374dd7b86fb800af428510", + "e8ae80bec4884254823832d2ab2676dd", + "d227862272c84259a412d95898a5ad4b", + "869d04103ba641e79c8530644859bd87", + "a0f64c308f6840ec9a38a83553caa667", + "92044ee896224ee1bcb6da38d33fbee3", + "06f13bce99f8497a88a1cb843b243e9d", + "7c8fd2a4839d49309e680e9e0d0c6ade", + "8cf28fcc6bfc4c01a242a853d8bab8f2", + "33c5e18a8a5f413499faff1e366fbac3", + "a80d27da5d2b46eabee84c5f4061913d", + "2c7907fd84794049824c235c7fc9e513", + "4c4a8a23d94a4f9cb430e35c6967a7ff", + "90dbb7174f4041ebbbc6e65fc11ee66f", + "3e03c696c45443a5a7add048ad9cba47", + "f11a9c953bf44a9d9f16e63c2fc13b09", + "c9094bfe4777461db55adcd323cceb60", + "edd005134afc4155a1dad87b1f3d95bb", + "adca025c96394202b52172c5f92bddc0", + "6e424047eb44426184746a6f0487d19f", + "f814628ec8f74df18cbe393c6e76cd0d", + "5caaa68f8935441299c6ebcc2a7be4f4", + "5eafafc2714a40ce8600886c95a8883b", + "4e0564db1ca94de9ab7df7d1f6ea9cd9", + "85842981b24940ba8f9c3a973ae73b6f", + "edaabddac46d4b57b6ec7de60cccafde", + "ae748d12ba0a4a618d27d11345d75a12", + "7b5d49abae8442e2a2d5d9bb0cb2243c", + "e68c827c2996490cba6be6de4652a67d", + "f2feaf98047f4e53afeaa661bcee20e1", + "863b112d64fc4a01a9eaeccc1c0b3e6f", + "966b653e494b49f0974ee4a79299b49c", + "c6968ff55e244d71924e9577de2f8e58", + "65ba5e0083824797a4a16a309e5e1584", + "8c655ee007b648c5b93195ffbea0b06f", + "5e16fb6d27a24a5a83ef0b6cfe7cdd54", + "7cee431b78cc4a708ac5bde74a286409", + "980fca9749bc45cd9271cc769fd5a27e", + "341c2fee1bf34895b6929195f6324308", + "cc35ea9a4a0640eabaf21bb54114e76e", + "5a0ba464174e4dbe94aecfe1a036ca6a", + "1418b42c970b4284a38a941a70f8c1be", + "3dc9f840d2d648118551670bb9a5f0cc", + "f894299417414214b87993f031259e37", + "ceae62b7d00b4c71926ddee0187f856d", + "921e4467c7904b21af139862e691eac0", + "550c42a971ce4208867459ec96251eba", + "bab02d08085840aea0e7eca93b4fc1ca", + "3505719257b745c19c95d9b28feca7fd", + "18c13b987e144102b8ec68328f2f6115", + "b5d5abdd08f04d23bf044d8246e69a6b", + "9ff7608b937e42d1af99a289abb22185", + "c2f9b76e6b184138a23dfda89829fa8b", + "9428cfca103244b98034d7438cfd3755", + "b9cb1c2002cd417aae9497c3c33960e8", + "d9952a6fe3e0462bb8856c4f1a7317cf", + "acd2f72bd9c7470d85beaae62fcf8f9c", + "9ac3632981ae4e528598e96978f300eb", + "7842a813fedc416884e59bc593a890c1", + "7fa78479a63b4358bd1edeba44f8266f", + "efe3e41775a646c2bc3109923fec9cf8", + "21d255f040b948a2b2af88de30c7b43f", + "0462dc66153b4a2e8968cf8d121a95f5", + "eead548258ef4a149d486c810a0a8885", + "75e25577f8cc44c9bc4ee089d235afc3", + "9a9da7e77f1e4216b86cff73352cb30e", + "952659ba28014472bbe3601bcf0fcdca", + "a437a8d36248432ba9bd5595f28815ed", + "2ddf67a348834f58b99594893b7dc011", + "26a3307ff2c24473955edee62adc755a", + "86bf5905728f40568a9b588851a27602", + "fbedd38da7744f6c832c9918a24c2335", + "4d105b45386d43d0a78d9f0291d14e8c", + "7cd81a3f53d04c3ebc91d60c70000ca1", + "2f1706233a3248cf9a74586fc2e7120c", + "3cdb3831222748558dbf76ba4b116cc2", + "ce0b1cb3c82842cebdb741142a035523", + "856c6193740a48368fc1fbe055ad2994", + "ee8f4e0e610f49edb2d900bfa0cef985", + "85a5187cf0ee4d4587233a901ab65525", + "cfefc2b54f3a4db1b549407a96a13d49", + "9403a721317a46a8ba05f76c9ffb86c6", + "5d8656f289ae4f9d994d77872d59787b", + "0c4531d8ec8c449ca9e79a390a4707ad", + "10dc2660dcdb482a88b46d3ca72d50c3", + "6671776968a747ff8f2fb665a62d1be9", + "b74b6bded4f54b1eb246fab1fa8357bc", + "601e83c5542a41068b96defdee70ba5d", + "b2c5ab0f4b3e48aaa30a00d26ac5848c", + "68564c8c02cd42b28deea1647b9adf92", + "f8ca6d3c18f2455c8186dcae492c7816", + "94a24190869d4cb28fc8d670252de71b", + "aebcbe16556f4850aa6c32e691c61a74", + "8c6ea1ed6d7b42fdbf0fce21142fb846", + "5b70904b26774f37aa9c2515a7a36fd8", + "3539061fdd4a4bc696914f0310b041d7", + "00f64dabbb6a498395b74675e17ea3a4", + "dd9e73d51edb43198bd40d0bbd2dd54e", + "07850a3af3514bccaa48c8ea450a5df5", + "044e121a90b5420b9f86e0cba313a5e3", + "989c473b622a4e38a29302039d7f04d6", + "ed3bdce6bb784e809004f61f55a1c930", + "c64c45bf1d804b659b37693d4284e867", + "da51e997bd06416c80f6e0e379945281", + "cabd5b36f40f41dca2004228060b029f", + "a1dafa8c1ff5440ab1fc05a1fcf239ac", + "a860d3dda964454f8fc3c692bfd8cf08", + "4f6c74f9f904439b8554078d1be14821", + "459fb07370e74a71afc2df4bdf682933", + "aaea418b4d3b444c9af4cf93df06b852", + "d1d0d85858934ecda8e92a38b1e616fb", + "3f31920c10a546b3955ba311b9c6ded6", + "2b289571925f4510bdaa94f3ea69f200", + "e73675b59b8b4a6b818487622dc330c1", + "04dd9f6b6cf14003a7ccc8387ccee3ad", + "c79ff4aa06434315b037e0f6275972ce", + "f679cbe92c49431ea7b2f2c155d25ecf", + "cca9920784ab42009dbf792e7b1a9409", + "77b02d4303744f2e883cb58552887a18", + "1a4723e5f7d64c60b11755f4181da705", + "5ba5959ecc044c5fa44dded4c75ea25a", + "3099e5a3876d499f9486fcbe48d4cffe", + "c583e05d523a4f4ebb12e93e281035a6", + "5814aad2b58e4dcda7848d5de8821da0", + "e28cc8906af74cbf906fdb1fcbb13d16", + "6689940027174693a688542b2846093d", + "7af7c8158dd24062a5e49d6a25799628", + "8b52b1f4c4c44bb9866146f60dbe534c", + "9e667d3e4a5049a8a5545d780402526e", + "4561f4875b7e479ea957aa6d7cb776ce", + "f3fba327f0d44b908948f365850b9160", + "0db114d7753344d6825aa4f21ec56db9", + "cbaf37cd86b64d9987407647537d123c", + "e55aff4bcb694de3b2d5fee812d8e462", + "024e92a937a444d0841a7c75e9cd2943", + "0be0000425e146f098bf7ef5d87cc372", + "dc738bd046474bcdb3ab71137d311234", + "02064882908145169ff83f39b3adddc4", + "a4e4f96bbbf34cceb8622b9313365013", + "9d2f849fe1b942eb8ecc2bcbab6bc9c9", + "feedba7ad7ad4416ad6abef2a09dabe0", + "5fc618d26227453c935eda6ccbb55d46", + "22a8606de16345729947b7ec10c655d4", + "eefeaf1945fe4d41b62b67551c28e34a", + "dfcd15bef17e4e3996809a5723482f8f", + "daf5e48f7578470cb309cb1797709561", + "ba0baa5f0f514726ae81436674eddac1", + "5ab48fd4819745b596df3ea39908e2e7", + "fed35fa514924ff480a9d7b761f977b0", + "6aa32d0b23e049ef949eb8f8b5c6bd58", + "c69cf89c62d14b4bb0e18b8eff1667d4", + "82780cbdeae548c582caf7ba16ed0f87", + "ef2f04f0e3e34adfb5fc17939b8c8b9a", + "c316c1fa3f7b499ebba3b44272b89c76", + "133b0ecddc364b4d8a997c02032b47b2", + "3ceae2eee6264843a77aaaf298134744", + "fe30ec8240234d40aaabec7ac26fed07", + "41fdc95a0d2148ba8f7911c4ef4f69c5", + "8acd766e66b6478a8843f03ebb085ba2", + "61c37ba84ea0476ea39bd3320c771baf", + "3f5273ba29ec4f1db90ed330ef6b6cd4", + "f91c7d2ed9824ccf8b52f8e99235dce9", + "2d5107a9476d47a0b27c17f589836133", + "90f6999599aa4f8c8c340ceeae0d3c02", + "25b63941dead4fd29eee6abf61ab8432", + "028ceba3e34a4ebeacb4bd5f81cc251a", + "602a07ce1db24ed5aa0d833c269cc917", + "33ce7928b38e4e55a865b0fcfa6a7558", + "30383e0b4cba424094b04e850f28a421", + "2ecc36c9c0e04db9a962480950df119c", + "52c9e26b0ad943c7a1d190d4cf3a2903", + "5aa9584d37b3404796508dfe18ddbaea", + "976b4290ac7f4a6dab143572d457bbab", + "43197f4d18144b4388a064e950fa34b3", + "364f1208ffaf42db9da456e87abc7eec", + "40d3e08bba4c4fa4bc775525f2418589", + "88472cc3c22e41cea63af8ad2d3a1310", + "7194f4ca9393451492b414b060980c2a", + "956745b6903b4934bb34b510c2e55be8", + "4f29c4d3fce74e088d2ba3b1a7f0be67", + "63c9391726d54b5e8c0e9e87d640dcd1", + "6c9f55d491d147d3897ebed4d14711ef", + "3b98a0a209364659a42eada05d59f56f", + "6a6fbcb75a1249ffb91247691c867cce", + "b6a3345a07774bf9a4ae41a0fd3bf449", + "ef60e03fbaac450ab664947ef72eb448", + "c174c529002347fc91889db5bc25588d", + "c4076d1b59744c259cfba836497140de", + "4b7662bfd57c4be79b01c7b16819b06b", + "0f7c8de0da78455fa78b0eddbe433742", + "497a2c9674c04312bed052798806939d", + "db83348d6d334155b031b905b1d9e80c", + "ae07246b47bf4ff09eb396c06f0621f1", + "f47fdcf9615d4e94a71e6731242a4c94", + "ed48393824414dbfa100ff0072fa52d8", + "085ed00898b244e48af3d63819094a03", + "10f72adc3c5f4e6db3322963d73e14ee", + "08fb109905b34d5fbcd715a68c5ab30c", + "db215ccb1d04490dae6de8e2c8c9707e", + "aaeb98d6ec314c16be460cf161fda746", + "eb9e9ebb5347447b8bc82f289cbabe70", + "cd2387cf2a0745db8ad4713e2ca9b9cd", + "1b13667bf6ef4ff583db26b608b0c50e", + "bc84a37c1a934aa08a93a4dbbe26e3b7", + "3217e8827dcf4e5f9ada995ad883b3c4", + "8ca34a0aff47470a9a41ad3b6aab32d6", + "737126c497f048e388935ffad2355f35", + "4f534b695fd14efdaa3d217c539f975a", + "7b86302721384590913615a50cfb7afd", + "6492d3e96bbf49b0b0d3c9d6fd3380a4", + "d40ef01e55344c4f87ee816b6e1fb6e3", + "16508811368a493d9088314be688f726", + "4093786ee7494060b08d78be58031dcc", + "c32281877e414502af5edb304be7684f", + "7c0e528403bb443f98759460b8f972bd", + "9566a7ad9cd144f9b8f294b7bf879e50", + "71c02dda95864ef4b5287b13863fe5cd", + "003ebdf86df345d39dc166563229fb85", + "7adc9c74b75e4860b0a51c850bde9957", + "00b267b43669422cbb4ec3a4e9b1c16e", + "eb867d25fb804bf7b30ac6e61d8415d9", + "99ad90534c184a6c8f764508b883b180", + "f84a07fb4f4a4ce88b603b031b9e6844", + "1b8960a5a36f4869a78d982d2ae9ed3d", + "99a8f14ee18a41039296926a6ed680d6", + "55010817f5c249ca9aacbbe2c8313ff9", + "e552e92f8b064ada9a387c259ae32c0d", + "42da6e2ac19b40f9b43e155ba23ac5b2", + "c34bf5dd25bd40568e08cd6660fb51ad", + "6f7201fbb58649379398a8d1d5c0cc7a", + "e7b71462d0734fba998b06c1a33cbf95", + "eee1a1ebdb614f38a722b52e26ebe038", + "b32002c7d4d54f49ba5b2f8be9b7d453", + "d73f41c9dce5400c8f2cb8e36d5f2706", + "6c6a1f5757b34f7485133a91bb85cabe", + "551ea772aabc44e0b240ebc564a0e2d8", + "3d118a9fd6e34ddab99cb0fab5540682", + "10e59b2548224b65b9e70b5f5a3c4f0e", + "80eddf91ba0e490099a56a7da413d034", + "d0d490b69fea45cc93151a4b83e055ad", + "f957a31cde7046e6908e464b588db822", + "35b1b9b094974418b4954d489970d3a5", + "94e7df930e884f2284cc3fe916908e35", + "f0f765ea810840858235ba1b900c0d52", + "627f8924e9e640d7be96f3e38c5c6330", + "d742a09ea2de4e19a0dfb03bd3c723f2", + "c15e41a62b46487fa6dcc67af7f7acee", + "a4432e2914cd480f816073001dee8f47", + "229d686ed3c348808432d9093621eefd", + "01f5e06df5964b1f86d67c14a7cec0b1", + "c4b168bff6de4327968daa2283846044", + "7b63d2b3df0d4b43896c47aba7a9635c", + "e9b769a750b74020973211f39f976037", + "aba81b5a85004b019e4fa21fa2cb6125", + "661cf949b4054322936e97956d0e4347", + "6e3773fcfa604e4e8c2b3b7538bc9246", + "1516d74d432747bc8cb2ec22221b504b", + "83f893a2d5b647239f2c221eb0e31632", + "843000ec4e604edbaa76946cd1a89501", + "a75541999f9443279513259e2b42f088", + "6c46f07779744b53945021408a5c0807", + "afd1924349bc404daa8fd5a104de8a75", + "5734834b9c0d436c9b581cf2257666bf", + "347409684d8f4ec298c1f571fe7c6122", + "33a68c221d3f460cb1cb1f78b9fe0bb7", + "92718bc81004402f936c4e2b7d41bea5", + "6d677dc282b84728b9b7e39cb38309c9", + "8e33263ac7e8424e852e9cb187df2593", + "c0b8b9cae0a54a028b7cd83289383b46", + "eb9bc6464f9f44cfba403a0cd1dc5cda", + "98f925fd86004cd793381174606efd04", + "636eacaa081b41e5ba35601626893a51", + "3d93b943f64b45179b187604bb2ee318", + "06ba681f45c74b68bf9fa5d6dec46a0e", + "c474f334880d4b8e9a8ee1bf72091484", + "16667c66adec42f6a5661c813cb3e51e", + "df1264b0053e454dba0e68f07f3c0615", + "6c79d4ecaf8a47ad89a970eaf0e32fdf", + "50758b07ab3c4abb8b8ed41c4f2b8b09", + "177eda88702e44838857cc4a7b8a2b1d", + "f0d2fd92e3e14b059f169a2302c60157", + "9319157691a84dcab80f4598e8d0098c", + "a3cd551df1d2452691bec6c8476184f4", + "6937a8e542934283828fc2a553dc7de4", + "f76b9394d7c5488c827e9580cfbdacae", + "14138954039548a5a6aa49219da9f0c0", + "cf3e466139e143e6b79413ae8bb7068c", + "b4da207833d343a3944e3961cd311e0d", + "793668f4c9ab4a8cab5d392b843a20e8", + "cbf53b01b1e245baa896d7c6af69f187", + "4acd6e81122542a58a9da9695185a231", + "731f2e4a42c7404d8b79a33dab0234b5", + "863e18625ca345c782442276ebfdd537", + "8e53d633dc1d459e94c7d041d5f05223", + "b8fe458a4a5043d1b9d9086453dce124", + "08e9a9602baf4927846b59889a3a77c3", + "94f27a10cd3b4318bdeabc38f384c41c", + "144d57a157a64ba68993d068f733f6a4", + "c90ce196ee7a40a3af8ca6b549478d13", + "526deb556e594128859f4a7d15c77dbd", + "1ac6a371fa734f77bb02e1d6cfd26cef", + "371c70cf9d294468b198d93f6f9dee71", + "a04f13408caf44d1af8827a1b5c7d746", + "d5d938791b30473498507ade5ad92066", + "04c549e299f84b6e86374b3dd191ba47", + "6638d9f038604e6ca35b5aae2af0d71b", + "4edad5ac33ad45d3b29005514938f77f", + "1e71ba6166ed49fdbaa508c1e593a386", + "1c1d34d73fd94e6b9e8f82b1eb7194a0", + "ef3c8125959e4554b08ad957d4fa43b7", + "e1a72a2329e942f584e379c24db4fe6a", + "d4d8b9a992be43ef8b433c6463c653c5", + "95890e15718d45778d7aaa13aae6d2da", + "15bd6087617a4a379953550c56edb839", + "b0cdeef47b9c4602b3c54f7cbe37f61e", + "3a80c0ac82ba47f381b002448b10cbb6", + "b9a10423eb464f8f9c7187641ccc34c5", + "03813fe8eab1417eb7bffb45f9f083b1", + "40ec1b501433481e914323239e043cf1", + "ff658652b0a54d989bb120e8a2705b38", + "99da82e00cad45449b5fd906e2c8b7db", + "5ce4459b281349598659c6c32914e690", + "483878b469c545e98d02d06130874f83", + "2848a13dd9ef4737869c81ee90212ce6", + "5e5dbdc9bc25410792f8d25904ba674d", + "8730d9c5250c4fdb8c407e61557ef825", + "485e47c82c0346a28cb449e2a793f5f8", + "d209acb0152d476aa7c1667c1b6a98b4", + "5bd66f8b4986448b8f3f6e2119d54bb5", + "e36a8b9b0df3473e82a0e2205da3bc65", + "1edf36a6436f439b9eb455461f1d9ab9", + "e04c1c8982994de99ddc8c9e3f7eefbd", + "fa3e9c175c244bedb457582f08cf8e31", + "83ef41f29e1d48339773de1c3207983a", + "f7ed4ed3c59b4015ad7e9f4a01490a7f", + "47c0b4ceaf3c42908f96e54be3539392", + "0540daec5ee54e7bacb3e346776be39c", + "394c6024c5ac4e16911f7655a732f6ef", + "67f1232d82654563baf399f4ace37907", + "c2892f05cbc34304927d1cf2d95a189a", + "99c0b4485e9b46f892cde91372c55757", + "cb68743a972c4096b053cff7508fbc5c", + "431170250cf14a2288e44e750f5d8371", + "55c4bc9678da4f7e817e9b10220715ec", + "6cc652b7d1d6494885fa26d15f4c093a", + "aba19eb66aeb48abae81132fb3517ce3", + "1d1deedefdfe47e9835f0703957e576e", + "1547c6f4962a4a30bec898f7295ddce4", + "e20c3851d52c4261891b692a1dfc18c6", + "df0583c8a0c342e7ac0348e2301784d4", + "f4c122d7819e4f85925b9d1aab72a696", + "2e3f1726d4a24114873f4bafb2681c49", + "66a3ec7fc15241bfac20c5c55baca66d", + "255dc2ef5dad4ea98c2b52b9c49401eb", + "29a8029d6022411ca4a6911ca13f9b3b", + "ee1c82b861ca4510a86ee759cf0002d9", + "a13129478cb84f08af160fee1f6e8639", + "32c04a4605d7466687cf10ae7cd85c11", + "e91f046f7d5c4dbda1571259b0460782", + "21de8e33a44f43ceaba18a60b64bfe2f", + "e2f903e972a24bf69e7679e89e8a5d9e", + "c9405115a26344bb810ab1eb31ff73bc", + "f3a651badc5846c4bd3c25f88d363a3d", + "a76c356dbf1e442f9cf89ced82a307fc", + "ff4074c4cecd46eeba96620bf44e3aee", + "b3a7c6081a2849c3ad4681698f0a74d6", + "36741e7913334f328f97f7e80403d9a0", + "07060d7247774dfbaeb5154501b04f7a", + "12aedfda04e344c9ae79defb15a1ec85", + "ff4a7d378974430aa811ec3c57bfec7e", + "4dea8c988c6141acad8c2217ad739a02", + "417915f419f945c8a424b2a7943eb25a", + "0f9d8fd5d3c34ceb825fdd87bb72890c", + "bd8c40b0ad2047218ce39507390a92f1", + "12d539debaf04972869e50c6609b68af", + "5dde5a7422d540198742b55e0e01dbc6", + "b3a5f407f6aa4aaaabdf1e84380c95da", + "6067c9b24fa846b68b119ddc2a6303ea", + "94f253a91bc14f21be83592faf5891ff", + "ccaa8369afbe4546a8830f564f34a539", + "32de6a92ad104e20aaa841c8e3eef93f", + "797a7dfd60534ac4956428496f2cdae1", + "8249f605bad54b11a345874d224af191", + "410290dc9c654a68b43eb9c696b4675a", + "b8d48b857ace4af48c858d44c6946476", + "0b9e0fa4f17e4ebcbddbe7ff44cad963", + "9365a09545414190ac3f1b4d572ef895", + "6a933bb79ab245ec87fb6b679f70ab4f", + "1bbc23a1c0374d64b92eebbdbb119017", + "22571a51c33f4d0ca05f12c3e786bb54", + "ea6e507253f14d438528836856358b7a", + "2761f326173e4aa4a2c6cff2bca88549", + "e7361ed3cc754135a0cd66101002471a", + "3130cc3252934eb4aea42db804d4f953", + "bb93b2f4aff94c588fab83acc7166225", + "42c6d87149ff488dbfc7ce61ea97c272", + "f496168739384cdb86ef6d65e2068a3f", + "aa44b7cb272b4a9d837fd9b46e9aa577", + "bf5152c1f1fc44f4a81dbca1d502304c", + "15d6576252d24719b32d9e686599ef56", + "a87a69075203401cb6a7e42bb8743aa0", + "70373503d38d45a3bd8c14ce64187df0", + "555a1a3b87764aa5b86adf82f487cecb", + "965278adacba415fa25b450e05dd5ab2", + "b4d7286e81654c00859459cbaffaee0c", + "89de8eec26d64178a832d7d89b0a2106", + "fd3a96ae4eed48ff8fbb462a07281c27", + "5c4458b038664783b17cafa6a9dfb83a", + "4c702c17ac4949058ad47b3e13706e68", + "08683731141f4795bb5583b6688f9680", + "96b0bcf7c604466cace09d3d46db4eab", + "70b30338245d4f1298f35d5ac3d42109", + "9273c66886cd4792a983263d2082da82", + "0052b71131614bddba4caac26c9998bf", + "0f0cc16787bf4f728553ed68a28afc7e", + "c604ab4e797643f88fcc1c899e8cd419", + "ab597b152e3642a4bc473cd473b45148", + "6ad42666536e415299c3dca5063c1543", + "7da97e81a45346cfad4a8e1ec47994ab", + "2250174349aa488182ac3e1667d2496d", + "ac664e78a4d643238c7ea7bf97d819e5", + "cb463b231c9f43f999ba9bf02204865b", + "b7ebf26f74874bc6891a5c6596672ca9", + "821a4b54868844b28bf4cdea0ca2e0ee", + "de4d37e433c0467c83e540717fd9ae07", + "6e18298e1cd1493a974c1274e0030701", + "d07f7f067f6d4d0eaf7c82aa5d0d57f8", + "91ba3826f2f74e08b108e507f5a1ecb0", + "e3ebef8131e24435b7af025f9be4ac2e", + "8563004d9d5e44b1b71daadd6c8b1716", + "291f3ba9654f4d09b10e1b807ff3a975", + "3beaf6f1797a41e9b16e307e26fa1f8e", + "dfd7207bcf784e2597665249ed12f3ce", + "2bef0fa71cde4348acdd067f3b5d5b57", + "1ffd1a6685c946c5aa87988cb5cbf29e", + "d55aae0bfdd8424cb4f7f7573a79f009", + "5bfad520d63047eebae4559ff29b670c", + "7e464462d6fd463e860f91f70db01848", + "e398537c9bde4106bde9a055a2495557", + "68946956fe0a4ec09abc23d067bb35ad", + "56f8e5f2184c49d199ba255914c9e5fd", + "6f77b85f07ec4dbeb5669677eb9a916b", + "11e10abe691a4f3aa698bb807e0004e7", + "6233ad12a9be46e496e27233b9b3b7de", + "3bde1ab67c6448169b604dedad6828d8", + "c4f77299116b42fd9879b3a9da9bed62", + "5c32977055dd4ee49b19b179f212a54d", + "de2e9e84e52844a0ab522e5e98202453", + "742d3d85328a4e898907ef39a6bf75e5", + "932a736f70894fa7b16950c6788cab49", + "20e8dfdb74c646539059771567dfd89e", + "9e135820251d4fb4a98b7200248ff371", + "6f8dca5796734a46918c70b128d705cd", + "d8bbff6f87a0452b8d9ad083599df0a4", + "6e0437e6a8b94a8bb5e6e2b59e248c36", + "f03e95525b4c48cfb659064a76d8cd53", + "9b233233c8fc437b9a4b4a79f49fc452", + "e7b3cde007844eb69daea81403d71792", + "1052ae995374454f853a3c190d4b1965", + "a243d1802d2d4102889adc7437fd35fb", + "d69f166807594444aaf8b1c72480e7bc", + "0e0f28026fec40da8c0f1dfd7a8dd45f", + "3f32c7db8db74969ad6f3e78674a5933", + "db90a1cf69d246599c9e0a23c9e1e827", + "dc16ef2fe078419fa8eae914c06d2080", + "2ea85fec1d3744fda5e00337aabc62be", + "bcdaf2efb530464c8faa7a0aef5679f8", + "0ffee04ccd4a4b32ae9a45d0b78914b7", + "f0742791a0ea432db1f432c24de83867", + "64e39011fe414955bd559883ea12face", + "f755e3f9e9e64c8db5ba49b0c821bf36", + "e7c052f0df7044569b7f89d4b869b13e", + "81b895de490646de8c6fb1ba03099e08", + "0523afd3e60c42119a726fc6c52eedbc", + "bdacb14603354250a2a9bf8fed27640c", + "78ec336851a94277aab633130b764654", + "a848538c7e4249a4af8e86c477193fa1", + "2db24687155348c4827c750fb67b28c4", + "97146b26ef7a4666b1f0e96e771eaa81", + "208947889c8140acbbbfaabbc671067c", + "c14060be9257436281dca96b55d118c4", + "6cd8fdfd28d74baab3e5497105499233", + "59a1052f5b28442e9f7e2ae66be5fa39", + "88ad23f94b564485985ddfd3eb14ed0d", + "8b647d638e7e4305be0ab948d67415c1", + "96c40e07d8ef46fca7bfa4b580813638", + "a2b2645701c94fa49e65661806219c6b", + "277ed1fe673741f5b5bb3c9ebcc2476c", + "827a5f280970497f90d2b54dd7318c6a", + "bc44a10863fe4ffdbb1a907f1353cffe", + "5272152dfe5f4cc5aafdf399b10a79e0", + "aa664ec569f54e18be734c577a4f31a2", + "da9b3104c4c749ec8c66176d00154a80", + "a9bffee2cac14831a5190d8f9252eb71", + "774971f63ea54cdba8119439f4ff09c5", + "eb7f7d43a73e4bc8aaa0ae47d95d3710", + "08e5277deb5546a699127562c83128d3", + "cd33432aa12e40a28a7058fb289c8a7f", + "ec10e65f0cf14576a90a634aa864ea82", + "48de5fd3726d4792a474cb9781549155", + "14661dbd0a64409a86ade599ff84efc9", + "534540122bb84605bd21edf9338f10d6", + "43a5984cf83647339260ec392c4a426a", + "8cd6c072be3a41e9aef0afcc6b0aae6c", + "2e91a6e049014e11befd329f9b11d0f6", + "17e2a68603464169b22ea5cdb8572f69", + "c63510b103fc4954ad36a84d7e26e7ec", + "f56ef2c3d01842708a797d02141e3454", + "df29163b85ad4912a648a8473cd9623f", + "13fa6c0259844f44a317a539bd0e4fe7", + "0fc69683beb74e6e87853e412d7ffe32", + "b92aa14cbe5848198ccdc9ac2396f219", + "efb6a0a74d0742e7954e80e33392899e", + "02f2bd71a28a421c87288b35524df8d0", + "796c8edcb69543ada938c9e02b380b99", + "9871bf23b8a04d30a0a9b9731bae1d14", + "69de7b6bd3004eba8c6aa41d37858d86", + "be237d4f0c7f4b84be5966275efc5c55", + "c33634017b1d40b48c07e312b6762bfd", + "0b6de1b8944342b58b334653de5a68a7", + "022f2092ded7436ca793f1948d7db12f", + "ba948986dadd4e43b7dac7c4ec59f8b2", + "c32c07a1cc154da7a70362019d891a24", + "711826d903444225a6f1d5cf991bd74c", + "f47fd7f41b0943359a9c7683d9bd600f", + "952a9577055d47bd9592063f645c5049", + "f3750246b6564607afbefc61cb1683b1", + "6d6b418bc9b344bebd82d9778d0d1f63", + "c03c76e00cb3410d86ea57895428efb5", + "3fcf6bcdba7948f9a1361ede1a87e4f0", + "2ed0b409fb994018abf11a4dc2e83da9", + "35ac912c7dc14175ab8be82a2c5fe551", + "81af3075df234522a73abb96bf07f64a", + "9bdbb414efb94a1e9eefcd07d4b0fea1", + "6e6b6847c00f407093c8a1aa50211c63", + "347135dc509345c0878ebf2a9a3b283e", + "35b8b3d0cc354a31806c4aafea11876c", + "0396e1e3075640179fb4cc52f4d97cd1", + "c5e23e5c8f4547e885cc0db9a92221a0", + "7daac324578348899321e9ea3cea25bb", + "2321d217ef85436694ba1f8f8e4aa28e", + "7b45cb9b387d4078af8a0b8e6096d0d9", + "25aae929274d427784e47ae896f46c15", + "b21647005ac64c9f8e9a79a5e75a7a0e", + "f69434d992a14787b6e1d05df65d93fc", + "bcd2db39dcad4a488a66696b88ca67a5", + "c630e3959eab49ae87cdad42937e21b2", + "09ffe26c6eb84500918ac02a7a00353c", + "f91eb6647f0b462e96fc61a61ea85287", + "a1393ad1120842618be2517936e4b0c6", + "6ce4f1af6f3948dd8602f36cfe67665a", + "8767b08e61fe42a183b50e5ced72472a", + "743858eaa3fa4a4b8981968c1fb268de", + "8812fae3931347fb9beedf2beee0fc8b", + "9fc0288efb674cb8aa37e2ccf0af5e5a", + "4186f1d496c44de3abbc11ce5210df68", + "f83f707747ec449e9bdb2f6d8b4a0a2a", + "e3613e555e304e0a8f2054c30cc0ead3", + "94022acc1ab042e095008a200aca9518", + "5224f34d95fa44eab99d674ebae68fef", + "a57dc9dbffd6402ba7841305dc8379ae", + "22da442751784128b72e7c99969fbef8", + "2a37056f25e440c5b57774e8e5197347", + "354087e8323642e2a4e78405fa271545", + "7bb9b012b54c45f488245ce86e8775e8", + "63edb731b8d144e283811e86c23cd6e7", + "db1241f9b33d48d29308ae5377793528", + "6ab15c35ac854f759fe1e7123d774ece", + "49373137c4684ce9b7e134ddd53c58ad", + "4276245463f54fa8be7f26151aed0876", + "1ed96f964b9d4d3eb9accf2240dfabd9", + "ab9e699c74764adb931d5f6bfbfaccbd", + "259fc16c23d548ba8d5802c563d8ebdc", + "216b5f7332b5475099c930c29acf9f37", + "0ae56a4a30dd48b391c11af22b375edc", + "42ad1e4a3541493c85214f8147257a40", + "fa277ef6ccd243108d501b0f0aa8fd3b", + "7b344fdb2ce846539cb420fe4d37fc13", + "623372ba49f64f2a8cc5e5a8aaba9ca3", + "7c234eb786c24f5daeaf3c0680981a19", + "abf0b05fab4d4ab69de1dba36e39ed49", + "eb7e97c713e6470b9558c543300a0f60", + "1c56f9b18a3f459891f6f8b902d192a0", + "cbdf402976724a82949f655eb2769db2", + "d4f8d31749e1476e828734cd4295e075", + "4bf1ba29222b4e9dbc3ec0e2535c6a1e", + "6788e0ef6d6b4c7eaf28d6820867f745", + "cc81397b429f44d39dc822d5d85609c3", + "ffebd77d0373462eb7c6d2d4941eb39c", + "fcbdb78c20ad4c788f25090fbda8da48", + "bbd60c6a76754d668c98f08c9ddf6bb9", + "6a1807c1ce13449089af44c81b1f8b6e", + "03fe104f539744518cd35d8f2e19418c", + "3836c93ff52a49948f874972d1dea822", + "feedeaa6508d4a4eba04c5c99f5cdee1", + "cd3ec9bd9c76470c8ab72a93a86e946e", + "8e4142c169514133b1d7a3b197d5e790", + "9aa2dcd62bc84afeadba4b71e19cef8d", + "ce5732fe86cc43939ea05dc6f893cd72", + "262b0aecfb814c2abab3aae1d4138d44", + "ae01fcb32cc34896bcaa3827abdf36b3", + "bac9ee64eb454a66a637ae0c20f56364", + "ae97003dff3d45ac9f17c2b8f3a25398", + "18d5c3a1fc484b5b957219dac99d3d45", + "8f63a888a2c3473eabef51c650c82b45", + "96e91bd740b0496ba7eea0f3be24ac9c", + "f5ac2fe8c38141549acbe0eaddec973f", + "abf88446568f4303bcb0b2480bd6d87c", + "2c805951fd4942bdba0cbec78fae2fd5", + "6bdb1305e851451cb3b7f849911a3033", + "80993e9e2d00478ca229bf35ba870b7d", + "647d9b99a20d4e788f84cf7aa33ad5f2", + "5e5a1b8c93cf415c894d94a81811fc2b", + "56f95367a4854cd9b5332a411b481944", + "9824a5e58892410c956cfaf9f2b07c29", + "7f9fa41bc5ae400fbd6e7c33410b776f", + "0611d3a55dd841a99d52b319e161e40b", + "f5bef92473d94fc5b2b01c16a02154aa", + "96e9fcb1e73c46b4b63fc06cfe424648", + "0ac6c9ca61c046f0a93e17471d16a8c1", + "83cd3a2e08b444f0adce38a315208739", + "8cd8a80c08134872b4bdc2a5d75f3eb4", + "059ddf8d773748a0aa32c778897e711e", + "43a39cc9d3e145af8cf8850d9f777083", + "843097ce271b4871aa367c9cc2ff3e38", + "3751276163fa46f8990337b79898b689", + "7b662da74e914c7ba12701cc42cb8138", + "a0be34e346774ebcb6d21988c4fee2f1", + "d58eea1a6ee746d29fd18f2d9e1a559d", + "a1cdb80462394cbeae982b8e2bca8763", + "f0e17c71b71b48d487b7b6a27ce78bb3", + "a9a7aab6a54748bca8496fb06eced203", + "fb867db8280f43a3baf4affd7a33bfa4", + "061e22e5717f43f2a4e5ee324d2c1db0", + "5fa40fc585f445c6b6fa028bd7c437a8", + "ecb29981ddc04a43aef3581e74edf8c0", + "d14cac0f34ab43368290fe51048df86e", + "7a7a2e31fab74525b32d4e42c4cb59db", + "bb89e4a8edea40fab1b65e8e0f6519a3", + "45847b6af30a4476bbeec52aa179c9c5", + "9f18125e50a1459fa2c889af1351601f", + "9338612e9fb54a79a42f9561fc22b697", + "ec042ced12384aa6924f44c7876a8faf", + "a9c485425fde4e53b618827e14b3b29b", + "62bd6067c24c470495c29752a9a14d72", + "82045aab6ebf4d8caf05840bde63fe71", + "3c6470b217594bd0a870b621409c708e", + "a1f6743d821c41028f095731fabf54da", + "82e254afff364e27a29d8581dc44f8ed", + "00785dade17c470c90a14c90b75b896c", + "56a1cea8ab20472cace9d81b3417e1ec", + "513b9a47fd4b417bacb641564d7b93f2", + "609890b1c9ba46eb9eb75d5840b5f5ea", + "d4fe99f677f74eaf94ad99e1969c472b", + "dd61325076be483085701ad8e469948d", + "8c502ac5061a4bfebc52043974c875e5", + "50d750a147394f15a91c5ed97492d438", + "e1bde52c7be5424ab9fe14e87a55f970", + "de8fc4e7a5684103ae0c26338895b413", + "10fe3d13e1d24c358ee0a88fb29f8840", + "7cb78813cc7d43548a4023441e4eb47e", + "2eb11c35df444325a120d414af3ebf30", + "db6a01dde2a34070a3cd97f09069239f", + "f719e6cbbdf34716ae4a26508bb2b601", + "40757344a0f24bc79e1b4d11deba756f", + "20de33c317ce49a687b9fe8075d60e8a", + "cfa91c978d4e4dd7b7b7a4462082a3a7", + "d185336a70504ee4bd78d606a13b415c", + "109712ba0bff4a91a9288efb1e0b0730", + "17f94bd6cc044dc0926e02f065767ea0", + "dab5024a1f67456c98f52bc23c1794d7", + "2f3d0b1bb4d8434483570201d5c67cae", + "ba4cbd0316914ac1860291cc4184d8d7", + "be78e19ba0594f25895404b35c53a5da", + "a64e1ac7f8c44821bbc365f0581d95b2", + "7635346b3109403c8f1f3089ea948d68", + "3446229dce1f47528fa871cc7669136c", + "b68136575348498fba7556a3aca39f7d", + "ef117e2e8e6b45c5922fa45bf220a0b2", + "b1a1c0eb77254acd81f94f38e6569c6a", + "3ffd0e1e5e0a44c7b574e2da240ea79d", + "3176f7652aff44678ecc2f2b9d896566", + "54b3933b79a84b608c6e498c072061a9", + "4d490b545571442898d63c27719c8779", + "b508b33eb0844fcc91a4296cc53323c7", + "9418613f6fc54d57997f78eaf4ef1f81", + "5846b28f25f3474aa4d4a01abacc8772", + "71671146c2fd4f478d513cc0a17ea493", + "c45a19185c4849449b93ea46b24020e3", + "6e9ed65dfa974429b5d9db328b8d040b", + "c30b276e2e174109b8e159512f3bc8da", + "590fbe5d0ae84e30b6b83502284e6d43", + "e4534228b724434f815d2b27d66f2088", + "3dd8ef4d52e2446c82346a93f460a0a8", + "622b86f6e51d4c3eb611550080857328", + "2a96032b9a3b493d84a039d3d03452a2", + "162e7a29aec04fc49641da7272d0cf65", + "5f87f95d821f4ab68cf3eda04a0ae873", + "b3b13e26164948c69910119558616485", + "5b16cb03f4434727852fbedb86223a2e", + "986c95d1d84e44929f6cebfc170fe71b", + "abf26dbf12e242e4ab1ece1ed6a4dc3b", + "c72e093befb54670986883d9cc402d5d", + "c01f810dad1e486eb050ffc07babc744", + "485e8ea7bd4947428521570a747fd459", + "dfbe936f6fcb40f79bef4d0de6d83a27", + "b0e88b2e8245410480b813c2cdade739", + "13d7e4706f5243b984ef7424e737731d", + "6a18e281e1ef44ae87bf8627a6114381", + "56381471de184b829a400903e5b942e4", + "bf1a64c7e3fc48e6a2d8c23277b56434", + "bcb223cc8a2b41b9850c668ce51077ec", + "81eed9f7c9194fa4ab7ceadc6171dbda", + "e62460403b514c348fdcae1a8628e886", + "98794f0126fa479398b029e87798b26f", + "fb0cca0059504c9d86400ffdbd79c3a0", + "62829a25b4634d63a2ba2b0220335b3e", + "77446cd081994bda89edad2b018000ec", + "985de17ce827452ca915f9cb73af59f1", + "fc23850e86934db29d6c8b44545a83bc", + "fd2315002f4144f7b8f08aca12857348", + "ecd69d02941b423a947c5db270b6d2a4", + "8721ccd40b0d43b0ab5a2e720cf7f439", + "25863ae2e1f34aff808c6f70a3c2217e", + "beafa0c479744c3da40996771a4ae257", + "e49ea080f49e4913aa02c48d096c45cc", + "81df1b776dc0401c90b634326187873c", + "aa570159302a40ffa0ecf2154e730631", + "1bfdbaee9d084f8cb127dced3ac91775", + "cdb68b0e758142ec92e476686cdef5a1", + "39f1f8e9142c4b1f9e525ece875a98b3", + "5a329ea9a61046e1a2da32b748b7ab5f", + "cf7f142c5aa8439d9b8d545993efdac4", + "e4d61e9add3e4b24ad1094274df317f1", + "cdb4e4354ec04ad786bfa361c4694436", + "7731af440e614f8eaf62644b056b9b32", + "c222c11591104696aa70eee471194acc", + "dcfd0262da6443f4be321ad2161d43d6", + "f517b60777124dfc9e56158c9b0a94f1", + "f33214580fdf4abe87ff098fe4d48194", + "d6c77b5fe7844dee9fbef1ce5390997d", + "5753a690188e481ba5551213ebf31e7c", + "f8f0d72e40d24bf8afa4b0157cbcb7c7", + "50e290b42f5043bcac216346207e90ac", + "bc84c709f8744a54b282d6df115106f0", + "88408a7ed7464911a7da9c4f598dc5b5", + "f25cb76a65ea4d88a92dc4d994cf4094", + "bd228f381ad443fa992358a030a1153a", + "9cfda83306c14bbbb6526dd4cdef64c9", + "e340f514d1c745d0ac27c3a2a45265f7", + "2afa82f1c44d40979456f0bfa67a0b19", + "f5baf23f59bd4c5c8f70eb8a2d8c7b1a", + "a4701579556149a08247749a938ecfe9", + "cefa27d2c42643e287f6f63cd905501d", + "f5085208560447d6b9a8948b6054f618", + "f245dd2b1de342d188e5279020e84108", + "fca51c36c5de4fd38f46aed30e2d7383", + "72094b1069634eef84e72888c9cc1e77", + "b2a7b641512e492c94f8afd91dda6f32", + "098a4a0e686f4e16bfc2f7db00a82b9f", + "a6ebddcfff9a4c8a912551530ebfdb45", + "df3c29202d7c41e5bf68e375ced35b82", + "4983839f10ac4456a750fe08c923cda6", + "b42f9fe550484b7f88396e74693ee42a", + "73f9ddfa1e96447093718cb3a6bc11fd", + "445f4524a69242fca6fa99805e95c3a0", + "43b9952b39d14295bfcc357786092c51", + "0549d65fc59a45618d6e3d542cbfa5b8", + "20aeb851c94043ef8591d147b0f4f25a", + "7aa589395b5a40f3a75168e9f537d750", + "36d3c4f4b9454f4d9aaf5aab892586ca", + "370b7c88b4334dd29cda3adce3a10fa6", + "b0d9c7815b6a4e5e8f5d839a899d8c73", + "a5971983ab3e4fa6b395e310490ccb9f", + "477459ba63f048b89252c56433042775", + "bbea37aaed504b308e33f5f96793a68d", + "f6230d8eff1f4de5b367a12a593018f8", + "709be93810c84ce793e77673612cad1f", + "4bf56ccfa2224d928d6abc3aa9290f1e", + "8a15fc1bfba54da0b7faeb59c0363035", + "2d8a56aafa5240aaa5a1c9e9fa15577d", + "43744f9bdf7d46c2bf45361c9acc32ad", + "0ca5cefbaecd4ece83e8b2fe9d011225", + "d1a2bc531cbb45f0b144de2103aa75a2", + "9f38cf569e584667aca4c86c31e06711", + "23ba9f6363f4488d9422eefa299c8945", + "f81bb451b3024110aeaaecbdd8aca814", + "6d14266b35f14468892123ae4122ab72", + "b2e7d7ea5219463a8bd910eb009dcee4", + "0c077d2c63334491ab9a2be05cf3e1f3", + "5a165086aa164d5fabed5fdff382baa4", + "c93c0f82e566486ab2e33ced4340577d", + "4c90a2ee69b64f58979f7ce2475f230f", + "0861d1d6c48a4bb6ad30852c9322c012", + "50d00dc77b8a493fa447235da2ea0c07", + "9029abfb2d1348b8af97dc6177fe1e76", + "8ac74bc427d3402f8d2ce3fbc0ceb4f7", + "f1b56f7d9fc34ee786f6a4c53205a2d2", + "a4a9acf0e53a48ab82ca0626b66ad95e", + "a67d59d2fb7f42d8b3f65b59429dc6da", + "166047fe68f243a3bf72965c472b4ae7", + "f5cc5fad1455453f97a5d432eb924e0e", + "f124c04d6f61407c855e8ad2532037e9", + "e2c68551a5ba4dfc9226ab8d6cb15398", + "b6617576d6df4cbf92cb1e59877ea1d6", + "6cb8754b72be4491a97fe8b05c10117d", + "cec60d576ea449069a0d17373982c0f8", + "36bd8fbd467e412780d9180b42416635", + "fcc9e5561b874f64825992515adec348", + "d01bdaf3eade459382052b044eac578d", + "be3d5131e634424e89ffd57ebb19804e", + "35ae83ad2dfe4274bf56621f8c20e6b4", + "c7ae24b23f48403c8d2bf12be1ceb1b4", + "2aa66d1949df46098409dae62300496c", + "9a89e1f5d3454923b1e14969333dfd8c", + "e1c0031a7438460d9b987f8a5df2beb2", + "6781ed46a1ad43adaec73dcafe764ed7", + "d501c3ff798945cebee84d7944edb19d", + "939328f7b4514e49a177548112d7a950", + "178a770d1bcf4145873b4c4d6adc0371", + "755546a1a5584d1ba9577e18863eb3de", + "61966fa4cea84f73bfc0bd89d5f5f556", + "b90b65af758d4c159cb9f37fee9c0f14", + "4a24de5470994e429e1fe79683a6ca06", + "e554428a881843a69c5ffa91ff2c3caf", + "78e79fd7278941aaacd8912370fc3ec4", + "6358dc2620ef463c95e346ed6928bfe2", + "5cd508e9465d4c709d064efc772031ad", + "cfcd4baf21944296bb93fc3c02d51dfe", + "1dd7467ee6b947e6b6cd03368c00a8e1", + "f47e3429f5de4a2f95ee3f0a82a3edd0", + "e86598f3a497429a87fa92003efb9422", + "743a8da5f8ec4f289a5712853ea40bc8", + "49868f0b7cc84b93a7aeff01fcd64546", + "c59744a732af4dec932a0f1448d7bb20", + "d6904dbdae8544f580c87c3054695219", + "791c9a8942d945369f9f6273a96e697c", + "ccac94b0d9914d949594809c6fc8011d", + "df49cd935f3f44e68612f346ac617a67", + "dc70d68a30304549ad432596ca13791b", + "10d2303218254e639b29cc18d3452c9e", + "32ceb994ebe94207949326ccab078c24", + "a1307a74fb2a4673af99ad9f2fbfbb7c", + "3763dc920bc041009127de518d505e77", + "cee1570d79fb4114a8709fc1d08a05ac", + "7c6fd1430d1a4e4fb04850bcb292bb07", + "2c437e4b36e046e8a9ad7e56c7005fa7", + "ee81eb66006b4d8980d0cf9ff6304b69", + "44af29843df04d8d8f6e74b38f48f7a7", + "dd0552b1f93b441cbdd626a5b2abebbf", + "0edcc9053a114e7f8a706cae0864e7be", + "0add92989216419da76ee607ec6e673f", + "63e4d8faac73435fa7e9e929baa2c175", + "f4a8a7db0cae4e02baba535d6f805da1", + "b690d85c01b34e0cad6ad27cb582663a", + "a8c06fd4d1a34c60ad37db4a487507c3", + "c82ca9d356d546a481ae3b1393888df0", + "542158414c9f4452828b12df34786c44", + "9819dff941814adc800633952503dc4d", + "d1edec23f016470193f7356ead195e78", + "64fdc917a7934b07a1ac3287e9ade405", + "e6264e6942954975a65e4b4ccec2508e", + "78948b205b93481a8bd85497db98964a", + "886b2e3ead1344ff9d29f77bfbb06817", + "a0d95a48947744be9a2aaebded6a5635", + "29ec3177bf844092a6e631bc45215b06", + "d2e28f4e3f48430288aad8f7dc3fc47c", + "5b63120d60e643869b47e9878442fa8c", + "7f9164e6018c4ec7a3585bbf6e6d70df", + "976f5b6e9a1344628642051f680b176b", + "cd1f700e4895400d8e8ad7ee46fb28bf", + "efff39484bf04edf94dd78a15a97304e", + "559808c2c60d422184b09f29734d65e3", + "98933b602bb4468d981a64279531faea", + "016aa8df34e946faa02a145bdabe4b48", + "faa4e8a0221d48f4837b863ed7805acd", + "d91cccd6e51442d5879ade2ec65dc422", + "919543b91c9448ac877fdf671fdcfee5", + "0801a28228f74b67a4969f93c277545a", + "b92ed25cf925432586b50439ccacb955", + "ef12dc4fce6e45dca2da7100a32c3c59", + "e9a319c03ae9420997a5caa7a75bedfa", + "ec545e196ff144aab6cc0b1461852d86", + "2dcd3f211ce2421781546914ab4152e1", + "7d7eb00d25834d6592800743e19d49aa", + "403e8cc91fcc414bb39363904f6d080d", + "03c5cc9626e1456eb247ea7dcca8e133", + "7f7155d68356435e916fa4b80b4468ca", + "401df6b99a4142eeb6bb1c02ef09c18d", + "dceb864f7786497ba4598d0b107ae533", + "5796b62e40984a5bbcc83fe7b1ed831e", + "23daa0bf3bc74efdbd95040c2a2ed324", + "62d7a62816b8450d95ecb6dd12480369", + "4387c9c39f8f41d29ff408b120cc8a73", + "f1d1eb1f7c934a1b9a9df628dfee003c", + "0feee3cfec1142499c2c6ae2b82e443e", + "8768e312ca144e4486e8de7968e228e8", + "e547b70f8bb549e3ad5cea9a4eed800d", + "e73ee672c8ca4d74a89ef66d1ecaab04", + "cdc2aa02d18f40cd9fbbe2762554520f", + "433529b3f44845f0abb742c1da85da4c", + "0fb7ad6685d0457190a08649b1883c06", + "ffd0e8c6c6b148ca877fbd8e4cd25d2b", + "f8f8fb8c0c3549fa81802b36467be157", + "61ca2677b5b8477fa7d2ce815651030b", + "9176cc47609642b7b47950e26ff2787f", + "641f57694ed34d93897713f71ac1b89b", + "abb34c0ea83b43c58232bcd07793d979", + "b185a4c6ab3f4c3eb87f042cad633cf3", + "48bc4666fc1f42fda938f5ce7750bcdf", + "556ffc27236e4083836907e8f4f8068c", + "deba60951da34a48ba91631c6f67b6a9", + "712d1e5c3a944dfba95bafcf92e0aeb2", + "a493a55c1e4c4e7fa4e7b5ee729ea9de", + "b0ed331c418d4959a3f050ce88f47346", + "e2be3a9c003a46e192847e2b2e7b4dd1", + "5ebd3720da554fa2a60e0fa280c5ae7a", + "867d69aa47e542658d8db8e3f9fce704", + "47ddc9cd995e48e7b07318a5886f511b", + "d972042bbd1f46f797e073502c807877", + "7671efdc7bb5476aaac39a2631810b7e", + "222d072cbd0f43eaa16a9e51e1f5078d", + "49be125faa9e4c679d851e798e3e955e", + "d2490859ff444e9b858034dff715a679", + "aadc2414af8c4e0f862bb18a9d81f774", + "7ada25d98c644ae98f7504e7ad1be3c6", + "89f5b1264bdb4d89b85c52b3b658e604", + "880044db2cdd45ab8f7a30ed57a7c217", + "377a6e03872c4a9698f310c6bdcb8270", + "edf10f983bf545468e569ba3bf97e610", + "c6ac6d88fb9a4480a11dc6be639980ad", + "cefa96fe14a84b5ea2e648e54a42a4c8", + "84eba5d3da9542fea14a6b517f13f7be", + "294b5774d94141358a7b6b1708860dde", + "fc34791dc62545758ee7290c8d0ff67e", + "ec33f88c15f041638f5b7c8ecc0705d5", + "24fe70afcebb4a08ab0917f313319611", + "b42b0ebf61cc436e88f8cfdebc3b463e", + "e5d8643821f44c5888271d1c236a55bf", + "d8986fdbf51d461aa1b71d16297d6b19", + "6277248072c84f9cb4248413b1a92de3", + "2b92a90c3fdd4460ab3ba2212868cc2f", + "1b0f23edb82f4474af49940c70a9b551", + "a63717d314ea41fd865669f58db82fce", + "8537f76e9cf2483094bc0b004c8a4462", + "8857c46674434a93be5255589f7c62c8", + "7760315d38844ea8afeaa5e51d4c6e25", + "5e7739880c6f4d41873ab5d6fc745121", + "4121216e285d4e20a0a01a427118859a", + "677ea756ec224280b144b061ab0fe4c9", + "b39d01d198b14732a71045aa26ff6f42", + "8d3e568f059244e19f3b5f7e789cccb2", + "8c564dccf3184669880b729e36541c3b", + "f32eb13ae3a345ee9f457561963dc0d7", + "63a8265be6874ff5a98bf605d10027b7", + "47c3d65091b04ed797dbe34c9bc4d820", + "2c48bc5dfd6e4a488828d0951e673d4c", + "cf72563cb8ce41fd87f47e04eac1720a", + "ffb33b1407ae4a50949d4b0f171d2090", + "6b96570d62fd4173aeeb9314ece38374", + "09a66af47bf14d51b483cb8d85765ab0", + "517d9d39ae3643559f10d7927a548bba", + "1bd37fc218714f04ae6a7ed55e42f345", + "f9dc30b767e74ffbaa8a5ea36d1f43bc", + "e80f4c6e5da542c1912d5295413292e3", + "9b47c3ded5bc420daed5a76d245720f6", + "23aeba85fce84bf2b97cd482d0a80595", + "a49958a44202425e8f3ef20503d92677", + "23be5867d2c94eacb99668eaa02572d9", + "a880b66d3afe4c398d09817370552f48", + "53c1ac4a7089403a850519eba65de629", + "13e21b22a38c4d82b3c4b2af2e9d765e", + "f178d4017b5a4000b92d37bc716b0dac", + "df03807b536444dc876e07165e48f53b", + "37d747c239c34ff581db1f0c22ef4b03", + "57fac69eac494c269cf8078530ff8b88", + "ecf7e409454d450cbde731259a51bbd5", + "b41a8203ab724a958d5b4d9d64dff99d", + "0c4fb9a131c34f09b534a289baf0f54b", + "b4a74e9908114d3382ef781e8e1034bc", + "ccd7decc3cc1451285803fe56dde3386", + "6902c19d05ff4550a5d85135158b046b", + "ba108dd7e81c477dbdc92ea200d11dd2", + "f2696756b0754a929ea3cfb4f61df5a6", + "a7a584ced03d4367901c9ac9279bcbde", + "90f88566741346d38ebad86d719340c3", + "4c8910708c7d4bc3ae5d89be85dede0c", + "2b47d4b9e6794051928e0dbac36cceec", + "f74431dc98004b9f9bb8311ce534a4b5", + "ea6789e450894b5da003051cf4ca19ab", + "353f435ff7174f46a8f00cd62f5db610", + "97eee04d5d43417e8f087205d233acdd", + "6f4d6343a1bd466e9472340e967a0a06", + "8a9de1f7ddd74ffa9028afb053b236a6", + "b0cb063fd6be4ffda9028eb20fe45f38", + "6d3e0e9ca9764ef19a49abe34ffcda9e", + "bb7f9ec1585844a1a19c89e4e6c127eb", + "120a8eb4bdc948f49d5217e34845ee9b", + "283da165bfab4476b2acea442ae43ba4", + "ce00c53372064605b6b39fa856419887", + "9912e15f89e14b8e892c5ad180ba6fc4", + "d46ca999d84f49a98743bd1885e925c8", + "e4bddf210b7d4f53ac3e7847b4b1cafc", + "5ad4e3f489ee494ea2c361415735b72d", + "50e0e11060df4c0db6a44daf3f32639d", + "0ab0576ae3564f5c822dd220a1b2fac4", + "5a8243d749264f319b2c9a9a985db956", + "cbc3b65f22384441856c789b78aaf887", + "219b123c0e694e359baba80b127329d1", + "800d3c5569b94abfa2da7976504d589d", + "ca5d21dc33514276ae91332696219ba6", + "e45e3b112dca4b9c896bb7034f05c625", + "d7a12b126e434c42bba61faa159ec7a7", + "624c9f7dcb2f4acd93237591ef10c76a", + "b83f67ce03054b64a2c46875d32ec9ed", + "bc872d79faa34693adfe6436bb806c39", + "15c4b54f48b94a49b0e5f1d99930cec9", + "6363e0aa7d24455996419b51fbf5fa3c", + "27d4f70bbd1f44e0b805e47571eb191e", + "7b55ae54ebc94f108b46939d513dc484", + "1c4bd99b9ec24ef7a00f8cf9fe3e755b", + "3a9dfff4734249d99c62eb925ed88080", + "9db5ed22c52547b89f8009327fbf0f1a", + "f90371bf90a44b37a0823011fe3d4683", + "7b9610aeb2ae4e0b937c72f29d63d310", + "f592a08883ed4fee8e6f8c7b59b3a514", + "7c18493e26df41b99cf4f5e350cc1d2b", + "7dabb777f7af4907a4856350b2b7c7ca", + "68e914a5d35649a8a6a34cb8b777a25f", + "b1cf459451ae4a33a4aad866d812fdd2", + "cdaa00b3051e4227981b78d88fe00721", + "e104a61c2a3b4b3a9461f95d2b2bd7f1", + "3cb28321e7784d15aea3fec16f07e6f3", + "b99c584dd11d4691b5d13303383371e5", + "b5052e8363464902be2140be5278a423", + "89c76529d15a424fba5b47c2c572a18b", + "7f7d9831de524660b6e2428ac19a674f", + "b80e6c299dfc4f69a0c236e09f00964d", + "6c5ac2547db34c3c81b2e4808b000386", + "b8d7ea9d15bc4ef287904de12f1d4466", + "b1c12c5bcc24440690f65f2c6a9b7e83", + "1a7346e0575149abab9fac3184dc94c3", + "b49a3cd72d5a43d786ca656094d2bc4e", + "89038877d06448f398c066b1b93228c2", + "a688cb270a6840e1a11e88512e12c417", + "9aa853351a55453f941ad11d10e99333", + "792f076506c14645a6511701fd179c5e", + "7905627f0cac45589f5e10f30cf79d38", + "bc204819e14d4c9b81d916ca7698a7fe", + "2f47ab99b8da45e2b343e28de4945696", + "6fb694271f7c458e82dcbc1340736831", + "5e37e7dde59e4c98af3b90985f492d43", + "548362a5ab6f4c8e8fda42143172614e", + "6b7d44f26f11402f9d424ed0b114daf5", + "ef3e64b3f227470495fc836f1ff451e8", + "d58718e65dff4ba2be87522d65ac5373", + "5d8cd259156248cca4e1cdcba6ffea67", + "71895bd2c24f4fb89482def7629b4343", + "64d55cb8c3e84f4f8f4cff206e74ac25", + "3f4d76a492784fd4aef9920c7af933d6", + "5c590c42fb5e401e8add8528ccd6e900", + "d93b3a3bd05a4278a1c5e5d2ba9b70d9", + "a06844be689f43a8a6e39c3515931220", + "4e719b26038f4011a59f4b901c10596f", + "70efc4b261324911bee731fa1b69fde2", + "05a830453669452f9b25f649462e3a6d", + "c5831340f01e4c7b97f4913aa85cfd1b", + "34d340bdbe6242c1b6483c41684262e9", + "6aece0955eec4837aba89da35eefaacc", + "b496adbf9b924ff99939ad38330eb3cf", + "9ca1b6d6ad9e49e88cb442f5ad66de97", + "16bed6e2f2be493ab51cc8c07963cd8c", + "e39cc079f57748a5b1c16d22557cf1f6", + "ec8855a1281949109243392b04da0484", + "6f92e0acc0d44989a6ae3b74fc67cc62", + "27e1bd2f309047089c0babab59dcb1d5", + "b263c4982a3b4b9c885d7d2b531f6e00", + "54c22b2a02034a53a8d93442a3b4a208", + "9b21af830046454cb7e4e8c411f2f28a", + "012024bd9b4d44a18dfdc298deea9bcc", + "bc411f6919d8457eb953a65b7006c8d6", + "e3ac447986de4165a273cb04246c8fdb", + "26e1bd2ea5264001bb1909dd183caf82", + "3ca015ed6f3e4c46889920f40677e4dc", + "b14c52913d9141d3935c3cb046fa4a62", + "d78c0bfaf7e2448cbd98a485ab079ad2", + "3d3cb54d7a594c4f880c0585d6175b5e", + "47b6b8030c6b41538ef260914d6a2a9e", + "66a907d6c3ff422186342a4aa24045ff", + "d630b595b2d3493bb030b5a3cf653c2d", + "b4853f8e7661447a87acc16705f61364", + "f9893c3dacdb48a3bcff0106ea5a5404", + "be0042e033484f9192a6116ebd02b988", + "5e449a73f9214903bbc77b03fc423b62", + "567b281ad7cc4268b015c843ad970bd3", + "debe06917deb4ecea4ee331486d020b0", + "c0ad735d84e749fd80dcd2cc92575862", + "497c793285d8482a941cd377c7458bea", + "ca8e20b9776b4bb3a46cb4685e9fc2f1", + "640b33ee7d784da68c25208c843b5419", + "5fb8bc0a6c584ab69627c3de8d6c7c01", + "426244116b834a0986d4bd6b5d975a6c", + "8dfbbc8e7847404b9a3bed36fe9c5bcc", + "8e6a1ec6c70f49c1b7c3aaa7901e19f3", + "53cce85d9068451a936c413369a7ed8f", + "d9ffbc4bbe1044bb902e1dddac52b0de", + "1b22cfe60b934d4bba8d256093d023cb", + "b7826b10a5684bafbfb8baeba8673f97", + "fe6ef80aa82d45abba038037d2a10879", + "f1d70f95625c47ed913bdb877717e55c", + "0fe1768ed60b462b9f5ec8497a86c2a4", + "8eef676fb3694402975fdfff345c04e9", + "a0f4ac3a3efd4340b401a6f7a1a33b32", + "59f464fc123947e2ac111a3c141dd815", + "94244ddae2a0411fad12da680912b238", + "c61227cac7224b86b43c53ac2a2b6ec7", + "fb3ab0f7e04247a09a5de927b316b3ed", + "3282a6fcefed41e4a56875f3bc896689", + "a284966b773646dcb86a34103108442c", + "89a6b322e4304245a5f6c496ca07f5fd", + "2b4c540b3ad141729a910d90046b01d3", + "490ea567e32f42748f654c41ff0f1873", + "146065c5fc6242c1a2f668f473ccdd6b", + "cf23a572a78d438f850fd273ff1b0c73", + "cc22f952842946f48c1b126d73320389", + "c4950486ca6a43efad88aa3787383064", + "686d56baefae44ed96352b042c658bbb", + "5cc7a99302964b229921aa445a1fcbb8", + "e38a4e71635f488fa8ab8c55cb1192fd", + "4af29eccccf44f5298b498fc231b8313", + "5125528b0ec043b98124ceaa9e44168f", + "9bce3889f01f4b62bdea932d41d0aab4", + "a2318552b2e1404fb2e875421c841c6c", + "2b58376d6aaf4641adf30d4c9044de74", + "4eeced2827ed48d68bbc3ae172d2eaa3", + "10ec200cadfd44439b3ea9e807d2d88a", + "0ccda97a90b14151ac2051373d8a0275", + "22a06a32275947e380363093faf3086b", + "f085813c5d1446b0a65e1c734debf8b0", + "9678a4672a2947d5995f76a56dbafe6e", + "09aa9e145b7f47aab9aeceadc37f20e2", + "060304b630764a299e619e26279fc123", + "e7b2eb21375a432e9c4e17939258f017", + "b65f907196434f32b69df6c9359896e8", + "3d8c8d3c7a4045b799656d445b586558", + "539e490ba92c4792992c7b0b439a7d70", + "2176ea4691054f229f2b2539ae126afe", + "07bc3c1e39944ca0935639b80c1d0bf7", + "d54546f22fa8487c887a8f3b9182f661", + "64cca1f9f2314ba89658aa8213e24258", + "cf031423f03b49c7a8674ca12a662ffa", + "7c25d215cb2144578e6665a7bb79be83", + "cc9b8def5f5d462d810f30e974322541", + "bbff3790fd444704a722f46f80dde018", + "3811ef0ceec64791bf8a52980928d0b7", + "db415d2f3d9d421c88caddad08cfe9f3", + "55bffef8dc834b98b40296b935e903d5", + "43dc12ed71db4f06b8161182f5d0c20f", + "3152adeef0934984b8c2830113cab821", + "bbd6a669a80b49f0965a569b27d7d5c7", + "32a8e1f2186545f79a572a8307ce72ae", + "f7101b71a5a04826bf10060bf4c4f29e", + "cc0ada94b34b4850bf8f57e3eafd5bf7", + "47987025844b48a6801903ea4b5a17b5", + "7242dc92501742cabc6edfc501e219a4", + "a6beafb75da24c7aa36c4cd95da7fd4a", + "1f54a72db6744f83aea120c84e2cc2bf", + "71e07ce5e7d4459a8b8102b8b04fb2c2", + "f7e3e961d25e46689a6bb3721c06ac36", + "826ec8fb717d4415a10d3af9ced10f3e", + "0cde834948cf41fcb4fa4ec3f4038732", + "41d1fffe051a41ac8956bf73a2a7674b", + "0748f751939e438c8b1e9ad4a1711bdb", + "e9d8ae0a9ef94fa082a5a63e092fd402", + "47859810e9854c0a8568fc7e8d01f1ce", + "a9e46996a5f845659ea8bf01a76b3920", + "65e61bb61a904da8b7688c55ac427825", + "74cec68d5d314dad9a6eb9df6f9682b4", + "c2883a67707946eabc541e0f4488dad8", + "8a22e1fd8600472597bfe478e7d0c9ba", + "f84e7dade99b4ff288f1dcd89d710879", + "30c0aaab8f3d4834895ca7d6cded5509", + "0772a648d4af4f56a74999169bcebd57", + "3a8fbf9f67974602bfc3f2c662f9f0be", + "1a063e0f585d45f38daba64df0ecc5eb", + "97b8b4e8a83045c5a5673f19d6b21e39", + "3d2f2fb28c594855b34eabd6747c8b8f", + "a7fa5398d1194dafba333d80d6f21da4", + "d5d2950fc2f84b30ae4d2c18608112d2", + "f9ca6bdb2af640e087112180bd1be152", + "017a558690624beabe08dcbbc88eb25b", + "8340658f78f5484bb32e797d4235c2b6", + "a7005fad11824d4199b952f45384d226", + "6e9bbc6183be4a2793d642d2cfba3cde", + "82c6768ddd1e4617831063223a7f1246", + "8036d50783f946cfab24eb61ac09a01f", + "5b06a8970db74a7fb900ca6c84b99ff8", + "c151d5588f18461ab6d9049e0079f639", + "715d8d85d7a74ca99c7c94356056d07f", + "0c7f84d9a93c4a409fce37bc7928fe06", + "c7eb6be1e8b3455e833767066405dcd8", + "438119e3015547299ebfbd5e3928f002", + "1f9e92f742564f28abea906b07a13db5", + "34d9439b0b4c4b8e9984987a89e9a9db", + "218112819f234c348ae754ba64d24917", + "420e464e77a84be1a746b53b2444a53b", + "6253f1a2ed104155bf661386c8a7582e", + "6942052efa664d8e95e3dee03c1a21dc", + "9146eb43193c47f0afee92b8d319b3c3", + "11f2e790c03844e79bc44efa5a05466b", + "695b9b8ae3354368952ad97c66ce3cef", + "47f6072b539f4292a9b7809e6fd5c8c6", + "1586710e689a49db886e519bc39f2bb5", + "173b986511f74ff6ab8bbde73ed05774", + "7f1392ba478242d7a2093930b213e954", + "cff7eff2aa6746aab0e43551647e8c94", + "18f2248f31e6497f8e8bd9fd517f0137", + "1021c13dc0194732bbfe277cd5fb89a7", + "ea901df9ad7241fdab3f92239ef276b3", + "531e32a371004849bd72a507aaf81643", + "41fa3210e50944eaa489c148e5e2ccc7", + "23a6146d3e7547cfa571889453276b12", + "232d825f11f5428382e14dacefa02f0c", + "c6cce8ec55634a0390055d0526029f1b", + "a9ed7b1e55824b37b7e5eabdba6545ff", + "3fd8d7bda863480fb4b1ad6a9d1c1043", + "db3b145b71784c17bb4fe2552484a8a5", + "48b70e34b3254812b6c89bb677cae4b6", + "939d96996e824628944ab943b33c6c3b", + "2f69495ce4e040878237eb7f46e7029e", + "65c138cb60144530a7fe3243d6534a9a", + "ea628bda86df419d9446b361344582de", + "5c18437f4d824b9ebc5b555ec67a90e4", + "47f72e9a3c3c43a4b26a494f38748905", + "bd23290d85434bb697e934079054a6f4", + "7ddfbc2541f94f21ace96a645ce061ea", + "cc02ca24d04147e29c0942830f74affc", + "2cf94df98556476cbe9c823175a8bae5", + "31d0aa0f341b4cb0a229a5bb49c28475", + "9187f71b16d647f0b34fbb1505146416", + "9c71f569b497428f9ff492f57e867c72", + "d1bf4dda263642a5ac79a7db401a6829", + "06f9e20d07184ad5832ab633b0e0005f", + "30e8921261ec4724b69d92859fa3512c", + "a92b6fa622a44a9b9f51888983b59dda", + "9252141c5ef641f2987be9ec21a51446", + "b8d3745c818b4e3c96671d9418996a4a", + "9c4f6493ccdd430db378b84b0702fe81", + "b497684568844c208a6f6b827b9eaa52", + "5f96958cb4b145e8b8188c83211d3e4b", + "cf8826a16c50499bbf8777dfe218e3db", + "1ed0fa6bbf6a42048013e0153f02c3fc", + "3d530513795f4ae68ae04b1ed3df277b", + "6baf8dec3d754ce8b9923bb42caad4af", + "50cefa99366146f6bfcaf87243e3ccad", + "96231d9e4a434046aa3c1845a3345b57", + "914d1dfc0d2b44c49103da81f230bfc5", + "3de88b14d5bb41039b73f9e632e453e2", + "d4ba44ced178428ba41ac835fccde714", + "ba309deed0d54461ad892e37ac1f70b5", + "b57100a0a1754af9addd4fec9566ceb6", + "e7bf013927104fee9bff0286708413b7", + "4357b57e23a945d98bda7bd57b68fd28", + "e31794846e984ab4a42f17f9010aec62", + "eba40eb9eca84aa38eeb3ff67a386ccb", + "06bb7196230c453d8bea4c1169a54cda", + "d08e632a682b443f9cbea787b771f488", + "8a4a3a90bc104f11b82cedd9b4e5ab6b", + "442067e552414bbfba051823e62759dc", + "370f39d807d94343a2873a4e55b35435", + "8f8e1646cc1549c6ab22f1a3c0cd2924", + "edeb4fef09454706a669282aa2c06a10", + "acd2dc6383c740c8aac5dd99b36211a4", + "2864c1a3e6dc42fc99ec49767f9005fe", + "411bfab979fc435eb129eef157bdf671", + "af78b89b4add4132bb3bbdf5ec263cb5", + "2cbce7d459ee404690cb421b8d11984c", + "dbd3fd6a97e64418bfbdedee9a018933", + "263284b3ce614005a913c2d507ba58fb", + "e1c9043ea6204efbb58e636fda61069d", + "6a2beadf7a964bb68dbc118d71da84df", + "952229607a2c4da3967e334fe1afa4cd", + "3306efbbc50640baa6cca0bba21fd7e0", + "1a99a7d2e1034609a657ae62ae49a8c6", + "4e5d012176e5459d9b8cad929999072e", + "6fd942297dc34b6cb12dca4be2710b80", + "b1e5257869b3437285f13275d21b43d8", + "1d3405416b0f4c3f80c28dfeb85af958", + "45c96c7e9dad4c9699fb6480fbcfb201", + "56ca9fe84583494c99b2f2fa0f4807fb", + "defeeecf615f4dbebad45fb4f310c5bf", + "ce497813bcb646fc8c60e77c78133a18", + "13c1fb8edb994f69a84a94c3d31e63a7", + "9c4133c9649647d597076711eeca73ac", + "1eff2077c9a74d7cbe2836ad16001d7c", + "87d99d809938482bb95d0f293550f778", + "28207b2593ff4e5f97ea3d1ffeeaa545", + "18390cb5d75a4f03931551d542f322f4", + "252f730f1a044efdb801f84c7eaabbce", + "7229d7c7b24e4cf8a124456625a4d1df", + "9a58a8ae7d034db0988e3cab0f0faaf8", + "e740b561cbaf472dba969724a0049dca", + "79a14a0c51a24128b979e076172f64a8", + "2d455ae454514f5fa6fb3bdc7927fb90", + "cc5bd63518694339842c2c05de831859", + "4c8af55af44c4e888fa9e3ca037f65e3", + "dcf0f8db45c94f09b45f84e2c6cc4016", + "94a93c542e4b4c0f91c718de3bb15946", + "88b957c1af714a61abf7bdaef37f9e0f", + "fe36e57eab7948cda439e965f88fa8bb", + "33208aa9e5134f76a66329bbd98382a7", + "71173f9603794e0eb52db39a7f26216a", + "26a21e1131984c0ba851142db44dffd7", + "b5846651c3404232bcd3ed2f679fae71", + "bdb711b30f224550a79a1c286a3c1119", + "a570bc258f974fabbe60bd142dee8fc5", + "fccc83cc82484a7583fb3325431e5257", + "b9b5d59e377749ffaf5ef8155fd889b4", + "b3b34636b31e42c5adcd45cdd5cde307", + "29ce6292101f4fa88a978d4f239b9422", + "7dcec4e910f04af783cb4d4f64cae2fd", + "a5c717c20b08461aa1d9ce462f3e019e", + "4de702a2ce24459e87678bdcb6e4a946", + "0ecc7556fa024ebb93f29f571fb5dfbf", + "12cfdfbfaf134692b500ff34991b60e9", + "f7e2323d6b6b4e6c8f4aea20c1261d7d", + "54a2e596c3064cc48c5cab6d521d4e39", + "dbac7acdfe6f4d05a8d3fea666f14971", + "88721b4b7ea34860a145dbf27e8704e4", + "d2785b57e7da45858f2fe8bf4dedd68d", + "f323fa36816549c8a8525171988828db", + "308cad8d9cfd4c9b82b89a0bbefa8b4c", + "e99b3be887c34f838588c6b2bdc1e525", + "9da90ae06fb344648b51e1529bdcdfe0", + "104fa0c1723e477bab1e01c9d6ccfc5e", + "6f4c1566b9674a208d618b4a00d0343c", + "862151dbee584974ba6d0c283a32358a", + "c7db4282e5a44111b6bf46c4ea2af167", + "25f9a07662ac481d986ca1c8211f00b7", + "b069b53865f64cd1991750e35646d6df", + "057c7ef49da5420888b4d6d04c9ad3b1", + "469281390a4643eaa6721218576f1c94", + "14531e18038a404c8653568975ef3e8f", + "1b32c464bf09435194b0b5f90748869f", + "8795471e399040f6bf10813221f6dc22", + "bc02544579d34003a703962d7b930e7b", + "e8ea571e8dad44a4aa1b67b4d4ed43d6", + "0a732d541e404e3e9bf6ae3841ff353c", + "613d472d04a7483cb81343dc9092fb7b", + "92001acb725e40f79a62ec4cd278d845", + "2ae4411201664650bdd0baa34007315d", + "ab989d1db61345cf9c1bbb641985d6bd", + "febf8c9e22ea491295404b6c1fc1d548", + "45e333cbd80d4511aa8bb4166af8f1cd", + "fc4e87ccad02448893f86449fa95a243", + "0597ccf3c15d4037bfb150deb96db374", + "a177e03854df40b188f3357be70f98ce", + "370fd41d81e74408aab90707b0c61094", + "65290c71cbc9426cac3b1a852f6514d1", + "ba31bc006ceb414b9bf5904f7bfeeca5", + "5a8c95a1768f4d3ca4ac774c6e63e6ca", + "83bfd9d4899e49448d4f5f8c286444f9", + "e73ee22363e840d8bda0dbea094436db", + "6bae5c9339724370b73d3aaba3a0664a", + "d2a5fa22ddfe4b769d61bd0cabb0e916", + "e30f6b8aca7c4af081f6b5f6997ea551", + "b56b81331886482a9da2126d2d9e1125", + "0fe76fe96e6a4e978a117b8811eb43d7", + "dfd9ef382d0a431f9195846aa58e64f1", + "4e5d2a37691949a9bcb380763d144532", + "ee8191c1c75f47389270cde684872a2f", + "c632c81b15fc4b188e437c2fc5bc9b7c", + "3ce2313542334a52985e4bdde47c8e00", + "e5527f4639164f44bc937e9e93e9b0f4", + "10854be00e2b421bb4f19f89a3a2b4b8", + "a13662e9a21e4841982903644096d34b", + "ffc7c509b8dd46e4abcf387ae5ab6503", + "2a54e15bb0f24f2299aede92b1a33708", + "fca96798057a4d949abee3631cf39365", + "1281d8a048ef4789a01cb5d749e073c4", + "e31d40d9a2564c95bf6474c77247edfb", + "88fab00e70e642aa96aaa331289ed05f", + "25255c777f9342bc94dacbeb027dd15d", + "c693078476134862a64944062f8d3efa", + "6a3e9d4c8c3a4d8a8b4c672a9c18ed87", + "79423b5af040464495ebd44e5e9f6390", + "649ed122d13b415ab673fb4d375c3063", + "7c5e617e522441f8b3c60386d2d8c257", + "412c5e089cd847f988fa0cd7a4a20b9b", + "ee5ef7c6a86f4d81848a1bf3741daabc", + "28f65a0c57024cfdbc451f9ed0f1cacb", + "b0c0c9c65d06443c87391134a62e2287", + "eb2c70476cec4c8790c3f70af38bc58d", + "0f2b7734df25406c8b58a1acd0b8389a", + "360eb6f19e764527a98b157516c2a193", + "e1324aa681024340905a2fdf238e8c27", + "a5a7d590bd0a4288b489c1421aa59c14", + "797e7c7f61104b6785c3bd0fdb99c74d", + "c420d45beb9847b79e8230a2b05ccbb5", + "87322743d6234d43a3348ea8617aafd3", + "da5be1985e2441b5a8d144127fe6c175", + "9b5633559e414cfba5fc055c53cc298b", + "2213b3576d854afab30b6e4ea8e44f0f", + "75f6eec12e024cdf88963e47be4eb44c", + "eab6a0eadeef48038900a372fab77645", + "bd9d5a2de5c14d0b9045e4667c6f3f9e", + "14cb40aad07e4a10a7aa731760d7941b", + "2e51bceeb4864a7f9a78731d257dabbb", + "eff8cac90aad4ac692f85c8b70fb07ab", + "1ea2dcb9f73c4141a936243b6616ae0e", + "a647ce86a7304864a125a5307ffff57b", + "1dc9dfe1c1f34563b0b747e741a441ac", + "157ab13a82c6409b8ed79ee1073e2227", + "4a0c9ff174bb47b0b40b47d23514eee9", + "c9f92a2dccb44a789afe1710a4c63e9b", + "d73a32a706134cc9b41891c41dc82a52", + "5c50e78e4772488688cbbc2968e6a230", + "b8792d1b3acf4081b0f173497d19d08b", + "eadc6f34f3444f4ab6312baba1b4e1b9", + "91c3a29f67a640a0a142ae9f68486ac4", + "48a77bd947e648e8900533bfaf76e78e", + "e24b623320cb424eb89c00c281266378", + "daaa3294f19e43549d95a42b4d24e45b", + "fe75194122fe42b4bf412bf2dc53eebf", + "7779b4ce78644c78bdd0ad7e4f0ee6bb", + "6f8f764ea8904c1b85b76e70bdc1ed93", + "d345f392b78f4150924590580068ebb1", + "c27e4be8cd0e4146bf7c2884615cf5e3", + "68a5c1e7ef5f404687ebda2d0da4a36e", + "d53a6c13c3c6420696aac17e21339a0e", + "d165593433754d2283f655e2b3cc8dc1", + "7d96451da81e4f72a87989415c2aaa9b", + "d6b51c17b0b941d8a24bd21b5936dc72", + "5849e74c343b45f887eb8657032574e4", + "f70e99d5022c49b08a0581778d88538e", + "b9314f3e47c642caba886e5e8b361b2f", + "bc760720fe814b89be4fc68ef796a58b", + "266749145fb748b98f1aba7b168c16fd", + "12d12706037a42c888fefde0f7445580", + "e602314868864b5db292f1a2eca976bc", + "f0c0386ee7b34b8880847a543b85509d", + "e1a1bde6851e4430961f0d4acfa91728", + "1dc0ec53ab874bc99c5930c1a87ef562", + "818462ce3d84424884d136db06e72244", + "fa9c188ebe9c49f994f6c5d6bac70ec6", + "b0647e882fad48059b176301b26d8475", + "779f428e61e54aebb0dcf7b116b0f445", + "aabd500e809740eeba13e61fd0789f0d", + "80eb64b70afb44c2947269ea14523f71", + "ece4a007b36b43aa95c029e5cbd0a216", + "f322b1f06bfd438bb20d8af16e92cc14", + "306aa51bb3c24464886dce788547e6cb", + "a5df78f66a9f4ead81b2b674415b95a4", + "4dadf1e7b439470b8af7a65e2f3a38c6", + "0ca62a91b19e49f6a832ab83806066a8", + "352c8dd649dc4069a63c8da71e8d4aea", + "0ddca456d7f34cb696e3cf15019864a2", + "a08d208d9ad74d41b35efe309c61aefd", + "f5fb2c4052154cd8a6b02c2118fbfc44", + "c5f031081be8441d8ad4a070af67602d", + "983e9a8be32e4eeda1ce2d42748db55e", + "c6d505d7002741bb97170d3c9462ebd7", + "45d14a78c6774b4da0289dd5ceb3da22", + "731ed11e19724572b0d79e59adfbabf4", + "3907c899eee443d58cf37d3fe99a5c9a", + "4a616480606545498d116ba215b3d6e9", + "a98487c488274be4a04d5ac01e5c0b2c", + "1975fe81c67746b588dceee03b315659", + "c3f41bfe02274a8e91a82343603553ec", + "4033e836df22474a9df4664de00122e1", + "3eded8e48f7f43759cf15b888f96c1a6", + "74f802ff758f41f8b4bf735c7279a07a", + "a350f2f90f3e4628a25bce1f45d4f26f", + "f84480d3a0314efcad486185b7eff4f1", + "219e9467a6934a438d76d29e81a496ab", + "fbeb7c776372466daffa619106e0b2e0", + "1c5d754539684e5da1a7eed0c75ce973", + "d606c9efe6ac45df80366037d4c303f1", + "a8e6b2cccf824109b3054dfd87235027", + "eb7dd0e6e47a466e9151c63b4a7a2de7", + "27a02bc817ad47bea32daafafd9ed865", + "5e624099dc3940508d3cea32efae77b8", + "73d0f3ce04b44ba595fe2d4ea5bc7861", + "fdde0abfdf914492b9d325babcd9e83c", + "1bf586d0f6ee4a9f80215ac9a4b11ecf", + "785adac191c449cb93a69014f42274b1", + "fb805fb7f45541ee9b3e9e478c949268", + "072a7e8d610f4143aa510256112d97cf", + "03ab0eea086049b4a329e3c75929dbe4", + "9e8cc8ba31504719abc726baf9069a0b", + "32a1b0dc8e164f7fb1773eb69d16f006", + "bbabe4090860470d86cb34e5e1c185ae", + "8ee1e1750d6d4f2597d1d2daf17f11c0", + "fa65acd9358f4e639e5ff13c66aff2f1", + "72584626e75740ca87a210d9fb8f80b2", + "3d2c61e3e7ef42d4b926016c4c91aec1", + "f777fef4969e4deeabbd891822f05271", + "3d47386d2bbe449e95eae4be81db2d9f", + "a6a77f3d44d44c2dacab02b7a55c0b4e", + "d70d24b8bd504c7d999e4ed4b17cc8c9", + "1f07c148a7bc4e7c88dc57de50dc36b3", + "0931f9240a7f482893203f3a09b788fb", + "3883d1fa36dc4030a9754366e6d35774", + "a05dbf30fe1d46b397c91025b075fe05", + "9be1e79ac96c448e9e016a93846591c6", + "4d04c734a4a94f5d8ef7f2e6bac78efa", + "7afc1997e98643dba90dd8b412c4d76d", + "ba4afd4437e2473696ce2d1955694a0c", + "eef54f067e254d4ea74dca5d9a9458f6", + "42612b64a3004d3c97872c4c444f9544", + "92580d6824c946ee8874f757a6766f33", + "773b1341f6a84f7d99cd0700e10b7a55", + "e098706085a44898abbd549693d12a64", + "e4d4f7e618b0466b86c5a23641028e33", + "158fa71ac6f940d8a92d1a1bff10acff", + "fac949a2ce8f4a58aa5b61aa5ec8ed11", + "f9ac9b0dc4a2414eb60cfa63a190230f", + "b9cbffb2c34f4771a6490c65886667a1", + "800d7b317d4746fa9c4ea0babb338862", + "c0a534186da9421f8573332b90f808c5", + "8983421696d54cecb10634a4115da469", + "1b6a3b856dee4d8195152cce1819a13e", + "78ad52407559472083428637948f9482", + "aaa548686dfd4cfe956d13e4468770b0", + "c8ce54d20c8e4169b0a8f0975e90f254", + "f85d114f12fe4b2584b79d4fc176152f", + "7732bb8b71ef49cf9b2690a2230392b3", + "81708289b0f44fef918015285b3b2d5c", + "ad5b2d656f0949e7a8df89da4ea604d5", + "f7ccbab194664ebd85593b9ff556b1e8", + "3d9100274d4949309aef125343a2893c", + "c6adc1f8e0b14ae9b86d69f7ba8d6a32", + "724d15b64c814d40b1143a901394cf4c", + "5be2396518564f10bace613add0f1711", + "46e7a742c00f4b6285abc347bc3ba217", + "5a9852d33094499e9e13675f3d1043e4", + "ae64843204ee4028941132ba4204249f", + "f47a4707def747f9942f5cdb128f851e", + "7fd564b3442f4e72b233b8810ac028ee", + "d188cfba30b8444788802b3830321e46", + "127dadb8391b40ad86903ddabefbeb72", + "860ddc5a5a064acfafe6c862a05282c3", + "def8ab76289c45bc86acf3c11552fbf4", + "64a0b2c2e36c4aee94e10ad2a1af0f0f", + "d74385131eb44c6f8750af227d41659b", + "d2203de922524f24a77e0d48de513bc5", + "9624eb32900549d6a0ee735aec6e53b4", + "d7e45db19de041419b28f95df0bbc298", + "753e0a4d13e444598ebcf65dae7e10ff", + "69bee68e5ce5434b894a9d0edcdb8dbe", + "d4aa83e27ec548cab58938fbb5d53d9e", + "c6de4b728fb74cddaa5ca1e156e45c17", + "ca7f9103d7fe4f468ef1acbf805fd187", + "adbaadd6d5a14b1ca3960dc312191d04", + "64b170e4864549c382b6c94c529203d7", + "f5dcc79f9ce8448da69d1fd4dbbfc55c", + "1f9f025d995c4554bcc39b97eed20c7d", + "0857f2ebd4fc46769a90e69225a558d4", + "77201c69b6d3477ba9135c4f14aa2c5f", + "c858d8f3f2fc4cfbab99b2f1a33a6bb6", + "d6465435cb3241f9a550067e34c28918", + "145054ef8065466fb5102fd08bcec581", + "075c29065cca48b7815fb78c7bada13d", + "de341f98e34b441ba1727fe9604470ad", + "eea062a7afaa4ab6bef8833112456eec", + "3573498c7ae74f0f93613d659fba94cb", + "f7a5d89883e547cd86e63ae67248eecb", + "e8a9b72425e148e48364bc0d3d05da13", + "5fd8ccccfbc3445d82c44b7cd138f088", + "4890acfba6874dcf9aa66c304f6562b0", + "96ad3cd8ede34667ba5b4819cc4335f8", + "c8b2d0e37996443f99046e4c178e3e1f", + "e1409dcd76b54c0a8a5dcecb37998316", + "5827545d50c04bfc82edbb45264f0456", + "f2a5059dad8f41d08a813c864ca7c2d7", + "f1798d1366fe4d7392be90ab0af31143", + "0c3b685ad3734eb1bd7ad7613a7889a0", + "ac54d8fde40d48b0913e008ba9cf2233", + "410e7d0c24744f03ba7b1c3231c22db1", + "7f0acec2bcf14dd1967fcc1d10ade876", + "452f70dca5c64c91beac48c54b2bd05b", + "d6d8625844124eee958ecf887395f32b", + "5d1f32cf43334c09955319df2552312c", + "fc168347158e4303a19326a5299d7b6c", + "6609a15e952a4ea2be993cdb9aead425", + "c62cba4534ae49328d4a830c56d9c34c", + "f2de7240cfe64ebebff8f6d78f7f7879", + "06199abc515d4850ade002767c980256", + "d84c128355c547809dd0ee8113b92238", + "2012f3a22b994ef4b98430d5ed8b310e", + "e3a78e329e7d4050a1c9d1c0bd19e47f", + "9a07ab079ba9438a857486e3f79f41e8", + "be91e82fddf84511adc8292cf83650bb", + "831a6db55f1649ce89ac56593c62e15b", + "5d31d395e0e24138900065b642ac8299", + "4949ac257c7848c7a6c9149218ecfaae", + "084f8b127c5943ceb9d0ce3268cacbd7", + "7781a8b39d36479d8891ed8776693fe6", + "7ab75a9c956340bbb917e5851c714536", + "8b5bd3cd5d6046b89884dbd8189c7582", + "49de9c377fab42b4958148e0ef5eab46", + "92b635363f0c4a31ba10415a8619135c", + "3ade5f8d1f68479fa054acc7d627939d", + "d48a9b5b03f847539be03868eedd482a", + "712934873dc242f385c17ff6a272b1a6", + "a82cf2f38ca549ed87982f422b9fb092", + "e311e426540d43f0805638bcad1763f3", + "b9f07394ae9b48c88be3b321cc655d98", + "17de70af186e4a35ac0efc7cc8d600b8", + "d8f3585482944774be1de8a03a7375cd", + "76c5b2ad9c214a2caa694ed5a8d69874", + "9becbb0754ea4d589c1a32a2665a0b3e", + "3fd7744bb84042c2b74c96e28c850f18", + "226e796ec90142d6b37c6aa0cc466490", + "adb0e767a0824a469d4a854d27e9458b", + "ef50c5b8c486485596a80de76d2c89e5", + "48557913856d48bab083a0fa05019f69", + "6c7858341c08466082912d2095417939", + "1ef567278bba4db68ac5488d6b4bc851", + "0c55bd8e29384070a72c33ef744d11be", + "27228be8a39f47d29de7edae371d6ba4", + "073f61374af74d4c81a80b11a698fe0a", + "27ae14bc052a4938bd17ddfd62966151", + "348e4a9916fb41eb94a90ceee14b4284", + "7a5b5f516881457a941937fc667fc61d", + "f673ab6508064e438f96b70502646949", + "686d73fd9dfd479e91c016c87dbd7cdf", + "c5bdec662adc4beab4e925551a34fdf3", + "2f1b1cbd276a44828d2b2b059c9efa15", + "b970e5d1289a492e9ccd207df8444210", + "c69f09bb812e46cdbd5bf6c62499b848", + "edb077bdea8446b89b9af51cbae345e0", + "29c1dee5992e485891703501f457a613", + "e1bdfd950aff4e3784e1562620326a94", + "ed83e749b47c4703be85d56539ee9f2e", + "a2d816261deb4a73a89925466cb72df4", + "cd0ede66813044d2b19a03d63bb237e5", + "929edd4aa17045d79d3a7fbb0183a6b3", + "e5118d7d84da4ac9986c0ae8c92eaf49", + "48c7b3e3648d448e971c590397d26c66", + "87feb5db6f284c60b42270803d34d85b", + "9d6276dd6744474391fc21031bf75404", + "3ab20a02d16a492e82f8b7691cf8dd22", + "7267e0e238744adb820b0f13dc0024e5", + "f1b2299c7e034451b5e34257246e2bb7", + "92e6ad65f7c541b38b949f643d24400e", + "f52ae6a143ea45919320dacbc1b91012", + "41a004d0af534bac87a2c35edaf3ef14", + "bd642abc17cf4ec39d956cf1b5f95dce", + "a5483e74a73143cdb3a453ebd167ce06", + "a543676fb6d8437fb59f58d983f5816b", + "16c8a444411a423fa19e17f5a454f740", + "3a5c848932a443f2b68ab6e7f6647824", + "602e75e0e08b4c8b80bf248581ee3de7", + "d0c64b4957d546cb99be983f656bdcce", + "7a02abc1ec9146b3b3c3dc05f76dae0c", + "d6849de2f338430faf6fa872168af215", + "2b2e7af2be4549d9b379ccaabdf0962c", + "e9bb779c489140518c4a9882636d1c8f", + "5f56f4c02624427f8c9e6d64344bd17c", + "f152bf8008384c70848e751e78ab82ff", + "f00455ef18b44bc9ba1844c546a675d0", + "7beef9a08a7e4114b95c297749b6ac69", + "9b3c7f2bb57a48f1a00c6b603847f4b8", + "6e127bf8350c4ceb90bbc5eefe4d3e4c", + "fa9be8bb53c8416f9efdf1de3e5369f5", + "3805d37885aa4a4bb94d0c94ebfea0c1", + "cf1e6a6d80b44655af1fa51dd30035bf", + "89dbf73cd4bc4a068bf7b0727d8c09a1", + "f1c16f4f5400430097e004f4f59bac09", + "9166b13b6ae341f4bfc093edb71d74f4", + "74fb76422a7244a2bd73757ab533ab94", + "5106114b26e64a98be39ef5b06d16273", + "4d6a489ba16340b99c6f9eec58e71ba4", + "b8e3c0435d6d4f85b2f76004921a6f91", + "02302fca239e4d7a9d26ce5cc46225e5", + "b50191176b6a4509aabca39d93bf7c18", + "b80dc6f0ddeb4fdb99536640faf9d22d", + "e71545e7f1804c5096e9348aaf6e0c26", + "4d3e4dafb3194bf39fd2d580660f7881", + "02aae39fc74e4592b6d16b8685dd2b58", + "74d467eb13b44d3890862046c3539992", + "898953e58e04438c9bb9c3d8651422bc", + "3a0d7939f81b46d5af0ef2c96553f3e2", + "fad833595d814d05a4c0eb3ac96a92bd", + "bfece1644c5644d5bb996fe90ab2db16", + "04bd8f55740342429cbf34ca9a5b9792", + "44b551a7dd8e48b8baa623faf8b16af4", + "3eff5591f80e4b2d8ad15893a7d52ed8", + "10e6b7479e564950aef2f6b6bdf5fca5", + "53f9d214eb3a489c8bf1530ad32cf2c8", + "18483cf78d944cf7a4b88986e71f103b", + "b9de1fa4c9714357859bc4dd10de5274", + "4e8cefda91a14aa5b6d56f4a20f0307b", + "6eae407bea6a4e39aac037486a65412d", + "74352759a8a44ba8bd6d77ce5d3ab47a", + "b3a6fe4781ed488994a89b61f822be5a", + "354d141e8e0d4a95856c7a373d849e0c", + "3959cdc6c8ca475eaa04f9a8d2dbf055", + "e08828678dab474baac6ecd120fa0b3c", + "5f3e2f1cddb24399ad5ddd51fe0add4f", + "daf37688a7734fbdbc975c3e4cccaf88", + "f7b17506c4c54b49abc3539697f76b1a", + "a7e3761565e54fd3a5c8890538c6e3ec", + "63d75ca22a30467cba9ad55126917aa1", + "327aa3ebd5274bb29e9db3731e917aef", + "6d4656b38d6841a69f4864cdfd21864f", + "bf63078640ee4df79b51f21b7ea5e0db", + "e294f6c900a645298a0b8486e1ee166a", + "7858bbc3075844e598e63c5adbf6ca89", + "fd2d4091773f40e7b0af1b11fb82cef1", + "d4ec03b9ff6047f78f588f327de1d4f0", + "e7b123784dc14a26b25a384400339b7f", + "96b035df0c4641e39614db40c535000e", + "b74c7b814fc646de8ec874abfc72d722", + "dc3cfbdb16d74b7cb1c68113d56c9559", + "578f30ee74b14478af9261ccc2d86dda", + "09ebe0457528476fa6ee5e64b002df48", + "ab333557203c425a96476a65488785d7", + "02415d9825194fccad3aaece64344508", + "761fd13227bd411a9a10d9ecae0e6b8d", + "cb68faf557fb4e94a5ec91ab0ead85fa", + "56d77628e4f8461cb47f3bceb610397e", + "4e88a88d9c17457fa75e09a404dc4e71", + "dcf0d48c05504da1a7f1352f22794c4c", + "09bda4f447494c8c87a577e7c69caf09", + "52d54d64e2544ace8a41d33d2ee03fdc", + "2c5b7dfb22e94b3cbdd6abcba9aea222", + "5ab8a2aa7994478c987c3b541016a56a", + "efb732c609244c5894ddf896e8612897", + "602ee7bcc9e34404875f6c5635c45f16", + "f9c0755c8c9448f3a643f0e452c6a996", + "ce26b3228816472fac46366a560b488d", + "b890d3daf5ad4be1bf36bfb63a28d460", + "41ecc0ec986d4d4eb0f37f66122334eb", + "47c7077773a24a6493320b2e263a2e1f", + "72c5ef5eb56047eaa088e2a514885203", + "0deff0a5da2546f9a52cdd42dcc2d4fb", + "4ffe35f61578414baba2f32ff6f57172", + "480cc34e93804086810480263b530804", + "6acbec139ac04331992e2b60e234712f", + "378872d618a148429a072c7015983a83", + "ff065f1169c94a81acfeb5f80d1efdfe", + "f50b83b0709b4b64a77e3465c982605a", + "87cd9f3b740b473facf9299c27a9fe6d", + "c96ec380d87b4eb6b55549cc17a0e395", + "e44c49a781c644b189a084147f913fd8", + "06fff96209494977ab54fb95ce4cdce5", + "e1e1548bfd4c466ea5364b8e473942ca", + "f54600496a0947488ae932cdd3cdd5d7", + "15986a1a263f40dcb7f861892f08fbcc", + "c649a680bfb24066bf53c69282f31a9f", + "2471b5dc0ce44b1e996f38ea2d275235", + "67854fd4a02c4dbbb9b7301f5cd8b1e5", + "1eb75ee3ccab43459accb4a4138915b2", + "987449105d4a48c3b6a301eeb3656f36", + "133a575503bf46988d41e61cc4e0e3fe", + "405968a5b66343b5a11a4fc06f8af6d8", + "1660677c6bd74dfdb628130ade6b4518", + "b78442de2bc542ef9393608c40664aa1", + "dec1bb1c2b85451183f33066311e73a8", + "dcb017d573b845ff90ababb4532fcb99", + "661f07b296ab4f2e8cc5ac822868f5b6", + "e15f62d49d5d4c11b29f945419d8e041", + "5f1781053cfe4eea8905857ee303dbaf", + "194d8940512b40c591ee4dccaeabcb68", + "38681fd4e3f24144b0722c5c85118d97", + "59c92595bf8145d283df34ae23b82d27", + "352b331184104bc0a81e3f40857a5561", + "51539bb92b8d403f953412637f39398b", + "3eb08b8263444b20a417ed556d64baa8", + "b3b07a386f9b4d47ba405f28cf941c65", + "a5dec9418fac4de0b47ad88b416075a5", + "c1f0c96d628e47deafaf75848eb41048", + "11d6b28cc5504c95bce893f1cadc316c", + "02fa220795594ecb85284ec1dfc41a4c", + "85071962da1845fbb3eebebd858335a8", + "5207b3e5668645c99dca8cde6def9b3b", + "e74c849c92054fdbb231bba1643d09da", + "acd8ae7c85044c74abf8514b977deb65", + "6fec10d93d9b49f09ae8641db2996baa", + "6d5c188ddfe143db90961503933f17d9", + "5039788de4ba4e19af3f56e54466e086", + "35626457781349f5a18ef9783f77c89d", + "3800caad4695418f9f60bfca87a85304", + "296e30630e5b4b75b2fc5c530ce9d69e", + "3436d75888484d42b594984b6eafe43f", + "54635b0503eb42b2acc54229b221f42b", + "9f8d92c0d01c4e1984f23ad363e93223", + "4b50efc9dd5943a780b96d5f25b75699", + "2af94225d74c4d9a89ca1d1d5a4fc612", + "cb97c1da9c284f77b1fd0842bd0b26ed", + "0d5ec64f025d4b3a8146dde17231deaf", + "f11f1c41919c44c98ecbebc6727660fc", + "0ce3b89790954c499f9dc67f3e3a621f", + "1328644731034bbebae79395cf0c22d8", + "1615977dcb1540c58db19c27059a60d8", + "5e110448aa9241409988e364bd9ace63", + "15e473ddae6642c69390e8c2002d7dbe", + "fc4ca771717b4027a905a283a7379410", + "6fb8956f04634749a006481fb9a904d1", + "6f44ef05ea5541eeb1ea8587332185c2", + "d149fc4c12084c669d6bd0ac24f213ee", + "2b141496ab3a41618d62b46dfa56f37d", + "9fd1cf20e209493cad5b6ad796b3a813", + "e189c4c23df2495bb4d141ee4fc58c5a", + "893532ea87284c749c4b12b39dcdc218", + "0248853631b74ad8b1d8cef898f08390", + "84b39e6893e84ec39dccce1077d694f7", + "a12133c2ff014c3b80ec0172e387fcea", + "6844d4663d9946dbaa36d7a7b13cd219", + "d4e58143ec94426aa0bbaac2c0d32507", + "8e10ae98f29942aa9464c0cb393d2f6e", + "e46506b6c91146c2a3ab7c98ba8350e5", + "60dfc3dc5d6546d385c545729688f45b", + "b7eba8f065ad458dacb7e658c536a89b", + "3c1a86b7f4e6446aa24ae28e695d44dd", + "1008a65991bc4db0be627573791e7ec4", + "9face2ab80034b6f8a73942e43ed18b5", + "f10c673852c54fac97f4481d124d6d39", + "bd5bbf262b0b48a0a9264f7b5c23be10", + "98be3833c45f4b00ae244e2bad07de8e", + "10040b70746743d1bc4823e7eee31c06", + "88255beed4ca4a0cb7c8c27f25e04f81", + "4ec0d650afed41fdbb662e7b88b09d0e", + "1edc76abe66c46c687d00a9aa7e32c8a", + "a65fe5c27464448cbce7fe61c49159ef", + "0102b2c1449f448687d62ea66ae2a26a", + "bbfe3dd1980b4c7c891a5ec93aa7763a", + "801322110e974df180f157dceccb8ad6", + "ca627c57c58e47ea8e4f120052f007a7", + "b9b3cf37608d43428a1d2473f379a1ad", + "09dbacab2f5349649bdcd8bb916ffd05", + "c6fbb628122d4e5ea9da1fff1c8e1d19", + "de0f1ffa93c64725a99e0f7a8b526501", + "593cbebc494f4937a0c9eef6c29c67a1", + "80b7fbd3a144432cb51510df9a6eee92", + "baa028a39ca64893b7b56e61e033a732", + "e8285d5a7b5e4eb38fa167d0daa47fbb", + "1accd8d8936b4debb977355bcc1a68d5", + "11c479ef149e49e1acf5c7f2d4813cc1", + "d2a33405d2fe447fb1ebb5d82a71acb9", + "badf3b8ada9345bc84d90fbdda8a6e4b", + "53585f2941bd4a92991d30a557bb30ab", + "b4e5fbe471274c848138586c50fdc85b", + "6f91e6c9587046c5b502b01696e7bf63", + "e6c5a685f63b433b8594a9c937fddd89", + "22fdb2cc40fb4882bb1828a954cc93f9", + "d1171aad2be34696a9c2235a775dc0dd", + "868fc40f0de2454e882e1cb895e74088", + "2190b03d39804f34960aaf6fcacced30", + "4f458eea419347639f3e210201cd3a5f", + "5bd1a6a26ed449868db8151d506c533e", + "eb3d33b4c7684d46acf8e98df77709ea", + "8567ec65cc5f44fa83b0d43c30e53d67", + "97629bcffa3442e08e094e93093d3676", + "8ae388979b4c45e0ae625e9120a017d8", + "9166765df5c741a1ad0d680c6964d36e", + "7fd1501cc085444791431362e854011e", + "b4cfcf8211494def845b1d00f2688e08", + "2b7b2029047c49f3bb54df5b2f93b914", + "acfd453ccb254fec87cae82046251009", + "229332a677d74c859b5eeed0d43d851c", + "661cbbdd1fb74beb914917ae3cae9c33", + "09f00d174f194ea188e9de71824aafd4", + "6e1a6841c5e44dd18554a20cac28c927", + "e42b6a497d484cccaca4d19978b8585e", + "f70db0cc60374a54919a4f9c6ad1dfd5", + "1596b924c1fb48a3a066fa85fe8a7d86", + "a8805d4ce9aa4d239e5455243555f09c", + "b050ceefa8fe4e358b1722c1efd4b3d6", + "62a8867ee70144dc9e1f8faf2fdcaba6", + "fd87b71239304574bd9f8796c41de05d", + "50e8f209ee1b478e996f54b707c38715", + "f0526d66eab8431f9b5cac7871a7c21f", + "27108f28ad1d4cb7876c2596ee5eda96", + "217a7bcb8c824aaaadd833e9eca2acc0", + "8e3c1c49387c4b799f422637449a060e", + "57baf38756304e7b979372500dac0e91", + "e8edbeb250a54ecc816a9018886d1c08", + "0c12545341d3412ea44f0a7358cf41ab", + "710ed30db285407c9aa1dd56421e6f87", + "d3e9bcba98f5440985832dd912a7f542", + "b7359423efcb4ebe8b3f5ed62134ecfc", + "7a16ce66ec734399953087438a0963ae", + "27645ea2c1774f12bc0a167b54188621", + "72d905df9a424913b203ebd9d97a912c", + "94d1fe920ecd4069b5962e5ce68c5f49", + "e0602d678f7b4ab093e03e70223eee6b", + "cd85a57df67b4187a2b9d5021d6f10ec", + "5d7d423759f245cfad8484b509b16e98", + "ef1162eaf3dd4765bd3671da8f3802cf", + "c0861ea40ffd42449c2604cd53f7e339", + "7d22e8fbe5a54519b2661fea300797fa", + "a0cfccecc5d846fd84fc8c9a907a2d9f", + "e31e51b3605e4fefbe4f0563edc7814b", + "60563ce8adcf4edab1bde9e3b128e9e1", + "937a135e5cf248d68bfd7e33d23e296a", + "f1fee32f875244679827c8a7962dd920", + "c30b0ff5b80d481083836a27596d18f7", + "83f31663e3ad4681b0df36e6a8595f8b", + "f6171b402d5e4de89bf9b1cb15033765", + "2066b78fc28143a2b46c63a64a649ddb", + "953ec99e510542b489d4cce969a83d43", + "e2fb2295f8fe4fa29183b9b362ed8359", + "ac064049727e49e2823c747e62dcf5a4", + "0df655fd63e44d038d0a71569886f37f", + "b9999f5814a542ffbbfae595305bb8c7", + "db9344bf45ca434fbdf4dcefab54e5c2", + "8cf15f4de2544fbaaeab8e3ec84e800d", + "da096f14c81540eebf1b637888ccf355", + "758b7a2e17e84718bedb009dd1db3d7d", + "37d8fc88f56b48c0b3707b87cb1db5b5", + "bfa98424fd04431692852c33111388fe", + "efa1c4c1f2a947659ded2e61e20eff31", + "4af7de2edd634b6596b167c56eb8b8cc", + "b4a98d86060d4a5799b1cc18586199c5", + "319fea7255454e66970fa64b681c517e", + "2e4c986248ed45c78cc751560bedce55", + "001abb1a3f4c412fbd707239acb68cd6", + "03579b4e630c461cb5136e57f321da6c", + "959a779a050745c5bd27f200928ddbc6", + "75b735754a2a468ebeb057438de08ccf", + "72cc36a8e0fa44d4b57a516c52d41418", + "72ac65ca62714856856370b95e6aa0ed", + "742c4c8c9a66401f9fc295dd72c2c451", + "efda343a05614711bae6202e45fb00f6", + "0b3d68f87fd34334bb411a59374bf0ed", + "989ef5a7827d4ec5b4340a7493df0065", + "21901bdd81f649e89af087ae6f67ca7e", + "f3f7d7e35ef143dcbf2d3f197aced4eb", + "346140d4c8c14bd7a500790122cfe5da", + "2ab889b770564166ae4f92d653cce107", + "a0dcefc83e6445ba9b8991cad2654840", + "220d80c0d9a9402aabfe945982251ad6", + "5ee3c671e6014f04ba3971c243acdfb9", + "f763fe77dbe34221b1247dae1ea84a5a", + "978a0fb1f4444fefbe4961a265adf232", + "ccd5c179aad548a09e6f7eb0d4142936", + "a7ff90a4675542579170e1efb20e32da", + "eafce3cdc1b64f30b0aa3d449de18134", + "dd3044b9e5044002a203aed8416c4e36", + "85e7bc2bb7024868b5c48420e15a5ac5", + "11b35bdc2d5148afb0b7868f18cc503b", + "135446e9cd4a42d2bb08014df3f89027", + "48d41b9edeb44def903b6930333c7699", + "b9619b2832414d54ad59786f008a41ea", + "8e878e5543424b61b81b247228cc92cc", + "47951f34aa21441eac07a67641763e3e", + "12e2c77dda014dd8a7509f72d259d739", + "4514184849a24660a7bb70e1bc0a346c", + "cc6077e3c08f481db58b8102bccd9587", + "0f2ae181a2dd4b00a6ec25073692037f", + "711c084a835d4634bc5fb83802a05935", + "aea0da72a6124406a048de68b3302ca6", + "906e40659dd44f11b45c0bf724d0bc35", + "3c0357d5fd7f4ba09a01ee737a149bf4", + "e7ba4a09f63247ab9fbb49ad09c412f7", + "bba37c5cec5047d598f1ade436e95325", + "c7085eba6e204c9ea3b45e8bec7a82ad", + "1bf6da131b5448f9a65d5a5933b1a432", + "cf7c389703c3460697371a0b0bb48262", + "588c98ddbc2c422796eb3dc5444b62d4", + "188cf7457f4646a790b1d3985450534a", + "d77c3c95ae1f45cbb6e1f4cc00d146ec", + "ac2136e155d9410b93920a9624b7d147", + "7507b8a916dc410eb94113c18b95a448", + "eab7c27212e9461fb3eb2eb16e0e43bb", + "71f123c49a5042348243ff409062ba47", + "aa6990763bd145ec954a0c41e9beb3f0", + "c1969377971847a5aa98aab13613d424", + "efa8f6ec44db491abacb80fce53eaf63", + "34dbf0b544b54934985aa74feee6361f", + "cf9c09fbcb2c43f39bcbdfc10adcb62b", + "7b2b1b1235b44c579d45fbc8d498e678", + "33d70246aca544cf9ddae738254bc1ef", + "d940a9c448ae4c1bb04f84b0f61f41d7", + "c4ee19920e9b45aaa6ebe37839b1ad2a", + "eae692466a7d4cc5b494839e55dfd641", + "789e5acbee0d4a13a5520f9a98e5e5ec", + "52b303cbf7914ccf9cf2d0df27aa26b6", + "4cfe34c552db450993724fe25b22234d", + "c6de25c3f565477fa7e938fbbab3d6e2", + "6abf2d940dc343a6bd76d5e105aaa8af", + "a737f8c7225148fda5ab801e7d99c9d3", + "7abe9a2b33d6443d83b5d54e467aaac5", + "76c7c59569fc4b778550e9fbef245469", + "e73064e272d6432cb6f1101de7f03b79", + "53aea8d34dd64cfcbff9edc2e7853a5b", + "ef6a417648f544f091abdac3c1619681", + "8e51b4247c2046b7be275095017e912a", + "359a17121a744e1cb1e9b5cee7b8161d", + "2a78d0109924415dbac9b5c50a5c3ed9", + "72ce873ac0fd400099f4a510af5a9461", + "cdd1ab7e718040a49644d47f2c49ef43", + "75c058a8028340e1adbdc9ea2dfda9d4", + "117490ef21d249fba0f69bdb223523f9", + "c49c596883a649ea9f86f3ac562270af", + "fe68abfc31a149e1803422f511152b10", + "a9620352dbf94f5fb3b4bb17adb2d8c7", + "caae0e16666b45c3bb47be55ee6f11fc", + "a6fa0df7d7ce4022b7202a9334a59763", + "4971affd44f5424e9338cdfd0dca866a", + "6ef95979598942cd8aa91922f35dc28f", + "bf921be3173a4c5ba5acef7bd41bd884", + "4cd2aeb3ebd747a4aa33c2782510e15d", + "668e21f076f047f7a1f21b18691f16ba", + "83c5216f54a54b0fa0ee29e86a8c66e8", + "ce86584fa4e240239f6325146be7d76f", + "a88c7801b1c14802bb71d3c9b34014b6", + "65e7074ec8fa41f6a865569c288d6be8", + "40279644d57b45449466dfc256309022", + "df3e836c6cb04beb891d86ba2fa01d90", + "4be0a2d29e0d4d2ba0d535856ca680ba", + "92180fdb64ec49c39c420135877ca394", + "641d827001434ad6b187b23bb348aa10", + "75c205adde02439682f91e4a307659c0", + "c4b6cc3c41644398983f6cb714a7fe14", + "5f28dc88604940abbd40ad593151b577", + "74cb411e581f4de38ea45fb2ce4a5911", + "63232a4cf7cb4f5284853c2dffd618f5", + "3159bfb7e2c14e97822451d6d5cce0bf", + "973f6383b4664e17987d191fc66e6e8b", + "5b4ce8e1cddc46f19978cef5cd3cb99c", + "d6a4cbb0ca144f3b992a174133bef6aa", + "5c6ce39026554e48af672dedc4db3b38", + "4a14453a482942c1971bd53ab16d06e4", + "dee4d9cd52ee4459bc91ae2988e95f32", + "f655b8411de94f13acc0439a82b94462", + "f339b76ef27c452cb476035a97627d6b", + "d5dd2f43432445048ec953c841c1159d", + "108c5ad03ebb453a8b1c064a6d9ae271", + "dc6154600fe34d4bb11b238b27946d6f", + "190d8f2ffbdb4dc8a64e13c8088e5571", + "160d40d975f94edfa5eb6e6f6a4201ee", + "3f19b9ba426f4fe495004ac41fe3fb7c", + "a98f4caeb1e6466aa953657bb24a3c64", + "8ce1da97aa404bc099a898f29a3025ae", + "fad3c3c733f04bf599233bae74921ca6", + "e560092fc7cd4461a15ba5aa2d84a1be", + "a6bf64a282b247cb9784f862e5da27e1", + "ff5d26dc548944f99dffb4262684bdbe", + "bb035ac458e8472a9bc4341819d4f441", + "955cf512b86c4a799aa3ef391d670e55", + "8c43549fe3824aadb24a5e6ae5f7fab4", + "f3bfb333728f425aa67b8d20244c46ed", + "7b3cdf65ced047e496b672fb7560964b", + "b618ea230ab04d9c8804eebe766a6426", + "7d1205de2a8048938cd1cc30b79b5f47", + "0af557e5e95641a38a05fbfb1954e552", + "7e4e736ec04349acb12c326acf9fe941", + "ac07d57a79bf40feba6e2bb89ec428b3", + "ed6973497d074fd6969fd06f52e8da04", + "8d94e455f2d740c7b4e29db1fbaf874a", + "9f0f49d21a40495b84a58c4a42c52ee0", + "821c4d9f12294380a9b0757b4adbb379", + "2aed1e413cfc4980986194bbc5f3f4fc", + "a141f5cbbea946c786f95af5d0b6a4f6", + "207cea3239944c91ab111ca8ee244024", + "951b07b30215454294698c5ecc726b60", + "d4b6090d1e8e424792c683ccaf31f2a8", + "1ed263bfe1d14978bb083fd268cf8024", + "326616aa3a3e47ca8be774684ea792b5", + "91c3814711da49ceb39d8011a7d8f3eb", + "1e488ff902e34e62affd7961c88293bb", + "bf39a73e496e49f7b3dade4ad8fe39d7", + "3f5b31ca165944ea9660e98194a9d96c", + "a3ae7f2eb29c404295ffd148ebdd2f63", + "ad180386f4054dc59ed50ccf49b9acb4", + "048e1ea3cd3c4903b73fc65f6d2489cc", + "f5ad7734e08f4f91a3b081d5a406ea32", + "f709c5f235424631a6f90bc7f31b8e6d", + "7c970353b8ea4a51a8d63cccffeae198", + "0b3ed14127224411bb1c7be793ccfba6", + "01c263a259ed4174bb345afe24859584", + "39ed3b28301b44ee830e49ad54d1ad52", + "86443b49bcbc4f5386bbc198d0e1a4fb", + "7b58228d95664e24aa54f9636a3de5a2", + "40e7333f9b114257b232a4f0271771c8", + "9818f07caf2f40d9a7003e03ea1bfdf3", + "531117c976f048a194ce6167188669ce", + "e13413e3872a4d0a90758c5f4b9076b3", + "0615fb09b7cd424d99d89f7c6e35eec3", + "65d325c2fc9443d88c61dc01976b8291", + "e2a3a6925fb64f4a828a4cc60debd991", + "5fb3b759a9c34a5782aabd094b8f5fce", + "0dca677c8a2b4420a5c36e8a61d80d7d", + "bb051a4d57894cdc918ea09b6bdcaadd", + "10b2cca7191841b2b187912e0e34827c", + "baea42ea9fa748a48774cd43133a7986", + "691d82ebc72546399cb01aa2c9fda2f8", + "974b33078c2c44658c445c2de7c8cdd9", + "33e751c2087542618e2e1a9d9ef77af8", + "6e86c103d95d4a07a5fb1819994526b5", + "5c42929b86854b899aa2a7168bede0c0", + "f846fda2f5bc48059e036b2e3d4e5ee2", + "d374a61f65ed47628d80d847bc87abf8", + "ea0e31ec222e49679cfcf40b0ce61b61", + "63b1958e83da4221952a609064be3ad6", + "0c1ec5c3e561484686b251fec88189f8", + "5007d3e9f5e94a90982078f0c4c50e23", + "4ff450c68b7143ea9df2e005147c0618", + "8c70d3ed793f43a495eb32f5294aaaad", + "10fb864c5def44d48758734dd82f1540", + "54926ff096ac4b5686211685e834d908", + "5c719ba3c87a4734af4814e91e658395", + "cfbfcd7142444471888e172b2a4098f8", + "380e5d96119448238719df01dc593de7", + "d4c1ade4f41f4e938925af158198b527", + "7099f4c91ee448ddbd4f3e6f7e249c87", + "4be5bee3a94249529147cc44543d1000", + "3760ddad38554591971ca31426e7a4a1", + "839211426c084e69a659d6b7e9a5ce85", + "73f53a07e5e040bbabfa98cbef2eb36d", + "c7c554b85f5547bea17534fe8ff29a01", + "12aaf1ba3598430b8ae44a84a8deec8d", + "a570507693f64e34ace976831e5af2bd", + "ea1152935b9049e4a0fcc949ebd31fa1", + "46c409b05ab34711b484d5cbad2dcb33", + "817d7cc7e5c447a9ba8ce29a86bbb531", + "2d69761f6cf04139884b5ce96cacca70", + "7b6ef146983f49938bebec7a6c5f073d", + "a249e3c5902347a39c9397b3c499257a", + "2a98c29837214e2282c656e371c2dc8c", + "4c9aa9f0114e41b58bebca61f86c628e", + "97b48a17579740f3bc7bcc826752b061", + "b3e002f575ad4fd59f77537419963a7b", + "3071a0b4ade44e7887f97664152575a9", + "ded805f4810c4df4b0f9536cb70f0a08", + "d8faed8c227c40c98a8c0f95ad5ed245", + "32eaa2dd93f54cefaee5516f19d2f152", + "a9b9fef4a01f4499a19950744ea0b09b", + "86c6273c777e4686a86e1bbd068d9522", + "33dbd28d8f894f1091e7a4112ee20e3b", + "0bf27e0d2abf4a8e84aefe9003ebbc9c", + "bd681cb6124543708eefefa13a6c25b7", + "d4ce9b744ddd40d28e7047f0a604f092", + "0e013d2807034a60bb434ec7706f415a", + "bf3f4a94da6f4cc1961f777349acb1b4", + "24ce2e678e714c35baacc8691a5d79cd", + "16eaf7d9336b4a23a6255414a81adab7", + "eb8efa96966b481d8fd254e2c1379cee", + "420e9076623e4806bbe4d30853bb3bff", + "3b933fea04cb486ab3a0d651ab7fb69d", + "9d3a26928bbe4c66ba834aad3428badf", + "4321efa610f5413385a9458fcaf68eea", + "b8db8dc5caad4fa5842a9ed6dbd2e9d6", + "0a5014dc066548f7b746ccfdbb4f2d9a", + "14daacbaf0f94f458851e15dfd717426", + "101efa7e4e7b4b59b975bfbb589432c3", + "71b53eaee72e4a829a9256a7bcfb7dab", + "43464df55c8345f39dd23bb879ddbb71", + "1a6e9922c1d34fc1855ad3897bb09766", + "a6cac3d2379b4b96940c522eba569aca", + "749d165084e04242b74e80218b552c3d", + "501287dfbce54bae986b31d1f364b281", + "579d800896d6489aa1563097358d15d7", + "d3756cf1a195466f978362146c8b7475", + "7115685c28d141ffa65fecc3ee1838b1", + "f2527a94e1fe46c2afa463bafae5d031", + "9ca7cf7fc4114c4082566b1f8d0160d6", + "2ca52d750d95471a953fb2c9eb577da6", + "b118f41b285849e29c4ee04a993c4c1e", + "4ade799e007e467a99261f6097a0c041", + "b3b2e3d24ca54f888c8c453e3611c255", + "06cb1d4606974462acdb130de5ca68a6", + "d0abcfaadb0a4c73a8db7dae6ac3368a", + "4fe0c97a751640d7a434f2e6b5461e46", + "c0555deea41d42688d43eb65fa0844d6", + "9063f044c2c541bdb06dbd13e925480b", + "efe3e7d2e9474ff9ac33a2af7cbae092", + "15f429114b6541f9bff407f829c59285", + "12a6d48ad07b48a6b86a207662151e06", + "98886a913e084cfdba4ea3dc026022b7", + "b8baf1d93b8648bdaa70b6495c0b8171", + "c981c7bfd98840ecb6cd4bc36ed8272f", + "014938ce127944cb8bc15dab853db72d", + "7a530334c93849deb8249c829e632fd5", + "ba9011655bdf45849ecb2f6deddd0232", + "db0ee78aa3744907bd3baef10be64cb8", + "262aba6fb5784022af77ef705cd650a3", + "27c73eabfff14bdb912f467374119dc8", + "8348e83531b0408a97a28ea7ea4e169c", + "afb758833fba438c9eb702322df64c65", + "b9c2b7c345744c21bd5716b3357afbde", + "03434e4224eb48f1aba7fefb900acbd3", + "b8b2168c2ec24e28b588657580faba2a", + "163602debda546718d15cdb65d0dd7e8", + "ccbf5fd5cc454efd83a955bac7397a39", + "ba06c2a925be47c4a78042ed3fa987ab", + "00d56831f9bc49f9a668f418c1af7558", + "0ba6c4545fe14f0d9b8406ff030fd042", + "e16849830e4c4d1aa89be7a1ed77dc32", + "f22902079b1a42979307e187505f22bc", + "b1dbfb8ff4d84a4cb5094772262e14d7", + "7902d58295c54372915401057b3fc82d", + "64490bebfedb48ad914b5c73cb59d7b0", + "7363fcdd2b644ab48d565bc7f1bf9972", + "72a394cdac1545e29100509a83a3e0c8", + "d300ad7588994642ad7e267f55813202", + "3c9b527bee674bc392f65340dd7f714d", + "b105174a65684b428179d9236171c3a9", + "5a95187f6f6f4528a05bd0805fca155f", + "d796d6d4c4fb4926a3baacbb9f914b3d", + "2b72a24dbf594086b02d168ea9280b89", + "4281fdefe6ee4cf0a81f5d4fe9bb67db", + "e20aac44e5de4cbd8ac8cdfc4a78be3e", + "93e7bcde91ba4169a415649a7a61034b", + "0483043dffe4441583b19642492a6861", + "1b5dcfa558f54a47b469252aae81b324", + "20356470bcd044fdad77665d60dc5fe6", + "dd6089a4fa2c4b2e9a2cd0ec2c7f2ee2", + "ead9c95d73494e5bb3d61fecea92c033", + "155ac9c778d041b1891ffa2c8f349c97", + "b661727aba18409ea821c049e0056c4e", + "d1d7750af5144d1bb7d9fcc66b137c4c", + "9fa2ca3f5fb041ac94cb610d18bd56cc", + "34f8f2779f7c4b2e82954118583a5fb2", + "d5b3a043a2f04aae8f56439cb8aa2f19", + "66c8364244c4455fb98dcdb4642dd75a", + "a0c99f1fe0074899a2c6f3050925baa3", + "08d0a15549dd424b9d18bcf2e4b40b2d", + "ef944e6d647d42889d7500cefb00f6ab", + "1e21399e4c674ff79832f7fce006b285", + "1d99f8f2f14c4fb68947a07e3833528d", + "ec467ff629e343d7a0101cf490726cd9", + "fcd28dd81075447480fa9c67c351bd3c", + "b882a4fd9e554e76924f55eac40d69c8", + "5b4c7522d0de4c47abae5d379a830799", + "b10785bcfc6e46a080614293c3ff6e1c", + "7feb4bfc67fa46c8a60be5b9a79e18cc", + "fa5315f553564b5e937f224c8c2c1423", + "2dadc239935f448688c88ab0d6fffbb7", + "305f482f30114fbc8649b4971e5b19ed", + "e500235d62c9433691e0fa7c51c5a161", + "d79245b37d20485e83abaf3da4de56c8", + "5700b45309a04d1f93de859bf44da6b0", + "0149740224074ee3858b523a5997f357", + "5167955e9d3a4e178a13f4424d3ed8de", + "e0f1701fd1dd431f9280dbf540494ced", + "60630a95931041c5a7cc09c13c884842", + "4781835143314e45a544c1eedc1e6daf", + "3443fae6cfea49cbb20492240ffadcea", + "e02760fabde04796bcc017769908b514", + "13d07b2909c446d490314e1fef65f2f8", + "4125db0e838245a58f8a92bca125b856", + "ea05e523bb2946f992ed02b2a1bdb51c", + "a548ec65b43844fb90f570ba132a0391", + "847d606e48844e6c981ebc45d2ac19e7", + "9b052ecea6004687a62bd538cfbcd4ec", + "f2834e5557a54c9a981c45d07eae0d4d", + "c8b51d54a9274aada44c39cb148aaa46", + "d1e9207b62f24ea6a5309f611f0a776a", + "eab8a05a7edd4784825cb4c1eaa16aca", + "abf2cc54e37e486696c25bd0c86402ba", + "5dacd02511514d96a9f91f0d199ed87c", + "347632d6839c40a79ba17218099adf99", + "f9112ea4c15043ebbb24fa121ffef920", + "b939c4e88e124c51aa5bf88c16caeceb", + "43f266d6cd6e4c6888b9943557528c0f", + "34b12514108a4ffd897c9324a4a35858", + "db166f33bb0e49bc9cc7adc3bb58f723", + "bb569daed0334a23afec5f52b7bac3f0", + "63cb795c6682462f9305811ac03ef60d", + "c821f8eec303421fbb9288ba3d299362", + "0ac105eb165c40aba9dab37c0615bb17", + "24e471ac730f40fcb0501930a83784be", + "e3986e780d9e48daaa375b872674cf75", + "e79bd24a88244433ab4d2997bdb69207", + "41b9b4576fd043b9bcda02fc9e9fd138", + "6713cc0cdad34f89a0256c5d2f68b7c1", + "7a601ef008d9418cb17526f7ce3b4482", + "d624bcbacd354c8399ae81dd1fd4a334", + "ca5c4333d8fd4cc8abf059890a53ff48", + "fd31c0eeda8f42adbd8122921cb75f48", + "2541db11c1c84adf9b3c371cd34dc287", + "bf200222d79d4411aade19ddf312f122", + "afb3bd3660e44bb381502aeae8519314", + "d0664fab6c6b44ea860e340ed0319d20", + "f25f82658d524bd2bd9a82c26bccf8e3", + "ed51fdea230b40599f8e99130ba1d38e", + "f3c251cbf4354ec4822db9e7db7554c4", + "b2c42f43b6154f5684fd73e68713ee3b", + "2c9f492f9d994283b5372f3a36e4c7de", + "4252a510f3c8476ab98fe9f99100696e", + "e2cf11638f7e4dc09d734c11f4d08f90", + "47a690dcecf847fca99c4f89111db85b", + "b2e5732dd9584e57ab9857d3a8b0350c", + "b082caaccec848fb90d5b9bb076015a4", + "f52cc95a58c946fe92b556d7a2d9af64", + "db78e34fa9ba49f1b7a4abaa3eb7431d", + "ff5d94e3b3634ec5b7e8689106968bec", + "6603d45a07dd49b697c327bdd2aff6c3", + "3947ab2baeb844d083ac1a29a77ea04d", + "6c10c97a77fb4e908dca4659486f0f0f", + "3feb90103dd6408796a9044a33c5e9fc", + "b542adf020a74c41a8cba1522cd2e568", + "3fc1e2c625ed4faa9fcb2d128b0394fe", + "e72c25c2b0da4254b096b39958a1ddf1", + "3e8253b1368f48b8b47f1779f9dc8e33", + "997371967efc4f6786a018c13b9d8916", + "aa9a7f23471a4bb6b461d5240c2bf1a7", + "0287751e95534929870bea1bed4a502d", + "6359190639544e98ab7646e47b17356e", + "29508dfcc96747dcb5d48b66cbe4904e", + "7a0af6d6285240648bc16fe39e359192", + "293dc02b3b084cd9b72e15001680be94", + "b420bfbdb5ca4fdfaaa2432cd4e76f97", + "50492962b9f641669238d37e071e0bb9", + "1e1bec71da534e7bb72fdbfc08b354d1", + "e037fa6d608241d2bc50c324d81b88d6", + "661b90a9b722433cb1b4e31c9f4a561d", + "90f49303cb3d4e2da9b80179f3f88c15", + "7f21e9b933e542d3b06f87a03380917a", + "3fb1a4b9d14c44abaac69fec119bf251", + "f3f4dc4232164bef83a39353d9ac60cd", + "a46a1e6b71704999ae5db810c99965e2", + "1de6d3ee67fb4f9fba7a4f6e42d1af2f", + "6d2f4d3e392d4319926bfb178d9de302", + "7a842fd1aee2498686717be52561430a", + "a1ebd09f35fb4e1eae497c73bf1114d2", + "bb915268fb554d7584854bbc6a670c3b", + "3830341e56834cbaafc0ae8d62baca01", + "d1367b53a8f541b39f6fbd8ce7bd4b48", + "dff3911fe8334334a108caf97349a1c2", + "a04d98062ac8436b8a7963afdedc0e99", + "ee04ec59e2534305a36ffa7b993ccc44", + "b86531d3096d4d32af2fe6467ff7e810", + "a3245442028f41c98c68e8a2edf18875", + "f1f579a60cad4559a10d71400c66d390", + "9e78f58c53f14f5881bac253a5ff0cef", + "85206be7185046ba9ca333083082c149", + "44f3cc38a71c41bcbf7bac32e48dc2e7", + "b52a83d7ef684da6be0d4a0aca818553", + "df4b6526ac8b4ed0905e29a65341ccd3", + "fe6568e83fed4a409333b2cd068f7206", + "13dff94561b64b12b727da12d641ccea", + "092e7fd1b6a248be9b4a0a457bff3dda", + "28a203c1ca3c41ca8a45ae79b0d8509e", + "32b04428fd064efb8a52dafa3b520c8b", + "1368b562a86d4ef4b0c2180be02ae675", + "286d133335914a4885a01f1c5ebc5f4a", + "7f9447b995ea484683debc7d2a8755bf", + "2dc53cb8f91042baad73034f4666e6a7", + "a3b2b9efdc194d2e84970e099008bc5f", + "a69cc063189f4d0ab1b79d4f9f4f780e", + "176d61750a5948779b24d7e93f022b8a", + "b1f9ad74ae914116b1d48bc3aae83b8c", + "a3e602c6990f4a62965ac8169a591ae8", + "7636272873a34036ab52618df4dabcdb", + "ba4d2e49f78b46a2b63f043c01ca0254", + "53af518a5cb04a8d86b5746268e15604", + "24bb6727742146f48f145bd6f0b8a322", + "6d52c7d7b1504c2fadd5383dd8ee0fff", + "91979ad79916460d92c7697464f2b5f4", + "f623ab40922944f881caf38d057e5d9d", + "b96f896453b240ae804d0399f1faf027", + "e7ca492f653840359283adb3e4cec1d5", + "db58509a85104a03bfb98cc35b1d929a", + "7d81cf9c77314401a0f328c77c4c8d33", + "4d9e698174704823adde230e2a85c419", + "3676762cdf1042f4926f53345e133234", + "e2ba4b02af654ff4bd75076b5ca4f9c9", + "5356ca9165744843b91e035b32cbcea4", + "5fe39851c88f4db5b343fd38ce8ef4ce", + "118e358d76a642329b51c5cdd2ffc1c6", + "9f9055b7bd2349b899f7dd87d5a1922d", + "1bf8c96dc8414e8d8e1587a175e937f4", + "cc397bf2484b488f85dcf844bf088559", + "6fc4fb026f0b4cea9b504da6215f27a7", + "90f162fa37344b43b84eb956f2040649", + "8d572c96435d4b26b2ca83aec07196a9", + "aaa2eea8e09b433bb4df528361c18e30", + "e3aeb51e3ea94bee9a40245e59504f3d", + "41470b26f15b4eac8dabe8a06f49b1e9", + "ce6ad5b75449480eac06fba064c0d939", + "4314b15066c340a6a0b39979884ef077", + "f76d0698a39548088d5192174ed3ac4e", + "90da01e2b378418b9b2ab8db8fd65739", + "806e841289804bffba1c89757582f0ca", + "a10569c0809246aabfb0f8b16a663a03", + "5ee4647f7994413d80652e10090d380d", + "ac1f12da1e654a3a8e31290d8959ae53", + "6f50614649a24b908634710dc65992a7", + "9d49bea56f3049dbb952b2eede39e91d", + "2eb45b9fe9604570bdaa5df747e4cb4c", + "25ca9426f4af4eb3b2f8ad379bb8724a", + "2ba45650e964418e852d9556b49b7608", + "629abc78a787477d972a4a6218ddbaad", + "3d06df9143fa4f98acade3c0a90df0b3", + "d796749f27984919a1dcf410500fa619", + "276a925ac9664513b72ac8e96776a704", + "64a0364ffb424438b26ac3c846ed2186", + "fc416eb996ee4290a70697d89b0365ed", + "36b97734e6e6437092707e82125ac902", + "7d07e67d17274011a16418d1bd05e6eb", + "798e37fdd08f47af85e77433e42f14e1", + "78d62891770841b9a616ec04d98dc009", + "b0ee64ec4a504764ab07eb93a1076feb", + "7167046ebd2549bba4349f00933529eb", + "1ec9ef29c1604487a2f498df7e744c88", + "84e58483108046c188529f5c2e5142a6", + "9178b512c16c4a7bb9768c82f54713e8", + "29e8455df549435294dc241a35fba3b2", + "63c0c5e987974c7ea48a4c86e0aa80fb", + "d7feee089e644cbda0c1cc3b0bc885ff", + "868c64cd122f4f5e850995e4c9f183c2", + "211ab520b68640a883ed9e2829f9b49f", + "cea016cbfb8f490593d737ede5fec8b1", + "b07edfb826db4a37b0df3bfa3443484a", + "fe97d02daaac44bea0caffc4f1cb93a4", + "7b8f5b7f14a44a75bc184e28b12b32bc", + "a613955681df4ad88034f6f2dca40b64", + "98fe9589ef1f422ead0e9ee3e3b52292", + "c25d29e7f10f4b01b476425613c87cb3", + "db57b8d1dc0140b59e055afe93fca4c7", + "a20f5595e1084c6a93d4c4b7d33b4ce2", + "8c5254a34ee04a3dbb5acc5daafea457", + "04d9983ba04242fe99182d4506ea0714", + "0db687e8e18b49f5a6458ad5a75f057b", + "7e3b464111194543925b64e85f6cc1b9", + "71b0b67f02ec4260aaf722c795490e5f", + "55a5a5afa9ce4a13acb14f52638f8fab", + "2a71ac0e4c16421799f8ecdd03923899", + "e144f6659eab44f887fc562b694714ae", + "0d5590d1d2184aa98797c3d6382afd7e", + "101cf07c250b4d95827797c8dbc8fecb", + "c760415dc6074e29b11305d432775aa3", + "c23b8c487c3c455cb8ff970a3ec3a5c2", + "064a4adc578f46c7939e743dd1ef4a56", + "26c5134adb214778acdd2724f75617e1", + "7fba4cc831724df5b936d02dd140c218", + "a9964b95aee34a8d94677fe648757ee8", + "0b0014c30c6440ebb8a9e389bcb298fd", + "411d1075691141fbb52f644602c6d5d3", + "7ceeeb4632f7465fbc18229c524abbc1", + "b01c06636ed24d55b39e8254ee3c4600", + "b225003a8e1c4acd8a51db302d59d978", + "794e6f1160b148ea83a546a0c715a233", + "de6857a0957b4047bff8c031877a255e", + "977be77c92f44e70b43459a8b2c32617", + "fcb098ed76754cb885c75c157e6bae58", + "50a9daec83c84e4cade6e4172284c971", + "df8be9d26f5f47d7bdf270db5e0a9a60", + "6d4c4411e9524e30a0a597706ffe3454", + "56afb1e21d6a47dcae8fef74c77a5cc8", + "023e632efc7449338e1d5c56e220cab1", + "2cf404729e4e4cf9ab776b851fdfde43", + "b8cdfa7faf164bd8b0c9e77c37101f03", + "52874229e5d94473a36c20983849fb2a", + "8a9e25c8c2a848ce81475240491d451f", + "f01cac074f544bb5b5cfd300f01f756a", + "04343a479ca8438c9951cc507aeec96d", + "adab872213d34d2c86add370c35fb8ba", + "6593d3a26d3d4530971c42eb86cb3feb", + "db49d1d472704b19836ab1a8aeb09d58", + "2e32184ea51d4b50968beaf48aef0d2a", + "8aad7cd878074e20b88ca3c86feb50aa", + "f0c51fd1a2fc472a8fd8afb0cbdbbced", + "88fbad9fc6c74a8db52f557c8d5eaebe", + "ff7de676e28c4e1c8dbde913a4b078cd", + "977130f6ab684c1ebb317435b273242c", + "82885197cfe14ac8a09532980f39cba7", + "4a713326b70a4a32aa7ec6eca918603a", + "ade41221909748209406d91b20c0b06d", + "498e3b44938e4ab692fdc6c3b5112b1e", + "f060e662b2fc463d8099777de48e603e", + "767f795eb4a649c3a16209a2614635cb", + "3ec4946f4ef3431cac30b4076830715d", + "87f2d57d6d7e4f22b2ac2da367dd6007", + "9746de160d884d4c870d761793fa4343", + "57b03dcc593448aca1d64c8d166333ce", + "f0e6873ba1bb47bbafbd5c54db38705c", + "ed5233f7d2d84a35a433361a5a058d36", + "ab8732d284e841b1a86a67d5a0049cc9", + "04a1b30ad282483b915207d7fff94359", + "3ae2f15facaa43809909fc883a9b7608", + "18775829f73a4246b12d4becd85eb7f9", + "4b27628be0804c0285d0b13dda025a0d", + "11778f72ec5048179efa3bdf9fad1d3d", + "43fdb74a2d834ae28422cacdc8e12060", + "cd21ca0bf715437bab64edc71ebd19a3", + "152cc2d77e4e4607b115ccf1454aab99", + "a83a693ec68f47b6aeaeef9c94e6ad9e", + "35cc811e49fa4bc6b5bf66348441a84b", + "74a1384111dd40f18fde5850e10fd56e", + "51729a7b387b4d81b518d05192da9f21", + "0b0228b5960f413da9234c42cd6e5a81", + "d3c586389db44a31a3736d9009c08152", + "462ff4e83a154f8490cdbe5b33007cc8", + "c34f1b3974d54933ae4461055b4ed594", + "ef9a705d9fb644d5aecee2563e7f91b5", + "5e68fc39623b4773a53a6d084782a6df", + "23532dc5c4db4d0cbed5466a451244bf", + "eaf2652babd44115843ad48369184819", + "1cb3d3a148394287bb88df9cef0fc2ee", + "89ae431e8de64deeb6393b57aee01db3", + "40027c98213243cda7387f7ce7184363", + "7f5c3c22dd2e47ec87ff4a0dabdd00ab", + "4e256797414942d0bead04fd5d7b3675", + "349a2f43580d4e09a379a3c422e0fb7b", + "19391ffab5ff40e0938d7cca939254b7", + "aa347cc960424360a263851aa5d5668b", + "51d4d60d40c6452c9e54e4aed5313c2f", + "fe6fc570090c4c53b4c6e1ab867fb1c5", + "5cab785830bb47ef80814ad2d5668833", + "d87bdc1154504fa18e127a1565cbb0fe", + "ad42a40191e24e1eadbf72b7916a1b83", + "19119b8686a9495f95f85ec370df31de", + "366c0727f28a47f9b994bf82f05556d0", + "6f654f9e40c346e6aafdc04ccc68dd48", + "c03d8b43ea2a455eb9f101eef1f0d95f", + "8d8ffad8f85746f39b68f58629a8ce68", + "c4acddbd83784f3497e99d309ac5904b", + "ffadf953f4e044f5a94432170359900b", + "8b23b9e1a40841009de42f61bb997f28", + "e34e512dbc304ab9b7addcec376f6226", + "b319095ba4334b95b82979039e7c1bfc", + "44871e7d550c41dc850af3f41faf03a9", + "97b7227921014b3098f051ae139cdc97", + "dc98f3242881403392950e5246d85ed1", + "488945dda5b3440fa46a912fb283ca51", + "45911c6ebebe483d8fe2d10635b238ca", + "e83f922d36304ba5af544dd190ff23f7", + "a96f2ce3d1ec429181031e97086d5b1f", + "1052e50c722547f992f5154267255ab9", + "9cca546beea94d35a925015173d00ec7", + "ab57d70b908a48759bf9dba95cbccb0e", + "64212f86eeb544c3be69a7b5cdd2a308", + "000a3d9fa4ff4c888e71e698694eb0b0", + "0365227fa8014beeab7b4597704c4485", + "fbdf6cd044234c30805764a749fc5506", + "e4287bf4f1a742829ff0ed1ad9683af9", + "7d40f94be37d458e98365e89dcdcae11", + "6cb6690202604d328d8a0f34c7d2c585", + "82bf19f3981647c48f59d780779aed13", + "72a92b038692477b8c049be0a3d4ef50", + "1e42af02a1f843e8826571824c43d450", + "85fa82e9de6441f6af00b2ebcbbe2ff4", + "5b7aefe2295f4ea5953bccb970ae76c0", + "f3ee2cae618d4ed0b9cb9ab6915357ce", + "be365d4a32184764abc4634c1280e6da", + "3f1d7079aaf746d5ae64999372394786", + "d147f184ab8a43f29542bf3ec4f10dba", + "15e14de8f3a043ddab9f772132af6bba", + "4a7b2ead63c34ba1a0799907181bfc7e", + "e5674d675edb42b6986d58fdda153c17", + "84286947d3ea4ed195a72c25125f60fa", + "1ded9f27d0ae46e9a7f4c871eef7ed8e", + "8f9de2ea0e2349ddbc86ca1fde1a029b", + "72d084f7de4c4e599940410963702493", + "d2379e9d0c8445c1a1c421fcf7063c58", + "e213da3b642640b2bc34a9ff8ae318e2", + "031574a75f51411b9d73c386893ca7a6", + "10906dbf08ca40e49e696d3e667a6dbf", + "0710b146f9e44170905a45a85621c02a", + "3e0903b811fb42e89fdec0fe24212047", + "5247b702b0eb464fafa4fe80ea2a6f07", + "55fcca49917a441282a22cd97299afa5", + "9aab2aab8c754cd988cd05b48ce4b6f8", + "5c4f8bd8e8c642498f78ecd1afb7d119", + "57d4f274c1d5409ea0eb340455163a13", + "8702f71889c84e8a9df86f508073fac4", + "0b3322f349274bffb294e2004ded6ff9", + "88afb31d1e5e4b31af2777e31ace429c", + "b200aaa1e12241f09c75c1e8bc28b88d", + "bf79fc067e974d67bd6759ee3b01daf6", + "52d850660e1d4358ad96b922ea75f62c", + "a7aed23f355a465b8dfce6a9920e1416", + "d7673a8f70a940cc8647affdfdc53049", + "9787e82ab3f441ac874490ecf369980b", + "0636415305924d2f8f31de1b038c95a1", + "8d1f5c1664b7474f94ed1ae7f03b9ce9", + "b3a2ef084619460aa4c00989e6d2910f", + "70176804007845359a9d17298c4cbb9b", + "5922ad8ba9fb4309b2dbf0f74ace98eb", + "e384089439894f9094d898a146990631", + "da9268ed32d8410085dab42c0b5cc9cb", + "52819e735d72479aa55bd596fe3f3386", + "d84ed4ce792a4fe0b8247c358a112c40", + "5f7108c70d6c482c99ddcba2533c1e87", + "002b5dcd1a7844b19c7ffa63a9b23c68", + "1fb443606f5844cf91959e4bc55c0b6b", + "c28e45e78c9e4c1fb423605cffc6c088", + "5957b94cfae743919311ffd6981174ce", + "f5797825fcc242c5ab723f17346d0df1", + "3b46b998c40143a5b4f530ec562df605", + "f290ed3f24814b15a82a02e67168d6b5", + "6138ac03aaee4755a23e9271d23a776a", + "69f3c5411dec4c9d9ca093ac47161b5a", + "b73497d937774c96a92f05947c738b9b", + "09b8055a63cf45b794cbf53c1b35c2fe", + "6be6a4e70e004221b999cdd61fd682ca", + "d2d5000b1e7a4d9a8a4a637267418061", + "f75b69b4b8964b15b772bc2fd63a8b74", + "a08dca7eaae04b63b9dba0830d546739", + "4ffda95129ca436fbe8e17025a880fa6", + "a62eca1552674a01acd2d9bd26982798", + "f577556c8cd04319b120dd945e33aa3e", + "aed497978aa441499e49fc72cdefed2b", + "e0081c37bdfe48b08eeed7abb426677a", + "8105a1116c1e4aea9a042f404f73ae3c", + "e597b83290c741a699d1b2a47fe73713", + "4f93ee32b9ce4442b74a487229e9b695", + "7f731275e50143b49dca4a1f224f98ec", + "a96f627b4f064580a8bfb6130118a686", + "217b60bb9d3047bebf36dffc344bf3f6", + "2ec41800c54f440cb8c9393618b2a9ae", + "998cccab49ed496586994d9f4774daa0", + "4d1735ef095044209e9ac12e60aec30a", + "3e2b31c4d352447585f4d7d453414b55", + "4b47320168ff4057b5f441a2e37821a1", + "e06d427214d548da8926d2c79bcefe44", + "143257511a88429dbb0367c111aad8a6", + "3e5b8566dbe24f4ba65473179650abd1", + "9ba01096e47b4be7b0b244b8e5dc8651", + "24b2bc017a0a40f08566326b90d44c60", + "807d145efdd3425c9da74a2ec8b52299", + "e72f3887c94a414286bf485f7139488e", + "5c8e8dc6b0ff45078000243688c9e94e", + "a36877923efe40cfb6d487616bb13f00", + "8cb5fe0e27ad48a2a388892e3d441e15", + "3f752c3834a74b4294c6686493c6fdb4", + "2ae1b5cee0264898b42c6bd168b8f53f", + "29ca3db97c2946a798caf97264e384b5", + "969238f50b5d40178951835d31f8e82d", + "014e9cc64c414162893ab309f6adc944", + "727ca78032304c028941a5dec1d76a9c", + "aad9ec8b83f244499dad6f663f1f952a", + "bb1c23461d8a40b3b30c6dd867a5f4e8", + "eb2b9ed28abb4d05aa8e3fe60ca43f36", + "451f4ebe5318469db152d089909c905e", + "098d594141834645a57baba60b4554cf", + "41f84ad265ff4aba8ef80f5fd079b0a8", + "f65a9fac1fd845c496b3324bed3b61d9", + "c39953222a6d42ee8f402b0057e084ff", + "8066ac9f03ab45a69ee4476a5efb92bf", + "a424d9d80c264bbf98b403440f6c6031", + "82bcf0bf0bd24cacb167a8daedf7a853", + "5c8b8d30a37543feae428846484d316b", + "83f6af2628494e0384a995fcc7815240", + "fb4c5d7b30cf444493062f4a6d24a587", + "0f95dd46f6774990b9e28ba9769f543e", + "2391f4ecfdd144bb974f14bd886b600e", + "af7091b52dc9450b8c8dcf1521b681f1", + "bcc01e3d7acc47808dccf5abddfbd863", + "f56a055d52a84a89abb40580f1af3cc1", + "e12e11f6fdd94539ba6215d0f3a684c3", + "b09adf160fc74260bca65cd4c5c66650", + "6e954fbac1fe4575ad142a2547aee6e6", + "267c9e22bc4549ce9fc131305c08739c", + "f2a8f127fed2427da29edf0832a70bc4", + "2e3ed055f29f433c9cee1466c77867be", + "21b4d22315b04552b8d628d37ce7aade", + "a205bd471e74481090e3c903070834af", + "7432d4cfd76d4dd89a9d97b7bb101f85", + "fd022c749fb0482e86a19cf06607fe2b", + "d4a5a9e62345405594cd16e733c126a9", + "4fe3cc6a501241ca8ec938f4515baa1b", + "b6cf6cc2083443e6a92f5fa5718a2b8d", + "9f08de24973b4929a7e9231fa4c41f36", + "d5583c4a750b446bae251b3a4f3fa88c", + "87d5bce4301c46d4b02ac318970b975f", + "86ccd4717a3e423a98aebcca7fac3b7a", + "b26434ee89514efea3ace4f65b255074", + "ee5604b40e6740c29b5b67a384994d67", + "320a811311874608bfc29070ab712635", + "9aa16665343e45c3a4724551cfeb51ab", + "cce39de2c1354b2d87a6f70f358a8f3c", + "7b2d142b86314edfa1c94a5556643842", + "730a57edd2784c2faa9515a90491aaa7", + "beb034c72a3f4a72aad127e1c7aef257", + "b72285dd5809472c9965551dea219938", + "c0c22523d7734b45a9a4b745654eb148", + "43a187b7a4a042b58bd2085fa58395cc", + "a79088a654fb4033b4c1bd0f69a2af87", + "7658fd3aa3914c6daf209be68a7f8adf", + "92ea79872df847a08cddf3646e2ffad3", + "fe160e29577b4d6eb76bf30e316e48f3", + "1fbe388016e14a3399da4aeb21d5ceb5", + "8aa5cf5a69264e07b2ad4a8f754a824d", + "85f5c6a7905245f291458cc6f2518ee1", + "6dcf6587c3234d47993dd79df008f4ac", + "4e102eb3e53b4f71901831cf9822db8d", + "638e3c18ad2f4b0a919ce2d94ce0d795", + "3ffa602fc7b741a0b83b141cbad4d1e5", + "92e28edf31074225ad28b652b426b4f4", + "1adbcfa802cd460cad46d44b3303184f", + "ce8ac0f5d678497eb34b2d3bdc5fc0b5", + "b9e55f04b6dc442fb3bebbab253460e7", + "bd20b3aaaaac4b19b65ca41b7b3ed0ed", + "607bbb98277d4259a20715a4750e52f0", + "690a03b9f7234bd4845eb4b8159eba8a", + "a1c7dbd554f04417ac93f59f9e6d296b", + "cf40b7fe364847cea3776267ecec1d51", + "a7703b666af6428eafd254cda0f0ebc6", + "f2ddc3ff108f4fbfb71bea165d9a964d", + "502b7f937d774b1c8b37610054e5b63f", + "1cd383e97d304d509109fe737a994e2b", + "56b12166465d4f18973849e7536cd532", + "539abad9c0384000a225a5145f9d5b52", + "cf0942bdd0ef4d54b0053a4293a45261", + "c29082f4a2bc4ee7ba49311b7f673457", + "2f7830ccab2f43cb83cbc1a2fa5bf87d", + "0cdceff1f9744759ab3b407b96f498d6", + "5bdd0cb4f17c497d9d1f9901c873613b", + "85cc12859e9b4033b7eda7ddd56e50dc", + "658ecf9f837246509b0b1c4aa81e9e5b", + "cc917494333f4d19aad507388badabe9", + "c1f6de6cdff84adea0b483af8a4d4362", + "bf0b01248aaa4c1890d2af96eed808c0", + "c38f02c4944c4a5ba11ba51f66be9572", + "170730f3a34d4650b89ca6090c8b9c42", + "60f5c32d2e6649f48c9cf3298b6db928", + "9939de46afe2412cb291eb313f26951d", + "a4b878779855447baea0d6791da6f9f4", + "18190985986841909d7743c9759427a9", + "6cc0c8450dea4c01890d89fb2a38f6fb", + "128facc0c53f4e5cb658741afd106b8b", + "32df7385c866435497f5a01954422429", + "015777939fc3429ba4b5343be9d51ffa", + "ed7ba64b6e3f4a1b8b253a103fd38162", + "8e2ae53cc8154c70b55c815038fd324c", + "4d9b843352994798aac92455fab062ce", + "74eb8a7fc6e4482f90be204b7fc176c2", + "aa103794b57044d5a969e6ce750cc89e", + "72249dddcb2c43e0a4d9e479e6ac0f13", + "3bb75665234c4e71ac52cd6411ffb935", + "366ecddcd9c14a69a95ceaa42c45817a", + "4b88c020ea55433dbfe5799cd78002e7", + "d30c207f4c0246588f766b0dd49b459c", + "c1465014181242acb40a5e1ee548676c", + "797bbd4e49554f2cac0e1810db8d6f27", + "cedae25d954141089bc46d297970e46f", + "eaf2cea840fa4457af2c1222c98c1f68", + "490835f8c39e44049ae077671474211e", + "f0d47fcb721e4040972fd7b494097d82", + "f5a20366fbfc4ee686025a5dd374d323", + "69f86e972f2040d4ab1d825c3c33f8ed", + "840cdfe9e26749ee89cb43ef36fa179f", + "91535afacf004ff8b9bb5db7c1641441", + "54a13e432b9a488ab35d1c6644d9bc0c", + "d4c035d5857f4b49baf2ee27f7051a16", + "067e3717fff84958a650ec7e504ca28a", + "ea0ede5af4084ea2bdfd029789281f7b", + "955355e7f7a0409ca34125ea986bf17e", + "f7ea7c088f3e48fdb61120473200a436", + "2dbb992f323f49628889b25f1cd62e06", + "7cf01ab661ea4e649d2145f103b898bc", + "64d88784946d4172b9e8acd3b4154f8b", + "4c4c85c4443442f8ba5494f1e033dcd2", + "3d81c31c40174f00af1cf992696a9f71", + "53d66bc83c1648cfbd9113492ea2f334", + "0c035053c6e4406c9ecd4860884a8d1f", + "baf6fb497f17440887f1c5be359413a9", + "10bfa9d3655d484fadaf15f9e184b3d5", + "ebc42901b4d44ef284da6df23c401312", + "b62e7675bbee49fd89327297b054fe6e", + "e78940dc9bc14145bb22ec2586d3431c", + "668af548c783458887f2a3c31402ac14", + "6b277767bdeb4088a26c5d897e2e2d6a", + "abfa138c9cc6425dabcbf6325d8d783b", + "980edd900421455584dc762f7b81f348", + "2b768e22e649444992ab3a5673dca200", + "7e7309da088c45ba9e1f72b75ceaf043", + "faa7b1c1ec064f27babc9aa599972420", + "67e3e8a11c4c4179bc5427758bba1304", + "19b9f06c6f714bc08e4d0450f78ce6f3", + "10d31cb05a1844bb89e83ec0827196d9", + "aa24d330e65d436cb4b75be13553f27a", + "0b0acee0ae274b08a5f6a3a2769c407f", + "6qeM3YAFAEA0btMLveFHAGH7ivQ", + "0995ef51a5354cd1ac59f96d97ec605c", + "1e88c90205f244f2af50e42079062006", + "0e09d9cd2efb473394e8977c57fba0f3", + "16ec0aa9e5a548fa849a622c11f35755", + "e17b0b52a340435c9f405f8ecbf91cb7", + "bc5d8b37c8e040ee80201d0d22312df4", + "995566da60d74a7eba6da902f62d2f0e", + "de5c761eedd14615bf45febfe1d858dc", + "7bc8af17601d40968c536fd8fe9c23ba", + "b81e2038bdc24e8a81a5a0e6e5012eb9", + "b57c5788aadb426784b30fc9b6d4cd0f", + "19abb349b55e4bad875e3ec2dc0e8a15", + "64e227842c254a2a81f6f9930b7d791f", + "68e0db8178ed46319fcd407f99d833a3", + "5fea3ad87a324c68905714115684fb35", + "277fc0f27a4a45f79b7a2cfc5e9f335c", + "87ca7f8bd6c9417db712069f568ece3d", + "1015bf1ff57445b69af7a2639788073b", + "1e8d2897bdbc4f8fb2b8ed9ab9fac453", + "12bbcaa59be246f0bf9d94a3f9dc869a", + "454783f25d8c46ac87969c8f161b1a16", + "67fe8916551c41b5859956139eb0b82b", + "11599ed7aec045528386be7bd83b69fc", + "acf5d77a09844803ad9620ad31826698", + "003199cc6ff2410cb2d8e6f8a9cbb163", + "09e3d40c21ff4747af88ad6a3df75626", + "e2d1acbdc2054a21a2360ffe03052fae", + "06255f5be4984f149afea0fce335bc99", + "ed2a53dd243f492b8ce3ad1f4f54457b", + "fca9ab0c60c341a4a8d6ddf61459677d", + "f010badd4b564f79ac5f293922baf5c6", + "64e5f63904ff47babe6f9f69a99d016c", + "ad17ef7161874f4890b4a89abb0850c2", + "d3386f9a3a27417d975e6002bb2eef11", + "173855bb0e584398a098ad7412feff98", + "0242fe38361c4bdabadcfddb42eb3325", + "ebc6e7d920474ba788fd25b6de4fa3f5", + "a88bc26076804daebe41bd0cdd931c42", + "d7a795fcb09940c0b1d56edf8e758454", + "2a8c2ca28f044793941c0fd5ce4b2f25", + "e87875f314e047fa9f1235eed1f62c9e", + "069fe37a0f144d8387db9b4594c501af", + "e188d4a006364d3a8b0566e4cfe2ee16", + "f90b711de42044159cd2c59902711b54", + "6c3b6d248fb64ba985024d6a6ec97078", + "51432a5a95414e6eb93e3630be5bd9f0", + "643b54f0839e486a9ce3c41eabdb9f3a", + "97d7a6fa313d42209b60f8d1368a9e8f", + "4a09a5fdbc1240f5a56abf874a4415a5", + "b8e612ccdb634e6388eeaf87ffbd46b3", + "1559927b8bda495e91013a9aecff2107", + "4ab861f340374326a9ebf9fe8b2cd2a2", + "231ae0675eb042b3a088bd613d4985aa", + "98413ebb22084d01bdc286a56da5900f", + "10c396b115a246428cd640155f9be7ab", + "8ea201cda6ec470f977a249dfd310d47", + "d244c12f8ee7479ebb3b027c277f402e", + "9f0ab60f02e34ff8986a2b199bfbce84", + "a8ddafed256e4123802aa0e42b2eacb6", + "c2f81e3dad9b454ca88e4e0a6dcbec31", + "25f100bf51094136b3b4d3787b2f61a5", + "88428be8b6fc49d1a63e5c09123e6f2d", + "069c2f46ec7749418e26b8c24c6fe27e", + "5d546ab0efde48b2a292845b2b32dcbe", + "e0a06c44e2f741d498bba083e07e9038", + "943a03495cca424694aea9767fcf3f83", + "d7cfc7da545949a58be64a838c711523", + "d6e1569f1e56484691a4935509c92f4c", + "894ba1c7e1bd4e76a1e808a3fa943346", + "de72bee94df9425eb4b99c375747629e", + "bbb3549bd8f04d51b04590e6af7b603e", + "011c33c121284bc88bb765a85511dae1", + "5e28365bb34e446db55bc3f4bf716b1c", + "5824ad9e57d04822aa176f0f08cf7b4f", + "93f0653d100e4df08c85e7fb5c811b7f", + "8316d507d6334b14b7232e9b806a950e", + "3f02844b6a3c45b684df86af7efb1043", + "d7e996223e1a4300a768808e07199b50", + "ca7e400c9cb34e02a6dfd74aecf26eff", + "92ec62842f434dd5a88f1683e099c277", + "f13da34ab30a4c9db3526c96b2fe2d97", + "8239215dfd6543c8adb25356f89f04c1", + "b2119b2c326d4ef9ba42c83a9c711166", + "3b2c8db611ca40cdb2951b153ef0cede", + "6c481ee9b724465d82aeb64e3e417c54", + "3711e52c0f3d41b18123326eee6e2661", + "1aaa8433fd684dfbb5473db00a0a946b", + "327a076dc0764243b0d7156be505ac58", + "09404754ddcf42b68e74ac2110036f77", + "2e97657e4fd849529e6184558f9670cd", + "bf2d05741b244d34a86d0fa6ddff3cef", + "a57576f25ecb4b359411e88e9ee5c4d5", + "eb20d35e84ac4bbeb1d61da5a10f6cf9", + "aafbc24567124f359ec93febf524e54f", + "8b17d4cd29874d33bdab59014a2dbc0d", + "f58620b073f848b0be2099b0a382df4b", + "d25cfbeafb984b9eafa2057dc6fc0c14", + "40b8a17099c64ddba5578a7335e5bfc0", + "9589ccefe735448f924ddbfef36e1d65", + "9cfbb2274ad74b808fe2e361cfd48e0e", + "4c47315a4ec34d21ab2302376be5eafd", + "c2dd1c2309ab4097a3c5d4d91b09b736", + "c5f9c1a3aeb7419daa68b9003d38bfa4", + "4d6837029c354d74b51f32a9bdc8270a", + "942c79805fe74491b82aac14f80959f6", + "7101eaf08447436bb5d3b26fe15ce744", + "e2b670f69b5a4dd58d021f0122b15b92", + "afdb609bc1ce4843b7160724bf9355bb", + "3badf1a197b242c2894c0b68416f7261", + "85e1abf52baa462a8934b6760a772763", + "aabe26b113f440848b8a31d2543e154e", + "72a26c63915c46978719702f59ce833a", + "0dd1fd9ce87f4b50b3a57f2f0dfd93b2", + "9a366bf23f8c4c92a5ce689a89f725b3", + "4b883942ae254cdbb32bfe9ff5420455", + "88b2e129b55043c6aeb2a8c419ba62b4", + "44aedfc2a7d8451ea53e3a64693f55db", + "da2a763a51d340da8a3339414e44b8c3", + "a808ab0e40004dcf866e9eb6d799ac04", + "0420bf1e2ee446cd8e3537484713e78d", + "d72654cf2adc4cc29529657ea402dbd6", + "4e6d591f6e50493aa5e31355084fc4e8", + "7ce9eb67a5f445c5b57bf9b4437b342e", + "6b80a99fa52b46eabbe27fb9cb558b31", + "9b361dcecae9477cadb486b0886bd7ff", + "6458ac945c14458a8e5f4a470495f042", + "f120452f84bf4e979139b106bf9f096c", + "e6c69ef3199d4dcdbcb5a113143944d5", + "efc4895a394047d98b2e2168a4f4dff5", + "e2e062c3b8904abca095ed3112d3b89d", + "e8f77d844fbf48d6b22a03d6c92f4735", + "f0614003d5c24e0982f2ad9cad1c22be", + "aa6923a3a31340c4a3ea8f65ee45fd68", + "da2fa47541154730ac8a5ec3c5cf176b", + "f855379bbcfe4f6d91427cfa342ba491", + "8965b91e0e1d422e9d96e4816ecce387", + "c431b92427a94a7d86c1e2790d94a798", + "2ca444fe810f4c70a3f3853d86b6faf0", + "547d76739b3a423b89f51e810fa69a4c", + "1bd54fd258ab4278979732c7ba5365e9", + "a9dfd6317d17438eba13f29d463b25b4", + "b9ce6f19425645b3be2cc218d56e0982", + "596c23e73f404426bc0e9bebf103eb34", + "333cf04856ec4f7aa93dc7e5ba9c49f3", + "8c8bcdb5c0fc47df824510ff085a0387", + "0723d6edc23d496e871e417ecc0e0aef", + "958773dd534349d08040acede85d78e3", + "68aa850b99f6485aba8d4d810eced097", + "0a280e2b64a84fd387667cca221ff255", + "008fda58985040279284e7498dd30c49", + "85193ec73d5e4c86ba682f1f325b9d08", + "1b9cea951c404fa0b022181c2f6a28d1", + "5600d87276b5446da7fd949a908b3893", + "e1bddbcc07f74d81b5555cde25e2017e", + "9a763745ce7d483eb9544edbec695527", + "4b5ae9b70251441a896a90fd14a79f66", + "de9d6291c2a145c79485f2ac0cdaf43d", + "1a16bcf11fae4352a615c8da88d2e9ac", + "14df8bcc73e04921993371a0849ad36e", + "1bad34d8c2d94a47b5e36abc6a1498a5", + "eea21cf4cf2f4eb99649f816da594f90", + "92b697b6581c49a8b7cf096c188bd7c3", + "b56fabd00a4e4b29b414ec708cee91d0", + "deeb1abf8a6b4c44adac7c7589da0df8", + "c9e2d40e2a3a49c8bc25d25ffc4b7b3a", + "7a51077a2ff349c0b4bb828bad115a61", + "56253bd1720a4363ae546de07954d0ce", + "5d04379f28bc418cb0699055183ebf92", + "11c2197867a942fe986d490807bba443", + "cb23c076db2a4799850f32eda807fb2c", + "d27743ef88c44e76a294be09f7d162ef", + "1fdb702ad88e41e2b90a5af4037bbfd3", + "3823ae0a401c43d5a02f4387a789db05", + "ef9ab39abd2946a29f94a1b670a9063b", + "c8c6b9fd04254a6489b3401696f60fc8", + "3eab64fff65c407aa0cf00ced4e493b0", + "b7719f1da53b4f51999b1ef9e4e1fe58", + "8b1db1daad3f4c1fafd41f9a36511855", + "bb9d7eff4493438d8c45ea7f784505e5", + "a9fd23771a0d47b6806571601801deb7", + "28c320e0f5ed4738a37bfeff473769cf", + "2e762d68e7ae4ac1a49553c03c940c61", + "16096057d0d844248280432f6aa1f0c7", + "5e4e00c0f88a450e86a5fe5ca36b8798", + "bb3f527e46ae4180ba07f5ebca951a2b", + "e8f919fbff4f4b8ebb4384cfbc66d4f9", + "47f1b331f0464a408afe100506115a55", + "d63f68acb88144178caa2289d30d743e", + "a12a11e501ac4248837cbd56318e5245", + "3df3b3990cf94416967ae876b6573f52", + "cfdc8b3756fa4bb4b7c26d8ac92fd1bc", + "848c73f2373f445f8bee528d50c8f637", + "632b06cd8d1e4ca0b5056d6d26762751", + "bd1b2591641f46b7a8c30c881bb463c2", + "777238e7561a4ac1b2d1ccefd1de5865", + "5a4583e655e34713975430b48aee3e38", + "4606e57de5b34290a3fed370efd7d7b7", + "991270e938174770bdb0bde23d9b4e82", + "9044e068d8c94db292e8266797d10835", + "9fed86dfca4d45709a985063c341fc45", + "f7fd3b9fcc9142909af85c941df8688b", + "76aa30acf9704f2ea56813c9ce2a9e8b", + "c7731a7d6398481796338fcf79bb9748", + "9029486d05b243ce8e13688af7f2a6c5", + "efc0ede1dfd84ed5b83deb39ec491f4d", + "169bf1da19c342069c42c31728122224", + "03860ba96d824aeb87acc457ca6e65f9", + "a79089ec4f9b46f1ab25d04041da42e7", + "8d50c19e138b403e8b2ede9b47d8be3c", + "4120bebe817c432e9a00affca0be7c14", + "3d57c116d09c4f52895f274f5de1419e", + "4fe6d72f20aa4c62bf5dc38f5a66f3a8", + "8965462b14ea420690822ff6e3d1abd0", + "64e96cb6e1a142628b31a2db98f0ff45", + "882feec1c8034af1b4a8db68e955f5a6", + "d31427d37be84bfcb6f0172e62c2ef83", + "5d1138d9ccfc43a3bf994438d92ad6c5", + "a235742577f749c583e397cde5098508", + "1c9a88e194264519b399106555f1c2fa", + "fece9847110e4f53823a8d5b51eacea7", + "dfad9314124e4eaf98dc4af830f3007d", + "5183846d201340aca58831bd2d3a0819", + "1fc1cabfad294fcd91689426f8b44554", + "1faf4c744f2f426f88de309fa4857f5f", + "f8531000e3db47c88cb726c57b9d8fb8", + "f0ef4adc17ee4929b40e894c608061ea", + "da1a9915bd0446299998a896311e4d64", + "b4f65f62d5c543e39fc89aa3a08dd1e9", + "726c8244c9924648b254138ac2fca19c", + "0929ffb7078347db81a4ec57cf17cb96", + "2664e926ecd840b6a1aefd6520ceaad6", + "acf09ce566af45f6ba357bba97273f16", + "d8159daa2d844379a941b99455d244db", + "69212c51833149d3bff82f8e72fe5d64", + "b8cebe4d2d154bffa37ecd7a11b0d12c", + "8b04c72222984df08f545e5533e119c7", + "84d7ca1b1245465487c78e9956a074f3", + "49c4e3ea069946cf9142fbe2b05b54a7", + "d751058aa4d046628f9f3cdca12558ee", + "0c82082dedd74fcdaff08002147cab29", + "4ef048afe072421fb32afedd270b8701", + "5af966079ae64db9b89dd826ab6b54aa", + "f348e7704ddc4216b39f3fc399bec0e6", + "195c945078684c24bb3de3f069d84118", + "eb79a52b8ab74a76899ebbf70b43fc5d", + "5968ffdd7701420ba9aae012b86ea823", + "dd0ec139989c430fb6572fa024ae1c20", + "2daeb6849ffa46d49ae24b97a0378880", + "a986ab66368f48539067bab12d8d2bc1", + "bb65024149824bc3b269b625f55b3a3f", + "604fd1202d9c4ef296e56dd7be91f9ca", + "6d87c7d4372a440898132af4142ade4a", + "2ff281fff571410598ba24d58425a83f", + "226e8b0d7c054b168a7c979a64e0bf00", + "ef4893a3b6554100b653ef2434a909e1", + "71837ebb23714b978e16d40d49a31b06", + "fbdd94329a5e41c1b069672ccc62b850", + "1a12c7951b90419c8e7b4f881231cd9f", + "8c8eb306af3741f09b5bd41c03518fbc", + "6d1b7b48dbc645bcb78eb205b73eceb8", + "439f0725eae54fc7b8085293179d6df7", + "e1b55dfdacf546beab1f3a74d9a12318", + "112b50bb7b1a4e0d8f190e8b5336efbf", + "9fe6f8a40cc64ef8a84fb08e4a859ab0", + "43280ec89088499a94259c5cb7d28b20", + "f98e59e1d512450ca89b3a58d70d3db1", + "b37f73c66c1a47fda9eb9822703fbdb2", + "a8dd30124e9d4c32a77fc5c4b8c689bd", + "a2f6af60112f4df18b7de0cf59477fdb", + "4934cddd48a04a3b9c9b1e9667e7470e", + "891fabe555f54e4caf5707e35890974f", + "642948714277463c9293b4e40566e395", + "df73503a9df447209178b0829ba702cb", + "1aba5376ea5c43ec84d01b9c0f713ee3", + "9dc20030bab04ec3bb80118644a0ca2e", + "52e494da4c5e42988b739224a4605e10", + "b2bbbf908e024323b2eb5e3c0336e9e9", + "c24a41bb09eb4cae8723d232043e5456", + "9f42c6d4503841a7a4729c2e9f64047c", + "6644791cdb544ff99cb1ec931718ab18", + "9e4cea767a0849d5acdf5a055c855c53", + "9d823ee6e1f94c72b34e2725c4e40241", + "0648107ec2b34ea9ad6f9f104a0da534", + "bcf815ce791249b1a70f1acdf074fb4c", + "a16da813df1e4eb2bd04ef8c179ebdaf", + "b46db7642f934f589d674f3bc09fd345", + "56573d84343b490785942284d102807b", + "bb3b8670bdf74b6e9feee00448139407", + "1ac3f2e941fc43478298292404623c8d", + "efc25f203f39472693a5869cac8a6dcf", + "8764db73f98f4a699e9f63d7a081fddf", + "e7f6fa23b4a24fe1b752fefc00aacb78", + "7cbd44a3141f4a1f889249c3fb1efa34", + "d73cb91bef2b4e8898be4dad20f26cb6", + "5a80787376204bfb8006173bcd0cc448", + "be0878c9cee0453da80e97ee49cf895d", + "38a83ebc9e6c456d85aa8fbeb9ad9b98", + "53b0ca6d0862417a86056a89187ce967", + "cd8df095f5db4fa38fe7d8799822cfc3", + "44989de2c9d042569124d5a45bf11f28", + "6a3d720664184cac83231c1da58c55b0", + "052449f0d798499b94ee30c112eda403", + "5adb3486557b46eaab0e1ab643709a9c", + "c3e73a5008ec4f159e4ff047b5d9904b", + "40b38fc043d14a29846993497766cb62", + "fe7d861ae9eb499d890f5b0b8049f43f", + "4c50439bcbc247629fe2194862d7acc9", + "4e656e7e7f5d4bbe9549e6f7b43868ca", + "6083670b853a48308dc1f62bc8d194fa", + "5206aa93bce448a8b936ce763cfc245d", + "953d6435ca844e07a1018d1e7302c920", + "9e37ff6c22094e91a81e9e3be1e32b80", + "b48082dde0c249bcbce009a5c619e7f5", + "04b7f47e732348aeb82a23cfc8986d1e", + "13a3d70752fd4622aac14806f7c7f947", + "0b98a124cd5c4f96ae702a8b5a0da70a", + "cbc7c5da7fa94e1ba2bb2db376389c3f", + "3d0a2acf839d46dbac4feb98df9250d7", + "f714e30be6e04f228b22281452948b93", + "64722dc854254548af4a6e12b18a08bd", + "23c778c563274a4a8f8b8cee580b212e", + "1f031d1ea5a049728295a7e4671d52c4", + "d5f59d515e73454380c9280f3ca9df01", + "60e44e54860745278875d5c331e2d735", + "a07bf565db7e439db781704bde8413bf", + "dbbdf0001be24af3872e18ff368825da", + "a9070aaf49a24af6ad4f5e0dae4780c4", + "f82f9985fe814667a44e0ba2952e73cd", + "96d752d6a5d745778ca0376552768ff4", + "7dd8c64d390a460c975b446e72c03301", + "3b6cc4c654a14593b8ce907361352d62", + "ac0c544b67fe43b8b4e96688077bf272", + "c14e98b47fdc420395e56a26986a7f10", + "727fcd6989e7473a9df1f23af9d21cbd", + "2b28e57e7f594b3d87d7d52db04ce43b", + "0f236b1b83524689b1901ccadfbbe468", + "d81bcea0168440f486e67b0ba9caf95a", + "1e9686f0fe714449a96f53f5b634bab0", + "e8221482c1a74687813f866c52f01abf", + "23bbeacca1854fb4b432ca92c36202ab", + "51eb9a215e684b8f829af4211f94a475", + "017c2dbbc5034eba8dbf46e44dbddb62", + "cb25b9b10ec54c10b9306e3bd3204c12", + "99246dbf8e0e48c388768a8edced8c3d", + "429536ff8dd84e538168c17ce6e82e28", + "5028c83d2c674ae8a47dd8ef2d10e8ec", + "a5507ec81a2e43de9f1341322ac49d94", + "59242aa4f2df44ae90748a5a732f29ad", + "736fd22de2d540ea98af1364991dc8b5", + "6687061f614f4340bd44b8c4006f7e2e", + "a5fb52f93ed0454cba45a0e8fd7beb8b", + "5952fd586b714b9e98250174dfc419c3", + "1f1798bb86fc4cb383969bb1f0060341", + "bb32988db7dd49bc9dfd7fb9af6215af", + "c901dfa120a0487a9f5c9a2d241f70ab", + "cdedc602cb47435399408dfa6a8cc9a1", + "a92b32df558544f6aa97cc62157cec76", + "cf7ee779ca86424aaea69fde95d9e61c", + "2d97b116cc244ce1932796315a1b842e", + "85ac889151324c24a9b696a7b905e185", + "1a2f71dc3d02489885a2680a07c1f1c4", + "6738d574614545bfb25cef43185b847c", + "a2832b845e4e4edd9d439342cf4fd590", + "f38c47a0b3cd4360b3fc5a53ee057e7c", + "6cdb44a5385047f48b2dcdf1c9edb771", + "0465a8009d50432caba8fa21c86c0bcd", + "faa8f9b40e87470493ede1c05f53096c", + "977334a14bd546779d835fe095b5b0e6", + "c2237b0373d146f3a06240e085d02dd2", + "d63fdbec56bd49208c17a9c9d1501629", + "75f663417e874f24b864348a5c9c3e68", + "6c1c05a2ee084bd98ade3800284b6e81", + "a2362ae283be4ecc86e3a18485c11aeb", + "be12aacca67e492d8f1f56aa45b15666", + "c39ed86a7b5a46cface590fb49062802", + "896eb0323e54480db6d702e48faa0689", + "aaa30c146cbe4d1f87046e3a6d2cc4fe", + "46765a29eff642af80898f93a62ca963", + "9c127b07958343bba6d9f0fa41578272", + "f5008636251d44f99e1187f057df7d91", + "58d421222f434d4a9a45da3bd4fcdc16", + "52735ffb60a44244a3ba87bdc1a0885b", + "b2b5272e7ed5470ca8652b6923d9b396", + "ce4734afcda3422caa9652ef7226326a", + "3e40ef02e3eb4e4faf41671a37190a63", + "6f8a603d1f7f44caaa3e50b995dc8472", + "c2f17eeb07074c04970a3e0e29bf0f49", + "99fc178ecc0943ae81454a3735e2eb5f", + "0097d3f7d6844162b38c587d61933c4f", + "ee5a96f1d8564b199b702dc355513a01", + "1756a32a03204b468202ca30aa02e4d3", + "fbbe8661f4fa4439b13a9b8985449d6d", + "47715b087a24415b8d88fb7680031cf7", + "1934240d051b435083855adc4eabaa73", + "237d3ea13cba4b059e513557aae3cf74", + "72e4849860d64619b71c5c17c7a22177", + "ec9dfa7a08254efa894c0ee564bf36e5", + "1d6c8a031c41489ebecda344fb2d4807", + "8fe2c19e20084f48a1fc52545b8b6a87", + "8e970452271940eab5fdf25fb635a39c", + "492124e24f8945e6890e4d0d69956dd7", + "6e4d796d03db4d38b58ef1ac2cae3747", + "c58ab5f264ee4c9d915ed946cb9b9075", + "f658c352668f43529af6bb97973b3d5e", + "d889023d07e749fc9844bafc5c7cb2ea", + "db912d84afe94d8ab0e18457deac494f", + "f191fe77dbd647be9741658645698fc7", + "be1d414591b94c4f9bad500a637d8c56", + "d3f1e80597034b0c8f91091f90ca183c", + "2de1dd3830864ade87756fbda17e6b22", + "3e08df9bc33f462bafe1fb42110e8e88", + "effe471c624f49cda0f1593966d1f073", + "0384b41f61194b319e22bbbc644d0c05", + "43331c8ba29a42889776a6931e31f15e", + "bb186e949a904cd0aeab7035a42cfb90", + "fdd252205ac34d94a023c459f1e1f4eb", + "f43df97f35604021abf9fc6e5c14629a", + "8ddb80e8bcc04eec8b49e35f59150f1c", + "dbe590e6304648d0821aaf430fe3a8e3", + "483f70dcf23f48e190203a6b84112915", + "55190fb38fca43a0926fd1b8cc9d8023", + "d68d50e2a5e54ec8ac8634ada064417d", + "c478f11cbd5647fa81efa515deb90e15", + "e51a29d61d6b4ed09537de40eb695617", + "526d00c728a24311bfbec50bf54142ca", + "7fa9d5093e424caea027e4c68d6a60c3", + "be5feef0db774c0d8db615190bfd649b", + "6473bcf2234b4fbc87c0a9b0986c29cf", + "6a93cec139b0447199d9e93ef2a84a1b", + "fa251e3a972e43e982957e6af1e12262", + "6ab96c76558f43a3b0e1442bc0065f68", + "dfa2855262b2424b8da810366bae9ec0", + "1284c1b143b84b2c8c256fa6d46b5d01", + "b04d0d9481e94c689da389402471a864", + "da15f5f1b7d449c69e3a9e6d69bfa934", + "ae62f92b5d2c4508aad184504cbd9a57", + "e0bfc49fde124fb89cd5cacb0be1a1d6", + "6a18c6f37a5e4c6bbcd3c707dfadef82", + "6f2b640a23d74fb2b3a4a1d2f533f326", + "f0ad6a3c1cf04f4c940c3296f1a2c322", + "e0ee9a93c85b4ebbb6fdb771a378c149", + "98b47905ddba4a1d80200d4be873fde7", + "0a00744980b94b97b573e05d646d31b8", + "2972712fbbc344219b1e46fcbbf30e78", + "149ab79d9b81432ab641029d524ef0ee", + "dbad657639e0440d9c2a439d28c88927", + "ffd2e8d398624a54ac859641cf47ee27", + "dc3c4b3cc513486b87a9d5f7d344d132", + "4174b22dd5234634ae9356da36b6b42b", + "343ca9e44e904869b23d40b30f1f4aae", + "a062944af8aa47998ce35ac43ea237b6", + "a4863d7e05ce4117bfda48ddf6af8af4", + "25617b4723b94665a35c44ed43dd6549", + "43c2184755544c86bb21e87c47fc0bbf", + "27c3f2de739c468786de91adb6bb2534", + "9b797f1173f54ab88a890582e9e22f14", + "c9c0ae8941494bf790710efca0fce073", + "554e2793885e46138014386b87be80bf", + "982cb3a76be1453fbe929d6a00922403", + "169d7e568e594e0780f5742c48a9e3b0", + "9c9f21a0a5404b4083be16376415e7a7", + "0996aa8335d5499b992d6b0a05d3ffe8", + "b523464178e04ff4bfeb5e76f0e4d005", + "02010e17a28845cc921858cc24ece163", + "63ca2c7241894778bd263f95ac0f494f", + "7b2a1cb30af34cf6ba689196afe9e2a1", + "8b8163d78bee402a90e6f91523afef7a", + "bc6e7c6a01bc492aa153a60480f434a9", + "7fdd51a5ca9b4754b1a77845d132e895", + "3a41cd0ae91446f9a61928b1aa827857", + "18b27b46871347988877a63ece9b84b8", + "269e62bfe6124fa1911a541a845f86c1", + "5b595bb41411426792a6491202aa38b6", + "6e542dc7844d435ab66647218a5602db", + "350fc9b99a284553a643826133c524a5", + "8ea2133c5abf44beb1cd529bbbcbb518", + "43431f19525f4d6984522b285977c48f", + "e3173857f9384aa4928daeabff75da44", + "d012d05e8bca49928a2944e043d93fb7", + "c653788d0664468291de17753577e00b", + "57ab34c523874fe2bdb62475c1c7c380", + "53606b16dd164dccb5dce00021cead4b", + "c55ad9d105a84cc49e5a496190cef311", + "41b7c648fc0046af987f394ca92120fb", + "24fd44383e8842df998d9f3d25cb0a91", + "c7c8730b5e4141df932958cde2e69261", + "8698e958077d46d583e77119d2f2aaf0", + "dee1ea44d01147a786280b7fa2a4305e", + "907ec92dd9a949e79f4633c3cabb2fa8", + "bf346177ad9b43fe8226c473ca13eec1", + "8b9f52f183e34a36b7105d02215d0b6b", + "e45b4406e2094c9c850fe40407a4ca02", + "89d38b9c53f8496a922ce1199ca57afc", + "3f8ac23a89984e7493d4284b6f99a835", + "50a023f83e8c434b8b908c4d41c0118b", + "ec184a627685495e9d0f3a370dfc1422", + "359d614e46fb44809bf6730a6ff92f2f", + "470d45710d644a8b899692ee9c8c6381", + "a801191432784b9cb5dc25bb01ee8341", + "b4ce5dbdc0da4c72a6d00c06ec8db662", + "ab77ec316ee34bbead3f615f004771dc", + "7402a65ccb3b408abe50795dddea113f", + "97c9143a092b4ef5af551305bf2e1c51", + "de8a8629512a4942a95761a19b1c3964", + "cdb42183b46d48f3a3424272c798428b", + "e27337ce96d74b12b2ae1a5b1a127b9c", + "49606934ad2c4e2ca6175bfbd96e44cd", + "1052394d9e9340289e5f7727f85b5e47", + "d44f838c48b748f3b51eab9c830193bb", + "5fae226e54d24820b5c62ac25ad062c3", + "4da59580fe6c48ea8e05ea4571e58ec8", + "3b8924e5483e497bba08484d2036db0f", + "d46ec5e299be44f1a34a00c42a3fbb35", + "1cca9e9e93e44aa898e665b60ea848c1", + "4b6ea1dff1474d4a9729b916433ad334", + "eafb40f6c55c4187988e8f6de625968d", + "d29b016cd35a4825881e4f885c855f14", + "9760df31938f4180940ad814b950d5d8", + "a800eb049d5f4ccaa85649d23ccd117f", + "fe6ee5b4aa584759bc157e2c8abb1aa2", + "3b4e38a9a6a0498aaf35a899f2a6f4c6", + "69d028818bbe4aa886e3abd45cd3623a", + "be318ada84e544aabd7293bc4f26f978", + "ef0cbb3c3d1b4f43849e8ac74aeefa64", + "fd7bc706c4074fa4ae6bb1ce1ffe02df", + "1001e27e43c04dda8d0f304dd4582202", + "e21090870313478f993bf5fec4b84f46", + "23e6d310c49146b58bc63caf1304a04f", + "c0877c267983442a82f45a53ebfea171", + "7aa816aa52f54e7b9249190b46ee4472", + "fbaec7e2d4ec4791ae95505f68e63070", + "b4bd7877b383494197e04edbe969c311", + "e48f29f0714a4c70ac75a34cedf6b3bc", + "d605550137dc47a18cc726ff4f2af2db", + "f45e518d6c9844a2b38b143a84833058", + "497579124e8e4d18917d836b278e5132", + "b592763cf4694010a9a7dbbcd3d1475f", + "decafd5380fb4324851decaf1b159a23", + "e66137c16fc34121b75ddb5607c5ac85", + "adb62bd32cdb437482a665d4e1934f60", + "22603320c8274778ae15fbf5c3738f02", + "4971b37e6c1343f58946e57f44cfc25e", + "98ddcab19b4c4a31910217efd5c70592", + "45f280deb29c41c8b96847a9fd6cfbe9", + "9b2e29167af34e05bd65d1efde8e44fc", + "76d32d2bcdb049079d2eba71b2b79648", + "1e8d0dea560548fd8d2803170fc69a1a", + "84716d7709e94fcab56cacc0029b7061", + "d0ac86d260254fcd9c8804918f88b8de", + "ec7db4ed503a42edb31aa8184db6094c", + "0838b73f246f4768aa0671e7b2ba7c30", + "b1cc93ae04d74cddbea477a27e190fb1", + "fb872d13a26d4449a6c7ee4327fe253e", + "2579a8652039496b8d99e894c7fc857c", + "adf60435b2fc4bcda6593c438adbec58", + "25c33058fb964704843324e4bb48f323", + "d09a9eaf6bf644f3a2f4a149c56e354e", + "bc993e6a4f9c47e5a197446a4698b486", + "2784873d3cc4475e90474973e4db5312", + "2a3709978a6b4c209569f97c997d4cb0", + "5f56f80717c34647ace6fe7675227d7c", + "d76aaded12a942de9ec839682d85fddf", + "83bb7dff14e84ecbbc99ebb80fe2977c", + "8ac14b7fad31482e85426c2b6d29cfa9", + "fcb96f36054a44ef870aac0bda271965", + "43d70e06250c456c892171f2b62920b6", + "985023747293419fb7cad8a93dd25b7a", + "f6aa562268e749bfa9f4f5da8d8196d1", + "729715b5365d468391b2fa5b98b63c5b", + "02d9cd99adae48ba9119adbf01003b97", + "162a5d683aba42a6ac7ada76cb50527d", + "faca809a30d54baaba4bcdf234e7d122", + "15c0bd51c1b24b209b8de93e74363854", + "c9bf211e3bc94ce188484d2bd7c4fed8", + "8ed49a95f393473490baba27f559368f", + "28fb9c2f1dae4da0ac59b5af02d420cf", + "48bbfc1990c7448187d188afbe9bda42", + "b7ba2e1507354f939b4dcd45aa6b79e6", + "b06cbd9f8fbe40ffa93ee49ed9f052c3", + "24aefa4b0940441bb2a88ebb0bbeac2f", + "eab46a489c5745a689bb02995f98bf77", + "370605dc38244553bc339afb5cab4e2c", + "d3f5eb15cb42415fb180a3c389e91d7e", + "a173e9948ecb4d22ad23f427652d5cdc", + "74d4cc8f0e874e4cad1214eab685229b", + "84c4e55948414c6db2473da7b6e9cbb7", + "3889bf1e6f744be7857d35ca8767a628", + "c6becc6bb6ed4919b6818fd3c26165e6", + "2eb66af869384273a5f533df64551a0b", + "ec1c3f9437e4401cbbb206ee55791490", + "f51f1d33be804a759207152154ac7714", + "0d9a45c2610f4f3aa638dabd8e29a492", + "2c7e733d9d2b4b229b97bc8d13ce04f4", + "30e57f4e0a844e189163fb8952c42ef6", + "6d49b300cc80496caf9192783eecbb55", + "ae214be8d5984abd8fb04c9bd1e4f444", + "25106c858d8e4056a372fbbdf3a7275a", + "00c86d330b034a0695bc008078d45e7c", + "dc3f65d227f74bb5ba34168a607eca66", + "359965886cc24453925b01ebe95421a3", + "3990cc9d604d4030a84b713db2ad4242", + "258a3d42ec59460daa6805fdad354c9c", + "e602ba1ecd974d10b8d29e602f0711c4", + "8eb0febb200f4ccfb63b1b1564ae024a", + "e42d6117ff2d44158eaa3f1cb1a4c40c", + "70b8a7f8ae4b45f5ab0580fbcb179823", + "9b6a637ead444bd28452178c74697653", + "be9ad6213c5a48368c0e9b15e46681a3", + "5504400e426141ecb2a52a26c644b992", + "4a6db2daa25046ab926327986d1cc527", + "5a0ae2276ac845c9a93b240c076aae19", + "684b3d859f924c229ef67d0bd8aaf4b8", + "268b4970a174419f8d621f469454be84", + "f295dd1a5b2a40bea76efbe8234eb0cc", + "7d6996fa197e486da9721a60d0c71170", + "6bf651b2080847628edba91ba203b14f", + "1c0a4977f9d145cc90f6ed355e3eff3c", + "767a90216c804b64a7f4be9f8ee97e2d", + "46fce6a66e884e8a97055ef47f7e4add", + "b8a847d396534a00bbe2269894d19aff", + "89509e3c894c40a68542bdc586b38c9c", + "8f340bb7c39b42fab68c628d9752f259", + "cc18d1ee58fc4556a72a5eb2c1b16622", + "ec937670c162493c92a7d13d76ad550f", + "66f0f196877a4c6ca390e5b5f275e43f", + "2ca171ded7104ca98d0010ec62c27d2c", + "8e70af869af548409eed3b3b40cfda9a", + "1483a55c785d4379a25441681153cfce", + "04522ed29d154c8ba643af8bd613e357", + "31c9702da6a04f4eb534fe83cf135c13", + "1e5c26dc09c34e3a89858812abaf7ad8", + "12c583dfa09a4ef2852eb27828e50626", + "cc77c6e2f0364c8abee4b411c579f854", + "861959a12e4a4da8ac7407c2be517794", + "ee2eb3d6f9a84f8e8c9dbd76adfab7e5", + "728fe13683464a98a7207fc65c8996a7", + "b7accfab74cf40e589b43e23ce8d8bab", + "42f2dacd02f3427190be53974344844c", + "d6455f4f705945edb80642d1e24b4753", + "64369e53063d4fc3a04cdd042ae1d33b", + "b29b03e9703848a99a32ee9d9b4dd7ad", + "02af6a8de3a7493696361ee81650442c", + "f244997ce8904cea9d15baca7754b76e", + "7dccc542a68f470a947bf5f698c27bbd", + "8b023c7bc0754d1aba4791348b53bec5", + "73003cee6e3645ce827fc168583bdab0", + "fe318f681f7b48628ffc3fe153cbb08a", + "e03fc4c50d5844628db3459619b4d3ea", + "821ea1ee87484b608b226a73303bc25d", + "c5225fa2398d4b509aa49bf2e4e1360e", + "f19d95b8da874d30a1d0425c93e695e0", + "fe27c397cf42404ea4c1f6a32a38a27f", + "16728b6182dd41098ed9a6c7f62fd2be", + "eccad1195469423aada2f0e7725a2890", + "38baa418ff3e4f42b5b71c82388560e6", + "5db1efd11c854c638454e07216b5c60c", + "4f4c77ca12c343298e4fe42882dfc94c", + "2da0790639284369b31a7c88523e33c9", + "e69e99eb82084c2cb45b35f21f929d49", + "8cc35c739c834b27b72d4761578dca3e", + "0550d37fa7394f8e98b6b7dc4bbcd31e", + "4018db5a2d5747f2b971e6bb7210063c", + "21b09159464244b9a6f620ed4ef82d27", + "e230d530ae1b4d74bb62f4d034b165ef", + "7b086f68c721467a935e7d58a89dde04", + "d63568fef8e94cc8b47aef0aef1c1655", + "307666f827cb41278cefbdd3c8da03c1", + "2ad7e5e86e8748e8baa05ff0e68676e4", + "13e4e3da76ae4750b9d7e6df88530d44", + "a406d95be3744ebbab81061808db56e1", + "a0a009a2812f4eb599918a6874ba1a37", + "e6863483617a4a5e8eeeeddedc85fae6", + "821fa675820346d2aae23e09b949f1d9", + "60c006be9a834849895438f15d4927c0", + "bd5867761a694057ac861fa818395ba2", + "c71a55fd1987469fa7987413afb85c29", + "99772edde54b44e1b430fbb18dfc49c7", + "6353119ea60d46e6a154374937c7c137", + "b62caa46c1c447b3ae78c3e18d47edca", + "a4ea5742827e426fb213410cfa001174", + "c9381ca85e454d418c0e923a94003dcc", + "883e4c1fdb0b42b48467191616b22edd", + "17f7e41a66af4603b47ec9f485e3bb8b", + "47c61d03fb734d469d1ccaeb933a7208", + "89039ea7c094485484be35acbf0f6db3", + "e95e6bbca085477db65ebf2b8773f67b", + "84aa0fda52b54a658e610e12ad989a6d", + "651e077933774f818763a14605adb381", + "0cbb8b22e90f4c6f98e920ab03382a01", + "3e9f884fde9141dfaae7236ae0f65306", + "ab7ca99c3f4c49828ad7e5c4d2fa28bd", + "0a83b0a01d304ab2b8653dbe97afb69a", + "341cb7dd930a427eab3f8e925718e6c0", + "63287bddbce64d04894ef40fac69ae09", + "b4215f3c452c4e7cbe845b56251d2877", + "19604e5f7e1d461f9ade081958241d62", + "56d3576ceea740f7a42118dd008ac664", + "d5f371b2d9c94e40960f53da88532f27", + "d3b26c6469c74ee9a653ded4a4dbf9ec", + "837d98d8a77c43ea8ac1545fe022fa06", + "8cff17fc96b44ada872cd4a3080b7320", + "f4f7e42405274eaab3f65a0e342940cd", + "7d185fa512604b3aaeca8a820c500661", + "9dc4ce0c08344a7e8f056905ac81b43b", + "ce3c0bc29dbe4b07acdf068c18d4f603", + "62a95ec9e7c84be79a66ac19f0f59a42", + "35e7855868414b91b8903d9a11e4ed88", + "6eef299b1aac4ff29f238abca0f7cff3", + "f68ae1c354a64ea39e160c4fe881349e", + "0cc33b4793fd4296a2700dfda4d8c35e", + "c73a1f2edf0c41b2848e95bf7a48af20", + "d9bc98544b9a4e5a979df1512c269a09", + "bdb0990c665748038b1f57f5c6d7ca72", + "1177bb51a3d94515b4b48eeb7ae7a9a3", + "b7a8a583a3e8409b823b4f04dc3e74ae", + "fd0408523e0d443ebe0d31a63b3587f9", + "54d13eeedc50469d8b37eaa455553ae0", + "3ba6045bedc44080b2d8e3860f36f144", + "91956030e9a74dd5bf2f3a03419c450b", + "2b697c4577e34347a204b48498085030", + "572d364642434810abd1fa7cfb6e7782", + "5ee9d642db254c2ea1bbc43982b17c6e", + "56b46cb4f5a3427ab86dae1ad1eae987", + "4fc629b0470f42a89a14538b80ef564d", + "2e29f654739445f0bdcacaffd61bdddc", + "966c74cfad20469f8beb3afac62bb9ea", + "c5ca1266a2c740a6aa3dc49ee33db56e", + "e3bf7751e01e4dfb9db33f9a48f04c49", + "38896b59219f424a9c095db2c955ae1f", + "41196597e7d14b5f8210e075873f3529", + "e822d0679b6e499a8cb3e9d2d185055b", + "facb6b3bea75488bb579ad893b8349b9", + "db5f9c28708142909b15212625a127f9", + "053039b95c314104b5fe0dfb19f43cb3", + "de945616c93145abb61cb5bff4de0d86", + "c9b3e4e3d0de41da9d587d14237137bd", + "611af31cdb9d48d9ab5c1bab48ee898a", + "4579cb8f24e44956b5d8682c509b4b13", + "c738846e5ebb4363ad1d284c3e814a7c", + "e1eeb579e9f644cda484d909824ed167", + "954bcc16347940af96136bc6b666cb69", + "acf21b6152b84ba0a849fc939c579b0c", + "934b7b5515da4720b0af2764924aad3a", + "3d7a17c78efb4b059d1cfcf65205509d", + "0fa0174b26d34275bf09436927d42623", + "54602080c9d14d5ab052cf9fa7403ce9", + "67392ca8071a410c9840746e97368fcf", + "fd1fdc80e8284306b56412e3261d1906", + "2ca42dd07637431ea6f1b7dda343df82", + "67afef47ad514609bbd488cee7496e0d", + "095b27cd328048439d6967c4d0f0a759", + "6f7f4c9ba5de483b97244118aa847ba1", + "46dba319bf184aaa83352bb7d187ebeb", + "acd92cf2414e423c8a1308bde73e92b3", + "bd6c256f77024d42b0de1688f1336a8c", + "bac56b6f8a6a426985c62115817c82a0", + "30d1c501adde4e9ea5d60b4fbe64e1ef", + "ef4d2daeecff4742b6b3bd92190f0adf", + "fd28219fdaf74022834cfe0bb1bde400", + "603f6559d0cc4152aadf0d8cd8e299e0", + "4c23af67946046a29a455dd4f4a8300f", + "c808579607074ab680b6506b9b127367", + "8b047833ef7d4a16b7ff97f66d1c2ddb", + "416eeb0fabf9443f9e3e9a9d273c89d0", + "de82074eeb324b3f931ad3adaf3c712c", + "c889035e87494847b2dcc0a02b824618", + "83acfd7b5c6d45deac06467080112f3d", + "34d29ecc6147477fbed92e75dfed1bfd", + "95919983de7f4118b1655e583969a895", + "b43c45317fd74a4aa9ba443b9a355ea3", + "08e8617db78c457f8b218971e6055e99", + "913530823cd94f13b7e8f6fc60e4f93b", + "c6faebfcb94f4f97ad125dc509d0fe39", + "72ea9b9996e147ef8400a213e9346c5d", + "67c98bb6b42c4fb285ee3eba942b38c0", + "1cf0d8795cf142739de1948f30a18a43", + "d74764fa60784ca8bb132598162168ff", + "1d13f35582814dcf86b7cf28ac5af12a", + "e5622dd4c0b04459a789fe1849617736", + "366d9596780c47829db69719eb2c7d02", + "4d2d747105e34ba38d734681b8d2dd1e", + "ce0d5eb86cf5459bb6bd20244cb44b27", + "6adac8e59c2949ad8e0acb003f49a7d9", + "b93e5ca5191e4f14b0724fc4b1142c93", + "c757953926bf453193a1edc6048ca8f3", + "a2eb6ec3f02c4d74955d0ccfe680cc53", + "1523afbd87ad443c9d9186db2a7df236", + "d6cf914677a74d44b808ab9e542f39f2", + "47f9813e9bb54eb69a215a84c6462ab5", + "d168c04013534be094c0adfb641454ec", + "fb75a3457283445faca6eebd98b9e8a3", + "09bb4299b0a9417597ea15bdc713d636", + "360d1e0f2be747629f88fb8da99dcf74", + "6a7b0147890242418a49f6db26657ab4", + "37075392da5c410ab6944dcd42359a3d", + "a76ec87524214428ad0190ed4e761f0e", + "e562556aec944d8e8c57b7715e3c1a0b", + "ece4453042144b4a82fb86a4eab1ba7f", + "6726e38c15444d9f8bfeef1b2f9627d3", + "11c2517d0a134796a6e401a72428ac68", + "0b3cf2928d524d298ac22cb271125bff", + "e9bb977320834368ae71b10dbe913c0e", + "4af7ff130a1a495b8141c564378fbcc5", + "97e35731d44a4070803b0e63dd3ab582", + "37085e3a281c41b1acd355b5bd9fb59e", + "d7b7f05d16854c359ca492c9063d3055", + "3606ba9e25e24b548be681b02700fac1", + "1f265e6319cc4c2487c940d0849c3c06", + "b3546bdd1edb4a06bf54e201f7d50083", + "14b86febb9054d4295a83191146b891d", + "d0bdb44945aa4313b7dcb943d1ac21aa", + "c9f36070dd93494dbca6e62d9d7476bb", + "054be0c3f09143f38c4d8038eb2588c6", + "fd073296a28e42089e5e8a59cce8c65c", + "ef5346a535fa4a0ebaf631dea1a7cea5", + "1be961388f3f4a858f9413232656c957", + "2556bb64f1414de7afb8a299097ef279", + "934311d8a24947538c90bc00404a4f06", + "da957a350433461c9924faf08ec76dea", + "f9bef8d737af4f80a33616d7ba49b2ca", + "765ab0735ffb40d59358ed1b1da92c3a", + "1b3eee421d92472b90c7a2d8ce33ce18", + "63c49ce5f17d4c4c8311f6c2d62a79bd", + "dc500e2702c448f093bd01f60c4f04b5", + "b30b6a9018f842e7b12622387979b0fa", + "bf7902fb64644da3beb0ce1fce07f4aa", + "21e23f5fe0714a98a1b76b4f6ae4eb9c", + "2b3c8d4a2dfc48d8ad7c7686ad14a68b", + "e90d9945f68d43ef9e04157eab355f8c", + "009fdf73a9c54e7bbd3a7d28496752e0", + "4ccf7c699f8b448593fbb79a2abcb3d5", + "5f491ea8b1ee4481be53ad63d402a7ca", + "e283656b021f4032bb02f8eea06391e0", + "b6f9128ace03477fa18875bcac5ab469", + "edc873210d034580ab1cdfae15668985", + "f5cd6ce9cb114e0ca11d721c9d3c4582", + "37006a5a27674a58aebaf4e17e0c4a95", + "ffa3993ffac54c0595bcfb5b1f5767b3", + "9b4039619bca402abd89e0765910567b", + "0edd324c10784e3a83b915fc652c9708", + "9c4f7e89f0364edfa7ba5a03f8542e13", + "3e8d1d6e11ac41e3b7f03978af2315dc", + "ca9ede83ef6c4f769fb8ffc000b73ab9", + "3d442e50799b43e98d5fa5e3c81e8b2c", + "3108e5f9977b409bb46d5b5dc7a3a452", + "13987a71b1b044268a78124b616c7fe6", + "47f7f9679a95418b98a5a360c17cd43c", + "07b97d13a37d48f0a74431ec832a3ce9", + "55aceab89e6c467fbde194994f006d99", + "baf3242c524f4e4483d7f6df5f0d9848", + "3d29c0ca23734c28954c1ec0c4d8f1ed", + "48571132f5e2443998e97fa3a498d816", + "4068b76c755349edbfac42eaa4ea34e5", + "54fdf47eb8f142739fe32864fa8e5dc8", + "0d010df52faa4e5d83db5ec06d83c18b", + "4217f807374e46cd95b93cc562acbeee", + "e49a8a18b4db48e09318d59166e0ff04", + "45431c14399a42e38a6c1d0b99de4c7c", + "ce9e4f6890444e69bbe3e87c2dde4b81", + "1c361808142e49cf96f6035bc60e507c", + "1af8825e55ca403a9808ef136a69939f", + "b58d4eb47f044bd9871201af4d72ec1d", + "695033364f3e4deea2ccd5dd0908be98", + "874326a374c94980a7c7a6fba918dce7", + "98003db78c8446338f8a7694ea9610ec", + "ba90f173220944eea071e7839547ee4e", + "796d74f06af34ced92f2085f660c17b7", + "deb540e37ceb45a0a22c7b2169a3c69e", + "138f793adde045a5a5247edf48f61eb1", + "dc812b5a60ff4ae58fcec00da99e3237", + "abfa2cf5257b499abfe717c24d49f81c", + "460cffc517b649bbbcf62e18fcfa4d53", + "aea7ce114d44422196160e6120a0187f", + "3ce7d2047483473dad63751c7b5927c0", + "b4cda635b075408096e9b57bbd2dc22d", + "a53d74ae0a83444d905b9ae7c9629a95", + "a993f196eae045ffaff92d5718c6f46d", + "b739f946b7784ecb9b7a800c58bc5264", + "ce241144d1f340869fccd0a9227de5d6", + "4481d9e392ab4175bc5d1508efce6038", + "889f4a84f24144c0b1808d4b59c04d82", + "0c79a8305c524872a6fd55f92425eccf", + "7d3b2a1ae57f4eda9d02163a0277811a", + "50f8b7da4a274cd0afd625839d130c49", + "a39b73078dca4cef8d87dcf41623f3d3", + "b0a98aa01eae4bb785e9f63e6fa076ac", + "3964e19915c34da29815091e1d7a800c", + "42ab0a962b964b9cb42e54cfee8ea443", + "0faf4ddffcd14326bfb5717c24f6e2b4", + "fb7131463f99420e9c3007569c019d7c", + "65473708254e42409fb54ac1e18d0ec5", + "6f74e104b47c465fa6735a527a83eaed", + "e329d44d69554ae699d8f24093ec0ae7", + "943945c69c6e4ef1bf2b66c6fae63763", + "52e0455b23784d64a647b81b2db8f609", + "612ab54b9ae4496b8d2db2743bb698ae", + "bcf87cce305f4c1f99a3782de1d2f020", + "bd59d215156e460fb1a5e83d99514233", + "c04aa47aad3e4e0ea10c51e1479017a0", + "cfb621e11f9a4f5f9f55752daf1d6d95", + "d6444e535fe54ada93e2234cbf23de37", + "515b783e0444464c84d7fa0cebd31cab", + "25a14525f06f47a2b073e73f2cfda3a7", + "3880ada0b5df492b81c5d1ba3ce3126d", + "e6f1333eb8ee4bedb84110a38f79bc40", + "5c43c2c8c49e45c7ac2fde88b42c8215", + "d8fea9a160664a17baef5f544b35e758", + "b772a9c3a6a44c4f8bba00681c57b984", + "83bdabc8afd940439b1287236a460eaf", + "e71d8a06787443c495a90e7b9f680047", + "f8aa5eb92cdc4d3ea4dcb4dc567d5579", + "f188778dcb974506831fa50aff7e48a8", + "477a2622764a4bc09a896f2bf3df8bc8", + "5afa9d97e6ed49cdbff010979b4a9fd7", + "4c43536c49e7409a911926dc7dd26aff", + "c39aa10f432e404492da796320557e74", + "65df7c2d34ca47d4ae0c0e2b91850ee7", + "3f1d714d470549d284b5662c116661c4", + "7370199a9ce64332ad9f76a0e14273ca", + "e413b7bd353d4941ba71c548a099e0b9", + "c3823204f92c45439436f9c27e2a81b9", + "3a3a887f69e045e2ab8c035db955e199", + "b6cc5a48eed64ee8b3297fc5188f3a9e", + "a86ee9565fd14d2eb3d8aa3f745d5949", + "ff24b004c06743dabf04f6c1b6d825c0", + "0d175b6ec39a45888b90af64d7fdf250", + "39b18962035544d78be6fe508a0d2aaa", + "ebea301a211342ae8058a06c99384c86", + "9e17d5737d564d2e92338c80c8324b78", + "19c24b7adc784f0ea668109f9560ad20", + "dc6dfe9c5a644082aa6673fde4916da3", + "529fdc10021e4c9f837ba2d9ecb58829", + "6e4a2a6fc13e4e339ba2e38d2ce5a136", + "9db6ee3d0f0b4dc7afb2b4791c153059", + "13d18e6764ec45689ced6e532a41fcc7", + "07859442442f4d24995ab93e1533106f", + "42e69ce5d2e947dc92fb34fc36dae4ec", + "5ebc336e5ac540b39120c3d667a245bf", + "6b46b33bdff44269bf9391774bb8dd63", + "e377d5de7c054d8b91905114ba92861b", + "595be90da0394ce39e2a78802cf1f2f7", + "32dc8a44ce3c4f2c8b20ebc393b4500b", + "f70bc7c1ed74430c867f320f2e8e3cef", + "1b832a6fb7614493b893f9592f39e9ea", + "d814b79fbcf2461faf106861bee7e112", + "8bca43dbd7ca4df9a17b8c84ae7ed3fe", + "1ef90928c6994bb28d8069069dd5adce", + "397e770da0244abd9724da5d3379ce3d", + "c9fd6abdd52546bf95e62e116bc66f40", + "e430254560ea4175b38be23bf4b57b6f", + "bdc696f637b94faea391e3ebe67988fc", + "61e313e05eb845779f12ae1bb32d5c19", + "33cb5127082e42ad9305e7e888099ab4", + "29cd8378983040f2bd4f2d9c823c1fde", + "dd3672fdf63f4884a081684143b9496e", + "f7680cef7ff1499ebf89e0348bcd99ac", + "e268788023f9444a93f8ba23d8f161fc", + "a91c1c6cf4114fad8d3c933f19e3ff25", + "caeb681795a54c6eb0bf120582fe7f45", + "b1bb8623bb8141bb8e0718783d473059", + "0b02f77e90994bafa6e2769a21f30c11", + "87d9a600683e456783152e8eab37a61b", + "2852ac8cf5a04333906a76f163fc0a43", + "32f9ee4b15104c1a8d14c99607d86c2a", + "6dba3fdbfa1e4202b3d39c0967e7e352", + "cb1bd0d4242f4690943e2d607f688e72", + "93a894c8c408490783789b35de5b592a", + "147b14b62268478da7e59fa36c949bae", + "adc2c82a953c47c4b197a8a42da12460", + "242c7a67a7c94aba8cb6ae639001803d", + "f51f842949f3425a928752670fedf717", + "52b016792dbd466eb479f77123005ed3", + "01c9b73ed5f1406b97f86e46774fcff6", + "01e6aa0666a64738994b8ffa8a1a6e15", + "d3b796cd92df460abdaaa2ebacfcf56c", + "3ce05b16354340058d5c3b06028cb9df", + "8505a16e81174d69ab838b45ac5f4a88", + "6e35f6fdf1264db4880049b802f18ea2", + "dbab208fee67406c978a11ae1aeab065", + "275eb6c21a0a47b3a87829751a7e7721", + "4bfb493631f84f8a9adc00bb69831000", + "a753edea0c1b47f08691093820015c65", + "05859b0ed5e546fe986382c895d01ba2", + "d1d5543b0bd0428397062914183fc5c2", + "746455b9c0e146ce9c479246bbd92416", + "4d92ac7449634342935c26d8d3c8b39c", + "508a7b54b73546bfadcb5a9d614eb315", + "70eef95489c046c5bc3fcc07a19b20fa", + "0b7ec4c4e35b49f0bfb278e5424c294c", + "0836af0bceab4fa3aa71357d37ae09e2", + "b7a6951c4864438b8f310d0fe01318d2", + "f3f669cf39b5401d92a573dba91f591d", + "7794a318d07d4fdf972d1fdbc7f61227", + "d0d69cc05bfa417cb2be33191be563b9", + "bac1c3d18a064032967d182c52782c29", + "b518692eda8a46969656a3f7720a93d6", + "c78df29082d94dfbba667101d748e924", + "53847ea1cd0343d3be08b1174339b009", + "a8614ccd87314bc7bca5919d4f219850", + "abdae5ed11294d06bad851a25271969b", + "c3a580c52d9448ac9541ef8b4c7b4db0", + "12304e30fc9d4c1288f6634dd80a2bb8", + "9fb734fd8aa94d079258008ff0376bba", + "f6ef41903e27424a9e5fab584e8db7e7", + "f4f3f69915154159bbde530030613b32", + "6b902382b9f34c6596d67b970af0d027", + "f20dfd7078d945028c497a8f2e3658a3", + "134f03f9454e40ccb7537c1990fc3e91", + "3b172a1b78a0489cb0fb2a0a22a1ead2", + "c3ee39912e90492b9b22359831e13921", + "ac51bc2baacb455b87ccc53d2d23f853", + "fd5695f123bc405ebbd69997f49efe2e", + "60d1d4b3fb494bfb971a920f16187b2b", + "15500b2788c2476a80567a9576369ce0", + "c8b35d665a0a44a5a55c005e0c4ca9f7", + "e316400192784e0b8b80b3f5eaa1d532", + "3d42390fa27748f6818a85182595a69c", + "4e59e28f19d44d5f974f80f0a9ee354c", + "3841ac0446dc4b71a494fe97b9ca8329", + "0da0a7b091d84391b6ecda1bb56a76c1", + "895524132ffc413a824c148e9868a6a4", + "9eac0814868248fc95deb9ce6ee36b81", + "2566774276944542a01ff47a67a6eb51", + "a36ffac5758a4104be79beb3ba5b6c92", + "05e77cfd5dfb4b8da52876490be720f4", + "cda432046de54e99b17aaf15816cb259", + "ff7cede13a394848a4416cee533b7478", + "cabcdfcdb2df473e8c2055bbc0c7b993", + "5844f16346f9439fa650e97432b24bc3", + "79d405d271df4f72aed2408eb9902104", + "d7d47b3557d0471988574c39be257ae7", + "c36767916bce4589910aea91c422282a", + "29004184ea8f4ca290d97115651543eb", + "71174c56c9a641f6b21cf59edffad3f3", + "e36a7b70842e49088bca1bd0861880ed", + "3edddcc65acb4783974e8665b368eb8d", + "44b527d7d10d428b9930732553f479a2", + "3e8b854c8b144272890265e32699f19b", + "958ca30428a244d9a01331fe5a09c179", + "0f1bdeeb5ad14e3f8424534f130e7dcc", + "93de4e34093742d098f852c0b86fff93", + "e8100bef7b8a48d4ac79684bffb349ba", + "a62703a137174702ae9de50d5d33524d", + "bb9978d28fa54f5ba47208f50836ae0d", + "954731db90784142950f8cc593da8717", + "de32df3ab7e04f3d8940e5d9722851db", + "e9ca3d407b844b64a22bc74b65ec7899", + "52b792f591ce418a9ac2685329f4bc4a", + "4ea529890078407299df913a84d21ddd", + "ccf6bb0ed5274683b0bd51c74b117b53", + "3db978bc04f84b20b88db8c2d787cccb", + "a7a8a64ca7ec4317ba59063748ce1cf5", + "60cc15b40490431fa19bc4e944facf50", + "9efe00ec5d734af8a2d6ca1275d03a9b", + "ed2ec9e7618f4e88b5293e15b37546cb", + "6d64aec1c7434acfa04df8d11de67a7c", + "fed9507fe93349f0b330acec71f4fe51", + "3acd13408b47464e96206ea797aa50a8", + "c5840d5affb64d9b967986c83dde61e6", + "0e4c8ade6b204c41900f744c403cf2dc", + "84515ab6c5694aedafa6c36fdad92234", + "121922992c4c44c9a121a40c82c79382", + "f8fa013bde3c4a0090b6c1db953f059e", + "79b839a15ac844d5a5e2917031461d97", + "7aeb9b9281734308ab4852f034abf50c", + "0bd1914cc9864973956c51a821f8c619", + "fbba22b8f51148c3bab4706292d13d47", + "9603ae140b8f46b3a944f3a6055cd18c", + "e82fc7fcea3f4d9f95b41ab255e26aed", + "8170cf1409924abc9c3fc8becccdd36e", + "c4f15eea9dba445f9d9ba67275369948", + "18770e741ef24ed19b42fcc1dde9e904", + "8de97dab517e4077b73fc56bd7ce6838", + "74adf6836c3f4d93a127d964f077db4d", + "ee0c1487492744eaa768824357daf3ab", + "a987896c6f8a43ee9e13830ba90c89c8", + "835a3f294d034cbdaa8fed6e5f769068", + "b849c7d0704240ed8e8304087e2c12f0", + "6412ec5ce99d4390b4c989a32bb64d36", + "7dd07cb23bb8437185d524bbbb3e9bbe", + "b65cba53888f46a4b3c363f1836d0851", + "7edddfba4b51475f9438cfd8043ded86", + "0b6b161114f94c0ebaf634f3c426792f", + "396530e9f959425d8660900bd3c5ce1e", + "7c45b3a5aab74619af0d6939b7cf5a70", + "3ae6d5989f164c6f8d91dcb996ed35bc", + "824db5aeb93a4e99afb002b39b0ee4ae", + "735f7039f2f84c8eb48ecea13967b1ca", + "ac0d7f80a0844f75b5dd483729ac2d50", + "a71c79dff1a64d80b1616fb04779aada", + "1245a2166d57443ca5e3b63eab057252", + "3e6bd896efcf4dcea70251fce685755c", + "a66f6c9eb3c24a3099894c4d91f68e0a", + "2302e3bb270b4f8b84a7f3166fc45b7a", + "10a2cfa8081b4a2c9c201220439ff7a4", + "cb6e3f9cc8104b9c8a2a7d47da56375f", + "525b1f5b6fbc47f38f66dfe5ab67934f", + "bf7946f301ff41179d88e144b95fd3cf", + "85942e1177c94edd842bb7bd2274b0bd", + "a951835bf6d04ba0a83f8945ae5ed06d", + "eb7e13eebe7e45e9ad219fd653bc6bfe", + "c19ac66555f8425bad39da8bf70199e9", + "e60dca44482045ce90a71946888a53b1", + "56c28545279b4be6b8fbd5f58dc791e7", + "c8208a0a46304cf8a3b78c21dcf2dba7", + "addb92302c0141f5b52b48b06e359f7c", + "3f23c9506077420fb762e12bfed7e7ad", + "d18d78a57c934bb59ae9c54936e87c15", + "b60ee204fd1a4367b63ba04f20073e57", + "dae7a42f991d466583e403aec5eb6f07", + "87d8dfe0014f4eb08a478118153257a7", + "12c83e9f00d0498b85ef1bb8218b5d36", + "f39c6c7bf3454a50877ca0f2c7f07cb9", + "235f67f4af244ea79e43c90785108192", + "d1d480f42cd04f7394c70a7b8ee7bd67", + "b44525285d1a40ef9b6744ff4031913e", + "936e11daf1d94cf69384c4d737cacc72", + "4095165c344842729ec6d3608833838b", + "193b5e63672a40788c838e1307a1a6d7", + "5b7e913a186b416c89df9313c4f16c7b", + "43f24fc3576549e092a976a61cd98aef", + "bc5c4aa995ad4bf5837b30a859d64f72", + "d1a0b96e5b3e44a9ba548ba9a8864c0d", + "070344de71fd4e1dab48022a5dc9266d", + "559ae91218c641a88f57ccd6d9522ae4", + "ac7838c1b6b34a72a216b219efcf9926", + "0243239775f24dedb4821836e090bbc7", + "4f43ded3dc8843c1a61e0f848158dd2c", + "93037025fcf04b5c8ff81a27ad269ccb", + "49b2c79d1efa4ae88c936678d3bebded", + "6c03f1f8cb9d4eaf9c59917ac89e73c3", + "1d1399f8fbb346b98794f0be2961fa0a", + "3f6379b182de4aed9eb20b3641281b82", + "433a681e7c2940309ca743c663037e44", + "4a9a9263d4064dd7adc68319824b3b40", + "b669de5025d84c8ba920c34e2f8691c2", + "7d3f22bf699048b1bbb8f78ec82cba78", + "82d0d383d9ec41a18d6ac8accb597fdd", + "6997fcaf69634d7982bb1893210afe26", + "e58a74ebfd00476495342ad08c2aaa32", + "56896e159e9c4a1380427fd0946b6a81", + "cdfe5361db8941ecbcc74485542acdf3", + "a2955d958e954af4a8586188b9e91c73", + "4886d6ca35094dd4a98ef8aaa11d6f90", + "a523192639d14e24bfed3dddec54d6f1", + "8d739b084bb44ad7b900fe0d0649d579", + "1ddb12132a6f4875b2f8f337b6e0c0c3", + "8c543fb16ff24ea09e26cd841bfddbe5", + "e4f60c5558eb458d84cf561e6d144fda", + "154f473fa4ad4a38aa874e4d28fa9c14", + "eaa08a9b86d745558ef18a0186766d44", + "b1e058916ac24415b2b7c74ce18db2fe", + "f1bbc61a42b94ee9a2976ca744f8962e", + "618129bf49864a35b0c4b3d61d4ee5b8", + "61af91b882fa40d9851777b1190b4d1a", + "cf806b4873d64406847a4f4505122b77", + "5c8902cbd38846c695af531884a15221", + "bf495d4fd93d461ebaa241f8613b777d", + "53c53a112c674d29a2afdbddbe3cecb5", + "6404bc5cfbfc4fdd83df8fe93fd8abdd", + "c9baa170dc344ed5a77090e0589a7de8", + "95d536e226364f1daa6b8867d1d8397c", + "2067d9d0d019411ba07cf5b1e829c868", + "319fe609a7044bae88ba343bec58a4d9", + "01e281242f8540c5b7c571210751cfc8", + "456d78b100704bb7956eca27e51921b7", + "e9758d826ea2408fb11cff36b3e315e1", + "cf41bf0b07ab4f9b9ca3624b19f4968f", + "04089668065a4ec69aecb89a332e6aea", + "79bbac89e92c47eb94af95a46639167c", + "435214a75d38452992f022bb6fe1fc7f", + "078c909947a448b1ab22cad611c6d56e", + "8b8b6a5ba71741e39934826d268a09af", + "1464e06b191041208b52d0bd038b3349", + "5293b1c1bd064d4680fded954e63178b", + "dbe182eee98144ec8738b63802282354", + "b6dbcdac7cc34379b22ff3099fa4bf5a", + "32e77e4dbaa64916a91e1338221fa6cb", + "99325395edd44438b36ad04cb308a3a0", + "f1b5b0c1a6484a6ba3d4af0934c5fe71", + "b44f96c88cfc4cf1bc196971ef204ac6", + "9837912cb08c45efb5a9ad41b8190a12", + "1a38842082494b0cb62f74e630a00043", + "0e820490bf3d409a91a0d409b2298290", + "92e6509f3b474298ae66709e8cc24255", + "beb46ddb580f466ba1171317596e3133", + "584979305dc64cb3bf775562748e5c28", + "b719e10aa53f450e89d54eb9ed55ad71", + "00f5c2a117cf4adebc6428b7fa972ceb", + "14abf9b637b64ded9aa2f74a472f8eb5", + "95f4c032011b4a3297623a9e5073f0f1", + "50f35f0ec8be493ab9f2d478abf89e8a", + "42445dc241ab43c6b416c32a7e2fdeb3", + "0a33a9c452cc4d6c98ddceb84d232119", + "e5d3728987c94385b70acfd34dc8f89d", + "9eced0b9937442298959383860626ca7", + "35855e388a504b9882272a30857e60c9", + "e579fbdd53384c198f502b905a567614", + "c68b01fc33a7464599d47915cacf9abe", + "f8feadbe79a746559c43fcde1c80d4f5", + "7b3b31b2c5584207a7fd9e885d84c502", + "f6f621900b774da8a7fdf810c4126b9d", + "371bca5130cd477aa81beb7119a8bd32", + "0c591ab89cff454bbec9f0be69458026", + "dc460d8700f54b40b8e61828303d20fa", + "b02036eb7bdd466b90970a73ee8cdc77", + "0cdba3bcda944c54817d0c2382be89f8", + "c6b77ed586b94c96b828a69e38c3bab0", + "386b1f6f4f7543568fe541f86b4e063f", + "c9acfd3b484b4601806d88e0d4aa2cb6", + "fbccbe1a047f421cbfd815dc3682faee", + "1bd0a8743a704cfd873143a1727ff0a7", + "0fa42f5b83084f0eb32533b760c8d146", + "047034b1ed1c425595276ba3ae178490", + "018487b190aa472caf198b265a3b4d61", + "119e19154a6e40429c47449b7b1e2717", + "8d8d54678f0442ff977001bac1959615", + "57a31b618b2749c39a044fe3b24ab27d", + "d3029779c7e54ee6afa3890b42a32098", + "5b4e5ae018dd46d69277e894a72d6e1a", + "2cfb46066da546b59a9cb1b9d968a406", + "9a1173bae60043028716e9d0601153fd", + "63cf54469f65453f8db374811a83863d", + "a6b6687787134131a451e7298f0a1ac2", + "f634e2a4f5a040c3b5a0c9569b500ea5", + "7e7655855a7248b089b7667d1a4f96d6", + "892106545fe343139ce36955563fd24d", + "3c3bf522e4854b42b158f4546d75b491", + "f4070203b492449f8bc2b43ae7946f48", + "9f5d084de0474c1fb2ad4e33920d29b6", + "e67e1b3c67804122b70eef386ebdc0be", + "87c2553e593c49c380412fac2d65cc1e", + "dec9e912d6574c71a23a02bf03022b27", + "e8915554fc484a0caf11ae021ac11e55", + "673ae444d8854a14ae43f663d7b3304c", + "319ec67c98e447eebda0039b143274c5", + "5794f6d3f7374cefa471122843b6574f", + "af1bf75d7a4049898fc42d7135fe4e49", + "928d285bcb684da19dddb2f684b5238f", + "95f90e93a7cc4bce8e813411e0c53483", + "2176cf8cab7745e5b145bcdfcff950ce", + "19c928e69d3748ea941e6c5537c7502b", + "b22f932e42e9467dbb6784c979b6dfe1", + "7ec7baa8878b41fc969f5ffa542c7176", + "9cd61226d8d64d549df0c9974d4460ab", + "9428c3d9fd814ba4a42b363ca92cd003", + "f2602d371c6e41c485620ff380f35c26", + "5b4885a9a1c54314943cc9836f2dcea4", + "0f4be86441694633b42c764a4574fd41", + "40c0747bd8b84d319850ca415644cb72", + "54eb11915cd74478bb14cde2ba2d0acc", + "48885e0b5eb0467392b405f362aef223", + "a9d3dac0c55042989309bdcf68c60f76", + "4b383818e58f48079a0a19a4add13637", + "e31399ac441f43b79430bfaadd22db8e", + "09fbd65b156045c592f0561d6a0d2ad8", + "08a3baeb2e0847939d53027824de5a49", + "bd2716459c774dc48fc793f1b76511e8", + "f9dfc01a5b894c2d946473c4c06000d6", + "22165d423dab42518641a7788f964291", + "121523fb980a4f44b51525ef3a4ec968", + "202f3448f68c44ceaa5f7f8e28807341", + "201c29fa168447a097cfe24d337cafda", + "26a47537deeb43fd993118e9bdffef75", + "4a6fd57d5244438090603cd9c55bfeb3", + "6f7eb2f032d146d6aa70d96d398bf3d7", + "2815b618ba8c4d6293906c12b2129ed7", + "c76723abab6e4e2696bf7e3e1a27e861", + "e5e90b174a6d4c1c97767b3366bd6d3e", + "864c859e084b48b791e4b4ea7e229a7e", + "d7203d7ff9694c4db1f2689bb0926529", + "311175c1155c439cacaa79afbb69d540", + "97e93200e22d459685d117f7bf9f7b9b", + "71e1a37141074168a3ead925e1f1ef19", + "3141ff2727a145baa67b08af0b3ad154", + "aea8ec106c3b42d0b421a799260ee15d", + "fdebdabc9fa24f518d19d1240ccba7a0", + "249401acf6f442f598c8feda6a09407c", + "05b8ddefe0ad45f7b9d42742cd549b11", + "0297ffd148ff48c1b02d32457be0387d", + "a2650310ca8b4e88bd5ea6aca7dd818d", + "bf3bfa7203f740f9b303f8daa3f4de91", + "ea5d7b8656c74af3843a5fcb34c30d21", + "2fd7954d31dc47d7a48f9e0cb8faeeba", + "10d7d72e93fb4fb7ae4a6fea9fb5f6f2", + "e3277743f4f5476ea4725a58ac483ec4", + "7b779e7621e3460896ff271f7747dcb4", + "af7cd2807d9249efb4304a8d7d4c1b51", + "e0f2d244cdd74403a9a1796eb9951981", + "7dceb5e3fa574027b6b8c6ffff8c980c", + "a1925183b0c744f5bbe7261c319327a1", + "bc80abca587f4190bb295743f3be06b0", + "4fccf2dfeb30495d9db383a9667940f3", + "28b7dcb472e5445ab944f1e40b78b36f", + "dd96e8295b5948ada2f5f3a6228de23a", + "2ba3753033dd450197e9c8afa67010ef", + "550f0b8f294c4450a992543df3fbcab0", + "7f9064e13f794110bdb9232f282b64e7", + "3763f243e18f4fd6821b3448974c2c63", + "9406d5ae16084bb5a0aa8b86cd34d33d", + "869232e678ba4f2e89feb9f6d334a663", + "32785e19fc764aec800d837ec7558362", + "163a813d5c4143e5ae033d6ec35c127a", + "d5128e0aafc8464784aff10c03c2d37a", + "d5e58061e1574ead967662f8cc1cb8a4", + "01ae21fd01614dc39f8d1a720a7804dd", + "211e925eaa5c49a2b9216d785413cc2a", + "6cbad24df9af41488e41971c0e8361b0", + "27c1c9d9a10d457dab4c6957d3ae930d", + "305e813b40a04102a608e556aec6b73a", + "863c47c3e6a94d50834d78167a885210", + "603d067ea2094550842bf65ad7c7e279", + "c505ffffc1524865ba63af837346f1f7", + "59de57c4d77a4e89b407db11dc8d3a5d", + "f9d4e81070b64950b7e16fd59d2d7361", + "bd7d5757e25c4f65a6677a72d5ae8bb7", + "799bca85c99042bda1b992819ccca7f9", + "fb67431f304c464fb47904e94c3a3a50", + "4813ef6ab83448eeb6ae03a6e5189317", + "4ae15c384cb1446f86f0e0b3c019b443", + "300a051bd82d49749be1dcf53fb97411", + "d524e590bc2f460d92dfae45d01d27b6", + "b068ee92d8a44f64bbdb10f0327156c6", + "728e03ecd80340f1ac62494b8d59bfb1", + "402ce1471960446893c584bc8fe5cf59", + "9425452149e848c18bcc7045e4c1885b", + "cda1f64d6c3f48248e15db0854e32c4a", + "de23895b6e9b4cfd870e30d14c2150dd", + "602ebe4864484b42a886b520deb69a79", + "84790dcb6e0a4683a800cb305b1437fb", + "06b1d64acaf14d178dd8b6e108a1e9fc", + "0694514962ba4fdfa36c545151675d97", + "f14bd9d3c5364db7bd30c40e15ea1760", + "2b1848f50486464fa10164dc1d8aede8", + "9828ee83e8314b8592cc7dbc0d077ac6", + "37118d566c83457f91df35d0d839613f", + "6c7affca797a4bd29edf63c9120248fe", + "ac7dac3451524fe0ad306d1841a0957a", + "2f4d7d754cc3403bbc7f8c2ed9f3de3b", + "ccc3f77d27f94ae5acc77992b90b146b", + "7c85cab92fe242b5a24fb2d766fc1e12", + "bba458a4a294440b95c7fe486d3a3d45", + "77b54c87bdb0484aaff9207389a1a34f", + "b522897d579b4520be476c586a5f14ab", + "0bbf336a2cb2467bb34608e6b38ef3ff", + "6147f2acab3c44c09e7883869d2c360a", + "017fe235577b4083ab32c2b7949ba022", + "31acda95fdaa4470b2621df3b9832fb7", + "f12b8be631134bbdbbf78abab1f08f86", + "f6e18dbe053d490382e5c46fa9ccac31", + "ae0e8d6823ed421ea263938e32d62617", + "f1a1c79ab153475ba926ef8d1111d59f", + "4cbca52ae7fc4654ae2d71438b7eb3f6", + "212980eff27d4d45abb2d72421a7ed9e", + "198df9a5f33b4ccf866930e05b581a01", + "30870e34a4344ab48ca56f72968c851c", + "6e91e8793ed942fdb6561976a893f4e2", + "1c5c7ffd7a95473dbe6c2d40d5623034", + "56e04573a718472cb7a92e439a005e8a", + "c27b018330da406680e58b94266c310b", + "eebe5055ac2f4fb8a25ef4a2d1ab077d", + "90cfde2775c04ec48f9bafd98131e808", + "e0e9a28ad22743ea85ba2e92e562da1e", + "f049d3b5d81b4a87bb4f9ceec33ee305", + "9fc1cb45c8404517aa8cee3bb47c14fd", + "5353f01d845c4edca00896baa353253c", + "526463de7cc4491c8bc3cd158811ab4e", + "71cc8493bee84ea8b9ade360e13cb565", + "dda2613eb5c04527a325a3b0bce9f79c", + "67503bb546a141c1a2b806a9c7fd9d5c", + "a1d790243227476ca11e3f3a0177584e", + "b523b2a9768e48f7807465990ea558f2", + "d902bf0f85df4a2896b7fdfcc4997de5", + "b16e5e1d884b4ccf9a1e065ac4b06610", + "00124bcf3ca3463fbe05f28218cc0f5c", + "c13555900d7f413bad3caec2086d3874", + "048a7e91bec24ed182671874b7cb6a47", + "5afaf3ae0c6d496e94f9ba733e0042a7", + "4b9c63c0cfd644d988c5712797cb7e2e", + "05a4c8fccea2443f8bc67e4b3152e056", + "b9349e58e44c4858b0dd01e815be94d0", + "a27409573f474f14a97268562b2e0cf1", + "8dd480171b034206a45960af38198cab", + "703809f97d054dbca0d363c55c1c8a84", + "44814788e2ba46e9a9b2e2bf1415bfdf", + "d51e89bfa33646ba8771ddf972dc1af2", + "eadc9424f7ed46d698dba6144ee34325", + "4150c4d220584b3f9f2af68ff5c2075c", + "841101b9ec594552afc2b97383c386fe", + "6ea8da6f8e004c9f8727eeedf8ded510", + "ffcd4919efe047329173e7a8d188be08", + "bafce5277aa84954935da388ac423dda", + "892bf03c6e6b40cb8e811bfe886203a6", + "34ca2a29fcd843d9a4610df37d2c3e9b", + "bace206257854cfa86bdbdc14dffc67e", + "a9c8cb2c961d47b2bea5ecc6b70c7244", + "7bd3f67b7ea2448796d23bf1f493df85", + "e8f3238186914ce5bee41f5518a4b6ff", + "0b76d30d697d4488bd35dee187d95fac", + "bba3a744c7424ca2886d1e8d29cfdcce", + "551d23edef9c4a78b67b6bba9e8f6294", + "d90fa437f67b4211a8231519e4619b2f", + "04abedebc4b7446297a4978df6c02477", + "6984d8d0f77b462ea908a4463c8f4c72", + "90a25e292964467cb2d3d8d4be1db01d", + "d385514c18724887a9eab6adece04a21", + "f7fb6e4589c441a0b25169459e2e2b43", + "dd573d4f219840dcbbe96f5e78478b0b", + "469f716110444a7a8398a3d130745c42", + "1ff94ec73f054bb6b14621b0585e1b8a", + "d1758f279bc54631b079733b6a4e96ab", + "a7fd4ae91eb3421ab802c5b51af3d706", + "e8ecaa36c67641dcac4e809fbc9c40e9", + "65ab98889be840c28be9f07a5f03427c", + "b385666043e243d3993c00b37dcb5645", + "c668b80bc4b34ca691c0d335442f07aa", + "dd5f87e5b8644111b8180515eed4c54e", + "efeb40afeee243d4b02335ee72edbc8c", + "e51e63e374ee4c25ae3fb4a9c74bd335", + "d3871730fd6c475e958d13bdf9a453e5", + "4cf8e68a3a724010bb103536fdbcefb6", + "04eeb41058c64a039ce777800cd22580", + "37d21d24a7594b99b1b1a396ac488201", + "a014bc0996224c0686c1b486c684060a", + "e42d749ba8af4e98a54a82f9e4312510", + "6201d6f1c6d8436789f05ba29d3dfb2c", + "d68c3754e6894447a7ed970038dd4f11", + "6788a348fe2d4403b29c16221d2eaf54", + "c0263f184b484120aef43b611df24ae0", + "60ea557999934e4ca5d513d99d8f8b70", + "37edd5526e474a51a9390c004b6e375d", + "15837138fd4c4932a654bb41ed6db5f1", + "f0689c5184874b709dd5cea91aaef5bd", + "983f87ae52a64cfc9d4c914c2874e911", + "faecb357a28c407c919ae129412fed99", + "19e9f218f8c84af0af0b9ed8e930775e", + "17b5fa0532f54027b2dfedc907f09f01", + "5b0cfada8e74466e891483ac54ccf3ed", + "bc7fa8ca32494fd4913cf5738d1122ef", + "8a965f40434f49fabeb393816fb5d069", + "bd0404ce546047008c6572f10a92e618", + "8b685bbf798947b9ae3d06a2133942fc", + "9e22e84a99e94d3ca290578fbae79f87", + "4049954e376d4fae9e9fac0b6397ab26", + "cfd71d082ff343938350a75e862613a0", + "b5b4f9c5b9224f3782d26746bc163913", + "bcfc180b2ceb431b819f12983dbd2ae9", + "a76bc33b7a40492fad7da0a6e40bcf98", + "537a7926a30049e2b89a22e813a70f94", + "d5de1bd7d24c4d5eb9fd0e55fada7954", + "cedd6d3b07344d889e18ca790d5e51ed", + "6873c50ab55048aebced2fa3684feb8c", + "da037ebf427e48ca8f62321beb464ede", + "03699163596b47d78d5b398d3bc57c25", + "03685bda9cb843d88f550a1f7f393184", + "8c3c6de7a8f548f3a54f8f07423c3096", + "ae427c1386384f3ebf0cf56282fd8049", + "499de4eed6ad4f5f964d091262e4af89", + "8501ae6ab10f43b2af2186d1e049c245", + "d8e0bae407aa40ed9ef4a184fa065a4d", + "edcba6a2767a40f4baf959cf3a30d1f6", + "5deb12a6e9964ae18c93786bef5587d9", + "6c479a2d5dff48ada02804c446561ad4", + "cb680d38bee541a5ab4ef331e323fa2d", + "7f77436d2e9e4f88b265f0a0e7f59142", + "db42f9d00cc941c6815c8d8b2d5a67d0", + "99c3800812b4445d9f14c1555668c784", + "e592bf7afd2b4bdd8ac917923a8d8518", + "cfb12af6bdb6488e8f637b2c7b35c725", + "114cbff289ed48f4bba8d20c5c0a8cb1", + "6f204b258be743ed8fb2171e1e65f6a3", + "ad4e3377729148ec9273173d00cea0df", + "bd93ad5ee72e424c98caa9e04d43ba9d", + "e1ca1313c2734145835ccf8ab269b297", + "fbce240aed1b4e08bd88ebb294301b9f", + "e0b03a1b66604fc2807e75b9f7ad7ead", + "6d5a4e1174dd4f5fa0a9a9076e476b91", + "a73ce725c2bb4893a01d4746c41a0e03", + "a2c7c8b6946c457b8a087b476b66293b", + "fac8c433d11748d180de89fb793bc8ba", + "01560b532c574ffb8fbd74d99fbd369a", + "9b801ab1aae145e5af5c7cdb52b92906", + "9b4f2da8f6c14ce7b8cd323e21df1d66", + "1c26e99596bf4c22ba6a2a8eb23f61fb", + "45d5c17faee745f3889074435bede0b2", + "c7c1c0cbe9594f4d8a7d05ce5aa25472", + "af9706b64738442bb73e9b1419120ba8", + "b3e28c45c71d41918ac94b927327c991", + "4f756b99f9714b1996b9de5b1595905e", + "ec1a69b97035419ca7e97f745e628769", + "76b7b9ca4d2a46d696a4ca257f722fa3", + "7414e62b8ec54cc0994c288a8103a006", + "5c3ac1729dab419f882127ac24078bb9", + "89a72e3ba745463ea626c89f206bac81", + "a4ef32d993734d37a8985c36927d4201", + "4ecdf690559b4222b1f638ad18264ace", + "bec807ae9ae44344ad1b0a1b151add22", + "f8a4d1ba05bc46ccaf32ed6cd7e40ce9", + "86daa7f49cc84063ba2a83620c99e68e", + "8b675aaca37148169d7dbbeb1cf9c526", + "f98221dc2b8848c79988d2e28143d296", + "fc6febe9b92c4da3aac0dd4de7f64e8f", + "bc595f06df9a43d6a8758d260a16eb1c", + "59e74a6ff89d4017bb707840ee9a9d1f", + "ae901246fdae4e9eb488b111f965e9a3", + "4bf732a8ff1a41539b2a37ed3056fc04", + "7b93efdf8a804433ae3e9ef01eca0214", + "18ab7923f9be4239abdc73246389a84e", + "3174d523011d4943ae8f576b3a0f272d", + "d6487b19844843148c87b24b6ed9cb8a", + "98f68a42da074617b881a2225c6040bd", + "912ec0992674468c85ae5bd279bae5df", + "1b0e13ac59d7428b80116e9453109609", + "a22d934510694562804ca9fadb0aa728", + "4e18d3bad0c84603aca3f44aaac2a82b", + "6d9ad814b30a41dfac2236e3939d9f62", + "116baf2d9f3949c482737b08b8e00a75", + "89d85d1bea1c4dd2862f064b4dff1e38", + "d56ad81fea524eb5bbca3af22552486c", + "5dae27d638174114b69a37ec0f40e6f7", + "5ab41b26dd914a459f029cb028ac2b2e", + "60bfdc6a3c884b91ae4f8ebd3f750a88", + "f22b7ccb70f64724843e15cc1b4f2549", + "1cd4eeeb72ab449bb1c835b6bfa85360", + "cab901c8415a425ab276e5bb30cdbaa3", + "e93b1521797f4ec29eda3696cd389b27", + "71e5d069a583437ab6734944f0ca599b", + "80d392ba1acc4d8493c2a0b70fd5831c", + "3d4f2655981e47e1916bba92f0a98f5f", + "d75ce527e1f74cc7b177bea434260b37", + "76b6c4fabeb34b2bbf03e66d38c536f3", + "dedb1824608f420c9803ef8df51a3713", + "dc82b272bf084ec6bffd6b22da948b6b", + "fcda92276f664359abb694ae215d3f4e", + "cdf3b1e6384346708a631dd2c1e86682", + "387e4943cf214dc293fe9f343e74fd74", + "7f526263e0ae48308447f5f82e1df9f8", + "34b001f315fd4565b7299813ec059ef6", + "6da4ed16f6aa4aeda365166e322f9371", + "317a477c66eb457a8a53fa78f981c7d9", + "3800a04a6ece48faaf4e9366385fb14e", + "8c0799fd30ad4b138470957d66b9e091", + "776a455c85454fe6b5d6bf3179894af7", + "bf5df76cfe7e4f2abd7e0ec3d231a9f9", + "7fc9094e39504a5db0584cc31a626e2f", + "9671a89f69e344fd8cd035ec3e96644d", + "b6b2c9281f9b40fcb8e21be458c51678", + "03e6f9553e6b4b59811cadbbc38b046a", + "da1002768b28495c8e027e692df7147f", + "a30a5de53a6748c39cbd2923946b5993", + "1c2018aabfaa42c88877cb2fe4d60c44", + "93576531af4b4a10ba88bdbde9347fd2", + "4869fef39a304c7696bb3683179637f3", + "2c380ac710d04516b5fb83b3a3d14bf0", + "79d20c4af74044ea88bfcd9607f7f3a9", + "b3ff2dc7dbfa416ebd6d7c6382cc21d3", + "f84f9aa625dd4c2c8bc5eb26d2c3f5e2", + "3b1ee117fa1742aeba97f24b1dee75f6", + "02427a2aa7d1446e9bc6b7d727803d39", + "ec6aefdb1c584976b047c95234be7807", + "c6036c95adcc499491d55010d2e51cd3", + "cbc508a5ad424d79b2f2c8a3de7e1cd3", + "0723b35415b0462eb5c01140b6b70340", + "11ac243d6f294da69ef9802e7b51fb8f", + "bb20bbffdcc741b0b1513db659a9110a", + "01ab0842feb1448bb18e8c7b85326d11", + "6adbcc2ecb03458587d72dcbea6b5a51", + "cbf99d910112471491374c352f4f17ae", + "e23bdddd6b1a4659a0134e5efa8ee4eb", + "c6a6636379904d6eaa68083a83c39694", + "9c55dcd4b76f42d8acbec2cbfa634c3c", + "53facdf53bc4451b812bb51c9586cda1", + "866d55094bce45dcaa0a0f667920a968", + "93bbae4519394c2ebd6ce3e279078ffb", + "7faeeb07b170406692befc0065790fa9", + "bbb149454c4646309476beb5f927ddcf", + "95b3227e56204df4a00b37b38f32c5f5", + "628c8f40cdaf49a5838cfa24503d7890", + "1bbe9240cc0044818c861b48cc697d8c", + "9168db000dd042c68865486beb09628f", + "43b07f7b86e94783ab6b4b88c646e57f", + "7fdad1eef0c2410480fd30f159cf7e92", + "a7e04e5aa00e4a338936eb4213b48f47", + "fbfcdb51466045cca7b88a903cf02807", + "64e8d14eb5af43a38b7fc3db7cf83ddf", + "63201d6b321f463fb1a8a459bf4a3c5c", + "c5157b378fdf42808376664a67008b2d", + "a6833aa6f18246eb9961f74806aa8341", + "547287713a9a423b8fc953e047dc963b", + "e782565e1f2349c39bd2e565f440fa17", + "b28b5f5e04614ec4851c998b5ea00d4d", + "bfdb7491cbe04dfd84a1f60bbac3f77e", + "9d5df9df7a24430888f683c9b2f74f81", + "240c5eb7b8314d59874b472fd74b880d", + "edfb316a2c3b4a53bc043dde77ab2e54", + "4058be3d4340463a8cd6fcb40b684488", + "b91d421abd0842bc8568a18ff7af21c0", + "76202fa4a1e942dda2acaa2e91a7e0c6", + "8c70a22a51ad48ffb3702ea60ccacaae", + "ffbcdbd186674294bd3aa0f7f249d45c", + "7f8e8616688649fc9257a8698882ba23", + "b27660310b994b9cb8cdcf11a30dbd60", + "13ce0d9f07d64ee9a9a70fb29f02af82", + "8d6cac74abfc4b408ec86c37661fa5a6", + "d53a41cb68c7420aaaa05f44ca0197b6", + "fb182647a3c447d69944d50e4ccd718e", + "fd2c37154c7348cfb6270ce97c333da8", + "965a7a50975b49069b80c716e9f5ef63", + "c1de9117be694285983b828fde18f539", + "9e0e5fd9d8c149f894c988817ba80a90", + "b8dc719c8aa141f29ffdfa7972df5206", + "45bd43443daa4b65b5511aed74422338", + "884ce43e55b94782b8c79dcf242feb4a", + "f80ce011020645478764f3d19d42abe1", + "a08b616aca57458f844d033c0a4479ad", + "dd4aeab12b4b4c3891156d7662b79cc2", + "fc9ded39af5241b6ab9c85568a597bb3", + "75afd2f8e5ef496ab0d18cd0ad4ad190", + "3bcaeac1fee841ad876ca71bf21aba0f", + "7f791ca21f494f548e9d6657d6c6507c", + "06d7778fd405446495f54acadf339f7f", + "abb8d6205e5740918422e5bed03626af", + "52bde7061ab94d8ea04e9f7c3141d433", + "8d4c11e02af342d4b4e309fa1f603949", + "0cc0d3f8406c4e12affef6e36b29d41a", + "df94fc680c404ffeb0a7b864958600a5", + "540c6d3ae07f4e7bbd5a87bbf760d354", + "047c214241fa48ce80c955cdf66e9b97", + "33d7aecfa8504b52b4740e684eb0eaca", + "8e7656d37d614fbfbd571ffe5ec1c4e3", + "9cccc2bdaeae48839e93691df30be3dd", + "7617bf448dc44e88af45e6b268745659", + "9ef08d88f2ae48298659d1076ef662bf", + "4e6bffb899694a77a7b8be5014f8ff55", + "66ab8d583ca24a0fa20f6096f66396b9", + "23a67fecb3ff4592a3b5d9d6b7344b10", + "81a6758d93024a2d9fd31f804a4b395c", + "a5aaf14066284b9a97a0990a7e5bf626", + "40e754e143eb42188d50630e7f16641a", + "ff6f1b6bc0214ace8739a7164c80d55f", + "78996f6b47924e868903c0e74b1acb88", + "9c91238e7d1748cba41f4d28777c7c3d", + "85ac9595228b4224b687f927a6c8981a", + "7e4a0ec60e5748edbf104ed8a51b4e2a", + "afa71ac1656b49189596c5205e5ea136", + "e6f29ef59e19450cbefc89c428bd9df4", + "52d34bb682c84bae855442833dc67abb", + "49fbdf2b8ba84facac8f9d3af6c26926", + "9069c49852c44a569f1dbfe143263007", + "fb62c1b7e5b24ab894be4f4da0c1ec34", + "8046983dbc5047d09c68ecd0d63a7015", + "9887e6b0bf8e4edabbc3ed9e24aae2c1", + "ff1f517e6b874e58a66d75dd1e990cfd", + "db1a7abdb9b24601980c243fafba5632", + "b69b2ba04d1b45719c0daba6ef14a6b6", + "712dfa3d9bb24d55bf5daa02929473db", + "0a78519ad00842e2a004385021aca64a", + "af10d726008d4c9aa016ff66f59e466f", + "b1a2e6023574419690b60e9616572564", + "7651dee7414e4b849c516427347d8452", + "3d5c1694eeee4c4a87349fbe63acad30", + "3RMPys8NIF4D955sDUD61IgcpYf", + "8003aa8ce7fb4019beb09194daa87400", + "02572a5016e3417ab2bed128d633ec4b", + "25a361dbe2e84b639d95d6fccaa9de6b", + "0ee443fd9cf041e08b708b338be5ffe2", + "43cb720ba27b4e149d86576cac666949", + "a4b4c90dbbab4b09ac42aa2f4ebbc860", + "eaf171fc039b4cc7aff2af5cd9355b82", + "fb4e924c5b7f4eb9a72762381f6076b5", + "dbee0880107449a8b5c525ada16315af", + "e4111831d16b450a86980918f93cdc7e", + "d2190b455c064dffaf3c8c72e10b982c", + "5fdd2647427b4543bd299acff008bc3f", + "5fbb7784bc0f4775bcf2bf8ae2b47c42", + "1d2852d08e3d43b6af5f75ee37921bfb", + "2d95746c71724633baf24d8066ecf8db", + "c7922841eef14f2b9531d1732628f68a", + "d016234ed97247f6ae916bc386999d03", + "9b1694d3bab34687b0b269fe0b776c92", + "d0c0522e9a6d4684a2744b06143bf9a5", + "e231ff874a03451e9194535912b5a0b0", + "6e444505ffb448e7bc23728ef5db5b97", + "40b360660ef34612a738bd6b7374b278", + "c4469abf45a247e98632f17fd2a2ab07", + "c283c87ee2164dd7a7e1bfb1c29898d4", + "ab83bfcbd82c4c5ab1e50f1db943b6f2", + "9afd267790164fa8ae4ea76d4b2036dd", + "3c2e193d2cfc4af7bffb11292792dba0", + "1a297736f32a442ba7be16776080ada2", + "5c2d2c485ca647339651c995070564f5", + "252ccf2de4c64e52ad72672c50bf7131", + "75b58a3f353f46f993d7493b279520c5", + "1076241113e94d5cae8325494e73da13", + "ac0081c460ec4b5a8310ef3c1b4ebac4", + "8406aeb84f5043958f3b3bd2697f1e2a", + "97c7b3d0147e4ccbaedf571c11fb735a", + "091cd1458a23457383191b9868c13ea4", + "fb0ec1ac57f74e92b450ca3bc10e0595", + "9b27119fda9c4c128d8abbb057c60550", + "0b701ac315774db2803c8ea31f6d9122", + "cc00b5addb584d15ac27379b6e5d76c0", + "4e2cacec1fce40ac9326918fe7214e23", + "8cf17ef7137e4aa4b34e5aa320645b8a", + "b8dd7b4730bb4d97b817ae136abefb0e", + "655e2fc7edaa4c12a9db785a241aacba", + "3fe38f30a84846ed8ab4e4e6cb320fda", + "f323dc9f6b804e8c9b6bfa9f781e4241", + "e9cda9a048e64f9886a7d71d90f466b6", + "afaa0d29b2b54dc3b7f97b353e6313fd", + "d37f2ff2083b4c0e86d9ce86627de1c4", + "9c8e4142e27e42b68c6adf823ddc0068", + "6edaa7e4dcbd49159a00bbddf2c509a5", + "0e21faea18a1471796f67de902818b8e", + "26ddd2c0c3484510bd5b6c4ca7a4bed0", + "8a319e3afee14f7ca1c9d625ad8345c2", + "51758621df8649f5990736c6ed3ebf46", + "cf76654347ab45a883d8906f1bd15c50", + "d342da714c19496391c651a663fa1927", + "d4bb619384164354969b6c1a381e7099", + "38e0c30e50ec4e15b88a60e4dcec9107", + "41a7761ba5f14f20904d90bb042fd5a1", + "09fe53d095e84e918f32ea206c9eb166", + "bf7bc1cfa4ca41bbb1b06b8aabc31352", + "3310a2a775d948cfb497eb4a930bc6ab", + "8b1d438414814fada8a82301d341bed3", + "a9bdb32efffa4f7cb7f98d4f7a877b5d", + "050649b4b5e642f0a8554b29cf22033b", + "6795956e393c43218de920b594c9e185", + "a5706ca3647a4513b86662787cb9efda", + "35398d85e5914f2f844a08a97b1d37d2", + "ff4adac17905436c9f244e432e1200a8", + "65239475ac9f400293b9f2cff7cc7cee", + "f2536b8f11b84cf3bc3c5f72cd887aba", + "8a44db6687db4e44882171d367659bb9", + "3a12c6619d0c4077a88dbb93c7a1f0fd", + "0e4cd5dff04143dda558b7b52d61f616", + "5998532604314fac865d68bf570c75e7", + "a9d71a86a8344606be0e512669b4acc5", + "8f741b9b5c7846818a1cc193be7722e7", + "427c72ed0f034229bb1795faade5eb5d", + "e82ccc11cc1d423385f84ccfedb79652", + "bb04007e9e3c464dae3a638cbb3fa00b", + "9ad720ea35384bbf9c9d6227565a92da", + "5d7cb3916c074068aa8b69e8225583bf", + "2254d3c911d74f9a9c5386e683c6ef85", + "b1133daef8eb4bccac700a17725f2c09", + "1b56d27bd90b4cfe9a70151078aad632", + "46995ee687d2475bb3194137403ca73c", + "52f9daa141994477b68087bf6a84b823", + "ba8e833a0fd8401cbe1f6de434feb925", + "a21e28fa4fd84438a542539d61be5bc7", + "56e2e01977df4650b75e0926ff235d34", + "185dbc3b7f5d42f8b74143860d18f3ab", + "30db76f464f842c1ba88edae466b6bf3", + "38404e2077ca4b209cd2f1db30541b94", + "4fe520e0583b45f4a4cd3cdb594970ea", + "67c883e04b5045fa80fab2add99a65fb", + "7b48ce1b7cba44bab337de2701f32296", + "b41c2e0f97e441cc85bf4c487689c022", + "01fb2f80dad74a2280a4c077d871b262", + "56f3fb6b0eee4bbdb68babf0bf4e90b4", + "b98c300a058645f9809ff6b50be80859", + "2a9c2b23a4124fc29f62bb1ae2e522f6", + "3a66d71eca3b44b5a004c5bd3e7d9073", + "2ca835385dc6423db40a2e308cec5b48", + "075f4e0645d84bcd9b661750b253310b", + "2cc16e027a9748faabe30d58da46778a", + "1409ae132e574092bafa8d19c3a054d2", + "bc2c7bdad9fb49d989ef6cc88d47ef07", + "2cd197434b5340e0a322a0893b9b08b7", + "d84b623ca339443ca622b1a414ae36ab", + "153b7bfc1aba4d41a1bce3bce2b8987a", + "365a20bd34c441f19a94a36706b4f253", + "326f5f8312c04ee8bc9e3e14e28b6e0c", + "0ad7aecfcb874fceaa38a98436991c03", + "e3dd13f1ff3f4fd29aaee664093a7436", + "ccac815b71d347c18e33201ef5bde3d8", + "95719378a4dd49cebe0fbb45713b33f0", + "7820d3725ec94b759c633eefcc30aeea", + "b8309b5acd1d4530ba07c68fab826adc", + "f530c5f5dfb543ceaf0d15493fbede41", + "584bce2744494427bd38b9c2a253ee0e", + "8d041195963541c386f27426964a05d2", + "770f0e2de45c421bab6edb6b8af89775", + "c363504df73f4120a81b02c530b477e1", + "fd50f489c15048e0b2548e06bb4df607", + "73a0b42692ea483a8bd9a18097753bad", + "577e3ba257a147bb8f06d1a5ad81d627", + "094c7fa16e9e4f01b997a6d1328422a9", + "bdfe585e3cb84b4a9f94d8247e7bc1e1", + "21b5220775af4bb6bad570d6d19a00c7", + "6e890bcf15fb4c889de6ac1773327978", + "ca1af864b3f3452b9177b2e2759f439a", + "c40bca9926264486be17efa258625b77", + "3b036e3cdaa149509d79457c0aeeb861", + "fea2059900234ffeb470c6235215efcc", + "22d472d1a9b84c8aa4bd752fea81502b", + "94c23435f0444d2f9a315df2a1665f47", + "19b60335538b4377b57537884341ebb0", + "8d17cb0964334a6cbe4b0e293c238956", + "e5449c37bb284598b6c838106f925c0c", + "2e11ed69dd064236aca7e18412ab89db", + "aa66b7d99fac45cb8790d22ecc124392", + "7352393b15e742518d4c1df28fffee3b", + "4183c8164e7c4336a44899feb51aaeaa", + "a8a587aa0f6d4f889f1d4adf878ccbb0", + "b08a7135cad84e0ca222a8cff075109b", + "2c603cab67f447d1b8ec8c9f45a30f36", + "a5f1843f7deb4efa9a273aa37cffd70c", + "51a935aad8404d24a41ed97da89d4575", + "e9c34a38d5a04ea7923a6577720b5194", + "7edd4e53fc174cd292b1ba8a6fb1e871", + "5c3393b4aff7401794bcb3cdb58894c3", + "164dec837ac040e0880169e0fe952a3d", + "27c901f716ce4c089c6223624dea058b", + "b87269381a95411a9742c227cc20c37d", + "d37492b382b34bfe8189846161e2a45c", + "eeed915e737b49f4b70a82921c2726b4", + "c8e1cac8152f447aab410fd11ff2d480", + "178f22467bae4c729bdcc15dbc7e445d", + "76677d5ac8af46a78f4db494a84ba280", + "678ed83880ba4aa3b16873f9aa118d8f", + "a2f2aef33fb942cc9d72d13df8a8b09f", + "f0cdb70413b7452baa1648aab5ae1dad", + "06ab2df0a94d4303a97ced64fa019e1f", + "985876d9d0694c2cbb5a4d5aafa14619", + "2af18abc78544b63a3f913ada2c44042", + "11a643d5679d47688464e49ec8c272a9", + "9d53c4f8a4394a9ca333da20138cd897", + "12b3ce23f32a4aa99cd5ba07330bf086", + "f6885a46a1194d43a70b0d874a87f577", + "4dd67b2cea5143e7b56450629f8cb120", + "e3e832dd142d4bfe8ef18d33dd797129", + "d8df49f051224c1880d061bca05f7ff4", + "d2698380da5a44ca858c7e7ac7dfac85", + "90411993876047408915de93e8bb65b6", + "8ee11b69300c4dada30557d29ae52e35", + "8256f0bcd50242368acbe6fd619f792f", + "ab92f0224e5749219ee1f09fc47b16b3", + "51f9fe949a3449d9b8c56758545155a9", + "fc76a8d1bafb4047bcc6aa16869445b8", + "c9351c81ccd142b399148305d67ac6d7", + "086642d0cbb247878004a7599be11350", + "e028200c278246399b15e7825f750a9c", + "6319d951306943959b1ec1c233a0ed21", + "84e8ae957f7d4e01a1afaf627b1c0ddc", + "f41fb97922f24cda96585b371f5312d8", + "4b8c7e8412fb409285528e79b70d1891", + "ac2416e85233443bbf0a9d43c4bff9ae", + "8b491093657e4281865beb3c3fd6fbbf", + "b65f31df07a74e41b6ad969623c09d21", + "8cd34fb8568d44d7a0940b51afde5957", + "6582e7b59c864701a3e2489b83250b2c", + "033e55f0466b4f8eb268afbbc264fb28", + "1a3a1f8930364b828d6ce53d911f7f24", + "9c33c6ab2a1c4e1a88e3a4367d385d5b", + "b9f17c40d1074b79952b86e502f8d392", + "310c51f6c6f7444994118c084b3b975f", + "90b34933a3b94c98ac5467dd4b55e5ba", + "a1c0226a38bb4daeb437398869623880", + "3b50fb746d834312bce22c9fe3472726", + "3ebfe45ff70a4356aa8381578cd0091c", + "8a3fb1f7fe9a483aa96b6f7b0969b7a4", + "cf3e112a4441414db938f3020ec8514f", + "862e46fae7604c6eb29f31544bc57c82", + "c3185a2e6f714b07bccc427f4babbfed", + "585855de381a44ba9860c3d3887b2f8b", + "ee48799fc98a45139d2e258537a9e1a4", + "5b910bad6f634f32b2536ed2b4a23649", + "a01b4bc9441a441aa2d812eecd2de234", + "15e5018352244d24b59f4ad11a19caf1", + "920fe660515d44a8947aae62dc34071d", + "5020b2952c324bb383267a94e120577a", + "e0bf61f270194b86b3ae09b638666865", + "9c960f3c686b4a53b9a304895d278f60", + "d16cd4c9fbea42e489fe7a5753513984", + "192e60a0614d499bbca91c05e297470b", + "914fa349f4b94c9691851d727b753967", + "e5958640008141daa2425d1fe70e1fc3", + "1ef49560568b459a832a2f11262d5fc9", + "18d0e36387d94708aab28889424db3e4", + "00e69c6b408a436db66c73c0f3b25e82", + "c5a8d10c43ec4e548a14e4492192071d", + "f9c78b235f9249a4b9336880750b5b3c", + "2df1b91b08d24a44921b9bb01692af73", + "6017b947ac0e4d82897d854f24358c09", + "b926906c98f9488caa679acf970e7238", + "0eb4710c61f14db7898a635d00958359", + "dafd425a53c84d8f98c0ae69c5649083", + "c48dff7e9c5848fa94cf2a02528ede08", + "4c844f3644d84632b38ef3a574074661", + "d97b0ec2bdfb4006bc4904cd7147482b", + "996c8d78905f433183ac368086580f82", + "ca85009e578547c0a4f0872a0b3363c2", + "c10898271f754c039231d97e9849f6f3", + "5efb7a6940894b5a835b4de2f3cf1559", + "21718f0b7fdf497fb092b7d095429487", + "c5ea812863d746fbab921844294b888a", + "b1e76c446237418886263437d63f7947", + "c47ccbe5107d4d8f92b3caaf93f3d9cc", + "f8b95316c2124d1785cdd8da5685f44b", + "fd1a9e2e5400478991740bda7bca1943", + "1e7183ccb6e44b59b8bfd9c907f2d08b", + "0488173f742e4ec08c53660cf4f87855", + "96a3fc052dc94c07b52109d71032fc89", + "88e5af78c0c2466cabe0e20c05bf7535", + "99ec19c24a684fe5b09615fb266248d2", + "7e887e5b58214c1ba618a154b6b0de46", + "38135087cae94516a7a2d48fc8904624", + "2250094cd7bf484d9443ed0c5a97483a", + "eec133d3b1634a4b94a294671cf7879f", + "9a11723f3e0446c2870187cb7e5a9328", + "f311652113bd4acfbbca1da9a1806a4a", + "9e82d5dcfcb84c4a939f46d479a91121", + "00e90648c8b94d0b9ea8a92858bd8e73", + "c532c913264741a1a6908d13a600895d", + "557cac7bf8cc4208a25777cb4acd0687", + "64b359e2bc9b44908b00c4c7d011cc88", + "1ad06881913646eb89114bcb4e1ae739", + "6fb5032d4c0f45c3b767c1a8d694ec70", + "9f5857d71d5d45598c171ab2c92cd467", + "308934a5d45345168ecefbb1d2783815", + "4a8dc4ec9dfe45f692c48d67798b77cc", + "ca1a9fbea14d4ab49183ebe2c5ad7f46", + "8dc1bdb356e4432f845d01e4dc690d14", + "587ea518b63f4047810042557cd99cee", + "af0ef2bfddb54c37b7c3e6a6967ac05c", + "7131527acb30419fba801ae4a552f21b", + "59309f1dd9f54927b0d232a1e9de5ae2", + "d18a570e0a214f0ab83c19f40926e2d3", + "040f40e20e9344f5bd368e4db3d3b2ac", + "f467e2d7a183468895aeecfae3fd4f54", + "72ab50fda36642169b03a1a16879d939", + "74cbb7e756584e219dd22c02d0f46201", + "16a4e4f583c94fb480eeeac033fef336", + "fce19791b3dc4cb0971a8441191283a3", + "4d7414c670fc4818868efd717c8556c0", + "f2439449622847df8450ad52e6c4f21b", + "faaf2b38d0f747ba904d8f37319b1a9c", + "87fece5d85a24e3383b2b13b502b141c", + "bf8cb2f9a32c4078a35d7328105ee0ca", + "f60cf12d53aa4fd19ebfdb53c8745f17", + "9d79433fc0994a07a185e5ba1c7dbcdb", + "5809e2f68ee74095842caa9035e38ead", + "b8784396e5f6424e88b036949164a473", + "f4458cc88f024acda4d5db288df37231", + "4a2f69beac63461d9010e3b8f2b262bc", + "c0212e29e3c748a5b499dc2d72f2cd84", + "278fc1e0516c401eba358d3aa2e55635", + "c4809405c7f54c85aa3ed910a8f8b33d", + "dc09459f51a74c1a942a1c8954fa3376", + "5deb007a05a946d28ce6403616f9629b", + "4891d518da8545d8ba04dd657e64522a", + "011c1d13de134d14a62d7b4af85dc810", + "8a1b90bd57634836bb4507a09f9e626f", + "4c215af6078846d4b8f441451743596e", + "acb7b36f067f486c9c288d7c6eb6c917", + "8d1e2ad7ad934951829cd77c82c1f5c5", + "6f6237d16821480e815f27bd97879618", + "da73f4b00c704d5eb44eb243e1593dc8", + "5666713f0192473884e46a633de14e38", + "1da3ef13f25e4ca9a75be48692da3787", + "87ac2dbdaeb24e0abe8f80c7c2d5ab5b", + "09bdd9d188e9405b88bbafdbbffbd93d", + "4fd0d543685047cd9c4cff156691a02c", + "a95b5e1807614532994845fb3d18e953", + "b7a0536506794bc98449419d41182e48", + "4e2537850c5b4d0690077480ae71694a", + "4ba40fde7b9b416e93d6680111130201", + "03c7e304bb6a460cba292e2c522b4d8d", + "ca14b71b328a4ba68d1f546c0b7dd11d", + "acc082e181914489a1957a42519a06be", + "bce1de4afabc43a69ebcfea96f45c62f", + "b6d93d36698d42acb08131f71ace7ff8", + "4ecb4b2226e24233b1806925897b66e1", + "df702c25881e4e31a431bce54b197f0f", + "5b2f22c1c2974ff989170cc4a2a5df37", + "a1fd7ffba5624500b7d7808a38f0312e", + "badaf3739deb498ca2c1e009d110efb2", + "50238366b2bb4d5c9b0f2e51000967b3", + "b2d8136c58df4f1085eadda5e9e8632a", + "599504c198dd4f9295557ec09848b402", + "43e2865757e74fbba4de6cf05eed6a37", + "6c77086d062543ea8a476d306254702a", + "4c351a39e0a54d6aa8746a1d9803b652", + "acf88310b7a044549ef91304d0014523", + "e074099f0ce948acb1c7b875fec45edf", + "aa4deab1d68245eaa7cf6b89373f68af", + "42d928695a0047ca905c7c54437a2048", + "8be6f79dd6704fc4a04cdfad08a2bb9e", + "107a277217ca4af2b5f50d32fdf474d0", + "197c1b8193ab40f38d168fcfb91ca304", + "a823097ee71f40faa673fedcf60af325", + "e67480fccdef480db204164c64f38b7e", + "c91963f582ad4c1196850ce7edbde055", + "592c5314203e4768af6e804b90089fec", + "512ab078829648bd9019da7d7ab3e0c7", + "bf9c9182d5154809ab05105f7c2469f2", + "320c8e35fba74463a8d69c0221451194", + "10d9ec53b8a140c7a7785ff54a7ecc22", + "77cb5742e49f4fe18963b1052de1027e", + "748254fce5d34002a4c153811d2e5f3d", + "cfa7c84140294a85a10db653c89100ad", + "52a97ce0d0c041de90180fd3257ea339", + "9bc25c38fca04ea49295da65fb2a0597", + "28e1b9e9950446f9abaea86f1975be3d", + "92d65d6c85e34cb9895fbdb85d81038f", + "e8af1f52ea6d407397e901df40e0a72a", + "092c1fec054a4c1aa5c44206778ff1b8", + "a8905818936541e38a9aa38f0eacbf0d", + "06b9717395af405abf17c56f6a40df17", + "02f8752150cc4f419ca4359cf0f04bc5", + "c4a85fc7317f45949da909f983efcde1", + "0d7cbcc6f6bc45eba998ebf86250b705", + "1d7e68b133c64d08811af3c8bb1193a1", + "99ed8d6c46c343729e63a0a581599add", + "a906c3a72029477885e27e0df6ee611d", + "7bf3ca44302d4859b49e984b037fe6dd", + "40c680856cd4470688140cc8bb606fd8", + "b4449d86e361479194c0b11e5b88a8a7", + "efbade7eb1e34e84a47001beff0d09f1", + "9057e49289d742eb9663edea9aadf3e8", + "2be3740c17a54af2ace945e1d265f358", + "f2f9e9619c944f7a99b19a218b7c702a", + "abbf0e6901484c05a68d2c6c485bdd9e", + "ab882baa73e64bc3b51dba5ca0742c41", + "c1b42855c6f64ecaa0de4822e727ccbe", + "dd0366e99d9543aeb1d45d3297a99230", + "844eaa33ff4b433fb91c62fef4f406cf", + "fa03c53592e44b6ab5297609de0f1888", + "dd7cc49db6d24c4ea8f82c3dd93310f7", + "8d6cf9bf4a784c0b91148ba6a993e2f3", + "8416d4ef3ac84feaa5db13694e857367", + "5e48bf9bf16745969a58c3a36f8b1c55", + "196caf120c9a49159ad1b877c8d595cd", + "ee849bc1b93f42038441ab541ee49021", + "834215e3107b46ca957eb299197722f9", + "41f0bbfbb0e34b9e853239a6d2d16716", + "cd2a4b5fdf9b4b5b83de34c24cec1f56", + "775c3753c84f49dbb685d0823eb5e5fb", + "531ee3cbbfbb4f7f9eae6ef5e8f2481d", + "a6153596a5f340bcb11abf909015cce2", + "38139f9121a54a7780fea927ee62f4ed", + "c85a49c58d414d2e9b12a51a7ab2f4e5", + "78628031adc3427e8be0ed017b843805", + "b823d45ecb19488d94008eb85e562753", + "40e3a8b7703842ab8fffffede816051f", + "85061b53386940b8abe130f1a7b03379", + "4a4bbec3d17b4015940209c10cdb678b", + "3880b4452571405e85565cb070d2fda3", + "035de419597d463880e8e5c52ff698a4", + "dd6e6caa8c104555a72a527e331db55d", + "38245d197f67465a859d17289580f847", + "bc9bbf1038e44b00b17ca7b5a59e6b5b", + "be74f0c2051c4c75b15247063e38a75e", + "cc9f42ab0a4b4543935908ff387cc06a", + "8f5a6278b0db478d83b1499832474208", + "e57f718a0ba34f3da07e83e1930a7c94", + "1ca90c233cfd4fa0bd52077b37efde97", + "139f5a778ee8447ba426bef981415619", + "5ecafce34997415499d49205141f1efe", + "d5f09b60f26f4d4680a001d0f8d73f06", + "c10d42bd12b2497ba5ced33dd50e3f1a", + "163f354a5ccc4cc4a6483cde7116791f", + "b3bae3c8b69c43d9892f356009019fd9", + "208757bc048249ad9b8a95743ede9b7b", + "0023b3edbc114be188ca9d8f729dfaaf", + "5ea18ce9e35148d186321bfdcb87fab5", + "430666d7e43948e1b31b294c736754fa", + "5d52d61b68a049519983f1e63471153d", + "af2fc0343d1d4588ba1e9cb29c92d16d", + "28997628a17744b5a00f898d7e029146", + "bc4b85625dd045608b498c41f8b5c1a7", + "f166028c67d840249cbdc0f6b4bf400d", + "ca50a464389b4ea8aa4c748bd43ec480", + "8eed6f4763ea4f0b9acd02e066e6c277", + "1e1b0163430b4d788151de1dbc45ec94", + "90961c1661ff454a8461e334ca18dc3f", + "0b1f06fc092c473094d2b4239839bd44", + "a038cd89cbcb443c832604a419fb67c4", + "9863ce9aa4c449758a304a92dbb03d6f", + "8b20be2b70fd427c89912a86858cd814", + "70cdd83b6330428cb51b92a4aa775019", + "346d0b5a95c94c2890dbff3b38984719", + "28ca591b0f1944c9af069e275e229669", + "70db1c37b96c4c50811b68a446c0de01", + "d8886310cfc74b7c9ed0293b7a460d55", + "13c7537d145b4d869e6bfab717aabc85", + "a243b78d6e454bbc81e9aae27f9e783d", + "16490ee439a54008afeeefcf53d8d051", + "806607b62e6a474fa3d72495a6e1f6ea", + "8192bb082e2547688f1ca4a30786060d", + "a23116cf46b048f593b4ae39f00d8304", + "b1bd4a382af347d1bc102bf731296331", + "b959e72cb7db41fb9ca7428e635d95ff", + "f93be18847144f1fbd87930d2070cb71", + "bc38c6e6d42540eba147d01fa5efccaf", + "342ec63a644c4d13a80086457881fb7c", + "4e8a3fbe5a9c44cda5830c391ca060c2", + "eb320910987847f0b361c8c1936d9574", + "b55af02fd11f49689a29d0a49597eaf6", + "7f74cf149f434c378816bbc17084323e", + "0776c1e9a7994a41a711d9e0741f5fbf", + "4d8e4c10086f4ad79f4a04f5fafa3e81", + "ab74bd46a3964519a432db4df8c3f22f", + "692d4d1536f647acb6c7f652a99ecca7", + "2d2b48e921b74905a027366578bc235a", + "9e6f5c57972346cfa5a83e81ef9d0845", + "3386cee12f9e427a8b8e6a383083ead4", + "9d1363775641452f9a7aed7ef86edc42", + "cf1c9dcafe0846329c10dc26a0182145", + "03180c852f0e4586839a2888e81c503f", + "6dcce9b7229e4383917ee9161a7ee1ee", + "67c5b266ea5f4db5850e3ec1a063e078", + "e4c593fcba3b47549ffd0eba2f17ff91", + "f732a033baa9417e88996e814fb1a22e", + "0bf5a09fd6124ec4beb39830839b2c63", + "4bb02868441d447187e27a60acfbc896", + "a513db1618494271888f6cd46d24f768", + "922cb0e832ea46748761c0f4033b33ad", + "0e8bae18369349a69017bdc2d7c26c59", + "34a68944284c4f2fa869c4a080514974", + "0c2491f4e91b48ec9b071e981df82340", + "5f906f1ccbde4b399b2f4dbfc497c34f", + "84b0711e13fc49c097312db5957d6c21", + "3b5adc5be8c4436eb913063c7e3f5c67", + "d1df23e7231340209bd045c1feae033e", + "a07501cd7f6c40fc9cf4cf438e41bac1", + "3dd8ef697a48422f860110674bce010b", + "fabb3a16609b49789c016f9e171785be", + "ad20cfd2517f4436b99503bd5e93faed", + "813d77c898504d7cb249b0cafea2a1e3", + "c4b9e709f6954acd9ea605f4a2a909ff", + "cdb717c843c64685acc4ae712f028864", + "e87312ee783d4f0d96f6dedfaf73477d", + "1a8537532c34412182652cbd392d9d0a", + "66bab1f5802f44238d47d3671f1c3555", + "39c1c24d0e164585ae9d523b20c71e50", + "e6cf4080c85747689483b78f88c0cd7d", + "bccaad9c6cef4e91a7bbf71666e45745", + "e318739f0145460b936ac453fc3b8803", + "550f5e6a96b945d893d6801876c9a6af", + "7fbb93d3aa7f486aa24a6b1ac3aa1818", + "7a46c16e3fd1464ab598f6d6a5d17230", + "f5e46e4b55a24cc79630b7837ee95f8f", + "3ef5480af39e49e0a87c3cf4eeb35dd2", + "bd0176444b9043ccbcf82e9e27346c78", + "e83d83f26c244266b681340a1620f56c", + "d5aa894255e74340816c5ba47a28d6e4", + "81853c50dd2243efa5b9eba0831b6d1f", + "6869e7b449cf4196a03a22ef84d87bed", + "f323fedacf9b4b15be6987ea02b41740", + "b865e7c40f7848789a148b1df097ed8b", + "62d3c0a24a3844ff81c4a3999616e19e", + "0d8b0c9d303e4a19a3c2995144f2c8af", + "b14f85722da84d969a103647af0f7422", + "1de9ac4b1a4e46279c271747becbf0eb", + "b488ae2632e54a15824515fa988d608f", + "f01a91e9773e4622b25c4d27903e85c6", + "67de2ca8f5ce49188476f95683138100", + "78ef2c18ed954e1f95e3342d5422fbee", + "3beebdeccab244658cf924b31d3f8c5f", + "a2223bdfca5147e0aede7b97c731b2fa", + "f68105e64cc142b59b4a701d4315d03b", + "b488d632a4804cd783e9ef009976bcd4", + "f1208cb6595642629c5f99627fce27cd", + "fd6ad281b6944d90b26adb78f1f37989", + "12574793d7cd49f59f075d8ada1381a9", + "08ec2ff5d829436c955f4b5e8e0e47a7", + "e50d668ae2eb42a4908473953a2f72f0", + "fdca58cddf0c4987adadf1863ebfcba6", + "13b2d318a1be4501976ac221f553315a", + "ddd91e3c9bb7493aa890ba9383bd72ae", + "6059089fe7ce45f398c7cbc8a1aae2d0", + "e3436f6df584408597aedecb7c06628c", + "00d943882e9d4a54a1bcadfc16358fa5", + "463023dd24d14b68b368aecb221425c4", + "b9dbae7ef66241e8b1afbf00af34de4a", + "54dd81cb2bd04bda97d96eaf31b7d7fe", + "990cd7959ccd47688c9652936d13171c", + "b8ef7ff0581648abbc4447fb5f86dcea", + "d99caf8f3d5140ec98c30cf1f5b7562d", + "01c9013483b6427fbc2f478e5e328810", + "93f48ed116e44dc8b1dc4801bbd3a3eb", + "063c97c804004197af8c6ebeb422f115", + "e0005517225845269ba96f394e945453", + "9e462908f2c44fc887249b2d53ed2bfd", + "3ae5918836e44c6a8825fbfeb61af398", + "4859d8480ec74b6eacc1722838541c16", + "88d2ef7eab8945eb8f6ecf6a876e0051", + "89ab416f35cf40da952c634ac955b300", + "01a0487f34fd4c6598159d2c55259dca", + "2f23dc3f378a4ba3a19dfa5cf955d3eb", + "7da4293f47504141b6941b4721edea17", + "f15fdf877b904446bbf002344bc20b51", + "3800ebe7b5c446d0bd576547e1013984", + "1d1d7509952743e9b83456c3437d6fae", + "6263c454897f4515a7eec31b958575d8", + "11668a48e2994d99812a8c1b9aebb3e7", + "f507a422e9344e76934c5fbf06eb81d7", + "2ad0b6946a8844258e526cdda23822ec", + "7e8ae4ada87f4bf498e1979a1231cf90", + "500f64e26b2b4cd09fde22c4f8b4b91b", + "b8d0e5ec21fe4650a723628600219142", + "6791ee07d4c94df3a94fd89938a2dfe9", + "8a4fa265227e46489bca9739d71e8542", + "cf07229b97f24177a2fcec950596c239", + "6477f6b7cf2d4c8fac2162ed69828ab6", + "f24b0ed98e8e46f3a8441ebcb6f055f6", + "f1cbec14e9794a6fa0e460018b11401e", + "46fd3ab9a51442d2b0bf0f86dfab97de", + "d5880c5272294a908cd65431840b69d5", + "5c4c4769394349d3a5d320ed46cc7db1", + "96c759d658d34c86990411ae22f2be27", + "9323c2c366724041a3e7c1d90d6f96e2", + "75c722d279594dc08c35fd5b2c879d60", + "766453309b0b4486ab55a596c821c050", + "9e8c217cadd643c0b7d9fb8370317d68", + "464674e86cde4284bc2314ee87bd33fd", + "4d1b5d90372641778c4eee6cf0d88a57", + "6f6764b2d75244c088f89ea7640d75d9", + "94a91248c6de47d8a85f60fa8111c859", + "d6a91e8dc386494b98ce97c6d3323921", + "f978801ccaf64a09bc7bd74cbbf03e9c", + "ea2768fdcc464b509e13e5b4b9009237", + "891942728c3143858f93071aa29b25d3", + "ef846ad93d734f7cbc4e55aeb81c0b81", + "7e3149918f7f4b82ad9660ca97564648", + "363887953a734322955e2f8279e09204", + "61ccd32e664b47e8a9021ad56d4635a2", + "1e7143dfafd04ff4891efcb06949a0b4", + "aa6e9c363fed4fc393d56defb52006ec", + "b52fdceb5c4d4b94a78306ff13ab9872", + "ce6f76fe62b7460b8dfd2f10e35cfef0", + "99b66dd4a20e4015add4c3157b2dcc17", + "14034702a8b54ca4ade8eabf0219d8ec", + "77c72e749da24942b34cc2d2959d66bf", + "7e5ad154d91d45039205b219587bc29e", + "72452bff819d4dd9a47dd7791b00d6b9", + "62d01cabbc3c43d2ae987925f283c992", + "c4d4a6d9597b46ffb38dd6bbb8644b8c", + "9ffab4b2b1c149469dd6e0664cffbb6b", + "78454c7b6c0244f6a1c8f7f708142176", + "6f2419658bed4ad98319068fe581ab36", + "72d7bf4ded6a49da860a840ea38d9fb6", + "54caa18b2c9b4cb0a65eee107f8169d3", + "5296065cb6d942ad9eb79f4f44cb4526", + "ded99b5d8f30441bafdc8b9860bbb4b9", + "15559f47e22e44a3a3cb2c4d413a7c24", + "3e13e1a8c7194eb19458b3d8f405196e", + "895e0c5280a6438bb3126fa2b3f08ae7", + "23f49f3502b54ccaa3d15113e5af83a1", + "1ad7c58da9a644169821cfe46d39ee0c", + "3a47832e3a294143b5823c5bb5697094", + "c26f933e1ebb4abe8467ea1a3ed47f85", + "6e90679b107b444fbd15ae34d03ada94", + "a4688f192a76473fb926f1227f773e2f", + "f228a81448184234ac94b878a8172cd8", + "9565b350499242aa9a7dea37c67113f6", + "7112ff509d064ad0a23d13553b5d558e", + "0e1f16189e8b4b4d9d9c3c60893d692b", + "89a82eac43a34bcd83a5a075b0e5368f", + "f9f0a5a874d8474dad7a7657ef27a531", + "7f1876fb391840519c9415c4c6ea081c", + "ec5c00503b054a8685b67fe07a8302a7", + "8d253eceb0b84626bb02cad8a1c0f9df", + "f817f0a83a3f49ac942d46e53f930136", + "2a115610451c4bd58a7f79d11a7bab61", + "e52fcf2655b048babfe10e3ffe72a316", + "df1f767a40db46b68d6774e0f6b1e2fd", + "3c9eb50ce25f4ce9bc74a006d39e8e5e", + "673b12ee248d4ff5a919f1678517d8be", + "e408a387dfae4de08107923698ef352e", + "f44f29e97f75481abaebe706a49d4e0d", + "f7995f56025e494eabe04fd9b7ed1cd4", + "d5ba60c1d118494fa665f8b26d4f5715", + "25d2e4dd016640139562a1ad23828ad3", + "e2fcbccf4d2446bfb25dc5fcc7f26af0", + "7abd885594bc4b18ad1ea5828c7a45ee", + "dfb714f625fe40e58cb576861add4eb0", + "0597f7fe0578494db936743fd621abca", + "4039ceba0ed04edb9a08f083f61db431", + "7c47510edd2b45399cc5f675dafbb135", + "9170ba9f384f442ba9977b48d4eef113", + "565c2da576404808b1d94dd7e8cbfce3", + "6c1b44e0848347299aa3676d1de38a2d", + "237d72410cab4732ab98446ded360ee6", + "3dd48d1cc70241128529a54df5b8d74c", + "6d7b4bff39a14886874773cc426c41bd", + "96b529d4b74e497d802bcf6779660669", + "c700e7c131454303b3a87d7a264e7252", + "de9b4e576114440f851d4e02e1df4fd2", + "85aa4f77833c41e7b2a5f03597e26eee", + "551f63465ec54b3eb26d736ea17abd9f", + "a1c92a301628450dbdb04f6ce63017d7", + "48b92bb377274583b2894697173e28ca", + "9b1834ac141e432fa8081e5bf5835fb4", + "eb0194bb7bfd4121bac8c60eb9980b41", + "3422f8f60e7d4035851e200fe8e50c55", + "3598d9e686ad46dc838e1443b910d91e", + "c187c6855fff419eb360e880615eb91d", + "b6db59bd7f10424eae54c71d19663a65", + "e6ebb3b9af6b4668a739b3622dd4dd35", + "8b4af118e69c4ad4a62de2a5ba94d1ce", + "d9b8edf3526e429fa80758c285dac858", + "c659eb6b84b548ab8b90f5fef0d278fd", + "fa207ee89711449b897e7a8107084b56", + "c10303f63d8c477e823d553ab017455f", + "e11110509faa49e4856c49e9c546a700", + "855edf1a39da46fd823233f320474051", + "d42aa6ec1ac04ac6a86fc295a99fbed5", + "9991844462334b1f83cf278e28f7019f", + "5ddb4b14fcc74ee49ea7c10932718302", + "6a47cbc4e3904833aede3d3b68e07ba5", + "8ead067881a64a7a81d94d2e6bf40d22", + "3638ec4cc3de4564be23919a3ecb9b17", + "3e562f02fa0c40598438c4236060c2cf", + "1073fd1838834c71b95f3fb3c37c1409", + "0df8a1e55d9b42818d8b9d1c3f040cfb", + "fc010cdf13b641b7947a5f6b6f3afe32", + "42977a17b5a34a9d90c490b9e0265bb1", + "d23c7e5565104a1db2e1c4641d4ed59b", + "4293cb6ba9524175b6e4ba3e10e52ec6", + "f3d0322e6aa044f984269be2f7ca1a3a", + "05ade23c1a4d4d01b1d546a3ba3145b7", + "197e75de6b454be18ca4a0829ef2d522", + "f830cd0f0e1e4b849b809ad1527ce4af", + "a1f834d6a70543a9b5dcb8fc7a5bfe39", + "8e6534b3df8c4bab973f27c67b2dac36", + "771ba35fc50c4d578f410f83f1e824e4", + "f637dfd2fca1486fa574cb4af07a891e", + "a3a33f7a69f84f57a25ac0a5a1c1ab7c", + "8fb221f5b2b84308b0707a8768f4a043", + "b2c16351e59b473e8b6c67f90142d3b7", + "8f86dc7876c64504bbd181ea3680e9b5", + "f501f639352545b992ccc5763976b7ea", + "91e9a8aea88f42e6b8fd6505dec761c4", + "08993cdf8b8c455eb3ddd4c6cb080550", + "9b65f6aa5c1b420c83ef3eb05069e595", + "57cd9f1e47634f4d90c0ac2d0247f73d", + "a9e9aef9d630407f9956eca64d54719e", + "414a08f14d5745559e2238bb62a0aedc", + "8002b22408aa4247ba8827cb6df9e52f", + "eedf3a271ae742129282ff74ab8603f9", + "8a4d8565411145edbff488abf191592f", + "7093e3a7290144528b0ed7070d92c8ee", + "d9fe4b53538c481084f0f6e78b5f59e4", + "4bc89e3be7fb4c11b3b1153e9ea384dd", + "f0bd42a4435e456a842cdb86a393ff1f", + "104ac40ef3ad4dac8079a11548c470e7", + "62fb044587d34c9db08f875e24863b4d", + "a7815053afa74f259e532a87b5dc31b0", + "feb96b6b2b534c58bbdf9e081f2f4e46", + "3ad45f20b534474bb129968dd3b65fcb", + "d10c9764f22e4fa3959db48d3955f282", + "c29a2ea96f6644cfae863f59c57d52e5", + "c5b45802a60c4e6fab47daea043d2460", + "bfde241c93014269928af8191f831224", + "f46e5c349e12499795e6e2e7fb258205", + "8fb06477b89b4d8c9e815d1c79bd7c7d", + "7c6b62da884c4b39afdb0fd23d808892", + "485b809b30ca4361be80ba37e715202e", + "80a0f58dcb604405869637c8387f5d36", + "6233f25e6f784473b0277028bd99a8ea", + "bf957884ff6445ecab9818d4a712fee0", + "4ed1cb3315b74e03a9ee1c51ac1e87a1", + "c13c8fa8a7104cff84fe59dcc0e2b8d0", + "52b6d5de9f8847dba363a93761874c9e", + "88ae4eb19a1d4c3c8765a70ccff59f8a", + "b2ab7e64eb9c41ac9b8724f6c8db3fbd", + "f80a2a0af6924562be10be7354b7a72f", + "29b2a7aeb57747d9bebfe2d8e24fa3e4", + "117237a5e57a4bf9b7159f3d7488a9e1", + "de894ecc99704a158720e18e17f19c3b", + "b23ec9725c48494788d1d88104acbb4a", + "a286ecb0a5b649088ab1e14a35c82f87", + "eeb4ce3b74724ee7b8e0a92f22b0041a", + "7982178a74c24bfcbfa51af8cc726494", + "adce194e275d4fb0887faf550ec739c1", + "5829d518fce64b06929721c8290d7ceb", + "67bace5056304a4da95e9903d52650e0", + "6494e79c39554da1a4ed68d5e1d10cb5", + "497eb74959514247954ff7ef08cc92a2", + "84fc22bdf7b24e0496578f00386c7559", + "dcf2348efe5e4c35895f84caa6418e2d", + "8f3c0241ceea47a49334e78c3a379f75", + "5e41e52f553c4a7d9ec2abf88f8791fc", + "2b157cd62bfb4f60a95a0b8f9d767e3a", + "52760940bfc640aba686e4b654a7f5ec", + "c5ebf86ec5af4bf5be6a97c482faff23", + "2b44fd5bc47a496295db9559dd0a4675", + "d2bc90ff533f4fbbaef213343c3d0c31", + "a24b4b74a40b42aeb083cd447b79683a", + "cb5a7d1dab4b4da8a6f6d1332f71b27f", + "3ae93c78f8214d61910564cc7fbbce29", + "5295140c3a2e4a3188b6480349ba28a1", + "51ba21f2a392472cacf68f02a5b762c1", + "cf4f97cf66ef4a5398cae98e57e7b975", + "30cf9f7983db48c9a8450ff34c403414", + "e4fda01f049d41e8b2cced62c06e4ed9", + "29e2a5af24a046a09e9cd979d07a0fbe", + "860abc53de134003b305b28f8a60e06c", + "31ec23f26c454643b84a20f24b05f4d5", + "c91524e74c8c463ca3ddf71bc73911db", + "d1e3a58799b146e4af6496ca9b8fba41", + "cfcfa84fa9d441c59e8047ffe3d539f4", + "cbd6932aac874d40a340660dfdcfe64d", + "8599f276c036405daca392ae1548bac6", + "444140f8b755453b950c5a146f448ff3", + "97c1780b06f7429aa80132bf5b9c40e8", + "5dd23327f3d846c687e89bf8228d872f", + "dc22338c893d4346b19aecb0cf7ebcbc", + "cd9a5677626f4b648a4a3b1e0d9ca5b9", + "df09f51886824cd78957d92017fef972", + "faa21e74405d4d169e6a8d76592a3550", + "401a4f488c514e418de467ba3b516871", + "4c88241c7e864900a30d433fd0beffee", + "ce8feb9a2686471da98fea2b4d262d69", + "25ec4ef119b24f2b8a46c8441b9b074a", + "7b9059d34cdf453e8bed8cb614885fb7", + "e0c4a54d889647d29e689164a062afca", + "6156ef9147984441b186c08752499344", + "3ee3920c39a841898ac0ea0a553f1669", + "c9502e4c04f64bd7968cb587ead97559", + "669bd4fe31d74967aee740a825ebef94", + "5c4f018f8d1344f2a214f6c3fbd25c4d", + "5d0857558a954fcdb247743693fe4b0f", + "7a2fa234149a4ace981a267fbf92a194", + "e8b11aec127e4ce896d5cbd474702703", + "6738a9cf79a54eb4888c9b288a736e96", + "38e22819d96c4ec3ac6362007258e4ac", + "f2ef719daead4527bffbb11ecb01ea7c", + "5498fc39dd594a8fbf365b8eb6f146e5", + "6f44910745a143a59b9fc08a58e6b1ab", + "efef8bc49fb0435d926d0c3825eb842b", + "26946be61da04c6594d3bcfd2439618b", + "bd4d35196e5f4a9b838beb1325daf5a4", + "9151c4e13c9944cbb35f4e4ad55c1fd7", + "f14094f2487b4fc19aa0646e2679cda9", + "695103af832e47f2809f3888373bb0e9", + "84a620c30bbc4bee8ce36d342debbad4", + "9b99a8d5ef584ddc88cd7b648abcbe6e", + "1ab7279669fa44be8e74e6c75a64819b", + "d77a2a32788c480da87748c304f42257", + "4911eff8aff04a87a5f191cced027282", + "deaec3c63ac64e0ba43f24b57767fd10", + "488409789e1e4a129b7244f60f15aec7", + "0c22c62d84304528a7afed0ac9e81f1d", + "2bd6b3c75bd7460896c0accb02300b93", + "0b7f13cf550b4d0d978d9df855c40c32", + "8f33b682ee2d4a53873a9b8698dfc109", + "6d37d06dd4c84fd68fa212e82c8d27bf", + "a30f0c80ce4943c79dd5a5fc3fdc7ec9", + "0c6c04758fbd45aea0332d212d6fd7bb", + "827c084126194e1a9577c101ea4942f8", + "ee65b0c6b4184bd1942bab77ed681d2a", + "361b96330d8a47a6b8640482608483db", + "62ed79a105214ce086c04c03dfdc877f", + "f8d2af8d4b2848c4bb1db77920197110", + "2eff26913e0e40ceb30558ba5256fce0", + "24b216067272446e90d07a52cbd6795c", + "1f3a8bf54c9847308993660331097f79", + "24d189a5d7b5420591d4153162a2d1b0", + "735a4bb2afda4318ab7f7d69005f53ab", + "ec29364b59b244b59c7c048ed6f7f0ed", + "58daa92fd325411780126c5c8ba84ca6", + "03680417fa26467dbc9c9b8d130e923d", + "1df64def6aac420e95b044d3c4b6a5cd", + "b5ff1fcea35a4024b69e4dd08c6e1c19", + "91720e498ae54b08ba6a0cfc97b10d52", + "f7b41a425f96471a9f8bc4fa9db3f724", + "679b2b3572d74da3b6fdd52d621963d3", + "a8f94279927d46d9919ff3775a834cd3", + "38cd4ee0559b4948a0e8894baf400646", + "790b86c8946b43bfa93e626f7fd0f886", + "b789d27d18ba4d4a98c3fef66e1384fa", + "b12139f023934b93b06ae240e999b131", + "f6721c355ae2429b91e9b3b33fba6534", + "c41f01f907614ddba147c324eec1b1d2", + "9de74d0da17b4130b1e97af5073f4996", + "285bc09ddd4149c3ad1a4a55877f1e8e", + "bd8cfd73b78745e2a3000e243fae0672", + "3242391bb5b64ec08e18c1dc9ab7eece", + "fe251a80bcd2478282303294f8524586", + "7506e9731f214d37a2498115de8f7623", + "4a1816e651914f3eb438c084c9d4ee7e", + "7ed6400f0ed34108b07acbfe38428e9e", + "e02be74a9657415886845d4d2f9f62d1", + "b220eea1400d41cda3b2c670fcc5c605", + "307dcbca47124ba8a2667edb34588a0d", + "bbbc8b128bbe4efb87c4e097163f9ccc", + "00fa05ae10834647a8bf00c5a5a899a1", + "71faaec870944d18ba03822bfdf15744", + "c2c99c157764423ebd85371c083a1d39", + "b38316547073495b9c425b068b7bcd6f", + "1e7c24861ab0453184cf78fa781e284d", + "f4d5461627144effb45cbba8ef2ef88f", + "7197a69fe5984776994ef1948162ca40", + "18e104a6d4814913ab1a3bc4d00521fa", + "d2929d60de2940bba5f7d92170f01bc1", + "f96a4fb0b5f44219afe401c72ac4d6dd", + "bbe90644fc334d75802321de09413f43", + "b9a919debbd6431fbafb893393bb6eac", + "07ff66a33eff4a0a93252317708d9cff", + "6deef5759c5449f9ae2bd86d56ebff6d", + "db8307d0cbf54b0a817e46372f5d22c2", + "913f788af384451385d3cd30cdb239aa", + "8bc75b4f622a4ba49d149dbf6c61586e", + "9522a37f51ab47ffbe5c084a14d9f04c", + "5187d91cf77244fd9718933f57efc100", + "6f2f754c78794734b794237913ba97cc", + "46468207ff3a4345b931616ec9dd5ba5", + "1beba9b24a9143df8559410f1522aad6", + "d509ecdc7f114380819d1a682c82292f", + "8e38e38dec81409e877f98b419121522", + "5f885317caee4058aa01e2c61d356341", + "4ebf4cef4ec642ff956fe680033b410a", + "2923432f2c2b4055a65ffb3903c6bd9b", + "c58674744b2947668b04324fb23c08e7", + "be9cb20e92364eceb02bbfd166cb54b2", + "0a68a840a3db463cbb94693ab695d536", + "a73300bff80749ab94845d2c600c6653", + "0ef0504cf59a4dd2900de194effee01e", + "a2944ad45bb34666876b382e90ac1bee", + "03e65b60334d4d01bdceb292d362b743", + "49e0b2c7cccd407e93af1162e086c686", + "bad72f6a2cab48eb9cd837df0d58a01b", + "9c8400c0580b4deda9bd6ad2aa84e421", + "8b51c922566b418bb0548d5d99688bdb", + "930bc7cc7bd7444bac3af3ce738143c7", + "f7bbf5d03a604452916d5c0cc85c867c", + "7207df141ccb4c0cb2db0a9aacada802", + "af51c3fdfb0a403d988d0780ba7a6e30", + "3421491ec7e04ceebe0342e411c9df6b", + "e19ccf3c45a94abe9bfcb2bdc4950ca2", + "93ffad1f024b4e138374d698078d785c", + "d22900b7791d4f48be366dc4266f11af", + "458347464a2947749c97a96f415794db", + "590b8e69109a49f3aa20ff1f6b231a99", + "e09c9e13385342a98c1d12f4ffc21bff", + "160d712e0098495086b6d798ceaeb24e", + "00cd033828da4531b802f9542c312670", + "7b0f363137e94d688db63da2b4e0b376", + "5c1723090dd3487aabcb2b2d5bc35c07", + "60e045fefbef4f5d8f8eb678a78d0764", + "bfa820aea52b46ea8767661d78db4374", + "95ad76902d08451da8ec776c91343a68", + "ee146d0824ca48d2a88805e11eadee5e", + "7609a6ee5d5747dca7c4d3c008fea4d3", + "4e933f931bf64806b1ce64fc18213361", + "e7b0a876c8f64ca59d76aa7190183b53", + "6023c6badaa646fb936218f77eb4de11", + "d3326208f4a948fe98d5e0d17921b94f", + "1390c6cae6b34933a06a88502e284236", + "a3b8ac02bd254cf1b7015f46599801c8", + "9baee10cdb5f4e55a75a8b8abaecf28b", + "75aa9519195647d99cf1e2d4863dbe87", + "49e746b3f92441b1a548ba9908689351", + "e5464200651b46f79ab8c9da38c68297", + "90677212ffb54129a85e9e18d644a2f9", + "6f8478060ccf4608a46188b29699335d", + "3597a7a470ac4f81b1b362eea66f4d6f", + "e99aa48377f34857a7772d4b7892cb19", + "de61eb0108664e40a05ad9a25b3a3110", + "571e6c6de43049b49375584fa18abce3", + "c8b183346ad7497e83e3f88b704312ed", + "0e2a45cb08fc458e9810de03afeb413d", + "37fee7d818054ae0889993592db930cf", + "cc0099a687194a31a052ac761f5fdfea", + "fd9b4061018d4fe091e8169b34194e71", + "755374ba4b954ce889573f004a0ba1a1", + "b2c76e5103144bf68d7382c51fea2e8e", + "b55660f5b8f14de28d4d6db5a0a8fa72", + "58c22522f0d847c9a0caf8c93b60810b", + "321c736059ef42d2909dcaf10a8c25d8", + "96666d8f253444809c81221d94048724", + "a0dff18c6eb44a4090012574802a384f", + "d7bcc29b07d743ec9838ecaf8cd55f4b", + "cb149914327e416f95e0f15016f028de", + "0673975bf6db4e7ea9a8ad011a573a8a", + "9102ac11b3884e179d2722cba6b84652", + "d5bd15eb103e4e909fe91efe37c65f50", + "2e8124ce4e6344c8b8cf110de25735ac", + "9490b6ec7ea34b19a204dceca9bc6af8", + "593919c12baf47248d1ebe368e838c9f", + "9398b9af7ec34520ab530759d6415bee", + "05b16b5539614ee3bb4366fec77206be", + "d3bf8831255e4ed9851a29216406307a", + "49731dbeeaa347e5835fe478796be4d8", + "97af58658d924b85b30a40ba47251a3a", + "f81d12b372c64eaa8ee38702749fcaa6", + "f251170274014dd99e092660f7cc4053", + "29c9477325274bdaac844c1a43334a55", + "b169f72f34da484f9713875e78a58b32", + "a0b201691d5e4d639cf51ec1b1e114b8", + "cd16add9da4b484dad22c981faf07136", + "945706e16a2d4978ac2a97b2c58d741c", + "db6185ab7479476ba34ea8b7580900c4", + "c2b2d8a8fc494b769e92af3db71764b2", + "2b1120c4b517409184413ed709c57a66", + "ed0064085b74437f8bbabf3c884640f8", + "a1ba5ab7bad448d195aa7f1fccddf843", + "5eea2590556a41f89be51e0d9e98cc2a", + "3e0ddefe82524314b0bc8eb0191950bc", + "e32dd7e919b84cf09ed542adaa0a2dd3", + "70f320ab009a4c7091daa0366217dd1f", + "abeae1a319444352870151d35aa45621", + "67cf672a17914350a603a0c292a55eca", + "e0dd0af5428d4a7e8970540359b087ba", + "548f44687f804a4db61c117907723721", + "5ecc887c3f8f40febfc08a7b81cfb965", + "ebdec22ac13b4d06bef509d4dc4d3352", + "1f1d8f8e1d2545df991a617c1f9d0ce2", + "fc9d4b562d1b4469a3d74478e77ea906", + "0c1cde72a0d24213be44365dddff85f3", + "00184eec45fe45ffa3826e9202fe7306", + "2d9f4b8fd344446dabc44fb3b58d21bb", + "3c8738bafad8492f90fc1ac03cae344a", + "41a0c5b365cb4a55903c8a2196063af3", + "62ba803c6b664cefbde0d2814ff88d20", + "0e44a23f754e40b18931b848f4761aca", + "f65c7e7faf164d12af60b59e44d4a511", + "2cead2a7cc0c45cbb5c79a50516a6104", + "0e58276af3bd424a9b276e310d8fbabd", + "c947c99867af42b2b666c92d97ed3151", + "5c14cfb7dee34b34843403d9ba420743", + "0a0152cbee0d40dc8289eb9118fcc35a", + "cbdd660d400749f29c1f3a2425652236", + "edcd0d2bd8ba4294b49cb9092c21a30e", + "75fc1765690b4f6f9b15adbaa6ff5888", + "23ce0662aa634361911fa7e62194db1d", + "c2d212d07d5c426bb045b4ad9dee7190", + "1cf0ba39a67441498652123ea1c84239", + "3fb3b312020048d7975bcdd067c721f6", + "e6552259de4441cf93531758745d8f31", + "854a178a730e41398124f2bdb7c0ae74", + "a15c234c0eaf410ea65d22ff912a9987", + "b47606854c694ff3b7f71df9c8c3fdd9", + "8acbfe479d574f69b953fca7d477b4d6", + "a1a53c83b98145b9a23d669e854f06c2", + "67b2ed839b3f4372a27b7b1e72375cff", + "82b0495db82040ffa9f983088f4f4ce6", + "90d1d5896adc45fc932a3903c2a65b1c", + "b6329d61cfdb4ca6a336c3ce9203efc8", + "54d901bea1f34af78c917b7fbf0ef879", + "4336815ca8734e099399473c8669f3ba", + "f2afb475f03f4355b42a6a9b1a43cfbd", + "d78436e8d78e42a287805d473e6c13b1", + "cb7a6e3c559b4d2bb6b9697fc0e3153c", + "1c6b3941750a4c25a88ae6e982a24aab", + "c7170bd4b0fe4e32b3a1cabf5afef70d", + "c64724448870413bbb7d896188dfac8c", + "d30daab1ca0c412c991d4712afc5d088", + "dc346d0048334a6e81189452aa2eb5a8", + "1022e9d02cf64a6cb69b4909ac385182", + "1c831100739d46ca9a5983e9bc8b0c64", + "1407b593b9e444fdb304085c423fb833", + "02cdd6703f7f4baf8b0d96c0ae4ad6b1", + "d370a3eb0a164dc19ba4547a89956599", + "9748427930a246fd93d306fb73b62d73", + "ea13a2db97c54ffb80896eb06cc3f8a5", + "be7cf368e6fb452ab99e115846622686", + "54ea03d661e64b279c7666f2212f3849", + "eef2f5ce5d2a42a5898fc5ddb3b6d536", + "5aa5eb5ffad8437eadf331c098d08296", + "9d325c012eae4dfe9b92908f865dfcc5", + "9de0f410e48341bc83b7ed43a864e34b", + "f6b185959e1748c5bd6d6acf1e713b55", + "48b87fc386194761950d11affc2d0cd0", + "c6296e731e3f41ce9b014b64ffbf9d10", + "cf3d0d8402c0430bad5df3dec541f267", + "95287d752a1e4b75bf7a2ebd4e410a20", + "a667f89b0f184c81995cf07937e4071a", + "c48be4def24d46aa90e9f0ad237d1e99", + "d2c529d598d04d278034564b6e4377a1", + "c87812f68a834cdf8d1249faef6351a6", + "b3ada2eb27eb498aacbcc94b66d7f3a4", + "2637ce99bdb3410a8eb4b93b3771bde4", + "04d6ac796ab347b0a3c914c05368a62e", + "10cf99350bfe4435a75868381a61abad", + "c46d64155bae47d4a0888cdfcf8c27dc", + "fb488cc23f144bce93e16b1412ea36b1", + "aa3416348d5b46fea65e7589ec0238e5", + "56348c155ed44af7bbda861bb30b65e4", + "209decd5a9ea427ba254f36d6553df53", + "3e54b8ce1fa042ab9a25fdb7594a0d0b", + "e75eb7b074db44e6bd32cd1d2469ad1e", + "7779eade266147c7a1468cce204de827", + "0084f2a137bd46b6829f136800b6270b", + "84020334d1d047b8b77152108844e786", + "65ee51af4e8645c39cfa0382f8e1dc76", + "75387ee3c9304c5fbb52f466f84e3ecd", + "0465fdef4f974d5cb20c41c1549322fe", + "efc12a37ad3f4d538dc11b0e7b5f8901", + "04b05337ec1a41a4b18a7e8f7dc096db", + "c2b24cc1f6cd4dd79dd0dc8f05644ef8", + "4625cec72a4d4664b130cc612af5b5d7", + "d7ee75d846324ca6ae6aa31ca8d926f2", + "9b2351daa0094e3d9cad7edf026368a1", + "b81260a3d49140dc8e61289eb5e4dac8", + "ec124f25d0284aa7a41fdfb7af4b0a00", + "8be09b9d10ad4fb8a9e2125f1b6d69a7", + "6b94e5aef92c484d8e55516457325c26", + "854a98abff3841439ee890dc0e78dd66", + "880f99937c414cccaca313e8940ed182", + "b674fe255a6d470eab510a1dc54b86d7", + "934881de51c342c19cc83894443d2482", + "f6b0a42876f946398bdeb9c916dea2c0", + "49add91ed5874ca590fa137ca2029353", + "c4b8b07d74764ca383e9806f25b6f192", + "2585fd2f595044afb522104c77a20612", + "39e4f4ca2b7a4d528986dee97a5b609c", + "77d37c2648b647de896108e2bd95d21e", + "d5a90f47f32f426e8b4e51c5a4f55b53", + "cdfbbb151df2425a9c3a1698f1e8e13b", + "75367fd0d4c94c1fbab3fbca6fc02dac", + "858f8c952ab74dbd87882e043f78df03", + "5883e3a8383e4fd9960adb00284bbe79", + "9ab69d7c4e0848b78b9bbf334bb98c91", + "f578ca7f91584ec6b416d57462b4d990", + "21e22be42472440da404c6c713cd8e27", + "999abc97b92b4c4592c4e39e41f7a7b7", + "bd7100c5d3964b52943878fcf01220f2", + "1e8216d5a24046cfa35021b3c11292f7", + "f509a077259644329b2d45c9d737339f", + "04c27525c52748b8a0dead78a14e2f58", + "935f22620af04e9da34b912596d8a05f", + "bbfdc45a9f5f4430838ffe988f122597", + "105338f077304fc3adebbb8d4f6a3274", + "fd7553c9c442409495203f6f943a7746", + "e0aa365964e14664a5ee5063bd164bf9", + "25f768edfd9245f0b018d40fa72c686e", + "baed2b671fc64bc3a74d9fcc4033e2e9", + "9c76ae0676404b5bb2fb7e870907f4fd", + "2d4c1989006c4e3282aaeedbe2a891fc", + "720928fdffbf4e1aadfe5b9f66ff2e0a", + "bfed092970544194bb940de841fc99b7", + "af958c82c89e4d3b96b40188757fe924", + "c13d7df71b4748df94470ff00aa67567", + "6faf04d006e64c9daf3be15db072f6cf", + "ae2a720d078943de9ada08566f75a134", + "565e4ef4358b43a0aac9a123089a4d4a", + "4896cf9b3e614662b29eec0f87d9a44b", + "d4c3d8b49c8a402d9535923addbe7608", + "5b5bc543670b4170a353e093a9cb2cdc", + "ec4cada0aad64e2c995000f6aadb4c0a", + "a5fe802486bf4bdca137bfc22637dff1", + "3ea2fd4e065147048064f4c97a89fe6f", + "e7475fb3d1d9483ebf2864436476300c", + "747fe7a49dae4ef6b067ec8916c808e2", + "07573fa831364d52a79cd0fccb8b105f", + "74977c16a33f4c388d69380bbcff2283", + "841c49dd74e9425cb07ffa6deb855220", + "c1e71fa5dbcc458f9c85231d11d1968b", + "0d2184b00e874c5f90d54dacae102a07", + "b3d142f6d72b4f0788e841f229041e74", + "666d10471e094bf6b9be9756ea97bf43", + "5332c62599864950a6a9a852f6cd270b", + "0a25fb69fc634713acffec225ac8fa70", + "a4ee55bca56c4e4db4f403ea62436a52", + "6441ba6422b74be0ba70003107ecacd7", + "4dbe298d82e7402dbf6831a435a549e8", + "f5c4359a43a74095986199e10c973c2f", + "557c9259640f4f41a273c04c35288cc6", + "18887f3feaf94be887287c211c253fa1", + "f0525338badc4e02b6bdb1e660bc96ba", + "739987a6a9e246f5810639bcff7abfae", + "fe0505aacf844c7aa9e9bf0f6ebd2622", + "579df71336a9493f8f52ddc815d2fc39", + "faf5bb303251489082665dbdcb05f3ac", + "31aaa65119ee417b9a2118b6c4d24303", + "c42bb527025b4a1e95932dc232b0ca8b", + "714971a855b34b1fb65f1b214f627472", + "e21cbbee70924977809639512e12209b", + "9abe4e86a7bb4a4b8ede20d1b394feb7", + "0c77dd485178478daa5c2d7b1b19e72a", + "3aafb89ff9cb4ae6a1d6e20b7a6d1354", + "f66c52d30f40424c8cd692d843349323", + "cbaa4fb6ab9344188019d150dc87c12d", + "db0c2198b89944e7b9ed40487849cbfa", + "232ba04a0aaa431983641fe78e4653ae", + "bf2b68bdcd7342a98b36efc03f872349", + "f3cd528b06b9446baccb0a86ae6caa3d", + "068525be5e4e44aaa10d34c01f72f545", + "3a7f5bda21e1457fad843422e745b02f", + "550aa2b9d82b4206afd77db4d7ee6388", + "b8de9468724e45afae59f54542e6fd58", + "7d63b577c581444b99f8bc4f92d1b8ed", + "d7afff23c741411c82a5994ae9940669", + "b55b9acad32b4ffe913c90dfcaaeec45", + "0228adbe91a94b6894e570b26c0dd040", + "49e1aa6c224041199eeee77d0023f75e", + "4f69ade46ef1427c95a2a4e1b132112e", + "7632e543ca5144bf870246f82c65246a", + "aad16a6c11fd4321b515f3292f45844b", + "f5bbcae719e1456fb57fd518aefc65cb", + "a2536d0580e44db9bafe0654c122e99e", + "a1d620701bbb4569886b7adf960e9534", + "3ab6ef0bf46e49bb84fc122640a521ea", + "6d91bda4e8b743558c8125d49d673afe", + "275356d8d6f54087868e2b984868476f", + "b6ea45bb0fa1462f8d49c59a14a87924", + "743237e08f06431d8fd9624de2c0008d", + "e73fc978a3d94d0985593f5393103e94", + "a574287a4a61468c95d19a49140638d8", + "be7165ffadad4063a14f9a30ba05d5ea", + "5d48dfa1f34d49a8bffc3bd3259cea15", + "cc26151d07f044fbb461ec458b8bb580", + "c3fc90e2a86240cdb82c06808bb4296d", + "12f1e1394b2241f7b05d2d9bac695cc3", + "5c0253ce98214d079413a13c1a2ecf36", + "18d603a1f4b149d1b232563eba466a8a", + "e05b1cfd53ce49f39741e692274254a7", + "ae6b7039ae1b4d0795f613e5514b2f7b", + "00c3f6de0c5b494bbf2885ff99ee6b96", + "e6333f9af2274726a986512cde1e0871", + "dd8bb1399d8f4171b14f4bc4e7c1c989", + "6c43f6ee547d4fd1a8f7aaf5435e29dd", + "af3cc99797714048a1c9b0157e4ed0da", + "ca762cb927fe4271973ab6a7f32813cd", + "9e3f3850320249b28b2b334b009af577", + "00aaecd7ebe54f7fbc4075d543669200", + "809a65f92a274e3184dfa14dbb15dc65", + "32d4e21454bc4431aaee22bd8a3f633c", + "54911b7d81a44991804c87c6fc58c4df", + "6292c807b5074fb2a41448d8fd9e8bdb", + "38e691d19ed64e0d93db14f4cc8cb88d", + "b2d9c4228f8f41fcb66de1b793e6e8e3", + "1d09f60e20734e19b30f9f71f26bc661", + "ca4f9a92cc2f4ee98fe9332db41bf7f7", + "d73c6dbe98ed44638f549f8a9fc81996", + "6db7646a44524aa695b4e617899d6d49", + "267770d4e1a640a0b87974ea5705a040", + "84252dd6d74f4a00bac4a460deef0a80", + "1cf5036994914c2d8a1c6befa1068793", + "b4a41eae4ac04443a999ac22f50ee1ec", + "54d272b8245c493e9293b77a12408672", + "048ca9ab42b0453ab344a0691fbd5058", + "e7408d63175b4d76b8e7b2ca7435fc10", + "f6608aad5a2b491aa4e334192c23b1a3", + "e8f63b8d11284c269325e61232c65ae2", + "5bc976c103f14f2995c048fae25feba8", + "83949d068c4d494b88d48501563f8b60", + "cb887989b19c4342a5648b6754179779", + "d9f074d6f0bd4a2f8d1bb100c2c72967", + "f790323b83a34e0993a6cc71c5ba189d", + "feba47844ff34ca094f9233f6ee09cfb", + "9a6d7e10076c4c22aa87402e805fd7fe", + "18d4d5a8ae0c4c49a94248a0b825536f", + "f51f497ffb7c44efa4af7ab6c9315ab6", + "7e3cdb9c09a64b31a75247c8d3d4e244", + "7d1bc33de2b946f380ac37e2bdde94d3", + "cbbb9ae9490449c0ba3c78f8525a2e0f", + "2f8aaecd33294c5ba81988949a937667", + "c15d1837e58c41cb81c3baf3b7e544ed", + "ed11e4cd21124037af70dff7bb69a1a1", + "d8bf7bf749784f1ba92c0b174c85c41a", + "9e7fbcf154a64d70968d93431dd4baab", + "6625af285cec48f7b160aa2433777ddb", + "f1679e3c5e45478387535d8bdbb9fa43", + "9a877d0ce24f4f59b9c5a960d85614be", + "b367339ad4b44530844a78efb149b770", + "487adb465f384d358a23097dd9191fd4", + "c8a67ebe663544dd9dca484c16f7f21f", + "8cad5b623c424d2db3c682a0a0c551df", + "069176742f1c4b7f8f57aaa86c53f0d5", + "0646cb09a5114642957044e721ab703d", + "d085520c33514fecaf6395bcb477c27e", + "5edfb3471cf4400e99ace18446f924b3", + "fb8932eb2a73433e8507770bcf919c55", + "891885ab77904f44a49bc1c869a4d9ec", + "dbf2139d6cfb47f1ab3fd2b32e2db09e", + "6e7beeda7b4b47b1a4a64c82c3318be9", + "52ef7a0dc7614bd1bab532c6b72dd5b0", + "cf964a1ff455478ba65771400a4ea1ab", + "5ee959ff7021463fafbb7fdde1fc8714", + "678c1af52815428e8375b19d7185ac1f", + "77bbe5406f464b83aef3c36f7024046e", + "30dec2b19405488b9c958ec4db3bf681", + "126c07f527ce42aca6a1f87c1cda8606", + "256197374670492f8ca1c1a954b2978f", + "9517a68f4973491b82cb7a445af93561", + "d926f6cc67264ad2a8fb6342ce415e7a", + "9da2f6970d7b4a68899c7323a21b3f71", + "f12954f8c7b5479b8a851414f93ee62f", + "6536b723e61640c8a85c5d250985fd5a", + "72b88f8a8a4f4832b90381c9a19f5a1b", + "965082403694407fb14ed19eb109018e", + "f9b4af38f22a495ba2aeb557cea6158b", + "a537eeeec2834b1d9669119a7144d7bf", + "2ff48e8f52134f16be3b58b10e5d8bfe", + "a437ee1e1a764344bf3d3bdbcf64c88c", + "9470120db2374da2800aace5da49557f", + "1ac8fa7a38fb45bdb74261b63696ecad", + "bcf0d5fbcf164d5080df79dc11f9a8fc", + "9492ef11394b495aa9e222594ddf0bcc", + "e1b04ac6e2b74275a1a0c2967c885ccb", + "4a7f99e067624fb49d401171e35cae7d", + "96d0de5c64ff429e9949a3479cc8f479", + "fed413356b80464cbafb2389ce18091f", + "25f88bc520b74f6ea9144bdf49d4c9d7", + "bbb5020467514e8781918234943dfdc6", + "29527175dccb4149b30a470e2cc6fbad", + "2227352d74d9471ebdd17e8e4cbab211", + "721b013ec4f84977a11d9d0549197368", + "6f737cbf6bd64a2d98b070c6dec65cf7", + "9565b76f6e1949b7a817c0f62ca9d896", + "59e522ed95274b22937bc306fcf1921f", + "79cf2a484f334d8cb90461333301224b", + "9155d1cb4d8c418cb313ad207e15a248", + "f7ac28c562b54b4db51ff5784a967bdb", + "87765915bcd34a1d963b80a401b2bc34", + "f500940881a243f88fe4850090787efb", + "2bf0d5cde39141948bfcb2994ad221d9", + "014968271f5d4a2e805a4c910ee8a614", + "5a1c06d1f04142279b9453a0113faab0", + "381a186b35094d4e803a209fe29aa3b0", + "50acecd0c96f484ca0de0de27900afc5", + "e3072ceec1a94fa29c531f930b637210", + "3fd793a9686b42a48f2e774ca49c7ef9", + "6b1b178e82724c5b8f509236688a3379", + "8f787609077d451cb874696ac1a7958b", + "a1c2262838724d1eb4c6427f04933fb7", + "716ab1797fac4d7489c2f3815b32fad2", + "51f963b12fc64b1b9c13ce622bedd35b", + "e4781fdc397e40e1bf5e80e09adfe780", + "8537a184f2d441aebd214689c0cd918a", + "ff21d75ab6554ad38bb4199d3315b99b", + "00cb95739afa429a8426e2b415e19829", + "e70de4b8c5a642b8a525acb036b98bbb", + "22e60495b7984dfa88d7198267512cb9", + "25bb45dce60c4940b99f09c5e09ae501", + "af0cebf5399e4770a36472e5072805e6", + "79fd2a0b4d7647c6a247eaf2714e0693", + "3403b6f0f47d428eb2dd098f864d9ae1", + "ee4aee8bab7e47309fd6957272bdfd2e", + "a90fd116b4b1485196eb3996f301b130", + "844c8bc92944471ca525e78dc97da253", + "03b0ac7d99c44197a09640179f360f3c", + "0b726db918f94fdb9e7a44048321472c", + "8c98941950954a98811912d6e4e3f8a3", + "60728cf9622947f89ab39e9bbf15fc20", + "44d7675cc83d45149c6a48f95c891bcb", + "650ed2b2fd164203959390fdd0441730", + "da1ec11ef9cd4013beb40359be96feed", + "a5d403034bf74a63ba8131d4f7f83ae4", + "6a5a92ad28514b56ab55fa04ba220925", + "af28fa9ff98f445f9a43148a054bb960", + "1804b2bf872e4b998a9a08732a83a05f", + "2ae2c62ef2434a0d82355c7a90848cf4", + "728d11b629494d63a02e01f3353c1b26", + "cd2b81eed57942c6b1c22049c4b036f2", + "2110def70b3c40048b73a42960aef78a", + "51047ad9b57942cf887b6084ca2b4a96", + "c57269269e51426f837813afb84466fc", + "7de1e7d0c2fd4f57997defcbb0b91d68", + "5c8284c0eb2243ccb735604eaaad1ce9", + "dad252fd32b047b7911ac0a332dbd129", + "d88f4a32eaf44c2594b20aa45dc5b79b", + "fabd9b92e1b74467aa5120f52e8c32ab", + "102884713a2742ce829e368d2a790c45", + "fe28a7ee0ce94e2e9eafd1cb127e6d10", + "8ab0baf0f68f42788285e4f952c454ba", + "e9ca8b2cf047415f87398f98d8b58af2", + "d985ac5ba3cb40e1ba8ed17582f381d8", + "4050a914b50848799ddf037969e30d4c", + "849a55423fa84a3e95c76d7b51f7bcf0", + "205c0164366c483aaf905cd8a4f5a590", + "a5feb56f36514b8fa9766d75735ff785", + "e4e126f3e81245a9857ae49a6bf6de40", + "fddaaa6ef24445cfb0906adf67800fda", + "6697d804cb6b42bb9916b9e4b334da7f", + "6d007a29c5a5445a8f0712253095e2cc", + "c801e2aa5feb4a3b8479c24875e2939a", + "40fdbf4c9f2e45fd97b02d9c4f03c6e5", + "61c7d849de9b4108b8bbb6a45e6d7f98", + "42035cf49db7473dbb78f60112838662", + "2c83137d2ab247fd8137c901ae129ab9", + "faf17d7ae78d4249862a1b4c126ac1b5", + "6f9431c68ffa44d0b2e7635d646c4000", + "52f4361d95254b8988be5fb5fdbec951", + "cb8ef0195f4b4b2b916c0a848f47bd45", + "510049da419c4393979d4aaca655a353", + "52d17961536b49168fe88f0cc1229a92", + "60e0bfc4878b44ae9e2dc08fe04f9624", + "9872bc76b50d467cb3d7d3093f58fe04", + "6f1fc902303e4f4eb94e155000b8d811", + "1373eb3da7ac4d80b8b5418a562c2217", + "9e452ff4dd764bd2a40f0fb14a3df4cf", + "68ef91781477491e8a25dbe2c7877dbf", + "b204160d196c44028be0a898d0779de5", + "1d24de8c6db84d59a818944d00ac6f6b", + "e5dd790dbc1c4d669b3bd2586f1af5da", + "51433fe89f434205b5334eaeb63dc09d", + "dc1bc81aaec34a4aa8d906574fecaee5", + "98a184a2d84243d793a067ff3b03219e", + "f0d9eb24b76b4ef583d6e9a74056c613", + "f9a72fbd857249febfafad5f844e6990", + "041ee3f9d8ce453dbdc1a696431041c6", + "64a8b8c6bf374265815671049535dbb5", + "1683e4db051847cb8a5a38786e071d2c", + "78d3cf1de666401fa7f96948ab86d07d", + "d4c9180a46cf401fa24fa3afe9237a43", + "03e66c86209843ca956e9eac6097aeb6", + "c303dbba4962456986fc4ccd496179dd", + "9c2c626c8dbb414eb632cc7923a69474", + "ea71417c1d9841d4ad51e3522cce4207", + "d7590389c3d4445da4822800f8ebfa65", + "c48878632c60415988c410e852ab8b14", + "0e840e66012544178fb372274c2ae340", + "b7357866e35e4e1181e7488ae0577bdb", + "2cdbba1da1574f7986c85c96c9fa8716", + "0cb168c5176047439bfa91cd6599420c", + "9fcc9f3a4d184ba1a73a0b9431fb6552", + "c157935029774ccfb5a58f634cc58793", + "cbc798efa59d4d84a199edb1ffcbf547", + "bdc36b1402794c77bf4c0987f8399c8f", + "2cb8488d2bd24bf991053aba6798f869", + "961d2dd1e0f44ffdaa785058f76c4d53", + "4eac61bd39354aed9a8b716dae7f25f7", + "483fa14bd2804dd994acd137948bed97", + "0d6f1b3b07174a169d518ad12f6e2c0b", + "a4369ec6aa814f25954b0f01b04e888d", + "4949ac39d6744007b8268770451db986", + "fdb47e3496ef4cf5901313ea76ca23dd", + "82ef82c688484eeb8b6ce4320a3a41e2", + "c4d98ebaecec4f93853e50fbc5852712", + "2300339a8acf4cdb899fd238df5f006e", + "bc2f3cd9592e4524ba4b637430d4e32a", + "6441fe1ec6744bacaafd3b21c424fc91", + "1722b7b96fab48b4a11e3fc816f9bae2", + "aeb21d38f2274b04a940e0446431e502", + "59f9879327134d68b48f4d29bd9a6958", + "2a4b92a0d32b4e6dba64b9779aa6ae42", + "9f1fe811607440939ec237a224ec355a", + "3629a475d0294b8791ddabd881b5467f", + "43a31b033b1549e3b059246b04d47d9a", + "ab423ce396d94e05b7ae421c4acc43cc", + "78fb0d2d6dfe4d9f8b04da4477e89138", + "2a2bdef868ea448699fd8146b06ac160", + "d1110cebc3ed4b9a8b689d42c50f1a0e", + "0c0263bb58704128969eda0ea75c3150", + "5d6c6d1918b64f75b76f321e8bc7a0ee", + "5b2bb37f68da47d492df2325e464c397", + "8c603870f7984034a229d9ca0849df08", + "2e6df49b571d40b795532a78c8decfb2", + "610d94b2f85843b68404b6e69e58cb3d", + "05fa6151b41b4dbdb8633431135ad3cf", + "aebc93f3a0c443bd94a08f934323982d", + "befa3f35d1614027b6f02b80cb59afdc", + "225f0489a9794033bc7e2c9315fcdb1e", + "4c06e83b2c0d47b796d286a85b41bf2e", + "2919081a8ffe42dc8f21b552d7a24546", + "e54dc0a9e57345b691d1b5f66f3a49aa", + "ca533feee43e40099ec0a5ff2da5f4a5", + "92ed1dee5a3149cc92a862795b87ead4", + "7a1c5e570a9545c8b1316d0cf278c707", + "5d9771cd0b2e4b7f933d96087790d57f", + "bf6e7c0c748b47259677b7d4a33a0a5f", + "86da408f5b9c4b209310856c7d5ded77", + "85cbd74445ba4d19b2bbf532300821cc", + "bdc9ab4a846c49748b6a367d618f50e3", + "389078a5e6a6482aa3fb8642c6e112e2", + "9a466e88e8b24809b1b24428aa9b8d81", + "f8dd844d69d1456bacde4230e7ce9def", + "65515ed051e943e9bf988bf3318171c9", + "8702e4ba10ae40d8b58f61afc819c42d", + "619fb3582d704b11a3150a139043e0b1", + "fd35bebdb5c444fbb917dfd1979ab4e2", + "44f633120a434b71931dacf9c8235184", + "421cb6e21ac94abd826c5b28a5b39ee9", + "67407e8280974606a23d011c3da1fe1f", + "5095da65fa3845378fb2281e690ac801", + "72fb01a3d2d54f888aaa90874e134ae5", + "e1f1d2db99024853b3b7b6f43c055841", + "7e26e4c0dac94177b1d7b8daa8f41375", + "3d59bdf802704734a5ac60def30c9912", + "2628a80d4f454d75b5209df98d70a10e", + "eb6bbf726ed040c78371b87d224730c6", + "febe789cb2034ab1b7a3b5b9c33a05b3", + "9e194868da754d55afc876127dc8f74b", + "740e5d955a4f47dd9471902ed5d0aa6d", + "f2566811d3e44e85bbd8a1de92b5e053", + "2162ffbd1e674f0b8771dd35f0cd3f01", + "786e6d1ad19444f69da7bbec161d5eee", + "bfb2e482b27f4e49bd51f75d4b64a42d", + "384b947644154b368e23e077310f1268", + "6607918f4e894a12a187407b6224a42a", + "781e14252fd745bab52da09998441f5b", + "5229d196836a4fba8ceb834c1c0f5068", + "3111a9198a9f440d8116196f38d6bac7", + "356331c6ccf5437ea5de49886bffac40", + "2c1f8ffd2fc240eeb495d4e4f1274792", + "5914ea701e4648e2bc0d5c265b7b4059", + "f1a0e1c30965471aabfe64764184dca8", + "9753fcce430a463aa463240cea633d99", + "887060bec4924028815be1e133da5eec", + "0ad1b883c76c4591b9a04b0b656eda20", + "b2e3c75ff4dd41d6828bcf2d6354388d", + "40ac7442dcac41649415d5f57ef0f6a2", + "89b4ecbae24e4b7594ee8146eeee51a5", + "08ccb25dce7d4ec080686557676ca382", + "0c50e6e250af4f9fa3a2bcfb902a440f", + "3d9bc3fe92934c998ada834711c1ed6e", + "4204828e5e6d4de591aafa6605c13ebd", + "cdfd37d339da40389a2980ae0e6293e2", + "7e1a73208303481f98a39c5117df501e", + "4a199a2264d44fd69e5114730e774ae6", + "fc89fe933afe448084682263a5d0f10e", + "299d5672071e4954802237fb2f59ac22", + "f651bcd8d135493ab901b6c72a4f9e41", + "c2310837dca94c008d3cb31d0c8885bb", + "93c1e467f89f43eaafdfaa6588e92342", + "3c718d25fe814818bd1afbc2e1a12c82", + "4d7702f7ff64425eba0a8588352d3709", + "434f54e4f0ea438aafb4944403b8e5ef", + "123fd8b987174c6d90cc767bbb426df8", + "22e7c6f3dc1b43eb84ce081db6567e85", + "cfe4cc34c61a4826b632f0efc2f5251d", + "f4163676707944da93b6e43641fa534a", + "a4112060b9aa43a8af876f922f962cce", + "c17a25a68fa94ec48b8502d614a18960", + "96a15db1430c47869ccb7ab301ddd36f", + "b1e85b72b4d14309899f037ff46879e2", + "5d811fbdfdd443d9a4c2813ef01b6878", + "50e5d16c8ac9436baa42de018be7ae6f", + "a0b9780e8dc241e6840932c2ff8ad178", + "c1338e44401949c1be64e6668d38c100", + "9fd961a22cb84b9383570869b2f0efa9", + "d545236884ee417aad65c6378769b305", + "5404f764e6054d83ab563037d6c3dabe", + "25c91530364a435cb18f452a05bf08c4", + "ecd1e3f2418246fcb4d4952e4317a123", + "e0c620fa26814303834a42b3a0e09808", + "2f0743a1d27345269d1444a8becfce59", + "db50a1f088e4437cbd68b0510d419721", + "809fab32f5c94cc5916fbd00b7d9f659", + "d6ab7d9dbe1c40f5b8643bf02af21eaf", + "c1fb598c0063452b9a40eb10be5305c0", + "f654bfb8ae2b48dfac9ba5b6a86708d8", + "b327c7ee12f348de9c0b6081e7355f2a", + "a9a363b8c97644f18baf328105811ac4", + "37ad3ee717f64bab91565745a12319f4", + "5ef3d157916148e98f414f86b75aa824", + "674db922826f4c468d9672ad16e199f8", + "b1dcc2e6d6f54aaa90c15d9092d0a32e", + "dfed97ce1fe44f11a7a62def17c6d1ad", + "8078813c567542a3976f782e6c588905", + "8beba6076f024a5390ffde336e91577b", + "4d9f0aaa17ca4974aadd6c3566a7cf0f", + "b384e34bead84192b101dc029a859000", + "41c8f38c11f84baeb224c23c34233821", + "2dcec7bf3b6f479da33b28f50a578212", + "12129ccec914482dad760607dfb8583a", + "27b96c1b84ce4d6b8f1d3ea1fe780860", + "df6b010c8c4d46ca82ef984886d5a3f1", + "6055192e98664de2ac018c66294c0be0", + "e5aa03a5ac98441ebcff7b0270142291", + "ba823543b748494ab2a0da808acc56be", + "48123faca1774f79ab9e9dd410399323", + "26354cd6800744289bc1754cab8dbd4b", + "3a7e7cb8d062471dab1f4245a157d8c3", + "698156b9d9244ac78b67be4a6543deb0", + "9aed1de5f9434435a461c597360d9a91", + "842020ff8e474c15bed3b39db8298ae7", + "8fe5484d7735400db30c7b2e2e30b6d3", + "833f16e58245472e81ba424e43e2442b", + "04e4354b5c5048a69f03597c3e5872d2", + "6326e584b11a40cab68473b7bdff12bd", + "54a9ecef1895457487c63e91c8cfd5cc", + "ee5b3a2598824355b1ad5d13af1c083f", + "1575de83fa9f460aac62b72b715dddae", + "48738eced27746dbb8716a520dce2112", + "8e846acba94e44aaba3963ad2fef6909", + "4cfaefe43ba44cafa4b4b695eee75f3b", + "885b3b0d17be4bf29edb69d9000d1e0a", + "b5b3bfa374ae4b35a4dc839a5f453ccd", + "40146275463249dd87511ce2422575aa", + "48fd4f6e90d84d89b5740ee78587d0ff", + "fe4339a62a544ec081d23f85e1a8c7f7", + "1f1139d167304ea59626ef851d14dadd", + "593531cc188044c7bf5d716b50dd4a34", + "b05c601bb6b14735b8ef47f3f73674a8", + "cc6e8595709048b39519b5276452e237", + "5e48ccbd57b14e5482569e0168276880", + "dd764687cf90471d8f575c7cb62196b2", + "cca4a870e5b4475bab9f8ca848e46cd9", + "ee37bd783da64cf9a4c341e377c3e7b9", + "cace4f8d3c4846faa40796d883cdcd88", + "2091b93b135b4d65934365c51e8505c3", + "2b3e80b25a434b15b31cd5078b7f059a", + "ce3382f53a27486b96d9ac5ba2b14d55", + "f794ec5130424adaa18d025d65aaac13", + "ed8577a03a0148e68e9c1c9dcd59dacc", + "67c284806362449eb158ee9581746c71", + "920b9b5e4ae64f30a2280855080f80a4", + "b6386ac278674a3c962262b607abb420", + "bca5b11c49e444e18363c11a8436af15", + "01ec0eca84584d7c81972cf2672c9e7d", + "192d0b1de17f4fcdbfeca3fe873c7bdf", + "abeafbc37d6446058e1be53e67e0baef", + "e8196d182de94b52914ee491d605f971", + "77331e235b4a47f58943f4f6eab12c66", + "7b7b09d3e15348f4bc32db9afdccb41c", + "24dcffc5477a41de885a90c722012a0f", + "c04ec783be2041a6a7d7491fe5bafb59", + "a020beed33d24527b2c03ef59b1c7291", + "82e476a7e17a4593adc8c2a3179b4fb2", + "9d6ca5a3f0cd4f82a000603909c9c180", + "f2a213dd42c943489d58ab0dc696e1eb", + "8565a55b2ebd42aba238fc071060a70c", + "7a9e79960bb34a619dccb6998a99fe28", + "d3d0b478357f43c991bdf4eea88d1853", + "c2f48e3f95b64be2a7a70a8871f62f43", + "c66ca5635c2a42178b7dc5c5e547c404", + "b34ef557dc04429789c3338dc20ab3f3", + "ef0253ad994a4f808c42fccafed066e8", + "96d0e25b866c48dbb7c90d26298c91e1", + "8112a2098558473e8aaba1f7ede21800", + "572ff4b067a247f18c176599ad45c67b", + "781d6c1e3327489487bfba83ba53a82b", + "553c699f85fe45b58baf89db4e28cf15", + "8048d606fcb54bcc9b3e0b52c5d6a394", + "5d20918db52e47cbad6c7194db202075", + "37abbe8868e44a3c895bc79791425817", + "8ab1f9f3e6eb4adfa22c29351aae5d30", + "2c60fb7ca1e04933a61f578ee7a02c44", + "e6710ba4ae874ffb9c1f840a759dfec9", + "782a66b9cb8d42a88a7a5b6031b628ac", + "068c936a5343457eb9d4907234ea655f", + "dbace2dc5831441bbdf4d676e09e8abb", + "c2f5c0ec60ef487f8387496a2f771669", + "a83153e924c646fa9c0f9e041139b136", + "ca121c1f31a24824921f686f60a89359", + "b56be27d1f674349aacbb1352c6f914f", + "acc232eb79fc438b963823b6047cd919", + "2f45d519fc934e1bab5c9234fa33e6bf", + "9104ac024c8c4e4b80e5664c8a18fbce", + "88965eb5298d43d8afdaadaa6d8e1c2e", + "de4b883c58004a4eabbef4559f024735", + "ffc719a658354c2fbf833f3377e59081", + "4179ed636e2f4d47bb82691f7f536e84", + "667dc890cc7e4f68a8ac09bd069996cc", + "6a7a8e3060dc46dfa3d9c83f2169f371", + "897c70e0a023484d8cd2d87bd0f83c06", + "efa778ca442945b09300a70e34e68532", + "952c166d3ca540ddae7dd86c02c964ec", + "29b211c7b1574fd7863e669cf5db6832", + "4f7d1fb61753490da5c5001ce23149a5", + "cd12747a36c54cce8befd8faa2f2dee0", + "929f570129dc438eafe2cf7083fe98a9", + "5ad0f035a45a424291b5efa0a2a235f9", + "9ac6aa4fa5be4c0c9d03b5fa43345158", + "6425b54cbdb94219b1eb25b8ecdde6b8", + "af6ca88ada3842a382aea10163e875a5", + "fa4ef40a462d4f0994e77bd20072629e", + "8090e348038840d680aa296800550006", + "3e24dd9c694f45e1b3be2781561f0112", + "6a440d28424c451098a6ebbe51c848c7", + "005e3725b8d9484e94a71aeb9495aea6", + "955d09c7df624d77900b5500c5f5a1ac", + "b77fcf18510f410c915456193111a8db", + "f21a43f051f24c3d94bcd412948fd030", + "37ca6bdc2d214891a8bfc18b6166897d", + "294ab037e7004247ad775d657d3d4144", + "acef314e70264b9baa64b6506308a7c1", + "f2d7009d517a4fdb94937970ff6c3c2d", + "03b311710f5347dba54513de19199104", + "1b5aacd6e15d43d088964f679254e1d5", + "e340cfee9707468eab5f0250913ea1cc", + "ae54ed6897e7487484f96e0aae64d39d", + "506802a76f564f189a9a6a10a165acf7", + "20b990d003534ed08055d7b34493b2e3", + "484e6b44690a49b9aa63f5c04189d6d4", + "842284ca02804217b138b4687d8e0844", + "852a63f852584448a49d643ae944506e", + "7b8160d5c0c14b478029230d8a88bc33", + "ad7011caa5714a9dae06bfd54e220dc4", + "71199b86b8874de5a8823453c266e0e8", + "14b98b39474e49b49f0421b086a749aa", + "8182313edbfd4ade87c33bfb62e947e9", + "da3ca02151ca4130bf42834c75ff9126", + "ede6e2c3c8d644b09d44e6c83f6ca206", + "16416c467b174bc3b487655e95318987", + "8b1646c602ba4c758b48efb780f55a36", + "774c2cda63ad452cb722eee268bb0e21", + "292621234cdb42969c76680ce8100088", + "a2182bfeb53e4682a90f38dff752ef8a", + "40fe1e3a9dc645afaab0caffe6a5f81d", + "6b91e07e87664518b3caa190b86f2b4d", + "f1c382112c9e4f609c238a064fe7c6aa", + "800ba0d317de4b86b0e3646416c77193", + "f1fbf47a807143e9abb061f94c3bd6bc", + "63f09d19e88f4228b40c64425ba58b43", + "daf2f53b8eb2466dbffe92f6fe7069e6", + "783e2f9a2e5b44a985aaca74c347a5bf", + "147e2dbf27b142f6b4a85c77837ef02e", + "fd0c046a25fb464184bff7263bc3ffab", + "43a38d0e44234b679884f0e8d394c12d", + "0bbf6713817648f59e98de8861ba3913", + "ea1800fb5ecb47d99e39041db34862c1", + "3457cd69aee4442e87333e57943573af", + "bd2b824c98b34bd2a09462524452492c", + "caaf76f4506f4b01a2dffb553bae9342", + "ad7c112ca4cb423badd9d22610d6cd04", + "a932b7b42f554473a37db4e619aada48", + "ace4b731a17f4b00b9ae00b50f9910d2", + "bab2d06e16064619ac4f6ccf976f0d0a", + "4f32af3b4d3f4e41aecaa9d8f4d76ca5", + "0a80a213ae874021a82069bd5dee6af9", + "803117d73cb04619947f93b3b7a1cf3b", + "0f52c52e3bb2422aabee8d73fc4cc5ba", + "ff4c7aed4a664a0982b580cdb016aa6f", + "8fba1e7048c0421fb7e6b6e8be8fce88", + "10187bc37c9e42ef8770b28452ee7cd3", + "004bef020bb34445b2b31e97552cd421", + "283c1f3a3a4b4a9399fdbf9197e9a022", + "aefae4aaa0c54c1dafa842e27541341a", + "5fd07d04a0984c8985eba52a617b2dd3", + "ab37bb2a24c8485a8061fe8a3bb4debe", + "f60c11d2cf7944f88a5612138281db8d", + "ece0cd544108424ba1e665db2149d74d", + "7534d22f047c49acace85ddeccceef50", + "9e905cf8d59840bbb86fac19f86f34cb", + "f0f5f83715ef48b081915d990c345068", + "f536745fd82144eeb5cc4900a48e816e", + "93eefe10f4f648a099e0fff7954c56b5", + "aa993e9bc4854285830f9b2c9a9b72d6", + "1d4afb668a714188935966d3ee9b2e33", + "90de6d1e5d4b4a3093617e4d926835ac", + "5e11379a0b7b4014b0ac6003e950a3f8", + "fda442d5a1504affb6608cb3d81a085e", + "383a984a96d34845a6ae99faec09dd31", + "42737da524e14c07ac7b35f3e64c1d69", + "f4ce57bc858940af9bbb3907231edf87", + "18a1ceb4464c47469d7b6931ebab8700", + "3f35f4a5051e4136b54575995494cdd6", + "948d92f51a89422399e31ee2c3650c64", + "37809cf8a36442b1a412abc27348ad8e", + "c421c1db43154a21b3415b3068f76ba4", + "d5b01ea213cd490eaf98d0fb68848306", + "4e365c86d190478a9131b5058bfad23f", + "fb9bbfa411714fc5a455ffa16a87e054", + "a5c178713aae4cb6b19a3653a31b9fbb", + "1b776393073b4e2cac91ceaa48ef752c", + "6930ed2ea2574279937d5e2d96c9dccf", + "21b2513827744464b8d18083042380b5", + "44f10278ede4418d9df60b1eb58d5113", + "cf0dcbbf37084d0ba649bfc842b55759", + "486d457e5bc5438fa0128274fb97c22b", + "5b194ba28e1c4efbbf0875cc313b3674", + "0e708d1e0ce0447ba5637a5320f5729c", + "cfc6c6d0642f4a6f8a2cc9d39f3cefb5", + "90cbed27e8ce4b7a9202e996f816974b", + "e49f69782f02470795820a0865dccb04", + "73d35ab1db52466b9c70d321fa5ae024", + "e4c3a6c20b1949c3bef3659249ea23ec", + "05a7d1d72e5e4a5ebfe7705b8166d362", + "87aa46eb6d3242f699cb1b9fb3cfa4eb", + "d44ffc8c4e254e2bb87041c2540f8dc3", + "d4b1bdd4467d43f4b4a9f59aed18ff1d", + "00ac994290444f91bce94eb658936fe0", + "b2fbf3d086814e98bcbd471c23e9badd", + "fc985bc7c17b458f933f0160405af0b8", + "cf6094b02d634266a79473063a457244", + "c041b5b11696408088c4229100b6506c", + "26673839e93a412e93524be2cf109672", + "5d2e691731b44df5bd8eba1c7a7695f1", + "339b8902625e4f458882aeb764ecfb0c", + "d4e0b1590a9b4a2ca8a682a4d7d1dff4", + "0a8842d145f0476c8e726f62c78c93a6", + "103a984d3cd0456a95e03498ff8e3307", + "28274600c55a4280b2297f277c5540bd", + "1f698b4d051f46d282b6c6a044b50e0a", + "82b14fac0c084a0dbc5826d6526e8e62", + "eb700168ef994b96bc7865febae8c2ab", + "46da6b4b3a8e439e9192c76ca12fb176", + "0d9fb15eb0dd4de3937d7273888d9e06", + "17eb1ce141a946da89455feefdcbe650", + "85ca97658af94d03b3057d4562ad41ce", + "2397e27e45924de9b53b3c65642c435a", + "6acc715ffa2b4232b04a872fec5e1cea", + "9a4ca1bb560a469394996a45aebdbf86", + "2392d8cde5e240d8a0b35f7d762580fe", + "3d9327da17a447b5acc9b3784f460853", + "4b2983cc8e284a039f423e95c0fc41be", + "683c14c972a14f5396b7d423a26e8625", + "35c1c29616e146c59a39dcfbd56795db", + "b9ee0e80c94f4cb892a5b14fae1436be", + "0ed30c2278d941f9b04d2ddc51f35bed", + "73b856529f954ce3808a358cb3cf8e64", + "ec2dc94e022547beadee622b1ff34a5d", + "f9f57e75c23449ef8e844af9418d0d1f", + "bd7d993037a9473e99d380944c7bf5a1", + "2032ce20266a463dbdd1174fc6c09eb2", + "93521e214b8e4039aafde0833d104786", + "68fbfcf86cd042ecbba518e2d8c83cc1", + "f72642a034744cf5966f29a85eba4d05", + "2a66bd667a2b4103809ceac1a0ba8541", + "7c05b98d60884e12aa05ae00feda5bbe", + "e48cbc9f4e7b44ecb9ba17128be2de90", + "d4ee1942949e4da3ab17f5acc5fb8d2f", + "92042891266c4fc09ee4d6c54330beb2", + "41bb9363f30744048d0dee6889ccd469", + "d352d11ee06a4666a358765a4ccb551b", + "111366aed5b547c5add63937cc4b99e2", + "f3d6340d2985423486ce7dd887fbcf99", + "2f958357ddf048ae881585f3a6eb9e7e", + "bdf06e37a6254c8fa6c4a21320249991", + "ce17aabc51ba47bfbc7342a963b095e9", + "2d865c193e8144339ac366f1490d77b2", + "a6f7179dd15a487c8d4c463cc77eff0b", + "dfa0ff6d319149f8a0b7c9a556ae1210", + "c3b7d0a31071455db92cced63feab66c", + "2759a3b8773a449c82992cc042bb4289", + "f957820ce0c645f5a36d0e89350964ef", + "f184be17b4b2499abd51edd2bceac589", + "c89268927d9d42fc8d5cd949e8ff2bc4", + "cbc08e24225845b4addefb13c23085ed", + "afd46432f222405d8c0216ea9ed2d1e4", + "ca8f44a6e173420593465f83c5e829ef", + "d373849de39a41948bf2481fc51fd070", + "709b7464d77a46b3a7fcbad6741edaf1", + "a817493a83ad492081b818c0bf211797", + "81d93967f1194bc09596040665bc3e20", + "724a76aa05d2446094793e50e06d6e43", + "82c13f3487f84657bff6ae9a028eec49", + "fe3630c0005a4031855f0a39d3e8de81", + "a75289462fb743d1b00fed586f101b7c", + "03b69da8d2c94b5999bcf2605ee2ecd9", + "6d459af223cb46c8a78923a19538c5c0", + "565aea3028e54b4883e89577c971a43c", + "f4368b6d0ea94b268e728704eb0f9565", + "bba7ca142db74abe8e5d3b353b221f03", + "df145d381f96431d92d1ecd137d2251d", + "ac9898d3f14545e6b7e4aa8436575a30", + "c4d13d4557c341efa241a15b8544974f", + "ecebd5c1be464d2aae52df96f1e547a7", + "e8b8749f6acf42d38fb138b1258e2d11", + "fc06f7d9e1ab4981bee5adee2313173c", + "5954ff00a1df4147b83fa69b8ce47221", + "df10878c17b0410bb7984c0068b7eb85", + "72c18e357bd940068f2cdcd1a79fd5f5", + "7d65d348d5b345abb9836baaf3738ce9", + "62b442ef57b148c8b893beb56b2043aa", + "a0b35383783f4526b0025cc346bace53", + "bf9db78e27e34ab9b029b489c024a5e0", + "2b8040dbbcbc4b1894eb7cd1325a30ae", + "76b1531b0cb74a42952575bf02af5ca6", + "d7454589e56a4e5cb4665ae56eb9ee3c", + "22adabc71629423ca86406146293942b", + "399463ec209b435b8c467dfe343d7628", + "7f92080d86484d81b8dd30317bb28586", + "a581dab363ae4457adc362596b0330af", + "966c78478dd34a1bb581cc8b44db04cb", + "b93d03c2f8874bed87583a8dc2e53d77", + "72556fb70fcf4e988a1fca1cb3999263", + "3290e45558e84457bc297c0b0de89827", + "4b92c2d96bf944a2b94a4cc27dea32b6", + "92ff65712c62408dbe8406fb5c8908d1", + "f959f5e9cdef43dfaee21c017a006515", + "45645807486f4cd19befa4a65a4f2a03", + "9549049a459b4ddb8678a518468722b9", + "2f1ba13a0dcd4e8f96ff20a408f0e2d1", + "95335a4582e24288a32aaccf7364e933", + "e51f94eac4aa4205bf93be66928a7d9f", + "33694952d4e54715a620ab4499d14cbb", + "0c56257ff74e4dc789fa52c5a2620405", + "af510693bc6b456892f55f05c9e02197", + "7aa656976ded42348bf3432459b9517d", + "7b323d3fbea44d6092311dcd12016e18", + "88d55c11209340648290c4028f7de007", + "b72411a8065e4c5688fe27e98f1bf497", + "1b418690fedc45739274d05e81b88ffd", + "dd31d22f0fd3407c8b96df0a5af19894", + "d0dee9a9356b4bee9e0d4cda5bd7f903", + "ef6586852fbf4eafb952a9ac6bacb471", + "b95ee38c708746399153f2b00b52551c", + "5d9073f042274800a5e36129c98c1951", + "765edbf1bed345989049f2489d7bc980", + "c897e6cd6b7b4631b43c0a98469dac17", + "f5e491d9fd684af997f3738c0697c00c", + "6d02909a15964a36b49714ba6798c422", + "0657dbe783b949efbf62ee2583097029", + "7246b990dbb14c3caecfc4c7c2e70edf", + "72e0a59c1db545e899cfbb433337717b", + "58933b9685694c68a3c9f7e713d35003", + "302a313c27e349ff8f85d1e7c848d995", + "155e90546a374da0943c56118c01db9d", + "a363807ddbf649949303c52a9a3fbe3a", + "15103e8b557b4498ac39fa63934e5543", + "9d7aad765295411fa28f08cb93e599b5", + "122bef21e3fd46a89d6a099d411f02d7", + "783d2d80f163497aa02fda539e82755e", + "5c6f14140c8f492391c464c308190c62", + "4d16e8e3344f4c7499cf9d2c488e4c9b", + "bd9122f48db44881b3ccfadd63b1d219", + "285a4529911c43929396a21d19cbea74", + "b6efe4e2f87f42318943974bff072c25", + "1bf163160fa34a2bac8c9c6218675478", + "51dba5eb17c24e0c9fbd1f817505cd60", + "fef19d409ba94541b2e5aa4b13ea4975", + "5795b81cb8704f26a1cd1a6c31f15988", + "89f8f9a19a6c4c069aa79d613050450c", + "935a052e665b44348ea397da446a5852", + "e2462871cc894914adbdb8722838c3b0", + "e4763262165b4253b97d61af105cc90b", + "1f11ec52bd8c4421abc18f45197c198e", + "700b552e2a1c4080a5582e23ca379cd2", + "63630134a61b488fb95b6b83243bcfa0", + "af0c001ba99a4d44911caa948801359c", + "e448234a5f0c4d3ea59531f6a4e8c756", + "f59dc96c92d640da8592e995ff13f804", + "74535e12bd4c47a98105845c114e2bfb", + "e7ed7001ca5d47e784712a555db26bd2", + "450236e46fbc43fcb25815e028cdcbac", + "243d550e37264a7d87d437c4df11adea", + "2dd5d447d35545bba17380646e203b14", + "18b60c6979054b6bb2980c5e111a1c75", + "2058f14b03e84aef98cd36cc0fdfd99c", + "15de2061efae49d28176f7dae105b550", + "7831633b382242b89b77621ed3ef6e02", + "c693391735e9444183b88e7093014141", + "ae5a4a3e5c934d0bbdfbd78a75bb286a", + "6afd7a17e1384568b50b7270be20724a", + "a1ccd8fa9c0d4050a440157b6f734bc8", + "5c46e721a8604ef1aded680a3ee59018", + "fc10a3bd04ed495facda59faed87d600", + "79d2efd45f6c4782a822e693e6d50585", + "c076c78cc47f49cfb68e24c8731d60ed", + "e37e9b7bc8ce44b4af0702e07a549ef6", + "5667b981e1214d3580c529685ee3e7f6", + "c04866e573304ab29d6179d6d6c3bfce", + "e122ddf1829c4c1f958f38f70835bb86", + "57abc07bb5f4455aba4b0c14fda4a273", + "d9374c880c80434da39cb7d3aa420477", + "d464a17419b842e6bd0c56c8b9c92132", + "f2d5130daaf7414b892bafdca0f38a6a", + "58710cbfdcb740288b432998c140920e", + "90ad05c2929d40bd8998ae74b0d5813a", + "796523ecadb24b799e2a673fc48246bb", + "822c012ec4f4427d9f36929db2618260", + "b538af1a479242b69b76aa5e288b3bb4", + "4528c95e2c0c425585fc3a3f49f6bad9", + "e34f758004b24837a6688ad7cfce70fd", + "f699052fd5d7428ca67ba8e84afa1246", + "b8902b4ad8c74b50ac68b289a13a14ed", + "cbb8037ffaf34988a83266162a9f5423", + "c4263723ebb64c7da734946ea5ca27f9", + "035940399e0f492ba614817a99243eb0", + "a2f041ab9bff47529d3555708701dd91", + "32d17951703b4e05abed11a1c65f5909", + "5cc2bb8c64cd401c8b7c0c0625ab6ae7", + "057658eddc6a4729af79b02ca1e68513", + "9f4e1b7572b2494c97e8ceaa85b41cbc", + "f8b65fdd446742f6ba13038e5d9bae32", + "f8f2ac12f1b245dd91f0139a8755784a", + "f47d1265b095412481afaa41fe2de24a", + "6554b42b89c14beaaf7a921e4e51e29f", + "a19367aa0f84491d94e49612acf3a5b4", + "dcb283e4c48a47dfa70e7844a89d82ce", + "4bc0b18d07d94af0b192cc3e52ecd58e", + "43c8828e83124e1e90e85c9e57b404c8", + "4009109c83144e82899f8d9bb80960a9", + "de689014ee404dde90fad574a08149f9", + "6bfa6420cc464081b90afc806e3997da", + "9df575f5d85945129e4c73248b2cbbcf", + "769f8f845ba9457496d13b9d48787936", + "489266e9e2c44b5fbba13b2d933956f8", + "7d9851a8f4584c9197c825fe2b7266c3", + "cd9d25a99f2a4b3fa68c2e4a00481564", + "9afccd18cf294158b9ef976cd9c7bbf8", + "3291d6a301e548418d6d7cff145f355e", + "600a7775f4644a2c9c562abde136cd17", + "e7cf91ebc40443e2b9f930f604e4a040", + "d90c7f830f9c41398bb55de4a2e001be", + "3f140fc66d85455391e10baaa31fb5fa", + "f58bdf8de83d46e7be542ceeec7214ef", + "dfc462fb314a4ca2985b6ed7090d1e90", + "ef87a40c8fff4fb5ad20ea62c0f93ea8", + "0a2f4c3c75cc4c3399fc85a480e23b6b", + "9b20cc2fe37c4a189cdccb5e454ccd8a", + "b80246878f17451184b098df7b081cb7", + "8b5262b452fd47708d3227610d0aaff0", + "64998ee900d641d2b5096caaa5cdf006", + "128cb601059a45c2ba69b1823f94a4e8", + "f353b1d5b37c47da9970a25db4d79925", + "dbfa0f98cc774d01acbab1281c191b3a", + "effe3639486947c6b14dd1d2b573242a", + "c0a26335369947419d833134143a8aa7", + "04f214f6e969458ba7d6b91970eb3d6b", + "39076c677c0c49c399149016e390eea1", + "fb9c3a1ce13047de8f2449437e6bd325", + "6ca29c04aea54b0ca970e3968a83b1a9", + "8e0c87fa3d9f4314a6c2faf21b60e7fd", + "ce6d60a53ae9436294e18a6260022afb", + "77a9e78def324912ad26a378aa06403a", + "d690654a1dc644269f00855c69f508a2", + "33065ee8618b4e27bcdd46a9776ef534", + "7642cc93fcb24c398af98476f5f0ae83", + "17629c39c3474d199e63d638596c9420", + "2a981b97b0be4e7281232f1f10c9c8b7", + "d7644cd717124aa395607ff1ff6ba360", + "025d2d8615294deb847affe5f5534f37", + "df27288416df409891c3432a8ca23cd9", + "b0eebb6d4c874708be1c00276125f440", + "9d5448676ce94a8c82d120630577ebcd", + "50d68ae04ddb4ec897ffd72c23d9f937", + "a60e9bf5741646d78dfa12de4c7dbc0a", + "c6c2b4cc101c4ccda903bfe33f0639fc", + "601abad81a354192b2f47b88bfd32c8b", + "34060f6962944d4795ec4d6743350fc6", + "7727eee3068d4e3d9fca0c77b8506485", + "7e19c25fdbda4a89a4cb002676f6d4ae", + "20d6bb3aa6a74bd79e417fa841babcde", + "b6361d444ed24591b15b9b28d39ac2e0", + "fc347fa4d3b84a3c99df887a36c4e2fe", + "524e3301658c46a1888ecb46ac96b016", + "0c15255053f14ff0b28fa0fcd6a90115", + "eb791747cd334c2ba2261c826dd7fc30", + "1051b03086ba4388816a4b41fa96aee5", + "c0e527763360462985d305a7dfbb52e3", + "5fea87d107234eb89fbe267510939763", + "2ad083f232464b1186df4e752e586e3e", + "2fb4ce922d48466c9ae9cac570bbb41a", + "001a994fe20b48739e18cf8a4e9d6fa7", + "381e38bcf5b142ebad2c26df44d8cd11", + "ae0258a594bb44c4acf339a20e906431", + "cf33e2df757d4210a97d673093105138", + "6ec82b946a4e4447bca511daa8e5a7b9", + "422fb3960e3e45cb86e6afcd8a8f223f", + "c268b7cb334b4d2a8ccfaad3219603b3", + "932c037c0b30461891f8af1abaa9e7a1", + "6abe7c3d35de41349d416e1941d74bdb", + "2345603eec5e4e54a293c39833684525", + "92e8a44f3259460d99de2e6d20b00606", + "7936daa6416f4f57a60e9e76bd3b4bca", + "e5c62a05e35f4fe2bd0924b4b56b79a6", + "820d7900024f41978b3377810c172a48", + "a6104fabe1f8458dbae8ec348ae9432e", + "5ca3b4bdb3344824babb59ce9787573b", + "c4c74f0471394312b2b087a35833fb18", + "be4d85d133984f56ac6341fc6f01a38c", + "f640e3f4e2224643b76646b6847622a4", + "de99e817cbd7449f9238087dd6cdd53c", + "883ed84a09e64a0e9840fc5a307f04df", + "70483b20fb9646dab796135f06ac531d", + "fa50876774f742aeafb080d5a0006c4a", + "6e19e6f7b21048aaaf75c2e6487132af", + "9edd92b9ce47494499568bd79692cd1b", + "b5c94eb235cd4574a069f900e285ecea", + "fc817ca0bff440b0b184c2eeb84a6427", + "eef01b5f8ab14e3d8304bf6b437f2760", + "66cdb12bb3f34cfebbc95f6d82e53c3f", + "ea56d5c5e9d64eef971c264398350b85", + "663fa19bdcf14edab8cc90286996603d", + "683d408f83514001839845adcda008b7", + "2bb225e609604b60ae38d05bb7c0d75a", + "95ec5c318e0c4caba484d874da8f62c0", + "7dac64c06a1a49338f6573cd7c4e0cdc", + "b32cfba9c01d436f8eb3083ba248c186", + "e3ba3bf0fa16492b89f1439caee5083e", + "ebf2744c3c9c45a083588ad2fba57e68", + "d86376f3cc7e4cf595d9e984b39342e6", + "c8439db4ad2544ee869be621584e2c13", + "663b8b4d986844d388c680becbfd1f42", + "1f8bfcb47e78442ea3df4c739296b2e2", + "fda2d273f8a1435a96aa7cd1974fdc16", + "29af0b349bbd4faeb639e85344706a06", + "29e7d63b8b0d4e31836ece7090c9b1f6", + "09e0ad42f8af4fc9b5ff7816f523a7ce", + "6c0681e9f8ad4ab39d01025646e62ee1", + "b700e5b406da4338827dd19660b2ecda", + "c5f013cd391c4b0ca041e44b2a3337a9", + "4de4f3a86d6b435e90755ac29ecc002f", + "67c1247b7c1248f0ae696b913c555ca9", + "26ecb909ac4e402ebbb9d430598a2254", + "b3101b84f826423697c46c302e840deb", + "08bd8ca1e1c34540bc66c3e1d4f7f287", + "6e9f73510e3340e38838c40bcadb0d2f", + "7b1c177d4292480b85311a196e5080b0", + "7bc441e2c6cc4fc0a80a548fa4c68260", + "cdfca314bf0d4c348dccca1f6441d497", + "de5382f07a38467b9a6047b1afafd604", + "99f0887fd95145b7bc24e284be3d03fb", + "b3373981536640b98483a890d9a14060", + "5fd45ae9f2af46e3910bae04c0fbcb86", + "e39cbf7251b64bd6aeb5d0e01dfaa7f4", + "49e793ffcb684484a80b5f902d310946", + "0847d97a51aa4fc4b93b5d2557c318e2", + "66b282e65d3b4da8a883ae8579bfb33c", + "49cdc200eaf640489b99ca818165427a", + "19df87a3e28747a185ad949cf6f32933", + "775b43fe44a045c58fadaae42ab710c3", + "b9dcf679efbd4e5e95d7d6f5caaf6c1b", + "e2db7ceddb4246d1b880790863921d73", + "0110176112124a15ae2a97574a4a5895", + "ee0229f75b72438c9a858afe4f47ec8b", + "54b56ce71d054d60ab31425757a45cf7", + "33e3ee24e353431c83561c96faa6454e", + "418403a18f9948679d4272261cab4fe2", + "c5f828cf2c52461496a058f590e26cd6", + "4740195a7dfe4273be66a2c3c172a793", + "9eefd64788d040ffb765813b3da64333", + "a7625aa0bec84cd1ad71d8b9dcf115a4", + "26b056ab4c584d5ebe4234cfa865690b", + "7c39473ded9b4503b2f29d34c676dc08", + "bf0d2bc20ef940fe9a9d21613a895619", + "4d803603292845abae77cb7ea154a9c3", + "3da0c91738b64095bb9c0d987b6b5b57", + "7897b4c642f7429e873b08c790717c19", + "cf9d4ac001b545d684a5ba599e842dbc", + "7f01241325094db7b053a706499a9f06", + "04d95460c8014ffcb637ee64f0b41f6e", + "ea7da75b937847a9a1593c674c6e88d5", + "06a1025c30c847cca5f50064b8f7b0cf", + "33172c4e091e4af8bfa0071363ac6019", + "8ec7d178bdc140c6a20bad2386c8aa1e", + "ef66ddded4f14d55ae02eff8d445fcb7", + "21827b3100cf49d09dfd0f9f815d6ba7", + "842989f9dc4a4d3fb817f1517bf7ec4e", + "771a9b875a1b4baa91aff1d3ef4afabd", + "397e9951063f41769e5512dc74a484ea", + "0716cddd4b14421fb4db6eaedf59375f", + "b86b2f4d79c94531b8385b6397ac5600", + "6fc8997023a243fa8c94186f120d6eeb", + "eb130fcd003b4094aef0b7ea127d41c2", + "a4d9a0fbe5d844769c1865d7b9a6ad9d", + "1010d971cfe44b1aa8ff9b8350048f95", + "1f58aded768144539a67789fc9b4f59f", + "1804be5931164fe1a07db120d8fa033a", + "de602237595e447aac164858823d1572", + "bde2bc2bdf9b4bed85de529287eeffaf", + "8d620ada51e4448c9918d156abeacde7", + "17ad93f2e13a43ce8b9e1260c91ea9d5", + "b5709832fcde4254826090faa5fd8ad2", + "a6ff501e9c62452bbbe21e48df4def9d", + "3f244e65bff74f7e9c42655b41fee7b5", + "ae47fb3d061045569f1089aaabd840ca", + "4ebfa409ec98477cb3d78e0b6788941b", + "f8779434ed734c708baf2d2b4fb710f1", + "6b482f246ba84b49a59439731fe5c980", + "54325d61e5154117ae3038036487b7a1", + "1f6d8322912746a39b0c90c012fc910b", + "8169c87768c2438e95fe1047516f3bf7", + "578a8e3039834842989a1de9b893356a", + "eb61f24679654b0886bb97556193f771", + "68f42012751d4f2eb8e5b0d331a45892", + "69f1c0489a144f3c98e66dcfe72b3969", + "8d92600f641e4e1daeed9705afbb21bf", + "7f558fcd893a4a78aaa6e91e41ce798f", + "8298dabcec59406f9dca8eff370e2f7b", + "cb4bdf57933446988fc94081052a7cc5", + "b0a85651bffc4a498144f058e243f003", + "fa4681e9934e49ddaf51f110a4c989c6", + "4108d53b5a674b868d1e1d94144ed795", + "2b22e0705283414f9d4ac074ea2ad9f8", + "414fcbd163784665a371908362f2e965", + "3317dab62c6e458088a6575ed4c286c0", + "a0a09945abbb4aa1a853176a5dae5731", + "4a51c5baf04e49d4aa684b308165dfd5", + "b7e25d2b684747c08e90b8cf446bdb43", + "9bdacb0aed784c5fbd27ca104cbabf61", + "673907bd73384332b426d2dd8cc5edec", + "8a2e8ea27e6d40f0b3776cbe3a7d6101", + "0c30d20087604a84aa05893aee6823fd", + "353df240658049afaf6619266dfae4cd", + "bd8b3218695e42cea5290f113c630a1a", + "34e10445f90940c9b4708340682cc71b", + "cddeaa28d7d548fb8499fb187de41e0a", + "b9d055e0f5f24aaeae7571ec6a98d5f1", + "8dc7c518b313431da55094134bf8d79a", + "cb31e638a6dd42c48a29911706f96c78", + "6596fe999a4b4aa890d607409bcdab07", + "b70e7b02af84436d8a2563a74bdb0dc8", + "fca10e4c57f543fe8a5153551b551c7f", + "9f83f5090b1d449fa69350aed9dce10c", + "a3f4b43dfffd438f90a985b7f0c28090", + "090857589888406c94b8c22b8198b110", + "460c8d31ee2349679efee969ffd80fa0", + "786da44988f646a99fbd61a4e26af886", + "969285ae788c41cd914387cecf088708", + "ead01cc33fbc414795bfa835c19094f5", + "3b2ccb0cc5fc4dda8c929300ccd3d49c", + "9c51e91a7a9641bba7a2e8d756ed71f4", + "6bbeddd76e96457993eecfbab5415e09", + "8398765db21d4499920cac3f355d7e7c", + "45f9e55f493142a99b1673e4da1a4119", + "35525efda19e43aeae566e8caf93545f", + "88cbd31fd0ec4fb7a27c45eeaa2af596", + "3d1cb9cf4e244dbca966463b31ab6d92", + "70a5253f8cd54d73b081027e0d43ef80", + "668e312f5e77442187871ccee75da012", + "3a9859ba9f89411b99cbcb5352ef8573", + "b83b87a2a78d4f8c8c996ae43969ae56", + "1adc0204c300485e8a1e0f2da568f43f", + "04c91ce29a4d475882fb74b611fea099", + "6b778c1a588b40bcb907fa79c601ec5c", + "2e47ec5ca78e48cfa56fcc2e7c8a117c", + "5646fd127cf34cc49313dd3dd49aeb42", + "bfd10093f8354bebb2f6ba2a520fb89e", + "8e076ba031bb4969930dc8e49d35668d", + "0906b4391bc2490098dbb009e783a699", + "f741994b7d404eac9966313ada5b8a33", + "2555fbb01fd94eaf8d4be0d0361d368c", + "2268f6ba31dd4bd3bb17ad6b34a7545d", + "14cb3dea14864901af33816436a50b53", + "56cb0dc502ad4c8a85b290b358bbc058", + "0754d5b808ed4bd8adae168e23841c81", + "58ab5e16600140c3bcd9fa6b814d91ef", + "84afa6fa58f54bfabce2c9bf7433b827", + "bbf27404dee044dbadf5f508a597dc6e", + "90d05914d8684a9faf5fd40adc134374", + "90d32979dac545c6a465399e453c3484", + "2b608f2128b0492fad8a57e1340bea60", + "b6b80c6a199a411dbfe9c3082a10c365", + "d3f8e57d4cc146f8a43839b448d9ea0c", + "ebda73fde93f4b13b350d532efee5084", + "4e479017b6c14399b7fb7a76d42e14a7", + "68c7f1adcdcb4b6bb32457d1c7442913", + "6b49e3d3b9e649a99c3b75e769d3d522", + "a441874cf347496db7005aaa3960f601", + "6832002547be400e8bc7f46ff5f89e19", + "d8dfd54229a34cc2aa5ea2bdd86f1831", + "16fac8b9cc4e489f8c6f30dcd5773f7d", + "003442052c724e6fb5f38b32a192933c", + "1ebaeb7bd3c84808b43d7f06c7570edf", + "6bb5630e58e145a594a2832affbb2aa6", + "8d9ce1787c534bacbdb7c0452e476003", + "71b3fa39a16c4401bced12a1311c5d18", + "f71d7475ef4c465f89acdb1c18bc7ec0", + "f1a85ce96bfd420f883d8079feee35eb", + "6de641441dc24759803225696eef1b17", + "32ab53cfe10e422d933755f9fe32f88d", + "092d998579834a32acc69cfe59cb4139", + "694ab0c46f874e1ba7e30d2f271b3546", + "de1283e3b23a4fd5aa2e9932c78eba39", + "5b14771ef8564e73880955279d71dc78", + "5bf702b5d0a848c8853a28e5d37aa798", + "38ff74df366146aaafa235f1aff30ce0", + "68d83e2d634940f594df30998aba652c", + "973afdfcd7f54e4e9972c1bc976f4e51", + "94e27c60997849c9b41694f1291be424", + "812122c2907b44148ce0b39279f60bc4", + "cf0a2f438d894c658c19b0d7fc2fb769", + "5744b5b7c29f4aa290fc56aabe869229", + "f019ad2b4933444b8c8ed1b0f7f1d8fb", + "c2ad5758463b4f9490b6c770744e4884", + "a0e587bd3f9e4f2e973d7e9a8c27d3d0", + "69a149e1d61b4a8da5756761c7dfdb24", + "897c331a04dd48c8b6691e4c028ba285", + "3eff3a5b79a44aabb429046de29efc84", + "4ee448ccfda54d478dbfe22c329b9ae1", + "c331e96a3d7646999a8f528316d13686", + "12635b3ac45d4d45a04ecdc43ad5fa61", + "07cde4ef2a774bc18a3ca5f9bf08b90f", + "a5f19eda8f00477b9ba487c7335a903a", + "59dfe67d8ba34d5db858f8b3cfa5d1ec", + "4a6b5f41139f44e0aeb5b13a5ed96d0e", + "b49ded0e7a4b4b3fbb827951e92aca65", + "b38ae5ab27c743968d6575e4ec2c0515", + "98746c2704284e57a3676cd5d767a7d3", + "72a06d293e7a48dc88f651e2fcd639f3", + "515ec5fe998d428c8ccc6e0b1e550d30", + "6f9e5605b41d45d1a90f1afe83420d29", + "0cce98d6a1d644819ff48a2c42000dd2", + "e06845f1871c4027bffaf0b1370653ac", + "9de3d9d0a7df4c85b5e90fb260a9938d", + "d9e755724fb04411bf30b022aff229e7", + "ee25671274534436826f92af7e0191ec", + "f2d9d794171d46b89217bf01621b1e8d", + "cd85bc33522040e8a5d60f4bd66f5ecc", + "8026dc5f17254c9dbaeae2ee6e4f2779", + "041ff9ca49ac4bcaa8e3f07417702c75", + "4670c9d94f2846cf802bb95603926540", + "78a00718ec28407e8746d7407961a75e", + "9b983bd119404a94ae8a0c1271001c51", + "150afe52eb8b4de1a6906aab3dc9eed5", + "108214d790ae41038ca70d4e7782e0cf", + "ada08ecce8184524b640e139050e1fd6", + "d5a085d0983344f2a98efaa651dbdb36", + "fe9bb26f88ce4efd9b0855ea383f3e78", + "6c47cd7ba61d47ea9fde1c08b4eeee4a", + "d59974c6545143528cfda75f28392c62", + "f491eb62aaa24fdeb6dc52a1aab54d0c", + "9fed58e8dc0940dbad9072557cc61834", + "08f1f006b4bb4e04831555cfc1a3ea49", + "276301d570ec40c1a11890c17bafb2b3", + "8dc5487b286a44a9a60c0f22cef4f28d", + "e658620c55b04e21a853ca11fb990d82", + "bb64d4d1448b47ccb788656e5d522ec9", + "d5a1ef2b99d14051af1cf4ca621cbae0", + "cfd44489aa854cfa80fbb71d087ee633", + "cd9cf88f219048b9bf20fba0785eb747", + "d82bc43d5a714c4da30fccce9f5645f6", + "39046b987b664bd7b9e01bf03d188996", + "82492efff077414a894617eb75976358", + "46c3cd7760b54ba79c5e7c8ad5fe0270", + "56148c53e9664ee683b598fadb457992", + "d7efd8b1c963424ebe1eee2ad81df3f4", + "fe9879c5e6884adbb111b7e7dd88df7d", + "d0619d6964d045bf88e08148bdcfea82", + "9131cc9dde9444bf9934fcc1ce53ad43", + "77ff876381194041a525815d4b83d34f", + "7239ceff0bbf4510afe08656553978e0", + "5b79b73d89524c52aadf50ca68e10410", + "545c9ad4d411400f8cf93e97242f3160", + "6de9ad46b6794e78a08af59ebeb04ffd", + "9b2faefff8184144b7734c7aa5e53fdd", + "fb6658f857424bd18cae37d29f600b2b", + "5af587ad47a54a49bd3b8e559efda907", + "ec12601aca1c4f73878de8e985b06bfe", + "5204e63899c448a5b15367fc63d4443f", + "759e930e9b39480c881a047bb9eab6d6", + "6c93ea97a22e40aea4f57a4ba63ba06e", + "765d8da81a4a4905bec9a22d3354c0b6", + "38143712b23a495da9ef595d5dcde668", + "754f9a139a0046d98e6d9f80221f108a", + "9192bd2690894998aa7ff04abaedcc6e", + "688c0525bd564087a24e55a19b45e8d0", + "ffc3230bf88242859de41c0e2c7b9954", + "ba54d94d98a849d7907858587d55d6f3", + "872d486d55c74c5786e030e4218aa530", + "6677fcb1768141e2891165eb61a99fa0", + "7f06b36f3f8d4baf925ec3db19440bbb", + "55b745da340a4727b1837222624fff49", + "c6c08606ed24421f82c465eda33bb6ee", + "6abb1ba39e414450a20d7e8ac096d016", + "1c4018d8e86e476f8afc631396460629", + "48ea397d2cd64bc4a39f4aa98acd29a7", + "ea42d1c2e2af48cea115e22c29ab178b", + "f1b5a0d9e3674c55bc04c9ae395eefa7", + "30ba04c52b2942a89bb4b256c49a7777", + "8846701f077241e6bf4090b5abb19919", + "80303f3ce3bd47debfa63c104636b3cf", + "986ceaeb78b74d88bb0a86791f755851", + "cc77931e16b740bf9c701ce0f82251ad", + "7337db178c83485c923863164e3633c4", + "1cc9fe2b424641058db483d5448008c1", + "b17954980409426894425f895dc21d9c", + "d4f214ab52d54c98a39c925d98fadaca", + "6b72204b2a704e51965651a2a89a4093", + "f7df16f14b6a44b49753ce349c2d646e", + "b5b2e42309144dafaf2efe9b71a491c8", + "d0aa9991edf5438cb11a90ef43a518a1", + "4207d085ed204778b8814e459fbcdaf6", + "1f4ad051c7eb4d62aabb554c2f96a228", + "dbf86a22865544c0b3e81d2a0b8cca55", + "426caebd84a74fe9993bc8b0cbe6ada4", + "cc70e4f946454310867b35db6af2ad3c", + "aaf053bea7ef4171928db4f0456b10e2", + "fe79c57200ad46ee81952c5db4aefa92", + "7243321e0f1b4acf9c1ee72ca44dbd65", + "0e234089ce0f4347adcd31eec8d51fe4", + "8d472329fb1b40bfbc679bf36dec6709", + "76fc919160dc460fbea226bff705862d", + "9c9a63923431488595b4753589695912", + "e575f38bab5d4ed385935504e1e43b1b", + "6e87378f06f64fcf8a032a1606780a0b", + "decb36039a19469ab01dd62fc24b1480", + "28f47235ed4b4deb95d713b08ad2e1c5", + "c5a7b31800b84827bdee0425853d207e", + "2330467cc16f42e19fef2d0a7fe682a5", + "3ca14bf02e474a52b16518f9d694d15a", + "4041fb4050974000a5d47008914305e0", + "3edae53030ea45269fc63817312af4eb", + "b8778f50bdc74902b1aff81dc60df10f", + "50524b18d5a842ffa8cad5217f006914", + "75a7a3a8146849dea698cfd04f73482b", + "8bafbca3288c471f833ebb8071d55f24", + "8031fc7690e640038ff6a6766e97f19d", + "510d8c6ded1d40f2bcd288b614cda035", + "5d97c7ec9ac14e3ba8fe03644460fc0e", + "ca37b2a37380441d91bbdd54be53a40e", + "bdbdbc31b7a547d094c7be3027c5557d", + "ad4be5b7317a415ba067ede99463d42a", + "42025dadae1e4a20b4e25c8c138c86a8", + "aa86c95110234cdbb8bf1dc6050f32cf", + "339b3eace2684658a0deae5ac69719e2", + "8dfc897919d64d939d3f722e83f2ee23", + "887ca82b3c2f4f5ba0bc30c45148a84b", + "f5b9c041fb7e40ccbf9c6630a1978c9d", + "f62910d5adc942c5ac41ef709c94b54d", + "d44b337c669145a0b9df9067fbc6349e", + "ff2344351c384ee4be2adb73c22250e7", + "ec191d88b379427f8ed4dd43efbeb051", + "9458a4cf547d4521a62da7399c53c169", + "bef41fecbdff4a3fac184c6a1645ab35", + "9ec448557f25483a985fe531d02a1c66", + "49d9d35451314abba02fe1c06f779ae7", + "35a72ff20a20463ebf63a412cf424157", + "e15e56b956784ad2ae7c5e5224513445", + "c5b65ec589bd499d9224d43db9c00509", + "19766e5cf13b46958753744e36686064", + "1522b9a0752f48878728148d3852a661", + "e38433b796ca4b6b9b9b7fb6c98e6a84", + "e59590f912014f1b8b866185118a18e9", + "b4f4d8eaa2754572b59caecbeac20228", + "e13b0d848e9e4fd4acfba9b061ce2d41", + "813bce3523f8426ba3381baae43493ff", + "475b2d180e964d2ab8ab55ff1bee2de6", + "744a278961a24cb799dc3dc76ab45387", + "b47b8654942c4143a4423b3eec748a1c", + "d2018b07555b4c5f93fafe9dcb025026", + "43ff70e09b12481280988647fc9170b2", + "6471ba5bd6ce4951b440b7cccbaac56a", + "3301395940f949ff9a20166eacc6a040", + "b597fb7b2e8645f4a3d261d1ed7241d9", + "751d6d2b2d2a4b33a8fb5079ec48468d", + "7381bbf380474edca44a40bd783e7214", + "f1b87a3c86c146c199b2b220b9b72f03", + "405fbffd66b3403f819b46b808d3ca20", + "19e9b01f53d04513900835b5d06ea55c", + "4e7f37bee0674d569f558b0f08b7fdb7", + "6e3e38b674474dc8877a051e7c5794d7", + "37556bfdbab1444f83bb0962d14f3364", + "65892db69b5c4b0cadb25af7c9051360", + "0e4768df975d44c288f9c8d221a04153", + "6503a3b060ee4b79bf3f7b173ccfcbcf", + "64e9d2ab4c4d4459a8a53b5e2aa74afd", + "3f0135973eea4cbebab3a84e7e655415", + "8300ee896a4145a89aa3f18cfddccdbb", + "4c7904175d6d4676b73866c25110e8d3", + "a2932987a8a941c4b5406d07cecf8ba9", + "a3a2eeffb7a645608d8a28c3d0058f78", + "af1e7f65917f45dd8c8bbfd09d90d7e5", + "8a7ecc1192204f15b82ae57e8aa7f9c4", + "22e5715dbf614ed192f1210af10c29cf", + "fbf2ca604ced43a5b001879961987fae", + "f8a8d32652f64c9d9e1a8eb3fe263ba7", + "e0ad49d3316b44069260f59ea5f764c0", + "e3244268216244808d2603d23ef37310", + "fa810c81d17e4cb1b15ab6309b15eab2", + "aff1e4dda50049618542d51f15b87a98", + "db8e248a3ccd44a1b60bfa76c4b2c398", + "153cd88c9d134dcea87d013535ea2d80", + "9996d6e6a1f44ddcbbaecd8d3dc8e6e9", + "431394ee886141349e187fb8dcc2307a", + "3264ec81f296486d9c9d195e6b122441", + "b3c071a7fa9e471cb600491a249d6ac5", + "1d09c7b931844487b000ac698fb0b5a7", + "d6b0bf73a0d849d08c929f1f7af00805", + "1bdbe7ea2e5242948f6cd7cccfd7206e", + "b856c4f123694de3814645223fa3147a", + "b0a9b607c7d54d08a06204230f6da30a", + "e3e172ee8d184134bc2143f0834eb470", + "ae29f798e6884a12bc8fc779a51f0eda", + "39d8d13f1fed4f34afc9895aa99f0d2f", + "b986b5832f934247b693bd9e91a28552", + "43449ce635134b9780c6eafefbe24dd5", + "b06b2537958941019d5abc3a9e766d3a", + "65da26b626e24f3c86b66b77b08a69a2", + "fb696194295c4bf7ace119c932434f1c", + "1f79692c6d404751a47480a0009d8b73", + "1e6c1c38be55412a83d51627f6be4887", + "84bbd9034b5146a8b4608bb6527320dc", + "4a3da429148f48c9a5c941df2aea8339", + "198adfef07ac45c89ec51529b1e01c22", + "355af19eb7264c0a9af0293f125895c2", + "68f2b9fd83b349f9b285c360c447edbf", + "279d48d312a546618c5d21fd95128c7b", + "4613411c569d4185a2e07f31b1bf9e49", + "5a45aa7630304b7ebdda5a3b4821660c", + "fa22c5ec80a74398b856a20db9d3b14b", + "e67db84c8d2442519353afbae5220de0", + "81f414be3f95468995f5527647349920", + "473b6734823742a6b9b4ee3aa890f26e", + "5efc46745f1b4ddfbdba640bdbb4ce65", + "13cb5f6c327c4aeabe1f4690dbe73838", + "2151620998ae4282999a6c01b97a2e79", + "fccb65d701a54ba2b4874ab94c2be911", + "f66be8ad9f4a47cca8d947f551e916ab", + "370f02f7431642678d63eee200c0b172", + "501e12e00ed24a3f91a19da8d03bf318", + "4e902017e4624547b440da0a6658a689", + "7ec47f8eb69e4179a3f29382739d38bd", + "fc27ccf5b0bb486a999bb7e206edf06d", + "a514d7229b9a408182b57a21c0d3b1b9", + "15582d113ced44c4ad308aba2d9cefee", + "64d49a1f60cd4acc9beb4b5d13285601", + "e23bfe3655a74722ab28be343ccbc985", + "ec648787078d49a4a059825d757044c2", + "d8bf00993fcb4ee39c63e5c567d5e53c", + "28cc79da0b4446bf85f362f18f4a6f9c", + "608431214bad4e4f99522aae86b77bb8", + "36169306aba44a54aa55ab440d98200f", + "b3af98a2c2cd478b9174a5eda0a43b0e", + "e1d9171fef9e44c0bab4845502e4e297", + "4ebcea838aa8479095f59090bc499d8f", + "3ea434f4d29c4fca9b0ca4c0879e6edb", + "65e2f7b0452046be8ee948b49ee17ef4", + "91b66666487140f586dcf16de0ac54b4", + "3742738567af4589b9ec85bb9eddd700", + "87f4f595301c4ff08943b99f32707954", + "f97e3337f49b4d1784612c67838024ad", + "626cb4cd515f4611a1a2b4acf370a0eb", + "1c324391cba947408e96530ca8c4b115", + "0beaa1b3ce4e4e10b5a9923dbb6cc4e5", + "4fb45e1ca1e04e0aa5f1222b6aaebae8", + "96642eca0b8a4f71980d4ae0131d77c6", + "6987647c7ff14dcc80226088731ffb16", + "00f980c0932a42af9340b2b8ce2b7915", + "b49fe8bcb52844dfa4fd9f86e2a6bb7c", + "bcef675d1c1c44deab89221a960c47fc", + "f9b5e3d538c14491a19baea47d9125cd", + "516608a3bf714136bfad040e0b18f854", + "f888abfe6aad4a75b36f33039ab239e6", + "f71eb6d57f0348f8ab950bd2e12ec199", + "cb87435db3fc427a929b4d20f134c744", + "d674bfcc8b4c46be842188c17e34a83f", + "211bc03531284e2d8384e9e27e0d9c5a", + "50661c59e9314e018cba618c5fbe7a90", + "581a7056091e488bb2d89704d5f27ad3", + "0d8e9b33b6114387b226f2c7d9d696fd", + "e0a4f73243694711a38c376205beb4d5", + "338dfaa6765d47b7ac5febf36032ed61", + "6e90e98c65d04877b2dfbcc80956de04", + "748862a9693e4197afc2424e3181932c", + "b62f2e256a7a46c4a8615db21c199997", + "08491a07bad746078243f7417675f440", + "c057361b58f74f7888efa261d1eb3ac4", + "c1488f008d5243d29eb5a7acb41f50c1", + "0a06f7289d814282807f49a745a0b40b", + "421d7e28542d48359ad21f33bc76f9f8", + "9527ada3b62a49f583b9c1a86b21cc18", + "939b8ecc10a049c798165148453464d0", + "cb01643611514df8b2df2fa4af2160d4", + "8bd6e8b9603e4168aa3e38d299f28595", + "79393bf3231540e2a3bdd5a9640b33dd", + "f6cb6a953bd8431c820068a519400af1", + "c033d4bd9a354a5eae3fbb953cd9013b", + "4220e872cb634397a963383081d763dc", + "ad6943227ea44b70814a5dbabcfb76f6", + "25aeb6812a3f47c19e372a86fc852816", + "a010ba2dea0a41f49e7706176a62b8d2", + "c7815bb202754c32817dea07b0d7d86c", + "40ba61f23bf04e06b8a94fa55f96c1ad", + "f93f44c0599b4304adf7dd1a233d9097", + "b4c582544d904a4fa5c22f3a90ccb2b4", + "51ddddd189c245169be5994226d9cfd5", + "6441b7f2164b4891889cbf627e0d9da7", + "7d4f6a4e26f64944b92a6dcaa62d9ace", + "0f3678c502fb42f694a22ea03e1b6751", + "0108cf9b336b4c018ed3a3d6fbb73e6f", + "f88da0de76e74acfb0e71bb71c062ea1", + "fe604d1416a744dbbaf1aaf96381d449", + "d085591ac205493f8d41fa6300242df3", + "710100865395435cacb3bcf6514cb495", + "0eb15f1355a34ed8b2800b904749dcfa", + "6add0a1fa81942acbb24504b130661c1", + "4c380ce1afa34c5f808f4b2957659892", + "a6d1e50c93db488eb91b292eb8ba7765", + "d007d0a56bb14290875022e7a1916970", + "7d9697e32b8142a1ad6c9d3279883786", + "df0ab52ab1a04376bbd2a0e3c6c1824b", + "65228ff707a54c958905cc3806b30b01", + "376e1aba988e4b599789ad7e8ecd5357", + "45216c79e4a64f73a1df7739cb040300", + "6ff00ac341874350be3e70c4358089d3", + "e0ae8199a19b4f8c9cb7ff05e5f94030", + "d87f4d023f3f4c68b45fe247368cba33", + "3df39f0fec1e4b658abf94cb5b62bd39", + "ef5b4ebbae07448a93e8078e87af6475", + "e1a2d94d62ee4c13959e8b1dd3494045", + "e07de74e5be5434da249eb0c7202039c", + "099bef78983b411c8366a90b52960a42", + "c8778532ab804fc18cae6a0e20feffd3", + "89bcadea98aa48d39e0857cdcdaec702", + "9b0df931c3ce4b1182cc12ffed6717ff", + "3b415afda12d4cb781b5b3b063b45b28", + "d6f490d4213547598666bc0b8f491624", + "8b88d5ab779341cea80c71586738970f", + "1e4fa6e076ba46739fa391c41baf66e9", + "3f2814ac08c348b3bfe15262c8ec6b05", + "70b386f16399467aa30f43674acfb478", + "7d195612e7814905aa1bfefd13b80be1", + "60b0545433bf4072bad6e1e4f25cf712", + "34d899e38acd4eb38f2f614955f309b0", + "4afbf4bd95764e32b8a29168cb2549da", + "fc4777bad4c647d6a21637d68d5d40d1", + "03297a33c9ff4e3084b0d00303956c56", + "e81fb3f8db714dfc80acd41cacd230b6", + "0f86d02fcdf744c2bfaf2100e1570328", + "4d0e13c9b7da40958233b4a551e30522", + "ed032113763847609398eee2c03dd82d", + "ff2a0433d7544fb6b1e23b719fe72e7f", + "ea7123d1875446b4a336abc653c55580", + "6d0d0e667e9044ffa7518bbb07e8da36", + "ac7a64f0ad1c4f11b81689b7bc20c3ff", + "f71a628ddc1d45529b2dde4066f9ca71", + "a4c33c8c157d44158fce5ff8cc819230", + "d991a669311e4aa9bd2114adc2c62664", + "1a6a02daf9a84b108e437f75fdcab2f7", + "ad644c151bb54394baeb3bb5e2728e2f", + "e2f81876586b4f7396dc6a21dc717a04", + "84b153e8deb94f3ca54989ed7086f8a9", + "f07c48191d8a437cbee572cb1bd78961", + "d962ab7dde9943a1bcd6d6b0a728851e", + "bbe1d47c0d714884a66c53d6c1e5d177", + "68d42c707dec45808d6663b626106b47", + "7500ee9096a44579aecdf6e06e8d3cf0", + "b0d1aa58ef3a442e929363e8422641c7", + "ec24aa4f1a41459eba6f50a550306139", + "9c934adae75b4e0eacd3c8c017f64b6b", + "97aa2085a8c143c0aacdce273d66d03d", + "f01b1b1a2b4340928287aef7818df5bd", + "e8fd0c25765c4a578de0df1c7cf7b925", + "4cb3b3029ed142cc9291e83e93a293a0", + "604dfcb70ecc48b3a7d5b938682cc68e", + "48ecdf7441b6496c97a91c1a87c949e7", + "54a0c45e1b6444cbb7b98e0266febb90", + "7b2f7373c6904a32a76a9b9730983ccf", + "d149aab0593d401bab31c6696a6eeb32", + "ffde2ca21f534570a23481f6476d64d2", + "4f4cabd8af2c42b4aeef55cc61a1085f", + "da23a46238244ca4a789fd088c1ccb2f", + "7b6cf3f40ffc4e498c509c327ff9ae5f", + "d03b441a60364698942581eaa5a7d1e7", + "5f4ac924f6c8478e9276af22d26ba688", + "3996b96c48664caeb52992e454345ee1", + "6e95a8cb47114f2285be08a70e8990b6", + "8fb0c55beae3475fab0237d05dc7dd52", + "c24980e83e3c4b8393980358486b100c", + "a4b565b1ca7e41078e35dbf679f1c356", + "4d6074af12144035a518e878a82aabb3", + "2bb10b5967624d659c83e5ee1701fe56", + "d0eb520347d449699b342afaaea2ac4f", + "a87ae6282dec4eddb89d7c5c76187ba7", + "0ce49e1c745e40eda529a63f2781927a", + "dbb232318d2c493193cd2c6948eadfc7", + "ed8689dad919448bb78cd696725e12c5", + "a0f4187520b94ea0b5e64aac6a65622b", + "4a6bce4b058a42eda6cffe060de39667", + "cf18a24f7a9040b080290e07f43a6958", + "f04fee1aba4a40249471870e789ee411", + "0b90150c46f24f22b07bc1dd65b77cc0", + "56e3767794684b9dbed560c19aa18060", + "2dc339164cc14ff5bd6f906387ca29ff", + "f8008f8334074394a27b3881595f7fb5", + "6c35649cfcd74afd924690814d79e755", + "ac0e7f6d41b543ca96f69b4bd21298e1", + "8e73c1e9c85645378f6294f0b2351ab3", + "985b48efbd774f8f9fa74304508cad34", + "cbef101fd6cb4de69c80db5a9df81028", + "26778a5111bc479a961cb0f1c1860e62", + "9f79ce945b6845098059f42fdf9f2566", + "d892b203b1ff4824969a6ae6deb6def8", + "8bb166d787d54d4b95288f9768b3ea17", + "1e7d0d1fce524233aa01b5b5d879a6a1", + "a7793241073a48e08e92280f445a6a67", + "c6de7fb10d3249f0ab588680364e3a00", + "e845401a16ba4ba9b7ac3f2dc6237de9", + "6ba05685d37c41ff801a6728847f40e6", + "93ee7864e51c4c28bfd137ce0a965457", + "5108048e8b2a409aafe6b60375782927", + "b0a88f8144aa49d99a2fe01e03736799", + "0ed088bee0bc4915940013d533ab6907", + "a016cfe3be374da29a19ecc4456b720a", + "0a920656a7044660aa5f5c1f9a655364", + "c4ca254bf39b46caafe47ef62c8a1424", + "ce584250ab4a4838b729368324b5f2b7", + "f229b75945bb47f1ab2393fbbda82a43", + "c5090fbf444c4cd0b9d9dd441f75be3e", + "ac93361d354144fcbc9ea13c6bf9e11b", + "ccc3e809aaa042dfb8f0ad9f31f31936", + "f3d42a7a9d4c4581873a20840e51e699", + "a260532154784b3eba4f0a7c10a4a66d", + "282d529b70a04604a4e70f8d5a55c8c8", + "292a39eac72b4ba9abab123dd11f7283", + "3901647077394d9289300f06ff4b64c3", + "66f7b46d429748db81cf07ab22663874", + "23d2d9791e2a4775b87e799e8089f906", + "84efd04861944aba81481e25e2aa9e68", + "a0e2c20984314379a082a89966923e06", + "efd4249061464658ac21c4b0c307bb08", + "8ae3c19e5ad34d2d8e37ba0c88a80e72", + "d08fa0499599460db89f3657c198904e", + "30c45e4416c5437fac66cd142cbf29e7", + "b4065dd5ce9d46be90db3e1f3e4b9cc1", + "924c9b0f3cb4457b9fb4712e02384796", + "d508a95039a747d0bd7e20bca568a61c", + "a93fa93eb78b40c9aa13d395a3899ff2", + "5a0ac6f0906d4857a8f8877c02b6f851", + "f795e7e0c5b846eaa1a7bfa804c25a1e", + "7fba34f8b2704dfcb4c006d6abc340d7", + "2db604287805482f857a28c458f2bf9b", + "cf2e364e14884a2c982a2964ac735b76", + "e82feef327b941b69d7165e6bd64ca28", + "34fe6d9dd0d340ec99489705eb145fcf", + "50fd20b5b6d94d9fa7585fa65f684d11", + "dfc24e8b431a46cdbb828012b8c16e13", + "9308b88258ed48d193073c843b5933b6", + "536dbfc2fdbe4dec9203ab390b9a6eda", + "c82014b5e5b143f9a6d130b98988a4e0", + "90be7242f24749c3a8e0b0a69c616fc1", + "4b21aa9e643c4987a373d37eadffa464", + "f7b5e38a9a6c4fb2b445396c6bfc6368", + "11aea877a138495a8acb2f1c27c5d72e", + "e8f048aacfde49c8886fe72f72674965", + "b8bc9f0dec0e49bf854156a22035f804", + "b092c1d27d954c8e9c051299ef74038d", + "a23fabd3d8e748aa996fa3124dd5b36b", + "2da8f126c4fa4430869b4add6b6c002f", + "921a360d0ce446c08c498f7382652e30", + "5b3ce4c8e5e545cba43f394af1b2d711", + "8d2a40bb2f3940d3a8d050391327a2de", + "fd5ad4961a3c46fd948bc6a11c92666e", + "03c5557997e14d92b705cfb29f235b33", + "e4c76bf1e6cb4e51aae9b8a464998b53", + "5972eb71426b432dae6cb195caa581de", + "918cf95d53d543c4aa132b780d9d4518", + "3f2709a3d0be486fb809289122786090", + "01922143cd9a477d8f5ea5f805637691", + "71229448765c4f6f818cfd35913e56a4", + "a8f18495f9b74f218e711eb37e5c55ee", + "bb1d75d971de467fa9f3c26f3d8b4eef", + "e7e1c86addbf4dc1b91a861e7c97972a", + "a7aa70a9ba014d36bd2661a261ec6029", + "a16b31e1441c41df860c132d8cf2737b", + "718486a85ff649a5877110ddeaf27b3b", + "2e5e0055a9c64ff5868892ee7b07946a", + "a10174d6491a4a6995edc5bddd0a9bc3", + "60721f1bd93e4ad9a94908f894709572", + "fc40e67b4d1f4f47bc8fb23ba1199e38", + "89103ff87fc74647a96ffa0ac4ca5274", + "8833102f732d42e3b92148f7d8ee1c7a", + "3fb280d6294a4a32a16249f4a1a62f7d", + "864c7f9afa2e49e1a64ad05b2a29f66a", + "0f57e418a9c14b95b7134584470a1243", + "7d9ed9e524464399b4b04ef0751572aa", + "94b058e49f9948f286653725bac07083", + "0d8ac9660be14b1a95dfecbf33ec8675", + "95a7eeadf283465c88c1e91fedc4b904", + "5d75e1d76ccf4b6ca7c557f90f6540de", + "9f55c5fb6ac14005b5ded63d677d0673", + "6f789b3c1cd74db7b229fabbebf6b755", + "9e262c2c0cdf4a6bad090362ee92eef9", + "1dc69ad0354347f2909e63993a486bfa", + "f0eb1dd183fd487ba10dd8601a0c402a", + "826bc4f3c5e247ffbf81d98871b70b2b", + "941d8a3354d74b7289f5e5d8a4476a7e", + "43681992ecfc467d841aa9804997aa00", + "6f97dcf07cdf461e888888184b5039ba", + "7d8f07d1803e4e5687554629244deae6", + "be46f146812142569ff28a1334d14e3e", + "69d570f008be4b92881956cb3c64430c", + "da458ec5c1be4d8f96be9c52f49d4e53", + "864b4ab8ed1d4e399ce56bb61abf1762", + "5c2054af80b3448b9665367c5de529bd", + "a09592f04ebb495c9641ea1e7630b1de", + "f905619aa3d34ba683c3ba8515b32556", + "e64ebfc6c0ac406c961d0a8a0e8631a7", + "eae9fc470e674c458791cf00b892340f", + "22af367ad2b849a3a17716d1cc0575d4", + "b026abb7d9ac47aabe7cb32505e21f8c", + "d48a42e91c5d4716a8c254addf8c9d99", + "4d8dd06b107841f685a1f345dc385170", + "a82af6d92f0d47edb5a5bfe998469205", + "b1940f91170f40f5b766c1234ec74cb7", + "a2572112e61048ad81845af34f8ee90b", + "35fb68a78c1c4a84bbd4a66137ce033c", + "f18675d0123f4d939f3035f5f335f5fd", + "8372a1b1043246e4b3351c204f91b53d", + "1c19c1e1c38c4e1b84d6d420ac312cea", + "8f15f6d7cd5344729131c5556c73892c", + "38b90a332242433f83c751116c556a02", + "b523cc7996ea4826989a9a5aa501eae6", + "888b4113ceb44051a19612775accb065", + "5cc190f6b8fb45a7a045779a61b22774", + "bc65bca006ad4d20840a423b249a02fc", + "0ce0b1db42ac48df9941969494d11bbc", + "3a6e701aa3a94219b486466fd2105067", + "a93b58a74201428db860e1b7dff9ce53", + "9fa2da2c42234b58896e8d23393cac24", + "b8c4731778b14ff7ba3a4c6f0f8054c1", + "81aa18c093d842839954abeed1c7aebb", + "34a92d45ac344761a55b9fc69e0af333", + "3e0ff4fb14b24102839e9d5d49d4c363", + "fb8efea3d12e4c0e91bfbc6e0b46e58c", + "531a84899eb44401a1ff5d8f735aa6ad", + "27e5a88033364be7a4c08ec5343180b6", + "aaecea3567824779b46ef59007772d80", + "8dcac6d785b342cfacb24816250c25b9", + "d369c08e0f0c4e589e9efff9fc53156a", + "9a0041edd19749e9bafb3df0344db92b", + "13b66fd14378460aa5e8655c7e2af6b3", + "d9cd316a305a42debc41e9803c07d6bc", + "bd6eb4bc25db42109f7ddb46be748572", + "18f79eefe54c4ec0a2a57987a071611a", + "f03f9eb5ce5345d6be1a65d9085b37f4", + "7b85f1393f244782b3eb2f9e9c4a521c", + "bbe0c251bc924d4eacd4734ed1c471a9", + "f9a94145c6834578ac2c9ce5a4cf9edd", + "0896dc31d5154c97aa3f24e8ec1277aa", + "1cc8358910dc4f29b1f3f3a5375f87fc", + "f7c760e4f9e24abea2065964721b2e76", + "27aa283a480744729e0b740d1fe0a0cf", + "a1613311507a4fc8b6a4f3d859a447e6", + "d45c602c692c4b9f954b12670025779e", + "8ab8caf90a0b4d47ac2dc7911febfa66", + "6231a1b919514510bccb67745bba4495", + "a7ca84f5b2224c9087aac4b4fb88ae3e", + "2088b8a02ecc41df8f282d20b41bb288", + "8bfedaad32ae46fcaaf6ce2203a5ae4c", + "9e308582b90746d986ec3999ab42a6d5", + "b4a2cb799fbf43d68b9870f6f97f7a06", + "1b88fd9db542455bbccfabf5e54982b7", + "56bc9b48ba544f1ba80d6e8252b08c96", + "9f0244366a5245b1aa182e33b655106b", + "40e8fc657c054e47a7651cb3d7505374", + "ddafe31848954376b38860fe4eeab01a", + "3e5e246251af4df58b40657a94087698", + "ddb5de8e1ecd4abb80d485ba087b7d1f", + "7e13e7d8b8364eb2a34ae950461b9c5b", + "f23652d2b37d4627b22553e56235f641", + "518ca135a9074e8b81a4837b067c3e35", + "4da577d89c0b4a61967236cee9d745b5", + "80b914565c154cdfb31a31f669b900a7", + "4ef34cfc6c0f4679af00e400038147a7", + "c9ec32a675ec44c7a5540eb3abfceddc", + "0d84d12c400c4b4db2f7a459ddb9488c", + "a7e1ac57f9d143b195165c80407fd60d", + "a82425de6cad44f4a40f2d05bde2af5f", + "323195c6a19246beb3944167bd433046", + "c8f58c34099d4da49d0b491be5039025", + "dac3b8e43f3e4b48bc0f7d05031b8866", + "1653db41973e466ebd90f91d8dfdda29", + "121aaf7991b6443fbcca6e6afb51a50a", + "b40ad937675341e190dc39168f5ee8d7", + "6c6a04353dbb47b1bda4b9852f290cbd", + "091e139f26554be4844712ab50f8ad2a", + "70aa03b0f0e1477f81e9ce637d2140da", + "e292bcd9affb43f0be1087a1814b1b9e", + "a53fe1a211b74d9a84b27b9ad9ccc05c", + "ec7d156b2ca347bcad8131cb2ee8d2db", + "f3d49c9a1a13463e99622a7880fdf6cb", + "22b5a2f013234bf58bce842a05a3ade7", + "ddbcc3044aed46a689e65d7ba2901758", + "74d7117520f84fff825c8de9ed8c4b6e", + "de73b663acbc426e8e6c107fd25e08cd", + "5a49310711d748cdaa1fe66fe27016f2", + "b9b90dad522448e987976639c3d6860c", + "b6c212a12d85425bb166f43cd3d70248", + "ac35272044694eb9a97fb038ed26b8b5", + "d7fcaa3e8c844418a38b721c325bb2af", + "555cb2de36f54e80a588ddd461dab91b", + "bf2fd2381a854e00b618e4f559f34276", + "b0782caac0b1426797e38d98fe859dc9", + "8a39725a0bca47f88a7996619b5617e6", + "fc27fc019e8144d197a6b4246b251fca", + "abfd96948cf7419087d2cae231e9fe17", + "b2ccc7bc0c924e2a8e1f82d7a29c0217", + "91ed4988d1f44a0b974ab7f2f0cfcf40", + "a52438c668a8440788325236059a1f4d", + "d3c99262d8654599b30f5ad6ae1815c7", + "8f6f1a38f62c4c96b7fdb35bc4aeb78d", + "ff2831bb45274c8d8b44a0cd1046c94a", + "74a4eaa958d14604822266ae768b3a60", + "ee82fbd38ad945bbbcfa9418b4406b75", + "9a985c97964d4f368ce9a17916468e71", + "0ba903b566164dce9d2d7b2adc9ba921", + "de51dc61ec7c45eab148d81cd393dd11", + "178f5f9db1644cbd86a770291b625a81", + "bcb7c07cb1c648dd8871db5e01468ea3", + "a82fbbda824c4d62a97fc1e909c56a27", + "dd2a961700db4d1a81dd29b961827978", + "88d7f8845e054bb490173c36587ed5f7", + "60dd2f84af874a6cbd335e36cf0abc5c", + "3b68182199e244da916e36395895697c", + "44c3798efa5344818fe247e39d23e66b", + "20fd9eb478724fccb7a006ae76cacb8d", + "1c1ddf1e196b4fe8a1a0be371447ef37", + "9fa32fe9b45444d89989a29d00b88f4e", + "615e79f062844f22b24c57d0d776825b", + "f4c0e1cb4a0740faaa89dfd98fd228b9", + "63e6f5b2ee464f8ba40d3549021e0a12", + "37d8b88269d0429e804eab9319964792", + "ce85a8805a4c432ab39e89a4d78d3841", + "7b396d705487454da467cc590654c9ff", + "98d3cfc65e614c9a8b685b5e3d38e55e", + "e861ed0190f546b0961b936503fd8c53", + "afccc57d6f5943898766675c6010508a", + "e0cc6b7fa17b489a975cd5f9a63c6721", + "869fec02329b44f29b50ce81444689a2", + "09ee59423b4b428f94f01fc5beccd227", + "bbd98918bc6147d399e88e7baec8d324", + "d4bee845c7a443adbdc7dee04f63a423", + "bad55ce1183a4965896446aa526c7ac2", + "3af6861d9c604482a3a4354731c52c1a", + "2fc2ff8f300943c99ab68aaaa2af2d73", + "4e45d6c738c94e34a549003d2cb9b871", + "693f1bb7cea4492e946a158247cf4fe0", + "0b29f4d1c7804796ba1e491fce0188af", + "f0bc72c107db4eddbec146ae6e90c6ee", + "9e3c72a13fc54d7f845ffdc968703c2c", + "75df21d5523b4474932cda4f40e968cd", + "e2434fd6e92c4796a8870b1896c2f930", + "0061788e0741400c82289337a24af4f6", + "1074e7670750497780e664cc22d4c67d", + "c7aa636f24e345b3b831271bf7f1fe02", + "828c95d955ef4024a3791b26b4838c4e", + "e2ae105a424d4ff5b6f200921cfbe597", + "d6a1d8b3aeab4ef7a4186e0c7eafdf01", + "edac5c8bbbec4321b49bff0da2ca4fda", + "1b1554cbee9e4dc98b4e9f8282fd77c1", + "9a7a5e8dc05749948bcfdff556643885", + "74c95870e2a141a9903815715d25b8a7", + "e3ed48a3a0814d8283c3458c539ecf8d", + "b8525300c68f4f58ad774ec04a221e44", + "1b970b2cf7b1435a934bea7c1126c644", + "132920fe6f0444cbbecff8f40740a14e", + "84ef153d7c8e4841946a0e626274a24e", + "4db924f2eb5f43928a826244e88768dc", + "c8a9d0d162154189806e77a29460ecfc", + "d20c63815d634a92af85d59f47b6ac90", + "b7b9fd6fcea7401f88142168ef6616b4", + "434371f2ff7e40ad8180754fc17ebcde", + "2d92cc12ae7e448f9f508fbbde85c70e", + "2d3e3f7dee934468810da6794e8937f0", + "f7122decef0b4f7aaa3159f66876a9a3", + "9561bc4edb7849adb9928fc59b8a1d9d", + "0bc048539ba24a6a9a6b847e40e77f45", + "5a2ee0fc0d924298bc466195034647c2", + "23e4027a42974d88b593c86abd3aff57", + "d562bb4f37bf444ba9034be7fd3c21e7", + "5279337f0c384d6683898340cf60b5ae", + "ab6cfc1bb3494efe9aa636f4a938fdcf", + "d76a2b77e7074339937fa4e750d10002", + "254391f83622453babc6f0ab63947034", + "99c784499f0b40c6943c91fafa707b0f", + "f5d973c5aac74e3e977c2309997419b6", + "fb01a997ca3644e88cb6005627d7b174", + "14c7d75bc1ce41d9b6bd174ec570ee99", + "c5b1cb6338c04756b474065e8bbb619e", + "e397d8dd37064bb799c047ff37901418", + "8d28b4123c6641b19c6557cf8f2f80c6", + "76b8b232c4aa4a91999d949f2cf943d4", + "9bcbf197ee4c4f4185004224945f1bc6", + "1fe9b618f2d24502a0aaf73175829ea9", + "10a7b4f1577841a8847e7bf0535854ec", + "90769b4634b54b03989ed38252e6e293", + "63fdf43be04845a39f073b00f3f5c714", + "62de3a80736a45ffaac053b1676089ae", + "edff22a01fb648fc81c600f0bccb16b9", + "a668f2bf115548ea834e91c536cdb644", + "0ecac20b76804dbcbc7f155c7a41774a", + "4f38ce9f5cc9496f990cdd29f2756a40", + "40b8c51a423f4c9786e289c38f2c067a", + "b930438e1f804c409fd9c3f5e4b01628", + "59453ed7e25c44468b3e7bcd788dae4f", + "0c76b22dc39c445ead115600949d1129", + "57528e7eb15048eb9c268929c955f86f", + "b0d01b22e461405faaa5f0647a65d94a", + "42dc0771e4b3432b9252f9547bb132e4", + "222cbb6fec764c319be88ca67b7a4e70", + "3ae2963888d44806b880c5b80e25118a", + "487fdbc316324db08b61bb962b6c6838", + "bc770fe7e2554187904fc47056bb2be4", + "e230d46d4ebf433085ae188827b157d8", + "dc3fbd9205cf4027a4455d1f415e0478", + "468aa9e803d14e719eb97da28f9d5026", + "0152582550bb4fa4a42a07ffb815d841", + "93452f3774b4458499685fcbf8f549f0", + "337b25ed459c462ba1bf988511167b0c", + "b1dd2fdc7b4340228de533d73edeaae9", + "50840c7af0884c5b83f191c4cec21a52", + "bce4a505258343faacb4fc022bb52b1b", + "2ee631cfd24542b4b47eb6d88b34d4a8", + "285134ab18bf49d58a16f193b5403da9", + "438f3d412eba4d3e906a64ca935212fd", + "b96f8cf7efd143859eacba5efe4eae9a", + "d20a3de366a444468ce0e7abd7117e3e", + "569b72c271c44106a3caa51f7d32dcd6", + "d63fdc44128f44b0a5ca1d97f63bd0ec", + "980843351c694f2facc043a99ec7a355", + "f405d44051ab4bacb3bb996e3d634def", + "fb098cf166c141d0ae3e7348788cdd5a", + "a6448e3833bf4ec68c0a919ece796ce2", + "1b86dfbafb254630bf82517ece537cd4", + "47919881e30e418f900ea5a8dacef14b", + "d6c0191439214e1e899c4ad1ea77fa74", + "6552a18a2be54d468d720759d065f19d", + "2ebbe73bb3b140de9b74def3d580c30e", + "2e35b5ed4127406480403e4b8dadf5db", + "0fe70edc1fca44189d2947cb879a0446", + "47538f4859874867a3a895c8ddfef3fb", + "08f942bd6c13467091520f48223aea34", + "b6bafae4af4e43dfa002926ce6c93fef", + "d0e7783a976546ec8482a2c28322885a", + "057dd0154cbc47549c73a092aa15199e", + "aeb0e4832f04463280510e550e2cdbd5", + "704e2b1baecd410fa04082eef08e97bf", + "c22fd351c47c4f4790fd77a78fc51f6c", + "872086a135fa4ea4a726735403ac44cb", + "e64a2023de594ae38f9a4e79eb18074b", + "69e6f605b24345fc8828f568b7b96124", + "94421df4506e4737b6bc2ea9ea369dff", + "46d7abc3dcc248a2ad9fb3c151cc12b0", + "d96f554c1712449ea89e493785b6e94a", + "46186923868b4984b5c361048f9b0800", + "8e3be18ae3f5496e8156e174089fba66", + "780e747773f74ac287da0651097447d7", + "bf8ad9e849b24d93a005b961455701a6", + "400ce6fc25f54d149efd4cd429daa50f", + "7ab4aef02e08490ea413d57763175224", + "b6e30643e3ab49e79c05702582a7684b", + "83eff5ee5f2e4190a007a5976b505c96", + "a8a1301bc07d459eaf23bbfd6cff27d9", + "755dd108613b45588425a1a421af7b93", + "e10eb527561048b6bc1786c8c44cd0f5", + "0865d008b68f4776a8d2ce34ce198fb0", + "6fe88d088c17499f8f72a7171acc3b1e", + "3175f9b0f9e141329f05f77817021755", + "a11774af8f844018b4cbd8dc8260b226", + "3e32568eb19f478ebfb5b65e385ce327", + "51e39c197f6f46748b6023fc48cac396", + "0f5b12ea1f474887b9664fd7a171c17a", + "6e1bbb8464eb4879b102cbbdd566e61e", + "6511cf11970e465bb9a488853d23cd82", + "ee3b649aa5ad4cda9580dc3f4a32bba9", + "568b010cc9dd42ef875a54d67f2ba973", + "7f190e7829e544bf94a3c26014122a3a", + "0563c6e7a4ac4f02b6914f4f6e32b7fa", + "48ce0e2fdde14ef2b1e7e219daea8c87", + "fb0291f77665442fb5e54473a8d12b3f", + "269cc79ce7ca4dcf88030e7b7151dc36", + "95cf5b63b15549a2a173bb480577b6a9", + "bc023082c9f74a63a593ac9ce4f98a3f", + "e8fe8902cddf44eda16bd7113efbac7e", + "33a3329116a34ca59ed984378a070d37", + "79eb108dd7e442899565dd343ab71862", + "dd7b64ef3bb64e33afefe1aee36061bd", + "124297e7e4574c48b9c1b814b6ddf516", + "72801a6b5e8044a19fd14498493efc14", + "f8a64f4c4cdd46488e3beb823d0dce37", + "4d4c8d85a09b476c8136f0c4cd24c45a", + "f86e98a4927444de9b184ec212c19283", + "653a622f383244ab9e7859f9aa2dcc8f", + "736fb6af4ac542dda8d5f3e97c4448ea", + "f9e6cea281454cd7b0190bed1deb0788", + "3b5af9ff76fe41e3a6c8e9d5b592cb02", + "093e5b05faa947729b1be24c013e563b", + "946d86aebb694dde8b644fb13128ecf8", + "b343d7cece5c4e5eb1fb22522b3b04e9", + "d514470f61904fbb99bc4232fd60b5a1", + "4d3ed5de8ca74b4c81ccaa409a681eae", + "8ae6080d8a0943e8b6316148a7fe61d1", + "8f46bc56341749a1bd929ab0a3375fee", + "4491bc20adc545a7884254ac8eede3c9", + "f1d57e4747e84faabbb5bcbad6be72e2", + "84864c1240fd4fe7aa4e76e92828c7d8", + "782e2b5f61454d18bdc627c5210956a0", + "43a2ae4ca85c40399426f62a0ebd694a", + "074601e8cd6f40fd9077902233c3eb13", + "b2a193a08f654ed58147d8df30c8b4d9", + "ad368a89b62d4e67968d4a08b02edf81", + "7e11d6287b874f908ba40697bf49e6c6", + "66b40aabfe7447128fbe4126530e7e96", + "89986433667840e5a188fb3c81fabfc3", + "dbac58a0440f47709bf5c36d6f2116cd", + "2e8c766fcaa54804b24a345e9fd3a3d6", + "18427588b7304181a6c2095dae6517ae", + "cd7b42fde1494fafb43945c056a6f7b0", + "f1944531d33348c9a425956ab2f4c00a", + "74b3cfffc7274bd0b3b4efef8852b1c4", + "71b902f0b2c04498ad017c21639a9d51", + "b1c66721f837407c9afb305ad7099ff0", + "055bee798bdf47d09a2b5401484cf8f9", + "fbc91465203845f7a42b972b80a9c435", + "2df515e3f80242b2846cc9def064ec6c", + "c5018d48f82e48c69ec2901733e2db21", + "6ee7ecf9930e48ecae4ee848c92bf56f", + "42467088d63744fcbc917d9f9518077f", + "11774a25e4bd407c811a208a06c04290", + "27abbf7bfb5043aaa73a4f9030f06f43", + "29472731647d49eebccc6b5f8db95724", + "9c5db5a2d10c4dd59c5be947187ce367", + "36c5a7d36196442fb03e61d218a4a08e", + "54f6ef2fc523436bb5f3e21a976ded4c", + "45af3cd3f14d4534a87a2d9f6e53db06", + "522bf736cae646a998522d666430a5a1", + "7c010a0e2f054d0e9686333cabfdb7e7", + "59ab677ba6a6445795cc32c728d62b0b", + "30ccf8451bd24578adeb9f8d124f1553", + "1ccc59662c4245369721ce534e0c488e", + "27fcbef035fd4993b39b062a2a86385e", + "7b97137d2ce3441cacfb76ec2fecfb78", + "3e3e2099353948408a2737f8cc4d1738", + "5adcbf784df540a0b46dae8950bd3ec6", + "35328820cfc640d2a9b5eedb6d7b907b", + "701122fa341a4313a9a0789ae5cc0ec3", + "b29dcb2b1cea44cdaab3015abd2ffecc", + "fbd20f35d3194093a47e7a530e2aa217", + "3de961297e0d4f228d0f5d01527ee64f", + "6f2842271e0c4cf19bcc07d24897e5ac", + "092e79813e864d1080255c302151c3d1", + "9f5156a82f2f4d0a870f868458643eff", + "b525b8eaeeb549ada478c0d72b1411b2", + "0846167f9302450cba1926c6fc5d6d42", + "b7b92936bbad476a87a6464fe5555c2e", + "158566fdd0e643ddb22eaf920c1a82ac", + "b1710be443a2443b97c2c00bacc8d394", + "2ca5f3152c004734b00a71efee87960a", + "60743c97a4a1490587944e96d38286ce", + "dbce931873c540b08bb27af46d2c3c92", + "7f934774a0e146a3b54307a2bad27db4", + "2d400d61c1d14401865e8b74a0b72016", + "bb95a7323ad844fb8ae61f9f82d3c9e5", + "22ec01ae489a4408a7fd52e6caabb7eb", + "127c9d767260468f821da3cba9d7db7e", + "f130ebeb60f24ed8bd3714a7ed3ba280", + "0d00ebd882aa4f7482041ffa3de5bba1", + "1edb8ced7a73417fad2ca97a1b6b5d23", + "5e0d9ffaf6e24f7798f0dec36c3f3fc6", + "2ddc6a3da3fc47a5a3809f16fbcae475", + "f9b4fecdfd5f4b0585ab35d7b09ed015", + "b2e914cd6f7842278752aa8fb0b1a4c0", + "84424f446e7f4c3b8bf1c3204b581f28", + "aae1df2e73e141c081c92f64595a7d25", + "5d401697df2b445e845feba567d19216", + "48fb034f014f4d69a0da01dc9444f265", + "281891d0dd6a4affbda7530bed83f846", + "1e439d130092410a9abb5c9822b39881", + "95b6485c508c4b068d683dda16a33252", + "7a98759bc6fa427d8d0d29f668f9eb1a", + "885a6d7ea3d940c082caf9ee946c8602", + "ead85ab8ade140249ac6393267079596", + "a0befff564b54e0391fc210355580267", + "141245699297480a92ce81711823638f", + "cf380e1d8a7d4d6e945322a9cb9a7008", + "ffd9753a53284b588b955e24047ff56e", + "8c6c7a556b37410b94fd72dcb016326b", + "819f0b340f1b43899d167cc904e849b4", + "c8d83f0e016b406e8e057e764b29bc06", + "1b54d0a314954aadad40333cf80c2d28", + "c4f9b194abca4db7b4cd0ec6270f9d60", + "7075ff0a93d14fdd8cf34121f0897777", + "c850aecde41c4b7688c665ef8b8437e9", + "0717695aad8f4d5f9f8f5e1d57355218", + "0d57de610add4c07b7689e4751d6f63c", + "158cfa9cb5064e2886ebc6270c5c1528", + "65f97dc818e24302bb9f62b0ca68ee8b", + "3d0b78d5b0d5450eb94d59fb83986074", + "8bc4431d9b4b4abd925441ab60d93654", + "fe110d01a17d4689bda8304092e490d5", + "d3f9aaecb7e94b12bc28256c85a40ce0", + "7e7cc43a2fb84e44a03a67fecdd76ba8", + "fa3577bfb99e4dbf83d335ce75de5910", + "6c8816f628dc4596b82c497cac0b694d", + "cf3b4a63fe9e4a6f803391edb55e2050", + "208e5cf748404521894bf30c95f25c12", + "33aeac30422a444a8c09837108a045d6", + "a01b126f773c4d4e82403c0bb9da0b3a", + "dde8d2aa26354eaba3d82925d833b5a7", + "aac35ee9257e407c989f813cb97b0a58", + "8bef8e37f0ae4dd6bfb58192cf0b1563", + "46863d3659974498bbb4427811035177", + "08318294c24f4ccf968bfa046a327003", + "3ae6591496f04f5ba98e16de545abb04", + "7c8451376a7a42e79cfcef5c0d7836f5", + "a2916e544eba4b19b76b454fb0a638c5", + "f7acabae300d4a5681527c4288117201", + "261daa44d8c044bbb7e0b4c7db5cb937", + "ce92c014efd140deb6e918b3c59bf539", + "9b3dc9b1f27a4e6ead100ed4e641d8aa", + "01816801a27444cbb5cfb934de39d483", + "5ad347e986e546a3a06762ae64b1d61a", + "989983bf0b57475182c382572521ac2e", + "c70e67c11c934fb5b2aa5cc510220ab8", + "6470e27021dc468e88e68befca5f770a", + "6be91729aa09484ea8eecd2be72466f2", + "e618ce8bb9cf4eeea84d53ed7d16d28d", + "14bd0d858839450d9bebc359c07779e5", + "736cbeda0fc24a37994b017549ddcdd4", + "2204d5441372457daeb2fbaee085ebca", + "5fdc95a388cc4da399690de48d1fd720", + "07f2099e739e44dd979bca87f0551d75", + "ceb1f4401c804b638e57155b825302ac", + "5a778611b1f444ab864087954ccc0f00", + "2460380ef8e2433d97e2c1f69c3f16e4", + "f09eff1f6a794b9ca92a2587404125d9", + "3458799ca8ed4a029a33bfaa8b458bde", + "604886640ac948f1980d81bc4a3ed7cf", + "08bb065c943442b0b53301f0dcf20564", + "ec2abc3ddbd74f8685979d59b3ef0a7e", + "f8010cb1eba1423593cdf9eea2fed00a", + "ebf0aab18265488cb2403b6eb21fe990", + "561b8497a9044dd093c177db64a28043", + "f6a49b8df0654c3b9823ffc473df1703", + "50131b2e3f5a476eaa771c79a0363f60", + "d42dfb82a65a49f99a281335e3b2105c", + "73a26d8da4e44d18a3775c95bd5a970d", + "16daedff659a47539ddee0934750e839", + "62cacc45edb149f1b95804fa410ecbe1", + "e7415a59aaec40edba7a0eb32057fd03", + "011f5402c75e4b549010ef29def39e51", + "fa21afd3a99d448cb23fa527a784769c", + "e3eb2ca3aab649d6bdf4e3355fac97f3", + "0c398f7f15aa4527a733dfd7f4769265", + "9a7f48758b8a4c9ea6060c58f72ad21d", + "a653e92fad4f4721ad92fbd8f386acfe", + "acf8ea462f904f7d8d7520628949ef34", + "6a0dfe5830304ff999fbef3ae2870095", + "905644cc02634f0b80d6090f84543bdc", + "9d3007d40ca84bb7baec1f1a04e0f08d", + "79c790d6f7d14e20b7afcb0bdc62f869", + "4215328078f040c3b320aa8b6bdedf3f", + "d74e7913267b455fae10181ee77e8a1f", + "fab24b554e334e728da4273bff6d5cd2", + "56de4df672654ed599777d2980bf0f53", + "98db321819674f989ee989f9e567e20e", + "374adbda2ee649ab862c770545967c5a", + "7fea87e3f24e46938b3fae74574c07c5", + "16a24d859a7b4dacb5d9b65c1ae43da9", + "6e9a04f48d8f4c80a02a4f468eea13ac", + "674959decc084dc092b67fd3cb5193f3", + "8d333a52ca6b4afbaba8002d236c5ef0", + "3d0cfc268b334162a89f4e3061f5afcb", + "87799bc7863d4550bf8f4ada7026f48b", + "bbe937f9a0ea441496159d8f7821d07f", + "3cb0f51108aa4b43b19e20d43dcc141c", + "5e4a17118c334c9d8fe8feeea234eddb", + "7531ebcd840948e19686fcaaf17167cc", + "9a35b3f7bc594ff4897ec03d6272ab98", + "1722d738c3154ad29ef61cce2c972a3c", + "b5677cbb469d4be98e4777c244cfcf27", + "057934f97c4042e09a9882543dd5341e", + "102bf0ddb48245a58e494000f3654cb2", + "1501ea1ea68d460695204afda016aac3", + "9fbcb44010cf4a1a9eb3885f80d80a95", + "9f2c4930e87d44269466d4fe32947304", + "d54f8a1c5aac457c878d4a5cb3bfcd48", + "82f4d273bc2240c49f70fec7b6bc5fee", + "d579517b90a746acaa264cc38a40bf9a", + "65adaaa191fc4115862ac0a05d1462a6", + "b847a0be413a470ba361251c239b09cd", + "2687ac6a5dc94c949fe22d143868e301", + "703b12c3b17949f6ae384b8bc39ff56d", + "090772a1894b45f6813ca2a04ae0857c", + "52f18c46201e42fe9a1773f1a6baf480", + "4f831057cc2b4034a04c424fdbbe7cb3", + "f993e699a344415c9ad687e7e02eb73a", + "ae38d8c85b83447dbbc3b64ab2447968", + "546d6c7e9f0b44cc8968fda1f1ba1804", + "9ffd86a03b80447ca75e965825ddf8e2", + "b126deaf7dfb4e74ae518f021e2f3dfd", + "509a2cc74d0742f7a6ba5d3036deab32", + "c12e3b933d77412c91fad5734645db67", + "41a08ecb524940e9971bbf7ff5418fb4", + "6c807780df124dbfb7105dd64160bb2b", + "8b7e291e55cf4234a0d77d18355df9b3", + "2120c5a47f104230bdab745d5fe43add", + "c7cfb74916684c08ac60573fc72adab2", + "f235278f31e9421b85747a82eae272b2", + "47a08beda8ae415fa22f27087cc499cd", + "609200b0c7af4f40815ea1cefe6f7e0a", + "8014aa16057a495795f7bf8a02a3ebe0", + "edbb6a11d2cb4148a678315097da032a", + "49fc5dd4bdc34951b29fb43aaaa9f3b5", + "529d58c8aa734d7080279a4a91c7f837", + "4c5bab0933964adcb05751573111eb57", + "535425b7c36f4e58a1df42ad41356860", + "b5a45e9e7552423380766e69bb7ee3f6", + "714397383f014eafb4de216db99e851d", + "6e6be76a169343f3ad439c084d16231f", + "1bb9f4dfad1f40e8a23dea267fc2d576", + "e2d65b9c095142bd932d3114623ab93c", + "229cf483c0804368a8092dcc2524633f", + "f12ae5e50d434df0b7a4b23007b5e003", + "8587f6c667e5418784586883cb3ae1f7", + "adf6e1892ce8421eaa6653d5b918bd58", + "432c7e4510f34db0958c2998c5d8d8f6", + "26f81d8cf40e4f559cdc65a83e6412a5", + "5bf0c824c2a64ef8bfe62b6d346188d6", + "94d48c1f3eea45d4a7aceca6ff970707", + "be8452f1b9294a4c8d2bd72d4d0b04cb", + "0bd00d2ca0484adcaa4c9204b2dd01ef", + "9237b66bb30a479282cf0ddbb2a8318e", + "d2d0c7fbaadc43b2bacd15c51714265a", + "6daa3a8618db47edb7ff6a6911cc9532", + "d7a63b028a1a4014a1b9c6728fb4e067", + "c41108a3ef0a47cea07620df8de9cacd", + "c3d8781a43d344bb9d1d110eb9d2ad47", + "8c09c173bca842daae32fbe813156f8c", + "c248c3be5f814b4a874eff7693228ed9", + "aec2924a4e9f44f9ad569717301e30ec", + "0128bd0d7229499185abaa91fc54909e", + "fe4f7047a03247ecb5ef7a587de4e969", + "766b9386506c40c7862a9b32234298c2", + "39a161def61c4ca288182d60a7570dad", + "79fbc9501aff4538bf077197d2502016", + "81a531bbe9d2448b84d161c6aa9f048b", + "60cc6ac57e03488db516eeac956411eb", + "9b0bd81f3d9744a384549d4895ec89f9", + "e6a1829a33ca49dc8f7a2261058c3c17", + "bb669527cf7442c9bdd6df3a04045cc1", + "43819752da2e4346a8696f4e8802a1f7", + "bf62e3d6461544629d02daa3e441da84", + "871ed12da7484c86b4d59a306813b1f9", + "78b80c2ad2434545b846be4404664bfd", + "5cdb2f43bfe14e4b94baf8051a80218f", + "7bc588dde5224dc0840b9b4f1190c2a3", + "ae327ae50a7946cd9ffb609ed136d2fd", + "29119fd73cf44d70a4f038849a25dfb5", + "8630ce940c884057a82c9cd39998fd53", + "5a8f7d55f2b041aab35331336a6852d7", + "a55ad61abd044fe59fabf4dcd1d050cb", + "e6632b7316d241adab9c1b59b6b768a7", + "d1cbadb78dc641f1be9e3a16782d4821", + "27eeabb1e88d47d19e59ed0d54037aaa", + "644ed9dd11cf49538a0da51cea42a0a5", + "665ab73155a44d91908519d84e5fd002", + "e91fdb39898c4a6194f5e0aa23ad0454", + "5dd760de1fd443748381874910373367", + "891d7965aa984585a83366e33a87f05d", + "d2863654751640ae90ee7ffe0514f46e", + "a7f2673809bb43b4bcf3805c00b5ac5a", + "083444c1a756495896c8c2fe83d54410", + "f130817ddede45b5acd1d78f7af099d0", + "1b5f52a5181942ccb5415f1a4ff4ea3c", + "549dd016a9814885a94bef3231768976", + "ab58fb5cf1884d919afcb18610459c7e", + "b21ad606d20a467eac0e63e7d298488d", + "ecb01317a2f34926898fa43ed9754df2", + "cbe9d1ecf85e44b4998e205f86ba4311", + "4c074b5e3bc44dc1b338d6326c44a176", + "64350a72ad11412b9725721d8b27d225", + "4a6528079ece48828f2500964fd60e13", + "3969de02356547b0b7768b907959e7c8", + "0bc47e68d77243efa50a22b881970626", + "a55e471989d644d3aaba92e117b3fc14", + "2b80440f980049c6b89be1428073545f", + "9db26d3c966c45779bd7a58501ec4386", + "fffac5c39c104816bd76307f4fa4cded", + "dfdb7fe660714b698790a1e336f8d6aa", + "568c556465934fb6b427f60708bb0f45", + "a24ebddc8bfa4a4ab4b417f35c282721", + "45f941c495824cb583712dda57f58707", + "6cb74f5f5e1f49c9a128d689bd54d322", + "8eb9f7aff3454ab2a096bc78804f549a", + "6e9b43534e564e9989712aac6dc68ff0", + "7f18c636d8ab4f62ba880f03ecc9755e", + "d398339a6b1f44acbc0cc4edaaa2525b", + "542e27eef15b41bc93105e4f1d847942", + "78440f26dbb64b9ea0edf1a218ab8090", + "92167e12a3f04ca691a5126f25976017", + "b4a75080ec074204af9aa8a3dab4f427", + "29d81fba51324ac4b858cbe6f1777a56", + "80f48376a8104639b87aea73786a9cb7", + "e3b67df1edd04a66adb71854f1637b17", + "e71d797bad504ba3a3d15923e7aa1589", + "6b9c5b0ee5fd44dabbf0ed340e814c42", + "00286954e2d54db8bc7832cc8682b6ff", + "b44190f759194c45aac8e9393290d8d9", + "9d47b22f76c640c3af8d58ad3245b470", + "c0ab7ce091ca4f43be9dcd83eeba69da", + "50d20afcff9c4e60aea45514e0de1327", + "f2256509d4c14688849907217394e811", + "ba2cb0bb5cac4a41be57d0d806485ddd", + "107c432300ac4f3ebfe956ddf79d7363", + "7d8c777573e7447697da14620ca482e5", + "640377294e99498a808612f3af43c694", + "cd2959d5187c4536a02b51ec697a8ebd", + "c2414bdd1a3e4604a011c7889983c0dd", + "117392ebfa0f4549b3e364b5c0c62324", + "669f98a3dcf34443ae88062e498b05bb", + "16ca03acaabf40808470d20b64a88e24", + "3cea231970204cdd82696c90fc1ade2e", + "ef7335bba9924d6595e406890c5cffbf", + "4e72f79a24334b85bd211833aab2e516", + "e4a7ac2fe26443a4b9a786634a43f6e0", + "9e35487f302545d49f9b5617564dae63", + "50385c9fc9cc4dfb951d6b2aeb368204", + "895a9d0aef344d7482b6ee545ae9267a", + "cbb82162cd4d46818e7815d547d73edf", + "ea59609f81a94bb5964ae046fcf2a67b", + "8f14c1c884464034a6044a76c4471709", + "ee4d79c5f2b7404aa65ce90443a12f2a", + "4db70936b85a4ab287b4ea2a93772333", + "7f884444179e40f9bdd255a850122d1b", + "ce8076dd1426429ca438cee94dbf10c9", + "6d71e3de6ad848c5b46f6eaba4a8769f", + "eb364dedffca4de1a68c752f12f36e23", + "03625ebdd8b34cef85eb9cb3a099497f", + "6327f620b1044a16b21216caaf6b107a", + "6701792fb91a435aa637e53c87c42bce", + "e79f0768aec6431d8e6f3874e5acc5f2", + "c7c297cf6e334cd291f9f562f3aac35e", + "837fc9092c394f6f956b9d78a7d9c68c", + "c210364d40554146b5d619d64c29c251", + "8a555ce7382c4c55b798f4cf7b9cae0c", + "fab9443d48e24fbfa309187df78d58e6", + "420b6bcb2c594b9aad189ab98a22e0ff", + "160345df6cc544f2be85750ec2549708", + "db37e1a24c944aa9b40faba5e6a0b31f", + "6ecadc6b8e6b4004b2036414119506a4", + "b2f0a16456f94396a95be267b05b6d28", + "eb539c0af33a482382f932daded2d481", + "fb3bf5e4ac744a13b47a59e07301ce98", + "0ea35442d20649f39adf73e781ff6939", + "c1a4058298f84242a222410a210ed3fd", + "bbfc0860e635470f9a2b3a71753ceef3", + "2ed4eb60726e404f846cb4bb52b87a75", + "1fd1cdc4c2d94ecfa8d80a25f1818e8c", + "ae8a3a50203f4dcdbcd4c56bdafc653c", + "c09e054b25424ecebfb06fe072465df4", + "89411f4fc92c415291bc831e1fdb4a5c", + "7ad0f4f0ebbc455d9e9f829c956dda80", + "518b4616e9e84b8bb8b10a0bba450507", + "03a1523f990d4d82882fb924f9afa5c7", + "413e20559a1a45e7bc2e873946b78d22", + "44830aa7649e4fbb897d41768208b5e3", + "25dd2ffbff304e95840bbbf32f1210a7", + "ee106e9e6aa04b66a54a6f4552adbee1", + "30f93d9dae4948fe85cd4d60ac40c23f", + "200abb2fc82a48288bfae33cccc8f516", + "2780b01907884dc19bbd08e6d6ddd138", + "3205751668fe43ddbc3152832c1a3e03", + "a390df9b2c6647ea82ca92186921d8b6", + "304221ccb3824c8b8290b41a46769c9f", + "2581387ab6454f1787e50d5909b325aa", + "675ab80b477b40f280b7311f81fee730", + "ec2cd8ba3ba8478186679745ab1bb94a", + "b1367a8e263c41ac8690b20c98315bc3", + "1baab906e4774f93b024bfd81f2671f2", + "f13af657734f4eb98aefb2523a0c487b", + "ef7d06f13512466f8cb802e260cdced8", + "cdeff35b7a2541759a561bc921b8e01e", + "660a71e0c4c647748f927613a669a233", + "34e129782bd648a8afc47ddd4aab6688", + "c276f133f1cc40938d8ac44d698f5c44", + "577567b68cd24215ad68f5604cac1091", + "06d003d5a150421189b712eb876638c6", + "7f36c6cda81241438f3ac9e2871ac045", + "0305320232e344c08148f0a5aea78949", + "e9c1ff9a40494ea59c2263fd3d6ea477", + "3905f91101d14cf29525b9519748d92c", + "e1526b1163d84d6bbbf1f23a5f49f676", + "6940a3f265944d1e968226006bb3e1d5", + "8f5bcdc1b8ec47a395402c0284b47d6e", + "f51414aebee24b9f803baf9fee029769", + "310dc478b5d944ff839ae908d8e7ab14", + "a18c4acc74c5421eb657f976e910ab9e", + "1e7f4eaf50f249e38b7b34416f2f6355", + "8179436ddc934b409efaa9abeb906e1a", + "c51490f95ced46a9ba82cb6888cd2117", + "6d1a92514b6b4dbaaee2e28cbcb365b9", + "8dc2b2b3dfd044bc8e8053892b88d605", + "f47db77d09fa4b9ca59927b02e2b33e9", + "6c5355e6928e47308a6999f51aff70ab", + "00b360de1846428eb5c23464824c5fc8", + "7e42eeabb07843a9a5617366319bf345", + "9c0fe3afda4a4bbeb66e482f79c1e070", + "36342df2dae44dd4894ad4658720c2a4", + "2441ccdd33ed484a87f027b50f39a6e5", + "399aa9a8fcab44d4834bee2bf66ae5aa", + "5c90a52c2154413ca7ece3c8cd9b957d", + "997a14e417bf4299833a1f9daad511af", + "3e4365dca3f641ceb107ddea64838df7", + "b958f90f18ee472282bc14a0407598aa", + "f61b6e3edf854a718cf41a81a6cfc102", + "901d1a2e9e26465db2432939b35bc384", + "f54fbc89eeb6482eb4d571f5e61ed525", + "0ea3e2fa6d4f42ebbd2a0095060ce39e", + "8e62c7345c6d479485863166a8816493", + "0f5bf2fab1eb425dae1b58dcacba6267", + "a0014ea5b16542f3b788a8690f57981f", + "82822706425d40f89d4bbdc63a8ec821", + "7ff73be80293427ea2de0bdd02c4f4c4", + "af26f5af2e5d4667b9064a04a048f3d1", + "0d1fe81a88ff46d99d2ea6ccf85ff60d", + "666a7dec5b7b45da96cf3e21c81c2517", + "8bdb06a7395a43b0a790b8dd2948e3fa", + "1a8acf811bbe4b05bb32c55a8528b286", + "5dfc06cd44804b11af56820fa0d0d19b", + "95867cc0e7744d4bbba31c39814a67d5", + "571a98840c5d49a0abed18cd4492c858", + "e94c8400036d4ebcbb624f1e263fd07b", + "b3ba067109b54b60bd6a29d083654792", + "285d88277adc42f6860e0d156e7e254e", + "5f67d8502bde4aceaf6cab5e801faed0", + "de6042df3d614fc78097992b9450a23c", + "00e4a92210b04f4a9707cc89ddac0e63", + "62e03de5b2eb4e8d81d1ffe8e94720b8", + "c937e661d6a94537b8d54c8e4f24e51e", + "a0b3b8e2850a4b16a41ebaa496c566ed", + "0d5c93d02d514a06abfa76c49309b268", + "31b2f043d06449148d123d05900ab843", + "f83cf557ae874a33a2a3ae2cb1da5f35", + "cc7c7d05ae2f494c8aa4067b5c556068", + "aa39a8cc7be04b0c8e02c6142a007137", + "c9182a48d26e44e88337911294a81949", + "792f1d88997640b2bc307cb67f0fc59a", + "0155d77767024adbbe2c5c9b9bfd2c81", + "8f4477d93fe84d4180260e7f45410aa4", + "94f3741f368742a5aa04962ce30c30e2", + "907dc3f6d55f439eb5a43a68695aefbc", + "759ce0da12d64fe589911e79ab767fcf", + "d2bfe0a0062e4fabbf315ff08b7b8826", + "3d20e12029dd4e279ded26eb6cdd8d73", + "f73f09fba1b040b1a35ce31d0f5f81e7", + "3297f0944c624cdf98a80af047cd44b3", + "3c69763602904e7f8c7276b1b8459bd4", + "4e9f8bfcb1df4e268d567a33cdd90e07", + "4ceb5c93c5484b95b91bb1d1a2813025", + "db8ec8387d2547f7a875be843726e479", + "4b13b9f6a8b445c48c1e610b34978449", + "7c1ffd91594c46759bff62385604f219", + "6626c646918448cfbabe1c70d8836acf", + "d5eec69c8aaa4146a3fa2f35f5771bbc", + "43e95c43931a4801849639bb08ece288", + "abcb6181604d405caec3a3e3c8e1dd4f", + "e8f8f5ad248c4fbe9936b9d5e6669a9e", + "ab41d89037394fbf9e0bdcf0629eda37", + "f84beda470b540e998e8a1dcfec93336", + "a6193c4a6e4547d19060b8e120dcc377", + "a84a5bcafdc14e5d95843df63553065a", + "be9f207835dd4e389905af2527b4a5f9", + "8086d117922c4fbd8eb66f20111a63d3", + "728b63a6333145009ed6aff9f03a047d", + "4fa5df7fb3d64d6eb218d7cc12da51c8", + "d6cb54911a4e4b178e8506db50d83a34", + "72b0be313f554effbeb939f60a3c3b03", + "781678fa9b204421b6abdb2ecc0c6c56", + "04e31084b28a4bf6accda57d848ba9b6", + "76903e55c40d4107a7787adf87f4e999", + "37007daa91f34701ac6165c553d59200", + "5d9f94e4f5034d8cba3ac4b05dbc06ad", + "24cadc713d1f45bbada202d8fc9de4af", + "0db32ef1b56b4038a3ae8b2b8ee14e4a", + "ac7e8e30509a4e5b97125f49447c254a", + "f17cf7f2da59456d8d7e532e72b807c6", + "1d4c42c6fb614608b43ed75aa9457f16", + "bee5245db8244413aaa46110b3b35ff1", + "87e7cc96be034342b6d2fa8d6e2053a1", + "2b1c58ff1bdc481cb317faf26e65ab22", + "24f9bc38b64e4aed871dcf11080c5e8b", + "496270f009aa48ef9145dac2938b3403", + "bb6fb8959d2f408fb88e24e365e6a6a8", + "a11e682607ef4903bebb1114d675ab8c", + "68b6f49d0e594e0ab01243f337bafea1", + "e01cd8d9e805408997292b6882936c5d", + "9bff301aa8324b81944bb3c9dcebac93", + "cb560e13c9584c03b5a52143dba7c155", + "ab4e7faabf274811b024052f15623222", + "d8dd9e3d38274fd38b1aa8f7586afeac", + "b3fb4184c0364cc296bf306b323fb610", + "2a49fa597aaf4c56b95c696f429e83f6", + "283c845f2c2c4567971d42dc46831372", + "143e23a0436449f686ea0dd947e6f634", + "ea4fd1c592064b51b0d68032020b2113", + "a2d829a2680c44cdaa7773c05d29ce68", + "1dd8ba33fe9b4372a91acb129bbaf34d", + "42c9ae9b6b724735851cb72417c296c5", + "ce5c3d5ec30d4527a886b396169609d1", + "5db4a3bc2e7e4150b1eba1a466bcf37c", + "ebd106ddf4af4bdbaa3de413483ae07a", + "e88096969777469c804357a74b234cb6", + "394c2988169b49f38bc345b5cd975879", + "bdefe0425b9e4c63af6991cec186cc08", + "19a62f2cd913458d96fd0d61c92abc2b", + "4f647aa45b9441dea2f79970959d8137", + "b6cbfcecbb044cd38b9f6f2c36b6d866", + "afb1324784774f9d8de52f1c9756a052", + "b98f95b43819428c96d4d2ff4f9c1362", + "b51c7c0437bb4fb48619b7052dafba4c", + "a2b8eee763a14ffc9685506aeadc377e", + "16d741cdfb544c4ebe1303151a6d5ddc", + "6003379e0d22482d97397a74e778ae83", + "9dc191142fee4b329f0ac173ad8dae3f", + "52aa0e288b6d41a490272accfdbfb73a", + "8580c4545d1649efb3503c6c2a012641", + "fc62c6020b2f4b10823634d5116805ab", + "6cafbb1b368e4bd38a063404b5c93ad6", + "fe891e5fd0594add8b992207ef34d4d9", + "a4a55e7f5c6140f8b65b902adb042d5e", + "e13212de348549a1bd3c3b7b18dbe7b9", + "c5f496b180754980995691d12cb9bf44", + "b9ef0747d1b84dbc9414f3c141ae7d7a", + "ddd0e399d275441e81318b68eefa0e30", + "ca1530604bd54b88ae50d31626cbb0cf", + "6875bd180a0e4e399b8a1636c49e46d4", + "5f2556c873944bc6a529d3ec5a4463ce", + "e7af861512bb42d189bd38952651b538", + "fb17547e91ed4e809b99dc0467985978", + "419d8d3fca594dd29b50f625ccf9f2f9", + "3fdcc5bc702d40f6bfee171e7046e32d", + "fa0360111770494ab6edd9d3413162de", + "753109b3b35e4c63a9f51da6b80c16a1", + "a3900690b1914f75b476d0d72253bd5d", + "d006c847f6c14b6b8bd57869d18583cc", + "8d4ebe764f6b4672bbb392e4f3c69664", + "12c89905df1941afbba4d33a61d15735", + "daed13f9c8d746ab8bf04d50e7445061", + "6c0c7f2f53e947fabe42e50d409c2797", + "bf83213efac34b3cb2ad6ac5ddaf05d9", + "544b946d7002421f9d3bcb6df73ced43", + "08889596bcba4a2ab09f3533d7cf14f3", + "cb2efbf6e42f42a482d14876e78ad0d4", + "c8c10e8106c2425489b4fa4415fb182d", + "3a12484defd64d5091b613396df3eeea", + "b8dee2c7c5ed45d79713cd74df8268f2", + "cffefcce9ac24c25a738eb1c491ba8a4", + "5505fea9f35f4a1688f4b3f13056a706", + "c95ebc6dc00240f6931f068e4c7c3e49", + "3e6218af04de4a9aa2de7221331ccb87", + "b4fa8350738048549d2f3bc284208187", + "7e8aa36d46be4afc8d22e54b4ea844a9", + "a78ba41a6b9349869f71ed2fc658d5dd", + "e3d7f1717bb546c6bc875d010eadd690", + "4be7db24c34147cdbed5334358bb5d7e", + "b7dd410db57047528493373df2442fd6", + "202d31e1e8894d86861acb8baa92eb09", + "d7a8727b2bad4dfeaf51361cd1338fb5", + "371658eb3d8b4893bfafd943ebd73ec3", + "6126ea3363ef4a27a17a1074055d9f52", + "98aeec3157124afe8ae14d399a6ade0c", + "d8071ec4150947a88ccf5144cfa2927d", + "a212dcd1c71a462bbc0705648515ddf3", + "bcd322567e4447b383773e4465004786", + "ae9a9b7c9fc54eec935ec23db26df6cb", + "87583f33c1ac4e8293c63238ce29109b", + "31d46740ef6a41b18f67808225cef468", + "86bc1b563f724f19a653ce78a0e4ee0d", + "0d72ef49ea764361a865207e4d0d8252", + "1313700a4b644159b8298f297c7939a2", + "d717ec46652147989c5b90a3a9a0bc6a", + "346a601ab7604487b56bbec8530af20f", + "142f2b38673d4768912c9e7ca1dfc0f3", + "c8027aa24f614ac2acdf76037814b3ee", + "d89cf9a18ec243c587b18ec0fb5218a1", + "4ab4ee46dad54ad6ab608d88eb19530e", + "4f0a875a047d451cb65316f590bbcdc2", + "b89104ecab1d4f75b328cc1a20f0500c", + "bf2f02484d7a4a07aea4753a16f497e4", + "0f2b6f8f3035456f8e4c23896008c9f6", + "47af9ef907fb470ca2ff9d28e133ded2", + "256158b91b0c41b599674169d07263a1", + "5e69391ff8fd44cf9368d10a657d91ea", + "1a8fab413e98406a8c3ec3a2c408ea76", + "a9d3e75e446e45568005d620e84f57f0", + "c90289b34b58418fa2a88670c5e9c8c3", + "e44ad5e147e646098f00ec5033ba003b", + "bc0a622924c54731aed507c6d907fe6d", + "129e7c84dbf04d2384da7a84e7a2f877", + "d74165f8f58e40209ce4013c1057ebc4", + "1018862b44bf4afb9ab7edad916a0059", + "130ad85e76a2451599b0962e49f91ca7", + "88c3b1db49e945f09cd37f04534956c6", + "08eebd593f3a468b9ed7a5e3341ae16c", + "9f504e7071f746bfbe55feb25fe14de7", + "25f0b058cd2342fa9dfdf41c9df5fc82", + "b1a1d9930aaf45f2b956595ad6696c75", + "7adc38ead24746be844dea0e952b76d4", + "30bfa06a68a94728ba17ca3f9c99dea8", + "5ee55ea5e43d46ea8e6696b4a7308ab3", + "7fffdcdcf7134bfa8b8680208d5c46d0", + "bdce3efc24c84724a4d9f50fe64e4fcc", + "8e61eba9e4c8400a9bec05a0fd1d5bed", + "6b61ed3f4de244f08a8cbe0534e83ff1", + "df8437e0802749cfa0698b2b30ee663e", + "4a8ea9ec910c40b8b5013927ec68d655", + "2d157e52273f4212b288c40d2121769f", + "3461b2c6f57f4210949c4bc3cc750210", + "8554924e6142498f8b46df1b0e34bfc2", + "b0c00b0f224c4b04b4ecf0468445d0d8", + "355b59831763412fac5bde1f1c56b61f", + "a9c802979664448c808745ace2d70dc3", + "548b4aa0f2de4a708429aba87bf19c33", + "79e6d72fbcf94352bac8589ce677a7c4", + "a1853e688f7f4dbda9e5dfd9a9e9c840", + "eeb7838fa770487ba4a6e0aac8e07b1e", + "fe81b2623e4347fd914c64d83905f214", + "bdec7557eeb64a98a4ff19fc22e9142c", + "85e03bbaf084488ea66c11df8d009fd5", + "49b10c750cfd434bb7bf44db5192a538", + "c609327dd3a74fb597584e1b4a14a615", + "dc18fbedd63c458b9b31878d7909f9fd", + "a5da5c237eaf485f9059c91d802c8160", + "a20c08ad3c7c45c8ae17fb56c3250c1b", + "64e55ffd4f864a20a943710c581d194f", + "ab5958f47e294919a956c7e486276499", + "71c10106b4004a6c84f9e462edb17605", + "0529ffe277bb4016871c5a1118e80c67", + "3fb68260423d4a31bfecbbfb718d504f", + "e89af135f53e470ba5f2bb2f056c3952", + "2674f1f26f12465dad6a802cda49289e", + "0db963061cdd4c348b0e3335cb51dc00", + "fa7c15cc4fa5448fb6587a873ed63459", + "19d9aa2c51414e76ac59a12c87e98acb", + "838ff61e18204890ab406e0b35353be0", + "8b67dfff4a694398a50638bff750ab4b", + "6f3afdd50a464a4ab5476e100161c2e1", + "920dfe5c30254f1ea672688d08c1ccd1", + "65e8e2f18e2645198875e19f8ee4c86d", + "b46433e262994bfdb9f6515b310fe825", + "02a8266c929f4c05b6e5dc1867fb719d", + "e12374de48c64cd5836d86957eaf9be5", + "d5cb92f6e9b44a7d8f1818f701c31d7d", + "be7087facd644474b858deb1079a5bcf", + "884ceeefc40649388547665ed5f24c4d", + "1cf6fdafd5a049098b774bc00680aa2d", + "137bf24dc97e48efb5b5eb7541d5f932", + "caeaffd548e34e7889c791cbed73be75", + "51749275659d40198c491f951a27b4f9", + "4883d6cbb2a04f7597b324021593dee1", + "58738abce8c641de8dffd611c599953a", + "a76ab0a3f26745a1812694187f4c059c", + "60becd3edf51415c929eaf8ef196ee2f", + "e13bbc35eefa42938bda436fbb17c6f9", + "36f71117ba4d4dd7989bdefbc43c998f", + "0af496d645b94038971cb609f782a171", + "f5aa336ab89a45ffbc9b7dd2119ff25c", + "cab6cdc695df438ba893954bf6277c1a", + "37d1202f7f45483a88f5890c6daf8885", + "c3102c6cd57c4e60abe4ce9d0c3a41d3", + "71882e981b164d34a2ecf1bd614a2d31", + "7c3a9faba4e84fa49d8575a698fc5f27", + "d2474396006f4ba6aa84ff27e6475b45", + "398e905b84e147feaf483e5ce59d649b", + "34b72655ce9d4032a01eb31b5daa4570", + "36b61b53906e4274ac1826d1d6de5c5a", + "b3d14df9c54c47d0940fb1094d20c2fe", + "ddad88308c5e4cbb952158304efc246b", + "eaa971c743394cd7b0641d0309cc2009", + "d5f2b4b7d9874100be9c374d4b3eeca1", + "ed342f2d9a89412d80c4e273a963eaf3", + "35feaa052a88429a97b251f89be42fd1", + "7b2c965dcaf94932894e8d6eb7f4e34a", + "15f43d2554724b80976c05e6a414c347", + "87428dade9034cefac9eed6a1aeb14a1", + "02f2f34578474d45b9988f3c8b817a2a", + "87605b8662e349cba2ec63f92db4b45b", + "fdb658a6fb57411ebf9a7b9f658770c2", + "37c92ec9ec42449d990636d693b90bba", + "fe8cd72634bd4bb3889f38feeef9bd8c", + "0fb26210a2a74b2c8e5eb5e71414cdb6", + "049c20b8520342c1a46551a73fb0b57b", + "22a19ec7b1ed4e67a8258aaaaf16fd28", + "aa19f4a12ff34ce9998119352da687cd", + "c38293926711435d868dde2c389e748b", + "ab0a3f25354f4c859fdbce10e5b51279", + "3df2a8d050d0493a8872cb9e2d6d0209", + "aac15405fac54daca8c94549b38eaf16", + "09d7524612194157b0406f74fcb5672e", + "3d4fdebfcef342739eee585ad95338d2", + "870394045570459587face4cf047c06b", + "ba443b4e68c24265ab4d44c569c9ee6e", + "1f8c95814ddf48f8b3e4239819641557", + "17fef9881f9c4d5587dec6c06125562e", + "44c0e4bb667f4403819723cfbe7a6a9b", + "26b5f6c3ceb640d78829c0293c3ffbf9", + "eb9393eecfac448582737e73ae546518", + "8b323fecce674e0fbc90c69f63ea0a8f", + "f2e50c587abf4af8ba0aabce22e44841", + "000a00944e294f7a94f95d420fdd45eb", + "b3d746e8e89d4009b0bb19563b603f64", + "0f2e7e5cd8fa459f94fc2e257abd65da", + "1f51096857cb46c5a2bd1ef8bc2c1803", + "935cd42bcca4471892e14488d15263f0", + "579537e22b664e66a93e20917e6d0125", + "de5b3f50a0e94dbf98be9584e01201ed", + "c5f56c60860b45999f49efe5b2b57aea", + "f9b9f0aaa0994cc8892ecbda59c35bb4", + "9a95e95e16954914bb861af398af242e", + "e6dbdb8aa5174be78fd944c21ec72e5d", + "d772d4c5165849f4b37dfe98a04de41d", + "7f5ef64954ee4428b6abee16f4088ca8", + "fd312cdeeac34a828b90345479d3b7f8", + "e844114fc02a4ca3a39330b44ac0dac2", + "1ae9df327ded4cb6a9d0115d20316566", + "6d3b52f9606c4c2082bf9c60d1a800d6", + "684c85c249b54a6f84aae2caa29a8bf7", + "bde3f8af969d4414873ac66487337140", + "3bf3acd29f7948cd817b6a43923d07cc", + "a37e58a611d64f678834416bf2a4f107", + "c0be8d9d027b44b29da98baa937e1ca9", + "57d2004875be4878b25493723cf45469", + "1addca6527d246e783847c3e2065dd25", + "3a124fc5c6c04a1690209f340ffae441", + "26eb4f3fd6374da2b54ea86d35ff9b51", + "4142c4c8d5b8439eb40f68680f265df9", + "28f3639867884b1ab9357e990899d9d6", + "d89b3a8543fc4a02afd8ab29938f0c5b", + "1b36172e3e254b46a973f0132c4b2e08", + "ebff999fe68b40dcb89b5bfb069100d8", + "3d1c606dd9ba46cfb3f5b55e78e192b3", + "59ee00866fcf467591681c091e1de20f", + "13f63e55353e492183ed4acf05aea855", + "9408ce8ad5fa45e1a8430ca58f311f22", + "f4ec12056fc04342ada7b287d07bd7a1", + "532b02858c67410f9a1973544f25dcc4", + "61bb272c9ea149e18511c2e9c6a77d49", + "232e6d20323542e886ebeb483f5d95c3", + "6fc30ca34f3a4e2eb076e4e819f1b7c2", + "cba025c03d144ddd83dd04057d95b935", + "c64164760318411588b90671b76adb9c", + "ab7ef6a133244de8bdefa32130aa4948", + "d1f180ca1b3643469c450769133b7517", + "82e0bcfe1f6b41efbe10deed14185b88", + "39a0cafae6b64d82a645a121746587a4", + "bfe676a782da45e19be08f49e1f2b9ae", + "dd8b8bd637b5420badb323d5ec82a948", + "b4f4e2fcacec4ebcbdbd8f55bf9f3f67", + "977a0b39a6924df49143560577d27218", + "78f9eb9e49ea4c03b14832c76c8ef6d9", + "f839c554576e4aed9ce90f5813656d8f", + "d9b022c5b0ef4f3bb6a1f5e1c4627aff", + "725e84ffb4834360bb26287050a0ee63", + "c33fa7f91afa4431a28c56f6e62ec59d", + "ae0d40ec0b59459dbdfde84138bae813", + "2747086901444c188692d76d52c6c25b", + "63c794b7d98f4f6985d0ce146ec14e82", + "0f2f0e489ab445108c939820a00d4888", + "af514ae1105f4aa5b0496a79e42a0fee", + "3dab2a85b1c048eca160fc5961e9ef34", + "561ee2b9725b41a58c6792b09bf4698b", + "cfee66951a2d42af908f6829676cc369", + "297c2536534c4045aa0be028d10d39d4", + "e0f1e693070f4a84bdddd18023b17e12", + "fa13369e246348059b24bf556281138e", + "c470116c9a10405488a7e82b8a86149f", + "bca6c71fbdce4c9a813744aefe926467", + "99cd3901e0f94cf7a621c89dfde9e86e", + "5d3c21cf6fa24b919b1221e9c7c9816f", + "6d523d60eaf14b4097bcc953db69f8d2", + "ed1d1e31426e4368a9478e6fa9291e7b", + "5329a470fe4e429a9151c6ff2544f8cd", + "ade75f989f9c4d5189b84e568cb6acc5", + "ff1c458022734dbda358ab2f73a62fa2", + "2b382918cd56429db76672b0782bd039", + "0c1b7448f6694b028d2c6f78f49919e6", + "3dbccd077e3f41ecb23c81c7f215c156", + "d5145151f9584f21a655f63b97ae5b62", + "d1fb860a57c34033a6d9587f1f881bdd", + "b89bb5bc35354b60a908bebbc7aaa899", + "e105827387464d0d8548e0dd144bfdc1", + "ce04df43a32e4bc7826d145977996abe", + "da5c1c6eef7849b3be5f858279164019", + "fce56ff9023e413cb319cedbffd06f94", + "6c2f62ce110744a1b9cf8af67198aaf4", + "e0aed417d06d4a82a68f221a32c1ced8", + "40d2e7afca9f4d3d94cd16038a190333", + "1bedca252e4d46d7b92826271a578154", + "7003e0fffd0d408d804602af2adccac2", + "a5d1ead883724214b1be64efadb3b4ac", + "b3bc25f585124574bd7e81cf061928ae", + "cf8ddabc2c3540079623c39bfd133ca1", + "61a609a96d8a48adb9b6e218e8ebc016", + "6e8249006144427a899a810f9ebae0c2", + "fe9bb3d3bcf94566904ff9acd24d1e15", + "55dbf0658a194e469dcabb7271cfd5ab", + "ed6850e61792430581c8f9851fb7b4c5", + "e26df6f24b974351a00dbc472d691442", + "affd8f5de88c4e46a5f3963c70055ac9", + "7c78945516654ceeaffdfaed8b60af61", + "07d8a9286eea4a80ae8dec18d1b35b3d", + "823e79f5e5ee41668abce9d8755c4926", + "8ce246aff3544818a0f4406010703221", + "049a1db6b9bb498d8d74370be258e0b6", + "500715ca29c24a5c9322f90aea06b818", + "94c002a46f7f4ac498b294e69e4e62cf", + "c82e45e542b84bd191dce61efab5051a", + "1898d35154c64b0cba12881ea68e56d9", + "4843cb827f1c4accabc80d0b9c6da82d", + "5bc552f44d6d4777a406de864a4af282", + "f13b94e000d14309a2ef175054b661a6", + "6363fc4d6d3a49198c5d25d14798c4cb", + "a9495c8226bd4c72b54e1e71b3f98acb", + "4b291cec60cf4cfd92b3037f6bbb6ec0", + "ec89ac5fffb440d780b2cc3550f81e34", + "ca84373f029c43599deeeafcbfc9f3bb", + "be1feaa978dc4c9fb3b2851a96a89307", + "018644330f9c44dcb49ade255b281a52", + "b7ecc8cc78ae48dfaf10441dcc304cd2", + "adcd33fed52641f4a15c8370fe8c4c1e", + "74383f15d59540d8a063bf456b81f307", + "68055038a07e4819bd38bc3ff3ee39be", + "076f21619c614b5db750544e959b9ba2", + "74dc47f150784be6808df5fbd3d6801d", + "e5e185f84e644a1381e629ecfc8162a2", + "27b34ca5f7a940bfa3ef5245c664024b", + "7a98375a88294cf98c848e6951d863a6", + "f59d64661ad2466eab2e588d61750767", + "4ccc7c0d2ba44a8cbb69ee295a9bcb51", + "adb3f4a93ab84e25be74441ddc3ec0cd", + "9cd826d44ae14ea492a4f06f2dec2c83", + "5e7ca80a58e44c3eb6bd75a89be80d26", + "a5251e46b8d5463fb365bb8e2c816494", + "9abdd45256664cfa83a57bbc93bcf5e1", + "d61741ef22c84dfabf222cb2c9b30e13", + "32542a2ec4974da5b800d21bcab0be52", + "0f1245e2da8f4a09818cb8192fa96c63", + "8e8337b83069431fa43d536a7a101922", + "8bfa354e4afb4d95b2274a7b45cf4986", + "4dfe531deb234506a8a26fe410c18252", + "da5ba32a71eb46359ec370a023d1f0ff", + "2071bda681b642218b6829b82e4fd93b", + "f4ad0128edd843d98ce2aa6ca0710efe", + "f195dea3125d4b188ad6134121ce60d3", + "b0bedc070e1941f789294bd0fb4853f3", + "a17cf46a3d8045f5958d5947ed1f94d9", + "a65d2e4e3bae4230bf72f4e07f2ea146", + "1d166425316544a8a8c449797c44183c", + "7a8f962342b5422bb0a5d1234a4b5747", + "542ace798af8420aa3147990ff14c1db", + "ff10170d6b9447e794e8a4171e4f3fce", + "79e205bf89454102b85dbd488c3201ba", + "a9e2dfb69fb44536be2ac33ca1f5cb8d", + "be2dbc64a79c4e85b9810789e314580b", + "66a8cf9d10d244cb96793e4143842f82", + "51e93e919dbf41e99d4ef84e8b8a82ec", + "45590434b55141129754ae8a72a28f5f", + "ebeb34618c144e4788e04bbf830798dd", + "052e003ffae8401fbc6746f933a562aa", + "896b70abd5a14ab3a832e7477bca42d2", + "8e24a6d4d15c4c62ae053cfa67d99e67", + "5a75d007bcb64ad29a326669d67a30dc", + "f19745ffe8ad4527a6f5f8332d7ecdec", + "0a36fc7335524892884a73c3ca1c37d6", + "b91de84c7e3d422a958bf8a868d88377", + "81dd319a52484c26b41e5556f3bf86da", + "f1cb64be69af4f16b6a1a53ec8ce6411", + "c568d445fae34c9eb3dec11bb0869b2d", + "05ecd3142b864c1da554fd27c829f786", + "0fc92e9a5a9542dd95a020c5c9a4b81a", + "8ae753ddcfcc4f3a9830d6bec7925017", + "e0de2fb2eed747edbee56379f31b6777", + "678dfe84d8bf476a86db351bd2b8ba98", + "0c4f6b97f9f14e228299a46ab5a00468", + "686eabdb419f47c38f7353b5742a0ac6", + "7ad5a7d350884a258a7326dfee5fbf8a", + "37831c39556e472cbd722846573b0e38", + "c929302426cd458184aeaf3025ccfd34", + "3b63269c27024f29868b8f94c9930419", + "f34b02ae57894ca7b00d2cf3f5ab210d", + "2b3543bb1b924a36ac8b12d871477989", + "7b323200b39349a1a688c9029bbc1a97", + "0d4da3e22a004645b2df75cf80601fc9", + "6d53285d41d941f8b12daf03164ce3f3", + "a0501b0193884ceabbc7309952ab5f09", + "bcf3a4e49ee14eeda2faca7c7455161d", + "6e0a33bb4d7c47a0b771042a44f441c4", + "966037025d4d41d38e074744f8505484", + "0685a60d052e46ab9a4b96a62f30ee77", + "a9937f5516dc435cb47d94d8103ee19d", + "5f63c438bb304f25a8e0f116a24acacc", + "c61d219cec184a4cbcacc71fe3116ea2", + "042862f1e47041a9949ee2d565955075", + "66783b21a83d45ed9b9ea7e60748aa12", + "1c3be347aa1c4c17b69578bf3f01dcb7", + "22f0407d78ed40409959ff57f2d96792", + "5054e4c4a391422998ba42261360620b", + "ea3931bb3115482fb537488432cb1280", + "7a61a39d24be4393a80cfebff1499e8f", + "071123d3a3a0452fbc3a560c5eddbd93", + "91b54b0d1b7a461aaed4bd88628c13c9", + "f04e1f28b912435c842477778d2426c0", + "ad8c845bfd6046659ef93fcae11dcd81", + "25ffa3995af5446e9a30339ad5aaf60b", + "148cee97600c4356b82dc72ac0a25054", + "80c118248845433ba608e30ba4f787e8", + "67eee79193b44b93b0ef1bc0934953c0", + "54c4465c1b51443ea1eedc0385e2e5cb", + "9d45f15fb21f4fc89118b2631eec5fda", + "5414d0231cfd4fd398ab4820e9a8f5a7", + "eac0d2c3cdbd499e82def321248ffeb6", + "8d283399dde7478f8aa977b48a427c36", + "11e572d8b4214f02955ed4f97dfe2afc", + "4fbbdf9506be4b6ea0d4ce74007a37f8", + "3750417613224e16a089a78ee37b9e5c", + "0d0d1c59b0474d2ea92ce2e172c9f56a", + "06e99d152db34f3fab6d72204cf5fcc4", + "6ba7bfcf3d814377b7c3542759672c4c", + "b50870ee9db34d60b741df3a8cb5dbb9", + "70886b390e4c4c28a7b0571092998102", + "1985d2c6b0d3455789622e6e599f070d", + "1afa71987fbd4632af1f13099c9f94f2", + "4ba977305a54449fafa390a7a1e426f1", + "5beafb96f8774fc299c794742727a833", + "511aa069fb8f4e759de014e569b22a05", + "4577c29670074ff7b19e623f0975265a", + "1b2ed84386de41e68e8627049b98838c", + "271800d72414443bac04a6f60c5eb738", + "5cbc44ac658b4828b663f97c0d23df79", + "c57f54e0009b40ba94988a47ce9b2b68", + "39e0d95fb7d94a2fb9017d48046eded3", + "0bd602d9d59a4eadb35f871c6723d2b4", + "f564f7c3dbe640dcab807975975d02a6", + "a14d853273364a889699d161205090e9", + "2da008c410be42d188a0c95aa1bca05e", + "6c48c94be8974dc7a5932f697c0ba68f", + "4979ba26b80d407f80cafc9fc5997f37", + "02797d5feaac4ccabfdf8b357fa2a13a", + "5bcb64077fb34c4e8037b16033be435e", + "2555a69678e64f91a286dd8132f7e937", + "ba7f8d096bde49879e59116fdd85681e", + "b1b96d9229854ac38d1040e5b06330c0", + "a98145cfd04d46c48b011615bfab352a", + "b61e3045c32646ce89342031818ae5c9", + "c64119f83ef54b5da36106662313a07c", + "5677c97a09bb4f5ea7b1c9eb7f4ebaa0", + "754e8b5b79bf4103b6f57682830a9d3b", + "fd2951e29c6f4ae499f368a35475a8b7", + "833a9d386caf49c19bf267a676238af4", + "520243df8f944a6bbbb31a4c24a22cf6", + "3753a0642fd541fc9ca6c046b42eb328", + "dbb929d28e4641baa75563ff155d2a3b", + "7e94ff0063b043da9ca1951c65ab79c7", + "2b3c041fd7df4c82bb7de58f3d6a1712", + "ff993f2a369240ec94bf52612c964bb8", + "e2ae4d405c3440169f8b6b864de10d65", + "c100d8b9e4684e6e9be20c16c74cc257", + "b2566e74d1574932965c1fc42e535ab0", + "bb01282cb8b64470866260455b0b46fa", + "e5bd39c7c8f14fc7be0b7c9ede636a1c", + "d16ba0c33e934b3689b4f6b280d81f9b", + "8c838d3ea1e8494396438b5f5dc78ad8", + "fc28c62a47f24280874fd00cddb4cea7", + "e0c6a24f9b974c97a89bb2f876680310", + "1b01f83a5c9a41cab8b6dea8c14e4538", + "43860f8a9f174cb9b9cc15a3f6786fbf", + "db2a8ac735f04a28993cb6a2d3677680", + "2ec20f15b08c4c2fb16e4df5d837b893", + "a633e00842e246bca3710a800194bd6d", + "5ec1da29362447e9957eabffb724bbeb", + "49d6184fb96d47e8a39d126c622615db", + "c6af42f5c0d14575b8c254b253c9d620", + "45e061790f364b1da9ff876382adca02", + "0b09f15655154b1f9968ef54656843c1", + "8216bda774f04260b83302141101fe64", + "2a43955d24514e4998ee6fd478399f66", + "07ad1f1137f6426eb2d66f6418cab2e5", + "10b2191029b44f81a6dfe08955a7ff5d", + "3ee4942079b342358e14e8e06c1f29d6", + "c926ea899184451083114fa55e8c205a", + "feda32db28b840cf81f1be28a1267e68", + "2fd52fe6d4b04b34aa214a1e783e7084", + "5a293649f3f64061accc9afdb4008c25", + "5e07dbc5f69345379da81e24c5c24cd8", + "12ecf41ddb8b488d9cf3820ecd56153f", + "31c2ce5ed746407f912315bf2f7e6de7", + "5bca4779ad2146c78fd2d988b055509e", + "4711c516a9d04f0c8892752ad82b1f12", + "2447f7535657403f8b99256638d011e5", + "0331d321e5e5498b9275402736b406e4", + "974e872e471e492a970e8b6519c58146", + "f62314240a0140a89e29119829aec000", + "f08a0ecdd8164436ab13b5aae2552b98", + "61b47a7780354d56b3d937bc5330c88f", + "ca64685b4d9244589c6bd65aac88a35f", + "4f3edd9bf5fb4b6ab11433cbd9e19c74", + "c2d11728b7c94a25b6e19110f0a6a270", + "990c1dc517e84e15a7b4a56114250b45", + "a151a5305eb445cd86eb8838ecd97e69", + "f341308cee4a42668fc7433a64b95a5f", + "40d85183b2384f3db6a8fd5ed8ee601c", + "676efb31f0024a4bbcfb2eda42d45ebf", + "c730cefa973944eea0adab30f2afb76d", + "0166cd3012284d0cb89d0c6548f9680c", + "bfccc771e7fe42559e5742701ae9a908", + "6d114a9090fd4b88af3d1d65839a12cf", + "7aa5b4a496de4fdd9d5f3608b3120657", + "c9ee9856ab9844ee863c3674654e03e1", + "dd63402df69742e39e989801f282e58a", + "e6270b9f9da84810a41ceb333f083b2f", + "ed62ad059a8842ce9d1ae53d553c5195", + "34426897925b459d827a8eaad0a9dfd6", + "6e67803ed20b4f9e91c5267290a83ee5", + "0f91a706c6d0454ba101e0d711011b6a", + "72641abc7ce94bcc8d5bf0667fa9a52f", + "aed0063e5ad24f529a12d4dab86c3cd9", + "42cbfc14c40b468db869bd1ac032ab75", + "27d97837f8444c9cbaea5f5479341de1", + "f90e2befebcd4088ae3cdbb8921a87ea", + "ef545e6268cd463fb5c23b277242cf69", + "341fd3bde213474c9cff8d2665afccfd", + "895a8e5622df45b588d166d59d564acf", + "3b26397a93cb4fbea998b2d3d9706dcb", + "2c2ee6ce1deb42c2adc2e422d779b7e9", + "8ccdcce5978f4f84a95bc20d6d1071a3", + "dfede8db0202431c98e195b222b34d19", + "d86b51c741984d1fb89a5e17bfea5cc4", + "27dd3a502f8f43ca92469df0e3e12dce", + "33e610a5e99240318b543169547b898b", + "b1c14cabcfdc4cb4933c95848cdb411a", + "7641b507fa82442d837dccee5c20a41d", + "6e039c6c606c4c26a1359514352629fd", + "7a95d0269fa0478495b179a7bc866d49", + "57946e0708f7425486d19903b3bd997a", + "2dfdd57b93224b0cb2f72015deac0978", + "2e51e1c5ef2f44b68a37307f21e665f8", + "5ed2149d80e54bf98e9f31fbd4b80df1", + "3b6a01e1699f4a1191bc91e85e792d27", + "f0d609a12d9d4dbbbc01419a0fc367c9", + "ffd59a0fc93e4b079d7022090606ffcd", + "7f9d019516954738b232cab140ea3e61", + "5fe748911af44df1932a6fa9213ede67", + "63329ab989a24abf9f3b7298e8f85da8", + "74e7cee7ed044439aca9241b0739156e", + "8e8daba4147d4ed3b47d48733b4b5c36", + "f588da6033394001afb578eefd875718", + "1afac70684af45f8ad89fb636604c664", + "557bc13b763c4f51bccc831c7cc1119c", + "36075e83866046b2b296880a6a553d43", + "82a2349e304d4590884b42cce133de86", + "e53fd86f4ad04f8fad7681c30a576ffc", + "00fd0618c93b4979b258f25df0109a6a", + "f53c9f92f0ad42ab9994e57cfe711c96", + "26f24f5defe740ad8964d3fb8f81b6b0", + "535258125b254ad59690f08b4578ea30", + "6baed46c9b77400abe31d2260cb4232d", + "128a9d2c601e4662acaafc1adf0514aa", + "58f8f8e2d4434cc0b0b2e6e7f47cc354", + "504de538d4d94baabcd2e06d15f784ee", + "5bc3336c6b6b4350b06f9b81af685ee7", + "6b6fd5794d3440b996b1fffa87e5abbd", + "c6f67e740d3242ef97f4e7a8d338de2c", + "7955c65e40b345b782d6a833f0c41acb", + "f206c7140ab9469eba2a4c759eb7b23e", + "2f0a7082f7c844b1844a7be5205f9db9", + "70fdef1abc1744e3a3e0a828d6821fbf", + "87fbad645cf449a6a8158993bec30e50", + "46adf980624a4725a180360348c26325", + "df12be70236a40c0b7be2f999813b894", + "e9f53b64daec4b35b4f18e0fe9ba415d", + "203455b8624149b1a8621935ac746757", + "f818488f99b14ef39858c0c215515bd0", + "1c207c5e7e5a4f45ac1bff888665c1e4", + "924a5601dc914ba3b0c368b8b1e92047", + "f2b0dff5fd604427811e59ac41fa1e34", + "21b3159c70ed435b9862379e2da550e6", + "665ff23a1a9a4c90836bd5e7d3d8a4dd", + "d8daffcac9c64f4d8075d78959ff9130", + "44672cde0c444f4a93f829261f97a3b4", + "93c594a9cda145a7b799394860d542d6", + "23402b8258c349bb81b3170be01fa98f", + "3d2138a8ab7c43afa07b2c1825a28888", + "165a86b9ef6a48a1a53add653ab7c979", + "3ab9495bcc284c489719bc9b8a6eeeb0", + "a1a8db1845ad4cb1a7751c88c88c19f2", + "7726480ab2444375ae94de296f0849d0", + "5e1c5212624041a8901dfe3503107bde", + "de7f4c25ae51431abf89ca02cda7781c", + "901284a4a0154d0f9c0d3177ad552320", + "a0d0ea06fcea41fd843af40691e85f34", + "cb31805592fc4a4a99d9a294cbe50694", + "e54ce0d44f1b4b07a51b81fdac130a89", + "2742b6b24a354c8eb53aeee887e27736", + "dce1783b027f46d4890462622091bca8", + "9b42ef1096da4103a12fb80cad01ac15", + "f4f04b082af5442f914fd4a72640a76e", + "61466ebe080e4d22b4cfc39f6c69e0f4", + "cef43d0b4ee54de191d8d6d1c607c3b4", + "9bb1930da1b24614a1b2f05350944129", + "d3c265077d874a5d9ddda9440e7cb278", + "ed52754821444b92a7e4973a13f9cd11", + "eb87f944a2b344ada73814966ba05634", + "67549616d13246cfb1a540f9d6969078", + "9688990fdc614e838f2dd54715a15b19", + "d0711d74a81040ab8495cc5bdd5f7369", + "0b11ed1d707540d5a444208d0e558ef5", + "5d73c308c7b54ef6a1d1f0647a269c56", + "486fbed84ffa4fb6bc3efac9ef581079", + "28a5072d83f84ef4917896fa9c5c1a4d", + "cb23c0e192cf4a378a35d39350009648", + "9a486de0f04b49b9aa1095675bc42b15", + "80c1cc223503498fa5ed7f2bec2f96b3", + "6d54fad228034db89b8db77a05516d06", + "461f173474e04eb5b9c5de29753c28e7", + "10965a1ebcd64aa8b5dbafce0c7926a2", + "7a09c75d40e84b10acfd4f8c40e08375", + "aea2ad64c7d7452f84f7dac3a5fbd8f2", + "bda7f77e18a44c539294a6830b6a4216", + "3316a5d3b2ef42f28d9809c1a5af9b45", + "35029a5ab68c41399b8400e3188b42df", + "1bd2933b309943febc7e3e2b63a89205", + "0f4fa19fb31c47e5a1f46981b01f4d07", + "85fe558b25b146988732dc6d64556141", + "beebcf86bb35455aaaa18b8de071daac", + "8cd47efed2904a40968775b349c01e9a", + "f209de0f9c7b490da5e4089241f4705c", + "8ff34c1ebbef423190062a3bd6883493", + "39498c5ba771460cad3caf12b2ac2f92", + "4f28eb03688b4e78b4dd4947d66551b3", + "46b4b4f592c54f04ae524d656f1e1d2d", + "27bce186f25a4316a7c6345cbc749b88", + "6b47d0ab0b1644c3a700cd853308500c", + "b8c251d79e104922bc0497a5d2fdf822", + "a7b8c6dd86024e0d83ca0431e3a69eff", + "b580bc11933a4a5087bb5620269c5f95", + "a13d2e0b2ad84f7f9b87a34cebbbc7f7", + "c27f71e432b84353a245fb9b65dcdbf2", + "9a1c691fac774bcca4e2ba565c4c9d9b", + "f538de1dbb5d4fdab92098305efa8d76", + "c6ea23d3e053419cbf7addee94f2ff7c", + "e291611cd3484a6c99d385855c595f56", + "3087925346ee49e79c02b1237c9dc9dc", + "cfe6466ff2474104bfde9ec8ec9a8b71", + "d85b6766605142928a18091923f10120", + "fd3ed249ee5b427ea2ff7183df30b75e", + "4d465440bc9840bf98c748458f23e99d", + "c3de8f6d87bd4cd19ccd1f6ead3d4d2b", + "a98226b277084009b914fa7ed09110ba", + "8b75312d97f94825be8f69aa1df9e505", + "9a4dbe959c38406d937929af06ea27fb", + "313e8caf7f374d28becf2240a3a9d626", + "fe949f804d1a4f2b80cceb544220517d", + "6d54835f0e7243ca8c51a2563d121599", + "2d85ffeffe9b47619caf1822ff736487", + "c9f25a7857e04bb0877f2d479d54e8e7", + "4663dc46ff0c4cbb88e325b5a2b346ca", + "8a96f01efd46487e8d97d52b247cb3c4", + "67c96714afe944c7ae15377659a5c2bc", + "132b635ab00748ab905bbc279497d6d9", + "764b0727c9a14a6186a54b99d553d339", + "f032a505b21246b9b272219c5435ab16", + "7aeae41398f34c4fa5de50c2e6276b11", + "c144bebbfb484f41b47b87c1619b62f5", + "4dd72b81abfb49c6a0ef3d32e1386b32", + "a114586cd915407b869b138853fc59af", + "772863c556de44e6a78042aa047bc8ff", + "6f67d30b547844a18ca5ddfcc86f7cd7", + "8b9955cbbbac4615be02728d2fda6106", + "f9f92c3196ce41f9acac925d3c9f7116", + "46c430d6ef1749f3a5aca170907c14e5", + "f87caf6ac5a445ccad1a97653688e16e", + "ede24e6264df47078fb625e3073b7db4", + "2facffef819b49558d93d4b4714b86e9", + "fed2fac6be1a4e0ea225bd9001e88a79", + "b882fd37f09840bb9168479ca5fad5e2", + "100f381b845644a699ccb4cb39572888", + "4721a75efb6b4d1ba91cf61696fc9a31", + "fd9c2492eb7a4aabb19597af10269f5a", + "470f1dec4a7543cc9cb88ce8d8c7e858", + "b093c1c6676649668b7c34b1d9be22a6", + "a0d141c60b1a49b3b33d5afd456291f0", + "624e62d36ee149deb66a7318130617ed", + "4582749fcf9b4cefbddfb02f0e0ed1c7", + "f734d62f5184445880e73f7a64935c0f", + "ce16a205f1f84966b0f698e495d5c952", + "9077c15457a44edaad811a5a9f1aeb2f", + "ee1e4fa481484989b0e01b0078b71a96", + "f3c2bc67d4a54f37b41433fd67c83aa8", + "e8da09c01d4645e6998cfa69f6dfc88a", + "1063be937b5347ef8a8b89596c558c01", + "d944627e130147a4bd1bc1973ca29b09", + "c601af58d0874673ab9d2032863fa30a", + "29ea03d0fc854638b8f4ba397bab778d", + "67ea6da8af1341cba1322027bc47feaa", + "14e196352a6c4af2ae155c4615a22c05", + "4aa03084501446a680b7114d08cdf888", + "cecc02e65997485a887b784ead9b19e5", + "19589cfd59f54a63806b00b512768fc6", + "d4af05114809411c9c2c6833c02374b9", + "86dd24f21a9b45169508891d4a48856b", + "2c31c17e27b6493bb9819363a7526d9e", + "a839b8728d734521bc1c0cbc6a6b768e", + "3224038611c94142bf382861ee816119", + "a00ce0281ed848ba95661139442b6661", + "711644519efb4bce81e75e7cfbbad08a", + "3163530e1c434fbeb23ad58db4cab882", + "5b7672a50d884fa9a570ad2a9a8d4a99", + "75818b59a80c42a289d25968fc64ca42", + "287e999f673846b38ab67ad366ef2aee", + "4616aeae6df647a5bbb36b9e534937f9", + "3260106bb8d5474f8ff56ed51515c5d4", + "d1a021a45a214dd7ba5c22a7f3cb561d", + "afdd9821de124cd0bd6003b433d4c3f2", + "6142a5564edb4a7ba1c948673460afe0", + "c76665e489844306b8b29ba46f0022ea", + "8f36a5348ed54ebf95fbd0e4611a47f7", + "a4c0eaf66bf748c5a2a1d6bb595672c7", + "684f3b1f63f74ac8b4465152f1d48d56", + "dcfe42a0c7ec4bf99f51409d0c1fdea4", + "06b6e2b916584faab430bd03c0c19499", + "f3effd0b2f6949a3b7dcabcd1eda1cd6", + "a727d5b20e0f451195de686e7b0058e7", + "d1e0313decaf4eae973f60d3186f71ba", + "aea0971e7f4c45759c7981c4f301eab3", + "bcd8340ea346483099d7fbbbe1e64544", + "eae004cbb5844f0a98f3e72acc9783a7", + "a82bff9b83be4072871d3e2afc6cec14", + "a7780e3667954bbf97bb619cb8a3e272", + "45ef4b97649b494992315925009f81ab", + "584bb20c09394fa19477ed0933895b9e", + "dfe85adb94894e48951fa24b9a9eb910", + "7aa4dd2c136a46c3a6179f780a37078e", + "629d138b40054e01b82af4541e2bc16c", + "3a50bbf9a3724cfeab7c1f9c89c0aa83", + "2f7881a0309245d9a0b2d2099dff776c", + "ccab11861ee4417d8dbd49ca5106116f", + "b3c10eca1243496abdde1e0062c1f6ad", + "6fac63bf15bb409b8d4340544bb1b9df", + "6e4bbc7894aa452bbb154b522a771f65", + "b217bb1abb8e40beae7d3d29b9e283c7", + "25d9a6bf3c72495d951f738da383c606", + "fbe5dfc571c64709896218d5eede38d5", + "be775135995c4734972317dea2c0593b", + "109d5f12e82b4bb4a081c536f39cf729", + "9ee5cc7674134b53887064a85f34f605", + "a0dc88016c2a4dd2914ceb2dac17b3a6", + "9deae426da2440668c1ee3f725434eca", + "965f145e23b243539eca393618371889", + "6b74c05999a248d996216f0d3e714bf0", + "b92464211274439b955700e3aa5c321f", + "7615cd261f4543719484c8401a9301a6", + "a6da0dff0f9b4a5a8e821c40b370a98f", + "6a93d71aeb3b404ba04038e22355ef19", + "8a3cb8d5caa0407192a578af52174202", + "5fd7910daac5432db0c03770ceea636f", + "5cb6fa3b42e24e85b9dafe6bb238fc54", + "44c451ae01c04b14bb8eeb43176c1da4", + "5c140c08635346eb99d8c4c7caeb35e1", + "ce0b00c8ad374d748929a8c418609993", + "d64bf29444564dd0bf70df1110d32931", + "4a16befac30b417fbe9f0fffce267e22", + "9d607bc6fbfa479694bb080c730cf0ed", + "f4570d48e64d41999b5646964b05bac8", + "7afcf5cb4cb3423d98ad4e040df15044", + "a02a908f2dd143d390472b8d204ecf9e", + "e3df63ad33f2444f89e8414f5f10badf", + "fd4d821a9e5f46cab786d4530133fc30", + "4816a443feb749419a17cdc172b70a0e", + "9046c67502204a579a17f1619e90696e", + "57f74d6a8e334b78af143ad7eee99921", + "b2440d84e734429680d57e557b2790d3", + "78f07f838562405fbe18e74994464943", + "1bc1166b18a34a938bf5efd6ee5bbe69", + "18f4d2cca6944b058fc41566e239c350", + "bc28743d0cc342a491ec0809d95c3e89", + "ba7dd992be614b3185d24177dde6a127", + "ac5e627d068e43c8aa8b81b07611c2c5", + "ebc21d3f3ba84dcc95c683a00b536fd0", + "8f43a990cbd14895b3bae5f43328a5a0", + "f04d12dd1e5444109f860c78679fafc0", + "d35cec82ec35416392c9d803d0979ee8", + "f39bbcd144d3442f9281e79aab127cde", + "8f9490febf2941b28a1b62d08572d884", + "e35ef4ddc03046b9b1cbf7be62766c23", + "48a602e8671a4534a3db78e715c6ab9b", + "bbe1dbc3c5fc4f9cbbcb609880f7aa6d", + "c475f9167f5d4c21a46fe19d76f6d24c", + "4dd25dda394440ba909d7018dfac5180", + "87af12bff8c04a6dbd284ad119cbaf07", + "1e5af48355a347a4a5572be89666e621", + "54fdc11e168e45e0870931f48da6bc0b", + "6c081ad43b234f9a8eb3fb8b6fc56c00", + "188af88ff0ce49729119e42a268f29af", + "46f6b1cd2d7846a7b9a26b6e4f12e38d", + "1610f417cb6d4cf493c0dcd6997f881b", + "3bdd6f3dae3f4c5f85643b2a90b5983e", + "087b5a3601b040aa96adce426f8e685d", + "f04011033fff4e95ab702b051fb641e3", + "4a5ca7cdb8ee43a590b9a2befe8ad8f2", + "fc92ad2532a646ee8e70ae466415a9e5", + "aec3dc73450847b2b4ea8cec90f7fe8b", + "b29af0089ec64705992db7d052dd25ca", + "2c4cc834436e405a9159000c54e3e82d", + "4623d3de0732435dba83a4f962a87f04", + "0002064ef02e46f9a10b4bff10bae805", + "0ac651eb518a4bc69873b117cc7e3dd2", + "dee110d229e54d59a9e084173b18fd26", + "9b567716507942519b5ede5ab5dba6dd", + "0bfaf9026c7449af90ca88d9e671c403", + "2002554fca3f4f0293af0aef48dc6124", + "ef3169dcf91a4d2b957ff4718d27e4e1", + "13c190d8bd9340759c7c4480feb84c25", + "f1b4215ff6234c8a938018158713bc3e", + "6cba3eb138c44a81b1ef1db7110b1c67", + "67a772498c40455cb4a68befc71df6b0", + "607bca1f9bb2447eaa67143515b73ca7", + "f701868432d4484cbc209620e044e5d3", + "b0b3cfc84d794031b27b17f90d19c025", + "93cf008ee9a040cc98ac303a600fd74c", + "9e08891f3fc849ad9180c9385ec5fa6b", + "c45bf6b96a6249289ae388765881ea7d", + "330fbffa5e824adab2e609a2bd2aa3f8", + "39c63779483c4fa38bb384f644b9cc8c", + "acee9d1ddac2425d8272555cfce2c61b", + "42cd12a7c1a24f639679fa5cd5491f76", + "2767b0e2f63d497fb946d1558891ba64", + "1b2eed690ce84d26b868ca8e22acf267", + "bb2e9011ff02422ba769fae50c5c7f40", + "e9a3185d4e574e99a747d68477c7b65b", + "cb054408c8f648a9a3601d021a17c655", + "1ce34947a40e4f8f8c2baa7bb6ff6633", + "3b3e36070dbc49059348a8d8f7e61d2a", + "8e23b92742784ad0ac67d3906883a71d", + "e7261dfa68b2426d907cc6c64ca0f4d5", + "a70b2d1f31a743828c8ec3ca000aa029", + "a0f21a9806bd4387becfb4fe3c8dcf50", + "76f7abaa49014cc8a9e2aab39cabf628", + "907a4dcea6b04b4c920936860c308323", + "4a4797da80254abc9ec61bfa6b496651", + "804413e30a314fd0b0d9a307f237c7bb", + "3f302c3a3aee4c78ad9a9827304f8d35", + "e9e3875224864854b69c14c6efb0a4a4", + "280ea8a81d604c4099b84525b646ffc7", + "8277e0c967a6411082b4d15ada73cea8", + "4f222c59dce2485ab7836753fdf6e6c8", + "32c6df0a60314d089ff2469a4eb5ad2d", + "be088d1e73784d1fa07cd92a40af8dcf", + "cc102cd9cb8944baa96bd78d3d8104c0", + "5968c31b92614587a1af89a39ce539e1", + "d3dcf36e0d6340078c82b61a20b596d0", + "cf05070f346a45889fe01210854aec09", + "9193046520a84c3bb1ffdf6083d2b18a", + "32f5781f0b7e491b99ffd04e77a877bf", + "8e194394fb864e2da73913b89e240a71", + "97b89d7cc77d4883bcea9d4736a8f00e", + "1d5db6e1f7724c65a1fa704452c203a1", + "ea50c83418b2428fbfcb26282f0f277a", + "593098a9230d4438a40688957784237d", + "6bc2f0cfcfb043d8b4465368ece05b67", + "e328d1e4fd5b4f23a0dc04c9b5c7110d", + "20359d2c63bb4aae9a71bbb6511df407", + "020a2199c72a4f8eaea8f1212271a1b0", + "adbbe7953c1b4f678e1ee2f1033fcff1", + "b736e7b7c669452d9f3df53a9f54e55f", + "d459f6fe92b54842b7faac076f756cd1", + "fe461f4242724c5f8807a45717e41df8", + "90fcac796045401cbf96cc089e41b009", + "6f7ce57ba5f94444b23ae4fb7b8cc209", + "4990a971585a456aaf1a46bbfd2c9aa3", + "7bddff065f5645ffaceba58606439a42", + "cb6235ce0d844f948de11a62db298697", + "6d19454feff8409ea697102783c17bc8", + "330782d406964b9783d99b46b656d4fb", + "baa749f0b81f42299c61f5ddb049f793", + "9ad6bc278e224ff8b652a7a2be644019", + "fd1618d824504cfb86e24f263956f76e", + "1e9cf376e032420997ae15fc47eb54a4", + "a6eeeb8dc3ff48ef98c8e0a8101eb6a4", + "b0fcbdbaff9f427593910ec5f7809cb4", + "e881baf02b2149d2b7a68d886788316e", + "7dabe5cbcbc94cbdb93a6afa83d9410e", + "b596b7a786174689bea1514809c37ce5", + "a13b804df8a948aaa083695825b5561f", + "8a3f1ff2c1c14f74915222454eba92b9", + "973774edc7aa40649871f026aa590e9f", + "0382fbd2da974f6d86b465dbf5acb125", + "d65e1b9bbff9463ba5ac2ba1cc48beef", + "2d62085f95e64665bf8eb1e623f1f0f3", + "b09a49034a4b4f5991793a270793474e", + "5b8eeaf52ebf409bbf7b19f7e3b89037", + "528fff68f99748febb1c9b2f1879e2a8", + "dd7183e276b3406c930e18e79a7b8c6c", + "70f547f5fdf947b896f1a5a950bf552a", + "ec31245b85b14e43b9b0c8846e0e861d", + "71b5d87275584524aa112f25c7227918", + "0bc57dea0074432eb6c9e1459f456b0f", + "b549e94cddf74e56a8177c799e45e633", + "6681ee683fda4039b08f2ad6e299bc5d", + "3eac971c2d8f43b2810b584af3f06dbf", + "4f0dc7efa8344611a3b72fc95060e2bd", + "85d7e91f9ff7481fab88daf098c1194f", + "b31e7c34e52946a98bf21de1fcb86ec0", + "c0ede770317e47c1b6766752c45496d1", + "86db39b403424e44b9a76b43e60131bc", + "e9ad16e9809c4066aa26c143e09ac1c4", + "1ee2629fbe3748de8df58324c954a743", + "620052dd9fa9454f9a54d55f7c3023c1", + "f5d57677c6404af1bb43276c97c9e37c", + "01d9dd3aa5dc46c3a44bfd40d5898c0e", + "bffff45d3fda434aaba30eb0d5485d73", + "9f22d859b45f4727b1c253cb61de7a42", + "1642e2e9a91d4f7f9495607208ff1ea8", + "0e5e7c985b3944f5b84140990ec8189e", + "c4dacdd173914c648a64b205479a6822", + "e50c186613c94c1c8778e246b178eb2f", + "f635d6cd833d4a1092889ea60cd547ed", + "b691798eb62c4af7b509a4935698dcf1", + "2f90e282d95842daaab99fe02144001b", + "52ecfc53e47541dabf49cac11b6e04bc", + "e2af87d30bce4ee08611c20bbab345e1", + "4b213aac56bb4484b57cdedfa4c146fc", + "efd82d8cc4f54c6e82e3d21825c19dbd", + "594556459b204019996e1e2c2b0a97d8", + "bb97d31f66274e4497bcaae710f82715", + "8c2721e6b4274665a08c570e4a4352da", + "8f2f0b7be0184c47842a360876f2f578", + "3883d608c14448499231df167a59e67d", + "023233c2dea547c7b84c05ebe437d64a", + "caf6d29f508a4691b56601c5dab9dcd8", + "63483e9144504d20b0edb7aec86bc937", + "580ba3b412a24ee29c62a9ccf6bdc80c", + "02cc6c3b10d14048b06a518bb6870c40", + "3875f2b773ce49ffaa936184b85b7f33", + "d15b3e6d7ca548c3b3705d29db16a412", + "3e58170eb8964fe2b797c838c4f2dcca", + "20624325fcca44e18dc0a96e63bfebac", + "f8f5e6b1fe554edb894bf39647bebb67", + "ad2d84efd79944e8b77cf6e169fc59c6", + "1213cb19a69d40108f84809febf2ac9b", + "0d865d89962140509f8b991be0fc3ef0", + "cb52296694db4a08936b193c5a09f0ee", + "5e43a92d7f674eaa81b542e735717018", + "bb4559e5a6cc43d58efed1e4b651f4f2", + "3b4d8e3ac5eb40d8befcdb6e5874237a", + "2833d5f978ee415bb2ac663a5efa946d", + "db96249afc944cd7ac860533c50d27b2", + "8f8ebd43fbd6423eb4e1042a7d53b91e", + "09a5d01a58164acd8c9335ed0e6295c9", + "ab624f26fc36400c80fd6b0b1c48e20b", + "8e30f525aa61481f8ec4ca22a3a5cc83", + "864b8ce5d520478481198d1face5a7e5", + "41589a39a0234cec8fc171e734d8359d", + "87dfa336e9b546398d96cb5920a2709b", + "7374193137af460e8161f15a9cd0a806", + "35a33e5da56c44b68c7a937281697517", + "01f400d6d38f4b4e8632c2ee496837ae", + "4f7231725bcd4605ad280fb513673a14", + "93da6ffee73d46ae9bd1aaeb93e185af", + "64ed1d20cb7d4cf2b36a00c26b61c2d1", + "373972947ad4474882bf65cafbeec21a", + "f6466a534681413485b361121deb01fd", + "ca46149feec7481289f4a3829c8a536d", + "db5d813fb2f841ee8e0d1bcb2a5f58ee", + "cf860a30743f4fc7a849732488a9005f", + "42fe768d71e04bf38e1848d70942e194", + "6272a7b6114a4f50ac6f450e6dc86e53", + "aa618f9ac59d454987bc326d9e3ef88f", + "1dc3cdad6b8c48e2b3c8e3ee5b767f68", + "31d548329aa149ffaab1a41169f87f74", + "1557ff8470954428be2944cd54b9a27c", + "de95f8b961c443d7849ec536b39d1b12", + "b0d8f34da95848a1950587d9b65e4136", + "59f53909155a4b38bbb70c70a22a2a9b", + "0e768df9f0b34fd7aa742fe675427e23", + "fa1892cc99d14b5d862895e2484fa527", + "91783b6495e5482d873db34550cf643c", + "cfb8a44488df4f27b0e4742a463450cd", + "85f6f00a63b94713b4be4ebee654b430", + "f61f0e0bba004228afd31d3ed3f71818", + "0bb615b99122441ab399e769f29a20cd", + "cba3e4df7c354d22b7913d45a28a8159", + "bccde59e7ca04b1a8c932d0ba18009a6", + "5afe0c451b5c4edfb0c7ef72e8d39045", + "47abdefdcdfe479a91e0cae48e70f8d0", + "c1e84a838f644940ae5b40e19bcdfff8", + "c6addc44e4eb43aaaa97cfa761b68954", + "92f9aa47f68f4a6c9281e0c88034ece2", + "49a6fe4995224d4e8e5ee1e23727e51d", + "063ceb75b220463fa2dde8df4154ba2e", + "e7059a39d799423283ec6774366225cb", + "e8f001c6463d449481252993c6414731", + "67981a3bcd6c4dfca90f6d1a55104d44", + "bee57b826c9047129b37e6a1fcced99e", + "5f7e0d429a9d41e0b6c60ec56715f959", + "c43146abb4804be794b78ec0aa4dd1b8", + "a58aabdd62854c778e2e6e779ce16124", + "5eddf36af49d478daa7ffd382b6247bf", + "597930b965f048919d70f9b9507c8ecf", + "ac3b7ab28bae4782841457e6ea6f957c", + "2db0a9e1d2ec4a15bf33ef9a11b12168", + "badd03bfce2b413f9b2adac9dd12e4ad", + "412c39e221f24112b99890cd0ce52023", + "e6caf7b73bc84fbc9f37e501a6935afc", + "d0b0983535f447ce95ce9d6a5fc84311", + "fc6c642593cc4bc6b4fe8db81995860e", + "2d90d0cea371423da4452870421aff5c", + "78aba4176b184cf2b1ca176502a35137", + "e81437f7bc974774800cb6470571b199", + "8b34d4b347154db5adad199575cb8fec", + "e38b0fd0db924e948160d611ce5cd93c", + "58d2fb70892a437fad6643c2dbb95749", + "ef1baf9a4c1c445ca874514b7744662d", + "6bc294bcf5ce4980827e036dc597c4ac", + "4439ce3762d744f49f0f45c76145ece0", + "4815c81c8ff14124b6d1cd39d02cd4f2", + "c408586d8c1547448c4ff47abb4fb981", + "fe22151f125b4293a9ed44f62a056c79", + "1646dced57074decb0afbb4c6ee9a721", + "8dafead095f243d8b197085b3c5a1bd2", + "0711d588d9d849bc82cab582dd96959b", + "9abc650d6e644236b998ddc3c090984b", + "9d71488123cf48d69fd26ff9c9615225", + "f1a1c38cb35c4266be0efb43f1411260", + "325c36e2e1bd4893bc412642a81afd1f", + "09db4eafd42f42ef9742d2335df83cad", + "4ad299bbeec344d89575050cc2ee725c", + "140728cbfa3a42c19d2402aabc88ff26", + "6e3b47e02fef407ea740c5956b7289b3", + "6b8b89bf1a844920b104f39ab5c2eefc", + "79ab6bfdaf02436397febdbf1c19a3c3", + "b561a183b1dc49359d43aaeeb305dce5", + "3ed3811ef99f4879974f0549915226d0", + "3791ba4746354cb2a854c6a54b8f677c", + "f60e5b1a2a0149ceafba863c25ba74d8", + "36e543c32fb44556843f02dac2fef55b", + "cd4731fc9ab742dfadb0d15178f9d75a", + "58bef950f0e14df28ec121c127bc5aad", + "78b1016e1a38434b8f4d5741b1f0720c", + "c1222de31eb6474abbdb6b636f8225a4", + "e91248be6a9e40fb8049c414f71cf68c", + "3c3de52be5e9491eb7613ad9c0acab54", + "28006272fe514cb68e3a0ac2125734aa", + "7ea5c29e97a14f329b0a541d92b3d184", + "ccbc43e6f4b24b5e94866f6acabb296d", + "4bb75b0b0c084a46878aaa20e9613e99", + "3a55aabcc7b1437b888c3887c8dffb13", + "a903bce6644a4b4692043b3ee1ddbb2b", + "295384601e0d4f1985a919253330d59d", + "7ca7ebcfad964498b49af73be442acf9", + "d0007d3494154dcc9f5e3b9e4f602673", + "a44d022040af4e609fef3fe1bd4ff462", + "7ee37c1cd1bf4fe78364d4a39136577d", + "60b52dd19079404386acac0c3bc33d7c", + "4526b1cbaf8244539c190be6ace277ab", + "27791e4b610845a1b91ee8b524d7a73f", + "18234b9b760f4833b68ba0fd6ca988c3", + "caa5374fe52a4e58bded914571311528", + "2fd452ea6803428d9fa1dfae6c53149d", + "689a7a3d712f4085bd2320512172226f", + "4aeba6175a754fc1bdd46e9141cef965", + "3cfde705683940579456cbd0abce811a", + "dd01059fca3447afa4726a997631739e", + "14fa34e16090452f88098c29e1ceca32", + "f2f17076947249918f5c2f75b372db92", + "f45802cfe890462ab5e11fbdeab646ee", + "70ef097e7a684ee89b6703634c1c266c", + "4ace4fbc91124683976db7e9530f98ae", + "dc707f81a94e48078069c6a463f59fcf", + "dc4c0568f44b4476a104e9778f3c3619", + "29a39d0b20cf4b6cbec4e0766e0e76f7", + "7245acbcd9404a10ae0e595705805d02", + "319376f14ac644759cc5f8fae239d6be", + "870f6ebb115a440da5b8fed8072d7d9e", + "494502aaf47d46ad907f17426712c815", + "9590563aa19f458a9f3a931fb0da09af", + "60affdd43efc4b31a88d3cc07acb8823", + "bd8de3ce9ff8408780bab8f2358dcd1b", + "8c3604465acd4bf096d22e3398b17073", + "29e61a713bd3413c8fc74c8453a1ada1", + "6e509bb275c44dc994d1e6bc694242f5", + "7cbebb45df7e49b6b9345a33de8df2e2", + "a2e8b19cf74948dd9b68cbcc413ca884", + "8fcd03712c3e410d9a1fb300d41fcdec", + "e419e37818a5446a8f05f4d21cbce7d5", + "5ee3339729b14c61bf1df973e51f96d9", + "1b96c00ba9d0407b8b6ee819c66079ed", + "598dffa75ef2443b9922195579e00051", + "2ea5626c87554af783a6a4bc1470be1d", + "9c5db8afcd094c87abcc543bba3b8242", + "769627476f704ac89e6e0ca87ebe04b1", + "43f6ede08b0c4f7f91cd634f3aa2af42", + "4f917e51a466483287530c297dee73ec", + "4e8adebf6a7440b3a9d64a21779d6af9", + "cf1fd797bc2b47e881800ce02f3d35f6", + "72ea4106ab1f4db297317650904c3628", + "fb70d2c633d6405190fcd6a0a9733b6f", + "491a12adf44d4cd283d32743d21ea683", + "6bd691bd406c4aa8b99938e9a429181d", + "699f5e64c98d491d977ca531c95e2844", + "1240671fe7444d48a1a8f1284baf8495", + "588c197060cd4bf7b41d5191c7aead3c", + "7681ce5abf894b968637585b616e665e", + "5436ef3fcb5b4621954136da5f1ee8cb", + "d2704f4bc12341ac85d717c9ad7d4689", + "2da380cb5c874c20a3f6a393a22057aa", + "fb0a0e9e62674beb8a48d8a1744419de", + "f4fee954475a46a5bfa98cf3f4f0d0d9", + "5ee8e1decdf141d998bcf7f9e474bff0", + "4d8c7b73dac44c51bd5421282d3b5860", + "c6d45f40b0cb4717b30f03ef14fdbeba", + "d08991777af64ce08d631b2d30fedcd0", + "b0d81f1adb544db2b20179f7af243ecf", + "b0171c4abf5b4d9dbdecc4a7dafe60da", + "9980d83eca5043fa923d12ec7fd6f866", + "5bd00d57971b48f5b154c6429d766347", + "bf47519956874c1e93155f7e0ccf3f4d", + "0da140cc02f548bab6bb35b949bd7210", + "0979139810bf44068470637ed33457f7", + "77be541856b64754b90fed35c33862a0", + "e5e87ddbf3f6470384bef58431351e2a", + "9d8f4acfe1834a2ebdfc4df0fc7df979", + "bab4f1912c9f457491c251764571b557", + "2c8465ce22f8446eac94a7d71d4a5137", + "e1dcd19f297c4350b5acc355ae4a4e6b", + "6fe8dd0143b44b7488c2055838729acd", + "18f33c2f40824d80bfa67e13eedbc1d7", + "68b91d6bdebe4558807dfb052d9f41c9", + "e2b37d4e86194374b177794bc9aea712", + "4d4969c198814b54a7691e9fb1c36aed", + "c99f906a5648445b96f890fead36643d", + "0051724d6efa42de84aaf8467629160f", + "62ad466c4c944d6389b7e7ddc9c9b4da", + "13289bcc70ee4bd8a2f573b642aa1133", + "39e36b4746ec49ad9e47a50480bcfd0c", + "de117a96fe844cf3b0fc3534eea1dadd", + "a9d0452fb03047238283b895777e2e97", + "9dd44cda400c48a083ffd9480067f04f", + "af0a2767517f443a98cd98ba4476fcf4", + "32760dd5ef044579938634e68eede737", + "a6cf4b8f85274a929b3e63f260492391", + "e8c036fa0fa64a17970fea4da1994969", + "0eb49f0b8732427a9f259040cef20366", + "080f0605746b4cfeaeea737eab8a6be2", + "41415a2e3054491baa46da5d7a859dfc", + "098db6acfad0452285ce77781932fd24", + "3aae0c7c77c24b4b99c63f05be02d808", + "dac833fdcf8d4c53946a3dad575d2c3d", + "6675169f44d8483da7e6232d0e63d43b", + "c556ae0c92224a32873cf5817620d730", + "66920a4ddc5f4090bc846ea46182b7db", + "6c646741333441dd8d06d823e90fe9c8", + "40f4ff4297cb4ff9a5e3b6149d520bca", + "933fa8d9832148e7967e244e455e1377", + "8a21e84b6782413cb47e031f68dfba9e", + "363b63967982455e9ad749851bee1d7a", + "a5986b39102f47c5b32b212365dd7276", + "cff2d3483c4a452aaa9201b2a1b7d984", + "4a673a28b08b461083c9a0270fc6e369", + "af11cb95cb5f4e72b08327e8424cc074", + "99a83e49b53c477ca4a91edd600e0016", + "da1301f7148f421698d6b9dc1858d45b", + "40be5a4ca73042deaa9bedfd98c44665", + "f2759f6bb0174cc3a94448d5a3dc5038", + "5363ee82fcd64424962324f9265fbdff", + "ad1ef89672ba41dca171b5b36e6a15ce", + "cb3646a27fc143ceae1473242ddae0c4", + "7a295697360645fdb1dab4947fa10ae6", + "c8d638eafc99422ba3a32987ac9c7b86", + "033df547df9c4910a71c12201330a202", + "233291c023b24d208453373334642ad3", + "8269198bb7274482a3e077f4f90ae460", + "409a6a6a92c448ca82cdc29fbf32730c", + "3a1136e0f8c94763814f748421906fd2", + "effc348522c84ea883b44b4b06e6ee84", + "c9bfaedb7cd74bba8c47dba1e11fa299", + "525ec03b09e54204a301238b062ee6d9", + "f164f8d53250415d9e57d92fd1191e5d", + "4dc97f742af14811854e4b14a5677e69", + "b8286ef1272f410785a01d00ce765ed1", + "8921360ad76148868907f9ad083899e4", + "540c7ce584814112bae1be4a2355328c", + "496667e838c2488f9606fe956e778d06", + "3e7747b1db4b44a4952d6d94488ee16e", + "622202ab925f4cbaab8269237e2a3480", + "4203f757f56c4d488388fc492e63acdf", + "8164d1322d7e4e9d857d71c79a90db17", + "538ae13a999845fa9206c6e884747df5", + "72aad2af1dac4d4d8ffc57ed37eead9a", + "f8f5a766be9f4cacae1d6754044fe422", + "d90331faf5ef40f68c25a9d4cbdbb9f6", + "ffa191ffe355485487b6231970c81ace", + "f5b3512c8afa4f24be830471f6f4e4c5", + "6327750707144dc9a19676cb78730d68", + "ba8e50398b4a439981e8c0adca993008", + "f1ccffa259d942a9bfcd1b3ce9236188", + "85812bc38c3d410f9d75339df78f8051", + "2493ab01f58f44f3bc5feb25b8f12418", + "a9246d0466984033957c03b2e6b4c266", + "5a6977aed137461daa3b70e316ce672d", + "bf84554ecf6842c7ad96a5c2ae8687d5", + "805f2a9e50f84c52ad68c379e4366429", + "c7118b7e9bdd4080930bab075ebbeb4f", + "f015375273454101a6a0cbd7e5a33c76", + "8f4e644572914d97b0ccf4d05da488a3", + "93be3863184d49b8b8b14184ed8595fb", + "5cffe65dde3a4e03a28449362ed0c657", + "8edc21dbd4e4458a953c4dcba53437e2", + "25461fb372fe4ed0887fca7a1de20f01", + "c9f3a5192df1405090dec2e3f325344f", + "0eeef145c31b4b65bccc12e000c5673f", + "8c95c5e879f24f8294d9c8c25804ab95", + "fca1a178324244ef9df1ab0cb54da4b5", + "55305f6a763d47b6b8c6a5896eed98c7", + "171ea8d8a0f149ea885a24349367554e", + "0061cdbbceef476a98025f10e19f5d13", + "38c5b18bb54e490fb9c7146410ed61a5", + "e654cb6e6e2c4217a7decb6bb9c0010d", + "40058e3fe3dd47de8f73efce14a128d9", + "21f1ac18511e4ec0bfc012a6c210f89f", + "3bf8be544fa348a69e3dcfdd4c6e51ad", + "c7088245fe4e49a6b3a3bbe01c479b2d", + "ebd73da0dd6f45e49a3c93212e5daf45", + "91c1af07cfc542f29a2c54c75cc9fa32", + "accf346b6f4845d8b9e856631168f012", + "202781e5ceea47b3af8096742a9297c2", + "cca6db19216344919b427d0e3b2107a8", + "5da32137611346eebf4125ce518a76fd", + "cd5b9f6a5c244bf784036d5067291bf7", + "532c0f79872f4680a3df7457a43b0319", + "8c4922fbc8aa44dcba4dc304b16fff80", + "38e53299cce04fe19235b8b198f7818b", + "e0d4745c293b4f63ab1966dd23240941", + "f30b97d8ad5843b1929d42c82c6b54f9", + "90f00bd20ed44437a03acb0a129e81a0", + "3df896b20b69448686a6e5949f37d79e", + "82df6dfc3ab54b85ac0209baeac9c018", + "f25191a3ed854903834e6be2b8a94062", + "8eec38e887ed42c58dd659dc1343ac8d", + "17bc64af683149b981398591b8f2504e", + "a077fd75db084974b273675dd6c5db69", + "f9d4c719cb474a8f938d13116e498c94", + "5dc6e33e6ff64ede997c37f83281f2ce", + "b44e1289a02d4daa947271b83b49ed08", + "9ff46ec6daa0427cba8809b3f815df7f", + "c2d87dbdbdc644e89a96da153af4284f", + "b9d0f0fc25004ac58d3a58ebd7eef002", + "25741169923147daabd091356e5ec078", + "457427b7fb284c3abcbfce351d61a986", + "3337c63374e64d969ef2e3adaf81e033", + "aa5a3cf340b543be985efe91554c3584", + "a2d43d4cd69b48f0aa57567a11a9ef05", + "c8defa17aaca439cbca34114bde12d58", + "e650d7ac4c61485c9f3f37ca784afa49", + "df5a99d6427844419d4dc86dfc036f05", + "8c2deac5610e4b7481abfaf9aa907685", + "f9b76fa52a82427ea97a51b0775be4d5", + "91506a2864184c2fac3b2035733804ed", + "2ee2bc87756d4bf0932d83ab860ddb8f", + "3e04061413834c91819609b1fd6e2603", + "2800741740204267be10aca81521505a", + "f6f3eee2d418463bbab1abe93e274d60", + "41a0813f4ed04559a532a3956c5ae64c", + "c01c1f205b2f40d5a58cd3ff38a634bc", + "de5ab81a25ec470980f3c82e3d88188f", + "d9e8071c0e07458db3a8d02a87c53536", + "299106dc13884f76bacd09bcf37912bf", + "2acda1eeb71a4608ad76f57b5077d961", + "f6afc2c1fd9e4a47a023226f1aa151b2", + "bb920dd7ef50497a8b6330ea82e02e18", + "2b3e6f8e37344325b98a6165030f3340", + "d4026f4bbc384c5f9307d9b066a21d93", + "fd79111255bd4cc8a2ceeacf6ef1ed70", + "bf1aedc5afe54448a8b9215fb8a989e5", + "ce6383d8fb27451eb8c39a7193194307", + "a605905280c54e90ae8876b50f93f2d1", + "fef7c1969ee2420ea0e1481c3b4e6ec0", + "513b3435fbe34a0f82440c9c51ef86db", + "675f9a2ea9a84d2f85600835fb4abc6b", + "6e865e4cd26f4acbb80df1d46197738a", + "3ad84fa9d8714fe8a311139fb409d3a0", + "e2c5ef43106a476295458506169b55f5", + "5063e5ccff8949918f221202df3a3977", + "519e5107737748d9941953ae407c7de4", + "cb917aa0cf024ef3a8022385c05ee1af", + "862a2bfb08644ba79453bd86ed9874bb", + "44b6b58dd67b4f379c1484fa7fe46d99", + "9eeebcf9bead483d8fdf200a068c7013", + "a673a55088d047419b468df78700f8a1", + "bc096d0ad5c64ac1a48647200fd559c2", + "d184083b0de442f2b6db2e5201dcae10", + "01ff88bfc0034211b9f4996d620bc333", + "e60b0a1485584e24b63444124e7d8441", + "55bb0b05a9f04ee4a4f27a0ab990a71d", + "61d5ad6897954f2484b9ca8dc5998096", + "356baab40aeb4815878f375262cdd705", + "985a8ea1da334e3c9cb3545ef2364310", + "615c41572a98410d8a8b15a9f9bc4854", + "db9ab7d6bf2d4e508b825cc640d60fd9", + "210b4d5f9c714823bfa3ac5a4c23c039", + "5a9d562371aa4a9289ff15a0bb45ec03", + "0c94ab9eda8d43079f3bfb773cf10bda", + "c45228f2b22e4338a4094a16ab4a0389", + "d64f9a1aa0d24e34903f3ded7272b238", + "04383a7164f643e8b1a5378fa7398010", + "7e684a7c012c4fd0ac91844f22457640", + "5820e6a5ded7483abc5f7eddfb2da500", + "936d3487c10747fca7f7040ae76675ac", + "f50ece93d4684d77ad930d11c8e17f60", + "baec476b08af4a539389652fce06a084", + "304bcb95e181499d93e1fd75551f59f3", + "c2fbfde544a748fcab612ec50da4f6c1", + "05068915ce654951910e905e24e35d38", + "c78d3320c66a4a71bceb1d67e56470ea", + "02982073a4b74092b74cd87dffd06989", + "29d45cf5c404465e839c730393f9732a", + "ac6e1946611e49419940903b14c9b5e0", + "3ae84f0159b44f1da97efb8c57002c38", + "2e3ca82646d94dd5ba11428ac613706b", + "d3aaffde4b3f4af2842a5def1effaf0e", + "5c78985af2cd4cd590735e1609333ac5", + "63cbe44a46784449907d71c4b6953682", + "6b98ff028e984cbe821d8c6e58fb632b", + "9dfcf8339e0246889d6310ea5016a1f8", + "cfe227abfa0e4f1d836a615cbb075b97", + "26f2fca2d59247eabd38e3b78544646a", + "eb3f2354354a4e67a709bf2cab522049", + "843f701dad294aafba28bdb4cfdac31e", + "b81e99e6f7ba4e3ea3f4b318bd2b63a3", + "a420e9196b744919806ae532b3a11bf7", + "392abab3e48f444a80f79853dc50a163", + "002122c2db5a48b383598fec645cb459", + "9373999f13b64f14a15d8df1f014b562", + "f5a8be337bec4e6081242adcbc272437", + "29e245bc655942878879b93e658440e7", + "90773f553a7a4c32a4014e4b6e6e730c", + "16117c6784a74df2970bf5a4403afbd5", + "96da98a3b45d4fbb9423cf1386047526", + "57b87344eec2465cb0c3851ca4a38e90", + "5257f5522875473982e618ba7cfc5825", + "a35a466eace5463d937cf55ff264019f", + "e4d38d34acf245a9a30fa7c87ca81550", + "7da49ec6a0cb43029512338697c0d2fb", + "2d32e17cd4b44564aad129416e26d641", + "454285365cd44de1961acdf7cb6f3fe5", + "9cd840dafdc24fd6a800fe33cc3d4488", + "589a1058cb424781b4970a469bf4f538", + "26bc6008cb714215b2b5e77be75f49a6", + "7e0099fb40f147f28b6e60cb6bd49bb0", + "0830b75a1d164f459851573d37616e7f", + "088d0f8d8a3a4b1896bf7b0e8f4f4387", + "4b95709febaf4f208e1ce6824c5fd11f", + "fb03d133dd4142f2908a8cfc504dac59", + "1bded44250fd4a9bbc9809f0235bccb0", + "ebbcf3788f3743acab85e59c6d87b492", + "872255a79dd5436b858a08d36e1d1212", + "05f6e7861e8e4e7d86ad0ca67d9673c0", + "5a84bd98db5241cdbc7d2e984dfbe1ac", + "28a29720f5a041e5aa39a7e3b792f2f9", + "c10266c3ff8c4fa18332f03ed5d0b3e6", + "a21bd4eed2c642eaa7e702269f47b002", + "915fffa0a7d943d0980c835784340c77", + "678d46d290c7445288ef148dbec7cd81", + "a7e73eafa8774707b122031a6b60b306", + "1005ab42e83c413283e4dad32e55b1e4", + "aeca1b43758341ee9b0f4912cfc45cf5", + "c3e45d7d11cd4f7a907b9d28191a824d", + "9b0f5ceb4e6d44adadd185932836171a", + "44b89d43e3164b4581945ce837e60b76", + "c0e2bf89baea4383a0caf77e330c83bc", + "4c504e72808d46dbbaf2d02819ff90df", + "b040981edec74b0aa28f02c78b5f0e94", + "ac9399e754b64252b9293f15eea6f57f", + "7259db886098456abddc584fd826c204", + "bba869da739c4cbbb24e992c27b74e42", + "d02ba46d170143e58ec7f9e4c7edb09c", + "ab6e3c0001b148fdb49fc15ba08be149", + "40a1422594ed429a8678c7cbc27ce371", + "d56d8fc8bd10498888b4f22dad723344", + "ecefe6c7fce341efafb7cfa75c45c773", + "833f8317cddb435d9cbaf616649a5288", + "f19dd4720e8a4945900c92315fc28c65", + "b45aa763241b41858c9648368e9f4763", + "a1d2ef559c774fca910084b1136535a8", + "6a60f8f5170545d0a9c375dbd0140054", + "216521e7745b4775aa3e4a8380a1655b", + "947e0e814aaf4db09f007d68fd9b47e6", + "74e3ce0b70284201b17cc588c34998cb", + "8958d5065ce94a54b12d03568a0b45e7", + "02103f13c96b4caba35038e3df05a4ac", + "7e47040f75b544a2897770d5812a921c", + "fa9f51beb7634443be3fce568b66af73", + "643c1f4119ac44d7884f4d873cb7c3f2", + "6a4765c336cd425aa33cc2d5fc2ef29c", + "98b39c575de547a483f8fbaec2c0242f", + "bdd36c94f3f74f22b02b8a069c8d97b7", + "1a200b4c8d624f389b232d2cf7b6aefe", + "16f4d61504f647b4949e7e697b83090d", + "445869b3117349adaed1639cf201cb65", + "43d928caa6684b6d9b03658b4039a83a", + "701c112d7ce54788b2d95b2f406f6df7", + "391b232e8a5a463386f7742a16beb806", + "497ccb9d4b8d48ef9f6e75167c1dea49", + "8a41e4de506a4bd896c2a55229ba39e0", + "a88f3cab04b54c17bab42ef35f44372c", + "8ce9404534674d419f9d47bb096a1fbc", + "73bda35b6e7a499a80427fc1b049b192", + "73ca4d739ac74b558d837e13d2fe7410", + "c32c12343e3940d2ad99f702597bcc73", + "f0da8751cb0f436ea106a2088a5179e7", + "071be99aeb3044efa1d098f9c92a3449", + "5b098581cb7040d8ba30955ddf2e04c8", + "e38f11c29fd946eaa7460d7f43cf5313", + "e5f6fdcd6c1f4d12ad081a3d42dc243d", + "3535f5f33cd64bc19a67ebff580c782f", + "70e05053c8a345cb8fff91fcb9013942", + "e68820e2d14a46a08e23070e28c84b7b", + "8c0d13b70a3a4aeea0b60e2660104684", + "dca8d8736d5a4e38990960679e27a53b", + "1c77a05af556408dbfa04ad1999a8a32", + "73479897896947e19a0d21b61534ac4d", + "7136be03e2b647108d9802ca8f43b17f", + "5e7bc08049614731a8e6741c7007a121", + "a8cb6abfb49841ed97f8480a36c26b3b", + "05d140a49daf40fabd9f679df06ac1d3", + "ec5534eb7179436599d753c8658fad09", + "85355ce4a4824754bacf1241817a544d", + "05061c81afdb4308a051ba57798109bd", + "22e8163cf6e1413486faeb4e42222a99", + "9ad93c7544ae4f6fb242092d1ec7a5aa", + "6aa2ec8f845b45fb9bea7709800fc30e", + "c4a455b25c7d4883878d0be82f602752", + "bd953967b7044cdf92315626806108c6", + "15d1c83edab548a6b8d8b2b8be0c67e5", + "8aeacdcd0de84070b2ea64296ddba474", + "533e70ea184f432d8b3b5e4663a38689", + "51a12aa048754aeb99f9ecdea2db2006", + "a6f26aef519b4ff09e7ff922400c57b9", + "f759fa4b1bc0471db87f4a280daff759", + "db00442ac2f845519a95da2374f17352", + "ac029344ea9c41f8900b50e9a628444d", + "d8bc73eb1ead46fb8594b8caf926bda7", + "43327a074274479ab5e908f7ab610e6f", + "501bfd01f7924647a56334c4ae922fbb", + "47765d466d4743ee995dab0f21122114", + "f2dd0ea334df4eac831ca2c457853210", + "f287f538ea4c43f2a606377433645531", + "ef020a491f8d4cebb2ba7d0c18e5cdb3", + "a144d6cffd0d427eaa3e534f503f5d72", + "bcdd96f72c9e4034a6fe2a5121e93a87", + "2fc1abf210b348469d65914c62da19a7", + "04237685d8384bc9b1150ffa5a150cc5", + "ac0eaf563bd2405e93a152554211294e", + "6b154a39a0e64ba4b67926b32c8cba86", + "051152bb1331491eb5794b886b6e5f96", + "797e65bb72514344a294b2adce21aedc", + "368309e05a2d48cab82b00ae5a1d773c", + "476e1f16bdc84af7abef89659c465b7a", + "3a87a55210db4fd9a27565671824f894", + "4c288e19f6114f708f758d995fedf80c", + "6106573a3d8a41e8b50c4e189512a69f", + "e38bc70eb5bb44d8b293397e2f9578dd", + "2c2b2d988c7f43708de7eacf110f4a9d", + "43268bdfb12542d6a4ca7539a2ee054d", + "9019e3c6f5b14b0c8c1b2b8ba9d71987", + "69876d51e2f0462498b81dffe3387ae0", + "adc1d94528894ddbbac31f32d5323b44", + "9f1520a479b34af7bc2c2fbcc2f362f5", + "d949b5c56a28477da220d1df1071857c", + "02173070841943df89ec2015050f6c44", + "516c67bde08140dd8f26404047fdc5cf", + "4421fd833cfc45a58f91615d271489dd", + "9d9fcf74d8d044178389e5a51ded2bb6", + "2555964485304a7b88c9451401e768ee", + "0bd6b4a2d25c414baa59b05778fade4c", + "abe55929c3074a9687c9f7feb2d4b221", + "3c047b3262eb46c8bb07e80fe7a11698", + "5da54c127fa6453c80f3f1ffdeec1e45", + "9a768382ff8d4ec0a54b2864b19aa64e", + "230a48f1816e4eceaee16d5ad410a941", + "f5c9ad9d14514ce8b7b84ae65cc43003", + "7d65e661b2804e038c334c3c479854aa", + "037fff0f153c41ea8b9c9392c2e2439a", + "2a655e41e9544ca395bd53c3d42a164a", + "61f957a7bde34eb9ab3896f0cfe6144b", + "c0f13678104643989a75cce39a50742a", + "d04bf57ee1ae4504856032549bcfd810", + "b0c489d1f7f74c2c9a7fb8cc86663989", + "869addd5664c4ed99e2f3727c3742ab0", + "8181a84c9e9c4f28aac80ac6eae32a14", + "fa69daa48e28481cb76566460b59d8f8", + "07efa2f4d49b45e5ae34c04ccede19cd", + "e6d8ec2cc4fa4f8c8f42272e5767922d", + "5234927d0d5e4dafbbf7a356ecfe5527", + "223b4462ea33462a95f2abb4113edd10", + "cee81182d4fc452485531346d2887cac", + "e16f7a61df8043f1ba02668fee983bc6", + "909c4a4c8f8341aa821ae2854cf4e77d", + "2e6a081a99134030908ef400861ecf92", + "70326062031743259b8379f255db978f", + "08ccb9a009a34ca5916866149e5b51a3", + "3112d700980c49409b69b767ac9ef7ca", + "bc0ca35cb6ce4fcd80bd19fadf56976d", + "219f723c32b848a490c7dda0514f2c12", + "2485375ed472436aa20b33fc522f774b", + "ec8f6c52b0014291900389a983651f7f", + "908d57cd384c4f7986741724bac5a005", + "9e5df8d277044f0d97999bf26605f50f", + "e8b1fb98c62d4e6ebdc48e70e633e6e3", + "be1619d9449b4eddad0d6d3d70b6ceaa", + "b05d59be3d214f74adf1fa48a4e6bb7a", + "192c0827324d46d8b956e3f2f1c6a22f", + "294c59fc3e8d453bb887d5948bfd99e3", + "c2a6547d9ffe488fa26794da38fde0dc", + "4f58fbb81ac744d5ab9bddc927e6a15c", + "46a6940b831242b38244dc39cbe8d729", + "d48dca17027647999b914efa0ad4565d", + "8b5f9940ce764f99b9f02646976f16ae", + "f508910db7d64104b50cb4d30433da1e", + "3b7747a3ed6b49358f342e65c9482d25", + "353757b451094a678770ec2b774632ab", + "d88e3bb60d3749198345c21c6a6e008e", + "fb5a0e234eae4aa591bdd24035f3fce7", + "f7a96ca9ce3c4a0ba622088fffffa51c", + "c67d1a28ed8f4069916d9f6d999590f9", + "990b08fd8cc94184b555283379642cc9", + "81fb731f922c4c5a96dddd317eab6588", + "e92205e389f24d75811f463405a33bfe", + "5e71077e5afd498f850b49231e47a647", + "0df79b5bf0f74582a1473374c24dc326", + "a32c7695839540208d0d473aba72f1f8", + "f1470058877b422a8bf4d9ba0bd6a23e", + "7b858a06ddaf462ab1124f194ac51e05", + "27a29d0d044e4dde9aab937e43b6402a", + "e5756366246c4704bdece8786feb2fcb", + "f09bf24836e548fbb505edfb1bca1084", + "68a8966e65a44c25b455c8a006e8c267", + "9ab823b2e21446c8b2043e2d1a58b445", + "67b2d6983ae0405daa199b5ff2d06c5a", + "0db2ccefe9914b39a9db4a89b4012c8a", + "840ed19399d34d8099b1663796b3773b", + "44393a46a9d44fbbb4bb0bec6dc31d2a", + "469cc2160c8b402685a302a6a8dc5e66", + "26409dc84ff248f0b59ae125389756ba", + "85adeeed60cb4593a0fab99caccfe52e", + "e6225e5e006842dcb9214bef8041850b", + "0880941e1b444ea096d4c5e8c793c635", + "ef272b3001574c62846750f11ac8ac59", + "4ef2ec7867e947d983a723f73c678d5e", + "15fd42e4f36a4dbfb5d489c766a0cce7", + "85b9942d170a48cda257991821dc1175", + "55f91336dcd343ad9dea917789d23365", + "cad14c16803e4bd39f3204aa94b9639a", + "f9adf1ea51fa40d58e1d72386902ba32", + "06584ce1e46e43f5b8439e15a42bc5ed", + "b9ca1dbd956b4dbf9997c00852b40ef9", + "644c300e2244452c86d6fac0296477e1", + "1392b664d6084009a40721fef3850b4c", + "24c839f05c674cb99f1916a0312a1fb5", + "8e76608278884c5fb01b79ac2e1c152e", + "4c2c75123a644d4eb7324bb5235c6a86", + "0413d92d70f24a68b3afe8643301c515", + "f29bc960fcb6426b86a1477fe1948483", + "hh6HI5dnOK2IOfERAPHJF7OhZRy", + "63904d0df09c4be6a09518be761cf116", + "5d801c03124e4fa184b4e3271abfa9df", + "fe0ea2cee119476fb1a7524d5ff380dc", + "5e0f504bb5d144809390dac8c66a6dd5", + "d3680c43ae774a088d0708ebfd2e7f47", + "ead44eadeffc4f108537517e9ba34845", + "71edd9efc26548758924ec455ac4a197", + "ad9df9121bf94b71978a352cf6cec7ef", + "26198bd869d243489aa7b6ab03a83eae", + "0e92e5abf0f34444922783a90472073f", + "89b71eed14b4490c92db6394bdc7da4e", + "478e23b384014e23ad98cc157fc3d26e", + "2ee2003561cd42789f6346ed1b65b2ef", + "ffefbf2d4b4345778092317a47203e80", + "13bd7511918640fba71dd4ca554d5a5e", + "6b07248adf484a67b4bc68682e4f6088", + "86ee3fcc53ec41cc85aee9cb317512e3", + "faa5f03f2c7f4fd59e663f456d1784ff", + "306b6ea8f68f488292792e5611cf2830", + "2c55f313494849769f17ab44bd4d3fac", + "af589f9836554a83b6837ec862059001", + "7ea855bb5d654f59bfe2a49ce6b9096d", + "8e75a83817dd4ab4b679f1637e79ef78", + "0058d91949de484e820a046235487223", + "bc8a954d36ce481fb8c31ec05d854bac", + "117c7b0f25a94ea492deab9d1c1d768f", + "69d530f7e6bd45b9b3d9f16dae627348", + "729ac26b84044ff8956bd484056efbdb", + "7953176b75304c4a8c457cfb8a94c0ae", + "196aa60cdc034cdbbc2c9d6dd6517872", + "47e7baf853514c31bed2fcd399eae864", + "907847ce13a54415a4647a5adeeb5842", + "88f33fa2f8704e86b93a93e5c57e7b06", + "89c9a198e3b04292802e9a444f6476e0", + "d45111cbe4d84c9bbf37784bc140dca3", + "b45efecfd928440b9e7283789e5a9c3d", + "60e58a541bcd4fb3af6ca8c7d55f88a5", + "b1707caba97c422db9d344695c621b46", + "f5252fad68bd4060bac91e89d9661faa", + "c4c686361ba644fa9b10cef3461cc7b7", + "97deb26f29cf4ed79b7b0ce84b4f4794", + "5471355c677647849d4f6d495906607e", + "4eaa8a603b6a42218c8a94edde2999e0", + "ca451fe549c148bebe3666ea79f7249c", + "4414ae6e52094228afcc72a6729035ae", + "b171d86f932a4ce19396d64066fa3424", + "6bd218e1d4af4f0a8b4ffa50931dd5c3", + "7220e93b3ad14f218dfbed7acff2e184", + "8821be772d624c3e98bdf45f2735d216", + "1b5a261e06e04eb0a11ed1b5bfa96a71", + "019131b6267246bfa44afe60eca5cceb", + "8f07afc78361423195593319383256c8", + "06ef6cfe922c45bf865045c6ad04e623", + "a5e68d1f73d74a0f959150be8d0ca31c", + "664aa38dc05845cdbf7ad64d2877e5e4", + "a1e28c3f585a41a990814143e729b915", + "c1e33f6ea24543fd8970925b105f4685", + "6faf2d6a369146e484d9c6af7bb87cee", + "4722f5aa9abc449abef01e64045a0371", + "7f5b40ab8a4a48ff8cdc8a67fe1439b6", + "6b5cbcf70e944966bebdc102676cfb7e", + "b3257907af8248ab99cd27ff8c6a86d1", + "51f06d8c45dd4658923c3b209aa9427d", + "f61a2a3ee12344cdba2d9d76c5e899f0", + "c11a48ec8621478a99db0b02c754eff2", + "e1e65c20562a4d0eacc28c2b6943f1a0", + "10ff2bc625c84e858fb3229d3be525b1", + "8e6f77b513504b53992259fbffb046a8", + "bcd8eaf8dc13433493944a7f6b882f9a", + "8fcb19a048c84e2cb6091c38786979f7", + "98b5663abe0c46ef855e3c3f64a0d7f9", + "629bfc973d644bcdb675064d940ab43d", + "9696c81e699b483a94382d0886b464b0", + "7b92a9b32cdd430382f97d823f98e225", + "d0a816a10d734fb8ba77d5bb37181c4e", + "a4aaae85b73043878c494487d806f7b5", + "759d4ab0839c4dc58aed404a5d512456", + "1808a0a8ef0a4e448e2d76fab9595c3e", + "0bd87db318fa442f9e35883eacf62728", + "a9f20de2f8c64257af86e37bf27fb931", + "d5d7f7e111464dae951fdbf9cc7c079f", + "f21edc1d2d864e5b8bcbf3229dcbbde2", + "c7fe6a75ca2e4978b5eeb9ea7cd3f135", + "ab7a88ee339a4a1b9c36ddbae44ae4a2", + "7a84526ba2144b2b83259beede9ef363", + "53d172b789b94b629a504fab84bc4d7b", + "3cfef2da605646d2a3597444ad7130bd", + "717f8e05ee7341c0b084970780a3f797", + "33c5f344ae9f4d289cf02709e801f273", + "32f1cf6a13a64742883282e90ef68c8a", + "9fee928c3dd74c32b8add7a1a3fb06ff", + "5368c880fc81424bbd0c609ea27338c1", + "6829f6df49124a50ace106d4cb754064", + "cad5da0a14ae43759cd9221dd6099bb9", + "1c74e24e7ce14cce982e9f2bd7857a8e", + "62d137c3df4842e48a242794b33a546a", + "e819a9b41b25453397776f8059f2d5b5", + "f1752394e30446f7a08a8387d419670f", + "7b8b481d58d54ab59f5f4004de4c6b27", + "3b5555f4f2544005ba4b0ea5328def04", + "fe1a65abb15a4a7c83a908e0126fc525", + "de24547d5dce40a6b3f631f87f21b414", + "be40b822f50344c2a8bf84b68f56d991", + "f7c5bf006f014d74beff470e015c1261", + "b82896c35202456599d65190770789ea", + "c4d356968b8046249da720d73206e699", + "ec041db118094befa4f36434db9fdb89", + "44e81f0de2934a76a99aa074a0058ea6", + "fcc1aed5629849e6bc6d01bd1ca3c7e6", + "7c05c683425740febabd29a937de624f", + "e66068a7b1774abcabf96709695a7fe3", + "1dc2afef47ac47a0ac94b5a94efdf1b9", + "9e8ba75c316d4055b5cc6e5c1aacf859", + "6fd9f3ac8bf8489ea63c25fc6ef24878", + "67dfbea6a58346809116be2fefb50680", + "c13e795c070b4cd8ad45533d00977cef", + "1d726c734d124f468a48dc1fab6867ba", + "5f7e82c0cced45088bccf7954329e21b", + "914801b667544227a3df73063d57ffad", + "13d896955e8544e9aee219a2ddd8ecb1", + "bef0ada62b64410ba523923cf6ac56ce", + "8b6c30b2ab8b4611843572cd89d06d51", + "ca72e6c6a99241a6b9792de380ff48d6", + "e93d194abc3b4c9ea4252067b1f1a8c6", + "18774462ffa24333805f6755a38e89c0", + "bf2f4c168c41450fb77bd1fceb7aa43c", + "75647cd8b30548a9af8de5bd07446b16", + "c54f2737bc1644088703d988e3883247", + "287377fb017849809b6adf11a69c116a", + "69cf45c71c5a40eeb194c5e170823551", + "41db138b35db45cf97624669f03b89fd", + "d328bfacf7f4448d8875da6a844af97a", + "2529dbd639d5453c94b79d31b4be745d", + "a2f7fa91ec324f53884e687414edb964", + "326494dbe70441d790fd74d06e5b5a39", + "2e295f6f798048e2aa0d24e1b252d8f6", + "f6a2a80de6db45e29c1a0491cfe685fb", + "6c8e689b380749ceb91a4d96ff8209df", + "43fd2a71246842869cb9dc428a9d2a7e", + "a8600000fe3444fe95340815f59c50a0", + "ae960d106544486cb4db01f593422cbd", + "9cac8d2048ce44dcac5021cd2b63a371", + "ebe84ada4fe849ac85c2b6375f767358", + "571c5f9d65f142f1b3ee378196196283", + "94fb06bb13014835b611fe631316a5d1", + "2935449a1fcc41b58ba194f41e74c2cb", + "dd8318fcbc22481882a208ec208b4d92", + "120e0255832145c2ac1752a621acd33d", + "a7c7d39c461e457a811c8b206e178685", + "b648a6a1c27c4c139acf12f47c5a2d66", + "f00558f1fba44a9698a2df0d9feb0d59", + "21a6714ec4bc4f929497a3a0e62ad548", + "6d8bce057af54abda563bae1fd6ccc58", + "ca65bbda65534f3fb077951beee8ed3a", + "5edff150f71e4a1a940cb6f9657ee088", + "f6efe212a8d9426481d877236a548a5a", + "939b38e5613644a9860bc6579bf9016e", + "1af6b48c4cf74957ad6ebcd8c5cf2ad9", + "15706428e244497ebd88a515949c79c4", + "430f5651a39c46258abb30a22f7b5634", + "faa0ea95a9b74233a32013e381342d6b", + "b321e9a248ab4e21a01a10a2bdc3debc", + "eef24ebe601c4e2f99da3108ddc3b09b", + "8223c2a7e90f44ae9d3aae0de389617d", + "1e3322180ea74ef78edae05f4701f3d6", + "fb2fdd5f56dd4fde8338d7160af6a06b", + "34270b2281e641deb39b16f69ed84346", + "11c3d60b238f48b8879f63188cde5ab9", + "5a8106c9e9184c5eb5e2fdb63a75ac00", + "e940aef01d014a768ebd121762502398", + "25f6eb11e6814e0785d4f57b1ce6213e", + "e6fc1f3bafa141f6a322bf0531197ea7", + "2881b82bb13640a6816cf14d4aee5e3e", + "75a1e08e4b264ec8b9e2b082bb5d60f4", + "7cc573b557f6494a802c24b6ff02d641", + "489f3c3301c94de794fd7ae54f5b2fcf", + "bdf6c05eb95e455aa2de8634716618cd", + "02959ad818784bac87a52f4f4c966b4d", + "c6b4b6a6b83545f0bbe9fb5ec0b4144f", + "14c214f2527a481f92c6b564ebac6b87", + "dc352fcadd69463cb0a99c61b21c3f5c", + "054930982d164a689d1b51fcd67c25ae", + "6a67efee5d04416984d9bf77c222b331", + "efae586a477b49cea1a0777487cc2df3", + "dd5a6fdd09ec4ebb9af3453bb651397a", + "f9ae3e61ba254b63a6134d0445380ce2", + "449a9f55fe434ac5895aaa2b4299ba31", + "53c4eecf39c84d1898dba21ba0368f32", + "a691cd8930ba4dbc92967085f376bc85", + "a6ab06a3fe80463ca23d0cf3c14b573b", + "636b75352a134e07b26992c44383014e", + "0130ace3175343f68c0c2bb807e6bdc8", + "b29ea5232367477a8973e2d35d39f497", + "34f6ff7861c84e938b2e961b0f3e25dc", + "304f656a07d741caabdf36d58b9eb471", + "1592ec9e7b4c4541a3543fc0d2112ddc", + "a62b69ee18cd477d92e4655c84a79770", + "18e5a69550294ff2975fe7f5c8569832", + "f6ef5f55922f4168a3215cde6424b6a5", + "fa43a9abbacb4298b09b50d553e11c35", + "06b7951d4e2f43ecbc30d8f00cccb499", + "ecb62a6cf8a54a60bdb5ba02091cea3d", + "5da4090aba6f4e09aabd416bb546b809", + "b1758c86b7084b298c79ab6eedcda44f", + "0d92d7e395fb418892f926089a6e10b2", + "6d99c6c1a8bc4b3e97cebbc49d62115d", + "2b9a9d4b2d624b8f889f9d7be4c7a14d", + "3d4ab80086b6415eb6e10f08c06841ce", + "31ce101b0a0f4d768d6d801a4ed674d7", + "1f48a1a02fa448e5b9b2f350f05a401d", + "2db13086e2ee4f22baf77a8785b32d3a", + "95042c39e0784d75ad680b4d7b18ba7f", + "ce20e03cc42343ab96e65c364ba6c78c", + "7570bcc5e1004bbc9e96601ac772ea54", + "00985d5fe70b4bb28b04ca847c43b969", + "4941b660a4ed4711b55fc4293abbeca0", + "766be84457bd4b50a04c1d7442444baf", + "5cbcb1879330482fba912fc54916135e", + "b16f3bf656df4a029d869dfbdb5b390f", + "ec81ab8f32f64e1899736616932c9d28", + "b190dba1f961438ea5c7fbc437b6aa15", + "0fe3264cdfa8482a83830450d05ae1f1", + "9f482d29fe1c4e4290334795a5ed38c0", + "a07c8a9f559d481a9d88309339335a04", + "5c417d039cda44dbae38ace2bd18741a", + "426a5a6a3874409990da93902f43e708", + "b9968a00bc9249df927ff1969acf2f7e", + "bbd170a4e5024cc5a13b580a4858bd24", + "52a367debfca4d6cabb5cdc7de516fee", + "79dc836779d8496282cb3a046ec19515", + "7b59f1c70fdc4dedb4cdf0e73ecedab2", + "51b66585d32142058500fc5001567d1d", + "decf197fcdc54d2db7d400a8a7eea3f1", + "3e58838a56964b5fa8762d908675616f", + "a2056ccc0ed14427a42610e56fb7bd5f", + "efb3ef63a12c4b16b5ac0f66bbdf705d", + "65ee59c75d1e4c049e32a065d7a228c4", + "4c134fdcc85846879eb98957fa49e7fc", + "6f98c7c8ef0d456f8ce0a76e406c4696", + "1ce02e5ab405495c97083b757f44a65b", + "a5e22087037f4f62996006258bcdbdf0", + "4ae1654173bf4d3185a4b88723fa372f", + "fb21c4f65bf0461f9ff0b6f2b70331ff", + "f36087616e7a4205b942dd4f4457c9d4", + "332fbe9772fc4510b1a9dbba8962bbaf", + "435bab21e6494be28fd4106e58772674", + "9e849f2dd7834606a5faa636301f814e", + "405b12990ac045e98c6813f32d62cf57", + "92601efb9e7d4021bc4ecc7250a9930e", + "4d049c09a02e4a578c82f47466a9ab9c", + "b1ca81f2aa2148f0a65aaf09503907d7", + "ea9992f27d57427cb94944598bc83117", + "4426d269d52b4269b421226c054b9e07", + "1d702f4c5ec44f37bfa6ebafca3275a5", + "791b35e667584a639648621480627dbb", + "38f6251209504ddba51dc3b0be4061b7", + "5067abdd91464c0a9845d2757be46d09", + "fade0cb030a3493aa68d2c3f7cbfa09f", + "3abddfdafec3468d8d4a7e05020d4097", + "74611a68f6b449ebb48a62e617611037", + "f675f0984fc34347bf18d2b3646c71c5", + "e0abf121302644a180211dc0a03ac61e", + "46e8f848735b496e8aeda829d0b96023", + "527deee7bc3540febe5e44569dc934e3", + "c23e91ab16e0450e8832d7bd4baaa326", + "ec0a035603824e7b81f0c7bb326e2d58", + "eaf63782d5574515a89cc138e1d40cf8", + "9536a021944d44abbb8d3a228560bce2", + "04b870f441e848cb8537f931749125dd", + "36ec2a3c75ed42c3aa673597dec72a1a", + "64aa4901e39946208afe50fa0c2dd8ca", + "956b97c11aa94840a1e24ee1558fec73", + "b6d54fd1e9394a1f8884e833bf91db26", + "e8ebea679fcc4047bd483520995f9376", + "75945f055a8c47098fa8aa4b6a698b07", + "aba05909c9f04c1e819c9aec27cb32cd", + "4197de8f01d54781868350ab19503a4d", + "43220d243e5e453da062c2a21fb20d49", + "a57204655044471f84d2e00448aeb97f", + "3bc4be75e7634ce0bc8e07b50e2bc369", + "959824dd8d1d45f1bc66e6159f346521", + "154f869343954bdda90bb4802828a1f7", + "77d1498b156946eea65423cb72cce135", + "98145ff8ff97438e9869767390db3b79", + "fa8d39231c3040fba3aa2ba026dafdaf", + "dd324f84d894471da817ef20e3414c27", + "f184d645df9f428b9fe8aa8e74262b4f", + "dfb56c353e0a4bc8a6d795a23cfada12", + "47941ec1f8664b57980b1cd6609af220", + "8c9ae2b076384b598f824dcf56ca2337", + "b0fcc0d3b15d4d3abf2e130d8ab79b96", + "978737e65b6444809e67b63886ad8a30", + "806b12cd176c459cb7818fea8b56e593", + "1bcd1e1260f54f05b451f6ee90ec0331", + "d209e28d89c64922977d69d8bf296944", + "bad88afd42be49c9ada31481d639de05", + "aebf93e711ea440688db27f3042fafaa", + "d340b2b9f1f4406286e3b23722a546e1", + "3861f77828a9460ca3875f9eef00cef4", + "89170dbd2e6e4d9085eda23f535e25cf", + "d6341759e57945c58ed04c8a7fef092a", + "3887d194684943c98384acb97024510b", + "e24d32e6598b4fd9889d33b04679cce7", + "9885549266864bfca53f2e2ac3e005e1", + "e0de07c5feeb4ad49c12505fb088dd3c", + "4b8a97013faf46b0a86e1f835a5cc7c7", + "242afb0ec4804a8fbed220513e5a8649", + "36c8fbe3e046403eb813159180ef5278", + "3d97ddac9bfd4a7895e9ae5fbf7667fb", + "fed63bccb2ec4b94a212a16b52febfd9", + "9adf3208a6f9486f95c386ff63152c11", + "d9a81a38147440c8a2ac92a26d62d895", + "607c8859f08d4893aa6935eca3dd2236", + "5e0e5ec5ba124af39d7a7d737c70e959", + "588c1d1650c64a76940617f50dc5e2d1", + "1245cb93ecf243aa9b583c46e8c31a1a", + "6192652ccb3d44799dfb5a615f0a9603", + "417e2b8ab11e4789b3c2ddaf845874e1", + "5067f896ccb043099757c6db715d8034", + "c0444bbe112c4c02af1e1d3ee3a04184", + "413e2a18d7da438abdb0f783717014b5", + "914ae23f4de949e989a84ba33e81606d", + "29758a21696444848f4a41dbd90db576", + "5b30e3d8553a4cbcb75daf2a52b245c0", + "7e0da9c35c07467abba5ad6c947caead", + "4b3a4cffbbe4499b9e69eaf3157abf06", + "58b1498d53fc4a69a06a6618ae0c2b05", + "2546097d0ea94ba88452ce62c041fb87", + "15f70ffe17eb440db6cc6b82c9a96542", + "abbddf90816d47e3973c438b68f0eb81", + "6f45cb8405d846a98d517fed98cf6d54", + "4d7f020db96545519c43e5b0ec077a83", + "02c8999e26a34efe82dc0014a7a620bd", + "9f6d655939b54f47ac5432ad8ed0787f", + "b1d3d3a8edda4d52ae9019d2150e7bb8", + "86ad025427d64e34817022ab83415b74", + "81557af1e9704799831faa651c6f7992", + "09da214879cc40d1a060b07f472124bc", + "60ce153c8fc346b68410f2a3cd804a3a", + "ff622a8042364a46911aa9b67d3be8e5", + "00616f328a8b4b5a8e689f61e70758b6", + "5a7ae8e0097c4eea85e975d34031a538", + "cd8d26b2cb8341be8617b13a5ae74be8", + "c83fd12998524dcab47e8127bb22dc00", + "a910c3a649d04d488cebd406e13e83ff", + "eb264cd5dfe54d71b7b92c9702351338", + "4c302192035d40e59b7c0f18bb74f212", + "3d916467f33c4746a0df6ccad0db3f82", + "6635959084d74f8285220ce47d0b61da", + "3db7dbf96e144a1fa54dacdf8b263679", + "1ab28887546540d69a4c34618b285387", + "07ee2f3d802c4487a749020f963602cd", + "2cd8d1032b53426a92abb64a71743aa6", + "c892e540ba3f40c3aaf7834240325698", + "252eb742592a4d419fd9cc555a051245", + "5fd2c9bf3e834e839b26649db7afe4c1", + "7079a5fc5bd74143b36d3f1a123a4f03", + "7854d50ffff840968930b072dd1c8b6a", + "e728dd63c5df41faa8913528062fa3fa", + "b904684ad30b497b9c585dcdb6cbd869", + "f3d9535a0b014487b3171f68e2262e4a", + "f2501dae4b884f7ba9cb3347d9629ce2", + "6e4cc39012504c99b7841314f2218e0e", + "36bbeeea5d7d46b896f18088994acec0", + "6d28f889085845bda36ff56de0b6e9c7", + "39f9e1bc93ac4308a92e5ee5fce412dc", + "30f926383b8748b89c978a7812421aed", + "145d570cc1ba4946ab7206c2ec7c80b1", + "6e6542449495405aaa1807f5c8343633", + "45fccda8e74a4127b6a5c660dd1a86dd", + "f99d89afc12a4d48aaab2752b0bb5645", + "d4869195458541aead974fa95b6afbb7", + "fed532fdd0904552b3f3624ec7ad7fed", + "b4379858a3224dec8b89f93656ccd156", + "ff814230abf44128af37ea768b50ff90", + "f405dd5b3e304f66bb4502467ca7fec2", + "3be8c8d914d24bf89ab16ec4fcdbd937", + "413fcfb5c1db4ab5b56bac05fe923433", + "5a9ca3b40a02464fa385f3e95d4f45d3", + "933bf1e7d4c64ee58f380ce0a82ecab8", + "b83cc0072db440edae5429b2b5a6ef39", + "acf50680d8964e0fb7853349d3a222a4", + "18768fdf937b4874847980a2269df118", + "c11a8596c3314677a8b9321e141de275", + "7a2d7d19a5944fe9b16e33cab4ba886b", + "7b45769ec16e4575b3fdf3f324f1c471", + "4b9a943e117243b880fa4a7d1987dedb", + "47e100c8c6354934a5da2ff6df1dcea5", + "8b36c16555c54c639ae3f3a605236cc6", + "8cb3be58d9cf4321829abbaa995e1223", + "a2fdd459222d4f7daf89c5621d2c9635", + "c6eaff773b124702a8894825efc0a8f1", + "095c43ae06bc42c59b247d57242d6772", + "7d6c741a2fb94e328b22a9e929defb02", + "42875c098c33456b84bcfcdc4c7f1c58", + "e3cf66a5312a4890bfd994cb9badf9fb", + "b076dd3a2850489e8ce655126c64c57a", + "212d33f6b5904bed965a87b018325b26", + "36b2df81078b4f94af7c20c4a224b4f3", + "77748f51f2d14c9fab18fd2a70175c31", + "b8c3b9076fd14b0e934f2784d8de105a", + "3de9bc73be624f47876d1a34b98813ab", + "2c51d30209374966bbd887a4dc0ac19e", + "12b857a44b564254b772d00cbbd99685", + "83a6fc8e16e04f5fad3c929893f275b4", + "fe533dcb116d4d35bf55fcf5c0bfb008", + "8d1d0220ae854945ae04aeb242e6a4bc", + "db529ca286dd4e1e994d39508e02c445", + "2bd76952a7a24ca7ac7bd5d7940de959", + "8e1627c5b589420c9bbed0e0cfef1502", + "d76cb0dd3c0f4e21adf3e489c14f43cb", + "f39ea96a07ee4a2c93bcc737d5672d49", + "75d95d639f9d41e3adef6f74a6f45305", + "0916c6ada1de431184bed899f37162e8", + "b8fed189a84741a0827b1006ba003a94", + "a4b55d6bee984e919d0afa9b53b3602e", + "cc04bbfdb69d439e8f211c25ceedb796", + "e0b6c3a33221476cbb321468586677f9", + "a1a1c7d24e984dbb858d2f1bd63180e4", + "216089295e6245c29445c2ef7c0f95da", + "d76c2f26905440cd957de261301d09ba", + "8896c1ce46684229a662167dafb43618", + "9b295aeacd7549d5a09f6e051a4712a1", + "3cd98f85b64a41c7989e7d6871b8281b", + "17bc158dc66a46adb36c7f90b744ee6c", + "1dcebebd1e5f4642b309294eee8b1bd3", + "e2067f6129624d6f91af6187b6c2feeb", + "31bebc39a5a0470983dc26e72d5cb68e", + "ecf6d258e2f14b0f89ea9683e2b13d7e", + "7383425b3cd549e98a7ef5a5438c9018", + "6bd9b2614dcc44a4b6faed27951ed252", + "e051667e1deb434eae8932496600f868", + "3bd786986e974eab9f90cb3f09e2834d", + "c24f6489c8da4cedb44a5f639e063eef", + "fb80ef2491214624b8ba9347e30b5c61", + "fefce37536b6407c8bcb80c70343c5b7", + "b4e5f0e6367e442c995eb1e241e61f74", + "0eab21851d2c4b79b0d8723aa154636b", + "05db4fe42370427cbdc67486424aae31", + "70b7b418af714050aa83e99deb2253b7", + "1a70a14d0ea54df09069a0a22328b18f", + "1f168fc42e1545a5abfbda6c18b7e1ab", + "c4182498f5a5435ba8589c0324fe1a60", + "e52a1fe4a9ab46cd80e9538dfc0b85c9", + "c0156044d4834a18a44eb9f01d406bcc", + "a38dc588f875474eb7e272c95fdeb154", + "ad9e40cbf6e84f76a2e9b9184c16ae50", + "b0f3e65d0c3c4a53893b6b2d650f4e95", + "45c8f611a28a4e0e9b74bb132ad43ae7", + "a1767c7025ab4c93bf18452a21fea774", + "531d3005b8cf40edb8767b7677a01aba", + "e1ca50858dd94a10a94b7ac2ca07c69e", + "42a1cfd5d17649f8ac4d6a835e21d6a7", + "f408ef68c38444ddb9dd2d3ba45e5227", + "a870845f474d4a5b8aba284cabd14d96", + "869366d687b94193a625a84040db4a64", + "acdebb423f374ed8ba161b1c9d7ee168", + "7018a6ab87024f1d90b58b0cbb6bb39e", + "61902b403ea4449f95ad3777ccd76c9b", + "2bb3bbb46fd441a0a1abcf93963bb8e5", + "df6baea7d79a4d2988ab55db5552d8d5", + "9d7346001d624b039ae727d56dd4bd99", + "c9e23e65e1824d57a3a97048d11f0b54", + "cdefddeef92940089d02bf3ee76fa9e5", + "7b59330fae2447ce8639a29b41f8f47a", + "2f42722313cc4c48861f43d1a4950834", + "2aca687143924c578171555f47db45bc", + "56eb4dae6885444c8e4390411d902811", + "d607b629a18443ba8555999da5eac4d7", + "03f6de03a15e4e398987ea88f53a1af0", + "c02369b8285041fd9463a3b5e88e335c", + "670b4ec3660844879b796afb74783112", + "dd633bf84e034fc196502cb908e7d7be", + "529e8e66d0174554a02af4cb148b7b00", + "c1e697a1e0f74f92bb1f169e40fa5e3c", + "3fc78bbc18014edc866142f654bfcec2", + "7e4a6dc716fa4ad189e9661bbe8c85c9", + "59f5621c258e4b3f95120ee5dbf5bc7f", + "144814e7504a47528107c35179185fed", + "90b2d16f30444e0c892fecbe69164200", + "ffbc1f59a2e94267a286d460f948632c", + "12551977a2de417ba46852c9e559b0f5", + "2a49fdcd95be44daa87a6b8bb4ed9f5b", + "d9e9b8f3a41b4dd39a0f5a948ace332e", + "8e55bab46e0d48afa3c22c339a6b738c", + "7c7640c570994e72a1409d3d5903f8c6", + "963846a5496344559761c02f62998b03", + "d00bf7fb398c477ab6d1c8b30f667722", + "f7fdd802e0bd464382c65e5aa8889e1f", + "b31e61bd006b49d5b2ee76fe81110b07", + "f87f1aa6d53241e89f9091cfc35cd325", + "d83f35ad19e8433d96187bba7352e9d7", + "2ab1282435fb429ab88b8a88bf9a82f5", + "feb1ef90bdaf42d5afa27b91a452657f", + "afe9e3d2401040e7b99f6dfcce58caca", + "590acdf57b384a17a0e7b4e9d20c5d48", + "cecf76fc406e430d928f009ac557126e", + "9b8ceb6bc94745b69b822cdeccb3a6d2", + "ce3cc609cfea4e919cb890b3a28f215b", + "eeae214a963a4aaabf9d8ea5dc4c3c03", + "177b69d4a5de40279eaed6cd348b10bd", + "376b495b9a994e0bbfab98d816659aaf", + "5d99827c456940bf9055dfe2dbc561e8", + "2beb642c96274e91b843d4eb5954501a", + "d6995fe908b54ff6a3f6770cab6482a1", + "881b5895519047bea595b8731e5a0d52", + "5661e1f99a3e4d4ea257a085fac5acfd", + "2bb8e23a826c43bc96bd522aa0fefee9", + "2252ca7fcd77407da704159152dfee0f", + "7483c5fa79b443d183dd7718baa009ae", + "7c020af957294c54b743e4321691f219", + "008a0b9867c241a190eb5941f5b4dffb", + "81eba26e19be43459cc5ae8c1e9778c0", + "ce1a06f7cbe1425099a145f851fc5dee", + "ff782717835c4790b222188346874146", + "5ca89b08b70e4828af6461bd3d8465ff", + "e9fa19e6bd6a4ecdafd21a9b51e02447", + "07d5590bb5164ee08b7c4b9c11c44643", + "b478d2ca73b64a7aae3db1aa5cde11ea", + "bbf7a246626f4b7d8ef9ac0ce70a376f", + "a78a200fd62941dba6ecdc59acef0f6e", + "8d7d68e3eda143ea8b07b0a1ef18a6a1", + "eb9f74b41ddb49f9bb9977a3d72f68c9", + "324208bbb2b3468082ced58f8b8113b7", + "d92f521bc1bf448aa0d5fea93ecc44b2", + "101b50323cc34fd69c827a42a818d4d3", + "bb540fc9fcb04a5aa13a5d9b72918f8f", + "594d34137d004e7291bf79331d6bb459", + "f1978fa3192d499db7233e900f43acdf", + "36576590b5f04ce6999c01c28fe7171e", + "a8e44d4d1e3e4d07b22016be040c4075", + "af85273c56464aaa835e57f8377ec7ad", + "1fcdadf6a8bf4a008de9196896e3636d", + "42529aab3e764437bd73bff8eb6e3a0c", + "2304f145b2f645f5bdf6ee4563ac9173", + "8be12b142f624dac97ebf0da44f12eb9", + "9e40e2f2780a4993b645d130bcf1d657", + "0daf244070a24a24ab29d0d6f86977ef", + "5e1fc505532240d7a6f48d013bd09d0f", + "aa9b5d16b0be4f12a0cc3acb97b91587", + "1222477e239145e2a46f642b44475912", + "25eefc82acd944ce862b7988c37c6d93", + "c977066fe17e4e3fbd931bb7b277aea4", + "84bcaa0c9a1c4385b8206c0385c38b78", + "4d9b418b79364283bacc3fc18c0f5f41", + "fdfb6af836054db1a52d175a97f13991", + "af8ed31338d04308990a0da9083fcccd", + "82a1431a18d44f4591225a6c706cc456", + "c54e11b16d24453689d59088d88841d8", + "660ed7eb17ee42c0b004f2787fded575", + "18dd54fb5e6e4924b10dee61cae63842", + "fd5ffe8306f24fd49bacb84e83a0e31f", + "79bc3c7436214c39ad32e03e1b164738", + "913e75e08bb347deb9b02d7ebb35ff37", + "c17577daa87849d09960669606c0ce27", + "fcd40d60d1384da196fbf105499ae54a", + "e14a2b9336df47a6b536a3a1cf829221", + "73b31a00e15a48fd99721b80865ff70c", + "69a1c7edb41b428e9591bfae97dfc124", + "ef7887bd8daa47dda33cc50974cb2a59", + "230a9d7b8c2b435d8d20b1ddd12e9d0e", + "2a614e2187e3416c9e0718b09f5f9927", + "8f4c555f31fd4e5dac2bba9c980ea2c3", + "a1e25d0e8f5d4b2199d5f1288ec9aedb", + "5e3990f50765489087ab4bbb95e98c4d", + "1def208820694300bb5102e8dd228bf6", + "18e8e405446849afb22b3760d3c73a31", + "b885a9e511464543aa81d0a8ec092ee1", + "34920ca3027c440d80047bc466a746f1", + "784812e01f71466cbdba96245add0e27", + "d21d6e51057e4a34afc715185b2b0aa1", + "97ea05fca12747d9bede1bc4518b752a", + "e95993cbd335456686c5033ff5b214bf", + "8cbbb4dd2fdf4397a011774ab21807dd", + "3de2985ed85e478387d2829b690d9523", + "1862fbf2f8a0413bb678b993c7ae17e2", + "369878e00e114c66b7d07c427c97bed1", + "fb056a7709f4467f924f0befc495c9e8", + "d80b3bf366aa443887ff5f422a6c12f1", + "aaeebbd60366461d98bdd275508788fb", + "7846c390707e49d2a0e601ee748aae9b", + "60d9fb6fef2c48628796a4d9cdcf34c0", + "1cb676309cff40c5b37d8791ed8ba12d", + "fdbf4c3eaad843fa9d833885d6e16e20", + "97f7dd4b5d9342fb8004763b67655f37", + "ecbcf91746d246c394823464af2feef4", + "e60f9b0745ac4ce1bfdd6b001dad1970", + "9b3b5cac17364178bc36f2c89756e5bf", + "da15b92a3a584a8387036ff688391d45", + "12b908ac5af54e79bb0aed793e7c66c7", + "88b74919afe440c6a9213921817efa33", + "dd371614f76f4f9b98d790962641ccce", + "91c1209278504577b4023e7192822a73", + "d93b0b8c5ae14985a7c860009f9a4d8b", + "081bbc6af697476da7f057ad89697f62", + "7358c2a670844a9ba6b00368cbd54811", + "f86b9aa9cd18453ab8d20f96ce8cb9bc", + "d0a95d95b5a94577a65cb21e0758da5c", + "a36de7afb1c64b059f2386825411909f", + "2955ec27152945219c8cb82637104790", + "0949edc313e14f7c8984249291ead708", + "1e3ed390353a40c397e2fde3093627aa", + "f7676d6ffe604418a821080edad91b6c", + "4c36a823b1fa43b4a297b39f1c31144e", + "a1a718baf77449cc9199d8e1d0cc9d28", + "d01658d342d943329c1db78de4fa71fa", + "6235bdbf4734422a81786daea9aa393f", + "bef2f96d165a4a20af0b84cfd1ad6df1", + "d88ffe0f39dd45568c33df48af1756a3", + "9ffb2ac9beab4506944489ab62feaeec", + "c5ed5e1d5a0b4a0bb6906aa0e75d787a", + "d725246436c94ca4bdf95198c4414702", + "0acffd6627844bc4bd91b8fff4cc604a", + "aa2acddb218646a59ece132bf95aa558", + "607a3bf3fbc54bd2b9da08c18f625ee4", + "7e5d37ebd8c64019be29900adf7a7172", + "781f8c1ee7944ad68eb3c110ce22d7b0", + "ca1990835c3c4be3b2f1c59eb3355bd9", + "a91098f0c18e4ccf8efa5894c6eb7bb5", + "82af323ccd47466e9b54a3f3c36f01f8", + "868171898ce84e198802e21b0c6700e0", + "7cd85a9d070f4e24b7bfb63d25da8276", + "828c6c627d74452aa97ee9bf7619f808", + "9b5caa6314774a91be5045b91066a709", + "73e2c657dd4248788c812fa838a1b7b8", + "0a36d75bf85f4cfbac0896034e6b95b1", + "b700b310e0f64567a47f554e3a2c465a", + "dc527ed86ba94586a20b8d5707130bba", + "93378b4a16b34c45bf1c3854c18fdda2", + "cdbd5e4590f4427dbe64083db6800d89", + "903e559f41114cd1b89ed2617c131208", + "7ba9f879b3ab41f6a5fb6c1c7728859a", + "e6e24214d8eb42a29a0f25bf324f637a", + "61df5683eb8248c08fcbb4773a887280", + "ca8e0bf7359f488483c75dec94f087ac", + "f5b4b23a214a4a86b6aaf147d3632d84", + "e1a65acaccc2421c924197ff7eebdf8d", + "05a8b16dd8f44350adf57ec1ec549274", + "8388e93c6d6549228dbdd676c220ff14", + "2d4d77ac85604a1ab61b934b19d301c8", + "d303cecffafb431c85f71ca13dbdf1f2", + "9b98ef881616492a8a10b28568a5d122", + "c91560e974fd48ac950d2ab3b01c56ca", + "dd00b8fd6e8b4638b9d2ce6583cfe659", + "d878d181cc3947f3a4e4fa22c6cd11f5", + "8bf9a9a0f5574468bc8a427e06922771", + "fe1bd031df584950b6d8b06f1613ae86", + "12bf4268db9b4acd8b5d0d5bc5c3256f", + "69511a7fad2f42ee8c4b0579bbc8fec6", + "eba71a3fabea4ab8a015fd4881ebd941", + "22dbe758a6fa450bbc73f65d4e599c35", + "dea744f73fb940988d4cb78d3aee3dc6", + "9e2fdfd32ff84406908df18eaff64e79", + "40f4bc1670064912b0fe82a19d979613", + "af1ca6261b1e421bafe3d839b43cfb15", + "42c9bdc4d27a418daa19b2d5ff690095", + "a50a3e4d28fc41dbb1b36032c29621d6", + "b5dd725f6bee4a41bdbeec3d3ca51cd2", + "276c92069ed044eeaad8eacef887058c", + "fee3f1e043eb4ee3b14fe68c0ff68804", + "fcd444c0e19e40f09ec612e8b68732e7", + "fce6f41ff39f4942b071d133bee3a1a5", + "69a33a97aa884e98be90b1cf87715cc2", + "e2571167e3d846e59769b61913f1de64", + "7e6709611ce2431ca35aef17cc0af981", + "4463fee420714c5cb6dbba7f938c5fa2", + "ce8e0cb54aec4949848a11bd94b97ae7", + "ab2625342f2c43fe8a383f8f9b4917ab", + "a1a4bc64ec224ba18208829f36a8d47d", + "961af2daa6344e4fba0c7a4c92ff91f8", + "e0312cf791da4abfb0bb66e446bcb9f8", + "e35b942ca87c402d8401cca544943ac1", + "3dd2cf55c1364c1ca4eb7d1543f0e89c", + "6c13df972c904b4b890087c592a4f905", + "5cfbbea6a52e42a5be74161462a9b823", + "72e578e1a62749dd8861b45f3cf2265e", + "4ab52d47364a433f8d16a9f595b67822", + "75af79cb707d48028cc85e657e8fba2a", + "cd0e60c7426441dcb6f59ca7f07473af", + "2c72fa9276ef4a5cb986397ce2fd9ab7", + "8bf24f1c4a3944d2a8e0f1ac7e8cbca2", + "9bef1038ad13459abbc1224beb01f48d", + "50e232096ee5475b8937742d5d35676c", + "7aa3c057efa6425a836a578b754c19ed", + "ca48e4c26516405693b34291c0f21e14", + "a3a6436253c244cca0c280b9b4026c4b", + "edba6260d2cf4a15bf4be7ca481b8c62", + "15da0ec38ef54a6ea9a62e444d1077b9", + "cc6e0fbce2704265b25b0ece37b453c5", + "7d7c48dd9e3548ff8a82c1ad5c6cbb20", + "7f36459d7f7b43548d56e63d899d7354", + "8175832c9f0f45559de7aff797940d3e", + "862bbf4daf8847618df614bad248cd3d", + "c188b9b11eee4c788a4c51e0e71abe33", + "302c2a1a4d9342f18acf2250cc99c04e", + "6af55ad721374ee38f2aae48f469e398", + "86aedf99c54e41079faed8609290c1b8", + "62bccb3b9cae4bff9b3d7080baf850de", + "8b2a6c17b6b640ee801b4048e8d6bb72", + "57396e794e2947c5b29c36c7d4764dc3", + "2a5d934f751842dd93c458cebcdbea4b", + "235b88889dce4b8c80375eeee45bcccc", + "93b01f3ac4e04bc6aab1c1e7404b04b4", + "dc412059597049e48d952fa4008555fc", + "130e6644c4d54e99ad3ef5163481ed60", + "fd831b815fcd4b6894d840adf460fb18", + "fe078f0b1b4e41c5af671c49a88bb27b", + "b06dab7a33ef4e51bc186272e19da9f0", + "154da6d5a31949129d209dd35c156f37", + "a2be177126644cb7bc7908740b2ff0bc", + "0aa48d7725c846f2a173f56448b5e148", + "77c957c8e7054cf4909472bfdaa04328", + "04540b11852b4c65bfe6c608c22641e4", + "6e69e33fff654cf896bf218e7c8325ac", + "5108735da82347739952d596a4fc2580", + "90d996fa29574fe0a10514d8f07f5a50", + "4a489bd2ebe84c97953410a1efe6f8e6", + "75fdc43a92d9469f8dc9176b56d75ba6", + "103b84e866904d69843f8cd3ed11bceb", + "ec36fdd6d5b743a1964bf34fe4effd70", + "57785575bce046049285859fcbbbcba5", + "f4f55594a2a744299a60a77c5b9bbe3b", + "a8c1ea7b3e844ba2a6299ccba466b23c", + "274bf0130e5e497990719d44c498ba00", + "889b64d83c244ae8857e12eec2744c92", + "68097329eafd41a4bd1d5f02c1926a72", + "cbbc7f89606d4b578f9d298a793e316b", + "970b7762e4594725ae00c011d9620400", + "c5bcfb2d53934421be8f9e8b407c2633", + "ed2b3ab21f174780ac09024f8f5f3381", + "be98f93cf1a949b7810af16618a48850", + "3fd7baa77b61400f87349811a796dbca", + "eb362329badf475ca683154b371f8c20", + "eea96944ec844f90b4f43139cbd91c09", + "a0aba9a22f6b49f3a7077396cf07f1a5", + "1204c7003a554471acebffc28248271e", + "197c895ef4d94a13b7beb2e8bf6b0ba3", + "02d029d007ec4b07a5a91cb8ec493493", + "6b4ab1eb046447f69fb514aece085fb3", + "250ffc764c0a47df9318302f008d30c8", + "2785d433c4944125b8ae9b801a7544e0", + "27e7637ff9c84479967618e9fef5d082", + "ad4a4b2ac1ab41f68f573f2b387a278e", + "f058995dd57c445a8e50030702a8dbc6", + "40d7491a077a4b4caa91794844f8d0b5", + "843566efd4464517a101d1c0dec94698", + "f8e991a5a44a465cb9997af2308f7a8c", + "133235b6713b4f288ad6ddae63a3d460", + "b9ef075241814f21bf98d3d85ecf42c2", + "80e7bc7c3a6848aa98318e84ec43b120", + "e0c549971e774aa8ab2ca67fc02d35cf", + "fe1e8b16f7c74f5ea2838eabe91ae92b", + "84fd98c561464b1ba5d3dd48ab161b9c", + "57d8083292a34edfba9e9c0af27b8dd3", + "8443ee8feeb740f094bbbe1eb629db36", + "86e0fb21f564469f96549e3f7393395e", + "687e906ba84e45f5929d57d2b644f6d3", + "353ffd3f3ab3479ea18bd9ed689d2358", + "623b78f05a1045a4b733bb56a5cac310", + "e322650be08b4024b7e7e7afce28f5c1", + "ee87869496e245bfb4e7e2b0b1339aa6", + "e89be0abe6dc4df5ae7121716a1716ec", + "85baaf5231bb4e999cb83def4d2e63a6", + "f2e9b40796e946518bc6ce1fbb31ad01", + "964fa8b171df41dd8fe6b1305da24812", + "2ab768304d0946dabb1662733e876bb9", + "be82f54dc95e4130b2803c10713686e3", + "5d3e1527bb6942bc9acafb783d54ad0d", + "e2e6dc756a5947f290b377f2931b6e61", + "025caf59ce094aa19bc6a2455fb9c7b7", + "9bc928c149884e0891c16be963c69f8c", + "e5184bb3bf2a455c8872e759bb97e13b", + "5e8221be8ce2493bb8cfd03a26942e69", + "4b7bfc85b73e4ab48fe09f9a739b79c0", + "4221e0d5bb7546778f24b0a6ba4b7277", + "9dd969f8aa0b41689aa28f7e4cdff5d0", + "2f31db3d679446eca15dd115119371d1", + "a2dce5767c2941988e3bd90e41ba80c9", + "bf841e790a1743fc950657d4db29353e", + "7eb8b5aaf4c642ceac82385635c37b94", + "7865c204560d416db00dd14467e4bd45", + "c255ea271b794bde8ccd7e77887abd3d", + "afc2693edc214c2b8607094993dad5de", + "e6871d08d03d4e4083cf4653fcd3744e", + "24966191cff0474facf8e56dcee453bf", + "5b1179db26874ccc84439b126cf42c06", + "83dd4e30036243b1b5e7b08b9de768a2", + "d6fe8a5e363f4e67b69a7052c4345f56", + "882d15e0d40046fb92c468a4db81e1be", + "27b6f2c33b4844f28f7bc663aa966bef", + "06e16069419242daa24a6ac7e3517aa4", + "582b841b0ad8431ab8d6daa2536f1851", + "1bbec1d9f9844c9ca5a86b78153a7b2b", + "908f4e160d8645038aa770ffcef3f605", + "5c4f8a6a24a940c5a534850879013201", + "bb52ae53bc8441d68dd912d1285e8511", + "91892daf06e04429be3b8f9c63e770ad", + "cbc3630e05e04f088a769bbb9e613f4b", + "ea77e76c3a2141dfbdc10ebe09061b4e", + "ba25d10d82a844b9af6fd135141955b5", + "df766528fc0a44eebfacf69d84001f4e", + "90b59b5185b14c52944573f236eb7175", + "6d594db7ab9741a7a0e0d8d61115926d", + "3651c329b15847268e6d155ad4ed9352", + "c19d1da1bd114f2d82d76ad149851fbe", + "c869dc1156cf4d0c8829787f9423a1c2", + "045b91b6257141d285c74a6bf1fceb9c", + "adf1d3bb56b549e286b1bfca928df98c", + "8ddd3cdb92d042e6879d1b5f1bed8726", + "fccbdc24b2f14616ae62c6d880cc7656", + "dd9c1d0087ae486ea98232c799c05846", + "bf1e66a733554a3cbd2d330260bae830", + "2c3ade337cb7454893669dd9bfea40ad", + "c0a1e0cd1c744f55b5c7df7e8f43eba9", + "271798cd680649e68be5958a7f1e072e", + "0a4234b6c2904978825282cf0cf7e616", + "7284a347f5c2435192b6e46484aefa1b", + "e6934ddb3982497e8ddb7936c56d089c", + "6613cc7fc0b948859303bc7dc0dc8847", + "09ca11888eac4a47914ab95d95a8b1e5", + "70416a5ece16478d8adf6f432277e0da", + "28147f8049894336abb243d022c910c9", + "437e50e2a7b441ba87d54392c39c0baf", + "bab7380b01094906b3dce44338f23237", + "3021153101a441989103550ebfaa2659", + "538b7ec077a4488c9e1151980f7064a3", + "21a4253e142345e8a43b128d2b3fb496", + "ad4378111a304560a38cc3b95d0c72a6", + "d938d2abefb84194bb48f0c4ff7e3702", + "c758b067bebd454da3cae34b621025a3", + "9193cd5a721944b093afd77b68093bc6", + "06dec00ebafe4c7fa88873efac4b587c", + "21cf6af4cb5a419ca00728253d290b3a", + "ab73f775a9374efc8d0f9f5ad112b9ba", + "1f566ba9fc09429a93e0faafbe3c2b7a", + "dc1af0a42c8042818c35de44fe79a615", + "7bc28b93cc364c97894215684b508313", + "4990f03cbdfa4c9d9b114b5637f24c60", + "b0117d56bb9b401f91442a1ce7f81329", + "bb34b711af314571a311b9186d570a39", + "34cdfe3cfc4f467bad8fb088a3949f3d", + "acf9c15a62584cfba1236f856622713b", + "a472667c9d46488fbd0a7404be4f4eff", + "957b170a1c934a2ea9c03fae7df57946", + "38e55b6a81b04502a8b199aec0d81828", + "637a36cb74204c719883af7feb4b7c28", + "f6e9f7ecb4784c81b26105f2567732d4", + "017c41aac5db41f3bfe2f7938a4834d1", + "8102032a85e34e1d9e9193e6149946f1", + "4cb1dec5f8a447079c2fed94bcfdbee4", + "847629266c0f442da74fb132f46f3baf", + "73eae40d79dc48bebc4a593ce5bce0ff", + "fbc9211966e548f6a7c62025d559d89b", + "7c9f1e277fb145ca9e92854809c9293f", + "deedab89816e4c31abefb1144c2b3c4d", + "461f6a648ae642a6aa0c2055400c8231", + "8522c1f3f87a425298067798a2c953f9", + "db4460e67e164cdcb33b0c3ba31c641d", + "67dcc56156aa4888b8aaa9a72cccd767", + "5feff566f0524190b510bee1f9760321", + "80b6ce3fb6ea418181ae2c5ff80d6776", + "0b0ea575968942ad9437579eb2fb94e3", + "05cd30c4b0784906b98276c1977dc4c3", + "1cfeb068c6b644e488d8a925a9f73046", + "0ed8532ab7db4e49bb630d568aacddd1", + "17f1f5a2990245cdaa4b4de417683613", + "6db334d133174099940e34706ccac451", + "dff1090376c54c96ba6663139bb6e198", + "f0d68dbbcdbb4e59bc8e690a58dee7af", + "296a053b72944d5780ea58bb3780064d", + "9bf7b9465aae4c61a2ab3ce07d0c3636", + "54d279b8d1b94864abd6987912d73741", + "35834fb2bd1647eb944d87219d1a9c1a", + "7687258d72fe42198b021fa63b6b2ca7", + "9c83657183904b31b6fcc1a33cf34b23", + "dde5b1486e994857861da6c0b9ef65fd", + "6b97d631e6084f94993bc94a471ca37c", + "52ebceafc8af4f2ab527e9a5a454998f", + "63622389aeab42aaaac37f956cdacdd7", + "611a450da7be400dadaf7c56aee402ce", + "1c5c0905f9f34b939309cff3ecd00870", + "aedb9509ef9347a5b055e02deeadeff7", + "2cb267748c1944d296c942ee537a3175", + "46aeb0303b854ba5a26dc73bcbfbb556", + "bddc50837de54c9e901229a7a7cd62a9", + "6a575ec757024924b9844d85f3afaa1e", + "32285d0de78b43b18defffcb3f647f37", + "f1592cef6d3c4d88ac07436f1cc8fd0b", + "1f5a007441124311a99d1f6156cb17f7", + "df2d8c79afdf4f6981cebb859351ac77", + "dae653eaaf7349469269c45047a80a27", + "83410495fe7f498c96c752c04ae1da23", + "1c0092759dfe4182b952080ffd404071", + "fc4cb15fefb44f23bb6b0cd2e8aa1609", + "b5daef21a1d14cb0986772b621627f31", + "10450e17f2dc46d5ad21ef0dd1d46166", + "f683c0dfc3e34320a1c4818891818021", + "06bf1edc7a7b4a3486dae576df1e9121", + "92386c23092240a9b0948867ca88aebc", + "d1e67b3479cc4f058eb3a7527b25d063", + "bdda2234bae0494995faedf33f434de4", + "e192766a610f4198834c9ee28bd1c27e", + "b7a9a04e62144bdc85d5580e594b0b22", + "16aef9b49f3944298d2ada5a6896691e", + "05efc9f676bc4e21a928cb8f2ac01bac", + "341b1485ae0d4e2b9ac030e5d332aa78", + "11651709717d491790987d9eeedeba4f", + "5cc60a924f2d4f3a825d3db21ff94613", + "a73301f65789445dbe146e2f34d83c93", + "d8072e417dbd476cadb270e39ad3d7c8", + "af4f3ed2e6df438c9c0a90e2ef7a7f45", + "4abb06a66fc14582ad0e0ec3951fcdd3", + "5b1307a11309451294ef38bb83a6f9cc", + "708f83d6fce940c5827cfd6ce942004d", + "50c2cd64486b407fbd07930ef7f2762c", + "1d7a66437c954638b69bbeefa774c4b2", + "c40d63d5d740405e91c7f5fce855076e", + "30b975722e7e4d8694ee9628cd669177", + "ba4ce43f7b07459b862eae024a6b0c82", + "fd0319678b484bd892eb3c9690785d78", + "09c0e8587a1148548a85014c34ee76c7", + "c10e207b60ec451fabde91c17d4cb2ac", + "bfcfe02939e34c91bf99deeaea6b5ee3", + "c8149928cb804b63a8cd39c5a5525c7c", + "4f6c9dcddd4d4dd1b0dbffab442b9c57", + "b988cea27d5840159761cd9320bb038c", + "c9a9bcb741164b008b07001488245b03", + "516dcd06fefe4b8d8e7f76d08ad6c774", + "afa5b6ce0490496a9394554b11a8e7a1", + "bac9fae881b84b0398ac6df01b72d25a", + "7b6d6f3e6bb34ef0a10c950f859d23f9", + "54c466359f8b459dbccea0168ea01c85", + "770db8b1bda8412096ccbcc4c000d751", + "f726d431a4a54ce0a82fb41a258628b7", + "dcb0d1c9b8be49e0945535fdd81c7525", + "15a583ac9db84a529e7ea1d2bd7eadbe", + "beb3aa19412246709a7bcdc2812cc4d7", + "7e575d53501a4a8ca80258bb13a96da7", + "5f3f49fa73884474a6a22ea872ad084b", + "fc7cdaabeb7749ec92d5fe3e71d97478", + "5c019bf89c544987b0ce6643f73a41c2", + "d5c902837556422c9eb651b2ef17abff", + "94dc57e2257244c48f801037e0b51b79", + "b15c4da4566642299f691ce89c473b15", + "7c5f400773d940cdb2bc6884c990e888", + "77b77ae1801e46af8abf4270b539210f", + "b2737ba987794081bfb9cebc6aa6b55e", + "c4fd2873ba1045cc9c8dfab4a1636aaa", + "57673b1e1e3044fda4d562cffdc1c965", + "f0fecb80afa243cda158bed844919846", + "fd61a0b52cb34e6dad584d3573bfcb09", + "0451ff98eb334c63a8190aa0b2a27313", + "ae3e519e3c7e4295bc77f437c3420be4", + "ce3f12895c374078bbe26df8b974d923", + "a2a2b1ce779d45c0bc8e058da08a438a", + "b5cae55032a94d098dcbeb863f33b27f", + "3a59856dddf04843bcf56d6dac2b8759", + "3177fdf2630c4922a43fecb876d96e1d", + "681a9c2f13f1478d95464de4c237b802", + "6e74ee87e8a94e70ac369dbb2d53b0ae", + "fc9e7e512a814025a60dc33519d049c0", + "b9d8bdff87814ac395c3a1943ee39ce4", + "bfef56fb285b40f683edfac9da38af8a", + "7a99e7a401ae4fa8ac96cce6450ebd69", + "f55d42dc491c486987b9884357401e10", + "a08875e41e9f4aa99de5f636e644c9e1", + "90fd75b96c624d7fb641045c3d3430e9", + "4e2dc4bfafd84ff48625ab8b2e42049e", + "d68dbcb779d04b64ac2df797e562c908", + "15b2ebce6f084c3ea8d582c168ff478e", + "af186ba73c8e44cfa63001ac17e08a4b", + "bbeed04b81474c1f8d72a4fdfeffd538", + "6c34e43b6f01492b9d336e4228deee62", + "46ce33100c39420aa22aa2ef263dba3a", + "dffa451e9a70420e80662e52d23ccb1e", + "68dff75bd52345a296800686ffa95eb4", + "e4dea23c40fb40ffa6a54d89913f3e9c", + "80c695a82cb34f39832b9585c965d923", + "4e284327d14047d880ae5ad74f73da35", + "7f10ef845b594690bff6cc5dc21c3f99", + "ac923a00b7f7479486fa1ef4cecdfd76", + "3269b8399110482cbf6bab889e70da25", + "3b05e5f9fbc14ba0b5b03e9fdf9c2c6f", + "614958bb98064d71bfae72b76896b84b", + "22b533839b8d40459615e517e7f435a8", + "8f275bd4aa5e43adb5dfef96eb015099", + "f0a50d4d635d4eb28088ba65c5dfb175", + "ad05029a921243c880b31f218483a91a", + "9d24aac8a4c444a1b440647aa6f96438", + "1d293cf048574b52bcced8d9b85116d9", + "6e444e52e656441d82394022f27053c4", + "b5702c673173484c99dd29816ac17ed9", + "6f2e81345f3042bfba020ef7579196b6", + "0e1ae51d32784728bb61d3f24e78573e", + "db80ace4988944d6a10298bb1dd9ef6b", + "370dec16ac1043218588b07d887acfb8", + "dfe1cf7e49184529bddc1d22dc985d65", + "dbc29ea919e24504b933a85d464a8f44", + "4808cdc0863346309c06dff414326c1e", + "9c83100af67842618427560b7fc2580b", + "f69952ac65ab4d8391b85736453a82f4", + "afcf3a0143f04f219fd1914fc0baef3f", + "be14535020724c3ca3328ec9e271ee0b", + "b85a2aa933e94f6786cef691aa42adff", + "1c94748821704dd09de0bf973f5abb5d", + "bf5a8c7e6935457882f5e9a5dadd0ecf", + "f15fb86d99564454a9e34d8bf8998885", + "4986a9bad50e4c04925316ec9cf4ad12", + "c1c9fa8a17b84e50b023794da5206a82", + "f8a0f212a4984f30a5724b5c1898d2d5", + "4bdcd84ae6864249af3171fc6af8b792", + "9356465e321a4d1a86cd39ee2ac5fd16", + "53a7952a10d1481bacfae775882d03f2", + "5191973a4996431e8f4055e4f8a75101", + "f50cb1f2e7c34d10919843e998e051cb", + "001d1b57e9df4273bede948b26429429", + "2d2e56a096a443e18074674deb076350", + "f96a1bf05acf4b5fb7abce383f748160", + "45bccd8afa834e84b690fb91e34f9262", + "126cac1ad45c47b6a91cbfea0baab9d0", + "b17717dc9c95477085b5ffe3f64d25f2", + "d6affe6e51354247824b8163d825659f", + "dd718e79655a4eb2ac5dba666bfd61ba", + "29a82673d9304ed3ad586ff43062a9f9", + "50faa76f94a3470ca68ce414c2c4eb12", + "8764c14c64f84bedaf6926ddd79a3bd0", + "c44c221824af4523bfd37a3cb5257979", + "e26fae6fe0b34fac80d6c3ec91e3d031", + "fc87b71b4385435dbb7c9056ee97e614", + "6b1099b97cec4d22bd11fa6b119b5d37", + "6dc3eff5252b4c208133e7fb9769b3b3", + "b13f9b0f47d94b17884c995ce4e3ccc2", + "9e18b3a1d41e458ab38c44c336e2841d", + "a22031e23f5d44258962759ab530d1fa", + "5422829738d64b5e8d599247ef2ed297", + "c8b416221569445382a3a0f3bcc792ec", + "467054cb138243298b97651aedfff0bc", + "9e89d5052f134ddea1459d376d850fa2", + "bc0a750b8363472e80eaa5881655ed23", + "ffd55e32c04c498681ed11584bdd49a5", + "555bf3c9d3aa4d3f8059ae31a23efa57", + "f8e67bafae6f4f38a45619edf080b8c8", + "062f472c5b2941bda2c498e489d7c207", + "803c646867dc44118210dbdbebfaf191", + "1bbcdb1d6dd34bfe8c9176ccfb7d5c3c", + "c07e8eb8f6c043e19b329fb74557bf2e", + "f0dbcaf76c83422c8890360fbccb7740", + "49c0eb22f12c42fa9dafb404ce223591", + "4493602bc41e482a975482c1830f77fb", + "44d5052c398248ddb3e4d521cae035a9", + "dbd7ac16d05c4accb4b7eb9093ab04f9", + "1729f88420514484bd0ef25a9e8cba5b", + "6b5aa037654c44eeb205543ea6486ed0", + "d94edeadf54e4824bcb04536aca4e140", + "42f05f33f0af4ab28d59593f86c0f5b9", + "034e769620ef440785374eaa6d7feb24", + "fbde233657574586aa5e8fe83b2f4675", + "57766f8721f24d368e531768349a5487", + "02dc97bdd42b4ebaac170ae0a75bb030", + "7efbe7e79b024764b3dd78e2c229b0e9", + "8614a5bcdcdd4f1dac9c76801a9c6bbd", + "1d41e84fd76241e7a8929a314052269c", + "335f6bcdd430412290561746a70bf421", + "9cb753e6285d4fb19b41f834aa7dd9ab", + "685ae71072744c459e74d9e7a17766a0", + "996639d18b72453190315b0bca315e97", + "c8a87c284e16437e9aef062cd8bb4119", + "582b46a2e22a4154a3070cd3a272ee50", + "92abcd8140fc4ef9b23efc6a5d6b4061", + "1a58b4a8b48b477e9449a622a4aa2be2", + "fb476739960b4ea194beaded86abe44d", + "d1bba038b5b244178cc0a6fb4796bf78", + "326552478ff54528b7c43954f6e950a7", + "959d5351cb5843d3ad2b2c169da63b90", + "aaf24cdd7ad84e45bd30a9bc3333de34", + "3c63c11d39ff412aae97af755ef445b1", + "d075feb7b0d941df81f23d8df4369ce4", + "84e9932dd0274af3a2ad91f779b58cf0", + "f33b5951360e45078fc7fd749bca7409", + "427ddd9df9114262b26a6503dc7991d0", + "f0c5c875161242a2977996cef5113dd6", + "68146b83617743b69060020d5882017c", + "791b5dc308f242e2ac730f7433e1d545", + "32213bf1847c403d8129588e53075b90", + "45b837210c1848f2b2daa3adb31337ca", + "e5edb72a961e40fc8572263eb42c8ae1", + "75995414661f47afa027457a0074b67c", + "88de35621a854e29a1b01ede2342d981", + "1e8296b489084d6ba76b485d1c2fd37c", + "249b018655d5490aa42cae25b3e0e5cc", + "be5595aa7e0b4aac8d92f4af0aab66b6", + "91bb386ac8984da5aee02d0632e4da0a", + "bc708900ae034c84a800567620e7eca2", + "9a5f0ba304d04497b6382da6377d8262", + "1337fce7e3b4489fa95c868225f73bba", + "2bccc1882bc9429bbe6a23990b4809d3", + "43671c36a613433f87b54cbe4e9c1ecc", + "b6d5cdb0a41340e0bbb27935ec4b955f", + "a83e1baf822a4442b0f50ed70d449198", + "108d7511cb564ab98efa1cb2f5fda7d1", + "344bb30c8c02401fa0bd21e5be84eca9", + "a59fe366e3dd4161b45b1817693e98b4", + "5807551b2fdd4f58b4ca7800b3a9febe", + "ea2a8f4ddbc749a4ae6cfeb70285baa7", + "e38557286d5b41049dc972ccc5bd7e39", + "63cf7909e5ef44c9966b6a1f6ceb4752", + "850b0ae1514247aeb069eb1d63738ff0", + "e6d905eb061c4035a9388536a88b8e7c", + "b19cec050c5347509c0dcd0e28ff30a5", + "e7ea8f4837354f6da7e4c4c9ee986ff1", + "56281ca6acfc4eeaa4af6e9649c7ab94", + "37726177b7d04f258c04eeb6c966e2e0", + "829e0fc85ec244eaa3d86310f6ef0150", + "629cd7e55be145cf8fad5735af63ea33", + "e9c627f9d5b14f3a8e53569b266cffc2", + "f71bb7af17f541708e9121f5a5a5b433", + "349a1d0c2d7b4b118b2f0a6d89704446", + "813f5aeef3f3430d947f3879c6941719", + "bba356a4e5d348e7839cc9caefac67da", + "0b80a14d9b454127ad80826551bc4d1c", + "5fefd235b77b4fb0a6bd5db14528d610", + "447463bb239748eca530e08ade2076a3", + "f5012f3d6ba54c2aa142d35bc8a00ac3", + "35bf247a88ce49c2a2be1af65279e374", + "21a7fd7502cd4c31949b6784dfcc4813", + "d2d85c3b86c243ef98ff587538e740c3", + "3343ab37925745f4ace15c17db21588c", + "0b716e33ffae462d818c957744f7ce17", + "a221e8934451486ea0c43bae862ff774", + "c7b5105792114b438fefe4a2e0c08d2d", + "525b9ac74fcd4c67a53a529f8aff4121", + "26587b743d2b460a865df2a69f4692d9", + "e56460239f2a465bafae891e1f3d694e", + "f0b7ca0f694c4213b799677e49041896", + "e7cdfc6c96e34f64b5e953bd534f4290", + "a3d61c47a454469ea55207ad8a1d0a91", + "9bfa66328d274aa784d0e2eb26b4ddfd", + "1320959ea88c445fbe3add44e02411d3", + "9867dbe105ff4e47a4a896e45f7ec194", + "25eeb3229c6b4d9485f5593d296f0afa", + "661a23e81a5342d1a8225bf078d5c028", + "73551aa6ade44f5fb396f437a2f8ac52", + "e4cc5e8b95b64fd5a4002efa28e8a50b", + "03474c14b2f046cab8c6271a1a013bff", + "5fef1dcae7dd40b18cbc3bc3a0085fad", + "1b22e19ca1d84951810f87a01fabc6e7", + "37457e13fac14c8ca12e3f7cc4d9efdd", + "b45a8a265434477a92087d0446c6db0e", + "65f03d139d3b442eb39292e4bd63a081", + "b0dbf778b81e4afba4edf11336e2a099", + "395ec8747038411684f9aebe6aa55501", + "ffb91bf23e564a8e845a4195dbc2aade", + "f6ca8fb964e64563b4c9960cee0f1590", + "2c51399de3d3439383dcabef349d72b0", + "d9698879bdb64e909df747e5a507aa53", + "f59bd69bd06b4c739f2471334384dc09", + "e43c904708844579896bcb31f4416726", + "1608fc9924344b529d71a66f2560fcd3", + "989876ca437a4effb8911fa52c0adb6a", + "626cbc01b17f49e2bbf8b0a286ffa0ec", + "94fab933b1474c8a8243c1c9d496a874", + "d5ed1efe62cb469084ca6946616035e8", + "24d1b493899d407780140688abae19bc", + "5f7c08cf173042fba0f57528ced82d85", + "6550002c76424ba98eea688dfff6fe8d", + "80928bbaf0864dd985d744717d2c887c", + "5becb229622042299aefb9f70f2a16f1", + "49c68a09a3ae4eccbf6990394e1b335c", + "6b8f2583e21047c886ac4df567b2bf5f", + "e0fed94af7104e5e8e72e0755042619d", + "7d70ed97202c430b8a124a99a030b36f", + "2c1c0b2a69f14c3c98b32d2119ca7653", + "a0216d3d531d4fe58fed2ef751000751", + "0d9f7c9353fa4596984e264e0ecf2067", + "f853023c58314654886fd9f12d2b7253", + "988a6e8067f846fab40b898a30df8d61", + "a0b89558829b45b9bfa4aa4083270c09", + "df5839b1bc7243fa97c3a13d18300002", + "35ef97c025e245d190b72a4419d5689b", + "f436b41f927941328b9cac832afae3e9", + "b2f538bcd6a44b67909f07cb8d0606f5", + "ae8965f525ac4521a3a5cdafc396101e", + "8d876a5df7ca40f091468c0b4cbce32d", + "a3d09afa012c4b2f8d06f49dff7af187", + "06f26c0afd10487ab66c448a04543110", + "a9e995cb9c5d4092afe8b2a05a04c1dd", + "f70efb72e2a147c0892be3346f821b41", + "d9c061979e9048dab4f780ff70337d9d", + "f9fefc5901824d19a7f56d3aeb8a7bc2", + "c6b09dc6d3814baf9466b5fdcce49d61", + "f6f2c4d0531046c7882855f9294b85f8", + "e7e55a94f3ea428f983ca688af432cb0", + "2458f980cf584c45a130df3fc39d47ff", + "abc35c5c30fc44c282188c3065a6daf0", + "1b51966a989242278b502c91a49e7adc", + "994aec4131c243dfa4cd2598e79eabaa", + "d2e2be34be9347cd854a34fa85487123", + "e392cd449282411b9e1985401ddd9c8e", + "d968ed8ee5d24c8e8eb6338a2d1af88a", + "5dda44f9dbbe4a238f7112303f8b9957", + "e4dec517cb3040d9a21decf2122507af", + "eae19856cb164b0cb2abddcc2e3ae3e9", + "89b80aade5464af29e6b6b98cbd44e03", + "ff5ff2a5b6784180a050a3c142ada9d5", + "9bcc9cda7b4d4db79ee6d7d105207f3b", + "3528c98382934f89be875c275f253e45", + "55f48e1d7ca14780900e27dfe1721bb7", + "fd16d37c66b34d0981cab82cc9881f77", + "35357e68cac1416a98c041b15c37365e", + "8ecc773bb7dc464880b202a114db9b38", + "58c973e1bff6400c8a568ee19753cfd8", + "f890e8bb091e48c6b8c217a77299e7c4", + "62a75d46919c4525904cc22c58b09eda", + "4c41aef7dbdf455b8b8edaea8f520fb6", + "414e34d317264e81924dcdfdaa955596", + "bd9bcf6ab77f4a39828badcde3705bc5", + "add75f0b8e424380a97b0a1cc3dbe162", + "f7afba1d4e91459e8c60237df5aa1a70", + "7b6c0297b0b3447b88cb76b141be36e2", + "d4ca4774cf9247d9bedcafcd202169ce", + "c70e8817b5a945aca8bb37e02ddbc6f9", + "9e78d9b0aba144fa8463fa0135f2da80", + "285af8e962924feca3d1dc61550aa716", + "f10262e2a822456dacd90a9879c77d82", + "9fce05a0a405405e9aac35a1883c3295", + "dd84fda383ec4b83a665075d16488d79", + "1ad1f9f5db1a4cc98d231705fa2a5661", + "0ee61dc73b724bb2a34109bd0f3d59c0", + "0d2dd8a6156245bbbee8e15d22a89157", + "f4254659e66c4ddb9b7973d51b05e8c7", + "c8c26f18c26a44d89fc09299907a38ce", + "750ac13000e445bc8f658434c65a6d9a", + "f0cbb596b0f54d0bb461daa675b4386a", + "20ade64290a644148ff144c240da50d9", + "ece1536067ba4fa0ab6a28b22ffea280", + "48a5a92a52ee4f51b241d7ee27ef8c8a", + "a87456d11f424ade9cc8c1e1c9cf6c95", + "0c1f3eb0ca00451fa6531f9ccf845904", + "66f44a0ca63540b0b55af063abf24078", + "463ad80621de403dbf66b65c966a6e2b" +] \ No newline at end of file diff --git a/apps/third_party/Wonder3D/docker/Dockerfile b/apps/third_party/Wonder3D/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..2c02ea6197ba7cdba746089e8eaf4784d640faec --- /dev/null +++ b/apps/third_party/Wonder3D/docker/Dockerfile @@ -0,0 +1,56 @@ +# get the development image from nvidia cuda 11.7 +FROM nvidia/cuda:11.7.1-cudnn8-devel-ubuntu20.04 + +LABEL name="Wonder3D" \ + maintainer="Tiancheng " \ + lastupdate="2024-01-05" + +# create workspace folder and set it as working directory +RUN mkdir -p /workspace +WORKDIR /workspace + +# Set the timezone +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get install -y tzdata && \ + ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + dpkg-reconfigure --frontend noninteractive tzdata + +# update package lists and install git, wget, vim, libgl1-mesa-glx, and libglib2.0-0 +RUN apt-get update && \ + apt-get install -y git wget vim libgl1-mesa-glx libglib2.0-0 unzip + +# install conda +RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh && \ + chmod +x Miniconda3-latest-Linux-x86_64.sh && \ + ./Miniconda3-latest-Linux-x86_64.sh -b -p /workspace/miniconda3 && \ + rm Miniconda3-latest-Linux-x86_64.sh + +# update PATH environment variable +ENV PATH="/workspace/miniconda3/bin:${PATH}" + +# initialize conda +RUN conda init bash + +# create and activate conda environment +RUN conda create -n wonder3d python=3.8 && echo "source activate wonder3d" > ~/.bashrc +ENV PATH /workspace/miniconda3/envs/wonder3d/bin:$PATH + + +# clone the repository +RUN git clone https://github.com/xxlong0/Wonder3D.git && \ + cd /workspace/Wonder3D + +# change the working directory to the repository +WORKDIR /workspace/Wonder3D + +# install pytorch 1.13.1 and torchvision +RUN pip install -r docker/requirements.txt + +# install the specific version of nerfacc corresponding to torch 1.13.0 and cuda 11.7, otherwise the nerfacc will freeze during cuda setup +RUN pip install nerfacc==0.3.3 -f https://nerfacc-bucket.s3.us-west-2.amazonaws.com/whl/torch-1.13.0_cu117.html + +# install tiny cuda during docker setup will cause error, need to install it manually in the container +# RUN pip install git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch + + diff --git a/apps/third_party/Wonder3D/docker/README.md b/apps/third_party/Wonder3D/docker/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9c88d6aace3688d5db09ef7080118dff74b279d1 --- /dev/null +++ b/apps/third_party/Wonder3D/docker/README.md @@ -0,0 +1,57 @@ +# Docker setup + +This docker setup is tested on Ubunu20.04. + +make sure you are under directory yourworkspace/Wonder3D/ + +run + +`docker build --no-cache -t wonder3d/deploy:cuda11.7 -f docker/Dockerfile .` + +then run + +`docker run --gpus all -it wonder3d/deploy:cuda11.7 bash` + + +## Nvidia Container Toolkit setup + +You will have trouble enabling gpu for docker if you haven't installed **NVIDIA Container Toolkit** on you local machine before. You can skip this section if you have already installed it. Follow the instruction in this website to install it. + +https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html + +or you can run the following command to install it with apt: + +1.Configure the production repository: + +```bash +curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ + && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ + sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ + sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list +``` + +2.Update the packages list from the repository: + +`sed -i -e '/experimental/ s/^#//g' /etc/apt/sources.list.d/nvidia-container-toolkit.list` + +3.Install the NVIDIA Container Toolkit packages: + +`sudo apt-get install -y nvidia-container-toolkit` + +Remember to restart the docker: + +`sudo systemctl restart docker` + +now you can run the following command: + +`docker run --gpus all -it wonder3d/deploy:cuda11.7 bash` + + +## Install Tiny Cudann + +After you start the container, run the following command to install tiny cudann. Somehow this pip installation can not be done during the docker build, so you have to do it manually after the docker is started. + +`pip install git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch` + + +Now you should be good to go, good luck and have fun :) diff --git a/apps/third_party/Wonder3D/docker/requirements.txt b/apps/third_party/Wonder3D/docker/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..1de9e2dfcc6ab57234975f9e8d289d3626592f05 --- /dev/null +++ b/apps/third_party/Wonder3D/docker/requirements.txt @@ -0,0 +1,36 @@ +--extra-index-url https://download.pytorch.org/whl/cu117 + +# nerfacc==0.3.3, nefacc needs to be installed from the specific location +# see installation part in this link: https://github.com/nerfstudio-project/nerfacc + +torch==1.13.1+cu117 +torchvision==0.14.1+cu117 +diffusers[torch]==0.19.3 +xformers==0.0.16 +transformers>=4.25.1 +bitsandbytes==0.35.4 +decord==0.6.0 +pytorch-lightning<2 +omegaconf==2.2.3 +trimesh==3.9.8 +pyhocon==0.3.57 +icecream==2.1.0 +PyMCubes==0.1.2 +accelerate +modelcards +einops +ftfy +piq +matplotlib +opencv-python +imageio +imageio-ffmpeg +scipy +pyransac3d +torch_efficient_distloss +tensorboard +rembg +segment_anything +gradio==3.50.2 +triton +rich diff --git a/apps/third_party/Wonder3D/example_images/14_10_29_489_Tiger_1__1.png b/apps/third_party/Wonder3D/example_images/14_10_29_489_Tiger_1__1.png new file mode 100644 index 0000000000000000000000000000000000000000..866827c406fbf3b05e76ba369e45056f84e945c0 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/14_10_29_489_Tiger_1__1.png differ diff --git a/apps/third_party/Wonder3D/example_images/box.png b/apps/third_party/Wonder3D/example_images/box.png new file mode 100644 index 0000000000000000000000000000000000000000..a254ff1f569342342d70c7ed6e4b922dadf40274 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/box.png differ diff --git a/apps/third_party/Wonder3D/example_images/bread.png b/apps/third_party/Wonder3D/example_images/bread.png new file mode 100644 index 0000000000000000000000000000000000000000..5814a3d1c69d9758da1a873ef4d5c6cae703c340 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/bread.png differ diff --git a/apps/third_party/Wonder3D/example_images/cat.png b/apps/third_party/Wonder3D/example_images/cat.png new file mode 100644 index 0000000000000000000000000000000000000000..3090618ec3b414dafba3d6843bbb951b41cb4356 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/cat.png differ diff --git a/apps/third_party/Wonder3D/example_images/cat_head.png b/apps/third_party/Wonder3D/example_images/cat_head.png new file mode 100644 index 0000000000000000000000000000000000000000..411fcf61ebf276dcc1de6ab971d1b70ab8fe84ab Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/cat_head.png differ diff --git a/apps/third_party/Wonder3D/example_images/chili.png b/apps/third_party/Wonder3D/example_images/chili.png new file mode 100644 index 0000000000000000000000000000000000000000..5af023cdccf295b7d521082b0aef59ce713f9460 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/chili.png differ diff --git a/apps/third_party/Wonder3D/example_images/duola.png b/apps/third_party/Wonder3D/example_images/duola.png new file mode 100644 index 0000000000000000000000000000000000000000..bd93331c4e9b3b7923d0e8a311e1d3f4e5a541c4 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/duola.png differ diff --git a/apps/third_party/Wonder3D/example_images/halloween.png b/apps/third_party/Wonder3D/example_images/halloween.png new file mode 100644 index 0000000000000000000000000000000000000000..7502e0346e7932e53c670b772d361b026350a1ab Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/halloween.png differ diff --git a/apps/third_party/Wonder3D/example_images/head.png b/apps/third_party/Wonder3D/example_images/head.png new file mode 100644 index 0000000000000000000000000000000000000000..373031cf8213279baf82ad79a80cdf4793081d99 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/head.png differ diff --git a/apps/third_party/Wonder3D/example_images/kettle.png b/apps/third_party/Wonder3D/example_images/kettle.png new file mode 100644 index 0000000000000000000000000000000000000000..de8e12d3ea2ed63a50864879360fb59a93fe4698 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/kettle.png differ diff --git a/apps/third_party/Wonder3D/example_images/kunkun.png b/apps/third_party/Wonder3D/example_images/kunkun.png new file mode 100644 index 0000000000000000000000000000000000000000..806c188eccfe9b2ad787d83ec979eee09a813127 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/kunkun.png differ diff --git a/apps/third_party/Wonder3D/example_images/milk.png b/apps/third_party/Wonder3D/example_images/milk.png new file mode 100644 index 0000000000000000000000000000000000000000..fc8821b09b7e05ed225bc198a22c697a585a00c6 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/milk.png differ diff --git a/apps/third_party/Wonder3D/example_images/owl.png b/apps/third_party/Wonder3D/example_images/owl.png new file mode 100644 index 0000000000000000000000000000000000000000..e45915d836361924ad75e581eaedf449df7b11e8 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/owl.png differ diff --git a/apps/third_party/Wonder3D/example_images/poro.png b/apps/third_party/Wonder3D/example_images/poro.png new file mode 100644 index 0000000000000000000000000000000000000000..98f5e9edfe23cb4de383835268efb369121db75f Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/poro.png differ diff --git a/apps/third_party/Wonder3D/example_images/pumpkin.png b/apps/third_party/Wonder3D/example_images/pumpkin.png new file mode 100644 index 0000000000000000000000000000000000000000..cc0f090df656f7290e968f262fc607f826d2c3e8 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/pumpkin.png differ diff --git a/apps/third_party/Wonder3D/example_images/skull.png b/apps/third_party/Wonder3D/example_images/skull.png new file mode 100644 index 0000000000000000000000000000000000000000..c03a28f6128884af63b478d3e7162bc3ef952f21 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/skull.png differ diff --git a/apps/third_party/Wonder3D/example_images/stone.png b/apps/third_party/Wonder3D/example_images/stone.png new file mode 100644 index 0000000000000000000000000000000000000000..91e2b33940e029ff29c14e7fa59a9473cee1878f Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/stone.png differ diff --git a/apps/third_party/Wonder3D/example_images/teapot.png b/apps/third_party/Wonder3D/example_images/teapot.png new file mode 100644 index 0000000000000000000000000000000000000000..1f13a6edfe67ced810b4513117279067f0360fae Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/teapot.png differ diff --git a/apps/third_party/Wonder3D/example_images/tiger-head-3d-model-obj-stl.png b/apps/third_party/Wonder3D/example_images/tiger-head-3d-model-obj-stl.png new file mode 100644 index 0000000000000000000000000000000000000000..009efbe7bd143682803e64b5042cd88cef555c12 Binary files /dev/null and b/apps/third_party/Wonder3D/example_images/tiger-head-3d-model-obj-stl.png differ diff --git a/apps/third_party/Wonder3D/gradio_app_mv.py b/apps/third_party/Wonder3D/gradio_app_mv.py new file mode 100644 index 0000000000000000000000000000000000000000..930218d453d2a70561f29a12f827a5029eb466d5 --- /dev/null +++ b/apps/third_party/Wonder3D/gradio_app_mv.py @@ -0,0 +1,439 @@ +import os +import torch +import fire +import gradio as gr +from PIL import Image +from functools import partial + +import cv2 +import time +import numpy as np +from rembg import remove +from segment_anything import sam_model_registry, SamPredictor + +import os +import sys +import numpy +import torch +import rembg +import threading +import urllib.request +from PIL import Image +from typing import Dict, Optional, Tuple, List +from dataclasses import dataclass +import streamlit as st +import huggingface_hub +from transformers import CLIPImageProcessor, CLIPVisionModelWithProjection +from mvdiffusion.models.unet_mv2d_condition import UNetMV2DConditionModel +from mvdiffusion.data.single_image_dataset import SingleImageDataset as MVDiffusionDataset +from mvdiffusion.pipelines.pipeline_mvdiffusion_image import MVDiffusionImagePipeline +from diffusers import AutoencoderKL, DDPMScheduler, DDIMScheduler +from einops import rearrange +import numpy as np +import subprocess +from datetime import datetime + +def save_image(tensor): + ndarr = tensor.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy() + # pdb.set_trace() + im = Image.fromarray(ndarr) + return ndarr + + +def save_image_to_disk(tensor, fp): + ndarr = tensor.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy() + # pdb.set_trace() + im = Image.fromarray(ndarr) + im.save(fp) + return ndarr + + +def save_image_numpy(ndarr, fp): + im = Image.fromarray(ndarr) + im.save(fp) + + +weight_dtype = torch.float16 + +_TITLE = '''Wonder3D: Single Image to 3D using Cross-Domain Diffusion''' +_DESCRIPTION = ''' +
+Generate consistent multi-view normals maps and color images. + +
+
+The demo does not include the mesh reconstruction part, please visit our github repo to get a textured mesh. +
+''' +_GPU_ID = 0 + + +if not hasattr(Image, 'Resampling'): + Image.Resampling = Image + + +def sam_init(): + sam_checkpoint = os.path.join(os.path.dirname(__file__), "sam_pt", "sam_vit_h_4b8939.pth") + model_type = "vit_h" + + sam = sam_model_registry[model_type](checkpoint=sam_checkpoint).to(device=f"cuda:{_GPU_ID}") + predictor = SamPredictor(sam) + return predictor + + +def sam_segment(predictor, input_image, *bbox_coords): + bbox = np.array(bbox_coords) + image = np.asarray(input_image) + + start_time = time.time() + predictor.set_image(image) + + masks_bbox, scores_bbox, logits_bbox = predictor.predict(box=bbox, multimask_output=True) + + print(f"SAM Time: {time.time() - start_time:.3f}s") + out_image = np.zeros((image.shape[0], image.shape[1], 4), dtype=np.uint8) + out_image[:, :, :3] = image + out_image_bbox = out_image.copy() + out_image_bbox[:, :, 3] = masks_bbox[-1].astype(np.uint8) * 255 + torch.cuda.empty_cache() + return Image.fromarray(out_image_bbox, mode='RGBA') + + +def expand2square(pil_img, background_color): + width, height = pil_img.size + if width == height: + return pil_img + elif width > height: + result = Image.new(pil_img.mode, (width, width), background_color) + result.paste(pil_img, (0, (width - height) // 2)) + return result + else: + result = Image.new(pil_img.mode, (height, height), background_color) + result.paste(pil_img, ((height - width) // 2, 0)) + return result + + +def preprocess(predictor, input_image, chk_group=None, segment=True, rescale=False): + RES = 1024 + input_image.thumbnail([RES, RES], Image.Resampling.LANCZOS) + if chk_group is not None: + segment = "Background Removal" in chk_group + rescale = "Rescale" in chk_group + if segment: + image_rem = input_image.convert('RGBA') + image_nobg = remove(image_rem, alpha_matting=True) + arr = np.asarray(image_nobg)[:, :, -1] + x_nonzero = np.nonzero(arr.sum(axis=0)) + y_nonzero = np.nonzero(arr.sum(axis=1)) + x_min = int(x_nonzero[0].min()) + y_min = int(y_nonzero[0].min()) + x_max = int(x_nonzero[0].max()) + y_max = int(y_nonzero[0].max()) + input_image = sam_segment(predictor, input_image.convert('RGB'), x_min, y_min, x_max, y_max) + # Rescale and recenter + if rescale: + image_arr = np.array(input_image) + in_w, in_h = image_arr.shape[:2] + out_res = min(RES, max(in_w, in_h)) + ret, mask = cv2.threshold(np.array(input_image.split()[-1]), 0, 255, cv2.THRESH_BINARY) + x, y, w, h = cv2.boundingRect(mask) + max_size = max(w, h) + ratio = 0.75 + side_len = int(max_size / ratio) + padded_image = np.zeros((side_len, side_len, 4), dtype=np.uint8) + center = side_len // 2 + padded_image[center - h // 2 : center - h // 2 + h, center - w // 2 : center - w // 2 + w] = image_arr[y : y + h, x : x + w] + rgba = Image.fromarray(padded_image).resize((out_res, out_res), Image.LANCZOS) + + rgba_arr = np.array(rgba) / 255.0 + rgb = rgba_arr[..., :3] * rgba_arr[..., -1:] + (1 - rgba_arr[..., -1:]) + input_image = Image.fromarray((rgb * 255).astype(np.uint8)) + else: + input_image = expand2square(input_image, (127, 127, 127, 0)) + return input_image, input_image.resize((320, 320), Image.Resampling.LANCZOS) + + +def load_wonder3d_pipeline(cfg): + + pipeline = MVDiffusionImagePipeline.from_pretrained( + cfg.pretrained_model_name_or_path, + torch_dtype=weight_dtype + ) + + # pipeline.to('cuda:0') + pipeline.unet.enable_xformers_memory_efficient_attention() + + + if torch.cuda.is_available(): + pipeline.to('cuda:0') + # sys.main_lock = threading.Lock() + return pipeline + + +from mvdiffusion.data.single_image_dataset import SingleImageDataset + + +def prepare_data(single_image, crop_size): + dataset = SingleImageDataset(root_dir='', num_views=6, img_wh=[256, 256], bg_color='white', crop_size=crop_size, single_image=single_image) + return dataset[0] + +scene = 'scene' + +def run_pipeline(pipeline, cfg, single_image, guidance_scale, steps, seed, crop_size, chk_group=None): + import pdb + global scene + # pdb.set_trace() + + if chk_group is not None: + write_image = "Write Results" in chk_group + + batch = prepare_data(single_image, crop_size) + + pipeline.set_progress_bar_config(disable=True) + seed = int(seed) + generator = torch.Generator(device=pipeline.unet.device).manual_seed(seed) + + # repeat (2B, Nv, 3, H, W) + imgs_in = torch.cat([batch['imgs_in']] * 2, dim=0).to(weight_dtype) + + # (2B, Nv, Nce) + camera_embeddings = torch.cat([batch['camera_embeddings']] * 2, dim=0).to(weight_dtype) + + task_embeddings = torch.cat([batch['normal_task_embeddings'], batch['color_task_embeddings']], dim=0).to(weight_dtype) + + camera_embeddings = torch.cat([camera_embeddings, task_embeddings], dim=-1).to(weight_dtype) + + # (B*Nv, 3, H, W) + imgs_in = rearrange(imgs_in, "Nv C H W -> (Nv) C H W") + # (B*Nv, Nce) + # camera_embeddings = rearrange(camera_embeddings, "B Nv Nce -> (B Nv) Nce") + + out = pipeline( + imgs_in, + # camera_embeddings, + generator=generator, + guidance_scale=guidance_scale, + num_inference_steps=steps, + output_type='pt', + num_images_per_prompt=1, + **cfg.pipe_validation_kwargs, + ).images + + bsz = out.shape[0] // 2 + normals_pred = out[:bsz] + images_pred = out[bsz:] + num_views = 6 + if write_image: + VIEWS = ['front', 'front_right', 'right', 'back', 'left', 'front_left'] + cur_dir = os.path.join("./outputs", f"cropsize-{int(crop_size)}-cfg{guidance_scale:.1f}") + + scene = 'scene'+datetime.now().strftime('@%Y%m%d-%H%M%S') + scene_dir = os.path.join(cur_dir, scene) + normal_dir = os.path.join(scene_dir, "normals") + masked_colors_dir = os.path.join(scene_dir, "masked_colors") + os.makedirs(normal_dir, exist_ok=True) + os.makedirs(masked_colors_dir, exist_ok=True) + for j in range(num_views): + view = VIEWS[j] + normal = normals_pred[j] + color = images_pred[j] + + normal_filename = f"normals_000_{view}.png" + rgb_filename = f"rgb_000_{view}.png" + normal = save_image_to_disk(normal, os.path.join(normal_dir, normal_filename)) + color = save_image_to_disk(color, os.path.join(scene_dir, rgb_filename)) + + # rm_normal = remove(normal) + # rm_color = remove(color) + + # save_image_numpy(rm_normal, os.path.join(scene_dir, normal_filename)) + # save_image_numpy(rm_color, os.path.join(masked_colors_dir, rgb_filename)) + + normals_pred = [save_image(normals_pred[i]) for i in range(bsz)] + images_pred = [save_image(images_pred[i]) for i in range(bsz)] + + out = images_pred + normals_pred + return out + + +def process_3d(mode, data_dir, guidance_scale, crop_size): + dir = None + global scene + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + + subprocess.run( + f'cd instant-nsr-pl && python launch.py --config configs/neuralangelo-ortho-wmask.yaml --gpu 0 --train dataset.root_dir=../{data_dir}/cropsize-{crop_size:.1f}-cfg{guidance_scale:.1f}/ dataset.scene={scene} && cd ..', + shell=True, + ) + import glob + # import pdb + + # pdb.set_trace() + + obj_files = glob.glob(f'{cur_dir}/instant-nsr-pl/exp/{scene}/*/save/*.obj', recursive=True) + print(obj_files) + if obj_files: + dir = obj_files[0] + return dir + + +@dataclass +class TestConfig: + pretrained_model_name_or_path: str + pretrained_unet_path: str + revision: Optional[str] + validation_dataset: Dict + save_dir: str + seed: Optional[int] + validation_batch_size: int + dataloader_num_workers: int + + local_rank: int + + pipe_kwargs: Dict + pipe_validation_kwargs: Dict + unet_from_pretrained_kwargs: Dict + validation_guidance_scales: List[float] + validation_grid_nrow: int + camera_embedding_lr_mult: float + + num_views: int + camera_embedding_type: str + + pred_type: str # joint, or ablation + + enable_xformers_memory_efficient_attention: bool + + cond_on_normals: bool + cond_on_colors: bool + + +def run_demo(): + from utils.misc import load_config + from omegaconf import OmegaConf + + # parse YAML config to OmegaConf + cfg = load_config("./configs/mvdiffusion-joint-ortho-6views.yaml") + # print(cfg) + schema = OmegaConf.structured(TestConfig) + cfg = OmegaConf.merge(schema, cfg) + + pipeline = load_wonder3d_pipeline(cfg) + torch.set_grad_enabled(False) + pipeline.to(f'cuda:{_GPU_ID}') + + predictor = sam_init() + + custom_theme = gr.themes.Soft(primary_hue="blue").set( + button_secondary_background_fill="*neutral_100", button_secondary_background_fill_hover="*neutral_200" + ) + custom_css = '''#disp_image { + text-align: center; /* Horizontally center the content */ + }''' + + with gr.Blocks(title=_TITLE, theme=custom_theme, css=custom_css) as demo: + with gr.Row(): + with gr.Column(scale=1): + gr.Markdown('# ' + _TITLE) + gr.Markdown(_DESCRIPTION) + with gr.Row(variant='panel'): + with gr.Column(scale=1): + input_image = gr.Image(type='pil', image_mode='RGBA', height=320, label='Input image', tool=None) + + with gr.Column(scale=1): + processed_image = gr.Image( + type='pil', + label="Processed Image", + interactive=False, + height=320, + tool=None, + image_mode='RGBA', + elem_id="disp_image", + visible=True, + ) + # with gr.Column(scale=1): + # ## add 3D Model + # obj_3d = gr.Model3D( + # # clear_color=[0.0, 0.0, 0.0, 0.0], + # label="3D Model", height=320, + # # camera_position=[0,0,2.0] + # ) + processed_image_highres = gr.Image(type='pil', image_mode='RGBA', visible=False, tool=None) + with gr.Row(variant='panel'): + with gr.Column(scale=1): + example_folder = os.path.join(os.path.dirname(__file__), "./example_images") + example_fns = [os.path.join(example_folder, example) for example in os.listdir(example_folder)] + gr.Examples( + examples=example_fns, + inputs=[input_image], + outputs=[input_image], + cache_examples=False, + label='Examples (click one of the images below to start)', + examples_per_page=30, + ) + with gr.Column(scale=1): + with gr.Accordion('Advanced options', open=True): + with gr.Row(): + with gr.Column(): + input_processing = gr.CheckboxGroup( + ['Background Removal'], + label='Input Image Preprocessing', + value=['Background Removal'], + info='untick this, if masked image with alpha channel', + ) + with gr.Column(): + output_processing = gr.CheckboxGroup( + ['Write Results'], label='write the results in ./outputs folder', value=['Write Results'] + ) + with gr.Row(): + with gr.Column(): + scale_slider = gr.Slider(1, 5, value=1, step=1, label='Classifier Free Guidance Scale') + with gr.Column(): + steps_slider = gr.Slider(15, 100, value=50, step=1, label='Number of Diffusion Inference Steps') + with gr.Row(): + with gr.Column(): + seed = gr.Number(42, label='Seed') + with gr.Column(): + crop_size = gr.Number(192, label='Crop size') + + mode = gr.Textbox('train', visible=False) + data_dir = gr.Textbox('outputs', visible=False) + # crop_size = 192 + # with gr.Row(): + # method = gr.Radio(choices=['instant-nsr-pl', 'NeuS'], label='Method (Default: instant-nsr-pl)', value='instant-nsr-pl') + run_btn = gr.Button('Generate Normals and Colors', variant='primary', interactive=True) + # recon_btn = gr.Button('Reconstruct 3D model', variant='primary', interactive=True) + # gr.Markdown("First click Generate button, then click Reconstruct button. Reconstruction may cost several minutes.") + + with gr.Row(): + view_1 = gr.Image(interactive=False, height=240, show_label=False) + view_2 = gr.Image(interactive=False, height=240, show_label=False) + view_3 = gr.Image(interactive=False, height=240, show_label=False) + view_4 = gr.Image(interactive=False, height=240, show_label=False) + view_5 = gr.Image(interactive=False, height=240, show_label=False) + view_6 = gr.Image(interactive=False, height=240, show_label=False) + with gr.Row(): + normal_1 = gr.Image(interactive=False, height=240, show_label=False) + normal_2 = gr.Image(interactive=False, height=240, show_label=False) + normal_3 = gr.Image(interactive=False, height=240, show_label=False) + normal_4 = gr.Image(interactive=False, height=240, show_label=False) + normal_5 = gr.Image(interactive=False, height=240, show_label=False) + normal_6 = gr.Image(interactive=False, height=240, show_label=False) + + run_btn.click( + fn=partial(preprocess, predictor), inputs=[input_image, input_processing], outputs=[processed_image_highres, processed_image], queue=True + ).success( + fn=partial(run_pipeline, pipeline, cfg), + inputs=[processed_image_highres, scale_slider, steps_slider, seed, crop_size, output_processing], + outputs=[view_1, view_2, view_3, view_4, view_5, view_6, normal_1, normal_2, normal_3, normal_4, normal_5, normal_6], + ) + # recon_btn.click( + # process_3d, inputs=[mode, data_dir, scale_slider, crop_size], outputs=[obj_3d] + # ) + + demo.queue().launch(share=True, max_threads=80) + + +if __name__ == '__main__': + fire.Fire(run_demo) diff --git a/apps/third_party/Wonder3D/gradio_app_recon.py b/apps/third_party/Wonder3D/gradio_app_recon.py new file mode 100644 index 0000000000000000000000000000000000000000..4153ae8f33530b2d82572cd26c610e6449f16555 --- /dev/null +++ b/apps/third_party/Wonder3D/gradio_app_recon.py @@ -0,0 +1,438 @@ +import os +import torch +import fire +import gradio as gr +from PIL import Image +from functools import partial + +import cv2 +import time +import numpy as np +from rembg import remove +from segment_anything import sam_model_registry, SamPredictor + +import os +import sys +import numpy +import torch +import rembg +import threading +import urllib.request +from PIL import Image +from typing import Dict, Optional, Tuple, List +from dataclasses import dataclass +import streamlit as st +import huggingface_hub +from transformers import CLIPImageProcessor, CLIPVisionModelWithProjection +from mvdiffusion.models.unet_mv2d_condition import UNetMV2DConditionModel +from mvdiffusion.data.single_image_dataset import SingleImageDataset as MVDiffusionDataset +from mvdiffusion.pipelines.pipeline_mvdiffusion_image import MVDiffusionImagePipeline +from diffusers import AutoencoderKL, DDPMScheduler, DDIMScheduler +from einops import rearrange +import numpy as np +import subprocess +from datetime import datetime + +def save_image(tensor): + ndarr = tensor.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy() + # pdb.set_trace() + im = Image.fromarray(ndarr) + return ndarr + + +def save_image_to_disk(tensor, fp): + ndarr = tensor.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy() + # pdb.set_trace() + im = Image.fromarray(ndarr) + im.save(fp) + return ndarr + + +def save_image_numpy(ndarr, fp): + im = Image.fromarray(ndarr) + im.save(fp) + + +weight_dtype = torch.float16 + +_TITLE = '''Wonder3D: Single Image to 3D using Cross-Domain Diffusion''' +_DESCRIPTION = ''' +
+Generate consistent multi-view normals maps and color images. + +
+
+The demo does not include the mesh reconstruction part, please visit our github repo to get a textured mesh. +
+''' +_GPU_ID = 0 + + +if not hasattr(Image, 'Resampling'): + Image.Resampling = Image + + +def sam_init(): + sam_checkpoint = os.path.join(os.path.dirname(__file__), "sam_pt", "sam_vit_h_4b8939.pth") + model_type = "vit_h" + + sam = sam_model_registry[model_type](checkpoint=sam_checkpoint).to(device=f"cuda:{_GPU_ID}") + predictor = SamPredictor(sam) + return predictor + + +def sam_segment(predictor, input_image, *bbox_coords): + bbox = np.array(bbox_coords) + image = np.asarray(input_image) + + start_time = time.time() + predictor.set_image(image) + + masks_bbox, scores_bbox, logits_bbox = predictor.predict(box=bbox, multimask_output=True) + + print(f"SAM Time: {time.time() - start_time:.3f}s") + out_image = np.zeros((image.shape[0], image.shape[1], 4), dtype=np.uint8) + out_image[:, :, :3] = image + out_image_bbox = out_image.copy() + out_image_bbox[:, :, 3] = masks_bbox[-1].astype(np.uint8) * 255 + torch.cuda.empty_cache() + return Image.fromarray(out_image_bbox, mode='RGBA') + + +def expand2square(pil_img, background_color): + width, height = pil_img.size + if width == height: + return pil_img + elif width > height: + result = Image.new(pil_img.mode, (width, width), background_color) + result.paste(pil_img, (0, (width - height) // 2)) + return result + else: + result = Image.new(pil_img.mode, (height, height), background_color) + result.paste(pil_img, ((height - width) // 2, 0)) + return result + + +def preprocess(predictor, input_image, chk_group=None, segment=True, rescale=False): + RES = 1024 + input_image.thumbnail([RES, RES], Image.Resampling.LANCZOS) + if chk_group is not None: + segment = "Background Removal" in chk_group + rescale = "Rescale" in chk_group + if segment: + image_rem = input_image.convert('RGBA') + image_nobg = remove(image_rem, alpha_matting=True) + arr = np.asarray(image_nobg)[:, :, -1] + x_nonzero = np.nonzero(arr.sum(axis=0)) + y_nonzero = np.nonzero(arr.sum(axis=1)) + x_min = int(x_nonzero[0].min()) + y_min = int(y_nonzero[0].min()) + x_max = int(x_nonzero[0].max()) + y_max = int(y_nonzero[0].max()) + input_image = sam_segment(predictor, input_image.convert('RGB'), x_min, y_min, x_max, y_max) + # Rescale and recenter + if rescale: + image_arr = np.array(input_image) + in_w, in_h = image_arr.shape[:2] + out_res = min(RES, max(in_w, in_h)) + ret, mask = cv2.threshold(np.array(input_image.split()[-1]), 0, 255, cv2.THRESH_BINARY) + x, y, w, h = cv2.boundingRect(mask) + max_size = max(w, h) + ratio = 0.75 + side_len = int(max_size / ratio) + padded_image = np.zeros((side_len, side_len, 4), dtype=np.uint8) + center = side_len // 2 + padded_image[center - h // 2 : center - h // 2 + h, center - w // 2 : center - w // 2 + w] = image_arr[y : y + h, x : x + w] + rgba = Image.fromarray(padded_image).resize((out_res, out_res), Image.LANCZOS) + + rgba_arr = np.array(rgba) / 255.0 + rgb = rgba_arr[..., :3] * rgba_arr[..., -1:] + (1 - rgba_arr[..., -1:]) + input_image = Image.fromarray((rgb * 255).astype(np.uint8)) + else: + input_image = expand2square(input_image, (127, 127, 127, 0)) + return input_image, input_image.resize((320, 320), Image.Resampling.LANCZOS) + + +def load_wonder3d_pipeline(cfg): + + pipeline = MVDiffusionImagePipeline.from_pretrained( + cfg.pretrained_model_name_or_path, + torch_dtype=weight_dtype + ) + + # pipeline.to('cuda:0') + pipeline.unet.enable_xformers_memory_efficient_attention() + + + if torch.cuda.is_available(): + pipeline.to('cuda:0') + # sys.main_lock = threading.Lock() + return pipeline + + +from mvdiffusion.data.single_image_dataset import SingleImageDataset + + +def prepare_data(single_image, crop_size): + dataset = SingleImageDataset(root_dir='', num_views=6, img_wh=[256, 256], bg_color='white', crop_size=crop_size, single_image=single_image) + return dataset[0] + +scene = 'scene' + +def run_pipeline(pipeline, cfg, single_image, guidance_scale, steps, seed, crop_size, chk_group=None): + import pdb + global scene + # pdb.set_trace() + + if chk_group is not None: + write_image = "Write Results" in chk_group + + batch = prepare_data(single_image, crop_size) + + pipeline.set_progress_bar_config(disable=True) + seed = int(seed) + generator = torch.Generator(device=pipeline.unet.device).manual_seed(seed) + + # repeat (2B, Nv, 3, H, W) + imgs_in = torch.cat([batch['imgs_in']] * 2, dim=0).to(weight_dtype) + + # (2B, Nv, Nce) + camera_embeddings = torch.cat([batch['camera_embeddings']] * 2, dim=0).to(weight_dtype) + + task_embeddings = torch.cat([batch['normal_task_embeddings'], batch['color_task_embeddings']], dim=0).to(weight_dtype) + + camera_embeddings = torch.cat([camera_embeddings, task_embeddings], dim=-1).to(weight_dtype) + + # (B*Nv, 3, H, W) + imgs_in = rearrange(imgs_in, "Nv C H W -> (Nv) C H W") + # (B*Nv, Nce) + # camera_embeddings = rearrange(camera_embeddings, "B Nv Nce -> (B Nv) Nce") + + out = pipeline( + imgs_in, + camera_embeddings, + generator=generator, + guidance_scale=guidance_scale, + num_inference_steps=steps, + output_type='pt', + num_images_per_prompt=1, + **cfg.pipe_validation_kwargs, + ).images + + bsz = out.shape[0] // 2 + normals_pred = out[:bsz] + images_pred = out[bsz:] + num_views = 6 + if write_image: + VIEWS = ['front', 'front_right', 'right', 'back', 'left', 'front_left'] + cur_dir = os.path.join("./outputs", f"cropsize-{int(crop_size)}-cfg{guidance_scale:.1f}") + + scene = 'scene'+datetime.now().strftime('@%Y%m%d-%H%M%S') + scene_dir = os.path.join(cur_dir, scene) + normal_dir = os.path.join(scene_dir, "normals") + masked_colors_dir = os.path.join(scene_dir, "masked_colors") + os.makedirs(normal_dir, exist_ok=True) + os.makedirs(masked_colors_dir, exist_ok=True) + for j in range(num_views): + view = VIEWS[j] + normal = normals_pred[j] + color = images_pred[j] + + normal_filename = f"normals_000_{view}.png" + rgb_filename = f"rgb_000_{view}.png" + normal = save_image_to_disk(normal, os.path.join(normal_dir, normal_filename)) + color = save_image_to_disk(color, os.path.join(scene_dir, rgb_filename)) + + rm_normal = remove(normal) + rm_color = remove(color) + + save_image_numpy(rm_normal, os.path.join(scene_dir, normal_filename)) + save_image_numpy(rm_color, os.path.join(masked_colors_dir, rgb_filename)) + + normals_pred = [save_image(normals_pred[i]) for i in range(bsz)] + images_pred = [save_image(images_pred[i]) for i in range(bsz)] + + out = images_pred + normals_pred + return out + + +def process_3d(mode, data_dir, guidance_scale, crop_size): + dir = None + global scene + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + + subprocess.run( + f'cd instant-nsr-pl && python launch.py --config configs/neuralangelo-ortho-wmask.yaml --gpu 0 --train dataset.root_dir=../{data_dir}/cropsize-{int(crop_size)}-cfg{guidance_scale:.1f}/ dataset.scene={scene} && cd ..', + shell=True, + ) + import glob + # import pdb + + # pdb.set_trace() + + obj_files = glob.glob(f'{cur_dir}/instant-nsr-pl/exp/{scene}/*/save/*.obj', recursive=True) + print(obj_files) + if obj_files: + dir = obj_files[0] + return dir + + +@dataclass +class TestConfig: + pretrained_model_name_or_path: str + pretrained_unet_path: str + revision: Optional[str] + validation_dataset: Dict + save_dir: str + seed: Optional[int] + validation_batch_size: int + dataloader_num_workers: int + + local_rank: int + + pipe_kwargs: Dict + pipe_validation_kwargs: Dict + unet_from_pretrained_kwargs: Dict + validation_guidance_scales: List[float] + validation_grid_nrow: int + camera_embedding_lr_mult: float + + num_views: int + camera_embedding_type: str + + pred_type: str # joint, or ablation + + enable_xformers_memory_efficient_attention: bool + + cond_on_normals: bool + cond_on_colors: bool + + +def run_demo(): + from utils.misc import load_config + from omegaconf import OmegaConf + + # parse YAML config to OmegaConf + cfg = load_config("./configs/mvdiffusion-joint-ortho-6views.yaml") + # print(cfg) + schema = OmegaConf.structured(TestConfig) + cfg = OmegaConf.merge(schema, cfg) + + pipeline = load_wonder3d_pipeline(cfg) + torch.set_grad_enabled(False) + pipeline.to(f'cuda:{_GPU_ID}') + + predictor = sam_init() + + custom_theme = gr.themes.Soft(primary_hue="blue").set( + button_secondary_background_fill="*neutral_100", button_secondary_background_fill_hover="*neutral_200" + ) + custom_css = '''#disp_image { + text-align: center; /* Horizontally center the content */ + }''' + + with gr.Blocks(title=_TITLE, theme=custom_theme, css=custom_css) as demo: + with gr.Row(): + with gr.Column(scale=1): + gr.Markdown('# ' + _TITLE) + gr.Markdown(_DESCRIPTION) + with gr.Row(variant='panel'): + with gr.Column(scale=1): + input_image = gr.Image(type='pil', image_mode='RGBA', height=320, label='Input image', tool=None) + + with gr.Column(scale=1): + processed_image = gr.Image( + type='pil', + label="Processed Image", + interactive=False, + height=320, + tool=None, + image_mode='RGBA', + elem_id="disp_image", + visible=True, + ) + with gr.Column(scale=1): + ## add 3D Model + obj_3d = gr.Model3D( + # clear_color=[0.0, 0.0, 0.0, 0.0], + label="3D Model", height=320, + # camera_position=[0,0,2.0] + ) + processed_image_highres = gr.Image(type='pil', image_mode='RGBA', visible=False, tool=None) + with gr.Row(variant='panel'): + with gr.Column(scale=1): + example_folder = os.path.join(os.path.dirname(__file__), "./example_images") + example_fns = [os.path.join(example_folder, example) for example in os.listdir(example_folder)] + gr.Examples( + examples=example_fns, + inputs=[input_image], + outputs=[input_image], + cache_examples=False, + label='Examples (click one of the images below to start)', + examples_per_page=30, + ) + with gr.Column(scale=1): + with gr.Accordion('Advanced options', open=True): + with gr.Row(): + with gr.Column(): + input_processing = gr.CheckboxGroup( + ['Background Removal'], + label='Input Image Preprocessing', + value=['Background Removal'], + info='untick this, if masked image with alpha channel', + ) + with gr.Column(): + output_processing = gr.CheckboxGroup( + ['Write Results'], label='write the results in ./outputs folder', value=['Write Results'] + ) + with gr.Row(): + with gr.Column(): + scale_slider = gr.Slider(1, 5, value=1, step=1, label='Classifier Free Guidance Scale') + with gr.Column(): + steps_slider = gr.Slider(15, 100, value=50, step=1, label='Number of Diffusion Inference Steps') + with gr.Row(): + with gr.Column(): + seed = gr.Number(42, label='Seed') + with gr.Column(): + crop_size = gr.Number(192, label='Crop size') + + mode = gr.Textbox('train', visible=False) + data_dir = gr.Textbox('outputs', visible=False) + # crop_size = 192 + # with gr.Row(): + # method = gr.Radio(choices=['instant-nsr-pl', 'NeuS'], label='Method (Default: instant-nsr-pl)', value='instant-nsr-pl') + # run_btn = gr.Button('Generate Normals and Colors', variant='primary', interactive=True) + run_btn = gr.Button('Reconstruct 3D model', variant='primary', interactive=True) + gr.Markdown(" Reconstruction may cost several minutes. Check results in instant-nsr-pl/exp/scene@{current-time}/ ") + + with gr.Row(): + view_1 = gr.Image(interactive=False, height=240, show_label=False) + view_2 = gr.Image(interactive=False, height=240, show_label=False) + view_3 = gr.Image(interactive=False, height=240, show_label=False) + view_4 = gr.Image(interactive=False, height=240, show_label=False) + view_5 = gr.Image(interactive=False, height=240, show_label=False) + view_6 = gr.Image(interactive=False, height=240, show_label=False) + with gr.Row(): + normal_1 = gr.Image(interactive=False, height=240, show_label=False) + normal_2 = gr.Image(interactive=False, height=240, show_label=False) + normal_3 = gr.Image(interactive=False, height=240, show_label=False) + normal_4 = gr.Image(interactive=False, height=240, show_label=False) + normal_5 = gr.Image(interactive=False, height=240, show_label=False) + normal_6 = gr.Image(interactive=False, height=240, show_label=False) + + run_btn.click( + fn=partial(preprocess, predictor), inputs=[input_image, input_processing], outputs=[processed_image_highres, processed_image], queue=True + ).success( + fn=partial(run_pipeline, pipeline, cfg), + inputs=[processed_image_highres, scale_slider, steps_slider, seed, crop_size, output_processing], + outputs=[view_1, view_2, view_3, view_4, view_5, view_6, normal_1, normal_2, normal_3, normal_4, normal_5, normal_6], + ).success( + process_3d, inputs=[mode, data_dir, scale_slider, crop_size], outputs=[obj_3d] + ) + + demo.queue().launch(share=True, max_threads=80) + + +if __name__ == '__main__': + fire.Fire(run_demo) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/README.md b/apps/third_party/Wonder3D/instant-nsr-pl/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7964ddfe4641028c4f92566532ea53f0ec20f30d --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/README.md @@ -0,0 +1,122 @@ +# Instant Neural Surface Reconstruction + +This repository contains a concise and extensible implementation of NeRF and NeuS for neural surface reconstruction based on Instant-NGP and the Pytorch-Lightning framework. **Training on a NeRF-Synthetic scene takes ~5min for NeRF and ~10min for NeuS on a single RTX3090.** + +||NeRF in 5min|NeuS in 10 min| +|---|---|---| +|Rendering|![rendering-nerf](https://user-images.githubusercontent.com/19284678/199078178-b719676b-7e60-47f1-813b-c0b533f5480d.png)|![rendering-neus](https://user-images.githubusercontent.com/19284678/199078300-ebcf249d-b05e-431f-b035-da354705d8db.png)| +|Mesh|![mesh-nerf](https://user-images.githubusercontent.com/19284678/199078661-b5cd569a-c22b-4220-9c11-d5fd13a52fb8.png)|![mesh-neus](https://user-images.githubusercontent.com/19284678/199078481-164e36a6-6d55-45cc-aaf3-795a114e4a38.png)| + + +## Features +**This repository aims to provide a highly efficient while customizable boilerplate for research projects based on NeRF or NeuS.** + +- acceleration techniques from [Instant-NGP](https://github.com/NVlabs/instant-ngp): multiresolution hash encoding and fully fused networks by [tiny-cuda-nn](https://github.com/NVlabs/tiny-cuda-nn), occupancy grid pruning and rendering by [nerfacc](https://github.com/KAIR-BAIR/nerfacc) +- out-of-the-box multi-GPU and mixed precision training by [PyTorch-Lightning](https://github.com/Lightning-AI/lightning) +- hierarchical project layout that is designed to be easily customized and extended, flexible experiment configuration by [OmegaConf](https://github.com/omry/omegaconf) + +**Please subscribe to [#26](https://github.com/bennyguo/instant-nsr-pl/issues/26) for our latest findings on quality improvements!** + +## News + +🔥🔥🔥 Check out my new project on 3D content generation: https://github.com/threestudio-project/threestudio 🔥🔥🔥 + +- 06/03/2023: Add an implementation of [Neuralangelo](https://research.nvidia.com/labs/dir/neuralangelo/). See [here](https://github.com/bennyguo/instant-nsr-pl#training-on-DTU) for details. +- 03/31/2023: NeuS model now supports background modeling. You could try on the DTU dataset provided by [NeuS](https://drive.google.com/drive/folders/1Nlzejs4mfPuJYORLbDEUDWlc9IZIbU0C?usp=sharing) or [IDR](https://www.dropbox.com/sh/5tam07ai8ch90pf/AADniBT3dmAexvm_J1oL__uoa) following [the instruction here](https://github.com/bennyguo/instant-nsr-pl#training-on-DTU). +- 02/11/2023: NeRF model now supports unbounded 360 scenes with learned background. You could try on [MipNeRF 360 data](http://storage.googleapis.com/gresearch/refraw360/360_v2.zip) following [the COLMAP configuration](https://github.com/bennyguo/instant-nsr-pl#training-on-custom-colmap-data). + +## Requirements +**Note:** +- To utilize multiresolution hash encoding or fully fused networks provided by tiny-cuda-nn, you should have least an RTX 2080Ti, see [https://github.com/NVlabs/tiny-cuda-nn#requirements](https://github.com/NVlabs/tiny-cuda-nn#requirements) for more details. +- Multi-GPU training is currently not supported on Windows (see [#4](https://github.com/bennyguo/instant-nsr-pl/issues/4)). +### Environments +- Install PyTorch>=1.10 [here](https://pytorch.org/get-started/locally/) based the package management tool you used and your cuda version (older PyTorch versions may work but have not been tested) +- Install tiny-cuda-nn PyTorch extension: `pip install git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch` +- `pip install -r requirements.txt` + + +## Run +### Training on NeRF-Synthetic +Download the NeRF-Synthetic data [here](https://drive.google.com/drive/folders/128yBriW1IG_3NJ5Rp7APSTZsJqdJdfc1) and put it under `load/`. The file structure should be like `load/nerf_synthetic/lego`. + +Run the launch script with `--train`, specifying the config file, the GPU(s) to be used (GPU 0 will be used by default), and the scene name: +```bash +# train NeRF +python launch.py --config configs/nerf-blender.yaml --gpu 0 --train dataset.scene=lego tag=example + +# train NeuS with mask +python launch.py --config configs/neus-blender.yaml --gpu 0 --train dataset.scene=lego tag=example +# train NeuS without mask +python launch.py --config configs/neus-blender.yaml --gpu 0 --train dataset.scene=lego tag=example system.loss.lambda_mask=0.0 +``` +The code snapshots, checkpoints and experiment outputs are saved to `exp/[name]/[tag]@[timestamp]`, and tensorboard logs can be found at `runs/[name]/[tag]@[timestamp]`. You can change any configuration in the YAML file by specifying arguments without `--`, for example: +```bash +python launch.py --config configs/nerf-blender.yaml --gpu 0 --train dataset.scene=lego tag=iter50k seed=0 trainer.max_steps=50000 +``` +### Training on DTU +Download preprocessed DTU data provided by [NeuS](https://drive.google.com/drive/folders/1Nlzejs4mfPuJYORLbDEUDWlc9IZIbU0C?usp=sharing) or [IDR](https://www.dropbox.com/sh/5tam07ai8ch90pf/AADniBT3dmAexvm_J1oL__uoa). In the provided config files we assume using NeuS DTU data. If you are using IDR DTU data, please set `dataset.cameras_file=cameras.npz`. You may also need to adjust `dataset.root_dir` to point to your downloaded data location. +```bash +# train NeuS on DTU without mask +python launch.py --config configs/neus-dtu.yaml --gpu 0 --train +# train NeuS on DTU with mask +python launch.py --config configs/neus-dtu-wmask.yaml --gpu 0 --train +# train NeuS on DTU with mask using tricks from Neuralangelo (experimental) +python launch.py --config configs/neuralangelo-dtu-wmask.yaml --gpu 0 --train +``` +Notes: +- PSNR in the testing stage is meaningless, as we simply compare to pure white images in testing. +- The results of Neuralangelo can't reach those in the original paper. Some potential improvements: more iterations; larger `system.geometry.xyz_encoding_config.update_steps`; larger `system.geometry.xyz_encoding_config.n_features_per_level`; larger `system.geometry.xyz_encoding_config.log2_hashmap_size`; adopting curvature loss. + +### Training on Custom COLMAP Data +To get COLMAP data from custom images, you should have COLMAP installed (see [here](https://colmap.github.io/install.html) for installation instructions). Then put your images in the `images/` folder, and run `scripts/imgs2poses.py` specifying the path containing the `images/` folder. For example: +```bash +python scripts/imgs2poses.py ./load/bmvs_dog # images are in ./load/bmvs_dog/images +``` +Existing data following this file structure also works as long as images are store in `images/` and there is a `sparse/` folder for the COLMAP output, for example [the data provided by MipNeRF 360](http://storage.googleapis.com/gresearch/refraw360/360_v2.zip). An optional `masks/` folder could be provided for object mask supervision. To train on COLMAP data, please refer to the example config files `config/*-colmap.yaml`. Some notes: +- Adapt the `root_dir` and `img_wh` (or `img_downscale`) option in the config file to your data; +- The scene is normalized so that cameras have a minimum distance `1.0` to the center of the scene. Setting `model.radius=1.0` works in most cases. If not, try setting a smaller radius that wraps tightly to your foreground object. +- There are three choices to determine the scene center: `dataset.center_est_method=camera` uses the center of all camera positions as the scene center; `dataset.center_est_method=lookat` assumes the cameras are looking at the same point and calculates an approximate look-at point as the scene center; `dataset.center_est_method=point` uses the center of all points (reconstructed by COLMAP) that are bounded by cameras as the scene center. Please choose an appropriate method according to your capture. +- PSNR in the testing stage is meaningless, as we simply compare to pure white images in testing. + +### Testing +The training procedure are by default followed by testing, which computes metrics on test data, generates animations and exports the geometry as triangular meshes. If you want to do testing alone, just resume the pretrained model and replace `--train` with `--test`, for example: +```bash +python launch.py --config path/to/your/exp/config/parsed.yaml --resume path/to/your/exp/ckpt/epoch=0-step=20000.ckpt --gpu 0 --test +``` + + +## Benchmarks +All experiments are conducted on a single NVIDIA RTX3090. + +|PSNR|Chair|Drums|Ficus|Hotdog|Lego|Materials|Mic|Ship|Avg.| +|---|---|---|---|---|---|---|---|---|---| +|NeRF Paper|33.00|25.01|30.13|36.18|32.54|29.62|32.91|28.65|31.01| +|NeRF Ours (20k)|34.80|26.04|33.89|37.42|35.33|29.46|35.22|31.17|32.92| +|NeuS Ours (20k, with masks)|34.04|25.26|32.47|35.94|33.78|27.67|33.43|29.50|31.51| + +|Training Time (mm:ss)|Chair|Drums|Ficus|Hotdog|Lego|Materials|Mic|Ship|Avg.| +|---|---|---|---|---|---|---|---|---|---| +|NeRF Ours (20k)|04:34|04:35|04:18|04:46|04:39|04:35|04:26|05:41|04:42| +|NeuS Ours (20k, with masks)|11:25|10:34|09:51|12:11|11:37|11:46|09:59|16:25|11:44| + + +## TODO +- [✅] Support more dataset formats, like COLMAP outputs and DTU +- [✅] Support simple background model +- [ ] Support GUI training and interaction +- [ ] More illustrations about the framework + +## Related Projects +- [ngp_pl](https://github.com/kwea123/ngp_pl): Great Instant-NGP implementation in PyTorch-Lightning! Background model and GUI supported. +- [Instant-NSR](https://github.com/zhaofuq/Instant-NSR): NeuS implementation using multiresolution hash encoding. + +## Citation +If you find this codebase useful, please consider citing: +``` +@misc{instant-nsr-pl, + Author = {Yuan-Chen Guo}, + Year = {2022}, + Note = {https://github.com/bennyguo/instant-nsr-pl}, + Title = {Instant Neural Surface Reconstruction} +} +``` diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/configs/neuralangelo-ortho-wmask.yaml b/apps/third_party/Wonder3D/instant-nsr-pl/configs/neuralangelo-ortho-wmask.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4411ac8173d87e17717ec7381165b03c5b464d7f --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/configs/neuralangelo-ortho-wmask.yaml @@ -0,0 +1,145 @@ +name: ${basename:${dataset.scene}} +tag: "" +seed: 42 + +dataset: + name: ortho + root_dir: /home/xiaoxiao/Workplace/wonder3Dplus/outputs/joint-twice/aigc/cropsize-224-cfg1.0 + cam_pose_dir: null + scene: scene_name + imSize: [1024, 1024] # should use larger res, otherwise the exported mesh has wrong colors + camera_type: ortho + apply_mask: true + camera_params: null + view_weights: [1.0, 0.8, 0.2, 1.0, 0.4, 0.7] #['front', 'front_right', 'right', 'back', 'left', 'front_left'] + # view_weights: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + +model: + name: neus + radius: 1.0 + num_samples_per_ray: 1024 + train_num_rays: 256 + max_train_num_rays: 8192 + grid_prune: true + grid_prune_occ_thre: 0.001 + dynamic_ray_sampling: true + batch_image_sampling: true + randomized: true + ray_chunk: 2048 + cos_anneal_end: 20000 + learned_background: false + background_color: black + variance: + init_val: 0.3 + modulate: false + geometry: + name: volume-sdf + radius: ${model.radius} + feature_dim: 13 + grad_type: finite_difference + finite_difference_eps: progressive + isosurface: + method: mc + resolution: 192 + chunk: 2097152 + threshold: 0. + xyz_encoding_config: + otype: ProgressiveBandHashGrid + n_levels: 10 # 12 modify + n_features_per_level: 2 + log2_hashmap_size: 19 + base_resolution: 32 + per_level_scale: 1.3195079107728942 + include_xyz: true + start_level: 4 + start_step: 0 + update_steps: 1000 + mlp_network_config: + otype: VanillaMLP + activation: ReLU + output_activation: none + n_neurons: 64 + n_hidden_layers: 1 + sphere_init: true + sphere_init_radius: 0.5 + weight_norm: true + texture: + name: volume-radiance + input_feature_dim: ${add:${model.geometry.feature_dim},3} # surface normal as additional input + dir_encoding_config: + otype: SphericalHarmonics + degree: 4 + mlp_network_config: + otype: VanillaMLP + activation: ReLU + output_activation: none + n_neurons: 64 + n_hidden_layers: 2 + color_activation: sigmoid + +system: + name: ortho-neus-system + loss: + lambda_rgb_mse: 0.5 + lambda_rgb_l1: 0. + lambda_mask: 1.0 + lambda_eikonal: 0.2 # cannot be too large, will cause holes to thin objects + lambda_normal: 1.0 # cannot be too large + lambda_3d_normal_smooth: 1.0 + # lambda_curvature: [0, 0.0, 1.e-4, 1000] # topology warmup + lambda_curvature: 0. + lambda_sparsity: 0.5 + lambda_distortion: 0.0 + lambda_distortion_bg: 0.0 + lambda_opaque: 0.0 + sparsity_scale: 100.0 + geo_aware: true + rgb_p_ratio: 0.8 + normal_p_ratio: 0.8 + mask_p_ratio: 0.9 + optimizer: + name: AdamW + args: + lr: 0.01 + betas: [0.9, 0.99] + eps: 1.e-15 + params: + geometry: + lr: 0.001 + texture: + lr: 0.01 + variance: + lr: 0.001 + constant_steps: 500 + scheduler: + name: SequentialLR + interval: step + milestones: + - ${system.constant_steps} + schedulers: + - name: ConstantLR + args: + factor: 1.0 + total_iters: ${system.constant_steps} + - name: ExponentialLR + args: + gamma: ${calc_exp_lr_decay_rate:0.1,${sub:${trainer.max_steps},${system.constant_steps}}} + +checkpoint: + save_top_k: -1 + every_n_train_steps: ${trainer.max_steps} + +export: + chunk_size: 2097152 + export_vertex_color: True + ortho_scale: 1.35 #modify + +trainer: + max_steps: 3000 + log_every_n_steps: 100 + num_sanity_val_steps: 0 + val_check_interval: 4000 + limit_train_batches: 1.0 + limit_val_batches: 2 + enable_progress_bar: true + precision: 16 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/__init__.py b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..432599afc6ce3de0a7ea128453bd3c913006deca --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/__init__.py @@ -0,0 +1,16 @@ +datasets = {} + + +def register(name): + def decorator(cls): + datasets[name] = cls + return cls + return decorator + + +def make(name, config): + dataset = datasets[name](config) + return dataset + + +from . import blender, colmap, dtu, ortho diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/blender.py b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/blender.py new file mode 100644 index 0000000000000000000000000000000000000000..3affa110ddc2f17db7c8678aad0980e799c83cef --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/blender.py @@ -0,0 +1,135 @@ +import os +import json +import math +import numpy as np +from PIL import Image + +import torch +from torch.utils.data import Dataset, DataLoader, IterableDataset +import torchvision.transforms.functional as TF + +import pytorch_lightning as pl + +import datasets +from models.ray_utils import get_ray_directions +from utils.misc import get_rank + + +class BlenderDatasetBase(): + def setup(self, config, split): + self.config = config + self.split = split + self.rank = get_rank() + + self.has_mask = True + self.apply_mask = True + + with open(os.path.join(self.config.root_dir, f"transforms_{self.split}.json"), 'r') as f: + meta = json.load(f) + + if 'w' in meta and 'h' in meta: + W, H = int(meta['w']), int(meta['h']) + else: + W, H = 800, 800 + + if 'img_wh' in self.config: + w, h = self.config.img_wh + assert round(W / w * h) == H + elif 'img_downscale' in self.config: + w, h = W // self.config.img_downscale, H // self.config.img_downscale + else: + raise KeyError("Either img_wh or img_downscale should be specified.") + + self.w, self.h = w, h + self.img_wh = (self.w, self.h) + + self.near, self.far = self.config.near_plane, self.config.far_plane + + self.focal = 0.5 * w / math.tan(0.5 * meta['camera_angle_x']) # scaled focal length + + # ray directions for all pixels, same for all images (same H, W, focal) + self.directions = \ + get_ray_directions(self.w, self.h, self.focal, self.focal, self.w//2, self.h//2).to(self.rank) # (h, w, 3) + + self.all_c2w, self.all_images, self.all_fg_masks = [], [], [] + + for i, frame in enumerate(meta['frames']): + c2w = torch.from_numpy(np.array(frame['transform_matrix'])[:3, :4]) + self.all_c2w.append(c2w) + + img_path = os.path.join(self.config.root_dir, f"{frame['file_path']}.png") + img = Image.open(img_path) + img = img.resize(self.img_wh, Image.BICUBIC) + img = TF.to_tensor(img).permute(1, 2, 0) # (4, h, w) => (h, w, 4) + + self.all_fg_masks.append(img[..., -1]) # (h, w) + self.all_images.append(img[...,:3]) + + self.all_c2w, self.all_images, self.all_fg_masks = \ + torch.stack(self.all_c2w, dim=0).float().to(self.rank), \ + torch.stack(self.all_images, dim=0).float().to(self.rank), \ + torch.stack(self.all_fg_masks, dim=0).float().to(self.rank) + + +class BlenderDataset(Dataset, BlenderDatasetBase): + def __init__(self, config, split): + self.setup(config, split) + + def __len__(self): + return len(self.all_images) + + def __getitem__(self, index): + return { + 'index': index + } + + +class BlenderIterableDataset(IterableDataset, BlenderDatasetBase): + def __init__(self, config, split): + self.setup(config, split) + + def __iter__(self): + while True: + yield {} + + +@datasets.register('blender') +class BlenderDataModule(pl.LightningDataModule): + def __init__(self, config): + super().__init__() + self.config = config + + def setup(self, stage=None): + if stage in [None, 'fit']: + self.train_dataset = BlenderIterableDataset(self.config, self.config.train_split) + if stage in [None, 'fit', 'validate']: + self.val_dataset = BlenderDataset(self.config, self.config.val_split) + if stage in [None, 'test']: + self.test_dataset = BlenderDataset(self.config, self.config.test_split) + if stage in [None, 'predict']: + self.predict_dataset = BlenderDataset(self.config, self.config.train_split) + + def prepare_data(self): + pass + + def general_loader(self, dataset, batch_size): + sampler = None + return DataLoader( + dataset, + num_workers=os.cpu_count(), + batch_size=batch_size, + pin_memory=True, + sampler=sampler + ) + + def train_dataloader(self): + return self.general_loader(self.train_dataset, batch_size=1) + + def val_dataloader(self): + return self.general_loader(self.val_dataset, batch_size=1) + + def test_dataloader(self): + return self.general_loader(self.test_dataset, batch_size=1) + + def predict_dataloader(self): + return self.general_loader(self.predict_dataset, batch_size=1) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/colmap.py b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/colmap.py new file mode 100644 index 0000000000000000000000000000000000000000..b6b389ebb09b8169019046ca8afbcce872e5d30a --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/colmap.py @@ -0,0 +1,332 @@ +import os +import math +import numpy as np +from PIL import Image + +import torch +import torch.nn.functional as F +from torch.utils.data import Dataset, DataLoader, IterableDataset +import torchvision.transforms.functional as TF + +import pytorch_lightning as pl + +import datasets +from datasets.colmap_utils import \ + read_cameras_binary, read_images_binary, read_points3d_binary +from models.ray_utils import get_ray_directions +from utils.misc import get_rank + + +def get_center(pts): + center = pts.mean(0) + dis = (pts - center[None,:]).norm(p=2, dim=-1) + mean, std = dis.mean(), dis.std() + q25, q75 = torch.quantile(dis, 0.25), torch.quantile(dis, 0.75) + valid = (dis > mean - 1.5 * std) & (dis < mean + 1.5 * std) & (dis > mean - (q75 - q25) * 1.5) & (dis < mean + (q75 - q25) * 1.5) + center = pts[valid].mean(0) + return center + +def normalize_poses(poses, pts, up_est_method, center_est_method): + if center_est_method == 'camera': + # estimation scene center as the average of all camera positions + center = poses[...,3].mean(0) + elif center_est_method == 'lookat': + # estimation scene center as the average of the intersection of selected pairs of camera rays + cams_ori = poses[...,3] + cams_dir = poses[:,:3,:3] @ torch.as_tensor([0.,0.,-1.]) + cams_dir = F.normalize(cams_dir, dim=-1) + A = torch.stack([cams_dir, -cams_dir.roll(1,0)], dim=-1) + b = -cams_ori + cams_ori.roll(1,0) + t = torch.linalg.lstsq(A, b).solution + center = (torch.stack([cams_dir, cams_dir.roll(1,0)], dim=-1) * t[:,None,:] + torch.stack([cams_ori, cams_ori.roll(1,0)], dim=-1)).mean((0,2)) + elif center_est_method == 'point': + # first estimation scene center as the average of all camera positions + # later we'll use the center of all points bounded by the cameras as the final scene center + center = poses[...,3].mean(0) + else: + raise NotImplementedError(f'Unknown center estimation method: {center_est_method}') + + if up_est_method == 'ground': + # estimate up direction as the normal of the estimated ground plane + # use RANSAC to estimate the ground plane in the point cloud + import pyransac3d as pyrsc + ground = pyrsc.Plane() + plane_eq, inliers = ground.fit(pts.numpy(), thresh=0.01) # TODO: determine thresh based on scene scale + plane_eq = torch.as_tensor(plane_eq) # A, B, C, D in Ax + By + Cz + D = 0 + z = F.normalize(plane_eq[:3], dim=-1) # plane normal as up direction + signed_distance = (torch.cat([pts, torch.ones_like(pts[...,0:1])], dim=-1) * plane_eq).sum(-1) + if signed_distance.mean() < 0: + z = -z # flip the direction if points lie under the plane + elif up_est_method == 'camera': + # estimate up direction as the average of all camera up directions + z = F.normalize((poses[...,3] - center).mean(0), dim=0) + else: + raise NotImplementedError(f'Unknown up estimation method: {up_est_method}') + + # new axis + y_ = torch.as_tensor([z[1], -z[0], 0.]) + x = F.normalize(y_.cross(z), dim=0) + y = z.cross(x) + + if center_est_method == 'point': + # rotation + Rc = torch.stack([x, y, z], dim=1) + R = Rc.T + poses_homo = torch.cat([poses, torch.as_tensor([[[0.,0.,0.,1.]]]).expand(poses.shape[0], -1, -1)], dim=1) + inv_trans = torch.cat([torch.cat([R, torch.as_tensor([[0.,0.,0.]]).T], dim=1), torch.as_tensor([[0.,0.,0.,1.]])], dim=0) + poses_norm = (inv_trans @ poses_homo)[:,:3] + pts = (inv_trans @ torch.cat([pts, torch.ones_like(pts[:,0:1])], dim=-1)[...,None])[:,:3,0] + + # translation and scaling + poses_min, poses_max = poses_norm[...,3].min(0)[0], poses_norm[...,3].max(0)[0] + pts_fg = pts[(poses_min[0] < pts[:,0]) & (pts[:,0] < poses_max[0]) & (poses_min[1] < pts[:,1]) & (pts[:,1] < poses_max[1])] + center = get_center(pts_fg) + tc = center.reshape(3, 1) + t = -tc + poses_homo = torch.cat([poses_norm, torch.as_tensor([[[0.,0.,0.,1.]]]).expand(poses_norm.shape[0], -1, -1)], dim=1) + inv_trans = torch.cat([torch.cat([torch.eye(3), t], dim=1), torch.as_tensor([[0.,0.,0.,1.]])], dim=0) + poses_norm = (inv_trans @ poses_homo)[:,:3] + scale = poses_norm[...,3].norm(p=2, dim=-1).min() + poses_norm[...,3] /= scale + pts = (inv_trans @ torch.cat([pts, torch.ones_like(pts[:,0:1])], dim=-1)[...,None])[:,:3,0] + pts = pts / scale + else: + # rotation and translation + Rc = torch.stack([x, y, z], dim=1) + tc = center.reshape(3, 1) + R, t = Rc.T, -Rc.T @ tc + poses_homo = torch.cat([poses, torch.as_tensor([[[0.,0.,0.,1.]]]).expand(poses.shape[0], -1, -1)], dim=1) + inv_trans = torch.cat([torch.cat([R, t], dim=1), torch.as_tensor([[0.,0.,0.,1.]])], dim=0) + poses_norm = (inv_trans @ poses_homo)[:,:3] # (N_images, 4, 4) + + # scaling + scale = poses_norm[...,3].norm(p=2, dim=-1).min() + poses_norm[...,3] /= scale + + # apply the transformation to the point cloud + pts = (inv_trans @ torch.cat([pts, torch.ones_like(pts[:,0:1])], dim=-1)[...,None])[:,:3,0] + pts = pts / scale + + return poses_norm, pts + +def create_spheric_poses(cameras, n_steps=120): + center = torch.as_tensor([0.,0.,0.], dtype=cameras.dtype, device=cameras.device) + mean_d = (cameras - center[None,:]).norm(p=2, dim=-1).mean() + mean_h = cameras[:,2].mean() + r = (mean_d**2 - mean_h**2).sqrt() + up = torch.as_tensor([0., 0., 1.], dtype=center.dtype, device=center.device) + + all_c2w = [] + for theta in torch.linspace(0, 2 * math.pi, n_steps): + cam_pos = torch.stack([r * theta.cos(), r * theta.sin(), mean_h]) + l = F.normalize(center - cam_pos, p=2, dim=0) + s = F.normalize(l.cross(up), p=2, dim=0) + u = F.normalize(s.cross(l), p=2, dim=0) + c2w = torch.cat([torch.stack([s, u, -l], dim=1), cam_pos[:,None]], axis=1) + all_c2w.append(c2w) + + all_c2w = torch.stack(all_c2w, dim=0) + + return all_c2w + +class ColmapDatasetBase(): + # the data only has to be processed once + initialized = False + properties = {} + + def setup(self, config, split): + self.config = config + self.split = split + self.rank = get_rank() + + if not ColmapDatasetBase.initialized: + camdata = read_cameras_binary(os.path.join(self.config.root_dir, 'sparse/0/cameras.bin')) + + H = int(camdata[1].height) + W = int(camdata[1].width) + + if 'img_wh' in self.config: + w, h = self.config.img_wh + assert round(W / w * h) == H + elif 'img_downscale' in self.config: + w, h = int(W / self.config.img_downscale + 0.5), int(H / self.config.img_downscale + 0.5) + else: + raise KeyError("Either img_wh or img_downscale should be specified.") + + img_wh = (w, h) + factor = w / W + + if camdata[1].model == 'SIMPLE_RADIAL': + fx = fy = camdata[1].params[0] * factor + cx = camdata[1].params[1] * factor + cy = camdata[1].params[2] * factor + elif camdata[1].model in ['PINHOLE', 'OPENCV']: + fx = camdata[1].params[0] * factor + fy = camdata[1].params[1] * factor + cx = camdata[1].params[2] * factor + cy = camdata[1].params[3] * factor + else: + raise ValueError(f"Please parse the intrinsics for camera model {camdata[1].model}!") + + directions = get_ray_directions(w, h, fx, fy, cx, cy).to(self.rank) + + imdata = read_images_binary(os.path.join(self.config.root_dir, 'sparse/0/images.bin')) + + mask_dir = os.path.join(self.config.root_dir, 'masks') + has_mask = os.path.exists(mask_dir) # TODO: support partial masks + apply_mask = has_mask and self.config.apply_mask + + all_c2w, all_images, all_fg_masks = [], [], [] + + for i, d in enumerate(imdata.values()): + R = d.qvec2rotmat() + t = d.tvec.reshape(3, 1) + c2w = torch.from_numpy(np.concatenate([R.T, -R.T@t], axis=1)).float() + c2w[:,1:3] *= -1. # COLMAP => OpenGL + all_c2w.append(c2w) + if self.split in ['train', 'val']: + img_path = os.path.join(self.config.root_dir, 'images', d.name) + img = Image.open(img_path) + img = img.resize(img_wh, Image.BICUBIC) + img = TF.to_tensor(img).permute(1, 2, 0)[...,:3] + img = img.to(self.rank) if self.config.load_data_on_gpu else img.cpu() + if has_mask: + mask_paths = [os.path.join(mask_dir, d.name), os.path.join(mask_dir, d.name[3:])] + mask_paths = list(filter(os.path.exists, mask_paths)) + assert len(mask_paths) == 1 + mask = Image.open(mask_paths[0]).convert('L') # (H, W, 1) + mask = mask.resize(img_wh, Image.BICUBIC) + mask = TF.to_tensor(mask)[0] + else: + mask = torch.ones_like(img[...,0], device=img.device) + all_fg_masks.append(mask) # (h, w) + all_images.append(img) + + all_c2w = torch.stack(all_c2w, dim=0) + + pts3d = read_points3d_binary(os.path.join(self.config.root_dir, 'sparse/0/points3D.bin')) + pts3d = torch.from_numpy(np.array([pts3d[k].xyz for k in pts3d])).float() + all_c2w, pts3d = normalize_poses(all_c2w, pts3d, up_est_method=self.config.up_est_method, center_est_method=self.config.center_est_method) + + ColmapDatasetBase.properties = { + 'w': w, + 'h': h, + 'img_wh': img_wh, + 'factor': factor, + 'has_mask': has_mask, + 'apply_mask': apply_mask, + 'directions': directions, + 'pts3d': pts3d, + 'all_c2w': all_c2w, + 'all_images': all_images, + 'all_fg_masks': all_fg_masks + } + + ColmapDatasetBase.initialized = True + + for k, v in ColmapDatasetBase.properties.items(): + setattr(self, k, v) + + if self.split == 'test': + self.all_c2w = create_spheric_poses(self.all_c2w[:,:,3], n_steps=self.config.n_test_traj_steps) + self.all_images = torch.zeros((self.config.n_test_traj_steps, self.h, self.w, 3), dtype=torch.float32) + self.all_fg_masks = torch.zeros((self.config.n_test_traj_steps, self.h, self.w), dtype=torch.float32) + else: + self.all_images, self.all_fg_masks = torch.stack(self.all_images, dim=0).float(), torch.stack(self.all_fg_masks, dim=0).float() + + """ + # for debug use + from models.ray_utils import get_rays + rays_o, rays_d = get_rays(self.directions.cpu(), self.all_c2w, keepdim=True) + pts_out = [] + pts_out.append('\n'.join([' '.join([str(p) for p in l]) + ' 1.0 0.0 0.0' for l in rays_o[:,0,0].reshape(-1, 3).tolist()])) + + t_vals = torch.linspace(0, 1, 8) + z_vals = 0.05 * (1 - t_vals) + 0.5 * t_vals + + ray_pts = (rays_o[:,0,0][..., None, :] + z_vals[..., None] * rays_d[:,0,0][..., None, :]) + pts_out.append('\n'.join([' '.join([str(p) for p in l]) + ' 0.0 1.0 0.0' for l in ray_pts.view(-1, 3).tolist()])) + + ray_pts = (rays_o[:,0,0][..., None, :] + z_vals[..., None] * rays_d[:,self.h-1,0][..., None, :]) + pts_out.append('\n'.join([' '.join([str(p) for p in l]) + ' 0.0 0.0 1.0' for l in ray_pts.view(-1, 3).tolist()])) + + ray_pts = (rays_o[:,0,0][..., None, :] + z_vals[..., None] * rays_d[:,0,self.w-1][..., None, :]) + pts_out.append('\n'.join([' '.join([str(p) for p in l]) + ' 0.0 1.0 1.0' for l in ray_pts.view(-1, 3).tolist()])) + + ray_pts = (rays_o[:,0,0][..., None, :] + z_vals[..., None] * rays_d[:,self.h-1,self.w-1][..., None, :]) + pts_out.append('\n'.join([' '.join([str(p) for p in l]) + ' 1.0 1.0 1.0' for l in ray_pts.view(-1, 3).tolist()])) + + open('cameras.txt', 'w').write('\n'.join(pts_out)) + open('scene.txt', 'w').write('\n'.join([' '.join([str(p) for p in l]) + ' 0.0 0.0 0.0' for l in self.pts3d.view(-1, 3).tolist()])) + + exit(1) + """ + + self.all_c2w = self.all_c2w.float().to(self.rank) + if self.config.load_data_on_gpu: + self.all_images = self.all_images.to(self.rank) + self.all_fg_masks = self.all_fg_masks.to(self.rank) + + +class ColmapDataset(Dataset, ColmapDatasetBase): + def __init__(self, config, split): + self.setup(config, split) + + def __len__(self): + return len(self.all_images) + + def __getitem__(self, index): + return { + 'index': index + } + + +class ColmapIterableDataset(IterableDataset, ColmapDatasetBase): + def __init__(self, config, split): + self.setup(config, split) + + def __iter__(self): + while True: + yield {} + + +@datasets.register('colmap') +class ColmapDataModule(pl.LightningDataModule): + def __init__(self, config): + super().__init__() + self.config = config + + def setup(self, stage=None): + if stage in [None, 'fit']: + self.train_dataset = ColmapIterableDataset(self.config, 'train') + if stage in [None, 'fit', 'validate']: + self.val_dataset = ColmapDataset(self.config, self.config.get('val_split', 'train')) + if stage in [None, 'test']: + self.test_dataset = ColmapDataset(self.config, self.config.get('test_split', 'test')) + if stage in [None, 'predict']: + self.predict_dataset = ColmapDataset(self.config, 'train') + + def prepare_data(self): + pass + + def general_loader(self, dataset, batch_size): + sampler = None + return DataLoader( + dataset, + num_workers=os.cpu_count(), + batch_size=batch_size, + pin_memory=True, + sampler=sampler + ) + + def train_dataloader(self): + return self.general_loader(self.train_dataset, batch_size=1) + + def val_dataloader(self): + return self.general_loader(self.val_dataset, batch_size=1) + + def test_dataloader(self): + return self.general_loader(self.test_dataset, batch_size=1) + + def predict_dataloader(self): + return self.general_loader(self.predict_dataset, batch_size=1) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/colmap_utils.py b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/colmap_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..fe5064d53fc4b3a738fc8ab6e52c7a5fee853d16 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/colmap_utils.py @@ -0,0 +1,295 @@ +# Copyright (c) 2018, ETH Zurich and UNC Chapel Hill. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of +# its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# Author: Johannes L. Schoenberger (jsch at inf.ethz.ch) + +import os +import collections +import numpy as np +import struct + + +CameraModel = collections.namedtuple( + "CameraModel", ["model_id", "model_name", "num_params"]) +Camera = collections.namedtuple( + "Camera", ["id", "model", "width", "height", "params"]) +BaseImage = collections.namedtuple( + "Image", ["id", "qvec", "tvec", "camera_id", "name", "xys", "point3D_ids"]) +Point3D = collections.namedtuple( + "Point3D", ["id", "xyz", "rgb", "error", "image_ids", "point2D_idxs"]) + +class Image(BaseImage): + def qvec2rotmat(self): + return qvec2rotmat(self.qvec) + + +CAMERA_MODELS = { + CameraModel(model_id=0, model_name="SIMPLE_PINHOLE", num_params=3), + CameraModel(model_id=1, model_name="PINHOLE", num_params=4), + CameraModel(model_id=2, model_name="SIMPLE_RADIAL", num_params=4), + CameraModel(model_id=3, model_name="RADIAL", num_params=5), + CameraModel(model_id=4, model_name="OPENCV", num_params=8), + CameraModel(model_id=5, model_name="OPENCV_FISHEYE", num_params=8), + CameraModel(model_id=6, model_name="FULL_OPENCV", num_params=12), + CameraModel(model_id=7, model_name="FOV", num_params=5), + CameraModel(model_id=8, model_name="SIMPLE_RADIAL_FISHEYE", num_params=4), + CameraModel(model_id=9, model_name="RADIAL_FISHEYE", num_params=5), + CameraModel(model_id=10, model_name="THIN_PRISM_FISHEYE", num_params=12) +} +CAMERA_MODEL_IDS = dict([(camera_model.model_id, camera_model) \ + for camera_model in CAMERA_MODELS]) + + +def read_next_bytes(fid, num_bytes, format_char_sequence, endian_character="<"): + """Read and unpack the next bytes from a binary file. + :param fid: + :param num_bytes: Sum of combination of {2, 4, 8}, e.g. 2, 6, 16, 30, etc. + :param format_char_sequence: List of {c, e, f, d, h, H, i, I, l, L, q, Q}. + :param endian_character: Any of {@, =, <, >, !} + :return: Tuple of read and unpacked values. + """ + data = fid.read(num_bytes) + return struct.unpack(endian_character + format_char_sequence, data) + + +def read_cameras_text(path): + """ + see: src/base/reconstruction.cc + void Reconstruction::WriteCamerasText(const std::string& path) + void Reconstruction::ReadCamerasText(const std::string& path) + """ + cameras = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + camera_id = int(elems[0]) + model = elems[1] + width = int(elems[2]) + height = int(elems[3]) + params = np.array(tuple(map(float, elems[4:]))) + cameras[camera_id] = Camera(id=camera_id, model=model, + width=width, height=height, + params=params) + return cameras + + +def read_cameras_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::WriteCamerasBinary(const std::string& path) + void Reconstruction::ReadCamerasBinary(const std::string& path) + """ + cameras = {} + with open(path_to_model_file, "rb") as fid: + num_cameras = read_next_bytes(fid, 8, "Q")[0] + for camera_line_index in range(num_cameras): + camera_properties = read_next_bytes( + fid, num_bytes=24, format_char_sequence="iiQQ") + camera_id = camera_properties[0] + model_id = camera_properties[1] + model_name = CAMERA_MODEL_IDS[camera_properties[1]].model_name + width = camera_properties[2] + height = camera_properties[3] + num_params = CAMERA_MODEL_IDS[model_id].num_params + params = read_next_bytes(fid, num_bytes=8*num_params, + format_char_sequence="d"*num_params) + cameras[camera_id] = Camera(id=camera_id, + model=model_name, + width=width, + height=height, + params=np.array(params)) + assert len(cameras) == num_cameras + return cameras + + +def read_images_text(path): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadImagesText(const std::string& path) + void Reconstruction::WriteImagesText(const std::string& path) + """ + images = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + image_id = int(elems[0]) + qvec = np.array(tuple(map(float, elems[1:5]))) + tvec = np.array(tuple(map(float, elems[5:8]))) + camera_id = int(elems[8]) + image_name = elems[9] + elems = fid.readline().split() + xys = np.column_stack([tuple(map(float, elems[0::3])), + tuple(map(float, elems[1::3]))]) + point3D_ids = np.array(tuple(map(int, elems[2::3]))) + images[image_id] = Image( + id=image_id, qvec=qvec, tvec=tvec, + camera_id=camera_id, name=image_name, + xys=xys, point3D_ids=point3D_ids) + return images + + +def read_images_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadImagesBinary(const std::string& path) + void Reconstruction::WriteImagesBinary(const std::string& path) + """ + images = {} + with open(path_to_model_file, "rb") as fid: + num_reg_images = read_next_bytes(fid, 8, "Q")[0] + for image_index in range(num_reg_images): + binary_image_properties = read_next_bytes( + fid, num_bytes=64, format_char_sequence="idddddddi") + image_id = binary_image_properties[0] + qvec = np.array(binary_image_properties[1:5]) + tvec = np.array(binary_image_properties[5:8]) + camera_id = binary_image_properties[8] + image_name = "" + current_char = read_next_bytes(fid, 1, "c")[0] + while current_char != b"\x00": # look for the ASCII 0 entry + image_name += current_char.decode("utf-8") + current_char = read_next_bytes(fid, 1, "c")[0] + num_points2D = read_next_bytes(fid, num_bytes=8, + format_char_sequence="Q")[0] + x_y_id_s = read_next_bytes(fid, num_bytes=24*num_points2D, + format_char_sequence="ddq"*num_points2D) + xys = np.column_stack([tuple(map(float, x_y_id_s[0::3])), + tuple(map(float, x_y_id_s[1::3]))]) + point3D_ids = np.array(tuple(map(int, x_y_id_s[2::3]))) + images[image_id] = Image( + id=image_id, qvec=qvec, tvec=tvec, + camera_id=camera_id, name=image_name, + xys=xys, point3D_ids=point3D_ids) + return images + + +def read_points3D_text(path): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadPoints3DText(const std::string& path) + void Reconstruction::WritePoints3DText(const std::string& path) + """ + points3D = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + point3D_id = int(elems[0]) + xyz = np.array(tuple(map(float, elems[1:4]))) + rgb = np.array(tuple(map(int, elems[4:7]))) + error = float(elems[7]) + image_ids = np.array(tuple(map(int, elems[8::2]))) + point2D_idxs = np.array(tuple(map(int, elems[9::2]))) + points3D[point3D_id] = Point3D(id=point3D_id, xyz=xyz, rgb=rgb, + error=error, image_ids=image_ids, + point2D_idxs=point2D_idxs) + return points3D + + +def read_points3d_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadPoints3DBinary(const std::string& path) + void Reconstruction::WritePoints3DBinary(const std::string& path) + """ + points3D = {} + with open(path_to_model_file, "rb") as fid: + num_points = read_next_bytes(fid, 8, "Q")[0] + for point_line_index in range(num_points): + binary_point_line_properties = read_next_bytes( + fid, num_bytes=43, format_char_sequence="QdddBBBd") + point3D_id = binary_point_line_properties[0] + xyz = np.array(binary_point_line_properties[1:4]) + rgb = np.array(binary_point_line_properties[4:7]) + error = np.array(binary_point_line_properties[7]) + track_length = read_next_bytes( + fid, num_bytes=8, format_char_sequence="Q")[0] + track_elems = read_next_bytes( + fid, num_bytes=8*track_length, + format_char_sequence="ii"*track_length) + image_ids = np.array(tuple(map(int, track_elems[0::2]))) + point2D_idxs = np.array(tuple(map(int, track_elems[1::2]))) + points3D[point3D_id] = Point3D( + id=point3D_id, xyz=xyz, rgb=rgb, + error=error, image_ids=image_ids, + point2D_idxs=point2D_idxs) + return points3D + + +def read_model(path, ext): + if ext == ".txt": + cameras = read_cameras_text(os.path.join(path, "cameras" + ext)) + images = read_images_text(os.path.join(path, "images" + ext)) + points3D = read_points3D_text(os.path.join(path, "points3D") + ext) + else: + cameras = read_cameras_binary(os.path.join(path, "cameras" + ext)) + images = read_images_binary(os.path.join(path, "images" + ext)) + points3D = read_points3d_binary(os.path.join(path, "points3D") + ext) + return cameras, images, points3D + + +def qvec2rotmat(qvec): + return np.array([ + [1 - 2 * qvec[2]**2 - 2 * qvec[3]**2, + 2 * qvec[1] * qvec[2] - 2 * qvec[0] * qvec[3], + 2 * qvec[3] * qvec[1] + 2 * qvec[0] * qvec[2]], + [2 * qvec[1] * qvec[2] + 2 * qvec[0] * qvec[3], + 1 - 2 * qvec[1]**2 - 2 * qvec[3]**2, + 2 * qvec[2] * qvec[3] - 2 * qvec[0] * qvec[1]], + [2 * qvec[3] * qvec[1] - 2 * qvec[0] * qvec[2], + 2 * qvec[2] * qvec[3] + 2 * qvec[0] * qvec[1], + 1 - 2 * qvec[1]**2 - 2 * qvec[2]**2]]) + + +def rotmat2qvec(R): + Rxx, Ryx, Rzx, Rxy, Ryy, Rzy, Rxz, Ryz, Rzz = R.flat + K = np.array([ + [Rxx - Ryy - Rzz, 0, 0, 0], + [Ryx + Rxy, Ryy - Rxx - Rzz, 0, 0], + [Rzx + Rxz, Rzy + Ryz, Rzz - Rxx - Ryy, 0], + [Ryz - Rzy, Rzx - Rxz, Rxy - Ryx, Rxx + Ryy + Rzz]]) / 3.0 + eigvals, eigvecs = np.linalg.eigh(K) + qvec = eigvecs[[3, 0, 1, 2], np.argmax(eigvals)] + if qvec[0] < 0: + qvec *= -1 + return qvec diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/dtu.py b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/dtu.py new file mode 100644 index 0000000000000000000000000000000000000000..39e3a36c54e95ca436ca99cc1e4d94d291c52b11 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/dtu.py @@ -0,0 +1,201 @@ +import os +import json +import math +import numpy as np +from PIL import Image +import cv2 + +import torch +import torch.nn.functional as F +from torch.utils.data import Dataset, DataLoader, IterableDataset +import torchvision.transforms.functional as TF + +import pytorch_lightning as pl + +import datasets +from models.ray_utils import get_ray_directions +from utils.misc import get_rank + + +def load_K_Rt_from_P(P=None): + out = cv2.decomposeProjectionMatrix(P) + K = out[0] + R = out[1] + t = out[2] + + K = K / K[2, 2] + intrinsics = np.eye(4) + intrinsics[:3, :3] = K + + pose = np.eye(4, dtype=np.float32) + pose[:3, :3] = R.transpose() + pose[:3, 3] = (t[:3] / t[3])[:, 0] + + return intrinsics, pose + +def create_spheric_poses(cameras, n_steps=120): + center = torch.as_tensor([0.,0.,0.], dtype=cameras.dtype, device=cameras.device) + cam_center = F.normalize(cameras.mean(0), p=2, dim=-1) * cameras.mean(0).norm(2) + eigvecs = torch.linalg.eig(cameras.T @ cameras).eigenvectors + rot_axis = F.normalize(eigvecs[:,1].real.float(), p=2, dim=-1) + up = rot_axis + rot_dir = torch.cross(rot_axis, cam_center) + max_angle = (F.normalize(cameras, p=2, dim=-1) * F.normalize(cam_center, p=2, dim=-1)).sum(-1).acos().max() + + all_c2w = [] + for theta in torch.linspace(-max_angle, max_angle, n_steps): + cam_pos = cam_center * math.cos(theta) + rot_dir * math.sin(theta) + l = F.normalize(center - cam_pos, p=2, dim=0) + s = F.normalize(l.cross(up), p=2, dim=0) + u = F.normalize(s.cross(l), p=2, dim=0) + c2w = torch.cat([torch.stack([s, u, -l], dim=1), cam_pos[:,None]], axis=1) + all_c2w.append(c2w) + + all_c2w = torch.stack(all_c2w, dim=0) + + return all_c2w + +class DTUDatasetBase(): + def setup(self, config, split): + self.config = config + self.split = split + self.rank = get_rank() + + cams = np.load(os.path.join(self.config.root_dir, self.config.cameras_file)) + + img_sample = cv2.imread(os.path.join(self.config.root_dir, 'image', '000000.png')) + H, W = img_sample.shape[0], img_sample.shape[1] + + if 'img_wh' in self.config: + w, h = self.config.img_wh + assert round(W / w * h) == H + elif 'img_downscale' in self.config: + w, h = int(W / self.config.img_downscale + 0.5), int(H / self.config.img_downscale + 0.5) + else: + raise KeyError("Either img_wh or img_downscale should be specified.") + + self.w, self.h = w, h + self.img_wh = (w, h) + self.factor = w / W + + mask_dir = os.path.join(self.config.root_dir, 'mask') + self.has_mask = True + self.apply_mask = self.config.apply_mask + + self.directions = [] + self.all_c2w, self.all_images, self.all_fg_masks = [], [], [] + + n_images = max([int(k.split('_')[-1]) for k in cams.keys()]) + 1 + + for i in range(n_images): + world_mat, scale_mat = cams[f'world_mat_{i}'], cams[f'scale_mat_{i}'] + P = (world_mat @ scale_mat)[:3,:4] + K, c2w = load_K_Rt_from_P(P) + fx, fy, cx, cy = K[0,0] * self.factor, K[1,1] * self.factor, K[0,2] * self.factor, K[1,2] * self.factor + directions = get_ray_directions(w, h, fx, fy, cx, cy) + self.directions.append(directions) + + c2w = torch.from_numpy(c2w).float() + + # blender follows opengl camera coordinates (right up back) + # NeuS DTU data coordinate system (right down front) is different from blender + # https://github.com/Totoro97/NeuS/issues/9 + # for c2w, flip the sign of input camera coordinate yz + c2w_ = c2w.clone() + c2w_[:3,1:3] *= -1. # flip input sign + self.all_c2w.append(c2w_[:3,:4]) + + if self.split in ['train', 'val']: + img_path = os.path.join(self.config.root_dir, 'image', f'{i:06d}.png') + img = Image.open(img_path) + img = img.resize(self.img_wh, Image.BICUBIC) + img = TF.to_tensor(img).permute(1, 2, 0)[...,:3] + + mask_path = os.path.join(mask_dir, f'{i:03d}.png') + mask = Image.open(mask_path).convert('L') # (H, W, 1) + mask = mask.resize(self.img_wh, Image.BICUBIC) + mask = TF.to_tensor(mask)[0] + + self.all_fg_masks.append(mask) # (h, w) + self.all_images.append(img) + + self.all_c2w = torch.stack(self.all_c2w, dim=0) + + if self.split == 'test': + self.all_c2w = create_spheric_poses(self.all_c2w[:,:,3], n_steps=self.config.n_test_traj_steps) + self.all_images = torch.zeros((self.config.n_test_traj_steps, self.h, self.w, 3), dtype=torch.float32) + self.all_fg_masks = torch.zeros((self.config.n_test_traj_steps, self.h, self.w), dtype=torch.float32) + self.directions = self.directions[0] + else: + self.all_images, self.all_fg_masks = torch.stack(self.all_images, dim=0), torch.stack(self.all_fg_masks, dim=0) + self.directions = torch.stack(self.directions, dim=0) + + self.directions = self.directions.float().to(self.rank) + self.all_c2w, self.all_images, self.all_fg_masks = \ + self.all_c2w.float().to(self.rank), \ + self.all_images.float().to(self.rank), \ + self.all_fg_masks.float().to(self.rank) + + +class DTUDataset(Dataset, DTUDatasetBase): + def __init__(self, config, split): + self.setup(config, split) + + def __len__(self): + return len(self.all_images) + + def __getitem__(self, index): + return { + 'index': index + } + + +class DTUIterableDataset(IterableDataset, DTUDatasetBase): + def __init__(self, config, split): + self.setup(config, split) + + def __iter__(self): + while True: + yield {} + + +@datasets.register('dtu') +class DTUDataModule(pl.LightningDataModule): + def __init__(self, config): + super().__init__() + self.config = config + + def setup(self, stage=None): + if stage in [None, 'fit']: + self.train_dataset = DTUIterableDataset(self.config, 'train') + if stage in [None, 'fit', 'validate']: + self.val_dataset = DTUDataset(self.config, self.config.get('val_split', 'train')) + if stage in [None, 'test']: + self.test_dataset = DTUDataset(self.config, self.config.get('test_split', 'test')) + if stage in [None, 'predict']: + self.predict_dataset = DTUDataset(self.config, 'train') + + def prepare_data(self): + pass + + def general_loader(self, dataset, batch_size): + sampler = None + return DataLoader( + dataset, + num_workers=os.cpu_count(), + batch_size=batch_size, + pin_memory=True, + sampler=sampler + ) + + def train_dataloader(self): + return self.general_loader(self.train_dataset, batch_size=1) + + def val_dataloader(self): + return self.general_loader(self.val_dataset, batch_size=1) + + def test_dataloader(self): + return self.general_loader(self.test_dataset, batch_size=1) + + def predict_dataloader(self): + return self.general_loader(self.predict_dataset, batch_size=1) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b839ed2505438786e2d33bd779b77ed1eedb778 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_RT.txt @@ -0,0 +1,3 @@ +-1.000000238418579102e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 +0.000000000000000000e+00 -1.343588564850506373e-07 1.000000119209289551e+00 1.746665105883948854e-07 +0.000000000000000000e+00 1.000000119209289551e+00 -1.343588564850506373e-07 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_left_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..97b10e711b1a86782cb69798051df209e8943b19 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_left_RT.txt @@ -0,0 +1,3 @@ +-7.071069478988647461e-01 -7.071068286895751953e-01 0.000000000000000000e+00 -1.192092895507812500e-07 +0.000000000000000000e+00 -7.587616579485256807e-08 1.000000119209289551e+00 9.863901340168013121e-08 +-7.071068286895751953e-01 7.071068286895751953e-01 -7.587616579485256807e-08 -1.838477730751037598e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_right_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c7ce665f9ee958fe56e1589f52e4e772f3069e1 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_back_right_RT.txt @@ -0,0 +1,3 @@ +-7.071069478988647461e-01 7.071068286895751953e-01 0.000000000000000000e+00 1.192092895507812500e-07 +0.000000000000000000e+00 -7.587616579485256807e-08 1.000000119209289551e+00 9.863901340168013121e-08 +7.071068286895751953e-01 7.071068286895751953e-01 -7.587616579485256807e-08 -1.838477730751037598e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..67db8bce2207aabc0b8fcf9db25a0af8b9dd9e7b --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_RT.txt @@ -0,0 +1,3 @@ +1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 +0.000000000000000000e+00 -1.343588564850506373e-07 1.000000119209289551e+00 -1.746665105883948854e-07 +0.000000000000000000e+00 -1.000000119209289551e+00 -1.343588564850506373e-07 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_left_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..bed4b8cf8913b5fbf1ec092bceea4da0e4014133 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_left_RT.txt @@ -0,0 +1,3 @@ +7.071067690849304199e-01 -7.071068286895751953e-01 0.000000000000000000e+00 -1.192092895507812500e-07 +0.000000000000000000e+00 -7.587616579485256807e-08 1.000000119209289551e+00 -9.863901340168013121e-08 +-7.071068286895751953e-01 -7.071068286895751953e-01 -7.587616579485256807e-08 -1.838477730751037598e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_right_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..56064b9ddb2afa5ae1db28cd70a93018c1f59c33 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_front_right_RT.txt @@ -0,0 +1,3 @@ +7.071067690849304199e-01 7.071068286895751953e-01 0.000000000000000000e+00 1.192092895507812500e-07 +0.000000000000000000e+00 -7.587616579485256807e-08 1.000000119209289551e+00 -9.863901340168013121e-08 +7.071068286895751953e-01 -7.071068286895751953e-01 -7.587616579485256807e-08 -1.838477730751037598e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_left_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..465ebaee41f28ba09c6e44451a9c200d4c23bf95 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_left_RT.txt @@ -0,0 +1,3 @@ +-2.220446049250313081e-16 -1.000000000000000000e+00 0.000000000000000000e+00 -2.886579758146288598e-16 +0.000000000000000000e+00 -2.220446049250313081e-16 1.000000000000000000e+00 0.000000000000000000e+00 +-1.000000000000000000e+00 0.000000000000000000e+00 -2.220446049250313081e-16 -1.299999952316284180e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_right_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a0c740f885267b285a6585ad4058536205181c5 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_right_RT.txt @@ -0,0 +1,3 @@ +-2.220446049250313081e-16 1.000000000000000000e+00 0.000000000000000000e+00 2.886579758146288598e-16 +0.000000000000000000e+00 -2.220446049250313081e-16 1.000000000000000000e+00 0.000000000000000000e+00 +1.000000000000000000e+00 0.000000000000000000e+00 -2.220446049250313081e-16 -1.299999952316284180e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_top_RT.txt b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_top_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..eba7ea36b7d091f390bae16d1428b52b5287bef0 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/fixed_poses/000_top_RT.txt @@ -0,0 +1,3 @@ +1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 +0.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 +0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 -1.299999952316284180e+00 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/ortho.py b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/ortho.py new file mode 100644 index 0000000000000000000000000000000000000000..b29664e1ebda5baf64e57d56e21250cf4a7692ba --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/ortho.py @@ -0,0 +1,287 @@ +import os +import json +import math +import numpy as np +from PIL import Image +import cv2 + +import torch +import torch.nn.functional as F +from torch.utils.data import Dataset, DataLoader, IterableDataset +import torchvision.transforms.functional as TF + +import pytorch_lightning as pl + +import datasets +from models.ray_utils import get_ortho_ray_directions_origins, get_ortho_rays, get_ray_directions +from utils.misc import get_rank + +from glob import glob +import PIL.Image + + +def camNormal2worldNormal(rot_c2w, camNormal): + H,W,_ = camNormal.shape + normal_img = np.matmul(rot_c2w[None, :, :], camNormal.reshape(-1,3)[:, :, None]).reshape([H, W, 3]) + + return normal_img + +def worldNormal2camNormal(rot_w2c, worldNormal): + H,W,_ = worldNormal.shape + normal_img = np.matmul(rot_w2c[None, :, :], worldNormal.reshape(-1,3)[:, :, None]).reshape([H, W, 3]) + + return normal_img + +def trans_normal(normal, RT_w2c, RT_w2c_target): + + normal_world = camNormal2worldNormal(np.linalg.inv(RT_w2c[:3,:3]), normal) + normal_target_cam = worldNormal2camNormal(RT_w2c_target[:3,:3], normal_world) + + return normal_target_cam + +def img2normal(img): + return (img/255.)*2-1 + +def normal2img(normal): + return np.uint8((normal*0.5+0.5)*255) + +def norm_normalize(normal, dim=-1): + + normal = normal/(np.linalg.norm(normal, axis=dim, keepdims=True)+1e-6) + + return normal + +def RT_opengl2opencv(RT): + # Build the coordinate transform matrix from world to computer vision camera + # R_world2cv = R_bcam2cv@R_world2bcam + # T_world2cv = R_bcam2cv@T_world2bcam + + R = RT[:3, :3] + t = RT[:3, 3] + + R_bcam2cv = np.asarray([[1, 0, 0], [0, -1, 0], [0, 0, -1]], np.float32) + + R_world2cv = R_bcam2cv @ R + t_world2cv = R_bcam2cv @ t + + RT = np.concatenate([R_world2cv,t_world2cv[:,None]],1) + + return RT + +def normal_opengl2opencv(normal): + H,W,C = np.shape(normal) + # normal_img = np.reshape(normal, (H*W,C)) + R_bcam2cv = np.array([1, -1, -1], np.float32) + normal_cv = normal * R_bcam2cv[None, None, :] + + print(np.shape(normal_cv)) + + return normal_cv + +def inv_RT(RT): + RT_h = np.concatenate([RT, np.array([[0,0,0,1]])], axis=0) + RT_inv = np.linalg.inv(RT_h) + + return RT_inv[:3, :] + + +def load_a_prediction(root_dir, test_object, imSize, view_types, load_color=False, cam_pose_dir=None, + normal_system='front', erode_mask=True, camera_type='ortho', cam_params=None): + + all_images = [] + all_normals = [] + all_normals_world = [] + all_masks = [] + all_color_masks = [] + all_poses = [] + all_w2cs = [] + directions = [] + ray_origins = [] + + RT_front = np.loadtxt(glob(os.path.join(cam_pose_dir, '*_%s_RT.txt'%( 'front')))[0]) # world2cam matrix + RT_front_cv = RT_opengl2opencv(RT_front) # convert normal from opengl to opencv + for idx, view in enumerate(view_types): + print(os.path.join(root_dir,test_object)) + normal_filepath = os.path.join(root_dir, test_object, 'normals_000_%s.png'%( view)) + # Load key frame + if load_color: # use bgr + image =np.array(PIL.Image.open(normal_filepath.replace("normals", "rgb")).resize(imSize))[:, :, :3] + + normal = np.array(PIL.Image.open(normal_filepath).resize(imSize)) + mask = normal[:, :, 3] + normal = normal[:, :, :3] + + color_mask = np.array(PIL.Image.open(os.path.join(root_dir,test_object, 'masked_colors/rgb_000_%s.png'%( view))).resize(imSize))[:, :, 3] + invalid_color_mask = color_mask < 255*0.5 + threshold = np.ones_like(image[:, :, 0]) * 250 + invalid_white_mask = (image[:, :, 0] > threshold) & (image[:, :, 1] > threshold) & (image[:, :, 2] > threshold) + invalid_color_mask_final = invalid_color_mask & invalid_white_mask + color_mask = (1 - invalid_color_mask_final) > 0 + + # if erode_mask: + # kernel = np.ones((3, 3), np.uint8) + # mask = cv2.erode(mask, kernel, iterations=1) + + RT = np.loadtxt(os.path.join(cam_pose_dir, '000_%s_RT.txt'%( view))) # world2cam matrix + + normal = img2normal(normal) + + normal[mask==0] = [0,0,0] + mask = mask> (0.5*255) + if load_color: + all_images.append(image) + + all_masks.append(mask) + all_color_masks.append(color_mask) + RT_cv = RT_opengl2opencv(RT) # convert normal from opengl to opencv + all_poses.append(inv_RT(RT_cv)) # cam2world + all_w2cs.append(RT_cv) + + # whether to + normal_cam_cv = normal_opengl2opencv(normal) + + if normal_system == 'front': + print("the loaded normals are defined in the system of front view") + normal_world = camNormal2worldNormal(inv_RT(RT_front_cv)[:3, :3], normal_cam_cv) + elif normal_system == 'self': + print("the loaded normals are in their independent camera systems") + normal_world = camNormal2worldNormal(inv_RT(RT_cv)[:3, :3], normal_cam_cv) + all_normals.append(normal_cam_cv) + all_normals_world.append(normal_world) + + if camera_type == 'ortho': + origins, dirs = get_ortho_ray_directions_origins(W=imSize[0], H=imSize[1]) + elif camera_type == 'pinhole': + dirs = get_ray_directions(W=imSize[0], H=imSize[1], + fx=cam_params[0], fy=cam_params[1], cx=cam_params[2], cy=cam_params[3]) + origins = dirs # occupy a position + else: + raise Exception("not support camera type") + ray_origins.append(origins) + directions.append(dirs) + + + if not load_color: + all_images = [normal2img(x) for x in all_normals_world] + + + return np.stack(all_images), np.stack(all_masks), np.stack(all_normals), \ + np.stack(all_normals_world), np.stack(all_poses), np.stack(all_w2cs), np.stack(ray_origins), np.stack(directions), np.stack(all_color_masks) + + +class OrthoDatasetBase(): + def setup(self, config, split): + self.config = config + self.split = split + self.rank = get_rank() + + self.data_dir = self.config.root_dir + self.object_name = self.config.scene + self.scene = self.config.scene + self.imSize = self.config.imSize + self.load_color = True + self.img_wh = [self.imSize[0], self.imSize[1]] + self.w = self.img_wh[0] + self.h = self.img_wh[1] + self.camera_type = self.config.camera_type + self.camera_params = self.config.camera_params # [fx, fy, cx, cy] + + self.view_types = ['front', 'front_right', 'right', 'back', 'left', 'front_left'] + + self.view_weights = torch.from_numpy(np.array(self.config.view_weights)).float().to(self.rank).view(-1) + self.view_weights = self.view_weights.view(-1,1,1).repeat(1, self.h, self.w) + + if self.config.cam_pose_dir is None: + self.cam_pose_dir = "./datasets/fixed_poses" + else: + self.cam_pose_dir = self.config.cam_pose_dir + + self.images_np, self.masks_np, self.normals_cam_np, self.normals_world_np, \ + self.pose_all_np, self.w2c_all_np, self.origins_np, self.directions_np, self.rgb_masks_np = load_a_prediction( + self.data_dir, self.object_name, self.imSize, self.view_types, + self.load_color, self.cam_pose_dir, normal_system='front', + camera_type=self.camera_type, cam_params=self.camera_params) + + self.has_mask = True + self.apply_mask = self.config.apply_mask + + self.all_c2w = torch.from_numpy(self.pose_all_np) + self.all_images = torch.from_numpy(self.images_np) / 255. + self.all_fg_masks = torch.from_numpy(self.masks_np) + self.all_rgb_masks = torch.from_numpy(self.rgb_masks_np) + self.all_normals_world = torch.from_numpy(self.normals_world_np) + self.origins = torch.from_numpy(self.origins_np) + self.directions = torch.from_numpy(self.directions_np) + + self.directions = self.directions.float().to(self.rank) + self.origins = self.origins.float().to(self.rank) + self.all_rgb_masks = self.all_rgb_masks.float().to(self.rank) + self.all_c2w, self.all_images, self.all_fg_masks, self.all_normals_world = \ + self.all_c2w.float().to(self.rank), \ + self.all_images.float().to(self.rank), \ + self.all_fg_masks.float().to(self.rank), \ + self.all_normals_world.float().to(self.rank) + + +class OrthoDataset(Dataset, OrthoDatasetBase): + def __init__(self, config, split): + self.setup(config, split) + + def __len__(self): + return len(self.all_images) + + def __getitem__(self, index): + return { + 'index': index + } + + +class OrthoIterableDataset(IterableDataset, OrthoDatasetBase): + def __init__(self, config, split): + self.setup(config, split) + + def __iter__(self): + while True: + yield {} + + +@datasets.register('ortho') +class OrthoDataModule(pl.LightningDataModule): + def __init__(self, config): + super().__init__() + self.config = config + + def setup(self, stage=None): + if stage in [None, 'fit']: + self.train_dataset = OrthoIterableDataset(self.config, 'train') + if stage in [None, 'fit', 'validate']: + self.val_dataset = OrthoDataset(self.config, self.config.get('val_split', 'train')) + if stage in [None, 'test']: + self.test_dataset = OrthoDataset(self.config, self.config.get('test_split', 'test')) + if stage in [None, 'predict']: + self.predict_dataset = OrthoDataset(self.config, 'train') + + def prepare_data(self): + pass + + def general_loader(self, dataset, batch_size): + sampler = None + return DataLoader( + dataset, + num_workers=os.cpu_count(), + batch_size=batch_size, + pin_memory=True, + sampler=sampler + ) + + def train_dataloader(self): + return self.general_loader(self.train_dataset, batch_size=1) + + def val_dataloader(self): + return self.general_loader(self.val_dataset, batch_size=1) + + def test_dataloader(self): + return self.general_loader(self.test_dataset, batch_size=1) + + def predict_dataloader(self): + return self.general_loader(self.predict_dataset, batch_size=1) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/datasets/utils.py b/apps/third_party/Wonder3D/instant-nsr-pl/datasets/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/launch.py b/apps/third_party/Wonder3D/instant-nsr-pl/launch.py new file mode 100644 index 0000000000000000000000000000000000000000..50cc6bea0e9627a819ea74bde50f5f8707da957c --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/launch.py @@ -0,0 +1,125 @@ +import sys +import argparse +import os +import time +import logging +from datetime import datetime + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--config', required=True, help='path to config file') + parser.add_argument('--gpu', default='0', help='GPU(s) to be used') + parser.add_argument('--resume', default=None, help='path to the weights to be resumed') + parser.add_argument( + '--resume_weights_only', + action='store_true', + help='specify this argument to restore only the weights (w/o training states), e.g. --resume path/to/resume --resume_weights_only' + ) + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--train', action='store_true') + group.add_argument('--validate', action='store_true') + group.add_argument('--test', action='store_true') + group.add_argument('--predict', action='store_true') + # group.add_argument('--export', action='store_true') # TODO: a separate export action + + parser.add_argument('--exp_dir', default='./exp') + parser.add_argument('--runs_dir', default='./runs') + parser.add_argument('--verbose', action='store_true', help='if true, set logging level to DEBUG') + + args, extras = parser.parse_known_args() + + # set CUDA_VISIBLE_DEVICES then import pytorch-lightning + os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID' + os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu + n_gpus = len(args.gpu.split(',')) + + import datasets + import systems + import pytorch_lightning as pl + from pytorch_lightning import Trainer + from pytorch_lightning.callbacks import ModelCheckpoint, LearningRateMonitor + from pytorch_lightning.loggers import TensorBoardLogger, CSVLogger + from utils.callbacks import CodeSnapshotCallback, ConfigSnapshotCallback, CustomProgressBar + from utils.misc import load_config + + # parse YAML config to OmegaConf + config = load_config(args.config, cli_args=extras) + config.cmd_args = vars(args) + + config.trial_name = config.get('trial_name') or (config.tag + datetime.now().strftime('@%Y%m%d-%H%M%S')) + config.exp_dir = config.get('exp_dir') or os.path.join(args.exp_dir, config.name) + config.save_dir = config.get('save_dir') or os.path.join(config.exp_dir, config.trial_name, 'save') + config.ckpt_dir = config.get('ckpt_dir') or os.path.join(config.exp_dir, config.trial_name, 'ckpt') + config.code_dir = config.get('code_dir') or os.path.join(config.exp_dir, config.trial_name, 'code') + config.config_dir = config.get('config_dir') or os.path.join(config.exp_dir, config.trial_name, 'config') + + logger = logging.getLogger('pytorch_lightning') + if args.verbose: + logger.setLevel(logging.DEBUG) + + if 'seed' not in config: + config.seed = int(time.time() * 1000) % 1000 + pl.seed_everything(config.seed) + + dm = datasets.make(config.dataset.name, config.dataset) + system = systems.make(config.system.name, config, load_from_checkpoint=None if not args.resume_weights_only else args.resume) + + callbacks = [] + if args.train: + callbacks += [ + ModelCheckpoint( + dirpath=config.ckpt_dir, + **config.checkpoint + ), + LearningRateMonitor(logging_interval='step'), + CodeSnapshotCallback( + config.code_dir, use_version=False + ), + ConfigSnapshotCallback( + config, config.config_dir, use_version=False + ), + CustomProgressBar(refresh_rate=1), + ] + + loggers = [] + if args.train: + loggers += [ + TensorBoardLogger(args.runs_dir, name=config.name, version=config.trial_name), + CSVLogger(config.exp_dir, name=config.trial_name, version='csv_logs') + ] + + if sys.platform == 'win32': + # does not support multi-gpu on windows + strategy = 'dp' + assert n_gpus == 1 + else: + strategy = 'ddp_find_unused_parameters_false' + + trainer = Trainer( + devices=n_gpus, + accelerator='gpu', + callbacks=callbacks, + logger=loggers, + strategy=strategy, + **config.trainer + ) + + if args.train: + if args.resume and not args.resume_weights_only: + # FIXME: different behavior in pytorch-lighting>1.9 ? + trainer.fit(system, datamodule=dm, ckpt_path=args.resume) + else: + trainer.fit(system, datamodule=dm) + trainer.test(system, datamodule=dm) + elif args.validate: + trainer.validate(system, datamodule=dm, ckpt_path=args.resume) + elif args.test: + trainer.test(system, datamodule=dm, ckpt_path=args.resume) + elif args.predict: + trainer.predict(system, datamodule=dm, ckpt_path=args.resume) + + +if __name__ == '__main__': + main() diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/__init__.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f2fa8c5785d3371ad963aca212ae0da32644c175 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/__init__.py @@ -0,0 +1,16 @@ +models = {} + + +def register(name): + def decorator(cls): + models[name] = cls + return cls + return decorator + + +def make(name, config): + model = models[name](config) + return model + + +from . import nerf, neus, geometry, texture diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/base.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/base.py new file mode 100644 index 0000000000000000000000000000000000000000..47b853bc9502ff2581639b5a6bc7313ffe0ec9ec --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/base.py @@ -0,0 +1,32 @@ +import torch +import torch.nn as nn + +from utils.misc import get_rank + +class BaseModel(nn.Module): + def __init__(self, config): + super().__init__() + self.config = config + self.rank = get_rank() + self.setup() + if self.config.get('weights', None): + self.load_state_dict(torch.load(self.config.weights)) + + def setup(self): + raise NotImplementedError + + def update_step(self, epoch, global_step): + pass + + def train(self, mode=True): + return super().train(mode=mode) + + def eval(self): + return super().eval() + + def regularizations(self, out): + return {} + + @torch.no_grad() + def export(self, export_config): + return {} diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/geometry.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/geometry.py new file mode 100644 index 0000000000000000000000000000000000000000..861edbe2726bb19e7c705c419837f369de170f28 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/geometry.py @@ -0,0 +1,238 @@ +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +from pytorch_lightning.utilities.rank_zero import rank_zero_info + +import models +from models.base import BaseModel +from models.utils import scale_anything, get_activation, cleanup, chunk_batch +from models.network_utils import get_encoding, get_mlp, get_encoding_with_network +from utils.misc import get_rank +from systems.utils import update_module_step +from nerfacc import ContractionType + + +def contract_to_unisphere(x, radius, contraction_type): + if contraction_type == ContractionType.AABB: + x = scale_anything(x, (-radius, radius), (0, 1)) + elif contraction_type == ContractionType.UN_BOUNDED_SPHERE: + x = scale_anything(x, (-radius, radius), (0, 1)) + x = x * 2 - 1 # aabb is at [-1, 1] + mag = x.norm(dim=-1, keepdim=True) + mask = mag.squeeze(-1) > 1 + x[mask] = (2 - 1 / mag[mask]) * (x[mask] / mag[mask]) + x = x / 4 + 0.5 # [-inf, inf] is at [0, 1] + else: + raise NotImplementedError + return x + + +class MarchingCubeHelper(nn.Module): + def __init__(self, resolution, use_torch=True): + super().__init__() + self.resolution = resolution + self.use_torch = use_torch + self.points_range = (0, 1) + if self.use_torch: + import torchmcubes + self.mc_func = torchmcubes.marching_cubes + else: + import mcubes + self.mc_func = mcubes.marching_cubes + self.verts = None + + def grid_vertices(self): + if self.verts is None: + x, y, z = torch.linspace(*self.points_range, self.resolution), torch.linspace(*self.points_range, self.resolution), torch.linspace(*self.points_range, self.resolution) + x, y, z = torch.meshgrid(x, y, z, indexing='ij') + verts = torch.cat([x.reshape(-1, 1), y.reshape(-1, 1), z.reshape(-1, 1)], dim=-1).reshape(-1, 3) + self.verts = verts + return self.verts + + def forward(self, level, threshold=0.): + level = level.float().view(self.resolution, self.resolution, self.resolution) + if self.use_torch: + verts, faces = self.mc_func(level.to(get_rank()), threshold) + verts, faces = verts.cpu(), faces.cpu().long() + else: + verts, faces = self.mc_func(-level.numpy(), threshold) # transform to numpy + verts, faces = torch.from_numpy(verts.astype(np.float32)), torch.from_numpy(faces.astype(np.int64)) # transform back to pytorch + verts = verts / (self.resolution - 1.) + return { + 'v_pos': verts, + 't_pos_idx': faces + } + + +class BaseImplicitGeometry(BaseModel): + def __init__(self, config): + super().__init__(config) + if self.config.isosurface is not None: + assert self.config.isosurface.method in ['mc', 'mc-torch'] + if self.config.isosurface.method == 'mc-torch': + raise NotImplementedError("Please do not use mc-torch. It currently has some scaling issues I haven't fixed yet.") + self.helper = MarchingCubeHelper(self.config.isosurface.resolution, use_torch=self.config.isosurface.method=='mc-torch') + self.radius = self.config.radius + self.contraction_type = None # assigned in system + + def forward_level(self, points): + raise NotImplementedError + + def isosurface_(self, vmin, vmax): + def batch_func(x): + x = torch.stack([ + scale_anything(x[...,0], (0, 1), (vmin[0], vmax[0])), + scale_anything(x[...,1], (0, 1), (vmin[1], vmax[1])), + scale_anything(x[...,2], (0, 1), (vmin[2], vmax[2])), + ], dim=-1).to(self.rank) + rv = self.forward_level(x).cpu() + cleanup() + return rv + + level = chunk_batch(batch_func, self.config.isosurface.chunk, True, self.helper.grid_vertices()) + mesh = self.helper(level, threshold=self.config.isosurface.threshold) + mesh['v_pos'] = torch.stack([ + scale_anything(mesh['v_pos'][...,0], (0, 1), (vmin[0], vmax[0])), + scale_anything(mesh['v_pos'][...,1], (0, 1), (vmin[1], vmax[1])), + scale_anything(mesh['v_pos'][...,2], (0, 1), (vmin[2], vmax[2])) + ], dim=-1) + return mesh + + @torch.no_grad() + def isosurface(self): + if self.config.isosurface is None: + raise NotImplementedError + mesh_coarse = self.isosurface_((-self.radius, -self.radius, -self.radius), (self.radius, self.radius, self.radius)) + vmin, vmax = mesh_coarse['v_pos'].amin(dim=0), mesh_coarse['v_pos'].amax(dim=0) + vmin_ = (vmin - (vmax - vmin) * 0.1).clamp(-self.radius, self.radius) + vmax_ = (vmax + (vmax - vmin) * 0.1).clamp(-self.radius, self.radius) + mesh_fine = self.isosurface_(vmin_, vmax_) + return mesh_fine + + +@models.register('volume-density') +class VolumeDensity(BaseImplicitGeometry): + def setup(self): + self.n_input_dims = self.config.get('n_input_dims', 3) + self.n_output_dims = self.config.feature_dim + self.encoding_with_network = get_encoding_with_network(self.n_input_dims, self.n_output_dims, self.config.xyz_encoding_config, self.config.mlp_network_config) + + def forward(self, points): + points = contract_to_unisphere(points, self.radius, self.contraction_type) + out = self.encoding_with_network(points.view(-1, self.n_input_dims)).view(*points.shape[:-1], self.n_output_dims).float() + density, feature = out[...,0], out + if 'density_activation' in self.config: + density = get_activation(self.config.density_activation)(density + float(self.config.density_bias)) + if 'feature_activation' in self.config: + feature = get_activation(self.config.feature_activation)(feature) + return density, feature + + def forward_level(self, points): + points = contract_to_unisphere(points, self.radius, self.contraction_type) + density = self.encoding_with_network(points.reshape(-1, self.n_input_dims)).reshape(*points.shape[:-1], self.n_output_dims)[...,0] + if 'density_activation' in self.config: + density = get_activation(self.config.density_activation)(density + float(self.config.density_bias)) + return -density + + def update_step(self, epoch, global_step): + update_module_step(self.encoding_with_network, epoch, global_step) + + +@models.register('volume-sdf') +class VolumeSDF(BaseImplicitGeometry): + def setup(self): + self.n_output_dims = self.config.feature_dim + encoding = get_encoding(3, self.config.xyz_encoding_config) + network = get_mlp(encoding.n_output_dims, self.n_output_dims, self.config.mlp_network_config) + self.encoding, self.network = encoding, network + self.grad_type = self.config.grad_type + self.finite_difference_eps = self.config.get('finite_difference_eps', 1e-3) + # the actual value used in training + # will update at certain steps if finite_difference_eps="progressive" + self._finite_difference_eps = None + if self.grad_type == 'finite_difference': + rank_zero_info(f"Using finite difference to compute gradients with eps={self.finite_difference_eps}") + + def forward(self, points, with_grad=True, with_feature=True, with_laplace=False): + with torch.inference_mode(torch.is_inference_mode_enabled() and not (with_grad and self.grad_type == 'analytic')): + with torch.set_grad_enabled(self.training or (with_grad and self.grad_type == 'analytic')): + if with_grad and self.grad_type == 'analytic': + if not self.training: + points = points.clone() # points may be in inference mode, get a copy to enable grad + points.requires_grad_(True) + + points_ = points # points in the original scale + points = contract_to_unisphere(points, self.radius, self.contraction_type) # points normalized to (0, 1) + + out = self.network(self.encoding(points.view(-1, 3))).view(*points.shape[:-1], self.n_output_dims).float() + sdf, feature = out[...,0], out + if 'sdf_activation' in self.config: + sdf = get_activation(self.config.sdf_activation)(sdf + float(self.config.sdf_bias)) + if 'feature_activation' in self.config: + feature = get_activation(self.config.feature_activation)(feature) + if with_grad: + if self.grad_type == 'analytic': + grad = torch.autograd.grad( + sdf, points_, grad_outputs=torch.ones_like(sdf), + create_graph=True, retain_graph=True, only_inputs=True + )[0] + elif self.grad_type == 'finite_difference': + eps = self._finite_difference_eps + offsets = torch.as_tensor( + [ + [eps, 0.0, 0.0], + [-eps, 0.0, 0.0], + [0.0, eps, 0.0], + [0.0, -eps, 0.0], + [0.0, 0.0, eps], + [0.0, 0.0, -eps], + ] + ).to(points_) + points_d_ = (points_[...,None,:] + offsets).clamp(-self.radius, self.radius) + points_d = scale_anything(points_d_, (-self.radius, self.radius), (0, 1)) + points_d_sdf = self.network(self.encoding(points_d.view(-1, 3)))[...,0].view(*points.shape[:-1], 6).float() + grad = 0.5 * (points_d_sdf[..., 0::2] - points_d_sdf[..., 1::2]) / eps + + if with_laplace: + laplace = (points_d_sdf[..., 0::2] + points_d_sdf[..., 1::2] - 2 * sdf[..., None]).sum(-1) / (eps ** 2) + + rv = [sdf] + if with_grad: + rv.append(grad) + if with_feature: + rv.append(feature) + if with_laplace: + assert self.config.grad_type == 'finite_difference', "Laplace computation is only supported with grad_type='finite_difference'" + rv.append(laplace) + rv = [v if self.training else v.detach() for v in rv] + return rv[0] if len(rv) == 1 else rv + + def forward_level(self, points): + points = contract_to_unisphere(points, self.radius, self.contraction_type) # points normalized to (0, 1) + sdf = self.network(self.encoding(points.view(-1, 3))).view(*points.shape[:-1], self.n_output_dims)[...,0] + if 'sdf_activation' in self.config: + sdf = get_activation(self.config.sdf_activation)(sdf + float(self.config.sdf_bias)) + return sdf + + def update_step(self, epoch, global_step): + update_module_step(self.encoding, epoch, global_step) + update_module_step(self.network, epoch, global_step) + if self.grad_type == 'finite_difference': + if isinstance(self.finite_difference_eps, float): + self._finite_difference_eps = self.finite_difference_eps + elif self.finite_difference_eps == 'progressive': + hg_conf = self.config.xyz_encoding_config + assert hg_conf.otype == "ProgressiveBandHashGrid", "finite_difference_eps='progressive' only works with ProgressiveBandHashGrid" + current_level = min( + hg_conf.start_level + max(global_step - hg_conf.start_step, 0) // hg_conf.update_steps, + hg_conf.n_levels + ) + grid_res = hg_conf.base_resolution * hg_conf.per_level_scale**(current_level - 1) + grid_size = 2 * self.config.radius / grid_res + if grid_size != self._finite_difference_eps: + rank_zero_info(f"Update finite_difference_eps to {grid_size}") + self._finite_difference_eps = grid_size + else: + raise ValueError(f"Unknown finite_difference_eps={self.finite_difference_eps}") diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/nerf.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/nerf.py new file mode 100644 index 0000000000000000000000000000000000000000..64ce5f9b839828eb02292faa4828108694f5f6d1 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/nerf.py @@ -0,0 +1,161 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +import models +from models.base import BaseModel +from models.utils import chunk_batch +from systems.utils import update_module_step +from nerfacc import ContractionType, OccupancyGrid, ray_marching, render_weight_from_density, accumulate_along_rays + + +@models.register('nerf') +class NeRFModel(BaseModel): + def setup(self): + self.geometry = models.make(self.config.geometry.name, self.config.geometry) + self.texture = models.make(self.config.texture.name, self.config.texture) + self.register_buffer('scene_aabb', torch.as_tensor([-self.config.radius, -self.config.radius, -self.config.radius, self.config.radius, self.config.radius, self.config.radius], dtype=torch.float32)) + + if self.config.learned_background: + self.occupancy_grid_res = 256 + self.near_plane, self.far_plane = 0.2, 1e4 + self.cone_angle = 10**(math.log10(self.far_plane) / self.config.num_samples_per_ray) - 1. # approximate + self.render_step_size = 0.01 # render_step_size = max(distance_to_camera * self.cone_angle, self.render_step_size) + self.contraction_type = ContractionType.UN_BOUNDED_SPHERE + else: + self.occupancy_grid_res = 128 + self.near_plane, self.far_plane = None, None + self.cone_angle = 0.0 + self.render_step_size = 1.732 * 2 * self.config.radius / self.config.num_samples_per_ray + self.contraction_type = ContractionType.AABB + + self.geometry.contraction_type = self.contraction_type + + if self.config.grid_prune: + self.occupancy_grid = OccupancyGrid( + roi_aabb=self.scene_aabb, + resolution=self.occupancy_grid_res, + contraction_type=self.contraction_type + ) + self.randomized = self.config.randomized + self.background_color = None + + def update_step(self, epoch, global_step): + update_module_step(self.geometry, epoch, global_step) + update_module_step(self.texture, epoch, global_step) + + def occ_eval_fn(x): + density, _ = self.geometry(x) + # approximate for 1 - torch.exp(-density[...,None] * self.render_step_size) based on taylor series + return density[...,None] * self.render_step_size + + if self.training and self.config.grid_prune: + self.occupancy_grid.every_n_step(step=global_step, occ_eval_fn=occ_eval_fn) + + def isosurface(self): + mesh = self.geometry.isosurface() + return mesh + + def forward_(self, rays): + n_rays = rays.shape[0] + rays_o, rays_d = rays[:, 0:3], rays[:, 3:6] # both (N_rays, 3) + + def sigma_fn(t_starts, t_ends, ray_indices): + ray_indices = ray_indices.long() + t_origins = rays_o[ray_indices] + t_dirs = rays_d[ray_indices] + positions = t_origins + t_dirs * (t_starts + t_ends) / 2. + density, _ = self.geometry(positions) + return density[...,None] + + def rgb_sigma_fn(t_starts, t_ends, ray_indices): + ray_indices = ray_indices.long() + t_origins = rays_o[ray_indices] + t_dirs = rays_d[ray_indices] + positions = t_origins + t_dirs * (t_starts + t_ends) / 2. + density, feature = self.geometry(positions) + rgb = self.texture(feature, t_dirs) + return rgb, density[...,None] + + with torch.no_grad(): + ray_indices, t_starts, t_ends = ray_marching( + rays_o, rays_d, + scene_aabb=None if self.config.learned_background else self.scene_aabb, + grid=self.occupancy_grid if self.config.grid_prune else None, + sigma_fn=sigma_fn, + near_plane=self.near_plane, far_plane=self.far_plane, + render_step_size=self.render_step_size, + stratified=self.randomized, + cone_angle=self.cone_angle, + alpha_thre=0.0 + ) + + ray_indices = ray_indices.long() + t_origins = rays_o[ray_indices] + t_dirs = rays_d[ray_indices] + midpoints = (t_starts + t_ends) / 2. + positions = t_origins + t_dirs * midpoints + intervals = t_ends - t_starts + + density, feature = self.geometry(positions) + rgb = self.texture(feature, t_dirs) + + weights = render_weight_from_density(t_starts, t_ends, density[...,None], ray_indices=ray_indices, n_rays=n_rays) + opacity = accumulate_along_rays(weights, ray_indices, values=None, n_rays=n_rays) + depth = accumulate_along_rays(weights, ray_indices, values=midpoints, n_rays=n_rays) + comp_rgb = accumulate_along_rays(weights, ray_indices, values=rgb, n_rays=n_rays) + comp_rgb = comp_rgb + self.background_color * (1.0 - opacity) + + out = { + 'comp_rgb': comp_rgb, + 'opacity': opacity, + 'depth': depth, + 'rays_valid': opacity > 0, + 'num_samples': torch.as_tensor([len(t_starts)], dtype=torch.int32, device=rays.device) + } + + if self.training: + out.update({ + 'weights': weights.view(-1), + 'points': midpoints.view(-1), + 'intervals': intervals.view(-1), + 'ray_indices': ray_indices.view(-1) + }) + + return out + + def forward(self, rays): + if self.training: + out = self.forward_(rays) + else: + out = chunk_batch(self.forward_, self.config.ray_chunk, True, rays) + return { + **out, + } + + def train(self, mode=True): + self.randomized = mode and self.config.randomized + return super().train(mode=mode) + + def eval(self): + self.randomized = False + return super().eval() + + def regularizations(self, out): + losses = {} + losses.update(self.geometry.regularizations(out)) + losses.update(self.texture.regularizations(out)) + return losses + + @torch.no_grad() + def export(self, export_config): + mesh = self.isosurface() + if export_config.export_vertex_color: + _, feature = chunk_batch(self.geometry, export_config.chunk_size, False, mesh['v_pos'].to(self.rank)) + viewdirs = torch.zeros(feature.shape[0], 3).to(feature) + viewdirs[...,2] = -1. # set the viewing directions to be -z (looking down) + rgb = self.texture(feature, viewdirs).clamp(0,1) + mesh['v_rgb'] = rgb.cpu() + return mesh diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/network_utils.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/network_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..bf1c4ab64487b68118e62cbc834dc2f1ff908ad7 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/network_utils.py @@ -0,0 +1,215 @@ +import math +import numpy as np + +import torch +import torch.nn as nn +import tinycudann as tcnn + +from pytorch_lightning.utilities.rank_zero import rank_zero_debug, rank_zero_info + +from utils.misc import config_to_primitive, get_rank +from models.utils import get_activation +from systems.utils import update_module_step + +class VanillaFrequency(nn.Module): + def __init__(self, in_channels, config): + super().__init__() + self.N_freqs = config['n_frequencies'] + self.in_channels, self.n_input_dims = in_channels, in_channels + self.funcs = [torch.sin, torch.cos] + self.freq_bands = 2**torch.linspace(0, self.N_freqs-1, self.N_freqs) + self.n_output_dims = self.in_channels * (len(self.funcs) * self.N_freqs) + self.n_masking_step = config.get('n_masking_step', 0) + self.update_step(None, None) # mask should be updated at the beginning each step + + def forward(self, x): + out = [] + for freq, mask in zip(self.freq_bands, self.mask): + for func in self.funcs: + out += [func(freq*x) * mask] + return torch.cat(out, -1) + + def update_step(self, epoch, global_step): + if self.n_masking_step <= 0 or global_step is None: + self.mask = torch.ones(self.N_freqs, dtype=torch.float32) + else: + self.mask = (1. - torch.cos(math.pi * (global_step / self.n_masking_step * self.N_freqs - torch.arange(0, self.N_freqs)).clamp(0, 1))) / 2. + rank_zero_debug(f'Update mask: {global_step}/{self.n_masking_step} {self.mask}') + + +class ProgressiveBandHashGrid(nn.Module): + def __init__(self, in_channels, config): + super().__init__() + self.n_input_dims = in_channels + encoding_config = config.copy() + encoding_config['otype'] = 'HashGrid' + with torch.cuda.device(get_rank()): + self.encoding = tcnn.Encoding(in_channels, encoding_config) + self.n_output_dims = self.encoding.n_output_dims + self.n_level = config['n_levels'] + self.n_features_per_level = config['n_features_per_level'] + self.start_level, self.start_step, self.update_steps = config['start_level'], config['start_step'], config['update_steps'] + self.current_level = self.start_level + self.mask = torch.zeros(self.n_level * self.n_features_per_level, dtype=torch.float32, device=get_rank()) + + def forward(self, x): + enc = self.encoding(x) + enc = enc * self.mask + return enc + + def update_step(self, epoch, global_step): + current_level = min(self.start_level + max(global_step - self.start_step, 0) // self.update_steps, self.n_level) + if current_level > self.current_level: + rank_zero_info(f'Update grid level to {current_level}') + self.current_level = current_level + self.mask[:self.current_level * self.n_features_per_level] = 1. + + +class CompositeEncoding(nn.Module): + def __init__(self, encoding, include_xyz=False, xyz_scale=1., xyz_offset=0.): + super(CompositeEncoding, self).__init__() + self.encoding = encoding + self.include_xyz, self.xyz_scale, self.xyz_offset = include_xyz, xyz_scale, xyz_offset + self.n_output_dims = int(self.include_xyz) * self.encoding.n_input_dims + self.encoding.n_output_dims + + def forward(self, x, *args): + return self.encoding(x, *args) if not self.include_xyz else torch.cat([x * self.xyz_scale + self.xyz_offset, self.encoding(x, *args)], dim=-1) + + def update_step(self, epoch, global_step): + update_module_step(self.encoding, epoch, global_step) + + +def get_encoding(n_input_dims, config): + # input suppose to be range [0, 1] + if config.otype == 'VanillaFrequency': + encoding = VanillaFrequency(n_input_dims, config_to_primitive(config)) + elif config.otype == 'ProgressiveBandHashGrid': + encoding = ProgressiveBandHashGrid(n_input_dims, config_to_primitive(config)) + else: + with torch.cuda.device(get_rank()): + encoding = tcnn.Encoding(n_input_dims, config_to_primitive(config)) + encoding = CompositeEncoding(encoding, include_xyz=config.get('include_xyz', False), xyz_scale=2., xyz_offset=-1.) + return encoding + + +class VanillaMLP(nn.Module): + def __init__(self, dim_in, dim_out, config): + super().__init__() + self.n_neurons, self.n_hidden_layers = config['n_neurons'], config['n_hidden_layers'] + self.sphere_init, self.weight_norm = config.get('sphere_init', False), config.get('weight_norm', False) + self.sphere_init_radius = config.get('sphere_init_radius', 0.5) + self.layers = [self.make_linear(dim_in, self.n_neurons, is_first=True, is_last=False), self.make_activation()] + for i in range(self.n_hidden_layers - 1): + self.layers += [self.make_linear(self.n_neurons, self.n_neurons, is_first=False, is_last=False), self.make_activation()] + self.layers += [self.make_linear(self.n_neurons, dim_out, is_first=False, is_last=True)] + self.layers = nn.Sequential(*self.layers) + self.output_activation = get_activation(config['output_activation']) + + @torch.cuda.amp.autocast(False) + def forward(self, x): + x = self.layers(x.float()) + x = self.output_activation(x) + return x + + def make_linear(self, dim_in, dim_out, is_first, is_last): + layer = nn.Linear(dim_in, dim_out, bias=True) # network without bias will degrade quality + if self.sphere_init: + if is_last: + torch.nn.init.constant_(layer.bias, -self.sphere_init_radius) + torch.nn.init.normal_(layer.weight, mean=math.sqrt(math.pi) / math.sqrt(dim_in), std=0.0001) + elif is_first: + torch.nn.init.constant_(layer.bias, 0.0) + torch.nn.init.constant_(layer.weight[:, 3:], 0.0) + torch.nn.init.normal_(layer.weight[:, :3], 0.0, math.sqrt(2) / math.sqrt(dim_out)) + else: + torch.nn.init.constant_(layer.bias, 0.0) + torch.nn.init.normal_(layer.weight, 0.0, math.sqrt(2) / math.sqrt(dim_out)) + else: + torch.nn.init.constant_(layer.bias, 0.0) + torch.nn.init.kaiming_uniform_(layer.weight, nonlinearity='relu') + + if self.weight_norm: + layer = nn.utils.weight_norm(layer) + return layer + + def make_activation(self): + if self.sphere_init: + return nn.Softplus(beta=100) + else: + return nn.ReLU(inplace=True) + + +def sphere_init_tcnn_network(n_input_dims, n_output_dims, config, network): + rank_zero_debug('Initialize tcnn MLP to approximately represent a sphere.') + """ + from https://github.com/NVlabs/tiny-cuda-nn/issues/96 + It's the weight matrices of each layer laid out in row-major order and then concatenated. + Notably: inputs and output dimensions are padded to multiples of 8 (CutlassMLP) or 16 (FullyFusedMLP). + The padded input dimensions get a constant value of 1.0, + whereas the padded output dimensions are simply ignored, + so the weights pertaining to those can have any value. + """ + padto = 16 if config.otype == 'FullyFusedMLP' else 8 + n_input_dims = n_input_dims + (padto - n_input_dims % padto) % padto + n_output_dims = n_output_dims + (padto - n_output_dims % padto) % padto + data = list(network.parameters())[0].data + assert data.shape[0] == (n_input_dims + n_output_dims) * config.n_neurons + (config.n_hidden_layers - 1) * config.n_neurons**2 + new_data = [] + # first layer + weight = torch.zeros((config.n_neurons, n_input_dims)).to(data) + torch.nn.init.constant_(weight[:, 3:], 0.0) + torch.nn.init.normal_(weight[:, :3], 0.0, math.sqrt(2) / math.sqrt(config.n_neurons)) + new_data.append(weight.flatten()) + # hidden layers + for i in range(config.n_hidden_layers - 1): + weight = torch.zeros((config.n_neurons, config.n_neurons)).to(data) + torch.nn.init.normal_(weight, 0.0, math.sqrt(2) / math.sqrt(config.n_neurons)) + new_data.append(weight.flatten()) + # last layer + weight = torch.zeros((n_output_dims, config.n_neurons)).to(data) + torch.nn.init.normal_(weight, mean=math.sqrt(math.pi) / math.sqrt(config.n_neurons), std=0.0001) + new_data.append(weight.flatten()) + new_data = torch.cat(new_data) + data.copy_(new_data) + + +def get_mlp(n_input_dims, n_output_dims, config): + if config.otype == 'VanillaMLP': + network = VanillaMLP(n_input_dims, n_output_dims, config_to_primitive(config)) + else: + with torch.cuda.device(get_rank()): + network = tcnn.Network(n_input_dims, n_output_dims, config_to_primitive(config)) + if config.get('sphere_init', False): + sphere_init_tcnn_network(n_input_dims, n_output_dims, config, network) + return network + + +class EncodingWithNetwork(nn.Module): + def __init__(self, encoding, network): + super().__init__() + self.encoding, self.network = encoding, network + + def forward(self, x): + return self.network(self.encoding(x)) + + def update_step(self, epoch, global_step): + update_module_step(self.encoding, epoch, global_step) + update_module_step(self.network, epoch, global_step) + + +def get_encoding_with_network(n_input_dims, n_output_dims, encoding_config, network_config): + # input suppose to be range [0, 1] + if encoding_config.otype in ['VanillaFrequency', 'ProgressiveBandHashGrid'] \ + or network_config.otype in ['VanillaMLP']: + encoding = get_encoding(n_input_dims, encoding_config) + network = get_mlp(encoding.n_output_dims, n_output_dims, network_config) + encoding_with_network = EncodingWithNetwork(encoding, network) + else: + with torch.cuda.device(get_rank()): + encoding_with_network = tcnn.NetworkWithInputEncoding( + n_input_dims=n_input_dims, + n_output_dims=n_output_dims, + encoding_config=config_to_primitive(encoding_config), + network_config=config_to_primitive(network_config) + ) + return encoding_with_network diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/neus.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/neus.py new file mode 100644 index 0000000000000000000000000000000000000000..51fb9480059165f91685003bc617548bbfc6c83d --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/neus.py @@ -0,0 +1,341 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +import models +from models.base import BaseModel +from models.utils import chunk_batch +from systems.utils import update_module_step +from nerfacc import ContractionType, OccupancyGrid, ray_marching, render_weight_from_density, render_weight_from_alpha, accumulate_along_rays +from nerfacc.intersection import ray_aabb_intersect + +import pdb + + +class VarianceNetwork(nn.Module): + def __init__(self, config): + super(VarianceNetwork, self).__init__() + self.config = config + self.init_val = self.config.init_val + self.register_parameter('variance', nn.Parameter(torch.tensor(self.config.init_val))) + self.modulate = self.config.get('modulate', False) + if self.modulate: + self.mod_start_steps = self.config.mod_start_steps + self.reach_max_steps = self.config.reach_max_steps + self.max_inv_s = self.config.max_inv_s + + @property + def inv_s(self): + val = torch.exp(self.variance * 10.0) + if self.modulate and self.do_mod: + val = val.clamp_max(self.mod_val) + return val + + def forward(self, x): + return torch.ones([len(x), 1], device=self.variance.device) * self.inv_s + + def update_step(self, epoch, global_step): + if self.modulate: + self.do_mod = global_step > self.mod_start_steps + if not self.do_mod: + self.prev_inv_s = self.inv_s.item() + else: + self.mod_val = min((global_step / self.reach_max_steps) * (self.max_inv_s - self.prev_inv_s) + self.prev_inv_s, self.max_inv_s) + + +@models.register('neus') +class NeuSModel(BaseModel): + def setup(self): + self.geometry = models.make(self.config.geometry.name, self.config.geometry) + self.texture = models.make(self.config.texture.name, self.config.texture) + self.geometry.contraction_type = ContractionType.AABB + + if self.config.learned_background: + self.geometry_bg = models.make(self.config.geometry_bg.name, self.config.geometry_bg) + self.texture_bg = models.make(self.config.texture_bg.name, self.config.texture_bg) + self.geometry_bg.contraction_type = ContractionType.UN_BOUNDED_SPHERE + self.near_plane_bg, self.far_plane_bg = 0.1, 1e3 + self.cone_angle_bg = 10**(math.log10(self.far_plane_bg) / self.config.num_samples_per_ray_bg) - 1. + self.render_step_size_bg = 0.01 + + self.variance = VarianceNetwork(self.config.variance) + self.register_buffer('scene_aabb', torch.as_tensor([-self.config.radius, -self.config.radius, -self.config.radius, self.config.radius, self.config.radius, self.config.radius], dtype=torch.float32)) + if self.config.grid_prune: + self.occupancy_grid = OccupancyGrid( + roi_aabb=self.scene_aabb, + resolution=128, + contraction_type=ContractionType.AABB + ) + if self.config.learned_background: + self.occupancy_grid_bg = OccupancyGrid( + roi_aabb=self.scene_aabb, + resolution=256, + contraction_type=ContractionType.UN_BOUNDED_SPHERE + ) + self.randomized = self.config.randomized + self.background_color = None + self.render_step_size = 1.732 * 2 * self.config.radius / self.config.num_samples_per_ray + + def update_step(self, epoch, global_step): + update_module_step(self.geometry, epoch, global_step) + update_module_step(self.texture, epoch, global_step) + if self.config.learned_background: + update_module_step(self.geometry_bg, epoch, global_step) + update_module_step(self.texture_bg, epoch, global_step) + update_module_step(self.variance, epoch, global_step) + + cos_anneal_end = self.config.get('cos_anneal_end', 0) + self.cos_anneal_ratio = 1.0 if cos_anneal_end == 0 else min(1.0, global_step / cos_anneal_end) + + def occ_eval_fn(x): + sdf = self.geometry(x, with_grad=False, with_feature=False) + inv_s = self.variance(torch.zeros([1, 3]))[:, :1].clip(1e-6, 1e6) + inv_s = inv_s.expand(sdf.shape[0], 1) + estimated_next_sdf = sdf[...,None] - self.render_step_size * 0.5 + estimated_prev_sdf = sdf[...,None] + self.render_step_size * 0.5 + prev_cdf = torch.sigmoid(estimated_prev_sdf * inv_s) + next_cdf = torch.sigmoid(estimated_next_sdf * inv_s) + p = prev_cdf - next_cdf + c = prev_cdf + alpha = ((p + 1e-5) / (c + 1e-5)).view(-1, 1).clip(0.0, 1.0) + return alpha + + def occ_eval_fn_bg(x): + density, _ = self.geometry_bg(x) + # approximate for 1 - torch.exp(-density[...,None] * self.render_step_size_bg) based on taylor series + return density[...,None] * self.render_step_size_bg + + if self.training and self.config.grid_prune: + self.occupancy_grid.every_n_step(step=global_step, occ_eval_fn=occ_eval_fn, occ_thre=self.config.get('grid_prune_occ_thre', 0.01)) + if self.config.learned_background: + self.occupancy_grid_bg.every_n_step(step=global_step, occ_eval_fn=occ_eval_fn_bg, occ_thre=self.config.get('grid_prune_occ_thre_bg', 0.01)) + + def isosurface(self): + mesh = self.geometry.isosurface() + return mesh + + def get_alpha(self, sdf, normal, dirs, dists): + inv_s = self.variance(torch.zeros([1, 3]))[:, :1].clip(1e-6, 1e6) # Single parameter + inv_s = inv_s.expand(sdf.shape[0], 1) + + true_cos = (dirs * normal).sum(-1, keepdim=True) + + # "cos_anneal_ratio" grows from 0 to 1 in the beginning training iterations. The anneal strategy below makes + # the cos value "not dead" at the beginning training iterations, for better convergence. + iter_cos = -(F.relu(-true_cos * 0.5 + 0.5) * (1.0 - self.cos_anneal_ratio) + + F.relu(-true_cos) * self.cos_anneal_ratio) # always non-positive + + # Estimate signed distances at section points + estimated_next_sdf = sdf[...,None] + iter_cos * dists.reshape(-1, 1) * 0.5 + estimated_prev_sdf = sdf[...,None] - iter_cos * dists.reshape(-1, 1) * 0.5 + + prev_cdf = torch.sigmoid(estimated_prev_sdf * inv_s) + next_cdf = torch.sigmoid(estimated_next_sdf * inv_s) + + p = prev_cdf - next_cdf + c = prev_cdf + + alpha = ((p + 1e-5) / (c + 1e-5)).view(-1).clip(0.0, 1.0) + return alpha + + def forward_bg_(self, rays): + n_rays = rays.shape[0] + rays_o, rays_d = rays[:, 0:3], rays[:, 3:6] # both (N_rays, 3) + + def sigma_fn(t_starts, t_ends, ray_indices): + ray_indices = ray_indices.long() + t_origins = rays_o[ray_indices] + t_dirs = rays_d[ray_indices] + positions = t_origins + t_dirs * (t_starts + t_ends) / 2. + density, _ = self.geometry_bg(positions) + return density[...,None] + + _, t_max = ray_aabb_intersect(rays_o, rays_d, self.scene_aabb) + # if the ray intersects with the bounding box, start from the farther intersection point + # otherwise start from self.far_plane_bg + # note that in nerfacc t_max is set to 1e10 if there is no intersection + near_plane = torch.where(t_max > 1e9, self.near_plane_bg, t_max) + with torch.no_grad(): + ray_indices, t_starts, t_ends = ray_marching( + rays_o, rays_d, + scene_aabb=None, + grid=self.occupancy_grid_bg if self.config.grid_prune else None, + sigma_fn=sigma_fn, + near_plane=near_plane, far_plane=self.far_plane_bg, + render_step_size=self.render_step_size_bg, + stratified=self.randomized, + cone_angle=self.cone_angle_bg, + alpha_thre=0.0 + ) + + ray_indices = ray_indices.long() + t_origins = rays_o[ray_indices] + t_dirs = rays_d[ray_indices] + midpoints = (t_starts + t_ends) / 2. + positions = t_origins + t_dirs * midpoints + intervals = t_ends - t_starts + + density, feature = self.geometry_bg(positions) + rgb = self.texture_bg(feature, t_dirs) + + weights = render_weight_from_density(t_starts, t_ends, density[...,None], ray_indices=ray_indices, n_rays=n_rays) + opacity = accumulate_along_rays(weights, ray_indices, values=None, n_rays=n_rays) + depth = accumulate_along_rays(weights, ray_indices, values=midpoints, n_rays=n_rays) + comp_rgb = accumulate_along_rays(weights, ray_indices, values=rgb, n_rays=n_rays) + comp_rgb = comp_rgb + self.background_color * (1.0 - opacity) + + out = { + 'comp_rgb': comp_rgb, + 'opacity': opacity, + 'depth': depth, + 'rays_valid': opacity > 0, + 'num_samples': torch.as_tensor([len(t_starts)], dtype=torch.int32, device=rays.device) + } + + if self.training: + out.update({ + 'weights': weights.view(-1), + 'points': midpoints.view(-1), + 'intervals': intervals.view(-1), + 'ray_indices': ray_indices.view(-1) + }) + + return out + + def forward_(self, rays): + n_rays = rays.shape[0] + rays_o, rays_d = rays[:, 0:3], rays[:, 3:6] # both (N_rays, 3) + + with torch.no_grad(): + ray_indices, t_starts, t_ends = ray_marching( + rays_o, rays_d, + scene_aabb=self.scene_aabb, + grid=self.occupancy_grid if self.config.grid_prune else None, + alpha_fn=None, + near_plane=None, far_plane=None, + render_step_size=self.render_step_size, + stratified=self.randomized, + cone_angle=0.0, + alpha_thre=0.0 + ) + + ray_indices = ray_indices.long() + t_origins = rays_o[ray_indices] + t_dirs = rays_d[ray_indices] + midpoints = (t_starts + t_ends) / 2. + positions = t_origins + t_dirs * midpoints + dists = t_ends - t_starts + + if self.config.geometry.grad_type == 'finite_difference': + sdf, sdf_grad, feature, sdf_laplace = self.geometry(positions, with_grad=True, with_feature=True, with_laplace=True) + else: + sdf, sdf_grad, feature = self.geometry(positions, with_grad=True, with_feature=True) + + normal = F.normalize(sdf_grad, p=2, dim=-1) + alpha = self.get_alpha(sdf, normal, t_dirs, dists)[...,None] + rgb = self.texture(feature, t_dirs, normal) + + weights = render_weight_from_alpha(alpha, ray_indices=ray_indices, n_rays=n_rays) + opacity = accumulate_along_rays(weights, ray_indices, values=None, n_rays=n_rays) + depth = accumulate_along_rays(weights, ray_indices, values=midpoints, n_rays=n_rays) + comp_rgb = accumulate_along_rays(weights, ray_indices, values=rgb, n_rays=n_rays) + + comp_normal = accumulate_along_rays(weights, ray_indices, values=normal, n_rays=n_rays) + comp_normal = F.normalize(comp_normal, p=2, dim=-1) + + pts_random = torch.rand([1024*2, 3]).to(sdf.dtype).to(sdf.device) * 2 - 1 # normalized to (-1, 1) + + if self.config.geometry.grad_type == 'finite_difference': + random_sdf, random_sdf_grad, _ = self.geometry(pts_random, with_grad=True, with_feature=False, with_laplace=True) + _, normal_perturb, _ = self.geometry( + pts_random + torch.randn_like(pts_random) * 1e-2, + with_grad=True, with_feature=False, with_laplace=True + ) + else: + random_sdf, random_sdf_grad = self.geometry(pts_random, with_grad=True, with_feature=False) + _, normal_perturb = self.geometry(positions + torch.randn_like(positions) * 1e-2, + with_grad=True, with_feature=False,) + + # pdb.set_trace() + out = { + 'comp_rgb': comp_rgb, + 'comp_normal': comp_normal, + 'opacity': opacity, + 'depth': depth, + 'rays_valid': opacity > 0, + 'num_samples': torch.as_tensor([len(t_starts)], dtype=torch.int32, device=rays.device) + } + + if self.training: + out.update({ + 'sdf_samples': sdf, + 'sdf_grad_samples': sdf_grad, + 'random_sdf': random_sdf, + 'random_sdf_grad': random_sdf_grad, + 'normal_perturb' : normal_perturb, + 'weights': weights.view(-1), + 'points': midpoints.view(-1), + 'intervals': dists.view(-1), + 'ray_indices': ray_indices.view(-1) + }) + if self.config.geometry.grad_type == 'finite_difference': + out.update({ + 'sdf_laplace_samples': sdf_laplace + }) + + if self.config.learned_background: + out_bg = self.forward_bg_(rays) + else: + out_bg = { + 'comp_rgb': self.background_color[None,:].expand(*comp_rgb.shape), + 'num_samples': torch.zeros_like(out['num_samples']), + 'rays_valid': torch.zeros_like(out['rays_valid']) + } + + out_full = { + 'comp_rgb': out['comp_rgb'] + out_bg['comp_rgb'] * (1.0 - out['opacity']), + 'num_samples': out['num_samples'] + out_bg['num_samples'], + 'rays_valid': out['rays_valid'] | out_bg['rays_valid'] + } + + return { + **out, + **{k + '_bg': v for k, v in out_bg.items()}, + **{k + '_full': v for k, v in out_full.items()} + } + + def forward(self, rays): + if self.training: + out = self.forward_(rays) + else: + out = chunk_batch(self.forward_, self.config.ray_chunk, True, rays) + return { + **out, + 'inv_s': self.variance.inv_s + } + + def train(self, mode=True): + self.randomized = mode and self.config.randomized + return super().train(mode=mode) + + def eval(self): + self.randomized = False + return super().eval() + + def regularizations(self, out): + losses = {} + losses.update(self.geometry.regularizations(out)) + losses.update(self.texture.regularizations(out)) + return losses + + @torch.no_grad() + def export(self, export_config): + mesh = self.isosurface() + if export_config.export_vertex_color: + _, sdf_grad, feature = chunk_batch(self.geometry, export_config.chunk_size, False, mesh['v_pos'].to(self.rank), with_grad=True, with_feature=True) + normal = F.normalize(sdf_grad, p=2, dim=-1) + rgb = self.texture(feature, -normal, normal) # set the viewing directions to the normal to get "albedo" + mesh['v_rgb'] = rgb.cpu() + return mesh diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/ray_utils.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/ray_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..ca1866fa43aedb83e111233af1c5d0e37dbedf75 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/ray_utils.py @@ -0,0 +1,92 @@ +import torch +import numpy as np + + +def cast_rays(ori, dir, z_vals): + return ori[..., None, :] + z_vals[..., None] * dir[..., None, :] + + +def get_ray_directions(W, H, fx, fy, cx, cy, use_pixel_centers=True): + pixel_center = 0.5 if use_pixel_centers else 0 + i, j = np.meshgrid( + np.arange(W, dtype=np.float32) + pixel_center, + np.arange(H, dtype=np.float32) + pixel_center, + indexing='xy' + ) + i, j = torch.from_numpy(i), torch.from_numpy(j) + + # directions = torch.stack([(i - cx) / fx, -(j - cy) / fy, -torch.ones_like(i)], -1) # (H, W, 3) + # opencv system + directions = torch.stack([(i - cx) / fx, (j - cy) / fy, torch.ones_like(i)], -1) # (H, W, 3) + + return directions + + +def get_ortho_ray_directions_origins(W, H, use_pixel_centers=True): + pixel_center = 0.5 if use_pixel_centers else 0 + i, j = np.meshgrid( + np.arange(W, dtype=np.float32) + pixel_center, + np.arange(H, dtype=np.float32) + pixel_center, + indexing='xy' + ) + i, j = torch.from_numpy(i), torch.from_numpy(j) + + origins = torch.stack([(i/W-0.5)*2, (j/H-0.5)*2, torch.zeros_like(i)], dim=-1) # W, H, 3 + directions = torch.stack([torch.zeros_like(i), torch.zeros_like(j), torch.ones_like(i)], dim=-1) # W, H, 3 + + return origins, directions + + +def get_rays(directions, c2w, keepdim=False): + # Rotate ray directions from camera coordinate to the world coordinate + # rays_d = directions @ c2w[:, :3].T # (H, W, 3) # slow? + assert directions.shape[-1] == 3 + + if directions.ndim == 2: # (N_rays, 3) + assert c2w.ndim == 3 # (N_rays, 4, 4) / (1, 4, 4) + rays_d = (directions[:,None,:] * c2w[:,:3,:3]).sum(-1) # (N_rays, 3) + rays_o = c2w[:,:,3].expand(rays_d.shape) + elif directions.ndim == 3: # (H, W, 3) + if c2w.ndim == 2: # (4, 4) + rays_d = (directions[:,:,None,:] * c2w[None,None,:3,:3]).sum(-1) # (H, W, 3) + rays_o = c2w[None,None,:,3].expand(rays_d.shape) + elif c2w.ndim == 3: # (B, 4, 4) + rays_d = (directions[None,:,:,None,:] * c2w[:,None,None,:3,:3]).sum(-1) # (B, H, W, 3) + rays_o = c2w[:,None,None,:,3].expand(rays_d.shape) + + if not keepdim: + rays_o, rays_d = rays_o.reshape(-1, 3), rays_d.reshape(-1, 3) + + return rays_o, rays_d + + +# rays_v = torch.matmul(self.pose_all[img_idx, None, None, :3, :3].cuda(), rays_v[:, :, :, None].cuda()).squeeze() # W, H, 3 + +# rays_o = torch.matmul(self.pose_all[img_idx, None, None, :3, :3].cuda(), q[:, :, :, None].cuda()).squeeze() # W, H, 3 +# rays_o = self.pose_all[img_idx, None, None, :3, 3].expand(rays_v.shape).cuda() + rays_o # W, H, 3 + +def get_ortho_rays(origins, directions, c2w, keepdim=False): + # Rotate ray directions from camera coordinate to the world coordinate + # rays_d = directions @ c2w[:, :3].T # (H, W, 3) # slow? + assert directions.shape[-1] == 3 + assert origins.shape[-1] == 3 + + if directions.ndim == 2: # (N_rays, 3) + assert c2w.ndim == 3 # (N_rays, 4, 4) / (1, 4, 4) + rays_d = torch.matmul(c2w[:, :3, :3], directions[:, :, None]).squeeze() # (N_rays, 3) + rays_o = torch.matmul(c2w[:, :3, :3], origins[:, :, None]).squeeze() # (N_rays, 3) + rays_o = c2w[:,:3,3].expand(rays_d.shape) + rays_o + elif directions.ndim == 3: # (H, W, 3) + if c2w.ndim == 2: # (4, 4) + rays_d = torch.matmul(c2w[None, None, :3, :3], directions[:, :, :, None]).squeeze() # (H, W, 3) + rays_o = torch.matmul(c2w[None, None, :3, :3], origins[:, :, :, None]).squeeze() # (H, W, 3) + rays_o = c2w[None, None,:3,3].expand(rays_d.shape) + rays_o + elif c2w.ndim == 3: # (B, 4, 4) + rays_d = torch.matmul(c2w[:,None, None, :3, :3], directions[None, :, :, :, None]).squeeze() # # (B, H, W, 3) + rays_o = torch.matmul(c2w[:,None, None, :3, :3], origins[None, :, :, :, None]).squeeze() # # (B, H, W, 3) + rays_o = c2w[:,None, None, :3,3].expand(rays_d.shape) + rays_o + + if not keepdim: + rays_o, rays_d = rays_o.reshape(-1, 3), rays_d.reshape(-1, 3) + + return rays_o, rays_d diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/texture.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/texture.py new file mode 100644 index 0000000000000000000000000000000000000000..4a83c9775c89d812cf6009155a414771c5462ebf --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/texture.py @@ -0,0 +1,75 @@ +import torch +import torch.nn as nn + +import models +from models.utils import get_activation +from models.network_utils import get_encoding, get_mlp +from systems.utils import update_module_step + + +@models.register('volume-radiance') +class VolumeRadiance(nn.Module): + def __init__(self, config): + super(VolumeRadiance, self).__init__() + self.config = config + self.with_viewdir = False #self.config.get('wo_viewdir', False) + self.n_dir_dims = self.config.get('n_dir_dims', 3) + self.n_output_dims = 3 + + if self.with_viewdir: + encoding = get_encoding(self.n_dir_dims, self.config.dir_encoding_config) + self.n_input_dims = self.config.input_feature_dim + encoding.n_output_dims + # self.network_base = get_mlp(self.config.input_feature_dim, self.n_output_dims, self.config.mlp_network_config) + else: + encoding = None + self.n_input_dims = self.config.input_feature_dim + + network = get_mlp(self.n_input_dims, self.n_output_dims, self.config.mlp_network_config) + self.encoding = encoding + self.network = network + + def forward(self, features, dirs, *args): + + # features = features.detach() + if self.with_viewdir: + dirs = (dirs + 1.) / 2. # (-1, 1) => (0, 1) + dirs_embd = self.encoding(dirs.view(-1, self.n_dir_dims)) + network_inp = torch.cat([features.view(-1, features.shape[-1]), dirs_embd] + [arg.view(-1, arg.shape[-1]) for arg in args], dim=-1) + # network_inp_base = torch.cat([features.view(-1, features.shape[-1])] + [arg.view(-1, arg.shape[-1]) for arg in args], dim=-1) + color = self.network(network_inp).view(*features.shape[:-1], self.n_output_dims).float() + # color_base = self.network_base(network_inp_base).view(*features.shape[:-1], self.n_output_dims).float() + # color = color + color_base + else: + network_inp = torch.cat([features.view(-1, features.shape[-1])] + [arg.view(-1, arg.shape[-1]) for arg in args], dim=-1) + color = self.network(network_inp).view(*features.shape[:-1], self.n_output_dims).float() + + if 'color_activation' in self.config: + color = get_activation(self.config.color_activation)(color) + return color + + def update_step(self, epoch, global_step): + update_module_step(self.encoding, epoch, global_step) + + def regularizations(self, out): + return {} + + +@models.register('volume-color') +class VolumeColor(nn.Module): + def __init__(self, config): + super(VolumeColor, self).__init__() + self.config = config + self.n_output_dims = 3 + self.n_input_dims = self.config.input_feature_dim + network = get_mlp(self.n_input_dims, self.n_output_dims, self.config.mlp_network_config) + self.network = network + + def forward(self, features, *args): + network_inp = features.view(-1, features.shape[-1]) + color = self.network(network_inp).view(*features.shape[:-1], self.n_output_dims).float() + if 'color_activation' in self.config: + color = get_activation(self.config.color_activation)(color) + return color + + def regularizations(self, out): + return {} diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/models/utils.py b/apps/third_party/Wonder3D/instant-nsr-pl/models/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1d5c3cf19dd3e8f277783db68f1435c8f9755e96 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/models/utils.py @@ -0,0 +1,119 @@ +import gc +from collections import defaultdict + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.autograd import Function +from torch.cuda.amp import custom_bwd, custom_fwd + +import tinycudann as tcnn + + +def chunk_batch(func, chunk_size, move_to_cpu, *args, **kwargs): + B = None + for arg in args: + if isinstance(arg, torch.Tensor): + B = arg.shape[0] + break + out = defaultdict(list) + out_type = None + for i in range(0, B, chunk_size): + out_chunk = func(*[arg[i:i+chunk_size] if isinstance(arg, torch.Tensor) else arg for arg in args], **kwargs) + if out_chunk is None: + continue + out_type = type(out_chunk) + if isinstance(out_chunk, torch.Tensor): + out_chunk = {0: out_chunk} + elif isinstance(out_chunk, tuple) or isinstance(out_chunk, list): + chunk_length = len(out_chunk) + out_chunk = {i: chunk for i, chunk in enumerate(out_chunk)} + elif isinstance(out_chunk, dict): + pass + else: + print(f'Return value of func must be in type [torch.Tensor, list, tuple, dict], get {type(out_chunk)}.') + exit(1) + for k, v in out_chunk.items(): + v = v if torch.is_grad_enabled() else v.detach() + v = v.cpu() if move_to_cpu else v + out[k].append(v) + + if out_type is None: + return + + out = {k: torch.cat(v, dim=0) for k, v in out.items()} + if out_type is torch.Tensor: + return out[0] + elif out_type in [tuple, list]: + return out_type([out[i] for i in range(chunk_length)]) + elif out_type is dict: + return out + + +class _TruncExp(Function): # pylint: disable=abstract-method + # Implementation from torch-ngp: + # https://github.com/ashawkey/torch-ngp/blob/93b08a0d4ec1cc6e69d85df7f0acdfb99603b628/activation.py + @staticmethod + @custom_fwd(cast_inputs=torch.float32) + def forward(ctx, x): # pylint: disable=arguments-differ + ctx.save_for_backward(x) + return torch.exp(x) + + @staticmethod + @custom_bwd + def backward(ctx, g): # pylint: disable=arguments-differ + x = ctx.saved_tensors[0] + return g * torch.exp(torch.clamp(x, max=15)) + +trunc_exp = _TruncExp.apply + + +def get_activation(name): + if name is None: + return lambda x: x + name = name.lower() + if name == 'none': + return lambda x: x + elif name.startswith('scale'): + scale_factor = float(name[5:]) + return lambda x: x.clamp(0., scale_factor) / scale_factor + elif name.startswith('clamp'): + clamp_max = float(name[5:]) + return lambda x: x.clamp(0., clamp_max) + elif name.startswith('mul'): + mul_factor = float(name[3:]) + return lambda x: x * mul_factor + elif name == 'lin2srgb': + return lambda x: torch.where(x > 0.0031308, torch.pow(torch.clamp(x, min=0.0031308), 1.0/2.4)*1.055 - 0.055, 12.92*x).clamp(0., 1.) + elif name == 'trunc_exp': + return trunc_exp + elif name.startswith('+') or name.startswith('-'): + return lambda x: x + float(name) + elif name == 'sigmoid': + return lambda x: torch.sigmoid(x) + elif name == 'tanh': + return lambda x: torch.tanh(x) + else: + return getattr(F, name) + + +def dot(x, y): + return torch.sum(x*y, -1, keepdim=True) + + +def reflect(x, n): + return 2 * dot(x, n) * n - x + + +def scale_anything(dat, inp_scale, tgt_scale): + if inp_scale is None: + inp_scale = [dat.min(), dat.max()] + dat = (dat - inp_scale[0]) / (inp_scale[1] - inp_scale[0]) + dat = dat * (tgt_scale[1] - tgt_scale[0]) + tgt_scale[0] + return dat + + +def cleanup(): + gc.collect() + torch.cuda.empty_cache() + tcnn.free_temporary_memory() diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/requirements.txt b/apps/third_party/Wonder3D/instant-nsr-pl/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ab886c0d76248bfd1035579b460292458ef25e6 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/requirements.txt @@ -0,0 +1,12 @@ +pytorch-lightning<2 +omegaconf==2.2.3 +nerfacc==0.3.3 +matplotlib +opencv-python +imageio +imageio-ffmpeg +scipy +PyMCubes +pyransac3d +torch_efficient_distloss +tensorboard diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/run.sh b/apps/third_party/Wonder3D/instant-nsr-pl/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..617143ccecba268e77b2aeb48cb3ec266d098c40 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/run.sh @@ -0,0 +1 @@ +python launch.py --config configs/neuralangelo-ortho-wmask.yaml --gpu 0 --train dataset.root_dir=$1 dataset.scene=$2 \ No newline at end of file diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/scripts/imgs2poses.py b/apps/third_party/Wonder3D/instant-nsr-pl/scripts/imgs2poses.py new file mode 100644 index 0000000000000000000000000000000000000000..e4b6e0b19c7192fceee0518b2cde691bfabd4ff4 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/scripts/imgs2poses.py @@ -0,0 +1,85 @@ + +""" +This file is adapted from https://github.com/Fyusion/LLFF. +""" + +import os +import sys +import argparse +import subprocess + + +def run_colmap(basedir, match_type): + logfile_name = os.path.join(basedir, 'colmap_output.txt') + logfile = open(logfile_name, 'w') + + feature_extractor_args = [ + 'colmap', 'feature_extractor', + '--database_path', os.path.join(basedir, 'database.db'), + '--image_path', os.path.join(basedir, 'images'), + '--ImageReader.single_camera', '1' + ] + feat_output = ( subprocess.check_output(feature_extractor_args, universal_newlines=True) ) + logfile.write(feat_output) + print('Features extracted') + + exhaustive_matcher_args = [ + 'colmap', match_type, + '--database_path', os.path.join(basedir, 'database.db'), + ] + + match_output = ( subprocess.check_output(exhaustive_matcher_args, universal_newlines=True) ) + logfile.write(match_output) + print('Features matched') + + p = os.path.join(basedir, 'sparse') + if not os.path.exists(p): + os.makedirs(p) + + mapper_args = [ + 'colmap', 'mapper', + '--database_path', os.path.join(basedir, 'database.db'), + '--image_path', os.path.join(basedir, 'images'), + '--output_path', os.path.join(basedir, 'sparse'), # --export_path changed to --output_path in colmap 3.6 + '--Mapper.num_threads', '16', + '--Mapper.init_min_tri_angle', '4', + '--Mapper.multiple_models', '0', + '--Mapper.extract_colors', '0', + ] + + map_output = ( subprocess.check_output(mapper_args, universal_newlines=True) ) + logfile.write(map_output) + logfile.close() + print('Sparse map created') + + print( 'Finished running COLMAP, see {} for logs'.format(logfile_name) ) + + +def gen_poses(basedir, match_type): + files_needed = ['{}.bin'.format(f) for f in ['cameras', 'images', 'points3D']] + if os.path.exists(os.path.join(basedir, 'sparse/0')): + files_had = os.listdir(os.path.join(basedir, 'sparse/0')) + else: + files_had = [] + if not all([f in files_had for f in files_needed]): + print( 'Need to run COLMAP' ) + run_colmap(basedir, match_type) + else: + print('Don\'t need to run COLMAP') + + return True + + +if __name__=='__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--match_type', type=str, + default='exhaustive_matcher', help='type of matcher used. Valid options: \ + exhaustive_matcher sequential_matcher. Other matchers not supported at this time') + parser.add_argument('scenedir', type=str, + help='input scene directory') + args = parser.parse_args() + + if args.match_type != 'exhaustive_matcher' and args.match_type != 'sequential_matcher': + print('ERROR: matcher type ' + args.match_type + ' is not valid. Aborting') + sys.exit() + gen_poses(args.scenedir, args.match_type) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/systems/__init__.py b/apps/third_party/Wonder3D/instant-nsr-pl/systems/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..df114d15f57bfcceb5b626be4c97a8d4c442cee8 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/systems/__init__.py @@ -0,0 +1,19 @@ +systems = {} + + +def register(name): + def decorator(cls): + systems[name] = cls + return cls + return decorator + + +def make(name, config, load_from_checkpoint=None): + if load_from_checkpoint is None: + system = systems[name](config) + else: + system = systems[name].load_from_checkpoint(load_from_checkpoint, strict=False, config=config) + return system + + +from . import neus, neus_ortho, neus_pinhole diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/systems/base.py b/apps/third_party/Wonder3D/instant-nsr-pl/systems/base.py new file mode 100644 index 0000000000000000000000000000000000000000..c4bcdbdc76d810548f85ebbaf64870a33f5ddaf1 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/systems/base.py @@ -0,0 +1,128 @@ +import pytorch_lightning as pl + +import models +from systems.utils import parse_optimizer, parse_scheduler, update_module_step +from utils.mixins import SaverMixin +from utils.misc import config_to_primitive, get_rank + + +class BaseSystem(pl.LightningModule, SaverMixin): + """ + Two ways to print to console: + 1. self.print: correctly handle progress bar + 2. rank_zero_info: use the logging module + """ + def __init__(self, config): + super().__init__() + self.config = config + self.rank = get_rank() + self.prepare() + self.model = models.make(self.config.model.name, self.config.model) + + def prepare(self): + pass + + def forward(self, batch): + raise NotImplementedError + + def C(self, value): + if isinstance(value, int) or isinstance(value, float): + pass + else: + value = config_to_primitive(value) + if not isinstance(value, list): + raise TypeError('Scalar specification only supports list, got', type(value)) + if len(value) == 3: + value = [0] + value + assert len(value) == 4 + start_step, start_value, end_value, end_step = value + if isinstance(end_step, int): + current_step = self.global_step + value = start_value + (end_value - start_value) * max(min(1.0, (current_step - start_step) / (end_step - start_step)), 0.0) + elif isinstance(end_step, float): + current_step = self.current_epoch + value = start_value + (end_value - start_value) * max(min(1.0, (current_step - start_step) / (end_step - start_step)), 0.0) + return value + + def preprocess_data(self, batch, stage): + pass + + """ + Implementing on_after_batch_transfer of DataModule does the same. + But on_after_batch_transfer does not support DP. + """ + def on_train_batch_start(self, batch, batch_idx, unused=0): + self.dataset = self.trainer.datamodule.train_dataloader().dataset + self.preprocess_data(batch, 'train') + update_module_step(self.model, self.current_epoch, self.global_step) + + def on_validation_batch_start(self, batch, batch_idx, dataloader_idx): + self.dataset = self.trainer.datamodule.val_dataloader().dataset + self.preprocess_data(batch, 'validation') + update_module_step(self.model, self.current_epoch, self.global_step) + + def on_test_batch_start(self, batch, batch_idx, dataloader_idx): + self.dataset = self.trainer.datamodule.test_dataloader().dataset + self.preprocess_data(batch, 'test') + update_module_step(self.model, self.current_epoch, self.global_step) + + def on_predict_batch_start(self, batch, batch_idx, dataloader_idx): + self.dataset = self.trainer.datamodule.predict_dataloader().dataset + self.preprocess_data(batch, 'predict') + update_module_step(self.model, self.current_epoch, self.global_step) + + def training_step(self, batch, batch_idx): + raise NotImplementedError + + """ + # aggregate outputs from different devices (DP) + def training_step_end(self, out): + pass + """ + + """ + # aggregate outputs from different iterations + def training_epoch_end(self, out): + pass + """ + + def validation_step(self, batch, batch_idx): + raise NotImplementedError + + """ + # aggregate outputs from different devices when using DP + def validation_step_end(self, out): + pass + """ + + def validation_epoch_end(self, out): + """ + Gather metrics from all devices, compute mean. + Purge repeated results using data index. + """ + raise NotImplementedError + + def test_step(self, batch, batch_idx): + raise NotImplementedError + + def test_epoch_end(self, out): + """ + Gather metrics from all devices, compute mean. + Purge repeated results using data index. + """ + raise NotImplementedError + + def export(self): + raise NotImplementedError + + def configure_optimizers(self): + optim = parse_optimizer(self.config.system.optimizer, self.model) + ret = { + 'optimizer': optim, + } + if 'scheduler' in self.config.system: + ret.update({ + 'lr_scheduler': parse_scheduler(self.config.system.scheduler, optim), + }) + return ret + diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/systems/criterions.py b/apps/third_party/Wonder3D/instant-nsr-pl/systems/criterions.py new file mode 100644 index 0000000000000000000000000000000000000000..b101032ec7bc8d9943dd5df47557c4b6d3aa465b --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/systems/criterions.py @@ -0,0 +1,164 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class WeightedLoss(nn.Module): + @property + def func(self): + raise NotImplementedError + + def forward(self, inputs, targets, weight=None, reduction='mean'): + assert reduction in ['none', 'sum', 'mean', 'valid_mean'] + loss = self.func(inputs, targets, reduction='none') + if weight is not None: + while weight.ndim < inputs.ndim: + weight = weight[..., None] + loss *= weight.float() + if reduction == 'none': + return loss + elif reduction == 'sum': + return loss.sum() + elif reduction == 'mean': + return loss.mean() + elif reduction == 'valid_mean': + return loss.sum() / weight.float().sum() + + +class MSELoss(WeightedLoss): + @property + def func(self): + return F.mse_loss + + +class L1Loss(WeightedLoss): + @property + def func(self): + return F.l1_loss + + +class PSNR(nn.Module): + def __init__(self): + super().__init__() + + def forward(self, inputs, targets, valid_mask=None, reduction='mean'): + assert reduction in ['mean', 'none'] + value = (inputs - targets)**2 + if valid_mask is not None: + value = value[valid_mask] + if reduction == 'mean': + return -10 * torch.log10(torch.mean(value)) + elif reduction == 'none': + return -10 * torch.log10(torch.mean(value, dim=tuple(range(value.ndim)[1:]))) + + +class SSIM(): + def __init__(self, data_range=(0, 1), kernel_size=(11, 11), sigma=(1.5, 1.5), k1=0.01, k2=0.03, gaussian=True): + self.kernel_size = kernel_size + self.sigma = sigma + self.gaussian = gaussian + + if any(x % 2 == 0 or x <= 0 for x in self.kernel_size): + raise ValueError(f"Expected kernel_size to have odd positive number. Got {kernel_size}.") + if any(y <= 0 for y in self.sigma): + raise ValueError(f"Expected sigma to have positive number. Got {sigma}.") + + data_scale = data_range[1] - data_range[0] + self.c1 = (k1 * data_scale)**2 + self.c2 = (k2 * data_scale)**2 + self.pad_h = (self.kernel_size[0] - 1) // 2 + self.pad_w = (self.kernel_size[1] - 1) // 2 + self._kernel = self._gaussian_or_uniform_kernel(kernel_size=self.kernel_size, sigma=self.sigma) + + def _uniform(self, kernel_size): + max, min = 2.5, -2.5 + ksize_half = (kernel_size - 1) * 0.5 + kernel = torch.linspace(-ksize_half, ksize_half, steps=kernel_size) + for i, j in enumerate(kernel): + if min <= j <= max: + kernel[i] = 1 / (max - min) + else: + kernel[i] = 0 + + return kernel.unsqueeze(dim=0) # (1, kernel_size) + + def _gaussian(self, kernel_size, sigma): + ksize_half = (kernel_size - 1) * 0.5 + kernel = torch.linspace(-ksize_half, ksize_half, steps=kernel_size) + gauss = torch.exp(-0.5 * (kernel / sigma).pow(2)) + return (gauss / gauss.sum()).unsqueeze(dim=0) # (1, kernel_size) + + def _gaussian_or_uniform_kernel(self, kernel_size, sigma): + if self.gaussian: + kernel_x = self._gaussian(kernel_size[0], sigma[0]) + kernel_y = self._gaussian(kernel_size[1], sigma[1]) + else: + kernel_x = self._uniform(kernel_size[0]) + kernel_y = self._uniform(kernel_size[1]) + + return torch.matmul(kernel_x.t(), kernel_y) # (kernel_size, 1) * (1, kernel_size) + + def __call__(self, output, target, reduction='mean'): + if output.dtype != target.dtype: + raise TypeError( + f"Expected output and target to have the same data type. Got output: {output.dtype} and y: {target.dtype}." + ) + + if output.shape != target.shape: + raise ValueError( + f"Expected output and target to have the same shape. Got output: {output.shape} and y: {target.shape}." + ) + + if len(output.shape) != 4 or len(target.shape) != 4: + raise ValueError( + f"Expected output and target to have BxCxHxW shape. Got output: {output.shape} and y: {target.shape}." + ) + + assert reduction in ['mean', 'sum', 'none'] + + channel = output.size(1) + if len(self._kernel.shape) < 4: + self._kernel = self._kernel.expand(channel, 1, -1, -1) + + output = F.pad(output, [self.pad_w, self.pad_w, self.pad_h, self.pad_h], mode="reflect") + target = F.pad(target, [self.pad_w, self.pad_w, self.pad_h, self.pad_h], mode="reflect") + + input_list = torch.cat([output, target, output * output, target * target, output * target]) + outputs = F.conv2d(input_list, self._kernel, groups=channel) + + output_list = [outputs[x * output.size(0) : (x + 1) * output.size(0)] for x in range(len(outputs))] + + mu_pred_sq = output_list[0].pow(2) + mu_target_sq = output_list[1].pow(2) + mu_pred_target = output_list[0] * output_list[1] + + sigma_pred_sq = output_list[2] - mu_pred_sq + sigma_target_sq = output_list[3] - mu_target_sq + sigma_pred_target = output_list[4] - mu_pred_target + + a1 = 2 * mu_pred_target + self.c1 + a2 = 2 * sigma_pred_target + self.c2 + b1 = mu_pred_sq + mu_target_sq + self.c1 + b2 = sigma_pred_sq + sigma_target_sq + self.c2 + + ssim_idx = (a1 * a2) / (b1 * b2) + _ssim = torch.mean(ssim_idx, (1, 2, 3)) + + if reduction == 'none': + return _ssim + elif reduction == 'sum': + return _ssim.sum() + elif reduction == 'mean': + return _ssim.mean() + + +def binary_cross_entropy(input, target, reduction='mean'): + """ + F.binary_cross_entropy is not numerically stable in mixed-precision training. + """ + loss = -(target * torch.log(input) + (1 - target) * torch.log(1 - input)) + + if reduction == 'mean': + return loss.mean() + elif reduction == 'none': + return loss diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/systems/nerf.py b/apps/third_party/Wonder3D/instant-nsr-pl/systems/nerf.py new file mode 100644 index 0000000000000000000000000000000000000000..c5fc821f430aeee62880b7240e75a185ca9b15f2 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/systems/nerf.py @@ -0,0 +1,218 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch_efficient_distloss import flatten_eff_distloss + +import pytorch_lightning as pl +from pytorch_lightning.utilities.rank_zero import rank_zero_info, rank_zero_debug + +import models +from models.ray_utils import get_rays +import systems +from systems.base import BaseSystem +from systems.criterions import PSNR + + +@systems.register('nerf-system') +class NeRFSystem(BaseSystem): + """ + Two ways to print to console: + 1. self.print: correctly handle progress bar + 2. rank_zero_info: use the logging module + """ + def prepare(self): + self.criterions = { + 'psnr': PSNR() + } + self.train_num_samples = self.config.model.train_num_rays * self.config.model.num_samples_per_ray + self.train_num_rays = self.config.model.train_num_rays + + def forward(self, batch): + return self.model(batch['rays']) + + def preprocess_data(self, batch, stage): + if 'index' in batch: # validation / testing + index = batch['index'] + else: + if self.config.model.batch_image_sampling: + index = torch.randint(0, len(self.dataset.all_images), size=(self.train_num_rays,), device=self.dataset.all_images.device) + else: + index = torch.randint(0, len(self.dataset.all_images), size=(1,), device=self.dataset.all_images.device) + if stage in ['train']: + c2w = self.dataset.all_c2w[index] + x = torch.randint( + 0, self.dataset.w, size=(self.train_num_rays,), device=self.dataset.all_images.device + ) + y = torch.randint( + 0, self.dataset.h, size=(self.train_num_rays,), device=self.dataset.all_images.device + ) + if self.dataset.directions.ndim == 3: # (H, W, 3) + directions = self.dataset.directions[y, x] + elif self.dataset.directions.ndim == 4: # (N, H, W, 3) + directions = self.dataset.directions[index, y, x] + rays_o, rays_d = get_rays(directions, c2w) + rgb = self.dataset.all_images[index, y, x].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + fg_mask = self.dataset.all_fg_masks[index, y, x].view(-1).to(self.rank) + else: + c2w = self.dataset.all_c2w[index][0] + if self.dataset.directions.ndim == 3: # (H, W, 3) + directions = self.dataset.directions + elif self.dataset.directions.ndim == 4: # (N, H, W, 3) + directions = self.dataset.directions[index][0] + rays_o, rays_d = get_rays(directions, c2w) + rgb = self.dataset.all_images[index].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + fg_mask = self.dataset.all_fg_masks[index].view(-1).to(self.rank) + + rays = torch.cat([rays_o, F.normalize(rays_d, p=2, dim=-1)], dim=-1) + + if stage in ['train']: + if self.config.model.background_color == 'white': + self.model.background_color = torch.ones((3,), dtype=torch.float32, device=self.rank) + elif self.config.model.background_color == 'random': + self.model.background_color = torch.rand((3,), dtype=torch.float32, device=self.rank) + else: + raise NotImplementedError + else: + self.model.background_color = torch.ones((3,), dtype=torch.float32, device=self.rank) + + if self.dataset.apply_mask: + rgb = rgb * fg_mask[...,None] + self.model.background_color * (1 - fg_mask[...,None]) + + batch.update({ + 'rays': rays, + 'rgb': rgb, + 'fg_mask': fg_mask + }) + + def training_step(self, batch, batch_idx): + out = self(batch) + + loss = 0. + + # update train_num_rays + if self.config.model.dynamic_ray_sampling: + train_num_rays = int(self.train_num_rays * (self.train_num_samples / out['num_samples'].sum().item())) + self.train_num_rays = min(int(self.train_num_rays * 0.9 + train_num_rays * 0.1), self.config.model.max_train_num_rays) + + loss_rgb = F.smooth_l1_loss(out['comp_rgb'][out['rays_valid'][...,0]], batch['rgb'][out['rays_valid'][...,0]]) + self.log('train/loss_rgb', loss_rgb) + loss += loss_rgb * self.C(self.config.system.loss.lambda_rgb) + + # distortion loss proposed in MipNeRF360 + # an efficient implementation from https://github.com/sunset1995/torch_efficient_distloss, but still slows down training by ~30% + if self.C(self.config.system.loss.lambda_distortion) > 0: + loss_distortion = flatten_eff_distloss(out['weights'], out['points'], out['intervals'], out['ray_indices']) + self.log('train/loss_distortion', loss_distortion) + loss += loss_distortion * self.C(self.config.system.loss.lambda_distortion) + + losses_model_reg = self.model.regularizations(out) + for name, value in losses_model_reg.items(): + self.log(f'train/loss_{name}', value) + loss_ = value * self.C(self.config.system.loss[f"lambda_{name}"]) + loss += loss_ + + for name, value in self.config.system.loss.items(): + if name.startswith('lambda'): + self.log(f'train_params/{name}', self.C(value)) + + self.log('train/num_rays', float(self.train_num_rays), prog_bar=True) + + return { + 'loss': loss + } + + """ + # aggregate outputs from different devices (DP) + def training_step_end(self, out): + pass + """ + + """ + # aggregate outputs from different iterations + def training_epoch_end(self, out): + pass + """ + + def validation_step(self, batch, batch_idx): + out = self(batch) + psnr = self.criterions['psnr'](out['comp_rgb'].to(batch['rgb']), batch['rgb']) + W, H = self.dataset.img_wh + self.save_image_grid(f"it{self.global_step}-{batch['index'][0].item()}.png", [ + {'type': 'rgb', 'img': batch['rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'grayscale', 'img': out['depth'].view(H, W), 'kwargs': {}}, + {'type': 'grayscale', 'img': out['opacity'].view(H, W), 'kwargs': {'cmap': None, 'data_range': (0, 1)}} + ]) + return { + 'psnr': psnr, + 'index': batch['index'] + } + + + """ + # aggregate outputs from different devices when using DP + def validation_step_end(self, out): + pass + """ + + def validation_epoch_end(self, out): + out = self.all_gather(out) + if self.trainer.is_global_zero: + out_set = {} + for step_out in out: + # DP + if step_out['index'].ndim == 1: + out_set[step_out['index'].item()] = {'psnr': step_out['psnr']} + # DDP + else: + for oi, index in enumerate(step_out['index']): + out_set[index[0].item()] = {'psnr': step_out['psnr'][oi]} + psnr = torch.mean(torch.stack([o['psnr'] for o in out_set.values()])) + self.log('val/psnr', psnr, prog_bar=True, rank_zero_only=True) + + def test_step(self, batch, batch_idx): + out = self(batch) + psnr = self.criterions['psnr'](out['comp_rgb'].to(batch['rgb']), batch['rgb']) + W, H = self.dataset.img_wh + self.save_image_grid(f"it{self.global_step}-test/{batch['index'][0].item()}.png", [ + {'type': 'rgb', 'img': batch['rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'grayscale', 'img': out['depth'].view(H, W), 'kwargs': {}}, + {'type': 'grayscale', 'img': out['opacity'].view(H, W), 'kwargs': {'cmap': None, 'data_range': (0, 1)}} + ]) + return { + 'psnr': psnr, + 'index': batch['index'] + } + + def test_epoch_end(self, out): + out = self.all_gather(out) + if self.trainer.is_global_zero: + out_set = {} + for step_out in out: + # DP + if step_out['index'].ndim == 1: + out_set[step_out['index'].item()] = {'psnr': step_out['psnr']} + # DDP + else: + for oi, index in enumerate(step_out['index']): + out_set[index[0].item()] = {'psnr': step_out['psnr'][oi]} + psnr = torch.mean(torch.stack([o['psnr'] for o in out_set.values()])) + self.log('test/psnr', psnr, prog_bar=True, rank_zero_only=True) + + self.save_img_sequence( + f"it{self.global_step}-test", + f"it{self.global_step}-test", + '(\d+)\.png', + save_format='mp4', + fps=30 + ) + + self.export() + + def export(self): + mesh = self.model.export(self.config.export) + self.save_mesh( + f"it{self.global_step}-{self.config.model.geometry.isosurface.method}{self.config.model.geometry.isosurface.resolution}.obj", + **mesh + ) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus.py b/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus.py new file mode 100644 index 0000000000000000000000000000000000000000..ce273d0790a1fbea4d795b07e285c1318573a562 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus.py @@ -0,0 +1,265 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch_efficient_distloss import flatten_eff_distloss + +import pytorch_lightning as pl +from pytorch_lightning.utilities.rank_zero import rank_zero_info, rank_zero_debug + +import models +from models.utils import cleanup +from models.ray_utils import get_rays +import systems +from systems.base import BaseSystem +from systems.criterions import PSNR, binary_cross_entropy + + +@systems.register('neus-system') +class NeuSSystem(BaseSystem): + """ + Two ways to print to console: + 1. self.print: correctly handle progress bar + 2. rank_zero_info: use the logging module + """ + def prepare(self): + self.criterions = { + 'psnr': PSNR() + } + self.train_num_samples = self.config.model.train_num_rays * (self.config.model.num_samples_per_ray + self.config.model.get('num_samples_per_ray_bg', 0)) + self.train_num_rays = self.config.model.train_num_rays + + def forward(self, batch): + return self.model(batch['rays']) + + def preprocess_data(self, batch, stage): + if 'index' in batch: # validation / testing + index = batch['index'] + else: + if self.config.model.batch_image_sampling: + index = torch.randint(0, len(self.dataset.all_images), size=(self.train_num_rays,), device=self.dataset.all_images.device) + else: + index = torch.randint(0, len(self.dataset.all_images), size=(1,), device=self.dataset.all_images.device) + if stage in ['train']: + c2w = self.dataset.all_c2w[index] + x = torch.randint( + 0, self.dataset.w, size=(self.train_num_rays,), device=self.dataset.all_images.device + ) + y = torch.randint( + 0, self.dataset.h, size=(self.train_num_rays,), device=self.dataset.all_images.device + ) + if self.dataset.directions.ndim == 3: # (H, W, 3) + directions = self.dataset.directions[y, x] + elif self.dataset.directions.ndim == 4: # (N, H, W, 3) + directions = self.dataset.directions[index, y, x] + rays_o, rays_d = get_rays(directions, c2w) + rgb = self.dataset.all_images[index, y, x].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + fg_mask = self.dataset.all_fg_masks[index, y, x].view(-1).to(self.rank) + else: + c2w = self.dataset.all_c2w[index][0] + if self.dataset.directions.ndim == 3: # (H, W, 3) + directions = self.dataset.directions + elif self.dataset.directions.ndim == 4: # (N, H, W, 3) + directions = self.dataset.directions[index][0] + rays_o, rays_d = get_rays(directions, c2w) + rgb = self.dataset.all_images[index].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + fg_mask = self.dataset.all_fg_masks[index].view(-1).to(self.rank) + + rays = torch.cat([rays_o, F.normalize(rays_d, p=2, dim=-1)], dim=-1) + + if stage in ['train']: + if self.config.model.background_color == 'white': + self.model.background_color = torch.ones((3,), dtype=torch.float32, device=self.rank) + elif self.config.model.background_color == 'random': + self.model.background_color = torch.rand((3,), dtype=torch.float32, device=self.rank) + else: + raise NotImplementedError + else: + self.model.background_color = torch.ones((3,), dtype=torch.float32, device=self.rank) + + if self.dataset.apply_mask: + rgb = rgb * fg_mask[...,None] + self.model.background_color * (1 - fg_mask[...,None]) + + batch.update({ + 'rays': rays, + 'rgb': rgb, + 'fg_mask': fg_mask + }) + + def training_step(self, batch, batch_idx): + out = self(batch) + + loss = 0. + + # update train_num_rays + if self.config.model.dynamic_ray_sampling: + train_num_rays = int(self.train_num_rays * (self.train_num_samples / out['num_samples_full'].sum().item())) + self.train_num_rays = min(int(self.train_num_rays * 0.9 + train_num_rays * 0.1), self.config.model.max_train_num_rays) + + loss_rgb_mse = F.mse_loss(out['comp_rgb_full'][out['rays_valid_full'][...,0]], batch['rgb'][out['rays_valid_full'][...,0]]) + self.log('train/loss_rgb_mse', loss_rgb_mse) + loss += loss_rgb_mse * self.C(self.config.system.loss.lambda_rgb_mse) + + loss_rgb_l1 = F.l1_loss(out['comp_rgb_full'][out['rays_valid_full'][...,0]], batch['rgb'][out['rays_valid_full'][...,0]]) + self.log('train/loss_rgb', loss_rgb_l1) + loss += loss_rgb_l1 * self.C(self.config.system.loss.lambda_rgb_l1) + + loss_eikonal = ((torch.linalg.norm(out['sdf_grad_samples'], ord=2, dim=-1) - 1.)**2).mean() + self.log('train/loss_eikonal', loss_eikonal) + loss += loss_eikonal * self.C(self.config.system.loss.lambda_eikonal) + + opacity = torch.clamp(out['opacity'].squeeze(-1), 1.e-3, 1.-1.e-3) + loss_mask = binary_cross_entropy(opacity, batch['fg_mask'].float()) + self.log('train/loss_mask', loss_mask) + loss += loss_mask * (self.C(self.config.system.loss.lambda_mask) if self.dataset.has_mask else 0.0) + + loss_opaque = binary_cross_entropy(opacity, opacity) + self.log('train/loss_opaque', loss_opaque) + loss += loss_opaque * self.C(self.config.system.loss.lambda_opaque) + + loss_sparsity = torch.exp(-self.config.system.loss.sparsity_scale * out['sdf_samples'].abs()).mean() + self.log('train/loss_sparsity', loss_sparsity) + loss += loss_sparsity * self.C(self.config.system.loss.lambda_sparsity) + + if self.C(self.config.system.loss.lambda_curvature) > 0: + assert 'sdf_laplace_samples' in out, "Need geometry.grad_type='finite_difference' to get SDF Laplace samples" + loss_curvature = out['sdf_laplace_samples'].abs().mean() + self.log('train/loss_curvature', loss_curvature) + loss += loss_curvature * self.C(self.config.system.loss.lambda_curvature) + + # distortion loss proposed in MipNeRF360 + # an efficient implementation from https://github.com/sunset1995/torch_efficient_distloss + if self.C(self.config.system.loss.lambda_distortion) > 0: + loss_distortion = flatten_eff_distloss(out['weights'], out['points'], out['intervals'], out['ray_indices']) + self.log('train/loss_distortion', loss_distortion) + loss += loss_distortion * self.C(self.config.system.loss.lambda_distortion) + + if self.config.model.learned_background and self.C(self.config.system.loss.lambda_distortion_bg) > 0: + loss_distortion_bg = flatten_eff_distloss(out['weights_bg'], out['points_bg'], out['intervals_bg'], out['ray_indices_bg']) + self.log('train/loss_distortion_bg', loss_distortion_bg) + loss += loss_distortion_bg * self.C(self.config.system.loss.lambda_distortion_bg) + + losses_model_reg = self.model.regularizations(out) + for name, value in losses_model_reg.items(): + self.log(f'train/loss_{name}', value) + loss_ = value * self.C(self.config.system.loss[f"lambda_{name}"]) + loss += loss_ + + self.log('train/inv_s', out['inv_s'], prog_bar=True) + + for name, value in self.config.system.loss.items(): + if name.startswith('lambda'): + self.log(f'train_params/{name}', self.C(value)) + + self.log('train/num_rays', float(self.train_num_rays), prog_bar=True) + + return { + 'loss': loss + } + + """ + # aggregate outputs from different devices (DP) + def training_step_end(self, out): + pass + """ + + """ + # aggregate outputs from different iterations + def training_epoch_end(self, out): + pass + """ + + def validation_step(self, batch, batch_idx): + out = self(batch) + psnr = self.criterions['psnr'](out['comp_rgb_full'].to(batch['rgb']), batch['rgb']) + W, H = self.dataset.img_wh + self.save_image_grid(f"it{self.global_step}-{batch['index'][0].item()}.png", [ + {'type': 'rgb', 'img': batch['rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb_full'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}} + ] + ([ + {'type': 'rgb', 'img': out['comp_rgb_bg'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + ] if self.config.model.learned_background else []) + [ + {'type': 'grayscale', 'img': out['depth'].view(H, W), 'kwargs': {}}, + {'type': 'rgb', 'img': out['comp_normal'].view(H, W, 3), 'kwargs': {'data_format': 'HWC', 'data_range': (-1, 1)}} + ]) + return { + 'psnr': psnr, + 'index': batch['index'] + } + + + """ + # aggregate outputs from different devices when using DP + def validation_step_end(self, out): + pass + """ + + def validation_epoch_end(self, out): + out = self.all_gather(out) + if self.trainer.is_global_zero: + out_set = {} + for step_out in out: + # DP + if step_out['index'].ndim == 1: + out_set[step_out['index'].item()] = {'psnr': step_out['psnr']} + # DDP + else: + for oi, index in enumerate(step_out['index']): + out_set[index[0].item()] = {'psnr': step_out['psnr'][oi]} + psnr = torch.mean(torch.stack([o['psnr'] for o in out_set.values()])) + self.log('val/psnr', psnr, prog_bar=True, rank_zero_only=True) + + def test_step(self, batch, batch_idx): + out = self(batch) + psnr = self.criterions['psnr'](out['comp_rgb_full'].to(batch['rgb']), batch['rgb']) + W, H = self.dataset.img_wh + self.save_image_grid(f"it{self.global_step}-test/{batch['index'][0].item()}.png", [ + {'type': 'rgb', 'img': batch['rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb_full'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}} + ] + ([ + {'type': 'rgb', 'img': out['comp_rgb_bg'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + ] if self.config.model.learned_background else []) + [ + {'type': 'grayscale', 'img': out['depth'].view(H, W), 'kwargs': {}}, + {'type': 'rgb', 'img': out['comp_normal'].view(H, W, 3), 'kwargs': {'data_format': 'HWC', 'data_range': (-1, 1)}} + ]) + return { + 'psnr': psnr, + 'index': batch['index'] + } + + def test_epoch_end(self, out): + """ + Synchronize devices. + Generate image sequence using test outputs. + """ + out = self.all_gather(out) + if self.trainer.is_global_zero: + out_set = {} + for step_out in out: + # DP + if step_out['index'].ndim == 1: + out_set[step_out['index'].item()] = {'psnr': step_out['psnr']} + # DDP + else: + for oi, index in enumerate(step_out['index']): + out_set[index[0].item()] = {'psnr': step_out['psnr'][oi]} + psnr = torch.mean(torch.stack([o['psnr'] for o in out_set.values()])) + self.log('test/psnr', psnr, prog_bar=True, rank_zero_only=True) + + self.save_img_sequence( + f"it{self.global_step}-test", + f"it{self.global_step}-test", + '(\d+)\.png', + save_format='mp4', + fps=30 + ) + + self.export() + + def export(self): + mesh = self.model.export(self.config.export) + self.save_mesh( + f"it{self.global_step}-{self.config.model.geometry.isosurface.method}{self.config.model.geometry.isosurface.resolution}.obj", + **mesh + ) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus_ortho.py b/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus_ortho.py new file mode 100644 index 0000000000000000000000000000000000000000..803b2a84564e491e16883ee0177979c4280e8b3d --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus_ortho.py @@ -0,0 +1,358 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch_efficient_distloss import flatten_eff_distloss + +import pytorch_lightning as pl +from pytorch_lightning.utilities.rank_zero import rank_zero_info, rank_zero_debug + +import models +from models.utils import cleanup +from models.ray_utils import get_ortho_rays +import systems +from systems.base import BaseSystem +from systems.criterions import PSNR, binary_cross_entropy + +import pdb + +def ranking_loss(error, penalize_ratio=0.7, extra_weights=None , type='mean'): + error, indices = torch.sort(error) + # only sum relatively small errors + s_error = torch.index_select(error, 0, index=indices[:int(penalize_ratio * indices.shape[0])]) + if extra_weights is not None: + weights = torch.index_select(extra_weights, 0, index=indices[:int(penalize_ratio * indices.shape[0])]) + s_error = s_error * weights + + if type == 'mean': + return torch.mean(s_error) + elif type == 'sum': + return torch.sum(s_error) + +@systems.register('ortho-neus-system') +class OrthoNeuSSystem(BaseSystem): + """ + Two ways to print to console: + 1. self.print: correctly handle progress bar + 2. rank_zero_info: use the logging module + """ + def prepare(self): + self.criterions = { + 'psnr': PSNR() + } + self.train_num_samples = self.config.model.train_num_rays * (self.config.model.num_samples_per_ray + self.config.model.get('num_samples_per_ray_bg', 0)) + self.train_num_rays = self.config.model.train_num_rays + self.cos = torch.nn.CosineSimilarity(dim=-1, eps=1e-6) + + def forward(self, batch): + return self.model(batch['rays']) + + def preprocess_data(self, batch, stage): + if 'index' in batch: # validation / testing + index = batch['index'] + else: + if self.config.model.batch_image_sampling: + index = torch.randint(0, len(self.dataset.all_images), size=(self.train_num_rays,), device=self.dataset.all_images.device) + else: + index = torch.randint(0, len(self.dataset.all_images), size=(1,), device=self.dataset.all_images.device) + if stage in ['train']: + c2w = self.dataset.all_c2w[index] + x = torch.randint( + 0, self.dataset.w, size=(self.train_num_rays,), device=self.dataset.all_images.device + ) + y = torch.randint( + 0, self.dataset.h, size=(self.train_num_rays,), device=self.dataset.all_images.device + ) + if self.dataset.directions.ndim == 3: # (H, W, 3) + directions = self.dataset.directions[y, x] + origins = self.dataset.origins[y, x] + elif self.dataset.directions.ndim == 4: # (N, H, W, 3) + directions = self.dataset.directions[index, y, x] + origins = self.dataset.origins[index, y, x] + rays_o, rays_d = get_ortho_rays(origins, directions, c2w) + rgb = self.dataset.all_images[index, y, x].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + normal = self.dataset.all_normals_world[index, y, x].view(-1, self.dataset.all_normals_world.shape[-1]).to(self.rank) + fg_mask = self.dataset.all_fg_masks[index, y, x].view(-1).to(self.rank) + rgb_mask = self.dataset.all_rgb_masks[index, y, x].view(-1).to(self.rank) + view_weights = self.dataset.view_weights[index, y, x].view(-1).to(self.rank) + else: + c2w = self.dataset.all_c2w[index][0] + if self.dataset.directions.ndim == 3: # (H, W, 3) + directions = self.dataset.directions + origins = self.dataset.origins + elif self.dataset.directions.ndim == 4: # (N, H, W, 3) + directions = self.dataset.directions[index][0] + origins = self.dataset.origins[index][0] + rays_o, rays_d = get_ortho_rays(origins, directions, c2w) + rgb = self.dataset.all_images[index].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + normal = self.dataset.all_normals_world[index].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + fg_mask = self.dataset.all_fg_masks[index].view(-1).to(self.rank) + rgb_mask = self.dataset.all_rgb_masks[index].view(-1).to(self.rank) + view_weights = None + + cosines = self.cos(rays_d, normal) + rays = torch.cat([rays_o, F.normalize(rays_d, p=2, dim=-1)], dim=-1) + + if stage in ['train']: + if self.config.model.background_color == 'white': + self.model.background_color = torch.ones((3,), dtype=torch.float32, device=self.rank) + elif self.config.model.background_color == 'black': + self.model.background_color = torch.zeros((3,), dtype=torch.float32, device=self.rank) + elif self.config.model.background_color == 'random': + self.model.background_color = torch.rand((3,), dtype=torch.float32, device=self.rank) + else: + raise NotImplementedError + else: + self.model.background_color = torch.ones((3,), dtype=torch.float32, device=self.rank) + + if self.dataset.apply_mask: + rgb = rgb * fg_mask[...,None] + self.model.background_color * (1 - fg_mask[...,None]) + + batch.update({ + 'rays': rays, + 'rgb': rgb, + 'normal': normal, + 'fg_mask': fg_mask, + 'rgb_mask': rgb_mask, + 'cosines': cosines, + 'view_weights': view_weights + }) + + def training_step(self, batch, batch_idx): + out = self(batch) + + cosines = batch['cosines'] + fg_mask = batch['fg_mask'] + rgb_mask = batch['rgb_mask'] + view_weights = batch['view_weights'] + + cosines[cosines > -0.1] = 0 + mask = ((fg_mask > 0) & (cosines < -0.1)) + rgb_mask = out['rays_valid_full'][...,0] & (rgb_mask > 0) + + grad_cosines = self.cos(batch['rays'][...,3:], out['comp_normal']).detach() + # grad_cosines = cosines + + loss = 0. + + # update train_num_rays + if self.config.model.dynamic_ray_sampling: + train_num_rays = int(self.train_num_rays * (self.train_num_samples / out['num_samples_full'].sum().item())) + self.train_num_rays = min(int(self.train_num_rays * 0.9 + train_num_rays * 0.1), self.config.model.max_train_num_rays) + + erros_rgb_mse = F.mse_loss(out['comp_rgb_full'][rgb_mask], batch['rgb'][rgb_mask], reduction='none') + # erros_rgb_mse = erros_rgb_mse * torch.exp(grad_cosines.abs())[:, None][rgb_mask] / torch.exp(grad_cosines.abs()[rgb_mask]).sum() + # loss_rgb_mse = ranking_loss(erros_rgb_mse.sum(dim=1), penalize_ratio=0.7, type='sum') + loss_rgb_mse = ranking_loss(erros_rgb_mse.sum(dim=1), + penalize_ratio=self.config.system.loss.rgb_p_ratio, type='mean') + self.log('train/loss_rgb_mse', loss_rgb_mse, prog_bar=True, rank_zero_only=True) + loss += loss_rgb_mse * self.C(self.config.system.loss.lambda_rgb_mse) + + loss_rgb_l1 = F.l1_loss(out['comp_rgb_full'][rgb_mask], batch['rgb'][rgb_mask], reduction='none') + loss_rgb_l1 = ranking_loss(loss_rgb_l1.sum(dim=1), + # extra_weights=view_weights[rgb_mask], + penalize_ratio=0.8) + self.log('train/loss_rgb', loss_rgb_l1) + loss += loss_rgb_l1 * self.C(self.config.system.loss.lambda_rgb_l1) + + normal_errors = 1 - F.cosine_similarity(out['comp_normal'], batch['normal'], dim=1) + # normal_errors = normal_errors * cosines.abs() / cosines.abs().sum() + if self.config.system.loss.geo_aware: + normal_errors = normal_errors * torch.exp(cosines.abs()) / torch.exp(cosines.abs()).sum() + loss_normal = ranking_loss(normal_errors[mask], + penalize_ratio=self.config.system.loss.normal_p_ratio, + extra_weights=view_weights[mask], + type='sum') + else: + loss_normal = ranking_loss(normal_errors[mask], + penalize_ratio=self.config.system.loss.normal_p_ratio, + extra_weights=view_weights[mask], + type='mean') + + self.log('train/loss_normal', loss_normal, prog_bar=True, rank_zero_only=True) + loss += loss_normal * self.C(self.config.system.loss.lambda_normal) + + loss_eikonal = ((torch.linalg.norm(out['sdf_grad_samples'], ord=2, dim=-1) - 1.)**2).mean() + self.log('train/loss_eikonal', loss_eikonal, prog_bar=True, rank_zero_only=True) + loss += loss_eikonal * self.C(self.config.system.loss.lambda_eikonal) + + opacity = torch.clamp(out['opacity'].squeeze(-1), 1.e-3, 1.-1.e-3) + loss_mask = binary_cross_entropy(opacity, batch['fg_mask'].float(), reduction='none') + loss_mask = ranking_loss(loss_mask, + penalize_ratio=self.config.system.loss.mask_p_ratio, + extra_weights=view_weights) + self.log('train/loss_mask', loss_mask, prog_bar=True, rank_zero_only=True) + loss += loss_mask * (self.C(self.config.system.loss.lambda_mask) if self.dataset.has_mask else 0.0) + + loss_opaque = binary_cross_entropy(opacity, opacity) + self.log('train/loss_opaque', loss_opaque) + loss += loss_opaque * self.C(self.config.system.loss.lambda_opaque) + + loss_sparsity = torch.exp(-self.config.system.loss.sparsity_scale * out['random_sdf'].abs()).mean() + self.log('train/loss_sparsity', loss_sparsity, prog_bar=True, rank_zero_only=True) + loss += loss_sparsity * self.C(self.config.system.loss.lambda_sparsity) + + if self.C(self.config.system.loss.lambda_curvature) > 0: + assert 'sdf_laplace_samples' in out, "Need geometry.grad_type='finite_difference' to get SDF Laplace samples" + loss_curvature = out['sdf_laplace_samples'].abs().mean() + self.log('train/loss_curvature', loss_curvature) + loss += loss_curvature * self.C(self.config.system.loss.lambda_curvature) + + # distortion loss proposed in MipNeRF360 + # an efficient implementation from https://github.com/sunset1995/torch_efficient_distloss + if self.C(self.config.system.loss.lambda_distortion) > 0: + loss_distortion = flatten_eff_distloss(out['weights'], out['points'], out['intervals'], out['ray_indices']) + self.log('train/loss_distortion', loss_distortion) + loss += loss_distortion * self.C(self.config.system.loss.lambda_distortion) + + if self.config.model.learned_background and self.C(self.config.system.loss.lambda_distortion_bg) > 0: + loss_distortion_bg = flatten_eff_distloss(out['weights_bg'], out['points_bg'], out['intervals_bg'], out['ray_indices_bg']) + self.log('train/loss_distortion_bg', loss_distortion_bg) + loss += loss_distortion_bg * self.C(self.config.system.loss.lambda_distortion_bg) + + if self.C(self.config.system.loss.lambda_3d_normal_smooth) > 0: + if "random_sdf_grad" not in out: + raise ValueError( + "random_sdf_grad is required for normal smooth loss, no normal is found in the output." + ) + if "normal_perturb" not in out: + raise ValueError( + "normal_perturb is required for normal smooth loss, no normal_perturb is found in the output." + ) + normals_3d = out["random_sdf_grad"] + normals_perturb_3d = out["normal_perturb"] + loss_3d_normal_smooth = (normals_3d - normals_perturb_3d).abs().mean() + self.log('train/loss_3d_normal_smooth', loss_3d_normal_smooth, prog_bar=True ) + + loss += loss_3d_normal_smooth * self.C(self.config.system.loss.lambda_3d_normal_smooth) + + losses_model_reg = self.model.regularizations(out) + for name, value in losses_model_reg.items(): + self.log(f'train/loss_{name}', value) + loss_ = value * self.C(self.config.system.loss[f"lambda_{name}"]) + loss += loss_ + + self.log('train/inv_s', out['inv_s'], prog_bar=True) + + for name, value in self.config.system.loss.items(): + if name.startswith('lambda'): + self.log(f'train_params/{name}', self.C(value)) + + self.log('train/num_rays', float(self.train_num_rays), prog_bar=True) + + return { + 'loss': loss + } + + """ + # aggregate outputs from different devices (DP) + def training_step_end(self, out): + pass + """ + + """ + # aggregate outputs from different iterations + def training_epoch_end(self, out): + pass + """ + + def validation_step(self, batch, batch_idx): + out = self(batch) + psnr = self.criterions['psnr'](out['comp_rgb_full'].to(batch['rgb']), batch['rgb']) + W, H = self.dataset.img_wh + self.save_image_grid(f"it{self.global_step}-{batch['index'][0].item()}.png", [ + {'type': 'rgb', 'img': batch['rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb_full'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}} + ] + ([ + {'type': 'rgb', 'img': out['comp_rgb_bg'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + ] if self.config.model.learned_background else []) + [ + {'type': 'grayscale', 'img': out['depth'].view(H, W), 'kwargs': {}}, + {'type': 'rgb', 'img': out['comp_normal'].view(H, W, 3), 'kwargs': {'data_format': 'HWC', 'data_range': (-1, 1)}} + ]) + return { + 'psnr': psnr, + 'index': batch['index'] + } + + + """ + # aggregate outputs from different devices when using DP + def validation_step_end(self, out): + pass + """ + + def validation_epoch_end(self, out): + out = self.all_gather(out) + if self.trainer.is_global_zero: + out_set = {} + for step_out in out: + # DP + if step_out['index'].ndim == 1: + out_set[step_out['index'].item()] = {'psnr': step_out['psnr']} + # DDP + else: + for oi, index in enumerate(step_out['index']): + out_set[index[0].item()] = {'psnr': step_out['psnr'][oi]} + psnr = torch.mean(torch.stack([o['psnr'] for o in out_set.values()])) + self.log('val/psnr', psnr, prog_bar=True, rank_zero_only=True) + self.export() + + # def test_step(self, batch, batch_idx): + # out = self(batch) + # psnr = self.criterions['psnr'](out['comp_rgb_full'].to(batch['rgb']), batch['rgb']) + # W, H = self.dataset.img_wh + # self.save_image_grid(f"it{self.global_step}-test/{batch['index'][0].item()}.png", [ + # {'type': 'rgb', 'img': batch['rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + # {'type': 'rgb', 'img': out['comp_rgb_full'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}} + # ] + ([ + # {'type': 'rgb', 'img': out['comp_rgb_bg'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + # {'type': 'rgb', 'img': out['comp_rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + # ] if self.config.model.learned_background else []) + [ + # {'type': 'grayscale', 'img': out['depth'].view(H, W), 'kwargs': {}}, + # {'type': 'rgb', 'img': out['comp_normal'].view(H, W, 3), 'kwargs': {'data_format': 'HWC', 'data_range': (-1, 1)}} + # ]) + # return { + # 'psnr': psnr, + # 'index': batch['index'] + # } + + def test_step(self, batch, batch_idx): + pass + + def test_epoch_end(self, out): + """ + Synchronize devices. + Generate image sequence using test outputs. + """ + # out = self.all_gather(out) + if self.trainer.is_global_zero: + # out_set = {} + # for step_out in out: + # # DP + # if step_out['index'].ndim == 1: + # out_set[step_out['index'].item()] = {'psnr': step_out['psnr']} + # # DDP + # else: + # for oi, index in enumerate(step_out['index']): + # out_set[index[0].item()] = {'psnr': step_out['psnr'][oi]} + # psnr = torch.mean(torch.stack([o['psnr'] for o in out_set.values()])) + # self.log('test/psnr', psnr, prog_bar=True, rank_zero_only=True) + + # self.save_img_sequence( + # f"it{self.global_step}-test", + # f"it{self.global_step}-test", + # '(\d+)\.png', + # save_format='mp4', + # fps=30 + # ) + + self.export() + + def export(self): + mesh = self.model.export(self.config.export) + # pdb.set_trace() + self.save_mesh( + f"it{self.global_step}-{self.config.model.geometry.isosurface.method}{self.config.model.geometry.isosurface.resolution}.obj", + ortho_scale=self.config.export.ortho_scale, + **mesh + ) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus_pinhole.py b/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus_pinhole.py new file mode 100644 index 0000000000000000000000000000000000000000..ebc224e0c9bc9e45f9c364be804e7353927ba1d1 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/systems/neus_pinhole.py @@ -0,0 +1,343 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch_efficient_distloss import flatten_eff_distloss + +import pytorch_lightning as pl +from pytorch_lightning.utilities.rank_zero import rank_zero_info, rank_zero_debug + +import models +from models.utils import cleanup +from models.ray_utils import get_rays +import systems +from systems.base import BaseSystem +from systems.criterions import PSNR, binary_cross_entropy + +import pdb + +def ranking_loss(error, penalize_ratio=0.7, extra_weights=None , type='mean'): + error, indices = torch.sort(error) + # only sum relatively small errors + s_error = torch.index_select(error, 0, index=indices[:int(penalize_ratio * indices.shape[0])]) + if extra_weights is not None: + weights = torch.index_select(extra_weights, 0, index=indices[:int(penalize_ratio * indices.shape[0])]) + s_error = s_error * weights + + if type == 'mean': + return torch.mean(s_error) + elif type == 'sum': + return torch.sum(s_error) + +@systems.register('pinhole-neus-system') +class PinholeNeuSSystem(BaseSystem): + """ + Two ways to print to console: + 1. self.print: correctly handle progress bar + 2. rank_zero_info: use the logging module + """ + def prepare(self): + self.criterions = { + 'psnr': PSNR() + } + self.train_num_samples = self.config.model.train_num_rays * (self.config.model.num_samples_per_ray + self.config.model.get('num_samples_per_ray_bg', 0)) + self.train_num_rays = self.config.model.train_num_rays + self.cos = torch.nn.CosineSimilarity(dim=-1, eps=1e-6) + + def forward(self, batch): + return self.model(batch['rays']) + + def preprocess_data(self, batch, stage): + if 'index' in batch: # validation / testing + index = batch['index'] + else: + if self.config.model.batch_image_sampling: + index = torch.randint(0, len(self.dataset.all_images), size=(self.train_num_rays,), device=self.dataset.all_images.device) + else: + index = torch.randint(0, len(self.dataset.all_images), size=(1,), device=self.dataset.all_images.device) + if stage in ['train']: + c2w = self.dataset.all_c2w[index] + x = torch.randint( + 0, self.dataset.w, size=(self.train_num_rays,), device=self.dataset.all_images.device + ) + y = torch.randint( + 0, self.dataset.h, size=(self.train_num_rays,), device=self.dataset.all_images.device + ) + if self.dataset.directions.ndim == 3: # (H, W, 3) + directions = self.dataset.directions[y, x] + # origins = self.dataset.origins[y, x] + elif self.dataset.directions.ndim == 4: # (N, H, W, 3) + directions = self.dataset.directions[index, y, x] + # origins = self.dataset.origins[index, y, x] + rays_o, rays_d = get_rays(directions, c2w) + rgb = self.dataset.all_images[index, y, x].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + normal = self.dataset.all_normals_world[index, y, x].view(-1, self.dataset.all_normals_world.shape[-1]).to(self.rank) + fg_mask = self.dataset.all_fg_masks[index, y, x].view(-1).to(self.rank) + rgb_mask = self.dataset.all_rgb_masks[index, y, x].view(-1).to(self.rank) + view_weights = self.dataset.view_weights[index, y, x].view(-1).to(self.rank) + else: + c2w = self.dataset.all_c2w[index][0] + if self.dataset.directions.ndim == 3: # (H, W, 3) + directions = self.dataset.directions + # origins = self.dataset.origins + elif self.dataset.directions.ndim == 4: # (N, H, W, 3) + directions = self.dataset.directions[index][0] + # origins = self.dataset.origins[index][0] + rays_o, rays_d = get_rays(directions, c2w) + rgb = self.dataset.all_images[index].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + normal = self.dataset.all_normals_world[index].view(-1, self.dataset.all_images.shape[-1]).to(self.rank) + fg_mask = self.dataset.all_fg_masks[index].view(-1).to(self.rank) + rgb_mask = self.dataset.all_rgb_masks[index].view(-1).to(self.rank) + view_weights = None + + cosines = self.cos(rays_d, normal) + rays = torch.cat([rays_o, F.normalize(rays_d, p=2, dim=-1)], dim=-1) + + if stage in ['train']: + if self.config.model.background_color == 'white': + self.model.background_color = torch.ones((3,), dtype=torch.float32, device=self.rank) + elif self.config.model.background_color == 'black': + self.model.background_color = torch.zeros((3,), dtype=torch.float32, device=self.rank) + elif self.config.model.background_color == 'random': + self.model.background_color = torch.rand((3,), dtype=torch.float32, device=self.rank) + else: + raise NotImplementedError + else: + self.model.background_color = torch.ones((3,), dtype=torch.float32, device=self.rank) + + if self.dataset.apply_mask: + rgb = rgb * fg_mask[...,None] + self.model.background_color * (1 - fg_mask[...,None]) + + batch.update({ + 'rays': rays, + 'rgb': rgb, + 'normal': normal, + 'fg_mask': fg_mask, + 'rgb_mask': rgb_mask, + 'cosines': cosines, + 'view_weights': view_weights + }) + + def training_step(self, batch, batch_idx): + out = self(batch) + + cosines = batch['cosines'] + fg_mask = batch['fg_mask'] + rgb_mask = batch['rgb_mask'] + view_weights = batch['view_weights'] + + cosines[cosines > -0.1] = 0 + mask = ((fg_mask > 0) & (cosines < -0.1)) + rgb_mask = out['rays_valid_full'][...,0] & (rgb_mask > 0) + + grad_cosines = self.cos(batch['rays'][...,3:], out['comp_normal']).detach() + # grad_cosines = cosines + + loss = 0. + + # update train_num_rays + if self.config.model.dynamic_ray_sampling: + train_num_rays = int(self.train_num_rays * (self.train_num_samples / out['num_samples_full'].sum().item())) + self.train_num_rays = min(int(self.train_num_rays * 0.9 + train_num_rays * 0.1), self.config.model.max_train_num_rays) + + erros_rgb_mse = F.mse_loss(out['comp_rgb_full'][rgb_mask], batch['rgb'][rgb_mask], reduction='none') + # erros_rgb_mse = erros_rgb_mse * torch.exp(grad_cosines.abs())[:, None][rgb_mask] / torch.exp(grad_cosines.abs()[rgb_mask]).sum() + # loss_rgb_mse = ranking_loss(erros_rgb_mse.sum(dim=1), penalize_ratio=0.7, type='sum') + loss_rgb_mse = ranking_loss(erros_rgb_mse.sum(dim=1), penalize_ratio=0.7, type='mean') + self.log('train/loss_rgb_mse', loss_rgb_mse, prog_bar=True, rank_zero_only=True) + loss += loss_rgb_mse * self.C(self.config.system.loss.lambda_rgb_mse) + + loss_rgb_l1 = F.l1_loss(out['comp_rgb_full'][rgb_mask], batch['rgb'][rgb_mask], reduction='none') + loss_rgb_l1 = ranking_loss(loss_rgb_l1.sum(dim=1), + extra_weights=view_weights[rgb_mask], + penalize_ratio=0.8) + self.log('train/loss_rgb', loss_rgb_l1) + loss += loss_rgb_l1 * self.C(self.config.system.loss.lambda_rgb_l1) + + normal_errors = 1 - F.cosine_similarity(out['comp_normal'], batch['normal'], dim=1) + # normal_errors = normal_errors * cosines.abs() / cosines.abs().sum() + normal_errors = normal_errors * torch.exp(cosines.abs()) / torch.exp(cosines.abs()).sum() + loss_normal = ranking_loss(normal_errors[mask], penalize_ratio=0.8, + # extra_weights=view_weights[mask], + type='sum') + self.log('train/loss_normal', loss_normal, prog_bar=True, rank_zero_only=True) + loss += loss_normal * self.C(self.config.system.loss.lambda_normal) + + loss_eikonal = ((torch.linalg.norm(out['sdf_grad_samples'], ord=2, dim=-1) - 1.)**2).mean() + self.log('train/loss_eikonal', loss_eikonal, prog_bar=True, rank_zero_only=True) + loss += loss_eikonal * self.C(self.config.system.loss.lambda_eikonal) + + opacity = torch.clamp(out['opacity'].squeeze(-1), 1.e-3, 1.-1.e-3) + loss_mask = binary_cross_entropy(opacity, batch['fg_mask'].float(), reduction='none') + loss_mask = ranking_loss(loss_mask, penalize_ratio=0.9, extra_weights=view_weights) + self.log('train/loss_mask', loss_mask, prog_bar=True, rank_zero_only=True) + loss += loss_mask * (self.C(self.config.system.loss.lambda_mask) if self.dataset.has_mask else 0.0) + + loss_opaque = binary_cross_entropy(opacity, opacity) + self.log('train/loss_opaque', loss_opaque) + loss += loss_opaque * self.C(self.config.system.loss.lambda_opaque) + + loss_sparsity = torch.exp(-self.config.system.loss.sparsity_scale * out['random_sdf'].abs()).mean() + self.log('train/loss_sparsity', loss_sparsity, prog_bar=True, rank_zero_only=True) + loss += loss_sparsity * self.C(self.config.system.loss.lambda_sparsity) + + if self.C(self.config.system.loss.lambda_curvature) > 0: + assert 'sdf_laplace_samples' in out, "Need geometry.grad_type='finite_difference' to get SDF Laplace samples" + loss_curvature = out['sdf_laplace_samples'].abs().mean() + self.log('train/loss_curvature', loss_curvature) + loss += loss_curvature * self.C(self.config.system.loss.lambda_curvature) + + # distortion loss proposed in MipNeRF360 + # an efficient implementation from https://github.com/sunset1995/torch_efficient_distloss + if self.C(self.config.system.loss.lambda_distortion) > 0: + loss_distortion = flatten_eff_distloss(out['weights'], out['points'], out['intervals'], out['ray_indices']) + self.log('train/loss_distortion', loss_distortion) + loss += loss_distortion * self.C(self.config.system.loss.lambda_distortion) + + if self.config.model.learned_background and self.C(self.config.system.loss.lambda_distortion_bg) > 0: + loss_distortion_bg = flatten_eff_distloss(out['weights_bg'], out['points_bg'], out['intervals_bg'], out['ray_indices_bg']) + self.log('train/loss_distortion_bg', loss_distortion_bg) + loss += loss_distortion_bg * self.C(self.config.system.loss.lambda_distortion_bg) + + if self.C(self.config.system.loss.lambda_3d_normal_smooth) > 0: + if "random_sdf_grad" not in out: + raise ValueError( + "random_sdf_grad is required for normal smooth loss, no normal is found in the output." + ) + if "normal_perturb" not in out: + raise ValueError( + "normal_perturb is required for normal smooth loss, no normal_perturb is found in the output." + ) + normals_3d = out["random_sdf_grad"] + normals_perturb_3d = out["normal_perturb"] + loss_3d_normal_smooth = (normals_3d - normals_perturb_3d).abs().mean() + self.log('train/loss_3d_normal_smooth', loss_3d_normal_smooth, prog_bar=True ) + + loss += loss_3d_normal_smooth * self.C(self.config.system.loss.lambda_3d_normal_smooth) + + losses_model_reg = self.model.regularizations(out) + for name, value in losses_model_reg.items(): + self.log(f'train/loss_{name}', value) + loss_ = value * self.C(self.config.system.loss[f"lambda_{name}"]) + loss += loss_ + + self.log('train/inv_s', out['inv_s'], prog_bar=True) + + for name, value in self.config.system.loss.items(): + if name.startswith('lambda'): + self.log(f'train_params/{name}', self.C(value)) + + self.log('train/num_rays', float(self.train_num_rays), prog_bar=True) + + return { + 'loss': loss + } + + """ + # aggregate outputs from different devices (DP) + def training_step_end(self, out): + pass + """ + + """ + # aggregate outputs from different iterations + def training_epoch_end(self, out): + pass + """ + + def validation_step(self, batch, batch_idx): + out = self(batch) + psnr = self.criterions['psnr'](out['comp_rgb_full'].to(batch['rgb']), batch['rgb']) + W, H = self.dataset.img_wh + self.save_image_grid(f"it{self.global_step}-{batch['index'][0].item()}.png", [ + {'type': 'rgb', 'img': batch['rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb_full'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}} + ] + ([ + {'type': 'rgb', 'img': out['comp_rgb_bg'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + ] if self.config.model.learned_background else []) + [ + {'type': 'grayscale', 'img': out['depth'].view(H, W), 'kwargs': {}}, + {'type': 'rgb', 'img': out['comp_normal'].view(H, W, 3), 'kwargs': {'data_format': 'HWC', 'data_range': (-1, 1)}} + ]) + return { + 'psnr': psnr, + 'index': batch['index'] + } + + + """ + # aggregate outputs from different devices when using DP + def validation_step_end(self, out): + pass + """ + + def validation_epoch_end(self, out): + out = self.all_gather(out) + if self.trainer.is_global_zero: + out_set = {} + for step_out in out: + # DP + if step_out['index'].ndim == 1: + out_set[step_out['index'].item()] = {'psnr': step_out['psnr']} + # DDP + else: + for oi, index in enumerate(step_out['index']): + out_set[index[0].item()] = {'psnr': step_out['psnr'][oi]} + psnr = torch.mean(torch.stack([o['psnr'] for o in out_set.values()])) + self.log('val/psnr', psnr, prog_bar=True, rank_zero_only=True) + self.export() + + def test_step(self, batch, batch_idx): + out = self(batch) + psnr = self.criterions['psnr'](out['comp_rgb_full'].to(batch['rgb']), batch['rgb']) + W, H = self.dataset.img_wh + self.save_image_grid(f"it{self.global_step}-test/{batch['index'][0].item()}.png", [ + {'type': 'rgb', 'img': batch['rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb_full'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}} + ] + ([ + {'type': 'rgb', 'img': out['comp_rgb_bg'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + {'type': 'rgb', 'img': out['comp_rgb'].view(H, W, 3), 'kwargs': {'data_format': 'HWC'}}, + ] if self.config.model.learned_background else []) + [ + {'type': 'grayscale', 'img': out['depth'].view(H, W), 'kwargs': {}}, + {'type': 'rgb', 'img': out['comp_normal'].view(H, W, 3), 'kwargs': {'data_format': 'HWC', 'data_range': (-1, 1)}} + ]) + return { + 'psnr': psnr, + 'index': batch['index'] + } + + def test_epoch_end(self, out): + """ + Synchronize devices. + Generate image sequence using test outputs. + """ + out = self.all_gather(out) + if self.trainer.is_global_zero: + out_set = {} + for step_out in out: + # DP + if step_out['index'].ndim == 1: + out_set[step_out['index'].item()] = {'psnr': step_out['psnr']} + # DDP + else: + for oi, index in enumerate(step_out['index']): + out_set[index[0].item()] = {'psnr': step_out['psnr'][oi]} + psnr = torch.mean(torch.stack([o['psnr'] for o in out_set.values()])) + self.log('test/psnr', psnr, prog_bar=True, rank_zero_only=True) + + self.save_img_sequence( + f"it{self.global_step}-test", + f"it{self.global_step}-test", + '(\d+)\.png', + save_format='mp4', + fps=30 + ) + + self.export() + + def export(self): + mesh = self.model.export(self.config.export) + self.save_mesh( + f"it{self.global_step}-{self.config.model.geometry.isosurface.method}{self.config.model.geometry.isosurface.resolution}.obj", + ortho_scale=self.config.export.ortho_scale, + **mesh + ) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/systems/utils.py b/apps/third_party/Wonder3D/instant-nsr-pl/systems/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..dafae78295305113fd1854e9104bf44be24f4727 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/systems/utils.py @@ -0,0 +1,351 @@ +import sys +import warnings +from bisect import bisect_right + +import torch +import torch.nn as nn +from torch.optim import lr_scheduler + +from pytorch_lightning.utilities.rank_zero import rank_zero_debug + + +class ChainedScheduler(lr_scheduler._LRScheduler): + """Chains list of learning rate schedulers. It takes a list of chainable learning + rate schedulers and performs consecutive step() functions belong to them by just + one call. + + Args: + schedulers (list): List of chained schedulers. + + Example: + >>> # Assuming optimizer uses lr = 1. for all groups + >>> # lr = 0.09 if epoch == 0 + >>> # lr = 0.081 if epoch == 1 + >>> # lr = 0.729 if epoch == 2 + >>> # lr = 0.6561 if epoch == 3 + >>> # lr = 0.59049 if epoch >= 4 + >>> scheduler1 = ConstantLR(self.opt, factor=0.1, total_iters=2) + >>> scheduler2 = ExponentialLR(self.opt, gamma=0.9) + >>> scheduler = ChainedScheduler([scheduler1, scheduler2]) + >>> for epoch in range(100): + >>> train(...) + >>> validate(...) + >>> scheduler.step() + """ + + def __init__(self, optimizer, schedulers): + for scheduler_idx in range(1, len(schedulers)): + if (schedulers[scheduler_idx].optimizer != schedulers[0].optimizer): + raise ValueError( + "ChainedScheduler expects all schedulers to belong to the same optimizer, but " + "got schedulers at index {} and {} to be different".format(0, scheduler_idx) + ) + self._schedulers = list(schedulers) + self.optimizer = optimizer + + def step(self): + for scheduler in self._schedulers: + scheduler.step() + + def state_dict(self): + """Returns the state of the scheduler as a :class:`dict`. + + It contains an entry for every variable in self.__dict__ which + is not the optimizer. + The wrapped scheduler states will also be saved. + """ + state_dict = {key: value for key, value in self.__dict__.items() if key not in ('optimizer', '_schedulers')} + state_dict['_schedulers'] = [None] * len(self._schedulers) + + for idx, s in enumerate(self._schedulers): + state_dict['_schedulers'][idx] = s.state_dict() + + return state_dict + + def load_state_dict(self, state_dict): + """Loads the schedulers state. + + Args: + state_dict (dict): scheduler state. Should be an object returned + from a call to :meth:`state_dict`. + """ + _schedulers = state_dict.pop('_schedulers') + self.__dict__.update(state_dict) + # Restore state_dict keys in order to prevent side effects + # https://github.com/pytorch/pytorch/issues/32756 + state_dict['_schedulers'] = _schedulers + + for idx, s in enumerate(_schedulers): + self._schedulers[idx].load_state_dict(s) + + +class SequentialLR(lr_scheduler._LRScheduler): + """Receives the list of schedulers that is expected to be called sequentially during + optimization process and milestone points that provides exact intervals to reflect + which scheduler is supposed to be called at a given epoch. + + Args: + schedulers (list): List of chained schedulers. + milestones (list): List of integers that reflects milestone points. + + Example: + >>> # Assuming optimizer uses lr = 1. for all groups + >>> # lr = 0.1 if epoch == 0 + >>> # lr = 0.1 if epoch == 1 + >>> # lr = 0.9 if epoch == 2 + >>> # lr = 0.81 if epoch == 3 + >>> # lr = 0.729 if epoch == 4 + >>> scheduler1 = ConstantLR(self.opt, factor=0.1, total_iters=2) + >>> scheduler2 = ExponentialLR(self.opt, gamma=0.9) + >>> scheduler = SequentialLR(self.opt, schedulers=[scheduler1, scheduler2], milestones=[2]) + >>> for epoch in range(100): + >>> train(...) + >>> validate(...) + >>> scheduler.step() + """ + + def __init__(self, optimizer, schedulers, milestones, last_epoch=-1, verbose=False): + for scheduler_idx in range(1, len(schedulers)): + if (schedulers[scheduler_idx].optimizer != schedulers[0].optimizer): + raise ValueError( + "Sequential Schedulers expects all schedulers to belong to the same optimizer, but " + "got schedulers at index {} and {} to be different".format(0, scheduler_idx) + ) + if (len(milestones) != len(schedulers) - 1): + raise ValueError( + "Sequential Schedulers expects number of schedulers provided to be one more " + "than the number of milestone points, but got number of schedulers {} and the " + "number of milestones to be equal to {}".format(len(schedulers), len(milestones)) + ) + self._schedulers = schedulers + self._milestones = milestones + self.last_epoch = last_epoch + 1 + self.optimizer = optimizer + + def step(self): + self.last_epoch += 1 + idx = bisect_right(self._milestones, self.last_epoch) + if idx > 0 and self._milestones[idx - 1] == self.last_epoch: + self._schedulers[idx].step(0) + else: + self._schedulers[idx].step() + + def state_dict(self): + """Returns the state of the scheduler as a :class:`dict`. + + It contains an entry for every variable in self.__dict__ which + is not the optimizer. + The wrapped scheduler states will also be saved. + """ + state_dict = {key: value for key, value in self.__dict__.items() if key not in ('optimizer', '_schedulers')} + state_dict['_schedulers'] = [None] * len(self._schedulers) + + for idx, s in enumerate(self._schedulers): + state_dict['_schedulers'][idx] = s.state_dict() + + return state_dict + + def load_state_dict(self, state_dict): + """Loads the schedulers state. + + Args: + state_dict (dict): scheduler state. Should be an object returned + from a call to :meth:`state_dict`. + """ + _schedulers = state_dict.pop('_schedulers') + self.__dict__.update(state_dict) + # Restore state_dict keys in order to prevent side effects + # https://github.com/pytorch/pytorch/issues/32756 + state_dict['_schedulers'] = _schedulers + + for idx, s in enumerate(_schedulers): + self._schedulers[idx].load_state_dict(s) + + +class ConstantLR(lr_scheduler._LRScheduler): + """Decays the learning rate of each parameter group by a small constant factor until the + number of epoch reaches a pre-defined milestone: total_iters. Notice that such decay can + happen simultaneously with other changes to the learning rate from outside this scheduler. + When last_epoch=-1, sets initial lr as lr. + + Args: + optimizer (Optimizer): Wrapped optimizer. + factor (float): The number we multiply learning rate until the milestone. Default: 1./3. + total_iters (int): The number of steps that the scheduler decays the learning rate. + Default: 5. + last_epoch (int): The index of the last epoch. Default: -1. + verbose (bool): If ``True``, prints a message to stdout for + each update. Default: ``False``. + + Example: + >>> # Assuming optimizer uses lr = 0.05 for all groups + >>> # lr = 0.025 if epoch == 0 + >>> # lr = 0.025 if epoch == 1 + >>> # lr = 0.025 if epoch == 2 + >>> # lr = 0.025 if epoch == 3 + >>> # lr = 0.05 if epoch >= 4 + >>> scheduler = ConstantLR(self.opt, factor=0.5, total_iters=4) + >>> for epoch in range(100): + >>> train(...) + >>> validate(...) + >>> scheduler.step() + """ + + def __init__(self, optimizer, factor=1.0 / 3, total_iters=5, last_epoch=-1, verbose=False): + if factor > 1.0 or factor < 0: + raise ValueError('Constant multiplicative factor expected to be between 0 and 1.') + + self.factor = factor + self.total_iters = total_iters + super(ConstantLR, self).__init__(optimizer, last_epoch, verbose) + + def get_lr(self): + if not self._get_lr_called_within_step: + warnings.warn("To get the last learning rate computed by the scheduler, " + "please use `get_last_lr()`.", UserWarning) + + if self.last_epoch == 0: + return [group['lr'] * self.factor for group in self.optimizer.param_groups] + + if (self.last_epoch > self.total_iters or + (self.last_epoch != self.total_iters)): + return [group['lr'] for group in self.optimizer.param_groups] + + if (self.last_epoch == self.total_iters): + return [group['lr'] * (1.0 / self.factor) for group in self.optimizer.param_groups] + + def _get_closed_form_lr(self): + return [base_lr * (self.factor + (self.last_epoch >= self.total_iters) * (1 - self.factor)) + for base_lr in self.base_lrs] + + +class LinearLR(lr_scheduler._LRScheduler): + """Decays the learning rate of each parameter group by linearly changing small + multiplicative factor until the number of epoch reaches a pre-defined milestone: total_iters. + Notice that such decay can happen simultaneously with other changes to the learning rate + from outside this scheduler. When last_epoch=-1, sets initial lr as lr. + + Args: + optimizer (Optimizer): Wrapped optimizer. + start_factor (float): The number we multiply learning rate in the first epoch. + The multiplication factor changes towards end_factor in the following epochs. + Default: 1./3. + end_factor (float): The number we multiply learning rate at the end of linear changing + process. Default: 1.0. + total_iters (int): The number of iterations that multiplicative factor reaches to 1. + Default: 5. + last_epoch (int): The index of the last epoch. Default: -1. + verbose (bool): If ``True``, prints a message to stdout for + each update. Default: ``False``. + + Example: + >>> # Assuming optimizer uses lr = 0.05 for all groups + >>> # lr = 0.025 if epoch == 0 + >>> # lr = 0.03125 if epoch == 1 + >>> # lr = 0.0375 if epoch == 2 + >>> # lr = 0.04375 if epoch == 3 + >>> # lr = 0.05 if epoch >= 4 + >>> scheduler = LinearLR(self.opt, start_factor=0.5, total_iters=4) + >>> for epoch in range(100): + >>> train(...) + >>> validate(...) + >>> scheduler.step() + """ + + def __init__(self, optimizer, start_factor=1.0 / 3, end_factor=1.0, total_iters=5, last_epoch=-1, + verbose=False): + if start_factor > 1.0 or start_factor < 0: + raise ValueError('Starting multiplicative factor expected to be between 0 and 1.') + + if end_factor > 1.0 or end_factor < 0: + raise ValueError('Ending multiplicative factor expected to be between 0 and 1.') + + self.start_factor = start_factor + self.end_factor = end_factor + self.total_iters = total_iters + super(LinearLR, self).__init__(optimizer, last_epoch, verbose) + + def get_lr(self): + if not self._get_lr_called_within_step: + warnings.warn("To get the last learning rate computed by the scheduler, " + "please use `get_last_lr()`.", UserWarning) + + if self.last_epoch == 0: + return [group['lr'] * self.start_factor for group in self.optimizer.param_groups] + + if (self.last_epoch > self.total_iters): + return [group['lr'] for group in self.optimizer.param_groups] + + return [group['lr'] * (1. + (self.end_factor - self.start_factor) / + (self.total_iters * self.start_factor + (self.last_epoch - 1) * (self.end_factor - self.start_factor))) + for group in self.optimizer.param_groups] + + def _get_closed_form_lr(self): + return [base_lr * (self.start_factor + + (self.end_factor - self.start_factor) * min(self.total_iters, self.last_epoch) / self.total_iters) + for base_lr in self.base_lrs] + + +custom_schedulers = ['ConstantLR', 'LinearLR'] +def get_scheduler(name): + if hasattr(lr_scheduler, name): + return getattr(lr_scheduler, name) + elif name in custom_schedulers: + return getattr(sys.modules[__name__], name) + else: + raise NotImplementedError + + +def getattr_recursive(m, attr): + for name in attr.split('.'): + m = getattr(m, name) + return m + + +def get_parameters(model, name): + module = getattr_recursive(model, name) + if isinstance(module, nn.Module): + return module.parameters() + elif isinstance(module, nn.Parameter): + return module + return [] + + +def parse_optimizer(config, model): + if hasattr(config, 'params'): + params = [{'params': get_parameters(model, name), 'name': name, **args} for name, args in config.params.items()] + rank_zero_debug('Specify optimizer params:', config.params) + else: + params = model.parameters() + if config.name in ['FusedAdam']: + import apex + optim = getattr(apex.optimizers, config.name)(params, **config.args) + else: + optim = getattr(torch.optim, config.name)(params, **config.args) + return optim + + +def parse_scheduler(config, optimizer): + interval = config.get('interval', 'epoch') + assert interval in ['epoch', 'step'] + if config.name == 'SequentialLR': + scheduler = { + 'scheduler': SequentialLR(optimizer, [parse_scheduler(conf, optimizer)['scheduler'] for conf in config.schedulers], milestones=config.milestones), + 'interval': interval + } + elif config.name == 'Chained': + scheduler = { + 'scheduler': ChainedScheduler([parse_scheduler(conf, optimizer)['scheduler'] for conf in config.schedulers]), + 'interval': interval + } + else: + scheduler = { + 'scheduler': get_scheduler(config.name)(optimizer, **config.args), + 'interval': interval + } + return scheduler + + +def update_module_step(m, epoch, global_step): + if hasattr(m, 'update_step'): + m.update_step(epoch, global_step) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/utils/__init__.py b/apps/third_party/Wonder3D/instant-nsr-pl/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/utils/callbacks.py b/apps/third_party/Wonder3D/instant-nsr-pl/utils/callbacks.py new file mode 100644 index 0000000000000000000000000000000000000000..22f39efdb2f381ff677f5311c0586fbad88ae34f --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/utils/callbacks.py @@ -0,0 +1,99 @@ +import os +import subprocess +import shutil +from utils.misc import dump_config, parse_version + + +import pytorch_lightning +if parse_version(pytorch_lightning.__version__) > parse_version('1.8'): + from pytorch_lightning.callbacks import Callback +else: + from pytorch_lightning.callbacks.base import Callback +from pytorch_lightning.utilities.rank_zero import rank_zero_only, rank_zero_warn +from pytorch_lightning.callbacks.progress import TQDMProgressBar + + +class VersionedCallback(Callback): + def __init__(self, save_root, version=None, use_version=True): + self.save_root = save_root + self._version = version + self.use_version = use_version + + @property + def version(self) -> int: + """Get the experiment version. + + Returns: + The experiment version if specified else the next version. + """ + if self._version is None: + self._version = self._get_next_version() + return self._version + + def _get_next_version(self): + existing_versions = [] + if os.path.isdir(self.save_root): + for f in os.listdir(self.save_root): + bn = os.path.basename(f) + if bn.startswith("version_"): + dir_ver = os.path.splitext(bn)[0].split("_")[1].replace("/", "") + existing_versions.append(int(dir_ver)) + if len(existing_versions) == 0: + return 0 + return max(existing_versions) + 1 + + @property + def savedir(self): + if not self.use_version: + return self.save_root + return os.path.join(self.save_root, self.version if isinstance(self.version, str) else f"version_{self.version}") + + +class CodeSnapshotCallback(VersionedCallback): + def __init__(self, save_root, version=None, use_version=True): + super().__init__(save_root, version, use_version) + + def get_file_list(self): + return [ + b.decode() for b in + set(subprocess.check_output('git ls-files', shell=True).splitlines()) | + set(subprocess.check_output('git ls-files --others --exclude-standard', shell=True).splitlines()) + ] + + @rank_zero_only + def save_code_snapshot(self): + os.makedirs(self.savedir, exist_ok=True) + for f in self.get_file_list(): + if not os.path.exists(f) or os.path.isdir(f): + continue + os.makedirs(os.path.join(self.savedir, os.path.dirname(f)), exist_ok=True) + shutil.copyfile(f, os.path.join(self.savedir, f)) + + def on_fit_start(self, trainer, pl_module): + try: + self.save_code_snapshot() + except: + rank_zero_warn("Code snapshot is not saved. Please make sure you have git installed and are in a git repository.") + + +class ConfigSnapshotCallback(VersionedCallback): + def __init__(self, config, save_root, version=None, use_version=True): + super().__init__(save_root, version, use_version) + self.config = config + + @rank_zero_only + def save_config_snapshot(self): + os.makedirs(self.savedir, exist_ok=True) + dump_config(os.path.join(self.savedir, 'parsed.yaml'), self.config) + shutil.copyfile(self.config.cmd_args['config'], os.path.join(self.savedir, 'raw.yaml')) + + def on_fit_start(self, trainer, pl_module): + self.save_config_snapshot() + + +class CustomProgressBar(TQDMProgressBar): + def get_metrics(self, *args, **kwargs): + # don't show the version number + items = super().get_metrics(*args, **kwargs) + items.pop("v_num", None) + return items diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/utils/loggers.py b/apps/third_party/Wonder3D/instant-nsr-pl/utils/loggers.py new file mode 100644 index 0000000000000000000000000000000000000000..2d1a92302a431a75e0c920327208ab11e9559ec8 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/utils/loggers.py @@ -0,0 +1,41 @@ +import re +import pprint +import logging + +from pytorch_lightning.loggers.base import LightningLoggerBase, rank_zero_experiment +from pytorch_lightning.utilities.rank_zero import rank_zero_only + + +class ConsoleLogger(LightningLoggerBase): + def __init__(self, log_keys=[]): + super().__init__() + self.log_keys = [re.compile(k) for k in log_keys] + self.dict_printer = pprint.PrettyPrinter(indent=2, compact=False).pformat + + def match_log_keys(self, s): + return True if not self.log_keys else any(r.search(s) for r in self.log_keys) + + @property + def name(self): + return 'console' + + @property + def version(self): + return '0' + + @property + @rank_zero_experiment + def experiment(self): + return logging.getLogger('pytorch_lightning') + + @rank_zero_only + def log_hyperparams(self, params): + pass + + @rank_zero_only + def log_metrics(self, metrics, step): + metrics_ = {k: v for k, v in metrics.items() if self.match_log_keys(k)} + if not metrics_: + return + self.experiment.info(f"\nEpoch{metrics['epoch']} Step{step}\n{self.dict_printer(metrics_)}") + diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/utils/misc.py b/apps/third_party/Wonder3D/instant-nsr-pl/utils/misc.py new file mode 100644 index 0000000000000000000000000000000000000000..c16fafa2ab8e7b934be711c41aed6e12001444fd --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/utils/misc.py @@ -0,0 +1,54 @@ +import os +from omegaconf import OmegaConf +from packaging import version + + +# ============ Register OmegaConf Recolvers ============= # +OmegaConf.register_new_resolver('calc_exp_lr_decay_rate', lambda factor, n: factor**(1./n)) +OmegaConf.register_new_resolver('add', lambda a, b: a + b) +OmegaConf.register_new_resolver('sub', lambda a, b: a - b) +OmegaConf.register_new_resolver('mul', lambda a, b: a * b) +OmegaConf.register_new_resolver('div', lambda a, b: a / b) +OmegaConf.register_new_resolver('idiv', lambda a, b: a // b) +OmegaConf.register_new_resolver('basename', lambda p: os.path.basename(p)) +# ======================================================= # + + +def prompt(question): + inp = input(f"{question} (y/n)").lower().strip() + if inp and inp == 'y': + return True + if inp and inp == 'n': + return False + return prompt(question) + + +def load_config(*yaml_files, cli_args=[]): + yaml_confs = [OmegaConf.load(f) for f in yaml_files] + cli_conf = OmegaConf.from_cli(cli_args) + conf = OmegaConf.merge(*yaml_confs, cli_conf) + OmegaConf.resolve(conf) + return conf + + +def config_to_primitive(config, resolve=True): + return OmegaConf.to_container(config, resolve=resolve) + + +def dump_config(path, config): + with open(path, 'w') as fp: + OmegaConf.save(config=config, f=fp) + +def get_rank(): + # SLURM_PROCID can be set even if SLURM is not managing the multiprocessing, + # therefore LOCAL_RANK needs to be checked first + rank_keys = ("RANK", "LOCAL_RANK", "SLURM_PROCID", "JSM_NAMESPACE_RANK") + for key in rank_keys: + rank = os.environ.get(key) + if rank is not None: + return int(rank) + return 0 + + +def parse_version(ver): + return version.parse(ver) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/utils/mixins.py b/apps/third_party/Wonder3D/instant-nsr-pl/utils/mixins.py new file mode 100644 index 0000000000000000000000000000000000000000..b556cebc2cad678f89cb6aeb1c08bd6f2b2df920 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/utils/mixins.py @@ -0,0 +1,264 @@ +import os +import re +import shutil +import numpy as np +import cv2 +import imageio +from matplotlib import cm +from matplotlib.colors import LinearSegmentedColormap +import json + +import torch + +from utils.obj import write_obj + + +class SaverMixin(): + @property + def save_dir(self): + return self.config.save_dir + + def convert_data(self, data): + if isinstance(data, np.ndarray): + return data + elif isinstance(data, torch.Tensor): + return data.cpu().numpy() + elif isinstance(data, list): + return [self.convert_data(d) for d in data] + elif isinstance(data, dict): + return {k: self.convert_data(v) for k, v in data.items()} + else: + raise TypeError('Data must be in type numpy.ndarray, torch.Tensor, list or dict, getting', type(data)) + + def get_save_path(self, filename): + save_path = os.path.join(self.save_dir, filename) + os.makedirs(os.path.dirname(save_path), exist_ok=True) + return save_path + + DEFAULT_RGB_KWARGS = {'data_format': 'CHW', 'data_range': (0, 1)} + DEFAULT_UV_KWARGS = {'data_format': 'CHW', 'data_range': (0, 1), 'cmap': 'checkerboard'} + DEFAULT_GRAYSCALE_KWARGS = {'data_range': None, 'cmap': 'jet'} + + def get_rgb_image_(self, img, data_format, data_range): + img = self.convert_data(img) + assert data_format in ['CHW', 'HWC'] + if data_format == 'CHW': + img = img.transpose(1, 2, 0) + img = img.clip(min=data_range[0], max=data_range[1]) + img = ((img - data_range[0]) / (data_range[1] - data_range[0]) * 255.).astype(np.uint8) + imgs = [img[...,start:start+3] for start in range(0, img.shape[-1], 3)] + imgs = [img_ if img_.shape[-1] == 3 else np.concatenate([img_, np.zeros((img_.shape[0], img_.shape[1], 3 - img_.shape[2]), dtype=img_.dtype)], axis=-1) for img_ in imgs] + img = np.concatenate(imgs, axis=1) + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + return img + + def save_rgb_image(self, filename, img, data_format=DEFAULT_RGB_KWARGS['data_format'], data_range=DEFAULT_RGB_KWARGS['data_range']): + img = self.get_rgb_image_(img, data_format, data_range) + cv2.imwrite(self.get_save_path(filename), img) + + def get_uv_image_(self, img, data_format, data_range, cmap): + img = self.convert_data(img) + assert data_format in ['CHW', 'HWC'] + if data_format == 'CHW': + img = img.transpose(1, 2, 0) + img = img.clip(min=data_range[0], max=data_range[1]) + img = (img - data_range[0]) / (data_range[1] - data_range[0]) + assert cmap in ['checkerboard', 'color'] + if cmap == 'checkerboard': + n_grid = 64 + mask = (img * n_grid).astype(int) + mask = (mask[...,0] + mask[...,1]) % 2 == 0 + img = np.ones((img.shape[0], img.shape[1], 3), dtype=np.uint8) * 255 + img[mask] = np.array([255, 0, 255], dtype=np.uint8) + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + elif cmap == 'color': + img_ = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8) + img_[..., 0] = (img[..., 0] * 255).astype(np.uint8) + img_[..., 1] = (img[..., 1] * 255).astype(np.uint8) + img_ = cv2.cvtColor(img_, cv2.COLOR_RGB2BGR) + img = img_ + return img + + def save_uv_image(self, filename, img, data_format=DEFAULT_UV_KWARGS['data_format'], data_range=DEFAULT_UV_KWARGS['data_range'], cmap=DEFAULT_UV_KWARGS['cmap']): + img = self.get_uv_image_(img, data_format, data_range, cmap) + cv2.imwrite(self.get_save_path(filename), img) + + def get_grayscale_image_(self, img, data_range, cmap): + img = self.convert_data(img) + img = np.nan_to_num(img) + if data_range is None: + img = (img - img.min()) / (img.max() - img.min()) + else: + img = img.clip(data_range[0], data_range[1]) + img = (img - data_range[0]) / (data_range[1] - data_range[0]) + assert cmap in [None, 'jet', 'magma'] + if cmap == None: + img = (img * 255.).astype(np.uint8) + img = np.repeat(img[...,None], 3, axis=2) + elif cmap == 'jet': + img = (img * 255.).astype(np.uint8) + img = cv2.applyColorMap(img, cv2.COLORMAP_JET) + elif cmap == 'magma': + img = 1. - img + base = cm.get_cmap('magma') + num_bins = 256 + colormap = LinearSegmentedColormap.from_list( + f"{base.name}{num_bins}", + base(np.linspace(0, 1, num_bins)), + num_bins + )(np.linspace(0, 1, num_bins))[:,:3] + a = np.floor(img * 255.) + b = (a + 1).clip(max=255.) + f = img * 255. - a + a = a.astype(np.uint16).clip(0, 255) + b = b.astype(np.uint16).clip(0, 255) + img = colormap[a] + (colormap[b] - colormap[a]) * f[...,None] + img = (img * 255.).astype(np.uint8) + return img + + def save_grayscale_image(self, filename, img, data_range=DEFAULT_GRAYSCALE_KWARGS['data_range'], cmap=DEFAULT_GRAYSCALE_KWARGS['cmap']): + img = self.get_grayscale_image_(img, data_range, cmap) + cv2.imwrite(self.get_save_path(filename), img) + + def get_image_grid_(self, imgs): + if isinstance(imgs[0], list): + return np.concatenate([self.get_image_grid_(row) for row in imgs], axis=0) + cols = [] + for col in imgs: + assert col['type'] in ['rgb', 'uv', 'grayscale'] + if col['type'] == 'rgb': + rgb_kwargs = self.DEFAULT_RGB_KWARGS.copy() + rgb_kwargs.update(col['kwargs']) + cols.append(self.get_rgb_image_(col['img'], **rgb_kwargs)) + elif col['type'] == 'uv': + uv_kwargs = self.DEFAULT_UV_KWARGS.copy() + uv_kwargs.update(col['kwargs']) + cols.append(self.get_uv_image_(col['img'], **uv_kwargs)) + elif col['type'] == 'grayscale': + grayscale_kwargs = self.DEFAULT_GRAYSCALE_KWARGS.copy() + grayscale_kwargs.update(col['kwargs']) + cols.append(self.get_grayscale_image_(col['img'], **grayscale_kwargs)) + return np.concatenate(cols, axis=1) + + def save_image_grid(self, filename, imgs): + img = self.get_image_grid_(imgs) + cv2.imwrite(self.get_save_path(filename), img) + + def save_image(self, filename, img): + img = self.convert_data(img) + assert img.dtype == np.uint8 + if img.shape[-1] == 3: + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + elif img.shape[-1] == 4: + img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA) + cv2.imwrite(self.get_save_path(filename), img) + + def save_cubemap(self, filename, img, data_range=(0, 1)): + img = self.convert_data(img) + assert img.ndim == 4 and img.shape[0] == 6 and img.shape[1] == img.shape[2] + + imgs_full = [] + for start in range(0, img.shape[-1], 3): + img_ = img[...,start:start+3] + img_ = np.stack([self.get_rgb_image_(img_[i], 'HWC', data_range) for i in range(img_.shape[0])], axis=0) + size = img_.shape[1] + placeholder = np.zeros((size, size, 3), dtype=np.float32) + img_full = np.concatenate([ + np.concatenate([placeholder, img_[2], placeholder, placeholder], axis=1), + np.concatenate([img_[1], img_[4], img_[0], img_[5]], axis=1), + np.concatenate([placeholder, img_[3], placeholder, placeholder], axis=1) + ], axis=0) + img_full = cv2.cvtColor(img_full, cv2.COLOR_RGB2BGR) + imgs_full.append(img_full) + + imgs_full = np.concatenate(imgs_full, axis=1) + cv2.imwrite(self.get_save_path(filename), imgs_full) + + def save_data(self, filename, data): + data = self.convert_data(data) + if isinstance(data, dict): + if not filename.endswith('.npz'): + filename += '.npz' + np.savez(self.get_save_path(filename), **data) + else: + if not filename.endswith('.npy'): + filename += '.npy' + np.save(self.get_save_path(filename), data) + + def save_state_dict(self, filename, data): + torch.save(data, self.get_save_path(filename)) + + def save_img_sequence(self, filename, img_dir, matcher, save_format='gif', fps=30): + assert save_format in ['gif', 'mp4'] + if not filename.endswith(save_format): + filename += f".{save_format}" + matcher = re.compile(matcher) + img_dir = os.path.join(self.save_dir, img_dir) + imgs = [] + for f in os.listdir(img_dir): + if matcher.search(f): + imgs.append(f) + imgs = sorted(imgs, key=lambda f: int(matcher.search(f).groups()[0])) + imgs = [cv2.imread(os.path.join(img_dir, f)) for f in imgs] + + if save_format == 'gif': + imgs = [cv2.cvtColor(i, cv2.COLOR_BGR2RGB) for i in imgs] + imageio.mimsave(self.get_save_path(filename), imgs, fps=fps, palettesize=256) + elif save_format == 'mp4': + imgs = [cv2.cvtColor(i, cv2.COLOR_BGR2RGB) for i in imgs] + imageio.mimsave(self.get_save_path(filename), imgs, fps=fps) + + def save_mesh(self, filename, v_pos, t_pos_idx, v_tex=None, t_tex_idx=None, v_rgb=None, ortho_scale=1): + v_pos, t_pos_idx = self.convert_data(v_pos), self.convert_data(t_pos_idx) + if v_rgb is not None: + v_rgb = self.convert_data(v_rgb) + + if ortho_scale is not None: + print("ortho scale is: ", ortho_scale) + v_pos = v_pos * ortho_scale * 0.5 + + # change to front-facing + v_pos_copy = np.zeros_like(v_pos) + v_pos_copy[:, 0] = v_pos[:, 0] + v_pos_copy[:, 1] = v_pos[:, 2] + v_pos_copy[:, 2] = v_pos[:, 1] + + import trimesh + mesh = trimesh.Trimesh( + vertices=v_pos_copy, + faces=t_pos_idx, + vertex_colors=v_rgb + ) + trimesh.repair.fix_inversion(mesh) + mesh.export(self.get_save_path(filename)) + # mesh.export(self.get_save_path(filename.replace(".obj", "-meshlab.obj"))) + + # v_pos_copy[:, 0] = v_pos[:, 1] * -1 + # v_pos_copy[:, 1] = v_pos[:, 0] + # v_pos_copy[:, 2] = v_pos[:, 2] + + # mesh = trimesh.Trimesh( + # vertices=v_pos_copy, + # faces=t_pos_idx, + # vertex_colors=v_rgb + # ) + # mesh.export(self.get_save_path(filename.replace(".obj", "-blender.obj"))) + + + # v_pos_copy[:, 0] = v_pos[:, 0] + # v_pos_copy[:, 1] = v_pos[:, 1] * -1 + # v_pos_copy[:, 2] = v_pos[:, 2] * -1 + + # mesh = trimesh.Trimesh( + # vertices=v_pos_copy, + # faces=t_pos_idx, + # vertex_colors=v_rgb + # ) + # mesh.export(self.get_save_path(filename.replace(".obj", "-opengl.obj"))) + + def save_file(self, filename, src_path): + shutil.copyfile(src_path, self.get_save_path(filename)) + + def save_json(self, filename, payload): + with open(self.get_save_path(filename), 'w') as f: + f.write(json.dumps(payload)) diff --git a/apps/third_party/Wonder3D/instant-nsr-pl/utils/obj.py b/apps/third_party/Wonder3D/instant-nsr-pl/utils/obj.py new file mode 100644 index 0000000000000000000000000000000000000000..da6d11938c244a6b982ec8c3f36a90a7a5fd2831 --- /dev/null +++ b/apps/third_party/Wonder3D/instant-nsr-pl/utils/obj.py @@ -0,0 +1,74 @@ +import numpy as np + + +def load_obj(filename): + # Read entire file + with open(filename, 'r') as f: + lines = f.readlines() + + # load vertices + vertices, texcoords = [], [] + for line in lines: + if len(line.split()) == 0: + continue + + prefix = line.split()[0].lower() + if prefix == 'v': + vertices.append([float(v) for v in line.split()[1:]]) + elif prefix == 'vt': + val = [float(v) for v in line.split()[1:]] + texcoords.append([val[0], 1.0 - val[1]]) + + uv = len(texcoords) > 0 + faces, tfaces = [], [] + for line in lines: + if len(line.split()) == 0: + continue + prefix = line.split()[0].lower() + if prefix == 'usemtl': # Track used materials + pass + elif prefix == 'f': # Parse face + vs = line.split()[1:] + nv = len(vs) + vv = vs[0].split('/') + v0 = int(vv[0]) - 1 + if uv: + t0 = int(vv[1]) - 1 if vv[1] != "" else -1 + for i in range(nv - 2): # Triangulate polygons + vv1 = vs[i + 1].split('/') + v1 = int(vv1[0]) - 1 + vv2 = vs[i + 2].split('/') + v2 = int(vv2[0]) - 1 + faces.append([v0, v1, v2]) + if uv: + t1 = int(vv1[1]) - 1 if vv1[1] != "" else -1 + t2 = int(vv2[1]) - 1 if vv2[1] != "" else -1 + tfaces.append([t0, t1, t2]) + vertices = np.array(vertices, dtype=np.float32) + faces = np.array(faces, dtype=np.int64) + if uv: + assert len(tfaces) == len(faces) + texcoords = np.array(texcoords, dtype=np.float32) + tfaces = np.array(tfaces, dtype=np.int64) + else: + texcoords, tfaces = None, None + + return vertices, faces, texcoords, tfaces + + +def write_obj(filename, v_pos, t_pos_idx, v_tex, t_tex_idx): + with open(filename, "w") as f: + for v in v_pos: + f.write('v {} {} {} \n'.format(v[0], v[1], v[2])) + + if v_tex is not None: + assert(len(t_pos_idx) == len(t_tex_idx)) + for v in v_tex: + f.write('vt {} {} \n'.format(v[0], 1.0 - v[1])) + + # Write faces + for i in range(len(t_pos_idx)): + f.write("f ") + for j in range(3): + f.write(' %s/%s' % (str(t_pos_idx[i][j]+1), '' if v_tex is None else str(t_tex_idx[i][j]+1))) + f.write("\n") diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ef2610bdbde3f9c9db89c05fc5606362adc7d0c --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_RT.txt @@ -0,0 +1,3 @@ +-5.266582965850830078e-01 7.410295009613037109e-01 -4.165407419204711914e-01 -5.960464477539062500e-08 +5.865638996738198330e-08 4.900035560131072998e-01 8.717204332351684570e-01 -9.462351613365171943e-08 +8.500770330429077148e-01 4.590988159179687500e-01 -2.580644786357879639e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_left_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..7db25bbbec8a0d5a26724aa65681603e5bee6744 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_left_RT.txt @@ -0,0 +1,3 @@ +-9.734988808631896973e-01 1.993551850318908691e-01 -1.120596975088119507e-01 -1.713633537292480469e-07 +3.790224578636980368e-09 4.900034964084625244e-01 8.717204928398132324e-01 1.772203575001185527e-07 +2.286916375160217285e-01 8.486189246177673340e-01 -4.770178496837615967e-01 -1.838477611541748047e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_right_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..be45ed8f30f6625421524d141aa1c325dc2fdb8b --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_back_right_RT.txt @@ -0,0 +1,3 @@ +2.286914736032485962e-01 8.486190438270568848e-01 -4.770178198814392090e-01 1.564621925354003906e-07 +-3.417914484771245043e-08 4.900034070014953613e-01 8.717205524444580078e-01 -7.293811421504869941e-08 +9.734990000724792480e-01 -1.993550658226013184e-01 1.120596155524253845e-01 -1.838477969169616699e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..8278639ec5ec9d0f1e4c88d54295a0cd4acee593 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_RT.txt @@ -0,0 +1,3 @@ +5.266583561897277832e-01 -7.410295009613037109e-01 4.165407419204711914e-01 0.000000000000000000e+00 +5.865638996738198330e-08 4.900035560131072998e-01 8.717204332351684570e-01 9.462351613365171943e-08 +-8.500770330429077148e-01 -4.590988159179687500e-01 2.580645382404327393e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_left_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..6255b9f84ccb1bf3527897ef648811ff171aa025 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_left_RT.txt @@ -0,0 +1,3 @@ +-2.286916971206665039e-01 -8.486189842224121094e-01 4.770179092884063721e-01 -2.458691596984863281e-07 +9.085837859856837895e-09 4.900034666061401367e-01 8.717205524444580078e-01 1.205695667749751010e-07 +-9.734990000724792480e-01 1.993551701307296753e-01 -1.120597645640373230e-01 -1.838477969169616699e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_right_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1d76c85c1a05de1d6bf3dd70ed02721a40f73c2 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_front_right_RT.txt @@ -0,0 +1,3 @@ +9.734989404678344727e-01 -1.993551850318908691e-01 1.120596975088119507e-01 -1.415610313415527344e-07 +3.790224578636980368e-09 4.900034964084625244e-01 8.717204928398132324e-01 -1.772203575001185527e-07 +-2.286916375160217285e-01 -8.486189246177673340e-01 4.770178794860839844e-01 -1.838477611541748047e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_left_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_left_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd42197eaae14526b00cb4676528a2465cbaf1dd --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_left_RT.txt @@ -0,0 +1,3 @@ +-8.500771522521972656e-01 -4.590989053249359131e-01 2.580644488334655762e-01 0.000000000000000000e+00 +-4.257411134744870651e-08 4.900034964084625244e-01 8.717204928398132324e-01 9.006067358541258727e-08 +-5.266583561897277832e-01 7.410295605659484863e-01 -4.165408313274383545e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_right_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_right_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d37c0219db99aeeede6b48815b932058538adc6 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_right_RT.txt @@ -0,0 +1,3 @@ +8.500770330429077148e-01 4.590989053249359131e-01 -2.580644488334655762e-01 5.960464477539062500e-08 +-4.257411134744870651e-08 4.900034964084625244e-01 8.717204928398132324e-01 -9.006067358541258727e-08 +5.266583561897277832e-01 -7.410295605659484863e-01 4.165407419204711914e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_top_RT.txt b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_top_RT.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d71f22664b502cd5e1039f4621bec6ef41b1231 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views/000_top_RT.txt @@ -0,0 +1,3 @@ +9.958608150482177734e-01 7.923202216625213623e-02 -4.453715682029724121e-02 -3.098167056236889039e-09 +-9.089154005050659180e-02 8.681122064590454102e-01 -4.879753291606903076e-01 5.784738377201392723e-08 +-2.028124157504862524e-08 4.900035560131072998e-01 8.717204332351684570e-01 -1.300000071525573730e+00 diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/normal_utils.py b/apps/third_party/Wonder3D/mvdiffusion/data/normal_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..dff3730a312e96a2ed82dfd5a337d263baa0f2d8 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/normal_utils.py @@ -0,0 +1,45 @@ +import numpy as np + +def camNormal2worldNormal(rot_c2w, camNormal): + H,W,_ = camNormal.shape + normal_img = np.matmul(rot_c2w[None, :, :], camNormal.reshape(-1,3)[:, :, None]).reshape([H, W, 3]) + + return normal_img + +def worldNormal2camNormal(rot_w2c, normal_map_world): + H,W,_ = normal_map_world.shape + # normal_img = np.matmul(rot_w2c[None, :, :], worldNormal.reshape(-1,3)[:, :, None]).reshape([H, W, 3]) + + # faster version + # Reshape the normal map into a 2D array where each row represents a normal vector + normal_map_flat = normal_map_world.reshape(-1, 3) + + # Transform the normal vectors using the transformation matrix + normal_map_camera_flat = np.dot(normal_map_flat, rot_w2c.T) + + # Reshape the transformed normal map back to its original shape + normal_map_camera = normal_map_camera_flat.reshape(normal_map_world.shape) + + return normal_map_camera + +def trans_normal(normal, RT_w2c, RT_w2c_target): + + # normal_world = camNormal2worldNormal(np.linalg.inv(RT_w2c[:3,:3]), normal) + # normal_target_cam = worldNormal2camNormal(RT_w2c_target[:3,:3], normal_world) + + relative_RT = np.matmul(RT_w2c_target[:3,:3], np.linalg.inv(RT_w2c[:3,:3])) + normal_target_cam = worldNormal2camNormal(relative_RT[:3,:3], normal) + + return normal_target_cam + +def img2normal(img): + return (img/255.)*2-1 + +def normal2img(normal): + return np.uint8((normal*0.5+0.5)*255) + +def norm_normalize(normal, dim=-1): + + normal = normal/(np.linalg.norm(normal, axis=dim, keepdims=True)+1e-6) + + return normal \ No newline at end of file diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/objaverse_dataset.py b/apps/third_party/Wonder3D/mvdiffusion/data/objaverse_dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..650c50f20cde19e915b1bbdd4a9835524f4b9973 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/objaverse_dataset.py @@ -0,0 +1,513 @@ +from typing import Dict +import numpy as np +from omegaconf import DictConfig, ListConfig +import torch +from torch.utils.data import Dataset +from pathlib import Path +import json +from PIL import Image +from torchvision import transforms +from einops import rearrange +from typing import Literal, Tuple, Optional, Any +import cv2 +import random + +import json +import os, sys +import math + +import PIL.Image +from .normal_utils import trans_normal, normal2img, img2normal +import pdb + + +class ObjaverseDataset(Dataset): + def __init__(self, + root_dir: str, + num_views: int, + bg_color: Any, + img_wh: Tuple[int, int], + object_list: str, + groups_num: int=1, + validation: bool = False, + data_view_num: int = 6, + num_validation_samples: int = 64, + num_samples: Optional[int] = None, + invalid_list: Optional[str] = None, + trans_norm_system: bool = True, # if True, transform all normals map into the cam system of front view + augment_data: bool = False, + read_normal: bool = True, + read_color: bool = False, + read_depth: bool = False, + read_mask: bool = True, + mix_color_normal: bool = False, + suffix: str = 'png', + subscene_tag: int = 3, + backup_scene: str = "9438abf986c7453a9f4df7c34aa2e65b" + ) -> None: + """Create a dataset from a folder of images. + If you pass in a root directory it will be searched for images + ending in ext (ext can be a list) + """ + self.root_dir = Path(root_dir) + self.num_views = num_views + self.bg_color = bg_color + self.validation = validation + self.num_samples = num_samples + self.trans_norm_system = trans_norm_system + self.augment_data = augment_data + self.invalid_list = invalid_list + self.groups_num = groups_num + print("augment data: ", self.augment_data) + self.img_wh = img_wh + self.read_normal = read_normal + self.read_color = read_color + self.read_depth = read_depth + self.read_mask = read_mask + self.mix_color_normal = mix_color_normal # mix load color and normal maps + self.suffix = suffix + self.subscene_tag = subscene_tag + + self.view_types = ['front', 'front_right', 'right', 'back', 'left', 'front_left'] + self.fix_cam_pose_dir = "./mvdiffusion/data/fixed_poses/nine_views" + + self.fix_cam_poses = self.load_fixed_poses() # world2cam matrix + + if object_list is not None: + with open(object_list) as f: + self.objects = json.load(f) + self.objects = [os.path.basename(o).replace(".glb", "") for o in self.objects] + else: + self.objects = os.listdir(self.root_dir) + self.objects = sorted(self.objects) + + if self.invalid_list is not None: + with open(self.invalid_list) as f: + self.invalid_objects = json.load(f) + self.invalid_objects = [os.path.basename(o).replace(".glb", "") for o in self.invalid_objects] + else: + self.invalid_objects = [] + + + self.all_objects = set(self.objects) - (set(self.invalid_objects) & set(self.objects)) + self.all_objects = list(self.all_objects) + + if not validation: + self.all_objects = self.all_objects[:-num_validation_samples] + else: + self.all_objects = self.all_objects[-num_validation_samples:] + if num_samples is not None: + self.all_objects = self.all_objects[:num_samples] + + print("loading ", len(self.all_objects), " objects in the dataset") + + if self.mix_color_normal: + self.backup_data = self.__getitem_mix__(0, backup_scene) + else: + self.backup_data = self.__getitem_joint__(0, backup_scene) + + def __len__(self): + return len(self.objects)*self.total_view + + def load_fixed_poses(self): + poses = {} + for face in self.view_types: + RT = np.loadtxt(os.path.join(self.fix_cam_pose_dir,'%03d_%s_RT.txt'%(0, face))) + poses[face] = RT + + return poses + + def cartesian_to_spherical(self, xyz): + ptsnew = np.hstack((xyz, np.zeros(xyz.shape))) + xy = xyz[:,0]**2 + xyz[:,1]**2 + z = np.sqrt(xy + xyz[:,2]**2) + theta = np.arctan2(np.sqrt(xy), xyz[:,2]) # for elevation angle defined from Z-axis down + #ptsnew[:,4] = np.arctan2(xyz[:,2], np.sqrt(xy)) # for elevation angle defined from XY-plane up + azimuth = np.arctan2(xyz[:,1], xyz[:,0]) + return np.array([theta, azimuth, z]) + + def get_T(self, target_RT, cond_RT): + R, T = target_RT[:3, :3], target_RT[:, -1] + T_target = -R.T @ T # change to cam2world + + R, T = cond_RT[:3, :3], cond_RT[:, -1] + T_cond = -R.T @ T + + theta_cond, azimuth_cond, z_cond = self.cartesian_to_spherical(T_cond[None, :]) + theta_target, azimuth_target, z_target = self.cartesian_to_spherical(T_target[None, :]) + + d_theta = theta_target - theta_cond + d_azimuth = (azimuth_target - azimuth_cond) % (2 * math.pi) + d_z = z_target - z_cond + + # d_T = torch.tensor([d_theta.item(), math.sin(d_azimuth.item()), math.cos(d_azimuth.item()), d_z.item()]) + return d_theta, d_azimuth + + def get_bg_color(self): + if self.bg_color == 'white': + bg_color = np.array([1., 1., 1.], dtype=np.float32) + elif self.bg_color == 'black': + bg_color = np.array([0., 0., 0.], dtype=np.float32) + elif self.bg_color == 'gray': + bg_color = np.array([0.5, 0.5, 0.5], dtype=np.float32) + elif self.bg_color == 'random': + bg_color = np.random.rand(3) + elif self.bg_color == 'three_choices': + white = np.array([1., 1., 1.], dtype=np.float32) + black = np.array([0., 0., 0.], dtype=np.float32) + gray = np.array([0.5, 0.5, 0.5], dtype=np.float32) + bg_color = random.choice([white, black, gray]) + elif isinstance(self.bg_color, float): + bg_color = np.array([self.bg_color] * 3, dtype=np.float32) + else: + raise NotImplementedError + return bg_color + + + + def load_mask(self, img_path, return_type='np'): + # not using cv2 as may load in uint16 format + # img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # [0, 255] + # img = cv2.resize(img, self.img_wh, interpolation=cv2.INTER_CUBIC) + # pil always returns uint8 + img = np.array(Image.open(img_path).resize(self.img_wh)) + img = np.float32(img > 0) + + assert len(np.shape(img)) == 2 + + if return_type == "np": + pass + elif return_type == "pt": + img = torch.from_numpy(img) + else: + raise NotImplementedError + + return img + + def load_image(self, img_path, bg_color, alpha, return_type='np'): + # not using cv2 as may load in uint16 format + # img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # [0, 255] + # img = cv2.resize(img, self.img_wh, interpolation=cv2.INTER_CUBIC) + # pil always returns uint8 + img = np.array(Image.open(img_path).resize(self.img_wh)) + img = img.astype(np.float32) / 255. # [0, 1] + assert img.shape[-1] == 3 or img.shape[-1] == 4 # RGB or RGBA + + if alpha is None and img.shape[-1] == 4: + alpha = img[:, :, 3:] + img = img[:, :, :3] + + if alpha.shape[-1] != 1: + alpha = alpha[:, :, None] + + img = img[...,:3] * alpha + bg_color * (1 - alpha) + + if return_type == "np": + pass + elif return_type == "pt": + img = torch.from_numpy(img) + else: + raise NotImplementedError + + return img + + def load_depth(self, img_path, bg_color, alpha, return_type='np'): + # not using cv2 as may load in uint16 format + # img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # [0, 255] + # img = cv2.resize(img, self.img_wh, interpolation=cv2.INTER_CUBIC) + # pil always returns uint8 + img = np.array(Image.open(img_path).resize(self.img_wh)) + img = img.astype(np.float32) / 65535. # [0, 1] + + img[img > 0.4] = 0 + img = img / 0.4 + + assert img.ndim == 2 # depth + img = np.stack([img]*3, axis=-1) + + if alpha.shape[-1] != 1: + alpha = alpha[:, :, None] + + # print(np.max(img[:, :, 0])) + + img = img[...,:3] * alpha + bg_color * (1 - alpha) + + if return_type == "np": + pass + elif return_type == "pt": + img = torch.from_numpy(img) + else: + raise NotImplementedError + + return img + + def load_normal(self, img_path, bg_color, alpha, RT_w2c=None, RT_w2c_cond=None, return_type='np'): + # not using cv2 as may load in uint16 format + # img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # [0, 255] + # img = cv2.resize(img, self.img_wh, interpolation=cv2.INTER_CUBIC) + # pil always returns uint8 + normal = np.array(Image.open(img_path).resize(self.img_wh)) + + assert normal.shape[-1] == 3 or normal.shape[-1] == 4 # RGB or RGBA + + if alpha is None and normal.shape[-1] == 4: + alpha = normal[:, :, 3:] / 255. + normal = normal[:, :, :3] + + normal = trans_normal(img2normal(normal), RT_w2c, RT_w2c_cond) + + img = (normal*0.5 + 0.5).astype(np.float32) # [0, 1] + + if alpha.shape[-1] != 1: + alpha = alpha[:, :, None] + + img = img[...,:3] * alpha + bg_color * (1 - alpha) + + if return_type == "np": + pass + elif return_type == "pt": + img = torch.from_numpy(img) + else: + raise NotImplementedError + + return img + + def __len__(self): + return len(self.all_objects) + + def __getitem_mix__(self, index, debug_object=None): + if debug_object is not None: + object_name = debug_object # + set_idx = random.sample(range(0, self.groups_num), 1)[0] # without replacement + else: + object_name = self.all_objects[index%len(self.all_objects)] + set_idx = 0 + + if self.augment_data: + cond_view = random.sample(self.view_types, k=1)[0] + else: + cond_view = 'front' + + + # ! if you would like predict depth; modify here + if random.random() < 0.5: + read_color, read_normal, read_depth = True, False, False + else: + read_color, read_normal, read_depth = False, True, False + + read_normal = read_normal & self.read_normal + read_depth = read_depth & self.read_depth + + assert (read_color and (read_normal or read_depth)) is False + + view_types = self.view_types + + cond_w2c = self.fix_cam_poses[cond_view] + + tgt_w2cs = [self.fix_cam_poses[view] for view in view_types] + + elevations = [] + azimuths = [] + + # get the bg color + bg_color = self.get_bg_color() + + if self.read_mask: + cond_alpha = self.load_mask(os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "mask_%03d_%s.%s" % (set_idx, cond_view, self.suffix)), return_type='np') + else: + cond_alpha = None + img_tensors_in = [ + self.load_image(os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "rgb_%03d_%s.%s" % (set_idx, cond_view, self.suffix)), bg_color, cond_alpha, return_type='pt').permute(2, 0, 1) + ] * self.num_views + img_tensors_out = [] + + for view, tgt_w2c in zip(view_types, tgt_w2cs): + img_path = os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "rgb_%03d_%s.%s" % (set_idx, view, self.suffix)) + mask_path = os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "mask_%03d_%s.%s" % (set_idx, view, self.suffix)) + normal_path = os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "normals_%03d_%s.%s" % (set_idx, view, self.suffix)) + depth_path = os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "depth_%03d_%s.%s" % (set_idx, view, self.suffix)) + if self.read_mask: + alpha = self.load_mask(mask_path, return_type='np') + else: + alpha = None + + if read_color: + img_tensor = self.load_image(img_path, bg_color, alpha, return_type="pt") + img_tensor = img_tensor.permute(2, 0, 1) + img_tensors_out.append(img_tensor) + + if read_normal: + normal_tensor = self.load_normal(normal_path, bg_color, alpha, RT_w2c=tgt_w2c, RT_w2c_cond=cond_w2c, return_type="pt").permute(2, 0, 1) + img_tensors_out.append(normal_tensor) + if read_depth: + depth_tensor = self.load_depth(depth_path, bg_color, alpha, return_type="pt").permute(2, 0, 1) + img_tensors_out.append(depth_tensor) + + # evelations, azimuths + elevation, azimuth = self.get_T(tgt_w2c, cond_w2c) + elevations.append(elevation) + azimuths.append(azimuth) + + img_tensors_in = torch.stack(img_tensors_in, dim=0).float() # (Nv, 3, H, W) + img_tensors_out = torch.stack(img_tensors_out, dim=0).float() # (Nv, 3, H, W) + + + elevations = torch.as_tensor(elevations).float().squeeze(1) + azimuths = torch.as_tensor(azimuths).float().squeeze(1) + elevations_cond = torch.as_tensor([0] * self.num_views).float() # fixed only use 4 views to train + camera_embeddings = torch.stack([elevations_cond, elevations, azimuths], dim=-1) # (Nv, 3) + + normal_class = torch.tensor([1, 0]).float() + normal_task_embeddings = torch.stack([normal_class]*self.num_views, dim=0) # (Nv, 2) + color_class = torch.tensor([0, 1]).float() + color_task_embeddings = torch.stack([color_class]*self.num_views, dim=0) # (Nv, 2) + if read_normal or read_depth: + task_embeddings = normal_task_embeddings + if read_color: + task_embeddings = color_task_embeddings + # print(elevations) + # print(azimuths) + return { + 'elevations_cond': elevations_cond, + 'elevations_cond_deg': torch.rad2deg(elevations_cond), + 'elevations': elevations, + 'azimuths': azimuths, + 'elevations_deg': torch.rad2deg(elevations), + 'azimuths_deg': torch.rad2deg(azimuths), + 'imgs_in': img_tensors_in, + 'imgs_out': img_tensors_out, + 'camera_embeddings': camera_embeddings, + 'task_embeddings': task_embeddings + } + + + def __getitem_joint__(self, index, debug_object=None): + if debug_object is not None: + object_name = debug_object # + set_idx = random.sample(range(0, self.groups_num), 1)[0] # without replacement + else: + object_name = self.all_objects[index%len(self.all_objects)] + set_idx = 0 + + if self.augment_data: + cond_view = random.sample(self.view_types, k=1)[0] + else: + cond_view = 'front' + + view_types = self.view_types + + cond_w2c = self.fix_cam_poses[cond_view] + + tgt_w2cs = [self.fix_cam_poses[view] for view in view_types] + + elevations = [] + azimuths = [] + + # get the bg color + bg_color = self.get_bg_color() + + if self.read_mask: + cond_alpha = self.load_mask(os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "mask_%03d_%s.%s" % (set_idx, cond_view, self.suffix)), return_type='np') + else: + cond_alpha = None + img_tensors_in = [ + self.load_image(os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "rgb_%03d_%s.%s" % (set_idx, cond_view, self.suffix)), bg_color, cond_alpha, return_type='pt').permute(2, 0, 1) + ] * self.num_views + img_tensors_out = [] + normal_tensors_out = [] + for view, tgt_w2c in zip(view_types, tgt_w2cs): + img_path = os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "rgb_%03d_%s.%s" % (set_idx, view, self.suffix)) + mask_path = os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "mask_%03d_%s.%s" % (set_idx, view, self.suffix)) + if self.read_mask: + alpha = self.load_mask(mask_path, return_type='np') + else: + alpha = None + + if self.read_color: + img_tensor = self.load_image(img_path, bg_color, alpha, return_type="pt") + img_tensor = img_tensor.permute(2, 0, 1) + img_tensors_out.append(img_tensor) + + if self.read_normal: + normal_path = os.path.join(self.root_dir, object_name[:self.subscene_tag], object_name, "normals_%03d_%s.%s" % (set_idx, view, self.suffix)) + normal_tensor = self.load_normal(normal_path, bg_color, alpha, RT_w2c=tgt_w2c, RT_w2c_cond=cond_w2c, return_type="pt").permute(2, 0, 1) + normal_tensors_out.append(normal_tensor) + + # evelations, azimuths + elevation, azimuth = self.get_T(tgt_w2c, cond_w2c) + elevations.append(elevation) + azimuths.append(azimuth) + + img_tensors_in = torch.stack(img_tensors_in, dim=0).float() # (Nv, 3, H, W) + if self.read_color: + img_tensors_out = torch.stack(img_tensors_out, dim=0).float() # (Nv, 3, H, W) + if self.read_normal: + normal_tensors_out = torch.stack(normal_tensors_out, dim=0).float() # (Nv, 3, H, W) + + elevations = torch.as_tensor(elevations).float().squeeze(1) + azimuths = torch.as_tensor(azimuths).float().squeeze(1) + elevations_cond = torch.as_tensor([0] * self.num_views).float() # fixed only use 4 views to train + + camera_embeddings = torch.stack([elevations_cond, elevations, azimuths], dim=-1) # (Nv, 3) + + normal_class = torch.tensor([1, 0]).float() + normal_task_embeddings = torch.stack([normal_class]*self.num_views, dim=0) # (Nv, 2) + color_class = torch.tensor([0, 1]).float() + color_task_embeddings = torch.stack([color_class]*self.num_views, dim=0) # (Nv, 2) + + return { + 'elevations_cond': elevations_cond, + 'elevations_cond_deg': torch.rad2deg(elevations_cond), + 'elevations': elevations, + 'azimuths': azimuths, + 'elevations_deg': torch.rad2deg(elevations), + 'azimuths_deg': torch.rad2deg(azimuths), + 'imgs_in': img_tensors_in, + 'imgs_out': img_tensors_out, + 'normals_out': normal_tensors_out, + 'camera_embeddings': camera_embeddings, + 'normal_task_embeddings': normal_task_embeddings, + 'color_task_embeddings': color_task_embeddings + } + + def __getitem__(self, index): + try: + if self.mix_color_normal: + data = self.__getitem_mix__(index) + else: + data = self.__getitem_joint__(index) + return data + except: + print("load error ", self.all_objects[index%len(self.all_objects)] ) + return self.backup_data + + +class ConcatDataset(torch.utils.data.Dataset): + def __init__(self, datasets, weights): + self.datasets = datasets + self.weights = weights + self.num_datasets = len(datasets) + + def __getitem__(self, i): + + chosen = random.choices(self.datasets, self.weights, k=1)[0] + return chosen[i] + + def __len__(self): + return max(len(d) for d in self.datasets) + +if __name__ == "__main__": + train_dataset = ObjaverseDataset( + root_dir="/ghome/l5/xxlong/.objaverse/hf-objaverse-v1/renderings", + size=(128, 128), + ext="hdf5", + default_trans=torch.zeros(3), + return_paths=False, + total_view=8, + validation=False, + object_list=None, + views_mode='fourviews' + ) + data0 = train_dataset[0] + data1 = train_dataset[50] + # print(data) diff --git a/apps/third_party/Wonder3D/mvdiffusion/data/single_image_dataset.py b/apps/third_party/Wonder3D/mvdiffusion/data/single_image_dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..0d0d02dc6215bb03dc122b298c8801be27a575fd --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/data/single_image_dataset.py @@ -0,0 +1,305 @@ +from typing import Dict +import numpy as np +from omegaconf import DictConfig, ListConfig +import torch +from torch.utils.data import Dataset +from pathlib import Path +import json +from PIL import Image +from torchvision import transforms +from einops import rearrange +from typing import Literal, Tuple, Optional, Any +import cv2 +import random + +import json +import os, sys +import math + +from glob import glob + +import PIL.Image +from .normal_utils import trans_normal, normal2img, img2normal +import pdb + + +import cv2 +import numpy as np + +def add_margin(pil_img, color=0, size=256): + width, height = pil_img.size + result = Image.new(pil_img.mode, (size, size), color) + result.paste(pil_img, ((size - width) // 2, (size - height) // 2)) + return result + +def scale_and_place_object(image, scale_factor): + assert np.shape(image)[-1]==4 # RGBA + + # Extract the alpha channel (transparency) and the object (RGB channels) + alpha_channel = image[:, :, 3] + + # Find the bounding box coordinates of the object + coords = cv2.findNonZero(alpha_channel) + x, y, width, height = cv2.boundingRect(coords) + + # Calculate the scale factor for resizing + original_height, original_width = image.shape[:2] + + if width > height: + size = width + original_size = original_width + else: + size = height + original_size = original_height + + scale_factor = min(scale_factor, size / (original_size+0.0)) + + new_size = scale_factor * original_size + scale_factor = new_size / size + + # Calculate the new size based on the scale factor + new_width = int(width * scale_factor) + new_height = int(height * scale_factor) + + center_x = original_width // 2 + center_y = original_height // 2 + + paste_x = center_x - (new_width // 2) + paste_y = center_y - (new_height // 2) + + # Resize the object (RGB channels) to the new size + rescaled_object = cv2.resize(image[y:y+height, x:x+width], (new_width, new_height)) + + # Create a new RGBA image with the resized image + new_image = np.zeros((original_height, original_width, 4), dtype=np.uint8) + + new_image[paste_y:paste_y + new_height, paste_x:paste_x + new_width] = rescaled_object + + return new_image + +class SingleImageDataset(Dataset): + def __init__(self, + root_dir: str, + num_views: int, + img_wh: Tuple[int, int], + bg_color: str, + crop_size: int = 224, + single_image: Optional[PIL.Image.Image] = None, + num_validation_samples: Optional[int] = None, + filepaths: Optional[list] = None, + cond_type: Optional[str] = None + ) -> None: + """Create a dataset from a folder of images. + If you pass in a root directory it will be searched for images + ending in ext (ext can be a list) + """ + self.root_dir = root_dir + self.num_views = num_views + self.img_wh = img_wh + self.crop_size = crop_size + self.bg_color = bg_color + self.cond_type = cond_type + + if self.num_views == 4: + self.view_types = ['front', 'right', 'back', 'left'] + elif self.num_views == 5: + self.view_types = ['front', 'front_right', 'right', 'back', 'left'] + elif self.num_views == 6: + self.view_types = ['front', 'front_right', 'right', 'back', 'left', 'front_left'] + + self.fix_cam_pose_dir = "./third_party/Wonder3D/mvdiffusion/data/fixed_poses/nine_views" + + self.fix_cam_poses = self.load_fixed_poses() # world2cam matrix + + if single_image is None: + if filepaths is None: + # Get a list of all files in the directory + file_list = os.listdir(self.root_dir) + else: + file_list = filepaths + + # Filter the files that end with .png or .jpg + self.file_list = [file for file in file_list if file.endswith(('.png', '.jpg'))] + else: + self.file_list = None + + # load all images + self.all_images = [] + self.all_alphas = [] + bg_color = self.get_bg_color() + + if single_image is not None: + image, alpha = self.load_image(None, bg_color, return_type='pt', Imagefile=single_image) + self.all_images.append(image) + self.all_alphas.append(alpha) + else: + for file in self.file_list: + print(os.path.join(self.root_dir, file)) + image, alpha = self.load_image(os.path.join(self.root_dir, file), bg_color, return_type='pt') + self.all_images.append(image) + self.all_alphas.append(alpha) + + self.all_images = self.all_images[:num_validation_samples] + self.all_alphas = self.all_alphas[:num_validation_samples] + + + def __len__(self): + return len(self.all_images) + + def load_fixed_poses(self): + poses = {} + for face in self.view_types: + RT = np.loadtxt(os.path.join(self.fix_cam_pose_dir,'%03d_%s_RT.txt'%(0, face))) + poses[face] = RT + + return poses + + def cartesian_to_spherical(self, xyz): + ptsnew = np.hstack((xyz, np.zeros(xyz.shape))) + xy = xyz[:,0]**2 + xyz[:,1]**2 + z = np.sqrt(xy + xyz[:,2]**2) + theta = np.arctan2(np.sqrt(xy), xyz[:,2]) # for elevation angle defined from Z-axis down + #ptsnew[:,4] = np.arctan2(xyz[:,2], np.sqrt(xy)) # for elevation angle defined from XY-plane up + azimuth = np.arctan2(xyz[:,1], xyz[:,0]) + return np.array([theta, azimuth, z]) + + def get_T(self, target_RT, cond_RT): + R, T = target_RT[:3, :3], target_RT[:, -1] + T_target = -R.T @ T # change to cam2world + + R, T = cond_RT[:3, :3], cond_RT[:, -1] + T_cond = -R.T @ T + + theta_cond, azimuth_cond, z_cond = self.cartesian_to_spherical(T_cond[None, :]) + theta_target, azimuth_target, z_target = self.cartesian_to_spherical(T_target[None, :]) + + d_theta = theta_target - theta_cond + d_azimuth = (azimuth_target - azimuth_cond) % (2 * math.pi) + d_z = z_target - z_cond + + # d_T = torch.tensor([d_theta.item(), math.sin(d_azimuth.item()), math.cos(d_azimuth.item()), d_z.item()]) + return d_theta, d_azimuth + + def get_bg_color(self): + if self.bg_color == 'white': + bg_color = np.array([1., 1., 1.], dtype=np.float32) + elif self.bg_color == 'black': + bg_color = np.array([0., 0., 0.], dtype=np.float32) + elif self.bg_color == 'gray': + bg_color = np.array([0.5, 0.5, 0.5], dtype=np.float32) + elif self.bg_color == 'random': + bg_color = np.random.rand(3) + elif isinstance(self.bg_color, float): + bg_color = np.array([self.bg_color] * 3, dtype=np.float32) + else: + raise NotImplementedError + return bg_color + + + def load_image(self, img_path, bg_color, return_type='np', Imagefile=None): + # pil always returns uint8 + if Imagefile is None: + image_input = Image.open(img_path) + else: + image_input = Imagefile + image_size = self.img_wh[0] + + if self.crop_size!=-1: + alpha_np = np.asarray(image_input)[:, :, 3] + coords = np.stack(np.nonzero(alpha_np), 1)[:, (1, 0)] + min_x, min_y = np.min(coords, 0) + max_x, max_y = np.max(coords, 0) + ref_img_ = image_input.crop((min_x, min_y, max_x, max_y)) + h, w = ref_img_.height, ref_img_.width + scale = self.crop_size / max(h, w) + h_, w_ = int(scale * h), int(scale * w) + ref_img_ = ref_img_.resize((w_, h_)) + image_input = add_margin(ref_img_, size=image_size) + else: + image_input = add_margin(image_input, size=max(image_input.height, image_input.width)) + image_input = image_input.resize((image_size, image_size)) + + # img = scale_and_place_object(img, self.scale_ratio) + img = np.array(image_input) + img = img.astype(np.float32) / 255. # [0, 1] + assert img.shape[-1] == 4 # RGBA + + alpha = img[...,3:4] + img = img[...,:3] * alpha + bg_color * (1 - alpha) + + if return_type == "np": + pass + elif return_type == "pt": + img = torch.from_numpy(img) + alpha = torch.from_numpy(alpha) + else: + raise NotImplementedError + + return img, alpha + + + def __len__(self): + return len(self.all_images) + + def __getitem__(self, index): + + image = self.all_images[index%len(self.all_images)] + alpha = self.all_alphas[index%len(self.all_images)] + if self.file_list is not None: + filename = self.file_list[index%len(self.all_images)].replace(".png", "") + else: + filename = 'null' + + cond_w2c = self.fix_cam_poses['front'] + + tgt_w2cs = [self.fix_cam_poses[view] for view in self.view_types] + + elevations = [] + azimuths = [] + + img_tensors_in = [ + image.permute(2, 0, 1) + ] * self.num_views + + alpha_tensors_in = [ + alpha.permute(2, 0, 1) + ] * self.num_views + + for view, tgt_w2c in zip(self.view_types, tgt_w2cs): + # evelations, azimuths + elevation, azimuth = self.get_T(tgt_w2c, cond_w2c) + elevations.append(elevation) + azimuths.append(azimuth) + + img_tensors_in = torch.stack(img_tensors_in, dim=0).float() # (Nv, 3, H, W) + alpha_tensors_in = torch.stack(alpha_tensors_in, dim=0).float() # (Nv, 3, H, W) + + elevations = torch.as_tensor(elevations).float().squeeze(1) + azimuths = torch.as_tensor(azimuths).float().squeeze(1) + elevations_cond = torch.as_tensor([0] * self.num_views).float() + + normal_class = torch.tensor([1, 0]).float() + normal_task_embeddings = torch.stack([normal_class]*self.num_views, dim=0) # (Nv, 2) + color_class = torch.tensor([0, 1]).float() + color_task_embeddings = torch.stack([color_class]*self.num_views, dim=0) # (Nv, 2) + + camera_embeddings = torch.stack([elevations_cond, elevations, azimuths], dim=-1) # (Nv, 3) + + out = { + 'elevations_cond': elevations_cond, + 'elevations_cond_deg': torch.rad2deg(elevations_cond), + 'elevations': elevations, + 'azimuths': azimuths, + 'elevations_deg': torch.rad2deg(elevations), + 'azimuths_deg': torch.rad2deg(azimuths), + 'imgs_in': img_tensors_in, + 'alphas': alpha_tensors_in, + 'camera_embeddings': camera_embeddings, + 'normal_task_embeddings': normal_task_embeddings, + 'color_task_embeddings': color_task_embeddings, + 'filename': filename, + } + + return out + + diff --git a/apps/third_party/Wonder3D/mvdiffusion/models/transformer_mv2d.py b/apps/third_party/Wonder3D/mvdiffusion/models/transformer_mv2d.py new file mode 100644 index 0000000000000000000000000000000000000000..f9f0be6bcb554af916fe74ee7d919d0a1a47aa36 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/models/transformer_mv2d.py @@ -0,0 +1,986 @@ +# Copyright 2023 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from dataclasses import dataclass +from typing import Any, Dict, Optional + +import torch +import torch.nn.functional as F +from torch import nn + +from diffusers.configuration_utils import ConfigMixin, register_to_config +from diffusers.models.embeddings import ImagePositionalEmbeddings +from diffusers.utils import BaseOutput, deprecate, maybe_allow_in_graph +from diffusers.models.attention import FeedForward, AdaLayerNorm, AdaLayerNormZero, Attention +from diffusers.models.embeddings import PatchEmbed +from diffusers.models.lora import LoRACompatibleConv, LoRACompatibleLinear +from diffusers.models.modeling_utils import ModelMixin +from diffusers.utils.import_utils import is_xformers_available + +from einops import rearrange, repeat +import pdb +import random + + +if is_xformers_available(): + import xformers + import xformers.ops +else: + xformers = None + +def my_repeat(tensor, num_repeats): + """ + Repeat a tensor along a given dimension + """ + if len(tensor.shape) == 3: + return repeat(tensor, "b d c -> (b v) d c", v=num_repeats) + elif len(tensor.shape) == 4: + return repeat(tensor, "a b d c -> (a v) b d c", v=num_repeats) + + +@dataclass +class TransformerMV2DModelOutput(BaseOutput): + """ + The output of [`Transformer2DModel`]. + + Args: + sample (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)` or `(batch size, num_vector_embeds - 1, num_latent_pixels)` if [`Transformer2DModel`] is discrete): + The hidden states output conditioned on the `encoder_hidden_states` input. If discrete, returns probability + distributions for the unnoised latent pixels. + """ + + sample: torch.FloatTensor + + +class TransformerMV2DModel(ModelMixin, ConfigMixin): + """ + A 2D Transformer model for image-like data. + + Parameters: + num_attention_heads (`int`, *optional*, defaults to 16): The number of heads to use for multi-head attention. + attention_head_dim (`int`, *optional*, defaults to 88): The number of channels in each head. + in_channels (`int`, *optional*): + The number of channels in the input and output (specify if the input is **continuous**). + num_layers (`int`, *optional*, defaults to 1): The number of layers of Transformer blocks to use. + dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use. + cross_attention_dim (`int`, *optional*): The number of `encoder_hidden_states` dimensions to use. + sample_size (`int`, *optional*): The width of the latent images (specify if the input is **discrete**). + This is fixed during training since it is used to learn a number of position embeddings. + num_vector_embeds (`int`, *optional*): + The number of classes of the vector embeddings of the latent pixels (specify if the input is **discrete**). + Includes the class for the masked latent pixel. + activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to use in feed-forward. + num_embeds_ada_norm ( `int`, *optional*): + The number of diffusion steps used during training. Pass if at least one of the norm_layers is + `AdaLayerNorm`. This is fixed during training since it is used to learn a number of embeddings that are + added to the hidden states. + + During inference, you can denoise for up to but not more steps than `num_embeds_ada_norm`. + attention_bias (`bool`, *optional*): + Configure if the `TransformerBlocks` attention should contain a bias parameter. + """ + + @register_to_config + def __init__( + self, + num_attention_heads: int = 16, + attention_head_dim: int = 88, + in_channels: Optional[int] = None, + out_channels: Optional[int] = None, + num_layers: int = 1, + dropout: float = 0.0, + norm_num_groups: int = 32, + cross_attention_dim: Optional[int] = None, + attention_bias: bool = False, + sample_size: Optional[int] = None, + num_vector_embeds: Optional[int] = None, + patch_size: Optional[int] = None, + activation_fn: str = "geglu", + num_embeds_ada_norm: Optional[int] = None, + use_linear_projection: bool = False, + only_cross_attention: bool = False, + upcast_attention: bool = False, + norm_type: str = "layer_norm", + norm_elementwise_affine: bool = True, + num_views: int = 1, + cd_attention_last: bool=False, + cd_attention_mid: bool=False, + multiview_attention: bool=True, + sparse_mv_attention: bool = False, + mvcd_attention: bool=False + ): + super().__init__() + self.use_linear_projection = use_linear_projection + self.num_attention_heads = num_attention_heads + self.attention_head_dim = attention_head_dim + inner_dim = num_attention_heads * attention_head_dim + + # 1. Transformer2DModel can process both standard continuous images of shape `(batch_size, num_channels, width, height)` as well as quantized image embeddings of shape `(batch_size, num_image_vectors)` + # Define whether input is continuous or discrete depending on configuration + self.is_input_continuous = (in_channels is not None) and (patch_size is None) + self.is_input_vectorized = num_vector_embeds is not None + self.is_input_patches = in_channels is not None and patch_size is not None + + if norm_type == "layer_norm" and num_embeds_ada_norm is not None: + deprecation_message = ( + f"The configuration file of this model: {self.__class__} is outdated. `norm_type` is either not set or" + " incorrectly set to `'layer_norm'`.Make sure to set `norm_type` to `'ada_norm'` in the config." + " Please make sure to update the config accordingly as leaving `norm_type` might led to incorrect" + " results in future versions. If you have downloaded this checkpoint from the Hugging Face Hub, it" + " would be very nice if you could open a Pull request for the `transformer/config.json` file" + ) + deprecate("norm_type!=num_embeds_ada_norm", "1.0.0", deprecation_message, standard_warn=False) + norm_type = "ada_norm" + + if self.is_input_continuous and self.is_input_vectorized: + raise ValueError( + f"Cannot define both `in_channels`: {in_channels} and `num_vector_embeds`: {num_vector_embeds}. Make" + " sure that either `in_channels` or `num_vector_embeds` is None." + ) + elif self.is_input_vectorized and self.is_input_patches: + raise ValueError( + f"Cannot define both `num_vector_embeds`: {num_vector_embeds} and `patch_size`: {patch_size}. Make" + " sure that either `num_vector_embeds` or `num_patches` is None." + ) + elif not self.is_input_continuous and not self.is_input_vectorized and not self.is_input_patches: + raise ValueError( + f"Has to define `in_channels`: {in_channels}, `num_vector_embeds`: {num_vector_embeds}, or patch_size:" + f" {patch_size}. Make sure that `in_channels`, `num_vector_embeds` or `num_patches` is not None." + ) + + # 2. Define input layers + if self.is_input_continuous: + self.in_channels = in_channels + + self.norm = torch.nn.GroupNorm(num_groups=norm_num_groups, num_channels=in_channels, eps=1e-6, affine=True) + if use_linear_projection: + self.proj_in = LoRACompatibleLinear(in_channels, inner_dim) + else: + self.proj_in = LoRACompatibleConv(in_channels, inner_dim, kernel_size=1, stride=1, padding=0) + elif self.is_input_vectorized: + assert sample_size is not None, "Transformer2DModel over discrete input must provide sample_size" + assert num_vector_embeds is not None, "Transformer2DModel over discrete input must provide num_embed" + + self.height = sample_size + self.width = sample_size + self.num_vector_embeds = num_vector_embeds + self.num_latent_pixels = self.height * self.width + + self.latent_image_embedding = ImagePositionalEmbeddings( + num_embed=num_vector_embeds, embed_dim=inner_dim, height=self.height, width=self.width + ) + elif self.is_input_patches: + assert sample_size is not None, "Transformer2DModel over patched input must provide sample_size" + + self.height = sample_size + self.width = sample_size + + self.patch_size = patch_size + self.pos_embed = PatchEmbed( + height=sample_size, + width=sample_size, + patch_size=patch_size, + in_channels=in_channels, + embed_dim=inner_dim, + ) + + # 3. Define transformers blocks + self.transformer_blocks = nn.ModuleList( + [ + BasicMVTransformerBlock( + inner_dim, + num_attention_heads, + attention_head_dim, + dropout=dropout, + cross_attention_dim=cross_attention_dim, + activation_fn=activation_fn, + num_embeds_ada_norm=num_embeds_ada_norm, + attention_bias=attention_bias, + only_cross_attention=only_cross_attention, + upcast_attention=upcast_attention, + norm_type=norm_type, + norm_elementwise_affine=norm_elementwise_affine, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + for d in range(num_layers) + ] + ) + + # 4. Define output layers + self.out_channels = in_channels if out_channels is None else out_channels + if self.is_input_continuous: + # TODO: should use out_channels for continuous projections + if use_linear_projection: + self.proj_out = LoRACompatibleLinear(inner_dim, in_channels) + else: + self.proj_out = LoRACompatibleConv(inner_dim, in_channels, kernel_size=1, stride=1, padding=0) + elif self.is_input_vectorized: + self.norm_out = nn.LayerNorm(inner_dim) + self.out = nn.Linear(inner_dim, self.num_vector_embeds - 1) + elif self.is_input_patches: + self.norm_out = nn.LayerNorm(inner_dim, elementwise_affine=False, eps=1e-6) + self.proj_out_1 = nn.Linear(inner_dim, 2 * inner_dim) + self.proj_out_2 = nn.Linear(inner_dim, patch_size * patch_size * self.out_channels) + + def forward( + self, + hidden_states: torch.Tensor, + encoder_hidden_states: Optional[torch.Tensor] = None, + timestep: Optional[torch.LongTensor] = None, + class_labels: Optional[torch.LongTensor] = None, + cross_attention_kwargs: Dict[str, Any] = None, + attention_mask: Optional[torch.Tensor] = None, + encoder_attention_mask: Optional[torch.Tensor] = None, + return_dict: bool = True, + ): + """ + The [`Transformer2DModel`] forward method. + + Args: + hidden_states (`torch.LongTensor` of shape `(batch size, num latent pixels)` if discrete, `torch.FloatTensor` of shape `(batch size, channel, height, width)` if continuous): + Input `hidden_states`. + encoder_hidden_states ( `torch.FloatTensor` of shape `(batch size, sequence len, embed dims)`, *optional*): + Conditional embeddings for cross attention layer. If not given, cross-attention defaults to + self-attention. + timestep ( `torch.LongTensor`, *optional*): + Used to indicate denoising step. Optional timestep to be applied as an embedding in `AdaLayerNorm`. + class_labels ( `torch.LongTensor` of shape `(batch size, num classes)`, *optional*): + Used to indicate class labels conditioning. Optional class labels to be applied as an embedding in + `AdaLayerZeroNorm`. + encoder_attention_mask ( `torch.Tensor`, *optional*): + Cross-attention mask applied to `encoder_hidden_states`. Two formats supported: + + * Mask `(batch, sequence_length)` True = keep, False = discard. + * Bias `(batch, 1, sequence_length)` 0 = keep, -10000 = discard. + + If `ndim == 2`: will be interpreted as a mask, then converted into a bias consistent with the format + above. This bias will be added to the cross-attention scores. + return_dict (`bool`, *optional*, defaults to `True`): + Whether or not to return a [`~models.unet_2d_condition.UNet2DConditionOutput`] instead of a plain + tuple. + + Returns: + If `return_dict` is True, an [`~models.transformer_2d.Transformer2DModelOutput`] is returned, otherwise a + `tuple` where the first element is the sample tensor. + """ + # ensure attention_mask is a bias, and give it a singleton query_tokens dimension. + # we may have done this conversion already, e.g. if we came here via UNet2DConditionModel#forward. + # we can tell by counting dims; if ndim == 2: it's a mask rather than a bias. + # expects mask of shape: + # [batch, key_tokens] + # adds singleton query_tokens dimension: + # [batch, 1, key_tokens] + # this helps to broadcast it as a bias over attention scores, which will be in one of the following shapes: + # [batch, heads, query_tokens, key_tokens] (e.g. torch sdp attn) + # [batch * heads, query_tokens, key_tokens] (e.g. xformers or classic attn) + if attention_mask is not None and attention_mask.ndim == 2: + # assume that mask is expressed as: + # (1 = keep, 0 = discard) + # convert mask into a bias that can be added to attention scores: + # (keep = +0, discard = -10000.0) + attention_mask = (1 - attention_mask.to(hidden_states.dtype)) * -10000.0 + attention_mask = attention_mask.unsqueeze(1) + + # convert encoder_attention_mask to a bias the same way we do for attention_mask + if encoder_attention_mask is not None and encoder_attention_mask.ndim == 2: + encoder_attention_mask = (1 - encoder_attention_mask.to(hidden_states.dtype)) * -10000.0 + encoder_attention_mask = encoder_attention_mask.unsqueeze(1) + + # 1. Input + if self.is_input_continuous: + batch, _, height, width = hidden_states.shape + residual = hidden_states + + hidden_states = self.norm(hidden_states) + if not self.use_linear_projection: + hidden_states = self.proj_in(hidden_states) + inner_dim = hidden_states.shape[1] + hidden_states = hidden_states.permute(0, 2, 3, 1).reshape(batch, height * width, inner_dim) + else: + inner_dim = hidden_states.shape[1] + hidden_states = hidden_states.permute(0, 2, 3, 1).reshape(batch, height * width, inner_dim) + hidden_states = self.proj_in(hidden_states) + elif self.is_input_vectorized: + hidden_states = self.latent_image_embedding(hidden_states) + elif self.is_input_patches: + hidden_states = self.pos_embed(hidden_states) + + # 2. Blocks + for block in self.transformer_blocks: + hidden_states = block( + hidden_states, + attention_mask=attention_mask, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_attention_mask, + timestep=timestep, + cross_attention_kwargs=cross_attention_kwargs, + class_labels=class_labels, + ) + + # 3. Output + if self.is_input_continuous: + if not self.use_linear_projection: + hidden_states = hidden_states.reshape(batch, height, width, inner_dim).permute(0, 3, 1, 2).contiguous() + hidden_states = self.proj_out(hidden_states) + else: + hidden_states = self.proj_out(hidden_states) + hidden_states = hidden_states.reshape(batch, height, width, inner_dim).permute(0, 3, 1, 2).contiguous() + + output = hidden_states + residual + elif self.is_input_vectorized: + hidden_states = self.norm_out(hidden_states) + logits = self.out(hidden_states) + # (batch, self.num_vector_embeds - 1, self.num_latent_pixels) + logits = logits.permute(0, 2, 1) + + # log(p(x_0)) + output = F.log_softmax(logits.double(), dim=1).float() + elif self.is_input_patches: + # TODO: cleanup! + conditioning = self.transformer_blocks[0].norm1.emb( + timestep, class_labels, hidden_dtype=hidden_states.dtype + ) + shift, scale = self.proj_out_1(F.silu(conditioning)).chunk(2, dim=1) + hidden_states = self.norm_out(hidden_states) * (1 + scale[:, None]) + shift[:, None] + hidden_states = self.proj_out_2(hidden_states) + + # unpatchify + height = width = int(hidden_states.shape[1] ** 0.5) + hidden_states = hidden_states.reshape( + shape=(-1, height, width, self.patch_size, self.patch_size, self.out_channels) + ) + hidden_states = torch.einsum("nhwpqc->nchpwq", hidden_states) + output = hidden_states.reshape( + shape=(-1, self.out_channels, height * self.patch_size, width * self.patch_size) + ) + + if not return_dict: + return (output,) + + return TransformerMV2DModelOutput(sample=output) + + +@maybe_allow_in_graph +class BasicMVTransformerBlock(nn.Module): + r""" + A basic Transformer block. + + Parameters: + dim (`int`): The number of channels in the input and output. + num_attention_heads (`int`): The number of heads to use for multi-head attention. + attention_head_dim (`int`): The number of channels in each head. + dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use. + cross_attention_dim (`int`, *optional*): The size of the encoder_hidden_states vector for cross attention. + only_cross_attention (`bool`, *optional*): + Whether to use only cross-attention layers. In this case two cross attention layers are used. + double_self_attention (`bool`, *optional*): + Whether to use two self-attention layers. In this case no cross attention layers are used. + activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. + num_embeds_ada_norm (: + obj: `int`, *optional*): The number of diffusion steps used during training. See `Transformer2DModel`. + attention_bias (: + obj: `bool`, *optional*, defaults to `False`): Configure if the attentions should contain a bias parameter. + """ + + def __init__( + self, + dim: int, + num_attention_heads: int, + attention_head_dim: int, + dropout=0.0, + cross_attention_dim: Optional[int] = None, + activation_fn: str = "geglu", + num_embeds_ada_norm: Optional[int] = None, + attention_bias: bool = False, + only_cross_attention: bool = False, + double_self_attention: bool = False, + upcast_attention: bool = False, + norm_elementwise_affine: bool = True, + norm_type: str = "layer_norm", + final_dropout: bool = False, + num_views: int = 1, + cd_attention_last: bool = False, + cd_attention_mid: bool = False, + multiview_attention: bool = True, + sparse_mv_attention: bool = False, + mvcd_attention: bool = False + ): + super().__init__() + self.only_cross_attention = only_cross_attention + + self.use_ada_layer_norm_zero = (num_embeds_ada_norm is not None) and norm_type == "ada_norm_zero" + self.use_ada_layer_norm = (num_embeds_ada_norm is not None) and norm_type == "ada_norm" + + if norm_type in ("ada_norm", "ada_norm_zero") and num_embeds_ada_norm is None: + raise ValueError( + f"`norm_type` is set to {norm_type}, but `num_embeds_ada_norm` is not defined. Please make sure to" + f" define `num_embeds_ada_norm` if setting `norm_type` to {norm_type}." + ) + + # Define 3 blocks. Each block has its own normalization layer. + # 1. Self-Attn + if self.use_ada_layer_norm: + self.norm1 = AdaLayerNorm(dim, num_embeds_ada_norm) + elif self.use_ada_layer_norm_zero: + self.norm1 = AdaLayerNormZero(dim, num_embeds_ada_norm) + else: + self.norm1 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine) + + self.multiview_attention = multiview_attention + self.sparse_mv_attention = sparse_mv_attention + self.mvcd_attention = mvcd_attention + + self.attn1 = CustomAttention( + query_dim=dim, + heads=num_attention_heads, + dim_head=attention_head_dim, + dropout=dropout, + bias=attention_bias, + cross_attention_dim=cross_attention_dim if only_cross_attention else None, + upcast_attention=upcast_attention, + processor=MVAttnProcessor() + ) + + # 2. Cross-Attn + if cross_attention_dim is not None or double_self_attention: + # We currently only use AdaLayerNormZero for self attention where there will only be one attention block. + # I.e. the number of returned modulation chunks from AdaLayerZero would not make sense if returned during + # the second cross attention block. + self.norm2 = ( + AdaLayerNorm(dim, num_embeds_ada_norm) + if self.use_ada_layer_norm + else nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine) + ) + self.attn2 = Attention( + query_dim=dim, + cross_attention_dim=cross_attention_dim if not double_self_attention else None, + heads=num_attention_heads, + dim_head=attention_head_dim, + dropout=dropout, + bias=attention_bias, + upcast_attention=upcast_attention, + ) # is self-attn if encoder_hidden_states is none + else: + self.norm2 = None + self.attn2 = None + + # 3. Feed-forward + self.norm3 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine) + self.ff = FeedForward(dim, dropout=dropout, activation_fn=activation_fn, final_dropout=final_dropout) + + # let chunk size default to None + self._chunk_size = None + self._chunk_dim = 0 + + self.num_views = num_views + + self.cd_attention_last = cd_attention_last + + if self.cd_attention_last: + # Joint task -Attn + self.attn_joint_last = CustomJointAttention( + query_dim=dim, + heads=num_attention_heads, + dim_head=attention_head_dim, + dropout=dropout, + bias=attention_bias, + cross_attention_dim=cross_attention_dim if only_cross_attention else None, + upcast_attention=upcast_attention, + processor=JointAttnProcessor() + ) + nn.init.zeros_(self.attn_joint_last.to_out[0].weight.data) + self.norm_joint_last = AdaLayerNorm(dim, num_embeds_ada_norm) if self.use_ada_layer_norm else nn.LayerNorm(dim) + + + self.cd_attention_mid = cd_attention_mid + + if self.cd_attention_mid: + # print("cross-domain attn in the middle") + # Joint task -Attn + self.attn_joint_mid = CustomJointAttention( + query_dim=dim, + heads=num_attention_heads, + dim_head=attention_head_dim, + dropout=dropout, + bias=attention_bias, + cross_attention_dim=cross_attention_dim if only_cross_attention else None, + upcast_attention=upcast_attention, + processor=JointAttnProcessor() + ) + nn.init.zeros_(self.attn_joint_mid.to_out[0].weight.data) + self.norm_joint_mid = AdaLayerNorm(dim, num_embeds_ada_norm) if self.use_ada_layer_norm else nn.LayerNorm(dim) + + def set_chunk_feed_forward(self, chunk_size: Optional[int], dim: int): + # Sets chunk feed-forward + self._chunk_size = chunk_size + self._chunk_dim = dim + + def forward( + self, + hidden_states: torch.FloatTensor, + attention_mask: Optional[torch.FloatTensor] = None, + encoder_hidden_states: Optional[torch.FloatTensor] = None, + encoder_attention_mask: Optional[torch.FloatTensor] = None, + timestep: Optional[torch.LongTensor] = None, + cross_attention_kwargs: Dict[str, Any] = None, + class_labels: Optional[torch.LongTensor] = None, + ): + assert attention_mask is None # not supported yet + # Notice that normalization is always applied before the real computation in the following blocks. + # 1. Self-Attention + if self.use_ada_layer_norm: + norm_hidden_states = self.norm1(hidden_states, timestep) + elif self.use_ada_layer_norm_zero: + norm_hidden_states, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.norm1( + hidden_states, timestep, class_labels, hidden_dtype=hidden_states.dtype + ) + else: + norm_hidden_states = self.norm1(hidden_states) + + cross_attention_kwargs = cross_attention_kwargs if cross_attention_kwargs is not None else {} + + attn_output = self.attn1( + norm_hidden_states, + encoder_hidden_states=encoder_hidden_states if self.only_cross_attention else None, + attention_mask=attention_mask, + num_views=self.num_views, + multiview_attention=self.multiview_attention, + sparse_mv_attention=self.sparse_mv_attention, + mvcd_attention=self.mvcd_attention, + **cross_attention_kwargs, + ) + + + if self.use_ada_layer_norm_zero: + attn_output = gate_msa.unsqueeze(1) * attn_output + hidden_states = attn_output + hidden_states + + # joint attention twice + if self.cd_attention_mid: + norm_hidden_states = ( + self.norm_joint_mid(hidden_states, timestep) if self.use_ada_layer_norm else self.norm_joint_mid(hidden_states) + ) + hidden_states = self.attn_joint_mid(norm_hidden_states) + hidden_states + + # 2. Cross-Attention + if self.attn2 is not None: + norm_hidden_states = ( + self.norm2(hidden_states, timestep) if self.use_ada_layer_norm else self.norm2(hidden_states) + ) + + attn_output = self.attn2( + norm_hidden_states, + encoder_hidden_states=encoder_hidden_states, + attention_mask=encoder_attention_mask, + **cross_attention_kwargs, + ) + hidden_states = attn_output + hidden_states + + # 3. Feed-forward + norm_hidden_states = self.norm3(hidden_states) + + if self.use_ada_layer_norm_zero: + norm_hidden_states = norm_hidden_states * (1 + scale_mlp[:, None]) + shift_mlp[:, None] + + if self._chunk_size is not None: + # "feed_forward_chunk_size" can be used to save memory + if norm_hidden_states.shape[self._chunk_dim] % self._chunk_size != 0: + raise ValueError( + f"`hidden_states` dimension to be chunked: {norm_hidden_states.shape[self._chunk_dim]} has to be divisible by chunk size: {self._chunk_size}. Make sure to set an appropriate `chunk_size` when calling `unet.enable_forward_chunking`." + ) + + num_chunks = norm_hidden_states.shape[self._chunk_dim] // self._chunk_size + ff_output = torch.cat( + [self.ff(hid_slice) for hid_slice in norm_hidden_states.chunk(num_chunks, dim=self._chunk_dim)], + dim=self._chunk_dim, + ) + else: + ff_output = self.ff(norm_hidden_states) + + if self.use_ada_layer_norm_zero: + ff_output = gate_mlp.unsqueeze(1) * ff_output + + hidden_states = ff_output + hidden_states + + if self.cd_attention_last: + norm_hidden_states = ( + self.norm_joint_last(hidden_states, timestep) if self.use_ada_layer_norm else self.norm_joint_last(hidden_states) + ) + hidden_states = self.attn_joint_last(norm_hidden_states) + hidden_states + + return hidden_states + + +class CustomAttention(Attention): + def set_use_memory_efficient_attention_xformers( + self, use_memory_efficient_attention_xformers: bool, *args, **kwargs + ): + processor = XFormersMVAttnProcessor() + self.set_processor(processor) + # print("using xformers attention processor") + + +class CustomJointAttention(Attention): + def set_use_memory_efficient_attention_xformers( + self, use_memory_efficient_attention_xformers: bool, *args, **kwargs + ): + processor = XFormersJointAttnProcessor() + self.set_processor(processor) + # print("using xformers attention processor") + +class MVAttnProcessor: + r""" + Default processor for performing attention-related computations. + """ + + def __call__( + self, + attn: Attention, + hidden_states, + encoder_hidden_states=None, + attention_mask=None, + temb=None, + num_views=1, + multiview_attention=True + ): + residual = hidden_states + + if attn.spatial_norm is not None: + hidden_states = attn.spatial_norm(hidden_states, temb) + + input_ndim = hidden_states.ndim + + if input_ndim == 4: + batch_size, channel, height, width = hidden_states.shape + hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2) + + batch_size, sequence_length, _ = ( + hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape + ) + attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size) + + if attn.group_norm is not None: + hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2) + + query = attn.to_q(hidden_states) + + if encoder_hidden_states is None: + encoder_hidden_states = hidden_states + elif attn.norm_cross: + encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states) + + key = attn.to_k(encoder_hidden_states) + value = attn.to_v(encoder_hidden_states) + + # print('query', query.shape, 'key', key.shape, 'value', value.shape) + #([bx4, 1024, 320]) key torch.Size([bx4, 1024, 320]) value torch.Size([bx4, 1024, 320]) + # pdb.set_trace() + # multi-view self-attention + if multiview_attention: + key = rearrange(key, "(b t) d c -> b (t d) c", t=num_views).repeat_interleave(num_views, dim=0) + value = rearrange(value, "(b t) d c -> b (t d) c", t=num_views).repeat_interleave(num_views, dim=0) + + query = attn.head_to_batch_dim(query).contiguous() + key = attn.head_to_batch_dim(key).contiguous() + value = attn.head_to_batch_dim(value).contiguous() + + attention_probs = attn.get_attention_scores(query, key, attention_mask) + hidden_states = torch.bmm(attention_probs, value) + hidden_states = attn.batch_to_head_dim(hidden_states) + + # linear proj + hidden_states = attn.to_out[0](hidden_states) + # dropout + hidden_states = attn.to_out[1](hidden_states) + + if input_ndim == 4: + hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width) + + if attn.residual_connection: + hidden_states = hidden_states + residual + + hidden_states = hidden_states / attn.rescale_output_factor + + return hidden_states + + +class XFormersMVAttnProcessor: + r""" + Default processor for performing attention-related computations. + """ + + def __call__( + self, + attn: Attention, + hidden_states, + encoder_hidden_states=None, + attention_mask=None, + temb=None, + num_views=1., + multiview_attention=True, + sparse_mv_attention=False, + mvcd_attention=False, + ): + residual = hidden_states + + if attn.spatial_norm is not None: + hidden_states = attn.spatial_norm(hidden_states, temb) + + input_ndim = hidden_states.ndim + + if input_ndim == 4: + batch_size, channel, height, width = hidden_states.shape + hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2) + + batch_size, sequence_length, _ = ( + hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape + ) + attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size) + + # from yuancheng; here attention_mask is None + if attention_mask is not None: + # expand our mask's singleton query_tokens dimension: + # [batch*heads, 1, key_tokens] -> + # [batch*heads, query_tokens, key_tokens] + # so that it can be added as a bias onto the attention scores that xformers computes: + # [batch*heads, query_tokens, key_tokens] + # we do this explicitly because xformers doesn't broadcast the singleton dimension for us. + _, query_tokens, _ = hidden_states.shape + attention_mask = attention_mask.expand(-1, query_tokens, -1) + + if attn.group_norm is not None: + hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2) + + query = attn.to_q(hidden_states) + + if encoder_hidden_states is None: + encoder_hidden_states = hidden_states + elif attn.norm_cross: + encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states) + + key_raw = attn.to_k(encoder_hidden_states) + value_raw = attn.to_v(encoder_hidden_states) + + # print('query', query.shape, 'key', key.shape, 'value', value.shape) + #([bx4, 1024, 320]) key torch.Size([bx4, 1024, 320]) value torch.Size([bx4, 1024, 320]) + # pdb.set_trace() + # multi-view self-attention + if multiview_attention: + if not sparse_mv_attention: + key = my_repeat(rearrange(key_raw, "(b t) d c -> b (t d) c", t=num_views), num_views) + value = my_repeat(rearrange(value_raw, "(b t) d c -> b (t d) c", t=num_views), num_views) + else: + key_front = my_repeat(rearrange(key_raw, "(b t) d c -> b t d c", t=num_views)[:, 0, :, :], num_views) # [(b t), d, c] + value_front = my_repeat(rearrange(value_raw, "(b t) d c -> b t d c", t=num_views)[:, 0, :, :], num_views) + key = torch.cat([key_front, key_raw], dim=1) # shape (b t) (2 d) c + value = torch.cat([value_front, value_raw], dim=1) + + else: + # print("don't use multiview attention.") + key = key_raw + value = value_raw + + query = attn.head_to_batch_dim(query) + key = attn.head_to_batch_dim(key) + value = attn.head_to_batch_dim(value) + + hidden_states = xformers.ops.memory_efficient_attention(query, key, value, attn_bias=attention_mask) + hidden_states = attn.batch_to_head_dim(hidden_states) + + # linear proj + hidden_states = attn.to_out[0](hidden_states) + # dropout + hidden_states = attn.to_out[1](hidden_states) + + if input_ndim == 4: + hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width) + + if attn.residual_connection: + hidden_states = hidden_states + residual + + hidden_states = hidden_states / attn.rescale_output_factor + + return hidden_states + + + +class XFormersJointAttnProcessor: + r""" + Default processor for performing attention-related computations. + """ + + def __call__( + self, + attn: Attention, + hidden_states, + encoder_hidden_states=None, + attention_mask=None, + temb=None, + num_tasks=2 + ): + + residual = hidden_states + + if attn.spatial_norm is not None: + hidden_states = attn.spatial_norm(hidden_states, temb) + + input_ndim = hidden_states.ndim + + if input_ndim == 4: + batch_size, channel, height, width = hidden_states.shape + hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2) + + batch_size, sequence_length, _ = ( + hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape + ) + attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size) + + # from yuancheng; here attention_mask is None + if attention_mask is not None: + # expand our mask's singleton query_tokens dimension: + # [batch*heads, 1, key_tokens] -> + # [batch*heads, query_tokens, key_tokens] + # so that it can be added as a bias onto the attention scores that xformers computes: + # [batch*heads, query_tokens, key_tokens] + # we do this explicitly because xformers doesn't broadcast the singleton dimension for us. + _, query_tokens, _ = hidden_states.shape + attention_mask = attention_mask.expand(-1, query_tokens, -1) + + if attn.group_norm is not None: + hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2) + + query = attn.to_q(hidden_states) + + if encoder_hidden_states is None: + encoder_hidden_states = hidden_states + elif attn.norm_cross: + encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states) + + key = attn.to_k(encoder_hidden_states) + value = attn.to_v(encoder_hidden_states) + + assert num_tasks == 2 # only support two tasks now + + key_0, key_1 = torch.chunk(key, dim=0, chunks=2) # keys shape (b t) d c + value_0, value_1 = torch.chunk(value, dim=0, chunks=2) + key = torch.cat([key_0, key_1], dim=1) # (b t) 2d c + value = torch.cat([value_0, value_1], dim=1) # (b t) 2d c + key = torch.cat([key]*2, dim=0) # ( 2 b t) 2d c + value = torch.cat([value]*2, dim=0) # (2 b t) 2d c + + + query = attn.head_to_batch_dim(query).contiguous() + key = attn.head_to_batch_dim(key).contiguous() + value = attn.head_to_batch_dim(value).contiguous() + + hidden_states = xformers.ops.memory_efficient_attention(query, key, value, attn_bias=attention_mask) + hidden_states = attn.batch_to_head_dim(hidden_states) + + # linear proj + hidden_states = attn.to_out[0](hidden_states) + # dropout + hidden_states = attn.to_out[1](hidden_states) + + if input_ndim == 4: + hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width) + + if attn.residual_connection: + hidden_states = hidden_states + residual + + hidden_states = hidden_states / attn.rescale_output_factor + + return hidden_states + + +class JointAttnProcessor: + r""" + Default processor for performing attention-related computations. + """ + + def __call__( + self, + attn: Attention, + hidden_states, + encoder_hidden_states=None, + attention_mask=None, + temb=None, + num_tasks=2 + ): + + residual = hidden_states + + if attn.spatial_norm is not None: + hidden_states = attn.spatial_norm(hidden_states, temb) + + input_ndim = hidden_states.ndim + + if input_ndim == 4: + batch_size, channel, height, width = hidden_states.shape + hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2) + + batch_size, sequence_length, _ = ( + hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape + ) + attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size) + + + if attn.group_norm is not None: + hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2) + + query = attn.to_q(hidden_states) + + if encoder_hidden_states is None: + encoder_hidden_states = hidden_states + elif attn.norm_cross: + encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states) + + key = attn.to_k(encoder_hidden_states) + value = attn.to_v(encoder_hidden_states) + + assert num_tasks == 2 # only support two tasks now + + key_0, key_1 = torch.chunk(key, dim=0, chunks=2) # keys shape (b t) d c + value_0, value_1 = torch.chunk(value, dim=0, chunks=2) + key = torch.cat([key_0, key_1], dim=1) # (b t) 2d c + value = torch.cat([value_0, value_1], dim=1) # (b t) 2d c + key = torch.cat([key]*2, dim=0) # ( 2 b t) 2d c + value = torch.cat([value]*2, dim=0) # (2 b t) 2d c + + + query = attn.head_to_batch_dim(query).contiguous() + key = attn.head_to_batch_dim(key).contiguous() + value = attn.head_to_batch_dim(value).contiguous() + + attention_probs = attn.get_attention_scores(query, key, attention_mask) + hidden_states = torch.bmm(attention_probs, value) + hidden_states = attn.batch_to_head_dim(hidden_states) + + # linear proj + hidden_states = attn.to_out[0](hidden_states) + # dropout + hidden_states = attn.to_out[1](hidden_states) + + if input_ndim == 4: + hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width) + + if attn.residual_connection: + hidden_states = hidden_states + residual + + hidden_states = hidden_states / attn.rescale_output_factor + + return hidden_states \ No newline at end of file diff --git a/apps/third_party/Wonder3D/mvdiffusion/models/unet_mv2d_blocks.py b/apps/third_party/Wonder3D/mvdiffusion/models/unet_mv2d_blocks.py new file mode 100644 index 0000000000000000000000000000000000000000..4dfba32e67879ae52b14ef66173830dbf6cdd520 --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/models/unet_mv2d_blocks.py @@ -0,0 +1,922 @@ +# Copyright 2023 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from typing import Any, Dict, Optional, Tuple + +import numpy as np +import torch +import torch.nn.functional as F +from torch import nn + +from diffusers.utils import is_torch_version, logging +from diffusers.models.attention import AdaGroupNorm +from diffusers.models.attention_processor import Attention, AttnAddedKVProcessor, AttnAddedKVProcessor2_0 +from diffusers.models.dual_transformer_2d import DualTransformer2DModel +from diffusers.models.resnet import Downsample2D, FirDownsample2D, FirUpsample2D, KDownsample2D, KUpsample2D, ResnetBlock2D, Upsample2D +from mvdiffusion.models.transformer_mv2d import TransformerMV2DModel + +from diffusers.models.unet_2d_blocks import DownBlock2D, ResnetDownsampleBlock2D, AttnDownBlock2D, CrossAttnDownBlock2D, SimpleCrossAttnDownBlock2D, SkipDownBlock2D, AttnSkipDownBlock2D, DownEncoderBlock2D, AttnDownEncoderBlock2D, KDownBlock2D, KCrossAttnDownBlock2D +from diffusers.models.unet_2d_blocks import UpBlock2D, ResnetUpsampleBlock2D, CrossAttnUpBlock2D, SimpleCrossAttnUpBlock2D, AttnUpBlock2D, SkipUpBlock2D, AttnSkipUpBlock2D, UpDecoderBlock2D, AttnUpDecoderBlock2D, KUpBlock2D, KCrossAttnUpBlock2D + + +logger = logging.get_logger(__name__) # pylint: disable=invalid-name + + +def get_down_block( + down_block_type, + num_layers, + in_channels, + out_channels, + temb_channels, + add_downsample, + resnet_eps, + resnet_act_fn, + transformer_layers_per_block=1, + num_attention_heads=None, + resnet_groups=None, + cross_attention_dim=None, + downsample_padding=None, + dual_cross_attention=False, + use_linear_projection=False, + only_cross_attention=False, + upcast_attention=False, + resnet_time_scale_shift="default", + resnet_skip_time_act=False, + resnet_out_scale_factor=1.0, + cross_attention_norm=None, + attention_head_dim=None, + downsample_type=None, + num_views=1, + cd_attention_last: bool = False, + cd_attention_mid: bool = False, + multiview_attention: bool = True, + sparse_mv_attention: bool = False, + mvcd_attention: bool=False +): + # If attn head dim is not defined, we default it to the number of heads + if attention_head_dim is None: + logger.warn( + f"It is recommended to provide `attention_head_dim` when calling `get_down_block`. Defaulting `attention_head_dim` to {num_attention_heads}." + ) + attention_head_dim = num_attention_heads + + down_block_type = down_block_type[7:] if down_block_type.startswith("UNetRes") else down_block_type + if down_block_type == "DownBlock2D": + return DownBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + downsample_padding=downsample_padding, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + elif down_block_type == "ResnetDownsampleBlock2D": + return ResnetDownsampleBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + resnet_time_scale_shift=resnet_time_scale_shift, + skip_time_act=resnet_skip_time_act, + output_scale_factor=resnet_out_scale_factor, + ) + elif down_block_type == "AttnDownBlock2D": + if add_downsample is False: + downsample_type = None + else: + downsample_type = downsample_type or "conv" # default to 'conv' + return AttnDownBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + downsample_padding=downsample_padding, + attention_head_dim=attention_head_dim, + resnet_time_scale_shift=resnet_time_scale_shift, + downsample_type=downsample_type, + ) + elif down_block_type == "CrossAttnDownBlock2D": + if cross_attention_dim is None: + raise ValueError("cross_attention_dim must be specified for CrossAttnDownBlock2D") + return CrossAttnDownBlock2D( + num_layers=num_layers, + transformer_layers_per_block=transformer_layers_per_block, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + downsample_padding=downsample_padding, + cross_attention_dim=cross_attention_dim, + num_attention_heads=num_attention_heads, + dual_cross_attention=dual_cross_attention, + use_linear_projection=use_linear_projection, + only_cross_attention=only_cross_attention, + upcast_attention=upcast_attention, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + # custom MV2D attention block + elif down_block_type == "CrossAttnDownBlockMV2D": + if cross_attention_dim is None: + raise ValueError("cross_attention_dim must be specified for CrossAttnDownBlockMV2D") + return CrossAttnDownBlockMV2D( + num_layers=num_layers, + transformer_layers_per_block=transformer_layers_per_block, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + downsample_padding=downsample_padding, + cross_attention_dim=cross_attention_dim, + num_attention_heads=num_attention_heads, + dual_cross_attention=dual_cross_attention, + use_linear_projection=use_linear_projection, + only_cross_attention=only_cross_attention, + upcast_attention=upcast_attention, + resnet_time_scale_shift=resnet_time_scale_shift, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + elif down_block_type == "SimpleCrossAttnDownBlock2D": + if cross_attention_dim is None: + raise ValueError("cross_attention_dim must be specified for SimpleCrossAttnDownBlock2D") + return SimpleCrossAttnDownBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + cross_attention_dim=cross_attention_dim, + attention_head_dim=attention_head_dim, + resnet_time_scale_shift=resnet_time_scale_shift, + skip_time_act=resnet_skip_time_act, + output_scale_factor=resnet_out_scale_factor, + only_cross_attention=only_cross_attention, + cross_attention_norm=cross_attention_norm, + ) + elif down_block_type == "SkipDownBlock2D": + return SkipDownBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + downsample_padding=downsample_padding, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + elif down_block_type == "AttnSkipDownBlock2D": + return AttnSkipDownBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + attention_head_dim=attention_head_dim, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + elif down_block_type == "DownEncoderBlock2D": + return DownEncoderBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + downsample_padding=downsample_padding, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + elif down_block_type == "AttnDownEncoderBlock2D": + return AttnDownEncoderBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + downsample_padding=downsample_padding, + attention_head_dim=attention_head_dim, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + elif down_block_type == "KDownBlock2D": + return KDownBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + ) + elif down_block_type == "KCrossAttnDownBlock2D": + return KCrossAttnDownBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_downsample=add_downsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + cross_attention_dim=cross_attention_dim, + attention_head_dim=attention_head_dim, + add_self_attention=True if not add_downsample else False, + ) + raise ValueError(f"{down_block_type} does not exist.") + + +def get_up_block( + up_block_type, + num_layers, + in_channels, + out_channels, + prev_output_channel, + temb_channels, + add_upsample, + resnet_eps, + resnet_act_fn, + transformer_layers_per_block=1, + num_attention_heads=None, + resnet_groups=None, + cross_attention_dim=None, + dual_cross_attention=False, + use_linear_projection=False, + only_cross_attention=False, + upcast_attention=False, + resnet_time_scale_shift="default", + resnet_skip_time_act=False, + resnet_out_scale_factor=1.0, + cross_attention_norm=None, + attention_head_dim=None, + upsample_type=None, + num_views=1, + cd_attention_last: bool = False, + cd_attention_mid: bool = False, + multiview_attention: bool = True, + sparse_mv_attention: bool = False, + mvcd_attention: bool=False +): + # If attn head dim is not defined, we default it to the number of heads + if attention_head_dim is None: + logger.warn( + f"It is recommended to provide `attention_head_dim` when calling `get_up_block`. Defaulting `attention_head_dim` to {num_attention_heads}." + ) + attention_head_dim = num_attention_heads + + up_block_type = up_block_type[7:] if up_block_type.startswith("UNetRes") else up_block_type + if up_block_type == "UpBlock2D": + return UpBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + prev_output_channel=prev_output_channel, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + elif up_block_type == "ResnetUpsampleBlock2D": + return ResnetUpsampleBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + prev_output_channel=prev_output_channel, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + resnet_time_scale_shift=resnet_time_scale_shift, + skip_time_act=resnet_skip_time_act, + output_scale_factor=resnet_out_scale_factor, + ) + elif up_block_type == "CrossAttnUpBlock2D": + if cross_attention_dim is None: + raise ValueError("cross_attention_dim must be specified for CrossAttnUpBlock2D") + return CrossAttnUpBlock2D( + num_layers=num_layers, + transformer_layers_per_block=transformer_layers_per_block, + in_channels=in_channels, + out_channels=out_channels, + prev_output_channel=prev_output_channel, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + cross_attention_dim=cross_attention_dim, + num_attention_heads=num_attention_heads, + dual_cross_attention=dual_cross_attention, + use_linear_projection=use_linear_projection, + only_cross_attention=only_cross_attention, + upcast_attention=upcast_attention, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + # custom MV2D attention block + elif up_block_type == "CrossAttnUpBlockMV2D": + if cross_attention_dim is None: + raise ValueError("cross_attention_dim must be specified for CrossAttnUpBlockMV2D") + return CrossAttnUpBlockMV2D( + num_layers=num_layers, + transformer_layers_per_block=transformer_layers_per_block, + in_channels=in_channels, + out_channels=out_channels, + prev_output_channel=prev_output_channel, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + cross_attention_dim=cross_attention_dim, + num_attention_heads=num_attention_heads, + dual_cross_attention=dual_cross_attention, + use_linear_projection=use_linear_projection, + only_cross_attention=only_cross_attention, + upcast_attention=upcast_attention, + resnet_time_scale_shift=resnet_time_scale_shift, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + elif up_block_type == "SimpleCrossAttnUpBlock2D": + if cross_attention_dim is None: + raise ValueError("cross_attention_dim must be specified for SimpleCrossAttnUpBlock2D") + return SimpleCrossAttnUpBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + prev_output_channel=prev_output_channel, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + cross_attention_dim=cross_attention_dim, + attention_head_dim=attention_head_dim, + resnet_time_scale_shift=resnet_time_scale_shift, + skip_time_act=resnet_skip_time_act, + output_scale_factor=resnet_out_scale_factor, + only_cross_attention=only_cross_attention, + cross_attention_norm=cross_attention_norm, + ) + elif up_block_type == "AttnUpBlock2D": + if add_upsample is False: + upsample_type = None + else: + upsample_type = upsample_type or "conv" # default to 'conv' + + return AttnUpBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + prev_output_channel=prev_output_channel, + temb_channels=temb_channels, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + attention_head_dim=attention_head_dim, + resnet_time_scale_shift=resnet_time_scale_shift, + upsample_type=upsample_type, + ) + elif up_block_type == "SkipUpBlock2D": + return SkipUpBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + prev_output_channel=prev_output_channel, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + elif up_block_type == "AttnSkipUpBlock2D": + return AttnSkipUpBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + prev_output_channel=prev_output_channel, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + attention_head_dim=attention_head_dim, + resnet_time_scale_shift=resnet_time_scale_shift, + ) + elif up_block_type == "UpDecoderBlock2D": + return UpDecoderBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + resnet_time_scale_shift=resnet_time_scale_shift, + temb_channels=temb_channels, + ) + elif up_block_type == "AttnUpDecoderBlock2D": + return AttnUpDecoderBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + resnet_groups=resnet_groups, + attention_head_dim=attention_head_dim, + resnet_time_scale_shift=resnet_time_scale_shift, + temb_channels=temb_channels, + ) + elif up_block_type == "KUpBlock2D": + return KUpBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + ) + elif up_block_type == "KCrossAttnUpBlock2D": + return KCrossAttnUpBlock2D( + num_layers=num_layers, + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + add_upsample=add_upsample, + resnet_eps=resnet_eps, + resnet_act_fn=resnet_act_fn, + cross_attention_dim=cross_attention_dim, + attention_head_dim=attention_head_dim, + ) + + raise ValueError(f"{up_block_type} does not exist.") + + +class UNetMidBlockMV2DCrossAttn(nn.Module): + def __init__( + self, + in_channels: int, + temb_channels: int, + dropout: float = 0.0, + num_layers: int = 1, + transformer_layers_per_block: int = 1, + resnet_eps: float = 1e-6, + resnet_time_scale_shift: str = "default", + resnet_act_fn: str = "swish", + resnet_groups: int = 32, + resnet_pre_norm: bool = True, + num_attention_heads=1, + output_scale_factor=1.0, + cross_attention_dim=1280, + dual_cross_attention=False, + use_linear_projection=False, + upcast_attention=False, + num_views: int = 1, + cd_attention_last: bool = False, + cd_attention_mid: bool = False, + multiview_attention: bool = True, + sparse_mv_attention: bool = False, + mvcd_attention: bool=False + ): + super().__init__() + + self.has_cross_attention = True + self.num_attention_heads = num_attention_heads + resnet_groups = resnet_groups if resnet_groups is not None else min(in_channels // 4, 32) + + # there is always at least one resnet + resnets = [ + ResnetBlock2D( + in_channels=in_channels, + out_channels=in_channels, + temb_channels=temb_channels, + eps=resnet_eps, + groups=resnet_groups, + dropout=dropout, + time_embedding_norm=resnet_time_scale_shift, + non_linearity=resnet_act_fn, + output_scale_factor=output_scale_factor, + pre_norm=resnet_pre_norm, + ) + ] + attentions = [] + + for _ in range(num_layers): + if not dual_cross_attention: + attentions.append( + TransformerMV2DModel( + num_attention_heads, + in_channels // num_attention_heads, + in_channels=in_channels, + num_layers=transformer_layers_per_block, + cross_attention_dim=cross_attention_dim, + norm_num_groups=resnet_groups, + use_linear_projection=use_linear_projection, + upcast_attention=upcast_attention, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + ) + else: + raise NotImplementedError + resnets.append( + ResnetBlock2D( + in_channels=in_channels, + out_channels=in_channels, + temb_channels=temb_channels, + eps=resnet_eps, + groups=resnet_groups, + dropout=dropout, + time_embedding_norm=resnet_time_scale_shift, + non_linearity=resnet_act_fn, + output_scale_factor=output_scale_factor, + pre_norm=resnet_pre_norm, + ) + ) + + self.attentions = nn.ModuleList(attentions) + self.resnets = nn.ModuleList(resnets) + + def forward( + self, + hidden_states: torch.FloatTensor, + temb: Optional[torch.FloatTensor] = None, + encoder_hidden_states: Optional[torch.FloatTensor] = None, + attention_mask: Optional[torch.FloatTensor] = None, + cross_attention_kwargs: Optional[Dict[str, Any]] = None, + encoder_attention_mask: Optional[torch.FloatTensor] = None, + ) -> torch.FloatTensor: + hidden_states = self.resnets[0](hidden_states, temb) + for attn, resnet in zip(self.attentions, self.resnets[1:]): + hidden_states = attn( + hidden_states, + encoder_hidden_states=encoder_hidden_states, + cross_attention_kwargs=cross_attention_kwargs, + attention_mask=attention_mask, + encoder_attention_mask=encoder_attention_mask, + return_dict=False, + )[0] + hidden_states = resnet(hidden_states, temb) + + return hidden_states + + +class CrossAttnUpBlockMV2D(nn.Module): + def __init__( + self, + in_channels: int, + out_channels: int, + prev_output_channel: int, + temb_channels: int, + dropout: float = 0.0, + num_layers: int = 1, + transformer_layers_per_block: int = 1, + resnet_eps: float = 1e-6, + resnet_time_scale_shift: str = "default", + resnet_act_fn: str = "swish", + resnet_groups: int = 32, + resnet_pre_norm: bool = True, + num_attention_heads=1, + cross_attention_dim=1280, + output_scale_factor=1.0, + add_upsample=True, + dual_cross_attention=False, + use_linear_projection=False, + only_cross_attention=False, + upcast_attention=False, + num_views: int = 1, + cd_attention_last: bool = False, + cd_attention_mid: bool = False, + multiview_attention: bool = True, + sparse_mv_attention: bool = False, + mvcd_attention: bool=False + ): + super().__init__() + resnets = [] + attentions = [] + + self.has_cross_attention = True + self.num_attention_heads = num_attention_heads + + for i in range(num_layers): + res_skip_channels = in_channels if (i == num_layers - 1) else out_channels + resnet_in_channels = prev_output_channel if i == 0 else out_channels + + resnets.append( + ResnetBlock2D( + in_channels=resnet_in_channels + res_skip_channels, + out_channels=out_channels, + temb_channels=temb_channels, + eps=resnet_eps, + groups=resnet_groups, + dropout=dropout, + time_embedding_norm=resnet_time_scale_shift, + non_linearity=resnet_act_fn, + output_scale_factor=output_scale_factor, + pre_norm=resnet_pre_norm, + ) + ) + if not dual_cross_attention: + attentions.append( + TransformerMV2DModel( + num_attention_heads, + out_channels // num_attention_heads, + in_channels=out_channels, + num_layers=transformer_layers_per_block, + cross_attention_dim=cross_attention_dim, + norm_num_groups=resnet_groups, + use_linear_projection=use_linear_projection, + only_cross_attention=only_cross_attention, + upcast_attention=upcast_attention, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + ) + else: + raise NotImplementedError + self.attentions = nn.ModuleList(attentions) + self.resnets = nn.ModuleList(resnets) + + if add_upsample: + self.upsamplers = nn.ModuleList([Upsample2D(out_channels, use_conv=True, out_channels=out_channels)]) + else: + self.upsamplers = None + + self.gradient_checkpointing = False + + def forward( + self, + hidden_states: torch.FloatTensor, + res_hidden_states_tuple: Tuple[torch.FloatTensor, ...], + temb: Optional[torch.FloatTensor] = None, + encoder_hidden_states: Optional[torch.FloatTensor] = None, + cross_attention_kwargs: Optional[Dict[str, Any]] = None, + upsample_size: Optional[int] = None, + attention_mask: Optional[torch.FloatTensor] = None, + encoder_attention_mask: Optional[torch.FloatTensor] = None, + ): + for resnet, attn in zip(self.resnets, self.attentions): + # pop res hidden states + res_hidden_states = res_hidden_states_tuple[-1] + res_hidden_states_tuple = res_hidden_states_tuple[:-1] + hidden_states = torch.cat([hidden_states, res_hidden_states], dim=1) + + if self.training and self.gradient_checkpointing: + + def create_custom_forward(module, return_dict=None): + def custom_forward(*inputs): + if return_dict is not None: + return module(*inputs, return_dict=return_dict) + else: + return module(*inputs) + + return custom_forward + + ckpt_kwargs: Dict[str, Any] = {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {} + hidden_states = torch.utils.checkpoint.checkpoint( + create_custom_forward(resnet), + hidden_states, + temb, + **ckpt_kwargs, + ) + hidden_states = torch.utils.checkpoint.checkpoint( + create_custom_forward(attn, return_dict=False), + hidden_states, + encoder_hidden_states, + None, # timestep + None, # class_labels + cross_attention_kwargs, + attention_mask, + encoder_attention_mask, + **ckpt_kwargs, + )[0] + else: + hidden_states = resnet(hidden_states, temb) + hidden_states = attn( + hidden_states, + encoder_hidden_states=encoder_hidden_states, + cross_attention_kwargs=cross_attention_kwargs, + attention_mask=attention_mask, + encoder_attention_mask=encoder_attention_mask, + return_dict=False, + )[0] + + if self.upsamplers is not None: + for upsampler in self.upsamplers: + hidden_states = upsampler(hidden_states, upsample_size) + + return hidden_states + + +class CrossAttnDownBlockMV2D(nn.Module): + def __init__( + self, + in_channels: int, + out_channels: int, + temb_channels: int, + dropout: float = 0.0, + num_layers: int = 1, + transformer_layers_per_block: int = 1, + resnet_eps: float = 1e-6, + resnet_time_scale_shift: str = "default", + resnet_act_fn: str = "swish", + resnet_groups: int = 32, + resnet_pre_norm: bool = True, + num_attention_heads=1, + cross_attention_dim=1280, + output_scale_factor=1.0, + downsample_padding=1, + add_downsample=True, + dual_cross_attention=False, + use_linear_projection=False, + only_cross_attention=False, + upcast_attention=False, + num_views: int = 1, + cd_attention_last: bool = False, + cd_attention_mid: bool = False, + multiview_attention: bool = True, + sparse_mv_attention: bool = False, + mvcd_attention: bool=False + ): + super().__init__() + resnets = [] + attentions = [] + + self.has_cross_attention = True + self.num_attention_heads = num_attention_heads + + for i in range(num_layers): + in_channels = in_channels if i == 0 else out_channels + resnets.append( + ResnetBlock2D( + in_channels=in_channels, + out_channels=out_channels, + temb_channels=temb_channels, + eps=resnet_eps, + groups=resnet_groups, + dropout=dropout, + time_embedding_norm=resnet_time_scale_shift, + non_linearity=resnet_act_fn, + output_scale_factor=output_scale_factor, + pre_norm=resnet_pre_norm, + ) + ) + if not dual_cross_attention: + attentions.append( + TransformerMV2DModel( + num_attention_heads, + out_channels // num_attention_heads, + in_channels=out_channels, + num_layers=transformer_layers_per_block, + cross_attention_dim=cross_attention_dim, + norm_num_groups=resnet_groups, + use_linear_projection=use_linear_projection, + only_cross_attention=only_cross_attention, + upcast_attention=upcast_attention, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + ) + else: + raise NotImplementedError + self.attentions = nn.ModuleList(attentions) + self.resnets = nn.ModuleList(resnets) + + if add_downsample: + self.downsamplers = nn.ModuleList( + [ + Downsample2D( + out_channels, use_conv=True, out_channels=out_channels, padding=downsample_padding, name="op" + ) + ] + ) + else: + self.downsamplers = None + + self.gradient_checkpointing = False + + def forward( + self, + hidden_states: torch.FloatTensor, + temb: Optional[torch.FloatTensor] = None, + encoder_hidden_states: Optional[torch.FloatTensor] = None, + attention_mask: Optional[torch.FloatTensor] = None, + cross_attention_kwargs: Optional[Dict[str, Any]] = None, + encoder_attention_mask: Optional[torch.FloatTensor] = None, + additional_residuals=None, + ): + output_states = () + + blocks = list(zip(self.resnets, self.attentions)) + + for i, (resnet, attn) in enumerate(blocks): + if self.training and self.gradient_checkpointing: + + def create_custom_forward(module, return_dict=None): + def custom_forward(*inputs): + if return_dict is not None: + return module(*inputs, return_dict=return_dict) + else: + return module(*inputs) + + return custom_forward + + ckpt_kwargs: Dict[str, Any] = {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {} + hidden_states = torch.utils.checkpoint.checkpoint( + create_custom_forward(resnet), + hidden_states, + temb, + **ckpt_kwargs, + ) + hidden_states = torch.utils.checkpoint.checkpoint( + create_custom_forward(attn, return_dict=False), + hidden_states, + encoder_hidden_states, + None, # timestep + None, # class_labels + cross_attention_kwargs, + attention_mask, + encoder_attention_mask, + **ckpt_kwargs, + )[0] + else: + hidden_states = resnet(hidden_states, temb) + hidden_states = attn( + hidden_states, + encoder_hidden_states=encoder_hidden_states, + cross_attention_kwargs=cross_attention_kwargs, + attention_mask=attention_mask, + encoder_attention_mask=encoder_attention_mask, + return_dict=False, + )[0] + + # apply additional residuals to the output of the last pair of resnet and attention blocks + if i == len(blocks) - 1 and additional_residuals is not None: + hidden_states = hidden_states + additional_residuals + + output_states = output_states + (hidden_states,) + + if self.downsamplers is not None: + for downsampler in self.downsamplers: + hidden_states = downsampler(hidden_states) + + output_states = output_states + (hidden_states,) + + return hidden_states, output_states + diff --git a/apps/third_party/Wonder3D/mvdiffusion/models/unet_mv2d_condition.py b/apps/third_party/Wonder3D/mvdiffusion/models/unet_mv2d_condition.py new file mode 100644 index 0000000000000000000000000000000000000000..f1da502f37d4d7afce6593e348abd77f49e9fd9d --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/models/unet_mv2d_condition.py @@ -0,0 +1,1492 @@ +# Copyright 2023 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from dataclasses import dataclass +from typing import Any, Dict, List, Optional, Tuple, Union +import os + +import torch +import torch.nn as nn +import torch.utils.checkpoint + +from diffusers.configuration_utils import ConfigMixin, register_to_config +from diffusers.loaders import UNet2DConditionLoadersMixin +from diffusers.utils import BaseOutput, logging +from diffusers.models.activations import get_activation +from diffusers.models.attention_processor import AttentionProcessor, AttnProcessor +from diffusers.models.embeddings import ( + GaussianFourierProjection, + ImageHintTimeEmbedding, + ImageProjection, + ImageTimeEmbedding, + TextImageProjection, + TextImageTimeEmbedding, + TextTimeEmbedding, + TimestepEmbedding, + Timesteps, +) +from diffusers.models.modeling_utils import ModelMixin, load_state_dict, _load_state_dict_into_model +from diffusers.models.unet_2d_blocks import ( + CrossAttnDownBlock2D, + CrossAttnUpBlock2D, + DownBlock2D, + UNetMidBlock2DCrossAttn, + UNetMidBlock2DSimpleCrossAttn, + UpBlock2D, +) +from diffusers.utils import ( + CONFIG_NAME, + DIFFUSERS_CACHE, + FLAX_WEIGHTS_NAME, + HF_HUB_OFFLINE, + SAFETENSORS_WEIGHTS_NAME, + WEIGHTS_NAME, + _add_variant, + _get_model_file, + deprecate, + is_accelerate_available, + is_safetensors_available, + is_torch_version, + logging, +) +from diffusers import __version__ +from mvdiffusion.models.unet_mv2d_blocks import ( + CrossAttnDownBlockMV2D, + CrossAttnUpBlockMV2D, + UNetMidBlockMV2DCrossAttn, + get_down_block, + get_up_block, +) + + +logger = logging.get_logger(__name__) # pylint: disable=invalid-name + + +@dataclass +class UNetMV2DConditionOutput(BaseOutput): + """ + The output of [`UNet2DConditionModel`]. + + Args: + sample (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`): + The hidden states output conditioned on `encoder_hidden_states` input. Output of last layer of model. + """ + + sample: torch.FloatTensor = None + + +class UNetMV2DConditionModel(ModelMixin, ConfigMixin, UNet2DConditionLoadersMixin): + r""" + A conditional 2D UNet model that takes a noisy sample, conditional state, and a timestep and returns a sample + shaped output. + + This model inherits from [`ModelMixin`]. Check the superclass documentation for it's generic methods implemented + for all models (such as downloading or saving). + + Parameters: + sample_size (`int` or `Tuple[int, int]`, *optional*, defaults to `None`): + Height and width of input/output sample. + in_channels (`int`, *optional*, defaults to 4): Number of channels in the input sample. + out_channels (`int`, *optional*, defaults to 4): Number of channels in the output. + center_input_sample (`bool`, *optional*, defaults to `False`): Whether to center the input sample. + flip_sin_to_cos (`bool`, *optional*, defaults to `False`): + Whether to flip the sin to cos in the time embedding. + freq_shift (`int`, *optional*, defaults to 0): The frequency shift to apply to the time embedding. + down_block_types (`Tuple[str]`, *optional*, defaults to `("CrossAttnDownBlock2D", "CrossAttnDownBlock2D", "CrossAttnDownBlock2D", "DownBlock2D")`): + The tuple of downsample blocks to use. + mid_block_type (`str`, *optional*, defaults to `"UNetMidBlock2DCrossAttn"`): + Block type for middle of UNet, it can be either `UNetMidBlock2DCrossAttn` or + `UNetMidBlock2DSimpleCrossAttn`. If `None`, the mid block layer is skipped. + up_block_types (`Tuple[str]`, *optional*, defaults to `("UpBlock2D", "CrossAttnUpBlock2D", "CrossAttnUpBlock2D", "CrossAttnUpBlock2D")`): + The tuple of upsample blocks to use. + only_cross_attention(`bool` or `Tuple[bool]`, *optional*, default to `False`): + Whether to include self-attention in the basic transformer blocks, see + [`~models.attention.BasicTransformerBlock`]. + block_out_channels (`Tuple[int]`, *optional*, defaults to `(320, 640, 1280, 1280)`): + The tuple of output channels for each block. + layers_per_block (`int`, *optional*, defaults to 2): The number of layers per block. + downsample_padding (`int`, *optional*, defaults to 1): The padding to use for the downsampling convolution. + mid_block_scale_factor (`float`, *optional*, defaults to 1.0): The scale factor to use for the mid block. + act_fn (`str`, *optional*, defaults to `"silu"`): The activation function to use. + norm_num_groups (`int`, *optional*, defaults to 32): The number of groups to use for the normalization. + If `None`, normalization and activation layers is skipped in post-processing. + norm_eps (`float`, *optional*, defaults to 1e-5): The epsilon to use for the normalization. + cross_attention_dim (`int` or `Tuple[int]`, *optional*, defaults to 1280): + The dimension of the cross attention features. + transformer_layers_per_block (`int` or `Tuple[int]`, *optional*, defaults to 1): + The number of transformer blocks of type [`~models.attention.BasicTransformerBlock`]. Only relevant for + [`~models.unet_2d_blocks.CrossAttnDownBlock2D`], [`~models.unet_2d_blocks.CrossAttnUpBlock2D`], + [`~models.unet_2d_blocks.UNetMidBlock2DCrossAttn`]. + encoder_hid_dim (`int`, *optional*, defaults to None): + If `encoder_hid_dim_type` is defined, `encoder_hidden_states` will be projected from `encoder_hid_dim` + dimension to `cross_attention_dim`. + encoder_hid_dim_type (`str`, *optional*, defaults to `None`): + If given, the `encoder_hidden_states` and potentially other embeddings are down-projected to text + embeddings of dimension `cross_attention` according to `encoder_hid_dim_type`. + attention_head_dim (`int`, *optional*, defaults to 8): The dimension of the attention heads. + num_attention_heads (`int`, *optional*): + The number of attention heads. If not defined, defaults to `attention_head_dim` + resnet_time_scale_shift (`str`, *optional*, defaults to `"default"`): Time scale shift config + for ResNet blocks (see [`~models.resnet.ResnetBlock2D`]). Choose from `default` or `scale_shift`. + class_embed_type (`str`, *optional*, defaults to `None`): + The type of class embedding to use which is ultimately summed with the time embeddings. Choose from `None`, + `"timestep"`, `"identity"`, `"projection"`, or `"simple_projection"`. + addition_embed_type (`str`, *optional*, defaults to `None`): + Configures an optional embedding which will be summed with the time embeddings. Choose from `None` or + "text". "text" will use the `TextTimeEmbedding` layer. + addition_time_embed_dim: (`int`, *optional*, defaults to `None`): + Dimension for the timestep embeddings. + num_class_embeds (`int`, *optional*, defaults to `None`): + Input dimension of the learnable embedding matrix to be projected to `time_embed_dim`, when performing + class conditioning with `class_embed_type` equal to `None`. + time_embedding_type (`str`, *optional*, defaults to `positional`): + The type of position embedding to use for timesteps. Choose from `positional` or `fourier`. + time_embedding_dim (`int`, *optional*, defaults to `None`): + An optional override for the dimension of the projected time embedding. + time_embedding_act_fn (`str`, *optional*, defaults to `None`): + Optional activation function to use only once on the time embeddings before they are passed to the rest of + the UNet. Choose from `silu`, `mish`, `gelu`, and `swish`. + timestep_post_act (`str`, *optional*, defaults to `None`): + The second activation function to use in timestep embedding. Choose from `silu`, `mish` and `gelu`. + time_cond_proj_dim (`int`, *optional*, defaults to `None`): + The dimension of `cond_proj` layer in the timestep embedding. + conv_in_kernel (`int`, *optional*, default to `3`): The kernel size of `conv_in` layer. + conv_out_kernel (`int`, *optional*, default to `3`): The kernel size of `conv_out` layer. + projection_class_embeddings_input_dim (`int`, *optional*): The dimension of the `class_labels` input when + `class_embed_type="projection"`. Required when `class_embed_type="projection"`. + class_embeddings_concat (`bool`, *optional*, defaults to `False`): Whether to concatenate the time + embeddings with the class embeddings. + mid_block_only_cross_attention (`bool`, *optional*, defaults to `None`): + Whether to use cross attention with the mid block when using the `UNetMidBlock2DSimpleCrossAttn`. If + `only_cross_attention` is given as a single boolean and `mid_block_only_cross_attention` is `None`, the + `only_cross_attention` value is used as the value for `mid_block_only_cross_attention`. Default to `False` + otherwise. + """ + + _supports_gradient_checkpointing = True + + @register_to_config + def __init__( + self, + sample_size: Optional[int] = None, + in_channels: int = 4, + out_channels: int = 4, + center_input_sample: bool = False, + flip_sin_to_cos: bool = True, + freq_shift: int = 0, + down_block_types: Tuple[str] = ( + "CrossAttnDownBlockMV2D", + "CrossAttnDownBlockMV2D", + "CrossAttnDownBlockMV2D", + "DownBlock2D", + ), + mid_block_type: Optional[str] = "UNetMidBlockMV2DCrossAttn", + up_block_types: Tuple[str] = ("UpBlock2D", "CrossAttnUpBlockMV2D", "CrossAttnUpBlockMV2D", "CrossAttnUpBlockMV2D"), + only_cross_attention: Union[bool, Tuple[bool]] = False, + block_out_channels: Tuple[int] = (320, 640, 1280, 1280), + layers_per_block: Union[int, Tuple[int]] = 2, + downsample_padding: int = 1, + mid_block_scale_factor: float = 1, + act_fn: str = "silu", + norm_num_groups: Optional[int] = 32, + norm_eps: float = 1e-5, + cross_attention_dim: Union[int, Tuple[int]] = 1280, + transformer_layers_per_block: Union[int, Tuple[int]] = 1, + encoder_hid_dim: Optional[int] = None, + encoder_hid_dim_type: Optional[str] = None, + attention_head_dim: Union[int, Tuple[int]] = 8, + num_attention_heads: Optional[Union[int, Tuple[int]]] = None, + dual_cross_attention: bool = False, + use_linear_projection: bool = False, + class_embed_type: Optional[str] = None, + addition_embed_type: Optional[str] = None, + addition_time_embed_dim: Optional[int] = None, + num_class_embeds: Optional[int] = None, + upcast_attention: bool = False, + resnet_time_scale_shift: str = "default", + resnet_skip_time_act: bool = False, + resnet_out_scale_factor: int = 1.0, + time_embedding_type: str = "positional", + time_embedding_dim: Optional[int] = None, + time_embedding_act_fn: Optional[str] = None, + timestep_post_act: Optional[str] = None, + time_cond_proj_dim: Optional[int] = None, + conv_in_kernel: int = 3, + conv_out_kernel: int = 3, + projection_class_embeddings_input_dim: Optional[int] = None, + class_embeddings_concat: bool = False, + mid_block_only_cross_attention: Optional[bool] = None, + cross_attention_norm: Optional[str] = None, + addition_embed_type_num_heads=64, + num_views: int = 1, + cd_attention_last: bool = False, + cd_attention_mid: bool = False, + multiview_attention: bool = True, + sparse_mv_attention: bool = False, + mvcd_attention: bool = False + ): + super().__init__() + + self.sample_size = sample_size + + if num_attention_heads is not None: + raise ValueError( + "At the moment it is not possible to define the number of attention heads via `num_attention_heads` because of a naming issue as described in https://github.com/huggingface/diffusers/issues/2011#issuecomment-1547958131. Passing `num_attention_heads` will only be supported in diffusers v0.19." + ) + + # If `num_attention_heads` is not defined (which is the case for most models) + # it will default to `attention_head_dim`. This looks weird upon first reading it and it is. + # The reason for this behavior is to correct for incorrectly named variables that were introduced + # when this library was created. The incorrect naming was only discovered much later in https://github.com/huggingface/diffusers/issues/2011#issuecomment-1547958131 + # Changing `attention_head_dim` to `num_attention_heads` for 40,000+ configurations is too backwards breaking + # which is why we correct for the naming here. + num_attention_heads = num_attention_heads or attention_head_dim + + # Check inputs + if len(down_block_types) != len(up_block_types): + raise ValueError( + f"Must provide the same number of `down_block_types` as `up_block_types`. `down_block_types`: {down_block_types}. `up_block_types`: {up_block_types}." + ) + + if len(block_out_channels) != len(down_block_types): + raise ValueError( + f"Must provide the same number of `block_out_channels` as `down_block_types`. `block_out_channels`: {block_out_channels}. `down_block_types`: {down_block_types}." + ) + + if not isinstance(only_cross_attention, bool) and len(only_cross_attention) != len(down_block_types): + raise ValueError( + f"Must provide the same number of `only_cross_attention` as `down_block_types`. `only_cross_attention`: {only_cross_attention}. `down_block_types`: {down_block_types}." + ) + + if not isinstance(num_attention_heads, int) and len(num_attention_heads) != len(down_block_types): + raise ValueError( + f"Must provide the same number of `num_attention_heads` as `down_block_types`. `num_attention_heads`: {num_attention_heads}. `down_block_types`: {down_block_types}." + ) + + if not isinstance(attention_head_dim, int) and len(attention_head_dim) != len(down_block_types): + raise ValueError( + f"Must provide the same number of `attention_head_dim` as `down_block_types`. `attention_head_dim`: {attention_head_dim}. `down_block_types`: {down_block_types}." + ) + + if isinstance(cross_attention_dim, list) and len(cross_attention_dim) != len(down_block_types): + raise ValueError( + f"Must provide the same number of `cross_attention_dim` as `down_block_types`. `cross_attention_dim`: {cross_attention_dim}. `down_block_types`: {down_block_types}." + ) + + if not isinstance(layers_per_block, int) and len(layers_per_block) != len(down_block_types): + raise ValueError( + f"Must provide the same number of `layers_per_block` as `down_block_types`. `layers_per_block`: {layers_per_block}. `down_block_types`: {down_block_types}." + ) + + # input + conv_in_padding = (conv_in_kernel - 1) // 2 + self.conv_in = nn.Conv2d( + in_channels, block_out_channels[0], kernel_size=conv_in_kernel, padding=conv_in_padding + ) + + # time + if time_embedding_type == "fourier": + time_embed_dim = time_embedding_dim or block_out_channels[0] * 2 + if time_embed_dim % 2 != 0: + raise ValueError(f"`time_embed_dim` should be divisible by 2, but is {time_embed_dim}.") + self.time_proj = GaussianFourierProjection( + time_embed_dim // 2, set_W_to_weight=False, log=False, flip_sin_to_cos=flip_sin_to_cos + ) + timestep_input_dim = time_embed_dim + elif time_embedding_type == "positional": + time_embed_dim = time_embedding_dim or block_out_channels[0] * 4 + + self.time_proj = Timesteps(block_out_channels[0], flip_sin_to_cos, freq_shift) + timestep_input_dim = block_out_channels[0] + else: + raise ValueError( + f"{time_embedding_type} does not exist. Please make sure to use one of `fourier` or `positional`." + ) + + self.time_embedding = TimestepEmbedding( + timestep_input_dim, + time_embed_dim, + act_fn=act_fn, + post_act_fn=timestep_post_act, + cond_proj_dim=time_cond_proj_dim, + ) + + if encoder_hid_dim_type is None and encoder_hid_dim is not None: + encoder_hid_dim_type = "text_proj" + self.register_to_config(encoder_hid_dim_type=encoder_hid_dim_type) + logger.info("encoder_hid_dim_type defaults to 'text_proj' as `encoder_hid_dim` is defined.") + + if encoder_hid_dim is None and encoder_hid_dim_type is not None: + raise ValueError( + f"`encoder_hid_dim` has to be defined when `encoder_hid_dim_type` is set to {encoder_hid_dim_type}." + ) + + if encoder_hid_dim_type == "text_proj": + self.encoder_hid_proj = nn.Linear(encoder_hid_dim, cross_attention_dim) + elif encoder_hid_dim_type == "text_image_proj": + # image_embed_dim DOESN'T have to be `cross_attention_dim`. To not clutter the __init__ too much + # they are set to `cross_attention_dim` here as this is exactly the required dimension for the currently only use + # case when `addition_embed_type == "text_image_proj"` (Kadinsky 2.1)` + self.encoder_hid_proj = TextImageProjection( + text_embed_dim=encoder_hid_dim, + image_embed_dim=cross_attention_dim, + cross_attention_dim=cross_attention_dim, + ) + elif encoder_hid_dim_type == "image_proj": + # Kandinsky 2.2 + self.encoder_hid_proj = ImageProjection( + image_embed_dim=encoder_hid_dim, + cross_attention_dim=cross_attention_dim, + ) + elif encoder_hid_dim_type is not None: + raise ValueError( + f"encoder_hid_dim_type: {encoder_hid_dim_type} must be None, 'text_proj' or 'text_image_proj'." + ) + else: + self.encoder_hid_proj = None + + # class embedding + if class_embed_type is None and num_class_embeds is not None: + self.class_embedding = nn.Embedding(num_class_embeds, time_embed_dim) + elif class_embed_type == "timestep": + self.class_embedding = TimestepEmbedding(timestep_input_dim, time_embed_dim, act_fn=act_fn) + elif class_embed_type == "identity": + self.class_embedding = nn.Identity(time_embed_dim, time_embed_dim) + elif class_embed_type == "projection": + if projection_class_embeddings_input_dim is None: + raise ValueError( + "`class_embed_type`: 'projection' requires `projection_class_embeddings_input_dim` be set" + ) + # The projection `class_embed_type` is the same as the timestep `class_embed_type` except + # 1. the `class_labels` inputs are not first converted to sinusoidal embeddings + # 2. it projects from an arbitrary input dimension. + # + # Note that `TimestepEmbedding` is quite general, being mainly linear layers and activations. + # When used for embedding actual timesteps, the timesteps are first converted to sinusoidal embeddings. + # As a result, `TimestepEmbedding` can be passed arbitrary vectors. + self.class_embedding = TimestepEmbedding(projection_class_embeddings_input_dim, time_embed_dim) + elif class_embed_type == "simple_projection": + if projection_class_embeddings_input_dim is None: + raise ValueError( + "`class_embed_type`: 'simple_projection' requires `projection_class_embeddings_input_dim` be set" + ) + self.class_embedding = nn.Linear(projection_class_embeddings_input_dim, time_embed_dim) + else: + self.class_embedding = None + + if addition_embed_type == "text": + if encoder_hid_dim is not None: + text_time_embedding_from_dim = encoder_hid_dim + else: + text_time_embedding_from_dim = cross_attention_dim + + self.add_embedding = TextTimeEmbedding( + text_time_embedding_from_dim, time_embed_dim, num_heads=addition_embed_type_num_heads + ) + elif addition_embed_type == "text_image": + # text_embed_dim and image_embed_dim DON'T have to be `cross_attention_dim`. To not clutter the __init__ too much + # they are set to `cross_attention_dim` here as this is exactly the required dimension for the currently only use + # case when `addition_embed_type == "text_image"` (Kadinsky 2.1)` + self.add_embedding = TextImageTimeEmbedding( + text_embed_dim=cross_attention_dim, image_embed_dim=cross_attention_dim, time_embed_dim=time_embed_dim + ) + elif addition_embed_type == "text_time": + self.add_time_proj = Timesteps(addition_time_embed_dim, flip_sin_to_cos, freq_shift) + self.add_embedding = TimestepEmbedding(projection_class_embeddings_input_dim, time_embed_dim) + elif addition_embed_type == "image": + # Kandinsky 2.2 + self.add_embedding = ImageTimeEmbedding(image_embed_dim=encoder_hid_dim, time_embed_dim=time_embed_dim) + elif addition_embed_type == "image_hint": + # Kandinsky 2.2 ControlNet + self.add_embedding = ImageHintTimeEmbedding(image_embed_dim=encoder_hid_dim, time_embed_dim=time_embed_dim) + elif addition_embed_type is not None: + raise ValueError(f"addition_embed_type: {addition_embed_type} must be None, 'text' or 'text_image'.") + + if time_embedding_act_fn is None: + self.time_embed_act = None + else: + self.time_embed_act = get_activation(time_embedding_act_fn) + + self.down_blocks = nn.ModuleList([]) + self.up_blocks = nn.ModuleList([]) + + if isinstance(only_cross_attention, bool): + if mid_block_only_cross_attention is None: + mid_block_only_cross_attention = only_cross_attention + + only_cross_attention = [only_cross_attention] * len(down_block_types) + + if mid_block_only_cross_attention is None: + mid_block_only_cross_attention = False + + if isinstance(num_attention_heads, int): + num_attention_heads = (num_attention_heads,) * len(down_block_types) + + if isinstance(attention_head_dim, int): + attention_head_dim = (attention_head_dim,) * len(down_block_types) + + if isinstance(cross_attention_dim, int): + cross_attention_dim = (cross_attention_dim,) * len(down_block_types) + + if isinstance(layers_per_block, int): + layers_per_block = [layers_per_block] * len(down_block_types) + + if isinstance(transformer_layers_per_block, int): + transformer_layers_per_block = [transformer_layers_per_block] * len(down_block_types) + + if class_embeddings_concat: + # The time embeddings are concatenated with the class embeddings. The dimension of the + # time embeddings passed to the down, middle, and up blocks is twice the dimension of the + # regular time embeddings + blocks_time_embed_dim = time_embed_dim * 2 + else: + blocks_time_embed_dim = time_embed_dim + + # down + output_channel = block_out_channels[0] + for i, down_block_type in enumerate(down_block_types): + input_channel = output_channel + output_channel = block_out_channels[i] + is_final_block = i == len(block_out_channels) - 1 + + down_block = get_down_block( + down_block_type, + num_layers=layers_per_block[i], + transformer_layers_per_block=transformer_layers_per_block[i], + in_channels=input_channel, + out_channels=output_channel, + temb_channels=blocks_time_embed_dim, + add_downsample=not is_final_block, + resnet_eps=norm_eps, + resnet_act_fn=act_fn, + resnet_groups=norm_num_groups, + cross_attention_dim=cross_attention_dim[i], + num_attention_heads=num_attention_heads[i], + downsample_padding=downsample_padding, + dual_cross_attention=dual_cross_attention, + use_linear_projection=use_linear_projection, + only_cross_attention=only_cross_attention[i], + upcast_attention=upcast_attention, + resnet_time_scale_shift=resnet_time_scale_shift, + resnet_skip_time_act=resnet_skip_time_act, + resnet_out_scale_factor=resnet_out_scale_factor, + cross_attention_norm=cross_attention_norm, + attention_head_dim=attention_head_dim[i] if attention_head_dim[i] is not None else output_channel, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + self.down_blocks.append(down_block) + + # mid + if mid_block_type == "UNetMidBlock2DCrossAttn": + self.mid_block = UNetMidBlock2DCrossAttn( + transformer_layers_per_block=transformer_layers_per_block[-1], + in_channels=block_out_channels[-1], + temb_channels=blocks_time_embed_dim, + resnet_eps=norm_eps, + resnet_act_fn=act_fn, + output_scale_factor=mid_block_scale_factor, + resnet_time_scale_shift=resnet_time_scale_shift, + cross_attention_dim=cross_attention_dim[-1], + num_attention_heads=num_attention_heads[-1], + resnet_groups=norm_num_groups, + dual_cross_attention=dual_cross_attention, + use_linear_projection=use_linear_projection, + upcast_attention=upcast_attention, + ) + # custom MV2D attention block + elif mid_block_type == "UNetMidBlockMV2DCrossAttn": + self.mid_block = UNetMidBlockMV2DCrossAttn( + transformer_layers_per_block=transformer_layers_per_block[-1], + in_channels=block_out_channels[-1], + temb_channels=blocks_time_embed_dim, + resnet_eps=norm_eps, + resnet_act_fn=act_fn, + output_scale_factor=mid_block_scale_factor, + resnet_time_scale_shift=resnet_time_scale_shift, + cross_attention_dim=cross_attention_dim[-1], + num_attention_heads=num_attention_heads[-1], + resnet_groups=norm_num_groups, + dual_cross_attention=dual_cross_attention, + use_linear_projection=use_linear_projection, + upcast_attention=upcast_attention, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + elif mid_block_type == "UNetMidBlock2DSimpleCrossAttn": + self.mid_block = UNetMidBlock2DSimpleCrossAttn( + in_channels=block_out_channels[-1], + temb_channels=blocks_time_embed_dim, + resnet_eps=norm_eps, + resnet_act_fn=act_fn, + output_scale_factor=mid_block_scale_factor, + cross_attention_dim=cross_attention_dim[-1], + attention_head_dim=attention_head_dim[-1], + resnet_groups=norm_num_groups, + resnet_time_scale_shift=resnet_time_scale_shift, + skip_time_act=resnet_skip_time_act, + only_cross_attention=mid_block_only_cross_attention, + cross_attention_norm=cross_attention_norm, + ) + elif mid_block_type is None: + self.mid_block = None + else: + raise ValueError(f"unknown mid_block_type : {mid_block_type}") + + # count how many layers upsample the images + self.num_upsamplers = 0 + + # up + reversed_block_out_channels = list(reversed(block_out_channels)) + reversed_num_attention_heads = list(reversed(num_attention_heads)) + reversed_layers_per_block = list(reversed(layers_per_block)) + reversed_cross_attention_dim = list(reversed(cross_attention_dim)) + reversed_transformer_layers_per_block = list(reversed(transformer_layers_per_block)) + only_cross_attention = list(reversed(only_cross_attention)) + + output_channel = reversed_block_out_channels[0] + for i, up_block_type in enumerate(up_block_types): + is_final_block = i == len(block_out_channels) - 1 + + prev_output_channel = output_channel + output_channel = reversed_block_out_channels[i] + input_channel = reversed_block_out_channels[min(i + 1, len(block_out_channels) - 1)] + + # add upsample block for all BUT final layer + if not is_final_block: + add_upsample = True + self.num_upsamplers += 1 + else: + add_upsample = False + + up_block = get_up_block( + up_block_type, + num_layers=reversed_layers_per_block[i] + 1, + transformer_layers_per_block=reversed_transformer_layers_per_block[i], + in_channels=input_channel, + out_channels=output_channel, + prev_output_channel=prev_output_channel, + temb_channels=blocks_time_embed_dim, + add_upsample=add_upsample, + resnet_eps=norm_eps, + resnet_act_fn=act_fn, + resnet_groups=norm_num_groups, + cross_attention_dim=reversed_cross_attention_dim[i], + num_attention_heads=reversed_num_attention_heads[i], + dual_cross_attention=dual_cross_attention, + use_linear_projection=use_linear_projection, + only_cross_attention=only_cross_attention[i], + upcast_attention=upcast_attention, + resnet_time_scale_shift=resnet_time_scale_shift, + resnet_skip_time_act=resnet_skip_time_act, + resnet_out_scale_factor=resnet_out_scale_factor, + cross_attention_norm=cross_attention_norm, + attention_head_dim=attention_head_dim[i] if attention_head_dim[i] is not None else output_channel, + num_views=num_views, + cd_attention_last=cd_attention_last, + cd_attention_mid=cd_attention_mid, + multiview_attention=multiview_attention, + sparse_mv_attention=sparse_mv_attention, + mvcd_attention=mvcd_attention + ) + self.up_blocks.append(up_block) + prev_output_channel = output_channel + + # out + if norm_num_groups is not None: + self.conv_norm_out = nn.GroupNorm( + num_channels=block_out_channels[0], num_groups=norm_num_groups, eps=norm_eps + ) + + self.conv_act = get_activation(act_fn) + + else: + self.conv_norm_out = None + self.conv_act = None + + conv_out_padding = (conv_out_kernel - 1) // 2 + self.conv_out = nn.Conv2d( + block_out_channels[0], out_channels, kernel_size=conv_out_kernel, padding=conv_out_padding + ) + + @property + def attn_processors(self) -> Dict[str, AttentionProcessor]: + r""" + Returns: + `dict` of attention processors: A dictionary containing all attention processors used in the model with + indexed by its weight name. + """ + # set recursively + processors = {} + + def fn_recursive_add_processors(name: str, module: torch.nn.Module, processors: Dict[str, AttentionProcessor]): + if hasattr(module, "set_processor"): + processors[f"{name}.processor"] = module.processor + + for sub_name, child in module.named_children(): + fn_recursive_add_processors(f"{name}.{sub_name}", child, processors) + + return processors + + for name, module in self.named_children(): + fn_recursive_add_processors(name, module, processors) + + return processors + + def set_attn_processor(self, processor: Union[AttentionProcessor, Dict[str, AttentionProcessor]]): + r""" + Sets the attention processor to use to compute attention. + + Parameters: + processor (`dict` of `AttentionProcessor` or only `AttentionProcessor`): + The instantiated processor class or a dictionary of processor classes that will be set as the processor + for **all** `Attention` layers. + + If `processor` is a dict, the key needs to define the path to the corresponding cross attention + processor. This is strongly recommended when setting trainable attention processors. + + """ + count = len(self.attn_processors.keys()) + + if isinstance(processor, dict) and len(processor) != count: + raise ValueError( + f"A dict of processors was passed, but the number of processors {len(processor)} does not match the" + f" number of attention layers: {count}. Please make sure to pass {count} processor classes." + ) + + def fn_recursive_attn_processor(name: str, module: torch.nn.Module, processor): + if hasattr(module, "set_processor"): + if not isinstance(processor, dict): + module.set_processor(processor) + else: + module.set_processor(processor.pop(f"{name}.processor")) + + for sub_name, child in module.named_children(): + fn_recursive_attn_processor(f"{name}.{sub_name}", child, processor) + + for name, module in self.named_children(): + fn_recursive_attn_processor(name, module, processor) + + def set_default_attn_processor(self): + """ + Disables custom attention processors and sets the default attention implementation. + """ + self.set_attn_processor(AttnProcessor()) + + def set_attention_slice(self, slice_size): + r""" + Enable sliced attention computation. + + When this option is enabled, the attention module splits the input tensor in slices to compute attention in + several steps. This is useful for saving some memory in exchange for a small decrease in speed. + + Args: + slice_size (`str` or `int` or `list(int)`, *optional*, defaults to `"auto"`): + When `"auto"`, input to the attention heads is halved, so attention is computed in two steps. If + `"max"`, maximum amount of memory is saved by running only one slice at a time. If a number is + provided, uses as many slices as `attention_head_dim // slice_size`. In this case, `attention_head_dim` + must be a multiple of `slice_size`. + """ + sliceable_head_dims = [] + + def fn_recursive_retrieve_sliceable_dims(module: torch.nn.Module): + if hasattr(module, "set_attention_slice"): + sliceable_head_dims.append(module.sliceable_head_dim) + + for child in module.children(): + fn_recursive_retrieve_sliceable_dims(child) + + # retrieve number of attention layers + for module in self.children(): + fn_recursive_retrieve_sliceable_dims(module) + + num_sliceable_layers = len(sliceable_head_dims) + + if slice_size == "auto": + # half the attention head size is usually a good trade-off between + # speed and memory + slice_size = [dim // 2 for dim in sliceable_head_dims] + elif slice_size == "max": + # make smallest slice possible + slice_size = num_sliceable_layers * [1] + + slice_size = num_sliceable_layers * [slice_size] if not isinstance(slice_size, list) else slice_size + + if len(slice_size) != len(sliceable_head_dims): + raise ValueError( + f"You have provided {len(slice_size)}, but {self.config} has {len(sliceable_head_dims)} different" + f" attention layers. Make sure to match `len(slice_size)` to be {len(sliceable_head_dims)}." + ) + + for i in range(len(slice_size)): + size = slice_size[i] + dim = sliceable_head_dims[i] + if size is not None and size > dim: + raise ValueError(f"size {size} has to be smaller or equal to {dim}.") + + # Recursively walk through all the children. + # Any children which exposes the set_attention_slice method + # gets the message + def fn_recursive_set_attention_slice(module: torch.nn.Module, slice_size: List[int]): + if hasattr(module, "set_attention_slice"): + module.set_attention_slice(slice_size.pop()) + + for child in module.children(): + fn_recursive_set_attention_slice(child, slice_size) + + reversed_slice_size = list(reversed(slice_size)) + for module in self.children(): + fn_recursive_set_attention_slice(module, reversed_slice_size) + + def _set_gradient_checkpointing(self, module, value=False): + if isinstance(module, (CrossAttnDownBlock2D, CrossAttnDownBlockMV2D, DownBlock2D, CrossAttnUpBlock2D, CrossAttnUpBlockMV2D, UpBlock2D)): + module.gradient_checkpointing = value + + def forward( + self, + sample: torch.FloatTensor, + timestep: Union[torch.Tensor, float, int], + encoder_hidden_states: torch.Tensor, + class_labels: Optional[torch.Tensor] = None, + timestep_cond: Optional[torch.Tensor] = None, + attention_mask: Optional[torch.Tensor] = None, + cross_attention_kwargs: Optional[Dict[str, Any]] = None, + added_cond_kwargs: Optional[Dict[str, torch.Tensor]] = None, + down_block_additional_residuals: Optional[Tuple[torch.Tensor]] = None, + mid_block_additional_residual: Optional[torch.Tensor] = None, + encoder_attention_mask: Optional[torch.Tensor] = None, + return_dict: bool = True, + ) -> Union[UNetMV2DConditionOutput, Tuple]: + r""" + The [`UNet2DConditionModel`] forward method. + + Args: + sample (`torch.FloatTensor`): + The noisy input tensor with the following shape `(batch, channel, height, width)`. + timestep (`torch.FloatTensor` or `float` or `int`): The number of timesteps to denoise an input. + encoder_hidden_states (`torch.FloatTensor`): + The encoder hidden states with shape `(batch, sequence_length, feature_dim)`. + encoder_attention_mask (`torch.Tensor`): + A cross-attention mask of shape `(batch, sequence_length)` is applied to `encoder_hidden_states`. If + `True` the mask is kept, otherwise if `False` it is discarded. Mask will be converted into a bias, + which adds large negative values to the attention scores corresponding to "discard" tokens. + return_dict (`bool`, *optional*, defaults to `True`): + Whether or not to return a [`~models.unet_2d_condition.UNet2DConditionOutput`] instead of a plain + tuple. + cross_attention_kwargs (`dict`, *optional*): + A kwargs dictionary that if specified is passed along to the [`AttnProcessor`]. + added_cond_kwargs: (`dict`, *optional*): + A kwargs dictionary containin additional embeddings that if specified are added to the embeddings that + are passed along to the UNet blocks. + + Returns: + [`~models.unet_2d_condition.UNet2DConditionOutput`] or `tuple`: + If `return_dict` is True, an [`~models.unet_2d_condition.UNet2DConditionOutput`] is returned, otherwise + a `tuple` is returned where the first element is the sample tensor. + """ + # By default samples have to be AT least a multiple of the overall upsampling factor. + # The overall upsampling factor is equal to 2 ** (# num of upsampling layers). + # However, the upsampling interpolation output size can be forced to fit any upsampling size + # on the fly if necessary. + default_overall_up_factor = 2**self.num_upsamplers + + # upsample size should be forwarded when sample is not a multiple of `default_overall_up_factor` + forward_upsample_size = False + upsample_size = None + + if any(s % default_overall_up_factor != 0 for s in sample.shape[-2:]): + logger.info("Forward upsample size to force interpolation output size.") + forward_upsample_size = True + + # ensure attention_mask is a bias, and give it a singleton query_tokens dimension + # expects mask of shape: + # [batch, key_tokens] + # adds singleton query_tokens dimension: + # [batch, 1, key_tokens] + # this helps to broadcast it as a bias over attention scores, which will be in one of the following shapes: + # [batch, heads, query_tokens, key_tokens] (e.g. torch sdp attn) + # [batch * heads, query_tokens, key_tokens] (e.g. xformers or classic attn) + if attention_mask is not None: + # assume that mask is expressed as: + # (1 = keep, 0 = discard) + # convert mask into a bias that can be added to attention scores: + # (keep = +0, discard = -10000.0) + attention_mask = (1 - attention_mask.to(sample.dtype)) * -10000.0 + attention_mask = attention_mask.unsqueeze(1) + + # convert encoder_attention_mask to a bias the same way we do for attention_mask + if encoder_attention_mask is not None: + encoder_attention_mask = (1 - encoder_attention_mask.to(sample.dtype)) * -10000.0 + encoder_attention_mask = encoder_attention_mask.unsqueeze(1) + + # 0. center input if necessary + if self.config.center_input_sample: + sample = 2 * sample - 1.0 + + # 1. time + timesteps = timestep + if not torch.is_tensor(timesteps): + # TODO: this requires sync between CPU and GPU. So try to pass timesteps as tensors if you can + # This would be a good case for the `match` statement (Python 3.10+) + is_mps = sample.device.type == "mps" + if isinstance(timestep, float): + dtype = torch.float32 if is_mps else torch.float64 + else: + dtype = torch.int32 if is_mps else torch.int64 + timesteps = torch.tensor([timesteps], dtype=dtype, device=sample.device) + elif len(timesteps.shape) == 0: + timesteps = timesteps[None].to(sample.device) + + # broadcast to batch dimension in a way that's compatible with ONNX/Core ML + timesteps = timesteps.expand(sample.shape[0]) + + t_emb = self.time_proj(timesteps) + + # `Timesteps` does not contain any weights and will always return f32 tensors + # but time_embedding might actually be running in fp16. so we need to cast here. + # there might be better ways to encapsulate this. + t_emb = t_emb.to(dtype=sample.dtype) + + emb = self.time_embedding(t_emb, timestep_cond) + aug_emb = None + + if self.class_embedding is not None: + if class_labels is None: + raise ValueError("class_labels should be provided when num_class_embeds > 0") + + if self.config.class_embed_type == "timestep": + class_labels = self.time_proj(class_labels) + + # `Timesteps` does not contain any weights and will always return f32 tensors + # there might be better ways to encapsulate this. + class_labels = class_labels.to(dtype=sample.dtype) + + class_emb = self.class_embedding(class_labels).to(dtype=sample.dtype) + + if self.config.class_embeddings_concat: + emb = torch.cat([emb, class_emb], dim=-1) + else: + emb = emb + class_emb + + if self.config.addition_embed_type == "text": + aug_emb = self.add_embedding(encoder_hidden_states) + elif self.config.addition_embed_type == "text_image": + # Kandinsky 2.1 - style + if "image_embeds" not in added_cond_kwargs: + raise ValueError( + f"{self.__class__} has the config param `addition_embed_type` set to 'text_image' which requires the keyword argument `image_embeds` to be passed in `added_cond_kwargs`" + ) + + image_embs = added_cond_kwargs.get("image_embeds") + text_embs = added_cond_kwargs.get("text_embeds", encoder_hidden_states) + aug_emb = self.add_embedding(text_embs, image_embs) + elif self.config.addition_embed_type == "text_time": + # SDXL - style + if "text_embeds" not in added_cond_kwargs: + raise ValueError( + f"{self.__class__} has the config param `addition_embed_type` set to 'text_time' which requires the keyword argument `text_embeds` to be passed in `added_cond_kwargs`" + ) + text_embeds = added_cond_kwargs.get("text_embeds") + if "time_ids" not in added_cond_kwargs: + raise ValueError( + f"{self.__class__} has the config param `addition_embed_type` set to 'text_time' which requires the keyword argument `time_ids` to be passed in `added_cond_kwargs`" + ) + time_ids = added_cond_kwargs.get("time_ids") + time_embeds = self.add_time_proj(time_ids.flatten()) + time_embeds = time_embeds.reshape((text_embeds.shape[0], -1)) + + add_embeds = torch.concat([text_embeds, time_embeds], dim=-1) + add_embeds = add_embeds.to(emb.dtype) + aug_emb = self.add_embedding(add_embeds) + elif self.config.addition_embed_type == "image": + # Kandinsky 2.2 - style + if "image_embeds" not in added_cond_kwargs: + raise ValueError( + f"{self.__class__} has the config param `addition_embed_type` set to 'image' which requires the keyword argument `image_embeds` to be passed in `added_cond_kwargs`" + ) + image_embs = added_cond_kwargs.get("image_embeds") + aug_emb = self.add_embedding(image_embs) + elif self.config.addition_embed_type == "image_hint": + # Kandinsky 2.2 - style + if "image_embeds" not in added_cond_kwargs or "hint" not in added_cond_kwargs: + raise ValueError( + f"{self.__class__} has the config param `addition_embed_type` set to 'image_hint' which requires the keyword arguments `image_embeds` and `hint` to be passed in `added_cond_kwargs`" + ) + image_embs = added_cond_kwargs.get("image_embeds") + hint = added_cond_kwargs.get("hint") + aug_emb, hint = self.add_embedding(image_embs, hint) + sample = torch.cat([sample, hint], dim=1) + + emb = emb + aug_emb if aug_emb is not None else emb + + if self.time_embed_act is not None: + emb = self.time_embed_act(emb) + + if self.encoder_hid_proj is not None and self.config.encoder_hid_dim_type == "text_proj": + encoder_hidden_states = self.encoder_hid_proj(encoder_hidden_states) + elif self.encoder_hid_proj is not None and self.config.encoder_hid_dim_type == "text_image_proj": + # Kadinsky 2.1 - style + if "image_embeds" not in added_cond_kwargs: + raise ValueError( + f"{self.__class__} has the config param `encoder_hid_dim_type` set to 'text_image_proj' which requires the keyword argument `image_embeds` to be passed in `added_conditions`" + ) + + image_embeds = added_cond_kwargs.get("image_embeds") + encoder_hidden_states = self.encoder_hid_proj(encoder_hidden_states, image_embeds) + elif self.encoder_hid_proj is not None and self.config.encoder_hid_dim_type == "image_proj": + # Kandinsky 2.2 - style + if "image_embeds" not in added_cond_kwargs: + raise ValueError( + f"{self.__class__} has the config param `encoder_hid_dim_type` set to 'image_proj' which requires the keyword argument `image_embeds` to be passed in `added_conditions`" + ) + image_embeds = added_cond_kwargs.get("image_embeds") + encoder_hidden_states = self.encoder_hid_proj(image_embeds) + # 2. pre-process + sample = self.conv_in(sample) + + # 3. down + + is_controlnet = mid_block_additional_residual is not None and down_block_additional_residuals is not None + is_adapter = mid_block_additional_residual is None and down_block_additional_residuals is not None + + down_block_res_samples = (sample,) + for downsample_block in self.down_blocks: + if hasattr(downsample_block, "has_cross_attention") and downsample_block.has_cross_attention: + # For t2i-adapter CrossAttnDownBlock2D + additional_residuals = {} + if is_adapter and len(down_block_additional_residuals) > 0: + additional_residuals["additional_residuals"] = down_block_additional_residuals.pop(0) + + sample, res_samples = downsample_block( + hidden_states=sample, + temb=emb, + encoder_hidden_states=encoder_hidden_states, + attention_mask=attention_mask, + cross_attention_kwargs=cross_attention_kwargs, + encoder_attention_mask=encoder_attention_mask, + **additional_residuals, + ) + else: + sample, res_samples = downsample_block(hidden_states=sample, temb=emb) + + if is_adapter and len(down_block_additional_residuals) > 0: + sample += down_block_additional_residuals.pop(0) + + down_block_res_samples += res_samples + + if is_controlnet: + new_down_block_res_samples = () + + for down_block_res_sample, down_block_additional_residual in zip( + down_block_res_samples, down_block_additional_residuals + ): + down_block_res_sample = down_block_res_sample + down_block_additional_residual + new_down_block_res_samples = new_down_block_res_samples + (down_block_res_sample,) + + down_block_res_samples = new_down_block_res_samples + + # 4. mid + if self.mid_block is not None: + sample = self.mid_block( + sample, + emb, + encoder_hidden_states=encoder_hidden_states, + attention_mask=attention_mask, + cross_attention_kwargs=cross_attention_kwargs, + encoder_attention_mask=encoder_attention_mask, + ) + + if is_controlnet: + sample = sample + mid_block_additional_residual + + # 5. up + for i, upsample_block in enumerate(self.up_blocks): + is_final_block = i == len(self.up_blocks) - 1 + + res_samples = down_block_res_samples[-len(upsample_block.resnets) :] + down_block_res_samples = down_block_res_samples[: -len(upsample_block.resnets)] + + # if we have not reached the final block and need to forward the + # upsample size, we do it here + if not is_final_block and forward_upsample_size: + upsample_size = down_block_res_samples[-1].shape[2:] + + if hasattr(upsample_block, "has_cross_attention") and upsample_block.has_cross_attention: + sample = upsample_block( + hidden_states=sample, + temb=emb, + res_hidden_states_tuple=res_samples, + encoder_hidden_states=encoder_hidden_states, + cross_attention_kwargs=cross_attention_kwargs, + upsample_size=upsample_size, + attention_mask=attention_mask, + encoder_attention_mask=encoder_attention_mask, + ) + else: + sample = upsample_block( + hidden_states=sample, temb=emb, res_hidden_states_tuple=res_samples, upsample_size=upsample_size + ) + + # 6. post-process + if self.conv_norm_out: + sample = self.conv_norm_out(sample) + sample = self.conv_act(sample) + sample = self.conv_out(sample) + + if not return_dict: + return (sample,) + + return UNetMV2DConditionOutput(sample=sample) + + @classmethod + def from_pretrained_2d( + cls, pretrained_model_name_or_path: Optional[Union[str, os.PathLike]], + camera_embedding_type: str, num_views: int, sample_size: int, + zero_init_conv_in: bool = True, zero_init_camera_projection: bool = False, + projection_class_embeddings_input_dim: int=6, cd_attention_last: bool = False, + cd_attention_mid: bool = False, multiview_attention: bool = True, + sparse_mv_attention: bool = False, mvcd_attention: bool = False, + in_channels: int = 8, out_channels: int = 4, + **kwargs + ): + r""" + Instantiate a pretrained PyTorch model from a pretrained model configuration. + + The model is set in evaluation mode - `model.eval()` - by default, and dropout modules are deactivated. To + train the model, set it back in training mode with `model.train()`. + + Parameters: + pretrained_model_name_or_path (`str` or `os.PathLike`, *optional*): + Can be either: + + - A string, the *model id* (for example `google/ddpm-celebahq-256`) of a pretrained model hosted on + the Hub. + - A path to a *directory* (for example `./my_model_directory`) containing the model weights saved + with [`~ModelMixin.save_pretrained`]. + + cache_dir (`Union[str, os.PathLike]`, *optional*): + Path to a directory where a downloaded pretrained model configuration is cached if the standard cache + is not used. + torch_dtype (`str` or `torch.dtype`, *optional*): + Override the default `torch.dtype` and load the model with another dtype. If `"auto"` is passed, the + dtype is automatically derived from the model's weights. + force_download (`bool`, *optional*, defaults to `False`): + Whether or not to force the (re-)download of the model weights and configuration files, overriding the + cached versions if they exist. + resume_download (`bool`, *optional*, defaults to `False`): + Whether or not to resume downloading the model weights and configuration files. If set to `False`, any + incompletely downloaded files are deleted. + proxies (`Dict[str, str]`, *optional*): + A dictionary of proxy servers to use by protocol or endpoint, for example, `{'http': 'foo.bar:3128', + 'http://hostname': 'foo.bar:4012'}`. The proxies are used on each request. + output_loading_info (`bool`, *optional*, defaults to `False`): + Whether or not to also return a dictionary containing missing keys, unexpected keys and error messages. + local_files_only(`bool`, *optional*, defaults to `False`): + Whether to only load local model weights and configuration files or not. If set to `True`, the model + won't be downloaded from the Hub. + use_auth_token (`str` or *bool*, *optional*): + The token to use as HTTP bearer authorization for remote files. If `True`, the token generated from + `diffusers-cli login` (stored in `~/.huggingface`) is used. + revision (`str`, *optional*, defaults to `"main"`): + The specific model version to use. It can be a branch name, a tag name, a commit id, or any identifier + allowed by Git. + from_flax (`bool`, *optional*, defaults to `False`): + Load the model weights from a Flax checkpoint save file. + subfolder (`str`, *optional*, defaults to `""`): + The subfolder location of a model file within a larger model repository on the Hub or locally. + mirror (`str`, *optional*): + Mirror source to resolve accessibility issues if you're downloading a model in China. We do not + guarantee the timeliness or safety of the source, and you should refer to the mirror site for more + information. + device_map (`str` or `Dict[str, Union[int, str, torch.device]]`, *optional*): + A map that specifies where each submodule should go. It doesn't need to be defined for each + parameter/buffer name; once a given module name is inside, every submodule of it will be sent to the + same device. + + Set `device_map="auto"` to have 🤗 Accelerate automatically compute the most optimized `device_map`. For + more information about each option see [designing a device + map](https://hf.co/docs/accelerate/main/en/usage_guides/big_modeling#designing-a-device-map). + max_memory (`Dict`, *optional*): + A dictionary device identifier for the maximum memory. Will default to the maximum memory available for + each GPU and the available CPU RAM if unset. + offload_folder (`str` or `os.PathLike`, *optional*): + The path to offload weights if `device_map` contains the value `"disk"`. + offload_state_dict (`bool`, *optional*): + If `True`, temporarily offloads the CPU state dict to the hard drive to avoid running out of CPU RAM if + the weight of the CPU state dict + the biggest shard of the checkpoint does not fit. Defaults to `True` + when there is some disk offload. + low_cpu_mem_usage (`bool`, *optional*, defaults to `True` if torch version >= 1.9.0 else `False`): + Speed up model loading only loading the pretrained weights and not initializing the weights. This also + tries to not use more than 1x model size in CPU memory (including peak memory) while loading the model. + Only supported for PyTorch >= 1.9.0. If you are using an older version of PyTorch, setting this + argument to `True` will raise an error. + variant (`str`, *optional*): + Load weights from a specified `variant` filename such as `"fp16"` or `"ema"`. This is ignored when + loading `from_flax`. + use_safetensors (`bool`, *optional*, defaults to `None`): + If set to `None`, the `safetensors` weights are downloaded if they're available **and** if the + `safetensors` library is installed. If set to `True`, the model is forcibly loaded from `safetensors` + weights. If set to `False`, `safetensors` weights are not loaded. + + + + To use private or [gated models](https://huggingface.co/docs/hub/models-gated#gated-models), log-in with + `huggingface-cli login`. You can also activate the special + ["offline-mode"](https://huggingface.co/diffusers/installation.html#offline-mode) to use this method in a + firewalled environment. + + + + Example: + + ```py + from diffusers import UNet2DConditionModel + + unet = UNet2DConditionModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="unet") + ``` + + If you get the error message below, you need to finetune the weights for your downstream task: + + ```bash + Some weights of UNet2DConditionModel were not initialized from the model checkpoint at runwayml/stable-diffusion-v1-5 and are newly initialized because the shapes did not match: + - conv_in.weight: found shape torch.Size([320, 4, 3, 3]) in the checkpoint and torch.Size([320, 9, 3, 3]) in the model instantiated + You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference. + ``` + """ + cache_dir = kwargs.pop("cache_dir", DIFFUSERS_CACHE) + ignore_mismatched_sizes = kwargs.pop("ignore_mismatched_sizes", False) + force_download = kwargs.pop("force_download", False) + from_flax = kwargs.pop("from_flax", False) + resume_download = kwargs.pop("resume_download", False) + proxies = kwargs.pop("proxies", None) + output_loading_info = kwargs.pop("output_loading_info", False) + local_files_only = kwargs.pop("local_files_only", HF_HUB_OFFLINE) + use_auth_token = kwargs.pop("use_auth_token", None) + revision = kwargs.pop("revision", None) + torch_dtype = kwargs.pop("torch_dtype", None) + subfolder = kwargs.pop("subfolder", None) + device_map = kwargs.pop("device_map", None) + max_memory = kwargs.pop("max_memory", None) + offload_folder = kwargs.pop("offload_folder", None) + offload_state_dict = kwargs.pop("offload_state_dict", False) + variant = kwargs.pop("variant", None) + use_safetensors = kwargs.pop("use_safetensors", None) + + if use_safetensors and not is_safetensors_available(): + raise ValueError( + "`use_safetensors`=True but safetensors is not installed. Please install safetensors with `pip install safetensors" + ) + + allow_pickle = False + if use_safetensors is None: + use_safetensors = is_safetensors_available() + allow_pickle = True + + if device_map is not None and not is_accelerate_available(): + raise NotImplementedError( + "Loading and dispatching requires `accelerate`. Please make sure to install accelerate or set" + " `device_map=None`. You can install accelerate with `pip install accelerate`." + ) + + # Check if we can handle device_map and dispatching the weights + if device_map is not None and not is_torch_version(">=", "1.9.0"): + raise NotImplementedError( + "Loading and dispatching requires torch >= 1.9.0. Please either update your PyTorch version or set" + " `device_map=None`." + ) + + # Load config if we don't provide a configuration + config_path = pretrained_model_name_or_path + + user_agent = { + "diffusers": __version__, + "file_type": "model", + "framework": "pytorch", + } + + # load config + config, unused_kwargs, commit_hash = cls.load_config( + config_path, + cache_dir=cache_dir, + return_unused_kwargs=True, + return_commit_hash=True, + force_download=force_download, + resume_download=resume_download, + proxies=proxies, + local_files_only=local_files_only, + use_auth_token=use_auth_token, + revision=revision, + subfolder=subfolder, + device_map=device_map, + max_memory=max_memory, + offload_folder=offload_folder, + offload_state_dict=offload_state_dict, + user_agent=user_agent, + **kwargs, + ) + + # modify config + config["_class_name"] = cls.__name__ + config['in_channels'] = in_channels + config['out_channels'] = out_channels + config['sample_size'] = sample_size # training resolution + config['num_views'] = num_views + config['cd_attention_last'] = cd_attention_last + config['cd_attention_mid'] = cd_attention_mid + config['multiview_attention'] = multiview_attention + config['sparse_mv_attention'] = sparse_mv_attention + config['mvcd_attention'] = mvcd_attention + config["down_block_types"] = [ + "CrossAttnDownBlockMV2D", + "CrossAttnDownBlockMV2D", + "CrossAttnDownBlockMV2D", + "DownBlock2D" + ] + config['mid_block_type'] = "UNetMidBlockMV2DCrossAttn" + config["up_block_types"] = [ + "UpBlock2D", + "CrossAttnUpBlockMV2D", + "CrossAttnUpBlockMV2D", + "CrossAttnUpBlockMV2D" + ] + config['class_embed_type'] = 'projection' + if camera_embedding_type == 'e_de_da_sincos': + config['projection_class_embeddings_input_dim'] = projection_class_embeddings_input_dim # default 6 + else: + raise NotImplementedError + + # load model + model_file = None + if from_flax: + raise NotImplementedError + else: + if use_safetensors: + try: + model_file = _get_model_file( + pretrained_model_name_or_path, + weights_name=_add_variant(SAFETENSORS_WEIGHTS_NAME, variant), + cache_dir=cache_dir, + force_download=force_download, + resume_download=resume_download, + proxies=proxies, + local_files_only=local_files_only, + use_auth_token=use_auth_token, + revision=revision, + subfolder=subfolder, + user_agent=user_agent, + commit_hash=commit_hash, + ) + except IOError as e: + if not allow_pickle: + raise e + pass + if model_file is None: + model_file = _get_model_file( + pretrained_model_name_or_path, + weights_name=_add_variant(WEIGHTS_NAME, variant), + cache_dir=cache_dir, + force_download=force_download, + resume_download=resume_download, + proxies=proxies, + local_files_only=local_files_only, + use_auth_token=use_auth_token, + revision=revision, + subfolder=subfolder, + user_agent=user_agent, + commit_hash=commit_hash, + ) + + model = cls.from_config(config, **unused_kwargs) + import copy + state_dict_v0 = load_state_dict(model_file, variant=variant) + state_dict = copy.deepcopy(state_dict_v0) + # attn_joint -> attn_joint_last; norm_joint -> norm_joint_last + # attn_joint_twice -> attn_joint_mid; norm_joint_twice -> norm_joint_mid + for key in state_dict_v0: + if 'attn_joint.' in key: + tmp = copy.deepcopy(key) + state_dict[key.replace("attn_joint.", "attn_joint_last.")] = state_dict.pop(tmp) + if 'norm_joint.' in key: + tmp = copy.deepcopy(key) + state_dict[key.replace("norm_joint.", "norm_joint_last.")] = state_dict.pop(tmp) + if 'attn_joint_twice.' in key: + tmp = copy.deepcopy(key) + state_dict[key.replace("attn_joint_twice.", "attn_joint_mid.")] = state_dict.pop(tmp) + if 'norm_joint_twice.' in key: + tmp = copy.deepcopy(key) + state_dict[key.replace("norm_joint_twice.", "norm_joint_mid.")] = state_dict.pop(tmp) + + model._convert_deprecated_attention_blocks(state_dict) + + conv_in_weight = state_dict['conv_in.weight'] + conv_out_weight = state_dict['conv_out.weight'] + model, missing_keys, unexpected_keys, mismatched_keys, error_msgs = cls._load_pretrained_model_2d( + model, + state_dict, + model_file, + pretrained_model_name_or_path, + ignore_mismatched_sizes=True, + ) + if any([key == 'conv_in.weight' for key, _, _ in mismatched_keys]): + # initialize from the original SD structure + model.conv_in.weight.data[:,:4] = conv_in_weight + + # whether to place all zero to new layers? + if zero_init_conv_in: + model.conv_in.weight.data[:,4:] = 0. + + if any([key == 'conv_out.weight' for key, _, _ in mismatched_keys]): + # initialize from the original SD structure + model.conv_out.weight.data[:,:4] = conv_out_weight + if out_channels == 8: # copy for the last 4 channels + model.conv_out.weight.data[:, 4:] = conv_out_weight + + # if zero_init_camera_projection: + # for p in model.class_embedding.parameters(): + # torch.nn.init.zeros_(p) + + loading_info = { + "missing_keys": missing_keys, + "unexpected_keys": unexpected_keys, + "mismatched_keys": mismatched_keys, + "error_msgs": error_msgs, + } + + if torch_dtype is not None and not isinstance(torch_dtype, torch.dtype): + raise ValueError( + f"{torch_dtype} needs to be of type `torch.dtype`, e.g. `torch.float16`, but is {type(torch_dtype)}." + ) + elif torch_dtype is not None: + model = model.to(torch_dtype) + + model.register_to_config(_name_or_path=pretrained_model_name_or_path) + + # Set model in evaluation mode to deactivate DropOut modules by default + model.eval() + if output_loading_info: + return model, loading_info + + return model + + @classmethod + def _load_pretrained_model_2d( + cls, + model, + state_dict, + resolved_archive_file, + pretrained_model_name_or_path, + ignore_mismatched_sizes=False, + ): + # Retrieve missing & unexpected_keys + model_state_dict = model.state_dict() + loaded_keys = list(state_dict.keys()) + + expected_keys = list(model_state_dict.keys()) + + original_loaded_keys = loaded_keys + + missing_keys = list(set(expected_keys) - set(loaded_keys)) + unexpected_keys = list(set(loaded_keys) - set(expected_keys)) + + # Make sure we are able to load base models as well as derived models (with heads) + model_to_load = model + + def _find_mismatched_keys( + state_dict, + model_state_dict, + loaded_keys, + ignore_mismatched_sizes, + ): + mismatched_keys = [] + if ignore_mismatched_sizes: + for checkpoint_key in loaded_keys: + model_key = checkpoint_key + + if ( + model_key in model_state_dict + and state_dict[checkpoint_key].shape != model_state_dict[model_key].shape + ): + mismatched_keys.append( + (checkpoint_key, state_dict[checkpoint_key].shape, model_state_dict[model_key].shape) + ) + del state_dict[checkpoint_key] + return mismatched_keys + + if state_dict is not None: + # Whole checkpoint + mismatched_keys = _find_mismatched_keys( + state_dict, + model_state_dict, + original_loaded_keys, + ignore_mismatched_sizes, + ) + error_msgs = _load_state_dict_into_model(model_to_load, state_dict) + + if len(error_msgs) > 0: + error_msg = "\n\t".join(error_msgs) + if "size mismatch" in error_msg: + error_msg += ( + "\n\tYou may consider adding `ignore_mismatched_sizes=True` in the model `from_pretrained` method." + ) + raise RuntimeError(f"Error(s) in loading state_dict for {model.__class__.__name__}:\n\t{error_msg}") + + if len(unexpected_keys) > 0: + logger.warning( + f"Some weights of the model checkpoint at {pretrained_model_name_or_path} were not used when" + f" initializing {model.__class__.__name__}: {unexpected_keys}\n- This IS expected if you are" + f" initializing {model.__class__.__name__} from the checkpoint of a model trained on another task" + " or with another architecture (e.g. initializing a BertForSequenceClassification model from a" + " BertForPreTraining model).\n- This IS NOT expected if you are initializing" + f" {model.__class__.__name__} from the checkpoint of a model that you expect to be exactly" + " identical (initializing a BertForSequenceClassification model from a" + " BertForSequenceClassification model)." + ) + else: + logger.info(f"All model checkpoint weights were used when initializing {model.__class__.__name__}.\n") + if len(missing_keys) > 0: + logger.warning( + f"Some weights of {model.__class__.__name__} were not initialized from the model checkpoint at" + f" {pretrained_model_name_or_path} and are newly initialized: {missing_keys}\nYou should probably" + " TRAIN this model on a down-stream task to be able to use it for predictions and inference." + ) + elif len(mismatched_keys) == 0: + logger.info( + f"All the weights of {model.__class__.__name__} were initialized from the model checkpoint at" + f" {pretrained_model_name_or_path}.\nIf your task is similar to the task the model of the" + f" checkpoint was trained on, you can already use {model.__class__.__name__} for predictions" + " without further training." + ) + if len(mismatched_keys) > 0: + mismatched_warning = "\n".join( + [ + f"- {key}: found shape {shape1} in the checkpoint and {shape2} in the model instantiated" + for key, shape1, shape2 in mismatched_keys + ] + ) + logger.warning( + f"Some weights of {model.__class__.__name__} were not initialized from the model checkpoint at" + f" {pretrained_model_name_or_path} and are newly initialized because the shapes did not" + f" match:\n{mismatched_warning}\nYou should probably TRAIN this model on a down-stream task to be" + " able to use it for predictions and inference." + ) + + return model, missing_keys, unexpected_keys, mismatched_keys, error_msgs + diff --git a/apps/third_party/Wonder3D/mvdiffusion/pipelines/pipeline_mvdiffusion_image.py b/apps/third_party/Wonder3D/mvdiffusion/pipelines/pipeline_mvdiffusion_image.py new file mode 100644 index 0000000000000000000000000000000000000000..3414f9769336dd2564ba427a54c975b900cf423e --- /dev/null +++ b/apps/third_party/Wonder3D/mvdiffusion/pipelines/pipeline_mvdiffusion_image.py @@ -0,0 +1,509 @@ +# Copyright 2023 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import inspect +import warnings +from typing import Callable, List, Optional, Union + +import PIL +import torch +import torchvision.transforms.functional as TF +from packaging import version +from transformers import CLIPImageProcessor, CLIPVisionModelWithProjection + +from diffusers.configuration_utils import FrozenDict +from diffusers.image_processor import VaeImageProcessor +from diffusers.models import AutoencoderKL, UNet2DConditionModel +from diffusers.schedulers import KarrasDiffusionSchedulers +from diffusers.utils import deprecate, logging, randn_tensor +from diffusers.pipelines.pipeline_utils import DiffusionPipeline +from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput +from diffusers.pipelines.stable_diffusion.safety_checker import StableDiffusionSafetyChecker +from einops import rearrange, repeat + +logger = logging.get_logger(__name__) # pylint: disable=invalid-name + + +class MVDiffusionImagePipeline(DiffusionPipeline): + r""" + Pipeline to generate image variations from an input image using Stable Diffusion. + + This model inherits from [`DiffusionPipeline`]. Check the superclass documentation for the generic methods + implemented for all pipelines (downloading, saving, running on a particular device, etc.). + + Args: + vae ([`AutoencoderKL`]): + Variational Auto-Encoder (VAE) model to encode and decode images to and from latent representations. + image_encoder ([`~transformers.CLIPVisionModelWithProjection`]): + Frozen CLIP image-encoder ([clip-vit-large-patch14](https://huggingface.co/openai/clip-vit-large-patch14)). + text_encoder ([`~transformers.CLIPTextModel`]): + Frozen text-encoder ([clip-vit-large-patch14](https://huggingface.co/openai/clip-vit-large-patch14)). + tokenizer ([`~transformers.CLIPTokenizer`]): + A `CLIPTokenizer` to tokenize text. + unet ([`UNet2DConditionModel`]): + A `UNet2DConditionModel` to denoise the encoded image latents. + scheduler ([`SchedulerMixin`]): + A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of + [`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`]. + safety_checker ([`StableDiffusionSafetyChecker`]): + Classification module that estimates whether generated images could be considered offensive or harmful. + Please refer to the [model card](https://huggingface.co/runwayml/stable-diffusion-v1-5) for more details + about a model's potential harms. + feature_extractor ([`~transformers.CLIPImageProcessor`]): + A `CLIPImageProcessor` to extract features from generated images; used as inputs to the `safety_checker`. + """ + # TODO: feature_extractor is required to encode images (if they are in PIL format), + # we should give a descriptive message if the pipeline doesn't have one. + _optional_components = ["safety_checker"] + + def __init__( + self, + vae: AutoencoderKL, + image_encoder: CLIPVisionModelWithProjection, + unet: UNet2DConditionModel, + scheduler: KarrasDiffusionSchedulers, + safety_checker: StableDiffusionSafetyChecker, + feature_extractor: CLIPImageProcessor, + requires_safety_checker: bool = True, + camera_embedding_type: str = 'e_de_da_sincos', + num_views: int = 6 + ): + super().__init__() + + if safety_checker is None and requires_safety_checker: + logger.warn( + f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure" + " that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered" + " results in services or applications open to the public. Both the diffusers team and Hugging Face" + " strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling" + " it only for use-cases that involve analyzing network behavior or auditing its results. For more" + " information, please have a look at https://github.com/huggingface/diffusers/pull/254 ." + ) + + if safety_checker is not None and feature_extractor is None: + raise ValueError( + "Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety" + " checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead." + ) + + is_unet_version_less_0_9_0 = hasattr(unet.config, "_diffusers_version") and version.parse( + version.parse(unet.config._diffusers_version).base_version + ) < version.parse("0.9.0.dev0") + is_unet_sample_size_less_64 = hasattr(unet.config, "sample_size") and unet.config.sample_size < 64 + if is_unet_version_less_0_9_0 and is_unet_sample_size_less_64: + deprecation_message = ( + "The configuration file of the unet has set the default `sample_size` to smaller than" + " 64 which seems highly unlikely .If you're checkpoint is a fine-tuned version of any of the" + " following: \n- CompVis/stable-diffusion-v1-4 \n- CompVis/stable-diffusion-v1-3 \n-" + " CompVis/stable-diffusion-v1-2 \n- CompVis/stable-diffusion-v1-1 \n- runwayml/stable-diffusion-v1-5" + " \n- runwayml/stable-diffusion-inpainting \n you should change 'sample_size' to 64 in the" + " configuration file. Please make sure to update the config accordingly as leaving `sample_size=32`" + " in the config might lead to incorrect results in future versions. If you have downloaded this" + " checkpoint from the Hugging Face Hub, it would be very nice if you could open a Pull request for" + " the `unet/config.json` file" + ) + deprecate("sample_size<64", "1.0.0", deprecation_message, standard_warn=False) + new_config = dict(unet.config) + new_config["sample_size"] = 64 + unet._internal_dict = FrozenDict(new_config) + + self.register_modules( + vae=vae, + image_encoder=image_encoder, + unet=unet, + scheduler=scheduler, + safety_checker=safety_checker, + feature_extractor=feature_extractor, + ) + self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1) + self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor) + self.register_to_config(requires_safety_checker=requires_safety_checker) + + self.camera_embedding_type: str = camera_embedding_type + self.num_views: int = num_views + + self.camera_embedding = torch.tensor( + [[ 0.0000, 0.0000, 0.0000, 1.0000, 0.0000], + [ 0.0000, -0.2362, 0.8125, 1.0000, 0.0000], + [ 0.0000, -0.1686, 1.6934, 1.0000, 0.0000], + [ 0.0000, 0.5220, 3.1406, 1.0000, 0.0000], + [ 0.0000, 0.6904, 4.8359, 1.0000, 0.0000], + [ 0.0000, 0.3733, 5.5859, 1.0000, 0.0000], + [ 0.0000, 0.0000, 0.0000, 0.0000, 1.0000], + [ 0.0000, -0.2362, 0.8125, 0.0000, 1.0000], + [ 0.0000, -0.1686, 1.6934, 0.0000, 1.0000], + [ 0.0000, 0.5220, 3.1406, 0.0000, 1.0000], + [ 0.0000, 0.6904, 4.8359, 0.0000, 1.0000], + [ 0.0000, 0.3733, 5.5859, 0.0000, 1.0000]], dtype=torch.float16) + + def _encode_image(self, image_pil, device, num_images_per_prompt, do_classifier_free_guidance): + dtype = next(self.image_encoder.parameters()).dtype + + image_pt = self.feature_extractor(images=image_pil, return_tensors="pt").pixel_values + image_pt = image_pt.to(device=device, dtype=dtype) + image_embeddings = self.image_encoder(image_pt).image_embeds + image_embeddings = image_embeddings.unsqueeze(1) + + # duplicate image embeddings for each generation per prompt, using mps friendly method + # Note: repeat differently from official pipelines + # B1B2B3B4 -> B1B2B3B4B1B2B3B4 + bs_embed, seq_len, _ = image_embeddings.shape + image_embeddings = image_embeddings.repeat(num_images_per_prompt, 1, 1) + + if do_classifier_free_guidance: + negative_prompt_embeds = torch.zeros_like(image_embeddings) + + # For classifier free guidance, we need to do two forward passes. + # Here we concatenate the unconditional and text embeddings into a single batch + # to avoid doing two forward passes + image_embeddings = torch.cat([negative_prompt_embeds, image_embeddings]) + + image_pt = torch.stack([TF.to_tensor(img) for img in image_pil], dim=0).to(device).to(dtype) + image_pt = image_pt * 2.0 - 1.0 + image_latents = self.vae.encode(image_pt).latent_dist.mode() * self.vae.config.scaling_factor + # Note: repeat differently from official pipelines + # B1B2B3B4 -> B1B2B3B4B1B2B3B4 + image_latents = image_latents.repeat(num_images_per_prompt, 1, 1, 1) + + if do_classifier_free_guidance: + image_latents = torch.cat([torch.zeros_like(image_latents), image_latents]) + + return image_embeddings, image_latents + + # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.run_safety_checker + def run_safety_checker(self, image, device, dtype): + if self.safety_checker is None: + has_nsfw_concept = None + else: + if torch.is_tensor(image): + feature_extractor_input = self.image_processor.postprocess(image, output_type="pil") + else: + feature_extractor_input = self.image_processor.numpy_to_pil(image) + safety_checker_input = self.feature_extractor(feature_extractor_input, return_tensors="pt").to(device) + image, has_nsfw_concept = self.safety_checker( + images=image, clip_input=safety_checker_input.pixel_values.to(dtype) + ) + return image, has_nsfw_concept + + # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.decode_latents + def decode_latents(self, latents): + warnings.warn( + "The decode_latents method is deprecated and will be removed in a future version. Please" + " use VaeImageProcessor instead", + FutureWarning, + ) + latents = 1 / self.vae.config.scaling_factor * latents + image = self.vae.decode(latents, return_dict=False)[0] + image = (image / 2 + 0.5).clamp(0, 1) + # we always cast to float32 as this does not cause significant overhead and is compatible with bfloat16 + image = image.cpu().permute(0, 2, 3, 1).float().numpy() + return image + + # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.prepare_extra_step_kwargs + def prepare_extra_step_kwargs(self, generator, eta): + # prepare extra kwargs for the scheduler step, since not all schedulers have the same signature + # eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers. + # eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502 + # and should be between [0, 1] + + accepts_eta = "eta" in set(inspect.signature(self.scheduler.step).parameters.keys()) + extra_step_kwargs = {} + if accepts_eta: + extra_step_kwargs["eta"] = eta + + # check if the scheduler accepts generator + accepts_generator = "generator" in set(inspect.signature(self.scheduler.step).parameters.keys()) + if accepts_generator: + extra_step_kwargs["generator"] = generator + return extra_step_kwargs + + def check_inputs(self, image, height, width, callback_steps): + if ( + not isinstance(image, torch.Tensor) + and not isinstance(image, PIL.Image.Image) + and not isinstance(image, list) + ): + raise ValueError( + "`image` has to be of type `torch.FloatTensor` or `PIL.Image.Image` or `List[PIL.Image.Image]` but is" + f" {type(image)}" + ) + + if height % 8 != 0 or width % 8 != 0: + raise ValueError(f"`height` and `width` have to be divisible by 8 but are {height} and {width}.") + + if (callback_steps is None) or ( + callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0) + ): + raise ValueError( + f"`callback_steps` has to be a positive integer but is {callback_steps} of type" + f" {type(callback_steps)}." + ) + + # Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.prepare_latents + def prepare_latents(self, batch_size, num_channels_latents, height, width, dtype, device, generator, latents=None): + shape = (batch_size, num_channels_latents, height // self.vae_scale_factor, width // self.vae_scale_factor) + if isinstance(generator, list) and len(generator) != batch_size: + raise ValueError( + f"You have passed a list of generators of length {len(generator)}, but requested an effective batch" + f" size of {batch_size}. Make sure the batch size matches the length of the generators." + ) + + if latents is None: + latents = randn_tensor(shape, generator=generator, device=device, dtype=dtype) + else: + latents = latents.to(device) + + # scale the initial noise by the standard deviation required by the scheduler + latents = latents * self.scheduler.init_noise_sigma + return latents + + def prepare_camera_embedding(self, camera_embedding: Union[float, torch.Tensor], do_classifier_free_guidance, num_images_per_prompt=1): + # (B, 3) + camera_embedding = camera_embedding.to(dtype=self.unet.dtype, device=self.unet.device) + + if self.camera_embedding_type == 'e_de_da_sincos': + # (B, 6) + camera_embedding = torch.cat([ + torch.sin(camera_embedding), + torch.cos(camera_embedding) + ], dim=-1) + assert self.unet.config.class_embed_type == 'projection' + assert self.unet.config.projection_class_embeddings_input_dim == 6 or self.unet.config.projection_class_embeddings_input_dim == 10 + else: + raise NotImplementedError + + # Note: repeat differently from official pipelines + # B1B2B3B4 -> B1B2B3B4B1B2B3B4 + camera_embedding = camera_embedding.repeat(num_images_per_prompt, 1) + + if do_classifier_free_guidance: + camera_embedding = torch.cat([ + camera_embedding, + camera_embedding + ], dim=0) + + return camera_embedding + + @torch.no_grad() + def __call__( + self, + image: Union[List[PIL.Image.Image], torch.FloatTensor], + # elevation_cond: torch.FloatTensor, + # elevation: torch.FloatTensor, + # azimuth: torch.FloatTensor, + camera_embedding: Optional[torch.FloatTensor]=None, + height: Optional[int] = None, + width: Optional[int] = None, + num_inference_steps: int = 50, + guidance_scale: float = 7.5, + num_images_per_prompt: Optional[int] = 1, + eta: float = 0.0, + generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None, + latents: Optional[torch.FloatTensor] = None, + output_type: Optional[str] = "pil", + return_dict: bool = True, + callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None, + callback_steps: int = 1, + normal_cond: Optional[Union[List[PIL.Image.Image], torch.FloatTensor]] = None, + ): + r""" + The call function to the pipeline for generation. + + Args: + image (`PIL.Image.Image` or `List[PIL.Image.Image]` or `torch.FloatTensor`): + Image or images to guide image generation. If you provide a tensor, it needs to be compatible with + [`CLIPImageProcessor`](https://huggingface.co/lambdalabs/sd-image-variations-diffusers/blob/main/feature_extractor/preprocessor_config.json). + height (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`): + The height in pixels of the generated image. + width (`int`, *optional*, defaults to `self.unet.config.sample_size * self.vae_scale_factor`): + The width in pixels of the generated image. + num_inference_steps (`int`, *optional*, defaults to 50): + The number of denoising steps. More denoising steps usually lead to a higher quality image at the + expense of slower inference. This parameter is modulated by `strength`. + guidance_scale (`float`, *optional*, defaults to 7.5): + A higher guidance scale value encourages the model to generate images closely linked to the text + `prompt` at the expense of lower image quality. Guidance scale is enabled when `guidance_scale > 1`. + num_images_per_prompt (`int`, *optional*, defaults to 1): + The number of images to generate per prompt. + eta (`float`, *optional*, defaults to 0.0): + Corresponds to parameter eta (η) from the [DDIM](https://arxiv.org/abs/2010.02502) paper. Only applies + to the [`~schedulers.DDIMScheduler`], and is ignored in other schedulers. + generator (`torch.Generator` or `List[torch.Generator]`, *optional*): + A [`torch.Generator`](https://pytorch.org/docs/stable/generated/torch.Generator.html) to make + generation deterministic. + latents (`torch.FloatTensor`, *optional*): + Pre-generated noisy latents sampled from a Gaussian distribution, to be used as inputs for image + generation. Can be used to tweak the same generation with different prompts. If not provided, a latents + tensor is generated by sampling using the supplied random `generator`. + output_type (`str`, *optional*, defaults to `"pil"`): + The output format of the generated image. Choose between `PIL.Image` or `np.array`. + return_dict (`bool`, *optional*, defaults to `True`): + Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a + plain tuple. + callback (`Callable`, *optional*): + A function that calls every `callback_steps` steps during inference. The function is called with the + following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`. + callback_steps (`int`, *optional*, defaults to 1): + The frequency at which the `callback` function is called. If not specified, the callback is called at + every step. + + Returns: + [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`: + If `return_dict` is `True`, [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] is returned, + otherwise a `tuple` is returned where the first element is a list with the generated images and the + second element is a list of `bool`s indicating whether the corresponding generated image contains + "not-safe-for-work" (nsfw) content. + + Examples: + + ```py + from diffusers import StableDiffusionImageVariationPipeline + from PIL import Image + from io import BytesIO + import requests + + pipe = StableDiffusionImageVariationPipeline.from_pretrained( + "lambdalabs/sd-image-variations-diffusers", revision="v2.0" + ) + pipe = pipe.to("cuda") + + url = "https://lh3.googleusercontent.com/y-iFOHfLTwkuQSUegpwDdgKmOjRSTvPxat63dQLB25xkTs4lhIbRUFeNBWZzYf370g=s1200" + + response = requests.get(url) + image = Image.open(BytesIO(response.content)).convert("RGB") + + out = pipe(image, num_images_per_prompt=3, guidance_scale=15) + out["images"][0].save("result.jpg") + ``` + """ + # 0. Default height and width to unet + height = height or self.unet.config.sample_size * self.vae_scale_factor + width = width or self.unet.config.sample_size * self.vae_scale_factor + + # 1. Check inputs. Raise error if not correct + self.check_inputs(image, height, width, callback_steps) + + + # 2. Define call parameters + if isinstance(image, list): + batch_size = len(image) + elif isinstance(image, torch.Tensor): + batch_size = image.shape[0] + assert batch_size >= self.num_views and batch_size % self.num_views == 0 + elif isinstance(image, PIL.Image.Image): + image = [image]*self.num_views*2 + batch_size = self.num_views*2 + + device = self._execution_device + dtype = self.vae.dtype + # here `guidance_scale` is defined analog to the guidance weight `w` of equation (2) + # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1` + # corresponds to doing no classifier free guidance. + do_classifier_free_guidance = guidance_scale != 1.0 + + # 3. Encode input image + if isinstance(image, list): + image_pil = image + elif isinstance(image, torch.Tensor): + image_pil = [TF.to_pil_image(image[i]) for i in range(image.shape[0])] + image_embeddings, image_latents = self._encode_image(image_pil, device, num_images_per_prompt, do_classifier_free_guidance) + + if normal_cond is not None: + if isinstance(normal_cond, list): + normal_cond_pil = normal_cond + elif isinstance(normal_cond, torch.Tensor): + normal_cond_pil = [TF.to_pil_image(normal_cond[i]) for i in range(normal_cond.shape[0])] + _, image_latents = self._encode_image(normal_cond_pil, device, num_images_per_prompt, do_classifier_free_guidance) + + + # assert len(elevation_cond) == batch_size and len(elevation) == batch_size and len(azimuth) == batch_size + # camera_embeddings = self.prepare_camera_condition(elevation_cond, elevation, azimuth, do_classifier_free_guidance=do_classifier_free_guidance, num_images_per_prompt=num_images_per_prompt) + + if camera_embedding is not None: + assert len(camera_embedding) == batch_size + else: + camera_embedding = self.camera_embedding.to(dtype) + camera_embedding = repeat(camera_embedding, "Nv Nce -> (B Nv) Nce", B=batch_size//len(camera_embedding)) + camera_embeddings = self.prepare_camera_embedding(camera_embedding, do_classifier_free_guidance=do_classifier_free_guidance, num_images_per_prompt=num_images_per_prompt) + + # 4. Prepare timesteps + self.scheduler.set_timesteps(num_inference_steps, device=device) + timesteps = self.scheduler.timesteps + + # 5. Prepare latent variables + num_channels_latents = self.unet.config.out_channels + latents = self.prepare_latents( + batch_size * num_images_per_prompt, + num_channels_latents, + height, + width, + image_embeddings.dtype, + device, + generator, + latents, + ) + + # 6. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline + extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) + + # 7. Denoising loop + num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order + with self.progress_bar(total=num_inference_steps) as progress_bar: + for i, t in enumerate(timesteps): + # expand the latents if we are doing classifier free guidance + latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents + latent_model_input = torch.cat([ + latent_model_input, image_latents + ], dim=1) + latent_model_input = self.scheduler.scale_model_input(latent_model_input, t) + + # predict the noise residual + noise_pred = self.unet(latent_model_input, t, encoder_hidden_states=image_embeddings, class_labels=camera_embeddings).sample + + # perform guidance + if do_classifier_free_guidance: + noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) + noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond) + + # compute the previous noisy sample x_t -> x_t-1 + latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs).prev_sample + + # call the callback, if provided + if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0): + progress_bar.update() + if callback is not None and i % callback_steps == 0: + callback(i, t, latents) + + if not output_type == "latent": + if num_channels_latents == 8: + latents = torch.cat([latents[:, :4], latents[:, 4:]], dim=0) + + image = self.vae.decode(latents / self.vae.config.scaling_factor, return_dict=False)[0] + image, has_nsfw_concept = self.run_safety_checker(image, device, image_embeddings.dtype) + else: + image = latents + has_nsfw_concept = None + + if has_nsfw_concept is None: + do_denormalize = [True] * image.shape[0] + else: + do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept] + + image = self.image_processor.postprocess(image, output_type=output_type, do_denormalize=do_denormalize) + + if not return_dict: + return (image, has_nsfw_concept) + + return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept) + diff --git a/apps/third_party/Wonder3D/render_codes/README.md b/apps/third_party/Wonder3D/render_codes/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0993c92abebb6fbe9930e14bdd957fb8ad2daf1c --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/README.md @@ -0,0 +1,45 @@ +# Prepare the rendering data + +## Environment +The rendering codes are mainly based on [BlenderProc](https://github.com/DLR-RM/BlenderProc). Thanks for the great tool. +BlenderProc uses blender Cycle engine to render the images by default, which may meet long-time hanging problem in some specific GPUs (like A800, tested already) + +` +cd ./render_codes +pip install -r requirements.txt +` + +## How to use the code +Here we provide two rendering scripts `blenderProc_ortho.py` and `blenderProc_persp.py`, which use **orthogonal** camera and **perspective** camera to render the objects respectively. + +### Use `blenderProc_ortho.py` to render images of a single object +` + blenderproc run --blender-install-path /mnt/pfs/users/longxiaoxiao/workplace/blender + blenderProc_ortho.py + --object_path /mnt/pfs/data/objaverse_lvis_glbs/c7/c70e8817b5a945aca8bb37e02ddbc6f9.glb --view 0 + --output_folder ./out_renderings/ + --object_uid c70e8817b5a945aca8bb37e02ddbc6f9 + --ortho_scale 1.35 + --resolution 512 + --random_pose +` + +Here `--view` denotes a tag for the rendering images, since you may render an object multiple times, `--ortho_scale` decides the scaling of rendered object in the image, `--random_pose` will randomly rotate the object before rendering. + + +### Use `blenderProc_persp.py` to render images of a single object + +` + blenderproc run --blender-install-path /mnt/pfs/users/longxiaoxiao/workplace/blender + blenderProc_persp.py + --object_path ${the object path} --view 0 + --output_folder ${your save path} + --object_uid ${object_uid} --radius 2.0 + --random_pose +` + +Here `--radius` denotes the distance of between the camera and the object origin. + +### Render objects in distributed mode +see `render_batch_ortho.sh` and `render_batch_persp.sh` for commands. + diff --git a/apps/third_party/Wonder3D/render_codes/blenderProc_ortho.py b/apps/third_party/Wonder3D/render_codes/blenderProc_ortho.py new file mode 100644 index 0000000000000000000000000000000000000000..ddcae644d4dc4b5059a7f8c8feeda4294c1c5331 --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/blenderProc_ortho.py @@ -0,0 +1,493 @@ +import blenderproc as bproc + +import argparse, sys, os, math, re +import bpy +from glob import glob +from mathutils import Vector, Matrix +import random +import sys +import time +import urllib.request +import uuid +from typing import Tuple +import numpy as np +from blenderproc.python.types.MeshObjectUtility import MeshObject, convert_to_meshes +import pdb + +from math import radians +import cv2 +from scipy.spatial.transform import Rotation as R +import PIL.Image as Image + +parser = argparse.ArgumentParser(description='Renders given obj file by rotation a camera around it.') +parser.add_argument('--view', type=int, default=0, + help='the index of view to be rendered') +parser.add_argument( + "--object_path", + type=str, + default='/ghome/l5/xxlong/.objaverse/hf-objaverse-v1/glbs/000-148/2651a32fb4dc441dab773b8b534b851f.glb', + required=True, + help="Path to the object file", +) +parser.add_argument('--output_folder', type=str, default='output', + help='The path the output will be dumped to.') +# parser.add_argument('--scale', type=float, default=1, +# help='Scaling factor applied to model. Depends on size of mesh.') +# parser.add_argument('--depth_scale', type=float, default=0.1, +# help='Scaling that is applied to depth. Depends on size of mesh. Try out various values until you get a good result. Ignored if format is OPEN_EXR.') +# parser.add_argument('--format', type=str, default='PNG', +# help='Format of files generated. Either PNG or OPEN_EXR') +parser.add_argument('--resolution', type=int, default=512, + help='Resolution of the images.') +parser.add_argument('--ortho_scale', type=float, default=1.25, + help='ortho rendering usage; how large the object is') +parser.add_argument('--object_uid', type=str, default=None) + +parser.add_argument('--random_pose', action='store_true', + help='whether randomly rotate the poses to be rendered') + +parser.add_argument('--reset_object_euler', action='store_true', + help='set object rotation euler to 0') + +# argv = sys.argv[sys.argv.index("--") + 1:] +args = parser.parse_args() + +def scene_bbox(single_obj=None, ignore_matrix=False): + bbox_min = (math.inf,) * 3 + bbox_max = (-math.inf,) * 3 + found = False + for obj in scene_meshes() if single_obj is None else [single_obj]: + found = True + for coord in obj.bound_box: + coord = Vector(coord) + if not ignore_matrix: + coord = obj.matrix_world @ coord + bbox_min = tuple(min(x, y) for x, y in zip(bbox_min, coord)) + bbox_max = tuple(max(x, y) for x, y in zip(bbox_max, coord)) + if not found: + raise RuntimeError("no objects in scene to compute bounding box for") + return Vector(bbox_min), Vector(bbox_max) + + +def scene_root_objects(): + for obj in bpy.context.scene.objects.values(): + if not obj.parent: + yield obj + + +def scene_meshes(): + for obj in bpy.context.scene.objects.values(): + if isinstance(obj.data, (bpy.types.Mesh)): + yield obj + +def normalize_scene(): + bbox_min, bbox_max = scene_bbox() + + dxyz = bbox_max - bbox_min + dist = np.sqrt(dxyz[0]**2+ dxyz[1]**2+dxyz[2]**2) +# print("dxyz: ",dxyz, "dist: ", dist) + # scale = 1 / max(bbox_max - bbox_min) + scale = 1. / dist + for obj in scene_root_objects(): + obj.scale = obj.scale * scale + # Apply scale to matrix_world. + bpy.context.view_layer.update() + bbox_min, bbox_max = scene_bbox() + offset = -(bbox_min + bbox_max) / 2 + for obj in scene_root_objects(): + obj.matrix_world.translation += offset + bpy.ops.object.select_all(action="DESELECT") + + return scale, offset + +def get_a_camera_location(loc): + location = Vector([loc[0],loc[1],loc[2]]) + direction = - location + rot_quat = direction.to_track_quat('-Z', 'Y') + rotation_euler = rot_quat.to_euler() + return location, rotation_euler + + +# function from https://github.com/panmari/stanford-shapenet-renderer/blob/master/render_blender.py +def get_3x4_RT_matrix_from_blender(cam): + # bcam stands for blender camera + # R_bcam2cv = Matrix( + # ((1, 0, 0), + # (0, 1, 0), + # (0, 0, 1))) + + # Transpose since the rotation is object rotation, + # and we want coordinate rotation + # R_world2bcam = cam.rotation_euler.to_matrix().transposed() + # T_world2bcam = -1*R_world2bcam @ location + # + # Use matrix_world instead to account for all constraints + location, rotation = cam.matrix_world.decompose()[0:2] + R_world2bcam = rotation.to_matrix().transposed() + + # Convert camera location to translation vector used in coordinate changes + # T_world2bcam = -1*R_world2bcam @ cam.location + # Use location from matrix_world to account for constraints: + T_world2bcam = -1*R_world2bcam @ location + + # # Build the coordinate transform matrix from world to computer vision camera + # R_world2cv = R_bcam2cv@R_world2bcam + # T_world2cv = R_bcam2cv@T_world2bcam + + # put into 3x4 matrix + RT = Matrix(( + R_world2bcam[0][:] + (T_world2bcam[0],), + R_world2bcam[1][:] + (T_world2bcam[1],), + R_world2bcam[2][:] + (T_world2bcam[2],) + )) + return RT + +def get_calibration_matrix_K_from_blender(mode='simple'): + + scene = bpy.context.scene + + scale = scene.render.resolution_percentage / 100 + width = scene.render.resolution_x * scale # px + height = scene.render.resolution_y * scale # px + + camdata = scene.camera.data + + if mode == 'simple': + + aspect_ratio = width / height + K = np.zeros((3,3), dtype=np.float32) + K[0][0] = width / 2 / np.tan(camdata.angle / 2) + K[1][1] = height / 2. / np.tan(camdata.angle / 2) * aspect_ratio + K[0][2] = width / 2. + K[1][2] = height / 2. + K[2][2] = 1. + K.transpose() + + if mode == 'complete': + + focal = camdata.lens # mm + sensor_width = camdata.sensor_width # mm + sensor_height = camdata.sensor_height # mm + pixel_aspect_ratio = scene.render.pixel_aspect_x / scene.render.pixel_aspect_y + + if (camdata.sensor_fit == 'VERTICAL'): + # the sensor height is fixed (sensor fit is horizontal), + # the sensor width is effectively changed with the pixel aspect ratio + s_u = width / sensor_width / pixel_aspect_ratio + s_v = height / sensor_height + else: # 'HORIZONTAL' and 'AUTO' + # the sensor width is fixed (sensor fit is horizontal), + # the sensor height is effectively changed with the pixel aspect ratio + pixel_aspect_ratio = scene.render.pixel_aspect_x / scene.render.pixel_aspect_y + s_u = width / sensor_width + s_v = height * pixel_aspect_ratio / sensor_height + + # parameters of intrinsic calibration matrix K + alpha_u = focal * s_u + alpha_v = focal * s_v + u_0 = width / 2 + v_0 = height / 2 + skew = 0 # only use rectangular pixels + + K = np.array([ + [alpha_u, skew, u_0], + [ 0, alpha_v, v_0], + [ 0, 0, 1] + ], dtype=np.float32) + + return K + +# load the glb model +def load_object(object_path: str) -> None: + """Loads a glb model into the scene.""" + if object_path.endswith(".glb"): + bpy.ops.import_scene.gltf(filepath=object_path, merge_vertices=False) + elif object_path.endswith(".fbx"): + bpy.ops.import_scene.fbx(filepath=object_path) + elif object_path.endswith(".obj"): + bpy.ops.import_scene.obj(filepath=object_path) + elif object_path.endswith(".ply"): + bpy.ops.import_mesh.ply(filepath=object_path) + else: + raise ValueError(f"Unsupported file type: {object_path}") + +def reset_scene() -> None: + """Resets the scene to a clean state.""" + # delete everything that isn't part of a camera or a light + for obj in bpy.data.objects: + if obj.type not in {"CAMERA", "LIGHT"}: + bpy.data.objects.remove(obj, do_unlink=True) + # delete all the materials + for material in bpy.data.materials: + bpy.data.materials.remove(material, do_unlink=True) + # delete all the textures + for texture in bpy.data.textures: + bpy.data.textures.remove(texture, do_unlink=True) + # delete all the images + for image in bpy.data.images: + bpy.data.images.remove(image, do_unlink=True) + +bproc.init() + +world_tree = bpy.context.scene.world.node_tree +back_node = world_tree.nodes['Background'] +env_light = 0.4 +back_node.inputs['Color'].default_value = Vector([env_light, env_light, env_light, 1.0]) +back_node.inputs['Strength'].default_value = 0.5 + +# Place camera + +bpy.data.cameras[0].type = "ORTHO" +bpy.data.cameras[0].ortho_scale = args.ortho_scale +# cam = bpy.context.scene.objects['Camera'] +# cam.data.type = "ORTHO" +# cam.data.ortho_scale = args.ortho_scale +print("ortho scale ", args.ortho_scale) + +# cam_constraint = cam.constraints.new(type='TRACK_TO') +# cam_constraint.track_axis = 'TRACK_NEGATIVE_Z' +# cam_constraint.up_axis = 'UP_Y' + + +#Make light just directional, disable shadows. +light = bproc.types.Light(name='Light', light_type='SUN') +light = bpy.data.lights['Light'] +light.use_shadow = False +# Possibly disable specular shading: +light.specular_factor = 1.0 +light.energy = 5.0 + +#Add another light source so stuff facing away from light is not completely dark +light2 = bproc.types.Light(name='Light2', light_type='SUN') +light2 = bpy.data.lights['Light2'] +light2.use_shadow = False +light2.specular_factor = 1.0 +light2.energy = 3 #0.015 +bpy.data.objects['Light2'].rotation_euler = bpy.data.objects['Light'].rotation_euler +bpy.data.objects['Light2'].rotation_euler[0] += 180 + +#Add another light source so stuff facing away from light is not completely dark +light3 = bproc.types.Light(name='light3', light_type='SUN') +light3 = bpy.data.lights['light3'] +light3.use_shadow = False +light3.specular_factor = 1.0 +light3.energy = 3 #0.015 +bpy.data.objects['light3'].rotation_euler = bpy.data.objects['Light'].rotation_euler +bpy.data.objects['light3'].rotation_euler[0] += 90 + +#Add another light source so stuff facing away from light is not completely dark +light4 = bproc.types.Light(name='light4', light_type='SUN') +light4 = bpy.data.lights['light4'] +light4.use_shadow = False +light4.specular_factor = 1.0 +light4.energy = 3 #0.015 +bpy.data.objects['light4'].rotation_euler = bpy.data.objects['Light'].rotation_euler +bpy.data.objects['light4'].rotation_euler[0] += -90 + + + +# Get all camera objects in the scene +def get_camera_objects(): + cameras = [obj for obj in bpy.context.scene.objects if obj.type == 'CAMERA'] + return cameras + + +VIEWS = ["_front", "_back", "_right", "_left", "_front_right", "_front_left", "_back_right", "_back_left", "_top"] +EXTRA_VIEWS = ["_front_right_top", "_front_left_top", "_back_right_top", "_back_left_top", ] + +def save_images(object_file: str, viewidx: int) -> None: + global VIEWS + global EXTRA_VIEWS + reset_scene() + + # load the object + load_object(object_file) + if args.object_uid is None: + object_uid = os.path.basename(object_file).split(".")[0] + else: + object_uid = args.object_uid + args.output_folder = os.path.join(args.output_folder, object_uid[:2]) + os.makedirs(os.path.join(args.output_folder, object_uid), exist_ok=True) + + if args.reset_object_euler: + for obj in scene_root_objects(): + obj.rotation_euler[0] = 0 # don't know why + bpy.ops.object.select_all(action="DESELECT") + + scale , offset = normalize_scene() + + Scale_path = os.path.join(args.output_folder, object_uid, "scale_offset_matrix.txt") + np.savetxt(Scale_path, [scale]+list(offset)+[args.ortho_scale]) + + try: + # some objects' normals are affected by textures + mesh_objects = convert_to_meshes([obj for obj in scene_meshes()]) + for obj in mesh_objects: + print("removing invalid normals") + for mat in obj.get_materials(): + mat.set_principled_shader_value("Normal", [1,1,1]) + except: + print("don't know why") + + cam_empty = bpy.data.objects.new("Empty", None) + cam_empty.location = (0, 0, 0) + bpy.context.scene.collection.objects.link(cam_empty) + + radius = 2.0 + + camera_locations = [ + np.array([0,-radius,0]), # camera_front + np.array([0,radius,0]), # camera back + np.array([radius,0,0]), # camera right + np.array([-radius,0,0]), # camera left + np.array([radius,-radius,0]) / np.sqrt(2.) , # camera_front_right + np.array([-radius,-radius,0]) / np.sqrt(2.), # camera front left + np.array([radius,radius,0]) / np.sqrt(2.), # camera back right + np.array([-radius,radius,0]) / np.sqrt(2.), # camera back left + np.array([0,0,radius]), # camera top + np.array([radius,-radius,radius]) / np.sqrt(3.) , # camera_front_right_top + np.array([-radius,-radius,radius]) / np.sqrt(3.), # camera front left top + np.array([radius,radius,radius]) / np.sqrt(3.), # camera back right top + np.array([-radius,radius,radius]) / np.sqrt(3.), # camera back left top + ] + + for location in camera_locations: + _location,_rotation = get_a_camera_location(location) + bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=_location, rotation=_rotation,scale=(1, 1, 1)) + _camera = bpy.context.selected_objects[0] + _constraint = _camera.constraints.new(type='TRACK_TO') + _constraint.track_axis = 'TRACK_NEGATIVE_Z' + _constraint.up_axis = 'UP_Y' + _camera.parent = cam_empty + _constraint.target = cam_empty + _constraint.owner_space = 'LOCAL' + + bpy.context.view_layer.update() + + bpy.ops.object.select_all(action='DESELECT') + cam_empty.select_set(True) + + if args.random_pose : + print("random poses") + delta_z = np.random.uniform(-60, 60, 1) # left right rotate + delta_x = np.random.uniform(-15, 30, 1) # up and down rotate + delta_y = 0 + else: + print("fix poses") + delta_z = 0 + delta_x = 0 + delta_y = 0 + + bpy.ops.transform.rotate(value=math.radians(delta_z),orient_axis='Z',orient_type='VIEW') + bpy.ops.transform.rotate(value=math.radians(delta_y),orient_axis='Y',orient_type='VIEW') + bpy.ops.transform.rotate(value=math.radians(delta_x),orient_axis='X',orient_type='VIEW') + + bpy.ops.object.select_all(action='DESELECT') + + VIEWS = VIEWS + EXTRA_VIEWS + for j in range(len(VIEWS)): + view = f"{viewidx:03d}"+ VIEWS[j] + # set camera + cam = bpy.data.objects[f'Camera.{j+1:03d}'] + location, rotation = cam.matrix_world.decompose()[0:2] + + print(j, rotation) + + cam_pose = bproc.math.build_transformation_mat(location, rotation.to_matrix()) + bproc.camera.set_resolution(args.resolution, args.resolution) + bproc.camera.add_camera_pose(cam_pose) + + # save camera RT matrix + RT = get_3x4_RT_matrix_from_blender(cam) + # print(np.linalg.inv(cam_pose)) # the same + # print(RT) + # idx = 4*i+j + RT_path = os.path.join(args.output_folder, object_uid, view+"_RT.txt") + K_path = os.path.join(args.output_folder, object_uid, view+"_K.txt") + # NT_path = os.path.join(args.output_folder, object_uid, f"{i:03d}_NT.npy") + K = get_calibration_matrix_K_from_blender() + np.savetxt(RT_path, RT) + # np.savetxt(K_path, K) + + + # activate normal and depth rendering + # must be here + bproc.renderer.enable_normals_output() + bproc.renderer.enable_depth_output(activate_antialiasing=False) + # Render the scene + data = bproc.renderer.render() + + for j in range(len(VIEWS)): + index = j + + view = f"{viewidx:03d}"+ VIEWS[j] + + # Nomralizes depth maps + depth_map = data['depth'][index] + depth_max = np.max(depth_map) + valid_mask = depth_map!=depth_max + invalid_mask = depth_map==depth_max + depth_map[invalid_mask] = 0 + + depth_map = np.uint16((depth_map / 10) * 65535) + + normal_map = data['normals'][index]*255 + + valid_mask = valid_mask.astype(np.int8)*255 + + color_map = data['colors'][index] + color_map = np.concatenate([color_map, valid_mask[:, :, None]], axis=-1) + + normal_map = np.concatenate([normal_map, valid_mask[:, :, None]], axis=-1) + + Image.fromarray(color_map.astype(np.uint8)).save( + '{}/{}/rgb_{}.webp'.format(args.output_folder, object_uid, view), "webp", quality=100) + + Image.fromarray(normal_map.astype(np.uint8)).save( + '{}/{}/normals_{}.webp'.format(args.output_folder, object_uid, view), "webp", quality=100) + + # cv2.imwrite('{}/{}/rgb_{}.png'.format(args.output_folder, object_uid, view), color_map) + # cv2.imwrite('{}/{}/depth_{}.png'.format(args.output_folder,object_uid, view), depth_map) + # cv2.imwrite('{}/{}/normals_{}.png'.format(args.output_folder,object_uid, view), normal_map) + # cv2.imwrite('{}/{}/mask_{}.png'.format(args.output_folder,object_uid, view), valid_mask) + + +def download_object(object_url: str) -> str: + """Download the object and return the path.""" + # uid = uuid.uuid4() + uid = object_url.split("/")[-1].split(".")[0] + tmp_local_path = os.path.join("tmp-objects", f"{uid}.glb" + ".tmp") + local_path = os.path.join("tmp-objects", f"{uid}.glb") + # wget the file and put it in local_path + os.makedirs(os.path.dirname(tmp_local_path), exist_ok=True) + urllib.request.urlretrieve(object_url, tmp_local_path) + os.rename(tmp_local_path, local_path) + # get the absolute path + local_path = os.path.abspath(local_path) + return local_path + +if __name__ == "__main__": + # try: + start_i = time.time() + if args.object_path.startswith("http"): + local_path = download_object(args.object_path) + else: + local_path = args.object_path + + if not os.path.exists(local_path): + print("object does not exists") + else: + try: + save_images(local_path, args.view) + except Exception as e: + print("Failed to render", args.object_path) + print(e) + + end_i = time.time() + print("Finished", local_path, "in", end_i - start_i, "seconds") + # delete the object if it was downloaded + if args.object_path.startswith("http"): + os.remove(local_path) + # except Exception as e: + # print("Failed to render", args.object_path) + # print(e) diff --git a/apps/third_party/Wonder3D/render_codes/blenderProc_persp.py b/apps/third_party/Wonder3D/render_codes/blenderProc_persp.py new file mode 100644 index 0000000000000000000000000000000000000000..b0170267d1e6bbb498ea0e7c9e4afb830eca0edb --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/blenderProc_persp.py @@ -0,0 +1,468 @@ +import blenderproc as bproc + +import argparse, sys, os, math, re +import bpy +from glob import glob +from mathutils import Vector, Matrix +import random +import sys +import time +import urllib.request +from typing import Tuple +import numpy as np +from blenderproc.python.types.MeshObjectUtility import MeshObject, convert_to_meshes +import pdb + +from math import radians +import cv2 +from scipy.spatial.transform import Rotation as R + +import PIL.Image as Image + +parser = argparse.ArgumentParser(description='Renders given obj file by rotation a camera around it.') +parser.add_argument('--view', type=int, default=0, + help='the index of view to be rendered') +parser.add_argument( + "--object_path", + type=str, + default='/ghome/l5/xxlong/.objaverse/hf-objaverse-v1/glbs/000-148/2651a32fb4dc441dab773b8b534b851f.glb', + required=True, + help="Path to the object file", +) +parser.add_argument('--output_folder', type=str, default='output', + help='The path the output will be dumped to.') +parser.add_argument('--resolution', type=int, default=256, + help='Resolution of the images.') +parser.add_argument('--object_uid', type=str, default=None) + +parser.add_argument('--random_pose', action='store_true', + help='whether randomly rotate the poses to be rendered') +parser.add_argument('--reset_object_euler', action='store_true', + help='set object rotation euler to 0') + +parser.add_argument('--radius', type=float, default=1.5, + help='radius of rendering sphere') +parser.add_argument('--delta_z', type=float, default=0, + help='delta_z to rotate poses') +parser.add_argument('--delta_x', type=float, default=0, + help='delta_x to rotate poses') +parser.add_argument('--delta_y', type=float, default=0) + +# argv = sys.argv[sys.argv.index("--") + 1:] +args = parser.parse_args() + +def scene_bbox(single_obj=None, ignore_matrix=False): + bbox_min = (math.inf,) * 3 + bbox_max = (-math.inf,) * 3 + found = False + for obj in scene_meshes() if single_obj is None else [single_obj]: + found = True + for coord in obj.bound_box: + coord = Vector(coord) + if not ignore_matrix: + coord = obj.matrix_world @ coord + bbox_min = tuple(min(x, y) for x, y in zip(bbox_min, coord)) + bbox_max = tuple(max(x, y) for x, y in zip(bbox_max, coord)) + if not found: + raise RuntimeError("no objects in scene to compute bounding box for") + return Vector(bbox_min), Vector(bbox_max) + + +def scene_root_objects(): + for obj in bpy.context.scene.objects.values(): + if not obj.parent: + yield obj + + +def scene_meshes(): + for obj in bpy.context.scene.objects.values(): + if isinstance(obj.data, (bpy.types.Mesh)): + yield obj + +def normalize_scene(): + bbox_min, bbox_max = scene_bbox() + + dxyz = bbox_max - bbox_min +# dist = np.sqrt(dxyz[0]**2+ dxyz[1]**2+dxyz[2]**2) +# print("dxyz: ",dxyz, "dist: ", dist) + scale = 1 / max(bbox_max - bbox_min) + # scale = 1. / dist + for obj in scene_root_objects(): + obj.scale = obj.scale * scale + # Apply scale to matrix_world. + bpy.context.view_layer.update() + bbox_min, bbox_max = scene_bbox() + offset = -(bbox_min + bbox_max) / 2 + for obj in scene_root_objects(): + obj.matrix_world.translation += offset + bpy.ops.object.select_all(action="DESELECT") + + return scale, offset + +def get_a_camera_location(loc): + location = Vector([loc[0],loc[1],loc[2]]) + direction = - location + rot_quat = direction.to_track_quat('-Z', 'Y') + rotation_euler = rot_quat.to_euler() + return location, rotation_euler + + +# function from https://github.com/panmari/stanford-shapenet-renderer/blob/master/render_blender.py +def get_3x4_RT_matrix_from_blender(cam): + # bcam stands for blender camera + # R_bcam2cv = Matrix( + # ((1, 0, 0), + # (0, 1, 0), + # (0, 0, 1))) + + # Transpose since the rotation is object rotation, + # and we want coordinate rotation + # R_world2bcam = cam.rotation_euler.to_matrix().transposed() + # T_world2bcam = -1*R_world2bcam @ location + # + # Use matrix_world instead to account for all constraints + location, rotation = cam.matrix_world.decompose()[0:2] + R_world2bcam = rotation.to_matrix().transposed() + + # Convert camera location to translation vector used in coordinate changes + # T_world2bcam = -1*R_world2bcam @ cam.location + # Use location from matrix_world to account for constraints: + T_world2bcam = -1*R_world2bcam @ location + + # # Build the coordinate transform matrix from world to computer vision camera + # R_world2cv = R_bcam2cv@R_world2bcam + # T_world2cv = R_bcam2cv@T_world2bcam + + # put into 3x4 matrix + RT = Matrix(( + R_world2bcam[0][:] + (T_world2bcam[0],), + R_world2bcam[1][:] + (T_world2bcam[1],), + R_world2bcam[2][:] + (T_world2bcam[2],) + )) + return RT + +def get_calibration_matrix_K_from_blender(mode='simple'): + + scene = bpy.context.scene + + scale = scene.render.resolution_percentage / 100 + width = scene.render.resolution_x * scale # px + height = scene.render.resolution_y * scale # px + + camdata = scene.camera.data + + if mode == 'simple': + + aspect_ratio = width / height + K = np.zeros((3,3), dtype=np.float32) + K[0][0] = width / 2 / np.tan(camdata.angle / 2) + K[1][1] = height / 2. / np.tan(camdata.angle / 2) * aspect_ratio + K[0][2] = width / 2. + K[1][2] = height / 2. + K[2][2] = 1. + K.transpose() + + if mode == 'complete': + + focal = camdata.lens # mm + sensor_width = camdata.sensor_width # mm + sensor_height = camdata.sensor_height # mm + pixel_aspect_ratio = scene.render.pixel_aspect_x / scene.render.pixel_aspect_y + + if (camdata.sensor_fit == 'VERTICAL'): + # the sensor height is fixed (sensor fit is horizontal), + # the sensor width is effectively changed with the pixel aspect ratio + s_u = width / sensor_width / pixel_aspect_ratio + s_v = height / sensor_height + else: # 'HORIZONTAL' and 'AUTO' + # the sensor width is fixed (sensor fit is horizontal), + # the sensor height is effectively changed with the pixel aspect ratio + pixel_aspect_ratio = scene.render.pixel_aspect_x / scene.render.pixel_aspect_y + s_u = width / sensor_width + s_v = height * pixel_aspect_ratio / sensor_height + + # parameters of intrinsic calibration matrix K + alpha_u = focal * s_u + alpha_v = focal * s_v + u_0 = width / 2 + v_0 = height / 2 + skew = 0 # only use rectangular pixels + + K = np.array([ + [alpha_u, skew, u_0], + [ 0, alpha_v, v_0], + [ 0, 0, 1] + ], dtype=np.float32) + + return K + +# load the glb model +def load_object(object_path: str) -> None: + """Loads a glb model into the scene.""" + if object_path.endswith(".glb"): + bpy.ops.import_scene.gltf(filepath=object_path, merge_vertices=False) + elif object_path.endswith(".fbx"): + bpy.ops.import_scene.fbx(filepath=object_path) + elif object_path.endswith(".obj"): + bpy.ops.import_scene.obj(filepath=object_path) + elif object_path.endswith(".ply"): + bpy.ops.import_mesh.ply(filepath=object_path) + else: + raise ValueError(f"Unsupported file type: {object_path}") + +def reset_scene() -> None: + """Resets the scene to a clean state.""" + # delete everything that isn't part of a camera or a light + for obj in bpy.data.objects: + if obj.type not in {"CAMERA", "LIGHT"}: + bpy.data.objects.remove(obj, do_unlink=True) + # delete all the materials + for material in bpy.data.materials: + bpy.data.materials.remove(material, do_unlink=True) + # delete all the textures + for texture in bpy.data.textures: + bpy.data.textures.remove(texture, do_unlink=True) + # delete all the images + for image in bpy.data.images: + bpy.data.images.remove(image, do_unlink=True) + +bproc.init() + +world_tree = bpy.context.scene.world.node_tree +back_node = world_tree.nodes['Background'] +env_light = 0.5 +back_node.inputs['Color'].default_value = Vector([env_light, env_light, env_light, 1.0]) +back_node.inputs['Strength'].default_value = 1.0 + +#Place camera +cam = bpy.context.scene.objects['Camera'] +# cam.location = (0, 1, 0.6) +cam.data.lens = 35 +cam.data.sensor_width = 32 + +# cam_constraint = cam.constraints.new(type='TRACK_TO') +# cam_constraint.track_axis = 'TRACK_NEGATIVE_Z' +# cam_constraint.up_axis = 'UP_Y' + + +#Make light just directional, disable shadows. +light = bproc.types.Light(name='Light', light_type='SUN') +light = bpy.data.lights['Light'] +light.use_shadow = False +# Possibly disable specular shading: +light.specular_factor = 1.0 +light.energy = 5.0 + +#Add another light source so stuff facing away from light is not completely dark +light2 = bproc.types.Light(name='Light2', light_type='SUN') +light2 = bpy.data.lights['Light2'] +light2.use_shadow = False +light2.specular_factor = 1.0 +light2.energy = 1 #0.015 +bpy.data.objects['Light2'].rotation_euler = bpy.data.objects['Light'].rotation_euler +bpy.data.objects['Light2'].rotation_euler[0] += 180 + + + +# Get all camera objects in the scene +def get_camera_objects(): + cameras = [obj for obj in bpy.context.scene.objects if obj.type == 'CAMERA'] + return cameras + + +VIEWS = ["_front", "_back", "_right", "_left", "_front_right", "_front_left", "_back_right", "_back_left", "_top"] + +def save_images(object_file: str, viewidx: int) -> None: + + reset_scene() + + # load the object + load_object(object_file) + if args.object_uid is None: + object_uid = os.path.basename(object_file).split(".")[0] + else: + object_uid = args.object_uid + + # cname = "_r%.2f_dx%.1f_dy%.1f_dz%.1f" % (args.radius, args.delta_x, args.delta_y, args.delta_z) + # object_uid = object_uid + cname + os.makedirs(os.path.join(args.output_folder, object_uid), exist_ok=True) + + if args.reset_object_euler: + for obj in scene_root_objects(): + obj.rotation_euler[0] = 0 # don't know why + bpy.ops.object.select_all(action="DESELECT") + + scale , offset = normalize_scene() + + Scale_path = os.path.join(args.output_folder, object_uid, "scale_offset_matrix.txt") + # print(scale) + # print(offset) + np.savetxt(Scale_path, [scale]+list(offset)+[args.delta_x, args.delta_y, args.delta_z]) + + try: + # some objects' normals are affected by textures + mesh_objects = convert_to_meshes([obj for obj in scene_meshes()]) + for obj in mesh_objects: + print("removing invalid normals") + for mat in obj.get_materials(): + mat.set_principled_shader_value("Normal", [1,1,1]) + except: + print("don't know why") + + cam_empty = bpy.data.objects.new("Empty", None) + cam_empty.location = (0, 0, 0) + bpy.context.scene.collection.objects.link(cam_empty) + + radius = args.radius + + camera_locations = [ + np.array([0,-radius,0]), # camera_front + np.array([0,radius,0]), # camera back + np.array([radius,0,0]), # camera right + np.array([-radius,0,0]), # camera left + np.array([radius,-radius,0]) / np.sqrt(2.) , # camera_front_right + np.array([-radius,-radius,0]) / np.sqrt(2.), # camera front left + np.array([radius,radius,0]) / np.sqrt(2.), # camera back right + np.array([-radius,radius,0]) / np.sqrt(2.), # camera back left + np.array([0,0,radius]), # camera top + ] + + for location in camera_locations: + _location,_rotation = get_a_camera_location(location) + bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=_location, rotation=_rotation,scale=(1, 1, 1)) + _camera = bpy.context.selected_objects[0] + _constraint = _camera.constraints.new(type='TRACK_TO') + _constraint.track_axis = 'TRACK_NEGATIVE_Z' + _constraint.up_axis = 'UP_Y' + _camera.parent = cam_empty + _constraint.target = cam_empty + _constraint.owner_space = 'LOCAL' + + bpy.context.view_layer.update() + + bpy.ops.object.select_all(action='DESELECT') + cam_empty.select_set(True) + + if args.random_pose: + print("random poses") + delta_z = np.random.uniform(-60, 60, 1) # left right rotate + delta_x = np.random.uniform(-15, 30, 1) # up and down rotate + delta_y = 0 + else: + print("fix poses") + delta_z = args.delta_z + delta_x = args.delta_x + delta_y = args.delta_y + + + bpy.ops.transform.rotate(value=math.radians(delta_z),orient_axis='Z',orient_type='VIEW') + bpy.ops.transform.rotate(value=math.radians(delta_y),orient_axis='Y',orient_type='VIEW') + bpy.ops.transform.rotate(value=math.radians(delta_x),orient_axis='X',orient_type='VIEW') + + bpy.ops.object.select_all(action='DESELECT') + + + for j in range(9): + view = f"{viewidx:03d}"+ VIEWS[j] + # set camera + cam = bpy.data.objects[f'Camera.{j+1:03d}'] + location, rotation = cam.matrix_world.decompose()[0:2] + + print(j, rotation) + + cam_pose = bproc.math.build_transformation_mat(location, rotation.to_matrix()) + bproc.camera.set_resolution(args.resolution, args.resolution) + bproc.camera.add_camera_pose(cam_pose) + + # save camera RT matrix + RT = get_3x4_RT_matrix_from_blender(cam) + # print(np.linalg.inv(cam_pose)) # the same + # print(RT) + # idx = 4*i+j + RT_path = os.path.join(args.output_folder, object_uid, view+"_RT.txt") + K_path = os.path.join(args.output_folder, object_uid, view+"_K.txt") + # NT_path = os.path.join(args.output_folder, object_uid, f"{i:03d}_NT.npy") + K = get_calibration_matrix_K_from_blender() + np.savetxt(RT_path, RT) + np.savetxt(K_path, K) + + + # activate normal and depth rendering + # must be here + bproc.renderer.enable_normals_output() + bproc.renderer.enable_depth_output(activate_antialiasing=False) + # Render the scene + data = bproc.renderer.render() + + for j in range(9): + index = j + + view = f"{viewidx:03d}"+ VIEWS[j] + + # Nomralizes depth maps + depth_map = data['depth'][index] + depth_max = np.max(depth_map) + valid_mask = depth_map!=depth_max + invalid_mask = depth_map==depth_max + depth_map[invalid_mask] = 0 + + depth_map = np.uint16((depth_map / 10) * 65535) + + normal_map = data['normals'][index]*255 + + valid_mask = valid_mask.astype(np.int8)*255 + + color_map = data['colors'][index] + color_map = np.concatenate([color_map, valid_mask[:, :, None]], axis=-1) + + Image.fromarray(color_map.astype(np.uint8)).save( + '{}/{}/rgb_{}.webp'.format(args.output_folder, object_uid, view), "webp", quality=100) + + Image.fromarray(normal_map.astype(np.uint8)).save( + '{}/{}/normals_{}.webp'.format(args.output_folder, object_uid, view), "webp", quality=100) + + # cv2.imwrite('{}/{}/rgb_{}.png'.format(args.output_folder, object_uid, view), color_map) + # cv2.imwrite('{}/{}/depth_{}.png'.format(args.output_folder,object_uid, view), depth_map) + # cv2.imwrite('{}/{}/normals_{}.png'.format(args.output_folder,object_uid, view), normal_map) + # cv2.imwrite('{}/{}/mask_{}.png'.format(args.output_folder,object_uid, view), valid_mask) + + +def download_object(object_url: str) -> str: + """Download the object and return the path.""" + # uid = uuid.uuid4() + uid = object_url.split("/")[-1].split(".")[0] + tmp_local_path = os.path.join("tmp-objects", f"{uid}.glb" + ".tmp") + local_path = os.path.join("tmp-objects", f"{uid}.glb") + # wget the file and put it in local_path + os.makedirs(os.path.dirname(tmp_local_path), exist_ok=True) + urllib.request.urlretrieve(object_url, tmp_local_path) + os.rename(tmp_local_path, local_path) + # get the absolute path + local_path = os.path.abspath(local_path) + return local_path + +if __name__ == "__main__": + # try: + start_i = time.time() + if args.object_path.startswith("http"): + local_path = download_object(args.object_path) + else: + local_path = args.object_path + + if not os.path.exists(local_path): + print("object does not exists") + else: + try: + save_images(local_path, args.view) + except Exception as e: + print("Failed to render", args.object_path) + print(e) + + end_i = time.time() + print("Finished", local_path, "in", end_i - start_i, "seconds") + # delete the object if it was downloaded + if args.object_path.startswith("http"): + os.remove(local_path) + # except Exception as e: + # print("Failed to render", args.object_path) + # print(e) diff --git a/apps/third_party/Wonder3D/render_codes/distributed.py b/apps/third_party/Wonder3D/render_codes/distributed.py new file mode 100644 index 0000000000000000000000000000000000000000..218af223a842349dad368a31b9773a754c473a12 --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/distributed.py @@ -0,0 +1,174 @@ +# multiprocessing render +import json +import multiprocessing +import subprocess +from dataclasses import dataclass +from typing import Optional +import os + +import boto3 + +import argparse + +parser = argparse.ArgumentParser(description='distributed rendering') + +parser.add_argument('--workers_per_gpu', type=int, + help='number of workers per gpu.') +parser.add_argument('--input_models_path', type=str, + help='Path to a json file containing a list of 3D object files.') +parser.add_argument('--upload_to_s3', type=bool, default=False, + help='Whether to upload the rendered images to S3.') +parser.add_argument('--log_to_wandb', type=bool, default=False, + help='Whether to log the progress to wandb.') +parser.add_argument('--num_gpus', type=int, default=-1, + help='number of gpus to use. -1 means all available gpus.') +parser.add_argument('--gpu_list',nargs='+', type=int, + help='the avalaible gpus') + +parser.add_argument('--mode', type=str, default='render', + choices=['render_ortho', 'render_persp'], + help='use orthogonal camera or perspective camera') + +parser.add_argument('--start_i', type=int, default=0, + help='the index of first object to be rendered.') + +parser.add_argument('--end_i', type=int, default=-1, + help='the index of the last object to be rendered.') + +parser.add_argument('--objaverse_root', type=str, default='/ghome/l5/xxlong/.objaverse/hf-objaverse-v1', + help='Path to a json file containing a list of 3D object files.') + +parser.add_argument('--save_folder', type=str, default=None, + help='Path to a json file containing a list of 3D object files.') + +parser.add_argument('--blender_install_path', type=str, default=None, + help='blender path.') + +parser.add_argument('--view_idx', type=int, default=2, + help='the number of render views.') + +parser.add_argument('--ortho_scale', type=float, default=1.25, + help='ortho rendering usage; how large the object is') + +parser.add_argument('--random_pose', action='store_true', + help='whether randomly rotate the poses to be rendered') + +args = parser.parse_args() + + +view_idx = args.view_idx + +VIEWS = ["front", "back", "right", "left", "front_right", "front_left", "back_right", "back_left"] + +def check_task_finish(render_dir, view_index): + files_type = ['rgb', 'normals'] + flag = True + view_index = "%03d" % view_index + if os.path.exists(render_dir): + for t in files_type: + for face in VIEWS: + fpath = os.path.join(render_dir, f'{t}_{view_index}_{face}.webp') + # print(fpath) + if not os.path.exists(fpath): + flag = False + else: + flag = False + + return flag + +def worker( + queue: multiprocessing.JoinableQueue, + count: multiprocessing.Value, + gpu: int, + s3: Optional[boto3.client], +) -> None: + while True: + item = queue.get() + if item is None: + break + + view_path = os.path.join(args.save_folder, item.split('/')[-1][:2], item.split('/')[-1][:-4]) + print(view_path) + if 'render' in args.mode: + if check_task_finish(view_path, view_idx): + queue.task_done() + print('========', item, 'rendered', '========') + + continue + else: + os.makedirs(view_path, exist_ok = True) + + # Perform some operation on the item + print(item, gpu) + + if args.mode == 'render_ortho': + command = ( + f" CUDA_VISIBLE_DEVICES={gpu} " + f" blenderproc run --blender-install-path {args.blender_install_path} blenderProc_ortho.py" + f" --object_path {item} --view {view_idx}" + f" --output_folder {args.save_folder}" + f" --ortho_scale {args.ortho_scale} " + ) + if args.random_pose: + print("random pose to render") + command += f" --random_pose" + elif args.mode == 'render_persp': + command = ( + f" CUDA_VISIBLE_DEVICES={gpu} " + f" blenderproc run --blender-install-path {args.blender_install_path} blenderProc_persp.py" + f" --object_path {item} --view {view_idx}" + f" --output_folder {args.save_folder}" + ) + if args.random_pose: + print("random pose to render") + command += f" --random_pose" + + print(command) + subprocess.run(command, shell=True) + + with count.get_lock(): + count.value += 1 + + queue.task_done() + + +if __name__ == "__main__": + # args = tyro.cli(Args) + + s3 = boto3.client("s3") if args.upload_to_s3 else None + queue = multiprocessing.JoinableQueue() + count = multiprocessing.Value("i", 0) + + # Start worker processes on each of the GPUs + for gpu_i in range(args.num_gpus): + for worker_i in range(args.workers_per_gpu): + worker_i = gpu_i * args.workers_per_gpu + worker_i + process = multiprocessing.Process( + target=worker, args=(queue, count, args.gpu_list[gpu_i], s3) + ) + process.daemon = True + process.start() + + # Add items to the queue + if args.input_models_path is not None: + with open(args.input_models_path, "r") as f: + model_paths = json.load(f) + + args.end_i = len(model_paths) if args.end_i > len(model_paths) else args.end_i + + for item in model_paths[args.start_i:args.end_i]: + + if os.path.exists(os.path.join(args.objaverse_root, os.path.basename(item))): + obj_path = os.path.join(args.objaverse_root, os.path.basename(item)) + elif os.path.exists(os.path.join(args.objaverse_root, item)): + obj_path = os.path.join(args.objaverse_root, item) + else: + obj_path = os.path.join(args.objaverse_root, item[:2], item+".glb") + queue.put(obj_path) + + # Wait for all tasks to be completed + queue.join() + + # Add sentinels to the queue to stop the worker processes + for i in range(args.num_gpus * args.workers_per_gpu): + queue.put(None) diff --git a/apps/third_party/Wonder3D/render_codes/render_batch_ortho.sh b/apps/third_party/Wonder3D/render_codes/render_batch_ortho.sh new file mode 100644 index 0000000000000000000000000000000000000000..cb4de10625ee003fe97625527a150cdf5df5f5f8 --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/render_batch_ortho.sh @@ -0,0 +1,9 @@ + python distributed.py \ + --num_gpus 8 --gpu_list 0 1 2 3 4 5 6 7 --mode render_ortho \ + --workers_per_gpu 10 --view_idx $1 \ + --start_i $2 --end_i $3 --ortho_scale 1.35 \ + --input_models_path ../data_lists/lvis_uids_filter_by_vertex.json \ + --objaverse_root /data/objaverse \ + --save_folder data/obj_lvis_13views \ + --blender_install_path /workplace/blender \ + --random_pose diff --git a/apps/third_party/Wonder3D/render_codes/render_batch_persp.sh b/apps/third_party/Wonder3D/render_codes/render_batch_persp.sh new file mode 100644 index 0000000000000000000000000000000000000000..0a8a39d473d0889fa7a969ee93d996646567a3be --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/render_batch_persp.sh @@ -0,0 +1,9 @@ + python distributed.py \ + --num_gpus 8 --gpu_list 0 1 2 3 4 5 6 7 --mode render_persp \ + --workers_per_gpu 10 --view_idx $1 \ + --start_i $2 --end_i $3 \ + --input_models_path ../data_lists/lvis/lvis_uids_filter_by_vertex.json \ + --save_folder /data/nineviews-pinhole \ + --objaverse_root /objaverse \ + --blender_install_path /workplace/blender \ + --random_pose diff --git a/apps/third_party/Wonder3D/render_codes/render_single_ortho.sh b/apps/third_party/Wonder3D/render_codes/render_single_ortho.sh new file mode 100644 index 0000000000000000000000000000000000000000..6b826a5e1b782cbd5382dbe3be763b2ad1f94053 --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/render_single_ortho.sh @@ -0,0 +1,9 @@ +CUDA_VISIBLE_DEVICES=0 \ + blenderproc run --blender-install-path /mnt/pfs/users/longxiaoxiao/workplace/blender \ + blenderProc_nineviews_ortho.py \ + --object_path /mnt/pfs/data/objaverse_lvis_glbs/c7/c70e8817b5a945aca8bb37e02ddbc6f9.glb --view 0 \ + --output_folder ./out_renderings/ \ + --object_uid c70e8817b5a945aca8bb37e02ddbc6f9 \ + --ortho_scale 1.35 \ + --resolution 512 \ +# --reset_object_euler \ No newline at end of file diff --git a/apps/third_party/Wonder3D/render_codes/render_single_persp.sh b/apps/third_party/Wonder3D/render_codes/render_single_persp.sh new file mode 100644 index 0000000000000000000000000000000000000000..a49a1c96867e2b3f690b7fa2b6b46235728fc1a7 --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/render_single_persp.sh @@ -0,0 +1,6 @@ + blenderproc run --blender-install-path /mnt/pfs/users/longxiaoxiao/workplace/blender + blenderProc_persp.py + --object_path ${the object path} --view 0 + --output_folder ${your save path} + --object_uid ${object_uid} --radius 2.0 + --random_pose \ No newline at end of file diff --git a/apps/third_party/Wonder3D/render_codes/requirements.txt b/apps/third_party/Wonder3D/render_codes/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..fe6655629a4d2f2f3c4b3c49e72d8cf3ef0d48f9 --- /dev/null +++ b/apps/third_party/Wonder3D/render_codes/requirements.txt @@ -0,0 +1,27 @@ + +blenderproc==2.5.0 +boto3==1.26.105 +docstring-parser==0.14.1 +h5py==3.8.0 +imageio==2.9.0 +imageio-ffmpeg==0.4.2 +markdown==3.4.3 +matplotlib==3.7.1 +multiprocess==0.70.13 +objaverse==0.0.7 +omegaconf==2.1.1 +opencv-python==4.5.5.64 +opencv-python-headless==4.7.0.72 +pillow==9.4.0 +progressbar==2.5 +scikit-image==0.20.0 +termcolor==2.2.0 +tqdm==4.65.0 +tyro==0.3.38 +vtk==9.2.6 +wandb==0.14.0 +zipp==3.15.0 +natsort +mathutils==3.3.0 +argparse + diff --git a/apps/third_party/Wonder3D/requirements.txt b/apps/third_party/Wonder3D/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..221bbcf0c03d8d88dea81e3e904d491626162e73 --- /dev/null +++ b/apps/third_party/Wonder3D/requirements.txt @@ -0,0 +1,31 @@ +--extra-index-url https://download.pytorch.org/whl/cu117 +torch==1.13.1 +torchvision==0.14.1 +diffusers[torch]==0.19.3 +xformers==0.0.16 +transformers>=4.25.1 +bitsandbytes==0.35.4 +decord==0.6.0 +pytorch-lightning<2 +omegaconf==2.2.3 +nerfacc==0.3.3 +trimesh==3.9.8 +pyhocon==0.3.57 +icecream==2.1.0 +PyMCubes==0.1.2 +accelerate +modelcards +einops +ftfy +piq +matplotlib +opencv-python +imageio +imageio-ffmpeg +scipy +pyransac3d +torch_efficient_distloss +tensorboard +rembg +segment_anything +gradio==3.50.2 diff --git a/apps/third_party/Wonder3D/run_test.sh b/apps/third_party/Wonder3D/run_test.sh new file mode 100644 index 0000000000000000000000000000000000000000..167046f16f70188969b67d649239cff208ceb5bf --- /dev/null +++ b/apps/third_party/Wonder3D/run_test.sh @@ -0,0 +1 @@ +accelerate launch --config_file 1gpu.yaml test_mvdiffusion_seq.py --config configs/mvdiffusion-joint-ortho-6views.yaml \ No newline at end of file diff --git a/apps/third_party/Wonder3D/run_train_stage1.sh b/apps/third_party/Wonder3D/run_train_stage1.sh new file mode 100644 index 0000000000000000000000000000000000000000..f63dfb4335af4b7a5a60fe48ec16b56afd327c2a --- /dev/null +++ b/apps/third_party/Wonder3D/run_train_stage1.sh @@ -0,0 +1,3 @@ + +# stage 1 +accelerate launch --config_file 1gpu.yaml train_mvdiffusion_image.py --config configs/train/stage1-mix-6views-lvis.yaml \ No newline at end of file diff --git a/apps/third_party/Wonder3D/run_train_stage2.sh b/apps/third_party/Wonder3D/run_train_stage2.sh new file mode 100644 index 0000000000000000000000000000000000000000..18fe25e62c5c9425fdecc3af35d07c5c6a156b83 --- /dev/null +++ b/apps/third_party/Wonder3D/run_train_stage2.sh @@ -0,0 +1,2 @@ +# stage 2 +accelerate launch --config_file 1gpu.yaml train_mvdiffusion_joint.py --config configs/train/stage2-joint-6views-lvis.yaml \ No newline at end of file diff --git a/apps/third_party/Wonder3D/test_mvdiffusion_seq.py b/apps/third_party/Wonder3D/test_mvdiffusion_seq.py new file mode 100644 index 0000000000000000000000000000000000000000..71c1d75a99cae09e91298b15a4133b2ca2befb4f --- /dev/null +++ b/apps/third_party/Wonder3D/test_mvdiffusion_seq.py @@ -0,0 +1,325 @@ +import argparse +import datetime +import logging +import inspect +import math +import os +from typing import Dict, Optional, Tuple, List +from omegaconf import OmegaConf +from PIL import Image +import cv2 +import numpy as np +from dataclasses import dataclass +from packaging import version +import shutil +from collections import defaultdict + +import torch +import torch.nn.functional as F +import torch.utils.checkpoint +import torchvision.transforms.functional as TF +from torchvision.utils import make_grid, save_image + +import transformers +import accelerate +from accelerate import Accelerator +from accelerate.logging import get_logger +from accelerate.utils import ProjectConfiguration, set_seed + +import diffusers +from diffusers import AutoencoderKL, DDPMScheduler, DDIMScheduler, StableDiffusionPipeline, UNet2DConditionModel +from diffusers.optimization import get_scheduler +from diffusers.training_utils import EMAModel +from diffusers.utils import check_min_version, deprecate, is_wandb_available +from diffusers.utils.import_utils import is_xformers_available + +from tqdm.auto import tqdm +from transformers import CLIPTextModel, CLIPTokenizer +from transformers import CLIPImageProcessor, CLIPVisionModelWithProjection + +from mvdiffusion.models.unet_mv2d_condition import UNetMV2DConditionModel + +from mvdiffusion.data.single_image_dataset import SingleImageDataset as MVDiffusionDataset + +from mvdiffusion.pipelines.pipeline_mvdiffusion_image import MVDiffusionImagePipeline + +from einops import rearrange +from rembg import remove +import pdb + +weight_dtype = torch.float16 + + +@dataclass +class TestConfig: + pretrained_model_name_or_path: str + pretrained_unet_path:str + revision: Optional[str] + validation_dataset: Dict + save_dir: str + seed: Optional[int] + validation_batch_size: int + dataloader_num_workers: int + + local_rank: int + + pipe_kwargs: Dict + pipe_validation_kwargs: Dict + unet_from_pretrained_kwargs: Dict + validation_guidance_scales: List[float] + validation_grid_nrow: int + camera_embedding_lr_mult: float + + num_views: int + camera_embedding_type: str + + pred_type: str # joint, or ablation + + enable_xformers_memory_efficient_attention: bool + + cond_on_normals: bool + cond_on_colors: bool + + +def log_validation(dataloader, pipeline, cfg: TestConfig, weight_dtype, name, save_dir): + + + pipeline.set_progress_bar_config(disable=True) + + if cfg.seed is None: + generator = None + else: + generator = torch.Generator(device=pipeline.device).manual_seed(cfg.seed) + + images_cond, images_pred = [], defaultdict(list) + for i, batch in tqdm(enumerate(dataloader)): + # (B, Nv, 3, H, W) + imgs_in = batch['imgs_in'] + alphas = batch['alphas'] + # (B, Nv, Nce) + camera_embeddings = batch['camera_embeddings'] + filename = batch['filename'] + + bsz, num_views = imgs_in.shape[0], imgs_in.shape[1] + # (B*Nv, 3, H, W) + imgs_in = rearrange(imgs_in, "B Nv C H W -> (B Nv) C H W") + alphas = rearrange(alphas, "B Nv C H W -> (B Nv) C H W") + # (B*Nv, Nce) + camera_embeddings = rearrange(camera_embeddings, "B Nv Nce -> (B Nv) Nce") + + images_cond.append(imgs_in) + + with torch.autocast("cuda"): + # B*Nv images + for guidance_scale in cfg.validation_guidance_scales: + out = pipeline( + imgs_in, camera_embeddings, generator=generator, guidance_scale=guidance_scale, output_type='pt', num_images_per_prompt=1, **cfg.pipe_validation_kwargs + ).images + images_pred[f"{name}-sample_cfg{guidance_scale:.1f}"].append(out) + cur_dir = os.path.join(save_dir, f"cropsize-{cfg.validation_dataset.crop_size}-cfg{guidance_scale:.1f}") + + # pdb.set_trace() + for i in range(bsz): + scene = os.path.basename(filename[i]) + print(scene) + scene_dir = os.path.join(cur_dir, scene) + outs_dir = os.path.join(scene_dir, "outs") + masked_outs_dir = os.path.join(scene_dir, "masked_outs") + os.makedirs(outs_dir, exist_ok=True) + os.makedirs(masked_outs_dir, exist_ok=True) + img_in = imgs_in[i*num_views] + alpha = alphas[i*num_views] + img_in = torch.cat([img_in, alpha], dim=0) + save_image(img_in, os.path.join(scene_dir, scene+".png")) + for j in range(num_views): + view = VIEWS[j] + idx = i*num_views + j + pred = out[idx] + + # pdb.set_trace() + out_filename = f"{cfg.pred_type}_000_{view}.png" + pred = save_image(pred, os.path.join(outs_dir, out_filename)) + + rm_pred = remove(pred) + + save_image_numpy(rm_pred, os.path.join(scene_dir, out_filename)) + torch.cuda.empty_cache() + + + +def save_image(tensor, fp): + ndarr = tensor.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy() + # pdb.set_trace() + im = Image.fromarray(ndarr) + im.save(fp) + return ndarr + +def save_image_numpy(ndarr, fp): + im = Image.fromarray(ndarr) + im.save(fp) + +def log_validation_joint(dataloader, pipeline, cfg: TestConfig, weight_dtype, name, save_dir): + + pipeline.set_progress_bar_config(disable=True) + + if cfg.seed is None: + generator = None + else: + generator = torch.Generator(device=pipeline.device).manual_seed(cfg.seed) + + images_cond, normals_pred, images_pred = [], defaultdict(list), defaultdict(list) + for i, batch in tqdm(enumerate(dataloader)): + # repeat (2B, Nv, 3, H, W) + imgs_in = torch.cat([batch['imgs_in']]*2, dim=0) + + filename = batch['filename'] + + # (2B, Nv, Nce) + camera_embeddings = torch.cat([batch['camera_embeddings']]*2, dim=0) + + task_embeddings = torch.cat([batch['normal_task_embeddings'], batch['color_task_embeddings']], dim=0) + + camera_embeddings = torch.cat([camera_embeddings, task_embeddings], dim=-1) + + # (B*Nv, 3, H, W) + imgs_in = rearrange(imgs_in, "B Nv C H W -> (B Nv) C H W") + # (B*Nv, Nce) + camera_embeddings = rearrange(camera_embeddings, "B Nv Nce -> (B Nv) Nce") + + images_cond.append(imgs_in) + num_views = len(VIEWS) + with torch.autocast("cuda"): + # B*Nv images + for guidance_scale in cfg.validation_guidance_scales: + out = pipeline( + imgs_in, camera_embeddings, generator=generator, guidance_scale=guidance_scale, output_type='pt', num_images_per_prompt=1, **cfg.pipe_validation_kwargs + ).images + + bsz = out.shape[0] // 2 + normals_pred = out[:bsz] + images_pred = out[bsz:] + + cur_dir = os.path.join(save_dir, f"cropsize-{cfg.validation_dataset.crop_size}-cfg{guidance_scale:.1f}") + + for i in range(bsz//num_views): + scene = filename[i] + scene_dir = os.path.join(cur_dir, scene) + normal_dir = os.path.join(scene_dir, "normals") + masked_colors_dir = os.path.join(scene_dir, "masked_colors") + os.makedirs(normal_dir, exist_ok=True) + os.makedirs(masked_colors_dir, exist_ok=True) + for j in range(num_views): + view = VIEWS[j] + idx = i*num_views + j + normal = normals_pred[idx] + color = images_pred[idx] + + normal_filename = f"normals_000_{view}.png" + rgb_filename = f"rgb_000_{view}.png" + normal = save_image(normal, os.path.join(normal_dir, normal_filename)) + color = save_image(color, os.path.join(scene_dir, rgb_filename)) + + rm_normal = remove(normal) + rm_color = remove(color) + + save_image_numpy(rm_normal, os.path.join(scene_dir, normal_filename)) + save_image_numpy(rm_color, os.path.join(masked_colors_dir, rgb_filename)) + + torch.cuda.empty_cache() + + +def load_wonder3d_pipeline(cfg): + + pipeline = MVDiffusionImagePipeline.from_pretrained( + cfg.pretrained_model_name_or_path, + torch_dtype=weight_dtype + ) + + # pipeline.to('cuda:0') + pipeline.unet.enable_xformers_memory_efficient_attention() + + + if torch.cuda.is_available(): + pipeline.to('cuda:0') + # sys.main_lock = threading.Lock() + return pipeline + + +def main( + cfg: TestConfig +): + + # If passed along, set the training seed now. + if cfg.seed is not None: + set_seed(cfg.seed) + + pipeline = load_wonder3d_pipeline(cfg) + + if cfg.enable_xformers_memory_efficient_attention: + if is_xformers_available(): + import xformers + + xformers_version = version.parse(xformers.__version__) + if xformers_version == version.parse("0.0.16"): + print( + "xFormers 0.0.16 cannot be used for training in some GPUs. If you observe problems during training, please update xFormers to at least 0.0.17. See https://huggingface.co/docs/diffusers/main/en/optimization/xformers for more details." + ) + pipeline.unet.enable_xformers_memory_efficient_attention() + print("use xformers.") + else: + raise ValueError("xformers is not available. Make sure it is installed correctly") + + # Get the dataset + validation_dataset = MVDiffusionDataset( + **cfg.validation_dataset + ) + + + # DataLoaders creation: + validation_dataloader = torch.utils.data.DataLoader( + validation_dataset, batch_size=cfg.validation_batch_size, shuffle=False, num_workers=cfg.dataloader_num_workers + ) + + + os.makedirs(cfg.save_dir, exist_ok=True) + + if cfg.pred_type == 'joint': + log_validation_joint( + validation_dataloader, + pipeline, + cfg, + weight_dtype, + 'validation', + cfg.save_dir + ) + else: + log_validation( + validation_dataloader, + pipeline, + cfg, + weight_dtype, + 'validation', + cfg.save_dir + ) + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--config', type=str, required=True) + args, extras = parser.parse_known_args() + + from utils.misc import load_config + + # parse YAML config to OmegaConf + cfg = load_config(args.config, cli_args=extras) + print(cfg) + schema = OmegaConf.structured(TestConfig) + # cfg = OmegaConf.load(args.config) + cfg = OmegaConf.merge(schema, cfg) + + if cfg.num_views == 6: + VIEWS = ['front', 'front_right', 'right', 'back', 'left', 'front_left'] + elif cfg.num_views == 4: + VIEWS = ['front', 'right', 'back', 'left'] + main(cfg) diff --git a/apps/third_party/Wonder3D/train_mvdiffusion_image.py b/apps/third_party/Wonder3D/train_mvdiffusion_image.py new file mode 100644 index 0000000000000000000000000000000000000000..23e6b8a908fedd782ba91933f476aa90181065de --- /dev/null +++ b/apps/third_party/Wonder3D/train_mvdiffusion_image.py @@ -0,0 +1,728 @@ +import argparse +import datetime +import logging +import inspect +import math +import os +from typing import Dict, Optional, Tuple, List +from omegaconf import OmegaConf +from PIL import Image +import cv2 +import numpy as np +from dataclasses import dataclass +from packaging import version +import shutil +from collections import defaultdict + +import torch +import torch.nn.functional as F +import torch.utils.checkpoint +import torchvision.transforms.functional as TF +from torchvision.transforms import InterpolationMode +from torchvision.utils import make_grid, save_image + +import transformers +import accelerate +from accelerate import Accelerator +from accelerate.logging import get_logger +from accelerate.utils import ProjectConfiguration, set_seed + +import diffusers +from diffusers import AutoencoderKL, DDPMScheduler, DDIMScheduler, StableDiffusionPipeline +from diffusers.optimization import get_scheduler +from diffusers.training_utils import EMAModel +from diffusers.utils import check_min_version, deprecate, is_wandb_available +from diffusers.utils.import_utils import is_xformers_available + +from tqdm.auto import tqdm +from transformers import CLIPTextModel, CLIPTokenizer +from transformers import CLIPImageProcessor, CLIPVisionModelWithProjection + +from mvdiffusion.models.unet_mv2d_condition import UNetMV2DConditionModel + +# from mvdiffusion.data.dataset_nc import MVDiffusionDatasetV2 as MVDiffusionDataset +from mvdiffusion.data.objaverse_dataset import ObjaverseDataset as MVDiffusionDataset + +from mvdiffusion.pipelines.pipeline_mvdiffusion_image import MVDiffusionImagePipeline + +from einops import rearrange + +import time + +logger = get_logger(__name__, log_level="INFO") + + +@dataclass +class TrainingConfig: + pretrained_model_name_or_path: str + revision: Optional[str] + train_dataset: Dict + validation_dataset: Dict + validation_train_dataset: Dict + output_dir: str + seed: Optional[int] + train_batch_size: int + validation_batch_size: int + validation_train_batch_size: int + max_train_steps: int + gradient_accumulation_steps: int + gradient_checkpointing: bool + learning_rate: float + scale_lr: bool + lr_scheduler: str + lr_warmup_steps: int + snr_gamma: Optional[float] + use_8bit_adam: bool + allow_tf32: bool + use_ema: bool + dataloader_num_workers: int + adam_beta1: float + adam_beta2: float + adam_weight_decay: float + adam_epsilon: float + max_grad_norm: Optional[float] + prediction_type: Optional[str] + logging_dir: str + vis_dir: str + mixed_precision: Optional[str] + report_to: Optional[str] + local_rank: int + checkpointing_steps: int + checkpoints_total_limit: Optional[int] + resume_from_checkpoint: Optional[str] + enable_xformers_memory_efficient_attention: bool + validation_steps: int + validation_sanity_check: bool + tracker_project_name: str + + trainable_modules: Optional[list] + use_classifier_free_guidance: bool + condition_drop_rate: float + scale_input_latents: bool + + pipe_kwargs: Dict + pipe_validation_kwargs: Dict + unet_from_pretrained_kwargs: Dict + validation_guidance_scales: List[float] + validation_grid_nrow: int + camera_embedding_lr_mult: float + + num_views: int + camera_embedding_type: str + + pred_type: str + + drop_type: str + + +def log_validation(dataloader, vae, feature_extractor, image_encoder, unet, cfg: TrainingConfig, accelerator, weight_dtype, global_step, name, save_dir): + logger.info(f"Running {name} ... ") + + pipeline = MVDiffusionImagePipeline( + image_encoder=image_encoder, feature_extractor=feature_extractor, vae=vae, unet=accelerator.unwrap_model(unet), safety_checker=None, + scheduler=DDIMScheduler.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="scheduler"), + **cfg.pipe_kwargs + ) + + pipeline.set_progress_bar_config(disable=True) + + if cfg.enable_xformers_memory_efficient_attention: + pipeline.enable_xformers_memory_efficient_attention() + + if cfg.seed is None: + generator = None + else: + generator = torch.Generator(device=accelerator.device).manual_seed(cfg.seed) + + images_cond, images_gt, images_pred = [], [], defaultdict(list) + for i, batch in enumerate(dataloader): + # (B, Nv, 3, H, W) + if cfg.pred_type == 'color' or cfg.pred_type == 'mix': + imgs_in, imgs_out = batch['imgs_in'], batch['imgs_out'] + elif cfg.pred_type == 'normal': + imgs_in, imgs_out = batch['imgs_in'], batch['normals_out'] + # (B, Nv, Nce) + camera_embeddings = batch['camera_embeddings'] + + if cfg.pred_type == 'mix': + task_embeddings = batch['task_embeddings'] + camera_embeddings = torch.cat([camera_embeddings, task_embeddings], dim=-1) + + + # (B*Nv, 3, H, W) + imgs_in, imgs_out = rearrange(imgs_in, "B Nv C H W -> (B Nv) C H W"), rearrange(imgs_out, "B Nv C H W -> (B Nv) C H W") + # (B*Nv, Nce) + camera_embeddings = rearrange(camera_embeddings, "B Nv Nce -> (B Nv) Nce") + + images_cond.append(imgs_in) + images_gt.append(imgs_out) + with torch.autocast("cuda"): + # B*Nv images + for guidance_scale in cfg.validation_guidance_scales: + out = pipeline( + imgs_in, camera_embeddings, generator=generator, guidance_scale=guidance_scale, output_type='pt', num_images_per_prompt=1, **cfg.pipe_validation_kwargs + ).images + images_pred[f"{name}-sample_cfg{guidance_scale:.1f}"].append(out) + images_cond_all = torch.cat(images_cond, dim=0) + images_gt_all = torch.cat(images_gt, dim=0) + images_pred_all = {} + for k, v in images_pred.items(): + images_pred_all[k] = torch.cat(v, dim=0) + + nrow = cfg.validation_grid_nrow + ncol = images_cond_all.shape[0] // nrow + images_cond_grid = make_grid(images_cond_all, nrow=nrow, ncol=ncol, padding=0, value_range=(0, 1)) + images_gt_grid = make_grid(images_gt_all, nrow=nrow, ncol=ncol, padding=0, value_range=(0, 1)) + images_pred_grid = {} + for k, v in images_pred_all.items(): + images_pred_grid[k] = make_grid(v, nrow=nrow, ncol=ncol, padding=0, value_range=(0, 1)) + save_image(images_cond_grid, os.path.join(save_dir, f"{global_step}-{name}-cond.jpg")) + save_image(images_gt_grid, os.path.join(save_dir, f"{global_step}-{name}-gt.jpg")) + for k, v in images_pred_grid.items(): + save_image(v, os.path.join(save_dir, f"{global_step}-{k}.jpg")) + torch.cuda.empty_cache() + + +def main( + cfg: TrainingConfig +): + # override local_rank with envvar + env_local_rank = int(os.environ.get("LOCAL_RANK", -1)) + if env_local_rank != -1 and env_local_rank != cfg.local_rank: + cfg.local_rank = env_local_rank + + vis_dir = os.path.join(cfg.output_dir, cfg.vis_dir) + logging_dir = os.path.join(cfg.output_dir, cfg.logging_dir) + accelerator_project_config = ProjectConfiguration(project_dir=cfg.output_dir, logging_dir=logging_dir) + + accelerator = Accelerator( + gradient_accumulation_steps=cfg.gradient_accumulation_steps, + mixed_precision=cfg.mixed_precision, + log_with=cfg.report_to, + project_config=accelerator_project_config, + ) + + # Make one log on every process with the configuration for debugging. + logging.basicConfig( + format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", + datefmt="%m/%d/%Y %H:%M:%S", + level=logging.INFO, + ) + logger.info(accelerator.state, main_process_only=False) + if accelerator.is_local_main_process: + transformers.utils.logging.set_verbosity_warning() + diffusers.utils.logging.set_verbosity_info() + else: + transformers.utils.logging.set_verbosity_error() + diffusers.utils.logging.set_verbosity_error() + + # If passed along, set the training seed now. + if cfg.seed is not None: + set_seed(cfg.seed) + + generator = torch.Generator(device=accelerator.device).manual_seed(cfg.seed) + + # Handle the repository creation + if accelerator.is_main_process: + os.makedirs(cfg.output_dir, exist_ok=True) + os.makedirs(vis_dir, exist_ok=True) + OmegaConf.save(cfg, os.path.join(cfg.output_dir, 'config.yaml')) + + # Load scheduler, tokenizer and models. + noise_scheduler = DDPMScheduler.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="scheduler") + image_encoder = CLIPVisionModelWithProjection.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="image_encoder", revision=cfg.revision) + feature_extractor = CLIPImageProcessor.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="feature_extractor", revision=cfg.revision) + vae = AutoencoderKL.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="vae", revision=cfg.revision) + unet = UNetMV2DConditionModel.from_pretrained_2d(cfg.pretrained_model_name_or_path, subfolder="unet", revision=cfg.revision, **cfg.unet_from_pretrained_kwargs) + + if cfg.use_ema: + ema_unet = EMAModel(unet.parameters(), model_cls=UNetMV2DConditionModel, model_config=unet.config) + + def compute_snr(timesteps): + """ + Computes SNR as per https://github.com/TiankaiHang/Min-SNR-Diffusion-Training/blob/521b624bd70c67cee4bdf49225915f5945a872e3/guided_diffusion/gaussian_diffusion.py#L847-L849 + """ + alphas_cumprod = noise_scheduler.alphas_cumprod + sqrt_alphas_cumprod = alphas_cumprod**0.5 + sqrt_one_minus_alphas_cumprod = (1.0 - alphas_cumprod) ** 0.5 + + # Expand the tensors. + # Adapted from https://github.com/TiankaiHang/Min-SNR-Diffusion-Training/blob/521b624bd70c67cee4bdf49225915f5945a872e3/guided_diffusion/gaussian_diffusion.py#L1026 + sqrt_alphas_cumprod = sqrt_alphas_cumprod.to(device=timesteps.device)[timesteps].float() + while len(sqrt_alphas_cumprod.shape) < len(timesteps.shape): + sqrt_alphas_cumprod = sqrt_alphas_cumprod[..., None] + alpha = sqrt_alphas_cumprod.expand(timesteps.shape) + + sqrt_one_minus_alphas_cumprod = sqrt_one_minus_alphas_cumprod.to(device=timesteps.device)[timesteps].float() + while len(sqrt_one_minus_alphas_cumprod.shape) < len(timesteps.shape): + sqrt_one_minus_alphas_cumprod = sqrt_one_minus_alphas_cumprod[..., None] + sigma = sqrt_one_minus_alphas_cumprod.expand(timesteps.shape) + + # Compute SNR. + snr = (alpha / sigma) ** 2 + return snr + + # Freeze vae and text_encoder + vae.requires_grad_(False) + image_encoder.requires_grad_(False) + + if cfg.trainable_modules is None: + unet.requires_grad_(True) + else: + unet.requires_grad_(False) + for name, module in unet.named_modules(): + if name.endswith(tuple(cfg.trainable_modules)): + for params in module.parameters(): + params.requires_grad = True + + if cfg.enable_xformers_memory_efficient_attention: + if is_xformers_available(): + import xformers + + xformers_version = version.parse(xformers.__version__) + if xformers_version == version.parse("0.0.16"): + logger.warn( + "xFormers 0.0.16 cannot be used for training in some GPUs. If you observe problems during training, please update xFormers to at least 0.0.17. See https://huggingface.co/docs/diffusers/main/en/optimization/xformers for more details." + ) + unet.enable_xformers_memory_efficient_attention() + print("use xformers to speed up") + else: + raise ValueError("xformers is not available. Make sure it is installed correctly") + + # `accelerate` 0.16.0 will have better support for customized saving + if version.parse(accelerate.__version__) >= version.parse("0.16.0"): + # create custom saving & loading hooks so that `accelerator.save_state(...)` serializes in a nice format + def save_model_hook(models, weights, output_dir): + if cfg.use_ema: + ema_unet.save_pretrained(os.path.join(output_dir, "unet_ema")) + + for i, model in enumerate(models): + model.save_pretrained(os.path.join(output_dir, "unet")) + + # make sure to pop weight so that corresponding model is not saved again + weights.pop() + + def load_model_hook(models, input_dir): + if cfg.use_ema: + load_model = EMAModel.from_pretrained(os.path.join(input_dir, "unet_ema"), UNetMV2DConditionModel) + ema_unet.load_state_dict(load_model.state_dict()) + ema_unet.to(accelerator.device) + del load_model + + for i in range(len(models)): + # pop models so that they are not loaded again + model = models.pop() + + # load diffusers style into model + load_model = UNetMV2DConditionModel.from_pretrained(input_dir, subfolder="unet") + model.register_to_config(**load_model.config) + + model.load_state_dict(load_model.state_dict()) + del load_model + + accelerator.register_save_state_pre_hook(save_model_hook) + accelerator.register_load_state_pre_hook(load_model_hook) + + if cfg.gradient_checkpointing: + unet.enable_gradient_checkpointing() + + # Enable TF32 for faster training on Ampere GPUs, + # cf https://pytorch.org/docs/stable/notes/cuda.html#tensorfloat-32-tf32-on-ampere-devices + if cfg.allow_tf32: + torch.backends.cuda.matmul.allow_tf32 = True + + if cfg.scale_lr: + cfg.learning_rate = ( + cfg.learning_rate * cfg.gradient_accumulation_steps * cfg.train_batch_size * accelerator.num_processes + ) + + # Initialize the optimizer + if cfg.use_8bit_adam: + try: + import bitsandbytes as bnb + except ImportError: + raise ImportError( + "Please install bitsandbytes to use 8-bit Adam. You can do so by running `pip install bitsandbytes`" + ) + + optimizer_cls = bnb.optim.AdamW8bit + else: + optimizer_cls = torch.optim.AdamW + + params, params_class_embedding = [], [] + for name, param in unet.named_parameters(): + if 'class_embedding' in name: + params_class_embedding.append(param) + else: + params.append(param) + optimizer = optimizer_cls( + [ + {"params": params, "lr": cfg.learning_rate}, + {"params": params_class_embedding, "lr": cfg.learning_rate * cfg.camera_embedding_lr_mult} + ], + betas=(cfg.adam_beta1, cfg.adam_beta2), + weight_decay=cfg.adam_weight_decay, + eps=cfg.adam_epsilon, + ) + + lr_scheduler = get_scheduler( + cfg.lr_scheduler, + optimizer=optimizer, + num_warmup_steps=cfg.lr_warmup_steps * accelerator.num_processes, + num_training_steps=cfg.max_train_steps * accelerator.num_processes, + ) + + # Get the training dataset + train_dataset = MVDiffusionDataset( + **cfg.train_dataset + ) + validation_dataset = MVDiffusionDataset( + **cfg.validation_dataset + ) + validation_train_dataset = MVDiffusionDataset( + **cfg.validation_train_dataset + ) + + # DataLoaders creation: + train_dataloader = torch.utils.data.DataLoader( + train_dataset, batch_size=cfg.train_batch_size, shuffle=True, num_workers=cfg.dataloader_num_workers, + ) + validation_dataloader = torch.utils.data.DataLoader( + validation_dataset, batch_size=cfg.validation_batch_size, shuffle=False, num_workers=cfg.dataloader_num_workers + ) + validation_train_dataloader = torch.utils.data.DataLoader( + validation_train_dataset, batch_size=cfg.validation_train_batch_size, shuffle=False, num_workers=cfg.dataloader_num_workers + ) + + # Prepare everything with our `accelerator`. + unet, optimizer, train_dataloader, lr_scheduler = accelerator.prepare( + unet, optimizer, train_dataloader, lr_scheduler + ) + + if cfg.use_ema: + ema_unet.to(accelerator.device) + + # For mixed precision training we cast all non-trainable weigths (vae, non-lora text_encoder and non-lora unet) to half-precision + # as these weights are only used for inference, keeping weights in full precision is not required. + weight_dtype = torch.float32 + if accelerator.mixed_precision == "fp16": + weight_dtype = torch.float16 + cfg.mixed_precision = accelerator.mixed_precision + elif accelerator.mixed_precision == "bf16": + weight_dtype = torch.bfloat16 + cfg.mixed_precision = accelerator.mixed_precision + + # Move text_encode and vae to gpu and cast to weight_dtype + image_encoder.to(accelerator.device, dtype=weight_dtype) + vae.to(accelerator.device, dtype=weight_dtype) + + clip_image_mean = torch.as_tensor(feature_extractor.image_mean)[:,None,None].to(accelerator.device, dtype=torch.float32) + clip_image_std = torch.as_tensor(feature_extractor.image_std)[:,None,None].to(accelerator.device, dtype=torch.float32) + + # We need to recalculate our total training steps as the size of the training dataloader may have changed. + num_update_steps_per_epoch = math.ceil(len(train_dataloader) / cfg.gradient_accumulation_steps) + num_train_epochs = math.ceil(cfg.max_train_steps / num_update_steps_per_epoch) + + # We need to initialize the trackers we use, and also store our configuration. + # The trackers initializes automatically on the main process. + if accelerator.is_main_process: + # tracker_config = dict(vars(cfg)) + tracker_config = {} + accelerator.init_trackers(cfg.tracker_project_name, tracker_config) + + # Train! + total_batch_size = cfg.train_batch_size * accelerator.num_processes * cfg.gradient_accumulation_steps + + logger.info("***** Running training *****") + logger.info(f" Num examples = {len(train_dataset)}") + logger.info(f" Num Epochs = {num_train_epochs}") + logger.info(f" Instantaneous batch size per device = {cfg.train_batch_size}") + logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") + logger.info(f" Gradient Accumulation steps = {cfg.gradient_accumulation_steps}") + logger.info(f" Total optimization steps = {cfg.max_train_steps}") + global_step = 0 + first_epoch = 0 + + + # Potentially load in the weights and states from a previous save + if cfg.resume_from_checkpoint: + if cfg.resume_from_checkpoint != "latest": + path = os.path.basename(cfg.resume_from_checkpoint) + else: + # Get the most recent checkpoint + if os.path.exists(os.path.join(cfg.output_dir, "checkpoint")): + path = "checkpoint" + else: + dirs = os.listdir(cfg.output_dir) + dirs = [d for d in dirs if d.startswith("checkpoint")] + dirs = sorted(dirs, key=lambda x: int(x.split("-")[1])) + path = dirs[-1] if len(dirs) > 0 else None + + if path is None: + accelerator.print( + f"Checkpoint '{cfg.resume_from_checkpoint}' does not exist. Starting a new training run." + ) + cfg.resume_from_checkpoint = None + else: + accelerator.print(f"Resuming from checkpoint {path}") + accelerator.load_state(os.path.join(cfg.output_dir, path)) + # global_step = int(path.split("-")[1]) + global_step = 0 + + resume_global_step = global_step * cfg.gradient_accumulation_steps + first_epoch = global_step // num_update_steps_per_epoch + resume_step = resume_global_step % (num_update_steps_per_epoch * cfg.gradient_accumulation_steps) + + # Only show the progress bar once on each machine. + progress_bar = tqdm(range(global_step, cfg.max_train_steps), disable=not accelerator.is_local_main_process) + progress_bar.set_description("Steps") + + for epoch in range(first_epoch, num_train_epochs): + unet.train() + train_loss = 0.0 + for step, batch in enumerate(train_dataloader): + # Skip steps until we reach the resumed step + if cfg.resume_from_checkpoint and epoch == first_epoch and step < resume_step: + if step % cfg.gradient_accumulation_steps == 0: + progress_bar.update(1) + continue + + with accelerator.accumulate(unet): + # (B, Nv, 3, H, W) + if cfg.pred_type == 'color' or cfg.pred_type == 'mix': + imgs_in, imgs_out = batch['imgs_in'], batch['imgs_out'] + elif cfg.pred_type == 'normal': + imgs_in, imgs_out = batch['imgs_in'], batch['normals_out'] + + bnm, Nv = imgs_in.shape[0], imgs_in.shape[1] + + # (B, Nv, Nce) + camera_embeddings = batch['camera_embeddings'] + + if cfg.pred_type == 'mix': + task_embeddings = batch['task_embeddings'] + camera_embeddings = torch.cat([camera_embeddings, task_embeddings], dim=-1) + + # (B*Nv, 3, H, W) + imgs_in, imgs_out = rearrange(imgs_in, "B Nv C H W -> (B Nv) C H W"), rearrange(imgs_out, "B Nv C H W -> (B Nv) C H W") + # (B*Nv, Nce) + camera_embeddings = rearrange(camera_embeddings, "B Nv Nce -> (B Nv) Nce") + # (B*Nv, Nce') + if cfg.camera_embedding_type == 'e_de_da_sincos': + camera_embeddings = torch.cat([ + torch.sin(camera_embeddings), + torch.cos(camera_embeddings) + ], dim=-1) + else: + raise NotImplementedError + + imgs_in, imgs_out, camera_embeddings = imgs_in.to(weight_dtype), imgs_out.to(weight_dtype), camera_embeddings.to(weight_dtype) + + # (B*Nv, 4, Hl, Wl) + cond_vae_embeddings = vae.encode(imgs_in * 2.0 - 1.0).latent_dist.mode() + if cfg.scale_input_latents: + cond_vae_embeddings = cond_vae_embeddings * vae.config.scaling_factor + latents = vae.encode(imgs_out * 2.0 - 1.0).latent_dist.sample() * vae.config.scaling_factor + + # DO NOT use this! Very slow! + # imgs_in_pil = [TF.to_pil_image(img) for img in imgs_in] + # imgs_in_proc = feature_extractor(images=imgs_in_pil, return_tensors='pt').pixel_values.to(dtype=latents.dtype, device=latents.device) + + imgs_in_proc = TF.resize(imgs_in, (feature_extractor.crop_size['height'], feature_extractor.crop_size['width']), interpolation=InterpolationMode.BICUBIC) + # do the normalization in float32 to preserve precision + imgs_in_proc = ((imgs_in_proc.float() - clip_image_mean) / clip_image_std).to(weight_dtype) + + # (B*Nv, 1, 768) + image_embeddings = image_encoder(imgs_in_proc).image_embeds.unsqueeze(1) + + noise = torch.randn_like(latents) + bsz = latents.shape[0] + + # same noise for different views of the same object + timesteps = torch.randint(0, noise_scheduler.num_train_timesteps, (bsz // cfg.num_views,), device=latents.device).repeat_interleave(cfg.num_views) + timesteps = timesteps.long() + + noisy_latents = noise_scheduler.add_noise(latents, noise, timesteps) + + # Conditioning dropout to support classifier-free guidance during inference. For more details + # check out the section 3.2.1 of the original paper https://arxiv.org/abs/2211.09800. + if cfg.use_classifier_free_guidance and cfg.condition_drop_rate > 0.: + if cfg.drop_type == 'drop_as_a_whole': + # drop a group of normals and colors as a whole + random_p = torch.rand(bnm, device=latents.device, generator=generator) + + # Sample masks for the conditioning images. + image_mask_dtype = cond_vae_embeddings.dtype + image_mask = 1 - ( + (random_p >= cfg.condition_drop_rate).to(image_mask_dtype) + * (random_p < 3 * cfg.condition_drop_rate).to(image_mask_dtype) + ) + image_mask = image_mask.reshape(bnm, 1, 1, 1, 1).repeat(1, Nv, 1, 1, 1) + image_mask = rearrange(image_mask, "B Nv C H W -> (B Nv) C H W") + # Final image conditioning. + cond_vae_embeddings = image_mask * cond_vae_embeddings + + # Sample masks for the conditioning images. + clip_mask_dtype = image_embeddings.dtype + clip_mask = 1 - ( + (random_p < 2 * cfg.condition_drop_rate).to(clip_mask_dtype) + ) + clip_mask = clip_mask.reshape(bnm, 1, 1, 1).repeat(1, Nv, 1, 1) + clip_mask = rearrange(clip_mask, "B Nv M C -> (B Nv) M C") + # Final image conditioning. + image_embeddings = clip_mask * image_embeddings + elif cfg.drop_type == 'drop_independent': + random_p = torch.rand(bsz, device=latents.device, generator=generator) + + # Sample masks for the conditioning images. + image_mask_dtype = cond_vae_embeddings.dtype + image_mask = 1 - ( + (random_p >= cfg.condition_drop_rate).to(image_mask_dtype) + * (random_p < 3 * cfg.condition_drop_rate).to(image_mask_dtype) + ) + image_mask = image_mask.reshape(bsz, 1, 1, 1) + # Final image conditioning. + cond_vae_embeddings = image_mask * cond_vae_embeddings + + # Sample masks for the conditioning images. + clip_mask_dtype = image_embeddings.dtype + clip_mask = 1 - ( + (random_p < 2 * cfg.condition_drop_rate).to(clip_mask_dtype) + ) + clip_mask = clip_mask.reshape(bsz, 1, 1) + # Final image conditioning. + image_embeddings = clip_mask * image_embeddings + + # (B*Nv, 8, Hl, Wl) + latent_model_input = torch.cat([noisy_latents, cond_vae_embeddings], dim=1) + + model_pred = unet( + latent_model_input, + timesteps, + encoder_hidden_states=image_embeddings, + class_labels=camera_embeddings + ).sample + + # Get the target for loss depending on the prediction type + if noise_scheduler.config.prediction_type == "epsilon": + target = noise + elif noise_scheduler.config.prediction_type == "v_prediction": + target = noise_scheduler.get_velocity(latents, noise, timesteps) + else: + raise ValueError(f"Unknown prediction type {noise_scheduler.config.prediction_type}") + + if cfg.snr_gamma is None: + loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean") + else: + # Compute loss-weights as per Section 3.4 of https://arxiv.org/abs/2303.09556. + # Since we predict the noise instead of x_0, the original formulation is slightly changed. + # This is discussed in Section 4.2 of the same paper. + snr = compute_snr(timesteps) + mse_loss_weights = ( + torch.stack([snr, cfg.snr_gamma * torch.ones_like(timesteps)], dim=1).min(dim=1)[0] / snr + ) + # We first calculate the original loss. Then we mean over the non-batch dimensions and + # rebalance the sample-wise losses with their respective loss weights. + # Finally, we take the mean of the rebalanced loss. + loss = F.mse_loss(model_pred.float(), target.float(), reduction="none") + loss = loss.mean(dim=list(range(1, len(loss.shape)))) * mse_loss_weights + loss = loss.mean() + + # Gather the losses across all processes for logging (if we use distributed training). + avg_loss = accelerator.gather(loss.repeat(cfg.train_batch_size)).mean() + train_loss += avg_loss.item() / cfg.gradient_accumulation_steps + + # Backpropagate + accelerator.backward(loss) + if accelerator.sync_gradients and cfg.max_grad_norm is not None: + accelerator.clip_grad_norm_(unet.parameters(), cfg.max_grad_norm) + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + + # Checks if the accelerator has performed an optimization step behind the scenes + if accelerator.sync_gradients: + if cfg.use_ema: + ema_unet.step(unet.parameters()) + progress_bar.update(1) + global_step += 1 + accelerator.log({"train_loss": train_loss}, step=global_step) + train_loss = 0.0 + + if global_step % cfg.checkpointing_steps == 0: + if accelerator.is_main_process: + save_path = os.path.join(cfg.output_dir, f"checkpoint") + accelerator.save_state(save_path) + try: + unet.module.save_pretrained(os.path.join(cfg.output_dir, f"unet-{global_step}")) + except: + unet.save_pretrained(os.path.join(cfg.output_dir, f"unet-{global_step}")) + logger.info(f"Saved state to {save_path}") + + if global_step % cfg.validation_steps == 0 or (cfg.validation_sanity_check and global_step == 1): + if accelerator.is_main_process: + if cfg.use_ema: + # Store the UNet parameters temporarily and load the EMA parameters to perform inference. + ema_unet.store(unet.parameters()) + ema_unet.copy_to(unet.parameters()) + log_validation( + validation_dataloader, + vae, + feature_extractor, + image_encoder, + unet, + cfg, + accelerator, + weight_dtype, + global_step, + 'validation', + vis_dir + ) + log_validation( + validation_train_dataloader, + vae, + feature_extractor, + image_encoder, + unet, + cfg, + accelerator, + weight_dtype, + global_step, + 'validation_train', + vis_dir + ) + if cfg.use_ema: + # Switch back to the original UNet parameters. + ema_unet.restore(unet.parameters()) + + logs = {"step_loss": loss.detach().item(), "lr": lr_scheduler.get_last_lr()[0]} + progress_bar.set_postfix(**logs) + + if global_step >= cfg.max_train_steps: + break + + # Create the pipeline using the trained modules and save it. + accelerator.wait_for_everyone() + if accelerator.is_main_process: + unet = accelerator.unwrap_model(unet) + if cfg.use_ema: + ema_unet.copy_to(unet.parameters()) + pipeline = MVDiffusionImagePipeline( + image_encoder=image_encoder, feature_extractor=feature_extractor, vae=vae, unet=unet, safety_checker=None, + scheduler=DDIMScheduler.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="scheduler"), + **cfg.pipe_kwargs + ) + os.makedirs(os.path.join(cfg.output_dir, "pipeckpts"), exist_ok=True) + pipeline.save_pretrained(os.path.join(cfg.output_dir, "pipeckpts")) + + accelerator.end_training() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--config', type=str, required=True) + args = parser.parse_args() + schema = OmegaConf.structured(TrainingConfig) + cfg = OmegaConf.load(args.config) + cfg = OmegaConf.merge(schema, cfg) + main(cfg) diff --git a/apps/third_party/Wonder3D/train_mvdiffusion_joint.py b/apps/third_party/Wonder3D/train_mvdiffusion_joint.py new file mode 100644 index 0000000000000000000000000000000000000000..2948a1f11003b0dd8abd6559f7c18b099048a17d --- /dev/null +++ b/apps/third_party/Wonder3D/train_mvdiffusion_joint.py @@ -0,0 +1,773 @@ +import argparse +import datetime +import logging +import inspect +import math +import os +from typing import Dict, Optional, Tuple, List +from omegaconf import OmegaConf +from PIL import Image +import cv2 +import numpy as np +from dataclasses import dataclass +from packaging import version +import shutil +from collections import defaultdict + +import torch +import torch.nn.functional as F +import torch.utils.checkpoint +import torchvision.transforms.functional as TF +from torchvision.transforms import InterpolationMode +from torchvision.utils import make_grid, save_image + +import transformers +import accelerate +from accelerate import Accelerator +from accelerate.logging import get_logger +from accelerate.utils import ProjectConfiguration, set_seed + +import diffusers +from diffusers import AutoencoderKL, DDPMScheduler, DDIMScheduler, StableDiffusionPipeline +from diffusers.optimization import get_scheduler +from diffusers.training_utils import EMAModel +from diffusers.utils import check_min_version, deprecate, is_wandb_available +from diffusers.utils.import_utils import is_xformers_available + +from tqdm.auto import tqdm +from transformers import CLIPTextModel, CLIPTokenizer +from transformers import CLIPImageProcessor, CLIPVisionModelWithProjection + +from mvdiffusion.models.unet_mv2d_condition import UNetMV2DConditionModel + +from mvdiffusion.data.objaverse_dataset import ObjaverseDataset as MVDiffusionDataset + +from mvdiffusion.pipelines.pipeline_mvdiffusion_image import MVDiffusionImagePipeline + +from einops import rearrange + +import time +import pdb + +logger = get_logger(__name__, log_level="INFO") + + +@dataclass +class TrainingConfig: + pretrained_model_name_or_path: str + pretrained_unet_path: Optional[str] + revision: Optional[str] + train_dataset: Dict + validation_dataset: Dict + validation_train_dataset: Dict + output_dir: str + seed: Optional[int] + train_batch_size: int + validation_batch_size: int + validation_train_batch_size: int + max_train_steps: int + gradient_accumulation_steps: int + gradient_checkpointing: bool + learning_rate: float + scale_lr: bool + lr_scheduler: str + lr_warmup_steps: int + snr_gamma: Optional[float] + use_8bit_adam: bool + allow_tf32: bool + use_ema: bool + dataloader_num_workers: int + adam_beta1: float + adam_beta2: float + adam_weight_decay: float + adam_epsilon: float + max_grad_norm: Optional[float] + prediction_type: Optional[str] + logging_dir: str + vis_dir: str + mixed_precision: Optional[str] + report_to: Optional[str] + local_rank: int + checkpointing_steps: int + checkpoints_total_limit: Optional[int] + resume_from_checkpoint: Optional[str] + enable_xformers_memory_efficient_attention: bool + validation_steps: int + validation_sanity_check: bool + tracker_project_name: str + + trainable_modules: Optional[list] + use_classifier_free_guidance: bool + condition_drop_rate: float + scale_input_latents: bool + + pipe_kwargs: Dict + pipe_validation_kwargs: Dict + unet_from_pretrained_kwargs: Dict + validation_guidance_scales: List[float] + validation_grid_nrow: int + camera_embedding_lr_mult: float + + num_views: int + camera_embedding_type: str + + pred_type: str + + drop_type: str + + last_global_step: int + + +def log_validation(dataloader, vae, feature_extractor, image_encoder, unet, cfg: TrainingConfig, accelerator, weight_dtype, global_step, name, save_dir): + logger.info(f"Running {name} ... ") + + pipeline = MVDiffusionImagePipeline( + image_encoder=image_encoder, feature_extractor=feature_extractor, vae=vae, unet=accelerator.unwrap_model(unet), safety_checker=None, + scheduler=DDIMScheduler.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="scheduler"), + **cfg.pipe_kwargs + ) + + pipeline.set_progress_bar_config(disable=True) + + if cfg.enable_xformers_memory_efficient_attention: + pipeline.enable_xformers_memory_efficient_attention() + + if cfg.seed is None: + generator = None + else: + generator = torch.Generator(device=accelerator.device).manual_seed(cfg.seed) + + images_cond, images_gt, images_pred = [], [], defaultdict(list) + for i, batch in enumerate(dataloader): + # (B, Nv, 3, H, W) + imgs_in, colors_out, normals_out = batch['imgs_in'], batch['imgs_out'], batch['normals_out'] + + # repeat (2B, Nv, 3, H, W) + imgs_in = torch.cat([imgs_in]*2, dim=0) + imgs_out = torch.cat([normals_out, colors_out], dim=0) + + # (2B, Nv, Nce) + camera_embeddings = torch.cat([batch['camera_embeddings']]*2, dim=0) + + task_embeddings = torch.cat([batch['normal_task_embeddings'], batch['color_task_embeddings']], dim=0) + + camera_task_embeddings = torch.cat([camera_embeddings, task_embeddings], dim=-1) + + # (B*Nv, 3, H, W) + imgs_in, imgs_out = rearrange(imgs_in, "B Nv C H W -> (B Nv) C H W"), rearrange(imgs_out, "B Nv C H W -> (B Nv) C H W") + # (B*Nv, Nce) + camera_task_embeddings = rearrange(camera_task_embeddings, "B Nv Nce -> (B Nv) Nce") + + images_cond.append(imgs_in) + images_gt.append(imgs_out) + with torch.autocast("cuda"): + # B*Nv images + for guidance_scale in cfg.validation_guidance_scales: + out = pipeline( + imgs_in, camera_task_embeddings, generator=generator, guidance_scale=guidance_scale, output_type='pt', num_images_per_prompt=1, **cfg.pipe_validation_kwargs + ).images + shape = out.shape + out0, out1 = out[:shape[0]//2], out[shape[0]//2:] + out = [] + for ii in range(shape[0]//2): + out.append(out0[ii]) + out.append(out1[ii]) + out = torch.stack(out, dim=0) + images_pred[f"{name}-sample_cfg{guidance_scale:.1f}"].append(out) + images_cond_all = torch.cat(images_cond, dim=0) + images_gt_all = torch.cat(images_gt, dim=0) + images_pred_all = {} + for k, v in images_pred.items(): + images_pred_all[k] = torch.cat(v, dim=0) + + nrow = cfg.validation_grid_nrow + ncol = images_cond_all.shape[0] // nrow + images_cond_grid = make_grid(images_cond_all, nrow=nrow, ncol=ncol, padding=0, value_range=(0, 1)) + images_gt_grid = make_grid(images_gt_all, nrow=nrow, ncol=ncol, padding=0, value_range=(0, 1)) + images_pred_grid = {} + for k, v in images_pred_all.items(): + images_pred_grid[k] = make_grid(v, nrow=nrow, ncol=ncol, padding=0, value_range=(0, 1)) + save_image(images_cond_grid, os.path.join(save_dir, f"{global_step}-{name}-cond.jpg")) + save_image(images_gt_grid, os.path.join(save_dir, f"{global_step}-{name}-gt.jpg")) + for k, v in images_pred_grid.items(): + save_image(v, os.path.join(save_dir, f"{global_step}-{k}.jpg")) + torch.cuda.empty_cache() + + +def main( + cfg: TrainingConfig +): + # override local_rank with envvar + env_local_rank = int(os.environ.get("LOCAL_RANK", -1)) + if env_local_rank != -1 and env_local_rank != cfg.local_rank: + cfg.local_rank = env_local_rank + + vis_dir = os.path.join(cfg.output_dir, cfg.vis_dir) + logging_dir = os.path.join(cfg.output_dir, cfg.logging_dir) + accelerator_project_config = ProjectConfiguration(project_dir=cfg.output_dir, logging_dir=logging_dir) + + accelerator = Accelerator( + gradient_accumulation_steps=cfg.gradient_accumulation_steps, + mixed_precision=cfg.mixed_precision, + log_with=cfg.report_to, + project_config=accelerator_project_config, + ) + + # Make one log on every process with the configuration for debugging. + logging.basicConfig( + format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", + datefmt="%m/%d/%Y %H:%M:%S", + level=logging.INFO, + ) + logger.info(accelerator.state, main_process_only=False) + if accelerator.is_local_main_process: + transformers.utils.logging.set_verbosity_warning() + diffusers.utils.logging.set_verbosity_info() + else: + transformers.utils.logging.set_verbosity_error() + diffusers.utils.logging.set_verbosity_error() + + # If passed along, set the training seed now. + if cfg.seed is not None: + set_seed(cfg.seed) + + generator = torch.Generator(device=accelerator.device).manual_seed(cfg.seed) + + # Handle the repository creation + if accelerator.is_main_process: + os.makedirs(cfg.output_dir, exist_ok=True) + os.makedirs(vis_dir, exist_ok=True) + OmegaConf.save(cfg, os.path.join(cfg.output_dir, 'config.yaml')) + + # Load scheduler, tokenizer and models. + noise_scheduler = DDPMScheduler.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="scheduler") + image_encoder = CLIPVisionModelWithProjection.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="image_encoder", revision=cfg.revision) + feature_extractor = CLIPImageProcessor.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="feature_extractor", revision=cfg.revision) + vae = AutoencoderKL.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="vae", revision=cfg.revision) + if cfg.pretrained_unet_path is None: + unet = UNetMV2DConditionModel.from_pretrained_2d(cfg.pretrained_model_name_or_path, subfolder="unet", revision=cfg.revision, **cfg.unet_from_pretrained_kwargs) + else: + print("load pre-trained unet from ", cfg.pretrained_unet_path) + unet = UNetMV2DConditionModel.from_pretrained(cfg.pretrained_unet_path, subfolder="unet", revision=cfg.revision, **cfg.unet_from_pretrained_kwargs) + if cfg.use_ema: + ema_unet = EMAModel(unet.parameters(), model_cls=UNetMV2DConditionModel, model_config=unet.config) + + def compute_snr(timesteps): + """ + Computes SNR as per https://github.com/TiankaiHang/Min-SNR-Diffusion-Training/blob/521b624bd70c67cee4bdf49225915f5945a872e3/guided_diffusion/gaussian_diffusion.py#L847-L849 + """ + alphas_cumprod = noise_scheduler.alphas_cumprod + sqrt_alphas_cumprod = alphas_cumprod**0.5 + sqrt_one_minus_alphas_cumprod = (1.0 - alphas_cumprod) ** 0.5 + + # Expand the tensors. + # Adapted from https://github.com/TiankaiHang/Min-SNR-Diffusion-Training/blob/521b624bd70c67cee4bdf49225915f5945a872e3/guided_diffusion/gaussian_diffusion.py#L1026 + sqrt_alphas_cumprod = sqrt_alphas_cumprod.to(device=timesteps.device)[timesteps].float() + while len(sqrt_alphas_cumprod.shape) < len(timesteps.shape): + sqrt_alphas_cumprod = sqrt_alphas_cumprod[..., None] + alpha = sqrt_alphas_cumprod.expand(timesteps.shape) + + sqrt_one_minus_alphas_cumprod = sqrt_one_minus_alphas_cumprod.to(device=timesteps.device)[timesteps].float() + while len(sqrt_one_minus_alphas_cumprod.shape) < len(timesteps.shape): + sqrt_one_minus_alphas_cumprod = sqrt_one_minus_alphas_cumprod[..., None] + sigma = sqrt_one_minus_alphas_cumprod.expand(timesteps.shape) + + # Compute SNR. + snr = (alpha / sigma) ** 2 + return snr + + # Freeze vae and text_encoder + vae.requires_grad_(False) + image_encoder.requires_grad_(False) + + if cfg.trainable_modules is None: + unet.requires_grad_(True) + else: + unet.requires_grad_(False) + for name, module in unet.named_modules(): + if name.endswith(tuple(cfg.trainable_modules)): + for params in module.parameters(): + # print("trainable: ", params) + params.requires_grad = True + + if cfg.enable_xformers_memory_efficient_attention: + if is_xformers_available(): + import xformers + + xformers_version = version.parse(xformers.__version__) + if xformers_version == version.parse("0.0.16"): + logger.warn( + "xFormers 0.0.16 cannot be used for training in some GPUs. If you observe problems during training, please update xFormers to at least 0.0.17. See https://huggingface.co/docs/diffusers/main/en/optimization/xformers for more details." + ) + unet.enable_xformers_memory_efficient_attention() + print("use xformers to speed up") + else: + raise ValueError("xformers is not available. Make sure it is installed correctly") + + # `accelerate` 0.16.0 will have better support for customized saving + if version.parse(accelerate.__version__) >= version.parse("0.16.0"): + # create custom saving & loading hooks so that `accelerator.save_state(...)` serializes in a nice format + def save_model_hook(models, weights, output_dir): + if cfg.use_ema: + ema_unet.save_pretrained(os.path.join(output_dir, "unet_ema")) + + for i, model in enumerate(models): + model.save_pretrained(os.path.join(output_dir, "unet")) + + # make sure to pop weight so that corresponding model is not saved again + weights.pop() + + def load_model_hook(models, input_dir): + if cfg.use_ema: + load_model = EMAModel.from_pretrained(os.path.join(input_dir, "unet_ema"), UNetMV2DConditionModel) + ema_unet.load_state_dict(load_model.state_dict()) + ema_unet.to(accelerator.device) + del load_model + + for i in range(len(models)): + # pop models so that they are not loaded again + model = models.pop() + + # load diffusers style into model + load_model = UNetMV2DConditionModel.from_pretrained(input_dir, subfolder="unet") + model.register_to_config(**load_model.config) + + model.load_state_dict(load_model.state_dict()) + del load_model + + accelerator.register_save_state_pre_hook(save_model_hook) + accelerator.register_load_state_pre_hook(load_model_hook) + + if cfg.gradient_checkpointing: + unet.enable_gradient_checkpointing() + + # Enable TF32 for faster training on Ampere GPUs, + # cf https://pytorch.org/docs/stable/notes/cuda.html#tensorfloat-32-tf32-on-ampere-devices + if cfg.allow_tf32: + torch.backends.cuda.matmul.allow_tf32 = True + + if cfg.scale_lr: + cfg.learning_rate = ( + cfg.learning_rate * cfg.gradient_accumulation_steps * cfg.train_batch_size * accelerator.num_processes + ) + + # Initialize the optimizer + if cfg.use_8bit_adam: + try: + import bitsandbytes as bnb + except ImportError: + raise ImportError( + "Please install bitsandbytes to use 8-bit Adam. You can do so by running `pip install bitsandbytes`" + ) + + optimizer_cls = bnb.optim.AdamW8bit + else: + optimizer_cls = torch.optim.AdamW + + params, params_class_embedding = [], [] + for name, param in unet.named_parameters(): + if 'class_embedding' in name: + params_class_embedding.append(param) + else: + params.append(param) + optimizer = optimizer_cls( + [ + {"params": params, "lr": cfg.learning_rate}, + {"params": params_class_embedding, "lr": cfg.learning_rate * cfg.camera_embedding_lr_mult} + ], + betas=(cfg.adam_beta1, cfg.adam_beta2), + weight_decay=cfg.adam_weight_decay, + eps=cfg.adam_epsilon, + ) + + lr_scheduler = get_scheduler( + cfg.lr_scheduler, + optimizer=optimizer, + num_warmup_steps=cfg.lr_warmup_steps * accelerator.num_processes, + num_training_steps=cfg.max_train_steps * accelerator.num_processes, + ) + + # Get the training dataset + train_dataset = MVDiffusionDataset( + **cfg.train_dataset + ) + validation_dataset = MVDiffusionDataset( + **cfg.validation_dataset + ) + validation_train_dataset = MVDiffusionDataset( + **cfg.validation_train_dataset + ) + + # DataLoaders creation: + train_dataloader = torch.utils.data.DataLoader( + train_dataset, batch_size=cfg.train_batch_size, shuffle=True, num_workers=cfg.dataloader_num_workers, + ) + validation_dataloader = torch.utils.data.DataLoader( + validation_dataset, batch_size=cfg.validation_batch_size, shuffle=False, num_workers=cfg.dataloader_num_workers + ) + validation_train_dataloader = torch.utils.data.DataLoader( + validation_train_dataset, batch_size=cfg.validation_train_batch_size, shuffle=False, num_workers=cfg.dataloader_num_workers + ) + + # Prepare everything with our `accelerator`. + unet, optimizer, train_dataloader, lr_scheduler = accelerator.prepare( + unet, optimizer, train_dataloader, lr_scheduler + ) + + if cfg.use_ema: + ema_unet.to(accelerator.device) + + # For mixed precision training we cast all non-trainable weigths (vae, non-lora text_encoder and non-lora unet) to half-precision + # as these weights are only used for inference, keeping weights in full precision is not required. + weight_dtype = torch.float32 + if accelerator.mixed_precision == "fp16": + weight_dtype = torch.float16 + cfg.mixed_precision = accelerator.mixed_precision + elif accelerator.mixed_precision == "bf16": + weight_dtype = torch.bfloat16 + cfg.mixed_precision = accelerator.mixed_precision + + # Move text_encode and vae to gpu and cast to weight_dtype + image_encoder.to(accelerator.device, dtype=weight_dtype) + vae.to(accelerator.device, dtype=weight_dtype) + + clip_image_mean = torch.as_tensor(feature_extractor.image_mean)[:,None,None].to(accelerator.device, dtype=torch.float32) + clip_image_std = torch.as_tensor(feature_extractor.image_std)[:,None,None].to(accelerator.device, dtype=torch.float32) + + # We need to recalculate our total training steps as the size of the training dataloader may have changed. + num_update_steps_per_epoch = math.ceil(len(train_dataloader) / cfg.gradient_accumulation_steps) + num_train_epochs = math.ceil(cfg.max_train_steps / num_update_steps_per_epoch) + + # We need to initialize the trackers we use, and also store our configuration. + # The trackers initializes automatically on the main process. + if accelerator.is_main_process: + # tracker_config = dict(vars(cfg)) + tracker_config = {} + accelerator.init_trackers(cfg.tracker_project_name, tracker_config) + + # Train! + total_batch_size = cfg.train_batch_size * accelerator.num_processes * cfg.gradient_accumulation_steps + + logger.info("***** Running training *****") + logger.info(f" Num examples = {len(train_dataset)}") + logger.info(f" Num Epochs = {num_train_epochs}") + logger.info(f" Instantaneous batch size per device = {cfg.train_batch_size}") + logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") + logger.info(f" Gradient Accumulation steps = {cfg.gradient_accumulation_steps}") + logger.info(f" Total optimization steps = {cfg.max_train_steps}") + global_step = 0 + first_epoch = 0 + + + # Potentially load in the weights and states from a previous save + if cfg.resume_from_checkpoint: + if cfg.resume_from_checkpoint != "latest": + path = os.path.basename(cfg.resume_from_checkpoint) + else: + # Get the most recent checkpoint + if os.path.exists(os.path.join(cfg.output_dir, "checkpoint")): + path = "checkpoint" + else: + dirs = os.listdir(cfg.output_dir) + dirs = [d for d in dirs if d.startswith("checkpoint")] + dirs = sorted(dirs, key=lambda x: int(x.split("-")[1])) + path = dirs[-1] if len(dirs) > 0 else None + + if path is None: + accelerator.print( + f"Checkpoint '{cfg.resume_from_checkpoint}' does not exist. Starting a new training run." + ) + cfg.resume_from_checkpoint = None + else: + accelerator.print(f"Resuming from checkpoint {path}") + accelerator.load_state(os.path.join(cfg.output_dir, path)) + # global_step = int(path.split("-")[1]) + global_step = cfg.last_global_step + + resume_global_step = global_step * cfg.gradient_accumulation_steps + first_epoch = global_step // num_update_steps_per_epoch + resume_step = resume_global_step % (num_update_steps_per_epoch * cfg.gradient_accumulation_steps) + + # Only show the progress bar once on each machine. + progress_bar = tqdm(range(global_step, cfg.max_train_steps), disable=not accelerator.is_local_main_process) + progress_bar.set_description("Steps") + + for epoch in range(first_epoch, num_train_epochs): + unet.train() + train_loss = 0.0 + for step, batch in enumerate(train_dataloader): + # Skip steps until we reach the resumed step + if cfg.resume_from_checkpoint and epoch == first_epoch and step < resume_step: + if step % cfg.gradient_accumulation_steps == 0: + progress_bar.update(1) + continue + + with accelerator.accumulate(unet): + # (B, Nv, 3, H, W) + imgs_in, colors_out, normals_out = batch['imgs_in'], batch['imgs_out'], batch['normals_out'] + + bnm, Nv = imgs_in.shape[:2] + + # repeat (2B, Nv, 3, H, W) + imgs_in = torch.cat([imgs_in]*2, dim=0) + imgs_out = torch.cat([normals_out, colors_out], dim=0) + + # (2B, Nv, Nce) + camera_embeddings = torch.cat([batch['camera_embeddings']]*2, dim=0) + + task_embeddings = torch.cat([batch['normal_task_embeddings'], batch['color_task_embeddings']], dim=0) + + camera_task_embeddings = torch.cat([camera_embeddings, task_embeddings], dim=-1) + + # (B*Nv, 3, H, W) + imgs_in, imgs_out = rearrange(imgs_in, "B Nv C H W -> (B Nv) C H W"), rearrange(imgs_out, "B Nv C H W -> (B Nv) C H W") + # (B*Nv, Nce) + camera_task_embeddings = rearrange(camera_task_embeddings, "B Nv Nce -> (B Nv) Nce") + # (B*Nv, Nce') + if cfg.camera_embedding_type == 'e_de_da_sincos': + camera_task_embeddings = torch.cat([ + torch.sin(camera_task_embeddings), + torch.cos(camera_task_embeddings) + ], dim=-1) + else: + raise NotImplementedError + + imgs_in, imgs_out, camera_task_embeddings = imgs_in.to(weight_dtype), imgs_out.to(weight_dtype), camera_task_embeddings.to(weight_dtype) + + # (B*Nv, 4, Hl, Wl) + # pdb.set_trace() + cond_vae_embeddings = vae.encode(imgs_in * 2.0 - 1.0).latent_dist.mode() + if cfg.scale_input_latents: + cond_vae_embeddings = cond_vae_embeddings * vae.config.scaling_factor + latents = vae.encode(imgs_out * 2.0 - 1.0).latent_dist.sample() * vae.config.scaling_factor + + # DO NOT use this! Very slow! + # imgs_in_pil = [TF.to_pil_image(img) for img in imgs_in] + # imgs_in_proc = feature_extractor(images=imgs_in_pil, return_tensors='pt').pixel_values.to(dtype=latents.dtype, device=latents.device) + + imgs_in_proc = TF.resize(imgs_in, (feature_extractor.crop_size['height'], feature_extractor.crop_size['width']), interpolation=InterpolationMode.BICUBIC) + # do the normalization in float32 to preserve precision + imgs_in_proc = ((imgs_in_proc.float() - clip_image_mean) / clip_image_std).to(weight_dtype) + + # (B*Nv, 1, 768) + image_embeddings = image_encoder(imgs_in_proc).image_embeds.unsqueeze(1) + + noise = torch.randn_like(latents) + bsz = latents.shape[0] + + # same noise for different views of the same object + timesteps = torch.randint(0, noise_scheduler.num_train_timesteps, (bsz // cfg.num_views,), device=latents.device).repeat_interleave(cfg.num_views) + timesteps = timesteps.long() + + noisy_latents = noise_scheduler.add_noise(latents, noise, timesteps) + + # Conditioning dropout to support classifier-free guidance during inference. For more details + # check out the section 3.2.1 of the original paper https://arxiv.org/abs/2211.09800. + if cfg.use_classifier_free_guidance and cfg.condition_drop_rate > 0.: + # assert cfg.drop_type == 'drop_as_a_whole' + if cfg.drop_type == 'drop_as_a_whole': + # drop a group of normals and colors as a whole + random_p = torch.rand(bnm, device=latents.device, generator=generator) + + # Sample masks for the conditioning images. + image_mask_dtype = cond_vae_embeddings.dtype + image_mask = 1 - ( + (random_p >= cfg.condition_drop_rate).to(image_mask_dtype) + * (random_p < 3 * cfg.condition_drop_rate).to(image_mask_dtype) + ) + image_mask = image_mask.reshape(bnm, 1, 1, 1, 1).repeat(1, Nv, 1, 1, 1) + image_mask = rearrange(image_mask, "B Nv C H W -> (B Nv) C H W") + image_mask = torch.cat([image_mask]*2, dim=0) + # Final image conditioning. + cond_vae_embeddings = image_mask * cond_vae_embeddings + + # Sample masks for the conditioning images. + clip_mask_dtype = image_embeddings.dtype + clip_mask = 1 - ( + (random_p < 2 * cfg.condition_drop_rate).to(clip_mask_dtype) + ) + clip_mask = clip_mask.reshape(bnm, 1, 1, 1).repeat(1, Nv, 1, 1) + clip_mask = rearrange(clip_mask, "B Nv M C -> (B Nv) M C") + clip_mask = torch.cat([clip_mask]*2, dim=0) + # Final image conditioning. + image_embeddings = clip_mask * image_embeddings + elif cfg.drop_type == 'drop_independent': + # randomly drop all independently + random_p = torch.rand(bsz, device=latents.device, generator=generator) + + # Sample masks for the conditioning images. + image_mask_dtype = cond_vae_embeddings.dtype + image_mask = 1 - ( + (random_p >= cfg.condition_drop_rate).to(image_mask_dtype) + * (random_p < 3 * cfg.condition_drop_rate).to(image_mask_dtype) + ) + image_mask = image_mask.reshape(bsz, 1, 1, 1) + # Final image conditioning. + cond_vae_embeddings = image_mask * cond_vae_embeddings + + # Sample masks for the conditioning images. + clip_mask_dtype = image_embeddings.dtype + clip_mask = 1 - ( + (random_p < 2 * cfg.condition_drop_rate).to(clip_mask_dtype) + ) + clip_mask = clip_mask.reshape(bsz, 1, 1) + # Final image conditioning. + image_embeddings = clip_mask * image_embeddings + elif cfg.drop_type == 'drop_joint': + # randomly drop all independently + random_p = torch.rand(bsz//2, device=latents.device, generator=generator) + + # Sample masks for the conditioning images. + image_mask_dtype = cond_vae_embeddings.dtype + image_mask = 1 - ( + (random_p >= cfg.condition_drop_rate).to(image_mask_dtype) + * (random_p < 3 * cfg.condition_drop_rate).to(image_mask_dtype) + ) + image_mask = torch.cat([image_mask]*2, dim=0) + image_mask = image_mask.reshape(bsz, 1, 1, 1) + # Final image conditioning. + cond_vae_embeddings = image_mask * cond_vae_embeddings + + # Sample masks for the conditioning images. + clip_mask_dtype = image_embeddings.dtype + clip_mask = 1 - ( + (random_p < 2 * cfg.condition_drop_rate).to(clip_mask_dtype) + ) + clip_mask = torch.cat([clip_mask]*2, dim=0) + clip_mask = clip_mask.reshape(bsz, 1, 1) + # Final image conditioning. + image_embeddings = clip_mask * image_embeddings + + # (B*Nv, 8, Hl, Wl) + latent_model_input = torch.cat([noisy_latents, cond_vae_embeddings], dim=1) + + model_pred = unet( + latent_model_input, + timesteps, + encoder_hidden_states=image_embeddings, + class_labels=camera_task_embeddings + ).sample + + # Get the target for loss depending on the prediction type + if noise_scheduler.config.prediction_type == "epsilon": + target = noise + elif noise_scheduler.config.prediction_type == "v_prediction": + target = noise_scheduler.get_velocity(latents, noise, timesteps) + else: + raise ValueError(f"Unknown prediction type {noise_scheduler.config.prediction_type}") + + if cfg.snr_gamma is None: + loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean") + else: + # Compute loss-weights as per Section 3.4 of https://arxiv.org/abs/2303.09556. + # Since we predict the noise instead of x_0, the original formulation is slightly changed. + # This is discussed in Section 4.2 of the same paper. + snr = compute_snr(timesteps) + mse_loss_weights = ( + torch.stack([snr, cfg.snr_gamma * torch.ones_like(timesteps)], dim=1).min(dim=1)[0] / snr + ) + # We first calculate the original loss. Then we mean over the non-batch dimensions and + # rebalance the sample-wise losses with their respective loss weights. + # Finally, we take the mean of the rebalanced loss. + loss = F.mse_loss(model_pred.float(), target.float(), reduction="none") + loss = loss.mean(dim=list(range(1, len(loss.shape)))) * mse_loss_weights + loss = loss.mean() + + # Gather the losses across all processes for logging (if we use distributed training). + avg_loss = accelerator.gather(loss.repeat(cfg.train_batch_size)).mean() + train_loss += avg_loss.item() / cfg.gradient_accumulation_steps + + # Backpropagate + accelerator.backward(loss) + if accelerator.sync_gradients and cfg.max_grad_norm is not None: + accelerator.clip_grad_norm_(unet.parameters(), cfg.max_grad_norm) + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + + # Checks if the accelerator has performed an optimization step behind the scenes + if accelerator.sync_gradients: + if cfg.use_ema: + ema_unet.step(unet.parameters()) + progress_bar.update(1) + global_step += 1 + accelerator.log({"train_loss": train_loss}, step=global_step) + train_loss = 0.0 + + if global_step % cfg.checkpointing_steps == 0: + if accelerator.is_main_process: + save_path = os.path.join(cfg.output_dir, f"checkpoint") + accelerator.save_state(save_path) + try: + unet.module.save_pretrained(os.path.join(cfg.output_dir, f"unet-{global_step}/unet")) + except: + unet.save_pretrained(os.path.join(cfg.output_dir, f"unet-{global_step}/unet")) + logger.info(f"Saved state to {save_path}") + + if global_step % cfg.validation_steps == 0 or (cfg.validation_sanity_check and global_step == 1): + if accelerator.is_main_process: + if cfg.use_ema: + # Store the UNet parameters temporarily and load the EMA parameters to perform inference. + ema_unet.store(unet.parameters()) + ema_unet.copy_to(unet.parameters()) + log_validation( + validation_dataloader, + vae, + feature_extractor, + image_encoder, + unet, + cfg, + accelerator, + weight_dtype, + global_step, + 'validation', + vis_dir + ) + log_validation( + validation_train_dataloader, + vae, + feature_extractor, + image_encoder, + unet, + cfg, + accelerator, + weight_dtype, + global_step, + 'validation_train', + vis_dir + ) + if cfg.use_ema: + # Switch back to the original UNet parameters. + ema_unet.restore(unet.parameters()) + + logs = {"step_loss": loss.detach().item(), "lr": lr_scheduler.get_last_lr()[0]} + progress_bar.set_postfix(**logs) + + if global_step >= cfg.max_train_steps: + break + + # Create the pipeline using the trained modules and save it. + accelerator.wait_for_everyone() + if accelerator.is_main_process: + unet = accelerator.unwrap_model(unet) + if cfg.use_ema: + ema_unet.copy_to(unet.parameters()) + pipeline = MVDiffusionImagePipeline( + image_encoder=image_encoder, feature_extractor=feature_extractor, vae=vae, unet=unet, safety_checker=None, + scheduler=DDIMScheduler.from_pretrained(cfg.pretrained_model_name_or_path, subfolder="scheduler"), + **cfg.pipe_kwargs + ) + os.makedirs(os.path.join(cfg.output_dir, "pipeckpts"), exist_ok=True) + pipeline.save_pretrained(os.path.join(cfg.output_dir, "pipeckpts")) + + accelerator.end_training() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--config', type=str, required=True) + args = parser.parse_args() + schema = OmegaConf.structured(TrainingConfig) + cfg = OmegaConf.load(args.config) + cfg = OmegaConf.merge(schema, cfg) + main(cfg) diff --git a/apps/third_party/Wonder3D/utils/misc.py b/apps/third_party/Wonder3D/utils/misc.py new file mode 100644 index 0000000000000000000000000000000000000000..45a76c61f672afc392f507bd7a652c4d480d065c --- /dev/null +++ b/apps/third_party/Wonder3D/utils/misc.py @@ -0,0 +1,54 @@ +import os +from omegaconf import OmegaConf +from packaging import version + + +# ============ Register OmegaConf Recolvers ============= # +# OmegaConf.register_new_resolver('calc_exp_lr_decay_rate', lambda factor, n: factor**(1./n)) +# OmegaConf.register_new_resolver('add', lambda a, b: a + b) +# OmegaConf.register_new_resolver('sub', lambda a, b: a - b) +# OmegaConf.register_new_resolver('mul', lambda a, b: a * b) +# OmegaConf.register_new_resolver('div', lambda a, b: a / b) +# OmegaConf.register_new_resolver('idiv', lambda a, b: a // b) +# OmegaConf.register_new_resolver('basename', lambda p: os.path.basename(p)) +# ======================================================= # + + +def prompt(question): + inp = input(f"{question} (y/n)").lower().strip() + if inp and inp == 'y': + return True + if inp and inp == 'n': + return False + return prompt(question) + + +def load_config(*yaml_files, cli_args=[]): + yaml_confs = [OmegaConf.load(f) for f in yaml_files] + cli_conf = OmegaConf.from_cli(cli_args) + conf = OmegaConf.merge(*yaml_confs, cli_conf) + OmegaConf.resolve(conf) + return conf + + +def config_to_primitive(config, resolve=True): + return OmegaConf.to_container(config, resolve=resolve) + + +def dump_config(path, config): + with open(path, 'w') as fp: + OmegaConf.save(config=config, f=fp) + +def get_rank(): + # SLURM_PROCID can be set even if SLURM is not managing the multiprocessing, + # therefore LOCAL_RANK needs to be checked first + rank_keys = ("RANK", "LOCAL_RANK", "SLURM_PROCID", "JSM_NAMESPACE_RANK") + for key in rank_keys: + rank = os.environ.get(key) + if rank is not None: + return int(rank) + return 0 + + +def parse_version(ver): + return version.parse(ver) diff --git a/apps/third_party/mvdream_diffusers b/apps/third_party/mvdream_diffusers new file mode 160000 index 0000000000000000000000000000000000000000..8b318efac486784819502b88952fae970f40a47d --- /dev/null +++ b/apps/third_party/mvdream_diffusers @@ -0,0 +1 @@ +Subproject commit 8b318efac486784819502b88952fae970f40a47d diff --git a/apps/utils.py b/apps/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..29e72e3985fe106fbcc2c434f5b6ee08fd9a64c5 --- /dev/null +++ b/apps/utils.py @@ -0,0 +1,224 @@ +from typing import Dict, Optional, Tuple, List +from dataclasses import dataclass +import os +import sys +proj_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(os.path.join(proj_dir)) +import time +import cv2 +import gradio as gr +import numpy as np +import torch +import PIL +from PIL import Image +import rembg +from rembg import remove +rembg_session = rembg.new_session() +from segment_anything import sam_model_registry, SamPredictor + +import craftsman +from craftsman.utils.config import ExperimentConfig, load_config + +parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +def load_model( + ckpt_path: str, + config_path: str, + scheluder_name: str = None, + scheluder_dict : dict = None, + device = "cuda" + ): + cfg: ExperimentConfig + cfg = load_config(config_path) + + if 'pretrained_model_name_or_path' not in cfg.system.condition_model or cfg.system.condition_model.pretrained_model_name_or_path is None: + cfg.system.condition_model.config_path = config_path.replace("config.yaml", "clip_config.json") + + # cfg.system.denoise_scheduler= { + # 'num_train_timesteps': 1000, + # 'beta_start': 0.00085, + # 'beta_end': 0.012, + # 'beta_schedule': 'scaled_linear', + # 'steps_offset': 1 + # } + + system: BaseSystem = craftsman.find(cfg.system_type)( + cfg.system, + ) + + print(f"Restoring states from the checkpoint path at {ckpt_path} with config {cfg}") + system.load_state_dict(torch.load(ckpt_path)['state_dict']) + system = system.to(device).eval() + + return system + +def rmbg_sam(iamge, foreground_ratio): + return iamge + +def rmbg_rembg(iamge, foreground_ratio): + return iamge + +class RMBG(object): + def __init__(self, device): + sam_checkpoint = f"{parent_dir}/ckpts/SAM/sam_vit_h_4b8939.pth" + model_type = "vit_h" + sam = sam_model_registry[model_type](checkpoint=sam_checkpoint).to(device) + self.predictor = SamPredictor(sam) + + def rmbg_sam(self, input_image, crop_size, foreground_ratio, segment=True, rescale=True): + RES = 1024 + input_image.thumbnail([RES, RES], Image.Resampling.LANCZOS) + + if segment: + image_rem = input_image.convert('RGBA') + image_nobg = remove(image_rem, alpha_matting=True) + arr = np.asarray(image_nobg)[:, :, -1] + x_nonzero = np.nonzero(arr.sum(axis=0)) + y_nonzero = np.nonzero(arr.sum(axis=1)) + x_min = int(x_nonzero[0].min()) + y_min = int(y_nonzero[0].min()) + x_max = int(x_nonzero[0].max()) + y_max = int(y_nonzero[0].max()) + input_image = sam_segment(self.predictor, input_image.convert('RGB'), x_min, y_min, x_max, y_max) + # Rescale and recenter + if rescale: + image_arr = np.array(input_image) + in_w, in_h = image_arr.shape[:2] + out_res = min(RES, max(in_w, in_h)) + ret, mask = cv2.threshold(np.array(input_image.split()[-1]), 0, 255, cv2.THRESH_BINARY) + x, y, w, h = cv2.boundingRect(mask) + max_size = max(w, h) + side_len = int(max_size / foreground_ratio) + padded_image = np.zeros((side_len, side_len, 4), dtype=np.uint8) + center = side_len // 2 + padded_image[center - h // 2 : center - h // 2 + h, center - w // 2 : center - w // 2 + w] = image_arr[y : y + h, x : x + w] + rgba = Image.fromarray(padded_image).resize((out_res, out_res), Image.LANCZOS) + + rgba_arr = np.array(rgba) / 255.0 + rgb = rgba_arr[..., :3] * rgba_arr[..., -1:] + (1 - rgba_arr[..., -1:]) + input_image = Image.fromarray((rgb * 255).astype(np.uint8)) + else: + input_image = expand2square(input_image, (127, 127, 127, 0)) + return input_image + + + def rmbg_rembg(self, image, crop_size, foreground_ratio, background_choice, backgroud_color): + print(background_choice) + if background_choice == "Alpha as mask": + background = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image = Image.alpha_composite(background, image) + else: + image = remove_background(image, rembg_session, force_remove=True) + image = do_resize_content(image, foreground_ratio) + image = expand_to_square(image) + image = add_background(image, backgroud_color) + return image.convert("RGB") + + def run(self, rm_type, image, crop_size, foreground_ratio, background_choice, backgroud_color): + if "Remove" in background_choice: + if rm_type.upper() == "SAM": + return self.rmbg_sam(image, crop_size, foreground_ratio, background_choice, backgroud_color) + elif rm_type.upper() == "REMBG": + return self.rmbg_rembg(image, crop_size, foreground_ratio, background_choice, backgroud_color) + else: + return -1 + elif "Original" in background_choice: + return image + else: + return -1 + + +def save_image(tensor): + ndarr = tensor.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy() + # pdb.set_trace() + im = Image.fromarray(ndarr) + return ndarr + +def prepare_data(single_image, crop_size): + from third_party.Wonder3D.mvdiffusion.data.single_image_dataset import SingleImageDataset + dataset = SingleImageDataset(root_dir='', num_views=6, img_wh=[256, 256], bg_color='white', crop_size=crop_size, single_image=single_image) + return dataset[0] + +def expand2square(pil_img, background_color): + width, height = pil_img.size + if width == height: + return pil_img + elif width > height: + result = Image.new(pil_img.mode, (width, width), background_color) + result.paste(pil_img, (0, (width - height) // 2)) + return result + else: + result = Image.new(pil_img.mode, (height, height), background_color) + result.paste(pil_img, ((height - width) // 2, 0)) + return result + + +def sam_segment(predictor, input_image, *bbox_coords): + bbox = np.array(bbox_coords) + image = np.asarray(input_image) + + start_time = time.time() + predictor.set_image(image) + + masks_bbox, scores_bbox, logits_bbox = predictor.predict(box=bbox, multimask_output=True) + + print(f"SAM Time: {time.time() - start_time:.3f}s") + out_image = np.zeros((image.shape[0], image.shape[1], 4), dtype=np.uint8) + out_image[:, :, :3] = image + out_image_bbox = out_image.copy() + out_image_bbox[:, :, 3] = masks_bbox[-1].astype(np.uint8) * 255 + torch.cuda.empty_cache() + return Image.fromarray(out_image_bbox, mode='RGBA') + +def expand_to_square(image, bg_color=(0, 0, 0, 0)): + # expand image to 1:1 + width, height = image.size + if width == height: + return image + new_size = (max(width, height), max(width, height)) + new_image = Image.new("RGBA", new_size, bg_color) + paste_position = ((new_size[0] - width) // 2, (new_size[1] - height) // 2) + new_image.paste(image, paste_position) + return new_image + +def check_input_image(input_image): + if input_image is None: + raise gr.Error("No image uploaded!") + +def remove_background( + image: PIL.Image.Image, + rembg_session = None, + force: bool = False, + **rembg_kwargs, +) -> PIL.Image.Image: + do_remove = True + if image.mode == "RGBA" and image.getextrema()[3][0] < 255: + # explain why current do not rm bg + print("alhpa channl not enpty, skip remove background, using alpha channel as mask") + background = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image = Image.alpha_composite(background, image) + do_remove = False + do_remove = do_remove or force + if do_remove: + image = rembg.remove(image, session=rembg_session, **rembg_kwargs) + return image + +def do_resize_content(original_image: Image, scale_rate): + # resize image content wile retain the original image size + if scale_rate != 1: + # Calculate the new size after rescaling + new_size = tuple(int(dim * scale_rate) for dim in original_image.size) + # Resize the image while maintaining the aspect ratio + resized_image = original_image.resize(new_size) + # Create a new image with the original size and black background + padded_image = Image.new("RGBA", original_image.size, (0, 0, 0, 0)) + paste_position = ((original_image.width - resized_image.width) // 2, (original_image.height - resized_image.height) // 2) + padded_image.paste(resized_image, paste_position) + return padded_image + else: + return original_image + +def add_background(image, bg_color=(255, 255, 255)): + # given an RGBA image, alpha channel is used as mask to add background color + background = Image.new("RGBA", image.size, bg_color) + return Image.alpha_composite(background, image) \ No newline at end of file diff --git a/asset/logo.png b/asset/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b47d7331d7c8194bbc5ef0c98d9846d3e39cdfc6 Binary files /dev/null and b/asset/logo.png differ diff --git a/asset/teaser.jpg b/asset/teaser.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ce9c5fc1cb2cc85121acfd60018649bfff2399c9 Binary files /dev/null and b/asset/teaser.jpg differ diff --git a/asset/video_cover.png b/asset/video_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..be9770b623499f31db148d7e9954dc8c1954a702 --- /dev/null +++ b/asset/video_cover.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b8d3c4acb86162780604278dca4d147808ecf5bb1c6fa3ac450be272f9068d5 +size 1106978 diff --git a/ckpts/CRM/pixel-diffusion.pth b/ckpts/CRM/pixel-diffusion.pth new file mode 100644 index 0000000000000000000000000000000000000000..d5540db4a739a1cb7f601735cdaa2ab44751cc0e --- /dev/null +++ b/ckpts/CRM/pixel-diffusion.pth @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27445c0202f51cb7e6715978e2d7811d1f9a276adae0bc7af8bf7191dd2e71e0 +size 6162765693 diff --git a/ckpts/SAM/sam_vit_h_4b8939.pth b/ckpts/SAM/sam_vit_h_4b8939.pth new file mode 100755 index 0000000000000000000000000000000000000000..8523acce9ddab1cf7e355628a08b1aab8ce08a72 --- /dev/null +++ b/ckpts/SAM/sam_vit_h_4b8939.pth @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7bf3b02f3ebf1267aba913ff637d9a2d5c33d3173bb679e46d9f338c26f262e +size 2564550879 diff --git a/configs/image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6.yaml b/configs/image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6.yaml new file mode 100755 index 0000000000000000000000000000000000000000..e7b649eeb566ed3c0fc59e9b1c423ffd7ea2c3ab --- /dev/null +++ b/configs/image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6.yaml @@ -0,0 +1,148 @@ +exp_root_dir: "outputs" +name: "image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6" +tag: "${rmspace:${system.shape_model_type}+n${data.n_samples}+noise${data.noise_sigma}+pfeat${system.shape_model.point_feats}+normemb${system.condition_model.normalize_embeds}+lr${system.optimizer.args.lr}+qkvbias${system.shape_model.qkv_bias}+nfreq${system.shape_model.num_freqs}+ln_post${system.shape_model.use_ln_post},_}" +seed: 0 + +data_type: "objaverse-datamodule" +data: + root_dir: "data/objaverse_clean/cap3d_high_quality_170k_images" + data_type: "occupancy" + n_samples: 4096 + noise_sigma: 0. + + load_supervision: False + supervision_type: "occupancy" + n_supervision: 4096 + + load_image: True # whether to load images + image_data_path: data/objaverse_clean/raw_data/images/cap3d_high_quality_170k + image_type: "mvrgb" # rgb, normal, mvrgb, mvnormal + idx: [0, 4, 8, 12, 16] + n_views: 4 + load_caption: False # whether to load captions + rotate_points: False + + batch_size: 32 + num_workers: 16 + +system_type: "shape-diffusion-system" +system: + val_samples_json: "val_data/mv_images/val_samples_rgb_mvimage.json" + z_scale_factor: 1.0 + guidance_scale: 7.5 + num_inference_steps: 50 + eta: 0.0 + + shape_model_type: "michelangelo-autoencoder" + shape_model: + # pretrained_model_name_or_path: ./ckpts/3DNativeGeneration/michelangelo-aligned-autoencoder-l256-e64-ne8-nd16.ckpt + pretrained_model_name_or_path: "./outputs/image-to-shape-diffusion_bak/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6/michelangelo-autoencoder+n4096+noise0.0+pfeat3+normembFalse+lr5e-05+qkvbiasFalse+nfreq8+ln_postTrue/ckpts/last.ckpt" + num_latents: 256 + embed_dim: 64 + point_feats: 3 # xyz + normal + out_dim: 1 # only occupancy + num_freqs: 8 + include_pi: false + heads: 12 + width: 768 + num_encoder_layers: 8 + num_decoder_layers: 16 + use_ln_post: true + init_scale: 0.25 + qkv_bias: false + use_flash: true + use_checkpoint: true + + condition_model_type: "clip-embedder" + condition_model: + pretrained_model_name_or_path: "./ckpts/pretrained_weights/huggingface/hub/models--openai--clip-vit-large-patch14/snapshots/8d052a0f05efbaefbc9e8786ba291cfdf93e5bff" + encode_camera: true + camera_embeds_dim: 32 # 16 * 2[sin, cos] + n_views: ${data.n_views} + empty_embeds_ratio: 0.1 + normalize_embeds: false + # zero_uncond_embeds: true + zero_uncond_embeds: false + + denoiser_model_type: "simple-denoiser" + denoiser_model: + # pretrained_model_name_or_path: "./ckpts/CraftsMan/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6.pth" + pretrained_model_name_or_path: "./ckpts/CraftsMan/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6-It500000.pth" + input_channels: ${system.shape_model.embed_dim} + output_channels: ${system.shape_model.embed_dim} + n_ctx: ${system.shape_model.num_latents} + width: 768 + layers: 6 # 2 * 6 + 1 = 13 + heads: 12 + context_dim: 1024 + init_scale: 1.0 + skip_ln: true + use_checkpoint: true + + noise_scheduler_type: "diffusers.schedulers.DDPMScheduler" + noise_scheduler: + num_train_timesteps: 1000 + beta_start: 0.00085 + beta_end: 0.012 + beta_schedule: "scaled_linear" + variance_type: "fixed_small" + clip_sample: false + + denoise_scheduler_type: "diffusers.schedulers.DDIMScheduler" + denoise_scheduler: + num_train_timesteps: 1000 + beta_start: 0.00085 + beta_end: 0.012 + beta_schedule: "scaled_linear" + clip_sample: false # clip sample to -1~1 + set_alpha_to_one: false + steps_offset: 1 + + loggers: + wandb: + enable: false + project: "CraftsMan" + name: image-to-shape-diffusion+${name}+${tag} + + loss: + loss_type: "mse" + lambda_diffusion: 1. + + optimizer: + name: AdamW + args: + lr: 5.e-5 + betas: [0.9, 0.99] + eps: 1.e-6 + + scheduler: + name: SequentialLR + interval: step + schedulers: + - name: LinearLR + interval: step + args: + start_factor: 1e-6 + end_factor: 1.0 + total_iters: 5000 + - name: CosineAnnealingLR + interval: step + args: + T_max: 5000 + eta_min: 0. + milestones: [5000] + +trainer: + num_nodes: 1 + max_epochs: 100000 + log_every_n_steps: 5 + num_sanity_val_steps: 1 + check_val_every_n_epoch: 3 + enable_progress_bar: true + precision: 16-mixed + strategy: 'ddp_find_unused_parameters_true' + +checkpoint: + save_last: true + save_top_k: -1 + every_n_train_steps: 5000 \ No newline at end of file diff --git a/configs/shape-autoencoder/l1024-e64-ne8-nd16.yaml b/configs/shape-autoencoder/l1024-e64-ne8-nd16.yaml new file mode 100755 index 0000000000000000000000000000000000000000..099e7c3c29171c336fd8092515569e429480b48a --- /dev/null +++ b/configs/shape-autoencoder/l1024-e64-ne8-nd16.yaml @@ -0,0 +1,95 @@ +exp_root_dir: "outputs" +name: "michelangelo-autoencoder/l1024-e64-ne8-nd16" +tag: "${rmspace:n${data.n_samples}+${data.supervision_type}+rot${data.rotate}+noise${data.noise_sigma}+${system.shape_model.embed_type}+dsample${system.shape_model.use_downsample}+pfeat${system.shape_model.point_feats}+logits${system.loss.lambda_logits}+kl${system.loss.lambda_kl}+lr${system.optimizer.args.lr},_}" +seed: 0 + +data_type: "objaverse-datamodule" +data: + root_dir: "data/objaverse_clean/sdf_100k" + data_type: "sdf" + n_samples: 4096 + noise_sigma: 0. + rotate: False + + load_supervision: True + supervision_type: "occupancy" + n_supervision: 4096 + + load_image: False # whether to load images + load_caption: False # whether to load captions + + batch_size: 128 + num_workers: 16 + +system_type: "shape-autoencoder-system" +system: + sample_posterior: true + + shape_model_type: "michelangelo-autoencoder" + shape_model: + num_latents: 1024 # 1024 + embed_dim: 64 + point_feats: 3 # xyz + normal + out_dim: 1 # only occupancy + embed_type: "fourier" + num_freqs: 8 + include_pi: false + heads: 12 + width: 768 + num_encoder_layers: 8 + num_decoder_layers: 16 + use_ln_post: true + init_scale: 0.25 + qkv_bias: true + use_flash: true + use_checkpoint: true + use_downsample: true + + loggers: + wandb: + enable: false + project: "CraftsMan" + name: shape-autoencoder+${name}+${tag} + + loss: + lambda_logits: 1. + lambda_kl: 0.001 + + optimizer: + name: AdamW + args: + lr: 1.e-4 + betas: [0.9, 0.99] + eps: 1.e-6 + + scheduler: + name: SequentialLR + interval: step + schedulers: + - name: LinearLR + interval: step + args: + start_factor: 1e-6 + end_factor: 1.0 + total_iters: 5000 + - name: CosineAnnealingLR + interval: step + args: + T_max: 5000 + eta_min: 0. + milestones: [5000] + +trainer: + num_nodes: 1 + max_epochs: 100000 + log_every_n_steps: 5 + num_sanity_val_steps: 1 + # val_check_interval: 200 + check_val_every_n_epoch: 10 + enable_progress_bar: true + precision: 16-mixed + +checkpoint: + save_last: true + save_top_k: -1 + every_n_train_steps: 5000 \ No newline at end of file diff --git a/configs/shape-autoencoder/l256-e64-ne8-nd16.yaml b/configs/shape-autoencoder/l256-e64-ne8-nd16.yaml new file mode 100755 index 0000000000000000000000000000000000000000..cf779a3a7ad958e51ed6ea898ede9a497338f676 --- /dev/null +++ b/configs/shape-autoencoder/l256-e64-ne8-nd16.yaml @@ -0,0 +1,95 @@ +exp_root_dir: "outputs" +name: "michelangelo-autoencoder/l256-e64-ne8-nd16" +tag: "${rmspace:n${data.n_samples}+${data.supervision_type}+rot${data.rotate}+noise${data.noise_sigma}+${system.shape_model.embed_type}+dsample${system.shape_model.use_downsample}+pfeat${system.shape_model.point_feats}+logits${system.loss.lambda_logits}+kl${system.loss.lambda_kl}+lr${system.optimizer.args.lr},_}" +seed: 0 + +data_type: "objaverse-datamodule" +data: + root_dir: "data/objaverse_clean/sdf_100k" + data_type: "sdf" + n_samples: 4096 + noise_sigma: 0. + rotate: False + + load_supervision: True + supervision_type: "occupancy" + n_supervision: 4096 + + load_image: False # whether to load images + load_caption: False # whether to load captions + + batch_size: 128 + num_workers: 16 + +system_type: "shape-autoencoder-system" +system: + sample_posterior: true + + shape_model_type: "michelangelo-autoencoder" + shape_model: + num_latents: 256 # 256 + embed_dim: 64 + point_feats: 3 # xyz + normal + out_dim: 1 # only occupancy + embed_type: "fourier" + num_freqs: 8 + include_pi: false + heads: 12 + width: 768 + num_encoder_layers: 8 + num_decoder_layers: 16 + use_ln_post: true + init_scale: 0.25 + qkv_bias: true + use_flash: true + use_checkpoint: true + use_downsample: true + + loggers: + wandb: + enable: false + project: "CraftsMan" + name: shape-autoencoder+${name}+${tag} + + loss: + lambda_logits: 1. + lambda_kl: 0.001 + + optimizer: + name: AdamW + args: + lr: 1.e-4 + betas: [0.9, 0.99] + eps: 1.e-6 + + scheduler: + name: SequentialLR + interval: step + schedulers: + - name: LinearLR + interval: step + args: + start_factor: 1e-6 + end_factor: 1.0 + total_iters: 5000 + - name: CosineAnnealingLR + interval: step + args: + T_max: 5000 + eta_min: 0. + milestones: [5000] + +trainer: + num_nodes: 1 + max_epochs: 100000 + log_every_n_steps: 5 + num_sanity_val_steps: 1 + # val_check_interval: 200 + check_val_every_n_epoch: 10 + enable_progress_bar: true + precision: 16-mixed + +checkpoint: + save_last: true + save_top_k: -1 + every_n_train_steps: 5000 \ No newline at end of file diff --git a/configs/shape-autoencoder/l512-e64-ne8-nd16.yaml b/configs/shape-autoencoder/l512-e64-ne8-nd16.yaml new file mode 100755 index 0000000000000000000000000000000000000000..e32ef5272757c4f4c8d0f3067a1c029818543475 --- /dev/null +++ b/configs/shape-autoencoder/l512-e64-ne8-nd16.yaml @@ -0,0 +1,95 @@ +exp_root_dir: "outputs" +name: "michelangelo-autoencoder/l512-e64-ne8-nd16" +tag: "${rmspace:n${data.n_samples}+${data.supervision_type}+rot${data.rotate}+noise${data.noise_sigma}+${system.shape_model.embed_type}+dsample${system.shape_model.use_downsample}+pfeat${system.shape_model.point_feats}+logits${system.loss.lambda_logits}+kl${system.loss.lambda_kl}+lr${system.optimizer.args.lr},_}" +seed: 0 + +data_type: "objaverse-datamodule" +data: + root_dir: "data/objaverse_clean/sdf_100k" + data_type: "sdf" + n_samples: 4096 + noise_sigma: 0. + rotate: False + + load_supervision: True + supervision_type: "occupancy" + n_supervision: 4096 + + load_image: False # whether to load images + load_caption: False # whether to load captions + + batch_size: 128 + num_workers: 16 + +system_type: "shape-autoencoder-system" +system: + sample_posterior: true + + shape_model_type: "michelangelo-autoencoder" + shape_model: + num_latents: 512 # 512 + embed_dim: 64 + point_feats: 3 # xyz + normal + out_dim: 1 # only occupancy + embed_type: "fourier" + num_freqs: 8 + include_pi: false + heads: 12 + width: 768 + num_encoder_layers: 8 + num_decoder_layers: 16 + use_ln_post: true + init_scale: 0.25 + qkv_bias: true + use_flash: true + use_checkpoint: true + use_downsample: true + + loggers: + wandb: + enable: false + project: "CraftsMan" + name: shape-autoencoder+${name}+${tag} + + loss: + lambda_logits: 1. + lambda_kl: 0.001 + + optimizer: + name: AdamW + args: + lr: 1.e-4 + betas: [0.9, 0.99] + eps: 1.e-6 + + scheduler: + name: SequentialLR + interval: step + schedulers: + - name: LinearLR + interval: step + args: + start_factor: 1e-6 + end_factor: 1.0 + total_iters: 5000 + - name: CosineAnnealingLR + interval: step + args: + T_max: 5000 + eta_min: 0. + milestones: [5000] + +trainer: + num_nodes: 1 + max_epochs: 100000 + log_every_n_steps: 5 + num_sanity_val_steps: 1 + # val_check_interval: 200 + check_val_every_n_epoch: 10 + enable_progress_bar: true + precision: 16-mixed + +checkpoint: + save_last: true + save_top_k: -1 + every_n_train_steps: 5000 \ No newline at end of file diff --git a/craftsman/__init__.py b/craftsman/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..aaae1910181ee66ba098822f3009e44765e4a3a2 --- /dev/null +++ b/craftsman/__init__.py @@ -0,0 +1,52 @@ +import importlib + +__modules__ = {} + + +def register(name): + def decorator(cls): + if name in __modules__: + raise ValueError( + f"Module {name} already exists! Names of extensions conflict!" + ) + else: + __modules__[name] = cls + return cls + + return decorator + + +def find(name): + if name in __modules__: + return __modules__[name] + else: + try: + module_string = ".".join(name.split(".")[:-1]) + cls_name = name.split(".")[-1] + module = importlib.import_module(module_string, package=None) + return getattr(module, cls_name) + except Exception as e: + raise ValueError(f"Module {name} not found!") + + +### grammar sugar for logging utilities ### +import logging + +logger = logging.getLogger("pytorch_lightning") + +from pytorch_lightning.utilities.rank_zero import ( + rank_zero_debug, + rank_zero_info, + rank_zero_only, +) + +debug = rank_zero_debug +info = rank_zero_info + + +@rank_zero_only +def warn(*args, **kwargs): + logger.warn(*args, **kwargs) + + +from . import data, models, systems diff --git a/craftsman/__pycache__/__init__.cpython-311.pyc b/craftsman/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fdd02739ebf30ab292a84fde381cb39014769ca0 Binary files /dev/null and b/craftsman/__pycache__/__init__.cpython-311.pyc differ diff --git a/craftsman/__pycache__/__init__.cpython-38.pyc b/craftsman/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ae602b962e76d70f08d6a8635c2e94951963c9b Binary files /dev/null and b/craftsman/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/data/__init__.py b/craftsman/data/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..6548321fbbaf745526a3060ad9e3826c793b2f2b --- /dev/null +++ b/craftsman/data/__init__.py @@ -0,0 +1,3 @@ +from . import ( + objaverse +) \ No newline at end of file diff --git a/craftsman/data/__pycache__/__init__.cpython-310.pyc b/craftsman/data/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..533244b5257e1439dbf99999ec2a39f1a9a5ab3b Binary files /dev/null and b/craftsman/data/__pycache__/__init__.cpython-310.pyc differ diff --git a/craftsman/data/__pycache__/__init__.cpython-38.pyc b/craftsman/data/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe7fb6e708782671297bc33419978a06181211b3 Binary files /dev/null and b/craftsman/data/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/data/__pycache__/objaverse.cpython-310.pyc b/craftsman/data/__pycache__/objaverse.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48f210fd6ed4f965ce3beedc195ba6ed98427e7f Binary files /dev/null and b/craftsman/data/__pycache__/objaverse.cpython-310.pyc differ diff --git a/craftsman/data/__pycache__/objaverse.cpython-38.pyc b/craftsman/data/__pycache__/objaverse.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6a5e4c272d984fda71e82b8565e1797c998a803 Binary files /dev/null and b/craftsman/data/__pycache__/objaverse.cpython-38.pyc differ diff --git a/craftsman/data/__pycache__/objaverse_parquet.cpython-310.pyc b/craftsman/data/__pycache__/objaverse_parquet.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..218ef66f65b8d02539c9e112aaa909ef61d70d53 Binary files /dev/null and b/craftsman/data/__pycache__/objaverse_parquet.cpython-310.pyc differ diff --git a/craftsman/data/__pycache__/objaverse_patch_sdf.cpython-310.pyc b/craftsman/data/__pycache__/objaverse_patch_sdf.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e19b0883c14dc91bb0fb558ad2c7c85c37b4b72a Binary files /dev/null and b/craftsman/data/__pycache__/objaverse_patch_sdf.cpython-310.pyc differ diff --git a/craftsman/data/__pycache__/objaverse_sdf.cpython-310.pyc b/craftsman/data/__pycache__/objaverse_sdf.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac84be9d68686c37a5dd03a0ac8eb73825d59922 Binary files /dev/null and b/craftsman/data/__pycache__/objaverse_sdf.cpython-310.pyc differ diff --git a/craftsman/data/__pycache__/objaverse_sdf_parquet.cpython-310.pyc b/craftsman/data/__pycache__/objaverse_sdf_parquet.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f5f766e30b6556ff0ff83c8a1b68c778631627b Binary files /dev/null and b/craftsman/data/__pycache__/objaverse_sdf_parquet.cpython-310.pyc differ diff --git a/craftsman/data/__pycache__/shape.cpython-310.pyc b/craftsman/data/__pycache__/shape.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a41c08a10c6c4cecadd453232efa80d0cc48d01d Binary files /dev/null and b/craftsman/data/__pycache__/shape.cpython-310.pyc differ diff --git a/craftsman/data/objaverse.py b/craftsman/data/objaverse.py new file mode 100644 index 0000000000000000000000000000000000000000..7501f3ac2af1500ccb3c1270fc29921dc49ed9a2 --- /dev/null +++ b/craftsman/data/objaverse.py @@ -0,0 +1,311 @@ +import math +import os +import json +from dataclasses import dataclass, field + +import random +import imageio +import numpy as np +import pytorch_lightning as pl +import torch +import torch.nn.functional as F +from torch.utils.data import DataLoader, Dataset +from torchvision import transforms +from PIL import Image +from transformers import CLIPImageProcessor, CLIPTokenizer + +from craftsman import register +from craftsman.utils.base import Updateable +from craftsman.utils.config import parse_structured +from craftsman.utils.typing import * + +def rot2eul(R): + beta = -np.arcsin(R[2,0]) + alpha = np.arctan2(R[2,1]/np.cos(beta),R[2,2]/np.cos(beta)) + gamma = np.arctan2(R[1,0]/np.cos(beta),R[0,0]/np.cos(beta)) + return np.array((alpha, beta, gamma)) + +def eul2rot(theta) : + R = np.array([[np.cos(theta[1])*np.cos(theta[2]), np.sin(theta[0])*np.sin(theta[1])*np.cos(theta[2]) - np.sin(theta[2])*np.cos(theta[0]), np.sin(theta[1])*np.cos(theta[0])*np.cos(theta[2]) + np.sin(theta[0])*np.sin(theta[2])], + [np.sin(theta[2])*np.cos(theta[1]), np.sin(theta[0])*np.sin(theta[1])*np.sin(theta[2]) + np.cos(theta[0])*np.cos(theta[2]), np.sin(theta[1])*np.sin(theta[2])*np.cos(theta[0]) - np.sin(theta[0])*np.cos(theta[2])], + [-np.sin(theta[1]), np.sin(theta[0])*np.cos(theta[1]), np.cos(theta[0])*np.cos(theta[1])]]) + return R + +@dataclass +class ObjaverseDataModuleConfig: + root_dir: str = None + data_type: str = "occupancy" # occupancy or sdf + n_samples: int = 4096 # number of points in input point cloud + scale: float = 1.0 # scale of the input point cloud and target supervision + noise_sigma: float = 0.0 # noise level of the input point cloud + + load_supervision: bool = True # whether to load supervision + supervision_type: str = "occupancy" # occupancy, sdf, tsdf, tsdf_w_surface + n_supervision: int = 10000 # number of points in supervision + + load_image: bool = False # whether to load images + image_data_path: str = "" # path to the image data + image_type: str = "rgb" # rgb, normal + background_color: Tuple[float, float, float] = field( + default_factory=lambda: (1.0, 1.0, 1.0) + ) + idx: Optional[List[int]] = None # index of the image to load + n_views: int = 1 # number of views + rotate_points: bool = False # whether to rotate the input point cloud and the supervision + + load_caption: bool = False # whether to load captions + caption_type: str = "text" # text, clip_embeds + tokenizer_pretrained_model_name_or_path: str = "" + + batch_size: int = 32 + num_workers: int = 0 + +class ObjaverseDataset(Dataset): + def __init__(self, cfg: Any, split: str) -> None: + super().__init__() + self.cfg: ObjaverseDataModuleConfig = cfg + self.split = split + + self.uids = json.load(open(f'{cfg.root_dir}/{split}.json')) + print(f"Loaded {len(self.uids)} {split} uids") + + if self.cfg.load_caption: + self.tokenizer = CLIPTokenizer.from_pretrained(self.cfg.tokenizer_pretrained_model_name_or_path) + + self.background_color = torch.as_tensor(self.cfg.background_color) + self.distance = 1.0 + self.camera_embedding = torch.as_tensor([ + [[1, 0, 0, 0], + [0, 0, -1, -self.distance], + [0, 1, 0, 0], + [0, 0, 0, 1]], # front to back + + [[0, 0, 1, self.distance], + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, 1]], # right to left + + [[-1, 0, 0, 0], + [0, 0, 1, self.distance], + [0, 1, 0, 0], + [0, 0, 0, 1]], # back to front + + [[0, 0, -1, -self.distance], + [-1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, 1]], # left to right + ], dtype=torch.float32) + if self.cfg.n_views != 1: + assert self.cfg.n_views == self.camera_embedding.shape[0] + + def __len__(self): + return len(self.uids) + + def _load_shape(self, index: int) -> Dict[str, Any]: + if self.cfg.data_type == "occupancy": + # for input point cloud + pointcloud = np.load(f'{self.cfg.root_dir}/{self.uids[index]}/pointcloud.npz') + surface = np.asarray(pointcloud['points']) * 2 # range from -1 to 1 + normal = np.asarray(pointcloud['normals']) + surface = np.concatenate([surface, normal], axis=1) + elif self.cfg.data_type == "sdf": + data = np.load(f'{self.cfg.root_dir}/{self.uids[index]}.npz') + # for input point cloud + surface = data["surface"] + else: + raise NotImplementedError(f"Data type {self.cfg.data_type} not implemented") + + # random sampling + rng = np.random.default_rng() + ind = rng.choice(surface.shape[0], self.cfg.n_samples, replace=False) + surface = surface[ind] + # rescale data + surface[:, :3] = surface[:, :3] * self.cfg.scale # target scale + # add noise to input point cloud + surface[:, :3] += (np.random.rand(surface.shape[0], 3) * 2 - 1) * self.cfg.noise_sigma + ret = { + "uid": self.uids[index].split('/')[-1], + "surface": surface.astype(np.float32), + } + + return ret + + def _load_shape_supervision(self, index: int) -> Dict[str, Any]: + # for supervision + ret = {} + if self.cfg.data_type == "occupancy": + points = np.load(f'{self.cfg.root_dir}/{self.uids[index]}/points.npz') + rand_points = np.asarray(points['points']) * 2 # range from -1.1 to 1.1 + occupancies = np.asarray(points['occupancies']) + occupancies = np.unpackbits(occupancies) + elif self.cfg.data_type == "sdf": + data = np.load(f'{self.cfg.root_dir}/{self.uids[index]}.npz') + rand_points = data['rand_points'] + sdfs = data['sdfs'] + else: + raise NotImplementedError(f"Data type {self.cfg.data_type} not implemented") + + # random sampling + rng = np.random.default_rng() + ind = rng.choice(rand_points.shape[0], self.cfg.n_supervision, replace=False) + rand_points = rand_points[ind] + rand_points = rand_points * self.cfg.scale + ret["rand_points"] = rand_points.astype(np.float32) + + if self.cfg.data_type == "occupancy": + assert self.cfg.supervision_type == "occupancy", "Only occupancy supervision is supported for occupancy data" + occupancies = occupancies[ind] + ret["occupancies"] = occupancies.astype(np.float32) + elif self.cfg.data_type == "sdf": + if self.cfg.supervision_type == "sdf": + ret["sdf"] = sdfs[ind].flatten().astype(np.float32) + elif self.cfg.supervision_type == "occupancy": + ret["occupancies"] = np.where(sdfs[ind].flatten() < 1e-3, 0, 1).astype(np.float32) + else: + raise NotImplementedError(f"Supervision type {self.cfg.supervision_type} not implemented") + + return ret + + def _load_image(self, index: int) -> Dict[str, Any]: + def _load_single_image(img_path): + img = torch.from_numpy( + np.asarray( + Image.fromarray(imageio.v2.imread(img_path)) + .convert("RGBA") + ) + / 255.0 + ).float() + mask: Float[Tensor, "H W 1"] = img[:, :, -1:] + image: Float[Tensor, "H W 3"] = img[:, :, :3] * mask + self.background_color[ + None, None, : + ] * (1 - mask) + return image + + ret = {} + if self.cfg.image_type == "rgb" or self.cfg.image_type == "normal": + assert self.cfg.n_views == 1, "Only single view is supported for single image" + sel_idx = random.choice(self.cfg.idx) + ret["sel_image_idx"] = sel_idx + if self.cfg.image_type == "rgb": + img_path = f'{self.cfg.image_data_path}/' + "/".join(self.uids[index].split('/')[-2:]) + f"/{sel_idx}.png" + elif self.cfg.image_type == "normal": + img_path = f'{self.cfg.image_data_path}/' + "/".join(self.uids[index].split('/')[-2:]) + f"/{sel_idx}_normal.png" + ret["image"] = _load_single_image(img_path) + ret["c2w"] = self.camera_embedding[sel_idx % 4] + elif self.cfg.image_type == "mvrgb" or self.cfg.image_type == "mvnormal": + sel_idx = random.choice(self.cfg.idx) + ret["sel_image_idx"] = sel_idx + mvimages = [] + for i in range(self.cfg.n_views): + if self.cfg.image_type == "mvrgb": + img_path = f'{self.cfg.image_data_path}/' + "/".join(self.uids[index].split('/')[-2:]) + f"/{sel_idx+i}.png" + elif self.cfg.image_type == "mvnormal": + img_path = f'{self.cfg.image_data_path}/' + "/".join(self.uids[index].split('/')[-2:]) + f"/{sel_idx+i}_normal.png" + mvimages.append(_load_single_image(img_path)) + ret["mvimages"] = torch.stack(mvimages) + ret["c2ws"] = self.camera_embedding + else: + raise NotImplementedError(f"Image type {self.cfg.image_type} not implemented") + + return ret + + def _load_caption(self, index: int, drop_text_embed: bool = False) -> Dict[str, Any]: + ret = {} + if self.cfg.caption_type == "text": + caption = eval(json.load(open(f'{self.cfg.image_data_path}/' + "/".join(self.uids[index].split('/')[-2:]) + f'/annotation.json'))) + texts = [v for k, v in caption.items()] + sel_idx = random.randint(0, len(texts) - 1) + ret["sel_caption_idx"] = sel_idx + ret['text_input_ids'] = self.tokenizer( + texts[sel_idx] if not drop_text_embed else "", + max_length=self.tokenizer.model_max_length, + padding="max_length", + truncation=True, + return_tensors="pt" + ).input_ids.detach() + else: + raise NotImplementedError(f"Caption type {self.cfg.caption_type} not implemented") + + return ret + + def get_data(self, index): + # load shape + ret = self._load_shape(index) + + # load supervision for shape + if self.cfg.load_supervision: + ret.update(self._load_shape_supervision(index)) + + # load image + if self.cfg.load_image: + ret.update(self._load_image(index)) + + # load the rotation of the object and rotate the camera + rots = np.load(f'{self.cfg.image_data_path}/' + "/".join(self.uids[index].split('/')[-2:]) + f'/rots.npy')[ret['sel_image_idx']].astype(np.float32) + rots = torch.tensor(rots[:3, :3], dtype=torch.float32) + if "c2ws" in ret.keys(): + ret["c2ws"][:, :3, :3] = torch.matmul(rots, ret["c2ws"][:, :3, :3]) + ret["c2ws"][:, :3, 3] = torch.matmul(rots, ret["c2ws"][:, :3, 3].unsqueeze(-1)).squeeze(-1) + elif "c2w" in ret.keys(): + ret["c2w"][:3, :3] = torch.matmul(rots, ret["c2w"][:3, :3]) + ret["c2w"][:3, 3] = torch.matmul(rots, ret["c2w"][:3, 3].unsqueeze(-1)).squeeze(-1) + + # load caption + if self.cfg.load_caption: + ret.update(self._load_caption(index)) + + return ret + + def __getitem__(self, index): + try: + return self.get_data(index) + except Exception as e: + print(f"Error in {self.uids[index]}: {e}") + return self.__getitem__(np.random.randint(len(self))) + + + def collate(self, batch): + batch = torch.utils.data.default_collate(batch) + return batch + + +@register("objaverse-datamodule") +class ObjaverseDataModule(pl.LightningDataModule): + cfg: ObjaverseDataModuleConfig + + def __init__(self, cfg: Optional[Union[dict, DictConfig]] = None) -> None: + super().__init__() + self.cfg = parse_structured(ObjaverseDataModuleConfig, cfg) + + def setup(self, stage=None) -> None: + if stage in [None, "fit"]: + self.train_dataset = ObjaverseDataset(self.cfg, "train") + if stage in [None, "fit", "validate"]: + self.val_dataset = ObjaverseDataset(self.cfg, "val") + if stage in [None, "test", "predict"]: + self.test_dataset = ObjaverseDataset(self.cfg, "test") + + def prepare_data(self): + pass + + def general_loader(self, dataset, batch_size, collate_fn=None, num_workers=0) -> DataLoader: + return DataLoader( + dataset, batch_size=batch_size, collate_fn=collate_fn, num_workers=num_workers + ) + + def train_dataloader(self) -> DataLoader: + return self.general_loader( + self.train_dataset, + batch_size=self.cfg.batch_size, + collate_fn=self.train_dataset.collate, + num_workers=self.cfg.num_workers + ) + + def val_dataloader(self) -> DataLoader: + return self.general_loader(self.val_dataset, batch_size=1) + + def test_dataloader(self) -> DataLoader: + return self.general_loader(self.test_dataset, batch_size=1) + + def predict_dataloader(self) -> DataLoader: + return self.general_loader(self.test_dataset, batch_size=1) \ No newline at end of file diff --git a/craftsman/models/__init__.py b/craftsman/models/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..73b20fbfa46a26d96e273dd3b0a77a765bbe58c7 --- /dev/null +++ b/craftsman/models/__init__.py @@ -0,0 +1,5 @@ +from . import ( + autoencoders, + conditional_encoders, + denoisers, +) \ No newline at end of file diff --git a/craftsman/models/__pycache__/__init__.cpython-38.pyc b/craftsman/models/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34f64f0875b96cc02f7478e3ccb7afdd82ee9022 Binary files /dev/null and b/craftsman/models/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/models/autoencoders/__init__.py b/craftsman/models/autoencoders/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..623726edddecfa7d1aec09d765f8d58d0fc581ed --- /dev/null +++ b/craftsman/models/autoencoders/__init__.py @@ -0,0 +1,3 @@ +from . import ( + michelangelo_autoencoder, +) diff --git a/craftsman/models/autoencoders/__pycache__/__init__.cpython-38.pyc b/craftsman/models/autoencoders/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ecbd3992bc3cab0917eb9a8b3520a73d7f96955c Binary files /dev/null and b/craftsman/models/autoencoders/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/models/autoencoders/__pycache__/michelangelo_autoencoder.cpython-38.pyc b/craftsman/models/autoencoders/__pycache__/michelangelo_autoencoder.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e1e4acf28c56a45310a093f6e511134f75b3508 Binary files /dev/null and b/craftsman/models/autoencoders/__pycache__/michelangelo_autoencoder.cpython-38.pyc differ diff --git a/craftsman/models/autoencoders/__pycache__/utils.cpython-38.pyc b/craftsman/models/autoencoders/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..584e668da960b1c80b674fc8588b67b1494c1f25 Binary files /dev/null and b/craftsman/models/autoencoders/__pycache__/utils.cpython-38.pyc differ diff --git a/craftsman/models/autoencoders/michelangelo_autoencoder.py b/craftsman/models/autoencoders/michelangelo_autoencoder.py new file mode 100755 index 0000000000000000000000000000000000000000..23be1d4f9824b6aca6a87061ada52ba440a3c784 --- /dev/null +++ b/craftsman/models/autoencoders/michelangelo_autoencoder.py @@ -0,0 +1,326 @@ +from dataclasses import dataclass +import math + +import torch +import torch.nn as nn +from einops import repeat, rearrange +from transformers import CLIPModel + +import craftsman +from craftsman.models.transformers.perceiver_1d import Perceiver +from craftsman.models.transformers.attention import ResidualCrossAttentionBlock +from craftsman.utils.checkpoint import checkpoint +from craftsman.utils.base import BaseModule +from craftsman.utils.typing import * + +from .utils import AutoEncoder, FourierEmbedder, get_embedder + +class PerceiverCrossAttentionEncoder(nn.Module): + def __init__(self, + use_downsample: bool, + num_latents: int, + embedder: FourierEmbedder, + point_feats: int, + embed_point_feats: bool, + width: int, + heads: int, + layers: int, + init_scale: float = 0.25, + qkv_bias: bool = True, + use_ln_post: bool = False, + use_flash: bool = False, + use_checkpoint: bool = False): + + super().__init__() + + self.use_checkpoint = use_checkpoint + self.num_latents = num_latents + self.use_downsample = use_downsample + self.embed_point_feats = embed_point_feats + + if not self.use_downsample: + self.query = nn.Parameter(torch.randn((num_latents, width)) * 0.02) + + self.embedder = embedder + if self.embed_point_feats: + self.input_proj = nn.Linear(self.embedder.out_dim * 2, width) + else: + self.input_proj = nn.Linear(self.embedder.out_dim + point_feats, width) + + self.cross_attn = ResidualCrossAttentionBlock( + width=width, + heads=heads, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_flash=use_flash, + ) + + self.self_attn = Perceiver( + n_ctx=num_latents, + width=width, + layers=layers, + heads=heads, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_flash=use_flash, + use_checkpoint=False + ) + + if use_ln_post: + self.ln_post = nn.LayerNorm(width) + else: + self.ln_post = None + + def _forward(self, pc, feats): + """ + + Args: + pc (torch.FloatTensor): [B, N, 3] + feats (torch.FloatTensor or None): [B, N, C] + + Returns: + + """ + + bs, N, D = pc.shape + + data = self.embedder(pc) + if feats is not None: + if self.embed_point_feats: + feats = self.embedder(feats) + data = torch.cat([data, feats], dim=-1) + data = self.input_proj(data) + + if self.use_downsample: + ###### fps + from torch_cluster import fps + flattened = pc.view(bs*N, D) + + batch = torch.arange(bs).to(pc.device) + batch = torch.repeat_interleave(batch, N) + + pos = flattened + + ratio = 1.0 * self.num_latents / N + + idx = fps(pos, batch, ratio=ratio) + + query = data.view(bs*N, -1)[idx].view(bs, -1, data.shape[-1]) + else: + query = self.query + query = repeat(query, "m c -> b m c", b=bs) + + latents = self.cross_attn(query, data) + latents = self.self_attn(latents) + + if self.ln_post is not None: + latents = self.ln_post(latents) + + return latents + + def forward(self, pc: torch.FloatTensor, feats: Optional[torch.FloatTensor] = None): + """ + + Args: + pc (torch.FloatTensor): [B, N, 3] + feats (torch.FloatTensor or None): [B, N, C] + + Returns: + dict + """ + + return checkpoint(self._forward, (pc, feats), self.parameters(), self.use_checkpoint) + + +class PerceiverCrossAttentionDecoder(nn.Module): + + def __init__(self, + num_latents: int, + out_dim: int, + embedder: FourierEmbedder, + width: int, + heads: int, + init_scale: float = 0.25, + qkv_bias: bool = True, + use_flash: bool = False, + use_checkpoint: bool = False): + + super().__init__() + + self.use_checkpoint = use_checkpoint + self.embedder = embedder + + self.query_proj = nn.Linear(self.embedder.out_dim, width) + + self.cross_attn_decoder = ResidualCrossAttentionBlock( + n_data=num_latents, + width=width, + heads=heads, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_flash=use_flash + ) + + self.ln_post = nn.LayerNorm(width) + self.output_proj = nn.Linear(width, out_dim) + + def _forward(self, queries: torch.FloatTensor, latents: torch.FloatTensor): + queries = self.query_proj(self.embedder(queries)) + x = self.cross_attn_decoder(queries, latents) + x = self.ln_post(x) + x = self.output_proj(x) + return x + + def forward(self, queries: torch.FloatTensor, latents: torch.FloatTensor): + return checkpoint(self._forward, (queries, latents), self.parameters(), self.use_checkpoint) + + +@craftsman.register("michelangelo-autoencoder") +class MichelangeloAutoencoder(AutoEncoder): + r""" + A VAE model for encoding shapes into latents and decoding latent representations into shapes. + """ + + @dataclass + class Config(BaseModule.Config): + pretrained_model_name_or_path: str = "" + use_downsample: bool = False + num_latents: int = 256 + point_feats: int = 0 + embed_point_feats: bool = False + out_dim: int = 1 + embed_dim: int = 64 + embed_type: str = "fourier" + num_freqs: int = 8 + include_pi: bool = True + width: int = 768 + heads: int = 12 + num_encoder_layers: int = 8 + num_decoder_layers: int = 16 + init_scale: float = 0.25 + qkv_bias: bool = True + use_ln_post: bool = False + use_flash: bool = False + use_checkpoint: bool = True + + cfg: Config + + def configure(self) -> None: + super().configure() + + self.embedder = get_embedder(embed_type=self.cfg.embed_type, num_freqs=self.cfg.num_freqs, include_pi=self.cfg.include_pi) + + # encoder + self.cfg.init_scale = self.cfg.init_scale * math.sqrt(1.0 / self.cfg.width) + self.encoder = PerceiverCrossAttentionEncoder( + use_downsample=self.cfg.use_downsample, + embedder=self.embedder, + num_latents=self.cfg.num_latents, + point_feats=self.cfg.point_feats, + embed_point_feats=self.cfg.embed_point_feats, + width=self.cfg.width, + heads=self.cfg.heads, + layers=self.cfg.num_encoder_layers, + init_scale=self.cfg.init_scale, + qkv_bias=self.cfg.qkv_bias, + use_ln_post=self.cfg.use_ln_post, + use_flash=self.cfg.use_flash, + use_checkpoint=self.cfg.use_checkpoint + ) + + if self.cfg.embed_dim > 0: + # VAE embed + self.pre_kl = nn.Linear(self.cfg.width, self.cfg.embed_dim * 2) + self.post_kl = nn.Linear(self.cfg.embed_dim, self.cfg.width) + self.latent_shape = (self.cfg.num_latents, self.cfg.embed_dim) + else: + self.latent_shape = (self.cfg.num_latents, self.cfg.width) + + self.transformer = Perceiver( + n_ctx=self.cfg.num_latents, + width=self.cfg.width, + layers=self.cfg.num_decoder_layers, + heads=self.cfg.heads, + init_scale=self.cfg.init_scale, + qkv_bias=self.cfg.qkv_bias, + use_flash=self.cfg.use_flash, + use_checkpoint=self.cfg.use_checkpoint + ) + + # decoder + self.decoder = PerceiverCrossAttentionDecoder( + embedder=self.embedder, + out_dim=self.cfg.out_dim, + num_latents=self.cfg.num_latents, + width=self.cfg.width, + heads=self.cfg.heads, + init_scale=self.cfg.init_scale, + qkv_bias=self.cfg.qkv_bias, + use_flash=self.cfg.use_flash, + use_checkpoint=self.cfg.use_checkpoint + ) + + if self.cfg.pretrained_model_name_or_path != "": + print(f"Loading pretrained model from {self.cfg.pretrained_model_name_or_path}") + pretrained_ckpt = torch.load(self.cfg.pretrained_model_name_or_path, map_location="cpu") + if 'state_dict' in pretrained_ckpt: + _pretrained_ckpt = {} + for k, v in pretrained_ckpt['state_dict'].items(): + if k.startswith('shape_model.'): + _pretrained_ckpt[k.replace('shape_model.', '')] = v + pretrained_ckpt = _pretrained_ckpt + self.load_state_dict(pretrained_ckpt, strict=True) + + + def encode(self, + surface: torch.FloatTensor, + sample_posterior: bool = True): + """ + Args: + surface (torch.FloatTensor): [B, N, 3+C] + sample_posterior (bool): + + Returns: + shape_latents (torch.FloatTensor): [B, num_latents, width] + kl_embed (torch.FloatTensor): [B, num_latents, embed_dim] + posterior (DiagonalGaussianDistribution or None): + """ + assert surface.shape[-1] == 3 + self.cfg.point_feats, f"\ + Expected {3 + self.cfg.point_feats} channels, got {surface.shape[-1]}" + + pc, feats = surface[..., :3], surface[..., 3:] # B, n_samples, 3 + shape_latents = self.encoder(pc, feats) # B, num_latents, width + kl_embed, posterior = self.encode_kl_embed(shape_latents, sample_posterior) # B, num_latents, embed_dim + + return shape_latents, kl_embed, posterior + + + def decode(self, + latents: torch.FloatTensor): + """ + Args: + latents (torch.FloatTensor): [B, embed_dim] + + Returns: + latents (torch.FloatTensor): [B, embed_dim] + """ + latents = self.post_kl(latents) # [B, num_latents, embed_dim] -> [B, num_latents, width] + + return self.transformer(latents) + + + def query(self, + queries: torch.FloatTensor, + latents: torch.FloatTensor): + """ + Args: + queries (torch.FloatTensor): [B, N, 3] + latents (torch.FloatTensor): [B, embed_dim] + + Returns: + logits (torch.FloatTensor): [B, N], occupancy logits + """ + + logits = self.decoder(queries, latents).squeeze(-1) + + return logits diff --git a/craftsman/models/autoencoders/utils.py b/craftsman/models/autoencoders/utils.py new file mode 100755 index 0000000000000000000000000000000000000000..53a70e5a8e5c983619cd0d82c1bc859d511849d1 --- /dev/null +++ b/craftsman/models/autoencoders/utils.py @@ -0,0 +1,302 @@ +from dataclasses import dataclass + +import torch +import torch.nn as nn +from torch import distributed as tdist +from torch.nn import functional as F +import math +import mcubes +import numpy as np +from einops import repeat, rearrange +from skimage import measure + +from craftsman.utils.base import BaseModule +from craftsman.utils.typing import * +from craftsman.utils.misc import get_world_size +from craftsman.utils.ops import generate_dense_grid_points + +VALID_EMBED_TYPES = ["identity", "fourier", "hashgrid", "sphere_harmonic", "triplane_fourier"] + +class FourierEmbedder(nn.Module): + def __init__(self, + num_freqs: int = 6, + logspace: bool = True, + input_dim: int = 3, + include_input: bool = True, + include_pi: bool = True) -> None: + super().__init__() + + if logspace: + frequencies = 2.0 ** torch.arange( + num_freqs, + dtype=torch.float32 + ) + else: + frequencies = torch.linspace( + 1.0, + 2.0 ** (num_freqs - 1), + num_freqs, + dtype=torch.float32 + ) + + if include_pi: + frequencies *= torch.pi + + self.register_buffer("frequencies", frequencies, persistent=False) + self.include_input = include_input + self.num_freqs = num_freqs + + self.out_dim = self.get_dims(input_dim) + + def get_dims(self, input_dim): + temp = 1 if self.include_input or self.num_freqs == 0 else 0 + out_dim = input_dim * (self.num_freqs * 2 + temp) + + return out_dim + + def forward(self, x: torch.Tensor) -> torch.Tensor: + if self.num_freqs > 0: + embed = (x[..., None].contiguous() * self.frequencies).view(*x.shape[:-1], -1) + if self.include_input: + return torch.cat((x, embed.sin(), embed.cos()), dim=-1) + else: + return torch.cat((embed.sin(), embed.cos()), dim=-1) + else: + return x + + +class LearnedFourierEmbedder(nn.Module): + def __init__(self, input_dim, dim): + super().__init__() + assert (dim % 2) == 0 + half_dim = dim // 2 + per_channel_dim = half_dim // input_dim + self.weights = nn.Parameter(torch.randn(per_channel_dim)) + + self.out_dim = self.get_dims(input_dim) + + def forward(self, x): + # [b, t, c, 1] * [1, d] = [b, t, c, d] -> [b, t, c * d] + freqs = (x[..., None] * self.weights[None] * 2 * np.pi).view(*x.shape[:-1], -1) + fouriered = torch.cat((x, freqs.sin(), freqs.cos()), dim=-1) + return fouriered + + def get_dims(self, input_dim): + return input_dim * (self.weights.shape[0] * 2 + 1) + +class Sine(nn.Module): + def __init__(self, w0 = 1.): + super().__init__() + self.w0 = w0 + def forward(self, x): + return torch.sin(self.w0 * x) + +class Siren(nn.Module): + def __init__( + self, + in_dim, + out_dim, + w0 = 1., + c = 6., + is_first = False, + use_bias = True, + activation = None, + dropout = 0. + ): + super().__init__() + self.in_dim = in_dim + self.out_dim = out_dim + self.is_first = is_first + + weight = torch.zeros(out_dim, in_dim) + bias = torch.zeros(out_dim) if use_bias else None + self.init_(weight, bias, c = c, w0 = w0) + + self.weight = nn.Parameter(weight) + self.bias = nn.Parameter(bias) if use_bias else None + self.activation = Sine(w0) if activation is None else activation + self.dropout = nn.Dropout(dropout) + + def init_(self, weight, bias, c, w0): + dim = self.in_dim + + w_std = (1 / dim) if self.is_first else (math.sqrt(c / dim) / w0) + weight.uniform_(-w_std, w_std) + + if bias is not None: + bias.uniform_(-w_std, w_std) + + def forward(self, x): + out = F.linear(x, self.weight, self.bias) + out = self.activation(out) + out = self.dropout(out) + return out + +def get_embedder(embed_type="fourier", num_freqs=-1, input_dim=3, include_pi=True): + if embed_type == "identity" or (embed_type == "fourier" and num_freqs == -1): + return nn.Identity(), input_dim + + elif embed_type == "fourier": + embedder_obj = FourierEmbedder(num_freqs=num_freqs, include_pi=include_pi) + + elif embed_type == "learned_fourier": + embedder_obj = LearnedFourierEmbedder(in_channels=input_dim, dim=num_freqs) + + elif embed_type == "siren": + embedder_obj = Siren(in_dim=input_dim, out_dim=num_freqs * input_dim * 2 + input_dim) + + elif embed_type == "hashgrid": + raise NotImplementedError + + elif embed_type == "sphere_harmonic": + raise NotImplementedError + + else: + raise ValueError(f"{embed_type} is not valid. Currently only supprts {VALID_EMBED_TYPES}") + return embedder_obj + + +###################### AutoEncoder +class AutoEncoder(BaseModule): + @dataclass + class Config(BaseModule.Config): + pretrained_model_name_or_path: str = "" + num_latents: int = 256 + embed_dim: int = 64 + width: int = 768 + + cfg: Config + + def configure(self) -> None: + super().configure() + + def encode(self, x: torch.FloatTensor) -> Tuple[torch.FloatTensor, torch.FloatTensor]: + raise NotImplementedError + + def decode(self, z: torch.FloatTensor) -> torch.FloatTensor: + raise NotImplementedError + + def encode_kl_embed(self, latents: torch.FloatTensor, sample_posterior: bool = True): + posterior = None + if self.cfg.embed_dim > 0: + moments = self.pre_kl(latents) + posterior = DiagonalGaussianDistribution(moments, feat_dim=-1) + if sample_posterior: + kl_embed = posterior.sample() + else: + kl_embed = posterior.mode() + else: + kl_embed = latents + return kl_embed, posterior + + def forward(self, + surface: torch.FloatTensor, + queries: torch.FloatTensor, + sample_posterior: bool = True): + shape_latents, kl_embed, posterior = self.encode(surface, sample_posterior=sample_posterior) + + latents = self.decode(kl_embed) # [B, num_latents, width] + + logits = self.query(queries, latents) # [B,] + + return shape_latents, latents, posterior, logits + + def query(self, queries: torch.FloatTensor, latents: torch.FloatTensor) -> torch.FloatTensor: + raise NotImplementedError + + @torch.no_grad() + def extract_geometry(self, + latents: torch.FloatTensor, + bounds: Union[Tuple[float], List[float], float] = (-1.05, -1.05, -1.05, 1.05, 1.05, 1.05), + octree_depth: int = 8, + num_chunks: int = 10000, + ): + + if isinstance(bounds, float): + bounds = [-bounds, -bounds, -bounds, bounds, bounds, bounds] + + bbox_min = np.array(bounds[0:3]) + bbox_max = np.array(bounds[3:6]) + bbox_size = bbox_max - bbox_min + + xyz_samples, grid_size, length = generate_dense_grid_points( + bbox_min=bbox_min, + bbox_max=bbox_max, + octree_depth=octree_depth, + indexing="ij" + ) + xyz_samples = torch.FloatTensor(xyz_samples) + batch_size = latents.shape[0] + + batch_logits = [] + for start in range(0, xyz_samples.shape[0], num_chunks): + queries = xyz_samples[start: start + num_chunks, :].to(latents) + batch_queries = repeat(queries, "p c -> b p c", b=batch_size) + + logits = self.query(batch_queries, latents) + batch_logits.append(logits.cpu()) + + grid_logits = torch.cat(batch_logits, dim=1).view((batch_size, grid_size[0], grid_size[1], grid_size[2])).float().numpy() + + mesh_v_f = [] + has_surface = np.zeros((batch_size,), dtype=np.bool_) + for i in range(batch_size): + try: + vertices, faces, normals, _ = measure.marching_cubes(grid_logits[i], 0, method="lewiner") + # vertices, faces = mcubes.marching_cubes(grid_logits[i], 0) + vertices = vertices / grid_size * bbox_size + bbox_min + faces = faces[:, [2, 1, 0]] + mesh_v_f.append((vertices.astype(np.float32), np.ascontiguousarray(faces))) + has_surface[i] = True + except: + mesh_v_f.append((None, None)) + has_surface[i] = False + + return mesh_v_f, has_surface + +class DiagonalGaussianDistribution(object): + def __init__(self, parameters: Union[torch.Tensor, List[torch.Tensor]], deterministic=False, feat_dim=1): + self.feat_dim = feat_dim + self.parameters = parameters + + if isinstance(parameters, list): + self.mean = parameters[0] + self.logvar = parameters[1] + else: + self.mean, self.logvar = torch.chunk(parameters, 2, dim=feat_dim) + + self.logvar = torch.clamp(self.logvar, -30.0, 20.0) + self.deterministic = deterministic + self.std = torch.exp(0.5 * self.logvar) + self.var = torch.exp(self.logvar) + if self.deterministic: + self.var = self.std = torch.zeros_like(self.mean) + + def sample(self): + x = self.mean + self.std * torch.randn_like(self.mean) + return x + + def kl(self, other=None, dims=(1, 2)): + if self.deterministic: + return torch.Tensor([0.]) + else: + if other is None: + return 0.5 * torch.mean(torch.pow(self.mean, 2) + + self.var - 1.0 - self.logvar, + dim=dims) + else: + return 0.5 * torch.mean( + torch.pow(self.mean - other.mean, 2) / other.var + + self.var / other.var - 1.0 - self.logvar + other.logvar, + dim=dims) + + def nll(self, sample, dims=(1, 2)): + if self.deterministic: + return torch.Tensor([0.]) + logtwopi = np.log(2.0 * np.pi) + return 0.5 * torch.sum( + logtwopi + self.logvar + torch.pow(sample - self.mean, 2) / self.var, + dim=dims) + + def mode(self): + return self.mean diff --git a/craftsman/models/conditional_encoders/__init__.py b/craftsman/models/conditional_encoders/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..be7f5c66f7fa65b598a3e47e627d2318d769b260 --- /dev/null +++ b/craftsman/models/conditional_encoders/__init__.py @@ -0,0 +1,3 @@ +from . import ( + clip_encoder, +) diff --git a/craftsman/models/conditional_encoders/__pycache__/__init__.cpython-38.pyc b/craftsman/models/conditional_encoders/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ccb873be8e22f71330428529d306ad6db924c25 Binary files /dev/null and b/craftsman/models/conditional_encoders/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/models/conditional_encoders/__pycache__/base.cpython-38.pyc b/craftsman/models/conditional_encoders/__pycache__/base.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..beffb7a70ceb8236c6a611bf57112bf50fadb2dc Binary files /dev/null and b/craftsman/models/conditional_encoders/__pycache__/base.cpython-38.pyc differ diff --git a/craftsman/models/conditional_encoders/__pycache__/clip_encoder.cpython-38.pyc b/craftsman/models/conditional_encoders/__pycache__/clip_encoder.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..883250d27f42079814e36cf2eeaa5405557f843c Binary files /dev/null and b/craftsman/models/conditional_encoders/__pycache__/clip_encoder.cpython-38.pyc differ diff --git a/craftsman/models/conditional_encoders/base.py b/craftsman/models/conditional_encoders/base.py new file mode 100755 index 0000000000000000000000000000000000000000..7bda4c04e2a59d2a60a91356e11b76a4ae6c66bc --- /dev/null +++ b/craftsman/models/conditional_encoders/base.py @@ -0,0 +1,139 @@ +import random +import torch +import torch.nn as nn +import numpy as np +from PIL import Image +from dataclasses import dataclass +from torchvision.transforms import Normalize +from torchvision.transforms import InterpolationMode +from torchvision.transforms.transforms import _interpolation_modes_from_int + +from transformers import CLIPModel, CLIPTokenizer, CLIPImageProcessor +from transformers.utils import ModelOutput +from typing import Iterable, Optional, Union, List + +import craftsman +from craftsman.utils.base import BaseModule +from craftsman.utils.typing import * + +ImageType = Union[np.ndarray, torch.Tensor, Image.Image] + + +class BaseEmbedder(BaseModule): + @dataclass + class Config(BaseModule.Config): + pretrained_model_name_or_path: Optional[str] = None # the pretrained model name or path + + encode_camera: bool = False # whether to encode camera + camera_embeds_type: str = "sincos" # the type of camera embeds + camera_embeds_dim: Optional[int] = None # the dimension of camera embeds + n_views: int = 1 # the number of views + + empty_embeds_ratio: float = 0.1 # the ratio of empty embeds + zero_uncond_embeds: bool = True + + normalize_embeds: bool = False # whether to normalize the embeds + + cfg: Config + + def configure(self) -> None: + super().configure() + + if self.cfg.encode_camera: + self.distance = 1.0 + self.register_buffer( + "cameras", + torch.as_tensor([ + [[1, 0, 0, 0], + [0, 0, -1, -self.distance], + [0, 1, 0, 0], + [0, 0, 0, 1]], # front to back + + [[0, 0, 1, self.distance], + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, 1]], # right to left + + [[-1, 0, 0, 0], + [0, 0, 1, self.distance], + [0, 1, 0, 0], + [0, 0, 0, 1]], # back to front + + [[0, 0, -1, -self.distance], + [-1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, 1]], # left to right + ], dtype=torch.float32), + ) + + def encode_image(self, images: Iterable[Optional[ImageType]], camera_embeds: Optional[torch.Tensor] = None, **kwargs) -> torch.FloatTensor: + pass + + def encode_text(self, texts: List[str], **kwargs) -> torch.FloatTensor: + pass + + def encode_camera(self, c2ws: torch.Tensor): + if self.cfg.camera_embeds_type == "sincos": + assert c2ws.shape[-1] == 4 and c2ws.shape[-2] == 4, f"Invalid c2ws shape: {c2ws.shape}" + c2ws = c2ws.view(-1, 16) + return torch.cat([torch.sin(c2ws), torch.cos(c2ws)], dim=-1) + else: + raise NotImplementedError(f"Unknown camera_embeds_type: {self.cfg.camera_embeds_type}") + + def post_process_embeds(self, text_embeds, visual_embeds): + bs = text_embeds.shape[0] if text_embeds is not None else visual_embeds.shape[0] + + if self.cfg.normalize_embeds: + # post-process the text/visual embeds + if text_embeds is not None: + text_embeds = text_embeds / text_embeds.norm(dim=-1, keepdim=True) + if visual_embeds is not None: + visual_embeds = visual_embeds / visual_embeds.norm(dim=-1, keepdim=True) + + assert text_embeds is not None or visual_embeds is not None + + # return text_embeds, visual_embeds + if text_embeds is not None and visual_embeds is not None: + return torch.cat([text_embeds, visual_embeds], dim=1) + elif text_embeds is not None: + return text_embeds + else: + return visual_embeds + + def forward(self, batch): + bs = batch["surface"].shape[0] + + text_embeds, visual_embeds = None, None + + if random.random() < self.cfg.empty_embeds_ratio: + if "text_input_ids" in batch or "text_embeds" in batch: + if self.empty_text_embeds is None: + if not self.cfg.zero_uncond_embeds: + self.empty_text_embeds = self.encode_text([""]).detach() # [1, 77, 768] + text_embeds = self.empty_text_embeds.repeat(bs, 1, 1) + if "image" in batch or "image_embeds" in batch: + visual_embeds = self.empty_image_embeds.repeat(bs, 1, 1) + elif "mvimages" in batch or "mvimage_embeds" in batch: + visual_embeds = self.empty_image_embeds.unsqueeze(1).repeat(bs, 1, 1, 1) + else: + # for text inputs + if "text_input_ids" in batch: + text_embeds = self.encode_text(batch["text_input_ids"]) + + # for visual inputs + if "image" in batch: + if self.cfg.encode_camera: + visual_embeds = self.encode_image(batch["image"], cameras=batch["c2w"]) + else: + visual_embeds = self.encode_image(batch["image"]) + elif "mvimages" in batch: + n_views = batch["mvimages"].shape[1] + if self.cfg.encode_camera: + visual_embeds = self.encode_image( + batch["mvimages"].view(-1, *batch["mvimages"].shape[-3:]), \ + cameras=batch["c2ws"]).view(bs, n_views, *self.empty_image_embeds.shape[-2:]) + else: + visual_embeds = self.encode_image( + batch["mvimages"].view(-1, *batch["mvimages"].shape[-3:])).view(bs, n_views, *self.empty_image_embeds.shape[-2:]) + + return self.post_process_embeds(text_embeds, visual_embeds) diff --git a/craftsman/models/conditional_encoders/clip/__pycache__/modeling_clip.cpython-38.pyc b/craftsman/models/conditional_encoders/clip/__pycache__/modeling_clip.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..844975c8920f5806fd027efe14714680e946fb84 Binary files /dev/null and b/craftsman/models/conditional_encoders/clip/__pycache__/modeling_clip.cpython-38.pyc differ diff --git a/craftsman/models/conditional_encoders/clip/__pycache__/modeling_conditional_clip.cpython-38.pyc b/craftsman/models/conditional_encoders/clip/__pycache__/modeling_conditional_clip.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d0af12db96dfa86a8a930ce81e77fc70baba29c Binary files /dev/null and b/craftsman/models/conditional_encoders/clip/__pycache__/modeling_conditional_clip.cpython-38.pyc differ diff --git a/craftsman/models/conditional_encoders/clip/modeling_clip.py b/craftsman/models/conditional_encoders/clip/modeling_clip.py new file mode 100755 index 0000000000000000000000000000000000000000..cefb5c90e38f100934e3756c850c07dfcadbbba3 --- /dev/null +++ b/craftsman/models/conditional_encoders/clip/modeling_clip.py @@ -0,0 +1,1419 @@ +# coding=utf-8 +# Copyright 2021 The OpenAI Team Authors and The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" PyTorch CLIP model.""" + + +from dataclasses import dataclass +from typing import Any, Optional, Tuple, Union + +import torch +import torch.utils.checkpoint +from torch import nn +from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss + +from transformers.activations import ACT2FN +from transformers.modeling_attn_mask_utils import _create_4d_causal_attention_mask, _prepare_4d_attention_mask +from transformers.modeling_outputs import BaseModelOutput, BaseModelOutputWithPooling, ImageClassifierOutput +from transformers.modeling_utils import PreTrainedModel +from transformers.utils import ( + ModelOutput, + add_code_sample_docstrings, + add_start_docstrings, + add_start_docstrings_to_model_forward, + logging, + replace_return_docstrings, +) +from transformers.models.clip.configuration_clip import CLIPConfig, CLIPTextConfig, CLIPVisionConfig + + +logger = logging.get_logger(__name__) + +# General docstring +_CONFIG_FOR_DOC = "CLIPConfig" +_CHECKPOINT_FOR_DOC = "openai/clip-vit-base-patch32" + +# Image classification docstring +_IMAGE_CLASS_CHECKPOINT = "openai/clip-vit-base-patch32" +_IMAGE_CLASS_EXPECTED_OUTPUT = "LABEL_0" + + +# contrastive loss function, adapted from +# https://sachinruk.github.io/blog/2021-03-07-clip.html +def contrastive_loss(logits: torch.Tensor) -> torch.Tensor: + return nn.functional.cross_entropy(logits, torch.arange(len(logits), device=logits.device)) + + +def clip_loss(similarity: torch.Tensor) -> torch.Tensor: + caption_loss = contrastive_loss(similarity) + image_loss = contrastive_loss(similarity.t()) + return (caption_loss + image_loss) / 2.0 + + +@dataclass +class CLIPVisionModelOutput(ModelOutput): + """ + Base class for vision model's outputs that also contains image embeddings of the pooling of the last hidden states. + + Args: + image_embeds (`torch.FloatTensor` of shape `(batch_size, output_dim)` *optional* returned when model is initialized with `with_projection=True`): + The image embeddings obtained by applying the projection layer to the pooler_output. + last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`): + Sequence of hidden-states at the output of the last layer of the model. + hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`): + Tuple of `torch.FloatTensor` (one for the output of the embeddings, if the model has an embedding layer, + + one for the output of each layer) of shape `(batch_size, sequence_length, hidden_size)`. + + Hidden-states of the model at the output of each layer plus the optional initial embedding outputs. + attentions (`tuple(torch.FloatTensor)`, *optional*, returned when `output_attentions=True` is passed or when `config.output_attentions=True`): + Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length, + sequence_length)`. + + Attentions weights after the attention softmax, used to compute the weighted average in the self-attention + heads. + """ + + image_embeds: Optional[torch.FloatTensor] = None + last_hidden_state: torch.FloatTensor = None + hidden_states: Optional[Tuple[torch.FloatTensor, ...]] = None + attentions: Optional[Tuple[torch.FloatTensor, ...]] = None + + +@dataclass +class CLIPTextModelOutput(ModelOutput): + """ + Base class for text model's outputs that also contains a pooling of the last hidden states. + + Args: + text_embeds (`torch.FloatTensor` of shape `(batch_size, output_dim)` *optional* returned when model is initialized with `with_projection=True`): + The text embeddings obtained by applying the projection layer to the pooler_output. + last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`): + Sequence of hidden-states at the output of the last layer of the model. + hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`): + Tuple of `torch.FloatTensor` (one for the output of the embeddings, if the model has an embedding layer, + + one for the output of each layer) of shape `(batch_size, sequence_length, hidden_size)`. + + Hidden-states of the model at the output of each layer plus the optional initial embedding outputs. + attentions (`tuple(torch.FloatTensor)`, *optional*, returned when `output_attentions=True` is passed or when `config.output_attentions=True`): + Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length, + sequence_length)`. + + Attentions weights after the attention softmax, used to compute the weighted average in the self-attention + heads. + """ + + text_embeds: Optional[torch.FloatTensor] = None + last_hidden_state: torch.FloatTensor = None + hidden_states: Optional[Tuple[torch.FloatTensor, ...]] = None + attentions: Optional[Tuple[torch.FloatTensor, ...]] = None + + +@dataclass +class CLIPOutput(ModelOutput): + """ + Args: + loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `return_loss` is `True`): + Contrastive loss for image-text similarity. + logits_per_image:(`torch.FloatTensor` of shape `(image_batch_size, text_batch_size)`): + The scaled dot product scores between `image_embeds` and `text_embeds`. This represents the image-text + similarity scores. + logits_per_text:(`torch.FloatTensor` of shape `(text_batch_size, image_batch_size)`): + The scaled dot product scores between `text_embeds` and `image_embeds`. This represents the text-image + similarity scores. + text_embeds(`torch.FloatTensor` of shape `(batch_size, output_dim`): + The text embeddings obtained by applying the projection layer to the pooled output of [`CLIPTextModel`]. + image_embeds(`torch.FloatTensor` of shape `(batch_size, output_dim`): + The image embeddings obtained by applying the projection layer to the pooled output of [`CLIPVisionModel`]. + text_model_output(`BaseModelOutputWithPooling`): + The output of the [`CLIPTextModel`]. + vision_model_output(`BaseModelOutputWithPooling`): + The output of the [`CLIPVisionModel`]. + """ + + loss: Optional[torch.FloatTensor] = None + logits_per_image: torch.FloatTensor = None + logits_per_text: torch.FloatTensor = None + text_embeds: torch.FloatTensor = None + image_embeds: torch.FloatTensor = None + text_model_output: BaseModelOutputWithPooling = None + vision_model_output: BaseModelOutputWithPooling = None + + def to_tuple(self) -> Tuple[Any]: + return tuple( + self[k] if k not in ["text_model_output", "vision_model_output"] else getattr(self, k).to_tuple() + for k in self.keys() + ) + + +class CLIPVisionEmbeddings(nn.Module): + def __init__(self, config: CLIPVisionConfig): + super().__init__() + self.config = config + self.embed_dim = config.hidden_size + self.image_size = config.image_size + self.patch_size = config.patch_size + + self.class_embedding = nn.Parameter(torch.randn(self.embed_dim)) + + self.patch_embedding = nn.Conv2d( + in_channels=config.num_channels, + out_channels=self.embed_dim, + kernel_size=self.patch_size, + stride=self.patch_size, + bias=False, + ) + + self.num_patches = (self.image_size // self.patch_size) ** 2 + self.num_positions = self.num_patches + 1 + self.position_embedding = nn.Embedding(self.num_positions, self.embed_dim) + self.register_buffer("position_ids", torch.arange(self.num_positions).expand((1, -1)), persistent=False) + + def forward(self, pixel_values: torch.FloatTensor) -> torch.Tensor: + batch_size = pixel_values.shape[0] + target_dtype = self.patch_embedding.weight.dtype + patch_embeds = self.patch_embedding(pixel_values.to(dtype=target_dtype)) # shape = [*, width, grid, grid] + patch_embeds = patch_embeds.flatten(2).transpose(1, 2) + + class_embeds = self.class_embedding.expand(batch_size, 1, -1) + embeddings = torch.cat([class_embeds, patch_embeds], dim=1) + embeddings = embeddings + self.position_embedding(self.position_ids) + return embeddings + + +class CLIPTextEmbeddings(nn.Module): + def __init__(self, config: CLIPTextConfig): + super().__init__() + embed_dim = config.hidden_size + + self.token_embedding = nn.Embedding(config.vocab_size, embed_dim) + self.position_embedding = nn.Embedding(config.max_position_embeddings, embed_dim) + + # position_ids (1, len position emb) is contiguous in memory and exported when serialized + self.register_buffer( + "position_ids", torch.arange(config.max_position_embeddings).expand((1, -1)), persistent=False + ) + + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + position_ids: Optional[torch.LongTensor] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + ) -> torch.Tensor: + seq_length = input_ids.shape[-1] if input_ids is not None else inputs_embeds.shape[-2] + + if position_ids is None: + position_ids = self.position_ids[:, :seq_length] + + if inputs_embeds is None: + inputs_embeds = self.token_embedding(input_ids) + + position_embeddings = self.position_embedding(position_ids) + embeddings = inputs_embeds + position_embeddings + + return embeddings + + +class CLIPAttention(nn.Module): + """Multi-headed attention from 'Attention Is All You Need' paper""" + + def __init__(self, config): + super().__init__() + self.config = config + self.embed_dim = config.hidden_size + self.num_heads = config.num_attention_heads + self.head_dim = self.embed_dim // self.num_heads + if self.head_dim * self.num_heads != self.embed_dim: + raise ValueError( + f"embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`:" + f" {self.num_heads})." + ) + self.scale = self.head_dim**-0.5 + self.dropout = config.attention_dropout + + self.k_proj = nn.Linear(self.embed_dim, self.embed_dim) + self.v_proj = nn.Linear(self.embed_dim, self.embed_dim) + self.q_proj = nn.Linear(self.embed_dim, self.embed_dim) + self.out_proj = nn.Linear(self.embed_dim, self.embed_dim) + + def _shape(self, tensor: torch.Tensor, seq_len: int, bsz: int): + return tensor.view(bsz, seq_len, self.num_heads, self.head_dim).transpose(1, 2).contiguous() + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: Optional[torch.Tensor] = None, + causal_attention_mask: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = False, + ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]: + """Input shape: Batch x Time x Channel""" + + bsz, tgt_len, embed_dim = hidden_states.size() + + # get query proj + query_states = self.q_proj(hidden_states) * self.scale + key_states = self._shape(self.k_proj(hidden_states), -1, bsz) + value_states = self._shape(self.v_proj(hidden_states), -1, bsz) + + proj_shape = (bsz * self.num_heads, -1, self.head_dim) + query_states = self._shape(query_states, tgt_len, bsz).view(*proj_shape) + key_states = key_states.view(*proj_shape) + value_states = value_states.view(*proj_shape) + + src_len = key_states.size(1) + attn_weights = torch.bmm(query_states, key_states.transpose(1, 2)) + + if attn_weights.size() != (bsz * self.num_heads, tgt_len, src_len): + raise ValueError( + f"Attention weights should be of size {(bsz * self.num_heads, tgt_len, src_len)}, but is" + f" {attn_weights.size()}" + ) + + # apply the causal_attention_mask first + if causal_attention_mask is not None: + if causal_attention_mask.size() != (bsz, 1, tgt_len, src_len): + raise ValueError( + f"Attention mask should be of size {(bsz, 1, tgt_len, src_len)}, but is" + f" {causal_attention_mask.size()}" + ) + attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + causal_attention_mask + attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len) + + if attention_mask is not None: + if attention_mask.size() != (bsz, 1, tgt_len, src_len): + raise ValueError( + f"Attention mask should be of size {(bsz, 1, tgt_len, src_len)}, but is {attention_mask.size()}" + ) + attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + attention_mask + attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len) + + attn_weights = nn.functional.softmax(attn_weights, dim=-1) + + if output_attentions: + # this operation is a bit akward, but it's required to + # make sure that attn_weights keeps its gradient. + # In order to do so, attn_weights have to reshaped + # twice and have to be reused in the following + attn_weights_reshaped = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + attn_weights = attn_weights_reshaped.view(bsz * self.num_heads, tgt_len, src_len) + else: + attn_weights_reshaped = None + + attn_probs = nn.functional.dropout(attn_weights, p=self.dropout, training=self.training) + + attn_output = torch.bmm(attn_probs, value_states) + + if attn_output.size() != (bsz * self.num_heads, tgt_len, self.head_dim): + raise ValueError( + f"`attn_output` should be of size {(bsz, self.num_heads, tgt_len, self.head_dim)}, but is" + f" {attn_output.size()}" + ) + + attn_output = attn_output.view(bsz, self.num_heads, tgt_len, self.head_dim) + attn_output = attn_output.transpose(1, 2) + attn_output = attn_output.reshape(bsz, tgt_len, embed_dim) + + attn_output = self.out_proj(attn_output) + + return attn_output, attn_weights_reshaped + + +class CLIPMLP(nn.Module): + def __init__(self, config): + super().__init__() + self.config = config + self.activation_fn = ACT2FN[config.hidden_act] + self.fc1 = nn.Linear(config.hidden_size, config.intermediate_size) + self.fc2 = nn.Linear(config.intermediate_size, config.hidden_size) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + hidden_states = self.fc1(hidden_states) + hidden_states = self.activation_fn(hidden_states) + hidden_states = self.fc2(hidden_states) + return hidden_states + + +class CLIPEncoderLayer(nn.Module): + def __init__(self, config: CLIPConfig): + super().__init__() + self.embed_dim = config.hidden_size + self.self_attn = CLIPAttention(config) + self.layer_norm1 = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_eps) + self.mlp = CLIPMLP(config) + self.layer_norm2 = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_eps) + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: torch.Tensor, + causal_attention_mask: torch.Tensor, + output_attentions: Optional[bool] = False, + ) -> Tuple[torch.FloatTensor]: + """ + Args: + hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, embed_dim)` + attention_mask (`torch.FloatTensor`): attention mask of size + `(batch, 1, tgt_len, src_len)` where padding elements are indicated by very large negative values. + `(config.encoder_attention_heads,)`. + output_attentions (`bool`, *optional*): + Whether or not to return the attentions tensors of all attention layers. See `attentions` under + returned tensors for more detail. + """ + residual = hidden_states + + hidden_states = self.layer_norm1(hidden_states) + hidden_states, attn_weights = self.self_attn( + hidden_states=hidden_states, + attention_mask=attention_mask, + causal_attention_mask=causal_attention_mask, + output_attentions=output_attentions, + ) + hidden_states = residual + hidden_states + + residual = hidden_states + hidden_states = self.layer_norm2(hidden_states) + hidden_states = self.mlp(hidden_states) + hidden_states = residual + hidden_states + + outputs = (hidden_states,) + + if output_attentions: + outputs += (attn_weights,) + + return outputs + + +class CLIPPreTrainedModel(PreTrainedModel): + """ + An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained + models. + """ + + config_class = CLIPConfig + base_model_prefix = "clip" + supports_gradient_checkpointing = True + + def _init_weights(self, module): + """Initialize the weights""" + factor = self.config.initializer_factor + if isinstance(module, CLIPTextEmbeddings): + module.token_embedding.weight.data.normal_(mean=0.0, std=factor * 0.02) + module.position_embedding.weight.data.normal_(mean=0.0, std=factor * 0.02) + elif isinstance(module, CLIPVisionEmbeddings): + factor = self.config.initializer_factor + nn.init.normal_(module.class_embedding, mean=0.0, std=module.embed_dim**-0.5 * factor) + nn.init.normal_(module.patch_embedding.weight, std=module.config.initializer_range * factor) + nn.init.normal_(module.position_embedding.weight, std=module.config.initializer_range * factor) + elif isinstance(module, CLIPAttention): + factor = self.config.initializer_factor + in_proj_std = (module.embed_dim**-0.5) * ((2 * module.config.num_hidden_layers) ** -0.5) * factor + out_proj_std = (module.embed_dim**-0.5) * factor + nn.init.normal_(module.q_proj.weight, std=in_proj_std) + nn.init.normal_(module.k_proj.weight, std=in_proj_std) + nn.init.normal_(module.v_proj.weight, std=in_proj_std) + nn.init.normal_(module.out_proj.weight, std=out_proj_std) + elif isinstance(module, CLIPMLP): + factor = self.config.initializer_factor + in_proj_std = (module.config.hidden_size**-0.5) * ((2 * module.config.num_hidden_layers) ** -0.5) * factor + fc_std = (2 * module.config.hidden_size) ** -0.5 * factor + nn.init.normal_(module.fc1.weight, std=fc_std) + nn.init.normal_(module.fc2.weight, std=in_proj_std) + elif isinstance(module, CLIPModel): + nn.init.normal_( + module.text_projection.weight, + std=module.text_embed_dim**-0.5 * self.config.initializer_factor, + ) + nn.init.normal_( + module.visual_projection.weight, + std=module.vision_embed_dim**-0.5 * self.config.initializer_factor, + ) + elif isinstance(module, CLIPVisionModelWithProjection): + nn.init.normal_( + module.visual_projection.weight, + std=self.config.hidden_size**-0.5 * self.config.initializer_factor, + ) + elif isinstance(module, CLIPTextModelWithProjection): + nn.init.normal_( + module.text_projection.weight, + std=self.config.hidden_size**-0.5 * self.config.initializer_factor, + ) + elif isinstance(module, CLIPForImageClassification): + nn.init.normal_( + module.classifier.weight, + std=self.config.vision_config.hidden_size**-0.5 * self.config.initializer_factor, + ) + + if isinstance(module, nn.LayerNorm): + module.bias.data.zero_() + module.weight.data.fill_(1.0) + if isinstance(module, nn.Linear) and module.bias is not None: + module.bias.data.zero_() + + +CLIP_START_DOCSTRING = r""" + This model inherits from [`PreTrainedModel`]. Check the superclass documentation for the generic methods the + library implements for all its model (such as downloading or saving, resizing the input embeddings, pruning heads + etc.) + + This model is also a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass. + Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage + and behavior. + + Parameters: + config ([`CLIPConfig`]): Model configuration class with all the parameters of the model. + Initializing with a config file does not load the weights associated with the model, only the + configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights. +""" + +CLIP_TEXT_INPUTS_DOCSTRING = r""" + Args: + input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`): + Indices of input sequence tokens in the vocabulary. Padding will be ignored by default should you provide + it. + + Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and + [`PreTrainedTokenizer.__call__`] for details. + + [What are input IDs?](../glossary#input-ids) + attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*): + Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`: + + - 1 for tokens that are **not masked**, + - 0 for tokens that are **masked**. + + [What are attention masks?](../glossary#attention-mask) + position_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): + Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0, + config.max_position_embeddings - 1]`. + + [What are position IDs?](../glossary#position-ids) + output_attentions (`bool`, *optional*): + Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned + tensors for more detail. + output_hidden_states (`bool`, *optional*): + Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for + more detail. + return_dict (`bool`, *optional*): + Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. +""" + +CLIP_VISION_INPUTS_DOCSTRING = r""" + Args: + pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`): + Pixel values. Padding will be ignored by default should you provide it. Pixel values can be obtained using + [`AutoImageProcessor`]. See [`CLIPImageProcessor.__call__`] for details. + output_attentions (`bool`, *optional*): + Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned + tensors for more detail. + output_hidden_states (`bool`, *optional*): + Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for + more detail. + return_dict (`bool`, *optional*): + Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. +""" + +CLIP_INPUTS_DOCSTRING = r""" + Args: + input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`): + Indices of input sequence tokens in the vocabulary. Padding will be ignored by default should you provide + it. + + Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and + [`PreTrainedTokenizer.__call__`] for details. + + [What are input IDs?](../glossary#input-ids) + attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*): + Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`: + + - 1 for tokens that are **not masked**, + - 0 for tokens that are **masked**. + + [What are attention masks?](../glossary#attention-mask) + position_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): + Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0, + config.max_position_embeddings - 1]`. + + [What are position IDs?](../glossary#position-ids) + pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`): + Pixel values. Padding will be ignored by default should you provide it. Pixel values can be obtained using + [`AutoImageProcessor`]. See [`CLIPImageProcessor.__call__`] for details. + return_loss (`bool`, *optional*): + Whether or not to return the contrastive loss. + output_attentions (`bool`, *optional*): + Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned + tensors for more detail. + output_hidden_states (`bool`, *optional*): + Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for + more detail. + return_dict (`bool`, *optional*): + Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. +""" + + +class CLIPEncoder(nn.Module): + """ + Transformer encoder consisting of `config.num_hidden_layers` self attention layers. Each layer is a + [`CLIPEncoderLayer`]. + + Args: + config: CLIPConfig + """ + + def __init__(self, config: CLIPConfig): + super().__init__() + self.config = config + self.layers = nn.ModuleList([CLIPEncoderLayer(config) for _ in range(config.num_hidden_layers)]) + self.gradient_checkpointing = False + + def forward( + self, + inputs_embeds, + attention_mask: Optional[torch.Tensor] = None, + causal_attention_mask: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, BaseModelOutput]: + r""" + Args: + inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`): + Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. + This is useful if you want more control over how to convert `input_ids` indices into associated vectors + than the model's internal embedding lookup matrix. + attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*): + Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`: + + - 1 for tokens that are **not masked**, + - 0 for tokens that are **masked**. + + [What are attention masks?](../glossary#attention-mask) + causal_attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*): + Causal mask for the text model. Mask values selected in `[0, 1]`: + + - 1 for tokens that are **not masked**, + - 0 for tokens that are **masked**. + + [What are attention masks?](../glossary#attention-mask) + output_attentions (`bool`, *optional*): + Whether or not to return the attentions tensors of all attention layers. See `attentions` under + returned tensors for more detail. + output_hidden_states (`bool`, *optional*): + Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors + for more detail. + return_dict (`bool`, *optional*): + Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple. + """ + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + encoder_states = () if output_hidden_states else None + all_attentions = () if output_attentions else None + + hidden_states = inputs_embeds + for idx, encoder_layer in enumerate(self.layers): + if output_hidden_states: + encoder_states = encoder_states + (hidden_states,) + if self.gradient_checkpointing and self.training: + layer_outputs = self._gradient_checkpointing_func( + encoder_layer.__call__, + hidden_states, + attention_mask, + causal_attention_mask, + output_attentions, + ) + else: + layer_outputs = encoder_layer( + hidden_states, + attention_mask, + causal_attention_mask, + output_attentions=output_attentions, + ) + + hidden_states = layer_outputs[0] + + if output_attentions: + all_attentions = all_attentions + (layer_outputs[1],) + + if output_hidden_states: + encoder_states = encoder_states + (hidden_states,) + + if not return_dict: + return tuple(v for v in [hidden_states, encoder_states, all_attentions] if v is not None) + return BaseModelOutput( + last_hidden_state=hidden_states, hidden_states=encoder_states, attentions=all_attentions + ) + + +class CLIPTextTransformer(nn.Module): + def __init__(self, config: CLIPTextConfig): + super().__init__() + self.config = config + embed_dim = config.hidden_size + self.embeddings = CLIPTextEmbeddings(config) + self.encoder = CLIPEncoder(config) + self.final_layer_norm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps) + + # For `pooled_output` computation + self.eos_token_id = config.eos_token_id + + @add_start_docstrings_to_model_forward(CLIP_TEXT_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=BaseModelOutputWithPooling, config_class=CLIPTextConfig) + def forward( + self, + input_ids: Optional[torch.Tensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, BaseModelOutputWithPooling]: + r""" + Returns: + + """ + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + if input_ids is None: + raise ValueError("You have to specify input_ids") + + input_shape = input_ids.size() + input_ids = input_ids.view(-1, input_shape[-1]) + + hidden_states = self.embeddings(input_ids=input_ids, position_ids=position_ids) + + # CLIP's text model uses causal mask, prepare it here. + # https://github.com/openai/CLIP/blob/cfcffb90e69f37bf2ff1e988237a0fbe41f33c04/clip/model.py#L324 + causal_attention_mask = _create_4d_causal_attention_mask( + input_shape, hidden_states.dtype, device=hidden_states.device + ) + # expand attention_mask + if attention_mask is not None: + # [bsz, seq_len] -> [bsz, 1, tgt_seq_len, src_seq_len] + attention_mask = _prepare_4d_attention_mask(attention_mask, hidden_states.dtype) + + encoder_outputs = self.encoder( + inputs_embeds=hidden_states, + attention_mask=attention_mask, + causal_attention_mask=causal_attention_mask, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + last_hidden_state = encoder_outputs[0] + last_hidden_state = self.final_layer_norm(last_hidden_state) + + if self.eos_token_id == 2: + # The `eos_token_id` was incorrect before PR #24773: Let's keep what have been done here. + # A CLIP model with such `eos_token_id` in the config can't work correctly with extra new tokens added + # ------------------------------------------------------------ + # text_embeds.shape = [batch_size, sequence_length, transformer.width] + # take features from the eot embedding (eot_token is the highest number in each sequence) + # casting to torch.int for onnx compatibility: argmax doesn't support int64 inputs with opset 14 + pooled_output = last_hidden_state[ + torch.arange(last_hidden_state.shape[0], device=last_hidden_state.device), + input_ids.to(dtype=torch.int, device=last_hidden_state.device).argmax(dim=-1), + ] + else: + # The config gets updated `eos_token_id` from PR #24773 (so the use of exta new tokens is possible) + pooled_output = last_hidden_state[ + torch.arange(last_hidden_state.shape[0], device=last_hidden_state.device), + # We need to get the first position of `eos_token_id` value (`pad_token_ids` might equal to `eos_token_id`) + # Note: we assume each sequence (along batch dim.) contains an `eos_token_id` (e.g. prepared by the tokenizer) + (input_ids.to(dtype=torch.int, device=last_hidden_state.device) == self.eos_token_id) + .int() + .argmax(dim=-1), + ] + + if not return_dict: + return (last_hidden_state, pooled_output) + encoder_outputs[1:] + + return BaseModelOutputWithPooling( + last_hidden_state=last_hidden_state, + pooler_output=pooled_output, + hidden_states=encoder_outputs.hidden_states, + attentions=encoder_outputs.attentions, + ) + + +@add_start_docstrings( + """The text model from CLIP without any head or projection on top.""", + CLIP_START_DOCSTRING, +) +class CLIPTextModel(CLIPPreTrainedModel): + config_class = CLIPTextConfig + + _no_split_modules = ["CLIPTextEmbeddings", "CLIPEncoderLayer"] + + def __init__(self, config: CLIPTextConfig): + super().__init__(config) + self.text_model = CLIPTextTransformer(config) + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self) -> nn.Module: + return self.text_model.embeddings.token_embedding + + def set_input_embeddings(self, value): + self.text_model.embeddings.token_embedding = value + + @add_start_docstrings_to_model_forward(CLIP_TEXT_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=BaseModelOutputWithPooling, config_class=CLIPTextConfig) + def forward( + self, + input_ids: Optional[torch.Tensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, BaseModelOutputWithPooling]: + r""" + Returns: + + Examples: + + ```python + >>> from transformers import AutoTokenizer, CLIPTextModel + + >>> model = CLIPTextModel.from_pretrained("openai/clip-vit-base-patch32") + >>> tokenizer = AutoTokenizer.from_pretrained("openai/clip-vit-base-patch32") + + >>> inputs = tokenizer(["a photo of a cat", "a photo of a dog"], padding=True, return_tensors="pt") + + >>> outputs = model(**inputs) + >>> last_hidden_state = outputs.last_hidden_state + >>> pooled_output = outputs.pooler_output # pooled (EOS token) states + ```""" + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + return self.text_model( + input_ids=input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + +class CLIPVisionTransformer(nn.Module): + def __init__(self, config: CLIPVisionConfig): + super().__init__() + self.config = config + embed_dim = config.hidden_size + + self.embeddings = CLIPVisionEmbeddings(config) + self.pre_layrnorm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps) + self.encoder = CLIPEncoder(config) + self.post_layernorm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps) + + @add_start_docstrings_to_model_forward(CLIP_VISION_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=BaseModelOutputWithPooling, config_class=CLIPVisionConfig) + def forward( + self, + pixel_values: Optional[torch.FloatTensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, BaseModelOutputWithPooling]: + r""" + Returns: + + """ + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + if pixel_values is None: + raise ValueError("You have to specify pixel_values") + + hidden_states = self.embeddings(pixel_values) + hidden_states = self.pre_layrnorm(hidden_states) + + encoder_outputs = self.encoder( + inputs_embeds=hidden_states, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + last_hidden_state = encoder_outputs[0] + pooled_output = last_hidden_state[:, 0, :] + pooled_output = self.post_layernorm(pooled_output) + + if not return_dict: + return (last_hidden_state, pooled_output) + encoder_outputs[1:] + + return BaseModelOutputWithPooling( + last_hidden_state=last_hidden_state, + pooler_output=pooled_output, + hidden_states=encoder_outputs.hidden_states, + attentions=encoder_outputs.attentions, + ) + + +@add_start_docstrings( + """The vision model from CLIP without any head or projection on top.""", + CLIP_START_DOCSTRING, +) +class CLIPVisionModel(CLIPPreTrainedModel): + config_class = CLIPVisionConfig + main_input_name = "pixel_values" + _no_split_modules = ["CLIPEncoderLayer"] + + def __init__(self, config: CLIPVisionConfig): + super().__init__(config) + self.vision_model = CLIPVisionTransformer(config) + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self) -> nn.Module: + return self.vision_model.embeddings.patch_embedding + + @add_start_docstrings_to_model_forward(CLIP_VISION_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=BaseModelOutputWithPooling, config_class=CLIPVisionConfig) + def forward( + self, + pixel_values: Optional[torch.FloatTensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, BaseModelOutputWithPooling]: + r""" + Returns: + + Examples: + + ```python + >>> from PIL import Image + >>> import requests + >>> from transformers import AutoProcessor, CLIPVisionModel + + >>> model = CLIPVisionModel.from_pretrained("openai/clip-vit-base-patch32") + >>> processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32") + + >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg" + >>> image = Image.open(requests.get(url, stream=True).raw) + + >>> inputs = processor(images=image, return_tensors="pt") + + >>> outputs = model(**inputs) + >>> last_hidden_state = outputs.last_hidden_state + >>> pooled_output = outputs.pooler_output # pooled CLS states + ```""" + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + return self.vision_model( + pixel_values=pixel_values, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + +@add_start_docstrings(CLIP_START_DOCSTRING) +class CLIPModel(CLIPPreTrainedModel): + config_class = CLIPConfig + _no_split_modules = ["CLIPTextEmbeddings", "CLIPEncoderLayer"] + + def __init__(self, config: CLIPConfig): + super().__init__(config) + + if not isinstance(config.text_config, CLIPTextConfig): + raise ValueError( + "config.text_config is expected to be of type CLIPTextConfig but is of type" + f" {type(config.text_config)}." + ) + + if not isinstance(config.vision_config, CLIPVisionConfig): + raise ValueError( + "config.vision_config is expected to be of type CLIPVisionConfig but is of type" + f" {type(config.vision_config)}." + ) + + text_config = config.text_config + vision_config = config.vision_config + + self.projection_dim = config.projection_dim + self.text_embed_dim = text_config.hidden_size + self.vision_embed_dim = vision_config.hidden_size + + self.text_model = CLIPTextTransformer(text_config) + self.vision_model = CLIPVisionTransformer(vision_config) + + self.visual_projection = nn.Linear(self.vision_embed_dim, self.projection_dim, bias=False) + self.text_projection = nn.Linear(self.text_embed_dim, self.projection_dim, bias=False) + self.logit_scale = nn.Parameter(torch.tensor(self.config.logit_scale_init_value)) + + # Initialize weights and apply final processing + self.post_init() + + @add_start_docstrings_to_model_forward(CLIP_TEXT_INPUTS_DOCSTRING) + def get_text_features( + self, + input_ids: Optional[torch.Tensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> torch.FloatTensor: + r""" + Returns: + text_features (`torch.FloatTensor` of shape `(batch_size, output_dim`): The text embeddings obtained by + applying the projection layer to the pooled output of [`CLIPTextModel`]. + + Examples: + + ```python + >>> from transformers import AutoTokenizer, CLIPModel + + >>> model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") + >>> tokenizer = AutoTokenizer.from_pretrained("openai/clip-vit-base-patch32") + + >>> inputs = tokenizer(["a photo of a cat", "a photo of a dog"], padding=True, return_tensors="pt") + >>> text_features = model.get_text_features(**inputs) + ```""" + # Use CLIP model's config for some fields (if specified) instead of those of vision & text components. + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + text_outputs = self.text_model( + input_ids=input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + pooled_output = text_outputs[1] + text_features = self.text_projection(pooled_output) + + return text_features + + @add_start_docstrings_to_model_forward(CLIP_VISION_INPUTS_DOCSTRING) + def get_image_features( + self, + pixel_values: Optional[torch.FloatTensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> torch.FloatTensor: + r""" + Returns: + image_features (`torch.FloatTensor` of shape `(batch_size, output_dim`): The image embeddings obtained by + applying the projection layer to the pooled output of [`CLIPVisionModel`]. + + Examples: + + ```python + >>> from PIL import Image + >>> import requests + >>> from transformers import AutoProcessor, CLIPModel + + >>> model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") + >>> processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32") + + >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg" + >>> image = Image.open(requests.get(url, stream=True).raw) + + >>> inputs = processor(images=image, return_tensors="pt") + + >>> image_features = model.get_image_features(**inputs) + ```""" + # Use CLIP model's config for some fields (if specified) instead of those of vision & text components. + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + vision_outputs = self.vision_model( + pixel_values=pixel_values, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + pooled_output = vision_outputs[1] # pooled_output + image_features = self.visual_projection(pooled_output) + + return image_features + + @add_start_docstrings_to_model_forward(CLIP_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=CLIPOutput, config_class=CLIPConfig) + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + pixel_values: Optional[torch.FloatTensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + return_loss: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, CLIPOutput]: + r""" + Returns: + + Examples: + + ```python + >>> from PIL import Image + >>> import requests + >>> from transformers import AutoProcessor, CLIPModel + + >>> model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") + >>> processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32") + + >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg" + >>> image = Image.open(requests.get(url, stream=True).raw) + + >>> inputs = processor( + ... text=["a photo of a cat", "a photo of a dog"], images=image, return_tensors="pt", padding=True + ... ) + + >>> outputs = model(**inputs) + >>> logits_per_image = outputs.logits_per_image # this is the image-text similarity score + >>> probs = logits_per_image.softmax(dim=1) # we can take the softmax to get the label probabilities + ```""" + # Use CLIP model's config for some fields (if specified) instead of those of vision & text components. + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + vision_outputs = self.vision_model( + pixel_values=pixel_values, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + text_outputs = self.text_model( + input_ids=input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + image_embeds = vision_outputs[1] + image_embeds = self.visual_projection(image_embeds) + + text_embeds = text_outputs[1] + text_embeds = self.text_projection(text_embeds) + + # normalized features + image_embeds = image_embeds / image_embeds.norm(p=2, dim=-1, keepdim=True) + text_embeds = text_embeds / text_embeds.norm(p=2, dim=-1, keepdim=True) + + # cosine similarity as logits + logit_scale = self.logit_scale.exp() + logits_per_text = torch.matmul(text_embeds, image_embeds.t()) * logit_scale + logits_per_image = logits_per_text.t() + + loss = None + if return_loss: + loss = clip_loss(logits_per_text) + + if not return_dict: + output = (logits_per_image, logits_per_text, text_embeds, image_embeds, text_outputs, vision_outputs) + return ((loss,) + output) if loss is not None else output + + return CLIPOutput( + loss=loss, + logits_per_image=logits_per_image, + logits_per_text=logits_per_text, + text_embeds=text_embeds, + image_embeds=image_embeds, + text_model_output=text_outputs, + vision_model_output=vision_outputs, + ) + + +@add_start_docstrings( + """ + CLIP Text Model with a projection layer on top (a linear layer on top of the pooled output). + """, + CLIP_START_DOCSTRING, +) +class CLIPTextModelWithProjection(CLIPPreTrainedModel): + config_class = CLIPTextConfig + + _no_split_modules = ["CLIPTextEmbeddings", "CLIPEncoderLayer"] + + def __init__(self, config: CLIPTextConfig): + super().__init__(config) + + self.text_model = CLIPTextTransformer(config) + + self.text_projection = nn.Linear(config.hidden_size, config.projection_dim, bias=False) + + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self) -> nn.Module: + return self.text_model.embeddings.token_embedding + + def set_input_embeddings(self, value): + self.text_model.embeddings.token_embedding = value + + @add_start_docstrings_to_model_forward(CLIP_TEXT_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=CLIPTextModelOutput, config_class=CLIPTextConfig) + def forward( + self, + input_ids: Optional[torch.Tensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, CLIPTextModelOutput]: + r""" + Returns: + + Examples: + + ```python + >>> from transformers import AutoTokenizer, CLIPTextModelWithProjection + + >>> model = CLIPTextModelWithProjection.from_pretrained("openai/clip-vit-base-patch32") + >>> tokenizer = AutoTokenizer.from_pretrained("openai/clip-vit-base-patch32") + + >>> inputs = tokenizer(["a photo of a cat", "a photo of a dog"], padding=True, return_tensors="pt") + + >>> outputs = model(**inputs) + >>> text_embeds = outputs.text_embeds + ```""" + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + text_outputs = self.text_model( + input_ids=input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + pooled_output = text_outputs[1] + + text_embeds = self.text_projection(pooled_output) + + if not return_dict: + outputs = (text_embeds, text_outputs[0]) + text_outputs[2:] + return tuple(output for output in outputs if output is not None) + + return CLIPTextModelOutput( + text_embeds=text_embeds, + last_hidden_state=text_outputs.last_hidden_state, + hidden_states=text_outputs.hidden_states, + attentions=text_outputs.attentions, + ) + + +@add_start_docstrings( + """ + CLIP Vision Model with a projection layer on top (a linear layer on top of the pooled output). + """, + CLIP_START_DOCSTRING, +) +class CLIPVisionModelWithProjection(CLIPPreTrainedModel): + config_class = CLIPVisionConfig + main_input_name = "pixel_values" + + def __init__(self, config: CLIPVisionConfig): + super().__init__(config) + + self.vision_model = CLIPVisionTransformer(config) + + self.visual_projection = nn.Linear(config.hidden_size, config.projection_dim, bias=False) + + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self) -> nn.Module: + return self.vision_model.embeddings.patch_embedding + + @add_start_docstrings_to_model_forward(CLIP_VISION_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=CLIPVisionModelOutput, config_class=CLIPVisionConfig) + def forward( + self, + pixel_values: Optional[torch.FloatTensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, CLIPVisionModelOutput]: + r""" + Returns: + + Examples: + + ```python + >>> from PIL import Image + >>> import requests + >>> from transformers import AutoProcessor, CLIPVisionModelWithProjection + + >>> model = CLIPVisionModelWithProjection.from_pretrained("openai/clip-vit-base-patch32") + >>> processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32") + + >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg" + >>> image = Image.open(requests.get(url, stream=True).raw) + + >>> inputs = processor(images=image, return_tensors="pt") + + >>> outputs = model(**inputs) + >>> image_embeds = outputs.image_embeds + ```""" + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + vision_outputs = self.vision_model( + pixel_values=pixel_values, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + pooled_output = vision_outputs[1] # pooled_output + + image_embeds = self.visual_projection(pooled_output) + + if not return_dict: + outputs = (image_embeds, vision_outputs[0]) + vision_outputs[2:] + return tuple(output for output in outputs if output is not None) + + return CLIPVisionModelOutput( + image_embeds=image_embeds, + last_hidden_state=vision_outputs.last_hidden_state, + hidden_states=vision_outputs.hidden_states, + attentions=vision_outputs.attentions, + ) + + +@add_start_docstrings( + """ + CLIP vision encoder with an image classification head on top (a linear layer on top of the pooled final hidden states of + the patch tokens) e.g. for ImageNet. + """, + CLIP_START_DOCSTRING, +) +class CLIPForImageClassification(CLIPPreTrainedModel): + main_input_name = "pixel_values" + + def __init__(self, config: CLIPConfig) -> None: + super().__init__(config) + + self.num_labels = config.num_labels + self.vision_model = CLIPVisionTransformer(config.vision_config) + + # Classifier head + self.classifier = ( + nn.Linear(config.vision_config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity() + ) + + # Initialize weights and apply final processing + self.post_init() + + @add_start_docstrings_to_model_forward(CLIP_INPUTS_DOCSTRING) + @add_code_sample_docstrings( + checkpoint=_IMAGE_CLASS_CHECKPOINT, + output_type=ImageClassifierOutput, + config_class=_CONFIG_FOR_DOC, + expected_output=_IMAGE_CLASS_EXPECTED_OUTPUT, + ) + def forward( + self, + pixel_values: Optional[torch.Tensor] = None, + labels: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[tuple, ImageClassifierOutput]: + r""" + labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*): + Labels for computing the image classification/regression loss. Indices should be in `[0, ..., + config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If + `config.num_labels > 1` a classification loss is computed (Cross-Entropy). + """ + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + outputs = self.vision_model( + pixel_values, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + sequence_output = outputs[0] + + # average pool the patch tokens + sequence_output = torch.mean(sequence_output[:, 1:, :], dim=1) + # apply classifier + logits = self.classifier(sequence_output) + + loss = None + if labels is not None: + # move labels to correct device to enable model parallelism + labels = labels.to(logits.device) + if self.config.problem_type is None: + if self.num_labels == 1: + self.config.problem_type = "regression" + elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int): + self.config.problem_type = "single_label_classification" + else: + self.config.problem_type = "multi_label_classification" + + if self.config.problem_type == "regression": + loss_fct = MSELoss() + if self.num_labels == 1: + loss = loss_fct(logits.squeeze(), labels.squeeze()) + else: + loss = loss_fct(logits, labels) + elif self.config.problem_type == "single_label_classification": + loss_fct = CrossEntropyLoss() + loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1)) + elif self.config.problem_type == "multi_label_classification": + loss_fct = BCEWithLogitsLoss() + loss = loss_fct(logits, labels) + + if not return_dict: + output = (logits,) + outputs[2:] + return ((loss,) + output) if loss is not None else output + + return ImageClassifierOutput( + loss=loss, + logits=logits, + hidden_states=outputs.hidden_states, + attentions=outputs.attentions, + ) \ No newline at end of file diff --git a/craftsman/models/conditional_encoders/clip/modeling_conditional_clip.py b/craftsman/models/conditional_encoders/clip/modeling_conditional_clip.py new file mode 100755 index 0000000000000000000000000000000000000000..1f026e483b56cdd164ec62193a3742352d7cb305 --- /dev/null +++ b/craftsman/models/conditional_encoders/clip/modeling_conditional_clip.py @@ -0,0 +1,385 @@ +# coding=utf-8 +# Copyright 2023 Meta AI and The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Reference: +# * transformers/models/dinov2/modeling_dinov2.py +# * https://github.com/facebookresearch/DiT/blob/main/models.py#L101 +# * https://github.com/3DTopia/OpenLRM/tree/main/openlrm/models/encoders/dinov2 +""" PyTorch CLIP model.""" + +from typing import Dict, List, Optional, Set, Tuple, Union + +import torch +import torch.nn as nn + +from .modeling_clip import ( + CLIPConfig, + CLIPTextConfig, + CLIPVisionConfig, + CLIPEncoderLayer, + CLIPTextTransformer, + CLIPVisionTransformer, + CLIPModel, + CLIPVisionEmbeddings, + CLIPVisionModel, + CLIPOutput, + BaseModelOutput, + BaseModelOutputWithPooling +) + + +class ModLN(nn.Module): + def __init__(self, inner_dim: int, mod_dim: int = 32): + super().__init__() + self.mlp = nn.Sequential( + nn.SiLU(), + nn.Linear(mod_dim, inner_dim * 2), + ) + + for m in self.modules(): + if isinstance(m, nn.Linear): + nn.init.zeros_(m.weight) + nn.init.zeros_(m.bias) + + def forward(self, x:torch.Tensor, condition:torch.Tensor): + ''' + x: [N, M, C_in], M: num of tokens + condition: [N, C_mod] + ''' + shift, scale = self.mlp(condition).unsqueeze(1).chunk(2, dim=-1) + return x * (1 + scale) + shift + + +class ConditionalCLIPVisionConfig(CLIPVisionConfig): + def __init__(self, modulation_dim: int = 32, *args, **kwargs): + super().__init__(*args, **kwargs) + self.modulation_dim = modulation_dim + + +class ConditionalCLIPEncoderLayer(CLIPEncoderLayer): + """This corresponds to the Block class in the original implementation.""" + + def __init__(self, config: ConditionalCLIPVisionConfig) -> None: + super().__init__(config) + self.mod_norm1 = ModLN(config.hidden_size, config.modulation_dim) + self.mod_norm2 = ModLN(config.hidden_size, config.modulation_dim) + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: torch.Tensor, + causal_attention_mask: torch.Tensor, + condition: Optional[torch.Tensor] = None, + output_attentions: bool = False, + ) -> Union[Tuple[torch.Tensor, torch.Tensor], Tuple[torch.Tensor]]: + residual = hidden_states + + hidden_states = self.mod_norm1(self.layer_norm1(hidden_states), condition) + hidden_states, attn_weights = self.self_attn( + hidden_states=hidden_states, + attention_mask=attention_mask, + causal_attention_mask=causal_attention_mask, + output_attentions=output_attentions, + ) + hidden_states = residual + hidden_states + + residual = hidden_states + hidden_states = self.mod_norm2(self.layer_norm2(hidden_states), condition) + hidden_states = self.mlp(hidden_states) + hidden_states = residual + hidden_states + + outputs = (hidden_states,) + + if output_attentions: + outputs += (attn_weights,) + + return outputs + + +class ConditionalCLIPEncoder(nn.Module): + def __init__(self, config: CLIPConfig) -> None: + super().__init__() + self.config = config + self.layers = nn.ModuleList([ConditionalCLIPEncoderLayer(config) for _ in range(config.num_hidden_layers)]) + self.gradient_checkpointing = False + + def forward( + self, + inputs_embeds, + attention_mask: Optional[torch.Tensor] = None, + causal_attention_mask: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + condition: Optional[torch.Tensor] = None, + return_dict: Optional[bool] = None, + ) -> Union[tuple, BaseModelOutput]: + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + encoder_states = () if output_hidden_states else None + all_attentions = () if output_attentions else None + + hidden_states = inputs_embeds + for idx, encoder_layer in enumerate(self.layers): + if output_hidden_states: + encoder_states = encoder_states + (hidden_states,) + if self.gradient_checkpointing and self.training: + layer_outputs = self._gradient_checkpointing_func( + encoder_layer.__call__, + hidden_states, + attention_mask, + causal_attention_mask, + condition=condition, + output_attentions=output_attentions, + ) + else: + layer_outputs = encoder_layer( + hidden_states, + attention_mask, + causal_attention_mask, + condition=condition, + output_attentions=output_attentions, + ) + + hidden_states = layer_outputs[0] + + if output_attentions: + all_attentions = all_attentions + (layer_outputs[1],) + + if output_hidden_states: + encoder_states = encoder_states + (hidden_states,) + + if not return_dict: + return tuple(v for v in [hidden_states, encoder_states, all_attentions] if v is not None) + return BaseModelOutput( + last_hidden_state=hidden_states, hidden_states=encoder_states, attentions=all_attentions + ) + + +class ConditionalCLIPVisionTransformer(CLIPVisionTransformer): + def __init__(self, config: ConditionalCLIPVisionConfig): + super().__init__(config) + self.config = config + embed_dim = config.hidden_size + + self.embeddings = CLIPVisionEmbeddings(config) + self.pre_layrnorm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps) + self.encoder = ConditionalCLIPEncoder(config) + self.post_layernorm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps) + + def forward( + self, + pixel_values: Optional[torch.FloatTensor] = None, + condition: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, BaseModelOutputWithPooling]: + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + if pixel_values is None: + raise ValueError("You have to specify pixel_values") + + hidden_states = self.embeddings(pixel_values) + hidden_states = self.pre_layrnorm(hidden_states) + + encoder_outputs = self.encoder( + inputs_embeds=hidden_states, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + condition=condition, + return_dict=return_dict, + ) + + last_hidden_state = encoder_outputs[0] + pooled_output = last_hidden_state[:, 0, :] + pooled_output = self.post_layernorm(pooled_output) + + if not return_dict: + return (last_hidden_state, pooled_output) + encoder_outputs[1:] + + return BaseModelOutputWithPooling( + last_hidden_state=last_hidden_state, + pooler_output=pooled_output, + hidden_states=encoder_outputs.hidden_states, + attentions=encoder_outputs.attentions, + ) + + +class ConditionalCLIPVisionModel(CLIPVisionModel): + config_class = ConditionalCLIPVisionConfig + + def __init__(self, config: ConditionalCLIPVisionConfig): + super().__init__(config) + self.vision_model = ConditionalCLIPVisionTransformer(config) + # Initialize weights and apply final processing + self.post_init() + + def forward( + self, + pixel_values: Optional[torch.FloatTensor] = None, + condition: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, BaseModelOutputWithPooling]: + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + return self.vision_model( + pixel_values=pixel_values, + condition=condition, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + +class ConditionalCLIPModel(CLIPModel): + config_class = CLIPConfig + + def __init__(self, config: CLIPConfig): + super().__init__(config) + + if not isinstance(config.text_config, CLIPTextConfig): + raise ValueError( + "config.text_config is expected to be of type CLIPTextConfig but is of type" + f" {type(config.text_config)}." + ) + + if not isinstance(config.vision_config, CLIPVisionConfig): + raise ValueError( + "config.vision_config is expected to be of type CLIPVisionConfig but is of type" + f" {type(config.vision_config)}." + ) + + text_config = config.text_config + vision_config = config.vision_config + + self.projection_dim = config.projection_dim + self.text_embed_dim = text_config.hidden_size + self.vision_embed_dim = vision_config.hidden_size + + self.text_model = CLIPTextTransformer(text_config) + self.vision_model = ConditionalCLIPVisionTransformer(vision_config) + + self.visual_projection = nn.Linear(self.vision_embed_dim, self.projection_dim, bias=False) + self.text_projection = nn.Linear(self.text_embed_dim, self.projection_dim, bias=False) + self.logit_scale = nn.Parameter(torch.tensor(self.config.logit_scale_init_value)) + + # Initialize weights and apply final processing + self.post_init() + + def get_image_features( + self, + pixel_values: Optional[torch.FloatTensor] = None, + condition: Optional[torch.Tensor] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> torch.FloatTensor: + # Use CLIP model's config for some fields (if specified) instead of those of vision & text components. + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + vision_outputs = self.vision_model( + pixel_values=pixel_values, + condition=condition, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + pooled_output = vision_outputs[1] # pooled_output + image_features = self.visual_projection(pooled_output) + + return image_features + + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + pixel_values: Optional[torch.FloatTensor] = None, + condition: Optional[torch.Tensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + return_loss: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + ) -> Union[Tuple, CLIPOutput]: + # Use CLIP model's config for some fields (if specified) instead of those of vision & text components. + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + vision_outputs = self.vision_model( + pixel_values=pixel_values, + condition=condition, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + text_outputs = self.text_model( + input_ids=input_ids, + attention_mask=attention_mask, + position_ids=position_ids, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + image_embeds = vision_outputs[1] + image_embeds = self.visual_projection(image_embeds) + + text_embeds = text_outputs[1] + text_embeds = self.text_projection(text_embeds) + + # normalized features + image_embeds = image_embeds / image_embeds.norm(p=2, dim=-1, keepdim=True) + text_embeds = text_embeds / text_embeds.norm(p=2, dim=-1, keepdim=True) + + # cosine similarity as logits + logit_scale = self.logit_scale.exp() + logits_per_text = torch.matmul(text_embeds, image_embeds.t()) * logit_scale + logits_per_image = logits_per_text.t() + + loss = None + if return_loss: + loss = clip_loss(logits_per_text) + + if not return_dict: + output = (logits_per_image, logits_per_text, text_embeds, image_embeds, text_outputs, vision_outputs) + return ((loss,) + output) if loss is not None else output + + return CLIPOutput( + loss=loss, + logits_per_image=logits_per_image, + logits_per_text=logits_per_text, + text_embeds=text_embeds, + image_embeds=image_embeds, + text_model_output=text_outputs, + vision_model_output=vision_outputs, + ) diff --git a/craftsman/models/conditional_encoders/clip_encoder.py b/craftsman/models/conditional_encoders/clip_encoder.py new file mode 100755 index 0000000000000000000000000000000000000000..326f3b67b4a33ecc969e90cba5e1e893c201aec7 --- /dev/null +++ b/craftsman/models/conditional_encoders/clip_encoder.py @@ -0,0 +1,172 @@ +import random +import torch +from torch import nn +import numpy as np +from PIL import Image +from einops import rearrange +from dataclasses import dataclass +from torchvision.transforms import Normalize +from torchvision.transforms import InterpolationMode +from torchvision.transforms.transforms import _interpolation_modes_from_int +from torchvision import transforms + +from transformers import CLIPTokenizer, CLIPImageProcessor +from transformers.utils import ModelOutput +from typing import Iterable, Optional, Union, List + +import craftsman +from craftsman.utils.typing import * +from .clip.modeling_clip import CLIPModel +from .clip.modeling_conditional_clip import ConditionalCLIPModel +from .base import BaseEmbedder, ImageType + +@dataclass +class CLIPEmbedOutput(ModelOutput): + last_hidden_state: torch.FloatTensor = None + pooler_output: torch.FloatTensor = None + embeds: torch.FloatTensor = None + +@craftsman.register("clip-embedder") +class CLIPEmbedder(BaseEmbedder): + + @dataclass + class Config(BaseEmbedder.Config): + freeze_modulation: bool = False + config_path: str = '' + + cfg: Config + + def configure(self) -> None: + super().configure() + + # Load the CLIP model and processor + if not self.cfg.encode_camera: + self.model: CLIPModel = CLIPModel.from_pretrained(self.cfg.pretrained_model_name_or_path) + else: + if self.cfg.pretrained_model_name_or_path == '': + assert self.cfg.config_path is not None, "The config path should be provided" + conditional_clip_config = ConditionalCLIPModel.config_class.from_json_file(self.cfg.config_path) + conditional_clip_config.vision_config.modulation_dim = self.cfg.camera_embeds_dim + self.model: CLIPModel = ConditionalCLIPModel(conditional_clip_config) + else: + conditional_clip_config = ConditionalCLIPModel.config_class.from_pretrained( + self.cfg.pretrained_model_name_or_path, + ) + conditional_clip_config.vision_config.modulation_dim = self.cfg.camera_embeds_dim + self.model: CLIPModel = ConditionalCLIPModel.from_pretrained( + self.cfg.pretrained_model_name_or_path, + vision_config=conditional_clip_config.vision_config + ) + + self.tokenizer = None + self.image_preprocess = CLIPImageProcessor() + self.transform = transforms.Compose( + [ + transforms.Resize(224, transforms.InterpolationMode.BICUBIC, antialias=True), + transforms.CenterCrop(224), # crop a (224, 224) square + transforms.Normalize( + mean=[0.48145466, 0.4578275, 0.40821073], + std=[0.26862954, 0.26130258, 0.27577711], + ), + ] + ) + + self.logit_scale = self.model.logit_scale.exp() + + if self.cfg.zero_uncond_embeds: + self.empty_text_embeds = torch.zeros((1, 77, 768)).detach() + self.empty_image_embeds = torch.zeros((self.cfg.n_views, 257, 1024)).detach() + else: + try: + self.empty_text_embeds = self.encode_text([""]).detach() # [1, 77, 768] + except: + self.empty_text_embeds = None + if self.cfg.encode_camera: + self.empty_image_embeds = self.encode_image(torch.zeros(self.cfg.n_views, 224, 224, 3), self.cameras[:self.cfg.n_views]).detach() + else: + self.empty_image_embeds = self.encode_image(torch.zeros(self.cfg.n_views, 224, 224, 3)).detach() + + # Freeze the model parameters + self.model.eval() + for k, p in self.model.named_parameters(): + ks = k.split('.') + if 'mod_norm1' in ks or 'mod_norm2' in ks and not self.cfg.freeze_modulation: + p.requires_grad_(True) + else: + p.requires_grad_(False) + + def encode_image(self, images: Iterable[Optional[ImageType]], cameras: Optional[torch.Tensor] = None, force_none_camera_embeds: bool = False, return_dict: bool = False, **kwargs) -> torch.FloatTensor: + camera_embeds = None + if isinstance(images, (np.ndarray, torch.Tensor)): # for training process + assert images.min() >= 0.0 and images.max() <= 1.0, "The pixel values should be in the range of [0, 1]" + do_rescale = False + if self.cfg.encode_camera: + assert cameras is not None, "The cameras should be provided" + camera_embeds = self.encode_camera(cameras) + pixel_values = self.transform(images.permute(0, 3, 1, 2)) + else: # for inference process + do_rescale = True + if self.cfg.encode_camera: + if cameras is None: + bs = len(images) // self.cfg.n_views + cameras = self.cameras[:self.cfg.n_views].repeat(bs, 1, 1).to(self.model.device) + camera_embeds = self.encode_camera(cameras) + pixel_values = self.image_preprocess.preprocess(images, return_tensors='pt', do_rescale=do_rescale).pixel_values + + if force_none_camera_embeds: + camera_embeds = None + + packed = False + if pixel_values.ndim == 4: + packed = True + pixel_values = pixel_values.unsqueeze(1) + if camera_embeds is not None: + camera_embeds = camera_embeds.unsqueeze(1) + + if self.cfg.encode_camera and camera_embeds is not None: + vision_outputs = self.model.vision_model( + pixel_values=rearrange(pixel_values.to(self.model.device), "B N C H W -> (B N) C H W"), + condition=rearrange(camera_embeds, "B N C -> (B N) C") + ) + else: + vision_outputs = self.model.vision_model( + pixel_values=rearrange(pixel_values.to(self.model.device), "B N C H W -> (B N) C H W"), + ) + + if return_dict: + pooler_output = vision_outputs[1] # pooled_output + image_features = self.model.visual_projection(pooler_output) + + return CLIPEmbedOutput( + last_hidden_state=vision_outputs.last_hidden_state, + pooler_output=pooler_output, + embeds=image_features + ) + else: + return vision_outputs.last_hidden_state + + @torch.no_grad() + def encode_text(self, text_inputs: torch.Tensor, return_dict: bool = False) -> torch.FloatTensor: + if self.tokenizer is None: + self.tokenizer = CLIPTokenizer.from_pretrained(self.cfg.pretrained_model_name_or_path) + + if isinstance(text_inputs, list): + text_inputs = self.tokenizer( + text_inputs, + max_length=self.tokenizer.model_max_length, + padding="max_length", + return_tensors="pt" + ).input_ids + text_outputs = self.model.text_model(input_ids=text_inputs.to(self.model.device)) + + pooler_output = text_outputs[1] # pooled_output + text_features = self.model.text_projection(pooler_output) + + if return_dict: + return CLIPEmbedOutput( + last_hidden_state=text_outputs.last_hidden_state, + pooler_output=pooler_output, + embeds=text_features + ) + else: + return text_outputs.last_hidden_state \ No newline at end of file diff --git a/craftsman/models/denoisers/__init__.py b/craftsman/models/denoisers/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..b878f033b5bfc7ed68b926c4c692ed9fca17bced --- /dev/null +++ b/craftsman/models/denoisers/__init__.py @@ -0,0 +1,3 @@ +from . import ( + simple_denoiser, +) diff --git a/craftsman/models/denoisers/__pycache__/__init__.cpython-38.pyc b/craftsman/models/denoisers/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cb6488f20b57944d0636465b6d086a0ae737f4e Binary files /dev/null and b/craftsman/models/denoisers/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/models/denoisers/__pycache__/simple_denoiser.cpython-38.pyc b/craftsman/models/denoisers/__pycache__/simple_denoiser.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40fafaaf160a2990ced1878c5c84ecd94e462cf2 Binary files /dev/null and b/craftsman/models/denoisers/__pycache__/simple_denoiser.cpython-38.pyc differ diff --git a/craftsman/models/denoisers/simple_denoiser.py b/craftsman/models/denoisers/simple_denoiser.py new file mode 100755 index 0000000000000000000000000000000000000000..2b674a3fab1bac10d7aefdc2e26d8b01f8248710 --- /dev/null +++ b/craftsman/models/denoisers/simple_denoiser.py @@ -0,0 +1,191 @@ +from dataclasses import dataclass + +import torch +import torch.nn as nn +from typing import Optional +from diffusers.models.embeddings import Timesteps +import math + +import craftsman +from craftsman.models.transformers.attention import ResidualAttentionBlock +from craftsman.models.transformers.utils import init_linear, MLP +from craftsman.utils.base import BaseModule + + +class UNetDiffusionTransformer(nn.Module): + def __init__( + self, + *, + n_ctx: int, + width: int, + layers: int, + heads: int, + init_scale: float = 0.25, + qkv_bias: bool = False, + skip_ln: bool = False, + use_checkpoint: bool = False + ): + super().__init__() + + self.n_ctx = n_ctx + self.width = width + self.layers = layers + + self.encoder = nn.ModuleList() + for _ in range(layers): + resblock = ResidualAttentionBlock( + n_ctx=n_ctx, + width=width, + heads=heads, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_checkpoint=use_checkpoint + ) + self.encoder.append(resblock) + + self.middle_block = ResidualAttentionBlock( + n_ctx=n_ctx, + width=width, + heads=heads, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_checkpoint=use_checkpoint + ) + + self.decoder = nn.ModuleList() + for _ in range(layers): + resblock = ResidualAttentionBlock( + n_ctx=n_ctx, + width=width, + heads=heads, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_checkpoint=use_checkpoint + ) + linear = nn.Linear(width * 2, width) + init_linear(linear, init_scale) + + layer_norm = nn.LayerNorm(width) if skip_ln else None + + self.decoder.append(nn.ModuleList([resblock, linear, layer_norm])) + + def forward(self, x: torch.Tensor): + + enc_outputs = [] + for block in self.encoder: + x = block(x) + enc_outputs.append(x) + + x = self.middle_block(x) + + for i, (resblock, linear, layer_norm) in enumerate(self.decoder): + x = torch.cat([enc_outputs.pop(), x], dim=-1) + x = linear(x) + + if layer_norm is not None: + x = layer_norm(x) + + x = resblock(x) + + return x + + +@craftsman.register("simple-denoiser") +class SimpleDenoiser(BaseModule): + + @dataclass + class Config(BaseModule.Config): + pretrained_model_name_or_path: Optional[str] = None + input_channels: int = 32 + output_channels: int = 32 + n_ctx: int = 512 + width: int = 768 + layers: int = 6 + heads: int = 12 + context_dim: int = 1024 + context_ln: bool = True + skip_ln: bool = False + init_scale: float = 0.25 + flip_sin_to_cos: bool = False + use_checkpoint: bool = False + + cfg: Config + + def configure(self) -> None: + super().configure() + + init_scale = self.cfg.init_scale * math.sqrt(1.0 / self.cfg.width) + + self.backbone = UNetDiffusionTransformer( + n_ctx=self.cfg.n_ctx, + width=self.cfg.width, + layers=self.cfg.layers, + heads=self.cfg.heads, + skip_ln=self.cfg.skip_ln, + init_scale=init_scale, + use_checkpoint=self.cfg.use_checkpoint + ) + self.ln_post = nn.LayerNorm(self.cfg.width) + self.input_proj = nn.Linear(self.cfg.input_channels, self.cfg.width) + self.output_proj = nn.Linear(self.cfg.width, self.cfg.output_channels) + + # timestep embedding + self.time_embed = Timesteps(self.cfg.width, flip_sin_to_cos=self.cfg.flip_sin_to_cos, downscale_freq_shift=0) + self.time_proj = MLP(width=self.cfg.width, init_scale=init_scale) + + if self.cfg.context_ln: + self.context_embed = nn.Sequential( + nn.LayerNorm(self.cfg.context_dim), + nn.Linear(self.cfg.context_dim, self.cfg.width), + ) + else: + self.context_embed = nn.Linear(self.cfg.context_dim, self.cfg.width) + + if self.cfg.pretrained_model_name_or_path: + pretrained_ckpt = torch.load(self.cfg.pretrained_model_name_or_path, map_location="cpu") + _pretrained_ckpt = {} + for k, v in pretrained_ckpt.items(): + if k.startswith('denoiser_model.'): + _pretrained_ckpt[k.replace('denoiser_model.', '')] = v + pretrained_ckpt = _pretrained_ckpt + if 'state_dict' in pretrained_ckpt: + _pretrained_ckpt = {} + for k, v in pretrained_ckpt['state_dict'].items(): + if k.startswith('denoiser_model.'): + _pretrained_ckpt[k.replace('denoiser_model.', '')] = v + pretrained_ckpt = _pretrained_ckpt + self.load_state_dict(pretrained_ckpt, strict=True) + + def forward(self, + model_input: torch.FloatTensor, + timestep: torch.LongTensor, + context: torch.FloatTensor): + + r""" + Args: + model_input (torch.FloatTensor): [bs, n_data, c] + timestep (torch.LongTensor): [bs,] + context (torch.FloatTensor): [bs, context_tokens, c] + + Returns: + sample (torch.FloatTensor): [bs, n_data, c] + + """ + + _, n_data, _ = model_input.shape + + # 1. time + t_emb = self.time_proj(self.time_embed(timestep)).unsqueeze(dim=1) + + # 2. conditions projector + context = self.context_embed(context) + + # 3. denoiser + x = self.input_proj(model_input) + x = torch.cat([t_emb, context, x], dim=1) + x = self.backbone(x) + x = self.ln_post(x) + x = x[:, -n_data:] # B, n_data, width + sample = self.output_proj(x) # B, n_data, embed_dim + + return sample \ No newline at end of file diff --git a/craftsman/models/geometry/__init__.py b/craftsman/models/geometry/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..c8cc981885cc04d30da134fcdcdd54154702a3f9 --- /dev/null +++ b/craftsman/models/geometry/__init__.py @@ -0,0 +1,3 @@ +from . import ( + base +) diff --git a/craftsman/models/geometry/__pycache__/__init__.cpython-38.pyc b/craftsman/models/geometry/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1cdda25f3d4d8ee4c4d381118069a3d67dbc7d7 Binary files /dev/null and b/craftsman/models/geometry/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/models/geometry/__pycache__/base.cpython-38.pyc b/craftsman/models/geometry/__pycache__/base.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..882777f0115717b412dcb8649d1c5fcfe279506a Binary files /dev/null and b/craftsman/models/geometry/__pycache__/base.cpython-38.pyc differ diff --git a/craftsman/models/geometry/__pycache__/utils.cpython-38.pyc b/craftsman/models/geometry/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a12a1e75fc0f7b8d4561597e720e88c65aaa7611 Binary files /dev/null and b/craftsman/models/geometry/__pycache__/utils.cpython-38.pyc differ diff --git a/craftsman/models/geometry/base.py b/craftsman/models/geometry/base.py new file mode 100755 index 0000000000000000000000000000000000000000..aabea8a23e582879ef73507d50518ecf1950962d --- /dev/null +++ b/craftsman/models/geometry/base.py @@ -0,0 +1,194 @@ +from dataclasses import dataclass, field + +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +import craftsman +from .utils import ( + Mesh, + IsosurfaceHelper, + MarchingCubeCPUHelper, + MarchingTetrahedraHelper, +) + +from craftsman.utils.base import BaseModule +from craftsman.utils.ops import chunk_batch, scale_tensor +from craftsman.utils.typing import * + +class BaseGeometry(BaseModule): + @dataclass + class Config(BaseModule.Config): + pass + + cfg: Config + + @staticmethod + def create_from( + other: "BaseGeometry", cfg: Optional[Union[dict, DictConfig]] = None, **kwargs + ) -> "BaseGeometry": + raise TypeError( + f"Cannot create {BaseGeometry.__name__} from {other.__class__.__name__}" + ) + + def export(self, *args, **kwargs) -> Dict[str, Any]: + return {} + + +class BaseImplicitGeometry(BaseGeometry): + @dataclass + class Config(BaseGeometry.Config): + radius: float = 1.0 + isosurface: bool = True + isosurface_method: str = "mt" + isosurface_resolution: int = 128 + isosurface_threshold: Union[float, str] = 0.0 + isosurface_chunk: int = 0 + isosurface_coarse_to_fine: bool = True + isosurface_deformable_grid: bool = False + isosurface_remove_outliers: bool = True + isosurface_outlier_n_faces_threshold: Union[int, float] = 0.01 + + cfg: Config + + def configure(self) -> None: + self.bbox: Float[Tensor, "2 3"] + self.register_buffer( + "bbox", + torch.as_tensor( + [ + [-self.cfg.radius, -self.cfg.radius, -self.cfg.radius], + [self.cfg.radius, self.cfg.radius, self.cfg.radius], + ], + dtype=torch.float32, + ), + ) + self.isosurface_helper: Optional[IsosurfaceHelper] = None + self.unbounded: bool = False + + def _initilize_isosurface_helper(self): + if self.cfg.isosurface and self.isosurface_helper is None: + if self.cfg.isosurface_method == "mc-cpu": + self.isosurface_helper = MarchingCubeCPUHelper( + self.cfg.isosurface_resolution + ).to(self.device) + elif self.cfg.isosurface_method == "mt": + self.isosurface_helper = MarchingTetrahedraHelper( + self.cfg.isosurface_resolution, + f"load/tets/{self.cfg.isosurface_resolution}_tets.npz", + ).to(self.device) + else: + raise AttributeError( + "Unknown isosurface method {self.cfg.isosurface_method}" + ) + + def forward( + self, points: Float[Tensor, "*N Di"], output_normal: bool = False + ) -> Dict[str, Float[Tensor, "..."]]: + raise NotImplementedError + + def forward_field( + self, points: Float[Tensor, "*N Di"] + ) -> Tuple[Float[Tensor, "*N 1"], Optional[Float[Tensor, "*N 3"]]]: + # return the value of the implicit field, could be density / signed distance + # also return a deformation field if the grid vertices can be optimized + raise NotImplementedError + + def forward_level( + self, field: Float[Tensor, "*N 1"], threshold: float + ) -> Float[Tensor, "*N 1"]: + # return the value of the implicit field, where the zero level set represents the surface + raise NotImplementedError + + def _isosurface(self, bbox: Float[Tensor, "2 3"], fine_stage: bool = False) -> Mesh: + def batch_func(x): + # scale to bbox as the input vertices are in [0, 1] + field, deformation = self.forward_field( + scale_tensor( + x.to(bbox.device), self.isosurface_helper.points_range, bbox + ), + ) + field = field.to( + x.device + ) # move to the same device as the input (could be CPU) + if deformation is not None: + deformation = deformation.to(x.device) + return field, deformation + + assert self.isosurface_helper is not None + + field, deformation = chunk_batch( + batch_func, + self.cfg.isosurface_chunk, + self.isosurface_helper.grid_vertices, + ) + + threshold: float + + if isinstance(self.cfg.isosurface_threshold, float): + threshold = self.cfg.isosurface_threshold + elif self.cfg.isosurface_threshold == "auto": + eps = 1.0e-5 + threshold = field[field > eps].mean().item() + craftsman.info( + f"Automatically determined isosurface threshold: {threshold}" + ) + else: + raise TypeError( + f"Unknown isosurface_threshold {self.cfg.isosurface_threshold}" + ) + + level = self.forward_level(field, threshold) + mesh: Mesh = self.isosurface_helper(level, deformation=deformation) + mesh.v_pos = scale_tensor( + mesh.v_pos, self.isosurface_helper.points_range, bbox + ) # scale to bbox as the grid vertices are in [0, 1] + mesh.add_extra("bbox", bbox) + + if self.cfg.isosurface_remove_outliers: + # remove outliers components with small number of faces + # only enabled when the mesh is not differentiable + mesh = mesh.remove_outlier(self.cfg.isosurface_outlier_n_faces_threshold) + + return mesh + + def isosurface(self) -> Mesh: + if not self.cfg.isosurface: + raise NotImplementedError( + "Isosurface is not enabled in the current configuration" + ) + self._initilize_isosurface_helper() + if self.cfg.isosurface_coarse_to_fine: + craftsman.debug("First run isosurface to get a tight bounding box ...") + with torch.no_grad(): + mesh_coarse = self._isosurface(self.bbox) + vmin, vmax = mesh_coarse.v_pos.amin(dim=0), mesh_coarse.v_pos.amax(dim=0) + vmin_ = (vmin - (vmax - vmin) * 0.1).max(self.bbox[0]) + vmax_ = (vmax + (vmax - vmin) * 0.1).min(self.bbox[1]) + craftsman.debug("Run isosurface again with the tight bounding box ...") + mesh = self._isosurface(torch.stack([vmin_, vmax_], dim=0), fine_stage=True) + else: + mesh = self._isosurface(self.bbox) + return mesh + + +class BaseExplicitGeometry(BaseGeometry): + @dataclass + class Config(BaseGeometry.Config): + radius: float = 1.0 + + cfg: Config + + def configure(self) -> None: + self.bbox: Float[Tensor, "2 3"] + self.register_buffer( + "bbox", + torch.as_tensor( + [ + [-self.cfg.radius, -self.cfg.radius, -self.cfg.radius], + [self.cfg.radius, self.cfg.radius, self.cfg.radius], + ], + dtype=torch.float32, + ), + ) \ No newline at end of file diff --git a/craftsman/models/geometry/utils.py b/craftsman/models/geometry/utils.py new file mode 100755 index 0000000000000000000000000000000000000000..c97a94ed19a5e1c56cde804b08aa1288e41999e2 --- /dev/null +++ b/craftsman/models/geometry/utils.py @@ -0,0 +1,559 @@ +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +import craftsman +from craftsman.utils.typing import * + + +def dot(x, y): + return torch.sum(x * y, -1, keepdim=True) + + +class Mesh: + def __init__( + self, v_pos: Float[Tensor, "Nv 3"], t_pos_idx: Integer[Tensor, "Nf 3"], **kwargs + ) -> None: + self.v_pos: Float[Tensor, "Nv 3"] = v_pos + self.t_pos_idx: Integer[Tensor, "Nf 3"] = t_pos_idx + self._v_nrm: Optional[Float[Tensor, "Nv 3"]] = None + self._v_tng: Optional[Float[Tensor, "Nv 3"]] = None + self._v_tex: Optional[Float[Tensor, "Nt 3"]] = None + self._t_tex_idx: Optional[Float[Tensor, "Nf 3"]] = None + self._v_rgb: Optional[Float[Tensor, "Nv 3"]] = None + self._edges: Optional[Integer[Tensor, "Ne 2"]] = None + self.extras: Dict[str, Any] = {} + for k, v in kwargs.items(): + self.add_extra(k, v) + + def add_extra(self, k, v): + self.extras[k] = v + + def remove_outlier(self, outlier_n_faces_threshold: Union[int, float]): + if self.requires_grad: + craftsman.debug("Mesh is differentiable, not removing outliers") + return self + + # use trimesh to first split the mesh into connected components + # then remove the components with less than n_face_threshold faces + import trimesh + + # construct a trimesh object + mesh = trimesh.Trimesh( + vertices=self.v_pos.detach().cpu().numpy(), + faces=self.t_pos_idx.detach().cpu().numpy(), + ) + + # split the mesh into connected components + components = mesh.split(only_watertight=False) + # log the number of faces in each component + craftsman.debug( + "Mesh has {} components, with faces: {}".format( + len(components), [c.faces.shape[0] for c in components] + ) + ) + + n_faces_threshold: int + if isinstance(outlier_n_faces_threshold, float): + # set the threshold to the number of faces in the largest component multiplied by outlier_n_faces_threshold + n_faces_threshold = int( + max([c.faces.shape[0] for c in components]) * outlier_n_faces_threshold + ) + else: + # set the threshold directly to outlier_n_faces_threshold + n_faces_threshold = outlier_n_faces_threshold + + # log the threshold + craftsman.debug( + "Removing components with less than {} faces".format(n_faces_threshold) + ) + + # remove the components with less than n_face_threshold faces + components = [c for c in components if c.faces.shape[0] >= n_faces_threshold] + + # log the number of faces in each component after removing outliers + craftsman.debug( + "Mesh has {} components after removing outliers, with faces: {}".format( + len(components), [c.faces.shape[0] for c in components] + ) + ) + # merge the components + mesh = trimesh.util.concatenate(components) + + # convert back to our mesh format + v_pos = torch.from_numpy(mesh.vertices).to(self.v_pos) + t_pos_idx = torch.from_numpy(mesh.faces).to(self.t_pos_idx) + + clean_mesh = Mesh(v_pos, t_pos_idx) + # keep the extras unchanged + + if len(self.extras) > 0: + clean_mesh.extras = self.extras + craftsman.debug( + f"The following extra attributes are inherited from the original mesh unchanged: {list(self.extras.keys())}" + ) + return clean_mesh + + @property + def requires_grad(self): + return self.v_pos.requires_grad + + @property + def v_nrm(self): + if self._v_nrm is None: + self._v_nrm = self._compute_vertex_normal() + return self._v_nrm + + @property + def v_tng(self): + if self._v_tng is None: + self._v_tng = self._compute_vertex_tangent() + return self._v_tng + + @property + def v_tex(self): + if self._v_tex is None: + self._v_tex, self._t_tex_idx = self._unwrap_uv() + return self._v_tex + + @property + def t_tex_idx(self): + if self._t_tex_idx is None: + self._v_tex, self._t_tex_idx = self._unwrap_uv() + return self._t_tex_idx + + @property + def v_rgb(self): + return self._v_rgb + + @property + def edges(self): + if self._edges is None: + self._edges = self._compute_edges() + return self._edges + + def _compute_vertex_normal(self): + i0 = self.t_pos_idx[:, 0] + i1 = self.t_pos_idx[:, 1] + i2 = self.t_pos_idx[:, 2] + + v0 = self.v_pos[i0, :] + v1 = self.v_pos[i1, :] + v2 = self.v_pos[i2, :] + + face_normals = torch.cross(v1 - v0, v2 - v0) + + # Splat face normals to vertices + v_nrm = torch.zeros_like(self.v_pos) + v_nrm.scatter_add_(0, i0[:, None].repeat(1, 3), face_normals) + v_nrm.scatter_add_(0, i1[:, None].repeat(1, 3), face_normals) + v_nrm.scatter_add_(0, i2[:, None].repeat(1, 3), face_normals) + + # Normalize, replace zero (degenerated) normals with some default value + v_nrm = torch.where( + dot(v_nrm, v_nrm) > 1e-20, v_nrm, torch.as_tensor([0.0, 0.0, 1.0]).to(v_nrm) + ) + v_nrm = F.normalize(v_nrm, dim=1) + + if torch.is_anomaly_enabled(): + assert torch.all(torch.isfinite(v_nrm)) + + return v_nrm + + def _compute_vertex_tangent(self): + vn_idx = [None] * 3 + pos = [None] * 3 + tex = [None] * 3 + for i in range(0, 3): + pos[i] = self.v_pos[self.t_pos_idx[:, i]] + tex[i] = self.v_tex[self.t_tex_idx[:, i]] + # t_nrm_idx is always the same as t_pos_idx + vn_idx[i] = self.t_pos_idx[:, i] + + tangents = torch.zeros_like(self.v_nrm) + tansum = torch.zeros_like(self.v_nrm) + + # Compute tangent space for each triangle + uve1 = tex[1] - tex[0] + uve2 = tex[2] - tex[0] + pe1 = pos[1] - pos[0] + pe2 = pos[2] - pos[0] + + nom = pe1 * uve2[..., 1:2] - pe2 * uve1[..., 1:2] + denom = uve1[..., 0:1] * uve2[..., 1:2] - uve1[..., 1:2] * uve2[..., 0:1] + + # Avoid division by zero for degenerated texture coordinates + tang = nom / torch.where( + denom > 0.0, torch.clamp(denom, min=1e-6), torch.clamp(denom, max=-1e-6) + ) + + # Update all 3 vertices + for i in range(0, 3): + idx = vn_idx[i][:, None].repeat(1, 3) + tangents.scatter_add_(0, idx, tang) # tangents[n_i] = tangents[n_i] + tang + tansum.scatter_add_( + 0, idx, torch.ones_like(tang) + ) # tansum[n_i] = tansum[n_i] + 1 + tangents = tangents / tansum + + # Normalize and make sure tangent is perpendicular to normal + tangents = F.normalize(tangents, dim=1) + tangents = F.normalize(tangents - dot(tangents, self.v_nrm) * self.v_nrm) + + if torch.is_anomaly_enabled(): + assert torch.all(torch.isfinite(tangents)) + + return tangents + + def _unwrap_uv( + self, xatlas_chart_options: dict = {}, xatlas_pack_options: dict = {} + ): + craftsman.info("Using xatlas to perform UV unwrapping, may take a while ...") + + import xatlas + + atlas = xatlas.Atlas() + atlas.add_mesh( + self.v_pos.detach().cpu().numpy(), + self.t_pos_idx.cpu().numpy(), + ) + co = xatlas.ChartOptions() + po = xatlas.PackOptions() + for k, v in xatlas_chart_options.items(): + setattr(co, k, v) + for k, v in xatlas_pack_options.items(): + setattr(po, k, v) + + setattr(co, 'max_cost', 2.0) + setattr(po, 'resolution', 4096) + + atlas.generate(co, po, verbose=True) + vmapping, indices, uvs = atlas.get_mesh(0) + vmapping = ( + torch.from_numpy( + vmapping.astype(np.uint64, casting="same_kind").view(np.int64) + ) + .to(self.v_pos.device) + .long() + ) + uvs = torch.from_numpy(uvs).to(self.v_pos.device).float() + indices = ( + torch.from_numpy( + indices.astype(np.uint64, casting="same_kind").view(np.int64) + ) + .to(self.v_pos.device) + .long() + ) + return uvs, indices + + def unwrap_uv( + self, xatlas_chart_options: dict = {}, xatlas_pack_options: dict = {} + ): + self._v_tex, self._t_tex_idx = self._unwrap_uv( + xatlas_chart_options, xatlas_pack_options + ) + + def set_vertex_color(self, v_rgb): + assert v_rgb.shape[0] == self.v_pos.shape[0] + self._v_rgb = v_rgb + + def _compute_edges(self): + # Compute edges + edges = torch.cat( + [ + self.t_pos_idx[:, [0, 1]], + self.t_pos_idx[:, [1, 2]], + self.t_pos_idx[:, [2, 0]], + ], + dim=0, + ) + edges = edges.sort()[0] + edges = torch.unique(edges, dim=0) + return edges + + def normal_consistency(self) -> Float[Tensor, ""]: + edge_nrm: Float[Tensor, "Ne 2 3"] = self.v_nrm[self.edges] + nc = ( + 1.0 - torch.cosine_similarity(edge_nrm[:, 0], edge_nrm[:, 1], dim=-1) + ).mean() + return nc + + def _laplacian_uniform(self): + # from stable-dreamfusion + # https://github.com/ashawkey/stable-dreamfusion/blob/8fb3613e9e4cd1ded1066b46e80ca801dfb9fd06/nerf/renderer.py#L224 + verts, faces = self.v_pos, self.t_pos_idx + + V = verts.shape[0] + F = faces.shape[0] + + # Neighbor indices + ii = faces[:, [1, 2, 0]].flatten() + jj = faces[:, [2, 0, 1]].flatten() + adj = torch.stack([torch.cat([ii, jj]), torch.cat([jj, ii])], dim=0).unique( + dim=1 + ) + adj_values = torch.ones(adj.shape[1]).to(verts) + + # Diagonal indices + diag_idx = adj[0] + + # Build the sparse matrix + idx = torch.cat((adj, torch.stack((diag_idx, diag_idx), dim=0)), dim=1) + values = torch.cat((-adj_values, adj_values)) + + # The coalesce operation sums the duplicate indices, resulting in the + # correct diagonal + return torch.sparse_coo_tensor(idx, values, (V, V)).coalesce() + + def laplacian(self) -> Float[Tensor, ""]: + with torch.no_grad(): + L = self._laplacian_uniform() + loss = L.mm(self.v_pos) + loss = loss.norm(dim=1) + loss = loss.mean() + return loss + +class IsosurfaceHelper(nn.Module): + points_range: Tuple[float, float] = (0, 1) + + @property + def grid_vertices(self) -> Float[Tensor, "N 3"]: + raise NotImplementedError + + +class MarchingCubeCPUHelper(IsosurfaceHelper): + def __init__(self, resolution: int) -> None: + super().__init__() + self.resolution = resolution + import mcubes + + self.mc_func: Callable = mcubes.marching_cubes + self._grid_vertices: Optional[Float[Tensor, "N3 3"]] = None + self._dummy: Float[Tensor, "..."] + self.register_buffer( + "_dummy", torch.zeros(0, dtype=torch.float32), persistent=False + ) + + @property + def grid_vertices(self) -> Float[Tensor, "N3 3"]: + if self._grid_vertices is None: + # keep the vertices on CPU so that we can support very large resolution + x, y, z = ( + torch.linspace(*self.points_range, self.resolution), + torch.linspace(*self.points_range, self.resolution), + torch.linspace(*self.points_range, self.resolution), + ) + x, y, z = torch.meshgrid(x, y, z, indexing="ij") + verts = torch.cat( + [x.reshape(-1, 1), y.reshape(-1, 1), z.reshape(-1, 1)], dim=-1 + ).reshape(-1, 3) + self._grid_vertices = verts + return self._grid_vertices + + def forward( + self, + level: Float[Tensor, "N3 1"], + deformation: Optional[Float[Tensor, "N3 3"]] = None, + ) -> Mesh: + if deformation is not None: + craftsman.warn( + f"{self.__class__.__name__} does not support deformation. Ignoring." + ) + level = -level.view(self.resolution, self.resolution, self.resolution) + v_pos, t_pos_idx = self.mc_func( + level.detach().cpu().numpy(), 0.0 + ) # transform to numpy + v_pos, t_pos_idx = ( + torch.from_numpy(v_pos).float().to(self._dummy.device), + torch.from_numpy(t_pos_idx.astype(np.int64)).long().to(self._dummy.device), + ) # transform back to torch tensor on CUDA + v_pos = v_pos / (self.resolution - 1.0) + return Mesh(v_pos=v_pos, t_pos_idx=t_pos_idx) + + +class MarchingTetrahedraHelper(IsosurfaceHelper): + def __init__(self, resolution: int, tets_path: str): + super().__init__() + self.resolution = resolution + self.tets_path = tets_path + + self.triangle_table: Float[Tensor, "..."] + self.register_buffer( + "triangle_table", + torch.as_tensor( + [ + [-1, -1, -1, -1, -1, -1], + [1, 0, 2, -1, -1, -1], + [4, 0, 3, -1, -1, -1], + [1, 4, 2, 1, 3, 4], + [3, 1, 5, -1, -1, -1], + [2, 3, 0, 2, 5, 3], + [1, 4, 0, 1, 5, 4], + [4, 2, 5, -1, -1, -1], + [4, 5, 2, -1, -1, -1], + [4, 1, 0, 4, 5, 1], + [3, 2, 0, 3, 5, 2], + [1, 3, 5, -1, -1, -1], + [4, 1, 2, 4, 3, 1], + [3, 0, 4, -1, -1, -1], + [2, 0, 1, -1, -1, -1], + [-1, -1, -1, -1, -1, -1], + ], + dtype=torch.long, + ), + persistent=False, + ) + self.num_triangles_table: Integer[Tensor, "..."] + self.register_buffer( + "num_triangles_table", + torch.as_tensor( + [0, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 0], dtype=torch.long + ), + persistent=False, + ) + self.base_tet_edges: Integer[Tensor, "..."] + self.register_buffer( + "base_tet_edges", + torch.as_tensor([0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3], dtype=torch.long), + persistent=False, + ) + + tets = np.load(self.tets_path) + self._grid_vertices: Float[Tensor, "..."] + self.register_buffer( + "_grid_vertices", + torch.from_numpy(tets["vertices"]).float(), + persistent=False, + ) + self.indices: Integer[Tensor, "..."] + self.register_buffer( + "indices", torch.from_numpy(tets["indices"]).long(), persistent=False + ) + + self._all_edges: Optional[Integer[Tensor, "Ne 2"]] = None + + def normalize_grid_deformation( + self, grid_vertex_offsets: Float[Tensor, "Nv 3"] + ) -> Float[Tensor, "Nv 3"]: + return ( + (self.points_range[1] - self.points_range[0]) + / (self.resolution) # half tet size is approximately 1 / self.resolution + * torch.tanh(grid_vertex_offsets) + ) # FIXME: hard-coded activation + + @property + def grid_vertices(self) -> Float[Tensor, "Nv 3"]: + return self._grid_vertices + + @property + def all_edges(self) -> Integer[Tensor, "Ne 2"]: + if self._all_edges is None: + # compute edges on GPU, or it would be VERY SLOW (basically due to the unique operation) + edges = torch.tensor( + [0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3], + dtype=torch.long, + device=self.indices.device, + ) + _all_edges = self.indices[:, edges].reshape(-1, 2) + _all_edges_sorted = torch.sort(_all_edges, dim=1)[0] + _all_edges = torch.unique(_all_edges_sorted, dim=0) + self._all_edges = _all_edges + return self._all_edges + + def sort_edges(self, edges_ex2): + with torch.no_grad(): + order = (edges_ex2[:, 0] > edges_ex2[:, 1]).long() + order = order.unsqueeze(dim=1) + + a = torch.gather(input=edges_ex2, index=order, dim=1) + b = torch.gather(input=edges_ex2, index=1 - order, dim=1) + + return torch.stack([a, b], -1) + + def _forward(self, pos_nx3, sdf_n, tet_fx4): + with torch.no_grad(): + occ_n = sdf_n > 0 + occ_fx4 = occ_n[tet_fx4.reshape(-1)].reshape(-1, 4) + occ_sum = torch.sum(occ_fx4, -1) + valid_tets = (occ_sum > 0) & (occ_sum < 4) + occ_sum = occ_sum[valid_tets] + + # find all vertices + all_edges = tet_fx4[valid_tets][:, self.base_tet_edges].reshape(-1, 2) + all_edges = self.sort_edges(all_edges) + unique_edges, idx_map = torch.unique(all_edges, dim=0, return_inverse=True) + + unique_edges = unique_edges.long() + mask_edges = occ_n[unique_edges.reshape(-1)].reshape(-1, 2).sum(-1) == 1 + mapping = ( + torch.ones( + (unique_edges.shape[0]), dtype=torch.long, device=pos_nx3.device + ) + * -1 + ) + mapping[mask_edges] = torch.arange( + mask_edges.sum(), dtype=torch.long, device=pos_nx3.device + ) + idx_map = mapping[idx_map] # map edges to verts + + interp_v = unique_edges[mask_edges] + edges_to_interp = pos_nx3[interp_v.reshape(-1)].reshape(-1, 2, 3) + edges_to_interp_sdf = sdf_n[interp_v.reshape(-1)].reshape(-1, 2, 1) + edges_to_interp_sdf[:, -1] *= -1 + + denominator = edges_to_interp_sdf.sum(1, keepdim=True) + + edges_to_interp_sdf = torch.flip(edges_to_interp_sdf, [1]) / denominator + verts = (edges_to_interp * edges_to_interp_sdf).sum(1) + + idx_map = idx_map.reshape(-1, 6) + + v_id = torch.pow(2, torch.arange(4, dtype=torch.long, device=pos_nx3.device)) + tetindex = (occ_fx4[valid_tets] * v_id.unsqueeze(0)).sum(-1) + num_triangles = self.num_triangles_table[tetindex] + + # Generate triangle indices + faces = torch.cat( + ( + torch.gather( + input=idx_map[num_triangles == 1], + dim=1, + index=self.triangle_table[tetindex[num_triangles == 1]][:, :3], + ).reshape(-1, 3), + torch.gather( + input=idx_map[num_triangles == 2], + dim=1, + index=self.triangle_table[tetindex[num_triangles == 2]][:, :6], + ).reshape(-1, 3), + ), + dim=0, + ) + + return verts, faces + + def forward( + self, + level: Float[Tensor, "N3 1"], + deformation: Optional[Float[Tensor, "N3 3"]] = None, + ) -> Mesh: + if deformation is not None: + grid_vertices = self.grid_vertices + self.normalize_grid_deformation( + deformation + ) + else: + grid_vertices = self.grid_vertices + + v_pos, t_pos_idx = self._forward(grid_vertices, level, self.indices) + + mesh = Mesh( + v_pos=v_pos, + t_pos_idx=t_pos_idx, + # extras + grid_vertices=grid_vertices, + tet_edges=self.all_edges, + grid_level=level, + grid_deformation=deformation, + ) + + return mesh diff --git a/craftsman/models/transformers/__pycache__/attention.cpython-38.pyc b/craftsman/models/transformers/__pycache__/attention.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..326ccc1ec84109a7fbbe117701bbbe7761d4c4bb Binary files /dev/null and b/craftsman/models/transformers/__pycache__/attention.cpython-38.pyc differ diff --git a/craftsman/models/transformers/__pycache__/perceiver_1d.cpython-38.pyc b/craftsman/models/transformers/__pycache__/perceiver_1d.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8436a67a6b8e258fb4f12268cea3904d20f685ef Binary files /dev/null and b/craftsman/models/transformers/__pycache__/perceiver_1d.cpython-38.pyc differ diff --git a/craftsman/models/transformers/__pycache__/utils.cpython-38.pyc b/craftsman/models/transformers/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e42e801d97cdacd9f824d868e00b5d8e7c509a6 Binary files /dev/null and b/craftsman/models/transformers/__pycache__/utils.cpython-38.pyc differ diff --git a/craftsman/models/transformers/attention.py b/craftsman/models/transformers/attention.py new file mode 100755 index 0000000000000000000000000000000000000000..7d4119b44b7bf84b238d9358bc1b0eb967cec032 --- /dev/null +++ b/craftsman/models/transformers/attention.py @@ -0,0 +1,207 @@ +import math +import torch +import torch.nn as nn +import torch.nn.functional as F + +from craftsman.utils.typing import * +from craftsman.utils.checkpoint import checkpoint + +from .utils import init_linear, MLP + +class MultiheadAttention(nn.Module): + def __init__( + self, + *, + n_ctx: int, + width: int, + heads: int, + init_scale: float, + qkv_bias: bool, + use_flash: bool = False + ): + super().__init__() + self.n_ctx = n_ctx + self.width = width + self.heads = heads + self.c_qkv = nn.Linear(width, width * 3, bias=qkv_bias) + self.c_proj = nn.Linear(width, width) + self.attention = QKVMultiheadAttention(heads=heads, n_ctx=n_ctx, use_flash=use_flash) + init_linear(self.c_qkv, init_scale) + init_linear(self.c_proj, init_scale) + + def forward(self, x): + x = self.c_qkv(x) + x = checkpoint(self.attention, (x,), (), True) + x = self.c_proj(x) + return x + + +class QKVMultiheadAttention(nn.Module): + def __init__(self, *, heads: int, n_ctx: int, use_flash: bool = False): + super().__init__() + self.heads = heads + self.n_ctx = n_ctx + self.use_flash = use_flash + + def forward(self, qkv): + bs, n_ctx, width = qkv.shape + attn_ch = width // self.heads // 3 + scale = 1 / math.sqrt(math.sqrt(attn_ch)) + qkv = qkv.view(bs, n_ctx, self.heads, -1) + q, k, v = torch.split(qkv, attn_ch, dim=-1) + + if self.use_flash: + q = q.permute(0, 2, 1, 3) + k = k.permute(0, 2, 1, 3) + v = v.permute(0, 2, 1, 3) + out = F.scaled_dot_product_attention(q, k, v).permute(0, 2, 1, 3).reshape(bs, n_ctx, -1) + else: + weight = torch.einsum( + "bthc,bshc->bhts", q * scale, k * scale + ) # More stable with f16 than dividing afterwards + wdtype = weight.dtype + weight = torch.softmax(weight.float(), dim=-1).type(wdtype) + out = torch.einsum("bhts,bshc->bthc", weight, v).reshape(bs, n_ctx, -1) + + return out + +class ResidualAttentionBlock(nn.Module): + def __init__( + self, + *, + n_ctx: int, + width: int, + heads: int, + init_scale: float = 1.0, + qkv_bias: bool = True, + use_flash: bool = False, + use_checkpoint: bool = False + ): + super().__init__() + + self.use_checkpoint = use_checkpoint + + self.attn = MultiheadAttention( + n_ctx=n_ctx, + width=width, + heads=heads, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_flash=use_flash + ) + self.ln_1 = nn.LayerNorm(width) + self.mlp = MLP(width=width, init_scale=init_scale) + self.ln_2 = nn.LayerNorm(width) + + def _forward(self, x: torch.Tensor): + x = x + self.attn(self.ln_1(x)) + x = x + self.mlp(self.ln_2(x)) + return x + + def forward(self, x: torch.Tensor): + return checkpoint(self._forward, (x,), self.parameters(), self.use_checkpoint) + + +class MultiheadCrossAttention(nn.Module): + def __init__( + self, + *, + width: int, + heads: int, + init_scale: float, + qkv_bias: bool = True, + use_flash: bool = False, + n_data: Optional[int] = None, + data_width: Optional[int] = None, + ): + super().__init__() + self.n_data = n_data + self.width = width + self.heads = heads + self.data_width = width if data_width is None else data_width + self.c_q = nn.Linear(width, width, bias=qkv_bias) + self.c_kv = nn.Linear(self.data_width, width * 2, bias=qkv_bias) + self.c_proj = nn.Linear(width, width) + self.attention = QKVMultiheadCrossAttention( + heads=heads, n_data=n_data, use_flash=use_flash + ) + init_linear(self.c_q, init_scale) + init_linear(self.c_kv, init_scale) + init_linear(self.c_proj, init_scale) + + def forward(self, x, data): + x = self.c_q(x) + data = self.c_kv(data) + x = checkpoint(self.attention, (x, data), (), True) + x = self.c_proj(x) + return x + + +class QKVMultiheadCrossAttention(nn.Module): + def __init__(self, *, heads: int, use_flash: bool = False, n_data: Optional[int] = None): + + super().__init__() + self.heads = heads + self.n_data = n_data + self.use_flash = use_flash + + def forward(self, q, kv): + _, n_ctx, _ = q.shape + bs, n_data, width = kv.shape + attn_ch = width // self.heads // 2 + scale = 1 / math.sqrt(math.sqrt(attn_ch)) + q = q.view(bs, n_ctx, self.heads, -1) + kv = kv.view(bs, n_data, self.heads, -1) + k, v = torch.split(kv, attn_ch, dim=-1) + + if self.use_flash: + q = q.permute(0, 2, 1, 3) + k = k.permute(0, 2, 1, 3) + v = v.permute(0, 2, 1, 3) + out = F.scaled_dot_product_attention(q, k, v).permute(0, 2, 1, 3).reshape(bs, n_ctx, -1) + else: + weight = torch.einsum( + "bthc,bshc->bhts", q * scale, k * scale + ) # More stable with f16 than dividing afterwards + wdtype = weight.dtype + weight = torch.softmax(weight.float(), dim=-1).type(wdtype) + out = torch.einsum("bhts,bshc->bthc", weight, v).reshape(bs, n_ctx, -1) + + return out + + +class ResidualCrossAttentionBlock(nn.Module): + def __init__( + self, + *, + n_data: Optional[int] = None, + width: int, + heads: int, + data_width: Optional[int] = None, + init_scale: float = 0.25, + qkv_bias: bool = True, + use_flash: bool = False + ): + super().__init__() + + if data_width is None: + data_width = width + + self.attn = MultiheadCrossAttention( + n_data=n_data, + width=width, + heads=heads, + data_width=data_width, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_flash=use_flash, + ) + self.ln_1 = nn.LayerNorm(width) + self.ln_2 = nn.LayerNorm(data_width) + self.mlp = MLP(width=width, init_scale=init_scale) + self.ln_3 = nn.LayerNorm(width) + + def forward(self, x: torch.Tensor, data: torch.Tensor): + x = x + self.attn(self.ln_1(x), self.ln_2(data)) + x = x + self.mlp(self.ln_3(x)) + return x \ No newline at end of file diff --git a/craftsman/models/transformers/perceiver_1d.py b/craftsman/models/transformers/perceiver_1d.py new file mode 100755 index 0000000000000000000000000000000000000000..6705a2b7ddde912e5ff9a7e8cbc76b7e142d19d3 --- /dev/null +++ b/craftsman/models/transformers/perceiver_1d.py @@ -0,0 +1,48 @@ +import math +import torch +import torch.nn as nn +import torch.nn.functional as F + +from craftsman.utils.typing import * +from craftsman.utils.checkpoint import checkpoint + +from .utils import init_linear +from .attention import ResidualAttentionBlock + + +class Perceiver(nn.Module): + def __init__( + self, + *, + n_ctx: int, + width: int, + layers: int, + heads: int, + init_scale: float = 0.25, + qkv_bias: bool = True, + use_flash: bool = False, + use_checkpoint: bool = False + ): + super().__init__() + self.n_ctx = n_ctx + self.width = width + self.layers = layers + self.resblocks = nn.ModuleList( + [ + ResidualAttentionBlock( + n_ctx=n_ctx, + width=width, + heads=heads, + init_scale=init_scale, + qkv_bias=qkv_bias, + use_flash=use_flash, + use_checkpoint=use_checkpoint + ) + for _ in range(layers) + ] + ) + + def forward(self, x: torch.Tensor): + for block in self.resblocks: + x = block(x) + return x \ No newline at end of file diff --git a/craftsman/models/transformers/utils.py b/craftsman/models/transformers/utils.py new file mode 100755 index 0000000000000000000000000000000000000000..1ed8bbf3eaf6e7bddc489dcc929ed1eab561409f --- /dev/null +++ b/craftsman/models/transformers/utils.py @@ -0,0 +1,21 @@ +import torch.nn as nn + +def init_linear(l, stddev): + nn.init.normal_(l.weight, std=stddev) + if l.bias is not None: + nn.init.constant_(l.bias, 0.0) + +class MLP(nn.Module): + def __init__(self, *, + width: int, + init_scale: float): + super().__init__() + self.width = width + self.c_fc = nn.Linear(width, width * 4) + self.c_proj = nn.Linear(width * 4, width) + self.gelu = nn.GELU() + init_linear(self.c_fc, init_scale) + init_linear(self.c_proj, init_scale) + + def forward(self, x): + return self.c_proj(self.gelu(self.c_fc(x))) diff --git a/craftsman/systems/__init__.py b/craftsman/systems/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..c2b32ffee706936f19bd2cb8ae4c7ba070cc4288 --- /dev/null +++ b/craftsman/systems/__init__.py @@ -0,0 +1,4 @@ +from . import ( + shape_autoencoder, + shape_diffusion, +) \ No newline at end of file diff --git a/craftsman/systems/__pycache__/__init__.cpython-38.pyc b/craftsman/systems/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efd8d6e9dd06baaeaaa60857791f65a1f37af7f4 Binary files /dev/null and b/craftsman/systems/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/systems/__pycache__/base.cpython-38.pyc b/craftsman/systems/__pycache__/base.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d3042ca213f65d0e2abf78bc54351750bf4e338 Binary files /dev/null and b/craftsman/systems/__pycache__/base.cpython-38.pyc differ diff --git a/craftsman/systems/__pycache__/shape_autoencoder.cpython-38.pyc b/craftsman/systems/__pycache__/shape_autoencoder.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10b054083a07ea2de75d0ef275da6f450f62b130 Binary files /dev/null and b/craftsman/systems/__pycache__/shape_autoencoder.cpython-38.pyc differ diff --git a/craftsman/systems/__pycache__/shape_diffusion.cpython-38.pyc b/craftsman/systems/__pycache__/shape_diffusion.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b6fd33c4de84d5fc168be80622882e99ebd0958 Binary files /dev/null and b/craftsman/systems/__pycache__/shape_diffusion.cpython-38.pyc differ diff --git a/craftsman/systems/base.py b/craftsman/systems/base.py new file mode 100755 index 0000000000000000000000000000000000000000..e2b66bd0edf317e62d73e7d2db0e0daf83680db0 --- /dev/null +++ b/craftsman/systems/base.py @@ -0,0 +1,209 @@ +import os +from dataclasses import dataclass, field + +import pytorch_lightning as pl +import torch.nn.functional as F + +import craftsman +from craftsman.utils.base import ( + Updateable, + update_end_if_possible, + update_if_possible, +) +from craftsman.utils.scheduler import parse_optimizer, parse_scheduler +from craftsman.utils.config import parse_structured +from craftsman.utils.misc import C, cleanup, get_device, load_module_weights +from craftsman.utils.saving import SaverMixin +from craftsman.utils.typing import * + + +class BaseSystem(pl.LightningModule, Updateable, SaverMixin): + @dataclass + class Config: + loggers: dict = field(default_factory=dict) + loss: dict = field(default_factory=dict) + optimizer: dict = field(default_factory=dict) + scheduler: Optional[dict] = None + weights: Optional[str] = None + weights_ignore_modules: Optional[List[str]] = None + cleanup_after_validation_step: bool = False + cleanup_after_test_step: bool = False + + pretrained_model_path: Optional[str] = None + strict_load: bool = True + cfg: Config + + def __init__(self, cfg, resumed=False) -> None: + super().__init__() + self.cfg = parse_structured(self.Config, cfg) + self._save_dir: Optional[str] = None + self._resumed: bool = resumed + self._resumed_eval: bool = False + self._resumed_eval_status: dict = {"global_step": 0, "current_epoch": 0} + if "loggers" in cfg: + self.create_loggers(cfg.loggers) + + self.configure() + if self.cfg.weights is not None: + self.load_weights(self.cfg.weights, self.cfg.weights_ignore_modules) + self.post_configure() + + def load_weights(self, weights: str, ignore_modules: Optional[List[str]] = None): + state_dict, epoch, global_step = load_module_weights( + weights, ignore_modules=ignore_modules, map_location="cpu" + ) + self.load_state_dict(state_dict, strict=False) + # restore step-dependent states + self.do_update_step(epoch, global_step, on_load_weights=True) + + def set_resume_status(self, current_epoch: int, global_step: int): + # restore correct epoch and global step in eval + self._resumed_eval = True + self._resumed_eval_status["current_epoch"] = current_epoch + self._resumed_eval_status["global_step"] = global_step + + @property + def resumed(self): + # whether from resumed checkpoint + return self._resumed + + @property + def true_global_step(self): + if self._resumed_eval: + return self._resumed_eval_status["global_step"] + else: + return self.global_step + + @property + def true_current_epoch(self): + if self._resumed_eval: + return self._resumed_eval_status["current_epoch"] + else: + return self.current_epoch + + def configure(self) -> None: + pass + + def post_configure(self) -> None: + """ + executed after weights are loaded + """ + pass + + def C(self, value: Any) -> float: + return C(value, self.true_current_epoch, self.true_global_step) + + def configure_optimizers(self): + optim = parse_optimizer(self.cfg.optimizer, self) + ret = { + "optimizer": optim, + } + if self.cfg.scheduler is not None: + ret.update( + { + "lr_scheduler": parse_scheduler(self.cfg.scheduler, optim), + } + ) + return ret + + def training_step(self, batch, batch_idx): + raise NotImplementedError + + def validation_step(self, batch, batch_idx): + raise NotImplementedError + + def on_train_batch_end(self, outputs, batch, batch_idx): + self.dataset = self.trainer.train_dataloader.dataset + update_end_if_possible( + self.dataset, self.true_current_epoch, self.true_global_step + ) + self.do_update_step_end(self.true_current_epoch, self.true_global_step) + + def on_validation_batch_end(self, outputs, batch, batch_idx): + self.dataset = self.trainer.val_dataloaders.dataset + update_end_if_possible( + self.dataset, self.true_current_epoch, self.true_global_step + ) + self.do_update_step_end(self.true_current_epoch, self.true_global_step) + if self.cfg.cleanup_after_validation_step: + # cleanup to save vram + cleanup() + + def on_validation_epoch_end(self): + raise NotImplementedError + + def test_step(self, batch, batch_idx): + raise NotImplementedError + + def on_test_batch_end(self, outputs, batch, batch_idx): + self.dataset = self.trainer.test_dataloaders.dataset + update_end_if_possible( + self.dataset, self.true_current_epoch, self.true_global_step + ) + self.do_update_step_end(self.true_current_epoch, self.true_global_step) + if self.cfg.cleanup_after_test_step: + # cleanup to save vram + cleanup() + + def on_test_epoch_end(self): + pass + + def predict_step(self, batch, batch_idx): + raise NotImplementedError + + def on_predict_batch_end(self, outputs, batch, batch_idx): + self.dataset = self.trainer.predict_dataloaders.dataset + update_end_if_possible( + self.dataset, self.true_current_epoch, self.true_global_step + ) + self.do_update_step_end(self.true_current_epoch, self.true_global_step) + if self.cfg.cleanup_after_test_step: + # cleanup to save vram + cleanup() + + def on_predict_epoch_end(self): + pass + + def preprocess_data(self, batch, stage): + pass + + """ + Implementing on_after_batch_transfer of DataModule does the same. + But on_after_batch_transfer does not support DP. + """ + + def on_train_batch_start(self, batch, batch_idx, unused=0): + self.preprocess_data(batch, "train") + self.dataset = self.trainer.train_dataloader.dataset + update_if_possible(self.dataset, self.true_current_epoch, self.true_global_step) + self.do_update_step(self.true_current_epoch, self.true_global_step) + + def on_validation_batch_start(self, batch, batch_idx, dataloader_idx=0): + self.preprocess_data(batch, "validation") + self.dataset = self.trainer.val_dataloaders.dataset + update_if_possible(self.dataset, self.true_current_epoch, self.true_global_step) + self.do_update_step(self.true_current_epoch, self.true_global_step) + + def on_test_batch_start(self, batch, batch_idx, dataloader_idx=0): + self.preprocess_data(batch, "test") + self.dataset = self.trainer.test_dataloaders.dataset + update_if_possible(self.dataset, self.true_current_epoch, self.true_global_step) + self.do_update_step(self.true_current_epoch, self.true_global_step) + + def on_predict_batch_start(self, batch, batch_idx, dataloader_idx=0): + self.preprocess_data(batch, "predict") + self.dataset = self.trainer.predict_dataloaders.dataset + update_if_possible(self.dataset, self.true_current_epoch, self.true_global_step) + self.do_update_step(self.true_current_epoch, self.true_global_step) + + def update_step(self, epoch: int, global_step: int, on_load_weights: bool = False): + pass + + def on_before_optimizer_step(self, optimizer): + """ + # some gradient-related debugging goes here, example: + from lightning.pytorch.utilities import grad_norm + norms = grad_norm(self.geometry, norm_type=2) + print(norms) + """ + pass diff --git a/craftsman/systems/shape_autoencoder.py b/craftsman/systems/shape_autoencoder.py new file mode 100755 index 0000000000000000000000000000000000000000..383a1ecd7a5490c353782bd2c6ecc7aaa4f30772 --- /dev/null +++ b/craftsman/systems/shape_autoencoder.py @@ -0,0 +1,137 @@ +from dataclasses import dataclass, field +import numpy as np +import torch +from skimage import measure +from einops import repeat, rearrange + +import craftsman +from craftsman.systems.base import BaseSystem +from craftsman.utils.ops import generate_dense_grid_points +from craftsman.utils.typing import * +from craftsman.utils.misc import get_rank + + +@craftsman.register("shape-autoencoder-system") +class ShapeAutoEncoderSystem(BaseSystem): + @dataclass + class Config(BaseSystem.Config): + shape_model_type: str = None + shape_model: dict = field(default_factory=dict) + + sample_posterior: bool = True + + cfg: Config + + def configure(self): + super().configure() + + self.shape_model = craftsman.find(self.cfg.shape_model_type)(self.cfg.shape_model) + + def forward(self, batch: Dict[str, Any]) -> Dict[str, Any]: + if "xyz" in batch: + if "sdf" in batch: + bs = batch["sdf"].shape[0] + rand_points = torch.cat([batch["xyz"].view(bs, -1, 3), batch["patch_xyz"].view(bs, -1, 3)], dim=1) + target = torch.cat([batch["sdf"].view(bs, -1, 1), batch["patch_sdf"].view(bs, -1, 1)], dim=1).squeeze(-1) + criteria = torch.nn.MSELoss() + elif "occupancy" in batch: + bs = batch["occupancy"].shape[0] + rand_points = torch.cat([batch["xyz"].view(bs, -1, 3), batch["patch_xyz"].view(bs, -1, 3)], dim=1) + target = torch.cat([batch["occupancy"].view(bs, -1, 1), batch["patch_occupancy"].view(bs, -1, 1)], dim=1).squeeze(-1) + criteria = torch.nn.BCEWithLogitsLoss() + else: + raise NotImplementedError + else: + rand_points = batch["rand_points"] + if "sdf" in batch: + target = batch["sdf"] + criteria = torch.nn.MSELoss() + elif "occupancies" in batch: + target = batch["occupancies"] + criteria = torch.nn.BCEWithLogitsLoss() + else: + raise NotImplementedError + + # forward pass + _, latents, posterior, logits = self.shape_model( + batch["surface"][..., :3 + self.cfg.shape_model.point_feats], + rand_points, + sample_posterior=self.cfg.sample_posterior + ) + + if self.cfg.sample_posterior: + loss_kl = posterior.kl() + loss_kl = torch.sum(loss_kl) / loss_kl.shape[0] + + return { + "loss_logits": criteria(logits, target).mean(), + "loss_kl": loss_kl, + "logits": logits, + "target": target, + "latents": latents, + } + else: + return { + "loss_logits": criteria(logits, target).mean(), + "latents": latents, + "logits": logits, + } + + def training_step(self, batch, batch_idx): + """ + Description: + + Args: + batch: + batch_idx: + Returns: + loss: + """ + out = self(batch) + + loss = 0. + for name, value in out.items(): + if name.startswith("loss_"): + self.log(f"train/{name}", value) + loss += value * self.C(self.cfg.loss[name.replace("loss_", "lambda_")]) + + for name, value in self.cfg.loss.items(): + self.log(f"train_params/{name}", self.C(value)) + + return {"loss": loss} + + @torch.no_grad() + def validation_step(self, batch, batch_idx): + self.eval() + out = self(batch) + # self.save_state_dict("latest-weights", self.state_dict()) + + mesh_v_f, has_surface = self.shape_model.extract_geometry(out["latents"]) + self.save_mesh( + f"it{self.true_global_step}/{batch['uid'][0]}.obj", + mesh_v_f[0][0], mesh_v_f[0][1] + ) + + threshold = 0 + outputs = out["logits"] + labels = out["target"] + pred = torch.zeros_like(outputs) + pred[outputs>=threshold] = 1 + + accuracy = (pred==labels).float().sum(dim=1) / labels.shape[1] + accuracy = accuracy.mean() + intersection = (pred * labels).sum(dim=1) + union = (pred + labels).gt(0).sum(dim=1) + iou = intersection * 1.0 / union + 1e-5 + iou = iou.mean() + + self.log("val/accuracy", accuracy) + self.log("val/iou", iou) + + torch.cuda.empty_cache() + + return {"val/loss": out["loss_logits"], "val/accuracy": accuracy, "val/iou": iou} + + + def on_validation_epoch_end(self): + pass \ No newline at end of file diff --git a/craftsman/systems/shape_diffusion.py b/craftsman/systems/shape_diffusion.py new file mode 100755 index 0000000000000000000000000000000000000000..6a886951d1a9fca75c3b602c989834d1b11f251b --- /dev/null +++ b/craftsman/systems/shape_diffusion.py @@ -0,0 +1,391 @@ +from dataclasses import dataclass, field + +import numpy as np +import json +import copy +import torch +import torch.nn.functional as F +from skimage import measure +from einops import repeat +from tqdm import tqdm +from PIL import Image + +from diffusers import ( + DDPMScheduler, + DDIMScheduler, + UniPCMultistepScheduler, + KarrasVeScheduler, + DPMSolverMultistepScheduler +) + +import craftsman +from craftsman.systems.base import BaseSystem +from craftsman.utils.ops import generate_dense_grid_points +from craftsman.utils.misc import get_rank +from craftsman.utils.typing import * + +def compute_snr(noise_scheduler, timesteps): + """ + Computes SNR as per + https://github.com/TiankaiHang/Min-SNR-Diffusion-Training/blob/521b624bd70c67cee4bdf49225915f5945a872e3/guided_diffusion/gaussian_diffusion.py#L847-L849 + """ + alphas_cumprod = noise_scheduler.alphas_cumprod + sqrt_alphas_cumprod = alphas_cumprod**0.5 + sqrt_one_minus_alphas_cumprod = (1.0 - alphas_cumprod) ** 0.5 + + # Expand the tensors. + # Adapted from https://github.com/TiankaiHang/Min-SNR-Diffusion-Training/blob/521b624bd70c67cee4bdf49225915f5945a872e3/guided_diffusion/gaussian_diffusion.py#L1026 + sqrt_alphas_cumprod = sqrt_alphas_cumprod.to(device=timesteps.device)[timesteps].float() + while len(sqrt_alphas_cumprod.shape) < len(timesteps.shape): + sqrt_alphas_cumprod = sqrt_alphas_cumprod[..., None] + alpha = sqrt_alphas_cumprod.expand(timesteps.shape) + + sqrt_one_minus_alphas_cumprod = sqrt_one_minus_alphas_cumprod.to(device=timesteps.device)[timesteps].float() + while len(sqrt_one_minus_alphas_cumprod.shape) < len(timesteps.shape): + sqrt_one_minus_alphas_cumprod = sqrt_one_minus_alphas_cumprod[..., None] + sigma = sqrt_one_minus_alphas_cumprod.expand(timesteps.shape) + + # Compute SNR. + snr = (alpha / sigma) ** 2 + return snr + +def ddim_sample(ddim_scheduler: DDIMScheduler, + diffusion_model: torch.nn.Module, + shape: Union[List[int], Tuple[int]], + cond: torch.FloatTensor, + steps: int, + eta: float = 0.0, + guidance_scale: float = 3.0, + do_classifier_free_guidance: bool = True, + generator: Optional[torch.Generator] = None, + device: torch.device = "cuda:0", + disable_prog: bool = True): + + assert steps > 0, f"{steps} must > 0." + + # init latents + bsz = cond.shape[0] + if do_classifier_free_guidance: + bsz = bsz // 2 + + latents = torch.randn( + (bsz, *shape), + generator=generator, + device=cond.device, + dtype=cond.dtype, + ) + # scale the initial noise by the standard deviation required by the scheduler + latents = latents * ddim_scheduler.init_noise_sigma + # set timesteps + ddim_scheduler.set_timesteps(steps) + timesteps = ddim_scheduler.timesteps.to(device) + # prepare extra kwargs for the scheduler step, since not all schedulers have the same signature + # eta (η) is only used with the DDIMScheduler, and between [0, 1] + extra_step_kwargs = { + # "eta": eta, + "generator": generator + } + + # reverse + for i, t in enumerate(tqdm(timesteps, disable=disable_prog, desc="DDIM Sampling:", leave=False)): + # expand the latents if we are doing classifier free guidance + latent_model_input = ( + torch.cat([latents] * 2) + if do_classifier_free_guidance + else latents + ) + # predict the noise residual + timestep_tensor = torch.tensor([t], dtype=torch.long, device=device) + timestep_tensor = timestep_tensor.expand(latent_model_input.shape[0]) + noise_pred = diffusion_model.forward(latent_model_input, timestep_tensor, cond) + + # perform guidance + if do_classifier_free_guidance: + noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) + noise_pred = noise_pred_uncond + guidance_scale * ( + noise_pred_text - noise_pred_uncond + ) + + # compute the previous noisy sample x_t -> x_t-1 + latents = ddim_scheduler.step( + noise_pred, t, latents, **extra_step_kwargs + ).prev_sample + + yield latents, t + + +@craftsman.register("shape-diffusion-system") +class ShapeDiffusionSystem(BaseSystem): + @dataclass + class Config(BaseSystem.Config): + val_samples_json: str = None + z_scale_factor: float = 1.0 + guidance_scale: float = 7.5 + num_inference_steps: int = 50 + eta: float = 0.0 + snr_gamma: float = 5.0 + + # shape vae model + shape_model_type: str = None + shape_model: dict = field(default_factory=dict) + + # condition model + condition_model_type: str = None + condition_model: dict = field(default_factory=dict) + + # diffusion model + denoiser_model_type: str = None + denoiser_model: dict = field(default_factory=dict) + + # noise scheduler + noise_scheduler_type: str = None + noise_scheduler: dict = field(default_factory=dict) + + # denoise scheduler + denoise_scheduler_type: str = None + denoise_scheduler: dict = field(default_factory=dict) + + cfg: Config + + def configure(self): + super().configure() + + self.shape_model = craftsman.find(self.cfg.shape_model_type)(self.cfg.shape_model) + self.shape_model.eval() + self.shape_model.requires_grad_(False) + + self.condition = craftsman.find(self.cfg.condition_model_type)(self.cfg.condition_model) + + self.denoiser_model = craftsman.find(self.cfg.denoiser_model_type)(self.cfg.denoiser_model) + + self.noise_scheduler = craftsman.find(self.cfg.noise_scheduler_type)(**self.cfg.noise_scheduler) + self.denoise_scheduler = craftsman.find(self.cfg.denoise_scheduler_type)(**self.cfg.denoise_scheduler) + + self.z_scale_factor = self.cfg.z_scale_factor + + def forward(self, batch: Dict[str, Any]) -> Dict[str, Any]: + # encode shape latents + shape_embeds, kl_embed, posterior = self.shape_model.encode( + batch["surface"][..., :3 + self.cfg.shape_model.point_feats], + sample_posterior=True + ) + latents = kl_embed * self.z_scale_factor + + cond_latents = self.condition(batch) + cond_latents = cond_latents.to(latents).view(latents.shape[0], -1, cond_latents.shape[-1]) + + # Sample noise that we"ll add to the latents + # [batch_size, n_token, latent_dim] + noise = torch.randn_like(latents).to(latents) + bs = latents.shape[0] + # Sample a random timestep for each motion + timesteps = torch.randint( + 0, + self.noise_scheduler.config.num_train_timesteps, + (bs,), + device=latents.device, + ) + # import pdb; pdb.set_trace() + + timesteps = timesteps.long() + # Add noise to the latents according to the noise magnitude at each timestep + # x_t + noisy_z = self.noise_scheduler.add_noise(latents, noise, timesteps) + + # diffusion model forward + noise_pred = self.denoiser_model(noisy_z, timesteps, cond_latents) + + # compute loss + if self.noise_scheduler.config.prediction_type == "epsilon": + target = noise + elif self.noise_scheduler.config.prediction_type == "v_prediction": + target = self.noise_scheduler.get_velocity(latents, noise, timesteps) + else: + raise NotImplementedError(f"Prediction Type: {self.noise_scheduler.prediction_type} not yet supported.") + if self.cfg.snr_gamma == 0: + if self.cfg.loss.loss_type == "l1": + loss = F.l1_loss(noise_pred, target, reduction="mean") + elif self.cfg.loss.loss_type in ["mse", "l2"]: + loss = F.mse_loss(noise_pred, target, reduction="mean") + else: + raise NotImplementedError(f"Loss Type: {self.cfg.loss.loss_type} not yet supported.") + else: + # Compute loss-weights as per Section 3.4 of https://arxiv.org/abs/2303.09556. + # Since we predict the noise instead of x_0, the original formulation is slightly changed. + # This is discussed in Section 4.2 of the same paper. + snr = compute_snr(self.noise_scheduler, timesteps) + mse_loss_weights = torch.stack([snr, self.cfg.snr_gamma * torch.ones_like(timesteps)], dim=1).min( + dim=1 + )[0] + if self.noise_scheduler.config.prediction_type == "epsilon": + mse_loss_weights = mse_loss_weights / snr + elif noise_scheduler.config.prediction_type == "v_prediction": + mse_loss_weights = mse_loss_weights / (snr + 1) + + if self.cfg.loss.loss_type == "l1": + loss = F.l1_loss(noise_pred, target, reduction="none") + elif self.cfg.loss.loss_type in ["mse", "l2"]: + loss = F.mse_loss(noise_pred, target, reduction="none") + else: + raise NotImplementedError(f"Loss Type: {self.cfg.loss.loss_type} not yet supported.") + loss = loss.mean(dim=list(range(1, len(loss.shape)))) * mse_loss_weights + loss = loss.mean() + + return { + "loss_diffusion": loss, + "latents": latents, + "x_0": noisy_z, + "noise": noise, + "noise_pred": noise_pred, + "timesteps": timesteps, + } + + def training_step(self, batch, batch_idx): + out = self(batch) + + loss = 0. + for name, value in out.items(): + if name.startswith("loss_"): + self.log(f"train/{name}", value) + loss += value * self.C(self.cfg.loss[name.replace("loss_", "lambda_")]) + + for name, value in self.cfg.loss.items(): + if name.startswith("lambda_"): + self.log(f"train_params/{name}", self.C(value)) + + return {"loss": loss} + + @torch.no_grad() + def validation_step(self, batch, batch_idx): + self.eval() + + if get_rank() == 0: + sample_inputs = json.loads(open(self.cfg.val_samples_json).read()) # condition + sample_inputs_ = copy.deepcopy(sample_inputs) + sample_outputs = self.sample(sample_inputs) # list + for i, sample_output in enumerate(sample_outputs): + mesh_v_f, has_surface = self.shape_model.extract_geometry(sample_output, octree_depth=7) + for j in range(len(mesh_v_f)): + if "text" in sample_inputs_ and "image" in sample_inputs_: + name = sample_inputs_["image"][j].split("/")[-1].replace(".png", "") + elif "text" in sample_inputs_ and "mvimage" in sample_inputs_: + name = sample_inputs_["mvimages"][j][0].split("/")[-2].replace(".png", "") + elif "text" in sample_inputs_: + name = sample_inputs_["text"][j].replace(" ", "_") + elif "image" in sample_inputs_: + name = sample_inputs_["image"][j].split("/")[-1].replace(".png", "") + elif "mvimages" in sample_inputs_: + name = sample_inputs_["mvimages"][j][0].split("/")[-2].replace(".png", "") + self.save_mesh( + f"it{self.true_global_step}/{name}_{i}.obj", + mesh_v_f[j][0], mesh_v_f[j][1] + ) + + out = self(batch) + if self.global_step == 0: + latents = self.shape_model.decode(out["latents"]) + mesh_v_f, has_surface = self.shape_model.extract_geometry(latents) + self.save_mesh( + f"it{self.true_global_step}/{batch['uid'][0]}_{batch['sel_idx'][0] if 'sel_idx' in batch.keys() else 0}.obj", + mesh_v_f[0][0], mesh_v_f[0][1] + ) + # exit() + torch.cuda.empty_cache() + + return {"val/loss": out["loss_diffusion"]} + + @torch.no_grad() + def sample(self, + sample_inputs: Dict[str, Union[torch.FloatTensor, List[str]]], + sample_times: int = 1, + steps: Optional[int] = None, + guidance_scale: Optional[float] = None, + eta: float = 0.0, + return_intermediates: bool = False, + camera_embeds: Optional[torch.Tensor] = None, + seed: Optional[int] = None, + **kwargs): + + if steps is None: + steps = self.cfg.num_inference_steps + if guidance_scale is None: + guidance_scale = self.cfg.guidance_scale + do_classifier_free_guidance = guidance_scale > 0 + + # conditional encode + if "image" in sample_inputs: + sample_inputs["image"] = [Image.open(img) for img in sample_inputs["image"]] + cond = self.condition.encode_image(sample_inputs["image"]) + if do_classifier_free_guidance: + un_cond = self.condition.empty_image_embeds.repeat(len(sample_inputs["image"]), 1, 1).to(cond) + cond = torch.cat([un_cond, cond], dim=0) + elif "mvimages" in sample_inputs: # by default 4 views + bs = len(sample_inputs["mvimages"]) + cond = [] + for image in sample_inputs["mvimages"]: + if isinstance(image, list) and isinstance(image[0], str): + sample_inputs["image"] = [Image.open(img) for img in image] # List[PIL] + else: + sample_inputs["image"] = image + cond += [self.condition.encode_image(sample_inputs["image"])] + cond = torch.stack(cond, dim=0)# tensor shape 为[len(sample_inputs["mvimages"], 4*(num_latents+1), context_dim] + if do_classifier_free_guidance: + un_cond = self.condition.empty_image_embeds.unsqueeze(0).repeat(len(sample_inputs["mvimages"]), cond.shape[1] // self.condition.cfg.n_views, 1, 1).to(cond) # shape 为[len(sample_inputs["mvimages"], 4*(num_latents+1), context_dim] + cond = torch.cat([un_cond, cond], dim=0).view(bs * 2, -1, cond[0].shape[-1]) + else: + raise NotImplementedError("Only text, image or mvimages condition is supported.") + + outputs = [] + latents = None + + if seed != None: + generator = torch.Generator(device="cuda").manual_seed(seed) + else: + generator = None + + if not return_intermediates: + for _ in range(sample_times): + sample_loop = ddim_sample( + self.denoise_scheduler, + self.denoiser_model.eval(), + shape=self.shape_model.latent_shape, + cond=cond, + steps=steps, + guidance_scale=guidance_scale, + do_classifier_free_guidance=do_classifier_free_guidance, + device=self.device, + eta=eta, + disable_prog=False, + generator= generator + ) + for sample, t in sample_loop: + latents = sample + outputs.append(self.shape_model.decode(latents / self.z_scale_factor, **kwargs)) + else: + sample_loop = ddim_sample( + self.denoise_scheduler, + self.denoiser_model.eval(), + shape=self.shape_model.latent_shape, + cond=cond, + steps=steps, + guidance_scale=guidance_scale, + do_classifier_free_guidance=do_classifier_free_guidance, + device=self.device, + eta=eta, + disable_prog=False, + generator= generator + ) + + iter_size = steps // sample_times + i = 0 + for sample, t in sample_loop: + latents = sample + if i % iter_size == 0 or i == steps - 1: + outputs.append(self.shape_model.decode(latents / self.z_scale_factor, **kwargs)) + i += 1 + + return outputs + + + def on_validation_epoch_end(self): + pass diff --git a/craftsman/utils/__init__.py b/craftsman/utils/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..0e44449338cf3ff3bb3d124ef22c8f7bbca760a5 --- /dev/null +++ b/craftsman/utils/__init__.py @@ -0,0 +1 @@ +from . import base diff --git a/craftsman/utils/__pycache__/__init__.cpython-38.pyc b/craftsman/utils/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7765274149e74f3ca16da7a2960b729debc84839 Binary files /dev/null and b/craftsman/utils/__pycache__/__init__.cpython-38.pyc differ diff --git a/craftsman/utils/__pycache__/base.cpython-38.pyc b/craftsman/utils/__pycache__/base.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed161077ceb89e2861245863b9f02ce0cbcccd17 Binary files /dev/null and b/craftsman/utils/__pycache__/base.cpython-38.pyc differ diff --git a/craftsman/utils/__pycache__/checkpoint.cpython-38.pyc b/craftsman/utils/__pycache__/checkpoint.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ee1ebb32890cec380dd6b2b3fd8987271d7c815 Binary files /dev/null and b/craftsman/utils/__pycache__/checkpoint.cpython-38.pyc differ diff --git a/craftsman/utils/__pycache__/config.cpython-38.pyc b/craftsman/utils/__pycache__/config.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7db49bd24586bd16ba959a3abf0b52a9aed90e5f Binary files /dev/null and b/craftsman/utils/__pycache__/config.cpython-38.pyc differ diff --git a/craftsman/utils/__pycache__/misc.cpython-38.pyc b/craftsman/utils/__pycache__/misc.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..321ba2bb63158527d754576d0901062c56cbe0a0 Binary files /dev/null and b/craftsman/utils/__pycache__/misc.cpython-38.pyc differ diff --git a/craftsman/utils/__pycache__/ops.cpython-38.pyc b/craftsman/utils/__pycache__/ops.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2eca9760971a93e8744184314781d05aecd5bb14 Binary files /dev/null and b/craftsman/utils/__pycache__/ops.cpython-38.pyc differ diff --git a/craftsman/utils/__pycache__/saving.cpython-38.pyc b/craftsman/utils/__pycache__/saving.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f18acb05a059c37e691d02e99b684e268394a30d Binary files /dev/null and b/craftsman/utils/__pycache__/saving.cpython-38.pyc differ diff --git a/craftsman/utils/__pycache__/scheduler.cpython-38.pyc b/craftsman/utils/__pycache__/scheduler.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fea013c3f079bdd852119f654f88f1cd24851939 Binary files /dev/null and b/craftsman/utils/__pycache__/scheduler.cpython-38.pyc differ diff --git a/craftsman/utils/__pycache__/typing.cpython-38.pyc b/craftsman/utils/__pycache__/typing.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a4b821005a73f47532a0d7a0d38b0230612b4e8 Binary files /dev/null and b/craftsman/utils/__pycache__/typing.cpython-38.pyc differ diff --git a/craftsman/utils/base.py b/craftsman/utils/base.py new file mode 100755 index 0000000000000000000000000000000000000000..2fa680e1a683beb47f254f74e5133c86da2ca8eb --- /dev/null +++ b/craftsman/utils/base.py @@ -0,0 +1,118 @@ +from dataclasses import dataclass + +import torch +import torch.nn as nn + +from craftsman.utils.config import parse_structured +from craftsman.utils.misc import get_device, load_module_weights +from craftsman.utils.typing import * + + +class Configurable: + @dataclass + class Config: + pass + + def __init__(self, cfg: Optional[dict] = None) -> None: + super().__init__() + self.cfg = parse_structured(self.Config, cfg) + + +class Updateable: + def do_update_step( + self, epoch: int, global_step: int, on_load_weights: bool = False + ): + for attr in self.__dir__(): + if attr.startswith("_"): + continue + try: + module = getattr(self, attr) + except: + continue # ignore attributes like property, which can't be retrived using getattr? + if isinstance(module, Updateable): + module.do_update_step( + epoch, global_step, on_load_weights=on_load_weights + ) + self.update_step(epoch, global_step, on_load_weights=on_load_weights) + + def do_update_step_end(self, epoch: int, global_step: int): + for attr in self.__dir__(): + if attr.startswith("_"): + continue + try: + module = getattr(self, attr) + except: + continue # ignore attributes like property, which can't be retrived using getattr? + if isinstance(module, Updateable): + module.do_update_step_end(epoch, global_step) + self.update_step_end(epoch, global_step) + + def update_step(self, epoch: int, global_step: int, on_load_weights: bool = False): + # override this method to implement custom update logic + # if on_load_weights is True, you should be careful doing things related to model evaluations, + # as the models and tensors are not guarenteed to be on the same device + pass + + def update_step_end(self, epoch: int, global_step: int): + pass + + +def update_if_possible(module: Any, epoch: int, global_step: int) -> None: + if isinstance(module, Updateable): + module.do_update_step(epoch, global_step) + + +def update_end_if_possible(module: Any, epoch: int, global_step: int) -> None: + if isinstance(module, Updateable): + module.do_update_step_end(epoch, global_step) + + +class BaseObject(Updateable): + @dataclass + class Config: + pass + + cfg: Config # add this to every subclass of BaseObject to enable static type checking + + def __init__( + self, cfg: Optional[Union[dict, DictConfig]] = None, *args, **kwargs + ) -> None: + super().__init__() + self.cfg = parse_structured(self.Config, cfg) + self.device = get_device() + self.configure(*args, **kwargs) + + def configure(self, *args, **kwargs) -> None: + pass + + +class BaseModule(nn.Module, Updateable): + @dataclass + class Config: + weights: Optional[str] = None + + cfg: Config # add this to every subclass of BaseModule to enable static type checking + + def __init__( + self, cfg: Optional[Union[dict, DictConfig]] = None, *args, **kwargs + ) -> None: + super().__init__() + self.cfg = parse_structured(self.Config, cfg) + self.device = get_device() + self.configure(*args, **kwargs) + if self.cfg.weights is not None: + # format: path/to/weights:module_name + weights_path, module_name = self.cfg.weights.split(":") + state_dict, epoch, global_step = load_module_weights( + weights_path, module_name=module_name, map_location="cpu" + ) + self.load_state_dict(state_dict) + self.do_update_step( + epoch, global_step, on_load_weights=True + ) # restore states + # dummy tensor to indicate model state + self._dummy: Float[Tensor, "..."] + self.register_buffer("_dummy", torch.zeros(0).float(), persistent=False) + + def configure(self, *args, **kwargs) -> None: + pass diff --git a/craftsman/utils/callbacks.py b/craftsman/utils/callbacks.py new file mode 100755 index 0000000000000000000000000000000000000000..c0382c56d4a11ce1f6627324cf082aca74b32f05 --- /dev/null +++ b/craftsman/utils/callbacks.py @@ -0,0 +1,156 @@ +import os +import shutil +import subprocess + +import pytorch_lightning + +from craftsman.utils.config import dump_config +from craftsman.utils.misc import parse_version + +if parse_version(pytorch_lightning.__version__) > parse_version("1.8"): + from pytorch_lightning.callbacks import Callback +else: + from pytorch_lightning.callbacks.base import Callback + +from pytorch_lightning.callbacks.progress import TQDMProgressBar +from pytorch_lightning.utilities.rank_zero import rank_zero_only, rank_zero_warn + + +class VersionedCallback(Callback): + def __init__(self, save_root, version=None, use_version=True): + self.save_root = save_root + self._version = version + self.use_version = use_version + + @property + def version(self) -> int: + """Get the experiment version. + + Returns: + The experiment version if specified else the next version. + """ + if self._version is None: + self._version = self._get_next_version() + return self._version + + def _get_next_version(self): + existing_versions = [] + if os.path.isdir(self.save_root): + for f in os.listdir(self.save_root): + bn = os.path.basename(f) + if bn.startswith("version_"): + dir_ver = os.path.splitext(bn)[0].split("_")[1].replace("/", "") + existing_versions.append(int(dir_ver)) + if len(existing_versions) == 0: + return 0 + return max(existing_versions) + 1 + + @property + def savedir(self): + if not self.use_version: + return self.save_root + return os.path.join( + self.save_root, + self.version + if isinstance(self.version, str) + else f"version_{self.version}", + ) + + +class CodeSnapshotCallback(VersionedCallback): + def __init__(self, save_root, version=None, use_version=True): + super().__init__(save_root, version, use_version) + + def get_file_list(self): + return [ + b.decode() + for b in set( + subprocess.check_output( + 'git ls-files -- ":!:load/*"', shell=True + ).splitlines() + ) + | set( # hard code, TODO: use config to exclude folders or files + subprocess.check_output( + "git ls-files --others --exclude-standard", shell=True + ).splitlines() + ) + ] + + @rank_zero_only + def save_code_snapshot(self): + os.makedirs(self.savedir, exist_ok=True) + for f in self.get_file_list(): + if not os.path.exists(f) or os.path.isdir(f): + continue + os.makedirs(os.path.join(self.savedir, os.path.dirname(f)), exist_ok=True) + shutil.copyfile(f, os.path.join(self.savedir, f)) + + def on_fit_start(self, trainer, pl_module): + try: + self.save_code_snapshot() + except: + rank_zero_warn( + "Code snapshot is not saved. Please make sure you have git installed and are in a git repository." + ) + + +class ConfigSnapshotCallback(VersionedCallback): + def __init__(self, config_path, config, save_root, version=None, use_version=True): + super().__init__(save_root, version, use_version) + self.config_path = config_path + self.config = config + + @rank_zero_only + def save_config_snapshot(self): + os.makedirs(self.savedir, exist_ok=True) + dump_config(os.path.join(self.savedir, "parsed.yaml"), self.config) + shutil.copyfile(self.config_path, os.path.join(self.savedir, "raw.yaml")) + + def on_fit_start(self, trainer, pl_module): + self.save_config_snapshot() + + +class CustomProgressBar(TQDMProgressBar): + def get_metrics(self, *args, **kwargs): + # don't show the version number + items = super().get_metrics(*args, **kwargs) + items.pop("v_num", None) + return items + + +class ProgressCallback(Callback): + def __init__(self, save_path): + super().__init__() + self.save_path = save_path + self._file_handle = None + + @property + def file_handle(self): + if self._file_handle is None: + self._file_handle = open(self.save_path, "w") + return self._file_handle + + @rank_zero_only + def write(self, msg: str) -> None: + self.file_handle.seek(0) + self.file_handle.truncate() + self.file_handle.write(msg) + self.file_handle.flush() + + @rank_zero_only + def on_train_batch_end(self, trainer, pl_module, *args, **kwargs): + self.write( + f"Generation progress: {pl_module.true_global_step / trainer.max_steps * 100:.2f}%" + ) + + @rank_zero_only + def on_validation_start(self, trainer, pl_module): + self.write(f"Rendering validation image ...") + + @rank_zero_only + def on_test_start(self, trainer, pl_module): + self.write(f"Rendering video ...") + + @rank_zero_only + def on_predict_start(self, trainer, pl_module): + self.write(f"Exporting mesh assets ...") diff --git a/craftsman/utils/checkpoint.py b/craftsman/utils/checkpoint.py new file mode 100755 index 0000000000000000000000000000000000000000..363e2bf9ab23bfcabe5008f7ba40aee6b5b84f2a --- /dev/null +++ b/craftsman/utils/checkpoint.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +""" +Adapted from: https://github.com/openai/guided-diffusion/blob/22e0df8183507e13a7813f8d38d51b072ca1e67c/guided_diffusion/nn.py#L124 +""" + +import torch +from craftsman.utils.typing import * + +def checkpoint( + func: Callable[..., Union[torch.Tensor, Sequence[torch.Tensor]]], + inputs: Sequence[torch.Tensor], + params: Iterable[torch.Tensor], + flag: bool, + use_deepspeed: bool = False +): + """ + Evaluate a function without caching intermediate activations, allowing for + reduced memory at the expense of extra compute in the backward pass. + :param func: the function to evaluate. + :param inputs: the argument sequence to pass to `func`. + :param params: a sequence of parameters `func` depends on but does not + explicitly take as arguments. + :param flag: if False, disable gradient checkpointing. + :param use_deepspeed: if True, use deepspeed + """ + if flag: + if use_deepspeed: + import deepspeed + return deepspeed.checkpointing.checkpoint(func, *inputs) + + args = tuple(inputs) + tuple(params) + return CheckpointFunction.apply(func, len(inputs), *args) + else: + return func(*inputs) + + +class CheckpointFunction(torch.autograd.Function): + @staticmethod + @torch.cuda.amp.custom_fwd + def forward(ctx, run_function, length, *args): + ctx.run_function = run_function + ctx.input_tensors = list(args[:length]) + ctx.input_params = list(args[length:]) + + with torch.no_grad(): + output_tensors = ctx.run_function(*ctx.input_tensors) + return output_tensors + + @staticmethod + @torch.cuda.amp.custom_bwd + def backward(ctx, *output_grads): + ctx.input_tensors = [x.detach().requires_grad_(True) for x in ctx.input_tensors] + with torch.enable_grad(): + # Fixes a bug where the first op in run_function modifies the + # Tensor storage in place, which is not allowed for detach()'d + # Tensors. + shallow_copies = [x.view_as(x) for x in ctx.input_tensors] + output_tensors = ctx.run_function(*shallow_copies) + input_grads = torch.autograd.grad( + output_tensors, + ctx.input_tensors + ctx.input_params, + output_grads, + allow_unused=True, + ) + del ctx.input_tensors + del ctx.input_params + del output_tensors + return (None, None) + input_grads \ No newline at end of file diff --git a/craftsman/utils/config.py b/craftsman/utils/config.py new file mode 100755 index 0000000000000000000000000000000000000000..c2fc56ef8bce2c6580f849c524f20d6ee5912938 --- /dev/null +++ b/craftsman/utils/config.py @@ -0,0 +1,128 @@ +import os +from dataclasses import dataclass, field +from datetime import datetime + +from omegaconf import OmegaConf + +import craftsman +from craftsman.utils.typing import * + +# ============ Register OmegaConf Recolvers ============= # +OmegaConf.register_new_resolver( + "calc_exp_lr_decay_rate", lambda factor, n: factor ** (1.0 / n) +) +OmegaConf.register_new_resolver("add", lambda a, b: a + b) +OmegaConf.register_new_resolver("sub", lambda a, b: a - b) +OmegaConf.register_new_resolver("mul", lambda a, b: a * b) +OmegaConf.register_new_resolver("div", lambda a, b: a / b) +OmegaConf.register_new_resolver("idiv", lambda a, b: a // b) +OmegaConf.register_new_resolver("basename", lambda p: os.path.basename(p)) +OmegaConf.register_new_resolver("rmspace", lambda s, sub: str(s).replace(" ", sub)) +OmegaConf.register_new_resolver("tuple2", lambda s: [float(s), float(s)]) +OmegaConf.register_new_resolver("gt0", lambda s: s > 0) +OmegaConf.register_new_resolver("cmaxgt0", lambda s: C_max(s) > 0) +OmegaConf.register_new_resolver("not", lambda s: not s) +OmegaConf.register_new_resolver( + "cmaxgt0orcmaxgt0", lambda a, b: C_max(a) > 0 or C_max(b) > 0 +) +# ======================================================= # + + +def C_max(value: Any) -> float: + if isinstance(value, int) or isinstance(value, float): + pass + else: + value = config_to_primitive(value) + if not isinstance(value, list): + raise TypeError("Scalar specification only supports list, got", type(value)) + if len(value) >= 6: + max_value = value[2] + for i in range(4, len(value), 2): + max_value = max(max_value, value[i]) + value = [value[0], value[1], max_value, value[3]] + if len(value) == 3: + value = [0] + value + assert len(value) == 4 + start_step, start_value, end_value, end_step = value + value = max(start_value, end_value) + return value + + +@dataclass +class ExperimentConfig: + name: str = "default" + description: str = "" + tag: str = "" + seed: int = 0 + use_timestamp: bool = True + timestamp: Optional[str] = None + exp_root_dir: str = "outputs" + + ### these shouldn't be set manually + exp_dir: str = "outputs/default" + trial_name: str = "exp" + trial_dir: str = "outputs/default/exp" + n_gpus: int = 1 + ### + + resume: Optional[str] = None + + data_type: str = "" + data: dict = field(default_factory=dict) + + system_type: str = "" + system: dict = field(default_factory=dict) + + # accept pytorch-lightning trainer parameters + # see https://lightning.ai/docs/pytorch/stable/common/trainer.html#trainer-class-api + trainer: dict = field(default_factory=dict) + + # accept pytorch-lightning checkpoint callback parameters + # see https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.callbacks.ModelCheckpoint.html#modelcheckpoint + checkpoint: dict = field(default_factory=dict) + + def __post_init__(self): + if not self.tag and not self.use_timestamp: + raise ValueError("Either tag is specified or use_timestamp is True.") + self.trial_name = self.tag + # if resume from an existing config, self.timestamp should not be None + if self.timestamp is None: + self.timestamp = "" + if self.use_timestamp: + if self.n_gpus > 1: + craftsman.warn( + "Timestamp is disabled when using multiple GPUs, please make sure you have a unique tag." + ) + else: + self.timestamp = datetime.now().strftime("@%Y%m%d-%H%M%S") + self.trial_name += self.timestamp + self.exp_dir = os.path.join(self.exp_root_dir, self.name) + self.trial_dir = os.path.join(self.exp_dir, self.trial_name) + os.makedirs(self.trial_dir, exist_ok=True) + + +def load_config(*yamls: str, cli_args: list = [], from_string=False, **kwargs) -> Any: + if from_string: + yaml_confs = [OmegaConf.create(s) for s in yamls] + else: + yaml_confs = [OmegaConf.load(f) for f in yamls] + cli_conf = OmegaConf.from_cli(cli_args) + cfg = OmegaConf.merge(*yaml_confs, cli_conf, kwargs) + OmegaConf.resolve(cfg) + assert isinstance(cfg, DictConfig) + scfg = parse_structured(ExperimentConfig, cfg) + return scfg + + +def config_to_primitive(config, resolve: bool = True) -> Any: + return OmegaConf.to_container(config, resolve=resolve) + + +def dump_config(path: str, config) -> None: + with open(path, "w") as fp: + OmegaConf.save(config=config, f=fp) + + +def parse_structured(fields: Any, cfg: Optional[Union[dict, DictConfig]] = None) -> Any: + scfg = OmegaConf.structured(fields(**cfg)) + return scfg \ No newline at end of file diff --git a/craftsman/utils/misc.py b/craftsman/utils/misc.py new file mode 100755 index 0000000000000000000000000000000000000000..732835e7f4d2dba74a22c34f876ef4762db754e3 --- /dev/null +++ b/craftsman/utils/misc.py @@ -0,0 +1,168 @@ +import gc +import os +import re + +import torch +import torch.distributed as dist +from packaging import version + +from craftsman.utils.config import config_to_primitive +from craftsman.utils.typing import * + + + +def parse_version(ver: str): + return version.parse(ver) + + +def get_rank(): + # SLURM_PROCID can be set even if SLURM is not managing the multiprocessing, + # therefore LOCAL_RANK needs to be checked first + rank_keys = ("RANK", "LOCAL_RANK", "SLURM_PROCID", "JSM_NAMESPACE_RANK") + for key in rank_keys: + rank = os.environ.get(key) + if rank is not None: + return int(rank) + return 0 + +def get_world_size(): + world_size_keys = ("WORLD_SIZE", "SLURM_NTASKS", "JSM_NAMESPACE_SIZE") + for key in world_size_keys: + world_size = os.environ.get(key) + if world_size is not None: + return int(world_size) + return 1 + +def get_device(): + return torch.device(f"cuda:{get_rank()}") + + +def load_module_weights( + path, module_name=None, ignore_modules=None, map_location=None +) -> Tuple[dict, int, int]: + if module_name is not None and ignore_modules is not None: + raise ValueError("module_name and ignore_modules cannot be both set") + if map_location is None: + map_location = get_device() + + ckpt = torch.load(path, map_location=map_location) + state_dict = ckpt["state_dict"] + state_dict_to_load = state_dict + + if ignore_modules is not None: + state_dict_to_load = {} + for k, v in state_dict.items(): + ignore = any( + [k.startswith(ignore_module + ".") for ignore_module in ignore_modules] + ) + if ignore: + continue + state_dict_to_load[k] = v + + if module_name is not None: + state_dict_to_load = {} + for k, v in state_dict.items(): + m = re.match(rf"^{module_name}\.(.*)$", k) + if m is None: + continue + state_dict_to_load[m.group(1)] = v + + return state_dict_to_load, ckpt["epoch"], ckpt["global_step"] + + +def C(value: Any, epoch: int, global_step: int) -> float: + if isinstance(value, int) or isinstance(value, float): + pass + else: + value = config_to_primitive(value) + if not isinstance(value, list): + raise TypeError("Scalar specification only supports list, got", type(value)) + if len(value) == 3: + value = [0] + value + assert len(value) == 4 + start_step, start_value, end_value, end_step = value + if isinstance(end_step, int): + current_step = global_step + value = start_value + (end_value - start_value) * max( + min(1.0, (current_step - start_step) / (end_step - start_step)), 0.0 + ) + elif isinstance(end_step, float): + current_step = epoch + value = start_value + (end_value - start_value) * max( + min(1.0, (current_step - start_step) / (end_step - start_step)), 0.0 + ) + return value + + +def cleanup(): + gc.collect() + torch.cuda.empty_cache() + tcnn.free_temporary_memory() + + +def finish_with_cleanup(func: Callable): + def wrapper(*args, **kwargs): + out = func(*args, **kwargs) + cleanup() + return out + + return wrapper + + +def _distributed_available(): + return torch.distributed.is_available() and torch.distributed.is_initialized() + + +def barrier(): + if not _distributed_available(): + return + else: + torch.distributed.barrier() + + +def broadcast(tensor, src=0): + if not _distributed_available(): + return tensor + else: + torch.distributed.broadcast(tensor, src=src) + return tensor + + +def enable_gradient(model, enabled: bool = True) -> None: + for param in model.parameters(): + param.requires_grad_(enabled) + + +def all_gather_batch(tensors): + """ + Performs all_gather operation on the provided tensors. + """ + # Queue the gathered tensors + world_size = get_world_size() + # There is no need for reduction in the single-proc case + if world_size == 1: + if isinstance(tensors, list): + return tensors + return tensors + if not isinstance(tensors, list): + is_list = False + tensors = [tensors] + else: + is_list = True + output_tensor = [] + tensor_list = [] + for tensor in tensors: + tensor_all = [torch.ones_like(tensor) for _ in range(world_size)] + dist.all_gather( + tensor_all, + tensor, + async_op=False # performance opt + ) + + tensor_list.append(tensor_all) + + for tensor_all in tensor_list: + output_tensor.append(torch.cat(tensor_all, dim=0)) + if not is_list: + return output_tensor[0] + return output_tensor \ No newline at end of file diff --git a/craftsman/utils/ops.py b/craftsman/utils/ops.py new file mode 100755 index 0000000000000000000000000000000000000000..ad29b85540c1fef6cce28b380fdd7b1473a50cc0 --- /dev/null +++ b/craftsman/utils/ops.py @@ -0,0 +1,169 @@ +import math +from collections import defaultdict + +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +import craftsman +from craftsman.utils.typing import * + + +def dot(x, y): + return torch.sum(x * y, -1, keepdim=True) + + +def reflect(x, n): + return 2 * dot(x, n) * n - x + + +ValidScale = Union[Tuple[float, float], Num[Tensor, "2 D"]] + + +def scale_tensor( + dat: Num[Tensor, "... D"], inp_scale: ValidScale, tgt_scale: ValidScale +): + if inp_scale is None: + inp_scale = (0, 1) + if tgt_scale is None: + tgt_scale = (0, 1) + if isinstance(tgt_scale, Tensor): + assert dat.shape[-1] == tgt_scale.shape[-1] + dat = (dat - inp_scale[0]) / (inp_scale[1] - inp_scale[0]) + dat = dat * (tgt_scale[1] - tgt_scale[0]) + tgt_scale[0] + return dat + + +def chunk_batch(func: Callable, chunk_size: int, *args, **kwargs) -> Any: + if chunk_size <= 0: + return func(*args, **kwargs) + B = None + for arg in list(args) + list(kwargs.values()): + if isinstance(arg, torch.Tensor): + B = arg.shape[0] + break + assert ( + B is not None + ), "No tensor found in args or kwargs, cannot determine batch size." + out = defaultdict(list) + out_type = None + # max(1, B) to support B == 0 + for i in range(0, max(1, B), chunk_size): + out_chunk = func( + *[ + arg[i : i + chunk_size] if isinstance(arg, torch.Tensor) else arg + for arg in args + ], + **{ + k: arg[i : i + chunk_size] if isinstance(arg, torch.Tensor) else arg + for k, arg in kwargs.items() + }, + ) + if out_chunk is None: + continue + out_type = type(out_chunk) + if isinstance(out_chunk, torch.Tensor): + out_chunk = {0: out_chunk} + elif isinstance(out_chunk, tuple) or isinstance(out_chunk, list): + chunk_length = len(out_chunk) + out_chunk = {i: chunk for i, chunk in enumerate(out_chunk)} + elif isinstance(out_chunk, dict): + pass + else: + print( + f"Return value of func must be in type [torch.Tensor, list, tuple, dict], get {type(out_chunk)}." + ) + exit(1) + for k, v in out_chunk.items(): + v = v if torch.is_grad_enabled() else v.detach() + out[k].append(v) + + if out_type is None: + return None + + out_merged: Dict[Any, Optional[torch.Tensor]] = {} + for k, v in out.items(): + if all([vv is None for vv in v]): + # allow None in return value + out_merged[k] = None + elif all([isinstance(vv, torch.Tensor) for vv in v]): + out_merged[k] = torch.cat(v, dim=0) + else: + raise TypeError( + f"Unsupported types in return value of func: {[type(vv) for vv in v if not isinstance(vv, torch.Tensor)]}" + ) + + if out_type is torch.Tensor: + return out_merged[0] + elif out_type in [tuple, list]: + return out_type([out_merged[i] for i in range(chunk_length)]) + elif out_type is dict: + return out_merged + + +def randn_tensor( + shape: Union[Tuple, List], + generator: Optional[Union[List["torch.Generator"], "torch.Generator"]] = None, + device: Optional["torch.device"] = None, + dtype: Optional["torch.dtype"] = None, + layout: Optional["torch.layout"] = None, +): + """A helper function to create random tensors on the desired `device` with the desired `dtype`. When + passing a list of generators, you can seed each batch size individually. If CPU generators are passed, the tensor + is always created on the CPU. + """ + # device on which tensor is created defaults to device + rand_device = device + batch_size = shape[0] + + layout = layout or torch.strided + device = device or torch.device("cpu") + + if generator is not None: + gen_device_type = generator.device.type if not isinstance(generator, list) else generator[0].device.type + if gen_device_type != device.type and gen_device_type == "cpu": + rand_device = "cpu" + if device != "mps": + logger.info( + f"The passed generator was created on 'cpu' even though a tensor on {device} was expected." + f" Tensors will be created on 'cpu' and then moved to {device}. Note that one can probably" + f" slighly speed up this function by passing a generator that was created on the {device} device." + ) + elif gen_device_type != device.type and gen_device_type == "cuda": + raise ValueError(f"Cannot generate a {device} tensor from a generator of type {gen_device_type}.") + + # make sure generator list of length 1 is treated like a non-list + if isinstance(generator, list) and len(generator) == 1: + generator = generator[0] + + if isinstance(generator, list): + shape = (1,) + shape[1:] + latents = [ + torch.randn(shape, generator=generator[i], device=rand_device, dtype=dtype, layout=layout) + for i in range(batch_size) + ] + latents = torch.cat(latents, dim=0).to(device) + else: + latents = torch.randn(shape, generator=generator, device=rand_device, dtype=dtype, layout=layout).to(device) + + return latents + + +def generate_dense_grid_points( + bbox_min: np.ndarray, + bbox_max: np.ndarray, + octree_depth: int, + indexing: str = "ij" +): + length = bbox_max - bbox_min + num_cells = np.exp2(octree_depth) + x = np.linspace(bbox_min[0], bbox_max[0], int(num_cells) + 1, dtype=np.float32) + y = np.linspace(bbox_min[1], bbox_max[1], int(num_cells) + 1, dtype=np.float32) + z = np.linspace(bbox_min[2], bbox_max[2], int(num_cells) + 1, dtype=np.float32) + [xs, ys, zs] = np.meshgrid(x, y, z, indexing=indexing) + xyz = np.stack((xs, ys, zs), axis=-1) + xyz = xyz.reshape(-1, 3) + grid_size = [int(num_cells) + 1, int(num_cells) + 1, int(num_cells) + 1] + + return xyz, grid_size, length \ No newline at end of file diff --git a/craftsman/utils/saving.py b/craftsman/utils/saving.py new file mode 100755 index 0000000000000000000000000000000000000000..3f20a0dbf4c188f6efdac7d585be0480b79fdca4 --- /dev/null +++ b/craftsman/utils/saving.py @@ -0,0 +1,653 @@ +import json +import os +import re +import shutil + +import cv2 +import imageio +import matplotlib.pyplot as plt +import numpy as np +import torch +import trimesh +import wandb +from matplotlib import cm +from matplotlib.colors import LinearSegmentedColormap +from PIL import Image, ImageDraw +from pytorch_lightning.loggers import WandbLogger + +from craftsman.models.geometry.utils import Mesh +from craftsman.utils.typing import * + + +class SaverMixin: + _save_dir: Optional[str] = None + _wandb_logger: Optional[WandbLogger] = None + + def set_save_dir(self, save_dir: str): + self._save_dir = save_dir + + def get_save_dir(self): + if self._save_dir is None: + raise ValueError("Save dir is not set") + return self._save_dir + + def convert_data(self, data): + if data is None: + return None + elif isinstance(data, np.ndarray): + return data + elif isinstance(data, torch.Tensor): + return data.detach().cpu().numpy() + elif isinstance(data, list): + return [self.convert_data(d) for d in data] + elif isinstance(data, dict): + return {k: self.convert_data(v) for k, v in data.items()} + else: + raise TypeError( + "Data must be in type numpy.ndarray, torch.Tensor, list or dict, getting", + type(data), + ) + + def get_save_path(self, filename): + save_path = os.path.join(self.get_save_dir(), filename) + os.makedirs(os.path.dirname(save_path), exist_ok=True) + return save_path + + def create_loggers(self, cfg_loggers: DictConfig) -> None: + if "wandb" in cfg_loggers.keys() and cfg_loggers.wandb.enable: + self._wandb_logger = WandbLogger( + project=cfg_loggers.wandb.project, name=cfg_loggers.wandb.name + ) + + def get_loggers(self) -> List: + if self._wandb_logger: + return [self._wandb_logger] + else: + return [] + + DEFAULT_RGB_KWARGS = {"data_format": "HWC", "data_range": (0, 1)} + DEFAULT_UV_KWARGS = { + "data_format": "HWC", + "data_range": (0, 1), + "cmap": "checkerboard", + } + DEFAULT_GRAYSCALE_KWARGS = {"data_range": None, "cmap": "jet"} + DEFAULT_GRID_KWARGS = {"align": "max"} + + def get_rgb_image_(self, img, data_format, data_range, rgba=False): + img = self.convert_data(img) + assert data_format in ["CHW", "HWC"] + if data_format == "CHW": + img = img.transpose(1, 2, 0) + if img.dtype != np.uint8: + img = img.clip(min=data_range[0], max=data_range[1]) + img = ( + (img - data_range[0]) / (data_range[1] - data_range[0]) * 255.0 + ).astype(np.uint8) + nc = 4 if rgba else 3 + imgs = [img[..., start : start + nc] for start in range(0, img.shape[-1], nc)] + imgs = [ + img_ + if img_.shape[-1] == nc + else np.concatenate( + [ + img_, + np.zeros( + (img_.shape[0], img_.shape[1], nc - img_.shape[2]), + dtype=img_.dtype, + ), + ], + axis=-1, + ) + for img_ in imgs + ] + img = np.concatenate(imgs, axis=1) + if rgba: + img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA) + else: + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + return img + + def _save_rgb_image( + self, + filename, + img, + data_format, + data_range, + name: Optional[str] = None, + step: Optional[int] = None, + ): + img = self.get_rgb_image_(img, data_format, data_range) + cv2.imwrite(filename, img) + if name and self._wandb_logger: + wandb.log( + { + name: wandb.Image(self.get_save_path(filename)), + "trainer/global_step": step, + } + ) + + def save_rgb_image( + self, + filename, + img, + data_format=DEFAULT_RGB_KWARGS["data_format"], + data_range=DEFAULT_RGB_KWARGS["data_range"], + name: Optional[str] = None, + step: Optional[int] = None, + ) -> str: + save_path = self.get_save_path(filename) + self._save_rgb_image(save_path, img, data_format, data_range, name, step) + return save_path + + def get_uv_image_(self, img, data_format, data_range, cmap): + img = self.convert_data(img) + assert data_format in ["CHW", "HWC"] + if data_format == "CHW": + img = img.transpose(1, 2, 0) + img = img.clip(min=data_range[0], max=data_range[1]) + img = (img - data_range[0]) / (data_range[1] - data_range[0]) + assert cmap in ["checkerboard", "color"] + if cmap == "checkerboard": + n_grid = 64 + mask = (img * n_grid).astype(int) + mask = (mask[..., 0] + mask[..., 1]) % 2 == 0 + img = np.ones((img.shape[0], img.shape[1], 3), dtype=np.uint8) * 255 + img[mask] = np.array([255, 0, 255], dtype=np.uint8) + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + elif cmap == "color": + img_ = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8) + img_[..., 0] = (img[..., 0] * 255).astype(np.uint8) + img_[..., 1] = (img[..., 1] * 255).astype(np.uint8) + img_ = cv2.cvtColor(img_, cv2.COLOR_RGB2BGR) + img = img_ + return img + + def save_uv_image( + self, + filename, + img, + data_format=DEFAULT_UV_KWARGS["data_format"], + data_range=DEFAULT_UV_KWARGS["data_range"], + cmap=DEFAULT_UV_KWARGS["cmap"], + ) -> str: + save_path = self.get_save_path(filename) + img = self.get_uv_image_(img, data_format, data_range, cmap) + cv2.imwrite(save_path, img) + return save_path + + def get_grayscale_image_(self, img, data_range, cmap): + img = self.convert_data(img) + img = np.nan_to_num(img) + if data_range is None: + img = (img - img.min()) / (img.max() - img.min()) + else: + img = img.clip(data_range[0], data_range[1]) + img = (img - data_range[0]) / (data_range[1] - data_range[0]) + assert cmap in [None, "jet", "magma", "spectral"] + if cmap == None: + img = (img * 255.0).astype(np.uint8) + img = np.repeat(img[..., None], 3, axis=2) + elif cmap == "jet": + img = (img * 255.0).astype(np.uint8) + img = cv2.applyColorMap(img, cv2.COLORMAP_JET) + elif cmap == "magma": + img = 1.0 - img + base = cm.get_cmap("magma") + num_bins = 256 + colormap = LinearSegmentedColormap.from_list( + f"{base.name}{num_bins}", base(np.linspace(0, 1, num_bins)), num_bins + )(np.linspace(0, 1, num_bins))[:, :3] + a = np.floor(img * 255.0) + b = (a + 1).clip(max=255.0) + f = img * 255.0 - a + a = a.astype(np.uint16).clip(0, 255) + b = b.astype(np.uint16).clip(0, 255) + img = colormap[a] + (colormap[b] - colormap[a]) * f[..., None] + img = (img * 255.0).astype(np.uint8) + elif cmap == "spectral": + colormap = plt.get_cmap("Spectral") + + def blend_rgba(image): + image = image[..., :3] * image[..., -1:] + ( + 1.0 - image[..., -1:] + ) # blend A to RGB + return image + + img = colormap(img) + img = blend_rgba(img) + img = (img * 255).astype(np.uint8) + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + return img + + def _save_grayscale_image( + self, + filename, + img, + data_range, + cmap, + name: Optional[str] = None, + step: Optional[int] = None, + ): + img = self.get_grayscale_image_(img, data_range, cmap) + cv2.imwrite(filename, img) + if name and self._wandb_logger: + wandb.log( + { + name: wandb.Image(self.get_save_path(filename)), + "trainer/global_step": step, + } + ) + + def save_grayscale_image( + self, + filename, + img, + data_range=DEFAULT_GRAYSCALE_KWARGS["data_range"], + cmap=DEFAULT_GRAYSCALE_KWARGS["cmap"], + name: Optional[str] = None, + step: Optional[int] = None, + ) -> str: + save_path = self.get_save_path(filename) + self._save_grayscale_image(save_path, img, data_range, cmap, name, step) + return save_path + + def get_image_grid_(self, imgs, align): + if isinstance(imgs[0], list): + return np.concatenate( + [self.get_image_grid_(row, align) for row in imgs], axis=0 + ) + cols = [] + for col in imgs: + assert col["type"] in ["rgb", "uv", "grayscale"] + if col["type"] == "rgb": + rgb_kwargs = self.DEFAULT_RGB_KWARGS.copy() + rgb_kwargs.update(col["kwargs"]) + cols.append(self.get_rgb_image_(col["img"], **rgb_kwargs)) + elif col["type"] == "uv": + uv_kwargs = self.DEFAULT_UV_KWARGS.copy() + uv_kwargs.update(col["kwargs"]) + cols.append(self.get_uv_image_(col["img"], **uv_kwargs)) + elif col["type"] == "grayscale": + grayscale_kwargs = self.DEFAULT_GRAYSCALE_KWARGS.copy() + grayscale_kwargs.update(col["kwargs"]) + cols.append(self.get_grayscale_image_(col["img"], **grayscale_kwargs)) + + if align == "max": + h = max([col.shape[0] for col in cols]) + w = max([col.shape[1] for col in cols]) + elif align == "min": + h = min([col.shape[0] for col in cols]) + w = min([col.shape[1] for col in cols]) + elif isinstance(align, int): + h = align + w = align + elif ( + isinstance(align, tuple) + and isinstance(align[0], int) + and isinstance(align[1], int) + ): + h, w = align + else: + raise ValueError( + f"Unsupported image grid align: {align}, should be min, max, int or (int, int)" + ) + + for i in range(len(cols)): + if cols[i].shape[0] != h or cols[i].shape[1] != w: + cols[i] = cv2.resize(cols[i], (w, h), interpolation=cv2.INTER_LINEAR) + return np.concatenate(cols, axis=1) + + def save_image_grid( + self, + filename, + imgs, + align=DEFAULT_GRID_KWARGS["align"], + name: Optional[str] = None, + step: Optional[int] = None, + texts: Optional[List[float]] = None, + ): + save_path = self.get_save_path(filename) + img = self.get_image_grid_(imgs, align=align) + + if texts is not None: + img = Image.fromarray(img) + draw = ImageDraw.Draw(img) + black, white = (0, 0, 0), (255, 255, 255) + for i, text in enumerate(texts): + draw.text((2, (img.size[1] // len(texts)) * i + 1), f"{text}", white) + draw.text((0, (img.size[1] // len(texts)) * i + 1), f"{text}", white) + draw.text((2, (img.size[1] // len(texts)) * i - 1), f"{text}", white) + draw.text((0, (img.size[1] // len(texts)) * i - 1), f"{text}", white) + draw.text((1, (img.size[1] // len(texts)) * i), f"{text}", black) + img = np.asarray(img) + + cv2.imwrite(save_path, img) + if name and self._wandb_logger: + wandb.log({name: wandb.Image(save_path), "trainer/global_step": step}) + return save_path + + def save_image(self, filename, img) -> str: + save_path = self.get_save_path(filename) + img = self.convert_data(img) + assert img.dtype == np.uint8 or img.dtype == np.uint16 + if img.ndim == 3 and img.shape[-1] == 3: + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + elif img.ndim == 3 and img.shape[-1] == 4: + img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA) + cv2.imwrite(save_path, img) + return save_path + + def save_cubemap(self, filename, img, data_range=(0, 1), rgba=False) -> str: + save_path = self.get_save_path(filename) + img = self.convert_data(img) + assert img.ndim == 4 and img.shape[0] == 6 and img.shape[1] == img.shape[2] + + imgs_full = [] + for start in range(0, img.shape[-1], 3): + img_ = img[..., start : start + 3] + img_ = np.stack( + [ + self.get_rgb_image_(img_[i], "HWC", data_range, rgba=rgba) + for i in range(img_.shape[0]) + ], + axis=0, + ) + size = img_.shape[1] + placeholder = np.zeros((size, size, 3), dtype=np.float32) + img_full = np.concatenate( + [ + np.concatenate( + [placeholder, img_[2], placeholder, placeholder], axis=1 + ), + np.concatenate([img_[1], img_[4], img_[0], img_[5]], axis=1), + np.concatenate( + [placeholder, img_[3], placeholder, placeholder], axis=1 + ), + ], + axis=0, + ) + imgs_full.append(img_full) + + imgs_full = np.concatenate(imgs_full, axis=1) + cv2.imwrite(save_path, imgs_full) + return save_path + + def save_data(self, filename, data) -> str: + data = self.convert_data(data) + if isinstance(data, dict): + if not filename.endswith(".npz"): + filename += ".npz" + save_path = self.get_save_path(filename) + np.savez(save_path, **data) + else: + if not filename.endswith(".npy"): + filename += ".npy" + save_path = self.get_save_path(filename) + np.save(save_path, data) + return save_path + + def save_state_dict(self, filename, data) -> str: + save_path = self.get_save_path(filename) + torch.save(data, save_path) + return save_path + + def save_img_sequence( + self, + filename, + img_dir, + matcher, + save_format="mp4", + fps=30, + name: Optional[str] = None, + step: Optional[int] = None, + ) -> str: + assert save_format in ["gif", "mp4"] + if not filename.endswith(save_format): + filename += f".{save_format}" + save_path = self.get_save_path(filename) + matcher = re.compile(matcher) + img_dir = os.path.join(self.get_save_dir(), img_dir) + imgs = [] + for f in os.listdir(img_dir): + if matcher.search(f): + imgs.append(f) + imgs = sorted(imgs, key=lambda f: int(matcher.search(f).groups()[0])) + imgs = [cv2.imread(os.path.join(img_dir, f)) for f in imgs] + + if save_format == "gif": + imgs = [cv2.cvtColor(i, cv2.COLOR_BGR2RGB) for i in imgs] + imageio.mimsave(save_path, imgs, fps=fps, palettesize=256) + elif save_format == "mp4": + imgs = [cv2.cvtColor(i, cv2.COLOR_BGR2RGB) for i in imgs] + imageio.mimsave(save_path, imgs, fps=fps) + if name and self._wandb_logger: + wandb.log( + { + name: wandb.Video(save_path, format="mp4"), + "trainer/global_step": step, + } + ) + return save_path + + def save_mesh(self, filename, v_pos, t_pos_idx, v_tex=None, t_tex_idx=None) -> str: + save_path = self.get_save_path(filename) + v_pos = self.convert_data(v_pos) + t_pos_idx = self.convert_data(t_pos_idx) + mesh = trimesh.Trimesh(vertices=v_pos, faces=t_pos_idx) + mesh.export(save_path) + return save_path + + def save_obj( + self, + filename: str, + mesh: Mesh, + save_mat: bool = False, + save_normal: bool = False, + save_uv: bool = False, + save_vertex_color: bool = False, + map_Kd: Optional[Float[Tensor, "H W 3"]] = None, + map_Ks: Optional[Float[Tensor, "H W 3"]] = None, + map_Bump: Optional[Float[Tensor, "H W 3"]] = None, + map_Pm: Optional[Float[Tensor, "H W 1"]] = None, + map_Pr: Optional[Float[Tensor, "H W 1"]] = None, + map_format: str = "jpg", + ) -> List[str]: + save_paths: List[str] = [] + if not filename.endswith(".obj"): + filename += ".obj" + + v_pos, t_pos_idx = self.convert_data(mesh.v_pos), self.convert_data( + mesh.t_pos_idx + ) + v_nrm, v_tex, t_tex_idx, v_rgb = None, None, None, None + if save_normal: + v_nrm = self.convert_data(mesh.v_nrm) + if save_uv: + v_tex, t_tex_idx = self.convert_data(mesh.v_tex), self.convert_data( + mesh.t_tex_idx + ) + if save_vertex_color: + v_rgb = self.convert_data(mesh.v_rgb) + matname, mtllib = None, None + if save_mat: + matname = "default" + mtl_filename = filename.replace(".obj", ".mtl") + mtllib = os.path.basename(mtl_filename) + mtl_save_paths = self._save_mtl( + mtl_filename, + matname, + map_Kd=self.convert_data(map_Kd), + map_Ks=self.convert_data(map_Ks), + map_Bump=self.convert_data(map_Bump), + map_Pm=self.convert_data(map_Pm), + map_Pr=self.convert_data(map_Pr), + map_format=map_format, + ) + save_paths += mtl_save_paths + obj_save_path = self._save_obj( + filename, + v_pos, + t_pos_idx, + v_nrm=v_nrm, + v_tex=v_tex, + t_tex_idx=t_tex_idx, + v_rgb=v_rgb, + matname=matname, + mtllib=mtllib, + ) + save_paths.append(obj_save_path) + return save_paths + + def _save_obj( + self, + filename, + v_pos, + t_pos_idx, + v_nrm=None, + v_tex=None, + t_tex_idx=None, + v_rgb=None, + matname=None, + mtllib=None, + ) -> str: + obj_str = "" + if matname is not None: + obj_str += f"mtllib {mtllib}\n" + obj_str += f"g object\n" + obj_str += f"usemtl {matname}\n" + for i in range(len(v_pos)): + obj_str += f"v {v_pos[i][0]} {v_pos[i][1]} {v_pos[i][2]}" + if v_rgb is not None: + obj_str += f" {v_rgb[i][0]} {v_rgb[i][1]} {v_rgb[i][2]}" + obj_str += "\n" + if v_nrm is not None: + for v in v_nrm: + obj_str += f"vn {v[0]} {v[1]} {v[2]}\n" + if v_tex is not None: + for v in v_tex: + obj_str += f"vt {v[0]} {1.0 - v[1]}\n" + + for i in range(len(t_pos_idx)): + obj_str += "f" + for j in range(3): + obj_str += f" {t_pos_idx[i][j] + 1}/" + if v_tex is not None: + obj_str += f"{t_tex_idx[i][j] + 1}" + obj_str += "/" + if v_nrm is not None: + obj_str += f"{t_pos_idx[i][j] + 1}" + obj_str += "\n" + + save_path = self.get_save_path(filename) + with open(save_path, "w") as f: + f.write(obj_str) + return save_path + + def _save_mtl( + self, + filename, + matname, + Ka=(0.0, 0.0, 0.0), + Kd=(1.0, 1.0, 1.0), + Ks=(0.0, 0.0, 0.0), + map_Kd=None, + map_Ks=None, + map_Bump=None, + map_Pm=None, + map_Pr=None, + map_format="jpg", + step: Optional[int] = None, + ) -> List[str]: + mtl_save_path = self.get_save_path(filename) + save_paths = [mtl_save_path] + mtl_str = f"newmtl {matname}\n" + mtl_str += f"Ka {Ka[0]} {Ka[1]} {Ka[2]}\n" + if map_Kd is not None: + map_Kd_save_path = os.path.join( + os.path.dirname(mtl_save_path), f"texture_kd.{map_format}" + ) + mtl_str += f"map_Kd texture_kd.{map_format}\n" + self._save_rgb_image( + map_Kd_save_path, + map_Kd, + data_format="HWC", + data_range=(0, 1), + name=f"{matname}_Kd", + step=step, + ) + save_paths.append(map_Kd_save_path) + else: + mtl_str += f"Kd {Kd[0]} {Kd[1]} {Kd[2]}\n" + if map_Ks is not None: + map_Ks_save_path = os.path.join( + os.path.dirname(mtl_save_path), f"texture_ks.{map_format}" + ) + mtl_str += f"map_Ks texture_ks.{map_format}\n" + self._save_rgb_image( + map_Ks_save_path, + map_Ks, + data_format="HWC", + data_range=(0, 1), + name=f"{matname}_Ks", + step=step, + ) + save_paths.append(map_Ks_save_path) + else: + mtl_str += f"Ks {Ks[0]} {Ks[1]} {Ks[2]}\n" + if map_Bump is not None: + map_Bump_save_path = os.path.join( + os.path.dirname(mtl_save_path), f"texture_nrm.{map_format}" + ) + mtl_str += f"map_Bump texture_nrm.{map_format}\n" + self._save_rgb_image( + map_Bump_save_path, + map_Bump, + data_format="HWC", + data_range=(0, 1), + name=f"{matname}_Bump", + step=step, + ) + save_paths.append(map_Bump_save_path) + if map_Pm is not None: + map_Pm_save_path = os.path.join( + os.path.dirname(mtl_save_path), f"texture_metallic.{map_format}" + ) + mtl_str += f"map_Pm texture_metallic.{map_format}\n" + self._save_grayscale_image( + map_Pm_save_path, + map_Pm, + data_range=(0, 1), + cmap=None, + name=f"{matname}_refl", + step=step, + ) + save_paths.append(map_Pm_save_path) + if map_Pr is not None: + map_Pr_save_path = os.path.join( + os.path.dirname(mtl_save_path), f"texture_roughness.{map_format}" + ) + mtl_str += f"map_Pr texture_roughness.{map_format}\n" + self._save_grayscale_image( + map_Pr_save_path, + map_Pr, + data_range=(0, 1), + cmap=None, + name=f"{matname}_Ns", + step=step, + ) + save_paths.append(map_Pr_save_path) + with open(self.get_save_path(filename), "w") as f: + f.write(mtl_str) + return save_paths + + def save_file(self, filename, src_path) -> str: + save_path = self.get_save_path(filename) + shutil.copyfile(src_path, save_path) + return save_path + + def save_json(self, filename, payload) -> str: + save_path = self.get_save_path(filename) + with open(save_path, "w") as f: + f.write(json.dumps(payload)) + return save_path diff --git a/craftsman/utils/scheduler.py b/craftsman/utils/scheduler.py new file mode 100755 index 0000000000000000000000000000000000000000..d0da7c4c0a224e014a43eb394f78e6e81e3b2ff5 --- /dev/null +++ b/craftsman/utils/scheduler.py @@ -0,0 +1,104 @@ +import sys +import warnings +from bisect import bisect_right + +import torch +import torch.nn as nn +from torch.optim import lr_scheduler + +import craftsman + + +def get_scheduler(name): + if hasattr(lr_scheduler, name): + return getattr(lr_scheduler, name) + else: + raise NotImplementedError + + +def getattr_recursive(m, attr): + for name in attr.split("."): + m = getattr(m, name) + return m + + +def get_parameters(model, name): + module = getattr_recursive(model, name) + if isinstance(module, nn.Module): + return module.parameters() + elif isinstance(module, nn.Parameter): + return module + return [] + + +def parse_optimizer(config, model): + if hasattr(config, "params"): + params = [ + {"params": get_parameters(model, name), "name": name, **args} + for name, args in config.params.items() + ] + craftsman.debug(f"Specify optimizer params: {config.params}") + else: + params = model.parameters() + if config.name in ["FusedAdam"]: + import apex + + optim = getattr(apex.optimizers, config.name)(params, **config.args) + elif config.name in ["Adan"]: + from craftsman.systems import optimizers + + optim = getattr(optimizers, config.name)(params, **config.args) + else: + optim = getattr(torch.optim, config.name)(params, **config.args) + return optim + + +def parse_scheduler_to_instance(config, optimizer): + if config.name == "ChainedScheduler": + schedulers = [ + parse_scheduler_to_instance(conf, optimizer) for conf in config.schedulers + ] + scheduler = lr_scheduler.ChainedScheduler(schedulers) + elif config.name == "Sequential": + schedulers = [ + parse_scheduler_to_instance(conf, optimizer) for conf in config.schedulers + ] + scheduler = lr_scheduler.SequentialLR( + optimizer, schedulers, milestones=config.milestones + ) + else: + scheduler = getattr(lr_scheduler, config.name)(optimizer, **config.args) + return scheduler + + +def parse_scheduler(config, optimizer): + interval = config.get("interval", "epoch") + assert interval in ["epoch", "step"] + if config.name == "SequentialLR": + scheduler = { + "scheduler": lr_scheduler.SequentialLR( + optimizer, + [ + parse_scheduler(conf, optimizer)["scheduler"] + for conf in config.schedulers + ], + milestones=config.milestones, + ), + "interval": interval, + } + elif config.name == "ChainedScheduler": + scheduler = { + "scheduler": lr_scheduler.ChainedScheduler( + [ + parse_scheduler(conf, optimizer)["scheduler"] + for conf in config.schedulers + ] + ), + "interval": interval, + } + else: + scheduler = { + "scheduler": get_scheduler(config.name)(optimizer, **config.args), + "interval": interval, + } + return scheduler diff --git a/craftsman/utils/typing.py b/craftsman/utils/typing.py new file mode 100755 index 0000000000000000000000000000000000000000..21b1bb2dda7aac2ccc9f26fb47242892b470e671 --- /dev/null +++ b/craftsman/utils/typing.py @@ -0,0 +1,41 @@ +""" +This module contains type annotations for the project, using +1. Python type hints (https://docs.python.org/3/library/typing.html) for Python objects +2. jaxtyping (https://github.com/google/jaxtyping/blob/main/API.md) for PyTorch tensors + +Two types of typing checking can be used: +1. Static type checking with mypy (install with pip and enabled as the default linter in VSCode) +2. Runtime type checking with typeguard (install with pip and triggered at runtime, mainly for tensor dtype and shape checking) +""" + +# Basic types +from typing import ( + Any, + Callable, + Dict, + Iterable, + List, + Literal, + NamedTuple, + NewType, + Optional, + Sized, + Tuple, + Type, + TypeVar, + Union, + Sequence, +) + +# Tensor dtype +# for jaxtyping usage, see https://github.com/google/jaxtyping/blob/main/API.md +from jaxtyping import Bool, Complex, Float, Inexact, Int, Integer, Num, Shaped, UInt + +# Config type +from omegaconf import DictConfig + +# PyTorch Tensor type +from torch import Tensor + +# Runtime type checking decorator +from typeguard import typechecked as typechecker diff --git a/craftsman/utils/visualizers/__init__.py b/craftsman/utils/visualizers/__init__.py new file mode 100755 index 0000000000000000000000000000000000000000..40a96afc6ff09d58a702b76e3f7dd412fe975e26 --- /dev/null +++ b/craftsman/utils/visualizers/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/craftsman/utils/visualizers/color_util.py b/craftsman/utils/visualizers/color_util.py new file mode 100755 index 0000000000000000000000000000000000000000..7983243fd37f5fee47bc51475dc58c460a067830 --- /dev/null +++ b/craftsman/utils/visualizers/color_util.py @@ -0,0 +1,43 @@ +import numpy as np +import matplotlib.pyplot as plt + + +# Helper functions +def get_colors(inp, colormap="viridis", normalize=True, vmin=None, vmax=None): + colormap = plt.cm.get_cmap(colormap) + if normalize: + vmin = np.min(inp) + vmax = np.max(inp) + + norm = plt.Normalize(vmin, vmax) + return colormap(norm(inp))[:, :3] + + +def gen_checkers(n_checkers_x, n_checkers_y, width=256, height=256): + # tex dims need to be power of two. + array = np.ones((width, height, 3), dtype='float32') + + # width in texels of each checker + checker_w = width / n_checkers_x + checker_h = height / n_checkers_y + + for y in range(height): + for x in range(width): + color_key = int(x / checker_w) + int(y / checker_h) + if color_key % 2 == 0: + array[x, y, :] = [1., 0.874, 0.0] + else: + array[x, y, :] = [0., 0., 0.] + return array + + +def gen_circle(width=256, height=256): + xx, yy = np.mgrid[:width, :height] + circle = (xx - width / 2 + 0.5) ** 2 + (yy - height / 2 + 0.5) ** 2 + array = np.ones((width, height, 4), dtype='float32') + array[:, :, 0] = (circle <= width) + array[:, :, 1] = (circle <= width) + array[:, :, 2] = (circle <= width) + array[:, :, 3] = circle <= width + return array + diff --git a/craftsman/utils/visualizers/html_util.py b/craftsman/utils/visualizers/html_util.py new file mode 100755 index 0000000000000000000000000000000000000000..f90fe6cfefe6108655b48c36d60db537589993d5 --- /dev/null +++ b/craftsman/utils/visualizers/html_util.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +import io +import base64 +import numpy as np +from PIL import Image + + +def to_html_frame(content): + + html_frame = f""" + + + {content} + + + """ + + return html_frame + + +def to_single_row_table(caption: str, content: str): + + table_html = f""" + + + + + +
{caption}
{content}
+ """ + + return table_html + + +def to_image_embed_tag(image: np.ndarray): + + # Convert np.ndarray to bytes + img = Image.fromarray(image) + raw_bytes = io.BytesIO() + img.save(raw_bytes, "PNG") + + # Encode bytes to base64 + image_base64 = base64.b64encode(raw_bytes.getvalue()).decode("utf-8") + + image_tag = f""" + Embedded Image + """ + + return image_tag diff --git a/craftsman/utils/visualizers/pythreejs_viewer.py b/craftsman/utils/visualizers/pythreejs_viewer.py new file mode 100755 index 0000000000000000000000000000000000000000..70abbb7dce17361489f36eddca9c7e3089d4ec05 --- /dev/null +++ b/craftsman/utils/visualizers/pythreejs_viewer.py @@ -0,0 +1,537 @@ +import numpy as np +from ipywidgets import embed +import pythreejs as p3s +import uuid + +from .color_util import get_colors, gen_circle, gen_checkers + + +EMBED_URL = "https://cdn.jsdelivr.net/npm/@jupyter-widgets/html-manager@1.0.1/dist/embed-amd.js" + + +class PyThreeJSViewer(object): + + def __init__(self, settings, render_mode="WEBSITE"): + self.render_mode = render_mode + self.__update_settings(settings) + self._light = p3s.DirectionalLight(color='white', position=[0, 0, 1], intensity=0.6) + self._light2 = p3s.AmbientLight(intensity=0.5) + self._cam = p3s.PerspectiveCamera(position=[0, 0, 1], lookAt=[0, 0, 0], fov=self.__s["fov"], + aspect=self.__s["width"] / self.__s["height"], children=[self._light]) + self._orbit = p3s.OrbitControls(controlling=self._cam) + self._scene = p3s.Scene(children=[self._cam, self._light2], background=self.__s["background"]) # "#4c4c80" + self._renderer = p3s.Renderer(camera=self._cam, scene=self._scene, controls=[self._orbit], + width=self.__s["width"], height=self.__s["height"], + antialias=self.__s["antialias"]) + + self.__objects = {} + self.__cnt = 0 + + def jupyter_mode(self): + self.render_mode = "JUPYTER" + + def offline(self): + self.render_mode = "OFFLINE" + + def website(self): + self.render_mode = "WEBSITE" + + def __get_shading(self, shading): + shad = {"flat": True, "wireframe": False, "wire_width": 0.03, "wire_color": "black", + "side": 'DoubleSide', "colormap": "viridis", "normalize": [None, None], + "bbox": False, "roughness": 0.5, "metalness": 0.25, "reflectivity": 1.0, + "line_width": 1.0, "line_color": "black", + "point_color": "red", "point_size": 0.01, "point_shape": "circle", + "text_color": "red" + } + for k in shading: + shad[k] = shading[k] + return shad + + def __update_settings(self, settings={}): + sett = {"width": 600, "height": 600, "antialias": True, "scale": 1.5, "background": "#ffffff", + "fov": 30} + for k in settings: + sett[k] = settings[k] + self.__s = sett + + def __add_object(self, obj, parent=None): + if not parent: # Object is added to global scene and objects dict + self.__objects[self.__cnt] = obj + self.__cnt += 1 + self._scene.add(obj["mesh"]) + else: # Object is added to parent object and NOT to objects dict + parent.add(obj["mesh"]) + + self.__update_view() + + if self.render_mode == "JUPYTER": + return self.__cnt - 1 + elif self.render_mode == "WEBSITE": + return self + + def __add_line_geometry(self, lines, shading, obj=None): + lines = lines.astype("float32", copy=False) + mi = np.min(lines, axis=0) + ma = np.max(lines, axis=0) + + geometry = p3s.LineSegmentsGeometry(positions=lines.reshape((-1, 2, 3))) + material = p3s.LineMaterial(linewidth=shading["line_width"], color=shading["line_color"]) + # , vertexColors='VertexColors'), + lines = p3s.LineSegments2(geometry=geometry, material=material) # type='LinePieces') + line_obj = {"geometry": geometry, "mesh": lines, "material": material, + "max": ma, "min": mi, "type": "Lines", "wireframe": None} + + if obj: + return self.__add_object(line_obj, obj), line_obj + else: + return self.__add_object(line_obj) + + def __update_view(self): + if len(self.__objects) == 0: + return + ma = np.zeros((len(self.__objects), 3)) + mi = np.zeros((len(self.__objects), 3)) + for r, obj in enumerate(self.__objects): + ma[r] = self.__objects[obj]["max"] + mi[r] = self.__objects[obj]["min"] + ma = np.max(ma, axis=0) + mi = np.min(mi, axis=0) + diag = np.linalg.norm(ma - mi) + mean = ((ma - mi) / 2 + mi).tolist() + scale = self.__s["scale"] * (diag) + self._orbit.target = mean + self._cam.lookAt(mean) + self._cam.position = [mean[0], mean[1], mean[2] + scale] + self._light.position = [mean[0], mean[1], mean[2] + scale] + + self._orbit.exec_three_obj_method('update') + self._cam.exec_three_obj_method('updateProjectionMatrix') + + def __get_bbox(self, v): + m = np.min(v, axis=0) + M = np.max(v, axis=0) + + # Corners of the bounding box + v_box = np.array([[m[0], m[1], m[2]], [M[0], m[1], m[2]], [M[0], M[1], m[2]], [m[0], M[1], m[2]], + [m[0], m[1], M[2]], [M[0], m[1], M[2]], [M[0], M[1], M[2]], [m[0], M[1], M[2]]]) + + f_box = np.array([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], + [0, 4], [1, 5], [2, 6], [7, 3]], dtype=np.uint32) + return v_box, f_box + + def __get_colors(self, v, f, c, sh): + coloring = "VertexColors" + if type(c) == np.ndarray and c.size == 3: # Single color + colors = np.ones_like(v) + colors[:, 0] = c[0] + colors[:, 1] = c[1] + colors[:, 2] = c[2] + # print("Single colors") + elif type(c) == np.ndarray and len(c.shape) == 2 and c.shape[1] == 3: # Color values for + if c.shape[0] == f.shape[0]: # faces + colors = np.hstack([c, c, c]).reshape((-1, 3)) + coloring = "FaceColors" + # print("Face color values") + elif c.shape[0] == v.shape[0]: # vertices + colors = c + # print("Vertex color values") + else: # Wrong size, fallback + print("Invalid color array given! Supported are numpy arrays.", type(c)) + colors = np.ones_like(v) + colors[:, 0] = 1.0 + colors[:, 1] = 0.874 + colors[:, 2] = 0.0 + elif type(c) == np.ndarray and c.size == f.shape[0]: # Function values for faces + normalize = sh["normalize"][0] != None and sh["normalize"][1] != None + cc = get_colors(c, sh["colormap"], normalize=normalize, + vmin=sh["normalize"][0], vmax=sh["normalize"][1]) + # print(cc.shape) + colors = np.hstack([cc, cc, cc]).reshape((-1, 3)) + coloring = "FaceColors" + # print("Face function values") + elif type(c) == np.ndarray and c.size == v.shape[0]: # Function values for vertices + normalize = sh["normalize"][0] != None and sh["normalize"][1] != None + colors = get_colors(c, sh["colormap"], normalize=normalize, + vmin=sh["normalize"][0], vmax=sh["normalize"][1]) + # print("Vertex function values") + + else: + colors = np.ones_like(v) + # colors[:, 0] = 1.0 + # colors[:, 1] = 0.874 + # colors[:, 2] = 0.0 + colors[:, 0] = 1 + colors[:, 1] = 1 + colors[:, 2] = 1 + + # No color + if c is not None: + print("Invalid color array given! Supported are numpy arrays.", type(c)) + + return colors, coloring + + def __get_point_colors(self, v, c, sh): + v_color = True + if c is None: # No color given, use global color + # conv = mpl.colors.ColorConverter() + colors = sh["point_color"] # np.array(conv.to_rgb(sh["point_color"])) + v_color = False + elif isinstance(c, str): # No color given, use global color + # conv = mpl.colors.ColorConverter() + colors = c # np.array(conv.to_rgb(c)) + v_color = False + elif type(c) == np.ndarray and len(c.shape) == 2 and c.shape[0] == v.shape[0] and c.shape[1] == 3: + # Point color + colors = c.astype("float32", copy=False) + + elif isinstance(c, np.ndarray) and len(c.shape) == 2 and c.shape[0] == v.shape[0] and c.shape[1] != 3: + # Function values for vertices, but the colors are features + c_norm = np.linalg.norm(c, ord=2, axis=-1) + normalize = sh["normalize"][0] != None and sh["normalize"][1] != None + colors = get_colors(c_norm, sh["colormap"], normalize=normalize, + vmin=sh["normalize"][0], vmax=sh["normalize"][1]) + colors = colors.astype("float32", copy=False) + + elif type(c) == np.ndarray and c.size == v.shape[0]: # Function color + normalize = sh["normalize"][0] != None and sh["normalize"][1] != None + colors = get_colors(c, sh["colormap"], normalize=normalize, + vmin=sh["normalize"][0], vmax=sh["normalize"][1]) + colors = colors.astype("float32", copy=False) + # print("Vertex function values") + + else: + print("Invalid color array given! Supported are numpy arrays.", type(c)) + colors = sh["point_color"] + v_color = False + + return colors, v_color + + def add_mesh(self, v, f, c=None, uv=None, n=None, shading={}, texture_data=None, **kwargs): + shading.update(kwargs) + sh = self.__get_shading(shading) + mesh_obj = {} + + # it is a tet + if v.shape[1] == 3 and f.shape[1] == 4: + f_tmp = np.ndarray([f.shape[0] * 4, 3], dtype=f.dtype) + for i in range(f.shape[0]): + f_tmp[i * 4 + 0] = np.array([f[i][1], f[i][0], f[i][2]]) + f_tmp[i * 4 + 1] = np.array([f[i][0], f[i][1], f[i][3]]) + f_tmp[i * 4 + 2] = np.array([f[i][1], f[i][2], f[i][3]]) + f_tmp[i * 4 + 3] = np.array([f[i][2], f[i][0], f[i][3]]) + f = f_tmp + + if v.shape[1] == 2: + v = np.append(v, np.zeros([v.shape[0], 1]), 1) + + # Type adjustment vertices + v = v.astype("float32", copy=False) + + # Color setup + colors, coloring = self.__get_colors(v, f, c, sh) + + # Type adjustment faces and colors + c = colors.astype("float32", copy=False) + + # Material and geometry setup + ba_dict = {"color": p3s.BufferAttribute(c)} + if coloring == "FaceColors": + verts = np.zeros((f.shape[0] * 3, 3), dtype="float32") + for ii in range(f.shape[0]): + # print(ii*3, f[ii]) + verts[ii * 3] = v[f[ii, 0]] + verts[ii * 3 + 1] = v[f[ii, 1]] + verts[ii * 3 + 2] = v[f[ii, 2]] + v = verts + else: + f = f.astype("uint32", copy=False).ravel() + ba_dict["index"] = p3s.BufferAttribute(f, normalized=False) + + ba_dict["position"] = p3s.BufferAttribute(v, normalized=False) + + if uv is not None: + uv = (uv - np.min(uv)) / (np.max(uv) - np.min(uv)) + if texture_data is None: + texture_data = gen_checkers(20, 20) + tex = p3s.DataTexture(data=texture_data, format="RGBFormat", type="FloatType") + material = p3s.MeshStandardMaterial(map=tex, reflectivity=sh["reflectivity"], side=sh["side"], + roughness=sh["roughness"], metalness=sh["metalness"], + flatShading=sh["flat"], + polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=5) + ba_dict["uv"] = p3s.BufferAttribute(uv.astype("float32", copy=False)) + else: + material = p3s.MeshStandardMaterial(vertexColors=coloring, reflectivity=sh["reflectivity"], + side=sh["side"], roughness=sh["roughness"], metalness=sh["metalness"], + flatShading=sh["flat"], + polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=5) + + if type(n) != type(None) and coloring == "VertexColors": # TODO: properly handle normals for FaceColors as well + ba_dict["normal"] = p3s.BufferAttribute(n.astype("float32", copy=False), normalized=True) + + geometry = p3s.BufferGeometry(attributes=ba_dict) + + if coloring == "VertexColors" and type(n) == type(None): + geometry.exec_three_obj_method('computeVertexNormals') + elif coloring == "FaceColors" and type(n) == type(None): + geometry.exec_three_obj_method('computeFaceNormals') + + # Mesh setup + mesh = p3s.Mesh(geometry=geometry, material=material) + + # Wireframe setup + mesh_obj["wireframe"] = None + if sh["wireframe"]: + wf_geometry = p3s.WireframeGeometry(mesh.geometry) # WireframeGeometry + wf_material = p3s.LineBasicMaterial(color=sh["wire_color"], linewidth=sh["wire_width"]) + wireframe = p3s.LineSegments(wf_geometry, wf_material) + mesh.add(wireframe) + mesh_obj["wireframe"] = wireframe + + # Bounding box setup + if sh["bbox"]: + v_box, f_box = self.__get_bbox(v) + _, bbox = self.add_edges(v_box, f_box, sh, mesh) + mesh_obj["bbox"] = [bbox, v_box, f_box] + + # Object setup + mesh_obj["max"] = np.max(v, axis=0) + mesh_obj["min"] = np.min(v, axis=0) + mesh_obj["geometry"] = geometry + mesh_obj["mesh"] = mesh + mesh_obj["material"] = material + mesh_obj["type"] = "Mesh" + mesh_obj["shading"] = sh + mesh_obj["coloring"] = coloring + mesh_obj["arrays"] = [v, f, c] # TODO replays with proper storage or remove if not needed + + return self.__add_object(mesh_obj) + + def add_lines(self, beginning, ending, shading={}, obj=None, **kwargs): + shading.update(kwargs) + if len(beginning.shape) == 1: + if len(beginning) == 2: + beginning = np.array([[beginning[0], beginning[1], 0]]) + else: + if beginning.shape[1] == 2: + beginning = np.append( + beginning, np.zeros([beginning.shape[0], 1]), 1) + if len(ending.shape) == 1: + if len(ending) == 2: + ending = np.array([[ending[0], ending[1], 0]]) + else: + if ending.shape[1] == 2: + ending = np.append( + ending, np.zeros([ending.shape[0], 1]), 1) + + sh = self.__get_shading(shading) + lines = np.hstack([beginning, ending]) + lines = lines.reshape((-1, 3)) + return self.__add_line_geometry(lines, sh, obj) + + def add_edges(self, vertices, edges, shading={}, obj=None, **kwargs): + shading.update(kwargs) + if vertices.shape[1] == 2: + vertices = np.append( + vertices, np.zeros([vertices.shape[0], 1]), 1) + sh = self.__get_shading(shading) + lines = np.zeros((edges.size, 3)) + cnt = 0 + for e in edges: + lines[cnt, :] = vertices[e[0]] + lines[cnt + 1, :] = vertices[e[1]] + cnt += 2 + return self.__add_line_geometry(lines, sh, obj) + + def add_points(self, points, c=None, shading={}, obj=None, **kwargs): + shading.update(kwargs) + if len(points.shape) == 1: + if len(points) == 2: + points = np.array([[points[0], points[1], 0]]) + else: + if points.shape[1] == 2: + points = np.append( + points, np.zeros([points.shape[0], 1]), 1) + sh = self.__get_shading(shading) + points = points.astype("float32", copy=False) + mi = np.min(points, axis=0) + ma = np.max(points, axis=0) + + g_attributes = {"position": p3s.BufferAttribute(points, normalized=False)} + m_attributes = {"size": sh["point_size"]} + + if sh["point_shape"] == "circle": # Plot circles + tex = p3s.DataTexture(data=gen_circle(16, 16), format="RGBAFormat", type="FloatType") + m_attributes["map"] = tex + m_attributes["alphaTest"] = 0.5 + m_attributes["transparency"] = True + else: # Plot squares + pass + + colors, v_colors = self.__get_point_colors(points, c, sh) + if v_colors: # Colors per point + m_attributes["vertexColors"] = 'VertexColors' + g_attributes["color"] = p3s.BufferAttribute(colors, normalized=False) + + else: # Colors for all points + m_attributes["color"] = colors + + material = p3s.PointsMaterial(**m_attributes) + geometry = p3s.BufferGeometry(attributes=g_attributes) + points = p3s.Points(geometry=geometry, material=material) + point_obj = {"geometry": geometry, "mesh": points, "material": material, + "max": ma, "min": mi, "type": "Points", "wireframe": None} + + if obj: + return self.__add_object(point_obj, obj), point_obj + else: + return self.__add_object(point_obj) + + def remove_object(self, obj_id): + if obj_id not in self.__objects: + print("Invalid object id. Valid ids are: ", list(self.__objects.keys())) + return + self._scene.remove(self.__objects[obj_id]["mesh"]) + del self.__objects[obj_id] + self.__update_view() + + def reset(self): + for obj_id in list(self.__objects.keys()).copy(): + self._scene.remove(self.__objects[obj_id]["mesh"]) + del self.__objects[obj_id] + self.__update_view() + + def update_object(self, oid=0, vertices=None, colors=None, faces=None): + obj = self.__objects[oid] + if type(vertices) != type(None): + if obj["coloring"] == "FaceColors": + f = obj["arrays"][1] + verts = np.zeros((f.shape[0] * 3, 3), dtype="float32") + for ii in range(f.shape[0]): + # print(ii*3, f[ii]) + verts[ii * 3] = vertices[f[ii, 0]] + verts[ii * 3 + 1] = vertices[f[ii, 1]] + verts[ii * 3 + 2] = vertices[f[ii, 2]] + v = verts + + else: + v = vertices.astype("float32", copy=False) + obj["geometry"].attributes["position"].array = v + # self.wireframe.attributes["position"].array = v # Wireframe updates? + obj["geometry"].attributes["position"].needsUpdate = True + # obj["geometry"].exec_three_obj_method('computeVertexNormals') + if type(colors) != type(None): + colors, coloring = self.__get_colors(obj["arrays"][0], obj["arrays"][1], colors, obj["shading"]) + colors = colors.astype("float32", copy=False) + obj["geometry"].attributes["color"].array = colors + obj["geometry"].attributes["color"].needsUpdate = True + if type(faces) != type(None): + if obj["coloring"] == "FaceColors": + print("Face updates are currently only possible in vertex color mode.") + return + f = faces.astype("uint32", copy=False).ravel() + print(obj["geometry"].attributes) + obj["geometry"].attributes["index"].array = f + # self.wireframe.attributes["position"].array = v # Wireframe updates? + obj["geometry"].attributes["index"].needsUpdate = True + # obj["geometry"].exec_three_obj_method('computeVertexNormals') + # self.mesh.geometry.verticesNeedUpdate = True + # self.mesh.geometry.elementsNeedUpdate = True + # self.update() + if self.render_mode == "WEBSITE": + return self + + # def update(self): + # self.mesh.exec_three_obj_method('update') + # self.orbit.exec_three_obj_method('update') + # self.cam.exec_three_obj_method('updateProjectionMatrix') + # self.scene.exec_three_obj_method('update') + + def add_text(self, text, shading={}, **kwargs): + shading.update(kwargs) + sh = self.__get_shading(shading) + tt = p3s.TextTexture(string=text, color=sh["text_color"]) + sm = p3s.SpriteMaterial(map=tt) + text = p3s.Sprite(material=sm, scaleToTexture=True) + self._scene.add(text) + + # def add_widget(self, widget, callback): + # self.widgets.append(widget) + # widget.observe(callback, names='value') + + # def add_dropdown(self, options, default, desc, cb): + # widget = widgets.Dropdown(options=options, value=default, description=desc) + # self.__widgets.append(widget) + # widget.observe(cb, names="value") + # display(widget) + + # def add_button(self, text, cb): + # button = widgets.Button(description=text) + # self.__widgets.append(button) + # button.on_click(cb) + # display(button) + + def to_html(self, imports=True, html_frame=True): + # Bake positions (fixes centering bug in offline rendering) + if len(self.__objects) == 0: + return + ma = np.zeros((len(self.__objects), 3)) + mi = np.zeros((len(self.__objects), 3)) + for r, obj in enumerate(self.__objects): + ma[r] = self.__objects[obj]["max"] + mi[r] = self.__objects[obj]["min"] + ma = np.max(ma, axis=0) + mi = np.min(mi, axis=0) + diag = np.linalg.norm(ma - mi) + mean = (ma - mi) / 2 + mi + for r, obj in enumerate(self.__objects): + v = self.__objects[obj]["geometry"].attributes["position"].array + v -= mean + v += np.array([0.0, .9, 0.0]) #! to move the obj to the center of window + + scale = self.__s["scale"] * (diag) + self._orbit.target = [0.0, 0.0, 0.0] + self._cam.lookAt([0.0, 0.0, 0.0]) + # self._cam.position = [0.0, 0.0, scale] + self._cam.position = [0.0, 0.5, scale * 1.3] #! show four complete meshes in the window + self._light.position = [0.0, 0.0, scale] + + state = embed.dependency_state(self._renderer) + + # Somehow these entries are missing when the state is exported in python. + # Exporting from the GUI works, so we are inserting the missing entries. + for k in state: + if state[k]["model_name"] == "OrbitControlsModel": + state[k]["state"]["maxAzimuthAngle"] = "inf" + state[k]["state"]["maxDistance"] = "inf" + state[k]["state"]["maxZoom"] = "inf" + state[k]["state"]["minAzimuthAngle"] = "-inf" + + tpl = embed.load_requirejs_template + if not imports: + embed.load_requirejs_template = "" + + s = embed.embed_snippet(self._renderer, state=state, embed_url=EMBED_URL) + # s = embed.embed_snippet(self.__w, state=state) + embed.load_requirejs_template = tpl + + if html_frame: + s = "\n\n" + s + "\n\n" + + # Revert changes + for r, obj in enumerate(self.__objects): + v = self.__objects[obj]["geometry"].attributes["position"].array + v += mean + self.__update_view() + + return s + + def save(self, filename=""): + if filename == "": + uid = str(uuid.uuid4()) + ".html" + else: + filename = filename.replace(".html", "") + uid = filename + '.html' + with open(uid, "w") as f: + f.write(self.to_html()) + print("Plot saved to file %s." % uid) diff --git a/gradio_app.py b/gradio_app.py new file mode 100644 index 0000000000000000000000000000000000000000..526eee6ee0ff8b7f4d4926223a0bbbbb480d2181 --- /dev/null +++ b/gradio_app.py @@ -0,0 +1,272 @@ +import argparse +import os +import json +import torch +import sys +import time +import importlib +import numpy as np +from omegaconf import OmegaConf +from huggingface_hub import hf_hub_download + +from collections import OrderedDict +import trimesh +from einops import repeat, rearrange +import pytorch_lightning as pl +from typing import Dict, Optional, Tuple, List +import gradio as gr + +proj_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(os.path.join(proj_dir)) + +import craftsman +from craftsman.systems.base import BaseSystem +from craftsman.utils.config import ExperimentConfig, load_config + +from apps.utils import * +from apps.mv_models import GenMVImage + +_TITLE = '''CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner''' +_DESCRIPTION = ''' +
+Select or upload a image, then just click 'Generate'. +
+By mimicking the artist/craftsman modeling workflow, we propose CraftsMan (aka 匠心) that uses 3D Latent Set Diffusion Model that directly generate coarse meshes, +then a multi-view normal enhanced image generation model is used to refine the mesh. +We provide the coarse 3D diffusion part here. +
+If you found Crafts is helpful, please help to ⭐ the Github Repo. Thanks! + +
+*please note that the model is fliped due to the gradio viewer, please download the obj file and you will get the correct mesh. +
+*If you have your own multi-view images, you can directly upload it. +
+''' +_CITE_ = r""" +--- +📝 **Citation** +If you find our work useful for your research or applications, please cite using this bibtex: +```bibtex +@article{craftsman, +author = {Weiyu Li and Jiarui Liu and Rui Chen and Yixun Liang and Xuelin Chen and Ping Tan and Xiaoxiao Long}, +title = {CraftsMan: High-fidelity Mesh Generation with 3D Native Generation and Interactive Geometry Refiner}, +journal = {arxiv:xxx}, +year = {2024}, +} +``` +🤗 **Acknowledgements** +We use Instant Meshes to remesh the generated mesh to a lower face count, thanks to the authors for the great work. +📋 **License** +CraftsMan is under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html), so any downstream solution and products (including cloud services) that include CraftsMan code or a trained model (both pretrained or custom trained) inside it should be open-sourced to comply with the AGPL conditions. If you have any questions about the usage of CraftsMan, please contact us first. +📧 **Contact** +If you have any questions, feel free to open a discussion or contact us at weiyuli.cn@gmail.com. +""" + +model = None +cached_dir = None + +def image2mesh(view_front: np.ndarray, + view_right: np.ndarray, + view_back: np.ndarray, + view_left: np.ndarray, + more: bool = False, + scheluder_name: str ="DDIMScheduler", + guidance_scale: int = 7.5, + seed: int = 4, + octree_depth: int = 7): + + sample_inputs = { + "mvimages": [[ + Image.fromarray(view_front), + Image.fromarray(view_right), + Image.fromarray(view_back), + Image.fromarray(view_left) + ]] + } + + global model + latents = model.sample( + sample_inputs, + sample_times=1, + guidance_scale=guidance_scale, + return_intermediates=False, + seed=seed + + )[0] + + # decode the latents to mesh + box_v = 1.1 + mesh_outputs, _ = model.shape_model.extract_geometry( + latents, + bounds=[-box_v, -box_v, -box_v, box_v, box_v, box_v], + octree_depth=octree_depth + ) + assert len(mesh_outputs) == 1, "Only support single mesh output for gradio demo" + mesh = trimesh.Trimesh(mesh_outputs[0][0], mesh_outputs[0][1]) + filepath = f"{cached_dir}/{time.time()}.obj" + mesh.export(filepath, include_normals=True) + + if 'Remesh' in more: + print("Remeshing with Instant Meshes...") + target_face_count = int(len(mesh.faces)/10) + command = f"{proj_dir}/apps/third_party/InstantMeshes {filepath} -f {target_face_count} -d -S 0 -r 6 -p 6 -o {filepath.replace('.obj', '_remeshed.obj')}" + os.system(command) + filepath = filepath.replace('.obj', '_remeshed.obj') + + return filepath + +if __name__=="__main__": + parser = argparse.ArgumentParser() + # parser.add_argument("--model_path", type=str, required=True, help="Path to the object file",) + parser.add_argument("--cached_dir", type=str, default="./gradio_cached_dir") + parser.add_argument("--device", type=int, default=0) + args = parser.parse_args() + + cached_dir = args.cached_dir + os.makedirs(args.cached_dir, exist_ok=True) + device = torch.device(f"cuda:{args.device}" if torch.cuda.is_available() else "cpu") + print(f"using device: {device}") + + # for multi-view images generation + background_choice = OrderedDict({ + "Alpha as Mask": "Alpha as Mask", + "Auto Remove Background": "Auto Remove Background", + "Original Image": "Original Image", + }) + mvimg_model_config_list = ["CRM", "ImageDream", "Wonder3D"] + + # for 3D latent set diffusion + # for 3D latent set diffusion + ckpt_path = hf_hub_download(repo_id="wyysf/CraftsMan", filename="image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6/model.ckpt", repo_type="model") + config_path = hf_hub_download(repo_id="wyysf/CraftsMan", filename="image-to-shape-diffusion/clip-mvrgb-modln-l256-e64-ne8-nd16-nl6/config.yaml", repo_type="model") + scheluder_dict = OrderedDict({ + "DDIMScheduler": 'diffusers.schedulers.DDIMScheduler', + # "DPMSolverMultistepScheduler": 'diffusers.schedulers.DPMSolverMultistepScheduler', # not support yet + # "UniPCMultistepScheduler": 'diffusers.schedulers.UniPCMultistepScheduler', # not support yet + }) + + # main GUI + custom_theme = gr.themes.Soft(primary_hue="blue").set( + button_secondary_background_fill="*neutral_100", + button_secondary_background_fill_hover="*neutral_200") + custom_css = '''#disp_image { + text-align: center; /* Horizontally center the content */ + }''' + + with gr.Blocks(title=_TITLE, theme=custom_theme, css=custom_css) as demo: + with gr.Row(): + with gr.Column(scale=1): + gr.Markdown('# ' + _TITLE) + gr.Markdown(_DESCRIPTION) + + with gr.Row(): + with gr.Column(scale=2): + with gr.Row(): + image_input = gr.Image( + label="Image Input", + image_mode="RGBA", + sources="upload", + type="pil", + ) + with gr.Row(): + text = gr.Textbox(label="Prompt (Optional, only works for mvdream)", visible=False) + with gr.Row(): + gr.Markdown('''Try a different seed if the result is unsatisfying. Good Luck :)''') + with gr.Row(): + seed = gr.Number(42, label='Seed', show_label=True) + more = gr.CheckboxGroup(["Remesh", "Symmetry(TBD)"], label="More", show_label=False) + # remesh = gr.Checkbox(value=False, label='Remesh') + # symmetry = gr.Checkbox(value=False, label='Symmetry(TBD)', interactive=False) + run_btn = gr.Button('Generate', variant='primary', interactive=True) + + with gr.Row(): + gr.Examples( + examples=[os.path.join("./apps/examples", i) for i in os.listdir("./apps/examples")], + inputs=[image_input], + examples_per_page=8 + ) + + with gr.Column(scale=4): + with gr.Row(): + output_model_obj = gr.Model3D( + label="Output Model (OBJ Format)", + camera_position=(90.0, 90.0, 3.5), + interactive=False, + ) + + with gr.Row(): + view_front = gr.Image(label="Front", interactive=True, show_label=True) + view_right = gr.Image(label="Right", interactive=True, show_label=True) + view_back = gr.Image(label="Back", interactive=True, show_label=True) + view_left = gr.Image(label="Left", interactive=True, show_label=True) + + with gr.Accordion('Advanced options', open=False): + with gr.Row(equal_height=True): + run_mv_btn = gr.Button('Only Generate 2D', interactive=True) + run_3d_btn = gr.Button('Only Generate 3D', interactive=True) + + with gr.Accordion('Advanced options (2D)', open=False): + with gr.Row(): + crop_size = gr.Number(224, label='Crop size') + mvimg_model = gr.Dropdown(value="CRM", label="MV Image Model", choices=mvimg_model_config_list) + + with gr.Row(): + foreground_ratio = gr.Slider( + label="Foreground Ratio", + minimum=0.5, + maximum=1.0, + value=1.0, + step=0.05, + ) + + with gr.Row(): + background_choice = gr.Dropdown(label="Backgroud Choice", value="Auto Remove Background",choices=list(background_choice.keys())) + rmbg_type = gr.Dropdown(label="Backgroud Remove Type", value="rembg",choices=['sam', "rembg"]) + backgroud_color = gr.ColorPicker(label="Background Color", value="#FFFFFF", interactive=True) + + with gr.Row(): + mvimg_guidance_scale = gr.Number(value=3.5, minimum=3, maximum=10, label="2D Guidance Scale") + mvimg_steps = gr.Number(value=50, minimum=20, maximum=100, label="2D Sample Steps", precision=0) + + with gr.Accordion('Advanced options (3D)', open=False): + with gr.Row(): + guidance_scale = gr.Number(label="3D Guidance Scale", value=7.5, minimum=3.0, maximum=10.0) + steps = gr.Number(value=50, minimum=20, maximum=100, label="3D Sample Steps", precision=0) + + with gr.Row(): + scheduler = gr.Dropdown(label="scheluder", value="DDIMScheduler",choices=list(scheluder_dict.keys())) + octree_depth = gr.Slider(label="Octree Depth", value=7, minimum=4, maximum=8, step=1) + + gr.Markdown(_CITE_) + + outputs = [output_model_obj] + rmbg = RMBG(device) + + gen_mvimg = GenMVImage(device) + model = load_model(ckpt_path, config_path, device) + + run_btn.click(fn=check_input_image, inputs=[image_input] + ).success( + fn=rmbg.run, + inputs=[rmbg_type, image_input, crop_size, foreground_ratio, background_choice, backgroud_color], + outputs=[image_input] + ).success( + fn=gen_mvimg.run, + inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps], + outputs=[view_front, view_right, view_back, view_left] + ).success( + fn=image2mesh, + inputs=[view_front, view_right, view_back, view_left, more, scheduler, guidance_scale, seed, octree_depth], + outputs=outputs, + api_name="generate_img2obj") + run_mv_btn.click(fn=gen_mvimg.run, + inputs=[mvimg_model, text, image_input, crop_size, seed, mvimg_guidance_scale, mvimg_steps], + outputs=[view_front, view_right, view_back, view_left] + ) + run_3d_btn.click(fn=image2mesh, + inputs=[view_front, view_right, view_back, view_left, more, scheduler, guidance_scale, seed, octree_depth], + outputs=outputs, + api_name="generate_img2obj") + + demo.queue().launch(share=True, allowed_paths=[args.cached_dir]) \ No newline at end of file diff --git a/launch.py b/launch.py new file mode 100644 index 0000000000000000000000000000000000000000..854425983580adb24a56bc56071a9003e087f47d --- /dev/null +++ b/launch.py @@ -0,0 +1,299 @@ +import argparse +import contextlib +import importlib +import logging +import os +import sys +import time +import traceback +import pytorch_lightning as pl +import torch +from pytorch_lightning import Trainer +from pytorch_lightning.callbacks import LearningRateMonitor, ModelCheckpoint +from pytorch_lightning.loggers import CSVLogger, TensorBoardLogger +from pytorch_lightning.utilities.rank_zero import rank_zero_only +import craftsman +from craftsman.systems.base import BaseSystem +from craftsman.utils.callbacks import ( + CodeSnapshotCallback, + ConfigSnapshotCallback, + CustomProgressBar, + ProgressCallback, +) +from craftsman.utils.config import ExperimentConfig, load_config +from craftsman.utils.misc import get_rank +from craftsman.utils.typing import Optional +class ColoredFilter(logging.Filter): + """ + A logging filter to add color to certain log levels. + """ + + RESET = "\033[0m" + RED = "\033[31m" + GREEN = "\033[32m" + YELLOW = "\033[33m" + BLUE = "\033[34m" + MAGENTA = "\033[35m" + CYAN = "\033[36m" + + COLORS = { + "WARNING": YELLOW, + "INFO": GREEN, + "DEBUG": BLUE, + "CRITICAL": MAGENTA, + "ERROR": RED, + } + + RESET = "\x1b[0m" + + def __init__(self): + super().__init__() + + def filter(self, record): + if record.levelname in self.COLORS: + color_start = self.COLORS[record.levelname] + record.levelname = f"{color_start}[{record.levelname}]" + record.msg = f"{record.msg}{self.RESET}" + return True + + +def load_custom_module(module_path): + module_name = os.path.basename(module_path) + if os.path.isfile(module_path): + sp = os.path.splitext(module_path) + module_name = sp[0] + try: + if os.path.isfile(module_path): + module_spec = importlib.util.spec_from_file_location( + module_name, module_path + ) + else: + module_spec = importlib.util.spec_from_file_location( + module_name, os.path.join(module_path, "__init__.py") + ) + + module = importlib.util.module_from_spec(module_spec) + sys.modules[module_name] = module + module_spec.loader.exec_module(module) + return True + except Exception as e: + print(traceback.format_exc()) + print(f"Cannot import {module_path} module for custom nodes:", e) + return False + + +def load_custom_modules(): + node_paths = ["custom"] + node_import_times = [] + if not os.path.exists("node_paths"): + return + for custom_node_path in node_paths: + possible_modules = os.listdir(custom_node_path) + if "__pycache__" in possible_modules: + possible_modules.remove("__pycache__") + + for possible_module in possible_modules: + module_path = os.path.join(custom_node_path, possible_module) + if ( + os.path.isfile(module_path) + and os.path.splitext(module_path)[1] != ".py" + ): + continue + if module_path.endswith(".disabled"): + continue + time_before = time.perf_counter() + success = load_custom_module(module_path) + node_import_times.append( + (time.perf_counter() - time_before, module_path, success) + ) + + if len(node_import_times) > 0: + print("\nImport times for custom modules:") + for n in sorted(node_import_times): + if n[2]: + import_message = "" + else: + import_message = " (IMPORT FAILED)" + print("{:6.1f} seconds{}:".format(n[0], import_message), n[1]) + print() + + +def main(args, extras) -> None: + # set CUDA_VISIBLE_DEVICES if needed, then import pytorch-lightning + os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" + env_gpus_str = os.environ.get("CUDA_VISIBLE_DEVICES", None) + env_gpus = list(env_gpus_str.split(",")) if env_gpus_str else [] + selected_gpus = [0] + torch.set_float32_matmul_precision("high") + + # Always rely on CUDA_VISIBLE_DEVICES if specific GPU ID(s) are specified. + # As far as Pytorch Lightning is concerned, we always use all available GPUs + # (possibly filtered by CUDA_VISIBLE_DEVICES). + devices = -1 + if len(env_gpus) > 0: + n_gpus = len(env_gpus) + else: + selected_gpus = list(args.gpu.split(",")) + n_gpus = len(selected_gpus) + print(f"Using {n_gpus} GPUs: {selected_gpus}") + os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu + + if args.typecheck: + from jaxtyping import install_import_hook + + install_import_hook("craftsman", "typeguard.typechecked") + + logger = logging.getLogger("pytorch_lightning") + if args.verbose: + logger.setLevel(logging.DEBUG) + + for handler in logger.handlers: + if handler.stream == sys.stderr: # type: ignore + if not args.gradio: + handler.setFormatter(logging.Formatter("%(levelname)s %(message)s")) + handler.addFilter(ColoredFilter()) + else: + handler.setFormatter(logging.Formatter("[%(levelname)s] %(message)s")) + + load_custom_modules() + + # parse YAML config to OmegaConf + cfg: ExperimentConfig + cfg = load_config(args.config, cli_args=extras, n_gpus=n_gpus) + + # set a different seed for each device + pl.seed_everything(cfg.seed + get_rank(), workers=True) + + dm = craftsman.find(cfg.data_type)(cfg.data) + system: BaseSystem = craftsman.find(cfg.system_type)( + cfg.system, resumed=cfg.resume is not None + ) + system.set_save_dir(os.path.join(cfg.trial_dir, "save")) + + if args.gradio: + fh = logging.FileHandler(os.path.join(cfg.trial_dir, "logs")) + fh.setLevel(logging.INFO) + if args.verbose: + fh.setLevel(logging.DEBUG) + fh.setFormatter(logging.Formatter("[%(levelname)s] %(message)s")) + logger.addHandler(fh) + + callbacks = [] + if args.train: + callbacks += [ + ModelCheckpoint( + dirpath=os.path.join(cfg.trial_dir, "ckpts"), **cfg.checkpoint + ), + LearningRateMonitor(logging_interval="step"), + CodeSnapshotCallback( + os.path.join(cfg.trial_dir, "code"), use_version=False + ), + ConfigSnapshotCallback( + args.config, + cfg, + os.path.join(cfg.trial_dir, "configs"), + use_version=False, + ), + ] + if args.gradio: + callbacks += [ + ProgressCallback(save_path=os.path.join(cfg.trial_dir, "progress")) + ] + else: + callbacks += [CustomProgressBar(refresh_rate=1)] + + def write_to_text(file, lines): + with open(file, "w") as f: + for line in lines: + f.write(line + "\n") + + loggers = [] + if args.train: + # make tensorboard logging dir to suppress warning + rank_zero_only( + lambda: os.makedirs(os.path.join(cfg.trial_dir, "tb_logs"), exist_ok=True) + )() + loggers += [ + TensorBoardLogger(cfg.trial_dir, name="tb_logs"), + CSVLogger(cfg.trial_dir, name="csv_logs"), + ] + system.get_loggers() + rank_zero_only( + lambda: write_to_text( + os.path.join(cfg.trial_dir, "cmd.txt"), + ["python " + " ".join(sys.argv), str(args)], + ) + )() + + trainer = Trainer( + callbacks=callbacks, + logger=loggers, + inference_mode=False, + accelerator="gpu", + devices=devices, + # profiler="advanced", + **cfg.trainer, + ) + + def set_system_status(system: BaseSystem, ckpt_path: Optional[str]): + if ckpt_path is None: + return + ckpt = torch.load(ckpt_path, map_location="cpu") + system.set_resume_status(ckpt["epoch"], ckpt["global_step"]) + if args.train: + trainer.fit(system, datamodule=dm, ckpt_path=cfg.resume) + trainer.test(system, datamodule=dm) + if args.gradio: + # also export assets if in gradio mode + trainer.predict(system, datamodule=dm) + elif args.validate: + # manually set epoch and global_step as they cannot be automatically resumed + set_system_status(system, cfg.resume) + trainer.validate(system, datamodule=dm, ckpt_path=cfg.resume) + elif args.test: + # manually set epoch and global_step as they cannot be automatically resumed + set_system_status(system, cfg.resume) + trainer.test(system, datamodule=dm, ckpt_path=cfg.resume) + elif args.export: + set_system_status(system, cfg.resume) + trainer.predict(system, datamodule=dm, ckpt_path=cfg.resume) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--config", required=True, help="path to config file") + parser.add_argument( + "--gpu", + default="0", + help="GPU(s) to be used. 0 means use the 1st available GPU. " + "1,2 means use the 2nd and 3rd available GPU. " + "If CUDA_VISIBLE_DEVICES is set before calling `launch.py`, " + "this argument is ignored and all available GPUs are always used.", + ) + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("--train", action="store_true") + group.add_argument("--validate", action="store_true") + group.add_argument("--test", action="store_true") + group.add_argument("--export", action="store_true") + + parser.add_argument( + "--gradio", action="store_true", help="if true, run in gradio mode" + ) + + parser.add_argument( + "--verbose", action="store_true", help="if true, set logging level to DEBUG" + ) + + parser.add_argument( + "--typecheck", + action="store_true", + help="whether to enable dynamic type checking", + ) + + args, extras = parser.parse_known_args() + + if args.gradio: + with contextlib.redirect_stdout(sys.stderr): + main(args, extras) + else: + main(args, extras) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d191badbd144b4b5678aac5aed1da7faa1455b1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,35 @@ +datasets==2.19.0 +diffusers==0.27.2 +einops==0.8.0 +huggingface-hub==0.22.2 +imageio==2.34.1 +jaxtyping==0.2.28 +joblib==1.4.0 +lightning-utilities==0.11.2 +matplotlib==3.8.4 +numpy==1.26.4 +omegaconf==2.3.0 +opencv-python==4.9.0.80 +pandas==2.2.2 +pillow==10.3.0 +plyfile==1.0.3 +PyMCubes==0.1.4 +pyparsing==3.1.2 +pytorch-lightning==2.2.4 +PyYAML==6.0.1 +safetensors==0.4.3 +scikit-image==0.23.2 +scipy==1.13.0 +tensorboard==2.16.2 +tensorboardX==2.6.2.2 +timm==0.9.16 +tokenizers==0.19.1 +torch==2.3.0 +torchvision==0.18.0 +tqdm==4.66.2 +transformers==4.40.1 +trimesh==4.3.2 +wandb==0.16.6 +segment_anything==1.0 +rembg==2.0.56 +xformers==0.0.19 \ No newline at end of file