From 199575cc74391e14f0b72de90ca1c42e71a67bbd Mon Sep 17 00:00:00 2001 From: yudajiang Date: Wed, 20 Nov 2024 11:55:59 +0800 Subject: [PATCH 1/4] crm init --- configs/specs_objaverse_lvis.json | 116 + data_split/objaverse_lvis/exclude.txt | 3 + data_split/objaverse_lvis/test.txt | 2952 +++++++ data_split/objaverse_lvis/train.txt | 10331 ++++++++++++++++++++++++ data_split/objaverse_lvis/val.txt | 1476 ++++ datasets/dataset.py | 92 + datasets/fast_dataset.py | 945 +++ datasets/memory_dataset.py | 530 ++ make_chunk.py | 59 + make_chunk_sub.py | 80 + metric/lpips/__init__.py | 0 metric/lpips/lpips.py | 35 + metric/lpips/networks.py | 96 + metric/lpips/utils.py | 30 + metric/shape.py | 169 + train_crm.py | 903 +++ util/loss.py | 100 + 17 files changed, 17917 insertions(+) create mode 100644 configs/specs_objaverse_lvis.json create mode 100644 data_split/objaverse_lvis/exclude.txt create mode 100644 data_split/objaverse_lvis/test.txt create mode 100644 data_split/objaverse_lvis/train.txt create mode 100644 data_split/objaverse_lvis/val.txt create mode 100644 datasets/dataset.py create mode 100644 datasets/fast_dataset.py create mode 100644 datasets/memory_dataset.py create mode 100644 make_chunk.py create mode 100644 make_chunk_sub.py create mode 100644 metric/lpips/__init__.py create mode 100644 metric/lpips/lpips.py create mode 100644 metric/lpips/networks.py create mode 100644 metric/lpips/utils.py create mode 100644 metric/shape.py create mode 100644 train_crm.py create mode 100644 util/loss.py diff --git a/configs/specs_objaverse_lvis.json b/configs/specs_objaverse_lvis.json new file mode 100644 index 0000000..ff69ce8 --- /dev/null +++ b/configs/specs_objaverse_lvis.json @@ -0,0 +1,116 @@ +{ + "Model": "TrDGen", + + "Input": { + "task_mode": "batch", + "pcd_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis_ply", + "mesh_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis_mesh", + "render_img_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis", + "blender_transform": "/home/yudajiang/datasets/Objaverse/normalize_anno/meta_data_new.json", + "triview_color_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis_newdata", + "triview_xyz_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis_newxyz", + "prompt_path": "/home/yudajiang/datasets/Objaverse/Objaverse_anno.csv", + "dataset_name": "Objaverse", + "img_num": 16, + "split_dir": "data_split/objaverse_lvis", + "class": "lvis", + "camera_angle_num": 8, + "tet_grid_size": 90, + "validate_num": 16, + "dataset_type": "filesystem", + "chunk_path": "data/Objaverse", + "chunk_size": 256, + "scale": 0.95, + "radius": 3, + "resolution": [256, 256], + "resolution_img": [256, 256], + "resolution_triview": [256, 256] + }, + + "Pretrain": { + "mode": null, + "warm_up": 0, + "batch_size": 1024, + "warmup_iter": 0, + "decay": 0.0000, + "num_iter": 1000, + "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.0, + "rgb_decay": 1.0 + }, + "sample_points_num": 20000, + "query_sample_points_num": 60000, + "batch_size": 1, + "eva_iter": 80, + "save_chunk": 50, + "xyz_noise_scale": 0.00, + "eva_all_epoch": 10, + "tex_sup_mode": "blender", + "dep&sill_sup_mode": "blender", + "lambda_smooth": 1, + "lambda_nc": 0, + "lambda_lp": 0.2, + "lambda_color": 2, + "lambda_l2": 0.00, + "lambda_wzy": 0.0, + "exp_uv_mesh": false, + "doub": false, + "random_bg": false, + "sd_mode": null, + "sd_cfg": 100, + "sd_lambda": 10, + "shift": 0, + "geo_type": "flex", + "init_mdl_path": null + }, + + "ArchSpecs": { + "pc_enc": "img", + "unet_type": "diffusers", + "use_3D_aware": false, + "fea_concat": false, + "mlp_bias": true, + "q_plane": false, + "gt_triimg": true + }, + + "EncoderSpecs": { + "latent_size": 32, + "hidden_dim": 64, + "color_output": 64, + "unet_kwargs": { + "depth": 6, + "merge_mode": "concat", + "start_filts": 64 + }, + "plane_resolution": 256 + }, + + "DecoderSpecs": { + "c_dim": 32, + "unet_kwargs": { + "depth": 6, + "merge_mode": "concat", + "start_filts": 64 + }, + "plane_resolution": 256 + }, + + "Output": { + "exp_name": "exp-objaverse" + } +} diff --git a/data_split/objaverse_lvis/exclude.txt b/data_split/objaverse_lvis/exclude.txt new file mode 100644 index 0000000..30b5feb --- /dev/null +++ b/data_split/objaverse_lvis/exclude.txt @@ -0,0 +1,3 @@ +1d06ba8ef476420094ec09e818bbebb7 +4d7414c670fc4818868efd717c8556c0 +f4bdcfe475e842d6a95972211d68694c diff --git a/data_split/objaverse_lvis/test.txt b/data_split/objaverse_lvis/test.txt new file mode 100644 index 0000000..885652b --- /dev/null +++ b/data_split/objaverse_lvis/test.txt @@ -0,0 +1,2952 @@ +f8661def77f44417b54a665e726b80d4 +fa7c15cc4fa5448fb6587a873ed63459 +247300b3b51148a09fd4398a691d6297 +7905627f0cac45589f5e10f30cf79d38 +5921d829f1bd412eb07296ecb7cac372 +4125db0e838245a58f8a92bca125b856 +4d7132a60a174017ba7d0c029dcac4fc +d82c26f74b7c44ea9e71c53cf5af84f5 +c50701af72334361ac7f50fa01945efd +a06ac84d848242c58c3d4517c189f8e3 +97a1ccb66e524731adc91520d727aba2 +79005845160443a0b8a175614cf2926a +fe8eef087d6646fabb24833ea6af5550 +6277248072c84f9cb4248413b1a92de3 +21b2a8f0d3c64459bf024471d0999fbe +dd371614f76f4f9b98d790962641ccce +f8ca6d3c18f2455c8186dcae492c7816 +43fd2a71246842869cb9dc428a9d2a7e +633bd6eb599b4e5c8494bfc0c3c12cd5 +f567cf6300984cccb42cb75a81bcb248 +0a7b8a27d72240a0ac2a60accc4ce81e +e3316e8c891843fab3eb09b87b5840e7 +1da37b3d991a43a8ad9f58458053ac13 +7b93efdf8a804433ae3e9ef01eca0214 +a4d258638d684f318d3f93efcfb1b699 +095df5e33ab14a8c84ed1a0451154836 +f05759c515544ea4abc1f61c718c516d +fcb96f36054a44ef870aac0bda271965 +abb0b2c7e9604de9b5a02d7e647a861f +c2f9b76e6b184138a23dfda89829fa8b +43744f9bdf7d46c2bf45361c9acc32ad +8f2a04cbcf3741088978399924b46a92 +ca4bca236e72483ca07ccd79bac59eea +69c704a4679642dc9090b7b1caa1645b +0c94ab9eda8d43079f3bfb773cf10bda +3163530e1c434fbeb23ad58db4cab882 +9234d8196b73434684bcbb8092cc9e2a +c8ca01f1ab5c42728480328d02b0b2f9 +3dbfe22766a04d1fa551471247d55fff +b95a001246dc4c00b69ef669dbab8ff2 +cdd3f8ac36ef46d8871d1b0e217f7729 +06d7f1e741094b7aa460e88ba08cf049 +b24c917246ee420aad3262b03db38ea7 +34022bf9dd9148e2a3de014db888427c +6c2b3f8e6d574361b7121968f9ed0b73 +796e4d17b0ac43dda78c3a3a89a9bb0f +65707f83605e404c9d54581ed79cb0ee +6aece0955eec4837aba89da35eefaacc +f41e5cd3583c40e18a14df47287a43dc +c424492fd48d40a6bffa40a7a94296ef +2ad0b6946a8844258e526cdda23822ec +47e7baf853514c31bed2fcd399eae864 +986ceaeb78b74d88bb0a86791f755851 +24ddd62de82f4455b2cb25a9448bc4cf +a0cfccecc5d846fd84fc8c9a907a2d9f +83dd4e30036243b1b5e7b08b9de768a2 +cc455b8b2b54467d9560149ecda55395 +21ce12eaaede4527a9703d72e9bb5c06 +bb812edca066437b992f4a99d7463150 +75e9b25b1d1d4c0dab8b4dce94dbd5bd +05dafa582db84ae6a675533c73a3600a +62898588e87c4edcba25de3c20a8bfd7 +8b9e6c6d79f7473da5ccfe9b7f42ca3f +0badd2265db2428cad5033aacf3f7d2a +c163a94a1ed44b738d8d8abb10862966 +badd1d1abfbf4ca0b55fd1e0f8156160 +ef9780f0cd274c28a614f1745dad00ff +d023e43149234c3a92f34810624439ee +37ca6bdc2d214891a8bfc18b6166897d +8fd013e4352d4aa591287799b452a1cb +8c1485f88cbe48688a2d14c793a632ca +bd7808fc98464b5eb66c79f9a93c726b +832be807365c49d5b6cb9844c4aa66f8 +4926464addc64a0f9e281ad749f69c85 +e8e0d1c5c1834644a25b63980bcaa9ae +127c9d767260468f821da3cba9d7db7e +c3b02c96515d4e259b467a3453950e83 +39368256c6b047ed9112ed94d0538f6d +ecc132e2b5924adf8e5c0d595456fc88 +a10569c0809246aabfb0f8b16a663a03 +f92489a55882402ea3fb41a6aa5b0fac +0135d63c4b1c499d9f7bfe103e1cd2d0 +48ea397d2cd64bc4a39f4aa98acd29a7 +eeda09a2600943ccb5ee28bbca6ba868 +63171b7f228d48db90f0b4131d017067 +98972a311e6042d790e095c0dbbdb70b +8e92af109b0e437d93361a5c0c5108a4 +e99c2e4c5de64ac99b20755c7da2572d +1b0e13ac59d7428b80116e9453109609 +b08de9a1056e43a09320072a943e31db +418f684021d240d6bc69a0da1b17dd34 +b5a45e9e7552423380766e69bb7ee3f6 +bfb2e482b27f4e49bd51f75d4b64a42d +29c1dee5992e485891703501f457a613 +0243239775f24dedb4821836e090bbc7 +83191c1073b04a0f9b60d3975545adad +73d0f3ce04b44ba595fe2d4ea5bc7861 +7cd81a3f53d04c3ebc91d60c70000ca1 +4e7f37bee0674d569f558b0f08b7fdb7 +4fdd427bfed9482fb16b6c33056ecf9c +3da4121117424cf69c7304e1d06b17d1 +66540f4d84354ee780101780f5baa70f +735f7039f2f84c8eb48ecea13967b1ca +29a88585645f49d6ab1e5664eddbe380 +35b0be786e4d46209c063abd01278ca3 +b939c4e88e124c51aa5bf88c16caeceb +43464df55c8345f39dd23bb879ddbb71 +f98e59e1d512450ca89b3a58d70d3db1 +d414c185293e46eab32bf539f6fff808 +f857ecf2fe3d4113b31d6be463d8d645 +a612e935b5024d22a8afe143e8041afc +c90b62af44654d549be357a4825f6142 +780ee18030f34cb5ac2d37a5e3892fda +a265f9af877443d3abb04b8adb4840c4 +83979fb138fb491398602dbe3e5a60d3 +aaa99a374e0c4a98868383c42ff6ae0d +effe471c624f49cda0f1593966d1f073 +b8bc996da0834f19a7e8c001bbe60bb8 +cb87435db3fc427a929b4d20f134c744 +1572e083b9e64b52af2d3e76e20c027f +e57e7d7b5c0744c4b24e21fe44567e38 +ac26def69ffb4e52bbbdf576066bd0e5 +fe5b7e3935944c4b8ae48bc3e5f77d77 +89103ff87fc74647a96ffa0ac4ca5274 +100d28b5075941e986a98080b99b8166 +fbf1464ad39a4cffbd2b24c4e6d96aa6 +59783297884f457db1b8fe7362b27a59 +ad5abe641f5240cc99790c593fc5033a +69994077fc894249b3c9dc4c0dcb87da +677ea756ec224280b144b061ab0fe4c9 +5b6d0f3a343d4031af3046f5ca9e0d6d +5ba6a5759315437a85fac54749c46c82 +bcec690c4683424584f7ffb07e72b1cb +a482fd641c3d46ce9000c2f1e7348b2c +f5b3512c8afa4f24be830471f6f4e4c5 +426f0b2bd5e8400684d319e537937197 +12946fa673524f9ba82a3dfe58f2c6ef +7beef9a08a7e4114b95c297749b6ac69 +92e6509f3b474298ae66709e8cc24255 +2f4ee4fc911c4671b565a6d0b99abc65 +1116089f08a844248d87f3d51bdf1adf +678d46d290c7445288ef148dbec7cd81 +f7a5d89883e547cd86e63ae67248eecb +90616961550b44b58648d95ef3efbe54 +1ebb7e724fc64d7abb6279c63987e512 +fee6f8a30040418688c2c2111ee09179 +78454c7b6c0244f6a1c8f7f708142176 +7227d55e64d9484eac47f3ea6807a7eb +ed00cf5ea92741eab1d9ce1371681618 +cf40b7fe364847cea3776267ecec1d51 +6253f28ad04149c995d8ddaf57549b41 +acfd453ccb254fec87cae82046251009 +df03807b536444dc876e07165e48f53b +4d0e13c9b7da40958233b4a551e30522 +b542ac71e229471ca18e2e426c1bbb55 +1862fbf2f8a0413bb678b993c7ae17e2 +2bf4905d458c426199be919209943ee8 +f4ec12056fc04342ada7b287d07bd7a1 +aa6990763bd145ec954a0c41e9beb3f0 +47abdefdcdfe479a91e0cae48e70f8d0 +ba90f173220944eea071e7839547ee4e +f98b0ac1146e4217ad60d626c43ee64b +fe30ec8240234d40aaabec7ac26fed07 +a76c8a6132cf4747bfc50dc8cdfedbba +cc0099a687194a31a052ac761f5fdfea +a826d4dc23ac46a3b1f897138ff052e7 +cef56cbb91a9424884d8a8461fffd562 +357d2f25e3a34d16beea1ac295b33091 +6554891b758246348b682dfff4e4b462 +568c556465934fb6b427f60708bb0f45 +7854d50ffff840968930b072dd1c8b6a +c93acd5558564d4ab2c2c8b5a3cbc73e +b87d332af8094cc495292f6d711422b4 +304e4b1a8bf943118a74a85bedfadc82 +a63b986464e0458ca5418d94abadbc05 +7a936528fe154261afeb89ca132741b4 +2ee2003561cd42789f6346ed1b65b2ef +8daa31bb8f80438e8287da51d110a6d0 +73b98b9a1e664b60b4f614fddebe8bec +d726514a97f74f168b104fd6ba538331 +c43a66561dd34db8836178ee6b212846 +8c43549fe3824aadb24a5e6ae5f7fab4 +325ca51ea1254529af04305919a580ef +fcec3aefadd54be18d67574014c51ed9 +cc284b0624a44d6e8318a275b9110590 +a03c79ff3d524570afa5a1bde2121399 +0a7e5fcdaeac4f0f8d5194f42f4d4492 +c48aa0cc75394a07b5d9a718e23156b8 +fb21c4f65bf0461f9ff0b6f2b70331ff +d7309f0f6200411ab872aed55570a13b +05d58bc6964541a298032d24014cf899 +3f06dbb8db4347b8a6ffed1161689eb7 +f9873843c895404bb8f27b6330cc11c2 +eefd711998cd4e8da4adb7a80ff30968 +c1f73d85752749be8252622ae03bd3d6 +2c8832c80aff4268b83a0093380d803d +729a6873bb7d419ab8d76b47a75446dd +cb95025952a14090a61821580e5e3c18 +b752a7d173eb4f2e89bec0b100aaa20f +7c8b2bee6d7943329b78acf84b991a78 +fe7a627ee83f4af192ca74dcf10e72d6 +8c375ece6c444908bf8bfe784c332d30 +ceac388cb5ed406a9a728c48d6cda71f +44112469dea546f396dbb6d35539e8e0 +2c805951fd4942bdba0cbec78fae2fd5 +1347d88293c14f099a8697d619a5f228 +37edd5526e474a51a9390c004b6e375d +46f65621f5264d1885097d9b432856e7 +294b5774d94141358a7b6b1708860dde +d92ab9476b6c4223b9e942954aa58835 +cb2d1794d0ad4557a8aee26f1e6f2dcf +5998532604314fac865d68bf570c75e7 +f1c1e890de674fccabcad59e16e8e4d5 +e1e3a74aaa4c4dacb3ffdac4dd119830 +754a35fc531e43f5b3d1c27ccf35a139 +fb80ef2491214624b8ba9347e30b5c61 +db96249afc944cd7ac860533c50d27b2 +80c272f29b0f43189316ede9cb3f148d +d7c8e02d53e848cab05f84a29abe1d98 +5af4ab6f66e5408ea907d355df8c1387 +88207e92e16a4032adb336b3bc5169d1 +c75095f5bc9f442db98d6ddfe89db384 +1915ece903a5406d8b59b3af3954b943 +439f0725eae54fc7b8085293179d6df7 +f8d52b6ae9424e859108f4db0ff2c2c5 +885b71f984ec400a8443380a6b6d5551 +05ab63c372f94b4686b20c8930ffd4c4 +52f5b46223d447858d48f8ce15bde614 +f510996f662447d597cfd9b891ec4710 +2536e6eb87f94e7195115c551db52e76 +ad9b20a87d2e4e08a3df49615ce76ef7 +abf0b05fab4d4ab69de1dba36e39ed49 +c946316455a84545be460d16317f5d86 +e1bdfd950aff4e3784e1562620326a94 +c033d4bd9a354a5eae3fbb953cd9013b +13389c1f790249e3ad2d069d6168c74e +8f1d77fe247f405283dfd51a90331332 +c78a944eef3d427c80d47153e6f8b220 +bfd94071302f439485520566ee5228a7 +f7d2757432f94a2bb366c9a41503647b +ce1ad6c08a8c4e2f8c08eb910a0f8e1b +bfba8bb9916f4fd9b1c4b80df28a3c9d +17f7e41a66af4603b47ec9f485e3bb8b +f02c038597824d2e8ddd68b45078702b +de7a8f843afa4439b9296d3fe40e7aee +565aea3028e54b4883e89577c971a43c +eadefe937a734f8182aa077fe2f19da4 +c892e540ba3f40c3aaf7834240325698 +2f0598cba938424688cdd048a90b8339 +c1d72577d7e14f8499c7af0195e89ff9 +096a3d10bbbc45f0adfe6f3e8bf48cb1 +3bbdc49fee8b47cc98ee12592288c091 +9eefcf9a6fed458990b59f63a2870d9e +f992f2a23baf4eb49b13995a128f9775 +af8ed31338d04308990a0da9083fcccd +fee6a02fd14b42c38b578dca87db34aa +753e0a4d13e444598ebcf65dae7e10ff +b986d60d194246eeb0e02f6cf5e18495 +16daedff659a47539ddee0934750e839 +f2a8f127fed2427da29edf0832a70bc4 +5cf2199634ea400292cc9ded55a2ad29 +3cb0f51108aa4b43b19e20d43dcc141c +6d9ad814b30a41dfac2236e3939d9f62 +a6247837ecca4431a68ee391e4ebb780 +b523cc7996ea4826989a9a5aa501eae6 +5257f5522875473982e618ba7cfc5825 +5c590c42fb5e401e8add8528ccd6e900 +c869dc1156cf4d0c8829787f9423a1c2 +6edc9b08a06b4feb87ce09654c460a2f +8c0d285c1e6b4ba3b5ea777b563c4c80 +27a2bb91d63f4f508457383bb58fb105 +61cfc277da3941c8b19666345d622ae4 +cf33e2df757d4210a97d673093105138 +5841ce4a336f452981206067f08448c1 +8701afc9445b4b2dacefcf3643382e98 +e819525af9fa4dc0b8238cd740f416b3 +a9bf09f4f333493580d75b4bde98f9cb +adce1c32d04c4c1cb1936e0eb9eb200b +5bca086ba85f4a31b56762ef1947a0af +5b15b893b16743358a87221d599d0aa2 +be78e19ba0594f25895404b35c53a5da +84a656c9a1d3402aaccd1b83289b7b25 +2f45d519fc934e1bab5c9234fa33e6bf +287c3f62c2b04a3585e2efe26678b8a6 +65dcebe837d34f13ae6c7dc2fa3b79fc +3fc78bbc18014edc866142f654bfcec2 +089fb41566cd435895e1ebecc4dd3575 +127af08a23a34458b35b3a8a401502e5 +9b4f2da8f6c14ce7b8cd323e21df1d66 +d5023f5fb73243179092067efb3c9c70 +7f068aa71289489c856d2918b534f7b7 +aeb581e782194e70bc3c97123c7e9078 +712f9b2258f1440897ec369951188ec4 +bb1c23461d8a40b3b30c6dd867a5f4e8 +1bc5925b6a9c46bdb979a62c93cffbfc +f844ed37976c4be987907526a781f333 +f05b0c2f9bcf41cea188a4b4c848068a +fc662503b33e44649d04f8d017c0b82a +c32c12343e3940d2ad99f702597bcc73 +05fe9235420b4a0798a19b09cd9d497b +4c8910708c7d4bc3ae5d89be85dede0c +db1a56f564ec4c2bb20b64e46abeff55 +ca46149feec7481289f4a3829c8a536d +d4fe99f677f74eaf94ad99e1969c472b +05e20fa552964861a656a9fa9248f641 +e6539a42c12a45488e196b14935cacf1 +b691c4c7a57b450dbc5b7f04855c414e +8d9ce1787c534bacbdb7c0452e476003 +6b486ff516d64a5a89339e39624f6323 +3da866e97fde4f9b90a5651f84b6bff9 +07a7bb0587774d00a15414b5126a1889 +9f22d859b45f4727b1c253cb61de7a42 +b1f4ebda2c3d4e75b1619400dd409c12 +45076905be154f43b7964b325ba62417 +e95993cbd335456686c5033ff5b214bf +aa103794b57044d5a969e6ce750cc89e +98cc948d6551439fa4a272471e5b7e1d +91185ba35ece4a3792bbda7a205c830a +0048e8224b174b759771e39ff521ee2e +605ea5ffc77845cd8b5ffd32b6ef9e77 +a7fc2463dc0248eca7b51dcd012b01e7 +f802fa8051c643a2a4cd6995319a5715 +50e3b31e6935484e829696094b54eaf3 +9ec5bbe588e84b36abb8ce600b23980a +67d6494522b94a06a8058c5006c4caeb +57e2176e3b2b473db69c39a05b2ad732 +da2aac19bc914c87a1b3654d7f76e7f9 +fc7d79e6ce5a463093e24925c7518c93 +6346aa7ff84d4272a35da13dabb8193e +c3e73a5008ec4f159e4ff047b5d9904b +f5ea35b5769f4e4f8cfb6e2747f2ceb8 +9f0e4bc02edb44d8aa824ff870d5ed58 +77eb557575c147708f0e07b487055690 +09af8624f011406c974b7cd4678650db +97dcfb19b4ac4fdfa4228b8920131c3b +cbb4bfc4e5654500a70dfe72ffc0ce0a +5879e369b26a4343b57bc9fec9981ebb +b5bd6abdafe44673868edfb27e2c263c +2493ab01f58f44f3bc5feb25b8f12418 +47a690dcecf847fca99c4f89111db85b +1557fd3289104918ab475b8e1e6c7063 +f21e495f008f4c959d4974a3707a65ac +8eef676fb3694402975fdfff345c04e9 +2b74e98be6834219b9e3cb533d558d2d +ca8d526966a74d5ab796092e6e4531a8 +d2a79c02a5ad471d90cc975d0033b8e2 +2ed38b429e1e4c889b35cb8d7041d029 +7dc7f8ae7a5b47c6a9d26b676f3ac42b +dd99ebfc07e54d4fa674fd07b4bbef92 +14daacbaf0f94f458851e15dfd717426 +4de921e9a36c4e87baa71e9099a52cfc +0102b2c1449f448687d62ea66ae2a26a +a0d301249f9243ba9bbec30a99873f57 +90a0093f27f04ea19e33591f22910741 +d300f72448f14589be070c955c7781d7 +2555fbb01fd94eaf8d4be0d0361d368c +0a122f8d1a954276bda739ea64b1d9c3 +0653b954ac69491185acd500a45956c9 +7a46652dcb8341b0aba369318eb5a172 +3eb8d638a0ea4a649091a4a47d5c192b +84589627d9bb4faaad828970dddcba8c +338750859a814c8d99e45095ed95a2e6 +062943f3da5d45eca2ee3d40a1b876ff +561954f322f94c79b5f930ac00dfce2b +1b32c464bf09435194b0b5f90748869f +d9ecc99108a643ab887296cb986be937 +208f64a19478420e9b5874f70315b214 +423502aad8564e1b9fe1b810e204b7c6 +92dc9ea14d6f4c0aa4b1d1d07b25da81 +43a19f580f324bce946860cb2d61baa7 +989b8633de5a48d1aa7b1015f7ad8a16 +1768ad36821a43cda1c6fdfaf548c06b +9b8c4236495d4e3fba5e71760d12ac94 +10f03147643849b99acc31551af6c09d +d80a4dee19b34c85835ca99416cda15b +6ff3ec85501e444db8d0161c0dcfaedb +504fcade8ddc42d99a5e8cd46720879a +a7690401610f4c1f9b8b2f022ad3eb28 +a88bc26076804daebe41bd0cdd931c42 +0d24279daaef44a98b4b86dcd7d1525c +c0b36cf117a044f0b1817e4819f2f441 +d4febbe416104e9ea90cbe3e73c64250 +705052b54da546c7a79864fc76d87f87 +5ec36e995dd94222a1fd26b112b65cd2 +16e90be4f064482fbb718a5c44111603 +caae0e16666b45c3bb47be55ee6f11fc +e569c4763db04a32b2bc23361b82b3f0 +e7ea8f4837354f6da7e4c4c9ee986ff1 +7bd76fafb0e04c498fd1a764ae337ee5 +2cc16e027a9748faabe30d58da46778a +f6dba1a3f3174cb89b4ec110e150c07a +6b893ec7e2a8417b8438d3dc7a81a820 +2f9d407689c941d993f3d112a2af5595 +b59a7634e4ed43b0a5f7ae309253244e +0f7c1ad13f114f2b9da596641bb47fa7 +823b2f340b324f759fef8c0916eff2c7 +59d580d861a44a66b2f6d28638e363fd +b167e8b457cb4cddadbe5f7925504d3d +5f148bfc60f34a22813bc07d1fdcff0c +dce5a98e2e3c4d5bb6ffa09adc57d2e8 +d204621598054c4b93cef386f4bb24fe +a69e339b48f14a12a4d2a57a09708de2 +d1bb68aebb1b4532b026d8eb824d4c15 +2392d8cde5e240d8a0b35f7d762580fe +59310def624c420480d3f7127909db29 +da8388e9d6bc4655b54978ad61dbd5a2 +ec059ea5256148bd851cbbe100a0a969 +07b97d13a37d48f0a74431ec832a3ce9 +293914c166e94bf1a373d5bea376dca3 +3f80e4aa0bb04d739413b1d322e1de9c +01e6aa0666a64738994b8ffa8a1a6e15 +d53b49d528a64d7d958a0cea0db534a2 +6441b7f2164b4891889cbf627e0d9da7 +25aeb6812a3f47c19e372a86fc852816 +48e98b9f3fad4e709f608c7a89a46317 +4059fe481e754d588cbeefd0182b673a +1509b394dcfa4451ba7ebdaf7fc7a808 +2bb3bf4c10b94dc7b0aa4a3383e53f45 +77350cd19e18435c9718cc76e98de28c +8fdc644e107147a1ab280f78c89895e3 +25a90ce47f7142a9ae6918149abff3af +f32a7136b700447ca70fd8abd038e550 +0450b57c682d4454b3beb2f8724a73f5 +bf3fe82d714f4ccdb42bfe3f0843e80b +bb1d75d971de467fa9f3c26f3d8b4eef +1021b36999684deab4c2b77a8fc76ec9 +fb6c56b1e12c4541b80d24b580d9106a +99bafe10363e47e892f0033161b898bd +fea25ef07c5941ab9d7ee4f829d410d1 +919f4e79b11d4feca575fdc9213109dd +be875ce2075d48fda14a9a30882a51fe +e7c0b5ed29364a4baf82b9872adb0b42 +9fe3b3cbb19e4300893c4d3a1662c100 +549dd016a9814885a94bef3231768976 +579a894150d648bcab285c05eed7c800 +c4dacdd173914c648a64b205479a6822 +f7a96ca9ce3c4a0ba622088fffffa51c +4de36fd537c844b5800d003c06087d17 +d7e36dd5055b4634b72cd60f1c8cadef +1120299af488432887b09e660abd7821 +38f9f2f6bbc14977866692fbbcc8cb4b +4ca7bdbf4a17487a85c24160f6cfd6ed +f9201b604572460284a327cab6b4d34d +4ac179c3447f4636a273d8574a61a1c5 +50cefa99366146f6bfcaf87243e3ccad +a6e19d641a2642b4b9ddb68b0c5f3c56 +89c76529d15a424fba5b47c2c572a18b +1483a55c785d4379a25441681153cfce +2651a32fb4dc441dab773b8b534b851f +e7cc557fd77744b79fc2cac3762aa6a3 +a38dc588f875474eb7e272c95fdeb154 +fad3c78c87454f3296ba6fac46a69dd4 +df49cd935f3f44e68612f346ac617a67 +54f6ef2fc523436bb5f3e21a976ded4c +ce5e4170510f4530b9bb7d8a558ea363 +d0aad1c318e247ea856aa01325c863f7 +515b783e0444464c84d7fa0cebd31cab +efb6a0a74d0742e7954e80e33392899e +b0e5ee8710b8450fa8c01b2bb390a8a2 +e37125dc47654359971ecf964272c564 +7dd8c64d390a460c975b446e72c03301 +e867291098e44a55920a1f59fc69dfd4 +9793f91454ff4fe7b23590c53d451130 +47c4277a3e414b9084da8ae51cc15c87 +fa2387b422f642e0ab6d45bbd2226f5c +3fcf6bcdba7948f9a1361ede1a87e4f0 +006373e3885b472cb5538fc570235fcf +3c76cce1322948ffa467358ded7951cc +4f534b695fd14efdaa3d217c539f975a +b2c714f8e0f641249e90d88cdbcad4c7 +29a91650db644ef8a2f6cd48ec556eea +02f2f34578474d45b9988f3c8b817a2a +3248db9b720346ccad870b92b7d47e91 +e774329b14124cc18a87f484b58cea02 +ec33f88c15f041638f5b7c8ecc0705d5 +21e1712c27b847e393ac39214f2762a0 +f9f0a5a874d8474dad7a7657ef27a531 +640e241fec904e16991253ab3704e048 +001f5b9d3b7d4210b0dee5139c664a89 +f9f3fc83638a46f688d63eea8a5ca161 +4a6528079ece48828f2500964fd60e13 +23d22ba864ab495f82ea6efba5d3d1ee +4139cadb34e8433a881b8380fdf8ed51 +294ad9f9f0bb4223b8a71c2aec6f7104 +11d8e1e33f544e5d85d0c5a6b8e2f29a +942c79805fe74491b82aac14f80959f6 +a8c1ea7b3e844ba2a6299ccba466b23c +fef2e74c23434993b2ae9ec0b31b636c +aab6d5b2a3e44500b6974133134c64b1 +d16f1d8a8c2e418fa2ae54075147e2b1 +7dab0b937e7d4a7c8d01ee6822c1a37c +d0b08c213d0f48c58569ba375d4554ca +8eed6f4763ea4f0b9acd02e066e6c277 +b0a9b607c7d54d08a06204230f6da30a +a9fbcfa6fb214e508cc8788baa099d5b +d21aad74be654d35a43b8859a43c0fee +6e8201d113e44c1aafb189238104f377 +f18e13c907324232bca28cfe5f3380e8 +b04a6fb90f014498afeefe1d33be3bcc +8fe2c19e20084f48a1fc52545b8b6a87 +cbe6e0dcc10a414a84acc5cc08171b87 +1e72faf8f88e49689810b6701ed19f68 +65ba5e0083824797a4a16a309e5e1584 +0336333ea9f84e4b98494e74529e031e +f51de8ddeedb4826af4b0c32e635758b +3fcf02e89292492d99ad25c1ec26cbe3 +e298799a3d5d4b87a15d1d4af52fc2a5 +b8ab1b856a554b47b9ef43b6c2e89b7e +b9e63643fcb841698286cfb9f39b3492 +d717ec46652147989c5b90a3a9a0bc6a +2b70993763034bef8587d3730c7ca8ff +8ae346eae2ea48858ad3ec3265f0b3f2 +1fa51efeafc44a729e86e9bf6f7403c5 +1eb719a00700459191208db7ca450f8b +d4ec03b9ff6047f78f588f327de1d4f0 +0ec178daec3b40de9d993b6a3b68411f +767f795eb4a649c3a16209a2614635cb +7bd87ea90ec44d73867e3a91fe7efefb +070344de71fd4e1dab48022a5dc9266d +bc2f3cd9592e4524ba4b637430d4e32a +a835947bdb514fe29446aad5bf223973 +46b4a7dadd3147c0a842fbca38010daf +fe19aee8cbfc44d68f2af6cd39eb0b72 +c5ddc586f0854a4981638287f30c651a +50ffb91434ea4d978eaefe03220d36fe +fde824c094ee4620ab482a6f4a6a3afc +3e08df9bc33f462bafe1fb42110e8e88 +9b801ab1aae145e5af5c7cdb52b92906 +18f78ccf07084b658e61c81b6983617b +2581387ab6454f1787e50d5909b325aa +e554428a881843a69c5ffa91ff2c3caf +e37e9b7bc8ce44b4af0702e07a549ef6 +cc9525c43e364839b706dd564692267f +3f5273ba29ec4f1db90ed330ef6b6cd4 +f0b56669cfde44019f9648955c12173e +2dfa849756dc45f2bf6c6b2d8100905a +3426bc4b8e8249b087a534844ef93001 +f7ac28c562b54b4db51ff5784a967bdb +004bef020bb34445b2b31e97552cd421 +55c0a624d211469b849d44a59a691f57 +c2883a67707946eabc541e0f4488dad8 +fa78ca4e798c43f7a7bcca2751712120 +43280ec89088499a94259c5cb7d28b20 +85a2964910cc4bc6b58716d0187c3f16 +bc204ec140f94cd3b4c9c22855c3f0f2 +e3173857f9384aa4928daeabff75da44 +cd511cc09e2c4fa2a7f64759afe42f7e +045b91b6257141d285c74a6bf1fceb9c +56afb1e21d6a47dcae8fef74c77a5cc8 +ae63a2b6575147c2b705f8ee96eab451 +4dbf1a7a1a7a410c999bb39d3682e5e5 +f3ea72c81cd443ea8e2ad72fec9be73e +7ab75054dea04187bca4da0917f501a3 +c99f906a5648445b96f890fead36643d +4150c4d220584b3f9f2af68ff5c2075c +94d6405522de4c2895912c0a45332056 +a853f349137942558e114ced3bb38a58 +08e9a9602baf4927846b59889a3a77c3 +0d69051b3da345ff8a8f775e2127708c +46e0eae500c144acb4a26d31eb8f6d56 +bfa1801f2a7e40668953e4cd64472cde +70b386f16399467aa30f43674acfb478 +7337db178c83485c923863164e3633c4 +46b641045c954194aa1f47d7570a719f +dc86559181b54202b8c96c4d0b6e0d01 +65e18a7f558c42b28cf090858071b744 +7f53c16ce9e94644af896b93e8a73418 +2adc430b322c4130bdaadc4f9c92886c +eba59cad60684ebba2925e35eeba7940 +bfdb4a5ad3d042e2a449d004ea9d3436 +43d82abf482649ac98a51a05c6c95737 +dd9c3e237b514fe5ba0ed825d39e40d2 +f6a49b8df0654c3b9823ffc473df1703 +37d239396fa148858017dd63e9c01c6d +88763e24fba84cb8b513379f59ce9c89 +df3578dca7f844ab8b7205a1fbea5ed5 +95f3d6b37a16463e9d47d20f064af3fa +c4c686361ba644fa9b10cef3461cc7b7 +080bd350828d435896af81d268785173 +41d79e02b8ee47b7aa2549ae139420bd +8aa0a3ac43364e12a14769e8555662de +2ad12f444ceb49919e2f6e0afa046e87 +7953cf2a6bdc4e6a9eefca86ce5900dd +d8c1d7dc47cb40128826157775031dcc +bf049e158d774648a0df2f88e1e04ac2 +8b5ebcb4bf90407d9d0ad9024488e5ae +4b59720c67c74be7a95e59d9f52df88b +c5286827e65f455a888968ed87eafa00 +9db6ee3d0f0b4dc7afb2b4791c153059 +4038cf88cd384c6f98ecfe670147fc5c +a68b49030ac74b3fbd7425407baed09b +4503c0643c6e484785d13fcb142ec8ec +dd8fdc8d682e469792d432389344a49a +8aa00644caed4e57837b2deb98ecca0c +096eb5fd9b044b7688a026eb7f6c892b +7efbe7e79b024764b3dd78e2c229b0e9 +dcddd50460ce4d1295733d32369683a6 +d501c3ff798945cebee84d7944edb19d +50a7c04a53c74bc582b82609fa1ec0da +9ce4577b75d44bb983ee75d07f25cd16 +cf637b83ff4a48f0a34dd80ca0e7eaac +7b3bfdab414148a08cbf46fc105e280a +062f7cf613304d4db0d130b601619a4f +9d17119cc0f041e39b2a11211a677366 +4049849e40ea465187c952a9a716a59a +d69f166807594444aaf8b1c72480e7bc +a1335f1604b84ad9acda9177743bd890 +1b0215e2f6a149d3bbb51d7874ee5b1e +14084f216e834241a7f152cdfa4e5d59 +b60b4974c3724f478cfe7899a4896120 +4e8dec7f7e844a1e8661bedff3df4ee9 +8bde6991ce9a4be5994499df9aa0dc89 +e5015b222a6949478d68bd6b38fc6ee0 +e603a0d6a62b4577b354fd699c6a57ed +4ad299bbeec344d89575050cc2ee725c +2e43c950883c42408246997ac2a16d5a +651a731d4d494d8db733a18272eb8cc7 +7330d379778f40c6a0fcdf79105778e5 +bc3166936a574268b6c806159a1e45e0 +a5d54163a10043a885f7878f7fae0326 +19c3819d047c4ea5b792d7dab5fb7a19 +5bf702b5d0a848c8853a28e5d37aa798 +fd2d4091773f40e7b0af1b11fb82cef1 +39273ba4b01648508b07e8f76fff0841 +acb6f67e793d409ea1a05751530bf712 +fd7157646a0d49eba4a03e17fbc1cb65 +c9c562d08b91405786285de43fcc729c +cc947f7dee0147b49b589998f667c19f +1bf8c96dc8414e8d8e1587a175e937f4 +017c2dbbc5034eba8dbf46e44dbddb62 +4bb4ba5aff48482d8ca439d564c941b8 +c693078476134862a64944062f8d3efa +5370268604124a978b558a5044ff76d1 +321b591c82be47829b0ebccc522d4236 +d91cccd6e51442d5879ade2ec65dc422 +b926f529275c497a970dd8e95c2460a6 +448e57880fa744e19e18604e42d64cf3 +0bef0065fbea496ca1caf3539c42e166 +d6149a2198ec42e899f5f9829b77d5b4 +e88417df67b843e0bfc629a673a22b92 +87723236d2b04335a04428610b9752bc +7bc9181b2f1543a4adf048e58b35a70c +0128bd0d7229499185abaa91fc54909e +ed53ec916641459fa0ff2beb8d440753 +ac1c4e8ddb334d0fbd464fe8370e5aa9 +227c3efa8fd84efdbe6cbad56fcc6e38 +44989de2c9d042569124d5a45bf11f28 +6656586a17db4590ab4d843224089357 +4c23e2622a8749979f49ad1632cab94d +de918c5094e9407388283c1e6aae6ea3 +907ec92dd9a949e79f4633c3cabb2fa8 +eccf22e082b74764ae96ac88ef29bdf7 +777e4e22b73d4c408b2b94845269c87b +93ad81cd8bbe4a25bc306bf751d2d438 +7313a909cce04ce0943c2a78f76cb817 +ce16a205f1f84966b0f698e495d5c952 +f9fe6b0c9e8d4fbdb281dd991f05fa34 +60992edb4e2640b2871353156cd04d7b +8aedf051c5714409a1171ceed6543644 +7ff9af367e2c4d26be44e6123f589fa5 +ca7f9103d7fe4f468ef1acbf805fd187 +efb732c609244c5894ddf896e8612897 +dfa314a5b6bb4ec6b3fdbdc2ab59cbad +a1da5c1554d840fbbcdef35f5fd7c1a0 +444c3a478c984f339935b78180541370 +54d279b8d1b94864abd6987912d73741 +69a33a97aa884e98be90b1cf87715cc2 +f1946f7e1cf1456086c9a1a63f9f4f84 +d0d490b69fea45cc93151a4b83e055ad +ccab11861ee4417d8dbd49ca5106116f +c5225fa2398d4b509aa49bf2e4e1360e +1534c1b10378454697ea2f2aa888270c +4e05b99389e44f71b22e284c05d380d5 +b98a30007e3a4871a0486bc83e9cca76 +bee57b826c9047129b37e6a1fcced99e +f043da4899c841bd8c747ddea2a3eb41 +4ff91f3dd21d4e6ab2b7e6b79b979050 +e24595629480417595a252700cbb9acd +9b0c3e5255d04159bb332fcdff4a693f +569b72c271c44106a3caa51f7d32dcd6 +905455b40c12417f98569a20206b6577 +d225389de8c24d1c9cf7102c740eccf9 +27425c1e783c4210aec2be5ee61a73ad +4eaa8a603b6a42218c8a94edde2999e0 +2d74d996b42d4cf4aa23ea0247207da1 +bf18bfd89efd43389781050230467d58 +2bbbfdb7e7f54b64a70c860f7356aa52 +e4bddf210b7d4f53ac3e7847b4b1cafc +a6de52aed4a840a28ff95c7d97f79564 +70d78705ad7749d5b25d0f54850ccfc7 +46863d3659974498bbb4427811035177 +05fe79102fd94079b11f0465ef37e4aa +4032255c0a454f4795411d6e7fb3bdfd +d49cbf9a118b47df9efa7e124753dc27 +8abbd6cde4f74d71bfd07356b6c523d9 +f68d80456dae416fabab3856272627a2 +3e40ef02e3eb4e4faf41671a37190a63 +b3c10eca1243496abdde1e0062c1f6ad +6bdb1305e851451cb3b7f849911a3033 +5ec9697d85654005b27fd29bd6df987e +ee968d0c974744c2a0c0c06c6a86c8e4 +731ed11e19724572b0d79e59adfbabf4 +8af19fab703c458cb7e14eb5de74e858 +360eb6f19e764527a98b157516c2a193 +eda91f75faae470e8d6461e0e6fc86fa +4f6c74f9f904439b8554078d1be14821 +703c2391f70c47bea4f86412c8b4738b +1f26f834704c452d89cee72ba9e5e02d +a6e910bc1dc745389ee2473d9a9ac794 +ea0e67f95b7948328bfeb353245977c7 +e863537b272c4c389cd0e47f37c2a049 +ad90a7ed75064aec9e121c0f3521e55c +4bb55d0365454b1ea276786315740e64 +923472983df8487790ef5a90d467cfd7 +3a12484defd64d5091b613396df3eeea +18190985986841909d7743c9759427a9 +f5014b2827b448cf94d7c2c96f2cbbe8 +f8ca2b9c4f9a4d94813901e9685b8ed8 +733c2622fb954c8985582393c0dcaf25 +5d801c03124e4fa184b4e3271abfa9df +95b3227e56204df4a00b37b38f32c5f5 +64212f86eeb544c3be69a7b5cdd2a308 +73aeb50753f440d0a721305c7e8deaca +dbefe8a2c7e14b13910fe91e89598fc5 +f861f5c77d884861a593171ab9a31f98 +cc5bd63518694339842c2c05de831859 +b42b0ebf61cc436e88f8cfdebc3b463e +6145d25461f741ea952d03a85c8d0ca2 +1520e6bc869b4c0aa6c7f718573338ba +891123203ffb44d0a34cd04bc06cb04c +8ec18acfc3a94d6f91b22e28e1bb7219 +4a713326b70a4a32aa7ec6eca918603a +3ea2a0203bdb42de8faa11dcc81aa9f8 +965082403694407fb14ed19eb109018e +98fe9589ef1f422ead0e9ee3e3b52292 +2250174349aa488182ac3e1667d2496d +733f971061ba4b688ad098e44cf64a6c +faa4e8a0221d48f4837b863ed7805acd +4dd6d2a49310481ba0717a71ef76f100 +7a69405524ba417d8a02acc0ce00a9db +091c13376ab444db9ca72b965fa9df2f +39f9e1bc93ac4308a92e5ee5fce412dc +51be72dc58d4437bb3dfc408c751344d +ee82fbd38ad945bbbcfa9418b4406b75 +188af88ff0ce49729119e42a268f29af +0591b55eb2994a3e91a874993eb205ce +e67a264850ae4043bb69dad7ae3729e1 +1a34ec54dbf345a98afed993c2aecbed +03cba69a2c3140f7abc013d42d455fba +e5761d31a04d44f9a18b74f740b01956 +57ab23e35b784a1db07f2e20ebd65dfa +6b43e64a3353476eb3a96286eb0e00ca +f362de39440046c9926d4af720d35dc8 +639955874f824bc381702faf7684d779 +8e2be4f8958246aea77c868b42bdde6b +d40aa57bd3134878b573ba48cfa37f2f +67bace5056304a4da95e9903d52650e0 +d36b4ef6700d4123b5329e59e6db48f1 +5d51a5e31ee84792a18046a2a8df8bdd +6093bffcd68a40e0bad27a945b305dc5 +92386c23092240a9b0948867ca88aebc +fe09d52222b64b50a84df30386890a24 +b084b9ed0a104b59b3ff4ed6e9ed0593 +f03e5ba5e81b4562958645fe27565f3a +64c4b2642a3c4de5a95fdfa44e7a5fdd +4c7848d660cf49d69322f63636a71883 +abf88446568f4303bcb0b2480bd6d87c +07d5590bb5164ee08b7c4b9c11c44643 +3f38a8a2273441508889951f6e312ae0 +c1e69b274b9d4b05bcc2761993e3c554 +b6936bc501034c679b598d00a4944745 +b1a6eed00f1246d9b8f8f08003c59362 +019131b6267246bfa44afe60eca5cceb +b3ada2eb27eb498aacbcc94b66d7f3a4 +5fcb3f108f8048e790ddb27b1a4291b5 +6bafea3c607848f78a42239755eac8ee +781678fa9b204421b6abdb2ecc0c6c56 +33e610a5e99240318b543169547b898b +5111ea327f8e41afb177121ef86b8461 +5883e3a8383e4fd9960adb00284bbe79 +8736575d64ab4adaa3d191c01db770ff +8ef7952cdeba4177aabc97bde0479bf0 +043526cbc9d24c48a0614e07df838f5f +5f988ebf336a4e6a959fec74a188b041 +87af0524c71b48179c1cab34cf0350be +97b8b4e8a83045c5a5673f19d6b21e39 +d4ba24895a324321ab7438e8d1d87a39 +f60f796c34e64e6ba55320d40d07a690 +17bdf341fcc047888935f67a05dd2fea +898a07927b7b4e038662864268a4a4de +9f2c4930e87d44269466d4fe32947304 +bd44c05b4353483eaf89745feb95b059 +a81888a64bf84a6ebb46cd770050b132 +4c9816c6f1c04e2baa3bedc449b3dd9d +2dffea891a8a4121af4ccd29ae9aed18 +61f557ba982748368925e02c04ad80e6 +e45616f913fa43ab801289b52c6577ba +db5f9c28708142909b15212625a127f9 +0995ef51a5354cd1ac59f96d97ec605c +5849e74c343b45f887eb8657032574e4 +c4a85fc7317f45949da909f983efcde1 +0bdfe51cc72f480698f63adbb8086318 +a6e948b67b0248a8ae4157b1775672b3 +088fe6f815854b78a1b3998cf04b1583 +4da765730716470f8f8d2e2701ee7463 +5a440ed5f8b149d59e68027760fd0522 +c03374626b32491188a8c9e6a6ac87f0 +6f7f4c9ba5de483b97244118aa847ba1 +e709ff43041347c8ac9e2cc9bddc443b +b577ef44d92342ef8df8f01c926db0db +2c21f18251184d5091f7f03b429834ba +e0f1701fd1dd431f9280dbf540494ced +c9ba4062c51b4aac929a9d0f3c2cb5f5 +50eb97832f134a1a801cfa78f2d28292 +7df28d1b8c314a9081dcc7c550b5ae7e +0b2aa45abf1e4d36851cd97b6b8e99fe +0ba23e1b5ca346eea78fb885dd1a59d3 +de02b16a52aa4eb0a4280f2242b52b1e +4bb4be63c8fb4b469e787c30e81f9e71 +11aaac67c47e494ca6db891def8e829b +445498d0cd284f0793894ba768abd866 +accaf450af284db7ac55ad83bb6dc00d +ee50e01adc864ccc880caed9b5eb3bcb +43d928caa6684b6d9b03658b4039a83a +2916ee023b204aa99bfb8907a02ceb63 +efd4ba50d0734615ba224f9c0dbd61d2 +148504937cb840f78f0f22b85260d243 +5d04379f28bc418cb0699055183ebf92 +106a7193625a4472b77beb3f3efa5bb4 +3fc1e2c625ed4faa9fcb2d128b0394fe +8b9f52f183e34a36b7105d02215d0b6b +fe82c7e6699f4dc18ea37450ca61a1bc +d5b01ea213cd490eaf98d0fb68848306 +471a26eea65441cda4c383fac6a732bb +356031a2c4d34638ac2aa87a7f4302fe +ab25dae4b11943a8a2ad2287a0c4da3e +f0ce6821cca44d63bbe1ca6ff8f6913e +2015c029216b48f8872ae64b5452faaf +abeafbc37d6446058e1be53e67e0baef +a5bb7def7fe745829b18361a830d0ded +f130ebeb60f24ed8bd3714a7ed3ba280 +558c6158334e4e59be464397638d16b0 +7454d35729114dd2a8abfe8594891ece +78d62891770841b9a616ec04d98dc009 +7a842fd1aee2498686717be52561430a +4716d162a7ba4be0a489f5a9dd3c81e8 +5ccc72d43f0e4dc5ad5ef8eeb93cf3b0 +e5bbfa708fce411fb6ffbd18d50c971f +1207c326615c43a78e9944c33ba401a5 +a8fdfaba559e4f9899944f8d50f2bda6 +a78a17eba65b45cab925fa01c7a91380 +668cc358af5f4ee0997ed28c2996ab2e +2e5e3febe02d4cf4891ac045101f4ae1 +dae8940770ab4937b4d454533b0fb0b4 +f94fc652afd944c5b17da244e1a05b72 +c371737143bb4e38b3aeed591c08b9ca +78339a3e989d4720a317dcd59ed0f881 +9c09445c62f94d68804d3c822740c69f +76c92ae8920e4bd4b553122fadc8d570 +8231a91d0a1f41c88b045fe39d2bb7bc +0c4531d8ec8c449ca9e79a390a4707ad +857b2346837f4e4790cabbab2e76df1a +c1d4b28e4f2c404e944315ff0d2cbb2d +a27f92cc10a84afdb80fccfdc0bb5957 +7537f9eb3d55471aaa061c0896b7a740 +c34902c474b14ed6a927f67d79e0cbdf +b4bb8bd7791648fdb36c458fd9a877bf +91e06b9b94c64464804cc897f8c755ab +44962bf5f51242a790551dc6ba423ef1 +3a80c0ac82ba47f381b002448b10cbb6 +4ab4ee46dad54ad6ab608d88eb19530e +3d4a4881c25b4dfebeaa6cc70588e17f +69ec21a2adf249779d307ed55e5a3dbf +50492962b9f641669238d37e071e0bb9 +d8143872de8d4c6b85af59cb3395e9ee +26137866131f4c638ada57d85caea01f +1806b99f1cf042489cac792fa6c0149a +a0a353c03a6b4ce39ef1f0c74c3df1c0 +2ad7e5e86e8748e8baa05ff0e68676e4 +3b8e7fa8030344aa94324f6a1d1c5cee +824ffd9227004b52bd99cf1239e666e5 +9ac3804f84b84c8db8cbf39cef76faf6 +2138d71939cc403b9e740396a79fb9b1 +6b5f40ba934a4e2ca3a6e8419e96eac1 +c9b9c316434547c892e7ac7bde27a74b +0e38ef02f3de4711b47937ea81870f94 +a5f19eda8f00477b9ba487c7335a903a +341382ccefee484b9159a08ffd0e96ba +60f0b422eaab48e89c5dff0d81f11116 +fc4dfa3cfffc4d96aea34fcc726bffe1 +e3f150488ab843bebaa367f821fcb409 +1154bef203ce4b499d7c94d1cd5e4460 +f7b5e46465aa4214a7c5d389a517e925 +1147c87f17cb46f6b0b2ee2e6f5dd6b6 +b2596e7b857a4c89ba0d8754bc5a07be +708c7214aa7f4c30b5656f046be7ba1a +f24171aefcbe4541afa1e3d958366f7d +8a44869c542347fd8616463c74e0bb59 +b51e82ca7a934013a21c243c2b9f85b4 +32427dedc61b4fd0aacd976246117fe4 +230a9d7b8c2b435d8d20b1ddd12e9d0e +b542edb18a1d41f9bad314e01bf6f713 +e747b293687d432fa0604cf4473a6130 +c32281877e414502af5edb304be7684f +2eca47f8e6d3411980690c343fcc0162 +cc72293fb4ad4376b8bd6a72dbc0a053 +8bdac8c7141c4992aa1a5caccaa5e4c6 +d85b6766605142928a18091923f10120 +77c8995e6fef4dfc9744780fca98bed1 +437380ef2bb14d7bb63e41c26d4d1362 +c58368b5f05849ed935ab5819b87b187 +7df28e36733d48cf80bea6e42a626523 +06afd2b44b0f4523a85a5824b91a965b +4a379c0cff1f42369d49c56300c4fbae +fa2fbbe8e8324919b7e8a532fab33724 +0739f70ef74c4678a4895383b9447c3e +ca4ff3bb59f34232bf626a8839b36018 +ccd28aa0c67c46b0b9f918a58091fcca +6d677dc282b84728b9b7e39cb38309c9 +a8c4ffddfc4448909b48980530256c8c +eebff658809147f6b1738c7156dffe08 +cee96ea6984a4cb98cfba484a83c8e0f +a615b94d69124745a6b13a662366ffe7 +4a143fc43a234425a1b912df89dac355 +9334e4f73d7d470681688c3c09fc8edd +e773ac9fd3e04874bc20ee5d6a946adb +a06844be689f43a8a6e39c3515931220 +b7659eb02991433a98a60e0df0d363f5 +aabe26b113f440848b8a31d2543e154e +04ad5288fef14bd4a332a30bab550dc3 +b9dbae7ef66241e8b1afbf00af34de4a +c01608f095664cdcb00171e4cdd3b06a +512bf164aeb647e79e2fad406d11a982 +989dd76b37aa40c38a57cf6159e72a55 +6942052efa664d8e95e3dee03c1a21dc +18719d59bb62490c99779b4fb4def854 +fe4f7047a03247ecb5ef7a587de4e969 +1b2792e199ed472ba2d7e9d62b1d3565 +c582bc6fd8684866825bee8e9c09789d +2f77a26ab3ec4cbb9e8f0b17f2af2786 +6a1c3ed6920a4c1a81d1a995f62fc11b +ead53728d4004a6686de6cb323d39007 +87f446798bb544c6b0dca2504b1f9d50 +39d3b3dcd1414452bd49ca5b73b65bcf +95c4008c4c764c078f679d4c320e7b18 +111b45e33a8d4e39b1f37f269e8a2069 +4b1eeac388e641b9a6b975c32cf41439 +dd678588fa084e108b004d5b92328785 +c4aae071cc2543eeb98bcf1a76be40e4 +c5b65ec589bd499d9224d43db9c00509 +0a5439cbbbbc4f03884e82c49a5d9666 +d51ec58d8e7947bcbc9627c3e1b0d808 +2c8b8737e70544a1925e69620b2c0ce2 +4c093a58a84c475e85c01a27c34256f3 +0f4fe85e2c044bddabde194665739c5b +3d94c44b36564ffcaea1d02dff6a4c74 +47994470b8704b309dee48467a58a2fe +2cd8d1032b53426a92abb64a71743aa6 +2a272c45bbec40f6a4ddd6a7a83a97ea +c4ca254bf39b46caafe47ef62c8a1424 +33182480373c4c12a120b45d2d612155 +6fb694271f7c458e82dcbc1340736831 +3aafb89ff9cb4ae6a1d6e20b7a6d1354 +563b39480a6745d599eff1c90a38b47f +7ad37a39f5534d57bfb68f34fe0fbd22 +aedba510bc2c458c99bb6aa7fddf3b83 +7b0f1626f4ae4764b8859cfecb5ff3b1 +2803c3d1e17b4ca69b16670f73773a76 +815d12fdab2a481081365247c2f81bd3 +7a0b72c7d01944a8aafab59d44eb120e +a09908a3910f4110a835f15e0f774da4 +9a179f9803734a3e95630727b9db3477 +77c72e749da24942b34cc2d2959d66bf +e705883c8cd9496986b64f74083f720d +4696db7dbfbd44c299e071cc7ea65d6e +38f7cb1a7d964959b44d4a2c09b2a2a2 +87368cdc5317460eb3420d607e9ada0e +e5edca069e6c41dab5178f391ba6c76e +dd727f0df8054b1b8c77de6c12d16fad +0202478645b64d24bcae4eb58a2391e5 +c0b73b5a311e4ebb86d2c8411aa7ae44 +01ef5233779b474983a4c1f552107a45 +56f3fb6b0eee4bbdb68babf0bf4e90b4 +f123ef50ca8d499f8692a66a18fda6b5 +f87c4873073d49ada0f0052d0617a579 +91a65d069fb44892982b46be0a2a2553 +c83f8b1d56cc410292336bdd76947abd +b1aa9affc15f4fe8868f5120e16ed6c3 +cea266722325474984c2205a88c6fd52 +e41dac19ea5346cca73b664e8577488f +acd3c24b438948b7b352cc1b3a126c90 +c2a3c105953347d5b5d206bbfd7ce87f +c1264fc4cfed4f80809646ec39f76d20 +e0de2fb2eed747edbee56379f31b6777 +5c5bc5a44cd849998233294e6fb52d1e +e8a52be1754f46baba29a353888b1e1a +8d17cb0964334a6cbe4b0e293c238956 +da037ebf427e48ca8f62321beb464ede +ffbae2e9767348dd99a991ab7c9e8262 +21dd5c5356b148b6ae8c279f348626fb +b6db59bd7f10424eae54c71d19663a65 +fdb8227a88b2448d8c64fa82ffee3f58 +b3e1553b0c104cbc9ebdb0db7d8c1cd6 +a141f5cbbea946c786f95af5d0b6a4f6 +43c2184755544c86bb21e87c47fc0bbf +ed8577a03a0148e68e9c1c9dcd59dacc +a6e8bcdb300c4a40b75e2e3788914269 +36af1647d51e4a869af42b7127d64558 +90769b4634b54b03989ed38252e6e293 +e35b87439b3f4d6b9dc0a684e72278ce +b882a4fd9e554e76924f55eac40d69c8 +2c90746141b94f0eba8bc1c379d4f4d8 +3049fcce9cfd4bf4a164398966b3fd7d +fb8befba62114570953cb63f1e130083 +3155dbb685834929a432584f3a6099f3 +03be182bd1124f08ba6320bfacfa59d8 +f4bdcfe475e842d6a95972211d68694c +392963bf05984f5c8b7fe580282d304a +c1e71fa5dbcc458f9c85231d11d1968b +ae95b9c543404c9da64563dbd626e6cf +fb3b1c8073034d95927c3a91af195ba1 +4ef3179268ee4de8bf12e9f4905bbde9 +985a8ea1da334e3c9cb3545ef2364310 +a15c23f99687460b9a4763db10f2659d +97e35731d44a4070803b0e63dd3ab582 +38cd4b6c99b745d583bd35439e5fa1c5 +c6f97125d3c34334a5652c2d56897cb6 +c44c221824af4523bfd37a3cb5257979 +0ce1420f5d3045bfbbfc7e3683761e1e +42c6d87149ff488dbfc7ce61ea97c272 +71e7aa497fc84f638851767a3aacad8e +f00455ef18b44bc9ba1844c546a675d0 +15d00d76890d458ea454d34ce08cbda5 +ae3727ae2a974eb0aef1f42a11d5ec2a +2cd197434b5340e0a322a0893b9b08b7 +06b7951d4e2f43ecbc30d8f00cccb499 +8acbfe479d574f69b953fca7d477b4d6 +8e511ed204444bc3a19cb76c653a63a0 +b77fcf18510f410c915456193111a8db +463ead51d6254a12bfd623f840e5ca21 +3b30117fa5704683b71f88fee54004dc +13b66fd14378460aa5e8655c7e2af6b3 +c30b276e2e174109b8e159512f3bc8da +328675725a3048e5ab1d859d07dc96d8 +29a82673d9304ed3ad586ff43062a9f9 +3660dbfe55fa4e2fbd731264ffe0a94c +2b595c801e114eb3b3def91cf9a20504 +2b59a1815b1e47a298d4a3c084523d72 +2c7e733d9d2b4b229b97bc8d13ce04f4 +c0ea5b0b7421464c9eb0f62577ef8eb2 +ea39fde0274d48188b5deae9e07ee179 +4bfb5a6b0452458998e7cf28fd8c048f +1dd3f252a4344e0bab7d634555f0a052 +e8b1fb98c62d4e6ebdc48e70e633e6e3 +3b321da343714e9597e3e86af8a0a7a6 +f1e8cc5cf9584f7ea6c2570f66163275 +9cd840dafdc24fd6a800fe33cc3d4488 +a273497c03494d7bb962c7add0a7ddca +622a6275e0154c92969795ea4d7ae7f0 +08be716d9cc94ca3998bc3b38d95cdd9 +4bd4fc0e630b47d798314ecff829e0b9 +600520a16ece4ad69504eaabae7ec47e +14791efb33314b02ac5ac74b47c36d14 +43ec6a3241df4279ae477a2ccea3ef05 +3f0a8c0b6b6e46ce99da4db863fc754f +fe604d1416a744dbbaf1aaf96381d449 +6023c6badaa646fb936218f77eb4de11 +85d828420d6e4d6385088a149abfa368 +c244f7e2d44e49e096d0eec440fc90a6 +1db5ebb4246f4adcb1284cb3cabf226d +f47d1265b095412481afaa41fe2de24a +ec29364b59b244b59c7c048ed6f7f0ed +06cb1d4606974462acdb130de5ca68a6 +d55aae0bfdd8424cb4f7f7573a79f009 +6503a3b060ee4b79bf3f7b173ccfcbcf +eba40eb9eca84aa38eeb3ff67a386ccb +0bea4eeab5ec4ae9b3636057c631fb20 +fe8cd72634bd4bb3889f38feeef9bd8c +9915f322de534c38a716ef9c2bff4ac7 +145f6300e1184cad805e5ece2b09dffc +5612acc3504b4645ad64bd2f7fe97ebb +4f8a7f58e55847d7a7062885cdc2d7dd +a9824884957045829211090035900302 +b4ee64eab1824a9296525a91c5b5fd05 +cf72563cb8ce41fd87f47e04eac1720a +e83a1b69bd204e4187f30ffccea456d1 +2976934488a84a9fb84e9cfed4555d58 +7f8e8616688649fc9257a8698882ba23 +bd1b2591641f46b7a8c30c881bb463c2 +529e8e66d0174554a02af4cb148b7b00 +c0413a9a25144c908e9277633df66cc2 +a77c38a190204ace877fc62b77f466e1 +40fee272465042bb9d91788c916e9502 +c7f7a78ec67d42819bf33dbf82dd1bbe +39498c5ba771460cad3caf12b2ac2f92 +e57094e36af6477b9b4b1e3307f7a8a8 +c4cd974ce4b34b229f8627b647a32250 +22d097107ccc41ae873948a76825ca61 +ced5d54c132c4ac697d9d37f0e7732db +4fdf3ad3c88d4bb58ea7aabb9bfcffae +0ddc5b75bc3941fe8822e79aa3244ab1 +6a1419b7a698497b90916e9f21dd5264 +27090e998e4947d69bea68738864393e +4ebf4cef4ec642ff956fe680033b410a +90d4a86595cb4825bb79e5b166854e10 +84b39e6893e84ec39dccce1077d694f7 +eee1a1ebdb614f38a722b52e26ebe038 +db8bf91a266e4a13a10a787c246d8780 +42467088d63744fcbc917d9f9518077f +a26c8b185911421aa20cfa12d3176f39 +3f4c5e992fef4eb1bad58e576ce197a6 +e820f124728f417091eb6be6517e2279 +41f7071e3e474e26a7898a6042123974 +8481ac383f5348529d366c99cf86ab8e +c1c1df0ad9a2460aba5f15206818bcc1 +eaad34d0a1ab47b0a2a29c83d6fc22ba +0eabcd88d310476c96eb4cfeb3c7958c +f1a1c79ab153475ba926ef8d1111d59f +c9a94056e33a4fe29ead7bb2464218aa +19711ae60bce4ffb9315074fa7ecc94e +0f692fb8442544cf97bb742fa09d225b +90d32979dac545c6a465399e453c3484 +a132fb245d624274b218338c77376cf9 +415089c1150f47829e6dfcc3f54475a4 +5f151e09f3394314b11f64ce929acea0 +94fb019aff254873914f39b830953e30 +70805454ab3b42619d38c7e662dcdc96 +7aeae41398f34c4fa5de50c2e6276b11 +e403051d77f84c1ab359caa0866106b7 +20c65e01d9ee4e06a438d9523160d883 +6337644b5d2c4ee99312a05570af8d8b +09e3d40c21ff4747af88ad6a3df75626 +96f87b33e0884fd599ef1a1c83ec5f8c +8cc4336395c64a95a8f986a575f0b5f3 +b6a0c8b2f891484c9d95c1df64ef1662 +0648107ec2b34ea9ad6f9f104a0da534 +acb463b3910741b3ab7af89134e840be +8485da6530904916bdc99cef8d58f95c +cee1570d79fb4114a8709fc1d08a05ac +9816819af90e4f28a7ba853d48516bcb +9a131b2dfbb04b2aa5c06ba9667d6221 +e868e007bacf425cb0b3df2b44397bf6 +80928bbaf0864dd985d744717d2c887c +854f9e42e5c7421fb93a7f4a26418be5 +63e2323f49db4793bd087e67b20ac350 +634e876bc6374e46ba5b5554bf63cb75 +f6b589d0577a4eb899c6c14fc52b1049 +61b448368b3b439a80937048b3f9bb42 +1271987b3fed464daad412ebce14d33e +f341522dc244493d842c0f61e61c1f0c +e55ce2838c6b4ae49149586af72124fb +3a51cfca26b34da7a8ac02af373cd130 +22f50f6ab73a46718c9f54e0ced9a8f7 +c21be071cbe44b96abf7046507305c97 +a537b88845094a8fb2a25c29a2ee7bb8 +17b2119223214b969c4dbe178fd80015 +df587fc2bb7a4c8587604583412c131a +43f24fc3576549e092a976a61cd98aef +a53fe1a211b74d9a84b27b9ad9ccc05c +95e1d142682c45d08bb42079e3653f74 +485e5ce9d8724b68a02dfec6236406a3 +eacea7ef80f248da9c70aa1b5693a37f +00cb95739afa429a8426e2b415e19829 +399463ec209b435b8c467dfe343d7628 +2da86b2c453745eaa1e01a4c9f623092 +844892096f6f41a7b68fa71cdb5522a0 +9c4f7e89f0364edfa7ba5a03f8542e13 +caa582bdf5824596925d7be27f8b349a +c056df51fcab48cb8aae366b178c9537 +8f4019fde97f4ad09c45628fa2a253eb +c861646295044f7585824c827a524248 +d64f26970a7a489d90811e1dad4daf9d +b865c92c3ba943c4823de05ba15946ef +30a177eb777a48659f2eb4ea70375d29 +eeb043ed9c724e6f8ea6693977043879 +79d7d10b30b14ae09f2ef89872868560 +d6d3cd6d2d2a4a13bd16d0667410cf1e +d5a5b2c4ce994bf5963a2714dd71f1ff +6bae80d9ef9440f2a53248192e42c58f +d4050a2ab7814f4a83ef4b065f007f28 +885b4a83ad1a4db792715ba24c7a5d57 +928d285bcb684da19dddb2f684b5238f +dcedf982e8874a03b5df3a8c187616a5 +89d85d1bea1c4dd2862f064b4dff1e38 +442a6a19b1f94a1387c6be0924e15e92 +b3b13e26164948c69910119558616485 +e198f7e92cfc4802a3bdd1a10a9a44de +fca3823439324d57a625d5c002b7e038 +580f8df75f4646f2bde77e49e93d8cf9 +95e90fcf35cc42fb86126bd7dc4ee769 +413fcfb5c1db4ab5b56bac05fe923433 +22ac998056374bc3bd82d78b921debbd +1497aeb5b82f4f9b85642721ec170ecc +47951f34aa21441eac07a67641763e3e +f79d8e4ee82c44b495ed623f14796b62 +9aed1de5f9434435a461c597360d9a91 +ce3382f53a27486b96d9ac5ba2b14d55 +e8932a4a66ef462a8b6aaaf2ef550c15 +4dcf61939c924f1a8220fb589fbe62f2 +c91524e74c8c463ca3ddf71bc73911db +1d13f35582814dcf86b7cf28ac5af12a +f0916a69ba514ecc973b44528b9dcc43 +3770d46e9ea8408d87965bd52da4687e +d28690af06624a80b24bcf818666ab1d +05a830453669452f9b25f649462e3a6d +cce3dec670fc412b89a5ed963c79b7ca +41d1fffe051a41ac8956bf73a2a7674b +bf2f4c168c41450fb77bd1fceb7aa43c +407798efa2e7467c81a79d2e516a5544 +f037c301a59d44519af6c2e56b3cd346 +4af5b7533cef44e599d00e7063d6de63 +02230deb5a8c4050824692b2ca4e9ba1 +dea61a7bd5c7487cb74beda24c214d75 +c6f6d2bc33d94a0f82c3edc8c0aa2a39 +86881130d2264dbf8f3033d0e87daaec +1006883bdd9e4fb5a7321e654d4046dd +87322743d6234d43a3348ea8617aafd3 +81acc3b3e79c44188dca5d781f37df84 +337da284686a42f79c52918d862e95c8 +a495e0f2c88b46b68a1ed0fa58c27e09 +dd46240daf1f49e78016b12ebbe4e890 +81c1aa28265b48478c2f52da6fad6faa +12574793d7cd49f59f075d8ada1381a9 +ad69f4e6e234449d85ffe5b7c8be467d +b9ce6f19425645b3be2cc218d56e0982 +168e2ff924404046a14b39eadd4ef051 +cbb67bbbe42e42189931574ce0d4926d +cdae773fd7f048d4bd035fa0ed3e9d6b +a07c8a9f559d481a9d88309339335a04 +5fd1a7dfa3924792bdf883d7ab330885 +4ada74f745184909a012f9018183f1d7 +7fdfbbf11479421884402de1eab2082e +cea782742273430e82d2874624ab0dac +6f6cf0d96cbf4e7f8c639d6e2b7c0aea +2a5a1160fa2e47a5b193014e54977702 +35834fb2bd1647eb944d87219d1a9c1a +57d62df35f4541e693addf45604f85cc +cc054b30647b485f88675142295080fb +c99aaa2b602447b5b893f273291d987c +9d5c53fd0fb543e2afbcd4982ff4b893 +045e3304139b4db79918972ce228c933 +545c9ad4d411400f8cf93e97242f3160 +e53c551b2b614885b998e22749efdd75 +f1b23bd1614644dfb748b8de37bd07d6 +ca35ad3677c54042bc3184ed140d92b2 +01ad4a8234ec42efa916ce0ce65e9a9e +bb28444c224e4a4e94898e42bd50851d +71ec6a1de7964c1fa13e67c5276973f1 +61466ebe080e4d22b4cfc39f6c69e0f4 +9a633eafd4ec41f099eea1b5a435ffe0 +55273849a9394345b777d9df6438b26d +0e3e6cf6a7ee41e9af1f398da518c5ef +971452d0652c4fb984bb92151d0c4307 +b2ff4439edf84d99b413ae5aa8fd46c2 +70005f64dc8a4250bb3017515b83f878 +984038932f0d4586a3c619280cf89bad +76a0fe4d91324b9891d81faafa43e8b9 +29d864449f8040cb9fcac874da48da0e +9f881201ee344b0eb5fda2ab22197bcd +195d245f8c9c410b916ff8bbf4b63ecd +1059e4a648704d3d877a541c83ba1177 +a67015b5b2bb48cfa15eed7b20e7f195 +9c83657183904b31b6fcc1a33cf34b23 +796aca3b8ff44de98eb108fc7f1f8613 +d4aca7355e284270897fe9a778588fee +8908370a98644d09ad41e3545500f7e9 +3bcaeac1fee841ad876ca71bf21aba0f +71e4ee5e07ea4f9cb3663cd199cce0d1 +25fb43458b864c5d8a3e792e9cd218c6 +557b448ad7b44870b8a2409a7d7e768d +92ed1dee5a3149cc92a862795b87ead4 +759d4ab0839c4dc58aed404a5d512456 +16d433e744134617838f60642f7cebb0 +80bcd0dc25c04c8a94383e0dfc49fdcc +215542a03c634080b302875ccf66f956 +e7ff0a461bd34502a113920fda64f642 +4ecdf690559b4222b1f638ad18264ace +6992dae82b99461a9a43c2debd84cbd5 +ea688c0d65f64220a920fba40c9f2618 +275eb6c21a0a47b3a87829751a7e7721 +5b63120d60e643869b47e9878442fa8c +301cc59fdbf041c787810288f3255709 +7c05b98d60884e12aa05ae00feda5bbe +d72a69945cee44d8bc3b736e236c26e9 +c96ec380d87b4eb6b55549cc17a0e395 +fef52ffd517b4e56a3df2073a8dff903 +e348789bde904c2c87b99aae573637e4 +67746002feed40c68b31b87a0670d68c +b4379858a3224dec8b89f93656ccd156 +9536a021944d44abbb8d3a228560bce2 +0212e6648fc84e66b2b33b2c652055dd +c1511756307a4c63af12c67fef603dec +fab9443d48e24fbfa309187df78d58e6 +0f5b12ea1f474887b9664fd7a171c17a +85c0b43592a44346a0f1ef26f9d66dbe +c8b7cf9c7f5243868b4b283896367b83 +305f2b09e0de48bb919116026aba8f44 +14d12b29e7fe4c889908704e48c4e318 +c3a4ea9eb4574ce3981ab7f12403f532 +197e75de6b454be18ca4a0829ef2d522 +ebed0a3af94242a6be6bf0f8ed6cd49d +411bfab979fc435eb129eef157bdf671 +57dc3919998d439895e800ee5e0b0c64 +10e96502886e461e9cbdc7272bb1ab1e +11aea877a138495a8acb2f1c27c5d72e +294ab037e7004247ad775d657d3d4144 +fb62c1b7e5b24ab894be4f4da0c1ec34 +000f88bb21164319ae797d315be6bc0e +5d08554d639840d8a48cbaa2e6115d3b +3d4ab80086b6415eb6e10f08c06841ce +4c0f44f3884648e5b89b3797c4dbb944 +1158924818704a6fb8f3aa48649186ba +f13cbb13a3ac48f4bd7e1dd9187a55d6 +885bdbd6418b44cfa973fde3d418c5ce +8d6be6f1ef0a4f2fbfba2b77adc0b374 +381e38bcf5b142ebad2c26df44d8cd11 +4f051ab415dc4ce4ad81ae5f99da477a +d68b73d0d19c42769ff49216e2f2126a +ce49933eb26e400a82b36e920d79c22d +072aaaf01e1c4157a5f3b5166d7f021b +c621a1ff4fab429191b320279114db39 +a12059a9ff8f45e1979bd1af6fc1b8b2 +dc4a1ef856b24492a2290f45c8156d4e +05deebe7d64145f2a81da184ec294ed4 +e6c4858d34f0440394c2aa772ebaca38 +878df3bb45804a2fa246034420d03cfa +af85273c56464aaa835e57f8377ec7ad +b4489a25900c4605acd861e2eae782d9 +ed19baeab2d54fcab07afaa73376f94e +6937a8e542934283828fc2a553dc7de4 +330bf3505ed7405ea9896c8214990538 +94a24190869d4cb28fc8d670252de71b +8f56a64e780e4274a8ff72236540bb84 +a0ea4633726d4fa4b053f13c12b6bd8c +58f794f25c2b48918e31994195759ddc +cd6ad265b50f49a7921cdb3277526438 +8f07a87f281343009ff480f8d7e5db83 +db4cf8d2c50c4bb7bcf9f6a6b8df3d9e +49868f0b7cc84b93a7aeff01fcd64546 +177ff2ea25214145a708301b2657c529 +3a12c6619d0c4077a88dbb93c7a1f0fd +4dae36c0831c4ce4a66af78b8f2c4d9d +7cd0ab4306f04645ab6443ea27cd8e28 +94462929297f42d3a663c2e67a6c4f94 +a19092b10c014390af133e841cccd771 +8084f30382034d3099b7b3de82fed120 +bb7e31d730814e97b882bee710535b12 +54caa18b2c9b4cb0a65eee107f8169d3 +d3091630338141f3825a6fdc6adbfa75 +a19ca78ed3014507a0c12e22455987e3 +d67ed4cbbc0c4477ba5d89413e715c82 +efd6c0746ba94f26a53d5d820ba635ff +c801e2aa5feb4a3b8479c24875e2939a +6e3d0647797547a89bfe61405740e5cf +ac18467b45c341c384b2fbd7e3c6f745 +9104ac024c8c4e4b80e5664c8a18fbce +3cffef5a53b842428dbf50d95726011d +4f2331084ef24a759580091ff7575fc0 +a0dff18c6eb44a4090012574802a384f +7ac7e1d92a8a45108916d1ccd0908caf +0e92e5abf0f34444922783a90472073f +9bae7e7d44334b9bacbf0cbb6d038cd6 +b39fd711f1c44000bae69871cf30fc59 +b41b41a2858046fea0021f677dc010c4 +c5890a678d754ae1b7645f94381c94b6 +36b97734e6e6437092707e82125ac902 +155a93d394c14699bc261ae3fbbb3f08 +0256779d7f5d4aeaadc15f89ab24fb0a +c0555deea41d42688d43eb65fa0844d6 +5913807043744e2782fc841d52ae6e7b +4e102eb3e53b4f71901831cf9822db8d +e56c715f81564b1ba5455c7b914b1349 +4c7f4bf2735f4ac3a328288c1b275b78 +4bff8adea43045a5ba9ac44946ca0bd5 +3ecef2b424674831bae97a48c03a5306 +eed10614b28d4b9692fc3af550f05890 +515ec5fe998d428c8ccc6e0b1e550d30 +9e10ae30b11b474a9c759d6a28cfd23d +d8e66dc4a2934d0887782fb1d4fe9e3f +034e31bc4b8a471699c3056b671b97b3 +3889bf1e6f744be7857d35ca8767a628 +834be506a56c4880bb061bd48decbc31 +1d99f8f2f14c4fb68947a07e3833528d +374a3d2f72364ad9bdaf29197ca2f843 +0a2d39bf74694906a69f45a4b99cc7c1 +8f4af0f494fb4a01924d53ee7c34fa35 +e0966dff6bc340959a87bc5c7dc448f0 +39f9b772c8514dfc8ec304bf5c85ceda +e2ae105a424d4ff5b6f200921cfbe597 +8c262e6fd86d442ab0fa4b37ab46223e +3de7de1d7aa04832a056f596a6174e75 +773d387e68c14127a0fb1101b0b9a751 +b6dd89dadb104bfba43fc399477e5a3c +2005fc546e224c9aa283a496a175b806 +6ebecb69f35d461bac7d2ced50380c2d +4705d3b006694c2da3a6662f34060bfe +6815a7e99dd54e91a1b2a248bfb672b7 +0a791f64b8c349e0b06c16e645314c60 +0bb7db373532482d8520e8ac109394ab +953eab03e608463197bc3665c2c35c7e +6ec6be4b91564ffe9005f27ad911bbdf +559ae91218c641a88f57ccd6d9522ae4 +87fe870bd8e04dceabaed89bb2cd6e14 +40c7776c79d04366a7f9361ef8ab9558 +e52e5e0ebbd2473a89176545349dba34 +4f38ce9f5cc9496f990cdd29f2756a40 +f723433582e1405abf7c3950f781f898 +6fd99dee17cb4af0b7474bff3114d039 +33065ee8618b4e27bcdd46a9776ef534 +8e9a045134e044b58495834f87101ee7 +0b6de1b8944342b58b334653de5a68a7 +5252ba851ec44491a79a26c79a2827ad +94a0be547579426fa4ce901d6eb8cbab +78ad52407559472083428637948f9482 +85ca6ac110174c0c853f7d8f9f084dc9 +847d1cbbdb794e3d861340c8d5f44ce2 +1ae9df327ded4cb6a9d0115d20316566 +5319ac4845d84e6d979933c67b3c7374 +2d574d76425841a0a31b5e03c8a8570b +02af6a8de3a7493696361ee81650442c +b872e2c3f4f7457796edebcb7c0a290e +09ee59423b4b428f94f01fc5beccd227 +5072a6cbabee47d7b2d7b74865bbc03b +b39c8663081c4c9e8c5e14dda1c67bd8 +9228c67bc67e4396a4cf286d4b4aed50 +e98fef78c3654b148c1bb6033a6465c9 +f5d4b4e89c3440249722b503b2aa3e35 +6e91e8793ed942fdb6561976a893f4e2 +bedd61104d3b458b93fe2c78874ae8e0 +3a87780ff9c9462db4fda9287f348f4c +99fb4b3897f24a4c8e774fbd7cdd060e +7f675086fa7145dd912f272218f05971 +1faedc70b6bd420ea747970d7ae05631 +73e7721b8546482696f2a1289623e78f +41b9b4576fd043b9bcda02fc9e9fd138 +aa1cd41249774e5e8105f5b74b0e0769 +c95ebc6dc00240f6931f068e4c7c3e49 +3837b45508f84399820b8bad3d6c2520 +50b8c5a80825452f91ad30f900c14d1b +119d5abe285545559f2a8b25760f7354 +612736f7659d451e811c967c8fea370b +cf0942bdd0ef4d54b0053a4293a45261 +e73064e272d6432cb6f1101de7f03b79 +9029abfb2d1348b8af97dc6177fe1e76 +e3ba3bf0fa16492b89f1439caee5083e +7ddaf846feaf4646a964b6566113fa42 +e60fb42493fa47389195350fcf216ee7 +9fa2ca3f5fb041ac94cb610d18bd56cc +c55776fd11fa49cab1a42459f4b29b73 +65e5c193702e4be9beb5ec783c422b5e +c5ed5e1d5a0b4a0bb6906aa0e75d787a +ffcf987149df4e528ebf1e2dec6a9f8a +535e4ca30101418f8398a2bf35ed6346 +63e3afa5aaf84935bb9245d94bb79c7d +c420d45beb9847b79e8230a2b05ccbb5 +a627549afa71416590085ee4f9285563 +408ff45637bf44e4bb1dd0927c45da2d +b988cea27d5840159761cd9320bb038c +cff2c5c2e8734568ae170027bc736968 +3ed3c416510a4edeb03e82e1eb0d599a +03f6aaebc2d34ffe8040dff0f6bfc380 +7bdb028ee24e473c9c44f0aefdf1641e +97c96623b3554f11bfa7941a891b9c5e +d03f50ae268f436aba1da7eb5ac307a4 +cdcecae3371347018827eb6838e403c6 +3dc331f7a47441a7a08af2abfdb6fc07 +d32372f93ded475f9de2e3f9d6ea727b +21e51692f60e46ffb89428d8b4492f83 +7dda053766ea433ba2cb53765ca54b45 +a8b57da71e9549c9bed7425043408f91 +5a79396e6c754077a011ac8fdb7fda35 +a406d95be3744ebbab81061808db56e1 +46fff6b2667f4a67b7a48d69dcb06adb +3967341c1c7e4c1b8bc9346553157a73 +c5f1f57882fe47d89b701072c5d18a99 +edc1096ff97d430ea8ccca8945fc133c +3fbe870a98794cf08daeeebf163fdf24 +c4f77299116b42fd9879b3a9da9bed62 +c7cb694adeea44b2accb97946fb5d5e7 +8b5bd3cd5d6046b89884dbd8189c7582 +62ff0ef979144541b07bc8bf06c26582 +8383655021be4b24b5e341497940b3f1 +a1107b9e090244db974717681d00ac1e +fbadc209177641978444636641a6d515 +71e07ce5e7d4459a8b8102b8b04fb2c2 +2cab79beb5ff4ff8b206220800e877ea +71603dfdc70643448552dbc8cd0f36a8 +eb72d308cfb44dcb9d2e0f7b4e503bf4 +d0ca606a36584814a3464a7e82bc3691 +35d80c2ff3214a59bbf8f1995f69b9d9 +90fa309b7f3b41e9a3c236a101973b25 +6ae2e1e424374dd5b635d1748f7e61f9 +a9dfd6317d17438eba13f29d463b25b4 +896e7ff5903b465bb34e7ed4b918b3b1 +d6da27e3d95f48efaa4d936eeb9d6fe6 +e624608c7da648fbb9bc6dcd4081f78d +9e73d3d771e44e6a85c62b8e2f5bae52 +527bc6a2d9c24d969dc940ba4e5d6068 +a530bbe03c5c4a3ab6fce31481a6a4ea +cb8d85ba8b2545e6863fbd5463eec5ce +d209e28d89c64922977d69d8bf296944 +c1a0fdb7c3b546e4b846c8a8e1f710c5 +850f96e4ad3a4b4d8eb38c631e51fbb9 +326f5f8312c04ee8bc9e3e14e28b6e0c +4acfe7111dd34bde9b2fc04490d432fd +f0526d66eab8431f9b5cac7871a7c21f +44e652f9f89e42b2b40fece12aefd303 +cb58fcfebf294d20bb343dfb6c90d004 +4e45d6c738c94e34a549003d2cb9b871 +42ee6bdde3e74c89946fbee74d72aaba +bdacac78cd6e44d5844d1d7fde3b08c0 +a2ce58a7c4a64a42bfb13af2350d18db +99a67144dbcf413e9dd3aecabc9722fd +7acf77afc0a84f61b6520ee4f9f81d4e +f7306387666943a3a53852fca4a977a2 +468aa9e803d14e719eb97da28f9d5026 +14133736e62949d0b1da06ca15aa1506 +5665c6e3bec14190b3d2fe8f1e4b070d +45a86fd4b50c4228b5863709266246e5 +2a79482cf73f453381dc73a3908046ad +0695ed36d4aa47c2b13c8adb9999e0df +a8052c62fd6744ce8cd5321e28fb13cf +ea215b2cb8c2408ea8a65500255bf766 +46765a29eff642af80898f93a62ca963 +8992acdda2f1471fb64e925d3f558296 +9dbcb471690d4f559c64d6fb584799a1 +8dc244d4e06a4e868c6efa796cdcfcf6 +5adb70c13dd9452ca96b1d2be6ee95ec +ec7f4bd2203e44168384dde604f89c91 +f6885a46a1194d43a70b0d874a87f577 +d6951661c1e445d8a1d00b7d38d86030 +62b00923dd2d4ee4b9321b4cebe68460 +5a15c6466a254147ac4324b853b1d65f +ea60e33437f84341822c556805ea74c7 +98c7f8fb0ea049a0bbeb81628cb133fc +1393166a8b3a412c99e681732985415a +a2dc5b4ab0eb41c49bb2190e9f6f48bf +5952fd586b714b9e98250174dfc419c3 +0f1bdeeb5ad14e3f8424534f130e7dcc +71ab3427ad1142718af2ee8feb85c5fd +ed5204a418314ab6b68c1472fe03a27e +9033159bd5ad4737b75d6a81f0a8301b +74dfd9925fde4ae5882eb74c77c3c663 +1681865c1a414f3f8c473a4e47774571 +94b760a27658487dad23f2ed53c66951 +10aca2eb46534319bdaa6dba6519308c +b7e08942280c4eba9be4cd28f2bd6be0 +9afd267790164fa8ae4ea76d4b2036dd +15827f3c56014bec9ed1f1aae25f8f09 +d6006217de99465da78c9e5b08e1f9ae +b4cda635b075408096e9b57bbd2dc22d +185359b93eb3424ca73b5cd7719ccc0b +056d2c6e4c214506ac839faa644534c8 +1e23afcaf076420786d8078b479b0424 +6e424047eb44426184746a6f0487d19f +8505977020be4fd194854ad3d9808222 +602241fdaa124406b8b6db220a062357 +f29c003f8888476ca4415a2b3d591d3b +5af93a8816ae4290b8c925ecdee7d4b9 +cd5b9f6a5c244bf784036d5067291bf7 +1d8ba0570b864c8dab030b54a6192243 +91ab81b8d9b24e6980236396575d53ad +3e44a3db69ec409c9f39cae17b3797bd +f5e88b5040b5432789e147be28710d1a +baf6b704265942e3a16294cf18975b20 +0a222fb933e14f92b14f872d08200cea +978a8795190d4e7e91026d43be4b525c +e43b67c51af74f11964e4c3ee9c1b35c +f4259fc2c43d4c0f9c3b6d93336106e4 +01af78638a2e4d458e9838980c23c96a +8ac136d02b5d4a0cb526199bcd919439 +8ed49a95f393473490baba27f559368f +d3fd9470e5ad45e685295b1ebd620c55 +1dcebebd1e5f4642b309294eee8b1bd3 +f0d68dbbcdbb4e59bc8e690a58dee7af +5b99bf1d3491408cbe7f2f337aab13c0 +ed62ad059a8842ce9d1ae53d553c5195 +0f45a8874b234efcb59e3a3268f750b5 +619c004f87e74191abbafe9395c22259 +a82425de6cad44f4a40f2d05bde2af5f +6f4065870fc74114ac4604ff1f3d568e +62357db608254b13a5ba4910f4e07660 +4fa78f498f6c4bb2a9e34acaf8a89efd +0bb0cff367a04c8781b51bc4963338b4 +4fc842ad2ae647fdb13bc2ab13897bec +11ab7d7c48bf4a1ea4f44c9ad8279c1a +0110176112124a15ae2a97574a4a5895 +fd64a2892fd249c888323579c36ebfa4 +289edc9f71cd486193f980ee89a314da +85cc03c57535498fbb0dce673ec7a794 +9deae426da2440668c1ee3f725434eca +a044ea148b064d22930b4f62f91df7aa +ead0a5b7b0ba4a6299a60fd77d85f99a +7d572663201440f29ee52ae87e1a7bd5 +966784b16f6d4b1b9a85a1bfd2510d18 +2fbe8ebf76284db0b3c0ffd47e33d597 +3641eba2ee58429086aee65acb061b1e +593d23fc2dce494a8bfe03f6d7757050 +b8a0fa9ddd234f6695c1a130d8a69b47 +09ffebf34d6c42c4ac45999e790226d0 +f103ac43ea1f4398b19a23a44ecd85a7 +6017c29fe2a34e90a8c39c7383219881 +8821be772d624c3e98bdf45f2735d216 +d7bcc29b07d743ec9838ecaf8cd55f4b +884ce43e55b94782b8c79dcf242feb4a +9adf3208a6f9486f95c386ff63152c11 +3ecff6036a1e4afc874dba9f1a6218ce +fe191919c0f34c318536aa1d3a3a794b +f21edc1d2d864e5b8bcbf3229dcbbde2 +726b0790815f4f8b8cba4ef0c87d97ca +d7823a05fec446999446ae9f274c3315 +5d1ccc8f9f134068a7423f2ba66b9613 +9ea86a0b47f5437c95851a60ab7a7d0d +85fef97e48774694b74f621ac75b6711 +23ff15bc69d44c21be3fb5a4c3731527 +33172c4e091e4af8bfa0071363ac6019 +ecb5ab892ccf438b9083ff3f7c9131cd +10d9aa2700494deab67a644d91e2a579 +2b8368d2ae914d2f868d3fafd9377423 +270db66c866645c4993f2b6d64b71a81 +8f905d9289a14a31a0a7a75214e5f142 +4939d1bca386405f9cc22c48441b63de +17c503afdbbb485695adf8600602a79b +15582d113ced44c4ad308aba2d9cefee +a3cd551df1d2452691bec6c8476184f4 +1ffe56b55bc74f5ebea41814f51b0831 +519e5107737748d9941953ae407c7de4 +196ed80846d94df29e8e5464156d6257 +505cd7c1f05442b1b5ba6fd2a8ed3dea +60fee6466bb6453b96669ec451ac1358 +1a80d3c23a734a98b575ac2e7ec104a3 +43e75e57f18344e49bd5d58d3dfe72e2 +f1ccc55a65c744d7be201bf11b980e4d +b28b5f5e04614ec4851c998b5ea00d4d +b20e2f856acb46848711bfaea1c6acb9 +59fec10a91a247118ded6e2fdb906946 +2de69fb8e5e94f0880e4db3e72d53cce +4f8c0c5fcc084fe08851458fd213b3f4 +8ddb48adbaab449aa6f01f1a6dd55c86 +e9b92ee05ce44f618c9f374274a058b4 +ab42a8f0f4a646dc8ac0784eed873f23 +882feec1c8034af1b4a8db68e955f5a6 +90da01e2b378418b9b2ab8db8fd65739 +865a12da7eac48f5bc483e090441ccca +160422dda78d41e8bc6d3611f3e98dc0 +c248c3be5f814b4a874eff7693228ed9 +71bc97b4714e43418b469c57dfca330e +7b10478f3f234381992b821991f64bbf +ec121632cbf246dbaa3108cd03328b17 +fedc520b63c0422eace2b10bb39fec10 +30d037c1ef774c4b87c5a2f2b1449535 +7b9be5e13ba94f39be36112f2d254fb3 +7b973295fdc445ecb26a39c4bb6577b6 +8ccdcce5978f4f84a95bc20d6d1071a3 +9afbfb47db7f4ccf8696c5587f01af7c +855ac95ca93a46feb614e205e687aa43 +9cac8d2048ce44dcac5021cd2b63a371 +480cc34e93804086810480263b530804 +c7e812718cfe4c5abcbd5099a8e3f538 +3abb3e01b4734f44a312de3f7953bdd6 +225b6c873d804589946039010f801c73 +f531c888a2c648e5b10be6a7c6cc67c0 +5b86aa664756441d82a4a9d9bd32ed92 +4aeba6175a754fc1bdd46e9141cef965 +6895bc3ecb3540b3983f040a2b642110 +9e294bd726dd4a90b8ea1cdb329e15d6 +5224f34d95fa44eab99d674ebae68fef +8ca79d5982eb4ed7b67a84df1e38a84b +d94d4a66566147179144c88da741525e +0413d92d70f24a68b3afe8643301c515 +7f00a3be248148bb9c32b9f466fff49d +abd9f475ea184432ab8ddf964489bde5 +b7c97df584824ca682d26daabf401f87 +ac206c0833694797bdb0f4d5e930cb50 +4f372ecf378c47ae9ce6cd2bb734993c +b882fd37f09840bb9168479ca5fad5e2 +14a283046d4d41f1a7dcad35f01ade65 +dbce931873c540b08bb27af46d2c3c92 +c2a3f2ab906c41488b64c368e8049bc3 +d7e45db19de041419b28f95df0bbc298 +3c0d35f41da0454b8d1569b895bd607a +3d6ad17050e7425e94a9441028552c1b +c057361b58f74f7888efa261d1eb3ac4 +cb172bfc6d48406ebe87ad4fca359ea5 +69de621a1f7a41efba3e7b982054835e +a9c86b73958844658ab8494a18f8af40 +3ebbd29fa7a94959ae684c0cc4345751 +2676a62b12e1425a892bdf1855638921 +634657b52db74fa998acfc4968b4c8d4 +c9e2d40e2a3a49c8bc25d25ffc4b7b3a +e5b57ddb408644f89a16ca9b76d8cd2c +ebc42901b4d44ef284da6df23c401312 +21ec37b286474fedb43307f6f289269e +3f13ce0cf6564309915859a3038aa79c +b4103c80ca2649ecbdc328d0d64da1ba +7aa589395b5a40f3a75168e9f537d750 +ad65fd36ff284655ab9331e2e8a5a8a5 +68978b4eebba43719bfa5712b97e5bc8 +96aab8b000354be3b6c1eab7319c6abb +6a227fe2736345919250c9bd318cf49b +02c81d18c4f04b9b9275fde41d0e715b +94aa63eb26684465825f86062d82edea +6abb1ba39e414450a20d7e8ac096d016 +5c8cd9f1fdb7476d9528bdbc0e7a318c +e7f45a56725c4ad8b1a722b23c252e4c +b0d3149593084af6a23cf746008957fe +948d233fa56346f6b7f7c1f60fc57f93 +a977eac533564fd5bf83dd0ee16eb1c5 +23f49f3502b54ccaa3d15113e5af83a1 +a6651bdf90454307a22fd697ae8bd107 +1e686bb58a944bc4b75fb05fe6119415 +f55cbb2fc8784a3d86490248bc645f63 +02ab281f551a402ca72bda6531d26430 +991270e938174770bdb0bde23d9b4e82 +ccc140b40bb74b23b83fc16a37f528c1 +c661b38bd57c4668934c60068aa4156c +59af3ba10d034484b710348dcfa319d2 +e73675b59b8b4a6b818487622dc330c1 +0484a45547114a46be39022b66726bcd +ea5754be593d4f82a9dc6e1a2e06e51b +d464a17419b842e6bd0c56c8b9c92132 +32d5033eb7e7435696369ee300ad16e7 +a89e6f5e85fd485abe64f9b26eb14a57 +a9ae7bb81e1b45d6855457110ef6d3b8 +77e15f4310744d3b9e081edf4c0975c8 +07607092dffd429e8d07eaa050f79a7a +512ab078829648bd9019da7d7ab3e0c7 +87ac2dbdaeb24e0abe8f80c7c2d5ab5b +e7c052f0df7044569b7f89d4b869b13e +e1cd19689ed84a38ae4ac42390570710 +e6264e6942954975a65e4b4ccec2508e +5167955e9d3a4e178a13f4424d3ed8de +a06b6613ae2a4f61b15a66f6c8b8c92a +cdda6a4b1da043c4b44f2f5abd6a952e +75afd2f8e5ef496ab0d18cd0ad4ad190 +49543e34ddd040a7b1b428490a9a2ca0 +97787f3d265c4744a360fedd1a54c6ab +3e2eb53d58fd4bd5b8269e7db7cc39f6 +599504c198dd4f9295557ec09848b402 +e0998438e00d442f833888522bf289bd +c3d08efd7ea74cefb89c0af9d9332877 +fbc85cdc67964230aa39c646ce268ff8 +54602080c9d14d5ab052cf9fa7403ce9 +a58ae667aa1b43e789211047b8aae27c +9559090e8f5a41fda7a9eb8e9f0c472d +21b2513827744464b8d18083042380b5 +d14cac0f34ab43368290fe51048df86e +61d5a28260744d8e8c4ba24d5d33db77 +0e3135374d00472b91d12fd1018e967a +79ba96d1de0c4bfbb9f828d0b8590fdc +87fece5d85a24e3383b2b13b502b141c +35a33e5da56c44b68c7a937281697517 +82c0b6ada2924702a561101339ea3250 +b9cb1c2002cd417aae9497c3c33960e8 +787eee9d47f0440ba9491b9e9ed14606 +2ee91354914346d69b12af1c37a9ccd6 +abf6578dbf524295a784e940d09be0c7 +626c1b64d09d46e9a55504b684632451 +a9ca7f7f96684dc3b7c09cd5bdea5f84 +218071be4ad04809a9da07e86a7ed4d3 +a69b7b9b000041bc89a9e076e8891679 +16416c467b174bc3b487655e95318987 +ba3117d847ef4ad6adfbbd43fd68b3f7 +0c1ec5c3e561484686b251fec88189f8 +581ab344e5a948ac8a9d109954851038 +c512d5c1d036418ab2d173ba0f8f3ac3 +bacaa33407474fc684c82fe7929535ff +3c0cd4b426c7403c908d4d00d4bc4a1a +55aceab89e6c467fbde194994f006d99 +92d4d41e0f1744118a84a04bd4e8c8f8 +2ee060080fe541e5805e48437ae40b65 +5822d8d5d7c542368bbfad252b0c26cb +a21b0397dc3e4a60883bd03527070264 +aecdae3d17e74256a3536510d58b30d2 +08eef79633cf4fa78b2112b7e70b61b0 +71b0b67f02ec4260aaf722c795490e5f +f830aa10c0274c3994f47ca0ed990681 +51cfe336d19243eba66c5fac64a81507 +7a9e79960bb34a619dccb6998a99fe28 +c573fc6820fa41b0b1397a3bdce3fc0b +e0c3cbc945204bcd9c7ef92518b8b972 +03c5eb65be354c8c872d4a358f99317c +7b07838985a947fda70036aafd46b3ef +497c793285d8482a941cd377c7458bea +d5a90f47f32f426e8b4e51c5a4f55b53 +978a0fb1f4444fefbe4961a265adf232 +2e0a2bb4f1af488c81e79f9edb21c261 +608a5332c9d848db9e22ca189aa0ed7d +306ac890a1bb4f5f88cdabbf0d95e137 +335d95c24ef74c5d85791ea0fb05d366 +83546fa4286e445abbcaee30fe4e1f11 +310520c0d47044a9b6012a1d97a1ae97 +4f8003c35c13451eaf176ba3e44de20b +db49d1d472704b19836ab1a8aeb09d58 +2a0141217f9b4ae99abaf1a1a01683f1 +8713fae23b20464d821af051d856756a +b973b88b0a0846fbb1cf1535b56c8cc6 +5e0710bda5984399a56aedcc7ab0174d +71dce3dd627146e9a1e4776a490e786b +b782768a5ec1453fb2587bd9d82aaf7e +b547277417184471855155ded759a85e +eb545fbd84fe442ab0706b8bf5be1bd1 +64af3c54db5a40e78d9ec93002b7c111 +7d04fd3100df486cbac3e1ec69ea2f92 +1c6d3625b6f448d99c95498b5675c404 +d6849de2f338430faf6fa872168af215 +8164d1322d7e4e9d857d71c79a90db17 +94092dd95f954dafac03648e1e9bd569 +4e4e4681868846a9a6109bddc61d24af +786e6d1ad19444f69da7bbec161d5eee +81cd05f3c461428d80114bc2ed6872ea +9e308582b90746d986ec3999ab42a6d5 +98a184a2d84243d793a067ff3b03219e +3f64480e3b1c48139919a3da331f8c5f +f22cd9d7523c4c85ac81faef9eaa9441 +9155b2b4be5f452a98837459112a3b9b +d6b066a406df4c6980eca387ae481ef9 +36efa57fcfc5410b9cac8871484cc53f +2cc3c9adcfdd498c82fff3d6623d5c32 +c9e5af9c1f094349b694c13c85cbebda +518cc68fbf0e4aad946286150c8f88bc +7a43abb372334f64849736b0daaf4a6c +2a49fa597aaf4c56b95c696f429e83f6 +5ffa3aa646cd4387ad6f60f5f5fc2172 +d4adfab902254c62b7b7d164151d0870 +5b6a33958ffa492a8dd96c12322156f9 +623e5dd0a70a4c20bb1dcd4cd5ef4598 +c061a0712df3403294d412dbee770ce1 +ccc27d8bc7134d94aa7a94933ba04ace +4a0c9ff174bb47b0b40b47d23514eee9 +0b6fb2556a81434687066af8e65661ae +cff32b5f5c5a4cab9ccf8588157f1e3f +af0a2767517f443a98cd98ba4476fcf4 +49e50e28bb794399b6f293add351fc65 +1788b011e97b4c6086e749fac7489742 +d1b7ef458cf942bab26c49888fea6c68 +766b9386506c40c7862a9b32234298c2 +53e11060a7384144b1ba89dea86414af +f94c75745f4d456abf6d5a902352d5ab +5bc3336c6b6b4350b06f9b81af685ee7 +cab10f9eb7d6453db458046e3d1ce32b +8f57ec10b8ca4a16930bb55c15f46f60 +c609327dd3a74fb597584e1b4a14a615 +80de25d60f6b4148bdd8e5e55baf0c71 +fbfe5855b91c49899cf446f52a7b88a0 +d78ccbe406f744b881aa2c339fbd27ef +c8cc8891dc5a474781975d5209c734f5 +c6f69c82912b4961a6b5b7df2fa37747 +ccfff4c5f8c54ccb8deac282d52d6e66 +5096c9ad306a4776a1ab8b2e4b9bc6cb +2fe397dc515f4f27b3007891d0799f0b +f01ef223980444678ff4ebdb6783085e +795e5ecbe83d4844b20741830b7a9b70 +ac53955cc59442a7aa190ab950f9f12f +9332a8e1e5d643b6bdb284e016627f57 +e139d62f3f7b46cda1ca2a1f1e67879f +a3245c6fbaaf448180066145c658fcee +48b70e34b3254812b6c89bb677cae4b6 +990c417836e44d0bb0001bcd1c851e55 +e9c913bee614404dab5ac9886f7a88e2 +b47dc21973344b779445f4e1511a8042 +fbfcdb51466045cca7b88a903cf02807 +1e42af02a1f843e8826571824c43d450 +46d9c322e32d4cb38baace9c1ed2933a +0801a28228f74b67a4969f93c277545a +d54546f22fa8487c887a8f3b9182f661 +431e1b4a85d14029a8a4157ec6fc83ae +d040d73eb9914bcca943d9062f50a114 +7bae9eb1d0664018b4d2bbbd96ba80f3 +758801b2181441e086f8e923d51c763b +11c0327617354389ad923c0c77495ef2 +7674116150804999aacaf4c7de50e0ef +acf9c15a62584cfba1236f856622713b +44073b7daf6b4bd88c77bceff0db8a38 +50924c09991448f58681103aaee1d830 +caa27a9a97254f2281e932f5a79fabc1 +aa5a3cf340b543be985efe91554c3584 +7693673f97534564b8a14968ad5b31d4 +4bd0d6250de94dbc920468bfedc53fcc +d914d958f6b844f9aea3fa18208b6093 +c331e96a3d7646999a8f528316d13686 +0581b5b1349b4431b6beae7306021ed1 +675f9a2ea9a84d2f85600835fb4abc6b +624dd9dc5e6746e389f3c262df7a320d +3532b642348a4b88885e8f9e802f472e +b0e77ddf29404251aef996406e3ea70e +eb539c0af33a482382f932daded2d481 +a37e20eb85564e9ba21d0569198b20c8 +bb920dd7ef50497a8b6330ea82e02e18 +8899c8a210494d9180b3fe18ed478282 +32f8bafd9fcc48adbec217c79f8917a2 +69f1c0489a144f3c98e66dcfe72b3969 +21901bdd81f649e89af087ae6f67ca7e +2343abdae7674f46ad85071858db93c6 +4db0ba558ebf4978ae925ca4b1cf9477 +9f7a5b40f2d6400aae770c03fd1a066c +68f71e6ecbec40aaaee4da563efb0194 +b56fabd00a4e4b29b414ec708cee91d0 +46f13865d272442e95295884206afeb2 +bc9bbf1038e44b00b17ca7b5a59e6b5b +6b277767bdeb4088a26c5d897e2e2d6a +85d105a7589641a5a239d49db0e36feb +40782e7b182b4cad847ee222c1d5bc4d +ecf6d258e2f14b0f89ea9683e2b13d7e +99b2efc222874adc8443672fb734a97a +20856d9731014b8f9c1010f2867978dc +8178d61a0fee4437830b7a2fee5ca905 +0de1a85878f440138cc84e187e5ae346 +2555ca0bda09497d9caf277c1d9e228e +c68e6c50b4b040d780e3c137965a97f0 +853ab309a88f43dea30b37ef538b76d2 +ef4672490d0a47e3ad47e512207d82c9 +450e97b0289e436c8930cb17221a1a51 +b9022716c33c4814aa85b9a5a2b77184 +0333412b87ff4b858647ada6cb2a057f +4cc042033c5b4a698b62f331bbf3b426 +63cf54469f65453f8db374811a83863d +38b08cda681846b988b92a9eea95083f +d937d0a872cb4bf3ae5d8664f5242ed6 +3528f0dfa6d9454d99039deb92da3fbe +d543ccd6342e454e9f91e91b7796ba1d +20ef523bee784e4a939b4c5f8734edfc +9764210006844040ac9b250eb382569e +b14201002b5e4a22957819204be935d0 +3d79cc9684bd4c6094e1c0778e334ce4 +b87878b1d68c4916a9c5b890546cd893 +45aee654bbd541d18c9cd1a6c951f72d +b882cb6e4e7645c783ab856650c4df8f +14c4dd4621df4a7695e7b56db623c69b +6fec10d93d9b49f09ae8641db2996baa +bcc1527f2e684e95a5e8c3dc85ab1c87 +28c7af955b8547ce92264df91c1983d8 +fc71df6bb1c34cbb93e16a1a81e8b0c8 +0058d91949de484e820a046235487223 +aa773fe89c9b4067b7f3f9c29554e1dc +91d46bfbc4fc47a7a7257851076fc3d1 +55f6ac7870b246bd8fd4efde84611443 +e865bf2af35442289d39bddc362919cc +df29163b85ad4912a648a8473cd9623f +81aadd826c85488180fa3fa2d5f7a0aa +29551ec33f7b487f9ade7c32f089e786 +c5b79db93a1d41d78025b65b0d102be1 +6db16794a695461685033677fecf9639 +af42f063164e4035a2ba07438cbc17df +2a6243c813e74d25be19026c186240b0 +85568de0bae74304901701384e1c3d5b +38e4bc2cad0a4bbfb4b92d3985484200 +8e846acba94e44aaba3963ad2fef6909 +7bb2448c74a84111bf157b6ab1642dc4 +4a78392d905e48db9d12777c8b12f2d4 +4c47315a4ec34d21ab2302376be5eafd +81a80132d0514cbe84d88faeef676c71 +f23164c667c043e2acd4f179ecc0393f +c9fd6abdd52546bf95e62e116bc66f40 +30dec2b19405488b9c958ec4db3bf681 +b2119b2c326d4ef9ba42c83a9c711166 +d2e2be34be9347cd854a34fa85487123 +5819c81a7ee942deac939ed7c63b792f +f7680cef7ff1499ebf89e0348bcd99ac +16c504d81f5843c3985d7f208c27b79a +ceb7ad957f8e4016ab8250eb8396ff45 +ba545e4993cb46f5961cf4edec1ba139 +eb0807309530496aaab9dcff67bf5c31 +39551948552d438499e8694b7d3691c5 +95c53161769f4c259afbb41bfc94f5f3 +341ca375af784300a4fb44ee204dfc50 +6d39153a4cef4ea3b38cc5ba9543b37d +3039dea506c44acfb7920d135051f4d2 +55305f6a763d47b6b8c6a5896eed98c7 +dd06817af29643ac81f4bd17f8176999 +730f9af8d2834df39c645fbfd3afac32 +386aba5ab8cc4f048e5742a6b054071a +d09678347713483583a99831dd5aad57 +5443d2042c7b4b86a1cc736ee6869da5 +cf5278291d3b465c9481bac7759756eb +bbfc0860e635470f9a2b3a71753ceef3 +d170ef75c0624c20abe212ae72099dce +269e532c269e40f4be3bb8208e206ecc +ba21771aae634b62bd80284fa373abcd +0462dc66153b4a2e8968cf8d121a95f5 +bc6ab1edf3f846f491b84f9690bdedc1 +8bd6af15b49f4abc8f539c1ca4efeb2d +7c333a2f84f94c0195dea3272a65e675 +dc9652c425194c8192c34874503df434 +da72562d27944ea994d8198f714adcb3 +f15c7f6fbf7d4c4a88217b32dfd39eec +29d362e1972449e48851e4934b9b4423 +57d2db27bf97475dbc1fca6b1365f961 +accf85a9369e43faa28ad10e039bdc44 +5fe6a3cf65eb41e1834b1aca4fdd261d +860e1d94bdf64f2f98adfecfab845242 +70b7b418af714050aa83e99deb2253b7 +8c7af1451d4b4a0b918b62cad12a5b46 +422fb3960e3e45cb86e6afcd8a8f223f +ca515beed1f847619db60b5d10f6c8f1 +94244ddae2a0411fad12da680912b238 +5f63c438bb304f25a8e0f116a24acacc +4147cf2699744c72ac61d1bace258460 +252236660fb647c4885d25e2b629386f +6bd691bd406c4aa8b99938e9a429181d +b59a2fd7dcbc439c9607103ea33c36ed +a0b237057d0045e0951435af3113b01e +430a040458ad4db5b4fcde4c7db15e1a +1557f1fefc314cad8c603fbc6f64d0fd +f353b1d5b37c47da9970a25db4d79925 +ce6f76fe62b7460b8dfd2f10e35cfef0 +527bc1b22f7e4a709a81fe7c5ccd38b9 +a8fa5df505e64cbc8aba20ed1ac6c6dc +1d09f60e20734e19b30f9f71f26bc661 +0b11ed1d707540d5a444208d0e558ef5 +2aeedd3e629f4515ab487dfabc1d5d38 +44a2080f3d58431fb73a0279b84a487f +7cc59a5dc61b4208a62c26bbc5599bd8 +98c29f77095b45a9ad0a4e3014d111c6 +370f39d807d94343a2873a4e55b35435 +0ecae4d93e5a4de297b62f9fcb7a127b +00e242aa87fb4bd98c15c0ab5bf9bd00 +072a7e8d610f4143aa510256112d97cf +3748e33f7b884ed1be58704a73c064aa +4f69ade46ef1427c95a2a4e1b132112e +66abd679b8934298ba8af35db56d8106 +c199598ef0d94eb18fdfa5d89fdc9d4a +c0165f18adf846a48ad803fc8f4d0f87 +354087e8323642e2a4e78405fa271545 +08fab39eb0b34836bd21e5142f4aee31 +4acc9d61b5794aa991b29759c5b0c798 +0f5f943348a44039bdafe002db4f85e0 +2f337e1ed3e542958106900c59c48199 +a9c54b85471245beb10799fd43bfecb9 +33c7c6ea25664c9bb8f62827a4169df2 +4281e10a38c14998969e6a9130507dab +29d5c2ea3c8e43bcb44516096db4f3f5 +e9c627f9d5b14f3a8e53569b266cffc2 +90e5d7e4fbc8487fb5ae17e21818ad82 +68252b8d76e74206bcdb266606c3f840 +829f591452274982998f95e3be807baa +d34ff8df5d0e4c61827078e9a3842472 +4ea8139014c6402284d2d6a063f62a82 +e2506f09a30b4a73b2543c0f32651846 +607caf85a0f24586bb8b70a124d168a1 +f9dfc01a5b894c2d946473c4c06000d6 +4ad7875fbdd24c58b8d0a197a401d75a +7fd45af5443d4cb1ad02feb1ed1f4064 +1073fd1838834c71b95f3fb3c37c1409 +9d325c012eae4dfe9b92908f865dfcc5 +7c7640c570994e72a1409d3d5903f8c6 +5a8b5bdf2dba4adf99c37e630167794d +26cb34b5b9aa4d8c85e9e888fb470de8 +04d9983ba04242fe99182d4506ea0714 +743237e08f06431d8fd9624de2c0008d +d8a1ffdd367143f382c618663e020605 +a6f89746f95b47248b4858dab9138994 +b12f45fdde4041b6bc76a35c3ac769a7 +7b6cf3f40ffc4e498c509c327ff9ae5f +9fdec344b69d4cc89fc18b7171ef2e00 +f76d0698a39548088d5192174ed3ac4e +f83cf557ae874a33a2a3ae2cb1da5f35 +80b7fbd3a144432cb51510df9a6eee92 +2b66d433fad7419d994eb2b098293577 +0bd9facfd12a4e4cb08fc5c1717d9cf4 +ab624f26fc36400c80fd6b0b1c48e20b +409cfdc9cb1c4b9ea34833f8655b155e +2f90e282d95842daaab99fe02144001b +7030ac6c3d414ecf9001c40c6da0658c +4c43536c49e7409a911926dc7dd26aff +5718fec0c54f42bcb87be258c39b168b +c6efd7a599514ad28d61e826ae88ac89 +e169676dcff64d588da211ae0265cbf6 +b397436a707940459c553883ccb5a00e +837729c1b4d54186b9bc6322bb91e6e1 +e602ba1ecd974d10b8d29e602f0711c4 +47358cd3dcb346deb26e1c7e3bc14c63 +042d2d9e0dde4a5cb580d87540d9d643 +2a71e49698814e88b88db53016f0fef5 +cb8dbd22a66f4c33b62187189ce88e04 +b31e7c34e52946a98bf21de1fcb86ec0 +e83a068816b64c38b947abbee973b202 +ab882baa73e64bc3b51dba5ca0742c41 +3dd575e0223747f68d69aa5d549a0065 +f1ed3f4cc1c140b6badcff21d54479a5 +3f7478d095e74e3083a1169cd20c5856 +1f566ba9fc09429a93e0faafbe3c2b7a +fe03debc89a045f4a5cffe1974071347 +31ee425d76714cc28045e428f4315782 +a6ab53749ee9432a9872564d2e2ab5f0 +405fbffd66b3403f819b46b808d3ca20 +d1fb860a57c34033a6d9587f1f881bdd +3ae3d0a680ad47639672cd126a681af7 +a988e7ea72974529887c29ceab7f19d7 +18be8d9d50bf4ca4b24d81e404697b66 +c28b2bea77df496698a373358dbb9bca +e29346b8eb0a4919ba24115619cc02ca +ca8e20b9776b4bb3a46cb4685e9fc2f1 +72676e99b7da41fba2e591779a5895cc +c428a4e2e5bd4a098696363e1dd4f3f4 +af0f77af545544068793c44825af3d6e +bf2b68bdcd7342a98b36efc03f872349 +234e6bfc7dd346e9a0f821020a336ea1 +46fce676fc5c41b8801309c3dbb3aed8 +6292c807b5074fb2a41448d8fd9e8bdb +434b04afb75d4525ae5eb272282d736d +3a3a6a9d80ba460b8c784adc8757b0c8 +8554924e6142498f8b46df1b0e34bfc2 +2f13871237e74122bb1cf4ec21fe46cf +60d018afecb74033a0bc36c38c6c50fc +2983d92ac4e744f485492580ca7629f2 +940781484cb64c6db6c615473bee996a +d19f348e381f4ffebac97b1296aa9a23 +598306d7b9824f3eba00c1adaf225d6e +f64e17a334c243b9aadd8bc5b18bfb3f +edc344dcc65440ea97b5eae84f1957a4 +7cbd44a3141f4a1f889249c3fb1efa34 +c027cb3f85414b7caa59e31432686c1a +0c7f53e9f79d4a8e821b83705e9546de +f300d0943bc44c45862d07639534909f +e5bd39c7c8f14fc7be0b7c9ede636a1c +0f788280acd84006831b13b08c0f8bf8 +6da1c721dbc8466d8f45ac8ff91ecc7d +5d3ff2b3bd6d4be48784d04da0649b66 +c994f981028e4c4187d666e7c2620e4a +0a9d9fc1e45a42719b1b215f59dedc55 +4598f33325fb4e2b8e8b0744b75c8ac4 +837e03d1624d420abc3f448da3d0900e +a173e9948ecb4d22ad23f427652d5cdc +aa1ff58f50ba4286b4e0c987824ed571 +85942e1177c94edd842bb7bd2274b0bd +a22c12647d634f4e87e4f4993ac7d579 +5ba550465edf4a8fa2c5d6207a8494ac +609aed8d9cb84df5a139f276725b9b53 +9fa76511c2d04396a680628187392077 +f412bdec4b494692b9d5d9c03f4178ad +e5d24d29a6c44e91b51359e9a63f74f9 +f71d8f369cf7404c988081242dd70ff2 +a4884ea277164aaca6f98a9e8e6708a0 +6c9f55d491d147d3897ebed4d14711ef +609c328f2a68463ba1cc5d1dc2a15857 +8aeacdcd0de84070b2ea64296ddba474 +4d3104b405894a8f808524331458adfa +f60e67989a6a4be187f2c6cc2f5ff07b +e87a7521daf247c8b5b5656a111033e9 +5c3f4d1c558746808711eb84ec4b5731 +9178b512c16c4a7bb9768c82f54713e8 +db26c4344a284e79971b37c584872404 +dc8224840a6b43f08688db0ce45be476 +06f2017fee444e5f923826913a862d1c +4158d954ece94af599b25811c3c09e66 +c004e6ff052a4583b2088860b2806977 +19ed29dd7af04d06b6ff2f469022d3cf +62cd61b638294841aa616ebe33a203ea +71030c18f36740e3adb8985ebc11ec3c +0b0968b6b5ce4be48b849c1b50506258 +fd77489fe5054a0e8a1e5b2453154d2e +911fcbe1df084b58ac03d405d1c7bd94 +57c6a33fe3a949d3923e406465b3c91a +aa618f9ac59d454987bc326d9e3ef88f +458e74209cb945ff982a613b46f097ae +e0bfc49fde124fb89cd5cacb0be1a1d6 +7318fe695afb4131a83e0a2eafdfd0ac +e32dd7e919b84cf09ed542adaa0a2dd3 +4d7f020db96545519c43e5b0ec077a83 +24db25ee17234dab8cef37989a214da1 +4ea529890078407299df913a84d21ddd +a6995104b99c4399a20bc4e0031fbf8b +cbb83561e8b84704b55a9f6a597cd8bb +b849c7d0704240ed8e8304087e2c12f0 +b7d60407f41a4db5ba6f69320c5f5060 +1bfe99a6fb8a4ddc8de20a800c644bd3 +61ffc885367b4b418b6975d138d94048 +0b1f35e7a069479dae60af033e2c507e +798f80b7c857482e8e97d6748032c362 +8327c239c4eb41c2aaedf3a3fd682fcc +e74df1700f64493794fd743af3dcd67c +2da008c410be42d188a0c95aa1bca05e +488945dda5b3440fa46a912fb283ca51 +dbebc9fbcf2a45c1b983d91c416fd87e +ed2005ee49e7419e9c91cfe1d1c45dc8 +562239d70cae4fc2953aeb5c20535325 +0176be079c2449e7aaebfb652910a854 +d763a898b3584084b785badc123b8e2d +d1171aad2be34696a9c2235a775dc0dd +fbbb42068b4649139099e213db039531 +dbf2139d6cfb47f1ab3fd2b32e2db09e +4ba977305a54449fafa390a7a1e426f1 +2c417d1e328f43b6886baa3abd55df60 +e3436f6df584408597aedecb7c06628c +473d0ab58a594ff7aa7729ae1b816fcb +21db80a5e53c4af09c76d0b54676e89b +35dc6dfd128b4158986c82d8cc030cdf +513621a3eab84736a4dd3910363e7a98 +e74836a0171045fdbdcf341eecfea892 +dac6cbe10dd44d2eaf8037e54e37dedf +6e542dc7844d435ab66647218a5602db +69ed66b4d0554b329db72cbbda177406 +13f63e55353e492183ed4acf05aea855 +c5ebf86ec5af4bf5be6a97c482faff23 +6465b89b6ad4499993c90a39d7c512cd +652086b08ac9450f9d8014cd96e32471 +fbe6ee0468664971a661f75b6a6ab544 +73a0b42692ea483a8bd9a18097753bad +639b16c18916422db3bacb49edbc996d +9418613f6fc54d57997f78eaf4ef1f81 +520ed23a021448f7aac926c49401d51b +3c99d09f6c884c5fbfdcffb0d451418c +89a8388127274a60ad07d6a251e30e5c +41ecc0ec986d4d4eb0f37f66122334eb +c4114b4c1fd240f1b9aad57f9bb3f851 +abf26dbf12e242e4ab1ece1ed6a4dc3b +551ea772aabc44e0b240ebc564a0e2d8 +64704b3787f943f787a5a7857d5ded70 +a8c8a1ad33b7475e99d6ce956e7e76bd +a114586cd915407b869b138853fc59af +195c945078684c24bb3de3f069d84118 +3ed690485e07493dbec1e2a4036cd30f +c5090ffa4aec4bedb0db5d688e647538 +dd73641e18964587a8ad7ef70333103a +438be30ee60843dca4cb8050de942435 +cb278948a28a440d8e26573bbc8483df +00a66884dacb498b85701acd1cc77c5e +d11b3c01e5b34b91bde1231cc478b713 +272cfff0dc244bfd9c4ca8658a3013fb +48d69ed57f484334a908b163fb35b839 +858fd2535a9b4f4ebd69da6f958d0b21 +874fc7e11d674f51a4dc2082d29c9b9a +5b7672a50d884fa9a570ad2a9a8d4a99 +9ce8ab24383c4c93b4c1c7c3848abc52 +867118c06fdc49a682c8f9cfd945d82d +82a393a6680745ae8f189e24d41b817a +ccf0420eec274052a3877474908f8266 +3b2c8db611ca40cdb2951b153ef0cede +134f03f9454e40ccb7537c1990fc3e91 +62808a566e544968b1a0c2610fe47bd4 +e0d70a2ebb2c41c587906f7970292b99 +f26063c8ca6a438d9e328b28434d1c44 +6e4a2a6fc13e4e339ba2e38d2ce5a136 +84d7765fd30148499edef59415bb8dc0 +686d73fd9dfd479e91c016c87dbd7cdf +575bb83f8f03456dae21ccd06d67d19c +ca023ce7e8184205af165034ac1bf19b +f20f901592af42a7846857e55bce2081 +18e104a6d4814913ab1a3bc4d00521fa +4c1fdfa1694c44ba9dbcba8550ec4ca0 +0b726db918f94fdb9e7a44048321472c +67d3cd1be64f4bd398073e446b2455e8 +178f22467bae4c729bdcc15dbc7e445d +d1d5543b0bd0428397062914183fc5c2 +50e232096ee5475b8937742d5d35676c +f31f1101f1a14b119b22496a6f8ce8cf +ddefbf484ee443e9b9506769745e6f09 +da8efc70f6f4411dbaca3928136d7bcc +930d7e4ee4af4b8895572a79b4ab6b2e +edbeb81ef32645cea8bef89338f7e213 +11c5efb7f6514cc28b7df1c6b148bcd3 +4f911a8fb9654cd19305542d8d78d489 +3539250ac5ea40ff8135efd41a070136 +1676f233686a47c19859d5b4da162e78 +56b25c34c5e34f2c870516ce7af494c4 +cede6a606c024d4f8d92431213a84158 +fef7c1969ee2420ea0e1481c3b4e6ec0 +9db0be7342f04e12b8b8341941412def +7482e3dcb4a8495cb5dc87689ecd045c +9860c0037ea049eab5503975da06d9f2 +ad397ce44cc548618367d58c69e3400a +cc31edc74a7949d7b3d35a092cf5ea09 +e116c89672564c32975893a29d61bb74 +081194da071d494395827b3f9a277f8a +cc6e3402df74426b9fe77c6b2626d6d9 +4f834dba8a434209a7d1d9b39319ae77 +8f967d1053db48ce9edbf8741e376f4b +9867dbe105ff4e47a4a896e45f7ec194 +3c4466dc157c40fc807ab3acd7a2373a +8d66a96bf8de4bb1b65c941b2bee65e4 +f6563bbdbfc2403ba5efa1880a01c83b +5661e1f99a3e4d4ea257a085fac5acfd +3188e466f8f44fff81264ff64ceaff82 +9783d77d4f2449feb27f9dc2d53a9727 +3f7a12c2df124bdd9bc8546a3675981b +44e20762d5e944c5adf51117c2c2f152 +f6f3af46a30542139cbf23b2efee5439 +a0a09945abbb4aa1a853176a5dae5731 +87a8f3f885f44ae18759afedf3c0a960 +a0775f3f3ba54be3a6e72307ceb69c73 +5824bdd7838247a7a319b3fa75a9feca +91cecedbf7c34f5d80d034aa6356057a +91e13a32792744bf90d21b6aa56e68f1 +ec03f3b31cb34222a31402f087b17c9f +5809f034270947ecb32b597ed9e80afd +003219b0bec442d29725847969e4b6bf +9c219d7d26ac47beaa46539a9a4fa8da +15f227434085448e843bbe83d2d948c1 +bf99b14f3a054215a9d9cec9903b7ab6 +6cc3855fa5474bf0a11ccd66b12ab513 +3f859435a4e24735bc10f5bd9bf85c88 +460430af0bc941f09e48f556ccc28f76 +24204dccd16c4508bd0cc291de6980b6 +dfcd8def8c1147e59a2158df8c874ace +6f92e0acc0d44989a6ae3b74fc67cc62 +f9fefc5901824d19a7f56d3aeb8a7bc2 +d16f72508d29424d972da569a9551d11 +f9b5e3d538c14491a19baea47d9125cd +359965886cc24453925b01ebe95421a3 +2da0790639284369b31a7c88523e33c9 +77e8b5ee3f774a969681357a0205e2f8 +913b9945ea964caf965795fce08368d1 +db14fccd8ce4439399ab85c1eef0292b +bcdd24c905eb426f8c5268b824bb013b +f1aa36dbd7dc41c8a9542efc15def50e +e736a1e7cdcb48a5a4f2ca4100d52d28 +c3a9503855bd46a4ba0c7ea3d918aff6 +5d1181c610414c1c9d4a08c65971b355 +7cc6c57715a443c68dfe591f98cc4341 +bf25f8f14f5c4218bad49f50e2aad000 +5696792abcfa4559b3804c911068c1e1 +a390df9b2c6647ea82ca92186921d8b6 +61b3b54ef16742bd9854e3e7f33f3996 +32a4f80a37104b8480f5679f08816d59 +54c22b2a02034a53a8d93442a3b4a208 +1ad06881913646eb89114bcb4e1ae739 +f7937fac0b8f4161a5f902d1145bb08b +9da061dbf64e4a5a8cc6f538a84a373e +35f350a762c144f5a6c472fa68ab11f2 +e86598f3a497429a87fa92003efb9422 +5d505fdbcc594cb3b3f1b30be8240ad7 +54d272b8245c493e9293b77a12408672 +83036df81d05423dab94d4d12b3166e5 +bcfb61aa277d475d9c9ebf18be950178 +47a3abd6f9644477ba7f25e82c9329f8 +080ac3024b6243aead9171030161c95c +b21e9bab66fb4662af8ad66dd27cbcdc +7edb83d1a0e843ffabc87727d314ceed +3fb3b312020048d7975bcdd067c721f6 +7328dd0e91f24f7c903035a8ef26f944 +84874120faa84b89b65e8c9ee6b53559 +413fb19e6dc64e49ad64c49043694d07 +c2d0be1d829044be919771983b617aed +e971b701ee6f4d11aa22f70a46c54e52 +f89c972e822f4cdcab48e8008bdb6f17 +f6c08881622744ccb86c0385424e6971 +8207495e36704958a1bfb9b0cd4dd1a3 +55f16de75dba4bf7adce3e1ff5bdfa46 +5a51f9954ca349819b0029871d1f8e82 +9c8483481a134ecf84d3864b45faca6a +40f477d4d4b24d9a9e9f15f0f8e351b1 +7e0e83ef46ab43ddb9d8715627451bd4 +c0b8b9cae0a54a028b7cd83289383b46 +3343ab37925745f4ace15c17db21588c +f794ec5130424adaa18d025d65aaac13 +57785575bce046049285859fcbbbcba5 +1b6bd188c0d149339ce618780bca9b6a +72641abc7ce94bcc8d5bf0667fa9a52f +63aceb3f6c5d4a4188b20d0521826f82 +a286ecb0a5b649088ab1e14a35c82f87 +6153b4ce082d4ce08db452fde2ff55d7 +3cfb1f683c324d7b99bb3d117f8a9b6a +11e10abe691a4f3aa698bb807e0004e7 +efbade7eb1e34e84a47001beff0d09f1 +296a053b72944d5780ea58bb3780064d +30f926383b8748b89c978a7812421aed +429b4599b3374195abdbfeb4e6ea1016 +8b363c50623445c5b76be30f100364d8 +a0b89558829b45b9bfa4aa4083270c09 +d037558f2c4647a7a4fff1875f677579 +38f6251209504ddba51dc3b0be4061b7 +4983839f10ac4456a750fe08c923cda6 +b321e9a248ab4e21a01a10a2bdc3debc +bfe7d70e5cf14e3e95f4081be4c0e658 +c808579607074ab680b6506b9b127367 +989d796409514627807378b1feccbac1 +6e22f0a4099c448c80ab8dead3a82155 +f51306c13cd14d38bdcd7a31d8804bfb +af7730ac43514bdc84249d4ebb2f8ee9 +15926885c602418cbae100dc9646cb75 +b2bbbf908e024323b2eb5e3c0336e9e9 +5f06884e82394845bb1a4706a7ef548e +501b2931f04b41cf8e294cf000c67fed +ee19527c21df48408b75a82e72f1c0f4 +03c7117f045e473abfe5de90c5a8319d +4d9b843352994798aac92455fab062ce +b1d5762b6a1a470ca9009cbfd368e9f5 +bf76ef97ff844d5ca9c0de2e7985544e +107e0185fbcb428584da42905bf094d3 +4181d0137e0548f291396cf7f387d932 +6fce663938a24cb99d19dd28f946ecc5 +a3302a0c22d548e5b01b039cf8fc2e49 +c4182498f5a5435ba8589c0324fe1a60 +9bf986e0ca924aca92462c5bf271e3d3 +30f93d9dae4948fe85cd4d60ac40c23f +ab62a287fdfd45eab8a1f37dd803ceb1 +c604ab4e797643f88fcc1c899e8cd419 +380ca0a10a4a4c85ae00c547b489afe2 +dbe590e6304648d0821aaf430fe3a8e3 +ae75c00eff984a0a9f4ef7840a4221f4 +cac1d5ce87994f63a24090812bdb6281 +ee1b929bc0ef4f6189c10c0a7ffc20fd +3603cf85c49e4323a93b62db0258b36f +b2fe519bf8ca4aeabdb5f489c260294a +9e0a989a5aee4ecda68e08b62552a799 +a7fc42a0751c4be6a4cc22775b9b2cc5 +34ca2a29fcd843d9a4610df37d2c3e9b +97e61e9cb1e44fbc9893135f4a8b0f71 +17798af8932a4a46820ce46f2ccd4010 +5268dc011d584b17acc2480052325c5c +9b7422a20f7d448b887585f59bbc9773 +b3a9c7bb62b84e42a5e06e02f9e84b0f +d84c91514bbf40f2810f5f4e619391ab +2c4785f955bb4eedb825f2e655139cb6 +40b7570f0cc74ce3958df03f87d77c86 +c6bc65bdfc08458296644551d1421268 +6e74ee87e8a94e70ac369dbb2d53b0ae +47463f100d5840b2a180d1a94f6cd481 +21718f0b7fdf497fb092b7d095429487 +4ac6037405274ec4893b7979a707d625 +6b3020fed29c4976bc44ed1b7cb7e960 +03883aee33084ab0861288582ea76d6b +8ddc7865311c442b8d122fd53dbe742c +048a7e91bec24ed182671874b7cb6a47 +edbf04e437ac4e73b97319304d6ae725 +03f0aaf9ba814f8c9b485e9f27360e58 +340f8dccf3234b46a9ae48d23639d09b +cb2a6e17a1264f1db8ff7bcd7905398f +0465a8009d50432caba8fa21c86c0bcd +f5d9d526fd5b4078be3715359744a75f +a571a531ea024ef9aff37f9346cc3669 +9fc39591fac94d5eacd692e74795cf88 +7df995c96c6e49bc8875e4d0e0698739 +ab83bfcbd82c4c5ab1e50f1db943b6f2 +5b46a4763f88446b98b43f63549f8e8d +71af93b1d15f4f48ad836d36110626f7 +56f7c4586ad340d4a4320dabae38cf60 +d8c450e049fe40b29e9d7e2d8872d2ab +6c3b6d248fb64ba985024d6a6ec97078 +7d3b2a1ae57f4eda9d02163a0277811a +8102032a85e34e1d9e9193e6149946f1 +eccd13e2d8364c318116971101567c66 +1b8eaed363a74667a4ae4c41884aced6 +53d66bc83c1648cfbd9113492ea2f334 +6a11e3a5acd54b118166a9a55c672f51 +64e227842c254a2a81f6f9930b7d791f +0dd0e116105e4daaad459d03f3d8de8e +0a782cf62bde4206999bdd83021f082d +b65b3f90ac554033925f8b4a17c2a8f2 +739b014bdccd4993b94037057c96089d +cca4a870e5b4475bab9f8ca848e46cd9 +25baea74f1914aafb9ddef58d0106969 +f54b807ae28644a684d22dc84c0542a5 +4944b4320392432a87fee3a1269c74a6 +1779f886209f433db69ca6afa8af055e +ec072e396cf44b329a983264ae6f896c +3d2138a8ab7c43afa07b2c1825a28888 +f880b45cde9f41cf9b4afbfe25ce9887 +3dd98cf970d04d79b07fbf6087affcae +c9f36070dd93494dbca6e62d9d7476bb +a37f550f259940a7ac6d6999ef47754a +08149058f2994774a3580208ca9dd238 +0acfb2346cc44decadf6a93ea6ce940a +dec9e912d6574c71a23a02bf03022b27 +d8a31e7f87ea409086564218346b63bf +df9b3a2d51db493980d68fa3b56360bb +a09592f04ebb495c9641ea1e7630b1de +35c4e6defcea433aaeb2be4aa0e4d0fa +9252141c5ef641f2987be9ec21a51446 +ee91cf6dcab740efb0b04449a6b5b20e +caa8abc9ba85433f860010962dd0d91f +87b1622a80d64141a11721f1967f4c0a +b7898d2e04fc4f5988a32c5e0e54a4f4 +bc5102bd3369436a9e1a52e3ff4fc555 +30ba04c52b2942a89bb4b256c49a7777 +8c15c5881ca94ecf83a181be9731bf78 +dd61828ea85148c48b322402016b4c68 +e7e636e16f36410f9631235a695b0dba +9c2e859d7a8146dcadf9014c3885fa9c +948d92f51a89422399e31ee2c3650c64 +f8a1269b8d564045af13b78826833a7e +ec62873d22dc46d1bd52244b792c8c44 +03e65b60334d4d01bdceb292d362b743 +32df7385c866435497f5a01954422429 +93fc82feeb0b4939a2f64267f3e9d0da +b423150f22584bcfaf4ad681295f5663 +aacc55e455bf450e9c07470bf411496c +ba0f22d250694788a9e7bc32c5a197b1 +079495b273584867b3767d05aa244bad +5c43ea2005c0476f93f30d73dec3e8a1 +99cd51a8f0c0478088296520c60d5c65 +6b5aa037654c44eeb205543ea6486ed0 +38681fd4e3f24144b0722c5c85118d97 +e3a7aafcc9734f428ef6715b6cdfce26 +cb145eb6068a43bbbb50672350550f7b +0e111e6228a349c3983ec7f9a7e3d532 +8eea5c9eda6c4b959912a66408275807 +9b66435fdddd4a089b5c7f2c049d88d8 +71e1a37141074168a3ead925e1f1ef19 +f7ea7c088f3e48fdb61120473200a436 +6b97d631e6084f94993bc94a471ca37c +8c838d3ea1e8494396438b5f5dc78ad8 +7b323d3fbea44d6092311dcd12016e18 +4b7ff9b66a4f4b33b36f58c89b2e6e61 +0b420d09aa224062ad6c8031c382661e +2441ccdd33ed484a87f027b50f39a6e5 +7c2da5fbe14748f19ce893d4de560989 +f07c48191d8a437cbee572cb1bd78961 +73bda35b6e7a499a80427fc1b049b192 +7be5302628084c94a964cd703cbce9dd +30990ba94fa2430ea5973dccd98c0148 +1d8cf327109040c6b9f9b848ccbfceeb +cc0dcccd616c4d00a20a265803dd8c76 +c8f071466cd149968a5304b2267f270a +ec02a2b9aa524999a6dd1ac73ebd9d70 +9b608ca09b8d46fd8579986d22c7ecb7 +a2c57f38199346b3ba2ee9f73a81301c +8192bb082e2547688f1ca4a30786060d +2f4e263885014a3fa12e642cff873fba +418074a1454f4128a9d58daa05bb9610 +d0784ac4263d40efb74510bc948cc844 +401a4f488c514e418de467ba3b516871 +3800a04a6ece48faaf4e9366385fb14e +3913f071e02b42a181cd8b793c0e1cbe +4b1cd8bf8d04426ca244f17fbcfdb8fc +b1a3c42f6fc94fe89dc675d2bc129c3f +3141ff2727a145baa67b08af0b3ad154 +4d6810fae48b49928d765c4bcdd06f29 +24ade8295ad54611a4344bbb4a8b5d32 +f266dd57a0fb46f4a6877abdad2bbe86 +da0468db72b6469aa651259a1f812c1a +ea40e26803d045f1b93f225687b64797 +bef0f699a5374ca1a8fe8e27fb77788a +00944cf00144496dad2e14b5e2efc852 +4c5a08de9b0847859c01284f2b83a290 +e66a171f9d8d4787bd6e40f378d42191 +0be9c38a272c4c97a60e4f50ade2e094 +92042891266c4fc09ee4d6c54330beb2 +29642e0a9cad4275ac78c1d4f12660d6 +d60610e421414a4882321cd9fa3c12ea +4de4f3a86d6b435e90755ac29ecc002f +5c2875d888ad4963980807c9e2a1cc7a +7c42807127644030a2fa92e4bc326160 +60f55f81b61a48bbabe47f64af376ab4 +0da4c58c38bd4045b102de7d3c480e6b +1f68710121e64a56a33c6c0d4d1f22c1 +b88c5e628e3349428f9200ae4f1a345d +6359e3b9c5ec4c19be6640a8ac4d3530 +3623d7ff740e4b969539008999eebcf3 +f50f5a133d3a48e592c58cbecc32baf7 +c7dfb82541f648acae740c019d04a408 +80037f043d4d4d8581027ace99a5e2d0 +a2362ae283be4ecc86e3a18485c11aeb +f874bffa8e314743b4a7cb9ad4b9f3a8 +7d56ddc228904eccb1fd7ce31f39c26a +347f0780a7a048b8bd32226ae2af53cf +cd59a3e9fcea4e3cbb6918c1268a94e3 +7fefeb29ae3240f4af3b9aa9697d7057 +8b323fecce674e0fbc90c69f63ea0a8f +f1fbf47a807143e9abb061f94c3bd6bc +034f2eceb09c40cd9d559268412a756e +5a6d088f0c5d46a599c5c48f1a9f543c +1a5416207b594e77a22560f8cce02f65 +217ecd30faa54f20b03d8f0ad9ece9ee +04d150d363594b2d9a7781ed76340eec +bb9d7eff4493438d8c45ea7f784505e5 +9547a782d4a94027a7d218b44f0b5eff +1c5b01f4ebf14c4c968e3afd4061e001 +cd5ad7440a364ff0b30e92200dff63a3 +6bb92eefa68d4d4189837b90f43d6c2f +f679cbe92c49431ea7b2f2c155d25ecf +96dc535c87b342499cf9a542881d2103 +914eb8ffafc04db48f45da88093e0a68 +d6fdebb1970e454f8104647f1eaa3a1d +e46f7f814258411a919220e33c8b4572 +84a620c30bbc4bee8ce36d342debbad4 +cbd406d01c8d45a3ab2bc66855f8c955 +fbaec7e2d4ec4791ae95505f68e63070 +63c49ce5f17d4c4c8311f6c2d62a79bd +cbe9d1ecf85e44b4998e205f86ba4311 +bf881fa5cd554b3999b8af2037409bef +77c957c8e7054cf4909472bfdaa04328 +5615b16ba2e24f7ab6cd26eda7946ae8 +11c751284a3f470b95336598bfbc8755 +c6509a8fe1f44a5eac8aebe12be2699e +664d5ecb84dc452e82d658b05aaf59e6 +86af94f65403477f99acb2f413634ddc +78ad7f3c56a8425db589bc10f0b2f70a +ae3c1b7df3be411b81bd9e2945eac9a6 +f66be8ad9f4a47cca8d947f551e916ab +bd78942b89474892b34ac361223a9905 +ea19e8b075d44c2a86cd369d85ed77ee +efe93249652540128d1df1d5b21115fd +43df59c45e3f4b15bc4031cecb5f5d51 +080f0605746b4cfeaeea737eab8a6be2 +3dab2a85b1c048eca160fc5961e9ef34 +15234873d5a4498d8a490647a10aded3 +8e1ecdb8c34e45389642d0af43f5c67d +2a1edaa43d61499a905f034640e2877a +4c5c97fb51664899a1b2ec727286d5ba +030019585a6e4f79bbc3d7c10a3a31db +2da38cd8ce744d729f97b6db277a1934 +dd2d47524cc04928b480d7bdbbfbdf9d +eb9c96a5b212475fbbdd8467f8f73e4e +e96369b768ab44a39ed0e629ad6f2622 +8fba1e7048c0421fb7e6b6e8be8fce88 +21696f2141ed42f68436565f486080fc +0cc33b4793fd4296a2700dfda4d8c35e +da096f14c81540eebf1b637888ccf355 +e5c50afa83604537babdec3198322fd7 +8ee3f06179d24078bf39a44e0bd9ae7a +04b69c34c46a4c69834144ed33804180 +53b5353b12cb49bbbb21141257043fb9 +f8274dfd12274d2cb0224a2ac5faf987 +04e5f5f5959a4218818162eb4cdfcfc6 +a1197fa450a3428e88e13df8219e423e +c2926d2aa5014376a87fb9ba72c64e48 +cd55004dcab14b32b702c197213b297a +4fe520e0583b45f4a4cd3cdb594970ea +9055288483244d228a5d183b206ab9ec +ca4ed414fbfb4facb48ee72b1e671e5b +ebd6f15553cb4351b532925907262a8b +b0b56a5adb1049258d6bcd0ce9b19866 +ce8feb9a2686471da98fea2b4d262d69 +0017fed1dd804ec1ab2e06bbdbebab16 +cf8daee734f44f7f8fd4465918703754 +619563fb2e33466cb1286b5732da59f9 +a35a466eace5463d937cf55ff264019f +c46e8ee246aa4863a2cf602cddf1bfeb +70b58068fc0147f2805c2d5bacc8b484 +fb0ba6830d7446dc91b27325ecb60433 +9cf0d4d9c380433e9ae04b05d2397368 +4abb06a66fc14582ad0e0ec3951fcdd3 +e378694413e6481680a90972bcf653cf +4ac4cbca494048e3acc0339a17b71c31 +863c47c3e6a94d50834d78167a885210 +889385bf89b24564af1385bc0658cc10 +297c2536534c4045aa0be028d10d39d4 +90c9778e68e54a84be1a9ad773d71d8b +5b6306a729824493894bf091c8f7e3af +4231ea4a40b1497b858958c54842a642 +215983be30c9442ead3d51214cce23fb +25a3134916654257a9b5d965a101fe9c +8d501bf5a34040b2badba6f04d66c83b +89aa5f17e18848ca90e8c113359dbee9 +4d07a76bc1754ce0811e5d44fd4b34aa +8c121413fdb642788e25ce6d4a22cd17 +02cdd6703f7f4baf8b0d96c0ae4ad6b1 +62903f8a858f4baf9e6dda24d2a93c40 +15fae6e4ae89480c8bbfbc7b8a6678be +883d9a3f559b4f4ebbd994ffcb038664 +983041da163d420da1f66a106c3b9f47 +903490f82b774e569d467148ace66370 +f870d9c7f18a46f8ae386ae94cc87121 +cd37a99d810b42e39e722117ea49fbab +500b55ef102e453ebd4fddb2f3c8b3da +7c713e5e80684f7dab36ad5339302a45 +9b567716507942519b5ede5ab5dba6dd +8a5a4cbeca614457a2d839a62ec7403c +e72dcc58707843fa93384690e3f16d9f +ccb539dc46ed4cd395b31faff89f9014 +e12005c726144f0081cccc09ec96fe6a +a8310c07f509440fb29dc624b4b0a062 +c3ed13b77d9946c4a9875d56544b7f3c +3cf4f4f0d1704140aed771ee91489da0 +ba948986dadd4e43b7dac7c4ec59f8b2 +a3c7dfc9a4f84d3d936e199d65e28aaa +ffef2df2037041ad9aee816fe1f27ff2 +333668dd21264de788698d6eceadad5e +3a66d71eca3b44b5a004c5bd3e7d9073 +5d5e09ba22c449469b846b01b389416a +5fea50aad8544532bbf50107505aa709 +126a593d1a86446f869a3fe920564958 +f8abd9079f194334ae9be4f0a9f8ce49 +0cba1db0c1ad4b469553972ac9132a7b +26643059f5fa453f94ab4f4badb6b704 +44afa5e5e35a4d17858a7046cf16eff8 +d78dc1a99c6d44b38d4b581986ab9e26 +e1badb6d32ac47de8ef38e9f4dad79a6 +242f66ea0a454f5cb4fc174d1160b60b +6890f5b34af947f4b416a23cbd4e56c0 +de2d0e3416224e5e807bc794eb7d0d49 +32f9ee4b15104c1a8d14c99607d86c2a +f4076da3365f47e08c6979a01964ba61 +ca6ca83b83aa4d9d8d55834fa3cc9c8d +57ec7545f8704db082e784cc79b6a7fc +47f1b331f0464a408afe100506115a55 +7951f3c7fe1d477591e0717275272765 +1a0a1a14f5364b748a57b5d223cd461e +244a639e6ece4777b1ca836e40ffe3be +37b041d8521c4179b3c8679e2ff8dd17 +3beebdeccab244658cf924b31d3f8c5f +77c0313ad21144dcb904915d66a163b3 +d0c64b4957d546cb99be983f656bdcce +7617bf448dc44e88af45e6b268745659 +3e03fbff124f4a2fa366bd77b2efff11 +400c45a3ab4e4bd1b2145135b2e24929 +69d498ab12b14d63b30c9749a50b03fc +0bbf336a2cb2467bb34608e6b38ef3ff +3a3a887f69e045e2ab8c035db955e199 +14f204c003f74ba18c5952c0e75ea89a +362c9505cb314460815e88708aa906d2 +40c698c102e7405a91745d2f907c8a81 +7b5bcfa7e00c4c2fb82055df0c6d1d44 +6de9ad46b6794e78a08af59ebeb04ffd +aeab582353c34b85af07b7528bf6d611 +5b72a76136d547bf9789db41ac2323e2 +1494ce0d32e04ea88040cbcb3b8dbd96 +594d34137d004e7291bf79331d6bb459 +0529ffe277bb4016871c5a1118e80c67 +237e58299e06470e8d1b49bfbf6e3bcc +6436132bdc1746668aa2cf2423932d17 +2fd6f7dc02d8413da9af8195cf5f8239 +7a0c2a659e2441b6b568a9d2acf8419e +58b4495be6d14084ae6b8265ef082ed7 +6e890bcf15fb4c889de6ac1773327978 +89a530d9954b4003b112ffe2aa3b3b92 +a7d136ab51aa4d8291ace5294c90befc +cc397bf2484b488f85dcf844bf088559 +73d244a9d14f4d78bdc8b0b6bbaca4e8 +5744b5b7c29f4aa290fc56aabe869229 +57ba5706c58a488e80f654980cac67ad +9b1dd1cbe57e4bf7a8a4b1386250f2d4 +7bd35dbd3363425db41c9e6a391af2ab +4dd8ff756a8f43939ca22ea5f2706d16 +6d771706055241f281460006ee4f5a76 +68146b83617743b69060020d5882017c +003442052c724e6fb5f38b32a192933c +b807b00647a7417da3e8654c85f78d87 +643b54f0839e486a9ce3c41eabdb9f3a +01d2ea4a0b7a461caddc146938873b1f +3a7d0075025d4abb9f9790390fdd5b07 +b16686cb9b284cf892c5a939d357f73c +d15b3e6d7ca548c3b3705d29db16a412 +d7507a0caaec454aa6ebb7f0d6d5a261 +d7169cb8a6014252abf05c8a6576ec4f +f5ca6eff8f6741dfa44de5cda5fca188 +791b35e667584a639648621480627dbb +eb0b5f7b64fb45188a04e050537d3195 +111da9ffadb647bbafc45e21c2c3071c +a3073cb8ccb74bd28be6c8e7d18c4a81 +885b3b0d17be4bf29edb69d9000d1e0a +6b36d2db270843a8929ad72c8a8faed5 +e16617aad7e0489a973cfc6bd896d0c5 +55f2fbd4c3974467bc52b53608c331b6 +82a1431a18d44f4591225a6c706cc456 +42bed4663a1c486c983f38a0a0f36611 +d157bfeb30244d43b7da816c9d7dfa65 +38e53299cce04fe19235b8b198f7818b +e998b0ebc85847b0a42ea2da1a614a23 +f43de97cddcd466f93b69e59a56865a1 +11401f2a73274b5c9f232e70ba03bb62 +af371a83b24648599936caafdef8506b +2905736062c043d8966df18cd5910978 +ef8ced4cbe764fab9799113f7f700aff +3e575430bac047c6a5f064bca40b5065 +437e50e2a7b441ba87d54392c39c0baf +3d06df9143fa4f98acade3c0a90df0b3 +16882819ed9c4727add47d620d8eb4d1 +3d6b09c1a2e243dd9fd27240d252eb31 +9ecb77b349884efcb4c161cb701dbe23 +2da9df24e8ae459ca05269e130d15b68 +c7922841eef14f2b9531d1732628f68a +7c1616c054214a2c897aab648e22bb57 +c6b0d7c071964652be6aa900b146ed53 +0097d3f7d6844162b38c587d61933c4f +1f8abc738d7e4d74909522e06d342132 +a51be15d59ae4bc6987ac6d6b8c094a6 +7215e3564a2549f1af0dd57797970358 +672f7cd60edf414e933a4383ed5506bb +9522a37f51ab47ffbe5c084a14d9f04c +796c8edcb69543ada938c9e02b380b99 +e6caf7b73bc84fbc9f37e501a6935afc +2ef7d99516cb44b2ae0cb8b50f656e27 +2f495e17db5e4bc090a4e5c0ac7a5966 +fd52e107fa8647da946b990054d8283b +ac0e7f6d41b543ca96f69b4bd21298e1 +5e8240e270c64c83a8187506ac064575 +018644330f9c44dcb49ade255b281a52 +4bf732a8ff1a41539b2a37ed3056fc04 +6a62d098e0c548e384ae122d0947604a +b7719f1da53b4f51999b1ef9e4e1fe58 +22da442751784128b72e7c99969fbef8 +78d628831c3d473b9702b6ae4b6f4e68 +0b1b8114e4ff41c0802a901442abae79 +46d82043b859414db7832fa240568fcb +2e1532fa668f46b4939c537d1a51f352 +0115bca2d7bf45f092e9e93064ffada8 +4ace4fbc91124683976db7e9530f98ae +8d0a014482e347f1b43a60fee82f6ecb +42eec66827084ea6b1990c4796c800d5 +f30b97d8ad5843b1929d42c82c6b54f9 +d86b8632da384514965b9d920815334e +dbb232318d2c493193cd2c6948eadfc7 +6c79d4ecaf8a47ad89a970eaf0e32fdf +216c927d15204f7b81c59556fa7ebc57 +4ea1eb161ce34b3cad5b2aa50428d9f5 +ea94a300fbb149b3a8112a2a334f7f0b +531e32a371004849bd72a507aaf81643 +e8f94dc4787b499ab9c4974b7a447415 +1b5dcfa558f54a47b469252aae81b324 +d289352ec15449b285d6c94f6176060b +df6bd854d92845f2b409456456e21147 +0f77425d282c403e9cb8f4dc85bcee7c +0cea33fa41eb49d3a8b00d9e4d325053 +bbbc8b128bbe4efb87c4e097163f9ccc +2109fa9ab86c42f081d0f629b4731b5d +9069c49852c44a569f1dbfe143263007 +c77739420c56460b97e47677f4f983a5 +52f4361d95254b8988be5fb5fdbec951 +553bcb456da7476a8c869331cbb884af +46e87a7edb4f4c3ea685ff3a88a325c5 +36a060e40be04538afdb645bd8f1fb77 +798d5a5ecc6948c6a9b542520db9b4a6 +24b3630ebabf4c96b4d19d527efca2dd +7dabb777f7af4907a4856350b2b7c7ca +2c8b491dcbfb40e7b82ee93cae0d1edb +ea16c46502394e9b8959aa146e77fe5a +784b0a24c1324916aa5a054cf5d8804f +c69fd17f46c4409b95c9872d730368e1 +1dd9b373e3084cc0914a580ce5728cf8 +0e0b88c0baf8434fbd236ee93dc8d107 +456d78b100704bb7956eca27e51921b7 +dd0d0e2adfd24a3e8f115301e4b4d595 +cd2959d5187c4536a02b51ec697a8ebd +50d0933375b7451cbe87aca53223e154 +866745e5e2ae470cb19fb36e5b74af4c +607d6c0e703e43dfa62b0781c5cc2752 +f3209a6a45b844df92560099f982a508 +df5839b1bc7243fa97c3a13d18300002 +120771dca01f44539491395b8daec730 +1a970e6456844320b3247779f68d5f2a +40c2bb3dd9884b3b881d5d577d7d9746 +4eb072b2cdbd4277b63d80b98c9261ea +3cc4a5938dd744bab678b370d6bb52a3 +e411ae52798f4d2f8eb76aa7e7f8bfa7 +2c66b64c123b436eb522cd8a786142b5 +34924d7d866d46d69de52f5f31be9e32 +c6c37a6d80bd4ec7adef7740b5ac2776 +1a063e0f585d45f38daba64df0ecc5eb +fd8d8cafa0634bf9b803eafee7625979 +c3b08e6c355544808c8f34de3a4bfe35 +1e66110d80f049efa4f76f010417b853 +a8a6874f62da478f8572554959d3c62e +3175d88bd6b6480ea54378a9085b7a67 +452049761827436592b001b9094ae407 +0305320232e344c08148f0a5aea78949 +1404ce42aade48e480f22179ce41caf3 +728e03ecd80340f1ac62494b8d59bfb1 +c5a7b31800b84827bdee0425853d207e +ec88c3ea2d2340fdb5d691dc226bc187 +3cd932bcabf54ac5838f23e35fc6fb1b +031574a75f51411b9d73c386893ca7a6 +06fd1c033a204719a73be3901b18ad4f +64fcd02030d14bc39325abdc94413206 +682141ef5e4f40e5b0608f835de49c63 +93e2849f69894083866efab3278f009b +52772a421e784ac591bd93587a751ab8 +b8122e8ca26149458c401d593a5e7807 +01922143cd9a477d8f5ea5f805637691 +f1d196fecadd46889dffa94749595a89 +0c398f7f15aa4527a733dfd7f4769265 +62056bd9858049eca5c128441bd9665d +2da66ffaa2cf46b39cf28cf9f71e5665 +df20a205f05a4878a24ffd72d745bde6 +038b4934a9ea4f8bbc8854508bff3217 +899576e8549443e38ae557aad9f0fb5f +ce79dbeaf3b54dd686b3fd04d50fa6d3 +d9083e64d229434094dd91159de9bfd1 +eccd66922b80448286c256d68b53ed4c +8d00e925ebd24a9092b69d366ae024b6 +6af10ddad3704b1381381d2a6be905ce +5a4583e655e34713975430b48aee3e38 +322a01d12e394711a54da11c1be15a08 +88c3a9defa4541fb9c0145c35a79b7b6 +a58389f94ec047fd9dab83e054dcbe23 +5b4ce8e1cddc46f19978cef5cd3cb99c +508f23aaa6d7469996aace1463d9653d +eeefe5b0c3534b96ba6c692e347b94a3 +afd10a0435184da58cb5f391c0499b14 +e37741d255c94dd7ae6db1045c0ff48c +319ec67c98e447eebda0039b143274c5 +c30c7e5fe17f48dea888d2f76b7b7b3e +05366d30abc54c178d808f2f0d84ee57 +f166028c67d840249cbdc0f6b4bf400d +5a341104c84e46b6b5566a56150a4ef0 +75d11d363e1c4884a714a776049ea4a0 +fc562f62ad134dd6adea0f134b6c1771 +1c03f9b597b4456db030dbf72401a876 +03c190dcf15e4ee7b9398576313b4981 +c3c6edffc8ee4b75bf842b9a86ec7b7d +a19870d9871b4ca79bb0f0f7530cce5a +a0b11cbd59e5435eadf1027927c85e62 +63cdb278c4984c72bc7c65431e6130ba +04964dd85dd9427bbfe319b17cc26eff +960ac9ae4baa45b586fc5037a6e3bc96 +e8b11bbd44bd438b93bedb2e09716710 +d36b497645f14a2699d48ed727380738 +4c4de8f8b76e4cccba0ca388892796c1 +ab501450fc254917b497ee719b0bde66 +2d5107a9476d47a0b27c17f589836133 +4e0cd828f3b94c21b61a7de473533315 +20ab5a367f20474bba8140d4cc706acf +6ed5f68246594b87b33c7504939b9031 +cc00b5addb584d15ac27379b6e5d76c0 +24a294b94176474a924282204da22423 +774914583df848b9949addacfe61881d +9e046bf9912841f8bb7f77c8fe878a63 +198adfef07ac45c89ec51529b1e01c22 +ab6393f2bf8148ef867b051b0f844515 +77537462cf1c45cba9cf2cc087005b67 +ae0529d9da834820b8a9c30ec0b6228f +08162303550a4089b1eb98f13763c92e +078da6e1f86c4d2ca874e3f4381becb8 +b1c14cabcfdc4cb4933c95848cdb411a +381ebf452fa74d12a2eac1bfa332d5a0 +b78ac5ade0104cd6a85c51e60565aa3e +3a0e30464aed458cba62942932ed12c9 +c3fce21cff474c03aaf02834dd938e21 +a9e7ff47a1c442c9bd97b8fe8bfc8e12 +24afa6fc5e8c41ce9271a0c29fd75bb4 +3a41cd0ae91446f9a61928b1aa827857 +f7fd3b9fcc9142909af85c941df8688b +921667e8070444a68b0d7b95586b12fc +74fa123561744c32bff6d5ef60b88ad7 +a8c9b2a2d4604a68961c599c6e04db26 +045d9ad885b749b1bb826e2e801b57dd +5bb6dbefcd5d4926975e33a68612bc1d +c673ceda05184d9791c962009f2f02ee +3ac8ece5440a40ed909f7c2a01d53927 +405b12990ac045e98c6813f32d62cf57 +57766f8721f24d368e531768349a5487 +2ae855770d1046beb0440356f8ce5af9 +8c9ecc71fb114d3c9d0ed1e8fd348953 +fb488cc23f144bce93e16b1412ea36b1 +463ad80621de403dbf66b65c966a6e2b +4fc86d231e1f4f1fb32fcad11891a5da +4a16befac30b417fbe9f0fffce267e22 +f7d9f366a8f9416a87719cdacd5384de +7197a69fe5984776994ef1948162ca40 +beb3a53feb5147259c301dbc437d1916 +37556bfdbab1444f83bb0962d14f3364 +ca5d21dc33514276ae91332696219ba6 +7e887e5b58214c1ba618a154b6b0de46 +b86b2f4d79c94531b8385b6397ac5600 +0648e61d41504518a79b027332e67540 +21bcd49240a54f2b879dd3f91de4fca3 +854a98abff3841439ee890dc0e78dd66 +0365227fa8014beeab7b4597704c4485 +32d17951703b4e05abed11a1c65f5909 +b9dd553e4d4242dea05ae437695f4d66 +bd45bb0736e14a2880e7299f11186bb1 +4f58fbb81ac744d5ab9bddc927e6a15c +329bbcc440a545539e2ca4a98c9d5fa1 +deb84998fae54c9394720f282bfc582f +0fdda2322d5c499d9b90debbba5eb78f +1ca1aca0eba24f168092ba357b7507d0 +a691cd8930ba4dbc92967085f376bc85 +ed44d015d924440894be1326f94cf44e +c13893680b79494bb9bdd3c39fb9142f +29239105002b485e99e02090552c01f0 diff --git a/data_split/objaverse_lvis/train.txt b/data_split/objaverse_lvis/train.txt new file mode 100644 index 0000000..fe8c99b --- /dev/null +++ b/data_split/objaverse_lvis/train.txt @@ -0,0 +1,10331 @@ +f010badd4b564f79ac5f293922baf5c6 +cd23b5ffec794899acf4b36c6cee8a13 +3db3beb46cfe43f489866f9d9b6897e2 +ef665bb9b4d542d6ad15d6ebb4766723 +19abb349b55e4bad875e3ec2dc0e8a15 +b66f118b4f46416484cfaf0109cb9181 +49af779cc4344bdaaafae3082cb1fc64 +44e81f0de2934a76a99aa074a0058ea6 +04d985493afd4cf8a2ac6133116d4686 +da24f3dad875463da49fbcf4aa616ef8 +cca62f95635f4b20aea4f35014632a55 +d5bd15eb103e4e909fe91efe37c65f50 +6b6928f3094f41b38ab9941d0cc8f618 +64a7b5778049425c9f31fd0365212aa7 +301272e8d5354461a20cd7cdfb3e2f16 +fccf56cf28384cce8ac9e7fca423f9cf +c4b0cb4c231641a3a4c396fdf592b9fe +9f0e47cc9790492dae9a83f1c86006e6 +7727eee3068d4e3d9fca0c77b8506485 +af30b6a1f86e4438b7a877dbe81255af +0b63793c9cc44cd589938f940f9a0df6 +c9d9dc20498f43e69cfbbc7d576ebd35 +8486dec8ba204deaa98400593a14b9ba +c1e6ac573c37485f9e7acaaae418df30 +9f1c8da02e6f4806a4e2ce7ff5becc3b +dacb8c5e6d6046e98b91d75468b01c59 +a9de4519ecf84395a16f0852fbc1f058 +8e70af869af548409eed3b3b40cfda9a +3ae548d49256430eaece8eb6ee1d0bfc +6e31419378ee4ed799c00422c3c3fe83 +8831948aaa4449e5b164c62b10e4be6d +db4affe7ebb34fe7b67ff302436dd549 +cabbafb1f9794543a465819135594cb0 +71a197a9d2c14c85867ff3dfe62b3e77 +ab989d1db61345cf9c1bbb641985d6bd +0dd82c3846b74e3dab39daa8a62b5898 +6a3dbb7d0a364fefbdab1ae262d713a4 +2aaec6d2cf3348f4abe225570606a202 +6ca9e3bcedae4dfe9fd9d639639447b4 +529fdc10021e4c9f837ba2d9ecb58829 +8dc1bdb356e4432f845d01e4dc690d14 +9fdf57d1796649f0bef80035aa4d761c +8e62c7345c6d479485863166a8816493 +ef66ddded4f14d55ae02eff8d445fcb7 +4d465440bc9840bf98c748458f23e99d +f0d9cf1d6efb41728607669d03b85b2a +60725d424ef6402e96891568126aab54 +d4f466de30954aec87d5c629e45163c6 +912e06625feb4a38aebddb636b604a04 +4dadaa5050a345d9b362367752eb7c1b +3bcf2e379f0b48bab7969c6aa4f038f0 +53c2cfe6f21940a7a3b4cf59465acad6 +c13528cb6aa4497eaad832124ef2986b +6f7201fbb58649379398a8d1d5c0cc7a +7ce5f0c169a0433583e25b62c624780d +005349b8ece7424984e8b1f224a8dfe3 +3700b83e23e7418b94ccc4dd52114ff9 +44a46669bc524926893c0b82869fcd4c +0264eb8f32b34855aba25735bf611a74 +91852dca70874c3fafdac99e5be6bd97 +1b34de1b8208495abb37b4b629c1f8a3 +0d44f84ec5824261837ab03694b5a8d5 +b59197bb48314e539cfa834d3db37a22 +5a59b3b6ac644c11a3621cc7d5e5f7df +e9d8ae0a9ef94fa082a5a63e092fd402 +58e856cd176e4e60908754519a22a1fd +bdec6d6cbf2e4284928ba93effa75e24 +b207512fbdff42d7b5dc0a58d5254ed8 +b8f7f6ec414e442892482811e8630e94 +f69434d992a14787b6e1d05df65d93fc +94421df4506e4737b6bc2ea9ea369dff +4886a2ab89c44f9fa6f92c377a562425 +b9dc4b7181a14f5eb3ab618b4db129c5 +f9bef8d737af4f80a33616d7ba49b2ca +6b6fb74103114feba100c02fc5b284b3 +775a7a3c8d5047fbb1d0ec82bea8401c +3783d883641d423b8e78dbd2784d6bc5 +47ddc9cd995e48e7b07318a5886f511b +78c54c463c1e406abcfd228c5a234d5e +ac0081c460ec4b5a8310ef3c1b4ebac4 +26e8bf806c4c4d9fa58fdff3e33d26c8 +cbedb5e1f14f4198aea3be4b5e8fab89 +f31daa00bbf54bbe81790c3f7d9016aa +1b2ed84386de41e68e8627049b98838c +8c827f533043415496fd598718dde13f +98587ddd7f144805a7737ff3538cf664 +74851cdf119c4016ae17d22984aa38c7 +ba3d9e3b939446718c40d0e169ba6bcd +ae47fb3d061045569f1089aaabd840ca +b7e854a1fcb2494facd7fa602404c5d2 +3d93b943f64b45179b187604bb2ee318 +8e273ad665824e869a4d6440cb426dea +875d6d844ced424bb9eaa5659ef888ac +13bd7511918640fba71dd4ca554d5a5e +15d02240aa9648cfbc27b64330313f8b +c12681f6188a4201a939d46d5fef323f +63e4d8faac73435fa7e9e929baa2c175 +d42e67d8716d43c8bdd1585df6a5598c +ebf0aab18265488cb2403b6eb21fe990 +3d6c0cfd1a1a44a49ef6435aa4d325ee +16d799890d6c499a8762677449b9e179 +653f43ff658e42d9a8084ace2110d715 +d8cc158dee83439db9e64505e760d479 +c318fd0afa1d4a448ef0ce0b98f180e3 +99246dbf8e0e48c388768a8edced8c3d +ccd7a316ce2b47f99023d677a99ef681 +34ad55182bc0444f902d301e12650a71 +d298731943b24909b75fd439c6fefcbb +27c901f716ce4c089c6223624dea058b +c2f48e3f95b64be2a7a70a8871f62f43 +4a17a0973f4444dc82c327fe374c4550 +9102ac11b3884e179d2722cba6b84652 +b74ba902e1de48d4b0625c3bbb0cfeb3 +c6694b9cafe74e7ba46f5612a3e9a7f0 +e265fb3789864037bab682fda1003dd1 +0ac34c3eb29f40219c554ae8445860c9 +5c9113bbd9d2437da09723bcb8573778 +2f2a8835e5cc40f98a6e6bc14f58a6f8 +545054662bdf461a82ba8458bd31d31a +5b38c82c712941b39cd0c81737730ce3 +985466172dd34d4ca3a9b555a09ef1e2 +c7cfb74916684c08ac60573fc72adab2 +440be7eb5de8469f84dbadefec1f0786 +d2d2703896c34879a59a97c123f77176 +169bbcbc091747edb843d204747f504f +67917947ff9249ae8d73bd5fa78f673c +6754cd2e50374434878e574a02a60c6e +eb235738a0aa448f84c581a13341ceee +b51c7c0437bb4fb48619b7052dafba4c +16728b6182dd41098ed9a6c7f62fd2be +d843a23884734a4ab8ec9a7c4cbbb38f +da3ca02151ca4130bf42834c75ff9126 +b7742faa4dd148bb9fb6877c156c5e15 +06a27c6218924332b32f1c26c5b42959 +f229b75945bb47f1ab2393fbbda82a43 +3a80e07ff6364b4bbe5252d9b532a87a +1c229002b55148e99b144e58e4fd9562 +f4807cff90194ef5a17107cdf8a30641 +40c99f1d3fb24f0787abac5ce2944af4 +730a57edd2784c2faa9515a90491aaa7 +396d67176e4f4525a2a97a59a5f71ed8 +bed87049026640a59f3f8b5844614253 +b90827fc3c774912a76b62c7c8344bd5 +c3749ed9821046889b3b289ec0a32238 +f2f774b44930485b9506e1438b41e390 +28a1fc7c2b5b42b1b26e072d0c171885 +c50614b6796f4357aa6d7825d86f188e +28274600c55a4280b2297f277c5540bd +36e87223790a454f8b18c6ebd9615cf5 +7b25c3e8b503472f9229e413d2e8735e +d7cfc7da545949a58be64a838c711523 +604886640ac948f1980d81bc4a3ed7cf +459ce5b99da947438d3ea11d7c0d4225 +76e550147371413ba11fba13ee712bf9 +e109b84f42e74e03a42680e47bdc2e8a +a0a84e5e72c74a70af9c71f9302ce921 +d6465435cb3241f9a550067e34c28918 +7d840006d0184ef496c9860765023f52 +87461a8418374d79b38dea90e3d6a56d +a514d7229b9a408182b57a21c0d3b1b9 +ebec8fefb47d4363b2aef47850da0ebd +56aab9eeb57b4910bb72451f1dc06308 +faeab5ae48db457abc390b65f793e961 +40d3e08bba4c4fa4bc775525f2418589 +a47c3ab11ffa49448fb38fa235d6541c +36972ecb0f4240ed80650dde59dcc88b +e647e85b7a284578b508437cf0f07e69 +3bde1ab67c6448169b604dedad6828d8 +78fe14d4e6f3431686142a9faa75af49 +340090a0c11b451c835c26c4c050abfc +e730175fa6e942d3b42c00e8a0addfbd +f045413d71d743c58682881cb7421d64 +ab830e111ec24bdbbde41269d748766c +2e2af6de1adc45f3bd56ea9b07be781b +7014e0995a68423ca7a1da819463b6c2 +11113b28be364d93be509a012e6f257f +fdc6d98516c7469289038f44f68629b5 +9a5f0ba304d04497b6382da6377d8262 +5f112aca4795426f99561fb92af995f6 +7b9e48f7a223455aa9adf5115e4975c9 +7f39b77440c4416cab9dbba79f3262a2 +dce63cbd1b084cf7b5175d0c9f52a92d +fe4390b1fc444f74951b421e250b6fe2 +dc2ce8dcbb5b4bfea760fd1b1f918563 +9a180b8471c543efa5e3d1257ba5c7f4 +6671c5021ecf43ee8090646df1db9935 +6a9643a449ab416cba07aeae41f713df +cfba13ac9ad6440db68d6a65c22a01ed +15cfb4fcbbe64f8db346824a52dce1c3 +43cb720ba27b4e149d86576cac666949 +3b8f9b47275e4942a64920387c82240b +758eaa4f4cec4d31a41964a330bfaf46 +6b46b33bdff44269bf9391774bb8dd63 +9d8f4acfe1834a2ebdfc4df0fc7df979 +02797d5feaac4ccabfdf8b357fa2a13a +c0677ca12fa149c180df495a12eae0df +55f92a51ee8743cf918f590e7add8024 +f913bf792d5f480a8786e1ebdf704c4c +5d99827c456940bf9055dfe2dbc561e8 +e5c6cae2c71b45fe8fee9657af246c2c +237c379451fa4edba76c483bf7e6d08e +8237129bfae244d7a62d706937f9f106 +fedf4214d4364e98a7ec8ac693428032 +ca049ca2444c4ede874bb9744081ae64 +87cda81b50d745ac8d2c4ab1ee5bfa51 +e7af861512bb42d189bd38952651b538 +5feb04e6adac4ab7967c5097fe522f2a +4500b31d30404211b3ca69bf0d56a054 +b9766d88112141369b170070fb973c96 +4ec9181f5f274cacb2138714202020d1 +aa5bc1c5a4e842c4bab40cf08b9bcc3c +d683f90628944d81a017c58952414f96 +4968efa4a4c1494ead9a3a541351460c +581ae874afc948049e76bddf00f7c1a4 +f43a6bcb93b84f98b379c252274ee5ac +14af06cd758e4e37a919548fae755a1b +eacad791c62b46859a724aceb4948953 +95950c70053f42e0b5ee87077e8599cf +4c08526679324761855bece36a478dd1 +37e422065a294d21b0d2643bf3b56446 +09e0d00fe07542169f13fd46297a2f06 +377da8211b0349b2b13d2339eaffa4ac +6f2309ef36b34a7686cb62de0e2dd005 +2e53ce8ed59f41b8b63432496266a446 +40190261dee14648b9fa5eb8c555916e +fed6c4a6674948c092926d88346da376 +51b66585d32142058500fc5001567d1d +8d8ffad8f85746f39b68f58629a8ce68 +2c4dec67e0344109a285f3a4cb17f9aa +b10fd730b60a4b4f904db3834f92c83a +8d253eceb0b84626bb02cad8a1c0f9df +1e439c8c11a3416aa5e997a8e24dfe84 +341490d82d8d430bbc4402d8ea827d8c +b7abd02598894adbb848847f7b397d09 +a205bd471e74481090e3c903070834af +66f44a0ca63540b0b55af063abf24078 +0ed088bee0bc4915940013d533ab6907 +4d7f901aaf7a48819912db0c2d2e0bf3 +e93b720e48904e1eb354854e7501ca44 +d3f9aaecb7e94b12bc28256c85a40ce0 +c78d3320c66a4a71bceb1d67e56470ea +fd5039a460f0409294973429cb5d2d4e +748254fce5d34002a4c153811d2e5f3d +0872b511d8784e65a483bc3e7b8bc61f +335238c5914d408baabee713d7d4d474 +337e1aba96b245448e3ba95a5fdde348 +57946e0708f7425486d19903b3bd997a +01e28caba4a64c408413e5f621a58365 +6d71e3de6ad848c5b46f6eaba4a8769f +07ff66a33eff4a0a93252317708d9cff +8c4acb02deda4b7e888cfcf607b6c10d +f6b76042dd444cd395b76fc73e2f22b5 +6eded741814747329d1333ffa3222f99 +3b63269c27024f29868b8f94c9930419 +db415d2f3d9d421c88caddad08cfe9f3 +6bae77d7e87c4273a771d5ca2396cc45 +809f3456a353498299d508c171aa6274 +607bc6fac59b48a5b4b534eb104ede98 +03680417fa26467dbc9c9b8d130e923d +a22e4c087fe14d76af6fffcfd0d42dcf +ca39d6f0333348e59e66cbe4258a028a +f4160b557ee34182a33af737d2f9d397 +51b3266bf30c4db78e9f15135a380159 +f519892c383f479d9ca2431f66e0bbf4 +3c63c11d39ff412aae97af755ef445b1 +feca271009ca42f3b5572cdf48d030db +bf841e790a1743fc950657d4db29353e +f59dc96c92d640da8592e995ff13f804 +08f1f006b4bb4e04831555cfc1a3ea49 +2d8969d8aec14639b71df94596583ebc +c89b76a43e67454e9105e2da3e5e9300 +f5b158811ab441a8b03fffd4c9c27c4d +9a07ab079ba9438a857486e3f79f41e8 +03625ebdd8b34cef85eb9cb3a099497f +78e79fd7278941aaacd8912370fc3ec4 +90b59b5185b14c52944573f236eb7175 +5f6cc8885023489290a2c85919feac06 +b772a9c3a6a44c4f8bba00681c57b984 +ac8cda77b83c4b62a059224f382c04a1 +e104a61c2a3b4b3a9461f95d2b2bd7f1 +e51b119b63884299ae914941e673a5e9 +4ccf7c65e5ad447bae9de15ed0d53b16 +c19f127200aa41148fa97adfdb658387 +1cf0ba39a67441498652123ea1c84239 +b0998a4e5edc4995a9b364a3222262de +022662a5e24e4f99bde618ddefe1c7f1 +98b8bcc892a64973a1c4a4ca8af0691b +05046cb405cb40f99bdeb7108d8f69ba +102ae42bff9940fc8f0b12c8a53d2675 +d06106f340f64e26af8f0d6e6723c459 +b4954fa4806d44629a8848137c46690d +2ee23bbe8de44874afefc35d376c6bbd +8478b888c45b47e6a6bf2bc96ef2f88c +0657199531c5400e8e0bded9fce5a998 +72924a6dddd245959ecea87845fe813d +01e35903910841fdb2f3c4dc41ff8b74 +6ad051e986b24831af5eed4bcb319637 +d00b0f80275d433e9946d43a6ba01e4b +a39ea97eba1d4e55a35ab7fe7dd7efb5 +5f2556c873944bc6a529d3ec5a4463ce +7f60ec770fee4402aba503607c087705 +dc6154600fe34d4bb11b238b27946d6f +2967583f627d48928f2d2bc25f163678 +4df10c64589a467992367dcf859dc22e +abcb6181604d405caec3a3e3c8e1dd4f +355043f9aa2647d7b6963ba64ae949e5 +b2df9294d530400e814165917ca89b19 +a7014d2bb7f648bb9aa2297a326934ae +f7dfa603c0c241dbaedb6490e2866d91 +d4a5a9e62345405594cd16e733c126a9 +334020952e6d47d6b781612b1b270730 +ea58ab864fc342c1866ed9ff36ad6fab +5386fe84e7a94c0db15c0f6f2e5fe0fe +48a77bd947e648e8900533bfaf76e78e +e3edad5c3f1a4fc7bfc8e3ee1bc0e521 +ea045ee2bd364a6fb21a2c51181bcaf9 +eaa68bd6375048eb8f159a7f36ae7cc2 +b82595bea32a46a18574cfd3e1fffd3c +3651c329b15847268e6d155ad4ed9352 +18770e741ef24ed19b42fcc1dde9e904 +4eac596f106342b8816afae4a79400bc +9f84a4a96a824d129ac302cdd68bbd5c +c989a6f1f123404791f86f9ede48cc07 +462498b44e9a413ea94c58724b69ded5 +1f0f72563b6444738606014502d728ab +984e0d2c5ce147ffbd9df92b543b00d5 +de6042df3d614fc78097992b9450a23c +9d49a81015a641a3b9f89d1df65da5ad +ec30843c5a89489992b9f24cca9313e2 +309d2c2cb61d44ceab86a4044862633b +5c4a8c42277649d796448b52027a83cc +673d7693f8884e039c3462a5079c36df +ab4664db1e0e457aad11ed568807e078 +f769c1ea1ce84566a3a9c0b5f4388c0f +fd3ed249ee5b427ea2ff7183df30b75e +cfbcb02c981e4a6c92b6c86fb5ced91d +7a91dd2508d44405badf7eb96e2e32d4 +e1fe51efcfaf4c0da17b9ccd505691f5 +29a6c5c0c20c49ba823d3ea6b9d93ffa +56717487f363489da344ff8079a26317 +501287dfbce54bae986b31d1f364b281 +937b33e8c2914b788909607fecc334dc +6a18e281e1ef44ae87bf8627a6114381 +0318b84b37804cd2a9806d0947fa459b +7031d253cde1410a9ad39ae7ed300330 +d96dfe460f9f4b71a14369e5f0d5dd2f +a7764c9a884443109e9d335b6d281b77 +9f9d7e4c53d64dd19d82a7afc099f94d +02145b85eb14409ba6522d139c349d38 +3fee3d9c85b8468bb18833bf9521a87b +32c421ed129d4f4684a2a82b3742244f +c3b7d0a31071455db92cced63feab66c +f5c99bd1665a46c4acfb12531c0064c2 +a7d105477772404daf5bad8011b6f1a8 +0305b7bf2650453d8aca2639b9a3c5ca +4f30d3e65c45487abfa438c0368ce602 +307dcbca47124ba8a2667edb34588a0d +3d1c606dd9ba46cfb3f5b55e78e192b3 +85f670ad12fd43eeba1ca0fe8dca6554 +67e70e183487464cbeacbdf25c34ba46 +861bf5de961b45ca9636bf9b66beeea5 +c84221e0bc74453f96c27c6440081f56 +b3f85d00c64042b199c3302e7f7a8fa0 +90de6d1e5d4b4a3093617e4d926835ac +27abbf7bfb5043aaa73a4f9030f06f43 +b02f0c3435d447258155e1b8313eca71 +34a3ad1f5a1947c5a07cee4b252efb00 +15997fe949024e51b4a2cf8df3fe3b5a +65649513903f49dfaf00eaf843186780 +da8d3bb426ba4142962243b0394a40d1 +7fb16abf78b8428598837525379141bd +a5e397b1cdf3457a99573683198bdcea +8015ed2937b6422b9f7092a096c9453b +c83c466cf32341fc866a9a22e6576b37 +d3152fc451dc442b8f4a1ae87859d39c +d3ddf95f04ec4c3d887f719994d36a4d +3cb18b0abc31414d99b9439009e14549 +378d0cabc6a34e339640721bd7c73a42 +f8dd844d69d1456bacde4230e7ce9def +e1f1d2db99024853b3b7b6f43c055841 +072d0468bb97447ab1ca7e3edea25f1f +77c6c8ce9199433d8f81cd77f99ba978 +aafe3423e985485796b896bddebc8be1 +b96f896453b240ae804d0399f1faf027 +4aba936878a54041ac018267b754957c +34a4df9e08fa4808971c89a29cc3413a +b17717dc9c95477085b5ffe3f64d25f2 +83826b4fba9a4bbcae53e38c02ccbfea +c758edd810344a1b9e61d08908546c69 +badd499c7c754719af012bad43996707 +416f4870df6449dfaf9533be8aa18701 +1a3a1f8930364b828d6ce53d911f7f24 +3513ae49853d48609fdf8b26020d3c4f +98b013412b9948fc951fa2d57d32f7f1 +62ae011828394965bd85c199a629c313 +ecd70bf53b29493a84e21037e1c3aede +df406042e86f488ebe67a107d376695a +664466bfb15e4282a8dd4955b1d11e94 +84673ce712554863b64d0a633f5d78f2 +88a0fef863894ae3a7efca99b36e53a3 +593d9b663c414c0c8cbe48c311dd9878 +6839720020cd407dbf4d6a876054d746 +a57504f70f6240a080b0f86ac1197aea +9a87c4971eed4fd5aa6e1e3441cd1e70 +b525b8eaeeb549ada478c0d72b1411b2 +5b6f25eb897d4f0b80d19bc5c4cccaed +b6b28aa8ce634df4ae992cc8154f7368 +196caf120c9a49159ad1b877c8d595cd +4af7de2edd634b6596b167c56eb8b8cc +97eed67575434859b1ac2b2c1f6a8380 +65da26b626e24f3c86b66b77b08a69a2 +8ae388979b4c45e0ae625e9120a017d8 +85590b052efa4741897cd0ae4c021a8b +ec2abc3ddbd74f8685979d59b3ef0a7e +551d23edef9c4a78b67b6bba9e8f6294 +4b67b1d642b442e5b10114930cb90690 +4e656e7e7f5d4bbe9549e6f7b43868ca +dab93bda54de4470a46b07d5a520d0b3 +b95ee38c708746399153f2b00b52551c +005121da5ed340b4aedd168e33d56714 +f09bf24836e548fbb505edfb1bca1084 +51593e90dde84b52a57d5ffa7320b69c +bf76a9f3fa604c4297161af894541c95 +767a395d901d40128eb6c18bc64bd202 +6c46f07779744b53945021408a5c0807 +f70e99d5022c49b08a0581778d88538e +4acd6e81122542a58a9da9695185a231 +e9ed215eb0904811aa56b0b526795bb6 +924a5601dc914ba3b0c368b8b1e92047 +955b4434217e46ec93eb4ae80d51545c +5b8095131eca4914b6dce4e96b290a3f +bc84a37c1a934aa08a93a4dbbe26e3b7 +a991699c4a6f4d969af4eb46d9296957 +47b60d15269e4bf196013aba2fa2a7f1 +fe75194122fe42b4bf412bf2dc53eebf +7903499ed5a741cd9e4faa447013057d +85f535e135844d678cda6420d1579ef0 +96279c51379440b48577869ef83ea9ea +ddbdb49df4744430877621f83e08a737 +6d8fbfc1d5694a6da73ffd93ec75389d +3aab20b9e6364bbd8730c8af6ebf3587 +af3c587256c146baa928c71ffe9eff77 +579ff7f8f4ac4c23a54ef471f13a879e +e458cf96b19e4b6fac25433e1808ac10 +24c962aff49b429683acf426855211aa +eb0df79f44d84ebbbec3a7fb92f53503 +c858b13b32a94b4f973e96966c8657d1 +a1a159f78d284cbd92754465f03f21ad +d168d450c4964105aee709202134c903 +ca3015b2a66a405ea9105fae0aa3cd0f +fc796ca671ea48a98b0e51ba44801f1d +57f312a075654b428bce93f144b77077 +c3bb117172b2403c8db450ff57f76d09 +9871bf23b8a04d30a0a9b9731bae1d14 +b076dd3a2850489e8ce655126c64c57a +12e6d0ea1da049afaf3fee3c517ed64d +e3dd13f1ff3f4fd29aaee664093a7436 +c27d56c875834fb48ee7c68c79d10cc5 +5ad347e986e546a3a06762ae64b1d61a +3ecbdbdd34d949338e85c7594f606858 +4c15fd435ffe4154a3f3852d0820bd45 +ed5b5411b2524e1d9a875180aa1ebd51 +a1d790243227476ca11e3f3a0177584e +5982d309266d4654a01e01debe54d842 +12635b3ac45d4d45a04ecdc43ad5fa61 +b221ad482e084c449408c229cab380d6 +169d7e568e594e0780f5742c48a9e3b0 +062f472c5b2941bda2c498e489d7c207 +df9f6717fa6c4df89271613c20dd8b60 +8182a295ca93401b8e3006da7174e198 +53af518a5cb04a8d86b5746268e15604 +5d87131def87474883f7c7254d6ac313 +596d5066205c4546981c191f4d013795 +2ce176f569cf41709629e713ece8d1bb +2e295f6f798048e2aa0d24e1b252d8f6 +5c223d0fe2cb4478845491185d1b1e56 +a40b369b82844e57af5705f113432113 +96ce16c9193b4192bf3c08e6c58cc137 +625e45f9aca946ee8307ae335509822e +bfcfe02939e34c91bf99deeaea6b5ee3 +2cbadb89676245de801b4d68de8201ec +0ca8b71cd0e742fc907b7f336b119954 +43d70e06250c456c892171f2b62920b6 +fab02e58e5e7458eaa83b5e33a925d99 +368309e05a2d48cab82b00ae5a1d773c +8168ee85cf044d7ab0f7b5164da98460 +050649b4b5e642f0a8554b29cf22033b +c06d6248b9d64173b376926ee212fd6f +cc05187d1647454585f3ac0871dcc8fa +2070a8deb23c4df39c9c5bfd63345135 +0284d6ba1b13415da4be3c7ba6a7a622 +e4c3153dfbc642049402df3e15464a06 +560b013c4aed4cc093de013c517b696d +2fb3c8c315474a6caaccc63ec00d0536 +2cb1976df4464fb8916a18bf718bd6d1 +37a18af36f3e4d6384a37b2d3fc4049e +dbbad999b40242d2988fa7e95b5c5c34 +f3c251cbf4354ec4822db9e7db7554c4 +0861d1d6c48a4bb6ad30852c9322c012 +3c8738bafad8492f90fc1ac03cae344a +8e61eba9e4c8400a9bec05a0fd1d5bed +1d6f87444d75400bb9098c7c3b5044ef +aa9e0ee2c9b64f79a2cf6c6bd53a1fd3 +175ad4096e7647f2928f2d4575a5e718 +cd471b55a205468ba87a2e8494a99746 +2c3f8190cb374f6cbc8aafdbc4eb56e1 +384cfca19e1740e697e73a820f4b39a6 +098db6acfad0452285ce77781932fd24 +3e3e2099353948408a2737f8cc4d1738 +d0be4f93e59e4d4c970c9f4e37c03fd0 +3aab0a64b603430380860e8151c2fe1a +8ea0327e651d420db2efe1cb4353a3b9 +0bffe315f4644680acc6ed07f9f7d488 +520243df8f944a6bbbb31a4c24a22cf6 +e5e0396f288542919acc133f9bcdeafa +d6757e4317b541ad81bc7a23a48a27f1 +2e6d9e77be114535b01d7ef028c2f49c +f7ab52c4629740489294c89557d8c52a +acc9845b7c48479c9b23d93d3643612f +d8998b6605704851a7851060b2100887 +b0b3cfc84d794031b27b17f90d19c025 +056cfd8c9b984719b1f96fd7829c981d +7cc70b76e35f41dd9d8352d7f8210bfd +22536ec10cc2462db661e5279d83ab7e +3857946000c048d0b0b880e5bb65f5a9 +b661727aba18409ea821c049e0056c4e +59a9055a9a294e7cb5f79e102606c181 +c20c815f51f24e2e8b7a3213c1b73051 +dd8ffd134d3a412e90e90070d9eaf9cf +abf2cc54e37e486696c25bd0c86402ba +2458f980cf584c45a130df3fc39d47ff +0918fd7ec53740c1944b122008ee0e77 +d89adeb59f6f4f449c06284be12a9bcf +b959233d36ca40ad90a3eb9dd3953c20 +6a06f52061d84ff9951ee57c7c5332be +dcb5d1114c094e2ea12c33e7286a287d +f33fb37937a34aca8aa8602820460e51 +a12a11e501ac4248837cbd56318e5245 +2f9e7a1893674e01bc0d4f8ed425cdf1 +c924ee98c4324ab0a5f4a1e3a11c5eae +2204d5441372457daeb2fbaee085ebca +d3ead6bb072c4e67a4e417ef977ce731 +1e7f6a00a82f4c9483ff4a8fa8d3ad0b +bfa3b87b097548fc8ad6dcfae9db4dda +c4e5a8becd514290a3aa37721488a435 +9bd81e34ac8a4f3f9406d0c05949aa56 +af0c001ba99a4d44911caa948801359c +6e5c625b03a6417ab21263bd180df837 +da93f352bf434f108dfe5e6460a99766 +e4d61e9add3e4b24ad1094274df317f1 +48a23ccf80d54be88b9f7e39f10573d4 +4fda8102812c4a619a8cfc41f7434433 +ac00dd4042474b2cb5e245a8b72598e6 +bb186e949a904cd0aeab7035a42cfb90 +bcda2cf96cc6433ebd36c9eaed629588 +401df6b99a4142eeb6bb1c02ef09c18d +c55ad9d105a84cc49e5a496190cef311 +7aa9002b63e9405e81d9985790acde36 +ab795908c0874284a01556b71ac8f34a +ad9e59ebeae9456796439d5464d7dd08 +726571b60a4e45239fca5756c75f0691 +90f88566741346d38ebad86d719340c3 +817ba23d2e34484fb1cb3c59f055cf23 +be6ff8750f64417d9eb55c1ff4762d3d +008fda58985040279284e7498dd30c49 +b1a99e828103414a93e02ef2f8306578 +99325395edd44438b36ad04cb308a3a0 +894c7d8eaf3f4591ac4d4efaa2b71983 +8feb95d8b2a84d3ab7ac451efafd7247 +529c82e35aef4230849130e09e7f4522 +42f0a41639a14d62ba6ccd77846ba7f1 +f98c5ee54c4a48f8b5eafd35a81dde4d +84093c9ff75b4fe48a79b3fad099fdb0 +b2d9c4228f8f41fcb66de1b793e6e8e3 +bab7380b01094906b3dce44338f23237 +3e378d360d6b4a03ba69b0273bff73f6 +373851d3dd9641158f53e8d0531e271f +26444bf184ad4fe0bc3591edbac0420d +3b706feb53764c1c82271e02c10f25a8 +20db98f81da04a1bba33017f615876c7 +7b4241e0a1654d3b98ba922778089b14 +ab44344f1f0a4d36a0cf3fd720d875bb +9b5f6c0f630e4436a39f736f0d7dcbc9 +324d5bb9a82a4b178f3811bd66d2c9cb +026f0fb0f3d64bdea19afd4f4d0797a5 +cecf76fc406e430d928f009ac557126e +50c2cd64486b407fbd07930ef7f2762c +72e529836ebb4ec7b499993c12ad4858 +ed30919c961142c1a77c931dc13ad5bd +c86ced20a2884b448a28cd32d6139419 +e3467ea791e24a86a1349d25cf98a1c8 +40377ca02ba74e2287f2139e92048c5d +22d0965baf344085b8ad8f750b2052a5 +1ae202f921bd48e6863a01a93744e499 +f0b0ea89f20b4f10bb583c449ae04d9c +8a15fc1bfba54da0b7faeb59c0363035 +2b8040dbbcbc4b1894eb7cd1325a30ae +7c18e7ede4394b5598ab7130a12427b8 +c99de34b3c9742ba8c42e4d2328a4760 +393f1de0665a4b3aa509746ce9622078 +15a5990426d84e87aea12da6278ff4fd +44204a5aefa74435907c85e29587e914 +03813fe8eab1417eb7bffb45f9f083b1 +1e1a2a7587214031add2766799fe98bb +45f280deb29c41c8b96847a9fd6cfbe9 +1e9a0f0578434661a70056121f322f30 +c08fa9c29ffb4233ad16ab82a79b3125 +d84e5a3e4d9a48d8aaed93b7183235e2 +5e71077e5afd498f850b49231e47a647 +92a1f382f1564f199e954a05ed2dc349 +86a4e42f3f0e4847b58413ab69f0c789 +fd05cecce82346e5b85949a0e1be7dcd +b077971cff46463b8334f8cc510acd09 +abb2916c07214d9d95cd70bd2dafa8fc +9eefd64788d040ffb765813b3da64333 +6d7bf998d2374980ba9a08c5567fcf24 +d525ae1197d142f4aac2bbbb8f64a171 +759c2774396a45bcb0e04a1ae787346a +1d7ccf5cf71744a694b77dc7276577ee +30afb0dd7d714f6bbbcd4acc891214da +5df981cbb7744925834d66fe5a6e8504 +ea81050ee61843658b2b95d94161a2b8 +ab3294c0d6b84ad09daafc9fb433c2b2 +85cc12859e9b4033b7eda7ddd56e50dc +5a2e0fdbbc5c4122873988a15cbc0c39 +ad0a9385e5524d9bbc6b73ef5ca576c8 +b306d3d3e23a4eb2838e76fac3d7c097 +3ea32be2d0324a5ca831f2b60e4f8bc5 +497ccb9d4b8d48ef9f6e75167c1dea49 +2a3c480e033244578c3bff0fdf9d39dd +4253e72cb8124e1a97d9d7ad845fec23 +4ac4584387fd42fba25086c42148fd6c +1473f199ec744e86bf34008ab90ba58e +d5f59d515e73454380c9280f3ca9df01 +87eb1bf61b5648e4a6c0335ac4fc7fa8 +91b6e68c947a417dad03bca66d5a926e +d0f8edca337b43338674ca392f36c4df +a1ec1e0d08d1441dae73ecb170056df9 +07141ec4d54b4485be1819a52e8ce7f6 +8c2dd7c421e2494b8acd73e9938a426c +915df72510864d559a08a8695d379540 +d949b5c56a28477da220d1df1071857c +5b7c75521bd84fc3984e9abd9addabd4 +be46f146812142569ff28a1334d14e3e +e13114924120441d862fc221ac8a4c03 +02fa220795594ecb85284ec1dfc41a4c +1928920faa8c4a33acdb7c76d37c3cda +45fa2f2f335d4f73984042d16e5726d0 +f3d1ecf9bc324a96b70a0dc305300ea6 +63b20235d5134bf1877168cb2e232a0c +14670585f48a48738134523d6a5b17e6 +79fd371f7db5439e975242908dc8db44 +bc3a437f3b48412c9a2e22a35c9f82d7 +f5fb2c4052154cd8a6b02c2118fbfc44 +b07fe40e15334d65884e51c71c8099e0 +8b51a94040254d5d923a32b203d94a47 +23d7c85ed1dc449fae20b269fd798cb1 +cb5a7d1dab4b4da8a6f6d1332f71b27f +5b7538e15e4c4abebd03089cc2b51bf6 +b126deaf7dfb4e74ae518f021e2f3dfd +f0b12153a44f4f048bfb05fb593a8b4f +9f3ebb06393245f0a273e6e9baadd2a5 +91ed4988d1f44a0b974ab7f2f0cfcf40 +613da9912a4740a1a4c01e9de6dac0ce +3378aace9c7242d995af734294f73275 +88a53187eb424f4c8c24542438ed3731 +8d572c96435d4b26b2ca83aec07196a9 +04eebb0543df40bda1034ddefe0047f8 +2418fa403fff41f5959f459085d2eb08 +d9232d8cd4914992896854058199b961 +784182d18b0e42eebc66035666757814 +af5ace26f930451eb9469e1dd08c99b7 +0c77dd485178478daa5c2d7b1b19e72a +ac7a64f0ad1c4f11b81689b7bc20c3ff +a2a048847e414be6b4aa66fa6d3687e7 +f323dd4bb9f640a4859bd8dd31ec233c +45911c6ebebe483d8fe2d10635b238ca +5efc09934d6b481f8481e2246016554a +1acac8dba1ed46439a42d76eb97000af +25ec4ef119b24f2b8a46c8441b9b074a +346548d0577b44ff9817e2007048f859 +fc4777bad4c647d6a21637d68d5d40d1 +1b78be3a0a0e46ebbd7c0c12ee676ec0 +3297c67207d64233b53b390062c532d3 +9a4b89d7ff5c482dae835df596fdcc2f +bff3a33dff32414e83fa57e650e701ce +929f570129dc438eafe2cf7083fe98a9 +11c479ef149e49e1acf5c7f2d4813cc1 +bb2896720a1e4aefba3ab381d4b4554e +8e6a1ec6c70f49c1b7c3aaa7901e19f3 +052e699d724243cd98f76efcf847b39a +78948b205b93481a8bd85497db98964a +a71c9c05480a4979ad246fb3e2a026e0 +3edddcc65acb4783974e8665b368eb8d +8409e64103fe4f1d829f90adca90cba7 +c6be53b6203042bca827ae3d934a057f +3bd5dc4e0fe24014a6fbd2abe0fed088 +b6efe4e2f87f42318943974bff072c25 +1b99c507298a43bea0644669ef518eba +68bc5563e0d94362ac100275ce9b5ad7 +7da02269f3984896b8d9a73a111aee08 +9f47a26ae86b4bb39695d3734dd78ee5 +e95a6f1226f44ecfa761b3ffabdde9a9 +4dd64ee00ff94f7488ff7793c74a8cdf +5d5b2a197c664856ad17d813934d2c15 +33fb4b71dbb4421a86427d56d892587a +cf168933583e4716ae79b142a569a4a1 +6da9fd8b9d224e1c8a346f397396623a +cdd269a997704cd58960232f9c1f2c90 +1648379b01734c77ab248ed1bc81aebb +1486d72b4fba43acb829b5064cd4723e +800d3b0870e244b59495b835f464ff9d +5ed462dfc2b34b66acc820f95a04d426 +8bc661e726714de4926b7d95ab30c81a +2d157e52273f4212b288c40d2121769f +54926ff096ac4b5686211685e834d908 +741ed8274dea446994e5ee240ad61220 +3941b1c6743348ceafbaa3af4c0a7b0a +2f2a6a6f30f64fc38fca1c662903b591 +8bf18c30f52142c58229728492f58016 +9520ac8ad3e1424f85cbed8af58fe722 +bf5a8c7e6935457882f5e9a5dadd0ecf +50be70931dcb4a838b906382233a28f1 +c10d42bd12b2497ba5ced33dd50e3f1a +5e0f504bb5d144809390dac8c66a6dd5 +8c26e4c5d62c4354b44898c19f4bfff8 +a93177cd6d5f4fb2930b9c542549ca87 +65d4eef2ea6d40a38a07c5b421d1bc68 +bda77addf88245d69569bc351b55b3b3 +00e1490bb12f4ccab3bdf8973d165b04 +e49dfb061d51494d9ac1952130c5de0b +fc62c6020b2f4b10823634d5116805ab +3b9f8f47a2e94c71983ef4cdbf74a190 +9e6f5c57972346cfa5a83e81ef9d0845 +0283a4e6c0364efc812e11ac5473137c +801b4b81b9374f14987ba09aee7af925 +a7bb51d98e0b41c8a14df5d330df4ab5 +422bed8c63b243cf972c79df999be877 +6c16027c8c244358984a82677d768b00 +f69ef12bb68b4fa382f5680fe039656f +ea8039717cb244f5bdebc8d9e88a017e +04eeb41058c64a039ce777800cd22580 +08280e9d6f024942a3f57a9b8812dfff +9797a95cac50408d92c324513b21f226 +d200efc4f0a7413e95e6a6a779f91623 +f814628ec8f74df18cbe393c6e76cd0d +3fb1a4b9d14c44abaac69fec119bf251 +1a5ef5dbcd304f3a984848cd26de890f +b84402001e314a34b6ffe0a363f5feb3 +353ac8a56c6b427592666eb01dfec65b +329f0b6d71f245e89ff6cf8371180025 +a7f85b807068402cb71a691554b464b4 +9c242421a7c1447f941f72b57e7473e5 +eaf4a00ea3e54fe4a31806cbb7f91261 +3b1bbe5f59134a369fd613d2ef28c821 +15625b34fe114d3faa31dee3636a1349 +094697a23146463cb5564ac8bf89e5c4 +aa064f3c81904774bbb4ff1bc56e2d18 +678269e0220943e08404d555ffbf3873 +74d14ebdbbc94d8780f03df21cd93674 +e440e7d726f3411aa81ae37b10357124 +73bc5f5503de4782b8425fbbb8384f72 +1f925d3e397846aa8e20eea433f47e8d +0a68a840a3db463cbb94693ab695d536 +7aa5b4a496de4fdd9d5f3608b3120657 +423fab6060ef4d12bda58e99e6f76193 +b45efecfd928440b9e7283789e5a9c3d +8928df76a37e45a2b3cdddbe696087e4 +1638b8d4c254406c8d0c201a614034f0 +72174e0ccc1446bb939661a694a6ae19 +9ecba41efdac47f29bb180cbfaef03d1 +0f28b37837004b41b6e55573e5bdc813 +e60666a29ba547ba90ccb7c48389dd4a +79ee187249204dfaaa502bad9b5f77e0 +010e59ac3bc14cfcac5056b42978c9e6 +a3fd9d01f45a41c1a9b8532c086941c1 +872255a79dd5436b858a08d36e1d1212 +826eeb384b644d278e78c802ac59fbc3 +c05684e8316a4631be60fb1ae92532f7 +3529e97a616241f480a0115d74f97e80 +bc760720fe814b89be4fc68ef796a58b +ca63db1db205476fa6f54e1603b7d15d +5106f58927cb4cf4bc2f3c43c008bc1e +4b7662bfd57c4be79b01c7b16819b06b +6af22f373e5646cd912b9bc6b4211a9d +bbf27404dee044dbadf5f508a597dc6e +41a0c5b365cb4a55903c8a2196063af3 +1410096bb2304973809b99d0e1fef220 +ff4adac17905436c9f244e432e1200a8 +e24f99d09fdd4aa0831d11c27c4f725b +eec42e4c8e674a4a83e414107fb0642b +6afff5c83f1f4f989b53573c26072828 +5c933ef8b85040a9bc13299b3f5f5c86 +ccbf5fd5cc454efd83a955bac7397a39 +f165f665ca0448369c8ef1320678194a +23c639ca701d4713a8c7f6480d0a8797 +b5747dfbacdb47a3a4363170e6de5a85 +8e1627c5b589420c9bbed0e0cfef1502 +787542624be648b1b55e453052df8e1c +376690ee19d24138bb6de11d197141a6 +59b71b9ae89340a38d7b1a423765ba0f +49be125faa9e4c679d851e798e3e955e +28006272fe514cb68e3a0ac2125734aa +eeed915e737b49f4b70a82921c2726b4 +7bd3f67b7ea2448796d23bf1f493df85 +cb25b9b10ec54c10b9306e3bd3204c12 +d9fd5e64f2174769a222bdebac115181 +80659d45b56b4b9bb7279c146bf0c615 +33207568a3f04499a921e95ea7c49532 +847d606e48844e6c981ebc45d2ac19e7 +6cf47eab249c4ed7a476341a9f4a6758 +9c2e912b845f4ae5860dcd17e0df4e11 +1eb2a605dad84949bbb8d4911ec41359 +3f0ee2dce6434bcdb76c4369a5f97e2d +766453309b0b4486ab55a596c821c050 +1dd7467ee6b947e6b6cd03368c00a8e1 +f4fee954475a46a5bfa98cf3f4f0d0d9 +6a83113968ac40d5848d10e5a6536982 +0b9ff5b87b7b4711a8745c3703f08223 +cb36b152c73949328669752bdce6921d +00a1a602456f4eb188b522d7ef19e81b +b45a8a265434477a92087d0446c6db0e +b14840d1fe7a42b592807079df691f52 +bfc99e2cddf8495f93372974ef5a64f3 +7947114250634c919a6fc515c724ca7c +4bf930218b60442bb3b2fcebb3ec4850 +7fd2cf441c5044ebb005e68893f0882f +8e95fb7cac1f4064b1954510922f7886 +9e08891f3fc849ad9180c9385ec5fa6b +cb0a873201044b8aa5e4c3212fed3b19 +73f9ddfa1e96447093718cb3a6bc11fd +cadc1e7d00f54cbeb14e0beb3b1a2e7f +30a7d315b75048fcb92536f82840e7da +34f92922bdbf4275ba5c98fe0ae11e3c +d06d152ebbcc44f0b60f37ae9350bf35 +2190db3fd04844f88543787a913e8b4b +4e87929f724d4083aaebb99a3db71cbd +c1338e44401949c1be64e6668d38c100 +c05c98f523df45b78d50913b4917e9fe +d9e9b8f3a41b4dd39a0f5a948ace332e +0e3a24bd38a5430ab7bd333bb95afc1a +816db1932d6349808b98260b218726e8 +2a42d9a558ce4924a57308165adaf07c +0bdc57ff6f924a1fbb863ac0d4511fa4 +bae775567d574635a9661f028776dd51 +f339b76ef27c452cb476035a97627d6b +db690e8aa2d44b8fb362422b8a242eda +a9d846aa86944911bd5f983a6c9f2faf +e67480fccdef480db204164c64f38b7e +9f33e75c53614271a788e3a5e086cb2b +6beb8d90379f40578dce48864e73d648 +ca8714754e0c4a4f82adefadbf1b2d1d +9e882a49fa66490295c7e152732e39ad +8f4c5808e25648a9b78a2ea39f7d271a +f2b22f8753144b83b189b9b0b2f78976 +47448797a2474c6f8b5d33b946bed635 +d9f4807850a34eb08ae635412dc5b3ea +ea80b4bd735d49458568093df857e8be +77748f51f2d14c9fab18fd2a70175c31 +232ba04a0aaa431983641fe78e4653ae +62d84430af884405b0d8f2400de44ef6 +4786c095259146b393dcf903ca6c519e +ce5c3a6781574d0093ee3b7b67d61851 +e76f1e0f0dcf46a78cf31a3946622928 +c46d64155bae47d4a0888cdfcf8c27dc +42529aab3e764437bd73bff8eb6e3a0c +4a37f0744b7043c0b52253d9cba02fbc +fba908414c164fde8320f202382f7633 +9b6205bf8b034c02913c006cca62ed06 +bdb663c8be5e43fbb23522e994ae52d4 +d9943c3a36a24070a5e87a1b8750812e +196ab6a55cbd4b999beccbce3c7b92a0 +93aef5b792494836b4704a0dd7e7c3c5 +ef565ce5679d4ce693e5669ad13f020a +2127d3e788b24e1ca35c8f24cbe2db88 +9ffab4b2b1c149469dd6e0664cffbb6b +26ae14bd0d2b4650b4bf878ca85ad06a +8f43a990cbd14895b3bae5f43328a5a0 +2972712fbbc344219b1e46fcbbf30e78 +cf82dcad77e34c49ba2910451fe96f59 +8f8e1646cc1549c6ab22f1a3c0cd2924 +77a7cef9019c4a50b982e315b38a90df +be6a5866f8584b08b17c8bc5d00b71f6 +c23b33e166c14e7a80fa0e849b8b0ea0 +8afccda6a86743368429e4271348ddc7 +d4ed2c23bb1140a0b5540ff3ac7fb504 +6126ea3363ef4a27a17a1074055d9f52 +8cc60d44baec49558156ac767839c2ed +93810b0a321145ecbca82ec0d1d35410 +d5de1bd7d24c4d5eb9fd0e55fada7954 +037539f91cb34368a44f70eec628db67 +8d7469d6f0744edebeacbd5065bc68b8 +e68046fd93994b3e9c4e3b072d3cb624 +6187bcefb59d4bf884bbb97e3fa5832a +99a8f14ee18a41039296926a6ed680d6 +49a8eaee73a943e08fb77049f8b0d16d +36a37af9cdfb4ccc8e129910a35fec92 +9c30dba5b5aa4365bdf303a8eb6d5dd6 +5cc923ac81964bca8b6f794059719df7 +6e9bb944159841c4aff69d863388e64d +f678ca59b9704a83abd0737e0980d4c4 +62a8867ee70144dc9e1f8faf2fdcaba6 +a38476530668484b9cc902c12e8adce1 +45539fcd778e4de9bef329430a611f72 +83adcce7c3d140748082575bbcb4d19e +36a874c792ca401e851faab0fe747bfa +96c9dfe0456847a299e75f74e76b4bc6 +c50e844108c04a45814303e8e7be3bf3 +e91ea830e5be4111a045d674ac81f256 +6d594db7ab9741a7a0e0d8d61115926d +88408a7ed7464911a7da9c4f598dc5b5 +0f9fe38a1e424a47a77f8b1f8a3e4efb +cebda32042aa4159afca6a1638d00d40 +9bfa66328d274aa784d0e2eb26b4ddfd +f77acf98f116492a9f8bc927ba375123 +8b047833ef7d4a16b7ff97f66d1c2ddb +235f67f4af244ea79e43c90785108192 +55688f001d25496f9fd01476a5ced848 +09247d35f0e244c29c6b7f7c36a12d45 +d4e318b784674550bdcd6a687383a7ff +0d4bbf9da3a44860b22c3451c7c94ab4 +4bc60007e59a476fb01141f72bbfc825 +527f0ad9f3b847e4baeb2217c0907876 +71b53eaee72e4a829a9256a7bcfb7dab +35cf2964b5334e4db53649084137d477 +3d5472e75803434ca163b07db9831d7b +45b837210c1848f2b2daa3adb31337ca +666d10471e094bf6b9be9756ea97bf43 +a34e045f54bc4121a5b02f44f06654aa +d5e4fec6f3964e5e940ab0f5670f19fc +56e13a61114f4a2dac76f87d5257e984 +4873988f0e79415a86f6a392fc25d270 +a7bd3ef22d634e67861e82ed44214a0b +3d154ca29b1443beb9f8eadd35694737 +3ead0daeb4ee4d72aea385b1158ef1f1 +e88e7f1ebe9d4972b55cc05b45994c3f +869366d687b94193a625a84040db4a64 +4d9b418b79364283bacc3fc18c0f5f41 +99772edde54b44e1b430fbb18dfc49c7 +bd859aaeb06f4a20a48c6de7eb57ef39 +30a3a9483e824fefb8f59d5ec09d20bf +8a17a71aa6bd4bdaaf7fb4cdacb2f3ff +65ff77a1624949789cbbcaa315021186 +ab8f80b8ffd04e21801bde322a7efc75 +bd953967b7044cdf92315626806108c6 +1a38a86296524f35904eafb0289aeb75 +b74c7b814fc646de8ec874abfc72d722 +a58aabdd62854c778e2e6e779ce16124 +6cfe19c7198445d4946b534187ca93e2 +135964cd764e46ff8ce737fa0c160bde +58fcc949156b4092a2b575fb68b3c1d5 +1ac6a371fa734f77bb02e1d6cfd26cef +e408a387dfae4de08107923698ef352e +1018862b44bf4afb9ab7edad916a0059 +66b1175827b349d183341514e3659ce5 +e0c2951ac0ca47b8978b2a6eca426c3f +05ae3b8566454f3ea749d58417a64820 +c4ea42b0c5b745fb83d095281df54a5d +59f9879327134d68b48f4d29bd9a6958 +31e791f6fdcb42048b65193004ce05a9 +6534994bf1cf4f28846424479e41570d +43819752da2e4346a8696f4e8802a1f7 +c8a87c284e16437e9aef062cd8bb4119 +011c1d13de134d14a62d7b4af85dc810 +2975184cb1284d51b40724cddd0261ab +1582bd8176654bb98871b8c20ae94a72 +13b9b033c35247209bf07ed158a50a1b +e650ae377d914380af8cc66243aebf0c +b6cf6cc2083443e6a92f5fa5718a2b8d +9837589c6b9c43919c8e944754745d09 +b9b8d6b4123b49bd9118f3b6d39d08e9 +b44e188c76e94818bfeb0fa136c4e1eb +2d5479e9bf5d4b07a3b4b486cf092bff +19e6236a1f334717a06128e5c892be2f +1a8fab413e98406a8c3ec3a2c408ea76 +7a5adb4fc0894048b96fb92aba6edb59 +a837466af09845cb9b182e98dea872e0 +382c7fdc309d4c10b22a8c26614b7f0e +1b4a96d584b74ed593247669bbd8e38c +69cf45c71c5a40eeb194c5e170823551 +239e17db7ed94a699cdf3677378448b4 +8040408b970745ea8cfe69a3154aaaa6 +c0175dba479042c89c66fab958b0c29b +520f24d9638445d9937a08222a64286a +d84c128355c547809dd0ee8113b92238 +4ddfe24465c24769af01e5971e82d509 +36c1afefee604a88ae8b8cd7ca2a7c09 +b4898df586d54235b1cb01b173c41cc0 +3d29c0ca23734c28954c1ec0c4d8f1ed +9d54acd6abff450cbf58a8238d66a178 +98f68a42da074617b881a2225c6040bd +cb23c076db2a4799850f32eda807fb2c +31564ba77f5a468c911c1573869b5f69 +f026592a945d409784985b46e3876cce +544270f711e94f38ad6e5763a0be9043 +089826e5091b4d9cb6ab884639bb4f92 +bca5b11c49e444e18363c11a8436af15 +1898d35154c64b0cba12881ea68e56d9 +76c068d30f0b463bb800c0beaf792a4d +bc23e281a8fc43a3a59ec6fc92c1d855 +8e9a756595ee440fb8cd559eea6e1bda +c15fdea39c1147dcbb6dacc312f97596 +683e2043a99d4bddb750098a934e3533 +3227ac9dd92a449faa8b3f6533c65ff9 +e60ab5e5d40a45aa8f6189b28476e535 +a285cd47bff94f0dbf726c33e3f44b70 +4b3e3e9ad42944adb359bb5014e0c23a +4cc9c72932854d268551da5ec0c3bf36 +17385ac375154527959bef303a881404 +46b72ffede9c43d6aa237315bcfc6443 +b41329f9a7464f6fbde54cb150fde8ee +7de77265cd6c4a07af7eaf3896153ed7 +98886a913e084cfdba4ea3dc026022b7 +8d62757bbe0149d2b7672c1489a567d2 +a505344d484d4efa866c147808acf89e +4ad3ff1d9cc04163be00391ef77c9cd9 +a24c02163ca349d886d32eead5fdd9aa +ce6878e55df6491ca4a227da5f858579 +dc3d8c07769e4226833cbd01a2936939 +83f8b6d6484d4d14ad8a6f28f5e06cc6 +10b427bb13ab4ddb923004c59af0789f +41574a23a9ae4c9d990ffe672af6281e +3ca14bf02e474a52b16518f9d694d15a +5c4c713b9e2841648762800f677856ce +d1d480f42cd04f7394c70a7b8ee7bd67 +3576b933f3034f0bb81121463a023010 +4123853f54a040c6a24ab9ed97f1b841 +687667d848954107b4302ef0393f82c2 +aeba29512e8b40d2a0e9ffb7ce8a5a05 +3a345f16a90b44dc868772dbfba411d2 +f2670ef082da4d818f3c44635dd1358a +451aaaab47f846ceb2c6fcee2d1c1488 +36080ae42f2642a99342f0397f39b3b7 +d83ec64c6ad844ae82f46c234f9b7d45 +c9e848982b4e49e893d2b9b55f2d01a8 +74fb76422a7244a2bd73757ab533ab94 +12abfebe42664f19b69a84b5f0a83448 +4d595c5dee47445994b53c218d1f55ff +3da99d95bb1b4555b06f1ecc7e4667c2 +cfacd4eff82049b19775791ec1aad2d2 +8f2d3e44a30542559a5d09ffe577be39 +9f1ed56c02a04fd9b6acd2aacfe3d5cb +8d21d1ff64584cdf83f2bac359062f3b +11e0c6453f3a4881aa8d118a92787505 +61ccd32e664b47e8a9021ad56d4635a2 +a8ddafed256e4123802aa0e42b2eacb6 +909a985281c648db897ad1dc1a85905b +7f884444179e40f9bdd255a850122d1b +162a5d683aba42a6ac7ada76cb50527d +e8d121d8a25c4e469ae4e6b0db66bbb5 +90bcfc48347f4075865e438bd70c5c87 +117b47eb89f2490e82826d200755d64f +89591a21a3ad499f9178247b1ea78484 +ca4f7cb55b624842834454a20461eec2 +69162d0f819a4cb4bc884e339cd8760c +e915c0da07ce42a2b5ba080da135a751 +e83c1889c59145df878f7984fd7dcaf2 +9e18b3a1d41e458ab38c44c336e2841d +7dcf441ad32943278ac838e0018bd573 +4084ab4424d54411a3ecae635395c5fc +e11f7e3ac45f4b139ce5e2d36bec8b4f +450cb265a2124aa7bc45d3a0bc7874d9 +149d47c6c27648a6af26d6c912c03826 +7ab6f804440e4a1993699ed260140dee +2b924e8700034b5288a8aa36f69c86ab +68f8bb2d57a34002b9087a420ab8c39d +d27743ef88c44e76a294be09f7d162ef +b1bb8623bb8141bb8e0718783d473059 +64dba6a697494803ab48e7676c5cbbe3 +9ba49bfffea1433a99ad0377ad57dae6 +3f41aa660f394450b3aafe0ad8bb86eb +b9b5d59e377749ffaf5ef8155fd889b4 +12da08dc6fd34e989830b92466e11175 +eeccd33aab144e76937c1ebdbc1faa74 +61a1079729564a82b106bf2f75038ca4 +262acf541c264d4ab864c022075e347d +4907226f07604ee8ae9c98bae470069a +11e2ccf4fe834b25b02696f563fe770e +bde31c48a36d4e198c49f0d2aaa758e2 +7e8d8f533dc944c6a212d5f20997c69b +cdae08c447df4f04bba136075570f021 +8a21e84b6782413cb47e031f68dfba9e +c77dff3110b94fc5a05f29c3a42175d9 +1464e06b191041208b52d0bd038b3349 +10c8653be7944df78d1ff77394e62d9b +4883133a03024351a8d4bb2231db9b9f +10f8596282ad4644a7c4ffcb68dc2cf0 +17e20dcc4d3e43a19483554fb79455f1 +32760dd5ef044579938634e68eede737 +6458ac945c14458a8e5f4a470495f042 +3e6831cb4f2344efbcdb829cd34518d5 +4b6e9edf168d4520b86e0738c09b3830 +e871f8e7bdee4a958293e4228baae3f3 +4be131d7a01749d49f42cce7f8c538ab +f89df1bc75b54fcf9a03b7bad87e0f61 +da6c5b6425df42c7886690f6e587d940 +6123d1406869491e80b18c8bccf38660 +fdf932b04e6c4e0fbd6e274563b94536 +1596b924c1fb48a3a066fa85fe8a7d86 +d9c7e19aeef940fcac65efc964534a9c +6d114a9090fd4b88af3d1d65839a12cf +9b59afbf4a694e8cb6daa0e0235cff86 +568b4f1434784d179fd07022dd4c1469 +11e572d8b4214f02955ed4f97dfe2afc +cdefddeef92940089d02bf3ee76fa9e5 +7d444cd245694f9a8da42e6c8bf7d72d +db4af5ff74bd4f5a92209e1236299b22 +f21a2fe135c14509a7a50ca98b50fc84 +f397144b498f4b84ad18fd2efea88c11 +fb3ff27a30bb4243b8006bc997f4d8a4 +a0339aa975e54bb7ac65982ca3cc5802 +15500b2788c2476a80567a9576369ce0 +d9a913f6827c4337a666af1256cf10c6 +d32d9326740445359ead494154a62bb9 +90961c1661ff454a8461e334ca18dc3f +8ba0d24f3a1d43ffa5410d45406dea57 +826ec8fb717d4415a10d3af9ced10f3e +585e3a518b434183a4c1f799d9f0038e +a6615ac74bba49d4bb77092de480ba3b +488a3bb858eb4929be657ed74f2d04c5 +3505719257b745c19c95d9b28feca7fd +f7961f80c8864bcfbbf15f5ed5a6ceba +4d0db60c85104d8880fab712f158b0b4 +e24e0ecb38ae4a58aabaa78b2a53777d +3ca015ed6f3e4c46889920f40677e4dc +3eab4712ec7a45b28ede2f4b0de10ce1 +fe6da61fcbed48fca962a7a97e0e504c +84145cf4a3984ff59867f8abfe9138ad +bef1917591e245aeb0a7700e33ff0b90 +4514184849a24660a7bb70e1bc0a346c +bb039626a18e4effac3714e220f1034e +31e5a3a2fedb4ffd9f06bf2f2fd86bee +9811f127a39b480790d1beaef7af9fa7 +486bea1bf69748f1a9245447f1124fef +3f5682a7d46d4aa99d145d26258dee73 +d165593433754d2283f655e2b3cc8dc1 +e99210d90b08411fa55ddfd128977991 +dd43b715d4414a0fac8477dd0ddaab3b +3175a691aeb2421f881d8683ea06eb60 +6a550831e2b94eeb99aa4e0c3b9017a3 +89a6b322e4304245a5f6c496ca07f5fd +44f8899569284a22a283dde8abc4b6d5 +c3c8b8b037354369a3f9892530b346b0 +a84fb46b851e4294a47a3f0cad1f2484 +5f04e2fe311149afaa3e59871a465c65 +436c3a375dbc48da9ade6ddc3d86e0ff +5736985d6deb4af0a4e2c0ba885f72f8 +a1925183b0c744f5bbe7261c319327a1 +2a98c29837214e2282c656e371c2dc8c +46c3cd7760b54ba79c5e7c8ad5fe0270 +27adb8f296584f0399c63583a1afbee5 +2f4a67595f40485a8a51536b6c16fa54 +d09f470a3e0c4a30a7611f6fc9edc08e +c8f10fc275894e088e451453a2cab667 +ad915b1da6d54a1a90ba22483935f4ec +7ed892d894134524b94086589f5a0ee4 +2bccc1882bc9429bbe6a23990b4809d3 +6b2cea4d96084918bb0c8ee86431ff47 +604e4ea5a078467097d32984c7d82f44 +3a5018c5b2e04da5af5e9a30d3abf6bf +754f9a139a0046d98e6d9f80221f108a +ad86cf92069c4e55b3c5189895316569 +306711b76b464a2384ada69f3571837a +202cbb2a22ea4dda80160ec89a77dc39 +6c7aff76b2ff4aa982748430344217f5 +9a682652f7c848049e77a9d87c8dd999 +f06c2f76a517455988267f21f6e2cfaa +068e782e0c3943cf924b1608ffb5320a +db529ca286dd4e1e994d39508e02c445 +6210a8a2024144daaa80610d8f604e40 +58a6c7f34c32485da095a8e942b57756 +a255a76978e345fd804c887fb2da626c +d025942952774f50808e0511dc918556 +62cacc45edb149f1b95804fa410ecbe1 +c425a758d1a64bef878da358e66c2b92 +3a3d821048f0434f9223a20972325896 +0229e43f0ad0488aba90dd7cbfd8ee24 +35670b0cfeb0417daab2b05771a92232 +acf44ca1b3fe46c38368e53881a6be01 +fd16d37c66b34d0981cab82cc9881f77 +be1d93da1bf74d568f01f626a652ed2b +cd04f34b278c41de9ff714d65e2cc2ce +e4fda01f049d41e8b2cced62c06e4ed9 +be3559439f684332b3e2e82cc71b0c25 +f1b122751d0b4609926041975fef2bab +cd3ec9bd9c76470c8ab72a93a86e946e +118e60a3091a4cc6b2e63bda5dc7913d +9de59aaa95ff42408b9869a72f3a89e4 +a017feaa16de43f3b491f7163cdfa1ad +c7ebf5a3f3264793b6f7e8d194c23cbd +5a1593ce203e40c8a5adcd149a500021 +dccbfce73b8047a0a3157ae62360b498 +b2c5ab0f4b3e48aaa30a00d26ac5848c +0f03d940e6184871a0f38d429bfc006f +e23bdddd6b1a4659a0134e5efa8ee4eb +63af4c3ff86643ec8caffdd744162fa7 +73d96cfb751d4ad9a8decae6082c1a07 +5d2692dfcb154cf6b62f558ef5b2a829 +bc0e90729dd94eddbf8ddfb3d941d011 +07060d7247774dfbaeb5154501b04f7a +1ac8fa7a38fb45bdb74261b63696ecad +7dccc62d436c40efa2ea23b9c8179451 +4ccf0fa531124ac29b4c8173471f8e1b +6b98ff028e984cbe821d8c6e58fb632b +6d7f3fdb005741979e11ef6e10bf7ea8 +005e3725b8d9484e94a71aeb9495aea6 +6cc0c8450dea4c01890d89fb2a38f6fb +ba3713b51f7d4097a4207d8fec059c8c +6318cebd7ba544399e2c7a1fde02799a +3a3ecdcdc3b94cc898f8e7a2a59eff45 +8a41e4de506a4bd896c2a55229ba39e0 +d42867abdf0a48dfa4f938addeef5178 +d07757f46042429895b639742b59957c +3a0d7939f81b46d5af0ef2c96553f3e2 +163a813d5c4143e5ae033d6ec35c127a +ab333557203c425a96476a65488785d7 +7f996bcce4fd408f9c0db72cfd2e7e0e +91956030e9a74dd5bf2f3a03419c450b +e08bb2e734004870b1ed4c21f111a854 +1c41d7d358804a8085ad167d44a34e48 +3751c62f69614a929a54f8bd174c0d92 +9fa057e3d8a14cafbb1df0749537850f +3ae84f0159b44f1da97efb8c57002c38 +04db9a96f52c4290a0b6bb1aa441ccf7 +89dcd45ac1f04680b76b709357a3dba3 +479541eca11c42bd886793db88ceee6c +9d53c4f8a4394a9ca333da20138cd897 +6dbfd72a6aa048cda48b55cef525531b +426fef589d134bfda8d7f379cb234c9b +7df4925f2c6941c49d944be8c93618d6 +d2769b5a86b546fbad6540409d4d6d2f +3efb9e42f49f47c6bd1d36f86281888b +3244a24ab56148e19a3c55d17e5c1d71 +f112bf90127f42ae9bb6f06b45438789 +edaba58075ff4796a3ff5c4a43a765a7 +eb052bb7c5ee4cffba520b19b3d3c784 +64d138851af44e2fad075dabf2039453 +831e51aa43424c64a9d13501c60c0c10 +0e9ac704a4f249a9b325f6670c5190a9 +3d26b17e85214fc1b8f215cd613d5bb6 +02f0bcfb739e4a0fbb3d8e84db04c920 +0009a51366fb45e2876715bde6a574b7 +c66ca5635c2a42178b7dc5c5e547c404 +0e4768df975d44c288f9c8d221a04153 +db1a7abdb9b24601980c243fafba5632 +b2e7d7ea5219463a8bd910eb009dcee4 +7b62fa23c474424f8458087f7cbfc3ec +6930ed2ea2574279937d5e2d96c9dccf +295384601e0d4f1985a919253330d59d +70e364b143a24d4eaf85689be03e1898 +26af80179971467ca67a3edd8ef91343 +dcaddcc9fdb54ebe88785c425069044e +343b10aeb91c43cd902fceaa758c83b7 +2624ac2ce2364930ba2d5f70eb7aa1ea +5a3083e835ac45c6b8fdf66ffa9bb5c0 +3ac556171c5c48678f45a2daa0e7091f +b1a2e6023574419690b60e9616572564 +cb9adc6839ba42b09cbc34aa89410e43 +ea5f46e8eac74fd5a828137e3eab48ae +067d636263844d32ac4c8fc902f061d6 +4776bd54bdb547c19487404e0bcee5a7 +3f9438ff3bc4490d9ce4d1e8b43a09ac +b50191176b6a4509aabca39d93bf7c18 +7dcec4e910f04af783cb4d4f64cae2fd +00dfee50afad4153880d3a04d9a040aa +c0a5a32803c2462b897e7a5ed051d604 +e8ea571e8dad44a4aa1b67b4d4ed43d6 +f9945610ba8f40679ff07c690d4560f0 +db6ad304929748e284e4508fe7463fce +390f73142c25425789b1251f6ddfe9cb +e8f048aacfde49c8886fe72f72674965 +6fb26790e4b74ff0bb45a0ebb63646d7 +ee5edb945f33416a9e63f3b4aa665d56 +f9785251969c41a1b22bbbf319d42d08 +82a8c50900714a6e9a479603b729e745 +be775135995c4734972317dea2c0593b +3f17f07cab954cde84499e8941742dc1 +2ae47e82674e431ab4b0768249bccb30 +e88a24a6235e4eeb80173a879d2eff4f +6392c5c78f1442ada5083b4b7d19b54d +3289c148eda54700a379685262c62480 +5a9b5a0ce4944cad97fc9e2d6ddfc6a4 +d5cc618b12714b2aa7481887eeaae740 +53354ed7f5f34b79afcea170cdb6fb61 +be4426cef1054b5693ffca10699e6f3a +c7db4282e5a44111b6bf46c4ea2af167 +b282e6d00be04cf1ba4e94f30f3dd458 +399e199d27104285b27e05785e88d3e4 +2aa9982c23c94eb48745772e2a62260a +458347464a2947749c97a96f415794db +ff21d75ab6554ad38bb4199d3315b99b +935fc026f1ff44d0b61b46bdedacc6f7 +8c2721e6b4274665a08c570e4a4352da +dd84cdb121754138a863d29d4feb5248 +a974b6d4742042b1bf24918256a333cc +b005d2125a1545ad9e0994e0deb5e82e +f520912e94a24024913154a9eb62e6ea +d796749f27984919a1dcf410500fa619 +252f730f1a044efdb801f84c7eaabbce +3ea2fd4e065147048064f4c97a89fe6f +f2eec72e7981438ea1b0ae65f1297fbc +ad0c974f18514b0a8ac976d9740e094d +9ad80a7bd90b483f8dbf0e293251cff7 +60e4c8e7143f45b093d79ac99856a335 +72c5ef5eb56047eaa088e2a514885203 +e06d06101cc8434e91034b97211d5dd5 +2c086bb5b39a4e7688f363334143f3c2 +11ec73f295a6445d93b6a212aacc021b +106241c92afa4f769545877dd35bfce2 +0149740224074ee3858b523a5997f357 +62a09b0a7c094e5585f2057d64ee31f9 +66ae6c732fef4aa6b781246442b6616c +49d8617a99c84543a96282b2545a599c +ed5233f7d2d84a35a433361a5a058d36 +d182b8ab86ae4176be6a0d2be144392c +fca137cdd3ec4d52bb6686cefe867ccd +14c20ef093f643228070db75b2880b19 +a57c5e0607c0416ea43df0a68fcd2c2a +ba11f0bcd7c44f4cadafa4a91f964214 +0321b21b146546929495f7d2fa597418 +defb1b6416d14eaea97f7d79c34e8fed +b37929fe34f74ea5af022dfece52fdeb +538487c7b2f949f0b45ed438923941a9 +d524e590bc2f460d92dfae45d01d27b6 +20960256583b41abbab7da2c22de4478 +945706e16a2d4978ac2a97b2c58d741c +7d65d348d5b345abb9836baaf3738ce9 +3aaf97d27e574291b35114a33346d3f2 +7b2ab6b48a724f56b2a5fb9a38c5c74a +1aff3acca92145b591082da2e6ef43a6 +ad2d84efd79944e8b77cf6e169fc59c6 +23d2d9791e2a4775b87e799e8089f906 +5f84f8429cdd4b12ac3be5e189fcefe0 +c6c70861cfc84a2ba366b4bb5cc58aff +f307a980d98247b98fac39679fb47e0c +4016930e82234387b4a1fcd3c5bb0c12 +a6833aa6f18246eb9961f74806aa8341 +998d641ce1c74e44978a91fedc849905 +fd7bb9503c284c60b7776c539dad934a +c6498b9aec674265b6b828b287bc8512 +493cf761ada14c0bbc1f5b71369d8d93 +7d98893743f14315b160190e3f345168 +5066fe3def664b18a0eb7be570e731bf +5b70904b26774f37aa9c2515a7a36fd8 +f0ad6a3c1cf04f4c940c3296f1a2c322 +bd51773c52e54812a88c38c14935ae98 +8cff17fc96b44ada872cd4a3080b7320 +d86b51c741984d1fb89a5e17bfea5cc4 +12df0b75adc84fe58e49e602308dcef7 +4b85dff2f8354fca897ed5a5c72e1bc5 +985b48efbd774f8f9fa74304508cad34 +c1f38cc43c694137b711c260445137de +c590313610d2413cba2fe8a61f11ab30 +34d4e9d8837549199658133c36643bf0 +a69cc063189f4d0ab1b79d4f9f4f780e +1829bc2edec44901a2f7032fe2c5090f +63ed81a563604a9a887ac51ae0514305 +7e8ae4ada87f4bf498e1979a1231cf90 +d7907af6fe0e486499d5e0290b426d51 +f2602d371c6e41c485620ff380f35c26 +6fd59ded45e04e4bb0fea6c9e73c9496 +7b5d49abae8442e2a2d5d9bb0cb2243c +dd066d74be504299a473ed0d4f98aa84 +a52fb9604a774cffabea8278de62cbd3 +44e3d6ebaf1d497f90e41b751241e5e3 +4ab4b24ffbe54972b8cc7968ab3866da +991a4c60e7d54d74bfedc2d489bd71f0 +e0a0c576b0d443bebec317bed1e82a55 +aa51dbfa9cc24755b9382be28fc59ad5 +9d24aac8a4c444a1b440647aa6f96438 +e4c7780379b048bf98b21ef3858afc20 +09e1135b68da44df8cb3d73b7500557c +90b2f4b7e35a48f4812ef9d35df7eb10 +36e532ef9c454a9faa9ae3eb7282482c +052c74fdfee14ae0b53db1eb768fa3e1 +a80f36392aa543258ccd85e1a877e8d5 +e385a1629a664007bd12618b6f2480a6 +516608a3bf714136bfad040e0b18f854 +0b2e66c4acf649ebacea1e15c77e3b59 +4da56e7f67664c5e966320b4e15f6453 +94dc57e2257244c48f801037e0b51b79 +a6808f5c6a184a59915e36e44950d659 +fc4e87ccad02448893f86449fa95a243 +d796cf8784fc46169e3ac70375e0e8a8 +479ca7daee2542cebf6ad25e7e8fee58 +d99caf8f3d5140ec98c30cf1f5b7562d +005375787cbf42a38afcf8810cef9731 +2ace352d9dfb41549f265eb69a537622 +0c0da2cc1b4c441dadc2510212c25fb7 +dc076b86ee754e3898a81fb881ce26f1 +cdb68b0e758142ec92e476686cdef5a1 +701c17a1a77e469ab0d833e3aa1b1847 +c17637ca11494004bceced81e1fbb621 +4d98c602d2b14f1db312cb057ec07feb +767f17503edb45eabfd876771ffed9ed +235b88889dce4b8c80375eeee45bcccc +aa770b4931a243ecb0744471abc13eab +704371139f0d4b1db43dc2e243bf6df8 +33aa56c96efa44aba978240659bd1f62 +d62e0b6f29de4716a250b55359e87193 +2e4c986248ed45c78cc751560bedce55 +0349c93a75174dce821f05648aff5aa6 +1c357aa755ec4469b23e86f1b0c6aee5 +bef41fecbdff4a3fac184c6a1645ab35 +cbf99d910112471491374c352f4f17ae +4a0987f23c9a4b9099c63d39dd061ab4 +e32d1862e0294f90bb645bb81719cde1 +968ce1fb13ec45c7b89c5378d86034b5 +654d6638fab245ef814ca21bee970f2f +b4da207833d343a3944e3961cd311e0d +18887f3feaf94be887287c211c253fa1 +eb99ef1910944f7a9c85e681d8194914 +35302da1e80d4ec89189b71b1fb9eb93 +767201c13d9c4e3abddc78def3fabdaa +feb6d77f702b4ee2b5204e07d37373b5 +e3b4e0d9e3864fb584adbacb7a8adeb2 +78dd6c8318ee43ff8d33687267707a54 +95f5826629b24689b53ac945ac32ac49 +3bf3acd29f7948cd817b6a43923d07cc +3e2ce66a2379417db8e110c239c59f34 +93f4caa9a2e54d2595b7e16a677b65c8 +d4ea4336ae64441ab353dd814aba72d8 +220f1341596a4de5934254260f7684dd +3784966feebe435b9a1bcd99d17800d9 +9bef1038ad13459abbc1224beb01f48d +e892d17a63f847fab97f1a73e31a15b1 +19b2c1893f084653ab226cc3faf27c96 +6739184aa6c74f0eb6cf2965c731416a +215d9f8b0d0e4bada8c0e3cb65e37a35 +d44f838c48b748f3b51eab9c830193bb +3c5815d78bef4ae3b2a8bf6603e44807 +5fd2c9bf3e834e839b26649db7afe4c1 +79a3902f37f2482c97520f3f19e419ab +5be2814eaea44101a8c00419b73c03c7 +102023952b9e4eaa8de936f6e72ea21c +b7c2552b59a54ffaac10079f8fffd19c +9c9f21a0a5404b4083be16376415e7a7 +3a39afc98c3940f1923d59130512be0c +3f35794db04d4fecaaec1b3701c078af +e0578b70b5d748f286757ca785522430 +65ac23e97fd141569be711fd875dc162 +647d9b99a20d4e788f84cf7aa33ad5f2 +02b63726c08a4604b5c6f4240dc31786 +1f1704601c2943ecb7e1aab814a69326 +337d8611b99c445cbab9b07369c2a609 +bba38758996a47e886e843c8677a04f2 +a03242351c6f4bca9f4fe359ab27cff6 +859ff466962b48f189af47c556398c03 +63ca2c7241894778bd263f95ac0f494f +bed379559a57403ebe484566945d3c33 +9bd041f645834686aa62d9764346fd85 +8a20e56e69e14851bb157a3d0ce2eb9f +b27ffa86d9e94ec689f982e048f3bb08 +5d271445ab5d4928ad44f82a0aff28be +3b61e28b2af7473f9be019947f95498b +7671efdc7bb5476aaac39a2631810b7e +85880af5c95e4be4bc00ce5a74565e48 +f03eed5909e345d3b551097e9c849fd4 +da43ef76720a4cd996faf42242e51db3 +e5db252dcdc74bdf81cc4d7be5c03160 +a9e46996a5f845659ea8bf01a76b3920 +07a97f4ecf994f579ac4ec70d74c561c +a5aaf14066284b9a97a0990a7e5bf626 +d9db0cbb1b0542ff820e5e03f52b4387 +f0b7373a0b4c426b992af7a83e4193ae +20fc0680ea0143c0b7dcd66277eeaf80 +be1d414591b94c4f9bad500a637d8c56 +87eab647ca624962a7c178c0105643aa +627ebce56f204ae4a4dafdbdc993513a +b2e3c75ff4dd41d6828bcf2d6354388d +449a9f55fe434ac5895aaa2b4299ba31 +d50d61ef119b497094c4b155a6e50570 +e8b8749f6acf42d38fb138b1258e2d11 +a3ad19a9186b445b9fae07f9f36f3bce +b2461da511c649a69ccacc3b18146cad +de99e817cbd7449f9238087dd6cdd53c +37abbe8868e44a3c895bc79791425817 +6fbaa2229c4f4a53921e15825ddfebdc +dec1bb1c2b85451183f33066311e73a8 +2e32184ea51d4b50968beaf48aef0d2a +b0a8cc7ddda44f85b0d49577533bdb2f +c5163b50c1224757a8346bdb21fe09df +1d7cf73ccf8c48f39e90f5d899b98d3a +5f5bec4feddc4401b8acde5777080647 +00ac994290444f91bce94eb658936fe0 +fe97d02daaac44bea0caffc4f1cb93a4 +233c4548c26d4b66a54d69db0ea18da4 +4ccfa4b5c0064fbeae7b802ef789faf9 +1a26aea26ff34e9e904350d9e61e9e64 +5cd13916f89e4552a25efa27e03170b7 +d7963a23952140fb9306083654e2e0d5 +f0f438adb40a431d97e2891adcfb4ad8 +a07da643c2b246b8bd5e704a385bacb9 +d1f180ca1b3643469c450769133b7517 +596c71a7e55d4909b22514f3c018f15b +a3b9b84dcd2f4051af25a3d87b71f7f1 +957b170a1c934a2ea9c03fae7df57946 +5edd371a120d4a40b1248e79b79e5fa4 +14fdec73c83a4207ae06313dab325613 +eed34f04c238471488d8209da3896e0a +b1e2175e571a48d48c25f805545576c2 +a6f81ec460434a4fb999a1e201c6fa22 +ec97cda6d0dc47f78058bea31e85533e +dc0a1ae7d4bf4cc486b9b1ce5906d91e +ef0253ad994a4f808c42fccafed066e8 +8a3d4b05df3f4fda9aa446a39bf984f1 +95a107fee2ab41bdb6e21bac72741781 +4a2fe98254114412b73b6b831b1a38a4 +f5f6785f33234709bc297ee27725d5d0 +0f213ea073e745e6b014cb7c6a26880c +804d6814818247978f28d12efcc38cce +e1eac1e5e67544dcbc7775b5d7407e19 +a3e3805be6364321b60159793feb2f66 +c28bb9681cb143a7ab20ccf751bb7dcd +132a8ee2af3a40d39d270fbed3d3666c +cafa78b0a19f4dc3a437810132eb200b +0532b56bf74140dea8a411cab7709e4d +088819f8ded444479348733c5207a1cc +212f2713f3704907a2ca16c1546cb8f7 +017f6036af924341a358bb8a3bc0a74f +7d4cf08c9750498cabba8cb4b4dc2c7c +60e287ea45f045a1865bc2821ba53058 +73ce953592384ce68aacf472a93fdc3e +beb06d59c946427bac6bdb170db12ebc +8a983b17bc484fedbc1ead6eb61b55b5 +62306a10e27a4ee88ca76bdc93f75dfd +973e59c18bc647669f7f8af470b67b2e +6ea3a5efa51e4b8ab72470c6ee475945 +d4d902a56c8e4b5eafe80757557f0491 +28d33c1592e14d8b895d36a1e0dfaa5d +f8a25f8a4c5345e9a19c201da2edcf33 +73a349e6ed2446ecbbdeb83065519dc7 +12c89905df1941afbba4d33a61d15735 +1b2c7aaab85d4642809a5f34dec0dc0f +4e5afd0f0c5a424a88e5391f73402548 +f79090dd37d94deb82882104016c71d5 +2d5a9e8a5954436cae975569fed0368d +f47fdcf9615d4e94a71e6731242a4c94 +e268788023f9444a93f8ba23d8f161fc +b32ac9d9663a4214ae9d444d21e9b03f +ca1d830e42d7400d916a585b98ad5932 +335f6bcdd430412290561746a70bf421 +2c94bc1386cd468abc55afcb6cfa18be +ab4e7faabf274811b024052f15623222 +b3baaf8c624a4857b0b35c55677ef198 +daf37688a7734fbdbc975c3e4cccaf88 +76862cc301e5430c9de1b7a34850f192 +ccd5c179aad548a09e6f7eb0d4142936 +8ab0dd710f0f4372bf53a2bd944a783f +017e924d8918468a8c0def1a895b8f37 +c4f7f5028d90485abfcd107442e228ca +d9b8edf3526e429fa80758c285dac858 +d83368c3698a4d9b8572ff212c03c047 +dc76cf85a7cf4829a4694d6ba4a570b2 +bc5d99867a11431b95e5aa170eb12947 +0574df9de0884e7da4564f37fe37e439 +76cf741354b94868938e5958e066043c +d1dcd88b7a1340caa8f8784c4783d526 +7079a5fc5bd74143b36d3f1a123a4f03 +048d6d58981e4b0fbedc9500419719c8 +8b032ff6ba704134ad1e125e55c2f49d +9f5156a82f2f4d0a870f868458643eff +8ce1da97aa404bc099a898f29a3025ae +c34bf5dd25bd40568e08cd6660fb51ad +3e0ff4fb14b24102839e9d5d49d4c363 +146562854c044056abb08de66eb9426b +3c6f61a6436c43639ab6ef5c1bbf2b38 +32d5faef157f488fb146f46ec4a7ffab +ee4e02d868a34a7f87a83e45b58132b2 +4947a747442a4feeb12af2ea53e01d1c +849c7ccca2b840999f7589f81c38de76 +023ad6658397433ba96427dd595f537a +b5072b1616f040e197ca0b042e7f7a0a +c9ae86a51a7a4b688c67ef82f2e736bb +c04866e573304ab29d6179d6d6c3bfce +ea5f0b7f149b462d93432daa040fe185 +71e75c9cb3fe460c9549016297e694ec +83aa9bc0ba404af49cbeba8fdc0cf2ea +711e55e302a44095b336dda8ca4933b6 +05b7974e98044bcba1f586eef3fe4a9f +67b2d6983ae0405daa199b5ff2d06c5a +20de33c317ce49a687b9fe8075d60e8a +e3a5fd374386419680a26a3acaa18728 +6ee63765c42642928c61510dac7b3df4 +224d642a9d4f4f7084d4099659a7caa4 +641e8a73066041339d82539860fd5c29 +d5086765363b44bdaa1f053a0c7bb83e +01ab0842feb1448bb18e8c7b85326d11 +2679de77842d445c946697b8b7e04bbb +933fa8d9832148e7967e244e455e1377 +d3fe7b67a48c4fc89f7dbeffb3c6cc3d +61fa68acbd69489ab6d901eb33bd4a55 +dc08af0e13314841b999cf57badde6c7 +b0360d1b964642d3b7502f423c96c3ad +341bb6638e5549adb430e48f676eff7c +c93d61ec3bab4ed387c4cd80d2b332a9 +09ee949f846a4aa2a63fb3468cd97b8a +b91bda1c5c684f8e8d97c4923d86b889 +2ef5b079669c4c1d996c303b083c4f8d +56e47cb814494e4388ba06daaceef332 +6428763fe8084c378f8b65afec48f592 +2fd7954d31dc47d7a48f9e0cb8faeeba +866f0809dd6940c1a6a27a4e66564d2f +7b623365419e40dabe722b5fad0697a5 +e105827387464d0d8548e0dd144bfdc1 +15c2adf9af7a46fd8eb059ff053bec6a +a531156cab3e4d86a0385ffc0c0adab6 +016e93bac3c94a9fa78caf9630553b6b +44337ec77d5641bfb6e2c40e7bf585e0 +891a170bd9b549d6a1d3d8b6f64b9529 +d50f554707f24584b988e2feea162cc5 +99d6dce2e49e4ba185ac108ab044524d +53e7898031684a8dbcf12c8c7805c068 +20a41658fa284141815977b277a08520 +a2832b845e4e4edd9d439342cf4fd590 +4b2427e240764a8b9db635d7e14ddf43 +44bc7551bf1e4c91acd3526c57b39608 +73ebf2e05fa74f14be28720dc42d506c +d1fd6c28e8c54860946a5847f96df2ba +636f635cf2f64bad9aa836c0bb252fb6 +c93d24544fdd4f1784d482490465c00b +72865245ea7240d38d2ef575882b35d0 +c5090fbf444c4cd0b9d9dd441f75be3e +8a3f1ff2c1c14f74915222454eba92b9 +af930f73ef304cf4a4a6d09841c7eba6 +53720baedd98448a8c71395a0a23cc5d +40b38fc043d14a29846993497766cb62 +c5fa752238a54a2dbe8ac6f768a785e5 +deeb41e3f5f1480bb6f79f474c9f7ef5 +ae4982aad27e4ee5855d66d0ef3c46eb +737126c497f048e388935ffad2355f35 +53480f4ef063436faa10f060aa27ef77 +d8d13cf10bf44f21a9f23c5183db8c27 +72ac65ca62714856856370b95e6aa0ed +3f1d714d470549d284b5662c116661c4 +1afaa69215604838911ccd3221e4a6d6 +7adc38ead24746be844dea0e952b76d4 +a5f8660771f84c3692ce40882ce188e2 +1b98b99b6c374df6beeebd9dc3332abb +039c30f9160e4ffdbc5e9157ca6ce852 +de93559b3b75462ebfe9504931436abe +3e638da2bcc2461f9130db32c924f180 +d301e870e59d44f494c410ce1fcdd60b +d559d782ee5049ff88a46f7747f3e8b5 +b8c6125fd65f42fa9c99ee276ce481fb +1ce32cac533f4b43b17d8fb01af0e099 +1fe2e400f1bf46cd875fcbbfc9f3186e +8b7e291e55cf4234a0d77d18355df9b3 +1737b6b9d911454faa170be52e8f784b +0cdceff1f9744759ab3b407b96f498d6 +033a61d66f7646ceaac357b502a5f5dc +253ec28ed9d745f890f64ae7bb902cfe +94bba75bfd444c30ad6fac9d42887b6b +887092793d0b402e8571eda2d1a47cb4 +ad1f36995784401bbadc36e60354cd6b +b6a04764e3ea42cc9021327fdccd45ab +353757b451094a678770ec2b774632ab +1fd1cdc4c2d94ecfa8d80a25f1818e8c +fbbe8661f4fa4439b13a9b8985449d6d +934881de51c342c19cc83894443d2482 +8630ce940c884057a82c9cd39998fd53 +19a62f2cd913458d96fd0d61c92abc2b +51bb588d4cc546168478231e25729200 +ef0cbb3c3d1b4f43849e8ac74aeefa64 +822c012ec4f4427d9f36929db2618260 +fd47e62e36d74e8580616d60d935a99b +223b4462ea33462a95f2abb4113edd10 +4ac0f2cc6ad34655a45dc826090ded80 +c47502ead1e94b5eaae8447e512cc772 +3825d316bc544b98ad837d086166ab83 +acb2bdffd12d45668298c23ab51efb0d +8dedc9151d164124a6c4a2943bfed8b4 +e51c441a781d474d83b44b7dd3f6eb32 +e51f94eac4aa4205bf93be66928a7d9f +60b0545433bf4072bad6e1e4f25cf712 +0241e66e7f93462ea3cddfb1f326d753 +1d9cf098cbb844d0ba092d0f8f3be05c +4e1a4eb6b9854983b66098d989dfc91a +e48f29f0714a4c70ac75a34cedf6b3bc +7fbb93d3aa7f486aa24a6b1ac3aa1818 +eb3df3c8001b4778ac36156bd1cf79ab +65fe39b119a94d3bbef1b044908ec5f8 +4221e0d5bb7546778f24b0a6ba4b7277 +411c164757fc4de68dfecb35fa858223 +8b004ccbf98a4926937cac33d16041e3 +04ef3c46e9484fec90d670c6555789d6 +ac4108f79b654ec5b2a40c1b1f7c579c +8f9f88c340ec47798fa5cf07e92312be +05e1359c8ae14ca6965db3e7bf2d1e27 +678119818b7e4465aa21461d1c1c1c70 +557d665724ba4bafac8498ed8e1b7368 +f0fafe31662f453c845bdbb3d4e58cfc +bb32988db7dd49bc9dfd7fb9af6215af +15986a1a263f40dcb7f861892f08fbcc +fabe3515c09349b28d127202d20eec36 +a543676fb6d8437fb59f58d983f5816b +d10828ad347d4e21b9b3d1c6a5a415d3 +81c8356529ba41d19f41ed91985cd532 +e12662427483470cb750c1acebfd7309 +a65fe5c27464448cbce7fe61c49159ef +e2389b65271f4a57906fe194dbd0e56a +a912b548d6054ffb8d2b4d8ed46f7d81 +a93db43f956f440b840b5c93708f0281 +5b9b2c2da2474642bf72393c58f3b1b9 +8b96ed9d18ee4341b13084658cd64c7e +659afc7b5cd84c91beaf3911888acb30 +78ebe1fb7b354fd8a000b55775bf9570 +c1330c0379a14464956d4a07f9a70178 +5405ef962b9447a99dc35c98e28fad41 +a8db1a75233a4394abc5b6093105780d +4a1327799c864a2581c64e062d5f4be2 +e90e9810ab8e4e08843f57395f5fee59 +74555a6eb72543cdb5bd71ce98bf21db +73ad279aa1744086a90399c9e9f4d643 +5fdf4a70414d48e3b2803b8784a216a3 +5ebb6b41072547189da584d9ba1e217c +c0686894c7c64a95ba1b03a0db5a82e7 +e82a2d9de75646d185fb5b22f4fc37bc +ec65c14e29a64b6b900d73e690898844 +44c0231a2e07494e99a50037d1a0fb0b +8e2ae53cc8154c70b55c815038fd324c +a9f58735696e45fc868f6035d2477e28 +c3a580c52d9448ac9541ef8b4c7b4db0 +02427a2aa7d1446e9bc6b7d727803d39 +490ea567e32f42748f654c41ff0f1873 +3e4e78ea50844879a87064c6ee021762 +dcf889a3c32e46808523e8ef8e278090 +70c2a47dce0448e788464b7bc6a8d476 +4f32af3b4d3f4e41aecaa9d8f4d76ca5 +2ed3994bc6ff4a0db53216e1cea171b2 +de894ecc99704a158720e18e17f19c3b +04425ab580f04d70a87290ff13c7da4d +d8211f8358854c429971cd213f5aba52 +5a40e8ab0d734e55957453a2e927e47a +9796bcdd0869446da27813947ecceb8b +7f6f60f1ed344ff1b0811b95fffc6f0c +b6386ac278674a3c962262b607abb420 +68df6a442220474c8c697df2a6d3e94a +7732bb8b71ef49cf9b2690a2230392b3 +f47608086fc141a7a2bf05485e6562dc +61a7ee4d5cfe4c62bc568a30e8c74b8c +85adeeed60cb4593a0fab99caccfe52e +966a2965978c423eafc4b6efdee8fa0e +d725246436c94ca4bdf95198c4414702 +f6d6a80c25ca4b8aa7da66763275d0d5 +fa80b566272647418694b8a05ce62fab +e29de3f42b7c4f869c4edbd0e9676105 +bf5152c1f1fc44f4a81dbca1d502304c +fcd40d60d1384da196fbf105499ae54a +5c2d19a1e632495885d12b377d693eab +a4701579556149a08247749a938ecfe9 +b00d3c3a63084436990cad484bf258ec +1844319d768f4d62a25eb33babea5903 +a843bf5eda654feb946a85d1a93039b6 +19f76a0df81747369acf46406b36afa6 +bb20bbffdcc741b0b1513db659a9110a +62f1f2436c0c45dc90b7b7d2587a2300 +bc8ef24f33eb454b971ecef7ce17aa18 +343edd0babf743ba9fd43f99182d998d +76b8b232c4aa4a91999d949f2cf943d4 +e66bbf01dbd14d15999296d8355f985f +2c7a80e3990e4d769e9b2b6ae00cb516 +e8443bb1a96d48aa9695fbbe9f1428ea +d20e220795ff41ce8da53e7874bb6932 +387d9e29174e44d2aab2eb87d4ae6bf4 +13434f9dd67c4f63adf05fe79c7918e6 +c84828f9ffe14218a0028a59bf6fd4ad +175e4e432e6f4304af73c7fff56be773 +09fd6b85dfc84ccfac7b6d3ef378fea2 +7d1ddb5ab5704158835d80c14422e79d +3f32c7db8db74969ad6f3e78674a5933 +ab949cc33dfc4c06a7b79bbf8709ebe6 +ea9f3e4b09d048988864d6d373567b9b +a98131dd42c64d84a43bb58cf04ef532 +914ae23f4de949e989a84ba33e81606d +e89db313cf0149a09df61949018389fd +8496db52f2de487c8684f53da92fd9e4 +67a772498c40455cb4a68befc71df6b0 +10d412d46db54e0bb1f2e8e84668fee9 +6ee97010819742a8b8713605695ec703 +4e4eb016da0e4b458d8ecbe57048243b +61885b8e146747f7b842455c8672314a +7e3b35368929485d89df5fe9071afd06 +39d113d5868d473caf71e928d1d313a6 +acee2feffdd64389adf9b996f12e6cfb +0f89fc7be2c54d4b92256fe7363ca058 +f6a69b6ebbbc4f6baa151eef92213271 +7ec2fb3bf0664da5979a55a86f5cdbc5 +14fe19e7cfc84241b04db8ea99f1fdf7 +22732575b0644cc9b65cf21857288189 +07f62a6fb60a4fb0bc956b800822e611 +ea2db1936f2244dfa179cafb33e3e443 +4da1da94471c428d8fa007fbfd34e8bc +eab6a0eadeef48038900a372fab77645 +cbaea52a561a485985187467cc4cebba +e7925af708214cacbc776142e31e274d +2555a69678e64f91a286dd8132f7e937 +3439eede26b04e558c0a89d1e707dc39 +c6d45f40b0cb4717b30f03ef14fdbeba +f75268190ba14ea9ab7d12ecd1e794b6 +5001c2a5548c4691ba665003201364b7 +72b0be313f554effbeb939f60a3c3b03 +3b5555f4f2544005ba4b0ea5328def04 +080cf640b0454a888c0ef61c7c7924bd +dec837b2107944ef9211bceba0d12f13 +941e436603634c7f8e83e2f215680eb6 +946addeaca464bdd9bc5a96e0319b5f0 +75fa93a4f80f4d069cb617849fe35eff +db00bc4985f4432f98d12d39c03ee009 +20cf3d57187d4f8fadb45a5e808eed48 +cd0cf7f47e2d4d3086d2499dc0a2be61 +2170f37105414678a835ecf085ef956c +00f980c0932a42af9340b2b8ce2b7915 +1ad51f6676bd436eab77a198dbe991c6 +880044db2cdd45ab8f7a30ed57a7c217 +68655c9cf95642efa50c98f895c7a449 +ccebc76ca970421a954f6953c66dbf33 +4e8243af45ea441894b35d303edd4a34 +eb2c70476cec4c8790c3f70af38bc58d +87930f0080814d65b5add1987327e122 +ccc3f77d27f94ae5acc77992b90b146b +701d81bae20840e28df2e79a5c0a4c08 +5e3e6f8692584d67956cc501b869e02b +05a4c8fccea2443f8bc67e4b3152e056 +da3f963385d84c258b85f70b44f3e16e +f279979d9fdb4aafab73a2c26557136b +85c0c24608ca44c9a77a7210518bb25d +14a1e7cf66e5474da13d844c217a5cb2 +fec0a961dcf2456c939c2379f4683f21 +a6380b5071e34b908798ec97106a123c +230264f6d9e045ca9addfa56b694e62d +07ed32ee7f554b019ed54eaaf23ab99f +4426d269d52b4269b421226c054b9e07 +1404fdd7009e457a99035d19bef06657 +462ff4e83a154f8490cdbe5b33007cc8 +d7955e29c0184bfa87f96c2927107c86 +1d031ceb7dba490b879b6d45ebe7966e +22d472d1a9b84c8aa4bd752fea81502b +6362d3e9b11e4396aaafa854c3aa6f06 +fb74e652b3af43d3831b86235ac799cb +123eb7af58224f60b8e83b0358da12a2 +fc199f5a872e4e668b3b956322f341e2 +9ff12795a40e43c4906558267bf8581a +190ef7bc700047668cde6811f243d199 +9f5d084de0474c1fb2ad4e33920d29b6 +18b60c6979054b6bb2980c5e111a1c75 +a8c06fd4d1a34c60ad37db4a487507c3 +05485469a7a840c1b91aa1b213e658ae +f0b4a0131f784059b0b339d2911478f3 +eb447af370b94ce5b3faf6206fe8594f +c2310837dca94c008d3cb31d0c8885bb +c60c660948374590af6763d7254a59cc +6080b7f9e1264520bc70478cfa952307 +e2d5eb47994c442086c92a83c60ef303 +bd384d46514548cf8c4202f1ae6ea551 +95f4c032011b4a3297623a9e5073f0f1 +d0261c8292254d18bf51859d7e2e7eba +81669910c0b74f41a3a58febfd514794 +5b7c03fa21c74489a84c9d2d65a9d5e8 +6724446ce310413dae9a6bd75fe0f573 +cc9fdd9ba026488e870ff7a7949a8968 +cd2ec82cb798412eab45aea255c6ea07 +f56a055d52a84a89abb40580f1af3cc1 +0ecc98014d684f548032eed7e89079b0 +5b3443b6496046a1865d4d9f9c205356 +a591b58c546d43eab26763a294088094 +c459459cbc734fb1899f4e65b5f13f0c +39c1c24d0e164585ae9d523b20c71e50 +4f742b7262bc4a2ebced61073e66558d +e71d8a06787443c495a90e7b9f680047 +c6c1972b1f454f73995eef43de2e5540 +34122e3ff87441309d6714396d6e22d2 +f5c624361ae743e6b02e262289fd8374 +ae0fab3e19b94a8daf568fcb1c9e883a +355b59831763412fac5bde1f1c56b61f +d1d93eca5ec34f7483aedb9c27611152 +6bce2a4bf6f54ebd9502823a453db665 +aadd0e6c42cb45f9982b0ce99a33bd27 +f46a009e33234d0a8dc42863b441b25f +c74ccc573fd144729bd9bd33144782e5 +2edbc3b679ae488191bb5a15f85816fe +75f6a8f79319483cab0f61cfc45d6f5a +c334d1d281a54c78a91243b73e02d5c2 +bbf869aa654348bfaec30adcb26a181e +585464dfedaa4095a5f0f5b3c1d15cb6 +60aef48a110e408887caf314360d0d38 +9db7f69324c748e6bfbed697c5afaa1e +bd2716459c774dc48fc793f1b76511e8 +056d9b939742424db19aea4adda94e6e +eeb7838fa770487ba4a6e0aac8e07b1e +878e4386832448e2b2ac7d1afa5da715 +6abf2d940dc343a6bd76d5e105aaa8af +de341f98e34b441ba1727fe9604470ad +772ffde4a0a245ae8823b01ff58cf22f +8712e8bdc8604d04a76ec43c22edaaa1 +811daf3a66fe4777a2d26b2fca951528 +7a51077a2ff349c0b4bb828bad115a61 +3902551f1c5a4156ba67b9f8a8f5d59f +4108d53b5a674b868d1e1d94144ed795 +8429c06aa970491089cee1517ccf47b3 +356a507a5da348fbb1119b760dae286e +27d03b6a571f4b509cd44a4fced77dd7 +c01b7abbedfa4e49bd25f14c4b2a756a +69f894047a884feb83fbcc0caf09b0a1 +e6552259de4441cf93531758745d8f31 +4ea3bf9b3f9c4d9ab5ce7f314df1ac9e +86bf9f55ad4a419293e13284a68675bf +7842a813fedc416884e59bc593a890c1 +e93f95b217ea4ba3be66fdc801d0e2a6 +176e4cf301c94641a4fb6f8fdbe56b42 +c5840d5affb64d9b967986c83dde61e6 +cb4d425c165a47f89aa8478537f2f364 +7a70d85f889642d6868ffcc3f1cdd27d +2b30f9b848754e7bb55093f3fd0e6dcc +bbb9e35cc17c40f3951512cba121a92e +146b780acb0940069f58d7cc7e8684ca +261d9727bd054bfcbb6334ac2b516f83 +01c77468a1d04414ae24ecd1d1559f7d +b0afc9636fea407a88e11dfc77374b42 +15dd4489ca3d4c0183b2920c67f96d30 +8a0c7b9a58f44b0393efc253a94d453c +f3c6aabb3b2c477eb9ac80cf02bca5c7 +670ed19b6eb5436fb9a5ee8435ab2857 +1e2cac5238dc4168a6a2eb333451d27d +2df262e6815f4c2eb7572607ae5e0321 +a19e79ff161a43a4abf2969e22707d43 +a4d6a4618f554e5986fd94e04720488c +315366203dd14506bb215d6cd97662ec +f7783bf8a13847e589d2cda9590178ef +1da241d0c62c4e318baaf078cd0e3b89 +6da418c06b52440ea632a766a7489ba5 +524fa6dcbf81417cb2049e15ee5f7027 +2d76588c822942259b579e15640d7511 +89bfbe6008b143819a40f9c57a131fc5 +d21ddd9b309d42a0bba1fc281ca9221a +99565b63b54d429f99526428639037bf +8ba97f1802a94dd9b2bf5c59b11bc4b7 +4bc297dc9b2344618b286b43f95896ce +9d3b0aa454e14636bb4e976ba6e2597c +eaace4e2c59843198f0443243a1f26f4 +0cb168c5176047439bfa91cd6599420c +38135087cae94516a7a2d48fc8904624 +dbac58a0440f47709bf5c36d6f2116cd +e57b59b6037643a99662316493a831da +5a9852d33094499e9e13675f3d1043e4 +95c2cdb3812149c88daf1dc8431d1e05 +1b4dc73c97c043e0be33c6beb3ccbbec +db7987b1c47d461ea285c235ecc53d16 +54372e592c3a4342b705111fcbc4caab +e46deaab889548948a31e4264de61e5a +374adbda2ee649ab862c770545967c5a +231c465ba86a4a749b3336f0736865b0 +0684851262924daf9f1ff70c54e94b5e +333759bcdae74bb396deef5d35f8ee14 +af82f700434644dfb6e63c6117695527 +d83f35ad19e8433d96187bba7352e9d7 +b1f70147994249f7bec09c836deb28a4 +4ee8be1342d34881a85ed85edf83c403 +5c2d2c485ca647339651c995070564f5 +583a67982908427298dd3e9204bdb4f2 +5a134fe54c3140b093c0660e63f0880e +0d8e9b33b6114387b226f2c7d9d696fd +a22a5ec25ed747b1a1614ef0ee59725b +4fe1f83f69024d6296a731530e119c96 +1b4cc8034dc7455f9e516cf0dbf98c37 +5a9249e920b042ada84f8da026efb1ab +483d5634e6cb47a5a1a154aad3a9e9d0 +beced54230a146f6a83012d2dbc4f490 +a0271ab30fc9471ab2d91599e04107e2 +94e27c60997849c9b41694f1291be424 +c9add858e6f14b44a2613cc3f3237ee4 +22571a51c33f4d0ca05f12c3e786bb54 +75684e1baeec45d3a5510b97e985af03 +c4e26bd993ab4d8ab17d1fdbe9431367 +adf60e42de904d3abb1d45d3ae2c20ec +33aed51feb14402d838060745731350b +ebdafe6738cb4fcaa926cdd27eae74bc +8497de30e5564a0a94b03e62c3c4ae6c +bec1aeacb47f4911b853ba6f4b6dcf56 +0a7ec762364f45dc898d116d22caf70d +e0bfc635f5cf425eb0dc1fd1856d5c03 +2b22e0705283414f9d4ac074ea2ad9f8 +4665bdec11204bfa8e1edc00020c63aa +dae7a42f991d466583e403aec5eb6f07 +ae3e519e3c7e4295bc77f437c3420be4 +02415d9825194fccad3aaece64344508 +d76c80a319f64b45b24c56954cdcc844 +e7c53f17be19453d9ca4c7ea4d91bfa0 +b09519abed1a4ee6ad1a6a17db34cb94 +0c7b15ee169046c9a3f07329a322b578 +a7a26ee577ae4253b5f2f258df4b7504 +4fd6943807374eadbe1f066f22c9c7aa +214e634cf57d479098bd012bf124bc8a +baded4f3a22e4d6e9472e925e6f1fc12 +58351abc254d406583b120d2b2eeae37 +4228b3aa43444875bcd1051276e67456 +ff8ecb3583684711981b02d83bc721bd +b5daef21a1d14cb0986772b621627f31 +d2698380da5a44ca858c7e7ac7dfac85 +78ac2ed21a7b466bbc158930ca952c95 +b5c5b759e12148e78ddbc9b014f07690 +fbccbe1a047f421cbfd815dc3682faee +922e0df32fc24a2a91d25871a515e0d4 +e1326c176959417ea8d55c5db3139fa7 +c8e7c77b08bf42859fb6b5af90c8ff43 +0e1ed07bcd45477c93e2385f8557fe6e +f47e3429f5de4a2f95ee3f0a82a3edd0 +041ea96fc6ae4839bf9ce16f8ea4ad68 +c78b9c725db44324b3246cc59af1947e +7810777f8c0941a9a03fe50689b11e7a +5972f3f5f0d544829ea6c7fed807fa32 +1390c6cae6b34933a06a88502e284236 +4321efa610f5413385a9458fcaf68eea +121c06e0021a4f8290d318a1a4cb59b4 +5251c39ff8f6462faa49f14fcf5774ad +4a495f3e05e54982a1359d3b3987c3b4 +e13bbc35eefa42938bda436fbb17c6f9 +07b02a429907414f858cb947c6c0664e +420b54e055f445c6a988296c9d2cb0d8 +35029a5ab68c41399b8400e3188b42df +cdf3b49e57154f28a149301e34bc0c8e +53d0b31aa7f84bc4b1733224963d0114 +d5e6b8be218e4441a44eaa1aa72c27fe +ca0fb23acc5e42cd8d43bdb8cfb39c2f +164e0198b3ba4f06875374032145d18b +6603d45a07dd49b697c327bdd2aff6c3 +73d71b0bf2dc4beda4e156dc79b53c04 +5fa59e7ca42f407eb5cfc5721d337160 +dd0f0bfbc3524063af20e2fd14ae846d +d3aaffde4b3f4af2842a5def1effaf0e +d98a52d836a942fb9322fecf95c31ed1 +5f491ea8b1ee4481be53ad63d402a7ca +34f011fa3f0e4cc3b01ba603dc6e0d20 +833f8317cddb435d9cbaf616649a5288 +2a20de42531a4156bfcb388cae209101 +144051ab17b948359dc413c5a74968b6 +ba3a571a8077417f80ae0e06150c91d2 +a53633951e9e4dd0ab14bdc06e08984f +b5a17878c0594da989c3f02101db7340 +8983421696d54cecb10634a4115da469 +550db344f7674d81be9d49e550f668ba +f602b8aad3a749c8ae12d6a44ff062c7 +10906dbf08ca40e49e696d3e667a6dbf +bcab82613d3844aaba5d7049cedc5104 +d4026f4bbc384c5f9307d9b066a21d93 +69ed74ff54164b05ac7b565c6aeacc07 +7267e0e238744adb820b0f13dc0024e5 +727ca78032304c028941a5dec1d76a9c +c2c8476dbda14263b01e8dbb88b67f79 +3d78e01d40cd4532932ad8180bf9137d +389d5427a1f344c4aa4883ec5a6aaf05 +9458a4cf547d4521a62da7399c53c169 +8f46bc56341749a1bd929ab0a3375fee +75ac5035d4c54eae8bc096ebcf75004c +20aef99255c447d0b55a4c073b447b33 +62eb766517024004865f3e80699815ac +1702a2275a2c465d8f7a6d4fb26d2c50 +ff737ec0c534475592938a5085fd2e99 +8aac82b4ae9041ebaff9944e4d1bfa21 +87d5bce4301c46d4b02ac318970b975f +7779b4ce78644c78bdd0ad7e4f0ee6bb +f405d44051ab4bacb3bb996e3d634def +461f173474e04eb5b9c5de29753c28e7 +cba4bcda468540c7a3ff843b08f22412 +1bd6d34f5a324004a1f67c615c26889c +dc1615bd22ea472ea732bdfdbfa2cae4 +a3b2b9efdc194d2e84970e099008bc5f +d7fcaa3e8c844418a38b721c325bb2af +9a915eb89d544ebd9a8ba06f5e56ecc9 +41a8142416f14665bf0cf82304d02b68 +2a4a821350ca4527a9b702cf893499a7 +cd4731fc9ab742dfadb0d15178f9d75a +ce00c53372064605b6b39fa856419887 +7a6e5a855c8544dc897e6c5cebd641a2 +7590ca4ee92047fea87a5c287d3fe22c +6cebf458de3c49ffab3bd78dca6a4c85 +919d746a04c149e8872d3deb78c438b1 +c17577daa87849d09960669606c0ce27 +8609cf7e67bf413487a7d94c73aeaa3e +46617e30864a45eba268c756cf53c52f +040ac45698134ff9a4c79273bc830720 +cb6451947757498aadd36b41ed8757da +0d9a45c2610f4f3aa638dabd8e29a492 +bbcd5ba505c541f59b3e286e9abf3f4e +97491086f9c743e197534eb9042c66f6 +d4aa4126fce64397935d128ed54c3def +e0d4217ed43141b082361e9be071e3ad +22809785ee9f4226b4b89bbb46ec1a17 +97325850d52d455dafceba65147f4556 +9590ca9bbe8444fab91b347fff0675bb +58c973e1bff6400c8a568ee19753cfd8 +65515ed051e943e9bf988bf3318171c9 +eb8cba7322ee4827b92c539883638474 +937909ed882d40a3a8c6872253ef5aca +9926c2a955ce4529858a57fd0f9d60d4 +60d2fa9af6254551ad59f5077680a8f1 +cab3272b30354865bf7a650496401ff3 +eadf631145d24b7789b0fc82648833f2 +8eeb5ce7adc24212bb94acd8ba19e7e7 +674dc1556dac485585fb0d80c6b24727 +e365d8cfd6354316b57ba7e312c7de62 +28bc366ba09447a89fe6b75420299a4e +abba80511e8a429480df241b616d25fd +536712f214a44ed5a9a45abee1055ef1 +3e6218af04de4a9aa2de7221331ccb87 +5d3af04431e9481eade93f94f739ed28 +8a193bd9d7944b5baf2031f5fb80a7a3 +573b1ecb18cf4ad1b6c53e436986bb8a +4a5dd4a14890488ea17e0d420c524db2 +985415443c184be68e0e0c62edfac663 +e0613851ca1e4dadaf605d401c460771 +a22d934510694562804ca9fadb0aa728 +137f87454bac47c189bdc0c8ff7dc52d +b681993a7ef246568b819706f3e029e3 +f3cd528b06b9446baccb0a86ae6caa3d +4491bc20adc545a7884254ac8eede3c9 +aa578d64a6d247ddae18cc2cf73c1a06 +f1bd324be33042fcbed45b764c9a238b +86c2da6d42364cb3b3f5d732fd01b9c5 +63630134a61b488fb95b6b83243bcfa0 +bf603827d8c3432894049976dc9f17f3 +76beb95d0b5b41a3aae0d07c3eae99fa +f61affe06e6b48cb8ba40f60139fa0d1 +017fe235577b4083ab32c2b7949ba022 +b5b2012b2e894095b9ce21cb2b446cad +82c003cd4d724fc4b21bc61cfe7168ec +82771e37cb0c431a938adb1524c0610d +03fe104f539744518cd35d8f2e19418c +512fe7317a904514820af64a69d0cd9b +7275bace14d5436b958515f3ca408eeb +1097239bcdbf4e3cbe7d1c66dc29e483 +ac0c8969d3164dc5bf52a6066478ceab +97bd7574406d4df38d54ec4ac1f18c40 +878c1f882808477ab81c2fe86d5a3936 +bbe1d47c0d714884a66c53d6c1e5d177 +0af2815f046f406fb0fe1fb84b0229a0 +a7ff74de323f4811a95c3495dbe05f40 +40f4bc1670064912b0fe82a19d979613 +b47930ff784f4377937d51049aae380b +8dd98fa186144792bb9c9cf91a66e8c9 +214dd5630fd74a99a98511e756ef8dda +5bc1ac7fe7c740aeafc08970c410fcb5 +43ffd9117b9b41199f90f009fc17f351 +d3e56ae3e65d470e9cc571f2daf761da +a42dd5963b3c4d71811a19c51df647c7 +0af557e5e95641a38a05fbfb1954e552 +9529be282f2d4fc7a237168d365cb64b +64e61bf3cb704534bcaa3dea5fa2516d +1a121ba643144d7bb36655d999b10493 +2471b5dc0ce44b1e996f38ea2d275235 +4721a75efb6b4d1ba91cf61696fc9a31 +ded99b5d8f30441bafdc8b9860bbb4b9 +defbd463e037495e8cdc20f843c670a8 +89c547e2203b4ba1ab118aa324feeab6 +783e6e237f3e4d6faa8538ce5001a143 +f141ceb9ccca40d6963a62b8e883aa08 +60c006be9a834849895438f15d4927c0 +4a8dc4ec9dfe45f692c48d67798b77cc +4675560fa1de4097b96886bcb7bf65af +ab9a08f342624728bee06d9444094695 +b29dcb2b1cea44cdaab3015abd2ffecc +92372d8e682d49c2a5e209d31f92aa98 +a6ff501e9c62452bbbe21e48df4def9d +7fbe323be68742419263845302645be6 +9d19862bca0e435d9ffddfe75253b046 +3ec4459f787d4872b263496118c9a9e0 +d5a7d3ecec614226bd1a805b3f93c633 +0d3086601c914ca19404ad30a3fce593 +78629a0cb1564f459939be058303238e +86903f719a9347e6bd1e6c1a2e07989c +af554072b35a4234a2c13e2d87e39ca0 +050d92eccdaf4832a50f843dda6b7c34 +8c9bceca966f4d47b2a440a1dc434989 +69ec3826c4cc4eed970391aa55eb9006 +dfd3875d8807400dbab04a73b08ccf35 +a0d66f10a850469c9cb04c3cecc62a05 +260e5ee10a994a58b03c27debd985219 +2c23a943c53048a3a7991d68ed3cf069 +c80522fd9bed4d3f9b2a3a7c135dac25 +11ac243d6f294da69ef9802e7b51fb8f +18a1ceb4464c47469d7b6931ebab8700 +186c3d0657a44e2ca04ea9544c453437 +c475c9510a2b45048fec0b67f20c9387 +74cc2b0550d64e61aed0fab833ef407d +9bd05ca500804c1aa7ab7922dfc060d2 +8addefd5e4b44a22b0a4b696bf3c5ad1 +a8821371a98a4ccbad0beee12fd4f3e9 +714971a855b34b1fb65f1b214f627472 +264b9111902f47508c700afda63cb327 +39457cd0e75e4790a1c62a25e2246407 +8962eda79560473e90c067a7011c0ea5 +2ffa30f8ef5c4e19af9ffe6c6570fe30 +f94d3cf8ef574b168418709bcd2155ac +74868e16ced243c088207e5d7da8c750 +ceadf967d10346be9cfc37e8adf8ec74 +9d08bcd9c8664b1b97662691234a7ec6 +5fea3ad87a324c68905714115684fb35 +1042b9b3532444c4bd17f7d25a68adc1 +63cf7909e5ef44c9966b6a1f6ceb4752 +d2ed14b765d742a18f05e75c231f0e5b +2a43e6e50fdf4d8aac6bccd9e4ba629d +9403a721317a46a8ba05f76c9ffb86c6 +c5f878aa1c254f99ad16871e6b71e3e3 +b0f3e65d0c3c4a53893b6b2d650f4e95 +3824ff09fc63472d99a3f8b78061bb58 +2332ab4e2c4046f487fd89a840909d5c +6dfd26d4c1ba4e26a9c3dc19c6bfbc85 +ae44a25727c34933917457f1a677dc9b +5e77a057585d47309d2605934197669f +a08875e41e9f4aa99de5f636e644c9e1 +e8edbeb250a54ecc816a9018886d1c08 +1fa57770b4ab4581b65638e2ef31d66c +1ef4bb90026d431da3966041b6aa985e +166469433a8948c386d127c6cf374513 +319f10a612e54746a6f440836c5d1a49 +a17bfefbd1454c9c80cde4af908a6442 +4f310c5e1bfc4561a8bb278f5d0ce7ea +440afe6af0724b5e9c5ada5a754b28d4 +d9a1361bb7324e678ca21169533093d1 +62f6c6368c484dd6a85a2a162133d2e0 +95ba47a7cc8843839c87cf2ce6ad71ff +26b2b30e0484494b92ec4534bb7169dd +79decd9b09d44e04a47219011547355c +af1e5ee78a8043caab91cfd37a9d35b8 +eb41c6490a5546269055916029e623ee +d9cd316a305a42debc41e9803c07d6bc +5adb3486557b46eaab0e1ab643709a9c +91c3814711da49ceb39d8011a7d8f3eb +690bdd5d6bfd473889e9eaa6d8877dd0 +ea61bc6d27bd460eb328c2672279eee8 +683d408f83514001839845adcda008b7 +3beaf6f1797a41e9b16e307e26fa1f8e +4b3adf64384e450f9553ce3fba9882fd +1ec5b57a8354446886a2178b6e4b41e5 +e844114fc02a4ca3a39330b44ac0dac2 +3d5c1694eeee4c4a87349fbe63acad30 +9aadeeb6635440af88606903a06950d8 +c91560e974fd48ac950d2ab3b01c56ca +419152ee6ffe4022bb3feb152698066e +42e097aebea143b69beb9276ffd1cbc2 +1af05d5ebd334e36933f043355f54c25 +b6ac760f0e624c019becdfe986d01352 +ff75867adf374193ae3ab083e8df660e +6a8fc97303814b8fbf467c2d3ae060e3 +12cf48c0054f452794ca964f61ad3b05 +544e936d31b241f2ae04c7ec133eec05 +b2b4fc6f025d4de696c2897111edd3dc +3a00f75b74ed4202b2b1551add2aa620 +f011cfd101b24342b76f5bfc3e38ba6b +b38e301d631e4c5da6f0df225b2faee6 +542b1872814a44b797c0655c3a783178 +74611a68f6b449ebb48a62e617611037 +da6d646358d1451fa751f1a9141290a3 +3e32897a225f4cfe93ca7a02d51fcd30 +af4b617beb3f4c10bf3e005d6bc39550 +2d97b116cc244ce1932796315a1b842e +19b60335538b4377b57537884341ebb0 +69d530f7e6bd45b9b3d9f16dae627348 +4530d07e89fd46fcab248e855cf5dc0f +4de702a2ce24459e87678bdcb6e4a946 +fa15b3ffa9b64b3daff2241b65b92ab8 +e2067f6129624d6f91af6187b6c2feeb +c14060be9257436281dca96b55d118c4 +6bead16346974abba15357a2d1adc0d9 +2ab68590731040d7ad3f618469cb5f95 +104313c44e0f4e94a4d0221a94d46a32 +cdec8a3b9299474eb642509bc5b37844 +d5a2ca06677b49e78868350344752f94 +1cabd76a4bbc4288bbc2a4633cce1695 +ca9d03af291b45d0b2a77e739c713754 +f8aa5eb92cdc4d3ea4dcb4dc567d5579 +47f357729c5748b88aa3dfdbc9babd88 +87d8dfe0014f4eb08a478118153257a7 +044b951bc4ec498bad494aec7e977be8 +63e8fd7feb23426fb396a5e3f3551f6c +c2b2d8a8fc494b769e92af3db71764b2 +1897a2f4dd554b9d959685650d2be0b6 +e012f140709742b88feeacdbcf7f6262 +b5337ed2243e4ef0a0d669efd4c02891 +a36ffac5758a4104be79beb3ba5b6c92 +231f1fb0e9c24ab998b1af640404fe7b +f55d42dc491c486987b9884357401e10 +b45673fde9b74522963ca5a4148126b6 +c9502e4c04f64bd7968cb587ead97559 +a44544c27b6e47f190d7087c40c9e01f +f2f17076947249918f5c2f75b372db92 +4bdb1051c81447589ce3f1a24543e093 +1315415fe2c7459aba9555c31fd68b31 +7fe87a99a1a648a7980dc07bf0e65293 +b9cfba75e97f421a821d40d00a622a1a +39076c677c0c49c399149016e390eea1 +c0b338ca475d4147bfba00b071e0cbd9 +555cb2de36f54e80a588ddd461dab91b +0c3b685ad3734eb1bd7ad7613a7889a0 +4b90f6769631488b9b85c1dfc860d38d +10a2cfa8081b4a2c9c201220439ff7a4 +3904652d6f844298b6a851697d3f8345 +ebfee94b75c64bf293061e68ba58d5b7 +8f3650c8731d4d4c9809be426834ab4b +19b5d7a40e04470b92224f3909bbf4d4 +eb37bf62437c48f291831d9213ed0df6 +7a6ab41617384ab380ad3567af427a69 +4e0564db1ca94de9ab7df7d1f6ea9cd9 +dd8b8bd637b5420badb323d5ec82a948 +a673a55088d047419b468df78700f8a1 +42cd12a7c1a24f639679fa5cd5491f76 +5c03f6b1082a4decb33ae7511209271a +f93bb826f374423681a4772a3c49c1df +4698bc37e2094d69aab4ffb6d9d950b3 +a5f3815707bf4a218680f51aa48305f6 +daed13f9c8d746ab8bf04d50e7445061 +f1ddf7c1a91a46fa8630c091faa33dfa +052449f0d798499b94ee30c112eda403 +8c19d6525acf441b9cf3c1fd91598ff6 +8493a64aa0f648c1bca44b6ea141bfbf +7f934774a0e146a3b54307a2bad27db4 +5e19fc8028a34ea98560312259b23475 +9690cab969d04ed1ad3469765820ab06 +fb9b63acfa154b8681fa379eedfd6e9c +0387d3335d6140a783508862d645653d +42c85b6e79b949eea51fd5d6c37a457f +736e3ea67480426da4013dbca5fb8d20 +6dc3eff5252b4c208133e7fb9769b3b3 +d5affd73f6164334956b4cf5c772a59d +88b0b93487b74132b50e6dbb250aadbf +578a8e3039834842989a1de9b893356a +b741649233404cecb47cdba3811b86ec +fd42746284f343c19183fa2376d8ce25 +78262b7089d34c6c970d6b0f7dc0e8de +3e8c37f3d701413897c6333446a76a6b +4b277d86dbde4b538abd74266d0acb73 +bd1e662f253f4e1f821bfee4009034ab +7d2b60f3324547a880f1069ecb24c5a7 +26063555c841414fbd1bab9e204d34c1 +98ae66863ff744c6bde8f74fd2a3ddc1 +f7f8920be569488280d6403acaa82511 +bf1ef1e7852a40ef82efdc73311103d0 +26c4202196ce4adf82428684c88fceaa +410036d0def24c33a6236093e5e694e7 +2daeb6849ffa46d49ae24b97a0378880 +8a57a866af8b444795380b6ccc3f5359 +76d14ed8675046d686019a770b21d8b3 +000a00944e294f7a94f95d420fdd45eb +139639e00bd244a8a794c866e2061dd0 +de2df5e74ae54f7fb98002f5b13ef90f +540db7d882cb4d7aba339cb79b33c8e7 +ff24b004c06743dabf04f6c1b6d825c0 +18a474c6ab0842b09e3f6734ab551174 +b82e4d73accc4db28e45c9cc0d87a69e +b9458e04d30e4b6284d46d35880a9b95 +d5ea47a7d40c4afe9b2391faf783a305 +8bd675e4479c49b1ab326d1c2aec56c8 +25863ae2e1f34aff808c6f70a3c2217e +4fe8d6113f354715a2da2a5552a72dc9 +6ab71f99b8a44e08a20134d32e9c8a59 +6f97dcf07cdf461e888888184b5039ba +296893c411fe46dcac6df974b6093161 +b523b2a9768e48f7807465990ea558f2 +c700e7c131454303b3a87d7a264e7252 +474e014d7843408189fec04a0d71c6a3 +988d633830eb4f4a9ebf2d6f012771d3 +d5d2950fc2f84b30ae4d2c18608112d2 +25aef0a02c3d4e59921b628f31e567b7 +d2d63e52c8214f9fbc2186612fd068fb +27178a89bd744a65af64da4089d1b2ee +dfb7c3b51e264b5083dc28450e55c2a0 +e92a4d57fa4d4791990f102f9152ffcd +455f27474e9c46e5bc79215902fdd24b +9f57c839da2b49ba9fbdbcf0a8868ab0 +57baf38756304e7b979372500dac0e91 +94dba5bffa344e09aec68262673a25c2 +db4defc696c349f5abe5a99d00abc9d4 +f8d4de00a0e741bd80fbd50cab1c9397 +965f145e23b243539eca393618371889 +89fcd105c05849109695462b29762559 +abcd5cc76c494045acd303fa56f7426b +9c89f5c7427f4e1084a1ec29419f92fc +64d88784946d4172b9e8acd3b4154f8b +fe1388bf67c94f1a91ce094b8a5cfc83 +c23be007c1a649d9a2082f54af6dec7d +6b985fa7b20d4b2a9d404661652a81de +5c8b8d30a37543feae428846484d316b +8db69750b0d84b61be689f1454d9e31c +5240f9af9d244146a4a25503792598fa +f73581e1b3c94d51817a864eeff14417 +37c6cdee47f548b89f5927be0d01fd79 +b7826b10a5684bafbfb8baeba8673f97 +0ecef7c16c0943018045f31dde9fe4ff +5e18f410ea20470ea1efb0acf6b652ea +3a9f6b8c57c34f7f8c7af20835a4a3e8 +10a20acef37e4b76b3dbe7acced1ca4e +8cd648997eb14534839d2d03f0a7678c +64aa4901e39946208afe50fa0c2dd8ca +e69089e90c194318a3d2932557c8d3ea +ce8af2be4fed46009a2116f0e8bd08dd +cedbb1d9c25c491e948757c0a906c249 +526a77826ddb4773a66cc6a189747348 +3beaab22c97d4be49621380eb34290c5 +651c2501316046ea94249335a9b7f4eb +1d683dcfb41b4fce8077dc73853ef79b +6a1c8010067c44dcae726c0a486d4128 +c7eb6c770a0e409b946fe4ee34996308 +76c7881a28854ca898c06b210642456e +842284ca02804217b138b4687d8e0844 +9afc7f5ca9ab4a61b1be331ccdfcdfa8 +c740b8a8011e4c719ff9ed8043cb69c3 +b8cebe4d2d154bffa37ecd7a11b0d12c +8d89bff741d1486398a3a1bab4626abe +5bda8ef98bfb4a908bd671b248ee22ba +3880ada0b5df492b81c5d1ba3ce3126d +c9c679d465a84738b0380aab8716fe6b +0dc6f643c5aa4a22a8a81f0cbf3ac05b +052b3143437f412fb36be6b70e9fca22 +7e37bfff5662488aa10ca58a2ef077da +08ffb3156ec84e5dadaba2b13bcdb3d8 +69c8e841e0884f3d891f0c3b3869af61 +8cac7c52a8dc41c19ed61a242410bcbe +944b6c4785f8473e847f156338ecb804 +fba1b218e50e464b860514c0cef8f858 +861959a12e4a4da8ac7407c2be517794 +ae5a4a3e5c934d0bbdfbd78a75bb286a +89b71eed14b4490c92db6394bdc7da4e +a3b8ac02bd254cf1b7015f46599801c8 +7ada25d98c644ae98f7504e7ad1be3c6 +d7ee75d846324ca6ae6aa31ca8d926f2 +54d77ed2b16e48848425a9f36b69bb8a +aa793558285f4396890ec56dabec1d68 +0d2dd8a6156245bbbee8e15d22a89157 +2d609d3adf9e49ac945b62b5ce98573e +baddb68ba030434fbaa162e56f11edf3 +03297a33c9ff4e3084b0d00303956c56 +8f9490febf2941b28a1b62d08572d884 +a8f18495f9b74f218e711eb37e5c55ee +c88c3221f0b9436293a69a641948c36d +e98f3cd475654539a4d27156b307925e +4a0c523206464e40819f47d1770453dc +4654e02017d141238bce04c8ed4c5415 +a4e5031e0ffb495c83037f53510defc0 +813f5aeef3f3430d947f3879c6941719 +939d2bc7260d40a3ac5593d88df1b823 +65cebffc7aea42eb9488b6c6891a64d5 +e7bf013927104fee9bff0286708413b7 +3ae5918836e44c6a8825fbfeb61af398 +d6ee1a7166554559915bdc187d8d8cf6 +10ea339235c44707b34511d4dde1e025 +727eaad7ae154904a7f3d12a0affe14d +9df575f5d85945129e4c73248b2cbbcf +10e6b7479e564950aef2f6b6bdf5fca5 +9a139c3dd1cd4c2fabc0b4ee6f331fbc +f2439449622847df8450ad52e6c4f21b +fc9cc06615084298b4c0c0a02244f356 +ae0e8d6823ed421ea263938e32d62617 +7f526263e0ae48308447f5f82e1df9f8 +3f7c0551a34f4b0dbe60feebab893fc0 +3c718d25fe814818bd1afbc2e1a12c82 +c202f0c8f0d64d8d847c54776955089c +d29892a06fef40a592dcec3bd13d7d2b +c335732772454197817f29606b731655 +b978575bf7694f9185fcd906847bfd9c +0fb58ca488b64298ab8af6f0372e66b9 +4c713330a531497eab09d7bb7b19f841 +3ed3811ef99f4879974f0549915226d0 +4b8adf3292e1437387fdb5b90848642a +48a602e8671a4534a3db78e715c6ab9b +e1e4d1cfbbd048c494236380599dea66 +b0c6ef8cb62a41d4b6e4d94ba0040265 +bfbf68d4750f4a1c91eee39b0a4cdbac +e8486eb234eb46e2b0038e8a9398919a +a2d4d0fc855a499999c49eeb8053c49b +7d12f133d9044a17aacc33d16204bde7 +afd405f8e703423b83a942d8f76c4241 +97c96e278ffc4da394d65151156018e0 +42cf842f793b462f87b35a24a88f608f +bce1de4afabc43a69ebcfea96f45c62f +e3422158ba1845feb23ea7272ae4e208 +adf1d3bb56b549e286b1bfca928df98c +d8dc05000c26495793203d0323bca8cb +74fd2496e44a4c5fa91d5c1aa4eba64f +2dca3de53a8d4e8b8dd184eb48e3b273 +22d1626853964fc995cda04814792ae5 +e6cf4080c85747689483b78f88c0cd7d +f2256509d4c14688849907217394e811 +4cdd2939434f42f2925419aec5eded49 +59c85ab9efec436fb017b4c7805f9770 +ab30351d594f40fa92ec4e98fec412e5 +c80b9ba7152344d98980fd4b220b47fa +aec6709c445f48dd89fed14c0f1d45c9 +5f28dc88604940abbd40ad593151b577 +9e8dc02f4d744cf2a670fae763cd10aa +904a927cbfb84dcdb7ca991f28451890 +f54e5c6df5414ce48ed5eeca0ec9496f +bb1023a8c09141d29996924e425fe6c5 +dfcd6f9d7aba46938912a0f68d0ce676 +c5f031081be8441d8ad4a070af67602d +a98feaf5731b48feb0434896a94fdc4e +a76f1dc717114530806ab99b268ab801 +abfc7ac218264566a82ba5e5fb30a351 +da7886cbd431414496b42399dcb04956 +40604d4eb4f3454685e66a77e447f23e +a5483e74a73143cdb3a453ebd167ce06 +01c7785620d0449abacfb2b34e5dc4f1 +aa7e5d9e2dad49ba8124faebeb8b9e4d +c836b24779d94670bc814ae751189913 +9a2e0e42cb814438a949a6f265b9ac2b +043dc9a9464a4a09b6b1384777022a2d +7b5f0fc68ce34c78a98a1454597a8897 +ea52f1800e814b7eb9df555d8cf46725 +918bad4d31ab45d695c3bf08621f4ccc +82780cbdeae548c582caf7ba16ed0f87 +935a4292e9c84a51853efd5986876805 +f11a9c953bf44a9d9f16e63c2fc13b09 +b7a63454b7814967a460f97ea2bbcbfc +60de5b14f3514572ae1fe0f69c08a527 +ee8d0281536a472c9b0bf6ad4ce880c8 +6aa32d0b23e049ef949eb8f8b5c6bd58 +a23868ce6be440ccbe771b6aef9fa8ee +ceec28bc7b8b47df95671a470e9e9b65 +a9ed84b06e6549e486aa585129a1cf48 +d398339a6b1f44acbc0cc4edaaa2525b +c8b5cb9b83404c69b667cc043098a241 +276a01e4b8484fcda02061e073662dc7 +0316f2811433420a8315a6a2d19cab93 +d265074377ae48f0bbe1b97e206ec80f +81708289b0f44fef918015285b3b2d5c +5f7332013e4a41e6805b33d5ec1d7cb3 +0b85de1a9fbe45d393c9e812472759b5 +0289474b7e6c4f0882275bc1ccde6b5c +63a1b16501c44c55b5afc3cf93600467 +02f8752150cc4f419ca4359cf0f04bc5 +2bb6f28522dc4a5bbc1c95e82029b6e5 +08a82d744b39481dbb40289faea1ba8f +f997468c67d24927b24a927e91f893da +916afa8413284e2c8c5e524fb1e2458b +3ff8b6494f2a44299b21cee21be2e9b8 +e1526b1163d84d6bbbf1f23a5f49f676 +31ce101b0a0f4d768d6d801a4ed674d7 +5eb529ca7d8a46f5832c584c80b15f00 +ccc624d8515a4e2a8991256807d0e46d +d5d96ae5d0cc4c7cb83c2a2c35a2092e +a9e81d1bdbc14ce18e098ac3773e4111 +1b80a6912e2d44608c6dd4a0461a64a7 +c58796860c764ae68082b4f752bfd84a +f2477b1e3868442bb06027341e040b99 +107e4444065a45849a65df22c93050b9 +4ea8025cffa1406a937bc457f71bfd20 +56afb28a9ceb40fe9c578bb5551f39e2 +caeaffd548e34e7889c791cbed73be75 +6d24a8da0d684ee5a00f7d71b6fa74ca +8b7f97904ada4974b52bd6ad290e54a7 +eae79071ca8d48e980ea071c2fa70de1 +6d155e8051294915813e0c156e3cd6de +9fcbf84a8d024ed5b088457376bb53ab +6f8478060ccf4608a46188b29699335d +715e7c818f814ca18b83c7f255b6b4e4 +e58503a145144470be27e38f014db153 +9f2d291f0c5d48dea4107ad0e93a1798 +49855805dd124418a4c3f440ac60e8b9 +426c14adba6a45638752986c2f7d16b2 +115d7246cd1245fdbcebafc8b0310626 +86ef8aa3e94a41748d9e0698bd0d154e +0d4592517dd0436a8c9bcddb63099659 +14bd0d858839450d9bebc359c07779e5 +bb2e0c6de4a84bbf908e7ddd053e1fea +8a1b90bd57634836bb4507a09f9e626f +37f7c6b207da4b669ef7a5d6e7dfd2c0 +8f4566ea6396458c84ab116b1c8a1934 +35537c6b4c2f49088c32648100d1abc5 +af51fb8b592746b39cfb0423c9d9b708 +fd1a9e2e5400478991740bda7bca1943 +17fa66f2280043e6b34e4f93516f289c +f2696756b0754a929ea3cfb4f61df5a6 +ca6b81f51c284be2ba8e714b710f19df +c69cf89c62d14b4bb0e18b8eff1667d4 +93d7c9a0f0ba45eeb16897931d636720 +83ab10bfb21b4739ae0fe2edb9e13707 +59e342de144442cebfb035600e9ffc2d +2d23c0bdde2447ba8a80c6e22cd9cb6c +ce92c014efd140deb6e918b3c59bf539 +3ce2313542334a52985e4bdde47c8e00 +683ead17007546d29edc95aaf78c33ad +0961a471f2ed426c9cf32493b426cc56 +c1eb85c9157d42f9bc2ff527c4d8eb97 +84b0711e13fc49c097312db5957d6c21 +d96e52a67c42478186139b19374d503f +622f57d0e2924db8a2a0634ce5d29607 +8d22af983b8946a9843325dcd16bbda6 +3c82f3aee0ef4573a51a08c84382e9ee +3ed56e01a91b4988a473451002091701 +be91e82fddf84511adc8292cf83650bb +742fbdd5bf314a488494a4afdba92b25 +f3d9535a0b014487b3171f68e2262e4a +58de43d2ae934e12a116ae6af412ab50 +f84fb37480754051aacdbf4572142cb1 +0c77dfdf9430465f9767a58d56e8fca1 +879a32a914cf4f848477819965871d87 +c6483785fb2f46b7bb323704cd799ea0 +5dbfe3c5798445a5bdff4efca0b943a2 +ef6586852fbf4eafb952a9ac6bacb471 +2e3ed055f29f433c9cee1466c77867be +6b92b74ccd914d38b09a541c0acfaeb9 +bf7654a274f84ca4a5e31a58cf73ae09 +d4d07bcca6d241c888849e04d6f98cea +05e894c9119f4dc09b9b32d2e2607ef5 +a1b5d5c02c184429aded90b0c931762e +a221e8934451486ea0c43bae862ff774 +e16596122bde4624ad0adfe85c4d29ad +b5ee83754ffc4f9a9204f3c72610cd60 +3664f42ab5d346bca1a7fb7c7ebad895 +609890b1c9ba46eb9eb75d5840b5f5ea +bf63078640ee4df79b51f21b7ea5e0db +e3ce5ff8d950442992c6f728c7807cd6 +be5cb11a9d55445e9eb5f33151ac57ab +ec225182826d47469694e880d1b97ee2 +6f4c1566b9674a208d618b4a00d0343c +a35e1cb1d0fc4befb288c0d93e068edc +87d8da377ce7435182e49e5a07ffc583 +e58bf787309540e49140a33baf4322d1 +21091907075f4b8e8438c3e0ba3510dd +530222b7fcf348fb93d895aed319c5bf +01c1d0827e214229a1057bcb6ac3da9a +5eee9d9172dd4738adc6a1916f53eb1f +84625e10b6bb40ddbc12f411e75c68b3 +021fc6dda14f4801a8772a9a3380caba +7d315a4a870c4be0b1981efb0b95a3dd +2af9d5dbf2db486581d4ac15c9a1e44b +c00900cda58c485ebec08791cf490873 +0e013d2807034a60bb434ec7706f415a +2a81186134c549ae8c1009d12fb3edef +0f6331f190cf4a5ba09fbbe870ec2ec6 +55441980b3ae44ec817167ec3871d35e +56ca9fe84583494c99b2f2fa0f4807fb +33d01509e1fa4deeb23ccd807b686ad3 +6d633339bc2e4ab79d2153cf4c925140 +2ff48e8f52134f16be3b58b10e5d8bfe +5f4497f476404fb485e228e5f70fcdf2 +1bf0a5e504584e2ea60ca6eedc4509e9 +cfb29eac269642c1a203902f0677fd2f +072fe13c7a0d40819579ebdf7eb3dbba +3836ff67877248c2a820e6a969984aac +506a5c7f39bc4a24a55af42539189248 +f6466eb0534b4efd96d8720803ada26e +eb014aee22bc42cb863096b3314d7b95 +f6b0a42876f946398bdeb9c916dea2c0 +ecdbc391a69a4ad48127a9d8d595f8fd +2213bbe939594c0690aaa5d847888cdf +3ddfc1d67fdf412aa2f0ef9cab2f2323 +c03a4202245b4fb790e55ff5201a0731 +265c0991bf82496ba98d7c4e403d65cc +52613978506349859465ffb270c8f53d +41d7a4b0881548b197a36cb810023b07 +25c91530364a435cb18f452a05bf08c4 +2ab903c108e942bb992a194efa0b95b0 +8f04c4894cbb47e290e53f6c77b6e2a3 +a9070aaf49a24af6ad4f5e0dae4780c4 +712d1e5c3a944dfba95bafcf92e0aeb2 +7f791ca21f494f548e9d6657d6c6507c +b225003a8e1c4acd8a51db302d59d978 +5debae48de7a48e0adb1cdf1dd35eaf0 +37dc9ae154784a999c90f6baa2ee9cb8 +9c30a2ab33964b5dbf453e33d8fd5fb0 +30e3bd1ea6544900a6e38d97da2748c1 +fdebb507cacf45caa67ba468c8a041c3 +f34090dec2d845c1b1ec436325f5a56b +4033e836df22474a9df4664de00122e1 +a647bc9f973e46178bd672c7211b6a2e +d53d4663ca7943c881a9a6d20cdc7e91 +bd8d97ccfc3d43d09d27034e1a9edf31 +90ddd00b03374391adab15353d78a3e7 +a8a6f31816544dc08483db7399088bcd +5c127eb5a193408989a1f48189cb2207 +fe2b4a2708334ff880f62a947cfd3d50 +75df21d5523b4474932cda4f40e968cd +e6d865691b644b3b93114a0267257f4f +53a15531149a4798a506fc59e14f4bcf +ca7a5a97ec934b2984bd0ce28a392cae +21e9c031f3e74612891befaad6e228d3 +ffb617395c6c4fa2bbe0b54ea0ea33bf +41edb147672245bba0bec1327c38d2b5 +700755ac7a7b4eafa7d62664c95fb8ec +4af048cbd3fe4cb1a52bf14c2299e3c6 +a104c8ee588d4670ba5cd621bddb94c8 +933b943b67664ab692052bdceaf11f4e +d061b6a017e240fc873966b703483f76 +99a83e49b53c477ca4a91edd600e0016 +b0cdeef47b9c4602b3c54f7cbe37f61e +13ef8c3671204fd3924b0db9a05b21aa +b2fc25b82b5247efb864efec9899ca54 +c4d8cd0a027043f6ad6694784bde1eaf +3eea6c64f2bd4376b5737bb09a3ac852 +f7b5e38a9a6c4fb2b445396c6bfc6368 +0227272926fe430aaa5079f6d883d858 +5842dc1fdfe34ac9817222bf6a9bac17 +224b2e1336b641d4b8f3414260dc5522 +728e8c8600584eacae80208bba7eece4 +b56cedbe3e4345cb8ea48f623c329eb8 +8c09c173bca842daae32fbe813156f8c +1dd9473a4ccf428bbe4d3f0ef9fd2d0a +1362fdf6c7d341a48efc217b71b69e1e +7b45cb9b387d4078af8a0b8e6096d0d9 +96e12eb5891a46fca80207b73263bc6c +ec9c547a71a5441d8a066abed15ab62a +2674f1f26f12465dad6a802cda49289e +59b932c6bf7842d59830e1b45bc9c261 +8e6fa50d8ccb4a72a699f5bec1633e53 +387e4943cf214dc293fe9f343e74fd74 +902ad095fca94981b6156fa49a21e495 +29099749f462441b94c38c27a99d9329 +935533fe2ccf4fec84ca8760f6add3ba +1f168fc42e1545a5abfbda6c18b7e1ab +b53bef31d45f40689caf1970cc689423 +9a729923591544f1bc22527a25d18f7a +54a0472b77c84658a8be0a4d9b53817a +6f79223d321047059e1032c78b1b00a5 +fc6c4766cf7345528c5b1ad1ec58b12a +5e423a46382547079ee883d15f055ebc +c626625486104768a6cab5eb4ecf9cf3 +8b5262b452fd47708d3227610d0aaff0 +e51b432e19814a9f877f90d96d6347e3 +bfe676a782da45e19be08f49e1f2b9ae +3a1136e0f8c94763814f748421906fd2 +65bb2a14797947849da7160651d814f6 +4ad9b6a604754ddab28ad3021848efac +811d4d00678349f4a4f330502e87b218 +b19ef2650b4347348710eb6364ca90bd +d2152f81109d4d378b44defd61cff1f9 +37fd1b66b8884c1aa4fb0356048720f4 +0c79289f551d4eebb5512e9b941b4cae +b81e6c505db745aab15b93c2d2f0024a +5bea1379329140fba10cca0f4300d08b +297bc9310ed046708ee071f9f4e10ac0 +33a68c221d3f460cb1cb1f78b9fe0bb7 +e4b65ba340124ac1936ac9e689f9157e +39cd9a49f9f546438da0473e00ac6980 +620a912ae90c44339f49aa43e44178d4 +abedfdd937c24c7d83b0aaa5e9f11efe +9029486d05b243ce8e13688af7f2a6c5 +a94e6192075548b68af878e57db2ed38 +22aa8ea930ef4ac79b7bac03e1ae41ef +33bab2e3f5cc43d6a6863186b585f87f +4b1855527ecb48488e9e81049ae03fea +e07de74e5be5434da249eb0c7202039c +613fc896899349e4911ccce2f94e63ee +121310a3fb834e0791a35c95d5b5ec30 +80270537268f472fadf3b589245f40ff +aac6eec080db410a9200452719cb16e9 +69e6f605b24345fc8828f568b7b96124 +7f650d22e78941aa81d0a14a4c501180 +618129bf49864a35b0c4b3d61d4ee5b8 +55adaf6069c048bfb4f7b5f47c98384d +a7665e0f9f9c4b1fb3cccb14a5bbbba0 +94828a7f821c4790af789f67a3ac0520 +327a076dc0764243b0d7156be505ac58 +548be29c770a4b13b0e087a586d025f7 +4994c7dac1504b538ec8f30b453fed6d +25c29121183740059bdec15be94b3ac6 +7cbf4aa231594b7681ed6badb6905207 +d149e60429574bacab6815132824c59b +e6f2808109db4a1193cf8a8959d90d7c +6adbcc2ecb03458587d72dcbea6b5a51 +fa9f091f14124896aadb847091b0e48e +4de96f97ca814709a7664b1831a7c9c9 +7f84fa84c2064de496a68e2cab2acf51 +bcddb9a3683d40e4b33cf6b44f70400b +5369d70668b441eda59a5e1dba46ef1c +373fda1045994c07aa3a5e8b7a6d57b6 +f895bb31d5d244f6828608f438189993 +99a3a792278e423cb573036adf91cbba +240d85422edc47a09c695e2d7fbe2bd5 +f28f781755a84a4e83e56e36d06c624f +2bbfa4c7c546480fa1f7855aabaa10ad +d7af6fd7724d46b092d9c15c2ecb8849 +3724de1e56ba4f4bb0be2ca3170e39f2 +cd97e1e0d9e347afa9ee4f88fab19650 +cd46d738c59248ab87278bdd1e8f0175 +fb8ff119e9ee4ca0bba589ed6e7178fb +8e7e458f80434b87961d563143f2baf4 +8b7e0bc2035a49719c45e4ee01114527 +a78045c10ed845ddbb4e2d54da353ac3 +a7f3d93447934fb48b4224e132dd623e +18fa961d691245d48a3bc1454538bdff +08f1dfe418d2431bb1a6f48316208e88 +3f0dafeca37e479399f2d90011c1e35a +1183ab5f9fd945cfbaf6a9f4f53ddc3c +6170805a574d4dd68fc0680947d8ecec +11d6b28cc5504c95bce893f1cadc316c +8c12dafa63ab470a8c2196a66052a0df +9517a68f4973491b82cb7a445af93561 +b19b27b5bf0d498289c662177b465350 +ddfbadbed0db451c84185fa37c1d5e97 +889f4a84f24144c0b1808d4b59c04d82 +691d0e4cb6a1409ea72d960d0ab144ea +f6037ddde37646af93249b1d4b863f1c +fdc6b2fd40974708a07f1717a433e7c1 +b5d778728308459489ace2e98ae03e93 +345655b592e043e2a14a2c4cf8083512 +b8043a6925994d1daa3d29a2be22d5c0 +e3ee02557a7d43a59ac030f5292aa2d3 +bb051a4d57894cdc918ea09b6bdcaadd +867ab04528614d6581599e0e27684c52 +3b1c37c3deab4ecea7fe610afc277b13 +87c86eb31abd472083f7fe2d876d95e2 +4182dd9459994e22a883069bc41fea68 +79c0f5d111324264b4c6fea9402df88e +419396578e9f4165b38252ddec0b77c9 +a674d3398a9f4598994c14aa2aefe3c1 +0aef5e1b2ef446d7a5663674e75d45c8 +4c0f32f6c51c441dbfccb40d84738548 +3dadf081b021489c93278e1996451d08 +652c421271bf4a05a97ec80063f04919 +e2571167e3d846e59769b61913f1de64 +9cfda83306c14bbbb6526dd4cdef64c9 +d52590470d3d42649f4f421dd161820d +abb02be176d64b388475b6bead22649f +14fa34e16090452f88098c29e1ceca32 +d871bf2f8294452294a83c68a6a04576 +5ff8f865811a4bba88903b2995da1e13 +df12be70236a40c0b7be2f999813b894 +bad55ce1183a4965896446aa526c7ac2 +3aae6d64f58443d98a879d525b166f46 +5d1ea0ec43a14ec9a38e3a1572b1626c +d8dd9e3d38274fd38b1aa8f7586afeac +f2e66f07dac645f88a8464b790cfe751 +6931e14a96f64b158ac4cebcf7ae8763 +05874623f9c34a63984e011579b29394 +8ca3352bae634984aea6e7f12e7fa74a +6dcff056bc0f4d75abd0472f671ecb1d +8e85d1e8965d442fb7ea81eda1c37f25 +decb36039a19469ab01dd62fc24b1480 +8efdf2c4df22485a93cf14657111a1b1 +771ba35fc50c4d578f410f83f1e824e4 +18c13b987e144102b8ec68328f2f6115 +6fef8debf5f64a478b2fff6858d51201 +e987e80f79ff4e1c95a1ed79d85c012c +9eb5cd18c7254c2a89fc6a851fa89bda +1a8d612e3ab744f5b5593ff4576a63fb +6dcf6587c3234d47993dd79df008f4ac +2809ec55e0774a02b457030173debf3c +035940399e0f492ba614817a99243eb0 +b9031717c4254b24b7d0c42152dd77ff +12551977a2de417ba46852c9e559b0f5 +a331b3d7b0fe44b89cafd9f8821ee8a2 +c6af42f5c0d14575b8c254b253c9d620 +84182b0ee1124ecb9d546d893bc01cb7 +45049856d33745d59bdab6bdec53f923 +872d486d55c74c5786e030e4218aa530 +6235bdbf4734422a81786daea9aa393f +dc0d58d286ad4efca1b1d68c278c518f +0bc9914fc74a47f1a12e61ea45f1b5e0 +aa1c88c9217f47068a070fa815af4471 +24ecc294123d49cf8634d25bdf9b4e6d +476bdfe46cb04c069cc5a5589deaa0a8 +72972d93856f432983e56da4ddcd1be6 +e9bc8bd0f3f5489ca58babc65450235c +eaaa04d38d3d4db2b53ab35653659d2c +5bbdefa4234c4a6fab4e8de8b1ce6d30 +3005da6ad7be47cba014fc1e0e6e90ef +e27f4618d5fa4926bdce83ac79ce0c66 +ba0de8ab340c4c59842082d3f3fdf2d3 +e184a48c42914fb59ca92b093380ae11 +816405f909264b318e678999b2eef5d3 +b056db54ea6e4258bd3e97b8b5f158d8 +41b87aee97e0456b8275e5397ef6db37 +06b77ad6945c4f78907d12ffdbc9ccba +b2efbdb7322049ad808bf5b3ce327d09 +f1018bef8ced4fd282a8b94ccd2a91b2 +76e5c63c28ee46f8a08650d9540d1609 +c7ae24b23f48403c8d2bf12be1ceb1b4 +2c30322d4a7445809f4bd88a31da5c15 +458e54a470fb49aa8cc1887e50aefe6b +267c9e22bc4549ce9fc131305c08739c +e8db7c2f2d1147c1adf2c8fab5670ae0 +0ad1b883c76c4591b9a04b0b656eda20 +fa7f3bb3be7d4b19bbb49fd90f547d43 +5513e31ac13348dab310dde6911eba14 +5c93f6a79ee447c28ec421258612a254 +3598d4508c8c4568a35e2ed00e4cd193 +543c9a06fc8f47648f440b2c36b354d0 +660f033d3eac4025a7b71d3a829a5de8 +aa31c43caefb43658c6c8aa88e41a926 +e6c321d47483484d9828d8ce058cdae1 +bd80cf84a16e4f9c9eee13d373d29d8d +36c4b7b8daeb43e594164d109029266a +04bef8e589524b8c9d7a3bb206b206a8 +5fb8302331154d0b80e7aa9352a3b664 +70ff658259bf4e4eaf0023a01497afdb +3e9300d4e5da4e6ba09ad16a22fd4a29 +311f271153c64bd29486689b7d6f5116 +1de9441cb0744c0d8459ce957b8d0a57 +87e82aa304ce4571b69bdd5182549c72 +efd82d8cc4f54c6e82e3d21825c19dbd +c25171a3af184649a4ba2c30610ae9d0 +c6a9483d08a94ccfb2ba2b49abf97d07 +56fb5d352e964269b0263ab701dec0de +bd5708568d9042bf8b0e4893a416e92e +9544dc9d7f064c1c993f2cf17e858334 +d3e8264a68d544b2888528ee2ba2062d +a91492359e664c3f8010a041b2d05de8 +5b8a34ec3e9d4d15bf7d868ff576c9b0 +e0d4745c293b4f63ab1966dd23240941 +a888a151fc1b4272882a46a3d0de3abd +a7440e534ef6444895a6cc5feaf15a33 +60728cf9622947f89ab39e9bbf15fc20 +bd4d35196e5f4a9b838beb1325daf5a4 +b648a6a1c27c4c139acf12f47c5a2d66 +75fb17d3598048768893c96cedd0a5aa +6882c7b66d7f4d7f88f49841dcdfef22 +db69d2257ed74f0ea176572a2ed991a5 +5240e4eddba040818cc9de50df8e928b +fc9885213d394d08a4ba998d03fa300e +a0b900d9de78485bad2534a88e2c19c4 +a2a46facae184965af4e5dd138f4f9c4 +17c6a24dfab7436e927bffd1738b4081 +ba5949436eda404c8600aecc28905f86 +39c3ac74701b43b2af526437902bb98a +4c71b37b0d90450fa1ca0746b50b5ce6 +321c2770c5954931a491a619e40cb1b2 +392dcf37195e43948cfbffe099082108 +5e110448aa9241409988e364bd9ace63 +d4be9b208b1b4f238692875d83286a58 +ec1352ff44754308b602f3d75eb32acb +88563ad41f3049a6a48c7339a74d92d2 +4f70dc3b5dc649c48ffd3e43faf0efb0 +ea055e4fbffd4a60860a2a9482e98b49 +6836901c289f4e01a8bd49852669f0d5 +89ae431e8de64deeb6393b57aee01db3 +141202eed32747b7b1259a3efeba9c96 +16930ec31f5342a08e1233eaae01b2c9 +9a7f48758b8a4c9ea6060c58f72ad21d +ac7838c1b6b34a72a216b219efcf9926 +5b1925d5e4a144e4814acfe80bf6e9e7 +5c8f46b1ebc546028556d620026139e2 +27e5a88033364be7a4c08ec5343180b6 +a26a17d7213f4163b731efe224dc8ead +0849a8eb5c974781b94d05a35c5125ce +4598439406904c40922fa51740c72c52 +56139b42c28e490ab4b7509bdfb203af +8e8b342613f0477182ec8586876291cf +4010b64c855041eb9ce0b8989ec4a6b2 +752f4c1f4ea843bba5d29104f76d3f81 +9ba01096e47b4be7b0b244b8e5dc8651 +a10b2017cc9f4a08ba22b7346a8ba724 +352b331184104bc0a81e3f40857a5561 +75908be7a70c4cbf9d469a69e12acf80 +29ee91e1cb6f42db8cacfa713cc8da1d +85fe558b25b146988732dc6d64556141 +3875f2b773ce49ffaa936184b85b7f33 +3900f4cd73ed4dcd8d7ab20ce3aa2549 +ded99670d56f4ad099e88508faaa7aa3 +abcb70a7c51547429cbcb9c8930df941 +f8feadbe79a746559c43fcde1c80d4f5 +cc0e8ef824294538857f0dfe11d1f74b +094e79ef6fd844dd97f2389564b48bd0 +c2c9174c2ade465b80f82cb2d481a7b0 +bb7f8cd1ff07497494fe563e846b4c41 +f352ac67466b4b7c85f5c2fc69d52000 +2e9530070d5a42e58e2c923154adbacd +42b619c45e054c88a3b3940f0b6c5665 +ab8a2eb808d845c792b3487a7305ce2e +280687e9352e489b9ab980ca8e5a44d3 +2541db11c1c84adf9b3c371cd34dc287 +70416a5ece16478d8adf6f432277e0da +a3af48ddbd224bb1bfe7e5b96f7530ae +1af66c3c8fbb4a0884e2acedfe37d74a +a37e58a611d64f678834416bf2a4f107 +0b3293889e654904b2ec4313bf8d181d +9572ce7f1ea64768a968b600827e39b0 +f4bcc7b47a8a4285a1066a7ac8a3dd2a +1dec1597960e4f3cbbfa561dff2c04f8 +5c5a6601578346aa8ce974453909f175 +fd340792a4424819bbc3c27193e670e4 +cb4fafa835154a26af8967c289e61894 +311a344f517c4780a8a20e14520f1c52 +cc93110a684743e3853e20e94aedffd5 +1c1d34d73fd94e6b9e8f82b1eb7194a0 +df9eaa2fbdf8484e96111404bbe0c279 +0fb029e278b144c4b9a5d933e5f49167 +829d47b009ed4d42901a7fbc8a10aa24 +b77da5b9052e4ec1b0eae32d9e07beca +4ffc8ffb491f4db49308f4a730ae24a0 +84419b89ac4c45b1b2ac697dc6ecd974 +aed1aa465fe84ec5ab16d6cdad1ff78c +2decb1aa5c4948609e539cb357b63f78 +bee50cc724a640328020bf31be85e91d +3ade5f8d1f68479fa054acc7d627939d +fb712e616d724e03a7e034f1d5b5352b +3efcb43ee0de4232aef63b7411c8de95 +2f3d0b1bb4d8434483570201d5c67cae +2ff281fff571410598ba24d58425a83f +ff8451ebc4c7439da6427c355a0beb83 +7d2666198df94a12bd297d4e22f8d22e +f7461cfd7b01444d968eae27130a9d89 +d22040ba3c4a49629827d4c748443faf +6c816c2eb3ae42a38faab5cb1434658c +be18a2edd8c94f39b8a233f7d16f43ef +3ec4946f4ef3431cac30b4076830715d +2460380ef8e2433d97e2c1f69c3f16e4 +3fc3c4911f0d4b539b0530d0bea340af +55b7b356c25a4bfda49302313d6cea60 +a987896c6f8a43ee9e13830ba90c89c8 +90f63881bce341b287c1124433c3790e +ddf37a051ca14f479a5f11f938555692 +3fb4343374304f51ae190d2a3625a302 +304218dfe7494f7cba6d98271b46b0b5 +c120fc14873649e5b2436ec5e6172e79 +2e0879dd1c2449d29e60c3a06aa2e6a9 +3629a475d0294b8791ddabd881b5467f +e6ad659e1b8346799180a7be9bda5795 +13dbe30b0e45408c8bfaddfe6a4e8786 +7c47510edd2b45399cc5f675dafbb135 +51cde7b5f2b549e795f56883fa9da80b +82d8dba71b624d0cbcb62c0e7aaf001e +57faa0f08ed342f6a0d56464f06d1535 +8b92509204c04fe9ac5f71d216c1069e +a8c136c1ca6b44d18c5edda2b13f94ea +8deaddb9b5b645049df82172f3afa570 +8896c1ce46684229a662167dafb43618 +4a8fe5925e1f4c7089befdf00de3a768 +6f81bdd9e9434d24b614a628202733b7 +8ed3b61a67b741d798f6d842390e984e +6984d8d0f77b462ea908a4463c8f4c72 +6002e94b7b86410ebae4c6d614012c1f +275a7f052fbd4ad0b649f7162b1b8e30 +568135e44db84397b5881f336c90e493 +d61242df068e4bf69cb86b5794e58b1d +566ecb1412f44137ba6dd7a3c8f5a34e +211e925eaa5c49a2b9216d785413cc2a +7c7a9affeebe43e0b6f32729c3c8d0d9 +7dd1242005dc419ea9b05034a5f1fcb9 +dd5fc9e467da4e5aaa5b0cee001b6d94 +cb973ddaa1db485c824437d10aea2fb5 +5be739157f1b4f2d8eeb352ddce4481c +0f4be86441694633b42c764a4574fd41 +6e18298e1cd1493a974c1274e0030701 +84e9932dd0274af3a2ad91f779b58cf0 +86b1bc0763a747d181489a7c1e7bd89b +bab5e87d3da84efcaf8b62cbf2e4e730 +c13d7df71b4748df94470ff00aa67567 +919e4213a414421d804a3a9f19454479 +0d6f1b3b07174a169d518ad12f6e2c0b +c3c923711dd74bd58a4950456eefaa04 +2835e8497f6f4531a1825ae8fa7215a4 +d628850b03e44199b6936d190283765c +c26f933e1ebb4abe8467ea1a3ed47f85 +b0bba8e98d31421a86f82875d15e097e +cc2b9e63ef284a9cac2e3091b52a20fa +8bafbca3288c471f833ebb8071d55f24 +f6ef41903e27424a9e5fab584e8db7e7 +623505ff005947d79fc6417bc7b35264 +db8f248b9c6b4149ba1125f3174e90ac +5efb7a6940894b5a835b4de2f3cf1559 +b3d142f6d72b4f0788e841f229041e74 +c4469abf45a247e98632f17fd2a2ab07 +68ebf6492c9c45688661657bb6aeb320 +1ec9ef29c1604487a2f498df7e744c88 +f4ce57bc858940af9bbb3907231edf87 +1cc3d22c816f4216b309bdb8ab777741 +9a733f9a50564d0c9fe849fa0f933944 +07a45c5d00664738a5dabe6bd5b85928 +665ce053043047c48ada64329ec4bc11 +2a3709978a6b4c209569f97c997d4cb0 +a303605a16804886a292008b89884119 +6c441647b1874be4ab3c7d30533ca266 +e752a734ea7b40f78f2b9ee57a76e1a9 +d902bf0f85df4a2896b7fdfcc4997de5 +a0190c099edb4c378f0b3f8779ab3702 +9c617106f68f4e00862bce68531d36c2 +fb696194295c4bf7ace119c932434f1c +75b3fc82e74b49ac846f649487ccf409 +db5af30382ef40bb8622f65ea0beafc0 +ddf5b0d6b27d4df19c9a71570fcc32f7 +aead6bb3bab344eaab541c5ac52c657c +2ef0c41e12504884b9dd681c9be9ded9 +fa1f532e2a2b4c18a5d9cdc21159e26f +2227352d74d9471ebdd17e8e4cbab211 +af04261ebaf044a38879a1af439ea3c3 +dbc29ea919e24504b933a85d464a8f44 +85dd813ac17149deb7b80e7e79905423 +f9f5bde162454b5e8c3190e2a386b4ee +4863d1f6ec594d88a81e0bebef6ab379 +033e55f0466b4f8eb268afbbc264fb28 +4a6fd57d5244438090603cd9c55bfeb3 +26b8716a29474e75a9de1790c96d6404 +086642d0cbb247878004a7599be11350 +755aeb4bd2484d72935a5e435338a4b2 +9554eb0597ad4d0dad8a4caa90141329 +b5d9a25670bd4b06bf71be2f9841d392 +904e013d57e9403c9d2b69b072e54ff7 +a64c5648417a43d7968033602409bad8 +280c07a63da04facbb08e45308bfe4a4 +57e4c5c6250d47c48f59c031b52e1f07 +2fb4ce922d48466c9ae9cac570bbb41a +f74d7d05f12a4cd68fc2bf592be6842d +5fe985508f124c788694cf61803ec3dd +b8478cea51454555b90de0fe6ba7ba83 +110ba0ff4c8c414988c454749e52f3be +c3b30fc4e1c741ab936d8ab74f8b686b +ebe51811d90c4745b002014ce3d02096 +8afccf3a63944cf5995c678858762723 +436f908c0464454fae31a72c4012bf1c +580ae02e1dc44207bb8d412e520d674b +7db8c1b2b95e4f09b09917b7618b76a0 +5325402eeba44000a1bc9d34a9b043b2 +75ca0a0eccf2446aa2ae66b5645bf786 +0a7715ba11df454fb9a09b2f32d210a8 +7fa519370312408fa882e1fc8cc9c339 +8bca43dbd7ca4df9a17b8c84ae7ed3fe +d2b93d0306354ab1970dc1ad051405a2 +20f74d0ddc3b458ea4bc3bd05fb1cf43 +08d3d7cc1bbc4835973e54ced42902ca +e4d4f7e618b0466b86c5a23641028e33 +a5f57d3736584c44b221a181d558dc39 +36865d4cea3d470c892c649f9f8e625e +3e2aff5658f644d9a3289b27e755cf83 +f732a033baa9417e88996e814fb1a22e +3fc10df45a534661944db3dd7dfac9f5 +27827636f0a54440b7223f792bd8306b +868d9065879a4d1695ce10a6793113cd +886111253fe744dd86b8d1599aa535b3 +c08f39ce6a654ae4afcc925d7d11a6d3 +e53475f5c5ce4967aa956a9c7aaf86d2 +e96738ba83044e82a0f69963770481ef +9ec022e6f6bd4ac489e8853919358ef3 +0a1ee08e669843928c1f0caeb9971f85 +f15fb86d99564454a9e34d8bf8998885 +ffbb77d78c964bf18fa1babe8d2b9a90 +61902b403ea4449f95ad3777ccd76c9b +f45e1e17ce8a4ac9beb349705d67df4c +291588f79b3d497cb0587249f3af933d +be7c6a1ffa164952afabb8e0eeb0abce +1c0bac076c3c42d7b4a24d9b0bb1f54a +18f79eefe54c4ec0a2a57987a071611a +ac0d47d521fe449d8fc2532f38ebb679 +7a8dae0520a445049a9487b1950d838a +c27e4be8cd0e4146bf7c2884615cf5e3 +09ca07e8534d4cb2a25f074ca9bdabe9 +35eb45955e1d4557be9e31f04b446344 +47f6072b539f4292a9b7809e6fd5c8c6 +b7e94696cb9c441dbf2c5debac325d36 +2bfcba5222154f3e8ef42c7c1b5cbd6d +2f082f75277d4e2eafb53272cdc86ac4 +64a0b2c2e36c4aee94e10ad2a1af0f0f +f48fd6c63fa248ff93e200beb9ed5b12 +12308ae5dfcf421f800889498d99c2d4 +88d7eb34a2b44acb8894cbcdd8b92ce0 +6e69e33fff654cf896bf218e7c8325ac +12d12706037a42c888fefde0f7445580 +5a75d007bcb64ad29a326669d67a30dc +1ac9bf684da3476d918fd086d554bd5c +c754fc24504b4f769c386fd3f2dfb473 +9c61ab86b73740ed85d2d298be703a08 +a9f3c023a0fb4177bf798b65e47d1de8 +d0e330462ec44c79ae11ed74f2a1f025 +9f482d29fe1c4e4290334795a5ed38c0 +6bb1511500864030abde5c30630c5be9 +6b74e4c9570e45df973e73f8484c4cbb +ea6e507253f14d438528836856358b7a +5519c4c436c54946849d298f0dc13744 +f1d328dc5d49429e8b381ca3c38a25c4 +8a727f8beff5450d96a121749fb84231 +74984cf6e4fc4e9bbd52cd226bc0dd8c +5da54c127fa6453c80f3f1ffdeec1e45 +9ef388cd9cb947f48957a497e8b8184a +0025d57953fc4c8a80a44e59294e6841 +1653db41973e466ebd90f91d8dfdda29 +1fb892972d5041b2995f4ae940edd923 +be8452f1b9294a4c8d2bd72d4d0b04cb +b6d5e398382a4f72b22a898f071a194f +f5d3d6ee6d564038982c4ec2c76c4443 +f726fd6afd104ed18cb4bbeedbe7ff2e +b09bd813f93c41218d97691f31beaefe +35794214c74b4198ba11e9612b280863 +9be1e79ac96c448e9e016a93846591c6 +a23ae589a21e48688e39e065e8fa846b +93ad19db34bc49a0b7acc24e7a5a22fd +99cd3901e0f94cf7a621c89dfde9e86e +0915a9de42a040b39a570ad091021527 +d6341759e57945c58ed04c8a7fef092a +4ff4cf0cedd54b1aa63be8f376d9cb87 +19ccbeebbe91485ebaac67a0e352a703 +19df87a3e28747a185ad949cf6f32933 +b60b059e861b4a8599d3abe4422a0f24 +bbd98918bc6147d399e88e7baec8d324 +cc3f2e306e3c46ecb96bf47631bc76cd +3a131a461d01447d866c7ab119d1707b +129cac21a35949508b17c6549959b38d +6d496351c8bf485287da727c31fa8ae4 +18f3810848254462a820fcda25dd7713 +51a12aa048754aeb99f9ecdea2db2006 +9b898f0b2be344cfa07ba6b3a83708b4 +75b85ae9ac2a48a08cf8d55e0c311c83 +d361a461f05d4c5e8df00f6b8df9686c +8aa52ebaec02485dbad616338cebdf5a +33694952d4e54715a620ab4499d14cbb +828c8edf056d460faafa65870e8ffbf2 +2556bb64f1414de7afb8a299097ef279 +103b84e866904d69843f8cd3ed11bceb +3df896b20b69448686a6e5949f37d79e +e7471193f73a4bc0a26eacf144735b84 +fe40ed1bb88d47209e7577b06033a763 +cd21ed9a89ba497b992a92f17cf9345b +1943b9ee974640ca80172d49dd388723 +6ebc71dc1f3441059910b90c04d92541 +302a5d1194464b71b840e643b6abb0d8 +38b90a332242433f83c751116c556a02 +41dace169ab1483987e1c46bc07e4384 +f8f227f6a07e46d9bb312282c309bbf8 +3bab4f86771f4f5893c013353e96839f +673a0ce082ad42728f90f3649a6fc727 +264cb00bb0944ed887d7353a76624e2c +a0e077140dda4c4781159f5ac14f3e5a +bf122cd0854e422bb94704552c64810b +3de9bc73be624f47876d1a34b98813ab +15e51b665ab34dc19b7f96cef1ac1ac8 +79e0af6f7e93426ab5fbfd2a7f284e80 +ef7be8efe82947c29290a18ef94a8c35 +0b9b4d8173b04614bb9cb40ef2edd240 +2ffd3c11cacd42bf83a09cd2734c2209 +34b001f315fd4565b7299813ec059ef6 +87e42985816741a5b94c2a927264caf4 +0926265c0b7f4b66a3cde29f6df9ab34 +9e3175ee216a4f8882e536dd3cc80702 +4526b1cbaf8244539c190be6ace277ab +ca19b75bd5cf48b19b02ffd11d71f5dd +4ff86697ef694e948e8fc55971d4f704 +49ef953306874e7b9ebecb64093f09b6 +28103790207e4b1cbd67a900c4a2d0c0 +02bd26e1454448e7b58964bc2d702418 +895a8c87a5754ee1b9e1c6a6f064393c +688c0525bd564087a24e55a19b45e8d0 +222a5ea42903439aaaa344da26e7f9ec +bc52aa4d98744f999c1e1e5046addfe7 +83acfd7b5c6d45deac06467080112f3d +9caa1266f2df4ac7a379f5c2c304bfd0 +d596c9a34172459f84413dba6782512e +af525021a0bd4e489f7c886cf0f9c43f +5c0253ce98214d079413a13c1a2ecf36 +16fe88505c4644bd8501141ee1299578 +4625cec72a4d4664b130cc612af5b5d7 +3212b8b1fb254371888daa55f5a5724d +3cd23f8a38104a9fb1f676576773e75e +b93192a2c46b441e964d503b0c1f5204 +c583e05d523a4f4ebb12e93e281035a6 +e7b71462d0734fba998b06c1a33cbf95 +0e88f25b5cb1487786ccc2277629d16e +b3f86ea0972c4358a764225be1ef069f +1f81943ceb394e08992765d4b74039a2 +b802a7bf274c457a8f3fdc8b474b8c27 +3a7d66d3e1974438a679b9366c42ac81 +3977d242490741ee81a3bb0e2c794b91 +120e0255832145c2ac1752a621acd33d +e0a06c44e2f741d498bba083e07e9038 +e08fc7be68cb4069977ba85135fd7d98 +582b46a2e22a4154a3070cd3a272ee50 +285d88277adc42f6860e0d156e7e254e +4d6837029c354d74b51f32a9bdc8270a +bba822b058cb4bdea025510d2dbcb727 +e70078010e124ee89426dec56ed34886 +6c77dfc55d34470991f77ba78fc2bdf4 +4526172da4f34ef8bfb7483a468b504a +08ede3d2012c43f4900a72b29946d331 +f8a632aaa0fe488c9b197bf611624b47 +61b02d725b5c4f049cd1bdc0d7b9c8dd +d1263641f34344ad9d794f95f715e137 +d8f970bc64384f64b5846f3cb1344d40 +e802d8415bd04da8ab404d226e548a3f +f0e3c872f1984cf7a467645d9e0d3abd +792ce777806440aa846fa3c1ed77b352 +4613dae0903a4be894527ce441fef83a +64958f22e6e64a99b707241677753f46 +1cd4eeeb72ab449bb1c835b6bfa85360 +0849e24b30184cd78220783b8c185a8f +c6cce8ec55634a0390055d0526029f1b +76b48860863048d2b2b9a0a7c6a5655e +ba313d2ca6064986a7e7f59c58fd945f +0bd00d2ca0484adcaa4c9204b2dd01ef +b62e7675bbee49fd89327297b054fe6e +ba6f29fde2124ec4bb446714536ae5ba +7fc17c66a5eb462db209abce6527671e +54ca3a04e9c34511b9fe0313869ba0c4 +cd9ef47d964d4fcdb170718cddd521d5 +4ccbb5d870ea4189a5ce53291ddb7921 +7826fd32098346e6b4534bd20b8a3011 +b67c73427cd64754852f66c2bfab6c83 +8750b8098c6d421ca9f125e4685a0d64 +32ad2a78e2e14c1daa4ee8c4ee079fa0 +2db4e72ee66645f9bf87a4887f181f96 +35cc811e49fa4bc6b5bf66348441a84b +1df6a16b19754ac1ad40a8c6b690d9da +526bba8c0f264a59a28e9e152c2836b8 +3b28f114b60d4fd4b74931724666ae55 +d3a5f8daefe14149b9c6163ef9f42f23 +cad2ffa5d8a24423ab246ee0916a7f3e +7bc28b93cc364c97894215684b508313 +abcbf71d5a904a1d9abd21f6063e3bf9 +7f10ef845b594690bff6cc5dc21c3f99 +34a92d45ac344761a55b9fc69e0af333 +9a3484de337a4028b2d49140e9f1fdfb +b4c000f2e4cf49f2b89ab6e7ea2fea34 +cb6f558c4dce469a824fa54537a6753a +511753d447a542d590602f313b7c5b1f +4bb7b2ced116404d92eb1458721e8b47 +be5595aa7e0b4aac8d92f4af0aab66b6 +2f985ed18757481a9a73a233e73568f8 +17fef9881f9c4d5587dec6c06125562e +05cceb371c14447c86a0910703c18b15 +3ec809a3fea247e39bf054ebe676ecec +503fd41365d34beca9fa18264f7878c7 +bb6d66a3db1c46758ad31b6e12cc318a +963846a5496344559761c02f62998b03 +16185fb98c2340a8bd438fd6a94f43be +7a94425ceb6d488a91c835885843b77a +ba33bd49e6324da9829317357ef1e04c +6035b4865c8345fa9010a3332fac8faa +b15d7a05c8484f92b3a7859f536c0bcb +7d0e8812300e4ace826a8a2d9f107657 +4c11adab41894d68b8634eff0b011c4a +20d2cd4a0ec3455aa821aa2f76ddb521 +aedb5bc937364e2ca03d5d13ccd3158c +7ad3271d3edf4ddc93cc55afa9023461 +c2c5b668395a4e7b8ff67ad715e13084 +9a0c401dbc2743eb9a2b5ad5598e92e1 +0312bd8f47044ca790231904e9868329 +08b10e0176bb48fbb319616a496ce937 +684f1c02ed6c4c3aa8571d8d2addc737 +721cbb48ab1d481282416a3970be80fb +c659eb6b84b548ab8b90f5fef0d278fd +c898f64e3bea49e8910342d0406aaecf +3758db264c354e48aa076bce6c6c83f6 +dedac6c955a54251a25b87407e8bb2c6 +3f49d205292a4f33af0e9398d7fc72e9 +e7c2ddf2c5a0415a86b6079b91e5d225 +bf9db78e27e34ab9b029b489c024a5e0 +5f58daf8fd66450f97d21d8da6865413 +74c95870e2a141a9903815715d25b8a7 +05771efdd06144b89c7bfe1ff321656b +89853a54227a45da8f4cc067772753cd +11264170c99240678d47b47c769f2854 +6f3f880ed56743f9984189a79720daf4 +3199609e0be8459992743a0a631aa5da +b58983feb216409290fcd53c6c0651fa +f9cbfb4316ab49d1a355969e0f4c09eb +685ae71072744c459e74d9e7a17766a0 +9e37ff6c22094e91a81e9e3be1e32b80 +2c53c77476bb4e1db81644784853e74f +acca44bccd9e4d82ba0e2ed0eb1e478c +d45c39547a9846a9a54840faee0f8990 +c3a2ec0b2dc2432581093e4948d36160 +f3487c10d13546c29a369188eec6f0ee +99e25f692d9e4237a76d994704c98b1a +8cdb37c9edaf443295edf4061c679ec8 +e7b99e157e3a4a33a7d054a4542544f7 +59de57c4d77a4e89b407db11dc8d3a5d +cc9bface960c4e7c8c0f14245f985eb9 +c138ed1e11c14a919c6910045eb947b4 +94022acc1ab042e095008a200aca9518 +8e2a4923a1064dd5abf1fd93e4878910 +5eea9c1d0bbc4e80822245c79fd70938 +17353b094e7c4072b6f6544294cd194d +e8a9b72425e148e48364bc0d3d05da13 +a4ef6127b6dc450ab927227b891ca23f +f550f917394449578f5930a46512f169 +fb83e05ce81940cfb07e650a0560f1a3 +53dd2968b6c44c8abc925907b6a10d3b +d76fe6df084749e385f688c477f9f661 +cfee8afd67c94b2ba72842e8939a8a6d +933fdfca5aa749d19b0750dc08bb0592 +fd841e1452ba4eb199dde5601eb2e4c5 +64075b3d72844ef3983305b92aac6642 +1ba1c6aabda2468b89e743386cfe5b51 +45e3b8b81f0444c68fd4bcb23ba9251e +5afaf3ae0c6d496e94f9ba733e0042a7 +151650b9e5d54f0c931ab85147155eed +fc168347158e4303a19326a5299d7b6c +326f5b9fc6ac42b78bb6c5ab0da8873a +a441874cf347496db7005aaa3960f601 +0045e87262664927a3298f2ed0f640c1 +3aa30a9e0f774905a69475f8a054fb8f +1d212c374aa04377869a622d28b9a9e8 +66a185f373c944a68dc09ee3ff19ab0f +4156ba0320ab4510b7416b7b019f0ba9 +43a5984cf83647339260ec392c4a426a +2e67af60601b4673ab6323574e26838a +42ebbc013fae4437a68133f0811f94e4 +983f87ae52a64cfc9d4c914c2874e911 +14f90291f09148bda96fbbdd502cd79f +b90b65af758d4c159cb9f37fee9c0f14 +cd5fb1b98322454893c01497c5599e4a +aa02865509d549188c675d389b97e2a3 +943a03495cca424694aea9767fcf3f83 +e1fb91a9a91b4a7da1d2d3363dd6f89d +4d9107d7c30c42a3868dedd6e71c8005 +696c10ef1f5b43318c129318c9940561 +03cc1e92bbdc4d448701ac8979a6a4f6 +7bf2f8cc2bc54dfc9809c2245b5c775c +b7a91603be1b466b8c28a16956a264ba +e4e126f3e81245a9857ae49a6bf6de40 +251ecbd0d371435f985b705df00f5ecf +2709f6ce4e6249798d1502d7b22c61c3 +b3a363cb44f247dfb5c361ebb8a23d41 +5f242df8588f4e1aaa97cf6b48d1471a +97b7227921014b3098f051ae139cdc97 +296b31ccc3e241ffb0c9d3e2a4d6c037 +3458799ca8ed4a029a33bfaa8b458bde +1f577fff540c449f85cb29d91bf18d07 +46d80876968241f4814598a71b3dfd93 +67698d67326f4e57a96bace4d57e3f0b +10397d6321084a57a0a65e8faf273c19 +d01a6b0749534f149adc00a0d18a00af +2a542407ee1e4c9d94d466777082c89a +14fa7c1f2c694e5b93622403c2f38ddb +698909fb744b4ed6b708b36606cb7e98 +7b2a1cb30af34cf6ba689196afe9e2a1 +c67b706246d64d64ac6671f94e875d7f +97e05835987345d796e9db3d486831ef +49e709497f14462dafc21c18ffdc4727 +c9aeabca5050495eba4b5cdc08768d8d +e54cb84dc88144f1ba40c69c4cc6a5a8 +c1f0c96d628e47deafaf75848eb41048 +3ab26bbc62644e7ab6a08bd6ec78e5c6 +bac03ae66a6344cea37f5a661838939f +5dd49a59d3e146f8aabaceb76d3ba206 +250f64b994f548d58a4654399c3fa0f0 +6582e7b59c864701a3e2489b83250b2c +332f01ea98564ac083369bd6ef0934b8 +d09143c8b9894cecb8b934db411d5e14 +1da67f8cf6c8438b989dd5e62289a52a +dd31d22f0fd3407c8b96df0a5af19894 +619816bfba1742e3a6d078e14a01ba1b +e83968579ab84a4787a508a855cf5e27 +2e18c6e3cba04a01a42dde6e26da833d +eb5cb664d78b49fc8c99a1a617c185c3 +5df38e1b440d402b910fc5a986108ac9 +de2e40e2e05d4146b37154d821772c9a +69212c51833149d3bff82f8e72fe5d64 +e5abc2ece9ae4a80a047e7a7c5173a0c +2921c886bec54b62b43e13b022825d1f +277ed1fe673741f5b5bb3c9ebcc2476c +8d8bd092c4294c55ac726666306365d3 +2a0a78e6c910418e86b81bee9b3d12d5 +c257043bc3c44a77a381a924dbe43e5a +790b86c8946b43bfa93e626f7fd0f886 +90b91dcc9ef14a3886d8c7db49183fd9 +1c088324b71e4ede9b18f77be0880b83 +af0ef2bfddb54c37b7c3e6a6967ac05c +b3257907af8248ab99cd27ff8c6a86d1 +a886da137e7246d892f38189507e83ef +07f8d7482f1e44149acf81c8fbbfdc0d +f5e6adc41875410298181a9a50296deb +d4bee845c7a443adbdc7dee04f63a423 +ae8a3a50203f4dcdbcd4c56bdafc653c +57ded204d780415bbdae8dd4ad5bcbcd +4db46afedfbf450c9a19b04ffe279c3d +777b929d33a2456091e8ebe9c7d0deae +7f5c98f90a5f4328a4c1769c4ef2b8f3 +14b8ae60eae240ff8bf1abdf9af5e49c +43c8c807b35d46978658c564d876b0a2 +f26d1358631643e09f89c3c857ded45c +829e02fb7fd94dc2a65866dfdcf60c27 +b2a7b641512e492c94f8afd91dda6f32 +f77f7f7c14854173a60544dee5f7de0f +9394a7ec736b44cda5642813977ebed0 +8503ebe843d6428183a340652e5c03b1 +8c7f2110e5e240e08ace774094b0d843 +df32141a7c66437e8d7923c7cf0758a9 +00439fe1c7c24522bf408af0b2c155a9 +d76980fa818240178aa8aa082fc4ce6a +7a9135c0802f4be5b1385d5371309dda +504248ed68e3480a807aced6f002b2d5 +7a383f39b2ba46129284ccdad3c1c05a +ae88caa7c5ef4b689a881eb5fc23e759 +52badc3e6a8d40759d8f80efc5014509 +709e7fcc150c4843ac7bfc15d61f75bb +5b667e6797ba406a83d9440fb58468e1 +705933739e2a414084beeb01671ff7e1 +ca121fb9b7454fc18769d0d7b6e1781e +89db2baa84964584b8ec5dc760ca2d39 +c947c99867af42b2b666c92d97ed3151 +f96a4fb0b5f44219afe401c72ac4d6dd +abbc90bbd5474f73b16482ccd10e07ec +b55eebabfa19475e83adac5839892391 +ae83bed96e414beea7abb0e823d60616 +222a64990c7347778377f8a065e342b7 +aa39dc5c45904e179a8c8f849f2c9cc1 +5ca9d35f5a7544fc8cd6a1569420c322 +f759fa4b1bc0471db87f4a280daff759 +e0fed5c2a4494911b91105d8f9b8d477 +6dbe6b4be83648138957181916fd12ef +7c55eceb98564b78a0d24d9208c9ca71 +a424d9d80c264bbf98b403440f6c6031 +b7feadba78234e2d9c931d8181f47d11 +7531ebcd840948e19686fcaaf17167cc +5cf17083bf0a4baa978e20a7e8197a0c +e0d993974f054f0a838d43323de8140b +1e88c90205f244f2af50e42079062006 +76ce77a8c0a446dfab0459d390839f70 +dc3f65d227f74bb5ba34168a607eca66 +4fd347fd9f3e481186a7f167faa80ea8 +e79bd24a88244433ab4d2997bdb69207 +255373dfda964d14b988ca00e5d995d4 +b44f6fcc503d47e39d572d9c93564864 +da8e2322f9e24659bd8236bcf6bea05c +817c6e54217f4277b6711fd5b217a609 +f07e839957784ea390d512eab6fb61a8 +62aeeb7d51ae470c909c3b7fbdcdefb7 +7ac01f6a83b4439baa4a83905add294c +c48f7003cead466298150e09b83684f4 +dd4794ed162a4fcbaca147beeccc9c96 +ca1530604bd54b88ae50d31626cbb0cf +ee5f0ce47dcc4cdc9126db3b28ae49e7 +077f95c0c1b64e4fb9f02950ab098b56 +b0971a91ff204b6fa8d1ddc5725f2f54 +1e2f1be6900643308b16046bf930e3a2 +f8a2ddb686bc47bdb7395f63bbb5d428 +2f23dc3f378a4ba3a19dfa5cf955d3eb +f626dbe609b54078aca0bf676047f30a +c22a351375084f79a47ecec4b3d78ba7 +93b6eb454fc54f2184b252d147cb2323 +34770c6436114377924bbc5bff50966e +30937c9a9a54454d8390b050122b14c5 +f67a55fd106d49508e556fbb190ee8bf +728d645702484493924e368b11dbc914 +2c1f8ffd2fc240eeb495d4e4f1274792 +fc042d9a11b44df0af7ff4acff9a8ff7 +446fa63c29b44fa994f6b1a8fccd6e43 +6829f6df49124a50ace106d4cb754064 +00fa1623636640d7a21e5a465de4e496 +d8c6ce395b3d4e95af8957dcf084f368 +2f34c0d825e84b289880b21754b9ce36 +92af54ca2fc54f65bde19954bbfdb3dc +8516625900ea4d24b252e110cd7a6b38 +b4cbb014e9b8468d905f20b8e5fa2410 +01f74014d40f436e91fbf60e7f688057 +fb17547e91ed4e809b99dc0467985978 +b080707a31e648bd84409b98dd79be4f +9dd44cda400c48a083ffd9480067f04f +0e58276af3bd424a9b276e310d8fbabd +3f6b4ca2af34466a81d286c0bc84c4cc +ec0d3819a2644c27a538a2e1c2b38fcc +60de5641decb4d3bb80e3039e54c9626 +d3c01db2df584a95912a2e4f9d49d128 +ed90666cde13404fb8a964749c38106c +b4d7286e81654c00859459cbaffaee0c +e316400192784e0b8b80b3f5eaa1d532 +7b6d6f3e6bb34ef0a10c950f859d23f9 +46cc929cd9e443fea6b1dbcc54cf8e5e +35855e388a504b9882272a30857e60c9 +f2f0c7df12d94f4c8fbb758b1635cd35 +8126807d282947d496a7090bcef5dd55 +7aace2daa03b42a996e775a594890ff3 +beb71125f5a54b8f835c4d0fc7eb5057 +e62460403b514c348fdcae1a8628e886 +9d87fccee66d4e539e73acb700777b81 +b99dceb76d4e4da79d143084660442c7 +4763cadb193a4018bf3381c2f21ba396 +debe06917deb4ecea4ee331486d020b0 +1f06ed1e3ea6420fa2032a87f4cb30ee +6194af6cc47e419185d16445b76d7d46 +629d1327fd5f4a41a4a47b266e6c22c2 +a2a6fa541b4b4073ae823caea04f9df9 +a9596681996b4b0fa316565dc0658202 +5996e7a42fb14ca99715906e19fc511b +25f9a07662ac481d986ca1c8211f00b7 +ad6fbf4844504b4f8321a990fcc4d3bf +a51262faf0084b0b9c302d6cf1a95076 +cb3780dd61e34811b805ad31af1b2446 +97b48a17579740f3bc7bcc826752b061 +9057e49289d742eb9663edea9aadf3e8 +e213da3b642640b2bc34a9ff8ae318e2 +c83dc4dc30ac4116a454ba396edf6803 +672bf82f5d6843988b8dffbc4d2239cd +9bf7b9465aae4c61a2ab3ce07d0c3636 +9b71ad5fa8ec4ec3a7d0dbce24dadd0f +f8d2af8d4b2848c4bb1db77920197110 +9979bf07e68544609cca853e2ddf9b04 +a420e9196b744919806ae532b3a11bf7 +ef4bc2b9b457445188f619a7befedfcc +602ee7bcc9e34404875f6c5635c45f16 +828b1f60a6ec454faf8d42419413784e +dc8185e4e21747fb8b394e40d3ec125a +7a60e92f29694ed9b43d591788c9d0fa +ee4d318b807047bd993f8ff2f4da7b3e +5ddb1a9827464f1b89596d59a0eaa5f3 +6dd0eafabe514df0885ae54b1cea0187 +e58a74ebfd00476495342ad08c2aaa32 +29d81fba51324ac4b858cbe6f1777a56 +fa3e9c175c244bedb457582f08cf8e31 +3f6b7b02847e49d0892426b5d0abf317 +329ca55506c74283ac7f6bc9dc5e1015 +6eb0b6ef28e94f5bad9e4ac795c1d85d +99fec76bfc96443984da060499d30809 +8a22e6c7237044da9494812643897ff8 +a5083e2fe9ac4685a129df3eefbfde1d +0e44906698d74142a58cd90addbba927 +8cd40f962f2c440c9caf1db1a505357f +f12954f8c7b5479b8a851414f93ee62f +e8d39d9338c84c9c90be27003e0a4f9e +b38ae5ab27c743968d6575e4ec2c0515 +3bacb022e4464205ad227688d84ec5f8 +dcc258fbf97141b88b9b3f0e91b9a61f +818c64745413452296d03d32bd240962 +2fd452ea6803428d9fa1dfae6c53149d +b8286ef1272f410785a01d00ce765ed1 +6cc652b7d1d6494885fa26d15f4c093a +9d3cb105a87a4cb4b79c5cfc093bd5fe +e64a2023de594ae38f9a4e79eb18074b +080bc55e978a43f6b969614c02335811 +ccc7eb2d3337475c9975ec337cf30c63 +5ba4724327a1410e9d793e9bab34e1d7 +d0e4d02eef76412d9583ba383539130c +6c6279ff246e4d3fb46d609fb3faaaa1 +03434e4224eb48f1aba7fefb900acbd3 +716ce97771cb45a1aeda9ce9adf0a30e +75f07e6cf79c4134b4db95676d62d432 +2b4ed6a6259141ada645905678c746f8 +2d3b5a9ad85244f8a9e861d0305d9a60 +b007d9429d8b42d1a5a1c102ca996abe +0b7b4f4ee4ed4031814d62c526ab23a8 +a32716b79ef9466e8eb51746573c520a +96985644dbce4045b0fc8636a9874bde +9e4ab3769d7248fe8aa7594f4f7c0a5c +6b5629bc0d954e10a068d1a0c87fe795 +aa9a7f23471a4bb6b461d5240c2bf1a7 +291c896c7b524ded94208f70927d5ead +b37a3d92d35445f3a8dba72a0b7c708a +42e02b8cb8884ce09380943e8dd90372 +b8e612ccdb634e6388eeaf87ffbd46b3 +4cb98914614140529e3c08721df539d1 +46f6b1cd2d7846a7b9a26b6e4f12e38d +04b13a5595fc467c8e693ccefb18de34 +ce195c7adddb44d2bf963c526756362a +64d111cec3d842f09cbb8c68b1e49c8d +c7fe6a75ca2e4978b5eeb9ea7cd3f135 +526463de7cc4491c8bc3cd158811ab4e +1af024a1f0f94d1d855abe03fbef7125 +89cc806b25e347da9723b27177bacdf6 +ba4d2e49f78b46a2b63f043c01ca0254 +8cfa2353cb0f408cb1ec7badc455c193 +90c9c4191de04730a38f3d1cb44cb92f +892969a88e71495d9e869f96c95f0abf +dcae42c1802b46d28d768c6c156257d1 +366878b31b014e00ac598757a6499891 +f96dc8d2cd3d45e0a4d8e2c3767abed1 +ea80f20b0d074343802315c58980b594 +ac1be06d215d4428abec190f08156ef5 +4183c8164e7c4336a44899feb51aaeaa +d8a0fb1dc6d04c81aa1cccd1eae9cc06 +dfb3cdf1690a4c5a895b3243cd395107 +81d0a52aecd94f748ea7f7afb10e5711 +a55e471989d644d3aaba92e117b3fc14 +6330b75480b1471c8cc5f9a5ad59da03 +07c12f2505864ea68f001e36baf67224 +34f6ff7861c84e938b2e961b0f3e25dc +6add0a1fa81942acbb24504b130661c1 +d458595ebf0f4234a854681006791d2a +607c8859f08d4893aa6935eca3dd2236 +18737b58f6c34a39b4d8875afaf0b5bf +c3e75d0f0f9f4b5ea232a03cbc35c242 +4e719b26038f4011a59f4b901c10596f +574dd97c6aba4ec2a6829c0ff5bd24e7 +d9ed588e40a74777a9c81df3d93dfdae +9ad6bc278e224ff8b652a7a2be644019 +0b9c794a76f641f9a0338d1fab12af78 +a6104fabe1f8458dbae8ec348ae9432e +09095656ad6243c08d4efdf20e43de8d +729389d106544f388bd92378843ecf00 +540c7ce584814112bae1be4a2355328c +82e16f7b20604481b0c805e4b74b42af +b565a618eb5c45c3bebde69870d207b4 +799bca85c99042bda1b992819ccca7f9 +a5e61e7333034e1ea2b5b9def7ec8dac +a1d620701bbb4569886b7adf960e9534 +0567ae8c25954f43b03fc5b5264c3fcf +4207d085ed204778b8814e459fbcdaf6 +dbd6e256d4204ac3b78cbc1e16269198 +3692aa6a2c1b4b53991e6cdbef731351 +e7da84be9a474e67988ddc9127faff72 +4d8a09de354c43f29ddcbd64a1e23001 +4e8ce1e067b6426494cf724dbe4e0f71 +624b59b96c7f48a4b186704655e0fcbb +16e10a6f3e804231bfb3f1f3ec250171 +7c0e528403bb443f98759460b8f972bd +29049cd6560040f6afe23b6c4b89da59 +156f342bc2fb43988954a35b932f01bc +499db4b47e5f40308ad8d071a9630d1a +dd7183e276b3406c930e18e79a7b8c6c +217a445ce2ca4ccba61aee563f1713d1 +498f16743d0c4127abad3b933f011ecf +7d83cd5458f04930b6b962645079b4fc +3711e52c0f3d41b18123326eee6e2661 +96b3161ee04e4bb1854aece80aaf6598 +f43a41ce46fc4f4da95070cb765fa876 +1bf9bc9c320e49ab8a6a50fe4c03c933 +5501e17b8677457fb77bf232074c6244 +cbb8e7af40c44b3fa7937d84faf56999 +50c9a0c6d1a648a6896d3efdf07f0c4a +cef43d0b4ee54de191d8d6d1c607c3b4 +9589ccefe735448f924ddbfef36e1d65 +a94604849bb14ffcadcf8a9f7d1d6300 +3dc9f840d2d648118551670bb9a5f0cc +218112819f234c348ae754ba64d24917 +fa0021e12f9f4ec1971345c7c9434685 +0dd620043178479db6752ab103b1e04e +d0ac32d6475f46469df63df93b1c4e23 +f25e5865ff8746879c61c4b8158259f9 +7b30bdb2ea7a42a7af31ee9122d75f60 +1d06ba8ef476420094ec09e818bbebb7 +a88707201bc3489da43d2a0fb934308d +9ad720ea35384bbf9c9d6227565a92da +383b2df5c9c34c4dbc9abe055d9fe72f +d4bb619384164354969b6c1a381e7099 +7d7194c2eca748929da17d8ccdbfa6b5 +5bab6eaee5db47b79e0bddbfe50eb0db +668e312f5e77442187871ccee75da012 +b9b8b6aebfd146b8a11f840b2f8d0cca +92db5e13fa0c4c27a2689b962fc6305f +1260b644e6ad4af6844feb2fabc9304a +e8f919fbff4f4b8ebb4384cfbc66d4f9 +881b5895519047bea595b8731e5a0d52 +c65e566bf1004f5385770a4f28eec736 +79d45f283a6b45d792a10def38946a42 +ead44eadeffc4f108537517e9ba34845 +a4eee04528ac4e39850c73c9b788544f +d88dffc380904f1295728efa4499bcd4 +b0c2423e8c5f41a586193b1e25ad7610 +c5d986c0b14146f99119fcaf5b0baf06 +054458467ab8477a99400979e826a560 +7133823ee1c5439ca6e0ad35f0670d9e +1e439d130092410a9abb5c9822b39881 +5bf9d253e6b44b9c91a43f27238d2df0 +5800b532c1fe444f92f9d53172b72c28 +304f656a07d741caabdf36d58b9eb471 +a1c92a301628450dbdb04f6ce63017d7 +a4677757bdb6481f9bddeeb8eff95341 +004fb4d72f6c4e55a15b9025a868d1a3 +892ac0e281324005a32ad87adf78fc2d +a17054d5f5e24c129a81d72e48e3fd65 +da436f5030ed493a863900b5f157b3b4 +6ab495b21890493b9390c0b1f915713e +70cc94064c53499f8c793ffc221b0165 +e122ddf1829c4c1f958f38f70835bb86 +bac934617b4c4410a4701dd501177793 +ff34009732a34f2ea816435188c92a0d +b14de644bde5452dbc73e0d82995495a +cd33432aa12e40a28a7058fb289c8a7f +17c4643dddc14797ba3ef6fe6770e4db +dccc1ca16740471d84180d670db594b0 +69ce877c820448528a02800c8e7933a5 +23feb380870c443cac18afc6e26ef074 +1f4e5ea82d9e4e8bb6f4262f0355c7c9 +c07e8eb8f6c043e19b329fb74557bf2e +f1b5a0d9e3674c55bc04c9ae395eefa7 +f83afceed8d1483fbe86efcef9265488 +9cc9eb3c6e16440d95f2df2e84112b53 +0bddad71f2b8402887aab34dd9c226d7 +63952197ebd64211aff7d82d949c760a +2c54d1c79d27428aaea4d0909cae0635 +7f0e7e46c53146fa9d39ea8d1e80aa79 +14f5b8ed45da4450b5c3f606a59e64bd +e85310002a594da0a459a37589b346f6 +68b6f49d0e594e0ab01243f337bafea1 +da28757a8fac483aa4aa1205e96ea0cb +0c72802aa7234741a3b8ff6b6c7ec20e +aa2996808fc24e4eb19c449bf1655c85 +e68622d45dbc49148ecf492c541b3d76 +b32cfba9c01d436f8eb3083ba248c186 +022f2092ded7436ca793f1948d7db12f +0748fb88502146788ab627e35401c13e +03715d7247d1407c87d84485573983bd +92e3a69454e645229f0b1c374984fc00 +4e039f56282e4eaba43c607dcd83e9c2 +c34f1b3974d54933ae4461055b4ed594 +56e04a2391d943a38a492eb3300bd6e1 +74723877ee174c05b8dbacf902ca6cdb +b18150226582443aa0cfeeae531f3503 +7f18c636d8ab4f62ba880f03ecc9755e +67be9e77389c4ff99d5ed30e1b6b363c +b4bff18066bf460d9ab16b6d790d03d1 +eaf63782d5574515a89cc138e1d40cf8 +4c37518849f7447792dfd272ec7ec340 +193db2575fce4ff9a861e56e6a76dc39 +0afbd92ceee74327b2613284f6dcfaa7 +7e5f044ed9e24048b12601f8ba9accb3 +2db0a9e1d2ec4a15bf33ef9a11b12168 +f1de76cbacce4583a7268c7f1b39c6ef +46452458db2147c09c8e4a6aaf8b3614 +808aaeb2ccbb4ac29c356890bae9f892 +96c8538782f94a468bb58b0ce0a42f8b +ea33d1d2147740db8f28799438b3298a +6f5480698a7a43c7a8c0a8b1e295e4a0 +f9ec1e8cce62458db5c89c6d1825a307 +df5a99d6427844419d4dc86dfc036f05 +95cfff9846e14531a7de6ef4764c4c2f +2d58313d0a964d04a7724040dad750ce +992750b0df674378989fa915b0688ce1 +9863ce9aa4c449758a304a92dbb03d6f +c8149928cb804b63a8cd39c5a5525c7c +884ceeefc40649388547665ed5f24c4d +933c5e1acafd4b73990ea4c0eed831b9 +10d4ecc6b3f3427a9041087314b17ed5 +6b247c088f034d09908d4ee78c39dd18 +f23a6d27f3c04c84aedc2ce7f17e64a5 +97146b26ef7a4666b1f0e96e771eaa81 +da5c1c6eef7849b3be5f858279164019 +51bef98fad83423fb47b9f1b85a0dd28 +e3c719662981472f8479031a074bc727 +1d717faae4024e0da81794f25bce68a6 +3bc4be75e7634ce0bc8e07b50e2bc369 +3ae93c78f8214d61910564cc7fbbce29 +4bf1ba29222b4e9dbc3ec0e2535c6a1e +b926906c98f9488caa679acf970e7238 +f728858a202240588c6c2d14184f6188 +e38b0fd0db924e948160d611ce5cd93c +28445fc5177d4c1298c2efdac3458dc1 +1f79692c6d404751a47480a0009d8b73 +a7f60ca3dc264eee9c3206d8c7b038fb +e22390f629bc45839416cddb7d56d00b +baea42ea9fa748a48774cd43133a7986 +f709c5f235424631a6f90bc7f31b8e6d +9129e7dd1a864b1c9134c4224971335f +7f74cf149f434c378816bbc17084323e +3ef73be9f51d441c94fcde09e8e654d7 +f8b65fdd446742f6ba13038e5d9bae32 +a0ae41c430ac4f1190fff89a3c565b4a +670b4ec3660844879b796afb74783112 +7437ba359a5d4eff8dceadbc1919f976 +62e99b3760e84e4193857f0d7c1bafdb +023233c2dea547c7b84c05ebe437d64a +a9b48fd95d274cafb0a08896709ebce6 +ee0229f75b72438c9a858afe4f47ec8b +c0b8ff38acb14439ac2516b2b08dbd59 +64fdc917a7934b07a1ac3287e9ade405 +d7918fab9b774f10b9fbeffdfaf27616 +e419e37818a5446a8f05f4d21cbce7d5 +c4b168bff6de4327968daa2283846044 +6fac63bf15bb409b8d4340544bb1b9df +5cc824a22935448bbf1c9f5d13249a7f +0f90e7ca30284e83904f8c11826efdd9 +379a041a45d646cc94419609eefd2ab5 +b4d50597ef97453fbae92d276ba2de4a +f7338f63211b436c930f695dcecf0183 +8be64e99663246e0825ab1ead146968e +b8bbe412180248588180e94a0d675b63 +283e03dfc7cb4e48b9e0d7c3664052e0 +dcc4336464ff4325bd78a4bfa6b9fe98 +b171d86f932a4ce19396d64066fa3424 +c6d73780679d4b19b67086382152a533 +642f7070f855479d88406de3e518d049 +bc84b66e1c1f457e83b82a3f36e934ab +ffe84f53388043ba8d4eb211457ca432 +c2d2c347864d4663a220b2b21296a327 +29a9f10274f04aedb1d5103a08ad011a +2568b63db4c9410a863efe11467e6851 +03c16e1367cd438c90c884115b208e16 +236ccf2dae264fc3a11cd5be5bc4e280 +5fab6b3b052f4a7992bbd38e14fc31dd +bd09405bd03549238f69b34d43340d13 +7a7a2e31fab74525b32d4e42c4cb59db +201fb18d8cdf49039c8f06f958b22e7b +d2244b45ac76440f8391565a126af65d +2cbdc76448e44f1d9b20e44ba524c270 +7dafd5ae1cca4dc7bd75aad65fb4f5b2 +35b8b3d0cc354a31806c4aafea11876c +ce4e5766b3724944a83088b55b19b1ec +ec5d27a5618e47fc8f2b0c48bd26a690 +51ddddd189c245169be5994226d9cfd5 +2e5b2435af10441aab8ce9a3a1607c7f +dbef08259e8040bfb74d827a04f1abba +6e0f63f57fc844019e7a05542ee4a1d9 +940c5278bbb44e8f9725c0228556e493 +9531cdb48b8e4f728fb88eb24e17e027 +3945337ae7364c53b8df6dfed59ce26d +8cc35c739c834b27b72d4761578dca3e +65e9105d24314887bf8dafb06d3401d0 +f59d64661ad2466eab2e588d61750767 +a4d4ef2f17c843828cf24d538a9edbd3 +f68569fec6704c73b05e7e5eb472f638 +133235b6713b4f288ad6ddae63a3d460 +31f2bca19efb4a4da5c528776fd9e376 +29ed8275e7c24d158faf7c751baaa9c0 +3dc1d573c3fc42ecb53dc533d844b460 +d05cc75aabd6450994fab229d59c9fb1 +cbbb9ae9490449c0ba3c78f8525a2e0f +fa572293646b4bcbb1283fa401decffd +531a84899eb44401a1ff5d8f735aa6ad +b3ff2dc7dbfa416ebd6d7c6382cc21d3 +3eded8e48f7f43759cf15b888f96c1a6 +dc02f9c1fd01432fadd6e7d15851dc37 +585855de381a44ba9860c3d3887b2f8b +a52438c668a8440788325236059a1f4d +0bf75a6aaa9c42b1bb565cb12679cc6d +f723c6203a564ed28ee1f186681485fb +209c56eb6c36418abafafca259a8b818 +0cc5ab2e6c194b31b5ce5953fb1a1347 +0597ccf3c15d4037bfb150deb96db374 +9c7956fe92e44f7b9c4582973203c690 +c9ae74203c27437e8b80523666e6561e +393254e136ee4e759aa0a0664d81f97f +424120a0c9e042889b09eac5095476b4 +af90a3acd4af40a2bab4ff1f923d948a +2bb8e23a826c43bc96bd522aa0fefee9 +23ab9aa534064d47bf06f09e8b34e192 +3b2beb3418f34fd1ac182d968fda987c +310f1d21cf534fd0bcf073aa9b08a740 +c877e570455a43769758d151610534ff +42fae0e826cf41369f4b67fc10ee27ba +973aca271701469d89b546000d7705f4 +9daa7e197807443cab2f1953372f92f2 +886defe4dd444200a863f9d11a4fa82f +34c1665d16fd470ba8a126583f1cd839 +1e744cf9ae6f46c7ab67a211fe3cc7dd +c760415dc6074e29b11305d432775aa3 +41dd3652813a4183946e233def4d3731 +0a314c1c700f40f9a14aaad08bc59d96 +18f3e9d66b2047b59af80d9ee90fd036 +3337c63374e64d969ef2e3adaf81e033 +69d570f008be4b92881956cb3c64430c +3455acccec4b4d8b994e8391643e761f +780e747773f74ac287da0651097447d7 +206c60c7a47143b9959e3cff1e6ad404 +926e2afa1d5c4bf6ab1ab1e7460ff62c +08fb109905b34d5fbcd715a68c5ab30c +566ba77842584412ac327969a9f88e6c +23c52a98648948738a11cf7421ae1b03 +70020436290f46e8932574d34210c212 +e50c186613c94c1c8778e246b178eb2f +69511a7fad2f42ee8c4b0579bbc8fec6 +89e33a0b4f6045a0a62d8999b0905f3e +ad5b2d656f0949e7a8df89da4ea604d5 +abd0fde38a494cd7831df8438a8ff610 +b0221d4072664797b6650080cd7acb40 +f2d30a742e3243b5b702512246376ee8 +2e35b5ed4127406480403e4b8dadf5db +615868fa676a4c4fa64a0f76f97a220e +d149fc4c12084c669d6bd0ac24f213ee +a2182bfeb53e4682a90f38dff752ef8a +4a763a1c211044089b1315f9f025b027 +dd96e8295b5948ada2f5f3a6228de23a +38875d32338c41659dccebf7492ccf9c +2225dea84eb4484fb001da955b2f0230 +a2d43d4cd69b48f0aa57567a11a9ef05 +13d896955e8544e9aee219a2ddd8ecb1 +637c311ac8c246a4b25603047666732b +239325a362504d5eaafb60b0260a8880 +e9cc179ed7424f0f8961d5321388dcd6 +705e1d09e2fd4f0797bc540b34561e24 +c131a12840214149b296b84a9f39ab1d +4fe6d72f20aa4c62bf5dc38f5a66f3a8 +6c93ea97a22e40aea4f57a4ba63ba06e +bc379c569b8e4c34a1f9e64e626fe66c +89ae51450d324138ada40332b02b3f33 +f1d8575a914348e49790930a314305b0 +ed92cac6b8d64ea48ea4f91ce9bf350b +2c8d1ff84471461a9c4dffc9caf80719 +7d490276b6354542aa63911e02c5f5b9 +15d280f41a034434bf01d6955ff093a7 +9e1ea8f95c28479498f7c7af40772827 +3ff325601a5c4de38b90699c4f73defd +8225eace192b49f38c989d607f570aab +59f464fc123947e2ac111a3c141dd815 +fcd444c0e19e40f09ec612e8b68732e7 +45b8f6d2de174807a690b1c2ef381266 +b4961cb10c6b4485b366868f379b035d +5847669dfe3d4ba8b59e69dc64bc09c1 +3f7be769c796490ea28fc72c29cdb76a +12ecf41ddb8b488d9cf3820ecd56153f +64fc8375cf954a6c8460a1fe428383a0 +03f4c08b0b2040339a8423aa77ad1cfa +0c4c3245edb14e86a20ed84b7cc69ff1 +783c55d5d243491896b323ef0499d9d7 +fc34791dc62545758ee7290c8d0ff67e +e760eb48798d468bb761e17109ec8354 +cf7f142c5aa8439d9b8d545993efdac4 +b7ebb3cf37ba4aaeb93d1e3375850b06 +973afdfcd7f54e4e9972c1bc976f4e51 +1615977dcb1540c58db19c27059a60d8 +97eee04d5d43417e8f087205d233acdd +63483e9144504d20b0edb7aec86bc937 +7b84349f3a1d4a90b6cc44af79842a48 +cb6235ce0d844f948de11a62db298697 +5b115c0091a745af8a1f2f35fd44a4a8 +0384b41f61194b319e22bbbc644d0c05 +3ecdd1dd47a8402391ded8f8ab27c5b3 +15b2ebce6f084c3ea8d582c168ff478e +073603e3929441e3b6bffc1f0e180e89 +dae1166d6d9e49e39106ce1af27d03ee +27791e4b610845a1b91ee8b524d7a73f +1e80d8eb41394edf9452318f33c1dec7 +924e37086e964a459ffafbc9e11ef5cb +067e3717fff84958a650ec7e504ca28a +2ffe9fe2a32f478da74b7301ff0cba23 +6a801e7437de4457bcfae459d086dd4d +08d237ffee3d4898b000ae0878a15a5a +7da36ddc2a28494586269bca7d4a7942 +7bbfc922094c4588a13650de4467eeb4 +1761baf3b8464966aabf22b5e48013fb +1e524fe8e0e546d69baff4d6e20e7533 +ba68b7dd4cc34c92ab2745644dbc398f +036b57beece645d98d604c69bd6d6717 +3a6780be3d2c4a50bc19949e2156558a +51f63167c849450a89b65fcd7d81e8f7 +25aea220337a4d69a867c6da3edd8bce +f6ef5f55922f4168a3215cde6424b6a5 +60e8241011784f4ba68abdecc2240b7f +6784e4f16a7248518cd5ef1118a2198a +baf3242c524f4e4483d7f6df5f0d9848 +6997fcaf69634d7982bb1893210afe26 +7e6709611ce2431ca35aef17cc0af981 +3377107e093944d094336fe9e6555ad8 +a8a587aa0f6d4f889f1d4adf878ccbb0 +c20ff73f6713422591842e29a698230b +307174783278481b99d50d9f1b829d2b +7bf3dc8ff8d24d4aa37b669b37478714 +5676b179b3b744c0aaae53a3dcea2300 +21f6dccee186475d962a31e2bef9a072 +269cc79ce7ca4dcf88030e7b7151dc36 +f8a7f086e0d44883ae3b2210466a2dd1 +5c90a52c2154413ca7ece3c8cd9b957d +b4b9833506f542c38945b1ea2a29deeb +f9bfe0b1877e4d378551549eed8625f2 +6253f1a2ed104155bf661386c8a7582e +51ac88b15a2548638b9490f78cd9b30e +0a5c38536ce14e64955ae6d2ea9cfc4e +a788ff7615d54d10bd73eefc8360a82b +e5f8272a046641a9b9d5a3cbac727883 +ff70428886374665bf737a332cb251ab +b92be47157c54e8293927232b985b5a0 +a808ab0e40004dcf866e9eb6d799ac04 +e4b78578e26f40ad8ccea282f182c3f2 +583dc574a5654b34a39b6deb11ec535d +4fa7ebf1f33e4631963f98224531c661 +da0ae24a2f2943c298f8c020ca501e3a +a4112060b9aa43a8af876f922f962cce +b4065dd5ce9d46be90db3e1f3e4b9cc1 +1af52d5fc62e4aab9fc547259da2ba49 +e4c60ddfbcf6411584369f6750f85a83 +bbac19c170654c55a64bb3806320d53e +89986433667840e5a188fb3c81fabfc3 +818462ce3d84424884d136db06e72244 +8857c46674434a93be5255589f7c62c8 +9170ba9f384f442ba9977b48d4eef113 +a9699ed151a5481ea8ba2893b16abf6f +c594e11c44e24b76974ccd454ebc173d +3296240a02274c3eafc4122ef053e123 +d2bd517fdbc9454b93fd9a9551537441 +935152ad6c3c47bc8d3c8ed0fcbe8f17 +d88fbaa7a17b4c19b8a3c370448e29d4 +cedae25d954141089bc46d297970e46f +6a4765c336cd425aa33cc2d5fc2ef29c +6073902dde8645a5b34ed9ad9679af1a +b2bbf7e5e0d74145933511fe71b9e737 +b173574f823f425fb0cb710cde4278ca +5e384da966574a9a9a337d413dd37b9a +b154616b35724833b8915fd2184fa5d1 +2712c2ec1ff04f05a25f15b12e27323c +c04c370f2761457d88ab79abe75f6d32 +b6f0ab9d5e7f495d9f034a4d0cc1071a +ffd9753a53284b588b955e24047ff56e +0e5faa37ccfa41d88c80efcd1078352d +a2b3757dd4544a92b6b5602bc5bc65c6 +0cd54226b0eb451784badcb2ba968467 +51501258d322425a9cbf5148d353eec3 +942abf58826d4af9a59f064d98098539 +b8e7c778161242cebbbf012fc44e7287 +2864c1a3e6dc42fc99ec49767f9005fe +efc25f203f39472693a5869cac8a6dcf +aa96f905533044bb97ca639444c44597 +af76e633cd8e40f1b1f4fb985e9194a5 +bb9eb66d656545aba383bb0a0852e936 +72a1ef08a5c341b3886a4c08bd3e4184 +166047fe68f243a3bf72965c472b4ae7 +b8124524fc7e4c5a883d8263759c996a +735a4bb2afda4318ab7f7d69005f53ab +883e4c1fdb0b42b48467191616b22edd +5d221f35f45f4119aa1a2a446372d291 +81fe61e043ba411c951e4b3b80e82ca4 +9ac4e834028241cf825421ff77056e1c +3aa552cb12b3484385f56f89f317b1ce +b77ff389442745f399221f3c29e4f427 +e4b988f7671a4cd1a76957f7542afc7e +dbf0dbcf4229429088b0a984e8f05666 +09be27c7f2a9459082384bb382f8cea7 +867d69aa47e542658d8db8e3f9fce704 +4fe5e63b33074b9892285f452820307a +52ebceafc8af4f2ab527e9a5a454998f +d82eda5ddb9e4623ac06d8d888b6f466 +b0a2d8c6424342b1bde523da5c9b50af +c867c76118514deeaf3bfd8d08babd03 +b26434ee89514efea3ace4f65b255074 +a4a94fe3fdbf42839aeff23831fdff39 +f978801ccaf64a09bc7bd74cbbf03e9c +d8f7e48d4c1f4d70ae2864ec21812605 +3c7a36f25c5f464e8b75d69e69ea49b9 +b05e151bea8c45a2a4c8e92ecd2096f6 +4db924f2eb5f43928a826244e88768dc +077430ae3fcc430184f66a64f447213b +93fab0443ba44d55853a878826c4ca60 +88bfa0c9b60a4892b0e14824fccd9e1e +175fbd16eaa047c8bc3f0687dd01c38e +07c5c681dfa04593b9e64cb85c6b2876 +52bde7061ab94d8ea04e9f7c3141d433 +5958996dcbd54b829826c198d9ee2c7e +7bc76e4eef61474f970088eadcf82774 +daf387da62244a4fb0ecd3188eeaa7fe +3146c02a2b5e41b9ac8481c66c8e1ba1 +11ef58b1d5b341c5adb841d9af04e00f +e1fd08d2a4a54f2ba56e445aacad9edc +a0dc88016c2a4dd2914ceb2dac17b3a6 +7b3305e3369c4b5ba004d5747cce233b +ec334c6693124d3686665337a280d272 +77f00280d56b468381d75bf9392496be +aa9c7800e7944ea793db18a832c7b576 +db0ee78aa3744907bd3baef10be64cb8 +4781e8d4956e416b89bbc41744ac35af +2b768e22e649444992ab3a5673dca200 +b6d02e01fb8f49d6b9486db48b50a9e1 +8017ec74b8af45b69acb36f2cc084ad7 +de0545a1c3924479a4fa1d3b5210a2d5 +95e540c805ac49b4ae171c907118cdcc +095fae447c0e4f8d989c67ef2104df6e +1038a482155e4281a611269c9e59fa7b +1f32bc0b4dd740f49faefc1cbe0e5e45 +8b53d504de26437c8b677f224bf9d711 +d7934f608c6c4842ae3fdd115d2bd913 +ea09ce8bd3554d6ebbd61fec548bef7c +332831127f724ae8b55245abafe1306e +4f590098666a4d7598d8aa72c0380b92 +c3dbcefe14454b1ca55bae8d1af032ab +7f19504fdb2e477998ed871275f43b06 +cf8404e8ca7c463bbf50e700355bbc89 +bb2d52721c394447904afa41f70ca56c +f8b6bf5626914e1e9f05d784e7cecc19 +52093800205f440ca3b90389260dc031 +84fbebeae5354f5f8bf6f254008fedd2 +154da6d5a31949129d209dd35c156f37 +76c7c59569fc4b778550e9fbef245469 +3442fd87d62b483ba7574bd3de060a22 +ebee49fcd3f54f44bb083e2d803b793a +0d81e062005b47f9b738fe187db86398 +a802ecd67cfc459f9f1060f188ff6fc8 +5198c7a6817d477abba262bb327a5d47 +ab41d89037394fbf9e0bdcf0629eda37 +f6b185959e1748c5bd6d6acf1e713b55 +f191fe77dbd647be9741658645698fc7 +266749145fb748b98f1aba7b168c16fd +436adfa552e2473390d47b6a2dfeb294 +51e2822c9d3a4c9e96171553f96bdf04 +bbafa80686fa4c2c81f19f1a7e883be5 +ff91f534b54a49278647be854c5af631 +f060379cd25d42f398a96824c503307e +2ba80c2563dd4d03a5f719caa0bd1f1c +1021e67cf82b48e2bd773f55605d858f +2ea582f329e94f3ba94359d39d90918b +7e5de66b10694898ae9b60cb1927a361 +a01b126f773c4d4e82403c0bb9da0b3a +eab46a489c5745a689bb02995f98bf77 +4ec89acd68c04420bc5878f58c40bec9 +734ab343ed2d483b8127bf38d90311ad +7798228aad9b4500875eda3c4cf26b0c +ca1962844c344c048d5dd90d5750a610 +7241d57cd08e4508bc9b4914c7a27a4c +721ceca9782441b3ab2244a99e4304a4 +47140dafc57b4cb387346ff633319b57 +0628e42dc7404dbc89e4a224f0bb9459 +b3a0df3eb55c4f41b57d37c498b7a6b1 +42ef95c945084551b92ae7f63ef34f4c +8a1a854958604320b172d03e7cfb9768 +d0143f13110e4f02bd3a8f43f8416288 +44f41039246a4df59027c38023d5a576 +48dd3e9e150347e3b80e33af977d2993 +423a05e278474daa81019e6099082a77 +b92d13ca51ad405183eab8c125b39307 +a6c0f1a26f70409c861a1f6d0121cf2e +bf1a64c7e3fc48e6a2d8c23277b56434 +98dec21894e14ef1b4abf1ef233cfb8f +cdad3f76bdbb49d29c120cb251970742 +3ecbb2c1de924ae58f4fda67b3d160ad +6f50614649a24b908634710dc65992a7 +fdc3e88a736a4bba9baf9ac273a90ad7 +789a13c04d584eff833733ef7270a412 +37d75ddbac9249819b4cc1559f60752f +cbc3630e05e04f088a769bbb9e613f4b +b6eaf57de8f14b97b876bea2935d86b1 +3a40810c85cd4576af04b66e5a18e6a0 +1115d0518b744af7afa213ede890ed03 +5d3d8c8d4aa14d9db070b18c4c128864 +c1f34428e7e3411b80ad23f6c6ad8607 +33619cf0e6b94714bd611fdbd1268cc7 +71052e994ab043718c60408f2f6f4b94 +46adf980624a4725a180360348c26325 +f8c29fe91cdc45df89fcff864e21a834 +04fdc7633b734ccfb61fb1be7cd6a2bd +c4950486ca6a43efad88aa3787383064 +42840b5c292544b6bb4fb5778b52b01e +bc5c4aa995ad4bf5837b30a859d64f72 +5152d57b8e384e1d9497a5fdaa28e6dc +fb10650ba5084516b4bb2e32bf0096f1 +aac71bed4a784536964748569dcf1537 +c21e2a4d650b41abb3b24540494ea71f +4af08e1e8f594444ad79765332f299bb +a2b70c2f92af45d18d95f02b60621dbf +7114ef335ef74420bba552599c4f20c4 +78a00718ec28407e8746d7407961a75e +8870ef6ecfa9458b9cb383033f8f699f +8b70001c63874a1892f19efbf541002c +a8614ccd87314bc7bca5919d4f219850 +ef7d14fde18e4991805c179fbaf7b58a +c63510b103fc4954ad36a84d7e26e7ec +ab0a2921a8384680bed6f8cef5e20d0f +b6bafae4af4e43dfa002926ce6c93fef +b414f6da72c54cd2870e1a72292e23fe +caa065b78eb34f1b9f5fd400c9fe32c7 +acfa52dc286041f1aef53634829583d1 +195c84cd622749fb8fa283674da654c7 +2241ea5594de44a5b4f97daf97f70b53 +e2097054f3254a829b1f3857c20409af +d549c16638f04abeab33a48bdb272c22 +4fbb57124fec47d8b216101e19f5d385 +2a0a93ff48a44734bbc393084fef9ee0 +160d712e0098495086b6d798ceaeb24e +643e3c77db9c40c5a90f5cb78e3cd6c3 +bb3f1b2ffabb4e358c6234e061874abe +a13edfdfa3d04161849078be7facd99d +c90289b34b58418fa2a88670c5e9c8c3 +576daeaa281840cfb3ece4850cc42469 +dbf86a22865544c0b3e81d2a0b8cca55 +38cb4ee3a65d423089a32ea4b89eb95a +5cfedcc8dda541e284e5d8b3add46937 +df27288416df409891c3432a8ca23cd9 +6735874adfd64e229414f958b8f1f73f +1af76876711a4274b9fd4f8b12d923fb +e3a23127e0ed466196517b7733d6978d +f4da8ee5b2dd4695978cfa14b33fb8d3 +31139a065546483588ec923fe4e4361d +3d8c8d3c7a4045b799656d445b586558 +0cec59ff9bc543aea3cdd573a81d102a +40141581e7154d65937ba4ae75284e38 +a5ea47eb11f24bc6a4d4e47caa30b6dd +7b5467f79bbf44e48e74bc15b21706c7 +adb0e767a0824a469d4a854d27e9458b +aaeb98d6ec314c16be460cf161fda746 +24cc5c1c6b9b4a62a06c9056b3a2ce61 +82ffbd3663d74c62a1d7b0f16029cf56 +f436b41f927941328b9cac832afae3e9 +fd0a2dcfb518449396c1f0b578328498 +87e986b6a3784421a82b86f9a0977183 +4c2e96eba9fd4b669ae84e6a7eee409a +bfa9f09680b74465868ae4df72541a57 +477459ba63f048b89252c56433042775 +d2dfc5c9ea0c493a8ad8a85c9eb566dc +769eddee8c85445fbceb85580dc9a3e8 +640dd3a7507a4feb9df3c3aec0b4e885 +02cc6c3b10d14048b06a518bb6870c40 +78d9c88449ff49c09fbaaa87e23c2559 +416a462593e7453b8d0df0d965967677 +b4618084aa7d49e8b8d04fc4544ae093 +2cdb30045bf84c3a82c4defe2bbcc516 +bdd4181dbe334192ba5385810c9a58cd +f302068502764c2a8cfaffa325414d33 +fa37cfb2764f497ca0b07e27870eec4d +30700bc210844bdc991a5ccf16b6379f +541ee9c800b04a128d6b670f8c5fe6ba +5cdf4f469f034c58919d662d28ef16ab +363887953a734322955e2f8279e09204 +222c836c79c146528417409662571ed2 +569fdca963a242e5ae66258672dee5db +ab58fb5cf1884d919afcb18610459c7e +a116571cddad4b0d97062f107ee833c7 +a6ca57363110496cae1826dc7f97992f +9ad4ad07292943e59ccc25c127aecf20 +805eaec17fd94af3be9f404d764da6e1 +76aa30acf9704f2ea56813c9ce2a9e8b +cf964a1ff455478ba65771400a4ea1ab +74c33d16b31346f1a46a55c3ec8e8a78 +2d777903a4ce45b387a4bfb314bfc8c3 +deb540e37ceb45a0a22c7b2169a3c69e +0023b3edbc114be188ca9d8f729dfaaf +a3f75a289cfe423e9d095470fa5c67c1 +6a7b6a34cd2d4822bea3aebca4746b78 +bd8e92fcbf4a4a5ab7e96d89cb3ddc6d +d6ae3a30049241caafa76fee160300c4 +b6b80c6a199a411dbfe9c3082a10c365 +3ef5b607164848f995fe6b5071ac2192 +30c0aaab8f3d4834895ca7d6cded5509 +76c7e3b25a21457287247908d51ea705 +75b735754a2a468ebeb057438de08ccf +e8eb52e846114e16b2c121143b8ceb8b +c143f3a5099f47eb9c1c4039dde57628 +08cf90e320c444358867af5bc5f91fcf +53cce85d9068451a936c413369a7ed8f +1422444a7f5047468a27c1fc45787801 +5d1f32cf43334c09955319df2552312c +5e4a17118c334c9d8fe8feeea234eddb +e8ea3c96af9343e1ad9908e6b8e80106 +e72be75e9d5640e78ad27c24b31614f3 +be95674591e34ac9a566824dff1f5e0d +b68ea4b74a9f4a0d8c9d395f964e48bf +6f12fed83e6145b6b74982c804eaeaee +8912d944b0954e93840a3610660d5aab +b13ac3d99e4f4c09888639032e861631 +3eeda7ecca21476e9601bce4085179b1 +34270b2281e641deb39b16f69ed84346 +11ed23dd653b40e9bc4c144039816466 +e493838af1d64800bc2008c231925f11 +af58614759bb4e91aaa284668de93907 +90823a5572f842d6b037c891b9544e09 +48b2ce1eb4c94d05a5299451ec4ffe4d +c2fbfde544a748fcab612ec50da4f6c1 +6f654f9e40c346e6aafdc04ccc68dd48 +9bca231b88304dba8f5115a8cbc84cc2 +e283aa7835664a74a4ad39afb26d2ef3 +8f3609a949904713b692512b84f81664 +000a82b4e6bf4e909fbe5a3b0e6d67dc +17f2e9139ea349faafbce7ad851301ec +64c01997cc884bf9a7d92dd51d7342ae +07b31e4a08044459b746555c7bf3b19a +0e21675682ba457ea4e3e78e16bdaaf4 +3b03ece9c7b64a188e1139673cec4a38 +42a0335c77c34ff3bf08618a168f73ec +2b3a049aa36a4849ad77d0d2f633590c +6c13df972c904b4b890087c592a4f905 +6a98c08d4b73488baf05eca19e93d3cf +1b0619308be640a2b33a16cc898c8dfc +2da8f126c4fa4430869b4add6b6c002f +bfb029c7cd044080ac85ee3508a68246 +487356d4b9e148dba8d6b385a148e82c +29e61a713bd3413c8fc74c8453a1ada1 +2a93f91b3bf9462eb4e14ee87db9b54f +2382790f69cf4562a2f9689526e24b6d +bb7a3b0f97fd4eb88d835c767bf91394 +f5b9c041fb7e40ccbf9c6630a1978c9d +a68544fd4d124df5b08a6f34d0a3c718 +7339a87dac884f1e8aeed3bf80dc0a5f +a2536d0580e44db9bafe0654c122e99e +ebc7b075bc8b44a2b88adb59bbad9898 +h9m9VF9Uqy0oTp1vLmb7KjEfQic +427be76521fd421dac0e3668c072b210 +51b880c976b34f47a4e0e0c122b6d000 +82f8a9d5cff74aa2807f497ee1b1e961 +e0aa365964e14664a5ee5063bd164bf9 +d5eea4e95595496892ed15b711473cb2 +257512d4edbe4be2ac782d9ab74f8360 +7e4696fef0bd4f81ad7eb840d452380b +1022e9d02cf64a6cb69b4909ac385182 +792240a76bb94282b31494fdef52189d +f5d129892af5472ea3867a2342a033d3 +ed71b3090803449eaee55340bf833969 +95223d14d66a445bb09083dc69f6f02f +35cecc41cfed4c78bb31731b4db4b33a +d3f279329c034ad49288dee94b03fce9 +ee39e110fdbb4664af18fb1bf0b484d6 +6ae4241f2d374881bad6baf79081c53e +f8f5e6b1fe554edb894bf39647bebb67 +17e4ece66d4d477f942c0427ab45c8b5 +ba9c67b09b1240f6988abc0b61aeec87 +a8885471fd424baca0493d1eaffa10ae +1283ffb5acf74de7a2853390d3e39611 +201ab7e00f524aafa527532f69e73b4c +9cc4fbb68f8f45688149150356482382 +d814b79fbcf2461faf106861bee7e112 +ff2831bb45274c8d8b44a0cd1046c94a +a58871a82ded453581d4d49327c93bc6 +f2be311255b649b2a2d5e53e058c70c9 +f5fcd9ab4e66440587c3f4af48eb6891 +0f7366550f694e1cb9efddea214a3c33 +eddd78c746734197a81613e10affed89 +d4ba44ced178428ba41ac835fccde714 +106a182b1f95497bbd4c253c588d8e82 +76f76b249f3743ec9419119b5aef46b9 +7a16ce66ec734399953087438a0963ae +d2306f0660464e47aa9c4de7977ad796 +6b01d76f958b4fb38eb4674ee72e4d88 +21b7e85f54024a6888bb168f21bbb2e1 +f0b1f7c17d70489888f5ae922169c0ce +2e4f49f6b18943e6bb0b0ccd2b14312f +6738327269c3431aa2d2c208603c18b9 +d88321bd61a7449ebc780e9ce65c298a +d5b17a7d672a4ad291e0e6359abee38d +1ff6072d65bc4ea0be5f8894f2001a0d +81b173cb73a24af8ac15d50935351658 +98074cb87fb94ba6a487e678b444d2d9 +0fe5a30e68d24ff2931ea8c4aa6a11f8 +33ba899b46bd40da80a92e4594639937 +a22031e23f5d44258962759ab530d1fa +812122c2907b44148ce0b39279f60bc4 +644ed9dd11cf49538a0da51cea42a0a5 +d6336cbaa64f4a75aa5b51b97a9aae98 +4be0a2d29e0d4d2ba0d535856ca680ba +b5ff1fcea35a4024b69e4dd08c6e1c19 +9d4c857981fb4624b2c2226f9ee81124 +f397d7e2f05f4766b0589309339f8747 +d3307264b4b14e079ba5c861eeac839e +de2e9e84e52844a0ab522e5e98202453 +9eb895af086a4cbb95f86bc2fa773b60 +c1c8f8af133d464585c1795735a5f8f0 +aacf30223071418eac0484c95c24d46f +844c8bc92944471ca525e78dc97da253 +9a57589787144da49d7272fb153f726b +685d34bc87a643289d31c0c1e4072029 +079e24f4748747d592f2f9bae01de712 +2b2fa3b8357741c6a40758958222713b +0148e4be70934f47931055925051e0da +d6c77b5fe7844dee9fbef1ce5390997d +9d1ad8b8512040f5a200bc3f72577d8a +660f938476444ad781feaa2aa4ff456f +fd2b4c7ca9b34d6d946bb32b4a4e1d4c +ea47186e191743fea068b441b6fd4e30 +562fb778e7764dd1a1ec254a823546c7 +1fc1cabfad294fcd91689426f8b44554 +ff10170d6b9447e794e8a4171e4f3fce +fe701b8dac9f4f048897efc30ba83c9c +bdacb14603354250a2a9bf8fed27640c +6738d574614545bfb25cef43185b847c +950f6f4e17c94533bb62b588f2a39b84 +490a5cf17e414841924a2407e50787c9 +3a0d9015e379452e9ab93e0b4862066f +c85d5cedb1d84126b01368532f0a8209 +0a5013605cc848e89ae5b2e3396504da +a24bac93ec5b4c79b006291612f60759 +3aaad2ff33c04eaeb54fdea68cad8c90 +e56a1a53ce204d2087b5bf68f4bb9300 +e9f58587f4f241ccb8245e28fa10f717 +540aabf3688542a1a151169b786d4696 +e1d276a9514341ef9871bd771c20180b +34b72655ce9d4032a01eb31b5daa4570 +37d747c239c34ff581db1f0c22ef4b03 +e66258b7493c4110be4995d3187266a3 +4bc2ff75dc584af2afd0aa6bd8b79015 +92ccdbd9c39a4416b6fcaf4bcbd7ca78 +01049dbd8ad244a89cdff8ad2374f58a +dcd980a74cd44a1dbde7f8ad4d5818db +533e70ea184f432d8b3b5e4663a38689 +863b112d64fc4a01a9eaeccc1c0b3e6f +337b25ed459c462ba1bf988511167b0c +482c5168f1694911b597c81f3d0c73b1 +3df39f0fec1e4b658abf94cb5b62bd39 +215377ebdcd648bf8865106180539c1a +c6c2b4cc101c4ccda903bfe33f0639fc +63ae0999b11f455d99d78db69de7adc2 +0253ceabf9ae437fb885a74140070227 +b6d7a6e9690c4aabad51c83b37435282 +d022fc3857104da59e286822c20868e1 +02bcfdbdca964989861d5e7a207ffcf5 +f968f711e26e4a249fa8b43d6a3d685a +543d4431ce484fabb7ac23a31eca6463 +7b45769ec16e4575b3fdf3f324f1c471 +a84cecb600c04eeba60d02f99b8b154b +c0c05a27f0664978a056af56b8bf4dbf +361ede74a21b47adb53a812c6e2c6770 +cec6db923c744c459e1bd3560e3145fb +cafe7d385b49457fab07b3322d0693bf +454ed3d581ac4f929ff34022afa4c662 +6795956e393c43218de920b594c9e185 +db7887bc21a241f8b8354eeb5516446e +4c89969b0caa4d3eb30de9bac7ca1565 +dcb0d1c9b8be49e0945535fdd81c7525 +002122c2db5a48b383598fec645cb459 +053039b95c314104b5fe0dfb19f43cb3 +a2e2094321524a3ab622b515204f1993 +0c15255053f14ff0b28fa0fcd6a90115 +7a13c91f07e042a685b4d265644fdc06 +e8a54da09d964b3e8abe951d5d83fb59 +8914ffeed561484297a7d1a78a9d1a69 +5b07b536c93849ed875a837ed8bcbd6a +c4c8ee02e74b4a1a825da6daedfb6a4c +2149d4ef4b3946e6813a9f3e262d214d +f82277a43fc649f296e4c59063e78593 +24c96b6714b14d98953bcf72ddcbe3e2 +0b9929633fd5458c8f234eb9d415ac06 +087122bc1c7f4b8998b58b650605a67c +b47606854c694ff3b7f71df9c8c3fdd9 +bf6700a3203e4bb9a544c3f04b81c244 +6ae2bf4d943b4e7eb2df4e21edc8c513 +7250ab221633469b94035d0c9952c345 +4acb1491549f4543a0433e58dd397d96 +37006a5a27674a58aebaf4e17e0c4a95 +69f7f06a762745f289994d8066d7c57e +fc2dd2c7b51e4ff5b38d1d3611da1f93 +66f0f196877a4c6ca390e5b5f275e43f +238e26ee5b85425fb56c0a2f36bab3c0 +d1086009a04c4a06b7d02bc0d6dc3731 +cf7304e277a5465a821d1091a67010cf +3ee4942079b342358e14e8e06c1f29d6 +6a25379ebb134d259bd35c09682cc4ae +c60d0446a61d4558972929a45209b9ed +ec78aff7132d48a98b7f84f89e39d172 +4e62892943474f0eb3658325c6a3f32f +221ef05436294548aa792de2b9ffb12a +1512800cc19640c5addb7f469dadd7be +87dc4f75804b4635949a4e8c37c79d8b +45e3468808f844e8b56826655a2573f7 +c58ab5f264ee4c9d915ed946cb9b9075 +a8176d5e9c994343a8800453e8769905 +51f56db753844e949d251e47c8406c9a +3196ea27c20e4da389cdfb3e5206e3fe +00c86cb620a743cc81d9cb87ad4d8696 +ad0501050f0d4781aae97215dfafcb78 +550927d8f0d549548c994b184e98a3ff +e9edbd0c027c4f648e1405df96670cc1 +d2663d7899c04e73a43cc34ec3e14ee0 +8e18588b74404a18b5226953c427e567 +6fa3f6a894d942b6beabd6ae139ac835 +b28311e44a4f41fb99b91a489a637bed +601c9a990d504d80931996f0a90717b9 +646098778f434b6888f1ad12a1cd0a84 +2bd168a944884e69ae1c0bb13489cef2 +dc5bff50734947eea49451ed5d1c966d +94d4fb18b7e54635b9fb97c862ff990e +c72ab93dacfc4dbb81ea953173177f68 +e776fdc2f30745ceba1e8dba7fe565bc +c7c554b85f5547bea17534fe8ff29a01 +674d185819674b9f9140797b3a8b83bc +fb3bf5e4ac744a13b47a59e07301ce98 +53d406f487fe401ca82566ce5babba38 +ecb62a6cf8a54a60bdb5ba02091cea3d +b31bf7c6d10e493d879b902485c24daa +4caaeb95fc694b81b7dc264dbfc668ae +789fb1d496d54218888ead2fffe05995 +ae427c1386384f3ebf0cf56282fd8049 +6e865e4cd26f4acbb80df1d46197738a +216b2f1ead574acb80f47c3f5d31288e +f472245c56ff48ffb8af2489b50b2d6a +dfcd15bef17e4e3996809a5723482f8f +bc8a954d36ce481fb8c31ec05d854bac +94a4eba8ce784f95b726f7bdfbd086b7 +35cf77272b1546a3affd2a544cc0c576 +86daa7f49cc84063ba2a83620c99e68e +df42f5938f2c448a95d70ac55c48d349 +34e129782bd648a8afc47ddd4aab6688 +83646e018c4749abb112888eb2760a29 +48ecec8d39604c1580e9bef3b2fa4cc8 +f0299a558be8424da4fb917c58658779 +dc908f954a984b83b36433a3092b3085 +d215bdb9b8204f899a78fb1dc4b30f72 +064a4adc578f46c7939e743dd1ef4a56 +45a59784bd7d4a7bb503626136d39879 +821f57d137454002bc0211d5ee58b6b1 +6470e27021dc468e88e68befca5f770a +8b647d638e7e4305be0ab948d67415c1 +485b809b30ca4361be80ba37e715202e +859c1bdb52d34d30892613a527cbdbf0 +6511cf11970e465bb9a488853d23cd82 +b9905103b36b4d33aeadaa51353b1bb5 +497e4096c0bc4828b611aa8063157bd3 +3c1a86b7f4e6446aa24ae28e695d44dd +5569d97509f248d4b587f1bee3dc20aa +bac0ceef416c4ef88750f659f3bca592 +a5ba0961640447e1a25317e6df4791a5 +ae6d85933b3745fd9a8ac8f2aa5a1a9c +c41292560f464b1c8948747409f140f6 +54da2b57131c4c02a77aeac1977bd4df +64ef2a52613041bfa7b34f27a2dcf377 +a63717d314ea41fd865669f58db82fce +c747e79a65ee4c6ca51b6a694bc7b400 +035de419597d463880e8e5c52ff698a4 +4dd67b2cea5143e7b56450629f8cb120 +bf5e4d86b3884abc93add1a72fb1d2ad +593cbebc494f4937a0c9eef6c29c67a1 +3b9e7e5b955d4c7cba9406cf70ebcee5 +140dc25d6d1e4329a9a923c2e9b81fb4 +e282fa5aaeba43ae9c1edc7ca649cd6e +9b4756f0c0f2464786032a5c4f666e38 +f0b032268e4e472aac0eb0636c580ba3 +dd35db1524bb456f92f08c26145d906f +87210c1a114c47ecb6dbe9035d079be7 +5dba22e3d810499b893a52a665866b56 +4a387cc30acc49e59e243cf192ec2870 +dcd767affcb54b35834fa5297f52f9cb +6441fe1ec6744bacaafd3b21c424fc91 +8d92600f641e4e1daeed9705afbb21bf +6b80d946a3024479aaeb6d0e41e534b4 +0056fa33ff5941c295e30dbc70be20f5 +0ba46093caff4ef7b415279e4a28e3cc +704bc7fa4f1c4226908e3905c9730c22 +024e92a937a444d0841a7c75e9cd2943 +caf6d29f508a4691b56601c5dab9dcd8 +a74d7f9d98cf4ebfa6cb2302c46af02d +6b5ee48e336648729e7a82f3805a55a2 +307c5e4477254322995fd5b9d00bca53 +e1b22565fc6942a2866bdf8b51cf567a +01a9d2dd3c184268abc76693458bd5e5 +2ab1282435fb429ab88b8a88bf9a82f5 +973f6383b4664e17987d191fc66e6e8b +2fc0fc6ebe564a249c4617e6b3e6da93 +5580f7c37a33445c8aa1afa157b3de54 +eb2f87f7efc74cfd91167bbf91be186b +8f7df859a8374634a5e83ce396076e78 +c9bfe52cf3c9435286c354c5f3d51ffb +e5b8f1078dbd4fd987cf6b2f12b1f13c +7d34909efb9f45d08b9d680837e76b8f +950ce6642cc64475a0a3c1df3a5fb13c +e378a4f6f2454cfd9dbd9297a235c26e +02b212307b084a9ba2475751e4051cc7 +7ea465a1489c4b12bb5a8ff33325cccb +3fa441ba82d34eae85f3b00357613dd3 +d892b203b1ff4824969a6ae6deb6def8 +c34682ee2cba46a2bd55cc4be587eca4 +da8bb463567d4f39abd0d5be860243ea +104b4022e5a141efb9e1cde9fe9fab51 +48864fdf167643e09be7a49cba4b9065 +ea7e6a8cd09b4cb3a3b88d60c7f22bf2 +a98226b277084009b914fa7ed09110ba +5bd1a6a26ed449868db8151d506c533e +b92aa14cbe5848198ccdc9ac2396f219 +cfc4364c516544168dcc85096feccd40 +ea0d2add9f184b02a23331aa30f2077d +e25cf19b07e84656a9a7ab71b72c8e3b +a5cedd5926aa4de0a366dc7d5f920631 +fe1ee2ca85c0471ab7bf675cc389c08f +10f788e4da8842468c68efc1fe3d4890 +d0e7783a976546ec8482a2c28322885a +8a3a89158bff4d65813d5fe5607c5d14 +71b622c6e4aa4a848d9b6fcdbfc27ad7 +2f0ef6ad926b474189b6ef489d11954c +076f21619c614b5db750544e959b9ba2 +e024e4e52c1b4995b277cb3c61ac8388 +3308de942f37418e8f90f104191da0c8 +28d5f8f70d5c49258cd64381d0f6998c +b424adc1f8824b6bb2d287b587cf8ec3 +b1825deef0ab4085aa8832435a857ad8 +a002bdb64e9a40719857c653d1fcb2ad +c387552cb29f4e2f96e9514f0dbb1ddf +32ceb994ebe94207949326ccab078c24 +2beaf073b9de4d499d24f799865a59d0 +d5ba5090dd034ac7b3dd5fc9847c7656 +939328f7b4514e49a177548112d7a950 +4fccf2dfeb30495d9db383a9667940f3 +23063b3954ff49ec8b5136287e4def2c +cb2e9ae5febf4a57b8ef655d52be576f +be2f1efdf271439c80d435ab3c9f7e78 +4f5139ba94cc42bfb3dd80a0fab8746f +409624f89a75424ea5a2562018d5276f +ea7123d1875446b4a336abc653c55580 +58d2fb70892a437fad6643c2dbb95749 +e9d34a3af3c54910918b3221f9f770e4 +cd52e1b5299a40968f44c209899b4597 +6cd13786aef640c785b2a6d3e36f0fd8 +cbaf37cd86b64d9987407647537d123c +ebb7ce30d778471184defaf0719cb3df +464674e86cde4284bc2314ee87bd33fd +a0069ab1520b4a2494f24b07204d654e +8d193f5ff00d47fbb75e9f0a9a53c7c7 +9ef6c018a8ce4d41824ec40b9870e412 +5e11379a0b7b4014b0ac6003e950a3f8 +f07f9712e8064aed97feafdf5ada9afd +9b095e3e435948688a1a9a832b9df756 +57929b16fed84be89ffabae491a3de13 +3fb4baff1ad546d4ad76938f268ca2d7 +f1e6958e6c284026b8636899a18ab6a5 +93c15997949a48b4bf07c816746fce3f +eb3f2354354a4e67a709bf2cab522049 +4979e70504904c219dc8e0713656f944 +d40fdecddc254175996276153ea5ed7d +0bfaa65b72644313993599fe6146d5f5 +96b53d18fae64d428cc8a4098be30700 +6e7beeda7b4b47b1a4a64c82c3318be9 +42133f7fcc394ab89bb71584a946c6ae +75f06f19c7ff43368034cf736bcb110a +ca673585e3df4dbcb3bf95261a8af647 +d766481551eb4ab69ab1b26cc2518e33 +90029d3d459f4570866f15d73628993e +38296318f6234054bf849608ed7ca3b8 +a8dbbefdcbcc43728407c14b2a7608f6 +606bd19d8dcc4035b7f6a250cde38ff4 +55c93bf5ce5a42df82b4da70e0f77c7b +e546dd854b744467b0aa37bd36bd499d +dd23c7d47a974ee0a10454f731d04335 +2176ea4691054f229f2b2539ae126afe +6cea809f7ba747e6b59a0e7d1e6ae753 +bee533e6c67d4c4fa34c23e79b819146 +afb7e0918a2549788aaa83476adf5b8d +45bfa2baa4a54fefa51e1ab67fad8f61 +e408c968b0f44a9d92ac92ad390b608a +c6ae2bc70fae44f3afd5191fc6d4787a +adc180c348214933a016f902d83889b4 +3eccf8cdd75a41a19496680dac87b847 +347770adfbaa4962ac98c58bbc51b23f +081e967a3609471f8e0b384f44f3760e +d6487b19844843148c87b24b6ed9cb8a +41c3ebce72d84e4da9bd6561d98451b1 +60881fb8e28d4f4ea8bf91ea8bea43f8 +bf9e6f7de2a24d169f3e6236ab3096b4 +e05461cb1dea4015bfd01e9d39edbc62 +aa22e5ba7a474ccbb135fbab14b713bd +ee2c9fb3fbb041eca63157ad3a22e98e +2241e09cc3ad40a0a6da20cd76d7baa7 +d4916178603a41b1813a2e8a4ec8891e +fd31c0eeda8f42adbd8122921cb75f48 +b7aa7644a6f9481b89da16eb2b9ca39b +d1a388d93c0745d885c5c4fc5fe51cc2 +88448fe608f0435c83e3c6a5cae76186 +d19ab423e02546beb0c23719660fd1c7 +4c656b98557f433499726238dfa8eaa5 +755175daea384176813e7dc90b2245a5 +b8dd7b4730bb4d97b817ae136abefb0e +fd1618d824504cfb86e24f263956f76e +8f93891d042c4f21a3894017712adbd2 +3c77d58c59ac4220b086a88cf75c117b +3445c3528fb041aa9bb415ba1ac7ee15 +0edcc9053a114e7f8a706cae0864e7be +274bf0130e5e497990719d44c498ba00 +4b8c7e8412fb409285528e79b70d1891 +f3d8e925db784591ad54ce18a27e540d +bdd7787d4615463c9b7e93237670d10d +4ba531a854cd4213bdc34c62cfb7134e +df7e33c31d0d42d4ae7a5c7b009f39f8 +07b934766bd84c8788ebc1b36d4ee5d1 +ee70a460b9dc485f81eed2dc0ebf8619 +1e06b383b41a420cb980ebc8f23422b6 +5601480d04ed473296dd3d6a56d5df7a +a8d0d83288bc45a2ab4f00543bab40fa +5a8ae351c0444499b83d131668260443 +62fc82ddd5fb46a2a0eadb06d493e194 +52f79ac9ff0b40baa30feb68018fade9 +75c206e5f7854f169cc4013274e54c9f +0228981cd37f4a21962403b936f54629 +89c9a198e3b04292802e9a444f6476e0 +2037cb336566458786ae3fc5c91d8ca6 +a4b55d6bee984e919d0afa9b53b3602e +578e94244c8648d18ca7d0506379989f +9b3d5631d1e844ddaf2ab3f388b5d4c0 +7e5ad154d91d45039205b219587bc29e +c464fb60bc134c3db590a6a3790d6675 +b787519dbdc64f30bb20f499811dbdb5 +24cc42ed1dc64366a5146ca4665025bb +8c0799fd30ad4b138470957d66b9e091 +85a6f0f76604489dad2cac5048aad9b8 +d728ba0836a046a4a45c4a9d9f1ef885 +d04047147375415bb4b5ab32832a8d23 +1bd870512aff40efba5678a97e7b05f4 +416016bf305e448090a476a62bac701b +b1f629ca99684fecb19cbb1f8f49504b +c12391bcea2a4d8ba1e099308444693d +f8fd4ad7fc1949ddb23419ce6799db50 +c64fd63f94e54e4b865d62b6721893e5 +57c8bcfbaa8d4b7d898e74671da510cd +0e70c34b4d984442ae39ee20e56bb31b +2678ba288c7f4131ab1509e0c27c1c7a +c274989766c344ac97817f77a046c0e0 +493b70a6177d4a1385b6b0ce041a93b0 +912b855b12ed46719425f94743b32cbc +074f617227ee41fb86f212ce086a9004 +88f33fa2f8704e86b93a93e5c57e7b06 +fe1a3f59c9ff44c19cbf82cca69eb219 +4af7ff130a1a495b8141c564378fbcc5 +19c989a6681145bc999c332699eb852e +f6cb88c0b59e4d1ea3df34464f272cb3 +05e6f8ed25e74242957b34f9256ffc47 +c88e32bb901f49beb74ea3ed5c772ee2 +a2d829a2680c44cdaa7773c05d29ce68 +dc8ea337322f4170855c6162b5c2ffdf +c6f31f3925384a84ad558e67f556298d +d6ec7ee9a6dc44ac9a8333d1f23b5e94 +9308b88258ed48d193073c843b5933b6 +789e5acbee0d4a13a5520f9a98e5e5ec +2df864207ad248589dcaa149e445d7d8 +864c7f9afa2e49e1a64ad05b2a29f66a +36e1147ee29549ed821f8af0b687cd57 +9b5f5901aa9a403fa418dc3ada806c06 +cdcf02e2fb23431aba64cb895f1d993a +da9b3104c4c749ec8c66176d00154a80 +97f7935733d1458993a583ca9f6ccf30 +b481086605624413b9261961a7ce7e6c +56d0264bc99749989092b37b1272517e +fba528bb5a1541a8961c6e805c473108 +eeae214a963a4aaabf9d8ea5dc4c3c03 +45d4a354204840559f68c1441dc523cc +d8eef1546773469c951dde190b508257 +303b0a5b3c974cc586fe8ba7502e1ffc +39f4611db5fc494a85cd62906629bd0b +37e362e113994d1a9e977496c5001f93 +0a25fb69fc634713acffec225ac8fa70 +dcd16c31187d43df98a7480b8b2b63bb +46240f7b97a1467fa42532490a58e0b8 +ea33b0f4f7fa4b2594707d2588fd0f75 +801c8e36147d40f2ba5210dceaba91bb +ca72e6c6a99241a6b9792de380ff48d6 +4b6abe46e68940be872dea3daf3e1c39 +08320b83a7344141a3ec376aab20c9f4 +6d3b52f9606c4c2082bf9c60d1a800d6 +2b271bc246d1405398be1609704a3e14 +e4894c42af9f489e9a4f18328a44bde6 +39d8d13f1fed4f34afc9895aa99f0d2f +780348ee7ef1499ebff0cad026196d27 +cd6f9016db8644129af1b6026f9e46bd +8b7831b323234d70b8a553b67de90ed2 +f51f1d33be804a759207152154ac7714 +146209f3c07e4c65b16a0ae16616d27b +180f1c0ab5f64b90ac17db9f89c3eafc +31df1da7f21748d1836186724833b189 +d74385131eb44c6f8750af227d41659b +ce6383d8fb27451eb8c39a7193194307 +4f64dacffd70441cb3499030615fe66a +69bee68e5ce5434b894a9d0edcdb8dbe +9b20291215674e2b8e304f50f33b10ed +f7e5a12a2f22432c8f39eab29880e7ed +cca6db19216344919b427d0e3b2107a8 +5a8c95a1768f4d3ca4ac774c6e63e6ca +210b4d5f9c714823bfa3ac5a4c23c039 +7cbebb45df7e49b6b9345a33de8df2e2 +b0f59aea79634f2ab5a5eb0467e0926a +f5e8252067fc4fa5a1f79f4e3d7b7c45 +1c75c94dbe15458db73006a2bde8ed0e +281891d0dd6a4affbda7530bed83f846 +3f0b63f78c004821bdf73aa7acd2e917 +ddc9ee95b9904d29af3e518f6d3d29dc +df772d5a4c2d4f849f44969a4664fe4f +7838304674bf443cb7e2701e2126f65c +91c1af07cfc542f29a2c54c75cc9fa32 +61e313e05eb845779f12ae1bb32d5c19 +6a4fa3c27a1c4c74b75ae1259874c78c +53644b2adee1444b8ec19aed5fd23249 +af3281f986cc40b9b3cbca1f72e77f46 +04343a479ca8438c9951cc507aeec96d +0c4567b1f9a649e7bd268b11f48c116b +8b4c74e4dba746b7ba2f114590a52ddc +ba8e50398b4a439981e8c0adca993008 +e597b83290c741a699d1b2a47fe73713 +e2688126f09b444bb8f0dd4543499fef +e2def5d1ee0c4019b5f38604892f21a7 +c048d51a2e9a4ee99262dc27058d8b9e +a674b04133f545a0a2936767d6cd6bcf +01994d08f4834acd9734f1a4281570d8 +db31a6c16269415cafee6c2fe7377fb3 +7d1349aba9e346c592a4f91bfd422a20 +556ffc27236e4083836907e8f4f8068c +3ed9ed041bac4b82bf83552cf55e42ad +d5e6b6a11da646f68a5fcba661dcae99 +ea320c1693164d65b12322b478991efd +13f29fef23f5432f8e179118ae3c14c7 +c62ff270518645498927808d2adf9208 +94d7326dfcde4cef98939973b670f817 +6935152ccdd84bb3a900853147b35582 +5bca4779ad2146c78fd2d988b055509e +0c3412ab9a1c419daf79916e9c95af90 +7bcf8626eaca40e592ffd0aed08aa30b +00b360de1846428eb5c23464824c5fc8 +3396e5219f4649699bc3b357b21e72a8 +d529aa542b134b0589fee1f67e2bcc62 +117d56b0f6b94836b9cd750a9b23bcc7 +22e778c9e4604b35be0394b04024f94a +6aee0ca57dab4e33b93bcce375d0ee43 +6acfb5d8ccc44fa285121e45d4b25bbd +47915a64e6ea4de6bd5a747e27b0af32 +ddf090fe8ce242b498d4ed73cae4d0c0 +d63568fef8e94cc8b47aef0aef1c1655 +efb3ef63a12c4b16b5ac0f66bbdf705d +46cc1ad784d54003b15812936065a2c8 +112e8e061c3a48f7961d54106132a023 +c9c96db118264616adce39b362eae928 +e38d5972b3ec46a9ae0468435b5a9f14 +7dc297dba30340ae932878100dc12bf0 +fb0cca0059504c9d86400ffdbd79c3a0 +9eff909d56c74282a94551ccf38844b6 +0c0f21264142495fba769234e52a2f71 +313f3983b52e46baaeb35c15231ab73b +27c73eabfff14bdb912f467374119dc8 +cb15efe40a2244848c7426ea3219a47c +713a1d5203a1423285c789fa0531ad62 +8c9878a306294150933c72ebc8ec29b8 +54a8c3b2389346209919b86847252ebd +457e8081034b41649f6ca3172f6ade43 +c3802314587c40a4b705918346aaf622 +dd7cc49db6d24c4ea8f82c3dd93310f7 +7d9d047ebe724ec1ad99f317bbed04d4 +52b2faaf84ff4300b64195757976509a +1e1cf17d40d947deaa25bfc48effd1b0 +fa671dfbc7b6409ea6e8499fb89a2f03 +17540961a58a4d2bb29b800d63bc58bf +09db57200829447582394cb481ae03a6 +ad43e7cb927c4c2ab9951bae44f5d1f4 +3a9d89ec0d6642ee8a8fc42a1361c701 +8ab20ab8b3e549fc97e48923c7f287be +a12d3ae76e3944428f14e5b15d4f0efd +82268b0aaf6542d885f563a0f5b6c578 +31c33bda343346ca956c4adf480fa4fc +684b3d859f924c229ef67d0bd8aaf4b8 +2709ee3458884f8ea5d50630df12323b +101dba022a874617bc6070dad742bb47 +f49cc71f50f541829a48bf55b6cc8565 +5251ae2bde074e7a8925fc38141661a9 +e1d2eda711e9492c8be09b22c21fb4c4 +3db978bc04f84b20b88db8c2d787cccb +b17f1179fa6a4934bc03a796cdc4c8f8 +f43df97f35604021abf9fc6e5c14629a +25fc9ff88e5d4622b4e534b6524273dc +18d4d5a8ae0c4c49a94248a0b825536f +cb35450a7e2e4a69b8daa7910b03151e +a28843f21d784fe98cc220ef0d1df478 +86ccd4717a3e423a98aebcca7fac3b7a +77afe4274c794316bbff767eea063ee3 +fdd26e2f4be449c19d4d1c9f0c390cd3 +9d3be49270b74c2797c3b6bbac4a3722 +04522ed29d154c8ba643af8bd613e357 +bf9c9182d5154809ab05105f7c2469f2 +f323fedacf9b4b15be6987ea02b41740 +708cefb0cf1647ee93fe5f43622bd0be +a43d52fc78cc4d08b1242010ea9a20a4 +d187c96dde6f4c90950adf622d1bc4d7 +6ebf56eaade94c5dbbb662cf434ea58b +5cdc4fc134e84a8d97fb2d3ffaf5c5fb +b347e808f561465dab568fa61734e262 +95f90e93a7cc4bce8e813411e0c53483 +9490b6ec7ea34b19a204dceca9bc6af8 +b95b68673c824c8ebb15e16ffe5e1449 +665c7225bae7473cb65e79be3d7f7d42 +958a978869c840cfba1dba51c4b7542d +c4560059b71e4db1aca2facc2070b927 +ab1fc61c834a4195891e102698b09b57 +b7824aaee9a44211841f7ed8668b1dd6 +dc79f4e55ed8462e81ee02c6a01f7cea +ce0b00c8ad374d748929a8c418609993 +a49887894381400dac586e3a7f21c4b0 +c1fa7c935337414d822c1cbce8b7380a +ccea7e2e68c943b6b85cdb93fd9898f2 +42c9bdc4d27a418daa19b2d5ff690095 +050adf8979da45a29ae1dff03176a28f +17d4bd4b851c47c4b0c823b785aebc25 +2b23af67627c454681d8080e48904c1f +12c583dfa09a4ef2852eb27828e50626 +0136bc280f0d4977b528af83bd3b9642 +d29b016cd35a4825881e4f885c855f14 +8c9d0d9ddfb142c4b334780cd44b3c2b +7f9164e6018c4ec7a3585bbf6e6d70df +776462432cff4d6f89ec50d6a3342eee +84325c5b45a94969885195d3aa4c05ea +9192bd2690894998aa7ff04abaedcc6e +b4342345041740a7953f194361fe8e39 +00b8be166dfc491b89a8dc5503e87d34 +78d7972d52c54036aaee0d6af3d07d5d +bef14138813e4ebaa289b8a0a2868a84 +03f16302c1a54c46b438dac78e9d7048 +3bfbab5d5aef4be9aed5763111a989a0 +ce4929c6ab96465a929ddaecf762b6ae +55a84dfe45e745cc9a84f0e7da17f858 +283da165bfab4476b2acea442ae43ba4 +1b10b96e94634a7aa50783c4a99b8805 +ddd382fba03b4732968dc43256a69201 +ced850c3f651463b8c3d3ef08bf6db02 +bd7c92058cd143709b585f6a1411eb23 +bbdcc16a4f7f4bb1a4d93061bfb6d0d5 +f04ebeab61344bd6983108a32a7b3dd1 +49c68a09a3ae4eccbf6990394e1b335c +20aeb851c94043ef8591d147b0f4f25a +3d1fd419dcae41b3a3bc3869d850df79 +de75f62fd597451d9121e970429a313a +daf4bccecc2b4aec8c4b23f0fa03fa44 +2f1c112f6ccb456fa633e9902056d488 +200a6976e0a94c1f9c2ec4f64e0f3272 +ecc03f0875e34a0cb2e66c40b22383e5 +fdf8f4480d874f4c8cc2841727051da2 +3f43fad9e7714788a81ee27b0a39a4db +eb353582e5174076b8245ed823bef9e9 +a06d8af625a94434b9c35a9be70c441a +72ca268333164e59ac152cf401570254 +15b103f822ef4d92a386e95746a9aebe +d9c4d3b44b2e4e4aa24e360c9830c0a1 +4711c516a9d04f0c8892752ad82b1f12 +0b6766c2df0e4901b8c387283d544027 +fb882b00bd864d0abb808635650cc59d +d28187d5ff084832be45c689ebb3ac20 +d75965a9183345658c0b850c0d6b61ef +d0c641cbd3e44fbcb66a3bc9febeb092 +ad80889cf8094dfea4e888735e954ef1 +6a526b42e6a34a4ba12136a40d9a686b +5c1723090dd3487aabcb2b2d5bc35c07 +6aad34e9d1314a8c912aa43158aa039a +5af966079ae64db9b89dd826ab6b54aa +3fb280d6294a4a32a16249f4a1a62f7d +656f83a4d9224c29abc82ade2207d2ce +b17745c765504e75bdc0ca5d4d0192db +4d7ed627b1834922bdefafca91e54796 +7b396a16065046eb8d1bd6f528e82914 +57a31b618b2749c39a044fe3b24ab27d +0061788e0741400c82289337a24af4f6 +a0b3b8e2850a4b16a41ebaa496c566ed +412fdac55c8649a89992dd52ac4d9e19 +28bdcfb71e6c48a38781cfbfcb4a0cef +89b80aade5464af29e6b6b98cbd44e03 +d9d7989ac61848a09eeb60708dc0d941 +72ac90816f254c78993cee96411af1fb +7368207bfc9c44f4ad874d0383bc7815 +cb9298397f6341a8b4a547613367bbfb +f8f215d62e434cc093213256015eebef +6b7dabd875054f8991a4d977f1af1782 +0228adbe91a94b6894e570b26c0dd040 +b01d81c8f6d341c389b3f4dba84aa3f0 +7e3924420f8f4754bcb28ed0b6964b3a +6354119423d14471a803b77aa539b2eb +e82e5ff7ae9b49d9b8ff09e7067b1ada +c048fbabf7434dc38cec01d95897577e +d5559c1411fe4b43bbc337b6e5150271 +1d8aa893ef974efca23209d70170109f +39259b33b5b24361b91f2211f3e71691 +83410495fe7f498c96c752c04ae1da23 +8626d1c71fb647ad81ef71efb0ed526d +0b771346e87045da9daf425e6c2319b5 +b9643d6614c64b80a9662aeb2043f4b2 +d1b991b330bc47e7aaca98aad8ceed2d +2f5e0e395155408fb5a3726b61e52a12 +238162014a0e48f99b1b278e237d812d +3d1845c62a6e415498e8097520d8b3c3 +8a4d8565411145edbff488abf191592f +75fa365595564d68bcd42e6141b68a78 +791b545479544d168a5d9e744517dcb8 +04563f114c6e4205af0d34051314f876 +2c88306f3d724a839054f3c2913fb1d5 +75f6eec12e024cdf88963e47be4eb44c +cb463b231c9f43f999ba9bf02204865b +d6a1d8b3aeab4ef7a4186e0c7eafdf01 +e99aa48377f34857a7772d4b7892cb19 +312fc1390307489290786c97591d2bb0 +967f95cc38a445488fd5861b2ffe3512 +f98bfdce5d88400b938d2c984f106945 +8b51c922566b418bb0548d5d99688bdb +6726e38c15444d9f8bfeef1b2f9627d3 +70c51e0167be4af9a6d5bc268b149f5b +f1d057e664dc4970bc7d52398d8fd0b5 +0bfd91e18c5546d59021e574170c2bef +80c695a82cb34f39832b9585c965d923 +cd2387cf2a0745db8ad4713e2ca9b9cd +f256203558c24ea09385a861b917c75a +4a185716211446a3b02e77257065ab90 +cda9d8983e4e44bfa9aa176a079d676d +2c0a2a2350694f7590859c4ac32b5366 +f66278f4340f4f488ed56f581b07c5c1 +a2d6754a990c476c94f07cd98b12cf1e +5d796486542747d6adc8468f2d0af01c +27645ea2c1774f12bc0a167b54188621 +52432f571f904785832062171cca0f9c +3b4d8e3ac5eb40d8befcdb6e5874237a +fd1091cc07a842e285b92972ceab276f +fef4f3e831e64861b94d5e25fff93f35 +0ef0504cf59a4dd2900de194effee01e +eb3da58fb8bd4408a7901823387d29da +f1121a2715b643fca200e1a7047c074a +ca079c2ce1414d7b8a6364f4d200ef76 +627f07ff02df45259f86ad74c30f6745 +6ee29efd354e4bf291ee4cc06f97baa5 +6251869752b54edea1616104d58035ec +f66d5b2fb00243bf962e25334f312f2e +eba77c4126d2458a93481231c4831b3b +adb3f4a93ab84e25be74441ddc3ec0cd +a8989077813b44e8837fa1b283d3c050 +6db3837f2f3b4cc5b9324ed8a34c4161 +35b0a011814b438a85ae8fae5961fea2 +7bc441e2c6cc4fc0a80a548fa4c68260 +4e9c3cccbaaa4adc947ad8e8ab351d0d +6d64aec1c7434acfa04df8d11de67a7c +97efae7bf22842139ea0eb3c2a0bfefa +9d35187c2a19484297b7d88a6399ef6c +8beba6076f024a5390ffde336e91577b +96b035df0c4641e39614db40c535000e +5f7d0e379137459fbe75a903378ea59f +ea50c83418b2428fbfcb26282f0f277a +72e737a82cc24b78b66b89b09abdb2ca +6ac94462b21549ea8047228391f1239b +1f75786d2bf047a38f3971d7758aa990 +8bbefe57330941c6904f4e4618756553 +e12f46ef422844a7b3ef84cd9334cf04 +8552bf76b9a6434b9219b24ed8b905e8 +87bd7d269c7e4c82a1ab1521c13683ff +fc16ebc7d0b14553bc617033b4234936 +0d1b8a42f16049fcb61a28cbd2c57376 +3bb4f120d0df42fcba3dc4f550aaa9e5 +2cdcce5cff3d4aca9cb8d939137f0539 +4fd156d99362453b9592f6ace5344765 +685e148a899f4ceeaf03cb36bf891286 +f4d536baf41d4d1c80b89bccceded00f +d3c586389db44a31a3736d9009c08152 +0eb49f0b8732427a9f259040cef20366 +77b75758cac54200bc9bffc8a74e240f +18a797777a8a4da686960575de652d8e +541843465aa847e88e5aad30826359e0 +d48a903d948345e9904fba6e19345f85 +1fe98aa872364fd5ae3e8019695783db +580ba3b412a24ee29c62a9ccf6bdc80c +9b1e09abe5e34d6397937ebf59901898 +63d085ac43ef4b97be0202e1e7836104 +4e03a02d6bde492fbc8804b2e5b15c2d +b223a494c7d848428e37602bf0c2197a +0acd00b0410c4600a910899bc277b039 +f045c03591fc4ce2bf8c6abb764cbbd5 +f55671ec28d74e28b5f28e9fd906d8c8 +8f53709f9f41453ba11961174bcc7569 +ab15b3ca2356422eb463c3662e6e0321 +9bcc9cda7b4d4db79ee6d7d105207f3b +ff0dd18a3f264ec1bd4dc3f0fcc0209a +319fea7255454e66970fa64b681c517e +657e9abc1b564840a569bfceb1cd580c +70d185b09a154c799fd6f9aeff8c9579 +00c3f6de0c5b494bbf2885ff99ee6b96 +665aa05d24e54e3bb5d0f01ac52ce9ed +4cb3b3029ed142cc9291e83e93a293a0 +7589e46002e141daacad5bffd0ee803d +a8f94279927d46d9919ff3775a834cd3 +08708444f40949d697340fd8f9d7cbeb +2852ac8cf5a04333906a76f163fc0a43 +5798e024a3eb44b3beec875d8439c752 +caef7a1957744472ace263fbdc343b8e +f2d9d794171d46b89217bf01621b1e8d +14734817cb074dcf954acfcbc1140885 +06fff96209494977ab54fb95ce4cdce5 +3a0feca29d0140b89621cf80d1d97a09 +d29ea01da3ab497d8c0376108c419c18 +7a46c16e3fd1464ab598f6d6a5d17230 +df15298d3146457f82f82eafa1407c79 +467fd3bcc8b641f488cbb6a9d9e3520d +4b63af7c8b4442169c6f99c061085173 +2807c0032b494f9dae0dc9db3823db49 +7fc92abc3b6a449f881c6baba58e5866 +c10266c3ff8c4fa18332f03ed5d0b3e6 +91761aa110cb4a9298ad28a0112b5d2b +e2ae4d405c3440169f8b6b864de10d65 +6154520a963a4bb099642482a26aa9d3 +6c18505bd6be4ae9b1fc8b04fe96f026 +68e1accaf93d4ed18048c2a8b2c4fa95 +7957e646b140495089e79720e6aab917 +8925787ea2a44f238f0c4ca745f2bcc9 +c5ebbba0764a4a9c93fe957121893f6c +73665de25ab24f0b8bb334f2832da6e2 +5f998c0df25d4229a17e33cce6bfa0c4 +eae19856cb164b0cb2abddcc2e3ae3e9 +c470116c9a10405488a7e82b8a86149f +808576397a6143f695e84fa32194066f +c141e600831f47768acb5fe5a585218e +0c55f179b04541e581bb6973c5e1c994 +a3fe0f5ce664467a9ff0ce0c17933316 +f13af657734f4eb98aefb2523a0c487b +925ed87334c743328cbfd8ff46de338b +0ea33b6617174530b97d6b7a92c275fb +e21050bcf84c42afbe6b219533871371 +5b595bb41411426792a6491202aa38b6 +8c6c6356a7a648d79c1e4c050d9011e4 +af78b89b4add4132bb3bbdf5ec263cb5 +be46b9d8a13445ecba889449b4c5003d +c808b6c4239c4bb7becb3124c4b3543c +27a3e46fa9624da599a868eade2dc263 +fd45bbe5177a465b96dbfd3095cad7bc +b78d74efd9cb487fb8e90d5b03e4652b +24ce2e678e714c35baacc8691a5d79cd +a6cf4b8f85274a929b3e63f260492391 +67b5720fbfb34d9db5ad24a361b6d041 +01d5fbe1cfb748569ae3c2ebf1f1abe8 +ef7e34822e60420ca3a3a6d4a4509a95 +2a115610451c4bd58a7f79d11a7bab61 +25c6874d173a4f6ca63e150bbd505686 +25ab8294e60146e58aba0ab11278b4ed +5680a17f941743f3a56fabfbd8dea3c7 +f5ba42c4d75747268b9883b7c57a5669 +e6669ded739e43b2aca0b375c2d0fd0a +65046419ec5243ff862d3408b71472b2 +d5c94ab29a3342b1bde11702c5b8e968 +771a9b875a1b4baa91aff1d3ef4afabd +d68a8983d9b542e080c3a9483d3746c7 +9ac792db0d464cd49b1e581569af61ab +cc22f952842946f48c1b126d73320389 +c66d804313c549818cee3e795bc73aeb +b18a7d6210ca466f9dd9ceb8e1675a58 +15a85ff13ce242318af466c9a1caadde +4600f978c9c5410bbb7f86eabf54fcef +d8ebef3d836a42c2a8b00e7974f6c9df +aa422c90af77408f85e04df090e602b4 +8d8e00addeb04d858054f8650a770683 +3a2a7c597431416aa7655da8f747424b +451f4ebe5318469db152d089909c905e +b0aa6d2278c94e29abe44e93d972f3da +925aa367e025473a88f3588b02def70e +d2c6dbdfac514b01aac842d3f89a08e9 +684c2067c4e2425a927ece2acd11107c +0a0152cbee0d40dc8289eb9118fcc35a +07850a3af3514bccaa48c8ea450a5df5 +a373f7f69cd6454aaa69502a369f2494 +73d21c990e634589b0c130777751be28 +0c83005b0f9741a48730a4b4d2e45173 +8358c7e52d1a47bb8fbf80f543f96a0e +38dd2481ebbe4ed6b9d494cd2d1cfe30 +3f08a53550354e99b991ec2d43ff2751 +fa65acd9358f4e639e5ff13c66aff2f1 +a6ba4ee83fa84d11929a1135b8aaa4bd +fa9279bb070947718ae1a348c07c8614 +06a24fedb24d4114848c5b2adbef6220 +4baac09eefd4495e85a6b931d6437315 +621cceadac024b498ef7047e958cc336 +d654768b0a624940a8ac1f0be7319a8e +2f8aaecd33294c5ba81988949a937667 +ab423ce396d94e05b7ae421c4acc43cc +aec2924a4e9f44f9ad569717301e30ec +42a7a81a2217433db481dd8bc8ccb009 +c6618f5d3df8477ca2fc6808688deb2c +4bdcfe21d93140b19fcf056d20e3ba83 +cddd741895e6405c98de8501461c8bbe +39e4f4ca2b7a4d528986dee97a5b609c +392e2810e1e24b02b2fdbc1dd3f21064 +5be2396518564f10bace613add0f1711 +563540b49d2e4033a29b829595863fbe +8445d7c3a16d43d1837bc8a07ab82d0a +e2485d989591462c85c4eced4a6cec4b +a0a1eaf4185c440c816bc085f1af4bfb +a590d257787a4da78077002d0257d473 +8200f6774da54686ad6b92dc995ecb00 +29c7f92167f3476a9aa13029796146a0 +ee404b76ff34479982385a08441bacaf +c8b35d665a0a44a5a55c005e0c4ca9f7 +a898b0883f14450abaa808023afdf5e3 +ce421f10e46d415198d5d19c5bd265f2 +9c83100af67842618427560b7fc2580b +58bd57f213b7433abbb9cf0c77d53731 +aa8d7564d2d14b24bf89b2983c31a942 +699d0f6476f14be1bd9193cb16344ed7 +08bd8ca1e1c34540bc66c3e1d4f7f287 +63f27ae01a164941816ca9366c4062bf +3b1ee117fa1742aeba97f24b1dee75f6 +d6455f4f705945edb80642d1e24b4753 +c0b8074f7b154df2901144a2949acdc3 +013cd050d65a4e828610e4755c659729 +2894efe73dd340bd844646c8a612fd15 +46ab248d51954068be28e4be30c83ebd +ba705749a39d4f5382b265c7b157e962 +2f97688375ff49179223195c2b5032ac +a84e630e96b54f3f8e32064bc9dd1256 +a77f8c86090042c1973db829e3fb8b1e +f3af5b9bec9544b49f556dbe35b69ab2 +c5f8ada1dab549c3a1c77997dcea0ca2 +a0d0ea06fcea41fd843af40691e85f34 +08acb0c266f14531a7860463e66518de +054738a828404745b7333877f6f5e0a7 +58933b9685694c68a3c9f7e713d35003 +d0711d74a81040ab8495cc5bdd5f7369 +496270f009aa48ef9145dac2938b3403 +6a53dc2e9da84da69f709c3e665f4e5f +115670d120b7496f983fb7579ce14dcc +48694528de7d432dbde413b1adb2f85e +b8d7ea9d15bc4ef287904de12f1d4466 +38716613af0049e6bf0e54e71005e43a +59309f1dd9f54927b0d232a1e9de5ae2 +7994d3067a554e4dab14e88af242f174 +b5aece830f74464a89f239d656d9b4b3 +ccbcab6432ee46f8a56ad4544a490292 +aa584c852bd647ca978d7f00efc72c5c +104fa0c1723e477bab1e01c9d6ccfc5e +5d171aad72ff430487528e0f796db348 +184f5c59cc6b45e8abf85b8d10257add +718486a85ff649a5877110ddeaf27b3b +43671c36a613433f87b54cbe4e9c1ecc +950f1d50fac64c3a918b260deb108479 +3d9f2c89d3b34869a57550263ad01339 +7435f8558e3d472fbf6973e20b76567c +dc6dfe9c5a644082aa6673fde4916da3 +2aa050ea66254bcb811a00f13da64cef +d63fdbec56bd49208c17a9c9d1501629 +4d4b59e8293849a3bf79486a171b187a +b6a6865d41fa44649b1db7841255c2fd +ee1843c4778f4ca78fd2b116c20dd9c8 +4a056ba4d1ec48e9b4d7f30646f71052 +fd3afdcd22db4ce4a86c7a1257850a15 +d8e22e7fcbc04c4db77edb9df353e0ee +cfe6d514c97c43aa828816453e435c6e +e8f001c6463d449481252993c6414731 +1379bd87b588495fbc1436f46dc72f6e +fe80eb65469d4eaaa6c2186f4a672406 +6a049f880cb84d26933ddaaed1221329 +15bd6087617a4a379953550c56edb839 +3f80559dbbb6426b96ce7f4ad92f1a60 +0fd825c764c14c888d37228984823ab1 +cfe4cc34c61a4826b632f0efc2f5251d +ca9f04807f47442fab1e6e53279d7193 +56e2e01977df4650b75e0926ff235d34 +706732962b4846f38863bd28c8fbb1f9 +47e3fc610c2d487c98f37d6932a8ae87 +6826d90c0cff487ebff7282b1adc691e +ab88b5c1359e49e9a4c4199522735e79 +9dc563087ac64563ac8511a1e7d90d24 +d689beeaef7b4c92b2f1aa18a8482a5a +b80a2a5fbb3f4372a0bead029428fb96 +0637543be6bc42a89d8c76b08395b6eb +831dd489b8044ba8bb77f0ca253dcfde +0916c6ada1de431184bed899f37162e8 +35e60221be2a4b2999dd5cb9eab2c797 +36b38a6fdaf049f1a911a262b714d2db +b1e1180578d74280b2273e56c757addd +b2eff5a26f5848f8a10a58aee420d0e5 +76b1531b0cb74a42952575bf02af5ca6 +14abf9b637b64ded9aa2f74a472f8eb5 +67d4fe7e54104c6d90fd61ffb669d921 +ab02325e744d49aaad85c95f0c73786a +01dac0f367544b28a32ef3e276e3106e +152ca55383b2491e816f5ed5ac127677 +964aef818b3e41bbbaeea481be857af8 +9408ce8ad5fa45e1a8430ca58f311f22 +ce8ac0f5d678497eb34b2d3bdc5fc0b5 +7e2fa860ab9247f983657aa39a658726 +f2d34772149d46fbb9fc4f8ecb644e77 +bbd515ec9e5149dca308028b4ae1f8b7 +41470b26f15b4eac8dabe8a06f49b1e9 +4e3561477ea04c93b793c8da253c22db +158970a7d7a044588235c2e73793fe41 +15fb293dce6c4a9294d3eff4d455c9eb +e66e65af490642d9956a83d330320c01 +8b52b1f4c4c44bb9866146f60dbe534c +94eaa3d25028483b92bce8b4bc3e6e6a +84c1d0285e974953bb5f7c7bdf07b447 +7bed8fa479dd42788d122f93650b6194 +d188cfba30b8444788802b3830321e46 +fd6e07cfccef4b5aa6416183cb54c13b +544ca52414a848bdbf33794bc04752e2 +b3e28c45c71d41918ac94b927327c991 +4c41aef7dbdf455b8b8edaea8f520fb6 +7847011972fa4e4b8be0c1850ae40837 +15621a3fc76c4c78aa27ba48c7fc4fb7 +0d51b5b5444c4f08841dedb5cebf14d7 +e590553ebf174ab4963036f805e6d809 +0a5652c16e1a4575903dfc1696382502 +5e883726c95a4536828109d5b94483db +ac123823ea7c4bc383fc07efca43ddbe +f8a64f4c4cdd46488e3beb823d0dce37 +40cc72ae63c94ef7bda1610610942a0f +29e907cd254541c3ad8b42850e9ff504 +c850aecde41c4b7688c665ef8b8437e9 +86be8ad4a17646ba98a5326aae12bd43 +62f7ae66c3424809ba563314a0b52c7d +ec1caf01495346a6abbd7e833696c5c8 +6067c9b24fa846b68b119ddc2a6303ea +a7aa70a9ba014d36bd2661a261ec6029 +43f463875a7c44a6ac6862dd10e82e2b +b9dcd9029f1b4e91bdd3cbdcb45a18ba +59bc3d3f46a44d5ab506bbaf7ef4acd2 +342aec05aede4137b874b2b4ccf3ed64 +84c23b63fdbe42c393fa4a96a68f4ada +5f5940f6ee524df9b9c27aa59a7f613a +5f4c74fe57ad428ea6ec4c2412faa816 +3071a0b4ade44e7887f97664152575a9 +3c0a4febce5f4c189b25e3463ac18c66 +f4ee0a91d82c4e17a880c1052ca4c8d6 +440bfda47c0f44b5a8cf4c8dde81ebe5 +cba3e4df7c354d22b7913d45a28a8159 +8b685bbf798947b9ae3d06a2133942fc +c91c976f9ac14fddb902f9d655a8b2bf +fd4fbe0393b64ea886b677ff5f7bc97a +8804582d562944639552a8fe8bf0de50 +bee48f52ffe5407fab1f0f8b206f4424 +508e5e6c5d04417ab36fa02c703e768b +75c722d279594dc08c35fd5b2c879d60 +ba394828546644b0a2d5eecca4b9a3f9 +a039edc2c5624f7b873a533b170bc9bb +364298aa0f7c43daa104200ac70b199c +28279274a7ba4320bf862bd0360cbb7b +7e11d6287b874f908ba40697bf49e6c6 +18318af2ad484641a2be603b41a94039 +776eb1b52e18447c805e4628219d3b74 +57f55dba6d81428a8672019aab2509e3 +ce26b3228816472fac46366a560b488d +817d7cc7e5c447a9ba8ce29a86bbb531 +ad4a4b2ac1ab41f68f573f2b387a278e +629cd7e55be145cf8fad5735af63ea33 +08157e22487e4cf6a319b6023e766a3d +9436ee7021d64f4b81845cffbc0d987f +1c19c1e1c38c4e1b84d6d420ac312cea +101fafbaaf494d82acff69fbd7c2d6fd +e278943cc81449ffbffed19e5fb289a3 +fa809015f6854b978516741e0bc00ecd +95cac75020974c0a92d35bbd8c0ed0e7 +b6329d61cfdb4ca6a336c3ce9203efc8 +85611a5af04d4a848c3efaf3661716fb +321c736059ef42d2909dcaf10a8c25d8 +eb2de2f0434c44c9bcaa9ddd76bb8acb +9df0c703101c4ecf8b1cb43868ef782e +6aaff060849e413d93f4166ba934abb2 +3d442e50799b43e98d5fa5e3c81e8b2c +dd7b64ef3bb64e33afefe1aee36061bd +38a262b29d714cd3bb9fc45baa74e1dc +9820c165e450447b8b3d5060b3f5194e +f9aa5e60b29d460abdcf6fd618297621 +0ae58b68696843fa89548626d5d5f674 +bbe90644fc334d75802321de09413f43 +4276245463f54fa8be7f26151aed0876 +6cc9a8fc29f04adab3fe8b008e498e50 +38ba247199924158a8f84a6ba88ce487 +ecebd5c1be464d2aae52df96f1e547a7 +0b3322f349274bffb294e2004ded6ff9 +8d8a605ac22e422cb14c0c38abb7db44 +c3f760e21f5f47368347c1b1354485dd +d64895d7ac2e466dbf836674bacf5058 +c7cb831b5f9f4b398ec6843cc6b75afd +f07a192d16e648a09b02f73ec45ccc66 +4df5c828df0b4ca9b6ce73ff494e371f +dedb1824608f420c9803ef8df51a3713 +8169c87768c2438e95fe1047516f3bf7 +68b2ec30fdbf4780a12aa7333a9e5188 +f05320715d3b4eca89b4bbc5fb8c3d39 +7e7309da088c45ba9e1f72b75ceaf043 +21558c36a39f4f8b80eaf727aa5727fc +eac715e9aa034efd9f7ef3a584503041 +1898d80f359d46f898b4f81b37312a32 +3c3f5bfb98284924a70cf410ab532bc9 +695103af832e47f2809f3888373bb0e9 +92f9aa47f68f4a6c9281e0c88034ece2 +3c6ebd61910d4f74916d61c12ceafbc0 +de95f8b961c443d7849ec536b39d1b12 +7ba92c9b49aa4a3585d1db694462f918 +d8986fdbf51d461aa1b71d16297d6b19 +5f740bf3f52d439e8e9f8bcfde7e09f0 +4feab852e1074870a0cc8ea5bf48bb4e +5bec36e4ffb1434e8136088a6314bb6c +491a12adf44d4cd283d32743d21ea683 +f4f34692c8af4a56a4c7bcbdc780d9f6 +5644ddda1c2d43f29e7d97a2babc09d1 +1dc69ad0354347f2909e63993a486bfa +214671c96c5f49b2a1927d1638f0fb47 +072f50ccb520425d859608f1548ceec0 +6c1b44e0848347299aa3676d1de38a2d +0995a326f06c48619604551320215798 +2058f14b03e84aef98cd36cc0fdfd99c +5ee4647f7994413d80652e10090d380d +59a1052f5b28442e9f7e2ae66be5fa39 +1bd71f8b45204cd8878883d8fa1f9f82 +df57b9ca44394d1891a1278bfae9cf1e +acd11b98bf5f47309af91b913912c26c +6a7254f24cb043e290f2019f34eb4325 +ebf89ef157c54692a5e72d07986c618b +fd6ed7720d974309a90723a6caf83876 +3fc32f374cf9431fa36f735e414486bc +6da9a1f9d1784030ba18b02349229a62 +8c2deac5610e4b7481abfaf9aa907685 +15837138fd4c4932a654bb41ed6db5f1 +419a105395644219afea37b78d5c906b +db5a7d5bb378480bb40da086aab44c65 +966e1567b1e4421e8de70616cba6420f +9b745955aeaa40a996999e03976f58ea +b30087d53f0f4cc4901014f4dc37bbe6 +f93cbc21279d4423986d6d84ca4ba74f +631d44691024464eaf1eacc6ccdedd4c +bf2d05741b244d34a86d0fa6ddff3cef +e845401a16ba4ba9b7ac3f2dc6237de9 +745dbfde6a2e40f88d08dceb94dfe97b +d8663f24062e4525b86568138bf9b378 +a7830bb1abc348bd9390d126648377fd +a0d141c60b1a49b3b33d5afd456291f0 +75e1a9de3028440d95e146223e7ca66f +b55b9acad32b4ffe913c90dfcaaeec45 +bc096d0ad5c64ac1a48647200fd559c2 +c38f02c4944c4a5ba11ba51f66be9572 +3841c5c38c5640318fe5415f8e404500 +d176fb35083e415fa4146829912c4e31 +f4ad0128edd843d98ce2aa6ca0710efe +90f5205c3bb5417a95069f89257dddb4 +da73f4b00c704d5eb44eb243e1593dc8 +af09e849435a492f839af78e8b2d898f +9a9da7e77f1e4216b86cff73352cb30e +6763631bfec342c8840675dce2e9302f +244e006c51f94c63a95d501de5b62360 +774bc66d11c24855bf722e35249fddf7 +867d9ef7c29c4e5eb06b88ede2198587 +fc0de03866ae4bce9e213087295626d0 +01659373a49d4ff29e6b99abd3b734ce +e9854400c0c1410db01c8db897ef5359 +8926f6be27704713980076253a78e057 +712934873dc242f385c17ff6a272b1a6 +5007d3e9f5e94a90982078f0c4c50e23 +d732ef3bc58a4bfab81613c364b5fc4d +21cf6af4cb5a419ca00728253d290b3a +d2bd7596ef7d43adaa5017c59a280ae2 +daf5e48f7578470cb309cb1797709561 +233c3aa86f134d23a333a2cc49acb04e +7e12ed2519704d25b995c59884e62059 +a22bcd457cce4ff58bfc21de4f0fba02 +db358e2fde414de997f69c0984f54adb +223339de9de34ef0bda79697060c3da0 +534c7ef382f34700800f72f3374a10c5 +373972947ad4474882bf65cafbeec21a +b7ebee0ec2e44487b5b79e237a1afdab +6f52951e9a224929987a2dfeff50a315 +d796d6d4c4fb4926a3baacbb9f914b3d +d1f4aa651d9d4953a5a2742914b84635 +cfbfcd7142444471888e172b2a4098f8 +5fcce30de3e447dcba22c6d0ad841868 +a4c500d7358a4a199b6a5cd35f416466 +420fb4341f6847ee9a81de652957ba7a +98e4e35e21444a32a3e63008cc975ac7 +94032d9c7b1746079828b54b5d02c533 +914fa349f4b94c9691851d727b753967 +f4c122d7819e4f85925b9d1aab72a696 +7aa432d6815d4ac6a7ae319a954f6a37 +16dbce6f08404f4d8b2ceea9eeb689ce +ece9b0b818004e738a634294cbe1d2ff +d859eb1b182d46dbad4e1cdefd8255b4 +1bc2987dfc054796b5ab09f1bff1e569 +e8100bef7b8a48d4ac79684bffb349ba +cdcb0fa332344a32ad9f6ec81936acc7 +eb9354299d9e41b6a986ae9f7c3f6ca3 +53409613b45b42b98b979f12ab8faa12 +b2d47fad62064021a2334020ee121ab7 +d90e4353ae7047e0b4f37abc8bc58468 +a3ef7a173a9c44dcba0cf639f618e38a +62b7661faf0049449934786fde7e25f4 +6aa2ec8f845b45fb9bea7709800fc30e +7d3a25c1e14246ef868e2422b5fefe40 +627b2345d85c4625816330b60e7ea0e9 +1b0f23edb82f4474af49940c70a9b551 +7232408612424923838e8f67176056ce +18f8848d06eb4119834ace3ccdfc3d11 +539af081d1d649398a05e15b5eeeb35e +eec19e0deb6046cf9f909e63c5371203 +3020862e9f884a6eabe362553a76f575 +6014d7d241fd489d93003500709f3e5f +9272682c0f714933ac59202500f8d6c8 +1bf163160fa34a2bac8c9c6218675478 +7ea6582daadd4d6f9c685b5d1de07fa7 +53053c677f9d47edbab3e14c9f07c2ce +b7a9a04e62144bdc85d5580e594b0b22 +2b585eaa5ffb4117a58a29f52bf6a966 +3fe560a7da33420aa8d33094073e1684 +8b78239cb0a7415ab53605d1a8eb96aa +e80ad34c81044e499eacb414b5505c84 +6bfc709351b94a69a876d885a4cffde6 +09a4e785583044c782b43c4a18cf2008 +87cb0380b5c64e729474ad3a7c60ee8b +25461fb372fe4ed0887fca7a1de20f01 +f39323585e944587906c43398daa44e2 +0b7f13cf550b4d0d978d9df855c40c32 +05a035c3347645b8a7ceb6d65f825ac3 +da02455b180546f78f1eb0bb526aa5fe +caf7db0414454cf4adf7e8598f4954e4 +2bf69d6701024ae4a1668c17a4cd0d28 +5c417d039cda44dbae38ace2bd18741a +7b152150116445d9b7951ba0787fc88a +2268f6ba31dd4bd3bb17ad6b34a7545d +96a3fc052dc94c07b52109d71032fc89 +12ff5e2036c44c6fb709abf49b2570ba +8e82b9517681451384a1fd845d6e77e3 +a2c797a8f65c41d298d616f7a4110eed +21b53105b2634ef187a2228d34a7a497 +59d7aa3e1c4740029d47dc0bcd838444 +e9478aef8065474fafa7af4bd4cf36c4 +d5a5f0a954f94bcea3168329d1605fe9 +b1a7c5dcf8ce4c62a3c7bdaf8a4c6783 +93576531af4b4a10ba88bdbde9347fd2 +3d9bc3fe92934c998ada834711c1ed6e +619fb3582d704b11a3150a139043e0b1 +6ec724289a85469abab17058af037fdb +ce4340d8e3304435a461b1d78d44ea5b +c922aa870b0b492b9addd449cf79f5df +7a35d0c7b80f4ac4b48b87f1e04546dc +901d1a2e9e26465db2432939b35bc384 +7699acde27aa4b1f87f844d8465baf93 +f96348f9dea14859bd9c3a94ec7d118a +22dbe758a6fa450bbc73f65d4e599c35 +b7294b6b1ad64cc6b624f1185be8523e +3446229dce1f47528fa871cc7669136c +a128ff9bf7ef478991ab4ba8c95d38bb +f21a39ed702b4d6eb6ad043a63e351bd +32eaa2dd93f54cefaee5516f19d2f152 +4b88c020ea55433dbfe5799cd78002e7 +f4fa35b36f6c4a5e816ffa6b1e902d45 +b6c610357217437fa0cee2508e329e65 +fc27ccf5b0bb486a999bb7e206edf06d +cbfa6285b2ae4caaab5e7c2becf0ff59 +9be9e102cd6b45de81f15aeb21a6c00e +07f2099e739e44dd979bca87f0551d75 +6a8df6c3f3aa4631b6934e42c3090f52 +41a5488c67194a11965012514eb08714 +f4070203b492449f8bc2b43ae7946f48 +fca10e4c57f543fe8a5153551b551c7f +a0991f0d16e140268fa1cd3067e5a276 +995ec373d380457e990057e6fdadcfab +30705ef951a64da9bedd426d0d3aab70 +ce8be79e40e444709e31d2151b8d11a1 +52d34bb682c84bae855442833dc67abb +70076df786934605bfeed510bd1d0cad +255dc2ef5dad4ea98c2b52b9c49401eb +1a21f1d3028b49fdb290bd4462d7dd99 +270b9d405fab4d0fbb6fd29b43e237f2 +e2fd51f8ce0141f1bf3bfa2d7b1bf5ef +a869c645c3504e93a8b949f647e29970 +2d94ece999364621b858befc999ebb37 +dfa0ff6d319149f8a0b7c9a556ae1210 +ce316248e1994ddb9b47dfc9c2efaec3 +399b5aca63cb4b148019f9542a96ee03 +34d340bdbe6242c1b6483c41684262e9 +0c42257deeac4d45b134a72b42abdf20 +93b0857b4daf4a148cae4495f8a4b201 +1c74e24e7ce14cce982e9f2bd7857a8e +c230649ade1b475cbbe427c8d5a9b2dc +1c77bd376c0940cab3ec72b037a6fc46 +b58cfd8f0f6b4763b13a04c6a0c3e703 +3830341e56834cbaafc0ae8d62baca01 +2060a310cda64ca18db33b14b1c1d521 +9b736d751762436189e9e961c8277b2b +81b1724799d64da597eb9b312078996f +9baa161056964895aa72011fc528c406 +bdce3efc24c84724a4d9f50fe64e4fcc +46186923868b4984b5c361048f9b0800 +5f26c52bc04c44c8acb229bcc09a2d98 +ef7799bcdba043238c4deef9d2832730 +02eea1e2ab814436812f110f3e4aad6f +163602debda546718d15cdb65d0dd7e8 +af936b0e9b6f46c187cee334e957519a +b05c34706e5c4deab4fc22c7d3b677a5 +59ed9da27c2d419b959fad13027a0dec +b2db46a3cb60418ead8e87f312797561 +a33aac8ebefe48da9117c921095990f6 +3cd9c8ec6d914268a8ebb87a135af44a +bb89e4a8edea40fab1b65e8e0f6519a3 +615c41572a98410d8a8b15a9f9bc4854 +a5ec7346d918433d890ce66f5ca4e148 +ccbeb0fe3e1f405a82ec9c4538ea8c9a +d806163447c448328614d92545eef461 +e1fc2e71bbb84cb489bd6bce11979c2d +79c95bd9d19241f091f10d852c339ae0 +a868e0d715f8421eb3d1e9106365bc1a +04496fdafe5b4d1aaf60e2edf26f85ce +2aeeb8958bc64240962b093705abffdf +ec3d039cf5aa4f19b71275a2c66536a7 +5c14cfb7dee34b34843403d9ba420743 +7d9a7b7acba74b2d8f232a65d3d4f8e6 +b85a2aa933e94f6786cef691aa42adff +d53bd92890934d249d4ea2e099ae0461 +c6334399583149c69dfca2e4f8b85350 +744a278961a24cb799dc3dc76ab45387 +62bc3c79ffdb4b46982e8fe8c066c56a +912dbae7421b458fa723d72296991b8a +51fcfedb3c6d4b18849751ae7f2c7ab7 +962ef5773bf04418a90294483a3f741e +7b344fdb2ce846539cb420fe4d37fc13 +d21128282e46459d8e61cf8211113f1f +7ec228e046b84b89bf1edd74598e55b8 +ff9717e45a014315bebd5f88c3dbf70d +477f82df74674dedb22544d181644fc0 +f0f4773bc58149c68ef48d5dec42475d +d4d8b9a992be43ef8b433c6463c653c5 +a71cefe9b7c746c1b2fef86e28c994bf +1658ffe50e154dd8b830412a6f845b37 +90d1d5896adc45fc932a3903c2a65b1c +d8be00ffa4414c1ebe57d4210f41cf48 +e56eb6d72e564435a4204089a7dea774 +14eddfd59aff4c3689d3f16048fc478b +b828a4e728ef418ba0160dbb048b1104 +bd9122f48db44881b3ccfadd63b1d219 +f3f7d7e35ef143dcbf2d3f197aced4eb +d92e47c9fd7042a0abb5de6f056c09cc +5ec1da29362447e9957eabffb724bbeb +74b3cfffc7274bd0b3b4efef8852b1c4 +5353f01d845c4edca00896baa353253c +7db992dd324344f8a818aa7cc24e5bb8 +c5bdec662adc4beab4e925551a34fdf3 +330782d406964b9783d99b46b656d4fb +73551aa6ade44f5fb396f437a2f8ac52 +f0f8fd0862e24f95b0044c0423ec1ce2 +5dd760de1fd443748381874910373367 +ab00012a6fde4fee9de684f914702bf1 +fd6ad281b6944d90b26adb78f1f37989 +67598fc87de14e83961816d681dafce8 +cfe4fe307d0d4909b69ae838d6d184d1 +4dc24ce9621c49cb8d6cc50594b5e38a +335015fbbd6f469383e6f80b29d45cda +3598d9e686ad46dc838e1443b910d91e +93b14c97d75b42f0ab103c37bd4de22d +ee904511be724f0087c184e0b56c729f +99881ef3f7674d9db204fdbb69195a65 +2f4d7d754cc3403bbc7f8c2ed9f3de3b +04383a7164f643e8b1a5378fa7398010 +fabb3a16609b49789c016f9e171785be +6dcec535c1f043158bd766de36040c5c +cd6cbdf835564c91bb74a3c80a21b862 +53017a1b74634d19964bff04772beea7 +b98b8f64d935415aab0fe9b70074511f +40023055503f4248a5e11cce891f9a29 +6b3afe782b204dfba87a03ddaf222958 +66b40aabfe7447128fbe4126530e7e96 +83cfd20e5d814fde8bd3f9c0d8cedc7b +e39cbf7251b64bd6aeb5d0e01dfaa7f4 +d72ea381caac4711948ab868220a4322 +a9c8cb2c961d47b2bea5ecc6b70c7244 +382319dab129471aa4985d0f599bd48d +b8a85ace01444026a6218358fb590177 +5e8a63ad82944461ac280ce5ad8a10c2 +69cd0639a33945ec824b33ef3bf401ae +2e762d68e7ae4ac1a49553c03c940c61 +8d6818b50166443f9e529afac52204e5 +5b4c7522d0de4c47abae5d379a830799 +a1bf5853e3324d5c98d5afd44060f0be +6452680209734f9e9439b10704953441 +aebf93e711ea440688db27f3042fafaa +1765a8a8921947f8a9124badcc28aa23 +307a4f5a12fc4f799468bb6139a1be09 +bb0d0fc201ba4950961a366af66e1fd9 +502ff900e8ec4612acdde695650dd3cc +4808cdc0863346309c06dff414326c1e +8ab8caf90a0b4d47ac2dc7911febfa66 +8ef2078713b64532819fc7749fefc349 +513b3435fbe34a0f82440c9c51ef86db +6106573a3d8a41e8b50c4e189512a69f +72a06d293e7a48dc88f651e2fcd639f3 +2e83bc092a7e4dba9c7eac30243ecb19 +b5c94eb235cd4574a069f900e285ecea +f3fab17153d54ddfba5eb99e3259c268 +b44dcb3d1893406bb24e8835bd21e8b2 +a284966428304a7a8be43eb4a1eab008 +4ece5a37c3aa420d991d59520cdbb9c7 +b2440d84e734429680d57e557b2790d3 +015777939fc3429ba4b5343be9d51ffa +f9b1003886ef4211b7de70cf5df0bfb4 +25d61b7f56554876bae4b72c7be516cd +bc10ff32ac7343b8b0b5d71cece675cb +29832125251a44939fae1a21a3288f88 +93c4a32cccf44aa991b05b94db6790c0 +81ccc2282aa541cfb5577dd24c716bf3 +c0e5f00e1f3f47d2b19088ced9b85932 +1dece893506449fdbbe7c99ba7f51465 +f6dc2d3b77664e879f45ca4c9ec144b5 +6b00b5930b0f4516964d527ef0731386 +a36820f7ff30446d89e76a05a68d99ac +eb8f7ff9521e4ce48522f5125798fdcd +5ee3c671e6014f04ba3971c243acdfb9 +1522d7b6d8a14f4f8c19f996320fdc09 +4df589f33da6402b98a90b554c7564cf +f349f85cc4624ac1ac1b97062cf6bf77 +96d0e25b866c48dbb7c90d26298c91e1 +4b2990b08d5a4ca69d143595594716ca +96ebf942e78b474ea1018376b5ee5fc3 +835b5198d5084b6cb2c8a11e322ca58a +459fb07370e74a71afc2df4bdf682933 +05590035d2954909ab287208a42da45a +0ca534be1b5c4aeead7f539077734418 +fcf8dc63e22f4821a4006403f046eed8 +87765915bcd34a1d963b80a401b2bc34 +f34652448daa44c290c7b315d0c7d29a +c9cdde5ca1454ce784a8f278fbda90d9 +83848995cbfb4727b2b85ca713363d15 +941ff92e34a74de8aff76f66bad1c4f6 +a519aac644224af8a34f56b2440712a9 +8b220d579ee64c728d521b5da0eebbd5 +24985764343240ecbc680545c13c28d1 +e02123e2b43d4092820c8e78b4a48332 +6c481ee9b724465d82aeb64e3e417c54 +b1cc93ae04d74cddbea477a27e190fb1 +4bf8ad35caa84f12884c6f5ba6ad79f6 +4db405ba1fb7470cb2b9d43fd64a1d72 +f93be18847144f1fbd87930d2070cb71 +6231a1b919514510bccb67745bba4495 +b4853f8e7661447a87acc16705f61364 +490835f8c39e44049ae077671474211e +7fdad1eef0c2410480fd30f159cf7e92 +ebed102485f54839b28089344caf3c86 +128cb601059a45c2ba69b1823f94a4e8 +19cf952615cf48e48ed5d2128eb8b23a +4b8a97013faf46b0a86e1f835a5cc7c7 +5c8902cbd38846c695af531884a15221 +2f31db3d679446eca15dd115119371d1 +06bf1edc7a7b4a3486dae576df1e9121 +534da3d37c284d6980fd967acf2047d4 +28faa54f048a4463a48ea34d737c0b53 +e23540664dc34f938638e5d85786e13b +75f6dbd34b8d4622b392f57e23e352cc +63d36a28e7a143f8905869c06b2c3bf6 +d426eec602e34eb285137a023dfe848b +c489e9abec2447c2a5273a2ba62b6ceb +9b65f6aa5c1b420c83ef3eb05069e595 +f5b4c9ee88bd4172b304e1f275e3fbe8 +6d1e6f511aac48c286c83d5004dd9e93 +4e37b84aa5e1487ebb71c70f5142a318 +3a5fc9a496cb402297ffdb6700d2ab60 +62771a21b17646648a588b223afd6692 +f870e0b43a0b468c908dc1cb21d4f6d5 +69e85cded74144bea659f52af3e81b49 +14034702a8b54ca4ade8eabf0219d8ec +3d75ecc475504bfb8fa146ddfa09e3d5 +ac17cc6517d94ea1ac839dced28939fb +a4f9a93110d24298862e94ce1cb36046 +65091d727c074ecb8170953dbcf2af8f +f1482d733c074f98b1862345ff0188e0 +8cb702a0f818483690c6c73093fdff66 +05ef78d8424f49a39ca1562247ccdf80 +9efda05f8c90427bb608ec74614795d7 +69ef1ff3ef26482fb32f66f80ffbbfe7 +3ac6ae818cce468b8feb1c2d0084ec4f +d5d938791b30473498507ade5ad92066 +5914ea701e4648e2bc0d5c265b7b4059 +89247d41551c4909831b61bae5726d54 +f7c762e84f18435fa639e20f61b792ec +0ce49e1c745e40eda529a63f2781927a +d193887f6151412f92f33ac3ef91f783 +2e5faea64b4841c68c01bde24674a380 +e93d194abc3b4c9ea4252067b1f1a8c6 +854dbbb2ab994ec8a1b46289a333a9b4 +3c4e617b995544638d351fbe544c8286 +4dc01d84c784405eb50854a6b177c869 +16146eed0026466684d50b336e9fd29b +7ef6cf38f71e4b0d998cc19ddd73859b +b0f0f1fcadc641949f94db3abd7315da +b5cae55032a94d098dcbeb863f33b27f +4f62d41dd44b4a4fa4010a991f8e2220 +6f59091f379744a1a3f648ff81384c24 +4ad481d8dd3d4ced8130cdfe349dabea +ba2cb0bb5cac4a41be57d0d806485ddd +d1f6601e36c64a01aaa7465d629f22ab +4c665517fcb64b07a10a1854778e7870 +7dbfa863d15f4e1cb59b43e3249623b3 +7474b28305914cb984443b4a822db768 +c2237b0373d146f3a06240e085d02dd2 +9aa8d6f4d32a4d61876408a27ea4acea +52ef7a0dc7614bd1bab532c6b72dd5b0 +79e6c14217ab417abe524a99ffbb472e +03ab0eea086049b4a329e3c75929dbe4 +983aecd197b742b3a61e7da0565021a8 +8bc90676b9464068a65f324a553d81db +96d7dfca30f0463da09ed3f42347778c +85071962da1845fbb3eebebd858335a8 +3e995809ef6b4f0a9bfbc89f84566c67 +812121b9dc8043e2993685c4e3149179 +c8681df07757457d8cbe61174fe8929c +dc812d0f885f49b39bc583bf12ed9cef +3e4365dca3f641ceb107ddea64838df7 +52399e573a4545c2aa8e21291f742f20 +fa4a4b55227e43b9b552ba6a0ddbaa23 +49e83a6970214f7e98d961bf95b866b0 +6b7184f7634e49e899c5bf5476a1831e +fa91104769ad4bcd8e244ca2d22c858e +f1c67907a3d847f6a9d8a578314fc8cf +a7fa5398d1194dafba333d80d6f21da4 +9abe4e86a7bb4a4b8ede20d1b394feb7 +7d067512aadc42e1802e37a6a501689a +833149db44c9422182927e1bc278240d +743858eaa3fa4a4b8981968c1fb268de +c94d08a3c24349bbbbd7213532cd05ee +be9cda8dd60e4378b316e4933229d501 +cc9c8331b25349b7a709a9e5a85b2f3e +8bf9a9a0f5574468bc8a427e06922771 +8965462b14ea420690822ff6e3d1abd0 +c69f09bb812e46cdbd5bf6c62499b848 +03660ffa531544339c8746504286fe78 +06507b19ad684dada147ceac71dc2668 +684440b44e984bfebc6395587092bd35 +7a3f9b9ace0f4d9490ee05d7152c5980 +6419b8a1fc004446b4adf705433b7f51 +632fe78818124555b147c81fd423577b +3cd35c64e8c546c5bcaba7bee49cbc81 +ae52f5f6241b4759b9cbe48226a9db48 +7d1bc33de2b946f380ac37e2bdde94d3 +06a4a6b9008c4f95ae4e89d260a19db4 +9bce3889f01f4b62bdea932d41d0aab4 +5700b45309a04d1f93de859bf44da6b0 +eab7c27212e9461fb3eb2eb16e0e43bb +22fb22cfad184fb4ad14e572b3b18753 +47e49580cbb54476af742eb36cf9e8ac +ec124f25d0284aa7a41fdfb7af4b0a00 +8f5f5abc75bb49f9aa2fe9a7c39b5872 +782e2b5f61454d18bdc627c5210956a0 +61fb8d4e16a54a85a8532073d5ffa364 +9fcc9f3a4d184ba1a73a0b9431fb6552 +5187d91cf77244fd9718933f57efc100 +e5c9e6632e2d4807bef920c0b805d2e2 +8537a184f2d441aebd214689c0cd918a +d149aab0593d401bab31c6696a6eeb32 +7f775fb731e44cee88e8361aa7982388 +d227862272c84259a412d95898a5ad4b +8ec530bb19a14820b97d6c8dfeeb3026 +4ab324b82c4742e69576bfc5ba53b1ca +ea410c2c1ab54f53837f23ee9783f0b1 +7d43e0c0d060427094d7b193007d558f +6120ce6f49174414b981b183b815db98 +8cfd4b1c63c74e78abfa30680309fa8f +803117d73cb04619947f93b3b7a1cf3b +5c20db910da64745abd6b4a7b40780f6 +5faa3447f82e45fab5e8527def2c7770 +4fe508fb506141129fc138e1ea431bc6 +6ece45c8494d4f04b4fdbdd9039e395c +4ae1f4b440684b7f835e34cf10729459 +c5e836236ba14b32aa85d708dea55885 +63b6554d951144d0be5c5ec11cfd7810 +f27d48d3fade43e884a50c844071233a +bb298c6a88734bedbe5d4822542b9224 +a6bf64a282b247cb9784f862e5da27e1 +4682fe0accb24ddcaf9673d36c2bb94e +bc387203ef184f2dbd25b236945857c5 +f84beda470b540e998e8a1dcfec93336 +b03049ca14c3490a9949796d31562736 +7bc8af17601d40968c536fd8fe9c23ba +0002e50309b44e409c96f440202d90b3 +e7d86d674e934510bf8a228893729303 +2dbe1277caf74deb9a64ba032dff21b4 +9c5cc128e6d744528179b7807447260b +bea5524a0768437da94e2ed71adb2d50 +3a9c6080b7404f2e9aee0f9459b30e7c +fcb098ed76754cb885c75c157e6bae58 +74ec5b7d6e3b46319c4902595a93bcc1 +90fcac796045401cbf96cc089e41b009 +1245cb93ecf243aa9b583c46e8c31a1a +0e06763d63f44733b99c06ae18dcb13d +f9bc1e0b4e8f494dba71f7d33ee6d55d +33cc7075401a424fb60e8c32e3fe144b +d30cac84d31a47a3a0860f6f4758eebd +063ceb75b220463fa2dde8df4154ba2e +1fff04f8715443f6a23455e54f2aeec4 +58993b1cdb4045f5b7e692ada63d2409 +0c60e89749454792820b04867aaed414 +3b160b6445c340cfbca05da84acd86b7 +0741405f9d9942e292dc1d0eb20fa815 +00602ef508784e5384665aacaaf1f3a0 +367bbf8f210e4aa09befb267148b5158 +1a8a309a90c0441b92d078dd8435228c +de1f77087aa84632a8d113dacafdc860 +959c282f25714baa8d6c16d810aee199 +feb1ef90bdaf42d5afa27b91a452657f +7fe6509abe104fc29c9257d312f9b14f +9f6ec1995c3f4b0bbd3a990033890f3c +4bf56ccfa2224d928d6abc3aa9290f1e +f2b0fd061ee941d68541284616d16ba4 +b97c9e994c074cba83d0c00814f59dd4 +653c57247cf04ff9b099eb2074b6bab3 +4b90d207fa6647e588e93d1cbae32873 +ed7f1cb93ec446c89b903daf247ff051 +0bd1914cc9864973956c51a821f8c619 +4203689ce2ff4a128302bddd574b33fc +10b80e7d35564f25ad2fb9b3ff0275d7 +6a050ef1430f44618bdc179377476045 +aa9b90a1142b4208b995d42e71d46b4f +e6b23e29525c491bb1cf2f913ee9afcc +11b35bdc2d5148afb0b7868f18cc503b +135990262ca441569bc76dbe13dbe6ea +c686e4cd4a884e758220d77d34d4c979 +5430d891d903468ca91b667e08f074a1 +d43841f7163542e48ffe6cbd02c072e9 +a71daca5560140708880b9711fd9df4b +6822503876f04df79de2c3ab2277f6e6 +4406f384becb4d53823fd19d651f9c55 +9e452ff4dd764bd2a40f0fb14a3df4cf +0ca62a91b19e49f6a832ab83806066a8 +fadf9b71585446309544fa2701502627 +a23beb65a3e84c9f878265b47585d1de +43e95c43931a4801849639bb08ece288 +f80ce011020645478764f3d19d42abe1 +b753f606727646b7af8c4f43ff56b6f7 +ee3f18a9e8d54650af3b6569d2119ccf +cfa41567512a4ab78cd3eca7b6a58adf +75bd1fda860846c49101e0cc236e2c2b +ce41e1a47aea49c0a83dc4bb5edb2c18 +301fd15033a546908d55aa67756a740b +3af71e6dcc464d06ab264ab4085fee21 +88174b10475c4e84a7ef2b989571fda8 +6c5c7dc65f894a46af678e1ea1b0a4f2 +26d52ce7c2d2461eb0625875bffbe0f0 +3e8816e5e60949429f8e6166b9b004e3 +85515990ee094d7da1e66a5990e120f1 +cd23bd60bdf14fd7a0de52044b147c59 +8de129f29c2244a0ad43bef22c3267f8 +b6a0ac936c6041708d9478f1d5120004 +f699052fd5d7428ca67ba8e84afa1246 +bb915268fb554d7584854bbc6a670c3b +90f39e68feb64160b99af3632ad88e08 +b00ff03a2ab1438c95e1f34282e03545 +6d459af223cb46c8a78923a19538c5c0 +c2c99c157764423ebd85371c083a1d39 +e10f3563bf174aa0a80385e9840bca7b +7fcd555c03de4411a83aa5685fac1b5b +3e58813af68e4a7c99538e1e7558eace +87fd2e0ea7704985a3b0f6a8e586b22e +482c67c45711443ab1d91c4459d0574d +a8a4b6f1c851491ba79c84706ed745fa +c8d30b44f1e042e283ea3eb47f7e288c +047d421fa2044bdba0193c2222a2b8dd +4f756b99f9714b1996b9de5b1595905e +0273352444e14e8ab4f484679ff21ebe +35ba4ec704144c079dec0fe914b34792 +d21a338b81b94ed99193a0be5a7adb65 +365812aed83d401ea62b77d31df8c375 +349f07ecd7704df6b4e7112037f72af2 +198b8f2f1f584b249fdbbe0d7d8b59b7 +aa0be973535e48c4b3b15d50f1df176a +bd4a67c182db4fe0a2fb82a70b97f470 +f24c04715b874327baf86b74334c36d9 +1730a158d49b4c6b96659cdc9cadefaf +9046c67502204a579a17f1619e90696e +a5b53bd495cf46089b0169b0833086ad +45e061790f364b1da9ff876382adca02 +e392cd449282411b9e1985401ddd9c8e +af16623741714b90846a1a1f9e4fa19c +50f098a9a8a34549a81bbfd0e8ecb649 +407d81b508e244908edf9421a7e3f2b1 +4b7a1d998c2c4c068eb48395f69c1ccc +d9906e8140ff4cd7a4aff179eade29d5 +b0c2dce5b3e84c92bf798ce88913eb28 +cb4370c2bce047cca979b176bb4becdc +3c64848f8fca493d9f207961892b9b04 +6b77d17ccf304ebc9e576d1ab9c5f94b +9541e891a96444d4827360f3f6e1eba0 +cb72bb6e92c34c73ad0c3f8b12288543 +db6f9bdf3f2f48828e2236052a4154b6 +305e813b40a04102a608e556aec6b73a +13362422dc3e4140824dd23d03949b2a +e08828678dab474baac6ecd120fa0b3c +d345f392b78f4150924590580068ebb1 +b691798eb62c4af7b509a4935698dcf1 +297e44a133df4a5e9b85a6354b5ed087 +fb8932eb2a73433e8507770bcf919c55 +60a6471bad834ba5881d55e6125f8556 +7632e543ca5144bf870246f82c65246a +a4e4f96bbbf34cceb8622b9313365013 +bd0f8d2bfba24376bec2b827a0cbbabe +7275d3eb2e33411399d12e0ab14fc1f0 +1f7f03384deb436193ebae0e9adde2e2 +561141e945864cc29e2a5758d05e0994 +942a6c6671bd4c44a8704e28566d5dae +9ff1333690904e8db55023e3abb275c4 +d95d7987362245d8bd098987da21375b +8327cf2e178f4014877d4c6e64b1b73e +67407e8280974606a23d011c3da1fe1f +952743ebf53b44719c048672cb017678 +6677afd4de0d4fbd817f8c0876dab69c +f408ef68c38444ddb9dd2d3ba45e5227 +31788ae0024e4a6497606005416219b0 +8b6502af6db24c9699b5f2a2f8ef98fc +8d09ebe4129c457ebdd6acc3def3e587 +0ac0fc2c5a434f54bb50260741d214c8 +5bc1e53cbd044057bfb06dde2d22904e +879b5e4bb0fd438989dfaaff1e955acd +1f0d16d569a442f08fb5478de09cbd3c +540c6d3ae07f4e7bbd5a87bbf760d354 +73d45bdab24a41529f9509d7291ec334 +6a07a5ccb63747538b94fec7805fdf32 +f9f7ec3895d540e69e6671e0bd85452d +9b40ed6666b14c8d96942a2d7d0657a5 +bc411f6919d8457eb953a65b7006c8d6 +090857589888406c94b8c22b8198b110 +ae56922235964bdc9ce8f2b6747b4eb5 +2e29f654739445f0bdcacaffd61bdddc +cbf53b01b1e245baa896d7c6af69f187 +828c95d955ef4024a3791b26b4838c4e +2cb3e2c082f34506a5fa6e30d32c4ce9 +f58e43eb40f244f2b1c9b399e43a9bdb +e361095b9e434b1989aa6b4957c82d94 +98d3cfc65e614c9a8b685b5e3d38e55e +ea769d7a3ada49048454cd0a58fa4c52 +5858eb6c710d4514a25e3c3868035d9a +abb5588835f4455faa169b5d98c9c117 +1616df3ef6494e00812b0abfa2809806 +d0d69cc05bfa417cb2be33191be563b9 +59949b80aefe4a41a71afd16a0cbe67f +e64166631f324ac5abcacad21c1bf033 +e79a013b5a974c52bf8a3d5b369cb697 +8abd2fab09e741518eea0bfeba8499cb +d7a4858165d6442abcb47524bd15eb61 +db00442ac2f845519a95da2374f17352 +229cf483c0804368a8092dcc2524633f +8e92dd7490484eb3ab615f99a414bf55 +3ed408980a9b4f9396a7f7c48ec50aa4 +3d4d66d3905c41d2a45b86e539c9513a +89135ee7dd864d83bc3b2be77b53fb1a +2ecfcb2bf3d842dba639f2b7ea698855 +ad8d6aa0ae554474a0be8d77fdef27f3 +f4f465e072af475bae0068c08c07dbcc +4e7e47e5e6a84cfd9f7560cabe6b7018 +91a82a11e9a04589b3ba79a104f2cbf5 +547fd15df95e46fa9786cca309004aaa +1608fc9924344b529d71a66f2560fcd3 +d395532c07d347f9b5cf6544aaf96c56 +cad14c16803e4bd39f3204aa94b9639a +3378f67a424041f3acbc574b57bda90d +ea80a8ffde494fb59f015565e4c16e2a +62d69ecfc7b547008db2fa6475bb4e80 +8841b809f2124606975f504f4f52a9df +1fa75984e231488483182a29e2a3d859 +5c6c533c1ecb43f6b8ba9db3f6eda0ce +2a11fb8525ac40809d722d0547a00366 +f25cb76a65ea4d88a92dc4d994cf4094 +f0a9c037534c4172a2bd4ca3ad6f26c0 +9592001ce91647fea94c554e29ee9d8e +3990cc9d604d4030a84b713db2ad4242 +8dd79c785a4142e4a6e077567569e9c8 +d905bb89d4c248038d06b42d18fead99 +25290cec69eb4154b7c831f76a5c022e +b5c5272d6b944acdb424552c649f417a +9d2902a4d3ec4921b3bc9c4eeeb7c13d +86f58475306947ab814df2c87ac86df4 +28fb9c2f1dae4da0ac59b5af02d420cf +cd8df095f5db4fa38fe7d8799822cfc3 +41a08ecb524940e9971bbf7ff5418fb4 +aa3370e0b7ef4e1f9569a5d94c40f516 +4edad5ac33ad45d3b29005514938f77f +a37a0ea77f654aee830920ed148ec0f2 +0b52980cbfb2482cb8245ddf20e78106 +b22c72853f624c00b484e8cb16d19dcd +9a2c5ed79d634a61b1166836a8a5530f +71881ab98393404abe8f52ae10f6d100 +963dcceb1759436f87c80b6e46c08a36 +e54dc0a9e57345b691d1b5f66f3a49aa +cf1c9dcafe0846329c10dc26a0182145 +a42c42d9b3684b37946a45cd1a496b80 +b9df6a37d2d744d09eb0d7f2659682bc +90a25e292964467cb2d3d8d4be1db01d +16b850b59a9747c7a95c3ff904234ff7 +b166e9a1c5d540c19a1075b7f064f42f +5b28f20b21a34b33af9fa9cc193015e5 +a820c3cc463a4ee49b87e1e9a4029abc +16c43e9c3334470eba73f5f08cda2686 +64bced0aa85b4723bc398ea579b21350 +f22562f0e0ff43618941d02542123196 +fee48809247e41de88dad130ab9b339d +f8e13d5694464e8581907dde27bb59c8 +ab045945871144118dfcdc7a94d23a67 +038d1eeb927d442bb0b8f9100ad7dbb2 +1fd4655a17964145bf800005dab5c042 +4d38ae5edd3b4abcb2ba97400b65a98f +89f5b1264bdb4d89b85c52b3b658e604 +452383aa8f724fcbb9f52f7b45f33195 +4fe9650493664a4aac49da9827be7392 +7e74894792b2461b86b5dbe0a3a706df +e31399ac441f43b79430bfaadd22db8e +ca1155ccdfa04b1f965ad50b6f67a7a9 +7405f17de07d494990de5d5de296bbe5 +8de045536c7a4881ae01aa460a2d453d +3f02cff82a334e959c7d71f1c7307672 +04d0553202d34b299bc0bf43025b6ef8 +6521efc833d64f44a412ea1a303806e1 +b4f8f019018f47fdbf35f0119034e240 +fcf202af53994465976aea36aa261940 +487127f7508744d8beddb5d950dd9320 +4b383818e58f48079a0a19a4add13637 +4d490b545571442898d63c27719c8779 +1d702f4c5ec44f37bfa6ebafca3275a5 +b8cdfa7faf164bd8b0c9e77c37101f03 +5b862d56c15646c48442da6421b56f32 +7845bdc92976450db551c1e2098b5826 +0a80a213ae874021a82069bd5dee6af9 +be40b822f50344c2a8bf84b68f56d991 +d527ea272ab24cdfa6b6d9a8a0fe55e2 +c3868debf7d34e5abee8dc49d6369ee2 +b2a8b38e26bd4040802f4172a5cf6781 +d601c2907f114376bf9826272d686e81 +f8a101205c43481e86dd9f1f3970d1ef +9addea6a4129438b83a1fc3ed4a784ec +368561a819984ee3bb968b96d71f0006 +c8763050b62d4ab3a3ed9b175187fb48 +b99d652f0a3c48c8bdca5444e5982c77 +6a6e401e4b0241e2801ec3679e55747d +b51271ff9855493588d8f675e26751d8 +c71b73dd44dc45d58bb2f7dcb6a29997 +f74804052fe54f14bd5e2621e6a85505 +78c531b540c84e9db17e095dd4dbe9a6 +3ea434f4d29c4fca9b0ca4c0879e6edb +52e494da4c5e42988b739224a4605e10 +751ed3b5331d4c3c869f0dab880ac19f +4005811722a54afaba3d0c29d58b657d +eb0f2125b09042808397993c24fdf965 +a4d92dcd462b4c5aabc7a61392632314 +d44124e0b2b9435cada8949d4f445b3a +70b8a7f8ae4b45f5ab0580fbcb179823 +5b1b414827c6480b84fa83bcdfae8d41 +f42e615de5634df0af5550651f7272fe +21387dd7d2a94d67ac436cdfc13b29d3 +82ef689ce285475191cede0332dfe959 +a492765bdc0b4f46943be959cc55aecd +e7cbcb10bd2843cf97786ee8266a3ddc +c49fe9a654a444648230d73b7ded05e6 +8186e2b966c641cba743cd3e1a302243 +740b08ce6f3c4d3a844206b0622a93e2 +ffbe6bc8412b419c826ac9a3248f5c89 +658ef22fa0d64963af728ef45efd3818 +26623ff3730b4f64b139d2ec1a325df2 +72e0e0b03dec42dbbb67ae0d5b9ff0b0 +669323bcc4544890947260a45f91dc4c +d4257d92a7184e8c9f111e81ffdf3576 +ee4d79c5f2b7404aa65ce90443a12f2a +0c921828f79e422f82ee3b897d7fdcd1 +a2df68e14dea42c79ab2abaf0b0f8443 +10a1f80c971143548d99b3e9ccc118e6 +d8caad07019141a0963aa66abb0efbf7 +db4de4db4ba14c839e9a69b2cf846f6e +65c138cb60144530a7fe3243d6534a9a +ec467ff629e343d7a0101cf490726cd9 +18234b9b760f4833b68ba0fd6ca988c3 +ed032113763847609398eee2c03dd82d +d8159daa2d844379a941b99455d244db +e3277743f4f5476ea4725a58ac483ec4 +7d789534c58b4419aceadbb6017d2dc2 +27f7cc9385f64f29a6fc4e00d3fe0b9e +c668b80bc4b34ca691c0d335442f07aa +affd8f5de88c4e46a5f3963c70055ac9 +c5a3609b970b4924acd102377b8ccb69 +7bc7b0678e6d49a391fa1e101fe2ad5f +2924224f899b43de93e9fd43c9a0a079 +d36bfb3f96a7424cbbb348bd66cdc291 +5713fc403f4f4899bbc10e8e3d0e9185 +3b34354f40824c2c99e8e6b891257685 +f1c382112c9e4f609c238a064fe7c6aa +566492c26f6949ec8f082c0710ca93e5 +faa0ea95a9b74233a32013e381342d6b +929ac6fbe0ae4471b3a4f71b748a2efd +cad5da0a14ae43759cd9221dd6099bb9 +3ed0d34c6eea47fe88fbda2fc3d57b2e +efdbc2fa6f6548aeaeaac7826f211e50 +1815c01895bd4538bc0bd05c3394698d +3badf1a197b242c2894c0b68416f7261 +11b79895c01543048f61548c09454f44 +f2ddc3ff108f4fbfb71bea165d9a964d +b2ab96c4d1424afea71513cd0a4dcd7a +600e1e7db1cf48479da37f997e6c3448 +123096fa63924cd9b7535816dc3f7ff3 +02e71acb4e8f4b8ab159f81d0021b925 +2e0d7be0401a4cafb56940f7a73750b6 +48bbfc1990c7448187d188afbe9bda42 +457947902e1e4b3a8b2606cb4b963e11 +9ec7e03c7df7480b94a62563a60a7495 +b63c076b1f2d429c82484cac793742a8 +f44f29e97f75481abaebe706a49d4e0d +0f2f0e489ab445108c939820a00d4888 +5f848f99c3f044cfaf53ec4ad6cfb179 +50a023f83e8c434b8b908c4d41c0118b +03b0ac7d99c44197a09640179f360f3c +4e7600fafc8e41fca9cb00f3fa1b3f8d +aba05909c9f04c1e819c9aec27cb32cd +51749275659d40198c491f951a27b4f9 +c2069ccf3f4247b28c843e480da3118e +c59eca2d6a214358b1b3b89628cc34da +9a96cb9e351c460b9ecb10088be7d0cc +cd50c3ce1485436a9c3ae290af4d1303 +fb509f0edeae4f75ab4368a8133f4ccc +279e24fb9ec048a4a2abf17a80ef650e +99bdf8c957be479e9a11d5e1fc0d427f +4c039ee498fd42b396e8ead38751ad44 +b03c2f947d5741d9830305bb7f38a5a1 +6f669f70f123449ab4d73ea3ca3052d4 +694d018d3e224b65a02eb1831b666911 +08ccb9a009a34ca5916866149e5b51a3 +b2c020425d444757ad491af696cbb66b +d2524f238cd043cdaca559b51f7611dc +f668ea6a475b4abd950ae084a702c763 +9428c3d9fd814ba4a42b363ca92cd003 +739725a052de44eba143e7a6c1c260f8 +1b5f52a5181942ccb5415f1a4ff4ea3c +925ad46b0f54495aacd6540ae3e4bb21 +a9cb42717d294858a4691508df43d174 +476e1f16bdc84af7abef89659c465b7a +cb40bd1d48174c2e896f2c80de1ac496 +eae004cbb5844f0a98f3e72acc9783a7 +a9f20de2f8c64257af86e37bf27fb931 +8d071c61e24f426e8c2a5b80b451c885 +6f3a26af345341a39ed2af45437f8dc1 +fb51c6047003409b9c462b63bd992898 +00286954e2d54db8bc7832cc8682b6ff +ed244ef789654bf19cfae6ef9e0c2dda +9887e6b0bf8e4edabbc3ed9e24aae2c1 +53abef84940f4e1ea8bfef4c4e2b04e2 +4f6b919edbea4839ac5f117a98badd00 +130ad85e76a2451599b0962e49f91ca7 +634fa1602d8f44e7a8e3868fb02c6d39 +60fa9e11fb954927b80af21855258989 +ec7ca19df70b4b9e9d56f2a2c91dc401 +8fe1961bb0af46f0a3475e39ca8fec52 +4fbbdf9506be4b6ea0d4ce74007a37f8 +577e3ba257a147bb8f06d1a5ad81d627 +38347ea815fc4cb4a88ae3d0a3225efa +1652032bbb3d478cbc009d84f7e31cb9 +32720b491938476385fb3243e58b6029 +783d2d80f163497aa02fda539e82755e +d2979d2c1316486c8c02f19e119b5675 +f5a7b3ae249b46caa0efdfb30d725246 +c42920de88244b2f8fdca6dd408b53b8 +15d6576252d24719b32d9e686599ef56 +573801ef1f514db187fd15e13a42fc1d +776d44b2465f4c2c856fbe74c21d5927 +11f9d7f58bec486c8f3125e08f14d485 +019c5ddf853e4618a686feeb7c70cb3f +665807dffceb41ce8f861db2c654e7a8 +15f8ceaf052b4152b765f84610c0054c +43114d1a617c40c5bf45ea0b8e075809 +81b98c35166d4f75b559438a93843a71 +99da82e00cad45449b5fd906e2c8b7db +e2e5ed563cc340e69b824784748cc4e6 +1e2b4dc9efe348548b681a1fe0a1343b +08678839600a425cb4f5bb80a4074ffd +415990b9b8d7434099682efbc9993132 +7cc573b557f6494a802c24b6ff02d641 +f2d31eb0ddac4d21944df7dcc4af6d28 +d6ab7d9dbe1c40f5b8643bf02af21eaf +f96bd031cbdf45fea877bcb922462082 +e36749656e714104bb6c626096184cfd +fcf8a31165834f83a3f0e6b36563dc4c +1893a7e7d9ce4544ba71506a2ee90097 +41bcb2ce42be4d008f2dffd3f79c5ef4 +31818220c7154260b680bb360062f64c +c9c4e705bf794cb88d5d8726095f4917 +f5499ab7648a44f287649c02fc3fa027 +b3bbf1348c1a4c699b5654704a848555 +ccf2b1da93f84074b48270b7c8cdc78c +3ab6ef0bf46e49bb84fc122640a521ea +fa83302f5dc7470bb199d48d2a1c8085 +ddd491e7210744faa0aa7dca03a0bc43 +2304f145b2f645f5bdf6ee4563ac9173 +64289c570aef49f194e7cb74c62c3929 +8ef7f5715310451f9115585033e5fd65 +27020c400f534b9caf83d09e8fb4d5d7 +a6dafb544f764f7b911b19280b3be48e +7b9f124340a947d4bc523c42c9936ad6 +0023717f4f564cc99f4ded70db04f590 +da1ec11ef9cd4013beb40359be96feed +7b7f592996264d31b094ea795e336d15 +05d390d260054519be59659d5404d940 +673b69aaafc14d94940a862225794f01 +1e5919f8a1ef4618b4dea274e028f857 +400b2f945fb24beaa5e3ce576670144e +55ff02e48cc8496fa919d827b7ee3233 +84c96689f7aa46a98378416ad7080219 +e8977020b5344943964560a3d6bd724f +5feff566f0524190b510bee1f9760321 +237c48cbe43840b788ab4d8f0b318dda +5ad79e7737b44062978c7c39ec1445b2 +efb5f76948714689a43d7e41f712555a +7220e93b3ad14f218dfbed7acff2e184 +8d620ada51e4448c9918d156abeacde7 +13696393c7c44cdcbe60eb0863019def +46178db434914b67a639109d4d585bc4 +3765460b38944107acd180d9efa3fd76 +b257c8dba2154bbab0fd1d90ff4f75c0 +f7f4de7468304dd2bbd0bb260d166158 +8a59160c8374412d981c74730101df39 +b036f90734a74ebaa5a16c089c08a1ce +03d34765519a4121ac645f35ad742340 +877217db76bc44d8bffa38fde9982b31 +e0aaf0b7368441019b9ceed6ef46ce3c +f512afa2cbbf41e2802fb0cd043fa976 +1787fb8e12f14318899702ae6c502de5 +b9a0e8a376674efdbb5729ae7008907c +2701f53b0b1e4b7bac6e551050bcdcba +d10ab05314a043ff81602b59e0d479a2 +de516e7330e1491fac4144e3d2f458f1 +18ad95eb42c7465daac64ca03d177f34 +0cae68e893dc4d94bf2013a02789efe6 +f05a25da4b2c4e8d889db888cd3b2efe +b202e5ff0e2747c5a94cdc6e8856e823 +085ed00898b244e48af3d63819094a03 +ebfc326562624d07b08ac04baec46d80 +7c7b7cae6f884c9c9b90787389deef6c +5afe0c451b5c4edfb0c7ef72e8d39045 +104d34aa17e648adb50231219edf8665 +366d9596780c47829db69719eb2c7d02 +326616aa3a3e47ca8be774684ea792b5 +230eb27915684268a0262bdcbf97a1fb +65ab98889be840c28be9f07a5f03427c +04b7f47e732348aeb82a23cfc8986d1e +78873d11a9044d5d8d3e0f1bf538242f +7cb4d3334b2646df933df23c00a87c39 +be3d5131e634424e89ffd57ebb19804e +2d1a97de770e4ba9bf07f09a6d634408 +efa6032f252c45d5a41cc570d64adc80 +cc36e7c5445a4270b301f7ef938e671a +10d31cb05a1844bb89e83ec0827196d9 +5c416044a05241728e7b5b076e1065c3 +d6a5427888b8413fbfcbcaad14353af8 +2f75b87607704d1cb3848623d5ce6fa6 +e81c12b73b44472cbcc262069c03fc45 +514007eed6af4992ba47cd523b4f4f6e +759e930e9b39480c881a047bb9eab6d6 +27774440b2d74b15a32f4a609e53f73a +84181c6828384934b1df0f2120d9f77c +f1d9ac89b732426a91ca29d5e76b83c8 +8508e4d53ece455180428280cbdd7fe4 +19f43294c98b486883233d2173f8a195 +10219fa96ec643359b946924a6e3f59a +9e68a576b56b4cfd85d07660e5df752a +e2485852a5624624b9aac80d27222f0d +3618fc7f6847410f9aae342c21bbe98e +0cfb4b98ab324643bee6c9f3cb98acc1 +7ee37c1cd1bf4fe78364d4a39136577d +cce5e3551a204124882e7d8c4b1286b6 +4422afe841d346399e52938b929bb62c +7b8f5b7f14a44a75bc184e28b12b32bc +7a61a39d24be4393a80cfebff1499e8f +a2a074cabf7049869e7e6d4fcfb66b1a +58f8f8e2d4434cc0b0b2e6e7f47cc354 +28916281018645e1a805a0a416bb2192 +dcf23435c3d14370824e5b2802fc6bd3 +91fb64afeb0f4799974ef8fb628f9407 +d9ecc3fff6e2402d9d1ad524ab635808 +1d404926778b410498040ca00ebe6b8f +f9411ec107e940fa94dcde342368d711 +2bf0d5cde39141948bfcb2994ad221d9 +58efd7183ff44605a5edc5ccef40bfcb +e5ffc82181ae4a49bdd2137432db9718 +c6c0f931fba24903b6b480abf2be4ebb +6eac0832d89d4628b8309f4796803561 +438269450f57484596d1a7c8529d4505 +72249dddcb2c43e0a4d9e479e6ac0f13 +7f7513f97c30462f9e0a511e0cd6882b +382d0f26576749b2b497e84fdcb7c242 +74f4a43cd2f2469da86000b9904bc23b +fb0111a1d4b64066bf3d59f38ff815ff +b56cc6ebea1441f0aab1c1cc36299ecc +1b3d199a690f4a58aa39f45c9c040c77 +101efa7e4e7b4b59b975bfbb589432c3 +d51cd1e87ec24814bd64842c97320f48 +b10454cd501d4d7187842f471de153b7 +30fbfe60174b4748a212bd4f3e5aed68 +d563b12295ed4eeab3330c212eefdd56 +3f32c3fa162c418ea3b786e7fd34c943 +73b64c5ef8e0468583c84e1b9e1ae59d +2dbbc1914a484a71b90a58585387d9a7 +758f72d45dd74074b58b8320997879a0 +5206aa93bce448a8b936ce763cfc245d +2f20f58d1c8947baaa2c15a037fba623 +31ddd03174d64d019419a44984daa3b5 +dd0940d7750144a09b91ed9a4c4b6ad0 +05ffe73cf5b946b89ce81ed1a422125f +04f9c04cd24a438baba1acd0e30950c2 +b1508a88b6e849cabb421992fd63ad43 +c04e4fcece8d48ce903e2b44210dbe17 +e90c14b7a4054c9ab2a3b7fc161cc85f +445f6cd1f36a49e8a3bb64bb218e1fa1 +e979b358b82e45c3a6eb25ed1537429b +d1f9c2ef80bb4754822d15e8db7487db +9737c54341a749078e3997469382e68c +8de4f08f281244b5bf7f77e8319dd91f +7f7f192c09cb4e4a9fb60369d5544014 +d557073223684759856c7d73cd5a07c9 +e5d8643821f44c5888271d1c236a55bf +827f39e4163e4872b5a0734d17ed65bb +5e98b02245f6400bbbd61bba816db2d0 +524ff6162aaa4d8f82bac1bdb9e2f584 +a6a5f605426840bf9c9428c8f5f405d2 +032248834c034cbcbc0c9a3fdaf15c7b +ea9de7c3dbc1470ab98cda7f31d87ca7 +b4af74fae3cc46df9a1d38f6bfd996b4 +7b0b46fa543f4eef931990f02e210808 +8e877e1b22334580a2a79b0769a1ba85 +4b676d5593cd4349945c7dc7b9f4ad40 +34b15cc2e4a343268e287ea1f32e2a54 +4630cf631895489eaf3185b914aa14f5 +8891dc71ede1450b9d70ebde1b153822 +3bff1066fd3a4df08a45985be53e6047 +d06243f4c2814664a50c5659f6e2087c +b76f0c27cf014c038e6676faf4ce08d1 +3155e5ee434d4705a161320269df30ae +eb2ae31bbb1d4e669efc990209438d72 +91fa7ce2ea9e43a69d723cc3bd08f306 +f87ea30d8b0b46ac9cd97382bc5aaf96 +ce3cc609cfea4e919cb890b3a28f215b +ee9e5c89ef07454199212c4ac638e91a +63337087f4ef41c297e737ca96219b43 +950135a993bd41878b7d96a9273df459 +a260532154784b3eba4f0a7c10a4a66d +3c6b18692028416cb21b29ca43eb600f +efb9d1c5fb274efca2c91c03e2791347 +dccd0d629d704cc2bde905572b0947da +e48409ffce3242bfb2fe6a445e57cfb7 +d889023d07e749fc9844bafc5c7cb2ea +bdeadf60bf774adc9a39c744792c02c4 +708c31a78cac482eba35f576d54feb37 +296b7d6b6fd24030b31b1041e877612b +97a01b34ff944f928e39fb947b1ed09d +c3f33e2592e047c98633cf5c859bcce1 +11f2e790c03844e79bc44efa5a05466b +a0989f487f0e46e28794a011fc060fec +8cd34fb8568d44d7a0940b51afde5957 +50c6cc33366449be873b785c3b1efab6 +b8b046af916a49edb9b4854232a7e55b +15fff609e9824abf8bec685f297f9994 +8ca2cc2c39734528a219875461718668 +4719e069d94c43fa8e42043cc74f1372 +025caf59ce094aa19bc6a2455fb9c7b7 +057589dce19147cba5ed0ad4ad09212d +4d8187534458455f99fa4d9b327aacd2 +ce6c82f1f7cf4b04af854f8f53c55c2d +c4f9b194abca4db7b4cd0ec6270f9d60 +62658b70d76b4f499767326e98853e50 +8764c14c64f84bedaf6926ddd79a3bd0 +23ce25036e4545f88d60d1d6bb758ebe +3c0c16d6762740eab0aa539bec026771 +adc1d94528894ddbbac31f32d5323b44 +6fcaca0103704783a880829f28194e55 +ff2eeb8659264d6cb1ed76e89c0d632d +16ea785ea2764860abf0883eabdde25c +f673ab6508064e438f96b70502646949 +3d625e357197454fb4503ca1a0e7977d +eb264cd5dfe54d71b7b92c9702351338 +414e34d317264e81924dcdfdaa955596 +3d84c072273b4f8ca8fa9d91544f9f3d +554f19b02ccb406786cf1c59c64ea17c +fa1892cc99d14b5d862895e2484fa527 +b8bc290b0c3e4055918ab332c8747000 +2f149a27338641b19e89f9de47253e55 +de995fa74ccf4a0db10ca697e55985a9 +9b59b0122e0e4090acdf309d6c75dde8 +b6d728b57c8846f7bf7d1722d456c574 +6a59af66bf5b45a2988e575278b8c4f8 +8b023c7bc0754d1aba4791348b53bec5 +91e9a8aea88f42e6b8fd6505dec761c4 +a3a777e319f54851b420f0da7e54b782 +e6687809645341b58d89a30a1d25acb2 +60db48dfe11542739b8f3ada96fd6122 +5dc8cc11062c4ce59b8e93eb24a11cf9 +3b50fb746d834312bce22c9fe3472726 +b57706ed26c44dedaccbd99996e8d807 +7b4cfa7ea96f444f8941c14af9e57844 +80e2599b07714d7c93f68a048c07c4e3 +1d3e592e28224d239ef77e03923c563b +277fc0f27a4a45f79b7a2cfc5e9f335c +21251fb8a37e4f96aedbb473bc0220ab +3d916467f33c4746a0df6ccad0db3f82 +d6cf6beb0d124a1dab8f8fcc1d41f1a1 +5c2054af80b3448b9665367c5de529bd +8d379e0e7edf4b9b82258c024c634618 +4e88a88d9c17457fa75e09a404dc4e71 +ed66b5fea72d467c9bacef6ddefc542d +7576ab313087425ebf0ddc595e5040d3 +e43c904708844579896bcb31f4416726 +486d457e5bc5438fa0128274fb97c22b +60702d5f661048219e17138ccd4f9416 +24c8384d85524627845fc7a25bf28393 +d38460faf7c541668fa086eaa4d0b613 +3d3a3d78a3e94f4cbdb442542a0e11fd +4cfb8a1570404234b8044ed9eeff71ed +a2a396836384415b8476ef1f95c3db07 +6430f9d2863f4524baf56f9b96ee837d +117a24442f4e4550aa06c05f37cc6c4c +6fbfabba6df44e2f84d18d2fc8ca54e1 +3716f3bbb40e4933b470398e7a8284a3 +82b490fd735e472db2220f3b12d3e47e +4cfc4f9eefdd488ca5adc30676bdf3b9 +15dda994c29a4a2780840ef7c0242d7c +b9acf8366cae4ab794a8331611fe3ef6 +86c972a09b0d4111953b9f8eb28ce7c1 +8ef9c50ce9e646099e6e16774966a82c +009fdf73a9c54e7bbd3a7d28496752e0 +d4fe2d0a59a547989d3adc8f3e87a221 +72a864afb37046e3b5f65387d36d5747 +bac4c4b4245e41e9bb76518871419ad0 +fc0b1187763741a08985a693cd010420 +8163cb7486434fe7b3ab17dfc1a349df +7a49a0485d8e46d09647834d200c33fb +5ece83c92baf4cdf8d8383bacd9fc116 +4bcb32f952e940f68d74635f00aa2205 +2de3f52a3fb94a8d9e8d967ffb89464a +fa4268e505e0478c81ecce5ca4b228d5 +d2deb3a13c5a49a0bf7333e072eb1a3f +ba57aacc364544e5b13477e1a92c0196 +52c7076d511c47b8b30acea6edf47f78 +6010ec41025e4fb78593a2b47d1ae6eb +08534edf650d48c68fc19bbc5ce4157a +fb4b4fe24a354eea8cdbc82da78f5cb7 +fa913f8999434a198fe3b4d6d636b207 +47a595d6c2dc419bbc49e35bbc2c951d +e0d04cfb29a54c0d89fcc102f2773af1 +f4fef78656184aad8617a0c768cef73a +a39e86420f7f48d8b6ea4c8f80090635 +cda1f64d6c3f48248e15db0854e32c4a +8dd9a0b3faa84aaa813431b44c716a6d +f49a08efb8a544efb98d4d806b0d1c27 +18483cf78d944cf7a4b88986e71f103b +1a59cd9f74144cd1b9c39432b0940396 +b1a8fd887059417fb18ae8ecda2bc287 +a89fe2c852e943319904938586b4f5b7 +3d6f9421a9b54fe18b8cf894b17b3bff +1ef90928c6994bb28d8069069dd5adce +095c43ae06bc42c59b247d57242d6772 +8536f538e18e4097a3012321a07e00c1 +3317dab62c6e458088a6575ed4c286c0 +10fb864c5def44d48758734dd82f1540 +4809199aa426497daa46aeee398dd387 +4d3ed5de8ca74b4c81ccaa409a681eae +1078f49726f34447ba5ec116b6ee50d0 +7ec3859752304e1497fcad1dbc8fd27f +4eb66e5c0b4f4e60b8e3e2e8e2c8b84c +603d972228144b1c90fae734a251c659 +6851c90aa4b14c3bb7df2cfcc0b1da4a +98ceeeac76384710a1e6881c09766a03 +a1b271479687423da1ac060c4afd6d78 +43a38d0e44234b679884f0e8d394c12d +6d99c6c1a8bc4b3e97cebbc49d62115d +f01f4881d58248a7b0ae6d2fbf2fd5b6 +7af1578ab5d045f78f6c59b2b2b54a6d +783913c7b9df441ab99ec666eee4e052 +4c108902e9e74577901046818773ffa5 +de51dc61ec7c45eab148d81cd393dd11 +48b72421a4c7420eb201f893f3b6f4e7 +376453162e4342dba2c07b61f4abfd8e +dc688ff9c3ba4a8dbab7280c3653cb09 +2b33f63aa12d4201900657961b5472ca +6687061f614f4340bd44b8c4006f7e2e +0c49e3c5a5884cd9bc81fdf6fd3d997d +f012f4f8b64b4ea790346971029d73db +c077d30ffebc4e179a8f2a30caf4317c +841379796fd94dfb93837defec015587 +b4eb973dfc4e4deabe48dbcc944627a3 +797e7d8967e34d829788927f4599b4a1 +4253ed4b9fc6484293ecb0be4aca26d7 +d52fe68029fa44cc9367da6eb227b007 +664dcfe9ec1e43c18461a70cc08540ea +53b9e73599a74eb292c86ef1a219229f +657f2da8d75c4781b0f3faacda7561cb +7aba73c660a744f193388a9288deb859 +0c90ba77c3684886b859329b1ca2e6d5 +8accb353704a45d19cfce3d6de00a70a +f0bf366352f94f949576703019b1c202 +b621c64d0ed74283873c8c2b9a949bd3 +2d400d61c1d14401865e8b74a0b72016 +821ea1ee87484b608b226a73303bc25d +cab6cdc695df438ba893954bf6277c1a +606a31ff606744798e9a2c6844240466 +3e5b44b8eac24e2dadcc158e7ae421b2 +a30fb981effd439fb046a7318f0c2065 +343a88f0654f4a5094546c592032f647 +5ff6ac2f9192423db8b3d9464852a3ff +26a21e1131984c0ba851142db44dffd7 +5b098581cb7040d8ba30955ddf2e04c8 +e71545e7f1804c5096e9348aaf6e0c26 +a7fdd4d4ca904fadbab050762a30950d +9c6ca39cc8794dcbbd59de98fc1d88e1 +ca5ad243982441948501cd5df63a5634 +ea7b55a86b8e40f495deaa72b445c323 +6f1fc902303e4f4eb94e155000b8d811 +cc4bf1104f2840ddad4b3aaa68fc3f74 +011f5402c75e4b549010ef29def39e51 +2996697866e34d4d83740102d982490a +47c6bfb547c0468dbaef0cca60d3fca2 +925ccdc0b8d94d1f8250ac6faa9a1bae +b37713ed3a004e709da29dcd776d00e7 +b4c3afb8229e4149981b0fad3226c844 +bc6f833fe3b440058b967375c25f28c1 +8ffce3a498da47c0930f41fa58371e54 +01c9b73ed5f1406b97f86e46774fcff6 +25255c777f9342bc94dacbeb027dd15d +d210ff8277ae4fbfb3334ede70614b06 +2df64ba27a7a4a0b8d00230990b970bc +c1987ac31310458794ffabcbd8bc7a49 +83ef1a1ea3ad4a2fb6c5c18c8454fdbf +45597ff885684a29997a9b031225b385 +4a1c8d3f9ef24eeb8c4808b68f953c80 +557cac7bf8cc4208a25777cb4acd0687 +730811e3c39c494c8ab067967380a0dc +ca845d03fafb42daa973019abfc1a013 +bb01282cb8b64470866260455b0b46fa +4b88c4c4e94c497ca39f831f374e89fc +4c6aae2ee5f04cf99c9cf417122c4b91 +c880550174f0445098ff48fd5e5f2cb6 +c7edf48644e346b2b277f87df2d6ab22 +a76bd38f0af1422d96add0d9606e5fee +1e8d0dea560548fd8d2803170fc69a1a +9caf40f129294b2ca264e4539044fe87 +32f1cf6a13a64742883282e90ef68c8a +e096a8e12daf44768cdadd7aae36be49 +12e2c77dda014dd8a7509f72d259d739 +99081d46e2614b0f851318eb06d21d25 +aa8082f3408c470093afaa8372db6787 +2eb11c35df444325a120d414af3ebf30 +ac3b7ab28bae4782841457e6ea6f957c +3bfe6dee7eeb4ed5bbfaf2baf1672ee3 +093cef110898429cbb9e9fa7067d0c00 +7a209dabe66f45d782ce3f6b4a3a7b37 +f8ae73f41a6f40259d9d811f525ee745 +09a66af47bf14d51b483cb8d85765ab0 +c1cf347b22334794b88e25df2ee88708 +81af3075df234522a73abb96bf07f64a +87428dade9034cefac9eed6a1aeb14a1 +851309d1c6c34c5ea0e453b218b9b54a +b2f0a16456f94396a95be267b05b6d28 +85a796997c65490aac88c6ea6a06f787 +e7cdfc6c96e34f64b5e953bd534f4290 +800b21fff792444597b2424ae19f3452 +a4d58331575b422790c3947be8aeb51a +4661bc762d394e0aaa1be3e38b71e515 +1f60399f99304ff087274e0e39352389 +67cb54126dfb48f6a74d01095865b2eb +529d58c8aa734d7080279a4a91c7f837 +b1fb5b82ab694a8e8316693fa9fb37c4 +41fdc95a0d2148ba8f7911c4ef4f69c5 +29637003e3a0437cbe2836024792cebf +83a17e54c6d9442395f3dc0192424b9b +22bed08d490f454aaa6f29ae62241f4f +67481cfd3cfe40b1b5359b8198c3608d +17c796aeb1b8455d8f594a72490e11b7 +0d9c192ea3fe4078964180495d811df8 +16667c66adec42f6a5661c813cb3e51e +6e19e6f7b21048aaaf75c2e6487132af +8e878e5543424b61b81b247228cc92cc +1f33e40c27fe451e9efda612c69010ae +891d7965aa984585a83366e33a87f05d +8cafbab7a73e4fb7966a00659a4e31ef +a90fd116b4b1485196eb3996f301b130 +ac47aee373b3488fb6c2175823320acb +4af29eccccf44f5298b498fc231b8313 +f2ea714bfa5d475daed6816a5f274ded +85db5ae7d74c4d0ba690db265f28ad72 +8af644c2f5654e6fba4aeec1e245e8bd +4efef883e04a45f99eb2fde1ed60e48e +4645844855544d749ef6841d3e5d2a8d +9fd6d43d030a43a98a52baa1d5d303f2 +071be99aeb3044efa1d098f9c92a3449 +85ebb06733654cb5bad293dae518c4f8 +41780a6ecc2247f3b885291a9105362f +a390303a1e8e49afa629aa047d6493b1 +3d043b85f1ce4b29a3fbb03763c86203 +8d369bf078da4baea2abe89414accb55 +f75b69b4b8964b15b772bc2fd63a8b74 +6e9c67e3adc345a4b12d0e4f825851a2 +e0f26192e71f411ca90257c5c2fc1b54 +e0054749aa4b4844af0a4aaabe1d4657 +390010cbc1a34c9e8db93fb3fc44b863 +afc93c1289d74c80bef1b7d78ef1d412 +cbbec1cdf00f4501b26141717b9f8588 +f86b9aa9cd18453ab8d20f96ce8cb9bc +624e62d36ee149deb66a7318130617ed +f6b98543b5a84efdb88654af793a7791 +3ccf0f0e8e2e41dd8e6f6b88ce278738 +0c79a8305c524872a6fd55f92425eccf +3a50bbf9a3724cfeab7c1f9c89c0aa83 +2a4c53a53721412da328ae6d9e4917a3 +ac8332be15f345eab8849f957420e424 +118e358d76a642329b51c5cdd2ffc1c6 +08024993b7174695b70e0b8df52f31ae +ae0f4345cb2b4aada051856a7b4a6460 +3bd45e3b76324f358cef8b4ec0df47b5 +699e1a614d69413d9c2649c8a9db8a93 +3419c01530734ebab1deb2a69e4be0da +d88e3bb60d3749198345c21c6a6e008e +6f3d3a18535948908f7abe9b33ef05a0 +a958f0a830574d079a8bba15a6ae4ddf +bc418993f71e4207957e1f31d6fd3aeb +5fdd2647427b4543bd299acff008bc3f +6d5c188ddfe143db90961503933f17d9 +55385aa2ece44da89e871864e8d20929 +711826d903444225a6f1d5cf991bd74c +f4163676707944da93b6e43641fa534a +9493e95ec7cd4a218ee521acc550bc45 +56381471de184b829a400903e5b942e4 +ca0f242a4e21499bad2dd7974e6204a8 +dcd10af830824313ac1836eef8518ccd +4a7f99e067624fb49d401171e35cae7d +80488a1047834a558e0d571dfdd75cdb +9addb6a87d25402d994488ad84e32391 +94c002a46f7f4ac498b294e69e4e62cf +0c03c040f08d49d9b401e29937439bb9 +2a9e10ffd5b0405eaabfe496d61de0bd +491a8f42d03c4af5956925e7ab91a1dd +550c42a971ce4208867459ec96251eba +59a1dff4ef9847c6ac1b0b799e04b0c7 +a77f888bac654f8191442e74f0db4e7a +4dd25dda394440ba909d7018dfac5180 +0516d855f83e4337a5d5f526e19b94e6 +32a00e9c23fb4675a466b6ae3124424a +2fcbef3cf0a54e3c973403749de5b69c +c4ee70d74a7843f8bc89ca8d86a6398f +00130eea9e884209be92f68378a817e8 +2e75b800c76d49bc99010a89c6c328f4 +c93b148bf26e4b65b8bc2c4ddfe298f3 +147f57282f7046b09bc540bab1370db0 +ffebd77d0373462eb7c6d2d4941eb39c +fd36e971980b423c8c99bf1bfd679a89 +d2a4942ec5da4e83b8876d67bc03c164 +767fdd65a829495882060f45def86f41 +910cf7e424e6433abc8a7763bcf9f323 +a66c812b381b4ac59774e24872719d1a +a93a6ff3c8c14bd9a9e6a00a7dbde62a +00e4a92210b04f4a9707cc89ddac0e63 +3aa6b75b5512461cae6dea9613be60e8 +ee435def4a3d447596838518b2e35af1 +33310c3df38a4153b9f076286ee27636 +3bdd6f3dae3f4c5f85643b2a90b5983e +96e8b4d7e20c4b2c847524346a94bb86 +80eddf91ba0e490099a56a7da413d034 +4bb901d9c7fd4ac7a5a02e383361d3cd +07d2bc0ceda34626884c6226c01c5a57 +bbca8c63b76c4371b75bef10a712b4b5 +6d1afb8bee79475795b4c70f7630e6ca +0213a71af3314ac0aaae25030d565d44 +7d6996fa197e486da9721a60d0c71170 +88ad23f94b564485985ddfd3eb14ed0d +359772180f324b2da2a0b6b8d808cecb +1074e7670750497780e664cc22d4c67d +3a109ddd80bf4c479b5030c87e3e1707 +78a2afab899842d69630a7c9546c768c +7ef3494277264f0399723eee0e89b7ab +4adb5a9fc31443cf818c2e82f4899bcc +2db85be0e5b04a9aa077ab85ac5f6907 +9abdd45256664cfa83a57bbc93bcf5e1 +23e4027a42974d88b593c86abd3aff57 +6c5bd43da4164deb983a78d87281cfbb +4dff23e7a6d04f53a3dff42fd319e181 +ab9e699c74764adb931d5f6bfbfaccbd +e99de3df88794affb7d92495c30b7c33 +dd490f0219074655a8b08a97452b8b28 +f763fe77dbe34221b1247dae1ea84a5a +32fe939ce1544fa28a33bdfcf904a1ee +eafa8dc851804990a73c808861bdb24d +1519d1c0999940e1a51cb10a71348f83 +e1177f28df204e19a62e1e5fbb76e42d +7d3ab592920e4e98b71df547a8666091 +b23d22a46f374f05a5da3c85875ca5ee +577ff7950f9d4f3790bad37b8ddc6b86 +ca451fe549c148bebe3666ea79f7249c +bb24d541f83e4db2b7f1bf496f857d8e +b2b3622f96464f23bf3c3c0b10950194 +a68bfdc7043e469e8479b7e87bbd8071 +4ad47c6172c84ca88da0b0ded8f99429 +5e2fabb63f2046e9a44c47ec3e702495 +509f7dbf94514d1f9b91b188e1084436 +f30c5bbb75ec4639beec552a6f2a1fd6 +4f0c9e3fb6c9400ea943b3202af6775f +8c70a22a51ad48ffb3702ea60ccacaae +6259acff83c64763825e9538b5eacacf +975683f84bdd446ea1fb3c705459665a +d6e218214e1a464ebfe0ff6b6ac36900 +72801a6b5e8044a19fd14498493efc14 +84e58483108046c188529f5c2e5142a6 +fd04e222e3134fcda58487819de0f51f +3236ccf118cc44bf9225415f1f17ab6c +129e7c84dbf04d2384da7a84e7a2f877 +9fbc2b89e03947059af7c5514338c664 +2c36abcade164863a2f59cfcf66fb882 +1aec175ca4d1439a8adc0026b6c3ba4f +61649cbfc6f74ecc85d62b1fe8126399 +40d3913f9fd34ff2b48062aca2724e5a +34d29ecc6147477fbed92e75dfed1bfd +03a05076e4fb4d00a17ae2a31380a8d7 +3eac971c2d8f43b2810b584af3f06dbf +5e2d540faf4142feb4722bc137ab200e +eb1bf63cd0cf4a3395a806e6af81861e +475a9c6f93b84081ac11fc69ec042255 +4dc6168d7d6141139a0edeb8af6fec24 +02aae39fc74e4592b6d16b8685dd2b58 +f7c5bf006f014d74beff470e015c1261 +b93830a175f4466fab6bd4350fc8b444 +3fde813eb7544f06a1a1ac0a944347eb +539cebec2d764beb9b98130ecbd2e524 +0d00334b4c6b4f9fa34cc215be9990ed +cd5864107fa845e38d0c0449d29b73a1 +2f584f889a0d46d0b81d26dfab5105fd +7370199a9ce64332ad9f76a0e14273ca +73b31a00e15a48fd99721b80865ff70c +4314f2923bc74e278e74fcd41e3aa7d3 +81aa18c093d842839954abeed1c7aebb +10965a1ebcd64aa8b5dbafce0c7926a2 +b5c646604c7d4a33bed7d92c6764f756 +1557ff8470954428be2944cd54b9a27c +bfe88967727e4dfb90dbf648da62ed3a +37ae05c23fe34e3199ee6d2175fbe23f +d303cecffafb431c85f71ca13dbdf1f2 +6c1c05a2ee084bd98ade3800284b6e81 +0ca6cd3601b94830b296119219eea117 +526afb5fcb5d48da961c0e7d0e0b65fc +d0b5aa164d44429b95e2e91901b7e4cc +5b28b362e57e4e34b6df6ab2241ba1a4 +caeb681795a54c6eb0bf120582fe7f45 +7204c35a9c5a49748a317478318ffed6 +06f26c0afd10487ab66c448a04543110 +59988fdf28f843c68e7591e4ee1e5cc7 +63c4d6c3bb0b4dc991ed4cfadc464742 +4b213aac56bb4484b57cdedfa4c146fc +617edd940bed42159139736f6a20abae +eb0ea87925764e78a0854439fead928f +63c3595a0f344820b2e1d7d0b8a025b0 +45de993950c24e879eb641510e89e752 +a9e9aef9d630407f9956eca64d54719e +9b20cc2fe37c4a189cdccb5e454ccd8a +8b0e7d3a1b4d4dbb8ec788c3e4c5f1ed +ddeba12c5ed0473b8f99b8202b2ef714 +20f0268884b04e1e9acf8754b2fd4e80 +1f6b478c21244d0eb3562d986c7fb8e4 +5add20910a1d4016b2c174845567b15d +90af5d4457ac46838bfd9be441865e09 +ee801bec93124d479ef2d41d4592d78a +dceb864f7786497ba4598d0b107ae533 +a27a8dc5863c49bb8aa03756fb355890 +188af7078f7b4d6cbe44e37a3a57386c +52760940bfc640aba686e4b654a7f5ec +40844f37adb6440caba01451cc64c94b +538ebba83f784885a4a6bba96b03166e +85206be7185046ba9ca333083082c149 +8ae7ce20a306436e92e5684161068c3f +60abc0f79689415891be128338f811ab +a0b997f814b34cdb9fc1ce49bf1a2642 +075f4e0645d84bcd9b661750b253310b +f060e662b2fc463d8099777de48e603e +f37043230b5a405b87db09122d241651 +bbea37aaed504b308e33f5f96793a68d +6fd6b4bb05664b8489769706b49024ff +7ef22083747845b696838f2412fb7652 +659d2e4e1752459b874d63f2a8302aa1 +75483da53ce84a8fa5732d9af3a1ced7 +6c2aff20b3494faf8017ce2b909359e5 +9e8ba75c316d4055b5cc6e5c1aacf859 +9affcdc2582d4a73991473ae34c4393c +eb8b6ec93ad4479c929d6d355b41680c +42680c8a6be348c3afd40dd8ab8a5a49 +57fc7be2efcd4284a9514f05dbb51942 +910c7adbb78544fc8c846f62a7052749 +7bb9b012b54c45f488245ce86e8775e8 +b10ee58a01b649d381598d899850176c +6788e0ef6d6b4c7eaf28d6820867f745 +e8f8f5ad248c4fbe9936b9d5e6669a9e +d0dbe1b081e3421a866081e97ac7ccaf +84eab42d427545fcab4cffff9746eddc +4e9f8bfcb1df4e268d567a33cdd90e07 +7661b329d6eb45c3ab6fde9581a1e633 +ff2432bd9ae34b39a248e9b45dabdef8 +a4ecfbeef9c446c88d69fef8f5c2ff2b +98fb87f4107b4239b833394c00f525f6 +5be4442df31d4bb9bfed011d0ae8d579 +66b83fb8729948e9955cac4754ccd132 +739987a6a9e246f5810639bcff7abfae +8963ad4edfbc41429825c75b07b0581b +fcbf5bd42ca64336b04f5dd3a19159ef +bb7f4908308d4ba5bce1b07d4d730904 +9ee66510a72d4ba7b5ef4b0ac7a22373 +0ba6726d55484ce193a94d474b5d46bd +ccac815b71d347c18e33201ef5bde3d8 +03fa6768245446f4bab866db37a6caec +a1bc6499e44c41aea2d6d13280a7e8be +2c612d64e86848fb8af193018b8788a4 +7fb40ec36536459b9c1e6d6c344f806f +08870fb357ba4102b5d182f4f1158d71 +dfe66c9fa01d4d3782700395d2cd634a +9a643939a34e403a9965bc1eb58e2c92 +fccf7666461e466c84b1cf24515726af +9b42ef1096da4103a12fb80cad01ac15 +13cb5f6c327c4aeabe1f4690dbe73838 +b107acbb8b7949e2a82173abf4090d1a +60609764ba8b48588c76e9604532cbbc +67ceca24e6234eedb0ce7db7b3e32489 +8ea201cda6ec470f977a249dfd310d47 +c82a7e2bbf4c44e3ac1d1e7bac42e2b7 +af36a169ebb64d0cb1e387ae5925bd0a +d470399390d84c81ad409c4f33f21a24 +280f03acf3c447d184f8ff8116c0ccd1 +67d17da7d0944c4da18564fc90028315 +3e5393bd35e34531a576e22d45611060 +346a601ab7604487b56bbec8530af20f +da4f808afd264f20b9ae7bd8a13d51ec +18b27b46871347988877a63ece9b84b8 +a7dcd7cbf0c64915927c121058af91c2 +2b47d4b9e6794051928e0dbac36cceec +833a5dd05a9d40a893bf695b17f1c0d4 +319e97220c7a458383fb4ab17551d95d +3e6004858508416293b536efaa2cbedc +2b90a546e3a9486699acf16e22993126 +b7efe1d6d1784b5db62c974437b3da7c +452f70dca5c64c91beac48c54b2bd05b +3f35f4a5051e4136b54575995494cdd6 +e1807383f936415795021dd051ec3467 +0025c5e2333949feb1db259d4ff08dbe +3b9b92a5ef0f4bb99f3d716c5be79bc2 +8a04c2e40e254545a4e561a5ac0f2b97 +4461ca32dcc44d2293076560ab3edc30 +c2b31c7104554c41becfb0a960efcb4f +69d3e14dea2a440db05e741ef2bcb17d +3b1ae1ad437c45388efcdcbb05c51c4f +7b55ae54ebc94f108b46939d513dc484 +c534e37656024a9fba79be2c4386d626 +285af8e962924feca3d1dc61550aa716 +11e5211a59f74d9c89b5abaad75d39ca +4967c6aebe2f483caef9bc22ca17ef26 +3c3796309b8641feb5717ec910b38b58 +9e40e2f2780a4993b645d130bcf1d657 +c0e11012e5054fa889b937cd6c7dfb7c +ef8bb402335c480ca49a37a859fa8316 +d26cd27742be43ec9c3934c6900504e7 +fa7e295f28494f9ba23c07ccdf54666e +6fa2a9d40b9a460bb261db69a08bb113 +e0b6c3a33221476cbb321468586677f9 +c27b018330da406680e58b94266c310b +6bac7ea154b24666bb1268eea48dee39 +0fa49966a0ea48f7a96a57feb167aea6 +8bb9c087abce495ea493b63d112f86c5 +ed58014072a64680b0fe5ce4cac6234c +2162ffbd1e674f0b8771dd35f0cd3f01 +524e3301658c46a1888ecb46ac96b016 +cee46796242b421c99ff26529fe8b601 +34c8ff48374c4b56884811868e5b43ca +b22a6d32cd39423687ea4302cfa5a158 +ef71a9d082024c2aa83205c02943af02 +cc102cd9cb8944baa96bd78d3d8104c0 +a9948e60b45d47c6847e52e588119a23 +c5f5247389ff4badb18775b100f98348 +345846f5769641be990a0c33d95bda5d +3c867252612d4fd9a5d862066de8a925 +bcdaf2efb530464c8faa7a0aef5679f8 +bcd2db39dcad4a488a66696b88ca67a5 +a4765b9f04d54bf6a8e7e7f4990a95d1 +9168db000dd042c68865486beb09628f +a990deadb759463c9da96f134673ef39 +5967a2c18de44cdfafe7dfedb8d47f99 +8dc3831d53db4f63abaf0354ca4dc06c +c916baaa52044a53bc1ace1be6c1458d +f23e77a14d4a4b2eb885af2642897ffa +ab3a299901b841bea1040c4f0079d283 +2f6d2837fea045a1b5d976f51157a9df +6751ae324fd44195903cb0558580837c +6b6be66116804c828e41690825d0cc99 +73237e73f8c34eaab22194b4c594df34 +cd85bc33522040e8a5d60f4bd66f5ecc +c8976802708d45c39b695e50a0648f2c +b1a5549adc74497e9cdb068476fc1477 +3143568b420c43519ef858bf185c56b1 +78e3bf338a9b48de97c85af32ca144a3 +e7f79ad5dc8f4caa97fe9fc037008fb2 +5ecafce34997415499d49205141f1efe +7b6e70b24eaa456d993889d964f77314 +63ac173b927b404e9582e817361c583d +aaa2eea8e09b433bb4df528361c18e30 +b8ab0b7e24584f05affc70d69d9cdb13 +01ec7658fef64e18b69d68cf8b06548b +c7efb3b9611747ddb4e15d164540d291 +36e7a82224264eedb79a79f6676769d5 +3e8d1d6e11ac41e3b7f03978af2315dc +6da2baf841e24d17a2cbbd08540aafe0 +7ad429cc08984766a0fc8715e3029a49 +e10eb527561048b6bc1786c8c44cd0f5 +83b15d8e2b47424eb76a3340ab1988c9 +a208763e2eba4de4ace12977843313e4 +6e95a8cb47114f2285be08a70e8990b6 +c1f5b4e46fee4c2ebc28737898baeed7 +8757f15fb75040868bf8d944791d3bd8 +2656adba0f6d4f0585a60094f51482fe +e39385639fd0465aa1443d7ad22e6bd4 +0baf38666f4745aaa4e41c0e38bf1c71 +f90371bf90a44b37a0823011fe3d4683 +f5960b02d5f94925b2271e795913db02 +fe36e57eab7948cda439e965f88fa8bb +6471ba5bd6ce4951b440b7cccbaac56a +fd0ceac284a5446f98dc2a6f27316060 +cb52296694db4a08936b193c5a09f0ee +93a894c8c408490783789b35de5b592a +6a3d720664184cac83231c1da58c55b0 +dcb878f3b24c44e099b1f51011cd432d +a073561befef4547a4edd426d9e0eac7 +bd968c68d7b74629a7e062af0842082b +30c09497391d460894e7915a580fd60c +dfd734a9ae4343fc8f572b11fe09ead3 +5946f63acb3d4113bcc6d87febe30fdb +5ac257aee23e47e0a0f91a4e07a40692 +fad014b6221a4cdcbfcb6cc455eec985 +e47ec90c961c44d1901c1ffcfbeeb975 +cc77931e16b740bf9c701ce0f82251ad +3a6cda16adee41ebbe3cbb8c6cdbf464 +9bd569bdf69c43e1939d7b9c1747a81c +1c77a05af556408dbfa04ad1999a8a32 +003ebdf86df345d39dc166563229fb85 +dfad9314124e4eaf98dc4af830f3007d +27d7509f0b6d46a098a872df96e4ab23 +6862d6adcd8a4efaafad73672afac652 +9733523ae798418a9d2a7055c3d10b2e +0084f2a137bd46b6829f136800b6270b +4a2519f67a97499aabc1c2a228a69166 +055f7b0d165b430a819a3cb69f232e16 +ba393ddb5e68429c9a45796ca6d92000 +2cad40453ed34e63a784db137382ce32 +7b8e849ea0c945e09a2d34faef643a61 +14aae91ddd4e49918597b8150a1900a8 +e20d0d51217a4536b9e3d7a5c1d79551 +c2c000d5e6ad48d995d6e27d80dd1832 +0d6c4d23bd5642a1bfcc995fa8448ac5 +ba13f81138ca482d8cfe1cee50e30cc9 +a8d4d759557e458c89e5e01cc9a96917 +3f23c9506077420fb762e12bfed7e7ad +93f297c8736649bbafa731d0859c738f +71ff83cf547048cf8b3b4775f9df45fb +9ad9cef53a1f4236b06328c94519e313 +9e7fbcf154a64d70968d93431dd4baab +0434e614b2d946eb9ee72e2a50834c74 +a363807ddbf649949303c52a9a3fbe3a +b09adf160fc74260bca65cd4c5c66650 +5632f99c65cf4f6eab6bde38ba99afa2 +828c6c627d74452aa97ee9bf7619f808 +0bf4013527064475b4c7c41203e3b759 +f2ac26d3788949bbbaa49e8fa7059748 +f505f0acd0dd40fdb968548df3bf5451 +cafca447f286421e8759d1dacdcfa541 +dcb1415a4bba49a682b313eb9cf88e76 +4ade799e007e467a99261f6097a0c041 +94fd7e36195d4df68990d40d7e52d21d +3be546411ca148af8780e69151edd69c +4f72eca722a740408258920b2449059a +9562226299a045bab13c3d66f8593208 +32a6534055564cfb8e2609e4ad6dd856 +44d69f20e761400d93b0f1e72fe08528 +2fce67e5e5a347619fa791d33b1fb47c +5820e6a5ded7483abc5f7eddfb2da500 +03f6de03a15e4e398987ea88f53a1af0 +ad25654fd52a4e6ea2196cbf84a164e0 +63ca24d6d4224850a659d110f85d0f20 +5c18437f4d824b9ebc5b555ec67a90e4 +0e9861e2a05d4814adfefc93ae0f96b0 +f23d5373a40e41728772fd86bf0ebed0 +7c62c37ffa9145ddb309b1c60ff1f3dc +f87cfb03224b4b32a979c982ad0583fe +b52fdceb5c4d4b94a78306ff13ab9872 +32a63cda1edb428dbd0387c74c106cb8 +f590daf988f14981be7134ef2ea4ef84 +9760df31938f4180940ad814b950d5d8 +ac3847555e62428fb21221a318e2e684 +109e0c832cba471fae6387c302eb1088 +589a1058cb424781b4970a469bf4f538 +b7d882cb1790458abc58bac105e01a4f +5968ffdd7701420ba9aae012b86ea823 +efb74c2eadb5416695f3c76d59c97470 +a2eb6ec3f02c4d74955d0ccfe680cc53 +3d7a17c78efb4b059d1cfcf65205509d +a8f9e29403ce42a18d10db19daa47b82 +792a7ea907ae496cb81b0063dfd88745 +b8b6b59f763a4b4a8f4a1d46c66e6b98 +6e87378f06f64fcf8a032a1606780a0b +0716cddd4b14421fb4db6eaedf59375f +89e962fcce80418389482855f48778b3 +10db74af64c640398abe0dd681db577e +df4bf911a9374ecb987a222d017f12cf +5b3898052ca64641ab1857a638551039 +c8ff5e2bb2fa45e8aa18ebd16495168c +ad071f3fa42c44b1a239bfb80d36003c +e3ac447986de4165a273cb04246c8fdb +3a6019602c234c13a376c55a6c52c0b8 +e87d88babdaa4c0f91c558b1d38ddfc0 +19604e5f7e1d461f9ade081958241d62 +080019a994254303a35fae30cf6ebdb9 +d1cbadb78dc641f1be9e3a16782d4821 +44457c8007874907baf0f4cb1d12fe6b +843566efd4464517a101d1c0dec94698 +6c15637958824fe881b6c69987849673 +3eafffa90f564ca6b4fd517566c5d0a7 +7cfe8cabb7f94e7db4459dfba38122f4 +c0a26335369947419d833134143a8aa7 +08ee2c09286844ed9abf84e5bfef9b3e +3da7ca9ccc654a408c7b97216e945bba +712e1b9155e84173806bdae1868aa7a0 +52005ec1141549cbabe49fd9331b8d59 +05eb4a68e56249c5b3db4ea937a57b6e +66e162a4c38640789598d41f923ad722 +4a6e764d56f2496e8406e162e4852e46 +afda558215804278aff269830e3c5bc9 +c440b291045841abbd90cc3ab603a0c5 +1ec6b400d8ee4ace85244021c1e371c8 +1a6e9922c1d34fc1855ad3897bb09766 +b3efcfe9a17348a5aed9fde7ea2697ae +26777415c0d14c9f82bcc95f062bb377 +b014299cbcfa47ddb351612a0c82ea6d +19f68e57f79c40658b1c6bbe434a0386 +8bde00e0ca9540fba7d1d42ed76603e2 +51149a8e7ea045fdbe6aeedbf812a9c0 +d7ea2d2278f74e49bf089ea531e63fcc +033df547df9c4910a71c12201330a202 +1eae55cd80e146be8993d31015804219 +383bf7e5bc894e2b9a3aab61fe2db721 +1015bf1ff57445b69af7a2639788073b +2b1ac7abe2624487ade51c180bead840 +a51751c9989940e592eb61be41ee35cc +54ea03d661e64b279c7666f2212f3849 +a4bd65e095c64a3e8abc1c3506aca8c3 +285134ab18bf49d58a16f193b5403da9 +edc325da45b249a88cf3fa3b350769f7 +c277c4d1742b4f118becbfefd325ce71 +9c91238e7d1748cba41f4d28777c7c3d +4a81d008e366412db592a532696b3979 +0e337f3fb21743dc9b9d58282cf940e2 +4443ffc9247f4f2586d1613755ed0955 +997e14b915804f0690e5c911cb3a979a +e31e51b3605e4fefbe4f0563edc7814b +7e062558b9314dd8930d6e084930f4ba +e6ae56134408447d98a4e478ae012b2a +f395579ab95e4a20a4e484d7ef3c6dd0 +093797a8ea98481aa0d7f1062d48f8bc +c3145007481840a0ae9b77166ea437f0 +d921be7dade949888333cf9e3a6a4058 +22fc3b3ff33b432e918ef159876dc555 +41e8d234503c4c9d87e029480c5fb131 +660cff67e8fb4bdda64e2d3e0c0641a4 +736fb6af4ac542dda8d5f3e97c4448ea +81bedf312287496d8c30fcfb7784e959 +57bc95b7347d4cf3a1702f195d734c09 +f09d4774ded7420a8031b09226403701 +b4384cd0a4e548d1a7c8acc538b47195 +84c402789645463eacb8fbb081f0bb67 +9f0de396187d48f7aaac0486d12f1a37 +578d3232032446a2a4692a9bd670c1db +547548c8003a479a971727aace7d50bd +70a574ead25844a3bbee633b202376d1 +c66c5ca931344e44ad7232153727519e +8fcae78fe899467da8885cdbe04a139b +71c931156b9e4be3b8545e9641c73888 +8e0e716eb52c4d8fb8b4519ce0e5b45a +6d93d9e10b204e0b967c02a08c6feb6c +cd9a5677626f4b648a4a3b1e0d9ca5b9 +05308bf4da874a63b040399dca39489b +2935449a1fcc41b58ba194f41e74c2cb +42dafaf8980f4d2f852f2a15054aa3a5 +2c7171d6b50744fb9c2de5396a535957 +4436f000d53544fda0579470a0e4cbe3 +966f9c3ffac142adb4cca2f82682ad7d +92fa765da6504d2e8ee2c0fe3f41f7df +550aa2b9d82b4206afd77db4d7ee6388 +ada08ecce8184524b640e139050e1fd6 +060f3f8bc7de4e6ca2f348d414702e9d +a17070d3ce224e9d80bcb4cebd10c42b +f2566811d3e44e85bbd8a1de92b5e053 +9b983bd119404a94ae8a0c1271001c51 +66922cadf86d437b8fcd4433e5fbc086 +208d633e262a4e3bb94599ea25042d4d +6ab617cfe1aa4a86858863680346f53c +740cd732defb4c3bb16ace512ac4e19d +187e234b63ae4d9f84f49af9b6045db6 +e1b032a8e2744fcba242845382360d28 +48e834f645df4a4ba958a03e2eb23d5c +54c466359f8b459dbccea0168ea01c85 +efd5b3bb9a284ba0a54e3a128ab81b1d +00365fead4044f2a8ae896a68159625b +023e3d2170f54b219d4d44bea2075f36 +f85d114f12fe4b2584b79d4fc176152f +94b058e49f9948f286653725bac07083 +254391f83622453babc6f0ab63947034 +2e28ccd62dc54a7889dcb79dd5a788d8 +6b8e581574da4773a6896ff142e47daa +c5de7f697e0e442a96ecfea2c5bb57bd +89ffb36f56ab4e279a6165f57204958c +9527ada3b62a49f583b9c1a86b21cc18 +666a7dec5b7b45da96cf3e21c81c2517 +593ae0b4fde44ea6b172bb5bc1769bca +992afd9f039b4773a5a7b9b89b91a244 +f44a1c6538684c94b128e23c8a775ca9 +070ea6eae4bb40a99e799ed6d94698eb +bfba243df6a84234995b9f53413fbbc3 +205c0164366c483aaf905cd8a4f5a590 +3d3301d5945e4151bf26038070f42f4d +cb1bacb6260b4002a37d1b78a5763fe3 +44b10bf52d4d4b7484960d89fa70ed92 +a5eea808dc20404cb5f9e05680f7362f +de93fcfb54c740fdaa405ce3afba1031 +2b697c4577e34347a204b48498085030 +dde4f952f90a44c49db8b10d47952de3 +843bdab04cb04c5c8b352536a4499172 +69ad00f6688749de9934481f3e7ea669 +94de70836b884363a196479341fa40f3 +d0827a414b0540bbb9fa2d6ff3f38e16 +886a468c867a48bd8022e0752021493a +760799da34734f43bd03457fbde8764b +4a88ed6d9fbd457cbefe816e22534ed1 +b7d390377cc54884b5e2ab40982c90a6 +fb5e3443ac1b4e1cbc4099b84c75fca9 +1ed333dc22e74cf6b4aeb2c9dabd469c +9c4ff38d235a4e0d966657dae3061f0b +e37cc2a1af884cd28e7266c989112d80 +05722c72e46342faa4b3915d32897df6 +b719b1e056694de1b38f8e2548712fe1 +2848a13dd9ef4737869c81ee90212ce6 +2321d217ef85436694ba1f8f8e4aa28e +3bf37ebf060448c8992550c0c76b23dd +1ce34947a40e4f8f8c2baa7bb6ff6633 +6ab4a3d94a524ae78fcbdf811eea9b88 +76fcdf15d166452a94ec5fec385d907e +d9dc1aa63c6a43af8d830192e6f91b13 +5c8f46bd7a06484f941bb2bd420c87f0 +137107a9a148431ea6bd255a5a5a4cd2 +141b184c4705468b8bd7e17b0f748bfa +a229aeeb2b67432792fcf0c1ea4acdae +777de89152e645c5ae25d9f11c4399da +fff2d80091bd4770beacd30bea4c843d +f3bae65f598f41d48fc2d27aaa7f3d05 +7f607b4b0d514789b97270f83a6f4a93 +98db321819674f989ee989f9e567e20e +0592fecb8a124d598befd935159bd561 +94f253a91bc14f21be83592faf5891ff +6c77086d062543ea8a476d306254702a +7d7c48dd9e3548ff8a82c1ad5c6cbb20 +cc1a672c8c9447feb386c203f8396f27 +b088d87257a14d7db6b490910b4063ed +d7feee089e644cbda0c1cc3b0bc885ff +b193b648824040559bbb618ad5a33a51 +70cdd83b6330428cb51b92a4aa775019 +181124c146e94ea7a03022d0c9b0c8d8 +34fb79993988403594e9cc9b5ad09622 +c93f1ef0267e416eafba5c03e2f2f511 +4eb3ba34f50b4348b74a3f9a78793397 +4a3902780dd04d38a951a3c69efdf430 +f536745fd82144eeb5cc4900a48e816e +10d60b25c7ac4c0c9de056686ed01002 +a3d687b243014a2eaba4bb4091e9001d +ebdf3dc34c814e15b28abe626efa08c9 +64ad49b1a1ca425480a28a23dfa151a4 +21ec96c2259d47f4b6e95ff891abea64 +6003ba0de77f4f4698a2a057c28120a1 +22adabc71629423ca86406146293942b +8846701f077241e6bf4090b5abb19919 +78628031adc3427e8be0ed017b843805 +790ee621be764ca88d4708a89dd14016 +fe5d9844332447b08e83070e2c691957 +a1c0226a38bb4daeb437398869623880 +e2653a78beda4b01aafa0fe05d65aeb3 +f16ccbacda724e27ba5112b5b6355558 +4dbd31f8ccad4e6f8a9a4255d76448a7 +5cc6af098e754d94b49ca610def3f3d6 +e25fd144cdb447968f20d4f4a6166d4c +d8bab16d9c3242fcbdbe8e2f54973b6b +6d91bda4e8b743558c8125d49d673afe +6b5cbcf70e944966bebdc102676cfb7e +c557ddedd3ec4a2e9a0c0b993f371beb +8487824860ab4ff7b9c54665eaf2f050 +422fb4ef72de4ce58a29b80944ba6084 +f4b1e29dfe6242bb95d03636c739afb6 +9fd4896dc1fd4ff69ce855ba3d47298f +5ef8564938fe4de39fac93c3fd496015 +d96596e0c7164189b80888af2a02d10b +91903199dee5422484d0aa2ea266dd09 +9f82750202ba49f2bf0ac3e556961c69 +af589f9836554a83b6837ec862059001 +98a3a573af9d4c23b95e5ad38ce0b5e6 +b74b6bded4f54b1eb246fab1fa8357bc +d10c9764f22e4fa3959db48d3955f282 +f251170274014dd99e092660f7cc4053 +5a293649f3f64061accc9afdb4008c25 +1076241113e94d5cae8325494e73da13 +41b460fb56df49b88dee6d20da01ce99 +32b8dd2d96844c7db0fa0c5bf4a1214b +e4e29f337fab416ab4fe11aa1d656cc0 +cb72a029445445e4a9fb6cc76715d11d +4cd820652ceb4c36a480f62026e47137 +66fd712372f14a8f8d83d4d1e4ff6dce +692740a7c393466b9413c4b606b64dd4 +e243fab1a47d4427bff9de3ef44b1a15 +a3467b35348244b6a26897d46f218f86 +8f5bcdc1b8ec47a395402c0284b47d6e +e6a1829a33ca49dc8f7a2261058c3c17 +5a7d3b6c69da48dca3ca5fed7fa9e882 +236d43744d2e42db923b0dbd7ee0e911 +d4f4699d39c24c8fbb1ff841b49f87f1 +2b3717f437ab4bb89796d6fdd44db9ea +adb078c42d0746798efaa3e4686afd33 +0f02377585f84d4eaac1f68c19eb0d66 +b1132a4198f54427a93b887260b6c146 +4867c0ab819d4a3cbf32f63093939e6f +7352393b15e742518d4c1df28fffee3b +61c2ded1b4a2454aa4d7438fbeea8b41 +07fe989ba464464fae6943445703afca +d02fc474b9334159875e7f81a3f477d3 +f654bfb8ae2b48dfac9ba5b6a86708d8 +cc4781a456f34e708de0b5545d340bb2 +3ed05d0386d745ed95ae6ec7f4ee86dd +8274f23ad7c540e38734f9eaf048c40b +0931f9240a7f482893203f3a09b788fb +abc715989e3b4d3bbf37b1bea9fd04aa +79ab6bfdaf02436397febdbf1c19a3c3 +efa2f1f33966447e8d21d605fecf5231 +92601efb9e7d4021bc4ecc7250a9930e +1ba635669254461c957570a41d15616c +afd49ad1b1a945a3a495edddf97553cc +0ba903b566164dce9d2d7b2adc9ba921 +6f74e104b47c465fa6735a527a83eaed +1777cf946fef4caaa4113958fc0efc15 +7c4ce8f97abe48b2abfbfa6e1c9e1549 +766ea004832e4586a5af4055ae4e3aeb +0880be4c17d34b95af74efde0dea22c3 +2f716cd34c4944188655b8d64ed05438 +bc5b61d68ae04ba59ffc2cfce32b8a32 +a5c178713aae4cb6b19a3653a31b9fbb +cfbfff197509468b94534dbee3e4a287 +42ad1e4a3541493c85214f8147257a40 +cc6ce525111e490e93a2c32dd8f57c38 +fc5504fd32fd4842b5cfb7b49a88c437 +873545a97bbd4bf5b8818b9c2d62b54d +39046b987b664bd7b9e01bf03d188996 +a8d7fd1391494d7d8da879ffcc826862 +aa43cf45ba7f42ab8b03a896cd436d5f +93d9b410b00442c397e7d481f6940d73 +fa6edd547e8f4d6291364fb549688f2b +908f4e160d8645038aa770ffcef3f605 +e391894b3c3444ff8d2b1b0cee905ab5 +e20ebbfd0fa440c38a6bd1bb3f22a2f1 +6617f391661b43588f95183f17f8386e +989ef5a7827d4ec5b4340a7493df0065 +500c139510d64681886d217fde9eaa16 +be38157bd0b2440983c2da950bc63bf8 +051c3db9337c412e947887477a28bb27 +1e70b26e426c45dcb9ebbc9e062d6113 +fd2ef60140334681b0b5cff622eb7245 +4ec62ed9b3de428db25b6c25417b7897 +bebf423c0eae4e16ae1dad71e268a298 +baabf607c4e044179f16835f9501aa05 +8655b5bf7d4e4398b6cdd1dd90b0bb4a +9bdbb414efb94a1e9eefcd07d4b0fea1 +83c04eea513c4a57a805a077df97d55d +eee70cb7980a4ca7aa0a2f86c492283e +02aa3d2180c64a95b990a8b89d05a552 +1a335a75362d4151bc5a3189e37af2ff +354c1eb5814542759428d1db0b0a40ba +1b1b223e06644688a7593b82eb37ab1b +d8bf7bf749784f1ba92c0b174c85c41a +8994b29d62aa402c906a7c0aaccae93b +a44483bf93cd482ca92474620d405a1c +d18d78a57c934bb59ae9c54936e87c15 +eb0ceed46d014d3b8e8da7f3b2508b62 +b8fe458a4a5043d1b9d9086453dce124 +3a076319712c4d50b3120ee371a9b1c7 +e2c3a1bea177411dad535ccf3ddc2cf0 +b538af1a479242b69b76aa5e288b3bb4 +56c758c5f05549e5b3eac3942d796bf0 +e962d32beaea428ab1481ee63a20b130 +c7db153e97a94acdbd45824ca668497a +fcf3dd873bab4367b4c7b47feb68419a +406ab7c30cdf45c3902a868c89873666 +1722d738c3154ad29ef61cce2c972a3c +5b8eeaf52ebf409bbf7b19f7e3b89037 +70e12a92d4834dd8ba25c688a3f411ee +e5f37c5f821948628c5645a1d41b2afc +5736b49bac9d4ec0a4719a4be1c10450 +ddad88308c5e4cbb952158304efc246b +9dc5201b8839467d82064b2acf64c888 +d0f2a486c109484b877d7779518365e4 +bed23dbbe67b4d6db6fffe9e656917fd +ca30c85074dd4dd38bcdb447f1643a8a +18775829f73a4246b12d4becd85eb7f9 +0e2a45cb08fc458e9810de03afeb413d +127f498b23e14b779bebcb1c49e8ab82 +577e9b769a0d45528e18707aaaae18ff +72496e3f9ba54ee683fe00534ac3b174 +dd6c40832f1e464d8efc6f3e50a1d66b +7d70ed97202c430b8a124a99a030b36f +7f658554a3854ce28cae876c2a3fafd4 +ef6c07a0857740e5b725077bbdb03dc3 +b6ef9a1621b241f2af756cedfa742f91 +4a76b1f3c15e41d39267bf22782ab6af +e7cf91ebc40443e2b9f930f604e4a040 +c752129bf3c342ac8a1e096ff21231d4 +b4dc0da100dd446bb20567808f4db667 +001a994fe20b48739e18cf8a4e9d6fa7 +0b9ef48fb67e4e958dc54106df2ace4c +3c5357091a8b401a9321a502f845c98f +d60d5c6488f340ccb4d5bb67ad11907b +a25aefa12d0c460a8d181912e5dfe8fc +f3dd3064db4f4e8880344425970cecad +5a0ba464174e4dbe94aecfe1a036ca6a +298dff4d018c44e8af3d7209bdd36159 +217b4cdaa793475597e2a09adda50fa1 +197c895ef4d94a13b7beb2e8bf6b0ba3 +2179f56c4d4645ffa2c70c8e707b9065 +ae26f37f22404719807b2e6f3b812606 +cc5e3d70ebba4215890504ea311252ba +32237ac2c8204d13b741b43409bb5cd3 +e0c20469c46344ffbe37ff14ae669da7 +0a7b87d8b90744678766b2e6a0a09a07 +fcf9039e22554ff29ffc62cc4dfbc634 +ea0cf48616e34708b73c82eb7c7366ca +b7e25d2b684747c08e90b8cf446bdb43 +bef4da2a0676483ebd0b9b3b6d571ad3 +dd9db3259f804a7ea2dd5f89b4077183 +df325cfe1fa24108bdfef58ba7e88b3a +781a7688333545eb9ad14a358fac01e6 +91be501188314db69e32288ca00e97ee +a658898eea824f92ad471a0afec24607 +fcff3f35fc654c259e24710f89d1fcfd +8907f8c7c21842b7bf059b077ff99a35 +52c9fb78ff704faa821d193543ae2cc7 +a1767c7025ab4c93bf18452a21fea774 +452a0ba229d04c07aff64a4b5ebfdcb0 +9ded19c9334249188b060f989eb7df99 +cf3d0d8402c0430bad5df3dec541f267 +e953987a765c4b7b9ff02a1213125ed3 +5e40bee711c041028e19585429e7788b +c6296e731e3f41ce9b014b64ffbf9d10 +16d913f9f7164119bb0da629d6e9cbd3 +c913350fa1134c8ca4fb56843c2336f1 +c9405115a26344bb810ab1eb31ff73bc +0ef362e1b2fa4a77936531b160be843f +092e7fd1b6a248be9b4a0a457bff3dda +690a03b9f7234bd4845eb4b8159eba8a +20d9815b99a74ae78b2e4d39c924f864 +341b1485ae0d4e2b9ac030e5d332aa78 +9d4b50bef60d4bad8cc6edccbb58094c +77c971f5aed6409c89e30f3719307adf +15fd42e4f36a4dbfb5d489c766a0cce7 +12079c398b3a4e8db2d1f9a4da6b29d4 +335ea4f5a368410c9c2646062aef3545 +68cce42515f04a289071c2474f2b1652 +461f6a648ae642a6aa0c2055400c8231 +17870ffdfe024c36b2247716af656f05 +33d1d75841cf4d25abacb051b8fefe66 +0e1b13fda06e484d8387ce5557b32f76 +42cbfc14c40b468db869bd1ac032ab75 +218a1626f9dd491c8814b4011bb8077a +38f399f84b9f42898b58bdd2db22daf5 +fe255a26057341099c7139b9d6648e76 +8678fa1466c34436be7eff7cf4938a5c +f6dbff10bac748acbda37f4ad3318a56 +661cf949b4054322936e97956d0e4347 +1fef2b190b0940b39289d3d656fc0cd5 +53585f2941bd4a92991d30a557bb30ab +ba4064906552427a93e0b024eb1c1a62 +610d94b2f85843b68404b6e69e58cb3d +be9f207835dd4e389905af2527b4a5f9 +f4cd4c63624f4642b0e9cbb5f521894e +dc01c7c96ec64f6bab213fac36043fd1 +8acd10b3f80344d79202d8c2dbfa6e61 +bf0d2bc20ef940fe9a9d21613a895619 +316a0da5fb1b49af92a51a6baf719098 +90d996fa29574fe0a10514d8f07f5a50 +9b46e54611c543f3aeeacd2580994c34 +ac029344ea9c41f8900b50e9a628444d +747b402691154a048702ce7d9ca9914f +8058be93a9d14b35a2af0d8b218d650b +87feb5db6f284c60b42270803d34d85b +8d90fe24982c42719f22fb3033371b85 +88949b5ee225423dbda36628df8fe9a7 +88c3b1db49e945f09cd37f04534956c6 +5ed0c8ad482a44cdacd7f87ea6474885 +28bb1ccf95834df78ce479f59ce0249e +93974967271e4c4db08efec0023d06bc +97629bcffa3442e08e094e93093d3676 +f4d181dd05a24c259ba612cf68961445 +10e171454c1148be96e684fcf3b48d3b +1d339a286a7a4e62865717e01ea1357f +60c209ce9c25446dbdb0e880dbf51de2 +6b8ec1b507964b4e820b3069e72bf167 +477a3e0268974083ae89516feb89f959 +0e17563510fb41869a6f2a7f5f2c5f7a +eb11d4ec4a97447aa949630e372f86fa +5ebd04ad8a9647e999c04ae92dd2fe13 +7e575d53501a4a8ca80258bb13a96da7 +cfa4ec3fb60f446eaba4f1ab9b4adaf7 +002be48987e54ac0924772d6a562eb51 +4babe027b3aa43a09dffdfb8da19260f +7fd18af9af9741cf9005fb99b9a51323 +2892cc4cab4748cd865b7b7cf3805308 +5e0b0e29d0b64f398ea35b2a51e4c5b4 +0137fe739f5346a98bfdee5edb78c2c1 +978e8a84ecbb449cb45999c07bf49e37 +237d3ea13cba4b059e513557aae3cf74 +5183846d201340aca58831bd2d3a0819 +90f162fa37344b43b84eb956f2040649 +d1edec23f016470193f7356ead195e78 +dc4ecf9e517044b296e8ebb7505b42e7 +afb3d4c6128843f9b322de543abe48db +ff1f517e6b874e58a66d75dd1e990cfd +2dbb992f323f49628889b25f1cd62e06 +3cc1b049a8a9485fbb8772af8ba95cb9 +52de419237fa42ffac21b38c4b13bffe +3dc49a977873417088384f5ae78c5a6c +4f50e5d5a25849ee80b8049c4fdf098f +9231e77e152d4e54b1673eae6686ba0d +c95d35128efd4b34861bd381746671a3 +60152affe35d49a1afa2b48c7906bca1 +fdf39ca893a64368af45f82a6b6d68a4 +5eb658f503854de1a23943588dcf4286 +727fbedf464448c2ae648bc2ac268e29 +f0dc46563ca947cabe47f6d2ef6e8bdb +046f500444e64bb8be0e3cc09ccbb754 +f638d18097c140f489cb9d65ec4ff4b7 +6dba3fdbfa1e4202b3d39c0967e7e352 +60414585348f46d8ad930dafeaa5e4e0 +0144133a874d4fa9881d8947928999e0 +0d75351c6d8e42d2bd77f449c3e99b5d +35002d28d3fe4359be492bd444569744 +591fa396a54f4941bf50b451b99a6de4 +7279cac4115a40e6ac345d68e17f15d1 +e8868227230641279cd6a3c58e1c0e5d +9b526e5788a043a6835309ac2b64ddaa +01a259e3c4f34e56a33a4e076bba8458 +388dc49d323d42fdbd08e53021c10e82 +5b15e014a05a47359ced2318378d4cef +d24daba80e0041999d92e23eb1be5710 +67afef47ad514609bbd488cee7496e0d +d075feb7b0d941df81f23d8df4369ce4 +048e1ea3cd3c4903b73fc65f6d2489cc +e380a379439d44c1bbdc9b2628ce8867 +1093af0b9cad4a46bc19c02f79dbc226 +9bce6e3391bb485e90c671cbb6e7c52d +4cebaf3fabb54460a218740b0c4ffcef +17cac1aa2d46404ab39766a20c5f2e47 +bc5407469e1345e382ff93fe4627bfa4 +8166030178424d2c89bcb1ce02628dbb +69d028818bbe4aa886e3abd45cd3623a +b0e9b7df6068489da7d09a065de065d8 +9237b66bb30a479282cf0ddbb2a8318e +db4f1f8f757341248818540ffcf87364 +d41e2c59eacd4340bd7c03b8bafcb4ae +f8275823c6b94f33bbdcc1d857b1d983 +fa31f0a004ad419b85f431e462543d3c +2c9e9a7374334d55a6a343f2abf40618 +3585ddc206b24c9fb2298eecc2573974 +bdb0990c665748038b1f57f5c6d7ca72 +66365495cc944181848b3db883865c98 +b58d4eb47f044bd9871201af4d72ec1d +5982ab03c0804662b47ccb49c4d55b5a +e70b7558c605496ca192838c1ba42187 +94f2b4c2a34947819e3446c7dbc169ae +0754d5b808ed4bd8adae168e23841c81 +2651aa6a55944f34abdd12f29dcf99a2 +422c4d22f1574ae3958e50edde69df63 +18a1a0d5b70a492baec2b8858b8930bb +9a4bb1dacdd34654abc09367da5e03a4 +c314d1f2efac4e89a7277b63ad7a1152 +734b921c454c477bb20f3e3b37ac869c +2fa5e80feb2140a795d1f98e7909e238 +cdd9a9b1caf84b98a506a21d0e635c6f +017c41aac5db41f3bfe2f7938a4834d1 +315129e315b644329f392cfa2c205e93 +05914a4b18ee4bea87555bb71e5c7093 +a36f26f49e8842c7b14ff8538398c205 +c0ca5a0aa9a048b0adfd33864f738718 +8b8163d78bee402a90e6f91523afef7a +f80a2a0af6924562be10be7354b7a72f +491aecb4d6e04121be9dcd9bac6e9ba9 +c801881f25e34327bac908af98051914 +068c936a5343457eb9d4907234ea655f +07fe8f8d13ad40fbbf6675aa259273d4 +2d455ae454514f5fa6fb3bdc7927fb90 +c1d6c8b90929452d9abbc530af66954d +cfad2e0388d248ccad1480ce784801f4 +78a0fe5048d44c98987c08b1a1ba25b5 +756da5ef6d0249479510e6bdd1856e42 +c20b085586fd48be98413696b2e76291 +427e5402aafc47a19d4e071988e81956 +4d18ba843ae24b94a5ffc77717256c8c +73c023c90f8d45fb88294bccade836c0 +fa46b58fcad24c1cbcd49005fa6ae392 +f2d0cce3acaa4643bf6a724d16e6feac +5d7cd6e8dda0460c85f50a3c3a5127fd +33344266dad14c4593a0ad37b140e333 +017eaa0c64f749dfbf60e16c67ebd421 +bea06c34bd73434faf6b66b1318f55fd +3faac60ed14e4da6884ba53648695ef5 +5dd87a342bc64ffd96a4fd1dc48e89eb +2e6183a962d9447ba37368993aca785f +3fc1cbf024fb46ffb31b13133c8a3836 +f7bbf5d03a604452916d5c0cc85c867c +abb542cee2f143cd93df69f54ba43cec +df65e2b6c7b04354b3a6f9110b277e56 +c0a475b5318e48a387e2f8a1e5a20f1d +3f8ac23a89984e7493d4284b6f99a835 +54b976bfca894d4b9ec98fca600839a3 +864b4ab8ed1d4e399ce56bb61abf1762 +0b680fda12a6402fb93181a107b39b7a +629e5dada20a4bacbb5ada4b5fe17e08 +a69c357fe0ab4c28bdeebfe6671c0e7e +614faf34c8b24ad494645f396073b37f +6aed75fbbfa046b197ef497541cd489d +7b428e9abfcb41bd814176d4d661677b +c5333782f49e40e8bb4fafc5bff63b88 +ce28811d5c174f34b966b4fae3d2f5b6 +1759b50bec9b4e5f95a3069f08bb129c +eebe5055ac2f4fb8a25ef4a2d1ab077d +6612a34c526b457b9fef451bc4b37507 +2df97bfe17f14cfe985053582cd67e81 +958bea47f15349c5a2b888f5180c3023 +a0a80e5afb33458fbc0aa0ca6d0636b1 +1837c24636634148935c922e49892daa +bc090f6f5b0749ada5d7faecc01bf3f1 +8a9edd2804eb463db1cf8a634d058ee1 +240af2279855434b8b1e2e5d04ae30c6 +6251708b41514ee6b4fec0e3955c4b69 +5e3eb675741d4b48bb4550e7d769af45 +efa778ca442945b09300a70e34e68532 +c5a122c1cada4410b1dcfec2b02be30e +05b16b5539614ee3bb4366fec77206be +69e4410cd50d4bd1bbd83cdbe442dc06 +27234b8a603d412c903b156c632b4f5e +1641a9561ae24f49ab8524a7da9ff5b7 +78ebae28e4004b0ca62f587a8ad8a5e1 +7cf83f9b5a1247198ff9604b393ebc3b +bddcd0aa774f42cc9356a6941bb9d656 +72e4849860d64619b71c5c17c7a22177 +4a2aa976e29948168169f6da77c3deea +40b8a17099c64ddba5578a7335e5bfc0 +fa4681e9934e49ddaf51f110a4c989c6 +4f27c0f45c704cdb9858c073fe961ade +5be1ca551ecc4480b0eb35cb6c0e5255 +98fc33b429af49e6afcf35a513b25efb +0fb26210a2a74b2c8e5eb5e71414cdb6 +3ee5ad26416641d0a2c959841ba94843 +e8b022bed8d9416496512cd2f9d65a28 +7fed88b9da584b1a95c8cc1bb176c169 +f1bbc61a42b94ee9a2976ca744f8962e +1a19872b03ef4ad7b8b4ad2d24914799 +b47bc51cbbca4782bd8e3a192706051c +074601e8cd6f40fd9077902233c3eb13 +88b2e129b55043c6aeb2a8c419ba62b4 +ee0be183b042441e87abb36683a668b9 +f8e991a5a44a465cb9997af2308f7a8c +e294f6c900a645298a0b8486e1ee166a +9bce0daea34d47699777f50d71c6ec08 +a5986a27070c465280d7419cf783de31 +9e58f18c064a48c18b60399b1b341a48 +ad010b988fa44a48baaf9bba6bd97d9b +b1f84a10b47948ffa8769d48b3f3bec9 +7f5794c8941e4e3d8f64bcb1a5e205f9 +7186ebfc24fc42c599f81713cd28d55e +65b7f57cdca34db6a4c84c5cea59199b +a77b3f8fe48e44c695748adba881d321 +ac46c4d4d79740d7ad6c907ca3fddd46 +f53c9f92f0ad42ab9994e57cfe711c96 +0d672a10acf94737ba672b4f747f9c97 +710ed30db285407c9aa1dd56421e6f87 +782c61b71d76414e980d049dd521a848 +a44930f9c14544a6ae6967d5544417e8 +6e6b6847c00f407093c8a1aa50211c63 +823e79f5e5ee41668abce9d8755c4926 +8026dc5f17254c9dbaeae2ee6e4f2779 +793973cff95441a184ccba99df5c7c3f +424030e72ce0411ab511e35ee1e52371 +569c551891a14f8ba70ed992670e4cd3 +344f5845929c4f0e92d10c3a97249bd2 +226529047ee34d8ca35f77ec925fe300 +642ba4ea8c9e4c50adcc09f9a7462514 +9cbb4db4f5374e8daf3010ed613a8d04 +710deb40e2a04405bcb76e43efdefada +5e6edddf49c0419c990f68a78f2a2a22 +3bcc0c28ced04e3abf7f6cbf004d46b4 +223b376823b54d56a783f7b733aabe29 +9d587359a2d841f6ae05879027f76052 +cecc02e65997485a887b784ead9b19e5 +c19aec34d1bf44c2b390be568d114448 +d111b2412fb74366929d222ac6fbe359 +33d1ec20564b47b6b9ad363a6de06a2f +ea91bdbd359843df936ce40f63c1e40e +b891198a35a64b2c9c3c1a26338b1a48 +1fc1828ec1904802ba39e31209c86ab9 +37d735f6e5dc41589a58edb81ae8fe16 +0466ac2193a84f37ba6de5fea6186df8 +7099b3ad87df43b5ac8dd2f0e4db69de +f68ae1c354a64ea39e160c4fe881349e +e18c3147f7084f9096c6b54b094f08cd +3e8253b1368f48b8b47f1779f9dc8e33 +e705259c8dca47bfadb1a164565af7b2 +545d37a90a7d4c00b5e5bc551c71fbbf +44f10278ede4418d9df60b1eb58d5113 +af95b60825f34651a6f4e3f749078202 +1b591374cba9494eabcb0dd21dd15ed9 +170e195979d54b4fb4a084d3448b57ea +f117b0c64b534181a967b9a9a681a237 +75c058a8028340e1adbdc9ea2dfda9d4 +b0a1e64c90fa4705be2d6cc180594dce +a261df98b73740aeb8b93caed543f730 +678dfe84d8bf476a86db351bd2b8ba98 +cd1e63b16f804638873d21b822a23617 +5cbcb1879330482fba912fc54916135e +64eb3f327d3e40b4a01df1f9538883a4 +14f196c232d14b4d819c9377463169ff +462fd6084b9349a1aa97bd19528f54de +8424052f44274a4fbab7e59dc9ec601a +1fcdadf6a8bf4a008de9196896e3636d +347135dc509345c0878ebf2a9a3b283e +a76bc33b7a40492fad7da0a6e40bcf98 +8c900496173b4b32b8f8990c2d97886b +fe7d861ae9eb499d890f5b0b8049f43f +95c5d6515ff04092987d698ab2c8442a +e49ea080f49e4913aa02c48d096c45cc +e0e4b761e22c46c2a108b98abc88b95e +f9d4e81070b64950b7e16fd59d2d7361 +332a4fb450ae455286a24982317a0b60 +647133311005487c865cc33423c45b67 +655e2fc7edaa4c12a9db785a241aacba +a175d9593e764b259d690221771c5011 +5a7229d68d66455087205806af4b4558 +eab21bf368fa4abcaf1b01c5abc4d8ea +319fe609a7044bae88ba343bec58a4d9 +d012d05e8bca49928a2944e043d93fb7 +8cb19c3ad9df426ebfa2053d9d8ac1f8 +818d8f4773844a40bdf43379de718f6a +f0d343ecdbcb4fea80536550a8a2fb03 +d45ea22770f44818949e8933b853c6c4 +9f04dfb191724bf287ea9c42ab29b233 +4018db5a2d5747f2b971e6bb7210063c +250efd1d8a004228a10737967beddcf5 +39a813c157e94a3d9d1f2332134a47bb +9aa41f88b5094c20837091d3b9a26380 +953d35b8ae894ca4a300a6127bb867d6 +0e6356a258d3439b8362644bc0dec88b +e0ad49d3316b44069260f59ea5f764c0 +8dce1efec1294b4ea4c5d4129b0824b6 +a6af3d23dd274f7b9f23f3116e7e03cb +30e26e3d917a4a258420459f5d54bf49 +24cadc713d1f45bbada202d8fc9de4af +616e18c422eb45af9e1607839c5d5b81 +2391f4ecfdd144bb974f14bd886b600e +bfd8ab62a3a749628a982218b19c2d40 +579df71336a9493f8f52ddc815d2fc39 +3c6de8d50fbd45909cf2efeb6d636113 +89a82eac43a34bcd83a5a075b0e5368f +2ce349f95b78493f8fd15c103d84e5f8 +c635ad4172c14cd1801a29bd81c2fd3b +4a24de5470994e429e1fe79683a6ca06 +852e8d7eb9c4401f844fd889f85a45a8 +6878ca05f50147b0ae43217b66cea764 +69bd97e6e94a403a9cf4aa872907c95c +11074ca180a04e0eb41a2a656e91b8c7 +9f21ac519bc3429aa7e4e72cc9c057e3 +5b43effb211e4688a18fb4ed7ec06ca1 +4e43eb29aa144bdbada1ec500d218a81 +a9f5b1b3fe1849adbf13a4d9ecc5f080 +6a88d4caa17641b48534216759b204ee +5a4be383a62c4237b0eadb82f1ec9f8a +426bec4978e84abaa1009a6f30686319 +c9abeb537dff43c2b01bbdfac3913f55 +e3bfc0046bcf4ecea6e1b291311b8280 +02e5bda4ab97441e9d0107b2625af4ae +c38293926711435d868dde2c389e748b +e1c9043ea6204efbb58e636fda61069d +c3de8f6d87bd4cd19ccd1f6ead3d4d2b +eb2d55dabbd440eab651dd7085fcdb19 +d9c7f3d06d2a4e4eae0fd0cfca9870aa +0ac6c9ca61c046f0a93e17471d16a8c1 +f0857110021b4689bb767a83311b9466 +16a80a9f0375413e9f752e493ff24341 +fa01b6bf386d456e8539c49c1ccbe87a +7537fb9b87f34db991fffd18119d0865 +42875c098c33456b84bcfcdc4c7f1c58 +ab1d50e07eb148da81e9d82b947aaeb5 +fd40add519e541e5a9aa882397e25997 +91c0f9e543f04206b74bbfe1b2b312f1 +39d8bb144bb04bc68f5c9ba4adf17273 +9e6e5ed071214a0e9714a09051839f7a +bb8ea04fb536463eb6b03a93a17a7689 +5714c3bb38a2448e9644b2892956c218 +cc7ee8c5d3fa448b961b9042b61dbb68 +76a2f8d83b37400895e1a9b4da4ec206 +21b36ef4ac1140899763f6a0581a01eb +26673839e93a412e93524be2cf109672 +c04aa47aad3e4e0ea10c51e1479017a0 +35735db6d3ba4492844c562913a17c44 +20b8f2af1ade40dd8c4004196a048f8c +f76c502218884914a27148f656a9b656 +81ac1ff71f484a48857b622cfec06b1c +3c45e0be1c134e1182be081995064b81 +2ee631cfd24542b4b47eb6d88b34d4a8 +e667442a9acf4f8f8b4456a05cae039f +e8d5a5d300024a7fa981cd294e97ce60 +cee9536c923e4c118eec59851699f26a +a9ca6747427041c3aa4c7ff771933539 +0fa50cf622f44f2ba59eff6c11cb8fbd +5a6846f469f5426cb0520fff1680ac25 +c460666577e14dbe86a11c54b9a39bff +d048f7bd322a491cb270d6312962c2bc +097bc64010ee426bbb505b9877feba6a +d1dff8ae79cc413ca0ed64308786baa1 +e5184bb3bf2a455c8872e759bb97e13b +d89b3a8543fc4a02afd8ab29938f0c5b +1bad34d8c2d94a47b5e36abc6a1498a5 +9e22e84a99e94d3ca290578fbae79f87 +1f46425a6fbe47cbafac023e75df1975 +236fcc6d88ce4906afa3a4f577e4631d +a02a908f2dd143d390472b8d204ecf9e +7e01e354b9c44cc6b5a8a66b279b1588 +06ba42f61a0f429b8a8e8c4a58d2d972 +21d255f040b948a2b2af88de30c7b43f +2e18d865b85941e59304719cd325322b +cf4f97cf66ef4a5398cae98e57e7b975 +0bd602d9d59a4eadb35f871c6723d2b4 +20262cbdc8e2493fb9981919d415611e +0b5e54e410a94adfbd736e30a7c915e0 +6233f25e6f784473b0277028bd99a8ea +d6332219454e45f3b27d834224238f28 +ddce0ee2447f4812bd9bf448582aa5d7 +f52cc95a58c946fe92b556d7a2d9af64 +35ae83ad2dfe4274bf56621f8c20e6b4 +d3d0df59d20d4452a2165a4c76f62287 +444d3219776b4e5e8ae2b73a15090012 +abba6e0c876844dab89cdd207085f504 +447a6fc3783c4191a5bc9d5995bb7e17 +5ad7b20ef1df409dac02399d0983adf2 +fca9c0e7606847d6939f949b10f3afa5 +e283656b021f4032bb02f8eea06391e0 +39f1f8e9142c4b1f9e525ece875a98b3 +ce105cabdcd54cc1826494ce2fb6514e +f6f6011216834a94aff02d05ccab947b +63660b72eff64e63947bd7fd84629d94 +103877878e894600ad74bf8a12a315c3 +7865c204560d416db00dd14467e4bd45 +af10d726008d4c9aa016ff66f59e466f +0e9a611b6cb9431cb952ff2b7b2d7a51 +0d4051e6c71d4d8bbf159563ffff754f +28a300a3e3944e95a29b32e2d9e38baf +9a6d7e10076c4c22aa87402e805fd7fe +bcd322567e4447b383773e4465004786 +d4a37e00cee941598d8158f712bc8eab +06c382ef924d4ce58afba48a6225aaf6 +eb7ba8abcb384dc0b4f86ab869e5da8b +cff7eff2aa6746aab0e43551647e8c94 +31aaa65119ee417b9a2118b6c4d24303 +1f53297b7cab4282a55ff6b91f23c82c +ac664e78a4d643238c7ea7bf97d819e5 +ca2c4b34b90248f39add966df2ed8a8e +2d9f4b8fd344446dabc44fb3b58d21bb +7ef1158b735841f4a3f3ecf43aa87c97 +beea3a539f144690be327a5e233df509 +3736d43a804b41c29579cba3cbe6286c +e154caf0b8a64bdb8348bcdb80efde3b +f1208cb6595642629c5f99627fce27cd +59ab677ba6a6445795cc32c728d62b0b +f0b7ca0f694c4213b799677e49041896 +8c70d3ed793f43a495eb32f5294aaaad +e27337ce96d74b12b2ae1a5b1a127b9c +3087925346ee49e79c02b1237c9dc9dc +f79678ee4a6c4c829711b14fd0d78354 +a87a69075203401cb6a7e42bb8743aa0 +50a5cf176a15449bb3b5417c49fec47c +4fee7d4867b0467aabce9e07754afd8c +19382675a537455086f3e4e75adeeef7 +54d1d47e25b642a0bfdc8f7f10a0bcab +d36bea1f26ad47ea98f41e402d70d9b5 +290b9e48cad843639bda09239193e59f +88fab00e70e642aa96aaa331289ed05f +67010fac463641f7904c97a78629d697 +dcc3e04332ce4bd29841e4df893897d1 +b2f538bcd6a44b67909f07cb8d0606f5 +f130817ddede45b5acd1d78f7af099d0 +6985cdf53d3e4fc2b886b9f2f0f8081c +da6dd9f25f934ec3875bc5e42a8d428c +54d901bea1f34af78c917b7fbf0ef879 +495f7b4204584b3199e8ecbc59d7e598 +d22900b7791d4f48be366dc4266f11af +4dad2cb4f7ed41beba55d6d97400b00f +fd5bb0d5f7c843fe8b9d2a44d9a8d755 +6f762bd59fe04888b840f324c85d6e31 +ec97374d7b89442c93e3e82bb7185bcc +7816316002f1426c94d4c9b4c59e5696 +1847edbd371a43ddbc277adf4b78f47e +93f2f1d1fafc4baaa435f1a32870b7bd +e3fbc2dee3ff46b5b4dd42fa16867eaa +31c2ce5ed746407f912315bf2f7e6de7 +b14a2616f6974abd9870236fcd9d6b74 +174e9df0d4c94928ac1b03a972051966 +4c6f580df80c421a8fda20cdfffa715c +af998661f9d5407d90e60ba6df492463 +5b32d39eef874ecaa0aeca5f186ebdae +e2f903e972a24bf69e7679e89e8a5d9e +e451c15161684f3c98eba02e9bbbd987 +eaf9f2b531064719aaf911c5b40d716d +dd94803090f14100a07aa6fea44b2290 +b14880e53023400cb4781f8dc06d078f +80eafecb6a0448fbac3a5152a332f67c +59e74a6ff89d4017bb707840ee9a9d1f +e2ee65bf1c8b40ac8b78fe6a1e392575 +71895bd2c24f4fb89482def7629b4343 +a7703b666af6428eafd254cda0f0ebc6 +9cd93b871f6b442d96b7eacec7326e6b +2307ebbf827848999b3579c3e541463e +93d17033ef0f410791ee93b533c6782e +c40bca9926264486be17efa258625b77 +2b1c58ff1bdc481cb317faf26e65ab22 +df40ef6782884eb99af8fe39f367fc47 +3dc0ffede3c047a48b9de5bde0dafd88 +463023dd24d14b68b368aecb221425c4 +78440f26dbb64b9ea0edf1a218ab8090 +857e60a63bd24c73830d8e7b68ed216a +11d0a20b961f4195a44d4b0f150da4ea +b2c42f43b6154f5684fd73e68713ee3b +fd3beca9386548d185d4151e51325434 +1cd383e97d304d509109fe737a994e2b +1656d70baf7f431da59b6b622b1f83d5 +bc1f3dd452f544feb64b41bb9a092173 +4d0e453b6c94400b9dcede4e9e3b9a32 +6f4a0b64512f412aa46403796201ac1c +c78f13f842714863800899014754392a +b68fd365187f45cf843e316d2ea23260 +6d37d06dd4c84fd68fa212e82c8d27bf +ffd2e8d398624a54ac859641cf47ee27 +a16421ab77124c068604160da4de8781 +7b2ad0c3e4f94d61a46d1e567f30c2a8 +bb9978d28fa54f5ba47208f50836ae0d +e5622dd4c0b04459a789fe1849617736 +9cf145fd05b74275912a95bf27dd6bfb +50fe48f14baf49f6b03a317ec409f925 +7ae05225fbb04e22871d9f3310d1daaa +545c4941bb7d4e62844fc60725780003 +b7cbf91cb2fc4984b3778d1e37fbfe28 +875400ce508d435faffd6844d7fdddf4 +e1429326fa5449348f0e0693f44b4b7b +9a8f5b77d82f49c3a2eb6957728d3de6 +0a2f4c3c75cc4c3399fc85a480e23b6b +95198e3460b14c4db3749eb888a869b3 +35c2b77568af4caea603679ba85f4c7c +3588500d9a9e410497f8cd97d9863ccb +a870845f474d4a5b8aba284cabd14d96 +ab2625342f2c43fe8a383f8f9b4917ab +ca4f9a92cc2f4ee98fe9332db41bf7f7 +e92205e389f24d75811f463405a33bfe +3d780f883c6548b2849f98393e466388 +17bc158dc66a46adb36c7f90b744ee6c +b2b68fc8b9614657b5755d2f16876baf +8a3f51d301974cab8b5761119ead0ead +03bd1398d4fb417dbd1119b8d2eba072 +77ff876381194041a525815d4b83d34f +c024fd9af2dd4aa38e3821f7ae8edddf +6e2b8e1ef0e740cab650a075896764a9 +5907e9c9d6d84c6ca4df3057b302d95d +d1eebc8fe1974ff08a2c00028516ce50 +40c3fee5315c4ef2acbb368484a1fc7b +58cd445c1e0044dd8af2009d51b7be18 +fc163e373fb9476a8bce22dabe319f01 +958773dd534349d08040acede85d78e3 +a4b7354beadf4f4dbb91b3adca7f0f62 +2250094cd7bf484d9443ed0c5a97483a +5847cc0ce8584b26a40056491bc618ca +f0a106e66e7243fdad67ea79ea29f2ff +7fa3c674aac9458e856aefea1ccb6357 +c18d2ad9c6314943b32c4fda3dd7a231 +1305f495d1f24a0ab5b05d2481647329 +1f4dc36aace943328acd5337f5446aba +4383b3f88d9646c7b2f336266eaad947 +4efc832cb16540b3b4a3506855c4d90b +207524d73e004bdbab379e271acb9bd2 +10ff2bc625c84e858fb3229d3be525b1 +a8d5499be15f420dbd1379c33ebee4be +ecbe604d49364b7e879d019da1f92376 +5a3b50e19e5342c0aaf713f9b3f33527 +5aa9584d37b3404796508dfe18ddbaea +c8b9ce3fa7cd493cb2600026b887e792 +9454e6c9dea245f08ba88be96c12f126 +ea628bda86df419d9446b361344582de +c2c1282dd510447b8cd0b95f6c4ce44c +59f5621c258e4b3f95120ee5dbf5bc7f +05d89057c5f74801a1f4557fe3bae843 +6ae8a2dbfd2447ae84e8b03b1d67de3a +d276a1bfce364a9ca34031beb3d02cc4 +5eb868652fdc4531990e9e5454e00d89 +a8ad1bf89f6c43df8e4dca7237b306da +9b24c5e2eee24eb7a1d0386f22a26350 +e1324aa681024340905a2fdf238e8c27 +b9a919debbd6431fbafb893393bb6eac +d6444e535fe54ada93e2234cbf23de37 +bd7100c5d3964b52943878fcf01220f2 +c40d358a515e4c66a506e5d8d6530e8e +76c11a26bbb540c0aa9960272598c1ea +40fe1e3a9dc645afaab0caffe6a5f81d +8b8726e390134ebcba42c5cb1ad8e412 +6e0ecc9d43ad4cf9a17efab2900f72ee +901718e881cf4a11a61cf2f810e666d5 +26db2460912543e8aef9b086cac00fc3 +c46c5299740346a2b0a3c778cdcc140e +714694c15fc14e2197fb6deb251cf07c +7e1a73208303481f98a39c5117df501e +fd61a0b52cb34e6dad584d3573bfcb09 +f32e2f4ae4a348e3bbb3c97753632e6a +4450aaf22e02451199012358c3c61c98 +421a6e8ef6644c6880ace887c9dbfdd9 +af186ba73c8e44cfa63001ac17e08a4b +385c09d2ebb2483d96a78918c665db51 +d1af877523e04947a79976815fed451d +d48422d3febb479c822d39301d1bd3be +d0bf0076e829471a8b7ea85dbc32b363 +e9306460c713479886bb3a548f9c0cd6 +f1db0ed35b844c728c42a06d008681ef +5c50e78e4772488688cbbc2968e6a230 +d674a80e8b4a4c29a4ec8dcfb11ae2f0 +bb52ae53bc8441d68dd912d1285e8511 +5493b40fb6744ebe9e5e05feead9b79a +f805731bfb1c400a910397a8fe764357 +00e90648c8b94d0b9ea8a92858bd8e73 +4a2d838b90a64380a623362c3dc6be59 +e7ed7001ca5d47e784712a555db26bd2 +cdbfceb7fc4c448b9a3424df20b95d9c +7cee431b78cc4a708ac5bde74a286409 +596ed6a565d145af857952064bcce708 +411d1075691141fbb52f644602c6d5d3 +aa67b378bd9c4322a0bb1f98adab8174 +71b55cf7cb4c48f29e170b95b7e7bce0 +6fcc25c69a754ab09ab08d75cce06279 +aae1df2e73e141c081c92f64595a7d25 +1ab8ec6306904ae7b934bf9b3ac7819f +9fa32fe9b45444d89989a29d00b88f4e +2ba45650e964418e852d9556b49b7608 +07d500944f68482cafcf7a1d67ae515c +7e27fc0c53744e009b642309776c4981 +307b26004b154ef680b03474558061a6 +240379718378404f8efb2f2e5544c00a +5f9ae9329a1841b499e84f9915045659 +38afc4c821a845f7a667408a1e005583 +45ef4b97649b494992315925009f81ab +43e18ff7b1f34453b5045bb7062c9904 +c5e23e5c8f4547e885cc0db9a92221a0 +3ca284d6b066484893c650987fe49345 +c17c934df3a246f0905ae3138ceface9 +488802f3c3ad405f8a180bc2f67f04ce +70154629c8bc432ba4e3aa68851ad8f4 +529916f4db56489da9c73cb59e10be07 +724a76aa05d2446094793e50e06d6e43 +85e4d11083e744efaffb4411307efb7b +645b4a2217ef452581428e0510d7e607 +89e667d86eea41018821fd7796d09903 +dcd691724f6b4d29a6d16def24d14e6e +4baca7ff083d4589b3de6cf6d04226c1 +1cf7a367acda4ae39291fc3e46706c53 +e836eb07dc6e4dee859b920acb6d31f8 +4cb0c6db596a4d22a8c8d8778e3b8fd5 +3947ab2baeb844d083ac1a29a77ea04d +86d43c1fe20e4205a0e433d363d0b24f +4119ac2975e84a659f164b37025c558e +e9c4eb98d4144180b85c6d78c4ee9aa3 +d2c2036181114dd789a0c651ef66ec34 +9f85f18f95fa435982be7e5988ea3776 +4330849036a744b5a9c0876c049c62b8 +e549600391eb46b1aad1099fd39cffdc +f0e327c8b90c4c66a4cc5326e848b743 +5186770ffff244e885b211e1ddbe25b6 +60ea3018f5df4be7a54db3a7d002e867 +668e17c1b002416a8ab2df07d501dffa +ba4afd4437e2473696ce2d1955694a0c +d1e67b3479cc4f058eb3a7527b25d063 +60e698ad26ae467e9300158bdf83a6c5 +5e32d330fb2e4412b5319f1b501b3cdd +215cd872c8ab42679988fe7ddfc6baca +0b77970f7f984ce8ac5c0a03ed1fa1a8 +3c047b3262eb46c8bb07e80fe7a11698 +a81d24f5be1a41b28db06d54a606436b +5fb88b6b848b47a4b2f1534a1d7600f3 +e2ba4b02af654ff4bd75076b5ca4f9c9 +976b4290ac7f4a6dab143572d457bbab +f2ff1d3704c8454e95c6225bd64a5646 +0fbafa2f474f4bb0bc6506d2f0431469 +a5ece341020b4d169de462585acf8396 +4921401521064ccbbdb1e507416a62e3 +344bb30c8c02401fa0bd21e5be84eca9 +c570abc36b9a4fb1bf5b1aaf4c9c812f +84ef153d7c8e4841946a0e626274a24e +971bf873926a4cd7a2b466edce3d8589 +b1ca81f2aa2148f0a65aaf09503907d7 +2b83ee4069a346f29fda9069a3a5253e +7915ffa36b574bc6b4092f57bf07825e +c87376d985c044d8b3ab4e03310bd6f3 +b94dae0fb1ec4583804e1afb71a6f80a +357ce4fa68ba42f192492af88d8d99e2 +7b2a96dc42fd43b4bdd56bfecc29d56f +e8aad827ecb244e28427864c57b18587 +9c3da9c402ee47e7ad1e762d5610fa7d +0c6c04758fbd45aea0332d212d6fd7bb +7563647ebf814c7b8be00140f9816e1f +4b99fb410740400fa7bf127f5ec5a237 +bcdd96f72c9e4034a6fe2a5121e93a87 +c3d8781a43d344bb9d1d110eb9d2ad47 +32643ff9d5994b35a8c6bb28f4bb1199 +c5d80712ee2c4741a5f059530e523a7c +0ffc086cf006416e82c9e80616821414 +db935aad8a314805b973b5f8591261ef +1436c0030b1a41e69041dfe5bca52e01 +b2e14554b84e423ca1b53446160177d4 +22081620065e49828b7cf120d96331bf +47500b2c58704b929216a90c8c087567 +a6cac3d2379b4b96940c522eba569aca +1939d6d2524147ee9858ce0f96ed096e +1be961388f3f4a858f9413232656c957 +860911c447744c0396b618db994c535e +9ec96134d8e34be89cf946226dbf4209 +c1e20fa3e181424588ec632a4b62d923 +b262bfacec7b42c7aff6bf1f9e7cdc3a +9505179c04314ddc8728371b89e9a4c0 +89ebea4991e34ec292657bca82f73f60 +d3e9bcba98f5440985832dd912a7f542 +469e2019cf6447b7928a8cde7b792525 +f88fb764ab5d405f9c0959da094f1a25 +568f22034e364caca4e450a6d534dbd6 +1d3b28adaa824db39845d609d13a6b2c +d0b886095ff442b491c790da8cd8892c +e45403cce7dd4b0e81eaeb840bdc24b2 +a265ca9ff122441590eb653b2e248ea8 +84cc81f79c3840b28bddecc68cd5201d +625b0a764d0f40d48f3140acdd644823 +e80103292d164dd7b483ce4049640467 +66bbacf0c7c34f2cbb936654d9c79c05 +b2c76e5103144bf68d7382c51fea2e8e +c283c87ee2164dd7a7e1bfb1c29898d4 +48ddd91aa4f44321867d9d991b77699e +442f355461854f599e5a1a979cbdc59e +bf84554ecf6842c7ad96a5c2ae8687d5 +3661b71f9494405da64f0dbdcc1a4ae9 +c2786e2c18494cfc82ff4236074631e4 +46da560eb4ab4c5aa83a50b6c88875e1 +8112a2098558473e8aaba1f7ede21800 +84d5cdc68a674e12958f41500e988502 +52899074aea74a32b3ce6a5bb354af1f +82ec2060f2b0431699f57f1b1782ab18 +e1083bbb88ac4e55b31613f98bc39aee +121b97a4aea44a5cbb47e99670c58466 +16f136f3d4b44154816d7ffcc2b8c8e2 +7821a97af3b84737850b7aa52027a6b4 +de179cfe187542e79bc352f6ef72f2be +6635959084d74f8285220ce47d0b61da +ed1bee5d153b43a7aa9eec30dd3df7e7 +c8a9d0d162154189806e77a29460ecfc +c3d42b5b89d141b3b33c29bc34b44717 +df22b00f6ef942278aa2be7899ec07e6 +c7ec86e7feb746489b30b4a01c2510af +13b2c9c8ad33459eb494358a6c3d6bb0 +0960594160594a09862cbb405a8d7c85 +0db01abe3f89440393d3454e16b61f7f +800d7b317d4746fa9c4ea0babb338862 +3d5f9e59d99b4e22a43886ee0bb06c92 +c700f944b3eb4604867c4a52b5ebfbea +c77abe86b516417c96bdac3913f880fe +b6efaa71d12d4c7bb16b90a78de27daa +c4acddbd83784f3497e99d309ac5904b +6176a661fc1540539c981188987efe42 +02f2bd71a28a421c87288b35524df8d0 +47d1da77937a464a99c2b53c3b24b70e +67125d725ff94a9bb5b368b7904f8d79 +1103afdc2aaa4730a335857ed007f476 +7414e62b8ec54cc0994c288a8103a006 +4d26c963e0484e708835ca04cfa626fc +462e946d3d424d589171f5dc6eb2f11e +85a377347c804fb6a0b1a009f187ff0d +026cf4d0752e4a16b9445fa6793c1141 +1c74372d1aeb4bf2abb90358352d4282 +63be3269095d4448a3d4e08be1d4ab62 +edec8e53ce6b4200868178a24f376282 +3e38e8351c6e48e786cdd8bd181a09db +99e4d1337c904b549b4ec97f6ee56aac +93a848a5b65f44a7b1c1ba2e19cc3677 +8c95c5e879f24f8294d9c8c25804ab95 +67db1d2650a84fd0b062765c3a572e2a +2ee564564e374a6f826bbdd24922ad5b +2aa3256dfecf440a8bb26fdd17fa73c3 +929b54a0fbbe400f9ad0075205a014d7 +6ca29c04aea54b0ca970e3968a83b1a9 +a4618bdaf9314a9bb4690b009503811a +d4810efa0b394467a0efa989687e5351 +40ed7e89b92a4bfba04b9b82720d6523 +904bca0fecca474fac5e5cd45fa2592f +7eb601a5502549f9876a2eec0638b68a +7f501e1200434bd585f1dce0681edaea +2d199878d3d24d57b7624979d3ae1837 +f31118d47dce4a86a53a6daf525cb9a2 +65e61bb61a904da8b7688c55ac427825 +fe59d90ae79b42718095dbe513c1adeb +ba652714bc514e3888f94a606985f79e +01e3c476a3cd4d1db9dc8ded131a6d13 +0b9867d98c154737b422fa5afacfc178 +78a932a7fc414a7e886e4951435867d6 +de32ba1d09be48858e22ee9395fcd814 +26ca8d4db5f24a2d8bc4f567085bd5ab +7d82e16159e141678b917bd1e01396ef +5fe65070674845a588140aeb5f304d19 +85f28f613361473b8924fd98690d4fbd +80cfa4436ce34f0aa96bce0c956c5d16 +301fdddb9cd9420faa1174e68e0b56ab +47d5b51da3504cb7a2c6cf6ac0fd0312 +309ccba7b2cb40a6bfffb89f498fc54c +c02369b8285041fd9463a3b5e88e335c +cbc92e62b5c04401b49c356889325cd6 +41f0bbfbb0e34b9e853239a6d2d16716 +f5bef92473d94fc5b2b01c16a02154aa +87af12bff8c04a6dbd284ad119cbaf07 +06584ce1e46e43f5b8439e15a42bc5ed +20be3142dfac419f9c9be9c8aa8ea88c +3d43b4602cee469ab6dbba54a00eb4fd +bf4b47324d154da5a9fca6808222d08b +b74b57dda3eb43cd9b29d96fa23d81ac +e573304fce364cf299027494fc1afede +ac30b773e4ee444a9ed4a52fc3abdce3 +e48809045dfc41a7b1df7dd3ac370189 +e1211c160a9a414a9c4788a1bd4b0c2c +7d400cd6b3e84b299bc325942a2cb6ac +8f79bae18b2d467a9b3d1cbaab5bfe57 +d0aa9991edf5438cb11a90ef43a518a1 +89af79333eff4b38b4d2a967d1147978 +f3dfd9bcc4454b8082dac726d8b0fce1 +f84c35be43aa423585da752baae0d6ec +f5a3697dbb024d33bca2ba914479c147 +c80e2b05a1fb4d19937f2b7deb6ff2ff +b7210859cd4045c893a305e8fe91e079 +46ce33100c39420aa22aa2ef263dba3a +fbfe002d0ec34a819046c78493ae0178 +26198bd869d243489aa7b6ab03a83eae +c523d1ef93f34b5ab4db0e7ec1bd3247 +e886b88c572441d59d99994addcd283a +a9d5d0a3655e4e0a85e1ae9ef4f88ce0 +eea8846fdeec47e0a218d7778513a74b +cbaf560cba474efbad9c3dbd26b127ca +46376f79fe094112b639f06c6661e0cb +c24266661092477d8c1b5242abfa7c4a +ae5e8008775c45f5abfce067f91ee6b3 +dc97063e68c345e8b5ccda88b13ef7be +29e8455df549435294dc241a35fba3b2 +a038cd89cbcb443c832604a419fb67c4 +7642cc93fcb24c398af98476f5f0ae83 +fc341860f7b94257883cfef2a667a697 +e50b24d24f6a4b9d9c44e6f051194fc8 +ee00e4ecbb8e44f2b483dd6b092ff817 +cd0e60c7426441dcb6f59ca7f07473af +87aa46eb6d3242f699cb1b9fb3cfa4eb +0a46621504c24197b5653608f474f73b +2e5f007e3e1547598c75f0c399e9970a +1255af266cb644e4a1a2842535408b14 +14decedce1b742df81366e3a5d203411 +a36877923efe40cfb6d487616bb13f00 +d854b2c749a2481e912335511920532b +f9b76fa52a82427ea97a51b0775be4d5 +b3389be723684644b731483f31ccfc15 +c7f79fbc547b4b85826624566739d85a +d5516f52ba734bd381a7c182fe4f9082 +b653b88efc7c452586416f1e662d9271 +3968cb9c8c314815ad8b136c6561f860 +ce436a509bcb42d597b897b79cc6b02e +c25119c5ac6e4654be3b75d78e34a912 +55c916997beb492e9f5b55eb7d8495f7 +3e0ddefe82524314b0bc8eb0191950bc +56bc9b48ba544f1ba80d6e8252b08c96 +e480dd0ac63f4043b4c2cc43aa8657cb +b00408e6bf1c4eefb18c71102bf7d946 +23f75dd13d074f5ab08aa4f0db5fe648 +9566a7ad9cd144f9b8f294b7bf879e50 +85a79f745d484ec08d85b29992d7d576 +9233b529cb9d487e84849ecefc810c93 +61e3bbc68d414124863b1dab10525216 +742f06047a3d451e9c61951ef598c6ba +198940e8671e4c1a8b919bb5c839d555 +fcd4bea617444c818b026bb702b311af +154c2a94275e44efbd9604c95cc1c81d +cb8ef0195f4b4b2b916c0a848f47bd45 +38bf95fde0fc41ad8518fe33504536c3 +1eb75ee3ccab43459accb4a4138915b2 +827c084126194e1a9577c101ea4942f8 +bbee8a44206f4fae8f672f3f93297bd5 +e30b4da9ebdb41e997fd8bc455d43e0b +7edddfba4b51475f9438cfd8043ded86 +0202ec72baf548bb957406ed2d88961d +a354973dd4104388ad28d4c0da7c2f2b +4b4d870514cf4440a39d50533f656f8c +5785199fe2f849c295cd2b40a5cd6261 +898366645e6046838828d8637d6fa3c9 +50b7cf68173541c1a16b0dfaf39911af +6ad3ffb2b84a4e1d8e372b08c74ae88c +87562962d47e48b28cc1b874fa46a47f +518f42b92f594b3fb5f4820b286b2551 +c79ff4aa06434315b037e0f6275972ce +7fd4c11b1ce3435cb1985606de264e77 +688b42afa2744485a0cc38070b1bb008 +0cce98d6a1d644819ff48a2c42000dd2 +c1c9fa8a17b84e50b023794da5206a82 +2b3c041fd7df4c82bb7de58f3d6a1712 +12e8bfd01dac432c906c11f4047d221a +64a6fdc014054c60b7aa38935e58d23b +ad409625db7542a88cae62e20202d399 +0c5f661a51b6459992c94438f7dc4590 +23ab40ea94f34f0c80abf29defbe284d +9f9055b7bd2349b899f7dd87d5a1922d +eb7a7147e72b48348dc5211c4af45f63 +6f24a17465f741ddaa14d066f0c31eee +74d64b35a3dd4c3ba7b6deb35685ed8b +a8813ea1e0ce47ab97a416637a7520d7 +6f238f3e810c4a90acffc93b08f55d6a +82f4e31f472b4405b956b29abeeb7074 +37ad3ee717f64bab91565745a12319f4 +04b270a8666348b8a78c85bccb84e59b +b463d72bf3a84d45ab15243656023d84 +8e482e714930455691995d417c688791 +3d17b06570034048945a5118c7149a40 +e37ea992fa744f79998be179a1c12e10 +f8853612da5c4c558226ced5f5c184f2 +81c328132a674a4a940749f9a80d3b5a +fd93e10678864e2ca7fa4c9c272745a0 +04b1c0999a4842118c82914ab37f07d4 +d701121f4c564cb0b4de821d5806987e +e56196c72f9e4747aa33969f65046ff0 +585ce2411a214b1ba424b9d6f34fd266 +471d2007cc78405b9c6c1b95cf442cff +35fccced96e84be5b5203442c7e0f994 +a42fa0e9decb4756bc03095433919393 +b8d6c9706f0746628cdf184d268c0e56 +338dfaa6765d47b7ac5febf36032ed61 +2cc2b656d2124c2db990ab15425753bd +71a4502e9a20423ba847bf6b073a07a1 +7a2d7d19a5944fe9b16e33cab4ba886b +21e23f5fe0714a98a1b76b4f6ae4eb9c +f1424b5007664700b4f8b7d7f22abad8 +22b7bbd105734636b9fa92b52aa09d2e +9b2d0dcb628e4457a709d52817eda679 +4b9a943e117243b880fa4a7d1987dedb +9c02ef66b6ad41889b324bba06805c93 +74352759a8a44ba8bd6d77ce5d3ab47a +4b0f217a8b9043b781f23a271ceb2276 +72d084f7de4c4e599940410963702493 +e7f4c701048f4dcbb2b24a57c357ffa9 +46a1a1e9171f4b67a89ef1f6ece787a0 +b5846651c3404232bcd3ed2f679fae71 +c271718aff2b4777a38c76c5a040f91b +4f4764231a5e46e9a201219aebe592e7 +82c13f3487f84657bff6ae9a028eec49 +31bc449fa74f467b901fb8fbe0140113 +2d0bee1113e942bf97ecb0a3e5cad43a +d75ce527e1f74cc7b177bea434260b37 +5b254c22d7ac4d448138b6290e1c2d27 +36b7e57fc16e441282ff2ab358ea75b4 +7650a398a5f742309cfcb66b7235122d +18318634820b4fc2950d125788519f4d +32947af2b52a45c18dad043c87762430 +f43199f19c3142c68cc672db55d9a40d +3ad0705bb524404e939b8c04816d05b2 +f8ba7580d1954e1199b0b844f852401a +f3c4623a34ba414c973d8d07be98cec6 +24aefa4b0940441bb2a88ebb0bbeac2f +374fa73d8225480e95e20660915c12b0 +9e7578af65bb4307a12fd0ade5ad2e18 +33b8a04b72484302a1a1739677658675 +5922ad8ba9fb4309b2dbf0f74ace98eb +cbb8140178e54758a8cfeb9a90a7e0ec +c4c9b498476542f9ae03fc24d2be2c98 +8a54852e97eb4b7fb9d8484d16fa9b50 +7cc9e64d7ffd4e369595062abb3ab177 +4c5e1845990045e0a5ad238bafbe353c +60b5fae8d55e48f5bc3a554652d5d9ad +dec786f55cd94d528316bbe12b63743e +b9141491f0cc4d0294b767d228b0f7df +74bb2c7441cc4d078dcd5d82ca47da09 +9ed9a21768724eedbc18219e74cc5046 +cfad12facf684c138139145e6e9a731a +e7caba92073d4adba3477c21aa25e91f +93b709d60faf47edb4ff4bd238705c7e +7c65cae0690a497ca9e21d914c4e0ae7 +a697df469ce54400a8c662131c1b1276 +e886ef51f2e844ca8df77d041151068b +3b5c8cafe4724879bd06fadc28ec556f +3752f45780dc4b9c87ac541a334e1351 +f8010cb1eba1423593cdf9eea2fed00a +bf56a2b64dab4e7dbfa418c7ad0d6c60 +f4458cc88f024acda4d5db288df37231 +ab57d70b908a48759bf9dba95cbccb0e +2151620998ae4282999a6c01b97a2e79 +a0a41bee2ff848ce811ecca47736466d +9d3c0e1574734bfe92740bcfa8c3881f +2e47ec5ca78e48cfa56fcc2e7c8a117c +208a40369cc74270af9de03d12a72851 +883ed84a09e64a0e9840fc5a307f04df +c4740b53b1c447ea929bd13b2ee49017 +b2d30398ba3741da9f9aef2319ee2b8b +12ee0a4474394a2bad6fa802d46b69a8 +9241361a5ce14498ada7eb128b1f38ea +5ac72b904b7b41deae78c72f1b0e0bf2 +3331e1a05cad48ecb95d11e8d7930a20 +a01d9f81e26749aabd7bdca3726236f5 +ed91875db8ba418485cf52af6619669c +cdd861d7849440abb95fa8e37376d099 +7ae0b797a22d4c8c8defacbf11a55370 +b3cc5d4948414fc38d1e1859df426f88 +e188d4a006364d3a8b0566e4cfe2ee16 +c92881ee1087451ea5eef053ed77e77c +35f9117fdced42058c55e04b2dc70a1b +4ada604e78854b118594b621087835a7 +a6773090ec184aacb8239eb0050cd34b +7df779223b7744c89345ae2e4a2f3226 +7ab7e609af67482e8c61c5f2410a20a3 +75b58a3f353f46f993d7493b279520c5 +e526ae2b9b1b49e2822fcd2e631011d5 +fdb658a6fb57411ebf9a7b9f658770c2 +538e1ff6ba0f44fc9ff498b62d89f970 +621f6c1de14045b0a017e5bcf51b1e02 +a236754be2354420adebe13885ae90c2 +50661c59e9314e018cba618c5fbe7a90 +fce6f41ff39f4942b071d133bee3a1a5 +3729b2dd716f4c89b87a192290295808 +431394ee886141349e187fb8dcc2307a +8b099a2dfafc4436890eeaa7e928fd9b +fda8f9c3326745ac840f7115e50a8ce8 +8a49213fca41426d9d8310fb2e0a9f70 +dc0bb314a28d40bda1af9de1b012db8f +5b1a44cff3d34249b8feea2052ddd972 +26ab6b8bc0974e718bccc2f9cd61a3de +f073c339095340e7ac0865eb69b01aff +4090da9c2a304824982d8f17b5097166 +3b6cc4c654a14593b8ce907361352d62 +100c8d7f4f0041e3af111718f9f68595 +72ea9b9996e147ef8400a213e9346c5d +72e578e1a62749dd8861b45f3cf2265e +cd382cced38748238da190f7c9a90bd0 +0a135fff072846f2b27a8152dbd63eb9 +32de6a92ad104e20aaa841c8e3eef93f +1a5db996f6fd487b9390fa23ea3121fb +3ab0183cfddf40af88b2d0547a997e04 +100f381b845644a699ccb4cb39572888 +e40bdc9f634e418eac01c64674812bca +e19ccf3c45a94abe9bfcb2bdc4950ca2 +e526e7e23e7d43b5bff5b579ad939e5d +e619738ee34d48a18ed61201184a877e +a28b405a6e58472e9e9448aba55e0433 +8a6e4f02523d41bea9d126085f3eaf92 +df59ac5e13844fd28c84c0c279015cda +4966e7579fa44ac78a9781a15321ff94 +bf1e66a733554a3cbd2d330260bae830 +0e222159668549fe893fbe9491596f21 +2c5969f0fa024e9d9629bf91df6c8baf +2f42722313cc4c48861f43d1a4950834 +7d925df32b954d17a4482aee5a5ba6df +a43e81a6edad473b82ed33f9c2dfd284 +e377d5de7c054d8b91905114ba92861b +87605b8662e349cba2ec63f92db4b45b +22360b4290d14d6598e5b917244a4c74 +e5b70b26a4fc4c19a610497f6a925661 +e1876c13f0b241799a541932f3e7512a +9358e58612664ca09b4be5be1bc30252 +4c22475aa32e4fae987d9343c3ce1cbb +07ab113a3849450e81221c44d3a36af0 +290c94f1bb394656b3970972d94c52fb +a3141b91d24b47b4a5e48e51814ef162 +d1d8a64dbaf647589993ed2886c0c806 +b0c0c9c65d06443c87391134a62e2287 +d1fc138d06d04ca6b2de4f6ee09fb925 +a605905280c54e90ae8876b50f93f2d1 +641d827001434ad6b187b23bb348aa10 +476f8b64886f4edbae88e74f68d065c9 +f3daf79ea4e843c8a159e8ead7af6e74 +c33a102b4efc47ca98b31e56506fc564 +cadccdc1d08648a7be5b0233ba42ddfd +b823d45ecb19488d94008eb85e562753 +e12493a7481548129179d926b9a15b35 +599521760e8646cc93585eb501f9ec5e +5044961b5ccb4affb6f9b8d1cdaa834e +3bdb32166bfa4bf1b8294fc680ebef10 +3b99c3f912b545558f5e65736cb32bb4 +1615c1b99bb3419cae1913aaa5760aea +25a14525f06f47a2b073e73f2cfda3a7 +81b3eaf9958b444781323c733255db0e +49f4e93d6d0f4253a257c0391abe7d0f +2cb1ab1a393448e1ace72808c5b1d505 +32edacf73ab9492a92afc69333f84e3e +43bd716c4667417fb315a73225a78469 +43ff70e09b12481280988647fc9170b2 +844b6231123c43cd858019422f5a4611 +37d61dcafe4545c0bbfbd7224ed004cb +147b546598a440729ab545a9cd798c5c +8d4ebe764f6b4672bbb392e4f3c69664 +136368db06a044b68ea8a5baba5d6efe +4b9a5c4d5e20434793388325ec18ba57 +3ae3b153415d4987b171a08aec95ddc9 +778331cd602140e7867eb2667d8680b2 +b5b2e42309144dafaf2efe9b71a491c8 +e95aaed8cf7241f78861cc96139701c4 +7f18296ae3fa48efb3b22f5d4b1351aa +484e6b44690a49b9aa63f5c04189d6d4 +d8546803ede3453a8ba9f9e14237fece +e67f5d257163448cbb8a5ec78b38aff4 +ee933ad7d1cf4649b523994dc7fa9f4d +0efbc54a5a584494bf60f77698197f75 +d695caf6372e43fbb1cfe13273d32c07 +08129621ded8409c951bd1ae9a260127 +4f7231725bcd4605ad280fb513673a14 +cdb42183b46d48f3a3424272c798428b +4a2dbfb86b2545d69e1a10aeb7417fb9 +8b0d64278d504c508d02d33e22ea7f12 +5abcb852d549471080430a68854f2aae +5f59503760e646759acd1002ec585b44 +9ac757f47e8f42e8a7cc82a9cfe8753b +30e57f4e0a844e189163fb8952c42ef6 +10bc1bcc7cfd46e0ba4d109ec19b8c68 +1df829ce622643ce874b31cad96fe484 +91506a2864184c2fac3b2035733804ed +8c5b991b4c0a4bfcb13e0eea894343b1 +1d11eee328c146e48eeb3e76630b6724 +a0fe31afa2274bd78a13bbbf06f30aaa +023e632efc7449338e1d5c56e220cab1 +34a65735a898465ca5c8e930391cf0a5 +36b33e471e0045e09c201f417f397625 +59efc2e75b26405b86969819b6cd91c1 +19a1d4c33c094fa2ae7aea81c47db225 +35ed817e4e624a008574e33adb635c1c +40949184dcbc4d5cba5f115b1c0dcf6f +7e58a1f39e444a3c9263ac6f2f47991c +9f705c85b42943f49603eeb739310257 +6deef5759c5449f9ae2bd86d56ebff6d +23f898ce96f340ad92c33e023c140bfd +b40ed90b4be345ebb834b0fd98bb577b +001cfadfb9204424bccc45501ce6b90e +4d8dd06b107841f685a1f345dc385170 +e6d2cc4b176a42d89c35f25a5db4784a +aa265dd3c99e4336a3e958cad567f856 +36db4c44a1d743088275c8b8f0d33f36 +98746c2704284e57a3676cd5d767a7d3 +aa86a72ae86d49f0ab18cdb88903adae +7be295bd5d59481caa190727e2c5e485 +cce68f42b316473cb92e5f18a80c38dd +263e01c4624f42e09233a6a27fdfbf80 +120227461efb43f48777e8fc13b512cb +1893b247c3e844cd835cbc1934595171 +a1d1d527ad564662bdd105c4c62d7ae1 +759ec098a2c74d80b92f02eb1e61339a +2fbb3739ebea4a68b7898460dd6445cf +547d76739b3a423b89f51e810fa69a4c +478c11432a50470e9d6cb18cdea559bf +4bbadfbb42b841919c1b66ab3714d065 +845c215786744c17a20c38a738fea07f +f467b90c58bc489f97326bf6639cd427 +39db18dcfaf24ad183dcbf449698706e +27cff3716bf84fedadd282b23c64a092 +f7b5904680cd448e964650b019930155 +095afd8045d94a39bf3ed0ec20e0eb1c +00d159af87d944918a6f21a975602cb6 +b6f33df7c2e44687aae8bf452291989f +e51a29d61d6b4ed09537de40eb695617 +14802e7717ff4149bedb0569b93fd5ed +c54ead3f464248f9bc6d04ee8bcc7f6d +fc28c62a47f24280874fd00cddb4cea7 +6eab492592f848159ebc6340aad3057b +54a58ee03b2747529a3079226763c1e4 +94ee9b5b53894cd593462f18b2d71572 +85ac9595228b4224b687f927a6c8981a +626caadfc8e34042805f9eb230fd7246 +08eb01e7379444f9960bd5512f3f3324 +f4ab0103956b4e9787ebaece0fe574b5 +135eafff782a4580a70c0f5f09ded06c +63ea7be8390a40938613da78ec736038 +9a72bed7fd424f809ff904df12de3172 +9a33812786564517a7d644354131167c +639a0f42e3a6400999ec884356bcc0c7 +d32d6ee4339547a9bcd07032c16c28e4 +9d655856f1194e6f984deb27a3fe2ecb +c74b9392d7de4241a1a45004a6d0a713 +ef4ca7699fe94c84a6954405502eb5a1 +23405a46bd55450faf20617f15433da4 +3e7747b1db4b44a4952d6d94488ee16e +d0e31dfed6f4438090294599ed5134d4 +cce3a987bda2410993fbc7a24db70eb5 +c5928a3fcd7b4cfb98f539e4e98b2d23 +967d19d0704b47c0a12d2a85d44e30cf +f51877efa703411092451b97bdbc04b1 +e1386f645db7462a81d6bbee89607642 +2b63f788ce7944ae8f29aee20d98d7d2 +14e616e26823472c809a03042a94b990 +d8a64bf6320b489ca6aabc02001722cb +3ac81514068d4b5e979580d460fa6bf1 +1575de83fa9f460aac62b72b715dddae +c0ede770317e47c1b6766752c45496d1 +b95e29b0b4dc4fdfba81d740b6d5baf2 +a71c7c8529f246b3a3a5fbc76c33fed2 +8ad2c5cb23f247e4a5aee99612a4f2a2 +89a987bbaad04beda9955f70a8c12d90 +b89b03eb963740cc83407ac626a3855f +c8f2759149604f818c2fe1169945cee6 +49f02a5d29a245bd9d400bdcbc803d5b +15562ed7b1d24a7a842d971f6555216e +2965de09e84845a286d8a2986d3d3c8f +eab176a4a5a644eea446114f3bc19403 +81f7b0b5581f4e2b89b1c95259a054bc +7674012736d94c84891ebd0407fb4b11 +6c692bbf57364804a68d4a6477e788fa +969238f50b5d40178951835d31f8e82d +7fe13d5ae76e420995836688803340ca +903ed803932340b19104cf5232c5dcc4 +1aa6a053634648d58f5309b583834fd1 +60750153857c4559a59c761da40c69e9 +eb3d6519fc6644d0bb660cbc218c61c5 +3bec7dd69338472d8b4563c15de094e6 +e808a44eb85b4be38ed2d8074e9c4ff3 +57d5b09cf38b4dab99c97e25bac7760c +4e8cefda91a14aa5b6d56f4a20f0307b +6734e6f2fc6e4f80a887e6cfc9c92cc4 +a4f61071ea6a472684b6dcf281800c35 +31a843bd24d740158a57a59200ba0ac8 +7b2edc8d8a4d404bbe6ec15ced8e71fb +e02760fabde04796bcc017769908b514 +ae97977ccbd9452fa31075f6c0279dae +5fd164d6426a409ab3f4130c49e2d418 +d45e1c5f9a9c4aaa8fa5b92b5f23afef +41c5a2b3b0d5474297ff57be20312abd +d688c1d6c0ad4dd7b3d219ce2c23a942 +f15fdf877b904446bbf002344bc20b51 +d5ba60c1d118494fa665f8b26d4f5715 +6b837773d0c0406f9532d858a24febd6 +db066d9c0c4e4bf98e6fdd8f94ad4a6e +055bee798bdf47d09a2b5401484cf8f9 +ef545e6268cd463fb5c23b277242cf69 +5c8284c0eb2243ccb735604eaaad1ce9 +986c95d1d84e44929f6cebfc170fe71b +e6899c0b45524f64945f874e2a449961 +17f1c71fbd7740e4903a5aa1f0e86f4f +a362168e6de6429785c4eab863b6f516 +ac9399e754b64252b9293f15eea6f57f +76b6c4fabeb34b2bbf03e66d38c536f3 +6f10882020a34a6e8d9e5c3001bcb9da +9212ef9e7655478d8b31b46198b49b56 +68ee82fd97bf45eeadbeeaa556fa669b +f41e4adc95134845a92d0f38084bbe3c +b2496a1228354ec3bfd86f83337bef26 +f6e9c6898f3e4b29b7b2b5f45a896998 +b65f31df07a74e41b6ad969623c09d21 +4da95996e46c4ced8d59f6f4bd0b7295 +55fcca49917a441282a22cd97299afa5 +acac40848e1d4a719d189c4b906d1165 +4088481ad5fa4f01bd1b797a852d996d +08be0df170b44c44842590bdb3ad6f9c +5e05292a6c814430a2756e4921cd091d +38e725fbd2a24183a8f4563b68865e5f +c12748d4b0264e3d92f664a3db801e1c +ea1190c677314564948cbd5ed04b79bb +e86de1f3f4e14bdeb2535cc476dfb1d7 +0539e6b913864b389261ccc8c3076c81 +2b44fd5bc47a496295db9559dd0a4675 +a77bfd7bbadf4bbb857258fd5ce155f2 +964bb923973c4bfcb019fa320382c9c7 +50e8923c1d5e4784bd4e9ffd8e187613 +81a6758d93024a2d9fd31f804a4b395c +3fd793a9686b42a48f2e774ca49c7ef9 +0456bd2b6e314d94b400fae60dedb10a +85c3d3b9cfd64c108dc548e525052c4e +cafa12d984664b4e96f6fa442faed938 +e427c1aa489b4649895854dc955d479a +61a3b712a03d40f38a6702b97155cf4d +dca69f083d6849e5beef3526a2f9953a +6fc4fb026f0b4cea9b504da6215f27a7 +55325e3b09ac48b2ae3803bccf804741 +ee7b238ec83444bbb49b238de5ce137a +46d7abc3dcc248a2ad9fb3c151cc12b0 +e434980262d0440b939bc32a8b9affea +b9ef0747d1b84dbc9414f3c141ae7d7a +95a880d594e74fd4927a93df0452238a +cb68743a972c4096b053cff7508fbc5c +7dd07cb23bb8437185d524bbbb3e9bbe +824db5aeb93a4e99afb002b39b0ee4ae +da8205a591394b4e873c377cf05fe0f9 +e9b2953e3f70476bb3a5d85f0e0dfc9b +dffd4f97603c4792ab0f2c34273af1e5 +cd49ebf5f32b4c98b9b4b556c02d36ab +17f40d0ee47f442d9b9091d7a609e812 +8bc14b7bbb1644ce9c3318998448b586 +46a294a3d35146f79b0fa1a1761a7d2e +f7a1da7dcc954cecb132d9963f2edefe +afebd0f2418a4daca865cca0e485726f +ee972eed622d405a91586906536fc19b +a249e3c5902347a39c9397b3c499257a +4a1267b0e6504829bedc74c7ba0a7e98 +fc203fd849ea46f0b84d4843ba1aafcd +7fc9094e39504a5db0584cc31a626e2f +a2db41c7b60a4823bff66e2c32143734 +4534e0b8ff93409bb98443b2dca652a9 +6d53f59e378b45abadec9d0ea8fa547e +2c83137d2ab247fd8137c901ae129ab9 +bdacd07d23e0433c9714e3c3c45f3181 +c4d356968b8046249da720d73206e699 +b72411a8065e4c5688fe27e98f1bf497 +d4af05114809411c9c2c6833c02374b9 +c5eaee0fea464cfa944b0863061ba8ca +9454ca47b3014acabdc5c930681715ad +ae7142127dd84ebbbe7762368ace452c +dd33fad87aec468daeb0398ea4a6389f +02bf18c597f9421fa43127c11cc5fb97 +5505a440ca4e48c28d1134199a2d54aa +0880941e1b444ea096d4c5e8c793c635 +2ef99d7d8ae64d5cbcbdbe0f4bd28f4d +adf9105ce9e941d1a9d4b6a4d41de4c3 +535e3ec4fef941e0bda0da3930d15e65 +c0fa4fa507074ed7b5f4f2b557827ded +41db138b35db45cf97624669f03b89fd +93168ca432e046459b9e2c98cd9324bc +ea691c9ec4b2417886da31ba1107c269 +f2656927d6994722bd5a84d364928eb2 +51486cf2f5034c0c85289a1e43fa790e +d2929d60de2940bba5f7d92170f01bc1 +b199c6b0361944afbea19c0a68cc3c99 +4129518d0a5d41e7bdab5b42ffd8faec +cf4542cf2e074e54972574b24768acf0 +57d8fcf144264a309feaabd5da831da0 +fc2b5dd09f9c4dce9a3190d47f0e82f8 +ec443099fd2a43aab3f783da6986a984 +107d43ee934b431687fa659a857b5072 +e51e63e374ee4c25ae3fb4a9c74bd335 +f9b7be8237b94ac0aa0f042c462cd864 +38f2339bfc974f1e81fe7b1d2b96330a +ee3cfcf00b2841e0929ff8c560afcbd6 +da48ec59c51b4f04a678dc1f7935f166 +225c0da247c84f889183f4912b87774d +a1e5f86f0cf84ae5a79d06bc8826cc6d +ea8aee54a84346fcb0d303b2540b4668 +7693ada7661c4035969961c6124d320b +bfccc771e7fe42559e5742701ae9a908 +565dad22fecb484296b678972858d394 +bc4b85625dd045608b498c41f8b5c1a7 +7a61e008766e48ceac59e4adbc231433 +9f25e7c83840435396225970ba47b75e +6586e916ae8c4d27a0006987d5b1b49d +bad46dc1bdfd4dd1a34fe2d9f4365a25 +a7fd32c748b24462aca2fe61c46d9289 +7b842974a3934b8f933ee7b7e6627d07 +efce8c21a9ac4a4fa33a336127007c48 +3f2c42cac5cc4df0af22760b65bd23e0 +2cf2af64dcf44fbe98a9990b86fe7a2f +29ec3177bf844092a6e631bc45215b06 +5c4f018f8d1344f2a214f6c3fbd25c4d +7d22e8fbe5a54519b2661fea300797fa +7c16c589b89f48349fde69e6a20ad669 +651e077933774f818763a14605adb381 +47fd70d2b3bb408b8eda632c53d86515 +2e7fd233678f493b89c01ef2caea0444 +d8c00a03f1f540d398d8a4dbb5dbb996 +eb791747cd334c2ba2261c826dd7fc30 +ec1a69b97035419ca7e97f745e628769 +5ecf9d1175ae405a9a073db305786411 +50cf7bc1f7444c38b8a89e4c516a4fd0 +3131ea6f0f43420a911545efd7f495b0 +e59b9d14b7dd4407a94b0ef2baefd19e +26c05b15487b4c9792cd4d8b87ee4875 +74941cfdafaf4125bd14459a640a75eb +76c21237d8e142729aba9f80194cd73d +2dffc34b6db14d1aaab1bcd7e92447f3 +867dfc95e96a49878837f80428918ca9 +d793de7c08d74414beeb8ea50f730705 +82bf19f3981647c48f59d780779aed13 +826b0539e9394cc3ada0c2cd7faae5f4 +f4abced537f6473693f306729b096d5e +9b2351daa0094e3d9cad7edf026368a1 +2d44fd75427e4d7a8c029137b0b0d6e7 +f7840cf7013245a4a7b03291d582488e +f9f7a920d24b42c19d87a2d569e27436 +b864380dfe96422e90f030203d110421 +86d4292baa6c489ab5fab374bf803106 +b7a6951c4864438b8f310d0fe01318d2 +03592149579946dfa921c23c05304737 +54ad1ea47ba24884b05e71efd219e94a +b6dfb19988674d71a2b3fbc1b502e6a7 +3dc802d209dc4d1da2672284c97b0adb +bca02fb2be994ae899727704f3daca4a +4799088a279d4836902daa6e26530699 +a74ea88c7fbc46df9f6e7b8231621422 +e0fa281b98c44f098569706566e8de02 +d5790e5b165343ea9a0b6803dcccf41e +ac48f997ef5448729f73b36700336e66 +66a48c6e50b94aa6b8cff752c0784b97 +19d70a642a934888a931d816601ec41b +822bd4b8b8f44390b8ea0edd4f453c84 +dc6d02d3e246438f98ca1f1467791136 +31b2f043d06449148d123d05900ab843 +59224cc0351b4ae39ce2c580f9a01463 +61e84e04346241419ee6e33636fca3ae +e574e90cfb6d4e6d95df3083b40a7911 +f100fab40964464a99103ffe53e6b8f5 +97aa2085a8c143c0aacdce273d66d03d +9e884e487bf94784aa1e058e5aeafe61 +485e47c82c0346a28cb449e2a793f5f8 +eb79a52b8ab74a76899ebbf70b43fc5d +48ce0e2fdde14ef2b1e7e219daea8c87 +e666d13b9bb445e0814151f5af4d4fe7 +9d7b896cfa6b4761b2a497215754eb38 +d20d4a01042845289cd2149550b153d7 +158d45e79a9b449fbff24ddb7b36446d +9f960d99358a4b249cc8a6adf86e2ef2 +9077c15457a44edaad811a5a9f1aeb2f +97d7a6fa313d42209b60f8d1368a9e8f +cd14b616da35470eae6894259697314c +927592905950476eb2239bb45b5eb2be +6e6be76a169343f3ad439c084d16231f +bf5e6c6adf3346fe9b8425be4e200c26 +dd20303e82654cbd91413da0548ec608 +b2b821b31c054ebabfcc0f6df2bed260 +e0e9a28ad22743ea85ba2e92e562da1e +7271826d3a584a22849c949a7755f79d +4b0ae97b316d43868523452d219acb0b +5e1afc2f555c4eebb41705468c67223c +1376748734f34adc99fb06bfdefe50ae +6a93cec139b0447199d9e93ef2a84a1b +9746de160d884d4c870d761793fa4343 +2919081a8ffe42dc8f21b552d7a24546 +fa74a39529f5462e978b4f5dbc0b8add +0785c3de269f4a99aa74ff360c93138f +f0d9eb24b76b4ef583d6e9a74056c613 +6781c0c33763406ba9b95d640deef936 +7549ebc69f78460192cb321f401b3036 +320c029e234c4afdbd6008838bd64db3 +4eabbf7ab80e4db8910ece11c9fd853f +4ad79dd647d24b9da9cb9a1232f814ff +8f33b682ee2d4a53873a9b8698dfc109 +01ce620e70ff40708eb4a1b04f4a828e +d14289b68e8a4eb0bb227b85cf382dfc +2f7728abd2ea49dcabee0e838be24588 +e08b0f7828054291938d948f9a874d67 +eeb3a00dce8d468084d54d39b7aee627 +fd2315002f4144f7b8f08aca12857348 +9c76ae0676404b5bb2fb7e870907f4fd +db56253857f24dd983c8eb8a5eba3ab9 +5b757b80f41b4d2da72928c6f36f18b0 +c0beaf97cf1d4f8b819ee3a061fcf65e +ee2b20b59075408da2629882895672b3 +bc6dc947f27247cb8f69cb6e7f3dd266 +c7c9f3c0961e406986a0e7e3d5af3bba +f2feaf98047f4e53afeaa661bcee20e1 +715d8d85d7a74ca99c7c94356056d07f +0d097d04f0b04eb7adb0d6132dd910c4 +16933f17c995496db81657041d024da0 +76a5986de5ea44769349d5d2273f2c04 +5f0667411c0645209794376d11afb040 +0694514962ba4fdfa36c545151675d97 +a5def4decf18404cb999ca6b9e22fee2 +d94edeadf54e4824bcb04536aca4e140 +4038bc3ae5cf4fe0bc93d194883ec151 +363889a835534d758fed0f9c70c86ddb +98e3113adb614bc68c8a493837a03327 +f73a98c541a74f3ea90f27262fd3219f +eb3521f5a3f44752af14e75c006ed6f0 +649ed122d13b415ab673fb4d375c3063 +f4b822dbb3b342cc94938b465919d9b1 +d240a7bf160e48418c2f16e91cd62987 +5ceb84855a354989a30e342f43956e83 +7f788ba7ac0847b0a19ee2ff0d10da93 +e34e512dbc304ab9b7addcec376f6226 +7232b7e24b8547d7a57751d9e0876922 +5df89d991d3d469b9ee6d1f35ffaf554 +1625701880c54b7d9f50e77455cef39b +ed137be2b3f74b6bba9181902bd91bf8 +a7920b5cbefa47e0bc1c3eaef46ec1c9 +6c4561eb4b4a403983b30e68804be2bd +f1f579a60cad4559a10d71400c66d390 +f19bce8c90ee483ca52b41f29e6390b9 +9b7f4eeb5cfd454f836367163ade8ba3 +02ff6520d3d3480a834db1a5da124150 +89eb00cd21d3462b90302069159f30f9 +f1a0e1c30965471aabfe64764184dca8 +aa9b5d16b0be4f12a0cc3acb97b91587 +2970b9134a494f068c5f69868a43982c +4e284327d14047d880ae5ad74f73da35 +60dd2f84af874a6cbd335e36cf0abc5c +ce6ad5b75449480eac06fba064c0d939 +3d316350a1fe4401a2b55fcf2396470f +4b8d86761f9440cfb324d0b4d07336ff +ed30ac4045a14086bac01316768b3dc8 +a817493a83ad492081b818c0bf211797 +555da5d0183a4b13901999d5a58ae746 +2071bda681b642218b6829b82e4fd93b +73622641d52648df8bdef5da81f6f4bc +7a95d0269fa0478495b179a7bc866d49 +dd4b4cdb343742b68982e746805b112c +8971f0746b4e4f098c2329cb6b8962bb +4eadb7226f404c35aa3a506957f01bbf +a2f6af60112f4df18b7de0cf59477fdb +eb68e95943f648eea15c3956edfe6701 +500a64623ef1441db994bfc50e278ff6 +f8e29184e97541a18880d2a48637070d +eda9aaa229364399ab33ce64b71462de +998d8d17a4334167a4907f780491dff0 +2687ac6a5dc94c949fe22d143868e301 +6a0ae028c73b4baa84fdc8b1cb64224d +3ea1f0012c7c40ee98457c94dbe94a90 +56cf7ae89bc8454496c330e451ee56a1 +59e66731faa24a278a86a16650ee6b79 +b6be1f59174d4a10825270fd805f21ba +dc17980757b44206af6ad13e9154304a +b330d67632c545f5ae54eca434ac2367 +d02cfcd14b7440ee8dec5d45e29df6bf +b310935556f645508f49323791feed34 +f69829e8a1964f88b3ba9f15b8b85c9c +c68b01fc33a7464599d47915cacf9abe +16e61a9555f4486e90c0256b100b40be +27ada59b1f02426cae3d39ed0f845d4c +a55ab7c0c1ca4490ac674b9556129229 +862151dbee584974ba6d0c283a32358a +32f726f65d0c49fe928785cbdead8ea7 +bdce5e3b40df48ccb116ee46bb40eb32 +28327bf64cf04654aebfcbe538c15b90 +652d57b25adb412c800247f18f1a7e55 +f46755cce790463f81e4e7d7b1f756a9 +b18e833dbefd4cbbaca5796924ebae73 +e6a03065979847c9b6981938d1659575 +12b3ce23f32a4aa99cd5ba07330bf086 +b4e82eeecde647b0bfb8b07ed8a319ad +5951aa2f3b584186b43e503be52627fd +1935902c177542aaa8dcf5f0e40a4305 +7c6f89f1556c4b5aa159532c9f04038c +e61d16e2c1d94b3ab75dfcee75569502 +89170dbd2e6e4d9085eda23f535e25cf +a97db25d23d74adf9d67dfc888f2d1c9 +d7ef83a345a145c49824a360f26142b1 +e24b623320cb424eb89c00c281266378 +93f931b84d544aada33dbf6ab3a22bca +e8fdb7065c684239aaff56e5553cc461 +e5799780e4b74481a2d072483d7a3e2a +0c30a9f6b2f740b282b6a305accca96f +e9758d826ea2408fb11cff36b3e315e1 +809e1301466b4ea8adabae00924bdf29 +557bc13b763c4f51bccc831c7cc1119c +110c77747a81461ab3aa6618a8c8954f +abbf1556a020443c85fa5c492508b78d +6ef03a9e81e74b7ab8e98baf512e7e64 +d01852b9ab9249748b6ddd102bfdcda0 +2903d7855bfb4164ad6749c1c8c5fede +50bd4cc3a141400cb84ea66fd8dfb2a6 +f508910db7d64104b50cb4d30433da1e +dedf9003b63a4d38b9ad1934225c3709 +3dd6d435dcd24982b0a461e10237f06f +b1d620ff625b4a03aac49d17cbb1778b +8832fbf303f64c348b7751304b202f8d +dd577dd41b4c4598a106c771243ba01e +84520265b4114cfd9ab8b8e08533fdb9 +f5c0e9f929a24f4d9266394c10695632 +5d0a63c2e123406b8a88a854745d7768 +0155d77767024adbbe2c5c9b9bfd2c81 +b5706172bd35440b97fef2407416f45f +ee04ec59e2534305a36ffa7b993ccc44 +c8db5a6b6e0947c38888f476b7e4bd23 +ce61f81b34c747459f61b528d8967820 +e13413e3872a4d0a90758c5f4b9076b3 +e602314868864b5db292f1a2eca976bc +aeab3677db304519b52c5e1586fe6ab9 +09273dfa925643b4b44cb8a1d3a1b6f9 +44ef2ea4b50a49e395e5e3ebbdc99f98 +ad89f59278e5408a8dd8112dc07929e6 +d3418042e1214ec9ab693aca7ad70970 +d96d5cd080e148898199ca775519b593 +ac5392ff0b52414a855c0ce9b05cbd50 +14474f14e52a44ba997d385e458ae823 +e94536cb920947d598764738c5474a39 +b2ea1501b04f481a8311cf8ad03a8bc3 +a9d532b128ea4f37bdf268c6c8814710 +2296b05a1e494c79ad5ea8bdc37a5fb6 +cddac786890f4421b452bd495b9ba5e1 +ea59609f81a94bb5964ae046fcf2a67b +996c8d78905f433183ac368086580f82 +bb0a8ec8d00444d8a9956e0b1aa1913d +99d13fa0a3e94f408845dd86464d2d16 +32858afac3a1453d96d2feaed6f67b7e +985eb6e87c074efcaca374490a1c8447 +aad866316e0e4af7928dfe38b465c858 +574520c0b3ab4a2cbf17dc89a2991351 +9999197bbac04e3796ce1f4f04470490 +9326009f10634289816972c678d82617 +3d9dd0b02300445fb0d85d5c2c5f369d +1b14dc0571084740844dea2e0f6b3bb7 +929a503b845d42918d1fbc372dbf33d0 +0557110eb858411b84eea61ee6e6593e +5f4ac924f6c8478e9276af22d26ba688 +b791cb3ebcb347c6973d0ee82a8a4cc8 +ac2136e155d9410b93920a9624b7d147 +b10270c90fbb43a3a70a9e3f1c27c073 +15054c624ab34530a6e7422af81123ce +c601af58d0874673ab9d2032863fa30a +14f732cb083e47cf8cdd9a30f03ca8ea +bb96e13d69c640dc809ea6148bb803e2 +2e09fa7e7f994779b18135f93cdda111 +45c637b1c15c4d71a547d4550890c7a4 +a586d04e32c240c192285b4f2d46a7d9 +a8cc0ca704fe4d7884a73a8d9f8bc797 +aa0bc2a61bcf4fe88aabf32d2c0e3dbf +142f2b38673d4768912c9e7ca1dfc0f3 +a2f385420e0842efb354a25b72f05d15 +4eaed8be3334401380a21fe54704b167 +1cf6fdafd5a049098b774bc00680aa2d +38f4afb122be419fbc7c921f6ddd656c +5eed734fbd7f45f088688b7a50f8a70e +e2d65b9c095142bd932d3114623ab93c +ee668a20118343cbb7cf26f4ef7054fa +f152bf8008384c70848e751e78ab82ff +3f08823a3a8d408bb98af066b938c742 +0bd6b4a2d25c414baa59b05778fade4c +002b5dcd1a7844b19c7ffa63a9b23c68 +380e5d96119448238719df01dc593de7 +ec937670c162493c92a7d13d76ad550f +da9b588f7a7346519f391c3eb9532226 +de05fe8a0c314eeeb8f7478b92032f1d +ca875610880f440abcb0604c1552e2d5 +19c928e69d3748ea941e6c5537c7502b +e54a544796dc488b9c36b455815b983e +ccaefdb6c8b84b0ab018e6cbfcf33184 +f7bd10224540485f939974f7a3c57fe4 +fc8f1162901a4e38b506fe1ab229f296 +53c4eecf39c84d1898dba21ba0368f32 +7ea41e28383245aca626b100d7f6f53c +2ea5626c87554af783a6a4bc1470be1d +de59af6a151540f38ae352880c4c3be0 +da458ec5c1be4d8f96be9c52f49d4e53 +ac1e58afd7254f128a09592f940f44e5 +04dd9f6b6cf14003a7ccc8387ccee3ad +f29055aeb5c34b6fb6fab6a12a2eda2c +80c4b769405446b2b07e1ff6ba07289a +3d7912f4613a47d881df590357c58a94 +4dbf4febf1ef477abcf005c94746694c +ac3085611fae4753b7a46af8f7dcb51e +3f71baedb7424ac99bccda9bf4004fce +bfa820aea52b46ea8767661d78db4374 +66a3ec7fc15241bfac20c5c55baca66d +7c78945516654ceeaffdfaed8b60af61 +0a1e010a89324e33977f2961d6af6465 +4843cb827f1c4accabc80d0b9c6da82d +6cb49fc6c1e14f54a746fcb969741cf0 +264238d81649461a9159c1f112192fd3 +80deaae4d6744299987d68a4677684c1 +1d50f47636a444a68e5df401e50b920b +869d04103ba641e79c8530644859bd87 +829dc1d22b58409cab0165c57955b7cd +91c3a29f67a640a0a142ae9f68486ac4 +d468df5f301a4b098e6521d883a817da +5dc4b1ad81524116a7361b56e54c7580 +3bf865a8ab214ce1afc91dd1694e1193 +8980127fd98845bd87a5029116190657 +cba0908a220c4703b65fba6d094e11f3 +36b8cec90a834e03a2bed6bb27bfe800 +300ea0299b9c4b0881cad9b639100801 +dfe6f89d65be4a23b28abf07178efebf +f52615a329da4908a42f5fae1d0f37d1 +1cb3d3a148394287bb88df9cef0fc2ee +5e8221be8ce2493bb8cfd03a26942e69 +b8bbe4958da6453aa664f22183113233 +2ba3753033dd450197e9c8afa67010ef +2e90df082cfa4728b5aa8330cefd9812 +6da14fcf919940488e9b8c54ffff3f17 +16cd5c8bd38f4934a5b65d22c599b83c +0eb1d373ab604bcd97981fe8244da71f +78932b7ffef240379e83320660322fcd +78ed22024c844a44b4869a30e7acefbb +addfea2c1142463e814105108e521039 +680bd6dd918b4834ad309d892ca5533b +972f084ea5b944e38fa99a56d1372b1b +fcefa84aafdb431bba07d92efabec5e1 +ec81ab8f32f64e1899736616932c9d28 +26aa4fbd272849ce849b428e646d6082 +3184fcd76bf5421fb8354703f7691263 +e2c70e7411dd496a9c54be5711e09f77 +5ff4f40089104fd59a1204de9d6162e9 +cf3e112a4441414db938f3020ec8514f +697ee2742e234188a155fcbaf803f17f +0e541713f1144f039ec8e566e2cb9b56 +5251618b2a5744a99b3338fb2c099bae +460c8d31ee2349679efee969ffd80fa0 +8ed403bae1394c62abcacf2a524d6ab3 +b945655fba264c898f1ca5ee63c7496e +f8def3c5f656454c935fe3d626ed9fab +d7a12b126e434c42bba61faa159ec7a7 +edbb6a11d2cb4148a678315097da032a +cdd5eb23165b431dbf9fad48e757019c +d3b46595287d416b8da57183776ae4ce +ecf7e409454d450cbde731259a51bbd5 +3ef74b2ed60c4a6a808a595618908aa0 +5b1d40b2fa8348ec858431a1a311ad61 +ad1bc5b0800047f4b08db424eeb78437 +36dc07c8e85c4b859d78ccd4dd60c63d +682324ddfeca402db477da3bf90276cc +bb774df5bc1040859d93fa9d2f28d9a9 +e9cda9a048e64f9886a7d71d90f466b6 +85e1abf52baa462a8934b6760a772763 +00d1be4411f848efaeb72b936d4d1692 +13967f91e1524e58bb64bb47dc992b61 +dfbb335a32c74d9e979a868baeda2ef4 +7adcc8376d0c43ee87c40a3b70b9b1d5 +dd69fc9ace7949fbabfc63092a723ece +11c77194484147e9ac5442f4a7ecd59a +2aef33f2add148a7af1cadfeea487dd0 +72556fb70fcf4e988a1fca1cb3999263 +cfdc8b3756fa4bb4b7c26d8ac92fd1bc +a4ea5742827e426fb213410cfa001174 +de94359590d340dd9f60113fd657a356 +2f664bf777be402e94500b6a77c1e553 +35ddd05927d346a09ad6c76911530c6d +f673865741ff4a878204ed6bf28ea47d +13a47f4ce7014779a037cf7a17fd4f7c +4073f830912a4224aea1a487e9939dde +dc4b8bf86d8241c0af020071f9f73b2b +2902ba2bdee644dc8067a32b67fd0995 +be0042e033484f9192a6116ebd02b988 +7920adf74cb94d239e3294f562dcb082 +aeddd83827154346a2d8dfee4eb517d6 +1f879c34f81b467ab9afd5ecb9b1253d +2ff9d99775254cc5a393936f13a0c105 +8c6ea1ed6d7b42fdbf0fce21142fb846 +536619c65a554351908a02f2c82139bc +70ddf004ecb7474883d26cffdc443250 +f323fa36816549c8a8525171988828db +63edb731b8d144e283811e86c23cd6e7 +2c407fa958aa40aeb499a7b9550ae0ee +7351366cae2a4361aa3318f9d2fcb03a +792f1d88997640b2bc307cb67f0fc59a +43331c8ba29a42889776a6931e31f15e +ccb5165346a6426b964d40e7114ab5b5 +0c22c62d84304528a7afed0ac9e81f1d +ed295b0261434d6b90a71ea85b7ff9d0 +28653c6cc47940a8aca65745a700eda3 +2b98ba1d96fd40b1af2ec6bf4706d85b +d4c6c8e0f3f64e8bb5ccc970e53a9891 +938a6482de1e4b00859d26f3bcaf1d90 +bc6c5204b9374c17abd5e2ae97fe8744 +c7e11706a0ed48fa9543b7286aa83ba7 +0896dc31d5154c97aa3f24e8ec1277aa +62fb044587d34c9db08f875e24863b4d +2f1706233a3248cf9a74586fc2e7120c +893bab3514bc4a84a580fa9d5dde9e26 +f049ea345b0143d084f7b5cd67cb8f1e +6ed4d72f558b42dcaed6b278ccceba80 +4d293085dbea4d0686b304b88bffd6d3 +a2a02e46c64a4ef283fd97996fbe596d +7ef9d0673cc6423a9542470d435f09e3 +cdf2b718bb5f45fc98f1ab0dbc2b35c7 +8b3a66ebd56c49d5b24cd24c6337cda9 +5d31d395e0e24138900065b642ac8299 +bfbeb4132ca540a8b0bfb42c9a155c65 +822d4f8958764688a8e94a83fe37b86d +70dea595c5164a34959582a19c44e8f8 +492124e24f8945e6890e4d0d69956dd7 +f244997ce8904cea9d15baca7754b76e +e3986e780d9e48daaa375b872674cf75 +3daeaf6bf7a2454faaf1f97131bdb664 +6a8191f334784ee9880f029c82cf69b2 +a3e8c51f850a41ff978fa517bb5a9010 +38d6d1c01caa499cbbe2c4b2a037b073 +8b491093657e4281865beb3c3fd6fbbf +66ab8d583ca24a0fa20f6096f66396b9 +295d60432e3e4e269412002f4c316f9b +3a89b45a978347dc9567083d660cfcac +7781a8b39d36479d8891ed8776693fe6 +2f7881a0309245d9a0b2d2099dff776c +f10a7e5b1cf242bcac3633c324d023f5 +a210d4cdc7c944a4bc6c456e385a0bdb +629bfc973d644bcdb675064d940ab43d +d66341be20c54ac982dbc24c1a6a492a +b3f2df69f3114979ae80a13f7221b37a +ef59b9792e7d4fd99c26cf004e4e3194 +6c558fa5319945f2a40a240c83bafaa7 +43d50116a2af46c9b391a8549212681a +a075f9b382f24e4e85363a3af97fe0a9 +4d1d0606e7e44a84ac532d02f35d9919 +0549d65fc59a45618d6e3d542cbfa5b8 +93ccea4774854425a55611b72b750ca2 +f491721d52024dd084a942de34c79647 +e1409dcd76b54c0a8a5dcecb37998316 +d7a795fcb09940c0b1d56edf8e758454 +e09256bf6e4b4f0b97914dca034aecb1 +37ebdfda9ba24ba8bb1e8ef2f188d7a7 +85e7cd0d4d0f4c99adf9dd0ca9761dd1 +7f67a2c6a23a4197aa4f2037dbad1e38 +6b74c05999a248d996216f0d3e714bf0 +b6e77162f78747abbd85ca4a5c5ec487 +345e3b564cda42b5ad88ba7860de0219 +c22fd351c47c4f4790fd77a78fc51f6c +30cf9f7983db48c9a8450ff34c403414 +f5b9cbc9c76d495cb544572dfa511dcb +6168b4a2977640b7aaf289b4b9072b63 +313d87d0db804ff58ded52027608a0b3 +7f92127194344e3089dff95221082e84 +f6e18dbe053d490382e5c46fa9ccac31 +9c7a2dd5503943b2bdfd0b612848ba9f +c8208a0a46304cf8a3b78c21dcf2dba7 +3a124fc5c6c04a1690209f340ffae441 +dcdbbd4bba144aa3b3d57f5b66df8aa1 +595be90da0394ce39e2a78802cf1f2f7 +10511f3cb3f940b695c197dbde6efb0c +b60c397f0bd141fda1e5dfc8b6709096 +2a5bc8245cd048e78efec5f1838f08e3 +9ded2a6e40694a3aaa855801727e4e82 +4487ad10f7464a6c9bfb0aac6217a989 +2b814e91374444c5bcc2dd4bc002ec69 +075ad7624f3349d5ab3b598a0be7ec1e +da88fc6eebe04985b2d69347d03300da +aedd82f4db014b94bbce5b99907e382e +ca37a688c511429ea6cb543cfb8627c9 +c11a8596c3314677a8b9321e141de275 +31fe323db905406e96b3cad6d817512d +6dcfe567b48e4c9e8f6c78529f7930b2 +373b8890e4e54c20b1affa089ce91026 +6ae3b4f8864e4174baacb350231c054f +e9af14841c0a490bbf63767c844bbe96 +742051f5b90948adaaeb5e75c10b0c36 +7f9fa41bc5ae400fbd6e7c33410b776f +853c9b14acea46c8ab83cfc5358284ff +1b722d6e4d0c42e5b90cf324a7ce5caa +f5797825fcc242c5ab723f17346d0df1 +9d1f6924a3f14ee2920176083a558dfd +e2a3a6925fb64f4a828a4cc60debd991 +dc5a0c0c439942d58d038a10d7064c91 +909e1134b61c442ba60d7d2747fe2209 +ec5c00503b054a8685b67fe07a8302a7 +e75c407050594952a86e95ce8053bf53 +2fe69c6b366c4232975f2ab5bac6ad93 +a41505485d56456584028a04ebed46c6 +ade09852fa834238b68f77a223946c16 +ce11ff0bf3be446b939d4b01db9e1d43 +9e3e62378ee74002a1642029ddee7f6f +f57d78c50b544a6480b179cf0f97d295 +5c719ba3c87a4734af4814e91e658395 +c3634c8e985b412abcdfddb85c5fc8c8 +96493c107dc948969df4f184b6a2bcdd +09ffe26c6eb84500918ac02a7a00353c +66bab1f5802f44238d47d3671f1c3555 +9b5220a1ba104999832c11dfcf3fa01c +55c815ee24724611a0b58dd59cd482cb +7bdbfbab23f24e048b2ddd8e9d33438b +c29275e617e046d08fa813ac18d8f0a3 +c6278518c51e496a82687982f545ac3a +82e38b32baed40d080454474595e82f3 +44626765d6304529a5e0d7190db701e1 +65e8e2f18e2645198875e19f8ee4c86d +079f67e3d21b4559a5ef90f538d130ab +84e0b1cc83f84b7698532cd982f02b4f +99d6bc041c9d4f56ab414b771e14474c +0a8fd74072f8457db07182f7411bd4be +3ba75a7ee4914c5e8276e06d00ff6b1c +ece4577916614f138fb470e373193bec +45f9e55f493142a99b1673e4da1a4119 +2ccb6b62cb204f329eb35ac9c2621ea2 +681ff1d168f343b491c2fb755dea0668 +413da5acd4214fcc9c4752a048c1fe56 +04d95460c8014ffcb637ee64f0b41f6e +bbe54447c7074b9bb32645c68fee01b7 +02ca62d3440b416c967f33c883b61b65 +f818484ff04e47a7ace688faa5015a55 +bdf2563f714544cba5a63241c1b6ccb1 +804d7baa4f69496dbebc08e74753b977 +ac692295b820429d8ba562fa17c7b8c3 +d59525fcbb874b368292121edf53c633 +442ea3bd393443a2a275f535f9000e3a +2c843f62365b42feb94137f70582d7a7 +440cfd6ead814445baf4e3031efd7d45 +07b6a06735db46dea37bc28b83c2d884 +b8fbec68d48040038397540c32121b30 +dfa0638110b048d783ecc83b2fcd5662 +5a9ca3b40a02464fa385f3e95d4f45d3 +068525be5e4e44aaa10d34c01f72f545 +e5aa03a5ac98441ebcff7b0270142291 +2bd638a4490b4b3aa0de3e82a61df70b +a02bf18332f646069e7f1ebaedec9dcb +6ec22c4ce9394d0aa2d405708d2aafb6 +82045aab6ebf4d8caf05840bde63fe71 +041ee3f9d8ce453dbdc1a696431041c6 +0fc7c56aa9374b9c8ac548ccc02ff4cb +84c6db3662f948848619613c146a707f +0675f7176969428a9f0acb2b5cd49dc9 +84286947d3ea4ed195a72c25125f60fa +38fe7e066b484e74ac726f5147745fd3 +837fc9092c394f6f956b9d78a7d9c68c +4f494a27d56f4e2dae3a20d2722df302 +c270282668134f41812d5743bad2889b +db7339a98f464ff38e3c3e32c924ca65 +be9ea98f8fba4883aa5419efbb25aa64 +d8bffa8ee8664a8a955dbba29125b9bb +d0bde09e97f442a6ad89b29168945a80 +d680824cf0ac4bc5974ceedc4ba2c2e9 +13c1fb8edb994f69a84a94c3d31e63a7 +8de5d8f3c31f45b997feea9067b69f45 +0d6e9e60dc6345678d08f8fce1164b1f +dc346d0048334a6e81189452aa2eb5a8 +9f79ce945b6845098059f42fdf9f2566 +50f3de6126ef465a965df8d5b050ac7c +8519ef0c9c10444b91014eda4c9de30f +43220d243e5e453da062c2a21fb20d49 +a48b3b49a2c849e9ac2de85609cb6e0d +8a486cacf932449497d790dd7be22bad +cb08f60390414cf399aa2fd7231ca7c6 +6e86eb006f854c83bed8f5071c2da4ec +26a47537deeb43fd993118e9bdffef75 +85a5187cf0ee4d4587233a901ab65525 +1bedca252e4d46d7b92826271a578154 +d26b667147a34c90b70fbeee399499fb +d77a2a32788c480da87748c304f42257 +d6c7ed9bbb2a44e591a8c5168adfe362 +42f05f33f0af4ab28d59593f86c0f5b9 +a4ef32d993734d37a8985c36927d4201 +b0d1aa58ef3a442e929363e8422641c7 +e5fea53c70ad4e1c90cd0fcae7bd078b +75837c40672d47d89a97598811eac415 +94994e39935949b0905227a0f14c145d +84fd98c561464b1ba5d3dd48ab161b9c +31f4ea45ab034f33abc9715791134feb +efd4249061464658ac21c4b0c307bb08 +ad97ddacd915422e8aead0e64b9ff465 +22c0fa4190db425ca8f6b5318f9e162f +feebcb78c6c84a958d07d5e3d0542e9f +f3b118a1699046bfa851b6eb2d213ae2 +5650b43df0a046978615c057e646f937 +08d0a15549dd424b9d18bcf2e4b40b2d +f9c6d59bb4094c788ef67ba388df2938 +c730cefa973944eea0adab30f2afb76d +39f9f70164f04bd09bca721e13cc3491 +f5461e046f6d42368ef22f36382195a3 +1adffcff237848cc9d866330fffafc7c +ad26ef15cd8a4e798b71ea11e1e29af4 +e209a97ad4594e188c2140cd5e8ef582 +55dea6a409a5450e836c7da94b16c357 +232b7c4a39ae4a45b5e1b908ee2e0ba1 +94fca8c5ac9f4974bd4a02e8f571f493 +e3cf66a5312a4890bfd994cb9badf9fb +7f6e543144fd4bb59472d90442469363 +2de0b46b8fb449e4adaa6ee0ca00b5d6 +4121216e285d4e20a0a01a427118859a +bf630047daae421daa375d1d92858e88 +965a7a50975b49069b80c716e9f5ef63 +ae10ee3022bd4212970c723ffcae71fb +1024be9a916e41be84227a25432d82f0 +3d5a5d4daec8433ea2f258d7a66a77f2 +8898b12687f642d89d260244476df92d +a7b2ca1de7f14b91b15e0b8a331955be +3cf1e7cc92cb4e7a8ed32961b768190a +c41108a3ef0a47cea07620df8de9cacd +d32128f4b85d452a8ea5eb2db150e829 +0416f30815d6422791746b379f802405 +1864864213974c57aa9eb55294a39c33 +2020a7a4caeb4cbd836d92da1c6b7de6 +89672d75840a47108eaf47f61acce046 +f295dd1a5b2a40bea76efbe8234eb0cc +ef501e91ba6641a29e0515a10fdac631 +1263c4dacc1b46a0822eb5da85e6c38b +36190037aa2a47b6bd82bdf59840a1ec +dff67390ce4a4d83ae58eff74f6b8a21 +feba47844ff34ca094f9233f6ee09cfb +622fc5f8e60442439ebb0d8338108385 +dfdb7fe660714b698790a1e336f8d6aa +85c87b3d3377437da46714bf48b8b846 +e114be7a4e104228a10ec1b604c9a04d +e3140a8c501545a88f8d9d9b13c4ebdf +887ce59d9c564670950c6d5980d00a52 +b45d9f4370104ee28a5d84652201a6d6 +aee0ad8ace9d4ab6b134c6d7ac45b22c +62a5b060acb9413cbc42746fb34f9e94 +3eff5591f80e4b2d8ad15893a7d52ed8 +f19b8b01ac31493bb89958763c00c706 +5bb40f883aa3456eb8bc42080f63ccb0 +c4526bf6c2ba48f8acaad9a0783b0d1a +bfdd04a15273482694e7319ca98fc468 +4db02a025a4f45aa96a43e1743c3f4b6 +519e7994b912402cba806825e844ca07 +ebdfc87b2e104e51af6a7bc018a21d6b +1ae4148047c94a8d9f2d7c8443c29c5f +00ad7478cf0447f3b3494c00e7037177 +39a05ec9dc3b49fab9c6114ecc6c06dd +d74150a2d9d04cc1858b3e5af2d22898 +b52a83d7ef684da6be0d4a0aca818553 +3a8d707c2536440d8f89649626ea9df6 +94e6346040b14bd9b8a06a0cfffd1bb7 +f389bc7421f941c7b7085fd5b18d5a25 +d51e89bfa33646ba8771ddf972dc1af2 +a3fc2ab724c949c5b38d2059782906e4 +049c234ae04f42adaed9b2fed13765d1 +66fa4ded0b8943549430ac8a494e958c +d08bf7f2725a4b938d6093344e841c60 +b30316ab32824927a64fafd802eba182 +e1cb73bb23be4e159c507010394bda48 +b0eb1d60ac644bbcb8188a6fdb775e56 +30d2f234239e461c9473ddf3d62f5c69 +b02e258b63e948bcbb9e23af227e80a3 +8985db5fac7b46e0bb9a31b0a986241d +0a732d541e404e3e9bf6ae3841ff353c +4461e630d6af4ff58ba0ab98c2dcc7e6 +bac93491e0da453486f33676011cbd8a +0287751e95534929870bea1bed4a502d +878b53597a8b4f058bb67b7e3fb42274 +8c07e2864abb4ecf83c4eb5ed56a8344 +c280c9bf4a3f479990879a8fdaf71b87 +c6f67e740d3242ef97f4e7a8d338de2c +403e8cc91fcc414bb39363904f6d080d +22296c115d064f89bee065d5d6082a90 +bac56b3310ce49a3a862da59a5d61b07 +0d118b86c9f84117b32e2e85133e0847 +cdd9a3e7c19f4e23b9a0634a72905ed8 +dafd425a53c84d8f98c0ae69c5649083 +9f94540e2e91456280b025a75af16f6a +b7fab519cd2c4523b8f11675f487befe +8374edde2db34030833379b9784325e9 +9398b9af7ec34520ab530759d6415bee +53eb586c6a21437398e18e911e9dfa0a +80aa5db40c7e405ead5c3677737b69b7 +9155d1cb4d8c418cb313ad207e15a248 +ff7d426729174758a59add57eeb7f6a3 +bebb9f4cd0554f139556ef5700f99d00 +62db3a1161d94a25915d0f743bda31b2 +350f3337a3e6484291bdf29537b54689 +908858e3cc5d4341bcbfcaa42cee8a3b +ccac43b579d645c18ae10f635b779994 +88d595c0fdb641e2b880a2a3089ac061 +a9d25ff95e0840d2905096b45def8899 +3915e916610e43aba838d062b6e280b5 +02f13c9007ae4d5ab6c861f26341f441 +97deb26f29cf4ed79b7b0ce84b4f4794 +6f6237d16821480e815f27bd97879618 +f2eb49c0f5b34ab499b587b562437515 +32c5f698e4f649b5875830ed6e10ab70 +29eb6a4e7bf8403fb05cc2495bfc2dd9 +ec3071c0d56447ebbaa3f665664ff072 +818e088dc59f4a89bfea14cb46a4beca +a2350ca84e6541a1a010e6dd2db0314e +93c1e467f89f43eaafdfaa6588e92342 +5b1179db26874ccc84439b126cf42c06 +41b074fe3c6440f49e8e6d7ddccdb3cf +36f71117ba4d4dd7989bdefbc43c998f +35408acb34b74ca1a4fd23d2e6df2f47 +8769ace67ab844aeb72394587d8f281b +24057c211d0548f79031fdae979364ff +15383aab42fb4643b6d099f64b3653fe +1b41570c71164d84bc9e426eb51069d8 +e34aebe630df40a98ac41b16c7ab22fc +6839a82c7c644fe5a99fce0bf11be727 +a9007d4daa0f48a899152bfed3c654af +9361ab369aea47c8b44758df06f8a6cd +dca97787b1b24fd8a0fb6bb536e383e3 +d79fa51a9ce54f449212199fd37199a5 +ef22142bf6e94939bffd7fe74ca23184 +38404e2077ca4b209cd2f1db30541b94 +d9fe4b53538c481084f0f6e78b5f59e4 +55110a5563f846ac93c1c35bc6b80999 +930a5039b28c4858a2657395db3404f9 +cf116298b9f74a6883013d4ca2e43508 +be20ae3b9a48405ebd67a4cd530b8908 +24b4d9ed93e04d3d8ee83401196df405 +645886761a804fa5bfb184d1ec8221b1 +84cd8adb9d104010b10f3fa89e5f6a70 +c89f01b2d4bc4a27981d26ddb9b0e49d +2eede2354905407b9a72ab6d36964916 +4864cbc28d5142448e6ea9a836b25925 +fac3a16be50b4d36a1911bf846717cbe +4fb4d36654684810978ec1a012afced9 +21983501bac64993ac09cdc7936ffdf2 +aa555c383d5748fa91634b61dc3febf9 +b4738d0de0d642cdadd9809a887fe44a +57d0a2a0d0f44e659b589c21fa48f6e4 +8c3c6de7a8f548f3a54f8f07423c3096 +3d33ffacd1ac4b89b983ca18be2b80ad +c5792e9c68464dc0952a2ac9c463e1dc +0710b146f9e44170905a45a85621c02a +4f8fc3c05c2c4985a17a9b4b44d27e4a +9085d6e964a64880a6af9c73af6d1777 +55a2c35cc2f7467ca36847945d04ce9b +e3e172ee8d184134bc2143f0834eb470 +7347b2d9b9794a5d85e75f494efc4c71 +cc09098999ef4d2daa06e4d4576b2f1f +78511525b5b34ae8ba0add4f38025c12 +3f96a590f1644b55b83bd4053a665043 +cdaa00b3051e4227981b78d88fe00721 +06bb7196230c453d8bea4c1169a54cda +173b986511f74ff6ab8bbde73ed05774 +d8e0bae407aa40ed9ef4a184fa065a4d +467124c652a74241a0d59cbeca741074 +24006f127bec456a945b6b971506d5cd +20fd9eb478724fccb7a006ae76cacb8d +6010d990c39b4f778f8d246af74b4dbe +c0a589dc61ba423d98476db5a319f8e5 +ce4213c45a864884acd781ce657338f8 +3fe0a42547cd4e10b88cd7920dd413b4 +601fd508d0814d38898b7ff545564215 +d499d237c88f494e890d828185bd415c +27108f28ad1d4cb7876c2596ee5eda96 +67ea6da8af1341cba1322027bc47feaa +99ef536b8f174b9496516bed69368f46 +9cea8555d8374beb96275aabe574be84 +6873c50ab55048aebced2fa3684feb8c +afc8c9eb7029423daa20bcdb1fe87b3e +fad641f2a73e4924b8118acfe1bde2a7 +bfcefcb8f6c644b785ae555319075e3a +d2c1afc47ba54d4491ee7b55469d11c8 +1dc0fe17c77e40a9ac5a0c52462ecee5 +c8e1f757e11d4c9a92996196a1ea448b +829411d263a94025ae68002daa88a8d5 +b5883c4ea9ce48798274f0500bd12d1b +f124c04d6f61407c855e8ad2532037e9 +f1115dec140241dfbfea6ddeaaada472 +1f41a813c65441b5ac500a4408ad2dd8 +49fac825fa934efc84c808e45ffad4cc +d45823db89ef485a88788f8c0a03bea4 +dd8318fcbc22481882a208ec208b4d92 +54b56ce71d054d60ab31425757a45cf7 +d9b25bcec41d4c1fbe04c869fd2c6545 +1060361948a049489e30ecfd98d0fcb0 +d3655bb9762d4e55aa0728fbe4d0a31e +222ce23bad174017a05b97e5a88abbac +e23586f2f3bd410cb463f05115de28cd +23db4e971876417582d5fdac2b252762 +fd7bc706c4074fa4ae6bb1ce1ffe02df +c2ae194bd2564bb39abd79a45adb4744 +444e17f7be6c4231ac3c21feefbfe399 +c803f1e61acd408f86cd7f22e66fd3fb +7639f6843cf54925a9a5037385ddfeae +7b294e29e59843a1b02172d176e06a61 +70b545688f9e4b26a7253250352b7ffc +427da50ff3f54dffb63ed1510b743c8d +iEjmm8vp0s2TPcjq9j367AE43fA +73521a4eaf8d44ceb267ad6e8303a152 +fe110d01a17d4689bda8304092e490d5 +5dc3b7ffa3c4479292f45cc39d667db4 +2151e81af03d478f918511ffb1783218 +0231b3f6d9164c38b072d691bc1ea95b +09ddb48d33a64d6fa67ee82ac3bf8715 +cf1e6a6d80b44655af1fa51dd30035bf +520b167619584f1ca14ada756e6b4981 +de6311900fdb4f20982d06e318ba57d3 +dd0a255416fa47ddb9e5c179d86ef437 +76a53a147a834342be4e5497a9d985eb +f9e6cea281454cd7b0190bed1deb0788 +918cf95d53d543c4aa132b780d9d4518 +960e6f177b134d008307245d8127b9e5 +c198c7d48d1546c39d98bf40738bdede +29d638cb929241cc891beefc580b975a +941f63bfc76c4560af34c4914443f5ab +4ae6ac813d584d12a5d5d608a595bfe5 +8aee8c79afe042018e4eda67403d12a9 +c11e010dc7aa4670aa952f0ff8ec59d9 +36a231c7af324000b0ea55afb6a1bb92 +a5507ec81a2e43de9f1341322ac49d94 +8ed00b819e944ef48f28267ccddd16be +58d14538b81544f7992085e90232b338 +30eff37d79e7408c87cc0c8dcd9f5265 +70cd18ea107841aa9c6c853fa495bdef +8d2aca4eebb04a81a1f3bfedd28977f1 +1905809147e645c1bb082b49710a4e97 +076d0234ac2b4d41aeeb6a8eff180659 +56881c423cab436293fddd2b77e314d0 +952df22d32b3406d958a5979131665b4 +f802f7320e6445648d49a7f48d2cfda1 +3b007b71f5cd4ddd8f185795c8918f51 +2cc9988bfb09440f9b4bc4931f531971 +d71e0c931e85416b86419ea88953da04 +b68d4393cfb9433e9fc926d5f7bb04e2 +c738fe19a60b43de982dcf29b6574245 +8673cf294717420b929d72a488c8923a +46813c9124d84440beb13a0078702779 +2c70ddabd58343dd9f9d97db7821e8a1 +9ea4ce68c07842239f29674ac2d4f1a1 +551c57ef743e43ea8e3d66c2500dab0f +216c3f967e0f4895a9faf6fec328024d +f3b61cf7208a4ec38fe1d6b46a20a601 +3e58838a56964b5fa8762d908675616f +0f560501c1bc4df69c6a4f9ae5feb2a1 +a453e90d47b74260b5e5ccd5a965fe3e +a1cdb80462394cbeae982b8e2bca8763 +101b50323cc34fd69c827a42a818d4d3 +eb46b3407c67491f98a13df1b86950fa +fa03c53592e44b6ab5297609de0f1888 +7383de7d92614184b0e10ac7e20850b1 +85c44fcb5c674668b6b76dc8327374fe +003ba3e54a524999a0fbbf446573d589 +d4283317bd544b3e9a2b42a014cddf10 +820d7900024f41978b3377810c172a48 +f6be688c2b3941dfba118f78a76c64ec +eebf5f172f174113a6ab7934e3156fcb +b9483dc9fb1140c7bdbf20923f8ec4dd +f2d4f12e33aa4b15898a20e75d588ec3 +39969b5d66fc420da0367d7c17cc3f09 +e4f1c395626d49fa906b03cb5e31de18 +747fe8f37183402fa2f75bd5129c9d6b +f0b802fb8446473ea328d33060f7f5c9 +4b1358d15a044b76a65d97f5da72ae22 +697c29bc77a04a928e085a79262c91b8 +67d21a5b72a84aefa9a045b7fba5726e +9f48d7f42afc49f0acc4c3705c0f8bcf +dc6a7d667d5a4b269356986633983d77 +dd345d3248a2497088ef76408fa8938a +858dc301a0f245ec96bc32879b2f9792 +46995ee687d2475bb3194137403ca73c +67a2240611f642068a8896b2df3dfca8 +cdfca314bf0d4c348dccca1f6441d497 +9ee586f16cda46669156b252a67ddba4 +5fd121e337164b41a1aa23b34dfa2e12 +deecaa5d26af455dbcb12315249fd38c +15cd0e85b7d2472b876b7fa6cd09b8ee +89a750d568cc4817b163daec27625dd0 +c0b33a7cbd184b82943db196052a0f52 +89d6353a72ea463ea4e45ad4e160bf88 +c3278c478ccd40f69da77ca76327bccf +e64b5fd0fde2419cbcba07279c4291e8 +0400821fce28402a88999aa32a2a7934 +e94ec520e9ac49b4afbbe85cea98a2b4 +e1dcd19f297c4350b5acc355ae4a4e6b +34a2ea422c5f42b4b49081b3a8539e06 +c100d8b9e4684e6e9be20c16c74cc257 +94d400a7aebb4c89a5fe9a60ca3b2405 +ec5fa2338ae34f0682f6974dc3190861 +7f610066d3d04b80a1911d30fd8c136a +8239215dfd6543c8adb25356f89f04c1 +cb1b6006dbb64f5ba321abf27e0f97f9 +2b807dda52eb4235a0625f79c9851c15 +334e599a874f46c7ae4ab709da53dbad +6f799e5d14dd4ca28976c79e40b53fd6 +1bba0f4f9ec44f789aa8f036f10af12f +d673aaf2157149acbc55b624df95d693 +b0782caac0b1426797e38d98fe859dc9 +46aeb0303b854ba5a26dc73bcbfbb556 +c645474193ba436fba3154521629692d +8c42ea688b5f45e3885c43bfb82ba1bf +2488231f80cc45348ba8e772b7143df8 +90cfde2775c04ec48f9bafd98131e808 +dd108faff010488db0e4eebbaaa2cebe +333cf04856ec4f7aa93dc7e5ba9c49f3 +349a1d0c2d7b4b118b2f0a6d89704446 +d77c3c95ae1f45cbb6e1f4cc00d146ec +b668d4e063fa4ca8831297fb8a31c811 +8c73bdf9f6304a3899b406483b5a6834 +7e3988e1afd342418a05f1efd9128c31 +a9d3dac0c55042989309bdcf68c60f76 +4de6e3a6fdf7466a8290130cbff7ac54 +6326e584b11a40cab68473b7bdff12bd +5f7233c10f0f43d882bf6b704c7530c5 +b55289b594654879b6ac22891f86698a +e2b64f5031fa45e8be661a89baeae3f0 +e162e6533b224d769edb54cf55f7a62b +d41b44b66efd4833abf5581a76d60efc +0d089f6385db48f6b00b204efb6c0307 +85ed070c2a1b44c2a6924a71109397a8 +8cef9554ec9b4d43873fc63b65553347 +4269b97a679f40da91da28a69a7c9f45 +7d81cf9c77314401a0f328c77c4c8d33 +047be21efa814473a477aeac79bbb6cd +f1b34ddc53bc453282e17f0e6bbd2117 +9996692af7fb499e8a27d33bb1d23e87 +dea5557997d74b75bf651de920891480 +ada3335b784c4f3182217c0362906193 +4cabff429ac84eb0881fdebb4b202f68 +7bb94bd2fb1c4334a782afe3cc895951 +631912edaef947f8a345a41f16e15aa7 +ab3ea86bb5f945c89889c1d333f55c0d +de485d8f87f64932a26f910282034d9d +5f674ac6a3ed47109fa598fd6ead408c +1fab9642522247c09dc8754709f84628 +6bc7060fb3bb49acb77720f7ad76a4d6 +3a4df884aff945eaa44e31d1b3a16f7f +7c98e97b66c44a1b8c5020ec4c22db3c +6659d460a0924f3aaef320961a419198 +4ab91bbdd7e84ddca649031180d4da32 +aca2a3b47d894fa29d0c9fe5102c1357 +f67448936fb34ba6b1d03e5c227805f5 +e31d40d9a2564c95bf6474c77247edfb +e05b1cfd53ce49f39741e692274254a7 +0307be96ba5748df9bc359acd68eed3d +5dc66a375b9c447fabc6efc0a27eda4e +de24547d5dce40a6b3f631f87f21b414 +64db37183cdb4660907ed279a8f90705 +31ae4708a6bb48cfbd0b7397f480995e +cd0400cf0d2541e49d82efdfc0f0450c +f015375273454101a6a0cbd7e5a33c76 +a73d111dd871418dbb9e2126181c5612 +f2b3a71f48d040069fb144f76a1180d9 +f53db9ac6ac548f59f1fd5f066b61d59 +5954ff00a1df4147b83fa69b8ce47221 +379fce5503cc43ff930875b3e68e4193 +4cd15dfdd2b64b5695e940f4f4609087 +9a191b9a479a4ef9b9ef4794d19b6035 +3b65b7d0e3af4b99986a199d3df01517 +faf9f46a49364f9b902a7e7c196728ab +1c17e217e6264dfda3d343a311e1167d +a9932eb75d93443eab926b5866a099ae +84b71689b5834865ae97541ccb46929d +3fd7744bb84042c2b74c96e28c850f18 +7b6a036bf0164ca7ab809b1b3ddf4926 +b32efc7a37ad410ea98b77cf18e0ce0b +0a57e17824c64db7b4f4be03b2e99b2d +aa6923a3a31340c4a3ea8f65ee45fd68 +032ae3ee496b44639997ffdb9c97c5a5 +f078ec4957764c5daa43cc0105aaf064 +e311e426540d43f0805638bcad1763f3 +945b559539f541c5be08ec9f1475363a +45e9d996e0a84a558e7b41afface911b +137bf24dc97e48efb5b5eb7541d5f932 +68dc58d3c198413489db07e9c2b9ef62 +ca2084ce43a64a809be5ba0a0ec6cfa8 +ca0f91b3044e4f0ea315ae9ba64b49d9 +7d185fa512604b3aaeca8a820c500661 +92ff65712c62408dbe8406fb5c8908d1 +a84a5bcafdc14e5d95843df63553065a +5191973a4996431e8f4055e4f8a75101 +de0817a4e96142c0961c4d1561a8ea17 +401ac6fd05dd4ca7b14eb8dd607040d3 +f7afba1d4e91459e8c60237df5aa1a70 +d745dd41428f4a2c95161444a1f90368 +08d73e1168504bf2b8706cd838ad16ef +e1eae1ee03a146abb703fffd3c2cf4ec +8cfae5ff022e428490dec84fc5dd1043 +ee9ce6c896664ab6a86a0c3f9d52f276 +3258c42b472a42a29f07a9ada311c8bb +8b2a6c17b6b640ee801b4048e8d6bb72 +144ad4d46a284511986c60796966f201 +a965ef61e0f24077a3de4fe2101e8acb +02d9cd99adae48ba9119adbf01003b97 +20b9ef2a6579426da3a2806fdbb1c981 +7925f2c844a1418c8a265dfe7f1e97dc +878ff679e85643f1921552045d049672 +15559f47e22e44a3a3cb2c4d413a7c24 +b46c145c453147d9bb298e3a36c06fde +cd5aaf2005fb40d49a422547cff3d1fa +5a408836c8d7405a816d9b1d2f8c597f +411c990e22ec42b29926275308abfed3 +fc0e43a0de334f04867cb8c0521c5881 +4e441ef576e648768229966efe7a03b7 +7df8ae89ff1f4f3c9f82d5a3e0a3f396 +7be9dae9ffb24bf289bcc2a72c880992 +d4e0b1590a9b4a2ca8a682a4d7d1dff4 +01c803e133eb4de6a99feb24bd490fe4 +00ce4eefc9b0441f8a86be845e6ac51a +9fde607d57484bc2847f9d65a1538330 +faf4d744f7e84a1c88cb21c601b98ee7 +4e2c181f9ed14dd7b7bf40dd7e871fe1 +25eefc82acd944ce862b7988c37c6d93 +92d860455e9548e397de8ef3c09eb254 +29cb594c39904a17b0debcc015495a98 +5a649462ebef4028b6fee2656aa406d7 +5c117bc0be8b44a6b569e2e64e64e667 +47b3e990541a4e07be8595742f85df2d +d5583c4a750b446bae251b3a4f3fa88c +bf26de8621e647e08b84eb2b0b6794df +91892daf06e04429be3b8f9c63e770ad +0be23bef28794902a00239e5e33631c9 +02c088d3dbc2479ca157d85f147036f6 +ab60b69424b242bdaf63b0857415ec09 +6c818d3f813f4865885bad305a46e3dd +2fe1650ef89247a58fddeb07e47c43e9 +a4d9a0fbe5d844769c1865d7b9a6ad9d +629499bb34974b89befdc0f8bdb4939d +2f0a7082f7c844b1844a7be5205f9db9 +548c2d72088544168c7ae45b9afa9ed3 +354c05cae07c42cd8ecf2b00373cc77b +d6da308bb8df4f8eb196e75d20bb308b +b81e2038bdc24e8a81a5a0e6e5012eb9 +a4a078e0ce9d48d5bf11218bc22c2306 +8dd480171b034206a45960af38198cab +f5d973c5aac74e3e977c2309997419b6 +99d50b8b9c0a4b83aa38369abbf07e57 +d2132badba7846a29b9f3a4a5d80aeb4 +cd78d72dca1748048c7badfbb2f4e06c +824b341826474fa483dcbc0fa3b15fb0 +0e0be8c147bb4f7a883581c6434889b4 +7057c0cbf1e547d39aa6ac8d3f8810c1 +06eb5c9b0f2a49dba0c99207f053e048 +84643b518cae4f42919224a560dc9704 +d76c2f26905440cd957de261301d09ba +322ba3a159a845c7b7642467e23fcc2d +4a9fc7a5896242fa93cf94e4adeb8dde +1414976925354613b004d3173ac6459d +229332a677d74c859b5eeed0d43d851c +ba112a588e804424a1f4cd497500f111 +88ea9335400e4d41affc7bf29a5ab0ce +d016234ed97247f6ae916bc386999d03 +80303f3ce3bd47debfa63c104636b3cf +8e8337b83069431fa43d536a7a101922 +04c9a4a2ea5442e68aa4889e92b63d14 +7919a991d60a479882e97e3753a69b21 +93fa114375a84e61a4d0993353183137 +f487f0dd80574474bb4227228b508d8d +103e066a3c9545e4b3bfd2f176b38f52 +a0b9780e8dc241e6840932c2ff8ad178 +3b2ccb0cc5fc4dda8c929300ccd3d49c +212d5d395ad14367aacac0be70922acb +2f20d23e80ed432cb5866cab6f0f1461 +39ba87f0e3be4269a7e0d9148e1025fc +725de9fd2b784fbd9ae995fbea498f62 +1c0e71069aed474d8cc544cc8e350db1 +124208a44b1340eea1ff5572b37ab715 +05ada823740f461c94456a68f1146ee2 +d90db5cff6344a04b45cf95d1f32a8a9 +4f458eea419347639f3e210201cd3a5f +8e076ba031bb4969930dc8e49d35668d +bb4347b450a74f8986482c713971133b +a5675b663fbe43ce860f942cd33ca443 +c45228f2b22e4338a4094a16ab4a0389 +dca6d06ce3e545539b6b60eeb828dee8 +da394e8c38a84529a3b98729f1868c67 +04ae6c97835448d98fe5253875921557 +7018a6ab87024f1d90b58b0cbb6bb39e +e0f809c14bc74e028c1ded8297241f2b +b82896c35202456599d65190770789ea +5b3a08994f9f402ca109098c67afa5c7 +1985d2c6b0d3455789622e6e599f070d +b2081a8c11344cefab18b38c292a7ffe +13f6d5da886c45e1b15bb145777e3773 +e6ecefc487554fe3ae689095d425a6d0 +7fb9962ef55f4680849035f3cf805827 +901435dd6a2a4f49a46a8c596879d4c2 +69a2bffb744248598ee21c61039b1aab +2e0afa27358f4223b658e8351002d19f +be7087facd644474b858deb1079a5bcf +7f77436d2e9e4f88b265f0a0e7f59142 +2b84cfd2dcb74c56b1715a44766ed325 +5cc2ef84ef3a466babe4e315035a053e +7ff84e7e989141a6869c7afc12a5e398 +e75d11fdfdfb496886658366fcd6a812 +de6cf4566d214007b7e7713824889ce5 +5d9db62931a947d48d3c26625b69cbf0 +7b6c0297b0b3447b88cb76b141be36e2 +c5f3232de6c04ccbbff5eefaf5a32d57 +df664af748cd4e5ab5274c0c8ef93da6 +4823dcf53e804619a219c5a21d11a18c +f9876d14bb4d4e28bd442eea88c5227d +ce8b94b8bffb4172aa6fe63499d47568 +626c976266064f5f842fc7186aa253d1 +f4652dd83c134e17a730e02a2cdd234e +7ba42f65ec39422080c909400454c43e +b9349e58e44c4858b0dd01e815be94d0 +bce4a505258343faacb4fc022bb52b1b +212d33f6b5904bed965a87b018325b26 +ade41221909748209406d91b20c0b06d +a3c221e5504d40a8ba019f8f1bf5ab0e +b4ab34f9e2104d12b56cb25c76a25900 +20ce10ed388d4a90aaeaaa08202e4d41 +5e1fc505532240d7a6f48d013bd09d0f +7177d1c798d042aaaeb543e5bf7b3911 +a4a55e7f5c6140f8b65b902adb042d5e +1298dfc93c3a43f6bdfc3ed9baabbede +afe9e3d2401040e7b99f6dfcce58caca +e8a80cbc797248f0a50506ecb60fda4a +902377685bc04ddebde842b77066b164 +b87a65917e494aa4b306aeb6ee961182 +8863b1cf84bd4689a8b44bb2ddab6c29 +d53966f767e645199592a72d9897cce8 +0bd2f7281e094856a43330966d51a2b0 +7b7b09d3e15348f4bc32db9afdccb41c +a917736df3e24882af2a181ce5436ad6 +a759edc5f9af4ee0a08391d2c5049c0b +6cd4c51f23fe47049b78fdf1de5c8c90 +77d1498b156946eea65423cb72cce135 +9b0df931c3ce4b1182cc12ffed6717ff +d8bbff6f87a0452b8d9ad083599df0a4 +7824f1ce6ff047c283401056ef4afd58 +8b196cc56aba4c69911a554205553b49 +354d141e8e0d4a95856c7a373d849e0c +ec65400e36f8467284f6cfbeddd3c7d1 +e38b00deacc446fd8960e46570c4544a +e3e6c10f4d0d418ead167df69c583ccb +01d23b3ca3d9410993d55850730277d1 +baf345bb68fd4f1a9eac39faf456682c +223acfd933fa480e96bc45e38dc1537b +4d6a489ba16340b99c6f9eec58e71ba4 +b81af869f7a84e088181c0862cce73fd +a148270bcf8e4847af08fc6d8450db03 +37b10f9c92584dfdb3d1337697dc8843 +a0dcefc83e6445ba9b8991cad2654840 +426244116b834a0986d4bd6b5d975a6c +8a80dfcc4003402c8cbf1377d2e8be66 +59869709cfa145f18ad00e9418d9849a +8d35be41a63c4762b8cb5fe62e50fc52 +489f3c3301c94de794fd7ae54f5b2fcf +26e5998ebf0b418bad7d582913017f37 +53dcba32a9fb45f1b58fba02d9e55222 +192518f463434dec85a926037ad5e9b3 +4722f5aa9abc449abef01e64045a0371 +59e522ed95274b22937bc306fcf1921f +a867872715174fd6b96abd38971a7da3 +2ed0b409fb994018abf11a4dc2e83da9 +591f7d9f6337460ab1d93ef6c95e70e5 +30c45e4416c5437fac66cd142cbf29e7 +c594cb43f36140c8a422b069d6d9714d +52ac76e312b946a89c0da2517dd5f1e2 +459db9c0633244fabccad44ca329d5a1 +3cb0c95b955747aea22476264eecf390 +1c9866a995084b7ba237b8bcd36f68a2 +b24b26485a504199ac3192b995901dc2 +0acffd6627844bc4bd91b8fff4cc604a +acd2d2f99c934741b1c2af2737d596ee +15490024c156480a9e8bbf86753d0e58 +bfb6d044406e407eaea58f214b139d7f +11c5431997da4d5b9c362e819951a1f1 +df26b8155ac84c57a10f5451a5ac1a12 +59f4db25c1b447f18fddf3241b5e61e5 +963a1bcaae9345738440116ae7bb1ff4 +e638317e58c44b02a9aad7eb8891532f +9136dd94137742cd94e124d9ecd46c74 +4e4b8731493344fdaabafa2290e72faf +5e0ac045516e41ba91b53de9d1086f68 +77e0384786d84a688ba3a3e8ba31f697 +3dd2cf55c1364c1ca4eb7d1543f0e89c +c6becc6bb6ed4919b6818fd3c26165e6 +93c8d898046e4f03839dff06a7272af0 +13cc84fffef1437ba59f26902dc99483 +c12909c5b64943d6a11a9f2e3dded93e +a1fad496198c468f9674f148653f8336 +8a451338b2194387ae8cd6140ae51c97 +d72654cf2adc4cc29529657ea402dbd6 +8360d919decb4f93a595914b131f0839 +5a97a5d97bda43859452ce3b3125e4f0 +71faaec870944d18ba03822bfdf15744 +dfdcf768fc8b4b20b0b2d0c00e505a8f +0a36fc7335524892884a73c3ca1c37d6 +8528cbcefbb140d18ed5ec4e67cc0a0c +e2e82a222bf242a29b15e9aa6e8e7ecb +ceb7dc27a8484b149fc93a1de8d67f5c +d6dfe95ad1c34d9cb11cebde0298cce5 +6f2e90d6157a40958a500ace8c454a76 +d10e6d40f6864b84b216c6b67db89243 +4ddef4727e2b47d7a0b2302a62c3d6f4 +dcbcc248f981465692047949c96a5c09 +d90c7f830f9c41398bb55de4a2e001be +a93d800395eb4b4ab2a447405385e4a1 +36b3656d60d44061926820c4ffdbbaf5 +8ecc773bb7dc464880b202a114db9b38 +6494e79c39554da1a4ed68d5e1d10cb5 +57010d97dfde48bca2c072a6cfb9b6d5 +b385666043e243d3993c00b37dcb5645 +5880bdcf82504206af4e7a6d0f0a7ef7 +320a811311874608bfc29070ab712635 +8111d4a5bff64987a45250004e12a0c0 +2069a0d4429447c6971b4ee0783e3d83 +86b995b879914b629af34bcefade3bf9 +5468a215d8524196bae66624e6e30427 +f47f3f0762054e28835e20d31d05ae10 +cd7cec4d369846a69b5f87deeb9a8399 +946d829aa76645ea94027e156e03fb17 +00c64f875b4a4ee3809ca1e20cc180b7 +c3185a2e6f714b07bccc427f4babbfed +7dc8c30e10cc46a1a052e7a30cab8a83 +62aef320fbd6460c8b099486438714a3 +2553bf20c22f4400a827ef008cbe8233 +e1d0173f94b841919b1d5fb6b0409abc +2c32127e0a354be9b588bbeb8f9ac644 +c8675e9eeb34404ca391f6fa915a104d +258a3d42ec59460daa6805fdad354c9c +99d53b44586c418c83953a7b6d889a46 +b8902b4ad8c74b50ac68b289a13a14ed +fe3fcec21f3643f38ece8413bf9a8eb8 +86c9057e2b78440ab78b66ec4cb5d41f +7658fd3aa3914c6daf209be68a7f8adf +65ad095e176940b98a2458656d9c56ed +2513a9899d9c4fb2b1d76b341f2faf4f +306bbbfa962a4a7ab22b701f6458f96c +4d674c82e4d142129cef5f390d5ff22d +13e036c03bf8449b92c342fa1fcb7a64 +0e61ed2494314d80a1ce1bfb3d64d304 +f2debd76b076436c80106a0428f9e9fb +f195dea3125d4b188ad6134121ce60d3 +eec78b30ad464f43a650b8dd853b8f83 +9da90ae06fb344648b51e1529bdcdfe0 +ede795f1c6f74a99b6952183f340fcb8 +fb015ac74edf4ed4bd51a1e3a62fa475 +e2ae7590759740708e6f2f5bf01d531f +9cfb6d5121a14c3691bdf9c92a37c8d9 +9dfcf8339e0246889d6310ea5016a1f8 +4d4579615d0e485eb1fe57d3df39ab74 +a077fd75db084974b273675dd6c5db69 +cdf56b3d94724be4b6351ff6e9355d07 +0161624e84684e988bf3412174993e27 +1a7346e0575149abab9fac3184dc94c3 +661cbbdd1fb74beb914917ae3cae9c33 +5816ecb4bbd642308e9926b6a1b51a95 +ccad57a6f40640248a023dcee3d5cf3a +4400d37f005c4dc098106a4e4a3531b8 +7982178a74c24bfcbfa51af8cc726494 +3ab2eccb81fb481096066e27bd8d4a92 +edbb7502a3f54d638f7b66aaf3716b80 +793a45a116be4082aad5ca002ffeb5fa +ccb1f5791a7341ed85cb767bbddda2b3 +5e423be21887421ebbea83f33abea3c0 +f1d1eb1f7c934a1b9a9df628dfee003c +867d0427a47549ea941377db46832927 +ca0ba4fd910448b5818e0fb74ad5b412 +ab4de12c94184bd0b28fe3b952caeeb9 +ef7d06f13512466f8cb802e260cdced8 +28147f8049894336abb243d022c910c9 +34380eb566034cd5b1877527ee7bdc4c +9db3bdc7354143e89129ac650ef0ad09 +a6d34c9a1bf24146bcfbd91886d7df30 +51432a5a95414e6eb93e3630be5bd9f0 +c57b615960184f0c81e11e72ba1f46bb +946db96fc4c34d3691ba542501448caa +f277191dbcbe48e594f0877240c9b20e +1bd54fd258ab4278979732c7ba5365e9 +72ea4106ab1f4db297317650904c3628 +d52544963a1a4731911d6916c5c734aa +d8e8e17950a44b179d0c1ee61fb45b6c +572ff4b067a247f18c176599ad45c67b +3fa6a662e24b4aea8dcc21015687b721 +fb46c9e31bea4e65b1af9c5018c4ebdb +b2ed07551f5f49368b600cc140f9fb3c +09eb01f6fe9743deb23e35219ddff2ed +f23652d2b37d4627b22553e56235f641 +2af94225d74c4d9a89ca1d1d5a4fc612 +d61741ef22c84dfabf222cb2c9b30e13 +24d189a5d7b5420591d4153162a2d1b0 +a7258219829c4a14b37b711660ce0c81 +b7f382dcc5094561a88ffc765fabe978 +7ac65580fd7f4869990e00a6957d1c59 +3a07d98bd1c74dc7966345c53de7f725 +3019fe19701b44f18f6c49603b4b89f9 +acc19a79473b4e15a4875f583fb12762 +410249dc4e4642fbae64a42bc547e17d +0972c48a7e4548bca80975a47a823bab +de17015ccd3547579b26fc20270aa3b9 +3ea799bbbaf5492b894bb4af11620362 +9f44038502214a38a2e2e1dee33eaac6 +c3a81a5f13274874b776761c6e64716e +d2c7221ac2634362b29ba3b15f72aae1 +47de6f92d78942259f90738b194cef9f +12304e30fc9d4c1288f6634dd80a2bb8 +e70a77bc7bb548e6a89facf4defd9827 +154598525f904aae82c4ad29cf495a56 +44393a46a9d44fbbb4bb0bec6dc31d2a +947e0e814aaf4db09f007d68fd9b47e6 +de02148574c5434e80187d35378d1b8a +ea0ede5af4084ea2bdfd029789281f7b +d3b796cd92df460abdaaa2ebacfcf56c +2e24c83d4d354f90abf93148ce57914d +158cfa9cb5064e2886ebc6270c5c1528 +3ce05b16354340058d5c3b06028cb9df +6a053ef489ba43e7811ec4a6a19fc074 +496244e610f340179abd8360ee185763 +758dcba249944d88821eec226211c54a +dc18fbedd63c458b9b31878d7909f9fd +1f16565d7dda45319e7094c4ec7af66a +4eb843f1ce0a4eb780faa429d76c34b9 +25766ac81dca4864b25476dbe9200ba5 +a8716a40aa854cb9adb26852939ecf26 +3a62c9769cf84eef82560b64f87f829a +abe28d3df0ba41a08375fddf471b7172 +6201d6f1c6d8436789f05ba29d3dfb2c +49de9c377fab42b4958148e0ef5eab46 +0589b1efe9044be0b5953358878f8dca +9dc6696eef71420aa4114d3afe95e644 +3b3c48751a3d423f80585d38c55b3f97 +6e9bbc6183be4a2793d642d2cfba3cde +7fb4d851580942f380df59b26e905942 +317dac94ec404bdbaa6d41a85e04f51c +a44ee197b3524aa58f54898759940822 +b131fcfb173648478382745a3fb1b3c3 +59658925b3ab4cd18af03bf39c477616 +2ef361391cb4455b9dced66544b4b965 +225687d281294d5da4a8cae2d3ff2fbc +39c63779483c4fa38bb384f644b9cc8c +4b1fe1d9569346b69bb956bfae354dee +1fe7c163f84c4197a7a78b347586ddaa +3356144cda7f4b10a38231b06d9df544 +0fa9786e50a84b0481e5f436db794d89 +d688b2214a634be38527387bc9ce25ed +522bafb5245a4a07b2ffdab3833d1b03 +4be3573f710044a9a1e401cf8374a852 +f81d863bec684b00a9b1ba4c2d844001 +18c0a575446048a391c5c0634b5dccac +c3cc5a3e1b5f47cbaf841aee7125b759 +aed7e822412b49f4bd75a3d1e80143b2 +e4ce372b7b7f44c2b1ac991c65b47aba +b781f8cb073b416d8855b2f538dd47d0 +de5c761eedd14615bf45febfe1d858dc +567e92036c31406d815e9b5bbaa74b6f +c9b3e4e3d0de41da9d587d14237137bd +476b23ffca3f43b2a8cad354a35072eb +53f9d214eb3a489c8bf1530ad32cf2c8 +6c10c97a77fb4e908dca4659486f0f0f +c0a534186da9421f8573332b90f808c5 +fd5ffe8306f24fd49bacb84e83a0e31f +870394045570459587face4cf047c06b +6bceb4eba0b243409325fd4f647547ed +a9b2069741404f6ea68c3a00b2a231d7 +45c8f611a28a4e0e9b74bb132ad43ae7 +18f4d2cca6944b058fc41566e239c350 +a6afacafd3654fa0b095b25bad5eb319 +f04d12dd1e5444109f860c78679fafc0 +8e194394fb864e2da73913b89e240a71 +098d594141834645a57baba60b4554cf +d04114e38bf24254b66263a3f28ce13f +8d2a40bb2f3940d3a8d050391327a2de +f706fa6a3b54449297a7ba757bee0071 +c0ce5e3cd4ff4193a23b6d92f0922151 +3d9327da17a447b5acc9b3784f460853 +e3f411a7470a4ae4af6b6279bba85463 +2fc8e30ae72d4d968c44bf953312d62b +6eca527884f14174b8b951d1644b0dee +f56152e7c8654e52b55e032907c50684 +24a92fce6f284fc5adfe05d5e84de2f4 +3f48989f50894e48abcb1a12fcb70226 +e149e92179364001be680fc39064baaa +e1d9171fef9e44c0bab4845502e4e297 +37809cf8a36442b1a412abc27348ad8e +98097909abf64521b87e43d11d4e1839 +ce17aabc51ba47bfbc7342a963b095e9 +24f040d86b254a5cb683fcc85576dbf4 +1f7b8a16a6ea4da49082b4eee85d647b +96678fd69976488eba3ff1c211e0452f +2b9064abd0d04d84a4aee64ad3d624d8 +fa171cca6a624e70a6275f0167e5f61f +05197c7001b343e183e561c66134c951 +5b87502ac41f4eb2b2ba7b0cce6517aa +9a9060f938104d259f01454a2e461627 +58d9accd2cfa4328a385c9a3ea2075fe +fd2b9eb7b9ea41ae98efa46a607ac62c +7e47040f75b544a2897770d5812a921c +d044c7495830494fbb9d35e2373173b8 +94b74a459f9d4733bcb90e687dbcf5e5 +ef4b01dfce2446fda88041bbb195247e +25f51b2ed59a4b0ba72224449133253f +959291591aff4c8fab3f00b0db055932 +95606061c73c4a6da00294a038ce0c2a +e55f015272e747a2a0c1039559cb58b7 +24cd9876663d479fac2093fea173dce5 +a48318fd544b454492437e5cc4a3d3ec +b8603b3641c64b0fb473cc13297df19e +797e7c7f61104b6785c3bd0fdb99c74d +afd1924349bc404daa8fd5a104de8a75 +3f1b9d62a822439ebff2acb9de882875 +fa289390e7b34aa98e9b9a4d5b8f8cbc +bdc36b1402794c77bf4c0987f8399c8f +77236ee7dadd4a4d927978b0475575b1 +c478f11cbd5647fa81efa515deb90e15 +1139b853280b4dc1b3691396c7b9ad3c +169bf1da19c342069c42c31728122224 +a5d1ead883724214b1be64efadb3b4ac +f4b2252bfd1f4ef0afc2e895867d5b92 +f2834e5557a54c9a981c45d07eae0d4d +c85088416a5e469aa0d6bd22b02a08f4 +433529b3f44845f0abb742c1da85da4c +b7f7ab9bf7244c3a8851bae3fb0bf741 +544b946d7002421f9d3bcb6df73ced43 +b89a06e6e7554c5db7ecd1c51edd3bbe +415772a0e5954fe5a210353915e96445 +414c5775e9f444b4b280fff70b9465d6 +aacc17f3ac10497ea309d25b14a99b25 +ae7ac2f9f32142a4937758e11197413d +4c06e83b2c0d47b796d286a85b41bf2e +f7ade690a1f44d608fe0097156642510 +372fa5872d5f49bc8c1964d58635e7ff +17ba30c2d85d43298d85b3367748df73 +51e350cb42ae4c8eb7176f21778196c4 +1f6844f5392f406483e4dbf36bb1ba67 +d4c035d5857f4b49baf2ee27f7051a16 +292a39eac72b4ba9abab123dd11f7283 +ad622111edc448d1a349ca66f641e73b +db57b8d1dc0140b59e055afe93fca4c7 +b0fea0d8a5a54777acfc99fe482adccc +092d998579834a32acc69cfe59cb4139 +50d20afcff9c4e60aea45514e0de1327 +4398bcb5976945b08f195816340247b8 +4a538218026548c49551ceb5938eb39b +a6193c4a6e4547d19060b8e120dcc377 +663b8b4d986844d388c680becbfd1f42 +4bdcd84ae6864249af3171fc6af8b792 +15a06d5b503c44209aab85d579f422d0 +5627d69e5aa84d07b2d6ea516876b0ee +5750c153e7134812b28511edd18930bc +8a0c9d1a4da74f52bf88703d0e7230fd +33d98be6ffc84acb8aca4d15fb6c1755 +d815c3cf71ed4c279955f06e62a82197 +0f2b2014bb0945ea91ab650934ba6a49 +38cd0b9138c64c4fa5fb125c5f6796f6 +89e7a4216de8417a940cc16fb83f04db +63678f3fcfe1438f9271c85c987572df +9273c66886cd4792a983263d2082da82 +f43f4f4f9070467bb127e45fed7ca2fc +2d2685a7e6a04a7888fa88ed1d6237d0 +87b4aecaf25a424a81f76d7c5da5b701 +6363fc4d6d3a49198c5d25d14798c4cb +d9f8a0c160124f1f8dff7ccbb6b4b9a9 +2691691810b440b996905ec5be9e1ede +141245699297480a92ce81711823638f +badd03bfce2b413f9b2adac9dd12e4ad +2a17bf7d6ef54f5f873e62648aa5c03f +542ace798af8420aa3147990ff14c1db +720e855e1b7c480c897b39b600a45284 +c0ab7ce091ca4f43be9dcd83eeba69da +f09e41acad4348678ef9e95dd3963569 +e6892b89a01b4059b505975cbde5c2c4 +f304e177100749f8871d487076d554b0 +3285064ced1d4e0c99490483d8f0f95b +58585e1031b0444c9d9cc000b20a2296 +f923538fe3034464aeeef036d2b6afe6 +16cb358be674479c8c5dfd4bd670a700 +6111eb8442464acaa71f9ecdf9087c06 +f47771d9c463458ca2310307666021ee +26a47b71d54a418c994ec43c0eabfa58 +e73ee22363e840d8bda0dbea094436db +05ba9b63a093462885c1f034b3eff42a +c661b482f5744ca18a96426b9a41bc9d +59b733cccc284fd7845db3ef660880b8 +bb89b709772e41a58b6a4aef9df3cf66 +57778343e3ef4f9b8771374427edb189 +7abd885594bc4b18ad1ea5828c7a45ee +e413b7bd353d4941ba71c548a099e0b9 +2bb9a12882154fbfa07a11861ff7e6ee +e60b0a1485584e24b63444124e7d8441 +418bc9b5d4a04ffabdfc65df242b67c9 +6452cd738a1a46c59f45d2f7d20bfa77 +8f0c86b33e0240b48287498dec4fb2eb +58ea4c1ceac84e19aa9c2863a034af1f +6b3511d87b074b5c9ded318720b0c87b +1843ce30f1d34e4fa886b11449d7e6d4 +bba458a4a294440b95c7fe486d3a3d45 +3b35271f1fe84fae895a0bdd998fac26 +5b5bc543670b4170a353e093a9cb2cdc +3fc2fabfa49048caa079837cfb8be5cc +d2119364f0c849cc9ed40ab75d7e671b +a2784d7b873242878faffc2bf6c4db7f +bbd0840ebe8f4fbbb427af537f6ea41f +ce810a7347024b6a9bbaf4c4bd6c6a2e +956745b6903b4934bb34b510c2e55be8 +025d2d8615294deb847affe5f5534f37 +f578ca7f91584ec6b416d57462b4d990 +af6ca88ada3842a382aea10163e875a5 +9c8f15cc1584410f8d77b069e5098b01 +b70a5d186ddb4e5fa2289f52a93db635 +74dd3cfb132c4f0aa2c1f128ac8fc0de +69a7c36397914b81b853a910b5d30761 +0733ca3da7fc4250ae98ac1b61ec1b9f +83d0bd23211f4ca0815b957e15890bb0 +d8cba8750867408e8bffd62a00c97583 +fc310b75f3944505829b3ee13ee608c5 +ae0002dbfd2241488a8d0a586925aae0 +e542ab7c0c8a4a38a1f8d03df94f0fe0 +9146eb43193c47f0afee92b8d319b3c3 +f753ec2a20c24063ac0b9bccd04329b2 +dfd73a55acac4517bf06b673119d205a +22a19ec7b1ed4e67a8258aaaaf16fd28 +df145d381f96431d92d1ecd137d2251d +139f5a778ee8447ba426bef981415619 +5c21cdb1255a4c0b8a5ba65d18447b9d +ae716fc3bfc3441482336e57898f1534 +e35b942ca87c402d8401cca544943ac1 +90d220d0ffcd49f2a705497bdb371006 +9d6d460348e6436f97b4a17864358d14 +d78e17ffcf21431a93486509a048d9eb +ecce7607953a44d29f7a6aa3254f7797 +c2bd80794a3947238fe610f5733be9d2 +93b56a66331a4490b71a17a158b352a7 +151c2a4f217b49dfa4207a918e865d8f +e92a3df021e84de2a67443d2ad4af9d9 +b1e936cf2b8948ad877d0f598b69b7c6 +168ca4d0cad641f797fa4edba00164a5 +466f71e295014c5d8d95363d4e28f5e8 +256158b91b0c41b599674169d07263a1 +4631e22e938940caa841d632246b3f66 +0838b73f246f4768aa0671e7b2ba7c30 +5465728bdb8f43f290e71cebfe2b7e18 +615d65e63fbc4d62a3e28e6fd781ec49 +eb700168ef994b96bc7865febae8c2ab +1f4f0bb77ce14ea098755c71fa5c0308 +16096057d0d844248280432f6aa1f0c7 +546a398c655943dab83d0d5356e44405 +60c2a1b0a3004c979fdb1ed1152ac018 +b319095ba4334b95b82979039e7c1bfc +fc5f7716bba54284884136ca1403c59f +fade0cb030a3493aa68d2c3f7cbfa09f +a19f140d3012463a87a7c08f1ee6d799 +aa4deab1d68245eaa7cf6b89373f68af +eec2bde45a4a4273b96cfdee89a752cd +8036c969bd13427f8c0b56b1ca0ccc74 +866d215989bc4d1dae1d50589dc3a7a0 +72037fd5c2bf444da41a0220cc345d64 +8b1319902fef43dc904a257a377d9676 +ceff8c05e13146909e648cb2e2ab6701 +def38e744e744c6387ff4e29abfcfb81 +764b0727c9a14a6186a54b99d553d339 +f73eb160bf3f4689a9ecd504c3994f4c +f432f5ab498d4bbe9f05bd6dd3e93051 +24531e1143904ffaa505db85df9abaaf +4174b22dd5234634ae9356da36b6b42b +bf5f86199126425ea8c3711e7e116acc +5b84834cf9e846f1b289b2fe8909110a +9b4acc4a177c41e984a0199c6fdcf90e +c0bf4b6128bc46fe8468f3b8789b718c +e94e66553d02432eb69233d1936d7f8e +61ca2677b5b8477fa7d2ce815651030b +b67ccc84a7da41faafb0f948eea8c1c0 +c94f3f61ad484e5f86a4628797cfea52 +0cb0a6704c8a4fbd967039998a9d76ac +1d14570a943e46aa9da2ccfbb26d2baa +3535fb4ac14e42da8ac71ee05a594167 +db3b4773db17478786595286215e3061 +74cbb7e756584e219dd22c02d0f46201 +978be96600a0434e853c938e93b9c893 +0fd1d0546f8e422b97a4fd5cfe959d2e +ad837c6229fe4a82a1a60dda23c8a1ef +da67896db37045dfbd88a468392dd8a3 +ef94916c83e441d483e6e3b9647d274b +08df70392658445192550202836a33fa +03860ba96d824aeb87acc457ca6e65f9 +b8dc103a4cf54cfb81f1854bf58fafe5 +e560092fc7cd4461a15ba5aa2d84a1be +c64164760318411588b90671b76adb9c +544b5c976fdf4eb3a65c3d90fc99faa6 +03cb72b336394c8c969f169e10238aa7 +6a588b5657994546970b9d6e5d37ebf6 +dfd7207bcf784e2597665249ed12f3ce +6d54fad228034db89b8db77a05516d06 +6d30ed5d244a4bcaa9deba4133ff6372 +0f2592d5a67f41469a3b79e8cfa14ab3 diff --git a/data_split/objaverse_lvis/val.txt b/data_split/objaverse_lvis/val.txt new file mode 100644 index 0000000..3caba73 --- /dev/null +++ b/data_split/objaverse_lvis/val.txt @@ -0,0 +1,1476 @@ +71df3a6e3c624ba483d41f51774ea7eb +7d34a706b55d4acebea87abbe2e67d79 +33f8aadbf27c486d8d4efca0fe21246d +8926486211e84e7299fba16e4fbfd576 +b6975f0b781d4e41a22da7ea2ceb9938 +284743d09a574daba26d4f04db4031e6 +b33adcd6f07247d492bb856874d3cf31 +e1ef0cd124134ab9a2c75338c8a9b955 +fcafeb1ca1d84ad4bf71222a430d8c93 +7549165f264d4c25a06aa2da9c8a43da +609478e556384cd290a005f64519e031 +0f9d8fd5d3c34ceb825fdd87bb72890c +e75eb7b074db44e6bd32cd1d2469ad1e +8654c66cfebe43f4a14ebd24eb446440 +b28776c4f88b410a971f118b6ad07e32 +7afcf5cb4cb3423d98ad4e040df15044 +cc722e18d40548a2bd67c4c15cd17681 +5865959f730c4a9781aeb853b1db4861 +528252e7bd034e1e89f976adee6765d6 +f4f0fd05ee884db1898fd7c0aab57711 +2d27c6908c6d44cb8a624f3150ec1fd8 +2125c39434ed4b3696bdff0a0bdb6fb2 +6b137d98f6514ffd8a2b17954efc841f +f2a8992ae59c4696888ab0fd35a22ea1 +841101b9ec594552afc2b97383c386fe +b1dbfb8ff4d84a4cb5094772262e14d7 +2d3de083033642a0b366e90175448d66 +8179436ddc934b409efaa9abeb906e1a +4b32888874f842dcbec22dafe33a3d19 +ad3f2d78ec4848c9ac85bd9808ab304b +3108e5f9977b409bb46d5b5dc7a3a452 +35357e68cac1416a98c041b15c37365e +d70b862f383649cd94901bc04f81da58 +d912256c534e4a0b84b94ac1b6b272ba +0d4169812bd34eb29b7b6f17939841c0 +ab2c61765bfb4081b05c51a54087ddb8 +5e0d899bfed9431b8c1e59b9b541dc90 +e8241c085a6841ef85ee6671c4c0bc5d +c4f6141878534efbb2f0add1c4d99d27 +4c1ed7c7790444afa96de8881a65f04b +44b551a7dd8e48b8baa623faf8b16af4 +72df9741d1254c8f8e30742a118d6f1f +197dd882a69846e0825e80566996cbba +158fa71ac6f940d8a92d1a1bff10acff +6ccb03f85f284aabb7d89de7eaabe76b +51423fcd3b9f4168846902a7d8cd824a +0a5f52a298864b20a290fae141c2791b +a96f627b4f064580a8bfb6130118a686 +e7361ed3cc754135a0cd66101002471a +14cbf975ccfd46338d39cff250d91c8b +12b0d602619a494a8b61448194641d58 +6aee1290c4094c1480e32284e41471f5 +d5a4054644534737aa6eaa40ef693c8b +926a7987d9b04160916dc4f2b9f0efe5 +852927bae6724ff9a9df05ff36de2dd9 +8da3dddf0931464cb3177f55701b46d0 +9970c928900840e182d466d83a7e56f8 +7b48ce1b7cba44bab337de2701f32296 +6e7ffb6c00e94f6485efe5e8a406e2c6 +211ab520b68640a883ed9e2829f9b49f +7b18c069265a4ef090f2b255c62fbef1 +1c6b102d35234ab0bfc529d166e64c5a +a6d92daf52a44e6db5955506846953c9 +5bf0c824c2a64ef8bfe62b6d346188d6 +8e23ab2bf1af47438399316fd66aa0f3 +30711b2ca5414752ab2fda0203557fee +cb864a3768bc48938496b1923a752665 +a6cd451fa7a9428099429ad5225b1f77 +cfdec705db9341b881cd95147793892e +60e58a541bcd4fb3af6ca8c7d55f88a5 +3a9dfff4734249d99c62eb925ed88080 +507590be54d44703819bcddcc061213e +c268c7c7eeab424aa7d01a92b0e4a937 +18d603a1f4b149d1b232563eba466a8a +c47f0d68a38c4c1e9a7c3010b0820528 +69d0a671024e4928a12f5ee0d655f0a6 +1a4bcd31c5a2408aa93ecdac424e9e4c +237d72410cab4732ab98446ded360ee6 +9fc13419b7df453d8dadd1437381d390 +34f8f2779f7c4b2e82954118583a5fb2 +6ec82b946a4e4447bca511daa8e5a7b9 +6712e5113f4f4a60af61beebfac606f5 +759487938f8d45c4a6ca4b90822ee430 +32248c4ec53541e18c5487e7273887e5 +289ad47cb8914bed868e256d5ddd348b +bafce5277aa84954935da388ac423dda +bfde241c93014269928af8191f831224 +ea9c0c4d033a42bab8768294b392a85e +d9176822f72f45f68a3f65e369fdc9d1 +659d124e115148e7b7605cd1129292c4 +dcb283e4c48a47dfa70e7844a89d82ce +eaad95f996b749fbb7310c0cb4164e12 +de23895b6e9b4cfd870e30d14c2150dd +f2828c5f3cd543f2a7659f0d8d10b311 +2dcf8ac0eae145eebf7ea780c9ee8b77 +84a87c5e5a9c45b4882e841885d445c0 +473d3302496d4c62b86a5ad31f7aa374 +42e69ce5d2e947dc92fb34fc36dae4ec +796d74f06af34ced92f2085f660c17b7 +4e80cb5cbfea4390b8332e2239e769ac +6ceefc3cfafd45ecbccd9e208599d0c1 +a5feb56f36514b8fa9766d75735ff785 +502935649c254835af228163f5285179 +8786cee0a1324ae2a961f534a5a4840b +b91442e818154b54b507fc915475fcd9 +7bb4fc1414f245c3ab37f63e68593c5e +458f2154d1cf4bbba3787aaecf5389c9 +55fc25d20bfb4ba58c2957da32be0b46 +73d7b6f9a0b7410b945205338b090566 +a77d9a22ca964a71ab23519cab124ff6 +ae8965f525ac4521a3a5cdafc396101e +e3a78e329e7d4050a1c9d1c0bd19e47f +b0b5682c7a5d42fcb32faba1a55c8334 +e69e99eb82084c2cb45b35f21f929d49 +41428760d903437eacf2b4c73de73c75 +c17223df6bc64761aaab67a0a68296f2 +a33223313b554338b0dd395494bbd808 +9086ab59c4cd4ea1aa023dd16df8ab00 +33d892859ab54cc4bb41c9a01a6cada3 +4716650057ad40cc9610998ff7dcc725 +3edbd8ffbb34480ca4876aa5b9e6f0ca +6e54a7d3b4cc4917a6e40aad4ebeef05 +2edfb418a8df4051ba7258acee719e19 +b5b41bbc26a14da196880ed0d8d7285e +6d88456182294edeb190ad21b9847257 +bb34b711af314571a311b9186d570a39 +c1d790c39dcf4ba2a9a47b4c0dc8836b +2a614e2187e3416c9e0718b09f5f9927 +a88f3cab04b54c17bab42ef35f44372c +5fd7910daac5432db0c03770ceea636f +cc7c7d05ae2f494c8aa4067b5c556068 +d465c7533ebe41acb451a2d8deffd70a +e3c9e323f01d48c7adad038f6085fd98 +44e30921ff5c476c883b8063d6c293c5 +663fe416f86c48dd97e301ec50a7c5cd +f0a3a7fffa2f41ceabdfdc0b816fa662 +9247e928eab8480f9a202551abdf55b8 +5d940b4af2634153b14c9a0423402ed3 +31acda95fdaa4470b2621df3b9832fb7 +fa7abc1ab50c484db3323ccbf7f8514b +1fb443606f5844cf91959e4bc55c0b6b +45062a04f38f441e8dd626f91f17045f +fddc6b76b921419da88c5b8951adbb1d +486c58ff94504aa68d62372e4b4faf2b +d098b20f4fec45e0889984e557728cf3 +a13662e9a21e4841982903644096d34b +b4da1f80949746c99ca637de9ca40786 +c6a403de625f4a49b6a162f8cc22e0b3 +052e003ffae8401fbc6746f933a562aa +a6e69e07c381482baf86b59f0f4446f2 +b916735ebc8146a48ed3dd502068c591 +9f08de24973b4929a7e9231fa4c41f36 +b690d85c01b34e0cad6ad27cb582663a +c3170bfb1d0945f8b1c647afe1448904 +dc09459f51a74c1a942a1c8954fa3376 +6f98c7c8ef0d456f8ce0a76e406c4696 +8e24a545ed414e6393d1ad02f4395faf +9166b13b6ae341f4bfc093edb71d74f4 +e84989aa397c4bdfbaf6629e78eb3ed8 +49d6184fb96d47e8a39d126c622615db +8e689f15a8be4af1806c8165c6f0940b +2aa8947b216b4da294abe28ab1dfecc9 +cf76654347ab45a883d8906f1bd15c50 +88e4cb41e40d477eb8edfacce721cfc3 +b0aa0259376b435fab6645365a7fbd87 +03765a7e66374ec7b3fa18749795189a +fc24cb34811b42f2976e413939cbb08b +46e0b2e911594c699cff8a3cf533ff75 +4217e81034334e298d64ea673e7ba3f0 +7529a61d0cc043fd81ff986b8a8ad784 +deb570767fda4f24a6700f9106a616ae +36169306aba44a54aa55ab440d98200f +23b2d0e81d414836877c555e5b5fc18d +11c329b74f8c4b1a95e44d8c475dd452 +e1eeab2a570d4c2eb22d917ea9806d4a +de15e5fbc38a4ea8a367e3c4b49b9080 +aeb46a14b5e44f63a879e8733b4f0dc4 +51539bb92b8d403f953412637f39398b +4d2721bcb6e34b6f9e2fff7ab3707888 +1f7480b382d748bcb063c456e031f9d1 +862e46fae7604c6eb29f31544bc57c82 +9fdefa464e9044dca5fb5ce5d2aad4dd +4eeda6741c3344e3977530dc78eb8242 +5670e755313d46fca5f4db1293228921 +660a71e0c4c647748f927613a669a233 +0f1e001321bc485da2aa4a3f9879ca47 +c076c78cc47f49cfb68e24c8731d60ed +a05dbf30fe1d46b397c91025b075fe05 +67f4626c68074ca68568cdf29da47192 +8ebdabed48ed4963887435aa05f0b874 +65290c71cbc9426cac3b1a852f6514d1 +f43c23c42e9f4fb49c46a761ec9d8d77 +a64e1ac7f8c44821bbc365f0581d95b2 +9382585b9e5c47999f83ed9658f82dcb +423f60cebf204edd9cb40a17f53e32cd +2f64382e6c664df99b0aa2ca55c760cc +9b0f5ceb4e6d44adadd185932836171a +7ece989075a34708b69bb98b221173a3 +5479adf1797b4ab693b899e8f77d1423 +ecac37c1416c42aa940b7a935a1aadbb +937b7db3cece4037b4a0383d35bf3b37 +84fa9759a05d49c3a7e513953686c322 +c897e6cd6b7b4631b43c0a98469dac17 +588c197060cd4bf7b41d5191c7aead3c +ccba4426eeb34603a1de87c1ffcdd878 +27bb4436b0ab45abbc2a152198b7b885 +bbf60a0c1dfb4181ab374b5260616ec9 +2254d3c911d74f9a9c5386e683c6ef85 +0d8c95eb3acc4da29543dd8c8ced2688 +9f7328bcb0fd442d8943ab3c70c94133 +777238e7561a4ac1b2d1ccefd1de5865 +ee6c5b5255ca402d9cfd95ec6438c50d +2592cb40eacd4cafb35187f963dc889f +da2a763a51d340da8a3339414e44b8c3 +4d29f717981e4477bb3b71e712ea4d12 +59575e7bf8b74f4d8b3d38e26b34b603 +96f8d9d2728248008ab2fbfec4868b22 +282a990de8e24cdb9ba9d3aa093670a0 +6d1a66b916884778955a9d3f4e67ac5e +30ccf8451bd24578adeb9f8d124f1553 +981d39610fb840efa2a4a1913173b049 +f9b4af38f22a495ba2aeb557cea6158b +77d7f7bdeb5b46b89c6ad422457e396f +0680623e5d4d432fa1732446e609fb8d +f07bec578dda4f7eb84008bdf74a6548 +469281390a4643eaa6721218576f1c94 +9b04e85693604daea5c1f7ae41b85472 +afde31c8625943fb850f2da17f63b5b7 +a579862d86ec4e6abebc9ee37188fa7e +dbfb6e3ca44c4e8f928bd0a478658cf3 +71b5d87275584524aa112f25c7227918 +e8196d182de94b52914ee491d605f971 +fccbdc24b2f14616ae62c6d880cc7656 +0a494089e6954a05854a51e9cb473e4c +dde20601f2cb495f92554efc9843a5a6 +d508a95039a747d0bd7e20bca568a61c +45bd80f76b294b4985b76f055b7f8d72 +e2597b4355ad41a19017dc9745bcdf5f +97507caab9064024b9ce604bf83d0fdd +dc352fcadd69463cb0a99c61b21c3f5c +ddafe31848954376b38860fe4eeab01a +429bb251fbe844e78d03d84af8a38f23 +fd4851d6bb7e4738ba9dca10029e4f7f +44d4c7045eca453b9f225e20bfb0a955 +46e64593c4234183b3b00391fc960415 +4b783fa51e474bba934ddac207003fb9 +4d4225912d0c4564bc70f2225abb73ff +b16e5e1d884b4ccf9a1e065ac4b06610 +f07d483b876f4ed4adbcf81d8b0e7123 +d76a2b77e7074339937fa4e750d10002 +f184be17b4b2499abd51edd2bceac589 +4dc4fc2f96dc4dc08228f9d4445f1de0 +36741e7913334f328f97f7e80403d9a0 +3c6737c169aa4619b9a00e4ae90a9624 +d571df5e167b4102a51a964fb6391462 +52468daaba3e42aeab6d891ed90a3cbb +dc527ed86ba94586a20b8d5707130bba +3cfb22a556ce442f9570a64a6df31cb4 +71dc9cf06f5145ac90321303ff3f22fc +3d3e6cd1ed9549c288e33de168e7cbfb +ec4dfeb9f3524609844caa756ad93400 +14fe03d792914d51b6c6250b393c44fd +27191d78da6a41ce847aa634ae270b25 +ca937e7fe03e457f820eda8a27157b7a +cb5c705cc4bd4264a3bcdaa6355f643b +68e164f1a9414c29820ac2eaf6d8ac04 +c5f828cf2c52461496a058f590e26cd6 +6afd7a17e1384568b50b7270be20724a +154d951f702d46289878b56dc9f42a30 +f6b42b83687d4a809bff6269d49ec9fd +0de1fdd544c3438094edbbe1b01cf391 +1231d4a31e6c4e64845ca1fae0cf0450 +eb7ce2497e9c4f49b8facff6c9ba02b2 +e8c48f47d2f540618a117265dd7b9374 +f3994fe7c36948fb8cf5835e571b14f2 +86ecd638c8f841f799562900b8b94a51 +cbb82162cd4d46818e7815d547d73edf +ed42b058fda84754b4a4ce96b17bc91c +ce612acd03664358a5841316e35e0db7 +9c7421fad3c9482e8af52adfd97c5a5f +ec3e105d98e74ed4949ffe7c1cf1831f +72fc2f9279dc4a5bb76652fc272af184 +4387c530b415411fb885fcc30d3c4a96 +0ba6c4545fe14f0d9b8406ff030fd042 +f299834a8803461e8a81785c32b4b3e9 +a77921ba3ce244739e838429eca9e427 +5787863cd2a44e288d952a2dc455fe5c +2723964fe02d47ed818373fc311a09f4 +10a19cf4a0e9418389e554ba6426dd24 +9b61dfc7cf60428a834cae9f6d5495b2 +d968ed8ee5d24c8e8eb6338a2d1af88a +bf1d1a63b109446eb20c2c08b1b56e57 +a7930393e1ca408bb5eab9377b5873dc +f990595ecf5345738974b7bcc98d9c43 +f30a5e6239eb4d46916c0b5c0842cade +616d4017a9a94f1a83f90c3e6f535316 +8870b9e07f7c41fe9f4ff44d27b95cbe +6fcd4ae9f82844219ec465b49d4b69e0 +e951bbee28f148268bb4a534169a86aa +97b89d7cc77d4883bcea9d4736a8f00e +288a572dea614508a86c1742e899f917 +e70e0285fe1145228f5476f387129abe +48e4219341a4458a83c443fb3f0ff8ac +ac17d6adef4f4d6298716ff7463d05e6 +909b3f198d5b49cea3f68549a8f57b51 +4513f37e409642f085066f1470b09a25 +0c1ec94dcb5e4c7fbd495ed41087bdc5 +5e16fb6d27a24a5a83ef0b6cfe7cdd54 +58710cbfdcb740288b432998c140920e +7613cd31be404757aa0003643ee8f794 +1154c61009ee4dd28a52c06aaae2596a +e45aa7131e084849815c980bd3577e10 +5cb53bef00334e9b9819b1d5d2a051d6 +f73b67a17f9e4c698764fe2191803460 +602e75e0e08b4c8b80bf248581ee3de7 +ecd84640bef44237b1794d01b0f6d78e +c2802c9523e04bd5b1bb6f974e69451f +a5588c0e88cc47f38d21d6d345f891db +43327a074274479ab5e908f7ab610e6f +3e489f11f182434c88a3ba3de40a7a24 +efa711534830453f8420f84fdcb8a85b +4bee949d883f4005a8774d09ed3e2273 +6b59ae346345405290e6b4ab8912e2fa +7a35202825b446879e9a208e73ba18f4 +6bd564e520994c568488a685750d67f0 +bd681cb6124543708eefefa13a6c25b7 +50e8f209ee1b478e996f54b707c38715 +34ad91c327b545f3880367db1e25832f +90853681645c494092323583f1225a56 +1cf0d8795cf142739de1948f30a18a43 +24b90c1ffd93430aaaea2975ddec40ec +4c302192035d40e59b7c0f18bb74f212 +8bd6e8b9603e4168aa3e38d299f28595 +2622736aa0e84d93be7f38137110450f +837d98d8a77c43ea8ac1545fe022fa06 +c1a25a085a4b49cf85e9dae653d6d9f1 +a60e10dc03ce41b88c504781108e2279 +2ebbe73bb3b140de9b74def3d580c30e +f491eb62aaa24fdeb6dc52a1aab54d0c +98c4a9e2634148aba741da07d0ac3812 +8c7296a58c654a55bd6b80277f303e82 +23ee8c55da7143d59f1e0aad1b20be8a +8f487afb06fe437ea7633fd1974effe7 +9408edd069d74261a1093ddb1d5eb6f5 +d6f22918440544dbbc0c35aa796be84e +2429b2c0ce644cacb4c7ed7fb8e026d3 +a80875a2054345aa8afa79f20dcb3ddf +4556005c389d496a929e47f008283c3a +3cab709105184154be74c2bd6eb9ef9b +9ab69d7c4e0848b78b9bbf334bb98c91 +c6632441a5a14ae89c873b68706ce2cd +e42b6a497d484cccaca4d19978b8585e +1182b3f562bc4a3aa050f4c5791cc894 +be15ae5306b64e988ba2e3bb92c16dc5 +d504e243c2b240919fa582869fad12c5 +5139e2b96d2745d19ba5148239197d01 +f7fdd802e0bd464382c65e5aa8889e1f +4ce98baa83ad46e3a9c7778ee6c47270 +9dc20030bab04ec3bb80118644a0ca2e +6142a5564edb4a7ba1c948673460afe0 +f36087616e7a4205b942dd4f4457c9d4 +a38c0b0536d345ee86c883c931ad33c8 +f79f2bc987f94c9ead02a36844e7c48b +a755d0560236462faafc6ba391f0ba8e +013985cc621f4bdd9e16119462371c16 +5f7108c70d6c482c99ddcba2533c1e87 +665ff23a1a9a4c90836bd5e7d3d8a4dd +547287713a9a423b8fc953e047dc963b +fa88ade285a94eb5addfec93afcbfce5 +fc53dbf2b8954f12a1285355cadb4f99 +d21894ed7af24cf2aef2752ad5026dd1 +50db8b27c1414717b1aed8bd48ecf88d +2ae974bf45a3436c9d2a6d5e4bdca385 +7511c04cd6ef429ab354520485dd2bf4 +bb182cd70cd244b291ba0e3020f132ce +362cbe01dc734766927b2f4b50547a58 +1355323d390f4daa8f5f966aa178037c +2520483410b94f6eb06f2c3ce06fb0df +2859a3fdb9a9423aafe0b031af8ffa81 +a2fbe74abffa450aa9fec1f807b80904 +90187a70ed0742a7ab40ba27ef7d9539 +56eb5e56981f47f2a7ab4681c6636055 +33d13523ca594aebb62f4c87e400854b +e41ce871202547039f5a7a13f7b0d6c7 +e8c88d1bb95148ac8ae1fea9dec091f4 +8b04c72222984df08f545e5533e119c7 +38baa418ff3e4f42b5b71c82388560e6 +4bdcdb888f324c7daef328f9c6b84de3 +108e2769976840738db1515c6346f1a2 +d6cbe450a88f4917930ec3a144485550 +4a13c0429e35454391c9c79a1361caa1 +13407a0758804fc09ec4c7e51e9f9d0e +353d9e6667a042b5b086302f1309ce8a +b998ef07bd064100929c48b2450ade45 +7ffaddc5360e42f1a0bee75b4c811dd7 +0540daec5ee54e7bacb3e346776be39c +96ef35ea0f4e4a5b87e8e91722f2c36b +bd41ecc23835416bafea042d6a01a07b +c505ffffc1524865ba63af837346f1f7 +856833d6b91b4af4bcc5a41a941ecde6 +d209acb0152d476aa7c1667c1b6a98b4 +341eecd25e7f4914a6d321e71e5629af +0afe33cb89514278a88f626a04c3e546 +0e89da693a494bf98c717fba30a3676e +06b6504ca987450e871f64c77f29ab34 +40294ffab14b4802bc1c0845d30d6384 +3ea0f9bc15e1459ab659ee68037a8ad0 +3ddc447760594bc4a18d56c4916e34f1 +bac5fb96ec4345348ad530b4289c648e +8730d9c5250c4fdb8c407e61557ef825 +fba45572d694408188924e9df9468cdf +b4ed18118f2249b2bb28af78b7fb7a1d +5e0d9ffaf6e24f7798f0dec36c3f3fc6 +b9b3c597f1eb4d1c916e7d7d0cdc7754 +49cdc200eaf640489b99ca818165427a +6a102f4e252648ba9f868dd9e3d8ad0d +4e981994b487402c92b5a760b46aae82 +91902bf766224adaab7884b6136f75f4 +6e329d48dfe34854b89eb40e5ee4daae +eb7dd0e6e47a466e9151c63b4a7a2de7 +c0ede25790c64bd1a66d9757451bd8ce +90b65fc61a5b4fc5bffb13c951563951 +6e699f6e9d564bcda8afa3a1b26bc43c +6e35f6fdf1264db4880049b802f18ea2 +a30d5571018741439c99a17de18c7287 +172d8db2f07949fba8648bcb74ef064c +b721e71976a54715b43edcced4731533 +a064b7b98bba49b0a6744327c1119232 +f87312427ff9465eb9381c131cd09320 +c9f3a5192df1405090dec2e3f325344f +cc812eaa7c9f4e81929d6697a03b22de +cace4f8d3c4846faa40796d883cdcd88 +936fb087ef1145cba51974db9a73d828 +c678ec2b4d224e10a1fecf0c5e9ec3e2 +7506e9731f214d37a2498115de8f7623 +03474c14b2f046cab8c6271a1a013bff +6083670b853a48308dc1f62bc8d194fa +a848538c7e4249a4af8e86c477193fa1 +a4290c10749d464296659c34b5e109bc +503981072cbe456bb42dfdae1e27da6b +5ce01ee7147e4b6fb22d0d0b2732c9e2 +33d4fdde1bbb4a6b956fdc6ec2b3dda5 +07121d29537c4c70bccd4d02db6a6466 +e7945f4a49f3491380cd547e9c0b5195 +54635b0503eb42b2acc54229b221f42b +8ea717f32b474682b747fd397b34a271 +6546bb20aeaa4ff091fcf6cd4cf50373 +d14d87363fe44571854ea24b9552521e +f1f3132a87854e688a2068a079f95e75 +ccfec74015ce407487891074e8d65a50 +5925aef2b8a64539a6ba323242da4db7 +d38ac696de7f4506be4af16a9b364bfb +e346dd27ae8f41c2bc8d0e756d2d1913 +80cc44761a294682bd998b5b17287c8c +58874dc37c2e46088cfc1c0601c7e4a1 +c2b5ee64fbf64dd9b84ddae3521018c5 +f11413f39ae34684ac6ecbbbed58621c +7ee9b111c5b14e00bd7438578ee49d87 +2fec81b19797471bbdd28848751b2aac +5348e229f87f4dc581cfc4dd84aff2e3 +2ed4eb60726e404f846cb4bb52b87a75 +b115a450a05f4270a338a2ba280fa50f +80a443a0f64a4ba0bf4800e10dc3a37e +447208fbeb204949871667daa0de7ca7 +f46e0f9d7c99466994806b5b893e6550 +ad4378111a304560a38cc3b95d0c72a6 +71e9895cf75841f2a1ab1778861f1a89 +618248c268494adcb71c9f933b7c4c34 +104ac40ef3ad4dac8079a11548c470e7 +f69488efaf50489cbaf05de717ef35d5 +e4399b7dada04f7ab837420d8051a965 +8f0e0e368fa9401ba93e5ae2f7703335 +69569b663c3245afa2a14209e9c665d5 +445869b3117349adaed1639cf201cb65 +979b7dec28df4db0b493054afbfbad1c +2238fa39a5ba454a82a5b45070a5679f +8b64ae5088bd4f7cb806927262403809 +da81dfb3c49c49f7af336d686567265a +6bc9fd040c3c46168c1a2b80e2fc4b9e +e92f00ea8d6a48d38d591215142fa576 +d02ba46d170143e58ec7f9e4c7edb09c +32a8e1f2186545f79a572a8307ce72ae +858f8c952ab74dbd87882e043f78df03 +ae274daf47e341a6bfddbb1b47e73f58 +93eefe10f4f648a099e0fff7954c56b5 +3f3e204cb66b4189a3c6a7e66b4d27f1 +3ba1d322cdff4123a8e5e379e6fb7bcf +9da2f6970d7b4a68899c7323a21b3f71 +99fc178ecc0943ae81454a3735e2eb5f +1af68ba2e4ac4aad970612b6c6b5d07d +64e96cb6e1a142628b31a2db98f0ff45 +fc89fe933afe448084682263a5d0f10e +1850c472a3b944e0a1ad7c1da2ea14cf +b521c9a1162d45d2b4f138206e114fd2 +e7f6ffc0546d47d0862fa3afa1ba1004 +03123c98faad46faa39cb7d5158624ce +f64b5035c0ba440396b17ef73963ccaa +8c6f5f91a5b94051bae5d3be0937564a +a151a5305eb445cd86eb8838ecd97e69 +8dcb53d1b73841ddb6a1122220870954 +816c99db3a9745be8deb0b716be822db +2bd4697eae874ec581981dd7bb12ae77 +de79a920c48745ff95c0df7a7c300091 +f0864db153a3416695e681c575009daf +912ec0992674468c85ae5bd279bae5df +ca53ad389b8148bc8541b78bc2d87b8a +1dc9cf9b1e214359aedb021d1467f5a5 +967fe04da5154c6087dd1b834cb563f2 +e386f2abfefd423b8ab7cb967d79a200 +642321173359494899e82e1f98a41255 +a6a22663852845b89e48d232003bd32e +4ed1c284ae05448cb5131c20286301d9 +ea2f77aeac0846768778a114706eb92c +eb7e13eebe7e45e9ad219fd653bc6bfe +ef2a55c88dd445dc8d2d798651270557 +4482ac8c3ef64649b62d6f89369239dc +4d9e5cafc8164ff1bdba1ec4ddcf7296 +e31273100d7946a9a8edd0c6fa645ff9 +e15e56b956784ad2ae7c5e5224513445 +ffbc1f59a2e94267a286d460f948632c +0bbe1fa4b2024ec88b89a527dfcb74be +c64bf5d0ad644ef3993087a81cd4d013 +016faf19dae1433193b2792a34e6abdc +79be0b8b6278443a85b37f82ab426753 +1407b593b9e444fdb304085c423fb833 +373221542e6a4dd7a1797d603f171f4e +7c970353b8ea4a51a8d63cccffeae198 +95a513b9276b45809473224e88257a55 +667f789657074af1be75061cc7dbccd3 +1aa94c9127004536a5f2b14f9743675b +64947d2112e04f429884f7293f0d552e +a59d227991764b6f92664c98a032abeb +8e5838871a154b63a1000310887b0062 +8bd6eda897ec4f86816fbfe8616b041f +4d105b45386d43d0a78d9f0291d14e8c +096f3a6f0c11495a944fb7cf523318c1 +96e96772a7564df0b417244bd2be33f3 +1bdbe7ea2e5242948f6cd7cccfd7206e +808b2c0c11bf44c983e8b8c787ada844 +f27c5bccb70e4b49b7b1ebed36553836 +887879fa3a7642c4b1b68ef5dbacbca7 +295bc0c1ab4c4153b1117ee31a220b84 +e2c6a19e13db4a5a84a2ccf3ed41dfaa +5caaa68f8935441299c6ebcc2a7be4f4 +bf7902fb64644da3beb0ce1fce07f4aa +851d404f71e14d34b78996097928e126 +8a0481651bf144ae9826c3fdb6515aaf +962cda5a75b24554bd3b3c53b0828ecf +b3b2e3d24ca54f888c8c453e3611c255 +4a6cd8d53cbc423da9e33299f4263aed +dc1fe22f12f94049849654973a833cd2 +ea97efd2bb004178bdfe14e577ada72b +7306f0db4e824784ac90ec5de478253f +848e8db6ec734f06ac3920b58905b176 +bf6da7cb248d44eab09f79685fc204e4 +c0d363d197ba450fbef08224d3edd3ee +dcca5c46c2284767ae15971cc9ef29cb +5404f764e6054d83ab563037d6c3dabe +11d5f3da2f004f15a32f18c0fc220ef3 +7c442e696c96455d848d964e79e29464 +d3a17ef8e01a47dca84d44f543c97f35 +c45145941d114c85a575681079c61aff +25437ff5ae0e485bbb4d9e0c8b371888 +977eeff67a6d41c39d0bc5dd96d71e1b +c55e69e870624639bb21edcea867bb47 +47a1ecd89f7b4fc2970c767f7d538575 +bcdba5f7681344cf9b01ec8638505107 +aa840004cd12489daf8d8f5ca0fef013 +bbc60236960d4569b9d160e30e08278b +ed2c74f57f2f44f78361bda1c0c0952b +73a1eb92153a436e8332cb42bf0d4d9d +5582e8bac83b4e9992b3a82f1f9730f9 +b9314f3e47c642caba886e5e8b361b2f +3c8fad41a4d240d383cc123efcdeeb03 +e0de07c5feeb4ad49c12505fb088dd3c +7ad5a7d350884a258a7326dfee5fbf8a +fb00fe823303424e945ca4e38611e1ed +6c409a59f6784d778d9e844b78e7501e +f245dd2b1de342d188e5279020e84108 +3da0c91738b64095bb9c0d987b6b5b57 +2dadc239935f448688c88ab0d6fffbb7 +07161ec7fe8d4bc3b625efa33c1bb23b +b5e15bb0ec0c4edd88ae18dfb95ba6c2 +ba76e2ce6a9349e8b688ed7dad25d956 +18a7bc41962748aab88ace9c70b90c31 +c0000174ad6749a7b0141c375188b710 +0f49e27fe9c54065b9d1d1a08ff97f46 +7cdf0ab3d55242858dc9e728501a4c72 +7363fcdd2b644ab48d565bc7f1bf9972 +ce4e12ab751245e28819e9c8d16ce4c7 +a2f8bc5830b34a67b72ceedbe009a604 +ed7ba64b6e3f4a1b8b253a103fd38162 +668f8f1a408845fbbee93abbbec9abd7 +7f71bc5fa77848aea9fe421a2f2ca75b +37e80e6bb63947fabddfc9d5e5d921f7 +7f7d9831de524660b6e2428ac19a674f +ac2d1663b18e48be9693df967aec45d7 +9ebf8e7e34194f239f3b03a19f5ebe73 +d1ebfb01ef4d4f4ab5dff2d89ab21518 +0068a53f561d4dccbaef45841107a42d +b0647e882fad48059b176301b26d8475 +50d00dc77b8a493fa447235da2ea0c07 +bf921be3173a4c5ba5acef7bd41bd884 +ae2a720d078943de9ada08566f75a134 +e29cf40550774d1cab924d435f0a5b5a +f83a6cd3f3534a78b35e1a3490a3ac18 +960983ccf5c4467db300007d01ea6b8c +2e10a793298347439452bd8d99672015 +31b3d48ddc8f4b40a4099647fa016305 +47d8188ae1f4444aba571be0a5514ab2 +89d1fcd0ec0f486c8fc3e5d811a1fe5c +61c3f9ddde03444e820ff978e2622050 +3fcf56927ec44ff886f67a17be2538f2 +1702f71e798b4cc794ec12f8219405b9 +eb7e97c713e6470b9558c543300a0f60 +c431b92427a94a7d86c1e2790d94a798 +50ddddb58d01438e871a988d00930fb3 +29ea03d0fc854638b8f4ba397bab778d +d39e8f677eb844e9a0496830981a3603 +65e304546cdf4740b7d86b35755242c9 +24a30173a4f94a739c99513645e0d6f8 +8fd7e8f7b2c843fc94dc39808fb8e57c +e568bc1734aa40f082536697642687eb +8e1a9b000bf64b3faed962da7062c9dd +b625c3ccda8145fdb011ca9d0b00a5b0 +99be4d96aefd4a7c94bb3c92de11598e +8ebb8c08c9c041c38e279c0b1d5b5ef9 +2a9c2b23a4124fc29f62bb1ae2e522f6 +76be91128a544ce3855a1fac20e266e3 +bd4c17d17c394c688cea2294bafc7594 +9a11723f3e0446c2870187cb7e5a9328 +5232ae2dedce46b58cfcb41171e7c1ea +429536ff8dd84e538168c17ce6e82e28 +8aed7ddae831401aaae5ce30027bc4d3 +3242391bb5b64ec08e18c1dc9ab7eece +1eb6214373d64d63ab6770e486040176 +347a5f42b24648efb7606a661ac71a3f +05c264a8c6c94d6ca63993040bc2b2b6 +2190b03d39804f34960aaf6fcacced30 +24bfc22fd52f4a2096ea76bf3c759ebc +5fe39851c88f4db5b343fd38ce8ef4ce +59660cc5eda14db0ae4be27d3b5af26c +cd9cf88f219048b9bf20fba0785eb747 +4fcd9b8fac4f47ca935c698827b89621 +ae214be8d5984abd8fb04c9bd1e4f444 +91f6cc06ebc14e968a24da0f64bc504b +a6fa0df7d7ce4022b7202a9334a59763 +1c0092759dfe4182b952080ffd404071 +e8355b33ccfb41ed8d668cf4cf0dbd80 +80d392ba1acc4d8493c2a0b70fd5831c +b1701344f07d49f1b9f7cf0ff61f9295 +0456a6cd25df4305835e22428b2b57ca +b1339e4776284c2b933b01628cb5f5c5 +8428e4b19bc6488db38fa3f18963875c +c78071fe7eba49798a751fa07d0ee0fa +d5d7f7e111464dae951fdbf9cc7c079f +8a5b92a5cd9b48f9b3c471b81567423c +ea1ea4d5847b4550bc58ef4107df6f94 +150afe52eb8b4de1a6906aab3dc9eed5 +98428f7919ec4ddb994790f4b2af339e +62c046fe80614cd09d66b792b7947569 +8f741b9b5c7846818a1cc193be7722e7 +49f0d23ea8a94485b1497b1d303fbce2 +c22bd73cf8d247b8b8e4ed6fe23d52f6 +e5449c37bb284598b6c838106f925c0c +4ceb76440e1e4825a10ff9ace48adf26 +93c594a9cda145a7b799394860d542d6 +111366aed5b547c5add63937cc4b99e2 +79fd2a0b4d7647c6a247eaf2714e0693 +c9f7688b9b0d4e2ea8e660c2b08de980 +4afaddf0129d4aaab7947116bb1c89dd +1b89502851754885934d3857e0cda3ae +e8d19ae2e41645dc9eae55c9f948b34b +c6dfb019a1d44157963eca4ef5e5e06b +b185a4c6ab3f4c3eb87f042cad633cf3 +6f7c7477e7ba4096904b7fdba5aa575f +14442dff0a4d435dbf83d8b29f817f80 +cd4e1bd4e2dc4db6a65bb60fa5ee5b86 +9549049a459b4ddb8678a518468722b9 +6e22216e113641cdbd0d0588ae4dccce +79d2efd45f6c4782a822e693e6d50585 +3cc04622c4804587a9af5321beba2725 +93bbae4519394c2ebd6ce3e279078ffb +2258ad546c434096aab2822b8cf4cf27 +142ca651880543188ce9a8c3bff274ff +628ebafb6ade4c20a193fd51d88c037f +c0262529e44e4a30bd6b2935d8bd225a +1fab59b932464984a5bc535a7f67821c +9122cf9b31db4ecaaaaadd99a5db0625 +0e09d9cd2efb473394e8977c57fba0f3 +04b870f441e848cb8537f931749125dd +f1b4f7a525d24ea9a49b80c5d5969785 +3aae0c7c77c24b4b99c63f05be02d808 +29b8057ccbe34e92848ce364b3a555f6 +c187c6855fff419eb360e880615eb91d +36a862a20e1f4eb9a1655353af4924b1 +13ce0d9f07d64ee9a9a70fb29f02af82 +b8dee2c7c5ed45d79713cd74df8268f2 +767a90216c804b64a7f4be9f8ee97e2d +31a60af75d2c4ca3bfa9898007cfffaf +c0156044d4834a18a44eb9f01d406bcc +e2a2583ff9014e12a039c38b105673af +c738846e5ebb4363ad1d284c3e814a7c +af71d7fe4b87409f8d9b81452fcb9847 +40be5a4ca73042deaa9bedfd98c44665 +425e8e6e72c34c29b0832a897852f2e5 +230d900e77ea4505b8cb2447c4a7400e +59ee00866fcf467591681c091e1de20f +b60ee204fd1a4367b63ba04f20073e57 +5856ed19a9604c63875f7fca06b50d40 +c566976a0fda4f719f6ea9445bae89a3 +e91248be6a9e40fb8049c414f71cf68c +385ae2dd95914fdbaf1f7a64f53851cc +6f8260fe6b5f4c18b767ad577c18c46a +913530823cd94f13b7e8f6fc60e4f93b +55abb97f9a854f76a8bc574780058c3a +13aa3e52b28d42e7b3ff966003ee8ecf +77088ed10a6e4104a25f98121c3f4742 +f97e542ef1cf4907b128e80a99a900fb +fc7cdaabeb7749ec92d5fe3e71d97478 +4dea8508053049789a98de63471d0a8c +ea526c2ccd044c38b3a0e4ccba393e1b +d09c31ba28994f1d953362fceb3df226 +0d2786bd446d48caaf41ffd43dcb1450 +3df5df4d5d934a2d954e796b52031140 +f9fb93d4e1264cfb85a08a6439aa3f69 +ae14bdbcb5f44b2e98fd31d64adb2086 +5d7cb3916c074068aa8b69e8225583bf +508537073ba64d3dbd027816a20f20ae +cbea02f813454fdb88ddf695dad0ba95 +6844d4663d9946dbaa36d7a7b13cd219 +63f42695017f4e389a00c33a3820fe17 +554579aeec3141fb9d591fa7c0127b4e +8c3d449a43594c09a6289733c02891a9 +8eda68e54bb54e7c8a99f132bd4b266b +aa97f90e44664441bd7023abb290ba78 +d2eb59f553974d8a9dfe7a37b785fd73 +ef1baf9a4c1c445ca874514b7744662d +0d1d16ee22814a40b86df5f96ebac0f9 +3ce7d2047483473dad63751c7b5927c0 +e91fdb39898c4a6194f5e0aa23ad0454 +55a65a18296e437fbc3bd441f8456589 +2b3e6f8e37344325b98a6165030f3340 +8eb0febb200f4ccfb63b1b1564ae024a +798ffbb44f334de79b6f7185d762cce0 +2b72a24dbf594086b02d168ea9280b89 +1b1e585503d6435dae2dcb0d74679712 +6d523d60eaf14b4097bcc953db69f8d2 +2032ce20266a463dbdd1174fc6c09eb2 +a484b3ea93dc498e8a4d9e71d70d1fbf +0ea95f5b19514611bb0b18659a16f7c8 +cee81182d4fc452485531346d2887cac +77e50d3e45a04e63b2c2fc989bfaaf81 +6b91e07e87664518b3caa190b86f2b4d +7a38ff20948b413cbf2019e7bdff1521 +cb3646a27fc143ceae1473242ddae0c4 +c5b1ca5b8492426199932f6b1a64a4d9 +90d5a85e8e6e4ea9b0ac8628ce9041f5 +c380debe912d4e14aab032c00a7af0da +82fa6ca1a23e41c4afdb93382ee5644e +0f440e2b01ca42f8b3fdee8178c51f20 +5594893683184664b166db8a28a55bc0 +e6ebb3b9af6b4668a739b3622dd4dd35 +a521087bf51c48f394e983baddcf9edf +395ec8747038411684f9aebe6aa55501 +90158152f382484c876c56ccfba3a890 +9561b5ebf0644ec7be89285f1e986681 +732c23ce6f074e4e9eac662d523fc42f +8755f46074ba46d2b21dba17550c290d +06ea30fe0e394fcab3b1793439c473ac +c1685c8e53884231bf1602cb371e0ea6 +0162dea1b1044cd281c57af5e5fc2046 +7a01461b8659459eb399d632b8e32916 +0e41024d41344c9da9163b672c98d1fd +24a8cbec7e244aa5aeaf9a3ab0b50d38 +3e2b31c4d352447585f4d7d453414b55 +f84fa637826a4b8eb19d6ad4f9ba414d +181c2f0663664d2eaf444c0435334296 +cee4802cafe3483c9d72f27d6f3e06d1 +5d02b778587343bbb05cc2c03d395e40 +5a8f7d55f2b041aab35331336a6852d7 +b1eef8d330434ab6aec83cc171084d89 +995566da60d74a7eba6da902f62d2f0e +6732042e258b469a84262c07ec5b86a8 +cb5a4125a1ec451485085de830d0f137 +00b2c8c60d2f45a893ee73fd1f107e27 +86aedf99c54e41079faed8609290c1b8 +439c61b8881b483688be86e7ad0cbd1e +f77ec2ebcf7d4a25a8ff08d6cb1643ff +67392ca8071a410c9840746e97368fcf +3c6f04b0a330419c9b94e5da6248bb3f +adc1388c38884b67b17bbf976222b4f9 +a9bc9acf52fe4bcface7d4ee8f8f3d2a +ba06c2a925be47c4a78042ed3fa987ab +e77092787ecd48389d0239ab983f5a6e +4159867faf63453eb2d45cb64f0cc51f +b9ce3cd0680f41aeb056b9e6d4009157 +376d5fed44584570b3da415848d33811 +fb83cd5fdc114bceb9367dcbe00a33a5 +ad644c151bb54394baeb3bb5e2728e2f +0c47bc57d02a410cb5de011931aef56d +ac4e710fdceb42b9bed56733f6c47e95 +87eeade1219c4e12a9c446783b49ad11 +6d5f9ca3da4b4b01909f2a611762a1fe +19003077f2f44480963234a32ab30c24 +b7eba8f065ad458dacb7e658c536a89b +7736320934f64381a0b9ebd8b6025ffc +1f5e1848def2426389fc1f10bb7091ae +adcd40c1d4a148bdb52db9cfe35ecb2d +c5c2133684f646e9940ddb2ff7f81334 +72a394cdac1545e29100509a83a3e0c8 +8eef8f10ba56485aaaa6bc8756944b41 +9fa4f50b845f4ecd96c88dcca941db05 +363b63967982455e9ad749851bee1d7a +2ea85fec1d3744fda5e00337aabc62be +49b5d57469684ded9393eba871854755 +d0664fab6c6b44ea860e340ed0319d20 +120fd69494994dcaa23c95e499ebd6e5 +a7cc2764b1fe4cab91f358e790944c5a +3dc23c3e1d2141d189d8581b229ec131 +dab84cb8737d4cdb81afd578134bae02 +3ff2ab8f53de44e6b74dd3564598645f +8b1ea56831524781a70b8426faaac334 +af389b9c83c146dd88c3f91246f1fb97 +e99f7b2971b843bebdc0122bc63f9d95 +a9cf49c12fc34af5bbafbf50ff312113 +f32584f4df9545f6a0ad740f10de426a +7752407caa7142e3b5b1e58bd2e60c73 +8a7682aed12346c8abc9a5735a966410 +3d9ec96f668a4665a34def2b2550a837 +f50a1d6bb7e640cc9f03596fdeb2e0ed +4a3d504cdaee4cd2aafb617e9da5f259 +b2a4383526264bad9d87e5bab49e7a50 +26afc1d67fdb41b9a971b243a3ba846b +cbc5b979f7bf423bac0b4a0e8eef39f2 +a730a7bcef48485eabdaeef866db989a +6ba693789e4f4aafb70c6661d5c79f3b +b55b0ac070874a6ca861275daac9ebbb +8e112a961aaf44ed9895911856e57034 +383e1febaf6c41889a16e8fc06f0bec0 +609454d5168247168871bd422afec3b1 +78212eb338124202b4d12a932dcde4ea +664aa38dc05845cdbf7ad64d2877e5e4 +024f2d475867491e8a172591b27ce129 +cda570a9a10e43cfbd0ef0ebe94c0eeb +30aef1629c094b22a8b80444de4c4d59 +0d2020330f46460483846da5ee0749df +cf9c09fbcb2c43f39bcbdfc10adcb62b +1661d684ad1b41fea842cf65f12e11fc +8f67849acb6444978de8cfe9d6d2f761 +dc4a1cfb098448c0bcffa778a423efe5 +0276b7595fe44ae39e0f812b25727e54 +8a33c0bd94b34d99a125f4c23c6da524 +f3b47ab10bc745418ebe694aab4c07e6 +c68aad2d3fd04ad394e23a4031be1220 +a007e6ebd5a64ff7b1aa7ef645b1df31 +77a2c9bc4c594785bfdd4c21ef9be25f +7e1d9444d5424fc4b054713ddef74450 +1cb01af673d144649823d6d4076abe7b +e4961832b20c4959ad059fced0fbb529 +7c0bfe2e800742dba8e5e6c8e36b0cfb +c6bec657b24c407b8e1dd15d376b83af +935c106f6b264b3f8d6a66a5701919a3 +37050b9e700348f0816ae649df326f40 +40e8fc657c054e47a7651cb3d7505374 +7250baeb03e940d08aba4a03b91e081b +557c9259640f4f41a273c04c35288cc6 +e761496eb1a24b1e89b27bb22a3a8a84 +509561c9de194acfbb009f2efbc8d945 +112de0a85e7b40d8ac8d60afcbf2e1b7 +76db0470bab9472d86df4da8674e11af +59a4960983464ff794388244830f83e1 +6dc7ad3cc7ed490eacbcf168d652d6dc +b20887a16acf43a2bd102a857d67f1e5 +4f7cf10593824061bfe2e36ffd823cde +2a8c2ca28f044793941c0fd5ce4b2f25 +27fd1f2dac244a6da5cbd7a113c0b6ef +d6e2017f3bd94c629c06167649910234 +0646cb09a5114642957044e721ab703d +fd336d24aa5945b9b640409b9a5a9701 +b45539a475734094b4eaa89e5174b3d0 +eafaa4e2d3e648b486a8df83a188aad8 +810124cdbd5b4a16a4219d1d052580b9 +6251afafae2349e08204ea203aa4bed6 +8c70a119d1f74f158b31c07b349d824a +350584d8243c4f0e9a6ca2b306d287a3 +05e77cfd5dfb4b8da52876490be720f4 +03f2af58cebf4256925ba3179d32045e +dd573d4f219840dcbbe96f5e78478b0b +52ecfc53e47541dabf49cac11b6e04bc +83f93bd4697a41d887006f8310cd67fa +825ec0ea25204295a948615f5c36c846 +11e3537a91974cedaa7dd3222c9c58aa +ff814230abf44128af37ea768b50ff90 +d7d47b3557d0471988574c39be257ae7 +e321a9439efc4a3c845d296e589f5be5 +bb035ac458e8472a9bc4341819d4f441 +e940aef01d014a768ebd121762502398 +bac9ee64eb454a66a637ae0c20f56364 +a2916e544eba4b19b76b454fb0a638c5 +80f48376a8104639b87aea73786a9cb7 +93f2dd8f48894cdcbc1d7bdf2ea80aab +3d66ee325dfa450d942e864b554d877d +5fd13a5303af4f3bbbba993dad35f788 +8fd4c280d67d4bba94eba30c47742f68 +4c63de7b396c4420a30655a9c649d90f +1141e55270af42309f4d5598a0cc17a6 +467f78253a974f7c98506a85db5eebb6 +f00f60bfc27e4f498467f386cd559503 +549d314896eb4009b1c5b631eb1c1c14 +fd0c046a25fb464184bff7263bc3ffab +f77a7095794e460a8ba0b2a55f20a27c +c149f9d83e574e72830271f74e6bb13c +5cd3ea8eb94c4f5597cc086b2df40e58 +3a87a55210db4fd9a27565671824f894 +8cbc2e814ae642abaa938deb4f6f245a +435077bef9dd48d6a5cee72dd1f4a4ef +477a2622764a4bc09a896f2bf3df8bc8 +85ac889151324c24a9b696a7b905e185 +a0a1808ef24d4c04b39fcc39393cdd21 +9eb8bde2b59f443d8454eb4f17543489 +c07ed2f916bc49ef8529043bbe8b7ca5 +0b98a124cd5c4f96ae702a8b5a0da70a +76b11180241542babfcb9ed92cff558c +2b806085d7984b00ade892b053779328 +8eb9f7aff3454ab2a096bc78804f549a +03400f3a6ecd45b6aace4a36174ffd10 +aab2c93ec4b742d999417fae2f0194e2 +29b2a7aeb57747d9bebfe2d8e24fa3e4 +ad3b24b0d191461dbc850059987c8262 +79ca700ba2664018bc7811f4bf549bf9 +2ec1ab458bcd4ea59236bb58bc3707dd +259f7cd8c86b469bbceaa81aae533aa6 +e34b684db27443318642b3b6e9b50d01 +a2cdf40f331a4cb1a3722f995df5f293 +db215ccb1d04490dae6de8e2c8c9707e +98abc88264bd431b8551ee43212c4121 +539abad9c0384000a225a5145f9d5b52 +fc6c642593cc4bc6b4fe8db81995860e +bc03af64a3cb4af38771607b284e1ff9 +cc46444d28304d98aeb8f2fa2693d177 +51dba5eb17c24e0c9fbd1f817505cd60 +d0bdb44945aa4313b7dcb943d1ac21aa +cb7b2c3673c24d24a9615ed864735a31 +6acba1689895492eaea9fba5fe00f587 +5ed61d20ec7d4fc7b03c966d57e48300 +b4a2cb799fbf43d68b9870f6f97f7a06 +0bf35c07e9f54d9db4bc13d189df1e05 +45de76aab681423ca9570b6cddbe50df +79cf2a484f334d8cb90461333301224b +159cea36f78c459993943b44dbfb5339 +525b1f5b6fbc47f38f66dfe5ab67934f +dc639230642845bf8274b836cdecef93 +c929302426cd458184aeaf3025ccfd34 +82284b454e04439f9d2019407bd87b11 +919baf919de3479eb345090e59fbb832 +42b5982a009843888841127980231f3e +1dd1ecaa236146769c0f231d1c3bd9ec +9787e82ab3f441ac874490ecf369980b +015f736a3c6b4daf83a7eaa49b351c45 +7c2a12eee81f4e81a3399f7777b427e4 +784169583c2e42cd8b4bd8667898da44 +327aa3ebd5274bb29e9db3731e917aef +0d1971dfade24524aa4c3307b4104def +121922992c4c44c9a121a40c82c79382 +b2066ff7d6434f41a3a9745afd6b054c +46da0e25122b456b9f52930e58ce4bf9 +e9e93176d37b4849a768e3a3e7341770 +5a21282b2e454d1696547148f617d3d0 +b581ab5018df4e5ebfe5fb56333a98cc +a80d27da5d2b46eabee84c5f4061913d +bdd3ca67614149ca9a06e768e915315e +45c96c7e9dad4c9699fb6480fbcfb201 +a02c10bf6e104e4eb592343ce53bedd1 +bad26cec6af4420b92b203bd949bbf11 +02c4ee90724144fba9cb896602318f2d +bfd56e0a13fd44648fd2f360ecd7cf29 +24692a5bc2bb440c985fa430fd383ec8 +aa701db7f39244898f0d79391950c539 +09fe53d095e84e918f32ea206c9eb166 +1c4ceb980e174dc5b4cea84eb023983d +05a6b459d7d44a3e8d1e3696b2d377e6 +0979139810bf44068470637ed33457f7 +9ccf2fce68ea45e0b0861038d5aa035d +542e372feb6d4124a0adeb589b316096 +cba4cee91c0b4b48b0e1e2a988980556 +9b3c7f2bb57a48f1a00c6b603847f4b8 +102bf0ddb48245a58e494000f3654cb2 +a1a718baf77449cc9199d8e1d0cc9d28 +3db86693ddb54e5984bf31801f9f1597 +725e84ffb4834360bb26287050a0ee63 +271f04e7b2e24e48968c70f23c0cf795 +7416f0f3e04c48d1af25778171256341 +99be78357eee48069420ee38af0eb5a7 +d944bfa696014fd0b1301e83a31226e0 +88be8ad75f274c7b8da4a54fef3aaac9 +8d472329fb1b40bfbc679bf36dec6709 +e171a9ea1be34318bd8d1f785f648300 +b44e1289a02d4daa947271b83b49ed08 +bb52c144e79f47489b05a859b50f1656 +a77d9fda8a2e4dec975913d795fe6ab9 +7cedf5cdd7894f58bf4cae7f5be9d6ca +af6ddb4f17a54d74988aa78e4c98b51f +952f35a14f2e4fc0937325ecc09f8175 +ec72d8a6ccf4450d9925b0d7d62b8afd +344d9fe4bcc548cca31bf1fac927a07d +7609a6ee5d5747dca7c4d3c008fea4d3 +f14bd9d3c5364db7bd30c40e15ea1760 +5f3e2f1cddb24399ad5ddd51fe0add4f +5b1e483e1f9d4d3d98bda551b7caef76 +3763f243e18f4fd6821b3448974c2c63 +887e410d07854396b563325ae1929583 +8c057b309f9d4b5f9df4a12dd740b4d7 +a6792027730c4ac6bf13accc31f717f8 +6e59f642337c4f29bde09a601d14b146 +02750bcb389847bd8e8fa4b5f63439d3 +2eac97eb3c6c4675bf9ecc8436f11892 +5ff2d6beb2124266848ea957197ab107 +75c95aed02324c799a9b4d9bbf4c92eb +fa722472fc354575b83396ac139e1a64 +686c71ef72f04b50aa522325651e3222 +cd2b0592bb85402fb9c85d1d1779471c +84d37f86089d46148bd23a87d1c99488 +1f124d5de6364378bb937d5bf7c9da6d +c848036e1d5f455797476659dfd12b06 +9d45f15fb21f4fc89118b2631eec5fda +8443ee8feeb740f094bbbe1eb629db36 +171922b2761a46a0a4fe2c94ed894484 +1204c7003a554471acebffc28248271e +974d17751cb7497286baa1a4819458c4 +3b2db26a99584daca66ec3a0c731c620 +e205583fe1234598bffbe494b57dc2d8 +38036b2af8ae46dc83351fd81b3af1a5 +aec69c979166446eb2c8e1503f570d26 +f32ec9229a8749d1b79245813fbd6c31 +76e4af37bf424495bb4c195229168914 +0d8ac9660be14b1a95dfecbf33ec8675 +4284bc275d5a49f8b782b330258d2562 +45fe8cac96ab467eb643a48667a85fbd +571a98840c5d49a0abed18cd4492c858 +19429f27ad8a49cc97c99f2d783ad459 +08babe7fbc5e43e180e68c108dc45882 +cb4a3b204b994a9888fcf3ddb23f27fb +82e943e3cfac4da5a20d189ddbd6abdf +21e6bc59d0264e43a6eb0e8df5d6b868 +7ae72d29ede943798623e11231b70109 +19e5c19d811b4dfa95dcec728d3ed8c2 +20f603f201c14f3b8a4f5ce150693c2a +4a270f2477344b55b359e2913f5530f2 +7c450f3d167443ef9979f6852cadacd8 +ed6a25f396a84d808977aa6d074d610e +2a725ae04a33493fad2ee6dad98a85af +8bfeb8018fe9443b86dd74397ac6a5d7 +16cfc1219ace41819a7f4b3292207288 +8684b9b136a5410ca802bb9700ecfb13 +4d7414c670fc4818868efd717c8556c0 +ea71417c1d9841d4ad51e3522cce4207 +2390dfb117f148d4ab971fef73a293a4 +4c19ea76c6fa4dc3994a0d2564af6228 +b08a7135cad84e0ca222a8cff075109b +e3de2a327c0d43ccbaaef3c7277f7f51 +90e76d36b37e4b89abb6223f15a314d2 +6174162400fb4eb5be0dc4026d28dad3 +c892edb592c14d1b94067da032c2e0b5 +f3a115b5fc1e404fb81560dd5f2811f7 +52189db28bc744d1986dcb7e49ba4dfb +8810a9aad4f546a28fe5cda1e429758e +5e050c0699064a4dae8d32e030b46ff1 +ed07d2fdbc58437f844bb096170799d1 +0f5cff9fb78b4657b26ddefff4e10fcf +78c6c82ad2ad478787b2decbd8bd909f +52b7d1e80fa94a14af45cfc3b811714f +459556bba96b4c7b847c32d98bb09991 +a0c4f306d5f543c195c2618552134689 +689a7a3d712f4085bd2320512172226f +3f7a9c26fff14bb99c130bb52a405326 +fd28219fdaf74022834cfe0bb1bde400 +592660a89c2144bab3b39339300d34b7 +62392d7ff04e453fa2dfef12de8b8a41 +de69307eca7442f88c9f3bfe99300e9b +0aa13b8ee38f471097bcd5de12e1ae87 +e9f362c58d7f46159f2fd05d73667d8e +d54159382b7f4ec1a1152da8587e95ca +6a3f750c5be74bff8082f68a5314e063 +4caff3c560474f8988a37d7ceed5236d +57cd9f1e47634f4d90c0ac2d0247f73d +bc708900ae034c84a800567620e7eca2 +84dab97d3b90441883bfda5de6ac0dc9 +296a53dcaca64681819a43b8a7ff7db9 +1b381c2e7d3e4513985623d1e7feb31d +3692381a52364aeeb21a9186e2112961 +c8dd0c421bcc454b96b67f747b18cf4f +e3bf7751e01e4dfb9db33f9a48f04c49 +80ae3e593b594e5fa5390900115b61b4 +ba6d134ed911447cbce61c3e65b2e386 +a1a4bc64ec224ba18208829f36a8d47d +35328820cfc640d2a9b5eedb6d7b907b +f69f527c033c4c8781f37d27a63b1dcd +be74f0c2051c4c75b15247063e38a75e +03a25ce2e9124165a95891fe21a75142 +a432cd8831134a2c8a8f0576c964d3b6 +2ff3797559da49d5a8e43aa64cc05244 +ccf72d795dc14d739888c4750c9d1804 +5fec200c2fe2483fb85af10f55983a69 +69d4d839822e4e658ee95addec9fbc37 +43fa5f8086334ef2b3523dc8e461e60b +d5c902837556422c9eb651b2ef17abff +cd88e7a2de6d4ff7a26da0192f132dd0 +d7e6247241b74fe0862cf1f9e379a485 +715f1b7ccb7a40668b14ef1c9edfa7d2 +41589a39a0234cec8fc171e734d8359d +8c5c01c0e2994c1280ddde22dc095004 +3914ad05eb9342208bac51b1b280bae9 +920f6cb79cd14249aa90e7b2bef5b6cc +4a961d3cb44d4cf3a008480923fa7d89 +ed3591dbf22d49d88591f777cc64b905 +0ca96eab9467484d8543338b92022511 +73674a276a7e4cfd82d2b47f7d24cd2d +9fbcb44010cf4a1a9eb3885f80d80a95 +049244b637ae4f4d9548742f0389bba5 +0f3749cd30f143f9a3f2ae50fd8237e9 +8ca34a0aff47470a9a41ad3b6aab32d6 +6646f7209bbb4894b5feb2b0bc8c86e3 +e393be9a47a24a7cae6142e13f5686d1 +2bd22286264f4fca9a1477d90aed2f0f +90dfb9e99ddd4b4ca414be7599ea6469 +06f991fad4bf4a08b51007a6e23c6526 +3f0350f0300c406581748105e81c3dc2 +af3743bdb36c433ebf71a2135d3fcf60 +7e3b464111194543925b64e85f6cc1b9 +d274f36005274b33ba92900a403dc81d +92ea79872df847a08cddf3646e2ffad3 +15c2c6510e7a482a98db8bfc0cbf5498 +78996f6b47924e868903c0e74b1acb88 +dc1f8c763e8b4064b9b9c674aca4e85d +1d7e68b133c64d08811af3c8bb1193a1 +6a09bfb4032242898292932ee68622b5 +49d9d35451314abba02fe1c06f779ae7 +953ec99e510542b489d4cce969a83d43 +05f6e7861e8e4e7d86ad0ca67d9673c0 +0c8df5efed3d4bcf93ab2ca341cd34cb +e430254560ea4175b38be23bf4b57b6f +3b92e52edcad4873af627f3d6a59de98 +44f7223e15534f1494a164a9c9a28d69 +35dd3c8d812040edaa441cae3d8ad264 +52c9e26b0ad943c7a1d190d4cf3a2903 +197ecc13f22a4b8081e329c35ba1864a +9c8400c0580b4deda9bd6ad2aa84e421 +7f5ce90e3e7f4a78b596cfef3c6e1c0f +a9f27de045ff4869a48005dece8444a6 +7e684a7c012c4fd0ac91844f22457640 +7bddff065f5645ffaceba58606439a42 +37457e13fac14c8ca12e3f7cc4d9efdd +9e3c72a13fc54d7f845ffdc968703c2c +034ddb9bc4544023989f3433a613917c +80d5cfc2396b443b8a5358ff84edc2ec +43b9952b39d14295bfcc357786092c51 +ec14ee60607d48379fd381fc99e9a647 +6b1b178e82724c5b8f509236688a3379 +1dceb198db1d4c7db0777b85a57454ab +aebc93f3a0c443bd94a08f934323982d +7458b901eb0f40a0ab4065b12140a1ff +af6fdcfcaaad4a3a937f5b843f6efb31 +e0f2d244cdd74403a9a1796eb9951981 +f0b276f11d214c3794769175346b030b +03d4836e66e04a5b99c994fd0b6a5f44 +da33914642534516843ddaa8a89a5db6 +7f6d50f56d1745929a09810adf9bed8b +351a82ec49e1444fab944e18ab251ebc +f8a1e5cd151842a9b098692a4e4653b0 +5c0b2b8ade634237977a1db1ede5529d +18d0e36387d94708aab28889424db3e4 +60f5c32d2e6649f48c9cf3298b6db928 +bba7ca142db74abe8e5d3b353b221f03 +60279aff8aae432a9933b9fb6374c2f1 +cef2944921d84deda3570f39749bb73e +f4cfbce0b8a547dea98483656e4f4187 +013a5152dd424910a9e0e324f4c74e7b +9577021d0a9e466ebd42a98277a4005b +a73854935d294308827c9f575c52fe1c +3e1be8151025462685a6fb6cc23d0381 +29472731647d49eebccc6b5f8db95724 +cf7a84a290f8488abf6debdb058775f4 +242e061bb73b46fda6ede3be17ca1264 +eead548258ef4a149d486c810a0a8885 +acc5620be91a43b09f884292bd6358d0 +ec4630c3a8f1435dbc13576258f73f95 +7c65b27279444df5b70bc17e9e1a6c70 +eb6bbf726ed040c78371b87d224730c6 +c38cc2b2ae3b4bd1b035bb61ca8ed8ca +187452aba2d64e1db12c02796b103f00 +e72df1d4ff5240fb93ee0ac0565dc443 +9d5cb1b4fc2a4c61b4bc14eb92b7dbf2 +bba8f4448805408aabc5038e2ff2fc22 +e3596888fd9d4a509c8dcb2a449302f1 +16f756d366df480c9d75e8119c253715 +48461e78135844b0abc51c2369644b4a +ac07d57a79bf40feba6e2bb89ec428b3 +b91f3c0d62e449158228fa7d086d46da +366b50081c884690bb2ce4df6dacad59 +c23b8c487c3c455cb8ff970a3ec3a5c2 +cc93979fbbb449769c9b68a8e81aba31 +95a7eeadf283465c88c1e91fedc4b904 +f8459ee6eee2484d89c7155b71795cd8 +99787bb866eb4490817332831cc486e7 +ca29bb7f4cfa413b932acd6b4e29cee4 +e0eb9050274b479e84006a601c9824c4 +8090e348038840d680aa296800550006 +b118f41b285849e29c4ee04a993c4c1e +92044ee896224ee1bcb6da38d33fbee3 +0b7a5bc3652c4d04b40b8859d275d2dc +1caf8461fd9c4d48aeba0357847bb7f3 +4c89b72896194bdba62083649248e657 +ed53c8787255405b9863b9c01e0173be +b39c78a6a2ce4ff3805c4c1c7f165919 +f513c2d96ca74042b07373c672138442 +bc204819e14d4c9b81d916ca7698a7fe +9906e5863a89474da4ee4e178a2daa28 +999abc97b92b4c4592c4e39e41f7a7b7 +eb16370e0b33439abfbb66ce8d4d0867 +73a396c7006a41cb94c756f44a72672f +da2c388cd499491b9a15a0dd58f10a00 +90411993876047408915de93e8bb65b6 +4a039e32bfcc4af7b30732f7a53df9e6 +0a64625d5ba04833a4d9da63efb6c6ee +f080300151034ade99d1151dc8531eb1 +8ce755e91d1b4de587409b442ec224e4 +e3b3290b8200475993a37c5c56b18ee1 +7e74b12b2d094b11ad54c3f3949473e0 +600bc99bc01040cd99180f555b5b3a61 +d02e753de0604da69e7c132c1c61a17f +81eba26e19be43459cc5ae8c1e9778c0 +3a3082728e72427bbc8d50f8f8a8e8f8 +b7d174561a974ec39a709f6b0e9112eb +f651bcd8d135493ab901b6c72a4f9e41 +ee9bced1fcba48e299798eb22b63212e +8e38e38dec81409e877f98b419121522 +be17f3f93f984a9781792c4bb5e4d6c8 +a73426836efc4ebb86786f265c871875 +3112d700980c49409b69b767ac9ef7ca +5521857a2261482084a68b358618bfc7 +fed2d1e501ed4af4964571b8ae18c94e +a2b2645701c94fa49e65661806219c6b +5f3a574b8f494514ba42a0d84f594877 +740e5d955a4f47dd9471902ed5d0aa6d +2f298b123a5e4f2f9c3012890db2b5a3 +d940fb94a5f0481e9a34a766ef9a303b +a9deaf6a7bf94ad083f4d5cec02b4e0a +1bcf18a4172348359bb9160b8c8828c4 +126ec2dfb13b49bd9109c9bc61871484 +c1442fb2a16f459eb71282d771043476 +1f54a72db6744f83aea120c84e2cc2bf +be408bdd24ac49c6baa907a80d2d6777 +4ff0e8ae2f994bb7bc4de8105febee70 +b2a917737eab4866a8fda30fded72d1c +2670043699a041be822607602ba48e01 +3dc3bdbea2724a48ad2c843c8a34bb00 +fd7f416d84d7414cb4ff4989a27bdb2d +a022864ae7b642a39469652c3eda2b9a +3aec4887da6441e29226f717ef9054d8 +8412b78b8d6c4f5b86c66f49d62681c3 +d0de22a6f34e4694b089bab2aebd59df +67549616d13246cfb1a540f9d6969078 +668e21f076f047f7a1f21b18691f16ba +85f6f00a63b94713b4be4ebee654b430 +d8400af940bc4bfe8d172d8fe0b3cca3 +59909f9f4f984a26bdd795c789bb91be +da15f5f1b7d449c69e3a9e6d69bfa934 +888de04c27a2480ea720f2a914e7052c +f235278f31e9421b85747a82eae272b2 +b81260a3d49140dc8e61289eb5e4dac8 +ba43c7bbcca143c8ad2f77f5841b39de +6622a9be793f4326b040c74903c29bba +a0299c58b4a34a88bba05b3489c28917 +ce0ae78b7918474b9073fc9ef1288218 +132920fe6f0444cbbecff8f40740a14e +08cc55fc36994e04ad24bf36b9aef6e5 +58b1498d53fc4a69a06a6618ae0c2b05 +f611e8cfddc940068758190fe9aa1d3f +9d6276dd6744474391fc21031bf75404 +9fadf8cf832a490eb7c6910b0da2ba8e +ff4ce9d1854f40838745e0e25c24b946 +a93fa93eb78b40c9aa13d395a3899ff2 +9b0cd6fca3b14438961f21aef7288e8a +df0c28260f9d4417add600afca6ecf59 +58f66d35ccae498a958a90569398a419 +86f1d737bc5642d48893c0329302a6a5 +8c1b38fd35714adf95f20c9c3ccd8912 +1063be937b5347ef8a8b89596c558c01 +d8ed49732e73483286207cd15e5e84e1 +f524bd3f08e44a4299e0f42ced91c6c7 +e0b72fb2bbf64e4ab03bc3408753a236 +ec2dc94e022547beadee622b1ff34a5d +37c1b68a67d44385a435ecda1281f708 +dd00b8fd6e8b4638b9d2ce6583cfe659 +7773a9d469f1497aa078ca07b137798c +dfc7ab09596841edaa5182734d316109 +2dad32be0d884b5aa7be75b1f3f2663b +92f5f7ee6a8046bc982d7bd7d76b416e +7df4b9ae20514b65b5330a68c8b459f8 +b1191827a2ce4341869cc8d8a476bbcf +22798b1b718749608a0e729d576727a4 +49d0b382def54ff1b544cc6293ea1b22 +bda792eede214739b5f55a65a4e7f97e +617962b709cf4401bd0381410c072aca +f5a20366fbfc4ee686025a5dd374d323 +47a10d446a2942ca8fd7cbb0cc306b7e +c821f8eec303421fbb9288ba3d299362 +e5d2f0d496f8451b87c08c432781eaf3 +d0dee9a9356b4bee9e0d4cda5bd7f903 +3fa0d01bfae045acae2ae91eb2fcce8c +f8dfd4ebe2694700bdc4dadda81f2393 +56f311dbc6994f93b5b5d14992ca79fb +609d5ff430be4527bb08aaaebeff8c00 +103d99b1ca154045b058f552385a28e4 +8a1a2e0263aa401591c1e87d824a79ef +b2b5272e7ed5470ca8652b6923d9b396 +53ef79b8097248b3b77081d031486db7 +24f46b1fa0f5456a88e715ad591adc57 +9945e1eb5a6247cf9623506025d92e7b +efb07425b3744456a88b24d2c8636302 +cd1bdaef621d4a5d9c9af6a381aafcbd +44d5052c398248ddb3e4d521cae035a9 +f04fee1aba4a40249471870e789ee411 +b72285dd5809472c9965551dea219938 +fc9d4b562d1b4469a3d74478e77ea906 +0f81453b4d6e49fea0cf56264698016c +a854eacb9a784cfa96f49c07d44402da +e050dd76cc114581adab3c0f8caea016 +8b4ad3705b544f55b3b01f6fbb3fd577 +cfc1e09e8a24450090a75fcf6ba8849c +f6ae724d763646dfb09cee2e8df935da +2628a80d4f454d75b5209df98d70a10e +852a943086684f03b6c3157eed78bb08 +c33dfff904d44f4cbca526186aaa3fc9 +0ae0314810814139b3dea039a86d6504 +e05a65a4163b4f5eab6030e65d9d8de7 +6fdfebdcb17d4736b2509958f65f6bba +421ea023d4a740dfaa028e216496b237 +15b5caf2761447fc866fe365f39c0a61 +92a4d289d800484395b437991a69fe52 +2113b139d67f4c62a473e8b48a68853c +3176f7652aff44678ecc2f2b9d896566 +2e22e1cbe0be4da2a82a79ab76cb64a9 +b3d14df9c54c47d0940fb1094d20c2fe +875a64457c5b4e738d6897a44c9fd279 +6733f64d5d3143608ec60c04c666c1d7 +5b8e0438053f4f65b6d4189f23c7bf86 +f517b60777124dfc9e56158c9b0a94f1 +beec98230c8b4c66adcabbea825f4878 +52ec67773ee04608bcf37e4055670788 +4ccc7c0d2ba44a8cbb69ee295a9bcb51 +4ef2ec7867e947d983a723f73c678d5e +ad17ef7161874f4890b4a89abb0850c2 +91b2797e0dfc4bdf96ef45fe0c399f49 +80e8478cc29b4aad91176e584ca67e1d +4524f72c721040229bc33fd190a738d4 +d076b147c2214633bb1e821895093039 +5aa8e3db89e245b7908b3abcacad3e4f +0c15bf821a7546e7af4af3567a0efbdc +62e03de5b2eb4e8d81d1ffe8e94720b8 +63c0c5e987974c7ea48a4c86e0aa80fb +0f07b43af2ec4d60ad94115da8d21c42 +e65692b390a445ed9499b4402c35f3e2 +74e217b1521343e1b72b044f4cca865c +e67e1b3c67804122b70eef386ebdc0be +cfe0ad26828a42cebf49aea928ea8a15 +fb407b00aaaa4ecbacd63ec022f7b32c +ee146d0824ca48d2a88805e11eadee5e +a422d22e0ff64b3f87bd8c6fea8cd3fe +eef888832e0643a6a80db6789be50541 +5e10835be817425ead47ceb993cd8d75 +38a9b928560e4ad5b9e7c1c4dc2a0369 +163be3188b2d4030a859775f70a4111d +b559c90ca0f94114a934aa2bf849fe41 +0bf3ecacd69740e197803bd53302d1d5 +f69d75ec88ec46888619dd48087d89a2 +9f6f9018f14a4dbea1ad1aea0ce89e7c +8f0142bd566f4e7c8e7a2823d4dd6a16 +1eb7d441c3964c6b9d467fd8a4f530a5 +091031aeaf3f41b7bc0b9d8b682e5f54 +1e1b0163430b4d788151de1dbc45ec94 +0bf7985bf5f94236b8b5c2965270e08b +8ea0583721724e6f9a51764f47f7775f +c71f570d21634b7ab50364277e1badcf +70e05053c8a345cb8fff91fcb9013942 +b811f79494b048cbb91b17a7387b0dce +309c9156f9c049beab6813a2b1ca5b46 +7cc8affeefaa4e708dd0fb1dd36ef654 +02ff51f84324460cb826bf2a618358bc +03e706cd42504955b08379f45633c9ef +48a50fb5d233497eb5967a23ccec3d9d +dcb2153718f84286a5ec063049598fda +f719e6cbbdf34716ae4a26508bb2b601 +bc001ab61e0145a2b74fc93181171f0c +cf6ed4746a564dea8bdf96c2fc7d6344 +96b925daae4d4dc89035123053d3055c +6acbec139ac04331992e2b60e234712f +5b5d5fc3fc944ada81d00ca16003882b +ac51bc2baacb455b87ccc53d2d23f853 +9178b11770dd49fca81fad6da89caf2b +e909875deca1431d9e9e81746f6ea1a7 +b9214be998c746409dafa3755150fe8e +4565942629194e1da2965d3fe499d0e4 +6592c60e5caf48d0b92458bb9e086bc7 +05d140a49daf40fabd9f679df06ac1d3 +af99d40eb9bd4aad80ff83b92e955631 +9a122b5d958046949d07ff580799ffd4 +eaa08a9b86d745558ef18a0186766d44 +34ae6fccabe142358409f87e106cdaf1 +14c017540bd64fda812557411a24b0d9 +7970fdd20e194128a84ed8353a0e4826 +faae6d37ef744cdf9e6325977313a4e5 +2005d15daca8424c9050955716af2fa5 +8dd0d3d040d64126a9ab2d237a816436 +1c7c1fd10f72468e8551ab33d48f72b0 +940e996b136e4db0a364a88be43ef0ff +95b6485c508c4b068d683dda16a33252 +d11b693f56e0498bad0a3f573c870c83 +7a89051127924a2ba793a72d092abe74 +ab43b3cad1c844428cad83519b631927 +6e3e38b674474dc8877a051e7c5794d7 +29620ea7b8364bdda75c9d1f66bf68d2 +7a967d4fac69441ea8fd12efff8b496d +5deb12a6e9964ae18c93786bef5587d9 +41e6c8bfff7d44288b40adf21efc4225 +3c22408ba46840d189fcfbdbdc044f72 +9b4655dedefc4293a4da1d8f530b78f8 +99ed8d6c46c343729e63a0a581599add +5a95187f6f6f4528a05bd0805fca155f +9f421abdda024750a42ff5932f3bacdd +cddd1a1d6279464ca359ae4f75a4e754 +3c2ba2d3b7aa4cf7893cf57cbba2f2d6 +24d1bb5b02014ba8be693b6cca1ca752 +67e0ff55d772445db4f55b91f0afc6fa +c0b77d47832a452aad1d59e9190d3142 +f5baf23f59bd4c5c8f70eb8a2d8c7b1a +df85ba4998d841f7837cd7e04cb39f90 +45a7e7a2e2404d118ee66d59559de5f1 +22c55dcf1eb349e19e5848f0df6f713f +5a7ecef3d12242f9a4a9b4db971a96a5 +05166b03dfb745f79179d57d06d6c43f +3f1dd36d74a74f3eb61e07c5129e1f9a +c937e661d6a94537b8d54c8e4f24e51e +3b505e2a477c4b16a2ee88833c85c802 +a350f2f90f3e4628a25bce1f45d4f26f +e728dd63c5df41faa8913528062fa3fa +efc971c1e966434d803e733bc2f679a1 +a938d9527eb14bdfb9efe45073fa9c18 +f9408b76068b4b3e9699aaf83d8658ae +cff2d3483c4a452aaa9201b2a1b7d984 +f7fadf43cedb4f83a7edb28e3aa595b4 +b68136575348498fba7556a3aca39f7d +810906c7d15847c7ad082b211795e1cc +0db963061cdd4c348b0e3335cb51dc00 +c532c913264741a1a6908d13a600895d +631f3ef770bc4b8ebd1bb3c727d08813 +09711bbf9f884c44958c9dd37b764e00 +83c7586454d24b82ab7fa697efd4b9af +5c5d1c3bb4494ed9bcad956b6b4709d5 +160ab185da3341cda1efbd3d55966b76 +515d0d953687472a96d2a890efaca364 +a801191432784b9cb5dc25bb01ee8341 +f36612f3fb7c4c47a4973a8c305263d8 +2b82d90a50054a58a9ea607e1bbcb815 +8779541cdb3a4af7a23a597bcac90318 +542158414c9f4452828b12df34786c44 +d4c7eaf7b1304e6ba2b2d28e2c7010bd +ce535f14407f4f1ca01111d23a3696d4 +4fdc6821397142fbbc5dbacaa2fd4051 +8477a004d7814ea880483bba501f78da +87799bc7863d4550bf8f4ada7026f48b +f22b7ccb70f64724843e15cc1b4f2549 +cb31e638a6dd42c48a29911706f96c78 +5fdc95a388cc4da399690de48d1fd720 +d20d1d78836f4c37b543da288035f2d6 diff --git a/datasets/dataset.py b/datasets/dataset.py new file mode 100644 index 0000000..8b75b62 --- /dev/null +++ b/datasets/dataset.py @@ -0,0 +1,92 @@ +# Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +# property and proprietary rights in and to this material, related +# documentation and any modifications thereto. Any use, reproduction, +# disclosure or distribution of this material and related documentation +# without an express license agreement from NVIDIA CORPORATION or +# its affiliates is strictly prohibited. + +import torch + + +class Dataset(torch.utils.data.Dataset): + """Basic dataset interface""" + def __init__(self, device): + super().__init__() + self.device = device + + def __len__(self): + raise NotImplementedError + + def __getitem__(self, itr): + raise NotImplementedError + + def collate(self, batch): + # iter_res = batch[0]['resolution'] + # tets = batch[0]['tets'] + # points = batch[0]['points'] + # iter_spp = batch[0]['spp'] + res = { + 'uuid': list([item['uuid'] for item in batch]), + 'gt_pcd': torch.cat(list([item['gt_pcd'] for item in batch]), dim=0).to(self.device), + 'gt_pcd_colors': torch.cat(list([item['gt_pcd_colors'] for item in batch])).to(self.device), + 'gt_pcd_query': torch.cat(list([item['gt_pcd_query'] for item in batch]), dim=0).to(self.device), + 'gt_pcd_colors_query': torch.cat(list([item['gt_pcd_colors_query'] for item in batch])).to(self.device), + 'gt_render_imgs': torch.cat(list([item['gt_render_imgs'] for item in batch]), dim=0).to(self.device), + # 'verts': torch.cat(list([item['verts'] for item in batch]), dim=0).to(self.device), + # 'tets': tets.to(self.device), + 'gt_verts': list([item['gt_verts'].to(self.device) for item in batch]), + 'gt_faces': list([item['gt_faces'].to(self.device) for item in batch]), + 'mv': torch.cat(list([item['mv'] for item in batch]), dim=0).to(self.device), + 'mvp': torch.cat(list([item['mvp'] for item in batch]), dim=0).to(self.device), + 'campos': torch.cat(list([item['campos'] for item in batch]), dim=0).to(self.device), + 'alpha': torch.cat(list([item['alpha'] for item in batch]), dim=0).to(self.device), + 'alpha_ctn': torch.cat(list([item['alpha_ctn'] for item in batch]), dim=0).to(self.device), + 'depth': torch.cat(list([item['depth'] for item in batch]), dim=0).to(self.device), + 'normal': torch.cat(list([item['normal'] for item in batch]), dim=0).to(self.device), + 'persp': batch[0]['persp'].to(self.device), + # 'time': sum(list([item['time'] for item in batch])), + 'resolution': batch[0]['resolution'], + 'resolution_img': batch[0]['resolution_img'], + 'resolution_triview': batch[0]['resolution_triview'] + # 'spp' : iter_spp, + # 'img': torch.cat(list([item['img'] for item in batch]), dim=0) + } + if batch[0].get('triview_color') is not None: + res.update({ + 'triview_color': torch.cat(list([item['triview_color'] for item in batch]), dim=0).to(self.device) + }) + if batch[0].get('triview_xyz') is not None: + res.update({ + 'triview_xyz': torch.cat(list([item['triview_xyz'] for item in batch]), dim=0).to(self.device) + }) + if batch[0].get('prompt') is not None: + res.update({ + 'prompt': list([item['prompt'] for item in batch]) + }) + return res + + +# class DatasetPoints(torch.utils.data.Dataset): +# """Basic dataset interface""" +# def __init__(self): +# super().__init__() +# +# def __len__(self): +# raise NotImplementedError +# +# def __getitem__(self, itr): +# raise NotImplementedError +# +# def collate(self, batch): +# iter_res = batch[0]['resolution'] +# # iter_spp = batch[0]['spp'] +# return { +# 'mv': torch.cat(list([item['mv'] for item in batch]), dim=0), +# 'mvp': torch.cat(list([item['mvp'] for item in batch]), dim=0), +# 'campos': torch.cat(list([item['campos'] for item in batch]), dim=0), +# 'resolution': iter_res, +# # 'spp' : iter_spp, +# # 'img': torch.cat(list([item['img'] for item in batch]), dim=0) +# } diff --git a/datasets/fast_dataset.py b/datasets/fast_dataset.py new file mode 100644 index 0000000..b4af2fb --- /dev/null +++ b/datasets/fast_dataset.py @@ -0,0 +1,945 @@ +import math +import os +import shutil +from concurrent.futures import Future, ThreadPoolExecutor +from itertools import cycle +from pathlib import Path +from typing import List, Optional, Dict, Tuple, Union, Type +import random +import torch.distributed as dist +import pickle + +import numpy as np +import pyarrow as pa +import pyarrow.parquet as pq +import torch +import trimesh +from tqdm import tqdm +from .dataset import Dataset +from util import utils, renderer +from util.utils import SHAPENET_MAX_DEPTH, DEPTH_MAX, DEPTH_MIN, DEPTH_VALID_MIN, DEPTH_VALID_MAX +import json +import cv2 +from PIL import Image +import logging +import aiofiles +import asyncio +import io +logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO) + + +def chunk_with_size(lst, n): + """return successive n-sized chunks from lst.""" + for i in range(0, len(lst), n): + yield lst[i:i + n] + + +def chunk_with_number(lst, n): + """split lst into n chunks, all chunks have near chunk size diffrence no more than 1, just like np.array_split""" + chunk_size = len(lst) // n + remain = len(lst) % n + start = 0 + for i in range(n): + end = start + chunk_size + if i < remain: + end += 1 + yield lst[start:end] + start = end + +async def aread_file(file_path, mode="rb"): + async with aiofiles.open(file_path, mode=mode) as f: + return await f.read() + +async def abatch_read_files(file_paths: List[str]): + # read files from disk into memory, return a list of bytes + return await asyncio.gather(*[aread_file(file_path) for file_path in file_paths]) + +def buffer_to_cv2image(buffer): + # convert bytes to image + return cv2.imdecode(np.frombuffer(buffer, dtype=np.uint8), cv2.IMREAD_UNCHANGED) + +def batch_buffer_to_cv2image(buffers): + return [buffer_to_cv2image(buffer) for buffer in buffers] + + +class FastDataset(Dataset): + + def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_process=1, process_index=0): + # metadata_items: List[ImageMetadata], near: float, far: float, ray_altitude_range: List[float], + # center_pixels: bool, device: torch.device, chunk_paths: List[Path], num_chunks: int, + # scale_factor: int, disk_flush_size: int): + super(FastDataset, self).__init__(device) + self.device = device + self.glctx = glctx + self.mode = mode + self.cam_radius = input_specs['radius'] + self.fovx = np.deg2rad(45) + self.res = input_specs['resolution'] + self.res_img = input_specs.get('resolution_img') + self.res_triview = input_specs.get('resolution_triview') + self.render_color_img_dir = input_specs.get('render_img_dir', '') + self.triview_color_dir = input_specs.get('triview_color_dir', '') + self.triview_xyz_dir = input_specs.get('triview_xyz_dir', '') + self.prompt_path = input_specs.get('prompt_path', '') + self.aspect = self.res[1] / self.res[0] + self.pts_num = train_specs['sample_points_num'] + self.query_pts_num = train_specs['query_sample_points_num'] + self.epoch = train_specs['num_epochs'] + # self.its_per_epc = train_specs["its_per_epc"] + self.scale = input_specs['scale'] + self.render_mode = train_specs.get('tex_sup_mode') + self.dep_sill_mode = train_specs.get('dep&sill_sup_mode') + + # self.mode = input_specs['mode'] + self.pcd_dir = input_specs['pcd_dir'] + self.mesh_dir = input_specs['mesh_dir'] + self.class_name = input_specs['class'] + self.camera_angle_num = input_specs['camera_angle_num'] + self.split_dir = input_specs['split_dir'] + + self.train_set = utils.load_item(os.path.join(self.split_dir, 'train.txt')) + self.val_set = utils.load_item(os.path.join(self.split_dir, 'val.txt')) + self.test_set = utils.load_item(os.path.join(self.split_dir, 'test.txt')) + + random.seed(2023) + self.val_memory = sorted(list(self.val_set)) + self.validate_num = input_specs.get('validate_num') + self.val_memory = random.sample(self.val_memory, k=self.validate_num) + + self.objaverse_exclude = utils.load_item(os.path.join(self.split_dir, 'exclude.txt')) + self.all_set = self.train_set.union(self.val_set).union(self.test_set) - set(self.val_memory) + + self.img_num = input_specs.get('img_num', 24) + + self.uuid2transform = utils.load_transform(input_specs.get('blender_transform')) + chunk_path = input_specs['chunk_path'] + self.dataset_name = input_specs['dataset_name'] + class_name = input_specs['class'] + class_name_suffix = f'_reso{self.res[0]}_img{self.img_num}_fast' + class_name += class_name_suffix + + self.num_process = num_process + self.process_index = process_index + + if self.prompt_path != '': + self.uuid2prompt = utils.load_prompt(self.prompt_path) + + # # train, val, test = 7:1:2 + # mapping = { + # 'train': 1, + # 'val': 1 / 7, + # 'test': 2 / 7 + # } + + # num_chunk = math.ceil(input_specs['chunk_num'] * mapping[self.mode]) + chunk_size = input_specs['chunk_size'] + parquet_dir = os.path.join(chunk_path, self.dataset_name, class_name, self.mode) + + if not os.path.exists(parquet_dir): + os.makedirs(parquet_dir, exist_ok=True) + + parquet_paths = [os.path.join(parquet_dir, name) for name in os.listdir(parquet_dir) if name.endswith('.parquet')] + self.num_chunk = len(parquet_paths) + self._parquet_paths = parquet_paths + self.metadata = [] + + self.parquet_dir = parquet_dir + self.chunk_size = chunk_size + # if self.num_chunk > 0: + # print('Reusing {} chunks from previous run'.format(self.num_chunk)) + # else: + # self._write_chunks(parquet_dir, chunk_size) + # if self.mode != 'train': + # exit(0) + + self._parquet_paths.sort() + + chunk_indices = list(range(len(self._parquet_paths))) + self._chunk_index = cycle(chunk_indices[chunk:] + chunk_indices[:chunk]) + self._loaded_uuid = None + self._loaded_verts_list = None + self._loaded_faces_list = None + self._loaded_pcd_list = None + self._loaded_pcd_colors_list = None + self._loaded_render_color_img_list = None + self._loaded_render_depth_img_list = None + self._loaded_render_color_cam_list = None + self._loaded_fovx_list = None + self._loaded_triview_color_img_list = None + self._loaded_triview_xyz_img_list = None + self._loaded_prompt = None + self._chunk_load_executor = ThreadPoolExecutor(max_workers=1) + self._chunk_future = self._chunk_load_executor.submit(self._load_chunk_inner) + self._chosen = None + + def load_chunk(self) -> None: + chosen, self._loaded_verts_list, self._loaded_faces_list, self._loaded_pcd_list, self._loaded_pcd_colors_list, \ + self._loaded_render_color_img_list, self._loaded_render_depth_img_list, \ + self._loaded_render_color_cam_list, self._loaded_fovx_list, \ + self._loaded_triview_color_img_list, self._loaded_triview_xyz_img_list, self._loaded_prompt, self._loaded_uuid= \ + self._chunk_future.result() + self._chosen = chosen + self._chunk_future = self._chunk_load_executor.submit(self._load_chunk_inner) + + def get_state(self) -> str: + return self._chosen + + def set_state(self, chosen: str) -> None: + while self._chosen != chosen: + self.load_chunk() + + def __len__(self) -> int: + return len(self._loaded_verts_list) + + def _random_scene(self, mv=None, imgs=None, depths=None): + # ============================================================================================== + # Setup projection matrix + # ============================================================================================== + proj_mtx = utils.perspective(self.fovx, self.res[1] / self.res[0]) + + # ============================================================================================== + # Random camera & light position + # ============================================================================================== + + # Random rotation/translation matrix for optimization. + batch = self.camera_angle_num + if mv is None or imgs is None: + mv = torch.bmm( + utils.translate(0, 0, -self.cam_radius).repeat(batch, 1, 1), + utils.batch_random_rotation_translation(self.camera_angle_num, 0.25) + ) + depths = torch.zeros((batch,) + tuple(self.res) + (1,)) + imgs = torch.zeros((batch,) + tuple(self.res) + (3,)) + else: + img_num = len(mv) + index = random.sample(range(img_num), k=self.camera_angle_num) + + mv = mv[index] + imgs = imgs[index] + # imgs = imgs.T.view(imgs.shape[-1], self.res_img[0], self.res_img[1], 3)[index] + depths = depths[index] + # depths = depths.T.view(depths.shape[-1], self.res[0], self.res[1], 1)[index] + + mvp = torch.bmm( + proj_mtx.repeat(batch, 1, 1), + mv + ) + campos = torch.linalg.inv(mv)[:, :3, 3] + + return mv.to(self.device), mvp.to(self.device), campos.to(self.device), \ + imgs.to(self.device), depths.to(self.device), proj_mtx.to(self.device), self.res + + def __getitem__(self, idx): + # mv_list, mvp_list, campos_list, alpha_list, depth_list, norm_list, color_list = [], [], [], [], [], [], [] + # for _ in range(self.camera_angle_num): + if self.render_mode == 'blender': + mv = self._loaded_render_color_cam_list[idx] + imgs = self._loaded_render_color_img_list[idx] + depths = self._loaded_render_depth_img_list[idx] + + mv = mv.T.view(-1, 4, 4) + # imgs = imgs.T.view(imgs.shape[-1], self.res_img[0], self.res_img[1], 3) + raws = imgs.T.view(imgs.shape[-1], self.res_img[0], self.res_img[1], 4) + + imgs = raws[..., :3] + masks = raws[..., [-1]].expand(-1, -1, -1, 3) + imgs *= masks + + depths = depths.T.view(depths.shape[-1], self.res_img[0], self.res_img[1], 1) + + self.fovx = self._loaded_fovx_list[idx][0] + + mv, mvp, campos, imgs, depths, persp, iter_res = self._random_scene(mv, imgs, depths) + else: + mv, mvp, campos, imgs, depths, persp, iter_res = self._random_scene() + + verts = self._loaded_verts_list[idx] + + if self.dataset_name == 'Objaverse': + if self.uuid2transform: + transform = self.uuid2transform[self._loaded_uuid[idx]] + transport = torch.tensor(transform['offset'], dtype=torch.float32) + scale = torch.tensor(transform['scale'], dtype=torch.float32) + verts = (verts * scale + transport) * self.scale / 0.5 + else: + transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 + verts -= transport + scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) + + verts *= self.scale / 0.5 * scale + + if self.dep_sill_mode == 'blender': + alpha = alpha_ctn = (depths > 0).float() + normal, face_normals = renderer.render_mesh( + self.glctx, verts.to(self.device), + self._loaded_faces_list[idx].to(self.device), + mvp, campos, persp, iter_res, + normal_only=True + ) + else: + alpha, alpha_ctn, depths, normal, face_normals = renderer.render_mesh( + self.glctx, verts.to(self.device), + self._loaded_faces_list[idx].to(self.device), + mvp, campos, persp, iter_res + ) + + pcd_num = len(self._loaded_pcd_list[idx]) + index = random.sample(range(pcd_num), k=self.pts_num) + index_query = random.sample(range(pcd_num), k=self.query_pts_num) + + res = { + # 'verts': self.verts[None, ...], + # 'tets': self.tets, + 'uuid': self._loaded_uuid[idx], + 'gt_verts': self._loaded_verts_list[idx], + 'gt_faces': self._loaded_faces_list[idx], + 'gt_pcd': self._loaded_pcd_list[idx][None, index, ...], + 'gt_pcd_colors': self._loaded_pcd_colors_list[idx][None, index, ...], + 'gt_pcd_colors_query': self._loaded_pcd_colors_list[idx][None, index_query, ], + 'gt_pcd_query': self._loaded_pcd_list[idx][None, index_query, ], + 'gt_render_imgs': imgs[None,], + 'mv': mv[None, ], + 'mvp': mvp[None, ], + 'campos': campos[None, ], + 'resolution': self.res, + 'resolution_img': self.res_img, + 'resolution_triview': self.res_triview, + 'normal': normal[None, ], + # 'spp' : iter_spp, + # 'img' : img, + 'alpha': alpha[None, ], + 'alpha_ctn': alpha_ctn[None, ], + 'depth': depths[None, ], + 'persp': persp + # 'color': torch.stack(color, dim=1) + } + + if self.triview_color_dir != '': + triview_color = self._loaded_triview_color_img_list[idx] + # triview_color = triview_color.T.view(triview_color.shape[-1], self.res_triview[0], self.res_triview[1], 3) + rgbas = triview_color.T.view(triview_color.shape[-1], self.res_triview[0], self.res_triview[1], 4) + + imgs = rgbas[..., :3] + masks = rgbas[..., [-1]].expand(-1, -1, -1, 3) + imgs *= masks + triview_color = imgs + + res.update({ + 'triview_color': triview_color[None,], + }) + + if self.triview_xyz_dir != '': + triview_xyz = self._loaded_triview_xyz_img_list[idx] + triview_xyz = triview_xyz.T.view(triview_xyz.shape[-1], self.res_triview[0], self.res_triview[1], 3) + + triview_xyz *= masks + + res.update({ + 'triview_xyz': triview_xyz[None,], + }) + + if self.prompt_path != '': + prompt = self._loaded_prompt[idx] + res.update({ + # 'prompt': [prompt] + 'prompt': [self.uuid2prompt[self._loaded_uuid[idx]]] + }) + + return res + + + def _load_chunk_inner(self) -> Tuple[str, List[torch.FloatTensor], List[torch.LongTensor], + List[torch.FloatTensor], List[torch.FloatTensor], + List[torch.FloatTensor], List[torch.FloatTensor], + List[torch.FloatTensor], List[torch.FloatTensor], + List[torch.FloatTensor], List[torch.FloatTensor], List[str], List[str]]: + # if 'RANK' in os.environ: + # torch.cuda.set_device(int(os.environ['LOCAL_RANK'])) + + next_index = next(self._chunk_index) + chosen = self._parquet_paths[next_index] + + # loaded_chunk = np.load(chosen, allow_pickle=True) + # dict_chunk = loaded_chunk.item() + # num_rows = len(dict_chunk['uuid']) + + loaded_chunk = pq.read_table(chosen) + num_rows = loaded_chunk.num_rows + pandas_chunk = loaded_chunk.to_pandas() + + verts_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'verts_list_{j}'][i] for j in range(3)], axis=-1) + ) for i in range(num_rows)] + faces_list = [torch.LongTensor(np.stack( + [pandas_chunk[f'faces_list_{j}'][i] for j in range(3)], axis=-1) + ) for i in range(num_rows)] + pcd_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'pcd_list_{j}'][i] for j in range(3)], axis=-1) + ) for i in range(num_rows)] + pcd_colors_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'pcd_colors_list_{j}'][i] for j in range(3)], axis=-1) + ) for i in range(num_rows)] + uuid = [str(pandas_chunk['uuid'][i]) for i in range(num_rows)] + + render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list = None, None, None, None + if self.render_mode == 'blender': + render_color_img_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'render_color_img_list_{j}'][i] for j in range(self.img_num)], axis=-1) + ) for i in range(num_rows)] + + render_depth_img_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'render_depth_img_list_{j}'][i] for j in range(self.img_num)], axis=-1) + ) for i in range(num_rows)] + + render_color_cam_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'render_color_cam_list_{j}'][i] for j in range(self.img_num)], axis=-1) + ) for i in range(num_rows)] + + fovx_list = [torch.FloatTensor(np.array(pandas_chunk[f'fovx_list'][i])) for i in range(num_rows)] + + triview_color_img_list, triview_xyz_img_list, prompt = None, None, None + if self.triview_color_dir != '': + triview_color_img_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'triview_color_img_list_{j}'][i] for j in range(6)], axis=-1) + ) for i in range(num_rows)] + + if self.triview_xyz_dir != '': + triview_xyz_img_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'triview_xyz_img_list_{j}'][i] for j in range(6)], axis=-1) + ) for i in range(num_rows)] + + if self.prompt_path != '': + prompt = [str(pandas_chunk['prompt'][i]) for i in range(num_rows)] + + return str(chosen), verts_list, faces_list, pcd_list, pcd_colors_list, \ + render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, \ + triview_color_img_list, triview_xyz_img_list, prompt, uuid + + async def aprocess_one_data(self, data: dict, data_index:int): + """ + given data, read files and preprocess them, then put them into lists + """ + if data_index % 100 == 0: + logging.info(f"process index {self.process_index} start {data_index}") + + gt_path = data['gt_path'] + pcd_file = data['pcd_file'] + + gt_bytes = await aread_file(gt_path) + ref_mesh = trimesh.load(io.BytesIO(gt_bytes), + file_type=Path(gt_path).suffix, force='mesh', process=False) + verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) + faces = torch.LongTensor(ref_mesh.faces) + + pcd_bytes = await aread_file(pcd_file) + # load point cloud + pcd = trimesh.load(io.BytesIO(pcd_bytes), file_type=Path(pcd_file).suffix) + + pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) + gt_render_imgs = None + gt_render_depths = None + gt_transforms = None + fovx = None + if self.render_color_img_dir != '': + render_color_img_dir = data['render_color_img_dir'] + render_color_cam_file = data['render_color_cam_file'] + # rotate + verts[:, -1] = -verts[:, -1] + verts = verts[:, [0, 2, 1]] + + # color, normalized to [-1, 1] + pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] + + if self.dataset_name == 'ShapeNet': + + metadata = json.loads(await aread_file(render_color_cam_file, "r")) + + verts *= self.scale / 0.5 + pcd_tr *= self.scale / 0.5 + fovx = np.array([metadata['camera_angle_x']], dtype=np.float64) + img_list, depth_list, transform_list = [], [], [] + + assert self.img_num == len(metadata['frames']) + image_paths = [os.path.join(render_color_img_dir, metadata['frames'][i]["file_path"]) for i in range(self.img_num)] + bytes_images = await abatch_read_files(image_paths) + images = batch_buffer_to_cv2image(bytes_images) + for i, item in enumerate(metadata['frames']): + img_name = item['file_path'] + assert i == int(os.path.splitext(img_name)[0]) + + c2w = torch.tensor(item['transform_matrix'], dtype=torch.float32) + + c2w[:3, 3] *= self.scale / 0.5 + + w2c = torch.inverse(c2w) + # BGR -> RGB + raw = cv2.resize(images[i], tuple(self.res_img)) + # mask = torch.tensor(raw[:, :, [-1]], + # dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0, 3]], + dtype=torch.float32) / 255 + + # img = img * mask + + transform_list.append(w2c.reshape(-1)) + img_list.append(img.reshape(-1)) + + # depth + depth_name = f'{i:05d}_depth.png' + dep = cv2.imread(os.path.join(render_color_img_dir, depth_name), cv2.IMREAD_UNCHANGED) + + # reference + # https://github.com/openai/shap-e/blob/50131012ee11c9d2617f3886c10f000d3c7a3b43/shap_e/rendering/blender/view_data.py#L57-L62 + inf_dist = dep == 0xFFFF + dep = np.where( + inf_dist, + 0., + SHAPENET_MAX_DEPTH * (dep.astype(np.float32) / 65536), + ) + + dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 + + depth_list.append(dep.reshape(-1)) + elif self.dataset_name == 'Objaverse': + # transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 + # verts -= transport + # scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) + # + # verts *= self.scale / 0.5 * scale + pcd_tr *= self.scale / 0.5 + + K, _, _, _, w2cs = pickle.load(io.BytesIO(await aread_file(render_color_cam_file))) + + fovx = np.array([2 * math.atan(K[0, 2] / K[0, 0])], dtype=np.float64) + img_list, depth_list, transform_list = [], [], [] + image_paths = [os.path.join(render_color_img_dir, f'{i:03d}.png') for i in range(len(w2cs))] + bytes_images = await abatch_read_files(image_paths) + # logging.info("read objaverss done") + images = batch_buffer_to_cv2image(bytes_images) + + depth_paths = [os.path.join(render_color_img_dir, f'{i:03d}-depth.png') for i in range(len(w2cs))] + bytes_depths = await abatch_read_files(depth_paths) + depths = batch_buffer_to_cv2image(bytes_depths) + + # select per stride imgs + assert len(w2cs) % self.img_num == 0 + stride = len(w2cs) // self.img_num + + for i, w2c in enumerate(w2cs): + if i % stride != 0: + continue + w2c = torch.tensor(np.stack((w2c[0], -w2c[1], -w2c[2], np.array([0., 0., 0., 1.])), axis=0), + dtype=torch.float32) + c2w = torch.inverse(w2c) + c2w[:3, 3] *= self.scale / 0.5 + w2c = torch.inverse(c2w) + # BGR -> RGB -> [-1, 1] + # image = buffer_to_cv2image(await aread_file(image_paths[i])) + # try: + raw = cv2.resize(images[i], tuple(self.res_img)) + # except Exception as e: + # print(f'uuid: {data["uuid"]}, prompt: {data["prompt"]}, index: {i}') + # mask = torch.tensor(raw[:, :, [-1]], + # dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0, 3]], + dtype=torch.float32) / 255 + + # img = img * mask + transform_list.append(w2c.reshape(-1)) + img_list.append(img.reshape(-1)) + + # depth + # syncdreamer + if os.path.exists(os.path.join(render_color_img_dir, f'{i:03d}-depth.png')): + # depth_name = f'{i:03d}-depth.png' + # dep = cv2.imread(os.path.join(render_color_img_dir, depth_name), cv2.IMREAD_UNCHANGED) + dep = depths[i] + + # reference + # https://github.com/liuyuan-pal/SyncDreamer/blob/232a2ec22f0277b4bd429109fb34eaf8f61b13ad/eval_mesh.py#L16-L22 + dep = dep.astype(np.float32) / 65535 * (DEPTH_MAX - DEPTH_MIN) + DEPTH_MIN + mask = (dep < DEPTH_VALID_MIN) | (dep > DEPTH_VALID_MAX) + + # cs + elif os.path.exists(os.path.join(render_color_img_dir, f'depth_{i:03d}1.png')): + depth_name = f'{i:03d}-depth.png' + depth_path = os.path.join(render_color_img_dir, f"depth_{i:03d}1.png") + + dep =(np.array(Image.open(depth_path))[:,:,0]- 120)* 0.5 / 63 + mask = np.array(Image.open(depth_path))[:,:,0] == 255 + + dep = np.where(mask, 0., dep) + + dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 + + depth_list.append(dep.reshape(-1)) + gt_render_imgs = torch.stack(img_list, dim=-1) + gt_transforms = torch.stack(transform_list, dim=-1) + gt_render_depths = torch.stack(depth_list, dim=-1) + + else: + verts -= ((verts.max(0)[0] + verts.min(0)[0]) / 2).unsqueeze(0).repeat( + (verts.shape[0], 1)) + + # rotate & transport + pcd_tr = pcd_tr @ utils.rotate_x(-math.pi / 2).T[:3, :3] + pcd_tr -= ((pcd_tr.max(0)[0] + pcd_tr.min(0)[0]) / 2).unsqueeze(0).repeat((pcd_tr.shape[0], 1)) + + # scale + verts = verts / torch.max(abs(verts)) * self.scale + pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale + + # color + pcd_colors = (2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255)[..., :3] / 255 + + triview_imgs = None + triview_xyzs = None + if self.triview_color_dir != '' and self.triview_xyz_dir != '': + img_list, xyz_list = [], [] + triview_color_dir = data['triview_color_dir'] + triview_xyz_dir = data['triview_xyz_dir'] + + color_paths = [os.path.join(triview_color_dir, f'{i:03d}.png') for i in range(6)] + xyz_paths = [os.path.join(triview_xyz_dir, f'xyz_new_{i:03d}.png') for i in range(6)] + # bytes_colors = await abatch_read_files(color_paths) + # bytes_xyzs = await abatch_read_files(xyz_paths) + # logging.info("read done") + # colors = batch_buffer_to_cv2image(bytes_colors) + # xyzs = batch_buffer_to_cv2image(bytes_xyzs) + + for i in range(6): + # BGR -> RGB + color = buffer_to_cv2image(await aread_file(color_paths[i])) + xyz = buffer_to_cv2image(await aread_file(xyz_paths[i])) + # raw = cv2.resize(colors[i], self.res_triview) + # xyz = cv2.resize(xyzs[i], self.res_triview) + raw = cv2.resize(color, self.res_triview) + xyz = cv2.resize(xyz, self.res_triview) + + # mask = torch.tensor(raw[:, :, [-1]], + # dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0, 3]], + dtype=torch.float32) / 255 + xyz = torch.tensor(xyz, dtype=torch.float32) / 255 + + # img = img * mask + # xyz = xyz * mask + + img_list.append(img.reshape(-1)) + xyz_list.append(xyz.reshape(-1)) + + triview_imgs = torch.stack(img_list, dim=-1) + triview_xyzs = torch.stack(xyz_list, dim=-1) + + verts = verts.numpy().astype(np.float32) + faces = faces.numpy().astype(np.int64) + pcd = pcd_tr.numpy().astype(np.float32) + pcd_colors = pcd_colors.numpy().astype(np.float32) + + gt_render_imgs = gt_render_imgs.numpy().astype(np.float32) if gt_render_imgs is not None else None + gt_render_depths = gt_render_depths.numpy().astype(np.float32) if gt_render_depths is not None else None + gt_transforms = gt_transforms.numpy().astype(np.float32) if gt_transforms is not None else None + + triview_imgs = triview_imgs.numpy().astype(np.float32) if triview_imgs is not None else None + triview_xyzs = triview_xyzs.numpy().astype(np.float32) if triview_xyzs is not None else None + + if data_index % 100 == 0: + logging.info(f"process index {self.process_index} end {data_index}") + + return { + "data_index": data_index, + "uuid": data["uuid"], + "verts": verts, + "faces": faces, + "pcd": pcd, + "pcd_colors": pcd_colors, + + "gt_render_imgs": gt_render_imgs, + "gt_render_depths": gt_render_depths, + "gt_transforms": gt_transforms, + "fovx": fovx, + + "triview_imgs": triview_imgs, + "triview_xyzs": triview_xyzs, + "prompt": data.get('prompt') + } + + + def append_data(self, data: dict, + uuid, verts_list, faces_list, pcd_list, pcd_color_list, + render_color_img_list, render_depth_img_list, render_color_cam_list, + fovx_list, triview_color_img_list, triview_xyz_img_list, prompt) -> None: + uuid.append(data['uuid']) + verts_list.append(data['verts']) + faces_list.append(data['faces']) + pcd_list.append(data['pcd']) + pcd_color_list.append(data['pcd_colors']) + + if self.render_color_img_dir != '': + render_color_img_list.append(data['gt_render_imgs']) + render_depth_img_list.append(data['gt_render_depths']) + render_color_cam_list.append(data['gt_transforms']) + fovx_list.append(data['fovx']) + if self.triview_color_dir != '': + triview_color_img_list.append(data['triview_imgs']) + if self.triview_xyz_dir != '': + triview_xyz_img_list.append(data['triview_xyzs']) + + if self.prompt_path != '': + prompt.append(data['prompt']) + + + def prepare_metadata(self): + # multi mesh + for class_name in os.listdir(self.mesh_dir): + if class_name == self.class_name or self.class_name == 'all': + class_dir = os.path.join(self.mesh_dir, class_name) + if class_name.endswith('.json'): + continue + for i, object_name in enumerate(tqdm(os.listdir(class_dir))): + # if i > 999: + # break + if self.dataset_name == 'ShapeNet' and self.class_name == 'all': + record = '/'.join([class_name, object_name]) + elif self.dataset_name == 'Objaverse': + record = os.path.splitext(object_name)[0] + # exclude no transform data + if record in self.objaverse_exclude: + continue + else: + record = object_name + + if (self.mode == 'train' and record in self.train_set) or \ + (self.mode == 'val' and record in self.val_set) or \ + (self.mode == 'test' and record in self.test_set) or \ + (self.mode == 'all' and record in self.all_set): + + if self.dataset_name == 'ShapeNet': + # load vertices and faces + gt_path = os.path.join(class_dir, object_name, 'blank_model.ply') + pcd_file = os.path.join(self.pcd_dir, class_name, object_name, + 'models', f'pc_model_normalized.obj_mat_{self.img_num}_262144_131072.ply') + if self.render_color_img_dir != '': + render_color_img_dir = os.path.join(self.render_color_img_dir, class_name, object_name, + 'img', object_name, 'models') + render_color_cam_file = os.path.join(self.render_color_img_dir, class_name, object_name, + 'img', object_name, 'models', 'transforms.json') + elif self.dataset_name == 'Objaverse': + # load vertices and faces + gt_path = os.path.join(class_dir, object_name) + pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') + if self.render_color_img_dir != '': + render_color_img_dir = os.path.join(self.render_color_img_dir, record) + render_color_cam_file = os.path.join(self.render_color_img_dir, record, 'meta.pkl') + if self.triview_color_dir != '': + triview_color_dir = os.path.join(self.triview_color_dir, record) + if self.triview_xyz_dir != '': + triview_xyz_dir = os.path.join(self.triview_xyz_dir, record) + + res = { + 'gt_path': gt_path, + 'pcd_file': pcd_file, + 'uuid': record + } + + if self.render_color_img_dir != '': + if os.path.exists(render_color_cam_file): + res.update({ + 'render_color_img_dir': render_color_img_dir, + 'render_color_cam_file': render_color_cam_file + }) + else: + print("dont exist render color img", render_color_cam_file) + continue + + if self.triview_color_dir != '': + if os.path.exists(triview_color_dir): + res.update({ + 'triview_color_dir': triview_color_dir + }) + else: + print("dont exist color triview", triview_color_dir) + continue + + if self.triview_xyz_dir != '': + if os.path.exists(triview_xyz_dir): + res.update({ + 'triview_xyz_dir': triview_xyz_dir + }) + else: + print("dont exist color triview", triview_xyz_dir) + continue + + if self.prompt_path != '': + prompt = self.uuid2prompt.get(record, None) + if prompt is not None: + res.update({ + 'prompt': prompt + }) + else: + print("dont exist prompt", prompt) + continue + + self.metadata.append(res) + self.metadata.sort(key=lambda x: x['gt_path']) + + + def _write_one_chunk(self, chunk_index:int, + verts_list: List[torch.FloatTensor], faces_list: List[torch.LongTensor], + pcd_list: List[torch.FloatTensor], pcd_colors_list: List[torch.FloatTensor], + render_color_img_list: List[torch.FloatTensor], render_depth_img_list: List[torch.FloatTensor], + render_color_cam_list: List[torch.FloatTensor], + fovx_list: List[torch.DoubleTensor], triview_color_img_list: List[torch.FloatTensor], + triview_xyz_img_list: List[torch.FloatTensor], uuid: List[str], prompt: List[str], + parquet_writers: List[pq.ParquetWriter]): + logging.info(f"----process {self.process_index} start write index {chunk_index} {parquet_writers[chunk_index].where}----") + indices = torch.randperm(len(verts_list)).tolist() + shuffled_verts_list = [verts_list[i] for i in indices] + shuffled_faces_list = [faces_list[i] for i in indices] + shuffled_pcd_list = [pcd_list[i] for i in indices] + shuffled_pcd_colors_list = [pcd_colors_list[i] for i in indices] + shuffled_uuid = [uuid[i] for i in indices] + if self.render_color_img_dir != '': + shuffled_render_color_img_list = [render_color_img_list[i] for i in indices] + shuffled_render_depth_img_list = [render_depth_img_list[i] for i in indices] + shuffled_render_color_cam_list = [render_color_cam_list[i] for i in indices] + shuffled_fovx_list = [fovx_list[i] for i in indices] + if self.triview_color_dir != '': + shuffled_triview_color_img_list = [triview_color_img_list[i] for i in indices] + if self.triview_xyz_dir != '': + shuffled_triview_xyz_img_list = [triview_xyz_img_list[i] for i in indices] + if self.prompt_path != '': + shuffled_prompt = [prompt[i] for i in indices] + + columns = {} + columns['uuid'] = shuffled_uuid + for i in range(3): + columns['verts_list_{}'.format(i)] = [verts[:, i] for verts in shuffled_verts_list] + columns['faces_list_{}'.format(i)] = [faces[:, i] for faces in shuffled_faces_list] + columns['pcd_list_{}'.format(i)] = [pcd[:, i] for pcd in shuffled_pcd_list] + columns['pcd_colors_list_{}'.format(i)] = [pcd_colors[:, i] for pcd_colors in shuffled_pcd_colors_list] + + if self.render_color_img_dir != '': + for i in range(self.img_num): + columns['render_color_img_list_{}'.format(i)] = [ + render_color_img[:, i] for render_color_img in + shuffled_render_color_img_list + ] + columns['render_depth_img_list_{}'.format(i)] = [ + render_depth_img[:, i] for render_depth_img in + shuffled_render_depth_img_list + ] + columns['render_color_cam_list_{}'.format(i)] = [ + render_color_cam[:, i] for render_color_cam in + shuffled_render_color_cam_list + ] + columns['fovx_list'] = shuffled_fovx_list + + if self.triview_color_dir != '': + for i in range(6): + columns['triview_color_img_list_{}'.format(i)] = [ + triview_color_img[:, i] for triview_color_img in + shuffled_triview_color_img_list + ] + if self.triview_xyz_dir != '': + for i in range(6): + columns['triview_xyz_img_list_{}'.format(i)] = [ + triview_xyz_img[:, i] for triview_xyz_img in + shuffled_triview_xyz_img_list + ] + if self.prompt_path != '': + columns['prompt'] = shuffled_prompt + parquet_writers[chunk_index].write_table(pa.table(columns)) + parquet_writers[chunk_index].close() + # np.save(parquet_writers[chunk_index].where, columns) + logging.info(f"____process {self.process_index}end write index {chunk_index} {parquet_writers[chunk_index].where}____") + + + def _write_chunks(self, chunk_path, chunk_size) -> None: + logging.info("start") + self.prepare_metadata() + logging.info("first for done") + assert ('RANK' not in os.environ) or int(os.environ['LOCAL_RANK']) == 0 + + total_chunks = list(chunk_with_size(self.metadata, chunk_size)) + chunks_for_process = list(chunk_with_number(total_chunks, self.num_process)) + current_process_chunks = chunks_for_process[self.process_index] + + parquet_writers = [] + + logging.info(f'process_index:{self.process_index}, Allocating {len(current_process_chunks)} chunks, \ + with totol size of{sum([len(chunk) for chunk in current_process_chunks])} to dataset path {chunk_path}') + + j = 0 + for p_index in range(self.num_process): + for chunk in chunks_for_process[p_index]: + parquet_path = os.path.join(chunk_path, '{0:06d}.parquet'.format(j)) + j += 1 + if p_index != self.process_index: + continue + self._parquet_paths.append(parquet_path) + + dtypes = [] + dtypes.append(('uuid', pa.string())) + for i in range(3): + dtypes.append(('verts_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append(('faces_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.int64)))) + dtypes.append(('pcd_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append(('pcd_colors_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + if self.render_color_img_dir != '': + for i in range(self.img_num): + dtypes.append(('render_color_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append(('render_depth_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append(('render_color_cam_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append(('fovx_list', pa.list_(pa.from_numpy_dtype(np.float64)))) + if self.triview_color_dir != '': + for i in range(6): + dtypes.append(('triview_color_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + if self.triview_xyz_dir != '': + for i in range(6): + dtypes.append(('triview_xyz_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + if self.prompt_path != '': + dtypes.append(('prompt', pa.string())) + parquet_writers.append(pq.ParquetWriter(parquet_path, pa.schema(dtypes), compression='BROTLI')) + + + + bar_write = tqdm(total=len(current_process_chunks)) + bar_write.set_description("write") + + def do_one_chunk(obj, chunk, chunk_index): + nonlocal bar_write + verts_list, faces_list, pcd_list, pcd_color_list = [], [], [], [] + render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list = [], [], [], [] + triview_color_img_list, triview_xyz_img_list = [], [] + uuid, prompt = [], [] + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + futures = [obj.aprocess_one_data(chunk[i], i) for i in range(len(chunk))] + readed_data = loop.run_until_complete(asyncio.gather(*futures)) + loop.close() + for data in readed_data: + obj.append_data(data, uuid, verts_list, faces_list, pcd_list, pcd_color_list, + render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, + triview_color_img_list, triview_xyz_img_list, prompt) + + obj._write_one_chunk(chunk_index, + verts_list, faces_list, pcd_list, pcd_color_list, + render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, + triview_color_img_list, triview_xyz_img_list, uuid, prompt, + parquet_writers) + bar_write.update(1) + + + task_futures = [] + with ThreadPoolExecutor(max_workers=4) as executor: + for chunk_index, chunk in enumerate(tqdm(current_process_chunks)): + # do_one_chunk(self, chunk, chunk_index) + task_futures.append(executor.submit(do_one_chunk, self, chunk, chunk_index)) + + [task.result() for task in task_futures] # wait for all tasks done + + # for parquet_writer in parquet_writers: + # parquet_writer.close() + + print('Finished writing chunks to dataset paths') diff --git a/datasets/memory_dataset.py b/datasets/memory_dataset.py new file mode 100644 index 0000000..6a3a4a2 --- /dev/null +++ b/datasets/memory_dataset.py @@ -0,0 +1,530 @@ +# Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +# property and proprietary rights in and to this material, related +# documentation and any modifications thereto. Any use, reproduction, +# disclosure or distribution of this material and related documentation +# without an express license agreement from NVIDIA CORPORATION or +# its affiliates is strictly prohibited. +import json +import random +import time +import cv2 +import pickle + +import numpy as np +import torch +import trimesh +import kaolin +import os +import math +from tqdm import tqdm +from PIL import Image + +from .dataset import Dataset +from util import utils, renderer +from util.utils import SHAPENET_MAX_DEPTH, DEPTH_MAX, DEPTH_MIN, DEPTH_VALID_MIN, DEPTH_VALID_MAX + + +class MemoryDataset(Dataset): + def __init__(self, input_specs, train_specs, glctx, tet_grid_size, device, task_mode="debug", validate=False, visual=False): + # Init + super(MemoryDataset, self).__init__(device) + self.glctx = glctx + self.cam_radius = input_specs['radius'] + self.validate = validate + self.visual = visual + self.fovx = np.deg2rad(45) + self.res = input_specs['resolution'] + self.res_img = input_specs['resolution_img'] + self.res_triview = input_specs.get('resolution_triview') + self.aspect = self.res[1] / self.res[0] + self.pts_num = train_specs['sample_points_num'] + self.query_pts_num = train_specs['query_sample_points_num'] + self.epoch = train_specs['num_epochs'] + self.eva_iter = train_specs['eva_iter'] + self.render_mode = train_specs.get('tex_sup_mode') + self.dep_sill_mode = train_specs.get('dep&sill_sup_mode') + self.scale = input_specs['scale'] + + self.pcd_dir = input_specs['pcd_dir'] + self.mesh_dir = input_specs['mesh_dir'] + self.class_name = input_specs['class'] + self.camera_angle_num = input_specs['camera_angle_num'] + self.validate_num = input_specs.get('validate_num') + self.chunk_num = input_specs.get('chunk_num', 1) + self.split_dir = input_specs.get('split_dir') + self.render_img_dir = input_specs.get('render_img_dir', '') + self.triview_color_dir = input_specs.get('triview_color_dir', '') + self.triview_xyz_dir = input_specs.get('triview_xyz_dir', '') + self.prompt_path = input_specs.get('prompt_path', '') + self.dataset_name = input_specs['dataset_name'] + + if self.split_dir: + self.train_set = utils.load_item(os.path.join(self.split_dir, 'train.txt')) + self.val_set = utils.load_item(os.path.join(self.split_dir, 'val.txt')) + random.seed(2023) + self.val_list = sorted(list(self.val_set)) + self.val_list = random.sample(self.val_list, k=self.validate_num) + self.test_set = utils.load_item(os.path.join(self.split_dir, 'test.txt')) + self.objaverse_exclude = utils.load_item(os.path.join(self.split_dir, 'exclude.txt')) + + self.img_num = input_specs.get('img_num', 24) + + self.uuid2transform = utils.load_transform(input_specs.get('blender_transform')) + + if self.prompt_path != '': + self.uuid2prompt = utils.load_prompt(self.prompt_path) + + if task_mode == "debug": + # load raw vertices and faces + ref_mesh = trimesh.load(self.mesh_dir, force='mesh', process=False) + verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) + faces = torch.LongTensor(ref_mesh.faces) + + if self.pcd_dir.endswith(".usd"): + # load point cloud + pcd = kaolin.io.usd.import_pointclouds(self.pcd_dir)[0] + pcd_tr = pcd.points + pcd_colors = pcd.colors + + # scale + verts = verts / torch.max(abs(verts)) * self.scale + pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale + + self.data = [ + {'gt_verts': verts.cpu(), 'gt_faces': faces.cpu(), 'gt_pcd': pcd_tr, 'gt_pcd_colors': pcd_colors}] + + elif self.pcd_dir.endswith(".ply") and self.render_img_dir == '': + self.data = self._preprocess(verts, faces, self.pcd_dir) + + elif self.pcd_dir.endswith('.ply') and self.render_img_dir != '': + # render imgs + filename = os.path.split(self.render_img_dir)[-1] + + if self.dataset_name == 'ShapeNet': + imgdir = os.path.join(self.render_img_dir, 'img', filename, 'models') + elif self.dataset_name == 'Objaverse': + imgdir = self.render_img_dir + else: + raise RuntimeError('Not valid dataset_name') + self.data = self._preprocess(verts, faces, self.pcd_dir, imgdir=imgdir) + + else: + raise RuntimeError('Illegal point cloud format') + + elif task_mode == "batch": + # multi mesh + self.data = [] + for class_name in os.listdir(self.mesh_dir): + if class_name == self.class_name or self.class_name == 'all': + class_dir = os.path.join(self.mesh_dir, class_name) + if class_name.endswith('.json'): + continue + for i, object_name in enumerate(tqdm(os.listdir(class_dir))): + # if i > 99: + # break + if self.dataset_name == 'ShapeNet' and self.class_name == 'all': + record = '/'.join([class_name, object_name]) + elif self.dataset_name == 'Objaverse': + record = os.path.splitext(object_name)[0] + # exclude no transform data + if record in self.objaverse_exclude: + continue + else: + record = object_name + # validate set abort + if self.validate and record not in self.val_list: + continue + # train set abort + if not self.validate and record not in self.train_set: + continue + + if self.dataset_name == 'ShapeNet': + # load vertices and faces + gt_path = os.path.join(class_dir, object_name, 'blank_model.ply') + # load pcd + pcd_file = os.path.join(self.pcd_dir, class_name, object_name, + 'models', + f'pc_model_normalized.obj_mat_{self.img_num}_262144_131072.ply') + + elif self.dataset_name == 'Objaverse': + # load vertices and faces + gt_path = os.path.join(class_dir, object_name) + pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') + + # skip empty folder + if not os.path.exists(gt_path): + continue + + # skip empty folder + if not os.path.exists(pcd_file): + continue + + # load raw vertices and faces + try: + ref_mesh = trimesh.load(gt_path, force='mesh', process=False) + except Exception as e: + continue + + if not hasattr(ref_mesh, 'vertices') or not hasattr(ref_mesh, 'faces'): + continue + + # load point cloud + pcd = trimesh.load(pcd_file) + + if not hasattr(pcd, 'vertices') or not hasattr(pcd, 'colors'): + print("pcd has no attr vertices or colors", pcd_file) + continue + + if len(pcd.vertices) < self.query_pts_num: + print("pcd num less than query_pts_num", pcd_file) + continue + + verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) + faces = torch.LongTensor(ref_mesh.faces) + + if self.render_img_dir == '': + res = self._preprocess(verts, faces, pcd_file, uuid=record) + else: + if self.dataset_name == 'ShapeNet': + imgdir = os.path.join(self.render_img_dir, class_name, object_name, 'img', object_name, 'models') + elif self.dataset_name == 'Objaverse': + imgdir = os.path.join(self.render_img_dir, record) + else: + raise RuntimeError('Not valid dataset_name') + # skip empty folder + if not os.path.exists(imgdir): + continue + res = self._preprocess(verts, faces, pcd_file, uuid=record, imgdir=imgdir) + + res[0].update({'uuid': record}) + + if self.triview_color_dir != '' and self.triview_xyz_dir != '': + img_list, xyz_list = [], [] + triview_color_dir = os.path.join(self.triview_color_dir, record) + triview_xyz_dir = os.path.join(self.triview_xyz_dir, record) + for i in range(6): + # BGR -> RGB + raw = cv2.resize( + cv2.imread(os.path.join(triview_color_dir, f'{i:03d}.png'), cv2.IMREAD_UNCHANGED), + tuple(self.res_triview)) + xyz = cv2.resize( + cv2.imread(os.path.join(triview_xyz_dir, f'xyz_new_{i:03d}.png'), cv2.IMREAD_UNCHANGED), + tuple(self.res_triview)) + mask = torch.tensor(raw[:, :, [-1]], + dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0]], + dtype=torch.float32) / 255 + xyz = torch.tensor(xyz, dtype=torch.float32) / 255 + + img = img * mask + xyz = xyz * mask + + img_list.append(img) + xyz_list.append(xyz) + + triview_imgs = torch.stack(img_list, dim=0) + triview_xyzs = torch.stack(xyz_list, dim=0) + + res[0].update({ + 'triview_color': triview_imgs, + 'triview_xyz': triview_xyzs + }) + + if self.prompt_path != '': + res[0].update({ + 'prompt': self.uuid2prompt.get(os.path.splitext(object_name)[0]) + }) + + if res is not None: + self.data.extend(res) + + else: + raise ValueError("Error! Unrecognized task mode.") + + def _preprocess(self, verts, faces, pcd_file, uuid=None, imgdir=None): + # no render images or no blender mode + if imgdir is None or (self.render_mode != 'blender' and self.dep_sill_mode != 'blender'): + verts -= ((verts.max(0)[0] + verts.min(0)[0]) / 2).unsqueeze(0).repeat( + (verts.shape[0], 1)) + + # load point cloud + pcd = trimesh.load(pcd_file) + pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) + + # rotate & transport + pcd_tr = pcd_tr @ utils.rotate_x(-math.pi / 2).T[:3, :3] + pcd_tr -= ((pcd_tr.max(0)[0] + pcd_tr.min(0)[0]) / 2).unsqueeze(0).repeat((pcd_tr.shape[0], 1)) + + # color, normalized to [-1, 1] + pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] + + # scale + verts = verts / torch.max(abs(verts)) * self.scale + pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale + + return [{ + 'gt_verts': verts, + 'gt_faces': faces, + 'gt_pcd': pcd_tr, + 'gt_pcd_colors': pcd_colors + }] + + else: + # load point cloud + pcd = trimesh.load(pcd_file) + + if not hasattr(pcd, 'vertices') or not hasattr(pcd, 'colors'): + return + + if len(pcd.vertices) < self.query_pts_num: + return + + pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) + + # rotate + verts[:, -1] = -verts[:, -1] + verts = verts[:, [0, 2, 1]] + pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] + + if self.dataset_name == 'ShapeNet': + verts *= self.scale / 0.5 + pcd_tr *= self.scale / 0.5 + + with open(os.path.join(imgdir, 'transforms.json'), 'r') as f: + metadata = json.load(f) + self.fovx = metadata['camera_angle_x'] + img_list, transform_list = [], [] + depth_list = [] + for i, data in enumerate(metadata['frames']): + img_name = data['file_path'] + assert i == int(os.path.splitext(img_name)[0]) + + c2w = torch.tensor(data['transform_matrix'], dtype=torch.float32) + + c2w[:3, 3] *= self.scale / 0.5 + + w2c = torch.inverse(c2w) + # BGR -> RGB -> [-1, 1] + raw = cv2.resize( + cv2.imread(os.path.join(imgdir, img_name), cv2.IMREAD_UNCHANGED), + tuple(self.res_img)) + mask = torch.tensor(raw[:, :, [-1]], + dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0]], + dtype=torch.float32) / 255 + + img = img * mask + + transform_list.append(w2c) + img_list.append(img) + + # depth + depth_name = f'{i:05d}_depth.png' + dep = cv2.imread(os.path.join(imgdir, depth_name), cv2.IMREAD_UNCHANGED) + + # reference + # https://github.com/openai/shap-e/blob/50131012ee11c9d2617f3886c10f000d3c7a3b43/shap_e/rendering/blender/view_data.py#L57-L62 + inf_dist = dep == 0xFFFF + dep = np.where( + inf_dist, + 0., + SHAPENET_MAX_DEPTH * (dep.astype(np.float32) / 65536), + ) + + dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 + + depth_list.append(dep) + + gt_render_imgs = torch.stack(img_list) + gt_transforms = torch.stack(transform_list) + gt_render_depths = torch.stack(depth_list).unsqueeze(-1) + + elif self.dataset_name == 'Objaverse': + if self.uuid2transform: + transform = self.uuid2transform[uuid] + transport = torch.tensor(transform['offset'], dtype=torch.float32) + scale = torch.tensor(transform['scale'], dtype=torch.float32) + verts = (verts * scale + transport) * self.scale / 0.5 + else: + transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 + verts -= transport + scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) + + verts *= self.scale / 0.5 * scale + pcd_tr *= self.scale / 0.5 + + with open(os.path.join(imgdir, 'meta.pkl'), 'rb') as f: + K, _, _, distance, w2cs = pickle.load(f) + + self.fovx = 2 * math.atan(K[0, 2] / K[0, 0]) + + img_list, transform_list = [], [] + depth_list = [] + for i, w2c in enumerate(w2cs): + img_name = f'{i:03d}.png' + + w2c = torch.tensor(np.stack((w2c[0], -w2c[1], -w2c[2], np.array([0., 0., 0., 1.])), axis=0), dtype=torch.float32) + c2w = torch.inverse(w2c) + c2w[:3, 3] *= self.scale / 0.5 + w2c = torch.inverse(c2w) + # BGR -> RGB -> [-1, 1] + raw = cv2.resize( + cv2.imread(os.path.join(imgdir, img_name), cv2.IMREAD_UNCHANGED), + tuple(self.res_img)) + mask = torch.tensor(raw[:, :, [-1]], + dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0]], + dtype=torch.float32) / 255 + + img = img * mask + + transform_list.append(w2c) + img_list.append(img) + + # depth + # syncdreamer + if os.path.exists(os.path.join(imgdir, f'{i:03d}-depth.png')): + depth_name = f'{i:03d}-depth.png' + dep = cv2.imread(os.path.join(imgdir, depth_name), cv2.IMREAD_UNCHANGED) + + # reference + # https://github.com/liuyuan-pal/SyncDreamer/blob/232a2ec22f0277b4bd429109fb34eaf8f61b13ad/eval_mesh.py#L16-L22 + dep = dep.astype(np.float32) / 65535 * (DEPTH_MAX - DEPTH_MIN) + DEPTH_MIN + mask = (dep < DEPTH_VALID_MIN) | (dep > DEPTH_VALID_MAX) + + # cs + elif os.path.exists(os.path.join(imgdir, f'depth_{i:03d}1.png')): + depth_name = f'depth_{i:03d}1.png' + depth_path = os.path.join(imgdir, depth_name) + + dep =(np.array(Image.open(depth_path))[:,:,0]- 64) / 127 + mask = np.array(Image.open(depth_path))[:,:,0] == 255 + + dep = np.where(mask, 0., dep) + + dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 + + depth_list.append(dep) + + gt_render_imgs = torch.stack(img_list) + gt_transforms = torch.stack(transform_list) + gt_render_depths = torch.stack(depth_list).unsqueeze(-1) + + + return [{ + 'gt_verts': verts.cpu(), 'gt_faces': faces.cpu(), + 'gt_pcd': pcd_tr, 'gt_pcd_colors': pcd_colors, + 'gt_render_imgs': gt_render_imgs, 'gt_transforms': gt_transforms, 'gt_render_depths': gt_render_depths}] + + def _sample_scene(self, idx, num, rotate=False): + batch = 1 if rotate else self.camera_angle_num + + proj_mtx = utils.perspective(self.fovx, self.res[1] / self.res[0]) + + if self.render_mode != 'blender' and self.dep_sill_mode != 'blender': + if rotate: + ang = (idx / 20) * np.pi * 2 + mv = utils.translate(0, 0, -self.cam_radius) @ (utils.rotate_x(0.4) @ utils.rotate_y(ang)) + mv = mv.repeat(batch, 1, 1) + else: + mv = torch.bmm( + utils.translate(0, 0, -self.cam_radius).repeat(batch, 1, 1), + utils.batch_random_rotation_translation(self.camera_angle_num, 0.25) + ) + depths = torch.zeros((batch,) + tuple(self.res) + (1,)) + imgs = torch.zeros((batch,) + tuple(self.res) + (3,)) + else: + mv = self.data[num].get('gt_transforms') + img_num = len(mv) + index = random.sample(range(img_num), k=1 if rotate else self.camera_angle_num) + + mv = mv[index] + imgs = self.data[num].get('gt_render_imgs')[index] + depths = self.data[num].get('gt_render_depths')[index] + + mvp = torch.bmm( + proj_mtx.repeat(batch, 1, 1), + mv + ) + campos = torch.linalg.inv(mv)[:, :3, 3] + + return mv.to(self.device), mvp.to(self.device), campos.to(self.device), \ + imgs.to(self.device), depths.to(self.device), proj_mtx.to(self.device), self.res + + def __len__(self): + # return self.epoch if self.validate else self.its_per_epc + return 20 if self.visual else len(self.data) + + def __getitem__(self, idx): + if self.visual: + num = idx % len(self.data) + else: + num = idx + + # rotate or random scene + mv, mvp, campos, imgs, depths, persp, iter_res = self._sample_scene(idx, num, rotate=self.visual) + + if self.dep_sill_mode == 'blender': + alpha = alpha_ctn = (depths > 0).float() + normal, face_normals = renderer.render_mesh( + self.glctx, + self.data[num]['gt_verts'].to(self.device), + self.data[num]['gt_faces'].to(self.device), + mvp, campos, persp, iter_res, + normal_only=True + ) + else: + alpha, alpha_ctn, depths, normal, face_normals = renderer.render_mesh( + self.glctx, + self.data[num]['gt_verts'].to(self.device), + self.data[num]['gt_faces'].to(self.device), + mvp, campos, persp, iter_res + ) + + pcd_num = len(self.data[num]['gt_pcd']) + index = random.sample(range(pcd_num), k=self.pts_num) + index_query = random.sample(range(pcd_num), k=min(self.query_pts_num, self.pts_num)) + + res = { + 'uuid': self.data[num].get('uuid'), + 'gt_verts': self.data[num]['gt_verts'], + 'gt_faces': self.data[num]['gt_faces'], + 'gt_pcd': self.data[num]['gt_pcd'][None, index, ...], + 'gt_pcd_colors': self.data[num]['gt_pcd_colors'][None, index, ...], + 'gt_pcd_colors_query': self.data[num]['gt_pcd_colors'][None, index_query, ], + 'gt_pcd_query': self.data[num]['gt_pcd'][None, index_query, ], + 'gt_render_imgs': imgs[None, ], + 'mv': mv[None, ], + 'mvp': mvp[None, ], + 'campos': campos[None, ], + 'resolution': self.res, + 'resolution_img': self.res_img, + 'resolution_triview': self.res_triview, + 'normal': normal[None, ], + 'alpha': alpha[None, ], + 'alpha_ctn': alpha_ctn[None, ], + 'depth': depths[None, ], + 'persp': persp + } + + if self.triview_color_dir != '': + triview_color = self.data[num]['triview_color'] + res.update({ + 'triview_color': triview_color[None, ], + }) + + if self.triview_xyz_dir != '': + triview_xyz = self.data[num]['triview_xyz'] + res.update({ + 'triview_xyz': triview_xyz[None, ], + }) + + if self.prompt_path != '': + prompt = self.data[num]['prompt'] + res.update({ + 'prompt': [prompt] + }) + + return res diff --git a/make_chunk.py b/make_chunk.py new file mode 100644 index 0000000..d4f3a36 --- /dev/null +++ b/make_chunk.py @@ -0,0 +1,59 @@ +import os +import json +os.environ["CUDA_HOME"] = "/usr/local/cuda-12.1" +import argparse +# import nvdiffrast.torch as dr +from itertools import cycle +from tqdm import tqdm +import torch.distributed as dist + +from datasets.memory_dataset import MemoryDataset +from datasets.filesystem_dataset import FilesystemDataset +from datasets.fast_dataset import FastDataset +# from util.common import pcd_preprocess +from accelerate import Accelerator +from util import utils +from subprocess import Popen, PIPE + + +def main(): + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument( + "--exp_dir", "-e", + default="config/", + help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", + ) + arg_parser.add_argument( + "--config_name", "-c", + default="specs_clear.json", + help="config filename", + ) + + arg_parser.add_argument( + "-p", "--num_process", + default=1, + type=int, + help="Number of processes to use for data loading.", + ) + + + args = arg_parser.parse_args() + config_path = os.path.join(args.exp_dir, args.config_name) + + + python = "/home/yudajiang/softwares/miniforge-pypy3/envs/crm/bin/python" + p_ls = [] + try: + log_f = open("log.log", "w") + for i in range(args.num_process): + p = Popen([python, 'make_chunk_sub.py', '-e', args.exp_dir, '-c', args.config_name, f'-p {args.num_process}',f"-i {i}"], stdout=log_f, stderr=log_f) + p_ls.append(p) + + [p.wait() for p in p_ls] + except: + for p in p_ls: + p.kill() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/make_chunk_sub.py b/make_chunk_sub.py new file mode 100644 index 0000000..d083c20 --- /dev/null +++ b/make_chunk_sub.py @@ -0,0 +1,80 @@ +import os +import json +os.environ["CUDA_HOME"] = "/usr/local/cuda-12.1" +import argparse +# import nvdiffrast.torch as dr +from itertools import cycle +from tqdm import tqdm +import torch.distributed as dist + +from datasets.memory_dataset import MemoryDataset +from datasets.filesystem_dataset import FilesystemDataset +from datasets.fast_dataset import FastDataset +# from util.common import pcd_preprocess +from accelerate import Accelerator +from util import utils +from subprocess import Popen, PIPE + + +def train(specs, config_path): + input_specs = specs['Input'] + task_mode = input_specs['task_mode'] + tet_grid_size = input_specs['tet_grid_size'] + dataset_type = input_specs.get('dataset_type', None) + + train_specs = specs['Train'] + + device = 'cuda:0' + # glctx = dr.RasterizeCudaContext() + glctx = None + + dataset, dataset_val_all = [None] * 2 + + if dataset_type == 'memory' or dataset_type is None: + dataset = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode) + + elif dataset_type == 'filesystem': + dataset = FastDataset(input_specs, train_specs, glctx, device, 0, mode='all') + return dataset + + +def main(): + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument( + "--exp_dir", "-e", + default="config/", + help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", + ) + arg_parser.add_argument( + "--config_name", "-c", + default="specs_clear.json", + help="config filename", + ) + + arg_parser.add_argument( + "-p", "--num_process", + default=1, + type=int, + help="Number of processes to use for data loading.", + ) + + arg_parser.add_argument( + "-i", "--process_index", + default=0, + type=int, + help="Index of the current process.", + ) + + args = arg_parser.parse_args() + config_path = os.path.join(args.exp_dir, args.config_name) + + specs = json.load(open(config_path)) + dataset = train(specs, config_path) + + dataset.num_process = args.num_process + dataset.process_index = args.process_index + dataset._write_chunks(dataset.parquet_dir, dataset.chunk_size) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/metric/lpips/__init__.py b/metric/lpips/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/metric/lpips/lpips.py b/metric/lpips/lpips.py new file mode 100644 index 0000000..3fcd97c --- /dev/null +++ b/metric/lpips/lpips.py @@ -0,0 +1,35 @@ +import torch +import torch.nn as nn + +from metric.lpips.networks import get_network, LinLayers +from metric.lpips.utils import get_state_dict + + +class LPIPS(nn.Module): + r"""Creates a criterion that measures + Learned Perceptual Image Patch Similarity (LPIPS). + Arguments: + net_type (str): the network type to compare the features: + 'alex' | 'squeeze' | 'vgg'. Default: 'alex'. + version (str): the version of LPIPS. Default: 0.1. + """ + def __init__(self, net_type: str = 'alex', version: str = '0.1', device: torch.device = None): + + assert version in ['0.1'], 'v0.1 is only supported now' + + super(LPIPS, self).__init__() + + # pretrained network + self.net = get_network(net_type).to(device) + + # linear layers + self.lin = LinLayers(self.net.n_channels_list).to(device) + self.lin.load_state_dict(get_state_dict(net_type, version, device)) + + def forward(self, x: torch.Tensor, y: torch.Tensor): + feat_x, feat_y = self.net(x), self.net(y) + + diff = [(fx - fy) ** 2 for fx, fy in zip(feat_x, feat_y)] + res = [l(d).mean((2, 3), True) for d, l in zip(diff, self.lin)] + + return torch.sum(torch.cat(res, 0)) / x.shape[0] diff --git a/metric/lpips/networks.py b/metric/lpips/networks.py new file mode 100644 index 0000000..fe9184b --- /dev/null +++ b/metric/lpips/networks.py @@ -0,0 +1,96 @@ +from typing import Sequence + +from itertools import chain + +import torch +import torch.nn as nn +from torchvision import models + +from metric.lpips.utils import normalize_activation + + +def get_network(net_type: str): + if net_type == 'alex': + return AlexNet() + elif net_type == 'squeeze': + return SqueezeNet() + elif net_type == 'vgg': + return VGG16() + else: + raise NotImplementedError('choose net_type from [alex, squeeze, vgg].') + + +class LinLayers(nn.ModuleList): + def __init__(self, n_channels_list: Sequence[int]): + super(LinLayers, self).__init__([ + nn.Sequential( + nn.Identity(), + nn.Conv2d(nc, 1, 1, 1, 0, bias=False) + ) for nc in n_channels_list + ]) + + for param in self.parameters(): + param.requires_grad = False + + +class BaseNet(nn.Module): + def __init__(self): + super(BaseNet, self).__init__() + + # register buffer + self.register_buffer( + 'mean', torch.Tensor([-.030, -.088, -.188])[None, :, None, None]) + self.register_buffer( + 'std', torch.Tensor([.458, .448, .450])[None, :, None, None]) + + def set_requires_grad(self, state: bool): + for param in chain(self.parameters(), self.buffers()): + param.requires_grad = state + + def z_score(self, x: torch.Tensor): + return (x - self.mean) / self.std + + def forward(self, x: torch.Tensor): + x = self.z_score(x) + + output = [] + for i, (_, layer) in enumerate(self.layers._modules.items(), 1): + x = layer(x) + if i in self.target_layers: + output.append(normalize_activation(x)) + if len(output) == len(self.target_layers): + break + return output + + +class SqueezeNet(BaseNet): + def __init__(self): + super(SqueezeNet, self).__init__() + + self.layers = models.squeezenet1_1(True).features + self.target_layers = [2, 5, 8, 10, 11, 12, 13] + self.n_channels_list = [64, 128, 256, 384, 384, 512, 512] + + self.set_requires_grad(False) + + +class AlexNet(BaseNet): + def __init__(self): + super(AlexNet, self).__init__() + + self.layers = models.alexnet(True).features + self.target_layers = [2, 5, 8, 10, 12] + self.n_channels_list = [64, 192, 384, 256, 256] + + self.set_requires_grad(False) + + +class VGG16(BaseNet): + def __init__(self): + super(VGG16, self).__init__() + + self.layers = models.vgg16(True).features + self.target_layers = [4, 9, 16, 23, 30] + self.n_channels_list = [64, 128, 256, 512, 512] + + self.set_requires_grad(False) \ No newline at end of file diff --git a/metric/lpips/utils.py b/metric/lpips/utils.py new file mode 100644 index 0000000..51403b8 --- /dev/null +++ b/metric/lpips/utils.py @@ -0,0 +1,30 @@ +from collections import OrderedDict + +import torch + + +def normalize_activation(x, eps=1e-10): + norm_factor = torch.sqrt(torch.sum(x ** 2, dim=1, keepdim=True)) + return x / (norm_factor + eps) + + +def get_state_dict(net_type: str = 'alex', version: str = '0.1', device: torch.device = None): + # build url + url = 'https://raw.githubusercontent.com/richzhang/PerceptualSimilarity/' \ + + f'master/lpips/weights/v{version}/{net_type}.pth' + + # download + old_state_dict = torch.hub.load_state_dict_from_url( + url, progress=True, + map_location=device if torch.cuda.is_available() else torch.device('cpu') + ) + + # rename keys + new_state_dict = OrderedDict() + for key, val in old_state_dict.items(): + new_key = key + new_key = new_key.replace('lin', '') + new_key = new_key.replace('model.', '') + new_state_dict[new_key] = val + + return new_state_dict diff --git a/metric/shape.py b/metric/shape.py new file mode 100644 index 0000000..d611ca1 --- /dev/null +++ b/metric/shape.py @@ -0,0 +1,169 @@ +from tqdm import tqdm +import numpy as np +import torch +import kaolin +import pytorch3d.loss +from scipy.spatial.distance import cdist + + +############################################################################### +# Reconstruction metrics placed in the following block +############################################################################### + +def vol_intersect_over_union(verts_pred, faces_pred, verts_gt, faces_gt, device=torch.device('cuda')): + axis = torch.linspace(-1., 1., steps=101) + p_x, p_y, p_z = torch.meshgrid(axis, axis, axis, indexing='ij') + points = torch.cat((p_x.unsqueeze(-1), p_y.unsqueeze(-1), p_z.unsqueeze(-1)), dim=3) + points = points.view(1, -1, 3).to(device) + + # CYF note: it's weird that + # 1) cuda face inputs become cpu variable internally + # 2) verts is required dim-3 but faces is dim-2 + in_pred = kaolin.ops.mesh.check_sign(verts_pred, faces_pred.to(device), points) + in_gt = kaolin.ops.mesh.check_sign(verts_gt, faces_gt.to(device), points) + + intersection = torch.logical_and(in_pred, in_gt).sum().float() + union = torch.logical_or(in_pred, in_gt).sum().float() + + return intersection / union + + +def cdist_pt3d(pt_pr, pt_gt, norm): + """ + CYF Note: + utilize the unified pytorch3d method to compute Chamfer distances + """ + + assert norm in [1, 2] + loss, _ = pytorch3d.loss.chamfer_distance(pt_pr, pt_gt, norm=norm, point_reduction="mean", single_directional=False) + + return loss + + +def chamfer_distance(ptr_pred, ptr_gt): + return kaolin.metrics.pointcloud.chamfer_distance(ptr_pred, ptr_gt).mean() + + +def chamfer_distance_l1(ptr_pred, ptr_gt, device): + ptr_pred = ptr_pred.cpu().numpy() + ptr_gt = ptr_gt.cpu().numpy() + + mat = cdist(ptr_pred, ptr_gt, metric='cityblock') + n0, n1 = mat.shape + return torch.tensor(mat.min(axis=0).sum() / n1 + mat.min(axis=1).sum() / n0, dtype=torch.float32, device=device) + + +def silhouette_mask_iou(silhouette_pred, silhouette_gt): + tmp = torch.stack([silhouette_pred, silhouette_gt], dim=0) + inter = torch.all(tmp, dim=0).sum(dim=(1, 2, 3)) + union = torch.any(tmp, dim=0).sum(dim=(1, 2, 3)) + return (inter / union).mean() + + +############################################################################### +# Generative metrics placed in the following block +############################################################################### + +""" +CYF Note: +The following methods are for evaluating generative metrics, i.e., MMD, COV, 1-NNA. +They are borrowed or adapted from two code bases, i.e., LION, and Diffusion-SDF +""" + + +def mmd_cov_1nna(ref_pcds, gen_pcds, b_size): + results = {} + + # MMD and COV results + M_rs_cd = _pairwise_cdist_(ref_pcds, gen_pcds, b_size) + mmd_cd, cov_cd = lgan_mmd_cov(M_rs_cd.t()) + results["MMD-CD"] = mmd_cd + results["COV-CD"] = cov_cd + + # 1-NN results + M_rr_cd = _pairwise_cdist_(ref_pcds, ref_pcds, b_size) + M_ss_cd = _pairwise_cdist_(gen_pcds, gen_pcds, b_size) + one_nn_cd_res = knn(M_rr_cd, M_rs_cd, M_ss_cd, 1, sqrt=False) + results["1-NNA-CD"] = one_nn_cd_res['acc'] + + return results + + +def _pairwise_cdist_(ref_pcds, gen_pcds, b_size): + N_ref = ref_pcds.shape[0] + N_gen = gen_pcds.shape[0] + all_cd = [] + iterator = range(N_gen) + + with tqdm(iterator) as pbar: + for gen_b_start in pbar: + pbar.set_description("Files evaluated: {}/{}".format(gen_b_start, N_gen)) + gen_batch = gen_pcds[gen_b_start] + + cd_lst = [] + for ref_b_start in range(0, N_ref, b_size): + ref_b_end = min(N_ref, ref_b_start + b_size) + ref_batch = ref_pcds[ref_b_start: ref_b_end] + + b_size_ref = ref_batch.size(0) + gen_batch_exp = gen_batch.view(1, -1, 3).expand(b_size_ref, -1, -1) + gen_batch_exp = gen_batch_exp.contiguous() + + cd_b, _ = pytorch3d.loss.chamfer_distance(gen_batch_exp, ref_batch, norm=1, batch_reduction=None, + point_reduction="mean", single_directional=False) + cd_lst.append(cd_b) + + cd_lst = torch.cat(cd_lst, dim=0) + all_cd.append(cd_lst[:, None]) + + all_cd = torch.cat(all_cd, dim=1) # N_ref x N_gen + + return all_cd + + +def lgan_mmd_cov(all_dist): + # all dist shape = [number of generated pcds, number of ref pcds] + N_sample, N_ref = all_dist.size(0), all_dist.size(1) + min_val_fromsmp, min_idx = torch.min(all_dist, dim=1) + min_val, _ = torch.min(all_dist, dim=0) + mmd = min_val.mean() + + cov = float(min_idx.unique().view(-1).size(0)) / float(N_ref) + cov = torch.tensor(cov).to(all_dist) + + return mmd, cov, + + +# Adapted from https://github.com/xuqiantong/GAN-Metrics/blob/master/framework/metric.py +def knn(Mxx, Mxy, Myy, k, sqrt=False): + n0 = Mxx.size(0) + n1 = Myy.size(0) + label = torch.cat((torch.ones(n0), torch.zeros(n1))).to(Mxx) + + M = torch.cat((torch.cat((Mxx, Mxy), 1), torch.cat((Mxy.transpose(0, 1), Myy), 1)), 0) + if sqrt: + M = M.abs().sqrt() + INFINITY = float('inf') + val, idx = (M + torch.diag(INFINITY * torch.ones(n0 + n1).to(Mxx))).topk(k, 0, False) + + count = torch.zeros(n0 + n1).to(Mxx) + for i in range(0, k): + count = count + label.index_select(0, idx[i]) + pred = torch.ge(count, (float(k) / 2) * torch.ones(n0 + n1).to(Mxx)).float() + + s = { + 'tp': (pred * label).sum(), + 'fp': (pred * (1 - label)).sum(), + 'fn': ((1 - pred) * label).sum(), + 'tn': ((1 - pred) * (1 - label)).sum(), + } + + s.update({ + 'precision': s['tp'] / (s['tp'] + s['fp'] + 1e-10), + 'recall': s['tp'] / (s['tp'] + s['fn'] + 1e-10), + 'acc_t': s['tp'] / (s['tp'] + s['fn'] + 1e-10), + 'acc_f': s['tn'] / (s['tn'] + s['fp'] + 1e-10), + 'acc': torch.eq(label, pred).float().mean(), + }) + + return s diff --git a/train_crm.py b/train_crm.py new file mode 100644 index 0000000..ce033ca --- /dev/null +++ b/train_crm.py @@ -0,0 +1,903 @@ +import os +import json +import argparse +import shutil +import kaolin +import re +import random + +import numpy as np +import cv2 +import trimesh +import torch +from pathlib import Path +import time +import nvdiffrast.torch as dr +from itertools import cycle +from tqdm import tqdm +import torch.distributed as dist + +from model import TrDGen, MLPDecoder, PureDecoder, TriDecoder, FullDecoder, PCFullDecoder, PC2FullDecoder + +from util.utils import lr_schedule, nan_to_num +from util.loss import chamfer_loss, laplacian_smooth_loss +from datasets.memory_dataset import MemoryDataset +from datasets.filesystem_dataset import FilesystemDataset +from datasets.fast_dataset import FastDataset +from metric.shape import vol_intersect_over_union, chamfer_distance, chamfer_distance_l1, silhouette_mask_iou + +# from util.common import pcd_preprocess +from torch.utils.tensorboard import SummaryWriter +from accelerate import Accelerator +from util import utils +from util.utils import get_tri +from metric.lpips.lpips import LPIPS +import gc +def train(specs, config_path): + input_specs = specs['Input'] + task_mode = input_specs['task_mode'] + scale = input_specs['scale'] + tet_grid_size = input_specs['tet_grid_size'] + dataset_type = input_specs.get('dataset_type', None) + + train_specs = specs['Train'] + num_epochs = train_specs['num_epochs'] + sup_mode = train_specs["mode"] + sample_points_num = train_specs['sample_points_num'] + batch_size = train_specs['batch_size'] + l_rate = train_specs['learning_rate']['init'] + warmup_iter = train_specs['warm_up'] + scheduler_decay = train_specs['decay'] + eva_iter = train_specs['eva_iter'] + xyz_noise_scale = train_specs.get('xyz_noise_scale', 0.0) + init_mdl_path = train_specs.get('init_mdl_path', None) + eva_all_epoch = train_specs.get('eva_all_epoch') + lambda_nc = train_specs.get('lambda_nc', 0) + grad_acc = train_specs.get('grad_acc', 1) + lambda_lp = train_specs.get('lambda_lp', 0) + lambda_wzy = train_specs.get('lambda_wzy', 0) + save_chunk = train_specs.get('save_chunk') + + output_dirs = specs['Output'] + exp_name = Path(output_dirs['exp_name']) + + geo_type = specs["Train"].get("geo_type", "dmtet") + + if not exp_name.exists(): + exp_name.mkdir(exist_ok=True) + + # ensure output in one folder ( higher than 60% ) + if args.resume: + exp_dir = Path(args.resume) + else: + exp_dir = exp_name / (time.strftime('%m_%d-%H_%M_%S', time.localtime(time.time() // 5 * 5)) + args.note) + exp_dir.mkdir(exist_ok=True) + shutil.copy(config_path, exp_dir) + # + opt_rec_dir = exp_dir / "opt_rec" + opt_rec_dir.mkdir(exist_ok=True) + cur_rec_dir = exp_dir / "cur_rec" + cur_rec_dir.mkdir(exist_ok=True) + val_all_opt_rec_dir = exp_dir / "val_all_opt_rec" + val_all_opt_rec_dir.mkdir(exist_ok=True) + rdr_img_dir = exp_dir / 'rdr_img' + rdr_img_dir.mkdir(exist_ok=True) + + if args.resume: + print('load previous checkpoint') + checkpoint_path = cur_rec_dir / 'previous_params.pth' + if checkpoint_path.exists(): + checkpoint = torch.load(checkpoint_path, map_location=torch.device('cpu')) + epc = checkpoint['epoch'] + chunk = checkpoint['chunk'] + chunk_num = checkpoint['chunk_num'] + # assert chunk_num == input_specs['chunk_num'] + # assert chunk == 0 + start = epc * chunk_num + chunk + iter_all = checkpoint['itr_all'] + cham_dist_opt = checkpoint['cham_dist_opt'] # current best chamfer distance + rgb_err_opt = checkpoint['rgb_err_opt'] # current best rgb error + all_cham_dist_opt = checkpoint['all_cham_dist_opt'] # current best chamfer distance + all_rgb_err_opt = checkpoint['all_rgb_err_opt'] # current best rgb error + else: + raise RuntimeError('No resume checkpoint found, train without --resume') + else: + cham_dist_opt = 9999 # current best chamfer distance + rgb_err_opt = 9999 # current best rgb error + all_cham_dist_opt = 9999 # current best chamfer distance + all_rgb_err_opt = 9999 # current best rgb error + + start = 0 + chunk = 0 + iter_all = 0 # total number of passed training iterations + + accelerator = Accelerator() + # kwargs = DDPK(find_unused_parameters=True) + # accelerator = Accelerator(kwargs_handlers=[kwargs]) + # device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + device = accelerator.device + + # dataset + glctx = dr.RasterizeCudaContext() + + dataset, dataset_val_all = [None] * 2 + + if dataset_type == 'memory': + dataset = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode) + + chunk_num = 1 + + elif dataset_type == 'filesystem': + dataset = FastDataset(input_specs, train_specs, glctx, device, chunk, mode='all') + # dataset_val_all = FilesystemDataset(input_specs, train_specs, glctx, device, mode='val') + + chunk_num = dataset.num_chunk + + dataset_val = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, + validate=True) + dataset_vis = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, + validate=True, visual=True) + + # dataloader_val = torch.utils.data.DataLoader(dataset_val, batch_size=1, + # collate_fn=dataset_val.collate) + # + # for _ in dataloader_val: + # print('@') + + if accelerator.is_main_process: + writer = SummaryWriter(str(exp_dir)) + else: + writer = None + + # Encoder & Decoder & 3-layer MLP HEAD + if specs['Model'] == 'MLP_only': + model = MLPDecoder(specs, exp_dir).to(device) + elif specs['Model'] == 'Pure': + model = PureDecoder(specs, exp_dir).to(device) + elif specs['Model'] == 'Tri': + model = TriDecoder(specs, exp_dir).to(device) + elif specs['Model'] == 'Full': + model = FullDecoder(specs, exp_dir).to(device) + elif specs['Model'] == 'PCFull': + model = PCFullDecoder(specs, exp_dir).to(device) + elif specs['Model'] == 'PC2Full': + model = PC2FullDecoder(specs, exp_dir).to(device) + else: + model = TrDGen(specs, exp_dir).to(device) + + # model.load_state_dict(torch.load("/home/zhengyi/workspace/Text-to-3D/exp/10_31-17_26_34unet-pp/latest_params.pth", map_location = "cuda:"+str(accelerator.process_index))) + if init_mdl_path != None: + model.load_state_dict(torch.load(init_mdl_path, map_location = "cuda:"+str(accelerator.process_index))['model_state_dict'], strict=False) + + # dataset + # glctx = dr.RasterizeCudaContext() + + # dataset, dataset_val_all = [None] * 2 + + # if dataset_type == 'memory' or dataset_type is None: + # dataset = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode) + + # elif dataset_type == 'filesystem': + # dataset = FilesystemDataset(input_specs, train_specs, glctx, device, mode='all') + # # dataset_val_all = FilesystemDataset(input_specs, train_specs, glctx, device, mode='val') + + # chunk_num = dataset.num_chunk + + # dataset_val = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, + # validate=True) + # dataset_vis = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, + # validate=True, visual=True) + + # dataloader_val = torch.utils.data.DataLoader(dataset_val, batch_size=1, + # collate_fn=dataset_val.collate) + # + # for _ in dataloader_val: + # print('@') + + if accelerator.is_main_process: + writer = SummaryWriter(str(exp_dir)) + else: + writer = None + + + + optimizer = torch.optim.AdamW(model.get_params(l_rate))#(model.parameters(), lr=l_rate) + # DJ optimization schedule + scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, + lr_lambda=lambda x: lr_schedule(x, warmup_iter, scheduler_decay)) + + for timestamp in sorted(os.listdir(exp_name), reverse=True): + if re.fullmatch('\d{1,2}_\d{1,2}-\d{1,2}_\d{1,2}_\d{1,2}_tet90', timestamp) \ + and (Path(exp_name) / timestamp / 'val_all_opt_rec' / 'best_shape_params.pth').exists(): + params = Path(exp_name) / timestamp / 'val_all_opt_rec' / 'best_shape_params.pth' + print('load previous 90 tetrahedra checkpoint') + model.load_state_dict(torch.load(params)) + + for name, para in model.named_parameters(): + if 'encoder' in name: + para.requires_grad = False + + input_specs['tet_grid_size'] = 128 + tet_grid_size = input_specs['tet_grid_size'] + + train_specs['batch_size'] //= 2 + batch_size = train_specs['batch_size'] + + break + + if args.resume: + model.load_state_dict(checkpoint['model_state_dict']) + optimizer.load_state_dict(checkpoint['optim_state_dict']) + scheduler.load_state_dict(checkpoint['scheduler_state_dict']) + + lpips = LPIPS(net_type="vgg", device="cuda:" + str(accelerator.process_index)) + + model, optimizer, scheduler, lpips = accelerator.prepare(model, optimizer, scheduler, lpips) + # lpips = lpips.to(device) + + # verts_gt_val = dataset_val.data['gt_verts'] # load ground truth mesh for evaluation + # faces_gt_val = dataset_val.data['gt_faces'] + + # pcd_tr = torch.Tensor(dataset.pcd_tr[None, ...]).cuda() + # CYF comment + # the following shift/scale operation muted + # not seem necessary for ShapeNet pcd + # pcd_tr -= np.mean(pcd_tr, axis=0) + # bbox_length = np.sqrt(np.sum((np.max(pcd_tr, axis=0) - np.min(pcd_tr, axis=0))**2) ) + # pcd_tr /= bbox_length + # + # xyz_tr, gt_pt_tr = pcd_preprocess(pcd_tr) + + # DJ comment: pretrain SDF + # params = 'exp/net_params.pth' + # if not os.path.exists(params): + # self.pre_train_mesh(num_iterations=1000, gt_pc=sampled_pc) + # torch.save(self.state_dict(), params) + # else: + # self.load_state_dict(torch.load(params)) + + # its_per_epc = num_tr_pts // pt_b_size + + # distance between camera and origin + # radius = specs['Train']['radius'] + # mvps = random_scene(radius, num_epochs * its_per_epc) + + # no need to pretrain any more + pretrain = specs['Pretrain'] + if pretrain['mode'] is not None: + # find the most recent state dict + params = None + for timestamp in sorted(os.listdir(exp_name), reverse=True): + if re.fullmatch('\d{1,2}_\d{1,2}-\d{1,2}_\d{1,2}_\d{1,2}', timestamp) \ + and (Path(exp_name) / timestamp / 'net_params.pth').exists(): + params = Path(exp_name) / timestamp / 'net_params.pth' + break + + # !NOTICE Here! + if params: + # print(params) + model.load_state_dict(torch.load(params)) + else: + BVH = None + if pretrain['mode'] == 'sdf_gt': + # init sdf + import cubvh + BVH = cubvh.cuBVH(dataset.verts, dataset.faces) + + # CVX-H initialization + # Note: only for debug mode now; should expand dataloader for batch mode + pcd_num = dataset.data[0]['gt_pcd'].shape[0] + smpl_pcd = dataset.data[0]['gt_pcd'][random.sample(range(pcd_num), k=sample_points_num), ...] + model.pre_train_mesh(pretrain, smpl_pcd, writer, scale, BVH=BVH, device=device) + # model.pre_train_mesh(pretrain, None, writer, scale, BVH=BVH, device=device) + torch.save(model.state_dict(), exp_dir / 'net_params.pth') + + try: + tets = np.load('tets/{}_tets.npz'.format(tet_grid_size)) + except: + tets = np.load('tets/{}_tets.npz'.format(90)) + tet_verts = (torch.tensor(tets['vertices'], dtype=torch.float32, + device=device) * 2 - 1) * scale / 0.95 # covers [-scale/0.95, scale/0.95] + tet_verts = tet_verts[None, ] + tet_indices = torch.tensor(tets['indices'], dtype=torch.long, device=device) + + # # save groundtruth + # if accelerator.is_main_process: + # print('Save groundtruth') + # data = dataset_val.data + # for i in tqdm(range(len(data))): + # mesh = trimesh.Trimesh(vertices=data[i]['gt_verts'], faces=data[i]['gt_faces']) + # mesh.export(os.path.join(opt_rec_dir, f'mesh_{i}_gt.ply')) + # mesh = trimesh.PointCloud(vertices=data[i]['gt_pcd'], colors=data[i]['gt_pcd_colors']) + # mesh.export(os.path.join(opt_rec_dir, f'pcd_{i}_gt.ply')) + # + # # save val_all_groundtruth + # if dataset_val_all is not None: + # dataset_val_all.load_chunk() + # dataloader = torch.utils.data.DataLoader(dataset_val_all, batch_size=1, + # collate_fn=dataset_val_all.collate) + # for i, data in enumerate(tqdm(dataloader)): + # mesh = trimesh.Trimesh(vertices=data['gt_verts'][0].cpu(), faces=data['gt_faces'][0].cpu()) + # mesh.export(os.path.join(val_all_opt_rec_dir, f'mesh_{i}_gt.ply')) + # mesh = trimesh.PointCloud(vertices=data['gt_pcd'][0].cpu(), colors=data['gt_pcd_colors'][0].cpu()) + # mesh.export(os.path.join(val_all_opt_rec_dir, f'pcd_{i}_gt.ply')) + # + # if 'RANK' in os.environ: + # dist.barrier() + + dataloader_vis = torch.utils.data.DataLoader(dataset_vis, batch_size=1, + collate_fn=dataset_vis.collate) + dataloader_vis = cycle(dataloader_vis.__iter__()) + + seed = int(accelerator.process_index) + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + + if save_chunk is None: + save_chunk = chunk_num + + for tmp in range(start, num_epochs * chunk_num + 1): + epc = tmp // chunk_num + chunk = tmp % chunk_num + model.train() + + # if chunk not in [39, 81, 136]: + # continue + + # if dataset_type == 'filesystem' and tmp % (chunk_num * eva_all_epoch) == 0 and tmp > 0: + # # try: + # all_cham_dist_opt, all_rgb_err_opt = eval_and_save( + # accelerator, writer, model, tet_verts, tet_indices, + # sample_points_num, iter_all, dataset_val_all, device, + # val_all_opt_rec_dir, cur_rec_dir, all_cham_dist_opt, all_rgb_err_opt, glctx, + # type='_all') + # # except Exception as e: + # # print(e) + # # print(f'\033[91mtest: 004 error occur\033[0m') + + if (chunk % save_chunk == 0) and accelerator.is_main_process: + torch.save({ + 'epoch': epc, + 'chunk': chunk, + 'chunk_num': chunk_num, + 'itr_all': iter_all, + 'model_state_dict': accelerator.unwrap_model(model).state_dict(), + 'optim_state_dict': optimizer.state_dict(), + 'scheduler_state_dict': scheduler.state_dict(), + 'cham_dist_opt': cham_dist_opt, + 'rgb_err_opt': rgb_err_opt, + 'all_cham_dist_opt': all_cham_dist_opt, + 'all_rgb_err_opt': all_rgb_err_opt, + }, cur_rec_dir / 'previous_params.pth') + + # accelerator.wait_for_everyone() + + if dataset_type == 'filesystem': + dataset.load_chunk() + # skip empty chunk + if len(dataset) == 0: + continue + + try: + dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, + collate_fn=dataset.collate, shuffle=True) + dataloader = accelerator.prepare(dataloader) + except: + continue + + # k = 0.1 + # alpha = train_specs['lambda_color'] * np.clip(k * (epc / num_epochs - 0.5) + 0.05, 0, 0.1) + + # pcd_tr = dataloader.pcd_tr + for iter, data in enumerate(dataloader): + gc.collect() + model.train() + + # mvp = mvps[iter_all] + # pts = pcd_tr[:, itr * pt_b_size: (itr + 1) * pt_b_size].cuda() + # + if accelerator.is_main_process: + print(f"Training@Epoch %i, Chunk %i, Itr %i" % (epc, chunk, iter_all), flush=True) + + # print(data['uuid']) + # iter_all += 1 + # continue + # make data and tet sample size consistent + tet_verts_batch = tet_verts.repeat(data['gt_pcd'].shape[0], 1, 1) + result, verts, faces = model(data, tet_verts_batch, tet_indices, glctx, xyz_noise_scale=xyz_noise_scale) + + lap_loss_list, chamfer_loss_list = [], [] + # try: + for i in range(len(verts)): + lap_loss_list.append(laplacian_smooth_loss(verts[i], faces[i])) + + pred_points = kaolin.ops.mesh.sample_points(verts[i].unsqueeze(0), faces[i], sample_points_num)[0][0] + chamfer_loss_list.append(chamfer_distance(pred_points.unsqueeze(0), data['gt_pcd'][i].unsqueeze(0)).mean()) # use dataloader; pcd_tr.cuda() + + result['lap_loss'] = sum(lap_loss_list) / len(lap_loss_list) + result['chamfer_loss'] = sum(chamfer_loss_list) / len(chamfer_loss_list) + + # except Exception as e: + # print(e) + # print(f'\033[91mtrain: 004 error occur\033[0m') + # result['lap_loss'] = 0. + # result['chamfer_loss'] = 0. + if train_specs['tex_sup_mode'] == 'blender': + reso = result["albedo_list"].shape[-2] + lpips_train = result["albedo_list"].view(-1, result["albedo_list"].shape[-3], result["albedo_list"].shape[-2], result["albedo_list"].shape[-1]).permute(0,3,1,2) + lpips_gt = result["gt_render_imgs"].view(-1, result["gt_render_imgs"].shape[-3], result["gt_render_imgs"].shape[-2], result["gt_render_imgs"].shape[-1]).permute(0,3,1,2) + + if reso > 256: + startx = random.randint(0, reso-256-1) + starty = random.randint(0, reso-256-1) + lpips_train = lpips_train[:,:,startx:startx+256,starty:starty+256] + lpips_gt = lpips_gt[:,:,startx:startx+256,starty:starty+256] + + result['lpips_loss'] = lpips(lpips_train, lpips_gt) + else: + result['lpips_loss'] = 0 + # ) + if sup_mode == "rnd": + # shape supervision I: rendered silhouette and depth losses + loss = result['silhouette_loss']+ result['depth_loss'] + specs['Train']['lambda_smooth'] * result['lap_loss'] \ + + train_specs['lambda_color'] * result['color_loss'] + train_specs['lambda_l2'] * result['reg_loss'] \ + + lambda_nc * result['nc_loss'] + lambda_lp *result['lpips_loss'] + lambda_wzy * result["wzy_loss"] + if geo_type == "flex": + loss = loss + result["flex_surf_loss"] * 0.5 * 0.0 + result["flex_weight_loss"] * 0.1 * 0.1 + elif sup_mode == "pcd": + # shape supervision II: Chamfer distance loss + loss = result['chamfer_loss'] + specs['Train']['lambda_smooth'] * result['lap_loss'] + else: + raise ValueError("Error! Unrecognized supervision mode.") + + + # loss.backward() + # start = time.time() + accelerator.backward(loss) + # print(f'backward: {time.time() - start}') + + # # 打印梯度大小 + # for name, param in model.named_parameters(): + # if param.grad is not None: + # print(f"iter {iter_all+1}, Layer {name}: Grad Max: {param.grad.data.max()}, Grad Min: {param.grad.data.min()}") + + # for name, param in model.named_parameters(): + # if param.grad is not None: + # if torch.isnan(param.grad).sum() > 0: + # print("nan", name, torch.isnan(param.grad).sum()) + # param.grad[torch.isnan(param.grad)] = 0 + # if torch.isinf(param.grad).sum() > 0: + # print("inf", name, torch.isinf(param.grad).sum()) + # param.grad[torch.isinf(param.grad)] = 0 + + params = [param for param in model.parameters() if param.grad is not None] + if len(params) > 0: + flat = torch.cat([param.grad.flatten() for param in params]) + if torch.isnan(flat).any(): + print('==> find nan values') + print('==> nan grad') # We should keep track of this for nan!!!!!! + for name, p in model.named_parameters(): + if p.grad is not None: + if torch.isnan(p.grad).any(): + print(name) + nan_to_num(flat, nan=0, posinf=1e5, neginf=-1e5, out=flat) + grads = flat.split([param.numel() for param in params]) + for param, grad in zip(params, grads): + param.grad = grad.reshape(param.shape) + + if iter_all % grad_acc == 0: + optimizer.step() + scheduler.step() # DJ optimization schedule + torch.cuda.empty_cache() + optimizer.zero_grad() + + # normal = result['normal_image'][0].detach().cpu().numpy() + # cv2.imwrite(model.exp_dir.as_posix() + "/last_normal" +".png", normal*255) + accelerator.wait_for_everyone() + if accelerator.is_main_process: + writer.add_scalar('train/silhouette', result['silhouette_loss'], iter_all) + writer.add_scalar('train/depth', result['depth_loss'], iter_all) + writer.add_scalar('train/Chamfer', result['chamfer_loss'], iter_all) + writer.add_scalar('train/smooth', result['lap_loss'], iter_all) + writer.add_scalar('train/color', result['color_loss'], iter_all) + writer.add_scalar('train/lr', optimizer.param_groups[0]['lr'], iter_all) + writer.add_scalar('train/lpips', result['lpips_loss'], iter_all) + writer.add_scalar('train/wzy', result['wzy_loss'], iter_all) + if geo_type == "flex": + writer.add_scalar('train/flex_weight', result['flex_weight_loss'], iter_all) + writer.add_scalar('train/flex_surf', result['flex_surf_loss'], iter_all) + + # perform evaluation every eva_iter iteration + if iter_all % eva_iter == 0 or (iter_all < 500 and iter_all%20 ==0): + if accelerator.is_main_process and train_specs['tex_sup_mode'] == 'blender': + train_img_dir = exp_dir / 'train_img' + train_img_dir.mkdir(exist_ok=True) + try: + albedos = result["albedo_list2"][0] + except: + albedos = result["albedo_list"][0] + albedo_tensor = torch.cat((albedos[0], albedos[1], albedos[2], albedos[3]), dim=1) + albedo_tensor = albedo_tensor[..., [2, 1, 0]].detach().cpu().numpy() + cv2.imwrite(exp_dir.as_posix() + f"/train_img/ep{epc}-chunk{chunk}-iter{iter_all}-train-" + f"{accelerator.process_index}-" + f"{data.get('prompt',[['null']])[0][0].replace(' ', '-')}.jpg", + albedo_tensor + * 255) + # if accelerator.is_main_process: + # print(accelerator.process_index, data['prompt'], data['uuid']) + model.eval() + # try: + cham_dist_opt, rgb_err_opt = eval_and_save(accelerator, writer, model, tet_verts, tet_indices, + sample_points_num, iter_all, dataset_val, device, + opt_rec_dir, cur_rec_dir, cham_dist_opt, rgb_err_opt, glctx + ) + # except: + # print("eval failed, continue to train") + + # except Exception as e: + # print(e) + # print(f'\033[91mvalidation: 004 error occur\033[0m') + # try: + + if accelerator.is_main_process: + # visualize + data_vis = next(dataloader_vis) + if task_mode != 'debug': + print(data_vis['uuid'],data_vis.get('prompt')) + # print(data_vis['triview_color'].shape) + # print(data_vis['triview_xyz'].shape) + # try: + tnew_list = [0,100,200,300,400,500,600,700,800,900,999] + with torch.no_grad(): + result, verts, faces = accelerator.unwrap_model(model)(data_vis, tet_verts, tet_indices, glctx, tnew=tnew_list[(iter_all//eva_iter)%len(tnew_list)]) + + color_fine, _ = accelerator.unwrap_model(model).render_color_img(verts[0].unsqueeze(dim=0), faces[0], + data_vis, glctx) + color_fine_gt, _ = accelerator.unwrap_model(model).render_color_img(verts[0].unsqueeze(dim=0), faces[0], + data_vis, glctx, gt=True) + color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], + data_vis, glctx, gt=True) + color_shape_gt2 = color_shape_gt[..., [2, 1, 0]].detach().cpu().numpy() + xyzs2 = xyzs[..., [2, 1, 0]].detach().cpu().numpy() + # cv2.imwrite(exp_dir.as_posix() + f"/ep{epc}-chunk{chunk}-rotate.jpg", np.concatenate((xyzs2[0], color_shape_gt2[0]), axis=1)*255) + + # color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], + # data_vis, glctx, gt=True, mvp = side_scene_()[None,...].to(device)) + + # color_shape_gt[2] = color_shape_gt[2].flip(0) + # color_shape_gt[5] = color_shape_gt[5].flip(0) + # color_tensor1 = torch.cat((color_shape_gt[0], color_shape_gt[1], color_shape_gt[2]), dim=1) + # color_tensor2 = torch.cat((color_shape_gt[3], color_shape_gt[4], color_shape_gt[5]), dim=1) + # color_tensor = torch.cat((color_tensor1, color_tensor2.flip(0)), dim = 0) + # color_tensor = color_tensor[..., [2, 1, 0]].detach().cpu().numpy() + + # xyzs[2] = xyzs[2].flip(0) + # xyzs[5] = xyzs[5].flip(0) + # xyzs_tensor1 = torch.cat((xyzs[0], xyzs[1], xyzs[2]), dim=1) + # xyzs_tensor2 = torch.cat((xyzs[3], xyzs[4], xyzs[5]), dim=1) + # xyzs_tensor = torch.cat((xyzs_tensor1, xyzs_tensor2.flip(0)), dim = 0) + # xyzs_tensor = xyzs_tensor.detach().cpu().numpy() + + tri_img_dir = exp_dir / 'tri_img' + tri_img_dir.mkdir(exist_ok=True) + # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-color.jpg",color_tensor * 255) + # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-xyz.jpg",xyzs_tensor * 255) + if specs["Train"].get("random_bg", False): + color = data_vis['triview_color'][0].permute(0,3,1,2).clone() + xyzs = data_vis['triview_xyz'][0].permute(0,3,1,2).clone() + crgb = random.random() + cxyz = random.random() + for j in range(6): + mask = torch.mean(xyzs[j], dim = 0, keepdim=False) + mask = (mask == 0) + for k in range(3): + color[j][k][mask] = crgb + xyzs[j][k][mask] = cxyz + + cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-color-gt.jpg",get_tri(color, blender= True if specs["Train"].get("tex_sup_mode", "pcd-nnb") == 'blender' else False, c=crgb).permute(1,2,0)[..., [2, 1, 0]].detach().cpu().numpy() * 255) + cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-xyz-gt.jpg",get_tri(xyzs, blender= True if specs["Train"].get("tex_sup_mode", "pcd-nnb") == 'blender' else False, c=cxyz).permute(1,2,0).detach().cpu().numpy() * 255) + + # color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], + # data_vis, glctx, mvp = sds_scene(6)[None,...].to(device)) + # color_tensor1 = torch.cat((color_shape_gt[0], color_shape_gt[1], color_shape_gt[2]), dim=1) + # color_tensor2 = torch.cat((color_shape_gt[3], color_shape_gt[4], color_shape_gt[5]), dim=1) + # color_tensor = torch.cat((color_tensor1, color_tensor2), dim = 0) + # color_tensor = color_tensor[..., [2, 1, 0]].detach().cpu().numpy() + + # xyzs_tensor1 = torch.cat((xyzs[0], xyzs[1], xyzs[2]), dim=1) + # xyzs_tensor2 = torch.cat((xyzs[3], xyzs[4], xyzs[5]), dim=1) + # xyzs_tensor = torch.cat((xyzs_tensor1, xyzs_tensor2), dim = 0) + # xyzs_tensor = xyzs_tensor.detach().cpu().numpy() + + + # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-sds-color.jpg",color_tensor * 255) + # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-sds-xyz.jpg",xyzs_tensor * 255) + + img = accelerator.unwrap_model(model).visualize(result, epc, chunk, color_fine, color_fine_gt, rdr_img_dir, iter_all) + # only show the first validation mesh + writer.add_image('eval/visual', img[0], iter_all, dataformats='HWC') + # except Exception as e: + # print(e) + # print(f'\033[91mvisual: 004 error occur\033[0m') + # except: + # print("vis failed") + accelerator.wait_for_everyone() + iter_all += 1 + + return# model + + +def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_points_num, iter_all, dataset, device, + opt_rec_dir, cur_rec_dir, cham_dist_opt, rgb_err_opt, glctx, type=''): + if isinstance(dataset, FilesystemDataset): + num_chunk = dataset.num_chunk + else: + num_chunk = 1 + + chamfer_dist_all, vol_IoU_all, lap_loss_all, verts_list_all, faces_list_all, gt_verts_list_all, gt_faces_list_all, \ + pc_list_all, pc_colors_list_all = [], [], [], [], [], [], [], [], [] + chamfer_l1_all, mask_iou_all, color_loss_all, depth_loss_all, silhouette_loss_all = [], [], [], [], [] + triview_color_list_all, triview_xyz_list_all = [], [] + + for _ in range(num_chunk): + if isinstance(dataset, FilesystemDataset): + dataset.load_chunk() + # skip empty chunk + if len(dataset) == 0: + continue + + dataloader = torch.utils.data.DataLoader(dataset, batch_size=1, + collate_fn=dataset.collate) + + dataloader = accelerator.prepare(dataloader) + + # val_len = len(dataloader_val) + for data_val in tqdm(dataloader): + chamfer_dist, vol_IoU, lap_loss, verts_list, faces_list, gt_verts_list, gt_faces_list, pc_list, pc_colors_list = \ + [], [], [], [], [], [], [], [], [] + chamfer_l1, mask_iou, color_loss, depth_loss, silhouette_loss = [], [], [], [], [] + triview_color_list, triview_xyz_list = [], [] + with torch.no_grad(): + result, verts, faces = accelerator.unwrap_model(model)(data_val, tet_verts, tet_indices, glctx) + + torch.cuda.empty_cache() + # result = dict((key, value.detach().cpu()) for key, value in result.items()) + # verts = tuple(ele.detach().cpu() for ele in verts) + # faces = tuple(ele.detach().cpu() for ele in faces) + # data_val = dict((key, [torch.tensor(ele).detach().cpu() for ele in value] if isinstance(value, list) else value. + # detach().cpu()) for key, value in data_val.items()) + + for i in range(len(verts)): + pred_points = kaolin.ops.mesh.sample_points(verts[i].unsqueeze(0), faces[i], sample_points_num)[0][0] + chamfer_dist.append( + chamfer_distance( + pred_points.unsqueeze(0), data_val['gt_pcd'][i].unsqueeze(0)).detach().cpu().numpy()) # use dataloader + vol_IoU.append(vol_intersect_over_union(verts[i].unsqueeze(dim=0), + faces[i].type(torch.LongTensor), + data_val['gt_verts'][i].unsqueeze(dim=0), + data_val['gt_faces'][i], device=device).detach().cpu().numpy()) + lap_loss.append(laplacian_smooth_loss(verts[i], faces[i]).detach().cpu().numpy()) + chamfer_l1.append( + chamfer_distance_l1(pred_points, data_val['gt_pcd'][i], device=device).detach().cpu().numpy()) + mask_iou.append(silhouette_mask_iou(result['alpha'][i], result['alpha_gt'][i]).detach().cpu().numpy()) + + color_loss.append(result['color_loss'].detach().cpu().numpy()) + depth_loss.append(result['depth_loss'].detach().cpu().numpy()) + silhouette_loss.append(result['silhouette_loss'].detach().cpu().numpy()) + # for multiprocess metric gather + verts_list.append(verts[i].detach().cpu().numpy()) + faces_list.append(faces[i].detach().cpu().numpy()) + gt_verts_list.append(data_val['gt_verts'][i].cpu().numpy()) + gt_faces_list.append(data_val['gt_faces'][i].cpu().numpy()) + pc_list.append(data_val['gt_pcd'].cpu().numpy()) + pc_colors_list.append(data_val['gt_pcd_colors'].cpu().numpy()) + + if data_val.get('triview_color') is None: + triview_color_list.append(np.nan) + else: + triview_color_list.append(data_val['triview_color'].cpu().numpy()) + + if data_val.get('triview_xyz') is None: + triview_xyz_list.append(np.nan) + else: + triview_xyz_list.append(data_val['triview_xyz'].cpu().numpy()) + + chamfer_dist = accelerator.gather_for_metrics(chamfer_dist) + vol_IoU = accelerator.gather_for_metrics(vol_IoU) + lap_loss = accelerator.gather_for_metrics(lap_loss) + mask_iou = accelerator.gather_for_metrics(mask_iou) + chamfer_l1 = accelerator.gather_for_metrics(chamfer_l1) + color_loss = accelerator.gather_for_metrics(color_loss) + depth_loss = accelerator.gather_for_metrics(depth_loss) + silhouette_loss = accelerator.gather_for_metrics(silhouette_loss) + + pc_list = accelerator.gather_for_metrics(pc_list) + pc_colors_list = accelerator.gather_for_metrics(pc_colors_list) + verts_list = accelerator.gather_for_metrics(verts_list) + faces_list = accelerator.gather_for_metrics(faces_list) + gt_verts_list = accelerator.gather_for_metrics(gt_verts_list) + gt_faces_list = accelerator.gather_for_metrics(gt_faces_list) + + triview_color_list = accelerator.gather_for_metrics(triview_color_list) + triview_xyz_list = accelerator.gather_for_metrics(triview_xyz_list) + + torch.cuda.empty_cache() + + chamfer_dist_all.extend(chamfer_dist) + vol_IoU_all.extend(vol_IoU) + lap_loss_all.extend(lap_loss) + mask_iou_all.extend(mask_iou) + chamfer_l1_all.extend(chamfer_l1) + color_loss_all.extend(color_loss) + depth_loss_all.extend(depth_loss) + silhouette_loss_all.extend(silhouette_loss) + + pc_list_all.extend(pc_list) + pc_colors_list_all.extend(pc_colors_list) + verts_list_all.extend(verts_list) + faces_list_all.extend(faces_list) + gt_verts_list_all.extend(gt_verts_list) + gt_faces_list_all.extend(gt_faces_list) + + triview_color_list_all.extend(triview_color_list) + triview_xyz_list_all.extend(triview_xyz_list) + + chamfer_dist = chamfer_dist_all + vol_IoU = vol_IoU_all + lap_loss = lap_loss_all + mask_iou = mask_iou_all + chamfer_l1 = chamfer_l1_all + color_loss = color_loss_all + depth_loss = depth_loss_all + silhouette_loss = silhouette_loss_all + + pc_list = pc_list_all + pc_colors_list = pc_colors_list_all + verts_list = verts_list_all + faces_list = faces_list_all + gt_verts_list = gt_verts_list_all + gt_faces_list = gt_faces_list_all + + triview_color_list = triview_color_list_all + triview_xyz_list = triview_xyz_list_all + + metric = { + 'chamfer_dist': sum(chamfer_dist) / len(chamfer_dist), + 'vol_IoU': sum(vol_IoU) / len(vol_IoU), + 'lap_loss': sum(lap_loss) / len(lap_loss), + 'Mask_IoU': sum(mask_iou) / len(mask_iou), + 'Chamfer_L1': sum(chamfer_l1) / len(chamfer_l1), + 'color_loss': sum(color_loss) / len(color_loss), + 'depth_loss': sum(depth_loss) / len(depth_loss), + 'silhouette_loss': sum(silhouette_loss) / len(silhouette_loss) + } + + if accelerator.is_main_process: + writer.add_scalar(f'eval{type}/Chamfer', metric['chamfer_dist'], iter_all) + writer.add_scalar(f'eval{type}/vol_IoU', metric['vol_IoU'], iter_all) + writer.add_scalar(f'eval{type}/smooth', metric['lap_loss'], iter_all) + writer.add_scalar(f'eval{type}/Chamfer-L1', metric['Chamfer_L1'], iter_all) + writer.add_scalar(f'eval{type}/Mask-IoU', metric['Mask_IoU'], iter_all) + writer.add_scalar(f'eval{type}/color', metric['color_loss'], iter_all) + writer.add_scalar(f'eval{type}/depth', metric['depth_loss'], iter_all) + writer.add_scalar(f'eval{type}/silhouette', metric['silhouette_loss'], iter_all) + + print('ITER %i: C2-Dist, %f (%f); RGB Err, %f (%f); C1-Dist, %f; Mask_IoU, %f; DL, %f; Silh, %f' % + (iter_all, metric['chamfer_dist'], cham_dist_opt, metric['color_loss'], rgb_err_opt, + metric['Chamfer_L1'], metric['Mask_IoU'], metric['depth_loss'], metric['silhouette_loss']), flush=True) + + if 'RANK' in os.environ: + dist.barrier() + + # img = model.visualize(result, epc, chunk) + # # only show the first validation mesh + # writer.add_image('eval/visual', img[0], iter_all, dataformats='HWC') + + zip_data = [(pc, pc_colors, verts, faces, gt_verts, gt_faces, triview_color, triview_xyz) + for pc, pc_colors, verts, faces, gt_verts, gt_faces, triview_color, triview_xyz in + zip(pc_list, pc_colors_list, verts_list, faces_list, gt_verts_list, gt_faces_list, triview_color_list, triview_xyz_list)] + + gpu_idx = accelerator.local_process_index + + def save_export(mode): + if accelerator.is_main_process: + if (opt_rec_dir / f'best_{mode}_params.pth').exists(): + shutil.move(opt_rec_dir / f'best_{mode}_params.pth', opt_rec_dir / f'2nd_{mode}_params.pth') + torch.save(accelerator.unwrap_model(model).state_dict(), opt_rec_dir / f'best_{mode}_params.pth') + + # export mesh ( only eval_all ) + if type != '_all' or specs['ArchSpecs']['pc_enc'] == 'mix': + return + + with accelerator.split_between_processes(zip_data) as tmp_data: + for j, ele in enumerate(tmp_data): + pc, pc_colors, verts, faces, gt_verts, gt_faces, triview_color, triview_xyz = ele + + # export gt + if not os.path.exists(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_mesh.ply')): + mesh = trimesh.Trimesh(vertices=gt_verts, faces=gt_faces) + mesh.export(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_mesh.ply')) + if not os.path.exists(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_pcd.ply')): + pcd = trimesh.PointCloud(vertices=pc[0], colors=pc_colors[0]) + pcd.export(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_pcd.ply')) + + # export pred + data = { + 'gt_verts': torch.tensor(gt_verts, device=device).unsqueeze(0), + 'gt_pcd': torch.tensor(pc, device=device), + 'gt_pcd_color': torch.tensor(pc_colors, device=device), + 'verts': torch.tensor(verts, device=device).unsqueeze(0), + 'faces': torch.tensor(faces, device=device).unsqueeze(0), + 'triview_color': torch.tensor(triview_color, device=device), + 'triview_xyz': torch.tensor(triview_xyz, device=device), + } + if accelerator.unwrap_model(model).exp_uv_mesh: + accelerator.unwrap_model(model).export_mesh_wt_uv(glctx, data, opt_rec_dir, + f'{gpu_idx}_{j}_{mode}', device) + else: + accelerator.unwrap_model(model).export_mesh(data, opt_rec_dir, + f'{gpu_idx}_{j}_{mode}', device) + + # shpae model selection: save current best one + if metric['chamfer_dist'] < cham_dist_opt: + save_export('shape') + cham_dist_opt = metric['chamfer_dist'] + + # texture model selection: save current best one + if metric['color_loss'] < rgb_err_opt: + save_export('texture') + rgb_err_opt = metric['color_loss'] + + + # # for debug purpose, also save current model/performance + # torch.save(accelerator.unwrap_model(model).state_dict(), cur_rec_dir / 'cur_params.pth') + # for i in range(len(verts_list)): + # accelerator.unwrap_model(model).export_mesh(pc_list[i], pc_colors_list[i], + # verts_list[i][None,], faces_list[i], cur_rec_dir, i) + # print out major learning/validation information + + return cham_dist_opt, rgb_err_opt + + +if __name__ == "__main__": + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument( + "--exp_dir", "-e", + default="config/", + help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", + ) + arg_parser.add_argument( + "--config_name", "-c", + default="specs_clear.json", + help="config filename", + ) + arg_parser.add_argument( + "--note", "-n", + default="", + help="extra file name added to the output dir", + ) + arg_parser.add_argument( + "--resume", + default=None, + help="resume training from given checkpoint", + ) + # arg_parser.add_argument( + # "--file", "-f", + # required=True, + # help="input point cloud filepath, in csv or ply format", + # ) + # arg_parser.add_argument( + # "--outdir", "-o", + # required=True, + # help="output directory of reconstruction", + # ) + # + args = arg_parser.parse_args() + if args.resume: + config_path = os.path.join(args.resume, args.config_name) + else: + config_path = os.path.join(args.exp_dir, args.config_name) + specs = json.load(open(config_path)) + # torch.cuda.set_device(1) + # os.environ["CUDA_LAUNCH_BLOCKING"] = "1" + train(specs, config_path) diff --git a/util/loss.py b/util/loss.py new file mode 100644 index 0000000..089e705 --- /dev/null +++ b/util/loss.py @@ -0,0 +1,100 @@ +import torch +import kaolin + + +def laplacian_uniform(verts, faces): + + V = verts.shape[0] + F = faces.shape[0] + + # Neighbor indices + ii = faces[:, [1, 2, 0]].contiguous().flatten() + jj = faces[:, [2, 0, 1]].contiguous().flatten() + adj = torch.stack([torch.cat([ii, jj]), torch.cat([jj, ii])], dim=0).unique(dim=1) + adj_values = torch.ones(adj.shape[1], device=verts.device, dtype=torch.float) + + # 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 + L = torch.sparse_coo_tensor(idx, values, (V, V)).coalesce() + + # CYF Note: added for genuine Laplacian loss computation + # cor_idx = torch.asarray(range(V), device=verts.device) + # cor_idx = torch.stack((cor_idx, cor_idx), dim=0) + # cor_val = torch.asarray([1./L[i, i] for i in range(V)], device=verts.device, dtype=torch.float) + # cor_mat = torch.sparse_coo_tensor(cor_idx, cor_val, (V, V)) + cor_idx = torch.stack((diag_idx, diag_idx), dim=0) + cor_mat_ = torch.sparse_coo_tensor(cor_idx, adj_values, (V, V)).coalesce() + cor_mat = torch.sparse_coo_tensor(cor_mat_.indices(), 1. / cor_mat_.values(), (V, V)) + + return cor_mat.mm(L) + + +@torch.cuda.amp.autocast(enabled=False) +def laplacian_smooth_loss(verts, faces): + with torch.no_grad(): + L = laplacian_uniform(verts, faces.long()) + loss = L.mm(verts) + loss = loss.norm(dim=1) + loss = loss.mean() + return loss + + +def compute_edge_to_face_mapping(attr_idx): + with torch.no_grad(): + # Get unique edges + # Create all edges, packed by triangle + all_edges = torch.cat(( + torch.stack((attr_idx[:, 0], attr_idx[:, 1]), dim=-1), + torch.stack((attr_idx[:, 1], attr_idx[:, 2]), dim=-1), + torch.stack((attr_idx[:, 2], attr_idx[:, 0]), dim=-1), + ), dim=-1).view(-1, 2) + + # Swap edge order so min index is always first + order = (all_edges[:, 0] > all_edges[:, 1]).long().unsqueeze(dim=1) + sorted_edges = torch.cat(( + torch.gather(all_edges, 1, order), + torch.gather(all_edges, 1, 1 - order) + ), dim=-1) + + # Elliminate duplicates and return inverse mapping + unique_edges, idx_map = torch.unique(sorted_edges, dim=0, return_inverse=True) + + tris = torch.arange(attr_idx.shape[0]).repeat_interleave(3).cuda() + + tris_per_edge = torch.zeros((unique_edges.shape[0], 2), dtype=torch.int64).cuda() + + # Compute edge to face table + mask0 = order[:,0] == 0 + mask1 = order[:,0] == 1 + tris_per_edge[idx_map[mask0], 0] = tris[mask0] + tris_per_edge[idx_map[mask1], 1] = tris[mask1] + + return tris_per_edge + + +@torch.cuda.amp.autocast(enabled=False) +def normal_consistency(face_normals, t_pos_idx): + + tris_per_edge = compute_edge_to_face_mapping(t_pos_idx) + + # Fetch normals for both faces sharind an edge + n0 = face_normals[tris_per_edge[:, 0], :] + n1 = face_normals[tris_per_edge[:, 1], :] + + # Compute error metric based on normal difference + term = torch.clamp(torch.sum(n0 * n1, -1, keepdim=True), min=-1.0, max=1.0) + term = (1.0 - term) + + return torch.mean(torch.abs(term)) + + +def chamfer_loss(verts, faces, pcd_tr, test_point_num=5000): + pred_points = kaolin.ops.mesh.sample_points(verts.unsqueeze(0), faces, test_point_num)[0][0] + loss = kaolin.metrics.pointcloud.chamfer_distance(pred_points.unsqueeze(0), pcd_tr.cuda()).mean() + return loss From 8ad3baa20df10525fed1cffa800020df61128274 Mon Sep 17 00:00:00 2001 From: yudajiang Date: Tue, 26 Nov 2024 11:24:05 +0800 Subject: [PATCH 2/4] update: clear the code 1. README add pytorch installation and train procedures 2. Remove pcd related code 3. Remove shapenet related code 4. Specify packages version in requirements.txt 5. Remove useless code 6. Modify .gitignore --- .gitignore | 4 +- README.md | 31 +- configs/specs_objaverse_lvis.json | 8 +- datasets/dataset.py | 8 +- datasets/fast_dataset.py | 235 +++++++------- datasets/memory_dataset.py | 244 +++++++------- make_chunk.py | 20 +- make_chunk_sub.py | 31 +- model/crm/model.py | 518 +++++++++++++++++++++++++++++- requirements.txt | 6 +- train_crm.py | 339 ++++++------------- util/renderer.py | 104 +++++- util/utils.py | 16 + 13 files changed, 1010 insertions(+), 554 deletions(-) diff --git a/.gitignore b/.gitignore index e0657c2..f60b256 100644 --- a/.gitignore +++ b/.gitignore @@ -152,4 +152,6 @@ dmypy.json # Cython debug symbols cython_debug/ -out/ \ No newline at end of file +out/ +data/ +exp-*/ diff --git a/README.md b/README.md index e97fec2..87a66be 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,12 @@ Install nvdiffrast according to the official [doc](https://nvlabs.github.io/nvdi pip install git+https://github.com/NVlabs/nvdiffrast ``` +### Step 3 - Pytorch3d +Install nvdiffrast according to the official [doc](https://github.com/facebookresearch/pytorch3d/blob/main/INSTALL.md), e.g. +```bash +pip install git+https://github.com/facebookresearch/pytorch3d.git +``` ## Inference @@ -61,7 +66,31 @@ It will output the preprocessed image, generated 6-view images and CCMs and a 3D **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. -## Train + +## Train CRM +### Step 1. Generate Chunks +Multiprocess multi-threads chunks generation +```bash +python make_chunk.py -c specs_xxxx.json -p 4 # change to proper number of process for your machine +``` + +### Step 2. Train +Use the same config json file in **step.1** for training +#### Single GPU +```bash +python train_crm.py -c specs_xxx.json +``` +#### Multi GPU +```bash +torchrun --standalone --nproc_per_node=8 train_crm.py -c specs_xxx.json + +# Training break to resume training +torchrun --standalone --nproc_per_node=8 train_crm.py --resume exp-xxx/mm_dd-hh_mm_ss + +``` + + +## Train Diffusion We provide training script for multivew generation and their data requirements. To launch a simple one instance overfit training of multivew gen: ```shell diff --git a/configs/specs_objaverse_lvis.json b/configs/specs_objaverse_lvis.json index ff69ce8..0a66f4d 100644 --- a/configs/specs_objaverse_lvis.json +++ b/configs/specs_objaverse_lvis.json @@ -3,7 +3,6 @@ "Input": { "task_mode": "batch", - "pcd_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis_ply", "mesh_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis_mesh", "render_img_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis", "blender_transform": "/home/yudajiang/datasets/Objaverse/normalize_anno/meta_data_new.json", @@ -48,17 +47,14 @@ "warm_up": 0, "decay": 0.000, "learning_rate": { - "init": 1e-4, - "sdf_decay": 1.0, - "rgb_decay": 1.0 + "init": 1e-4 }, "sample_points_num": 20000, "query_sample_points_num": 60000, "batch_size": 1, "eva_iter": 80, "save_chunk": 50, - "xyz_noise_scale": 0.00, - "eva_all_epoch": 10, + "eva_all_epoch": 0, "tex_sup_mode": "blender", "dep&sill_sup_mode": "blender", "lambda_smooth": 1, diff --git a/datasets/dataset.py b/datasets/dataset.py index 8b75b62..3168b3b 100644 --- a/datasets/dataset.py +++ b/datasets/dataset.py @@ -29,10 +29,10 @@ def collate(self, batch): # iter_spp = batch[0]['spp'] res = { 'uuid': list([item['uuid'] for item in batch]), - 'gt_pcd': torch.cat(list([item['gt_pcd'] for item in batch]), dim=0).to(self.device), - 'gt_pcd_colors': torch.cat(list([item['gt_pcd_colors'] for item in batch])).to(self.device), - 'gt_pcd_query': torch.cat(list([item['gt_pcd_query'] for item in batch]), dim=0).to(self.device), - 'gt_pcd_colors_query': torch.cat(list([item['gt_pcd_colors_query'] for item in batch])).to(self.device), + # 'gt_pcd': torch.cat(list([item['gt_pcd'] for item in batch]), dim=0).to(self.device), + # 'gt_pcd_colors': torch.cat(list([item['gt_pcd_colors'] for item in batch])).to(self.device), + # 'gt_pcd_query': torch.cat(list([item['gt_pcd_query'] for item in batch]), dim=0).to(self.device), + # 'gt_pcd_colors_query': torch.cat(list([item['gt_pcd_colors_query'] for item in batch])).to(self.device), 'gt_render_imgs': torch.cat(list([item['gt_render_imgs'] for item in batch]), dim=0).to(self.device), # 'verts': torch.cat(list([item['verts'] for item in batch]), dim=0).to(self.device), # 'tets': tets.to(self.device), diff --git a/datasets/fast_dataset.py b/datasets/fast_dataset.py index b4af2fb..70cbc82 100644 --- a/datasets/fast_dataset.py +++ b/datasets/fast_dataset.py @@ -17,7 +17,7 @@ from tqdm import tqdm from .dataset import Dataset from util import utils, renderer -from util.utils import SHAPENET_MAX_DEPTH, DEPTH_MAX, DEPTH_MIN, DEPTH_VALID_MIN, DEPTH_VALID_MAX +from util.utils import DEPTH_MAX, DEPTH_MIN, DEPTH_VALID_MIN, DEPTH_VALID_MAX import json import cv2 from PIL import Image @@ -91,7 +91,7 @@ def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_pro self.dep_sill_mode = train_specs.get('dep&sill_sup_mode') # self.mode = input_specs['mode'] - self.pcd_dir = input_specs['pcd_dir'] + # self.pcd_dir = input_specs['pcd_dir'] self.mesh_dir = input_specs['mesh_dir'] self.class_name = input_specs['class'] self.camera_angle_num = input_specs['camera_angle_num'] @@ -159,8 +159,8 @@ def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_pro self._loaded_uuid = None self._loaded_verts_list = None self._loaded_faces_list = None - self._loaded_pcd_list = None - self._loaded_pcd_colors_list = None + # self._loaded_pcd_list = None + # self._loaded_pcd_colors_list = None self._loaded_render_color_img_list = None self._loaded_render_depth_img_list = None self._loaded_render_color_cam_list = None @@ -173,7 +173,7 @@ def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_pro self._chosen = None def load_chunk(self) -> None: - chosen, self._loaded_verts_list, self._loaded_faces_list, self._loaded_pcd_list, self._loaded_pcd_colors_list, \ + chosen, self._loaded_verts_list, self._loaded_faces_list, \ self._loaded_render_color_img_list, self._loaded_render_depth_img_list, \ self._loaded_render_color_cam_list, self._loaded_fovx_list, \ self._loaded_triview_color_img_list, self._loaded_triview_xyz_img_list, self._loaded_prompt, self._loaded_uuid= \ @@ -283,9 +283,9 @@ def __getitem__(self, idx): mvp, campos, persp, iter_res ) - pcd_num = len(self._loaded_pcd_list[idx]) - index = random.sample(range(pcd_num), k=self.pts_num) - index_query = random.sample(range(pcd_num), k=self.query_pts_num) + # pcd_num = len(self._loaded_pcd_list[idx]) + # index = random.sample(range(pcd_num), k=self.pts_num) + # index_query = random.sample(range(pcd_num), k=self.query_pts_num) res = { # 'verts': self.verts[None, ...], @@ -293,10 +293,10 @@ def __getitem__(self, idx): 'uuid': self._loaded_uuid[idx], 'gt_verts': self._loaded_verts_list[idx], 'gt_faces': self._loaded_faces_list[idx], - 'gt_pcd': self._loaded_pcd_list[idx][None, index, ...], - 'gt_pcd_colors': self._loaded_pcd_colors_list[idx][None, index, ...], - 'gt_pcd_colors_query': self._loaded_pcd_colors_list[idx][None, index_query, ], - 'gt_pcd_query': self._loaded_pcd_list[idx][None, index_query, ], + # 'gt_pcd': self._loaded_pcd_list[idx][None, index, ...], + # 'gt_pcd_colors': self._loaded_pcd_colors_list[idx][None, index, ...], + # 'gt_pcd_colors_query': self._loaded_pcd_colors_list[idx][None, index_query, ], + # 'gt_pcd_query': self._loaded_pcd_list[idx][None, index_query, ], 'gt_render_imgs': imgs[None,], 'mv': mv[None, ], 'mvp': mvp[None, ], @@ -373,12 +373,12 @@ def _load_chunk_inner(self) -> Tuple[str, List[torch.FloatTensor], List[torch.Lo faces_list = [torch.LongTensor(np.stack( [pandas_chunk[f'faces_list_{j}'][i] for j in range(3)], axis=-1) ) for i in range(num_rows)] - pcd_list = [torch.FloatTensor(np.stack( - [pandas_chunk[f'pcd_list_{j}'][i] for j in range(3)], axis=-1) - ) for i in range(num_rows)] - pcd_colors_list = [torch.FloatTensor(np.stack( - [pandas_chunk[f'pcd_colors_list_{j}'][i] for j in range(3)], axis=-1) - ) for i in range(num_rows)] + # pcd_list = [torch.FloatTensor(np.stack( + # [pandas_chunk[f'pcd_list_{j}'][i] for j in range(3)], axis=-1) + # ) for i in range(num_rows)] + # pcd_colors_list = [torch.FloatTensor(np.stack( + # [pandas_chunk[f'pcd_colors_list_{j}'][i] for j in range(3)], axis=-1) + # ) for i in range(num_rows)] uuid = [str(pandas_chunk['uuid'][i]) for i in range(num_rows)] render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list = None, None, None, None @@ -411,7 +411,7 @@ def _load_chunk_inner(self) -> Tuple[str, List[torch.FloatTensor], List[torch.Lo if self.prompt_path != '': prompt = [str(pandas_chunk['prompt'][i]) for i in range(num_rows)] - return str(chosen), verts_list, faces_list, pcd_list, pcd_colors_list, \ + return str(chosen), verts_list, faces_list, \ render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, \ triview_color_img_list, triview_xyz_img_list, prompt, uuid @@ -423,7 +423,7 @@ async def aprocess_one_data(self, data: dict, data_index:int): logging.info(f"process index {self.process_index} start {data_index}") gt_path = data['gt_path'] - pcd_file = data['pcd_file'] + # pcd_file = data['pcd_file'] gt_bytes = await aread_file(gt_path) ref_mesh = trimesh.load(io.BytesIO(gt_bytes), @@ -431,11 +431,11 @@ async def aprocess_one_data(self, data: dict, data_index:int): verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) faces = torch.LongTensor(ref_mesh.faces) - pcd_bytes = await aread_file(pcd_file) + # pcd_bytes = await aread_file(pcd_file) # load point cloud - pcd = trimesh.load(io.BytesIO(pcd_bytes), file_type=Path(pcd_file).suffix) + # pcd = trimesh.load(io.BytesIO(pcd_bytes), file_type=Path(pcd_file).suffix) - pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) + # pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) gt_render_imgs = None gt_render_depths = None gt_transforms = None @@ -448,65 +448,65 @@ async def aprocess_one_data(self, data: dict, data_index:int): verts = verts[:, [0, 2, 1]] # color, normalized to [-1, 1] - pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] + # pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] - if self.dataset_name == 'ShapeNet': + # if self.dataset_name == 'ShapeNet': - metadata = json.loads(await aread_file(render_color_cam_file, "r")) + # metadata = json.loads(await aread_file(render_color_cam_file, "r")) - verts *= self.scale / 0.5 - pcd_tr *= self.scale / 0.5 - fovx = np.array([metadata['camera_angle_x']], dtype=np.float64) - img_list, depth_list, transform_list = [], [], [] - - assert self.img_num == len(metadata['frames']) - image_paths = [os.path.join(render_color_img_dir, metadata['frames'][i]["file_path"]) for i in range(self.img_num)] - bytes_images = await abatch_read_files(image_paths) - images = batch_buffer_to_cv2image(bytes_images) - for i, item in enumerate(metadata['frames']): - img_name = item['file_path'] - assert i == int(os.path.splitext(img_name)[0]) - - c2w = torch.tensor(item['transform_matrix'], dtype=torch.float32) - - c2w[:3, 3] *= self.scale / 0.5 - - w2c = torch.inverse(c2w) - # BGR -> RGB - raw = cv2.resize(images[i], tuple(self.res_img)) - # mask = torch.tensor(raw[:, :, [-1]], - # dtype=torch.float32).repeat(1, 1, 3) / 255 - img = torch.tensor(raw[:, :, [2, 1, 0, 3]], - dtype=torch.float32) / 255 - - # img = img * mask - - transform_list.append(w2c.reshape(-1)) - img_list.append(img.reshape(-1)) - - # depth - depth_name = f'{i:05d}_depth.png' - dep = cv2.imread(os.path.join(render_color_img_dir, depth_name), cv2.IMREAD_UNCHANGED) - - # reference - # https://github.com/openai/shap-e/blob/50131012ee11c9d2617f3886c10f000d3c7a3b43/shap_e/rendering/blender/view_data.py#L57-L62 - inf_dist = dep == 0xFFFF - dep = np.where( - inf_dist, - 0., - SHAPENET_MAX_DEPTH * (dep.astype(np.float32) / 65536), - ) - - dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 - - depth_list.append(dep.reshape(-1)) - elif self.dataset_name == 'Objaverse': + # verts *= self.scale / 0.5 + # # pcd_tr *= self.scale / 0.5 + # fovx = np.array([metadata['camera_angle_x']], dtype=np.float64) + # img_list, depth_list, transform_list = [], [], [] + + # assert self.img_num == len(metadata['frames']) + # image_paths = [os.path.join(render_color_img_dir, metadata['frames'][i]["file_path"]) for i in range(self.img_num)] + # bytes_images = await abatch_read_files(image_paths) + # images = batch_buffer_to_cv2image(bytes_images) + # for i, item in enumerate(metadata['frames']): + # img_name = item['file_path'] + # assert i == int(os.path.splitext(img_name)[0]) + + # c2w = torch.tensor(item['transform_matrix'], dtype=torch.float32) + + # c2w[:3, 3] *= self.scale / 0.5 + + # w2c = torch.inverse(c2w) + # # BGR -> RGB + # raw = cv2.resize(images[i], tuple(self.res_img)) + # # mask = torch.tensor(raw[:, :, [-1]], + # # dtype=torch.float32).repeat(1, 1, 3) / 255 + # img = torch.tensor(raw[:, :, [2, 1, 0, 3]], + # dtype=torch.float32) / 255 + + # # img = img * mask + + # transform_list.append(w2c.reshape(-1)) + # img_list.append(img.reshape(-1)) + + # # depth + # depth_name = f'{i:05d}_depth.png' + # dep = cv2.imread(os.path.join(render_color_img_dir, depth_name), cv2.IMREAD_UNCHANGED) + + # # reference + # # https://github.com/openai/shap-e/blob/50131012ee11c9d2617f3886c10f000d3c7a3b43/shap_e/rendering/blender/view_data.py#L57-L62 + # inf_dist = dep == 0xFFFF + # dep = np.where( + # inf_dist, + # 0., + # SHAPENET_MAX_DEPTH * (dep.astype(np.float32) / 65536), + # ) + + # dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 + + # depth_list.append(dep.reshape(-1)) + if self.dataset_name == 'Objaverse': # transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 # verts -= transport # scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) # # verts *= self.scale / 0.5 * scale - pcd_tr *= self.scale / 0.5 + # pcd_tr *= self.scale / 0.5 K, _, _, _, w2cs = pickle.load(io.BytesIO(await aread_file(render_color_cam_file))) @@ -577,20 +577,20 @@ async def aprocess_one_data(self, data: dict, data_index:int): gt_transforms = torch.stack(transform_list, dim=-1) gt_render_depths = torch.stack(depth_list, dim=-1) - else: - verts -= ((verts.max(0)[0] + verts.min(0)[0]) / 2).unsqueeze(0).repeat( - (verts.shape[0], 1)) + # else: + # verts -= ((verts.max(0)[0] + verts.min(0)[0]) / 2).unsqueeze(0).repeat( + # (verts.shape[0], 1)) - # rotate & transport - pcd_tr = pcd_tr @ utils.rotate_x(-math.pi / 2).T[:3, :3] - pcd_tr -= ((pcd_tr.max(0)[0] + pcd_tr.min(0)[0]) / 2).unsqueeze(0).repeat((pcd_tr.shape[0], 1)) + # # rotate & transport + # pcd_tr = pcd_tr @ utils.rotate_x(-math.pi / 2).T[:3, :3] + # pcd_tr -= ((pcd_tr.max(0)[0] + pcd_tr.min(0)[0]) / 2).unsqueeze(0).repeat((pcd_tr.shape[0], 1)) - # scale - verts = verts / torch.max(abs(verts)) * self.scale - pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale + # # scale + # verts = verts / torch.max(abs(verts)) * self.scale + # pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale - # color - pcd_colors = (2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255)[..., :3] / 255 + # # color + # pcd_colors = (2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255)[..., :3] / 255 triview_imgs = None triview_xyzs = None @@ -633,8 +633,8 @@ async def aprocess_one_data(self, data: dict, data_index:int): verts = verts.numpy().astype(np.float32) faces = faces.numpy().astype(np.int64) - pcd = pcd_tr.numpy().astype(np.float32) - pcd_colors = pcd_colors.numpy().astype(np.float32) + # pcd = pcd_tr.numpy().astype(np.float32) + # pcd_colors = pcd_colors.numpy().astype(np.float32) gt_render_imgs = gt_render_imgs.numpy().astype(np.float32) if gt_render_imgs is not None else None gt_render_depths = gt_render_depths.numpy().astype(np.float32) if gt_render_depths is not None else None @@ -651,8 +651,8 @@ async def aprocess_one_data(self, data: dict, data_index:int): "uuid": data["uuid"], "verts": verts, "faces": faces, - "pcd": pcd, - "pcd_colors": pcd_colors, + # "pcd": pcd, + # "pcd_colors": pcd_colors, "gt_render_imgs": gt_render_imgs, "gt_render_depths": gt_render_depths, @@ -666,14 +666,14 @@ async def aprocess_one_data(self, data: dict, data_index:int): def append_data(self, data: dict, - uuid, verts_list, faces_list, pcd_list, pcd_color_list, + uuid, verts_list, faces_list, render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, triview_color_img_list, triview_xyz_img_list, prompt) -> None: uuid.append(data['uuid']) verts_list.append(data['verts']) faces_list.append(data['faces']) - pcd_list.append(data['pcd']) - pcd_color_list.append(data['pcd_colors']) + # pcd_list.append(data['pcd']) + # pcd_color_list.append(data['pcd_colors']) if self.render_color_img_dir != '': render_color_img_list.append(data['gt_render_imgs']) @@ -714,20 +714,20 @@ def prepare_metadata(self): (self.mode == 'test' and record in self.test_set) or \ (self.mode == 'all' and record in self.all_set): - if self.dataset_name == 'ShapeNet': - # load vertices and faces - gt_path = os.path.join(class_dir, object_name, 'blank_model.ply') - pcd_file = os.path.join(self.pcd_dir, class_name, object_name, - 'models', f'pc_model_normalized.obj_mat_{self.img_num}_262144_131072.ply') - if self.render_color_img_dir != '': - render_color_img_dir = os.path.join(self.render_color_img_dir, class_name, object_name, - 'img', object_name, 'models') - render_color_cam_file = os.path.join(self.render_color_img_dir, class_name, object_name, - 'img', object_name, 'models', 'transforms.json') - elif self.dataset_name == 'Objaverse': + # if self.dataset_name == 'ShapeNet': + # # load vertices and faces + # gt_path = os.path.join(class_dir, object_name, 'blank_model.ply') + # pcd_file = os.path.join(self.pcd_dir, class_name, object_name, + # 'models', f'pc_model_normalized.obj_mat_{self.img_num}_262144_131072.ply') + # if self.render_color_img_dir != '': + # render_color_img_dir = os.path.join(self.render_color_img_dir, class_name, object_name, + # 'img', object_name, 'models') + # render_color_cam_file = os.path.join(self.render_color_img_dir, class_name, object_name, + # 'img', object_name, 'models', 'transforms.json') + if self.dataset_name == 'Objaverse': # load vertices and faces gt_path = os.path.join(class_dir, object_name) - pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') + # pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') if self.render_color_img_dir != '': render_color_img_dir = os.path.join(self.render_color_img_dir, record) render_color_cam_file = os.path.join(self.render_color_img_dir, record, 'meta.pkl') @@ -738,7 +738,7 @@ def prepare_metadata(self): res = { 'gt_path': gt_path, - 'pcd_file': pcd_file, + # 'pcd_file': pcd_file, 'uuid': record } @@ -786,7 +786,7 @@ def prepare_metadata(self): def _write_one_chunk(self, chunk_index:int, verts_list: List[torch.FloatTensor], faces_list: List[torch.LongTensor], - pcd_list: List[torch.FloatTensor], pcd_colors_list: List[torch.FloatTensor], + # pcd_list: List[torch.FloatTensor], pcd_colors_list: List[torch.FloatTensor], render_color_img_list: List[torch.FloatTensor], render_depth_img_list: List[torch.FloatTensor], render_color_cam_list: List[torch.FloatTensor], fovx_list: List[torch.DoubleTensor], triview_color_img_list: List[torch.FloatTensor], @@ -796,8 +796,8 @@ def _write_one_chunk(self, chunk_index:int, indices = torch.randperm(len(verts_list)).tolist() shuffled_verts_list = [verts_list[i] for i in indices] shuffled_faces_list = [faces_list[i] for i in indices] - shuffled_pcd_list = [pcd_list[i] for i in indices] - shuffled_pcd_colors_list = [pcd_colors_list[i] for i in indices] + # shuffled_pcd_list = [pcd_list[i] for i in indices] + # shuffled_pcd_colors_list = [pcd_colors_list[i] for i in indices] shuffled_uuid = [uuid[i] for i in indices] if self.render_color_img_dir != '': shuffled_render_color_img_list = [render_color_img_list[i] for i in indices] @@ -816,8 +816,8 @@ def _write_one_chunk(self, chunk_index:int, for i in range(3): columns['verts_list_{}'.format(i)] = [verts[:, i] for verts in shuffled_verts_list] columns['faces_list_{}'.format(i)] = [faces[:, i] for faces in shuffled_faces_list] - columns['pcd_list_{}'.format(i)] = [pcd[:, i] for pcd in shuffled_pcd_list] - columns['pcd_colors_list_{}'.format(i)] = [pcd_colors[:, i] for pcd_colors in shuffled_pcd_colors_list] + # columns['pcd_list_{}'.format(i)] = [pcd[:, i] for pcd in shuffled_pcd_list] + # columns['pcd_colors_list_{}'.format(i)] = [pcd_colors[:, i] for pcd_colors in shuffled_pcd_colors_list] if self.render_color_img_dir != '': for i in range(self.img_num): @@ -884,8 +884,8 @@ def _write_chunks(self, chunk_path, chunk_size) -> None: for i in range(3): dtypes.append(('verts_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) dtypes.append(('faces_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.int64)))) - dtypes.append(('pcd_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - dtypes.append(('pcd_colors_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + # dtypes.append(('pcd_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) + # dtypes.append(('pcd_colors_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) if self.render_color_img_dir != '': for i in range(self.img_num): dtypes.append(('render_color_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) @@ -909,7 +909,8 @@ def _write_chunks(self, chunk_path, chunk_size) -> None: def do_one_chunk(obj, chunk, chunk_index): nonlocal bar_write - verts_list, faces_list, pcd_list, pcd_color_list = [], [], [], [] + verts_list, faces_list = [], [] + # pcd_list, pcd_color_list = [], [], [], [] render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list = [], [], [], [] triview_color_img_list, triview_xyz_img_list = [], [] uuid, prompt = [], [] @@ -919,12 +920,14 @@ def do_one_chunk(obj, chunk, chunk_index): readed_data = loop.run_until_complete(asyncio.gather(*futures)) loop.close() for data in readed_data: - obj.append_data(data, uuid, verts_list, faces_list, pcd_list, pcd_color_list, - render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, + obj.append_data(data, uuid, verts_list, faces_list, + # pcd_list, pcd_color_list, + render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, triview_color_img_list, triview_xyz_img_list, prompt) obj._write_one_chunk(chunk_index, - verts_list, faces_list, pcd_list, pcd_color_list, + verts_list, faces_list, + # pcd_list, pcd_color_list, render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, triview_color_img_list, triview_xyz_img_list, uuid, prompt, parquet_writers) diff --git a/datasets/memory_dataset.py b/datasets/memory_dataset.py index 6a3a4a2..9782713 100644 --- a/datasets/memory_dataset.py +++ b/datasets/memory_dataset.py @@ -23,7 +23,7 @@ from .dataset import Dataset from util import utils, renderer -from util.utils import SHAPENET_MAX_DEPTH, DEPTH_MAX, DEPTH_MIN, DEPTH_VALID_MIN, DEPTH_VALID_MAX +from util.utils import DEPTH_MAX, DEPTH_MIN, DEPTH_VALID_MIN, DEPTH_VALID_MAX class MemoryDataset(Dataset): @@ -47,7 +47,7 @@ def __init__(self, input_specs, train_specs, glctx, tet_grid_size, device, task_ self.dep_sill_mode = train_specs.get('dep&sill_sup_mode') self.scale = input_specs['scale'] - self.pcd_dir = input_specs['pcd_dir'] + # self.pcd_dir = input_specs['pcd_dir'] self.mesh_dir = input_specs['mesh_dir'] self.class_name = input_specs['class'] self.camera_angle_num = input_specs['camera_angle_num'] @@ -140,26 +140,26 @@ def __init__(self, input_specs, train_specs, glctx, tet_grid_size, device, task_ if not self.validate and record not in self.train_set: continue - if self.dataset_name == 'ShapeNet': - # load vertices and faces - gt_path = os.path.join(class_dir, object_name, 'blank_model.ply') - # load pcd - pcd_file = os.path.join(self.pcd_dir, class_name, object_name, - 'models', - f'pc_model_normalized.obj_mat_{self.img_num}_262144_131072.ply') + # if self.dataset_name == 'ShapeNet': + # # load vertices and faces + # gt_path = os.path.join(class_dir, object_name, 'blank_model.ply') + # # load pcd + # pcd_file = os.path.join(self.pcd_dir, class_name, object_name, + # 'models', + # f'pc_model_normalized.obj_mat_{self.img_num}_262144_131072.ply') - elif self.dataset_name == 'Objaverse': + if self.dataset_name == 'Objaverse': # load vertices and faces gt_path = os.path.join(class_dir, object_name) - pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') + # pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') # skip empty folder if not os.path.exists(gt_path): continue - # skip empty folder - if not os.path.exists(pcd_file): - continue + # # skip empty folder + # if not os.path.exists(pcd_file): + # continue # load raw vertices and faces try: @@ -170,33 +170,34 @@ def __init__(self, input_specs, train_specs, glctx, tet_grid_size, device, task_ if not hasattr(ref_mesh, 'vertices') or not hasattr(ref_mesh, 'faces'): continue - # load point cloud - pcd = trimesh.load(pcd_file) + # # load point cloud + # pcd = trimesh.load(pcd_file) - if not hasattr(pcd, 'vertices') or not hasattr(pcd, 'colors'): - print("pcd has no attr vertices or colors", pcd_file) - continue + # if not hasattr(pcd, 'vertices') or not hasattr(pcd, 'colors'): + # print("pcd has no attr vertices or colors", pcd_file) + # continue - if len(pcd.vertices) < self.query_pts_num: - print("pcd num less than query_pts_num", pcd_file) - continue + # if len(pcd.vertices) < self.query_pts_num: + # print("pcd num less than query_pts_num", pcd_file) + # continue verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) faces = torch.LongTensor(ref_mesh.faces) if self.render_img_dir == '': - res = self._preprocess(verts, faces, pcd_file, uuid=record) + pass + # res = self._preprocess(verts, faces, pcd_file, uuid=record) else: - if self.dataset_name == 'ShapeNet': - imgdir = os.path.join(self.render_img_dir, class_name, object_name, 'img', object_name, 'models') - elif self.dataset_name == 'Objaverse': + # if self.dataset_name == 'ShapeNet': + # imgdir = os.path.join(self.render_img_dir, class_name, object_name, 'img', object_name, 'models') + if self.dataset_name == 'Objaverse': imgdir = os.path.join(self.render_img_dir, record) else: raise RuntimeError('Not valid dataset_name') # skip empty folder if not os.path.exists(imgdir): continue - res = self._preprocess(verts, faces, pcd_file, uuid=record, imgdir=imgdir) + res = self._preprocess(verts, faces, uuid=record, imgdir=imgdir) res[0].update({'uuid': record}) @@ -243,105 +244,106 @@ def __init__(self, input_specs, train_specs, glctx, tet_grid_size, device, task_ else: raise ValueError("Error! Unrecognized task mode.") - def _preprocess(self, verts, faces, pcd_file, uuid=None, imgdir=None): + def _preprocess(self, verts, faces, uuid=None, imgdir=None): # no render images or no blender mode if imgdir is None or (self.render_mode != 'blender' and self.dep_sill_mode != 'blender'): - verts -= ((verts.max(0)[0] + verts.min(0)[0]) / 2).unsqueeze(0).repeat( - (verts.shape[0], 1)) + pass + # verts -= ((verts.max(0)[0] + verts.min(0)[0]) / 2).unsqueeze(0).repeat( + # (verts.shape[0], 1)) - # load point cloud - pcd = trimesh.load(pcd_file) - pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) + # # load point cloud + # pcd = trimesh.load(pcd_file) + # pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) - # rotate & transport - pcd_tr = pcd_tr @ utils.rotate_x(-math.pi / 2).T[:3, :3] - pcd_tr -= ((pcd_tr.max(0)[0] + pcd_tr.min(0)[0]) / 2).unsqueeze(0).repeat((pcd_tr.shape[0], 1)) + # # rotate & transport + # pcd_tr = pcd_tr @ utils.rotate_x(-math.pi / 2).T[:3, :3] + # pcd_tr -= ((pcd_tr.max(0)[0] + pcd_tr.min(0)[0]) / 2).unsqueeze(0).repeat((pcd_tr.shape[0], 1)) - # color, normalized to [-1, 1] - pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] + # # color, normalized to [-1, 1] + # pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] - # scale - verts = verts / torch.max(abs(verts)) * self.scale - pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale + # # scale + # verts = verts / torch.max(abs(verts)) * self.scale + # pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale - return [{ - 'gt_verts': verts, - 'gt_faces': faces, - 'gt_pcd': pcd_tr, - 'gt_pcd_colors': pcd_colors - }] + # return [{ + # 'gt_verts': verts, + # 'gt_faces': faces, + # 'gt_pcd': pcd_tr, + # 'gt_pcd_colors': pcd_colors + # }] else: - # load point cloud - pcd = trimesh.load(pcd_file) + # # load point cloud + # pcd = trimesh.load(pcd_file) - if not hasattr(pcd, 'vertices') or not hasattr(pcd, 'colors'): - return + # if not hasattr(pcd, 'vertices') or not hasattr(pcd, 'colors'): + # return - if len(pcd.vertices) < self.query_pts_num: - return + # if len(pcd.vertices) < self.query_pts_num: + # return - pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) + # pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) - # rotate + # rotate verts[:, -1] = -verts[:, -1] verts = verts[:, [0, 2, 1]] - pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] - - if self.dataset_name == 'ShapeNet': - verts *= self.scale / 0.5 - pcd_tr *= self.scale / 0.5 - - with open(os.path.join(imgdir, 'transforms.json'), 'r') as f: - metadata = json.load(f) - self.fovx = metadata['camera_angle_x'] - img_list, transform_list = [], [] - depth_list = [] - for i, data in enumerate(metadata['frames']): - img_name = data['file_path'] - assert i == int(os.path.splitext(img_name)[0]) - - c2w = torch.tensor(data['transform_matrix'], dtype=torch.float32) - - c2w[:3, 3] *= self.scale / 0.5 - - w2c = torch.inverse(c2w) - # BGR -> RGB -> [-1, 1] - raw = cv2.resize( - cv2.imread(os.path.join(imgdir, img_name), cv2.IMREAD_UNCHANGED), - tuple(self.res_img)) - mask = torch.tensor(raw[:, :, [-1]], - dtype=torch.float32).repeat(1, 1, 3) / 255 - img = torch.tensor(raw[:, :, [2, 1, 0]], - dtype=torch.float32) / 255 - - img = img * mask - - transform_list.append(w2c) - img_list.append(img) - - # depth - depth_name = f'{i:05d}_depth.png' - dep = cv2.imread(os.path.join(imgdir, depth_name), cv2.IMREAD_UNCHANGED) - - # reference - # https://github.com/openai/shap-e/blob/50131012ee11c9d2617f3886c10f000d3c7a3b43/shap_e/rendering/blender/view_data.py#L57-L62 - inf_dist = dep == 0xFFFF - dep = np.where( - inf_dist, - 0., - SHAPENET_MAX_DEPTH * (dep.astype(np.float32) / 65536), - ) - - dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 - - depth_list.append(dep) - - gt_render_imgs = torch.stack(img_list) - gt_transforms = torch.stack(transform_list) - gt_render_depths = torch.stack(depth_list).unsqueeze(-1) - - elif self.dataset_name == 'Objaverse': + # pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] + + # if self.dataset_name == 'ShapeNet': + # verts *= self.scale / 0.5 + # pcd_tr *= self.scale / 0.5 + + # with open(os.path.join(imgdir, 'transforms.json'), 'r') as f: + # metadata = json.load(f) + # self.fovx = metadata['camera_angle_x'] + # img_list, transform_list = [], [] + # depth_list = [] + # for i, data in enumerate(metadata['frames']): + # img_name = data['file_path'] + # assert i == int(os.path.splitext(img_name)[0]) + + # c2w = torch.tensor(data['transform_matrix'], dtype=torch.float32) + + # c2w[:3, 3] *= self.scale / 0.5 + + # w2c = torch.inverse(c2w) + # # BGR -> RGB -> [-1, 1] + # raw = cv2.resize( + # cv2.imread(os.path.join(imgdir, img_name), cv2.IMREAD_UNCHANGED), + # tuple(self.res_img)) + # mask = torch.tensor(raw[:, :, [-1]], + # dtype=torch.float32).repeat(1, 1, 3) / 255 + # img = torch.tensor(raw[:, :, [2, 1, 0]], + # dtype=torch.float32) / 255 + + # img = img * mask + + # transform_list.append(w2c) + # img_list.append(img) + + # # depth + # depth_name = f'{i:05d}_depth.png' + # dep = cv2.imread(os.path.join(imgdir, depth_name), cv2.IMREAD_UNCHANGED) + + # # reference + # # https://github.com/openai/shap-e/blob/50131012ee11c9d2617f3886c10f000d3c7a3b43/shap_e/rendering/blender/view_data.py#L57-L62 + # inf_dist = dep == 0xFFFF + # dep = np.where( + # inf_dist, + # 0., + # SHAPENET_MAX_DEPTH * (dep.astype(np.float32) / 65536), + # ) + + # dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 + + # depth_list.append(dep) + + # gt_render_imgs = torch.stack(img_list) + # gt_transforms = torch.stack(transform_list) + # gt_render_depths = torch.stack(depth_list).unsqueeze(-1) + + if self.dataset_name == 'Objaverse': if self.uuid2transform: transform = self.uuid2transform[uuid] transport = torch.tensor(transform['offset'], dtype=torch.float32) @@ -353,10 +355,10 @@ def _preprocess(self, verts, faces, pcd_file, uuid=None, imgdir=None): scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) verts *= self.scale / 0.5 * scale - pcd_tr *= self.scale / 0.5 + # pcd_tr *= self.scale / 0.5 with open(os.path.join(imgdir, 'meta.pkl'), 'rb') as f: - K, _, _, distance, w2cs = pickle.load(f) + K, _, _, _, w2cs = pickle.load(f) self.fovx = 2 * math.atan(K[0, 2] / K[0, 0]) @@ -415,7 +417,7 @@ def _preprocess(self, verts, faces, pcd_file, uuid=None, imgdir=None): return [{ 'gt_verts': verts.cpu(), 'gt_faces': faces.cpu(), - 'gt_pcd': pcd_tr, 'gt_pcd_colors': pcd_colors, + # 'gt_pcd': pcd_tr, 'gt_pcd_colors': pcd_colors, 'gt_render_imgs': gt_render_imgs, 'gt_transforms': gt_transforms, 'gt_render_depths': gt_render_depths}] def _sample_scene(self, idx, num, rotate=False): @@ -483,18 +485,18 @@ def __getitem__(self, idx): mvp, campos, persp, iter_res ) - pcd_num = len(self.data[num]['gt_pcd']) - index = random.sample(range(pcd_num), k=self.pts_num) - index_query = random.sample(range(pcd_num), k=min(self.query_pts_num, self.pts_num)) + # pcd_num = len(self.data[num]['gt_pcd']) + # index = random.sample(range(pcd_num), k=self.pts_num) + # index_query = random.sample(range(pcd_num), k=min(self.query_pts_num, self.pts_num)) res = { 'uuid': self.data[num].get('uuid'), 'gt_verts': self.data[num]['gt_verts'], 'gt_faces': self.data[num]['gt_faces'], - 'gt_pcd': self.data[num]['gt_pcd'][None, index, ...], - 'gt_pcd_colors': self.data[num]['gt_pcd_colors'][None, index, ...], - 'gt_pcd_colors_query': self.data[num]['gt_pcd_colors'][None, index_query, ], - 'gt_pcd_query': self.data[num]['gt_pcd'][None, index_query, ], + # 'gt_pcd': self.data[num]['gt_pcd'][None, index, ...], + # 'gt_pcd_colors': self.data[num]['gt_pcd_colors'][None, index, ...], + # 'gt_pcd_colors_query': self.data[num]['gt_pcd_colors'][None, index_query, ], + # 'gt_pcd_query': self.data[num]['gt_pcd'][None, index_query, ], 'gt_render_imgs': imgs[None, ], 'mv': mv[None, ], 'mvp': mvp[None, ], diff --git a/make_chunk.py b/make_chunk.py index d4f3a36..9652112 100644 --- a/make_chunk.py +++ b/make_chunk.py @@ -1,18 +1,6 @@ import os -import json os.environ["CUDA_HOME"] = "/usr/local/cuda-12.1" import argparse -# import nvdiffrast.torch as dr -from itertools import cycle -from tqdm import tqdm -import torch.distributed as dist - -from datasets.memory_dataset import MemoryDataset -from datasets.filesystem_dataset import FilesystemDataset -from datasets.fast_dataset import FastDataset -# from util.common import pcd_preprocess -from accelerate import Accelerator -from util import utils from subprocess import Popen, PIPE @@ -20,7 +8,7 @@ def main(): arg_parser = argparse.ArgumentParser() arg_parser.add_argument( "--exp_dir", "-e", - default="config/", + default="configs/", help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", ) arg_parser.add_argument( @@ -36,11 +24,8 @@ def main(): help="Number of processes to use for data loading.", ) - args = arg_parser.parse_args() - config_path = os.path.join(args.exp_dir, args.config_name) - - + python = "/home/yudajiang/softwares/miniforge-pypy3/envs/crm/bin/python" p_ls = [] try: @@ -53,7 +38,6 @@ def main(): except: for p in p_ls: p.kill() - if __name__ == '__main__': main() \ No newline at end of file diff --git a/make_chunk_sub.py b/make_chunk_sub.py index d083c20..4502f26 100644 --- a/make_chunk_sub.py +++ b/make_chunk_sub.py @@ -8,7 +8,6 @@ import torch.distributed as dist from datasets.memory_dataset import MemoryDataset -from datasets.filesystem_dataset import FilesystemDataset from datasets.fast_dataset import FastDataset # from util.common import pcd_preprocess from accelerate import Accelerator @@ -16,33 +15,11 @@ from subprocess import Popen, PIPE -def train(specs, config_path): - input_specs = specs['Input'] - task_mode = input_specs['task_mode'] - tet_grid_size = input_specs['tet_grid_size'] - dataset_type = input_specs.get('dataset_type', None) - - train_specs = specs['Train'] - - device = 'cuda:0' - # glctx = dr.RasterizeCudaContext() - glctx = None - - dataset, dataset_val_all = [None] * 2 - - if dataset_type == 'memory' or dataset_type is None: - dataset = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode) - - elif dataset_type == 'filesystem': - dataset = FastDataset(input_specs, train_specs, glctx, device, 0, mode='all') - return dataset - - def main(): arg_parser = argparse.ArgumentParser() arg_parser.add_argument( "--exp_dir", "-e", - default="config/", + default="configs/", help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", ) arg_parser.add_argument( @@ -69,8 +46,10 @@ def main(): config_path = os.path.join(args.exp_dir, args.config_name) specs = json.load(open(config_path)) - dataset = train(specs, config_path) - + input_specs = specs['Input'] + train_specs = specs['Train'] + dataset = FastDataset(input_specs, train_specs, None, None, 0, mode='all') + dataset.num_process = args.num_process dataset.process_index = args.process_index dataset._write_chunks(dataset.parquet_dir, dataset.chunk_size) diff --git a/model/crm/model.py b/model/crm/model.py index 9eb1642..3de135a 100644 --- a/model/crm/model.py +++ b/model/crm/model.py @@ -13,8 +13,10 @@ from model.archs.decoders.shape_texture_net import TetTexNet from model.archs.unet import UNetPP from util.renderer import Renderer +from util.utils import get_tri, trans_depth from model.archs.mlp_head import SdfMlp, RgbMlp import xatlas +import random class Dummy: @@ -33,15 +35,20 @@ def __init__(self, specs): self.tet_grid_size = input_specs['tet_grid_size'] self.camera_angle_num = input_specs['camera_angle_num'] + arch_specs = specs["ArchSpecs"] self.arch = Dummy() - self.arch.fea_concat = specs["ArchSpecs"]["fea_concat"] - self.arch.mlp_bias = specs["ArchSpecs"]["mlp_bias"] + self.arch.fea_concat = arch_specs["fea_concat"] + self.arch.mlp_bias = arch_specs["mlp_bias"] + encoder_specs = specs["EncoderSpecs"] + self.enc = Dummy() + self.enc.plane_resolution = encoder_specs["plane_resolution"] + decoder_specs = specs["DecoderSpecs"] self.dec = Dummy() - self.dec.c_dim = specs["DecoderSpecs"]["c_dim"] - self.dec.plane_resolution = specs["DecoderSpecs"]["plane_resolution"] + self.dec.c_dim = decoder_specs["c_dim"] + self.dec.plane_resolution = decoder_specs["plane_resolution"] - self.geo_type = specs["Train"].get("geo_type", "flex") # "dmtet" or "flex" + self.geo_type = specs["Train"].get("geo_type", "dmtet") # "dmtet" or "flex" self.unet2 = UNetPP(in_channels=self.dec.c_dim) @@ -53,19 +60,382 @@ def __init__(self, specs): 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.l1_loss = nn.L1Loss() + self.mse_loss = nn.MSELoss() + + self.ticker = 0 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 + self.denoising = False from diffusers import DDIMScheduler self.scheduler = DDIMScheduler.from_pretrained("stabilityai/stable-diffusion-2-1-base", subfolder="scheduler") + def small_fwd(self, data): + xyzs_list = [] + color_list = [] + # color0_list = [] + # print(data['triview_color'].shape) + # print(data['triview_xyz'].shape) + for i in range(len(data['gt_verts'])): + color = data['triview_color'][i].permute(0,3,1,2).clone() + xyzs = data['triview_xyz'][i].permute(0,3,1,2).clone() + + if xyzs.max() > 1.1: + xyzs = xyzs / 255 + # print("fix 255 bug") + if self.specs["Train"].get("random_bg", False): + crgb = 0.5#random.random() + cxyz = 0.5#random.random() + # for j in range(6): + # mask = torch.mean(xyzs[j], dim = 0, keepdim=False) + # mask = (mask == 0) + # grey_image = torch.zeros_like(cxyz) + # for k in range(3): + # grey_image[j][k][mask] = cxyz + for j in range(6): + mask = torch.mean(xyzs[j], dim = 0, keepdim=False) + mask = (mask == 0) + for k in range(3): + color[j][k][mask] = crgb + xyzs[j][k][mask] = cxyz + else: + crgb = 0 + cxyz = 0 + + shift = 0 + if random.random() < 0.5: + shift = int(self.specs["Train"].get("shift", 0)) + # print(color.shape) + color_tensor1 = get_tri(color, dim=0, blender=True, c=crgb, shift=shift, rgb=True) + xyzs_tensor1 = get_tri(xyzs, dim=0, blender=True, c=cxyz, shift=shift, fix=True) # , fix = True + # print(color_tensor1.min(), color_tensor1.max(), xyzs_tensor1.min(),xyzs_tensor1.max()) + + + # print(color_tensor1.shape) + color_list.append(color_tensor1) + xyzs_list.append(xyzs_tensor1) + color_tensor = torch.stack(color_list, dim=0) + # print(color_tensor.shape) + color_tensor = torch.nn.functional.interpolate(color_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") + + xyzs_tensor = torch.stack(xyzs_list, dim=0) + xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") + + # if random.random()<0.5: + # color_tensor = torch.nn.functional.interpolate(color_tensor, [256, 256*3], mode = "bilinear") + # xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [256, 256*3], mode = "bilinear") + # color_tensor = torch.nn.functional.interpolate(color_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") + # xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") + + # reso_tmp = random.randint(32, 256) + # xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [reso_tmp, reso_tmp*3], mode = "bilinear") + # xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") + + # !Notice + all_tensor = torch.cat([color_tensor, xyzs_tensor], dim = 1)# *2 - 1 + # print(all_tensor.shape) + triplane_feature0 = all_tensor + triplane_feature1 = all_tensor + return triplane_feature0, triplane_feature1 + + def forward(self, data, ctx, tnew=None): + # pcd_xyz = data['gt_pcd'] + # pcd_rgb = data['gt_pcd_colors'] + # dense_pcd_xyz = data['gt_pcd_query'] + # dense_pcd_rgb = data['gt_pcd_colors_query'] + + # print(data['triview_color'].shape) + # print(data['triview_xyz'].shape) + # CYF Note: Adding noise to xyz. In real applications, + # point cloud is generated by sensors and thus noisy + # pcd_xyz += xyz_noise_scale * torch.randn(pcd_xyz.shape).to(pcd_xyz.get_device()) + # dense_pcd_xyz += xyz_noise_scale * torch.randn(dense_pcd_xyz.shape).to(dense_pcd_xyz.get_device()) + + # print(verts.shape, tets.shape) + # print(self.renderer.flexicubes.verts.shape, self.renderer.flexicubes.indices.shape) + if self.geo_type == "flex": + # use the number of data not batch size + verts = self.renderer.flexicubes.verts.unsqueeze(0).repeat(len(data['gt_verts']), 1, 1) + tets = self.renderer.flexicubes.indices + + # if self.arch.tri_img: + with torch.no_grad(): + tri_fea_0, tri_fea_1 = self.small_fwd(data) + + # if self.denoising == True: + # # tnew = 250 + # if tnew == None: + # tnew = torch.randint(0, 1000, [tri_fea_1.shape[0]], dtype=torch.long, device=tri_fea_1.device) + # else: + # tnew = torch.randint(tnew, tnew+1, [tri_fea_1.shape[0]], dtype=torch.long, device=tri_fea_1.device) + # noise_new = torch.randn_like(tri_fea_1) *0.5+0.5 + # reso = tri_fea_1.shape[-2] + # cache1 = tri_fea_1[:,:3,:,reso*2:] + # tri_fea_1 =self.scheduler.add_noise(tri_fea_1, noise_new, tnew) + # tri_fea_1[:,:3,:,reso*2:] = cache1 + + # if self.arch.tri_img or self.arch.tri_mix: + # if self.denoising == True: + # tri_fea_2 = self.unet2(tri_fea_1, tnew) + # else: + tri_fea_2 = self.unet2(tri_fea_1) + # else: + # reso = tri_fea_1.shape[-2:] + # reso_tmp = random.randint(64, 256)#int(torch.randint(low=64, high=256, size=(1,), dtype=torch.int)) + # tri_fea_1 = torch.nn.functional.interpolate(tri_fea_1, size=(reso_tmp, reso_tmp * 3), mode='bilinear') + # # tri_fea_1 = tri_fea_1.clamp(-1,1) + # # KL here + # tri_fea_1 = torch.nn.functional.interpolate(tri_fea_1, size=reso, mode='bilinear') + + # tri_fea_2 = self.unet2(tri_fea_1) + + assert torch.isnan(tri_fea_2).sum() == 0, print("nan in triplane feature 2") + dec_verts = self.decoder(tri_fea_2, verts) + + pred_shape = self.sdfMlp(dec_verts) + assert torch.isnan(pred_shape).sum() == 0, print("nan in predicted shape primitives") + + pred_sdf, deformation = pred_shape[..., 0], pred_shape[..., 1:4] + if self.spob: + pred_sdf = pred_sdf + self.radius - torch.sqrt((verts ** 2).sum(-1)) + + for i in range(pred_sdf.shape[0]): + if pred_sdf[i].min() >= 0 or pred_sdf[i].max() <= 0: + print('004occur!', pred_sdf[i].max(), pred_sdf[i].min()) + pred_sdf[i] -= (pred_sdf[i].min().detach() / 8 + pred_sdf[i].max().detach() * 7 / 8) + + 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 + # print("weight shape", weight.shape) + # Debug HOLD: SDF output + # vis = out.detach().cpu().numpy() + # print(pred_sdf.min(), pred_sdf.max(), (pred_sdf <= 0).sum(), (pred_sdf > 0).sum()) + + # valid = True + # for i in range(len(data['gt_verts'])): + # xyzs = data['triview_xyz'][i].permute(0,3,1,2) + # ma1 = 255 + # ma2 = 255 + # mb1 = 0 + # mb2 = 0 + # for j in range(6): + # a1,a2,b1,b2 = find_bounding_box(torch.mean(xyzs[j], dim = 0, keepdim=False)) + # ma1 = min(a1, ma1) + # ma2 = min(a2, ma2) + # mb1 = max(b1, mb1) + # mb2 = max(b2, mb2) + # # print(min(ma1, ma2), max(mb1, mb2)) + # if min(ma1, ma2) != 0 or max(mb1, mb2) != 255: + # valid = False + + # valid = True + + result, verts, faces = self.renderer(data, pred_sdf, deformation, verts, tets, training = self.training, weight = weight) + # if not valid: + # print("valid is false") + # result['silhouette_loss'] *= 0 + # result['depth_loss'] *= 0 + + sdf_pos = pred_sdf[pred_sdf>=0] + sdf_neg = pred_sdf[pred_sdf<0] + result["wzy_loss"] = (torch.abs(sdf_pos-1).sum() + torch.abs(sdf_neg+1).sum()) / (pred_sdf.shape[0]*pred_sdf.shape[1]) + + # if self.tex_sup_mode == "pcd-raw": + # dense_pcd_xyz = data['gt_pcd_query'] + # dense_pcd_rgb = data['gt_pcd_colors_query'] + # # print("raw texture supervision") + # dec_d_pcd = self.decoder(tri_fea_2, dense_pcd_xyz) + # pred_rgb = self.rgbMlp(dec_d_pcd) # torch.cat((dec_d_pcd, dense_pcd_xyz), dim=2) + # color_loss = self.l1_loss(pred_rgb, dense_pcd_rgb) + self.mse_loss(pred_rgb, dense_pcd_rgb) + + # elif self.tex_sup_mode == "pcd-nnb": + # dense_pcd_xyz = data['gt_pcd_query'] + # dense_pcd_rgb = data['gt_pcd_colors_query'] + # # print("nearest neighbor supervision") + # with torch.no_grad(): + # pc_list = [] + # for i in range(len(verts)): + # pred_points = kaolin.ops.mesh.sample_points(verts[i].unsqueeze(0), faces[i], dense_pcd_xyz.shape[1])[0][0] + # # print(pred_points.shape) + # pc_list.append(pred_points.unsqueeze(0)) + # pcs = torch.cat(pc_list, dim=0) + # # pcs += noise_scale * torch.randn(pcs.shape).to(pcs.get_device()) # pcs collected from model, no need to add noise + # pcs_color = find_nearest_points(pcs, dense_pcd_xyz, dense_pcd_rgb) + + # dec_d_pcd = self.decoder(tri_fea_2, pcs) + # pred_rgb = self.rgbMlp(dec_d_pcd) + # color_loss = self.l1_loss(pred_rgb, pcs_color) + self.mse_loss(pred_rgb, pcs_color) + + # if self.tex_sup_mode == 'blender': + # if self.mvdream==False and (self.sd_mode == "sds" or self.sd_mode == "vsd"): + # resolution = [512,512] + # else: + resolution = data['resolution_img'] + gt_color = data['gt_render_imgs'] + result['gt_render_imgs'] = data['gt_render_imgs'] + # print(data["prompt"]) + img_list = [] + # if self.sd_mode == "sds" or self.sd_mode == "vsd": + # latents_list = [] + # latents_gt_list = [] + # img_list2 = [] + # if self.sd_mode == "vsd": + # latents_train_list = [] + # latents_train_gt_list = [] + # sds_bs = 4 + mvp_size = data['mvp'][0].shape[0] + for i in range(len(verts)): + mvp = data['mvp'][i] + # print(mvp.shape, data['mvp'].shape) + # if self.sd_mode == "sds" or self.sd_mode == "vsd": + # azimuth = 90*random.random() + # elevation = 30*random.random() + # fov = 15+(60-15)*random.random() + # mvp2 = sds_scene_mv(sds_bs, azimuth, elevation, fov).to(data['mvp'][i].device) + # mvp = torch.cat([mvp, mvp2], dim = 0) + # # print(mvp.shape) + + face = faces[i].int() + + verts_clip = torch.bmm( + F.pad(verts[i], pad=(0, 1), mode='constant', value=1.0).unsqueeze(0).repeat(mvp.shape[0], 1, 1), + mvp.permute(0, 2, 1)).float() # [B, N, 4] + rast, rast_db = dr.rasterize(ctx, verts_clip, face, resolution) + # print(verts.shape, faces.shape) + alpha, _ = dr.interpolate(torch.ones_like(verts[i][:, :1]).unsqueeze(0), rast, face) # [1, H, W, 1] + xyzs, _ = dr.interpolate(verts[i], rast, face) # [1, H, W, 3] + # print(alpha.shape, xyzs.shape) + xyzs = xyzs.view(-1, 3) + mask = (alpha > 0).view(-1).detach() + # do the lighting here since we have normal from mesh now. + albedo = torch.zeros_like(xyzs, dtype=torch.float32) + + albedo = albedo.view(-1, resolution[0], resolution[1], 3) + albedo[:mvp_size] = albedo[:mvp_size] - 1 + albedo = albedo.view(-1, 3) + + # print("4.0:{}".format(torch.cuda.memory_allocated(0))) + if mask.any(): + # print(mask.sum()) + dec_d_pcd = self.decoder(tri_fea_2[i].unsqueeze(0), xyzs[mask].unsqueeze(0)) + # print("4.1:{}".format(torch.cuda.memory_allocated(0))) + masked_albedo = self.rgbMlp(dec_d_pcd) + # print("4.2:{}".format(torch.cuda.memory_allocated(0))) + # print(albedo.shape, masked_albedo.shape, mask.shape, albedo.shape) + albedo[mask] = masked_albedo.squeeze(0).float() + # print("4.3:{}".format(torch.cuda.memory_allocated(0))) + del masked_albedo + albedo = albedo.view(-1, resolution[0], resolution[1], 3) + albedo = (albedo * 0.5 + 0.5).clip(0, 1) + # print("4.4:{}".format(torch.cuda.memory_allocated(0))) + # if self.mvdream==False and (self.sd_mode == "sds" or self.sd_mode == "vsd"): + # img_tmp = torch.nn.functional.interpolate(albedo.permute(0,3,1,2)[:mvp_size], [256,256], mode="bilinear").permute(0,2,3,1) + # img_list.append(img_tmp) + # else: + img_list.append(albedo[:mvp_size]) + # if self.sd_mode == "sds" or self.sd_mode == "vsd": + # img_list2.append(albedo[mvp_size:]) + + # if self.sd_mode == "sds" or self.sd_mode == "vsd": + # # print(data["prompt"][i]) + # cur_prompt = data["prompt"][i] + + # latents = torch.nn.functional.interpolate(albedo.permute(0,3,1,2)[mvp_size:], [512,512] if self.mvdream == False else [256,256], mode="bilinear") + # latents = self.unet_sd.encode_imgs(latents) + # if self.mvdream == True: + # t = torch.randint(20, 980 + 1, [1], dtype=torch.long, device=latents.device) + # t = t.repeat(latents.shape[0]) + # else: + # t = torch.randint(20, 980 + 1, [latents.shape[0]], dtype=torch.long, device=latents.device) + # noise = torch.randn_like(latents) + # latents_noisy = self.unet_sd.scheduler.add_noise(latents, noise, t) + # with torch.no_grad() if self.jacobi == False else torch.enable_grad(): + # if self.mvdream == True: + # camera = get_camera(4, elevation, azimuth).to(latents.device) + # uncond = { + # "context": self.mv_model.get_learned_conditioning([""]*4).to(latents.device), + # "camera": camera, + # "num_frames": 4, + # } + # cond = { + # "context": self.mv_model.get_learned_conditioning([cur_prompt[0]]*4).to(latents.device), + # "camera": camera, + # "num_frames": 4, + # } + # noise_pred = self.mv_model.apply_model(latents_noisy, t, cond=uncond) + # noise_pred_cond = self.mv_model.apply_model(latents_noisy, t, cond=cond) + # else: + # noise_pred = self.unet_sd(latents_noisy, t, "") + # noise_pred_cond = self.unet_sd(latents_noisy, t, cur_prompt)# cur_prompt + # if self.sd_mode == "sds": + # if self.mvdream == True: + # noise_cfg = noise_pred + self.specs["Train"].get("sd_cfg", 50) * (noise_pred_cond - noise_pred) + # else: + # noise_cfg = noise_pred + self.specs["Train"].get("sd_cfg", 100) * (noise_pred_cond - noise_pred) + # elif self.sd_mode == "vsd": + # noise_pred_lora = self.unet_lora(latents_noisy, t, self.unet_sd.encode_prompt(latents_noisy, cur_prompt)).sample + # noise_cfg = noise_pred + self.specs["Train"].get("sd_cfg", 7.5) * (noise_pred_cond - noise_pred) + noise - noise_pred_lora + # alpha_prod_t = self.unet_sd.scheduler.alphas_cumprod.to(latents.device)[t].unsqueeze(-1).unsqueeze(-1).unsqueeze(-1) + # beta_prod_t = (1 - alpha_prod_t).to(latents.device) + # pred_original_sample = (latents_noisy - beta_prod_t ** (0.5) * noise_cfg) / alpha_prod_t ** (0.5) + # # cfg_rescale = True + # # if cfg_rescale == False: + # # pred_original_sample = (latents_noisy - beta_prod_t ** (0.5) * noise_cfg) / alpha_prod_t ** (0.5) + # # else: + # # pass + # latents_list.append(latents if self.jacobi == False else latents.detach())#*alpha_prod_t ** (0.25) + # latents_gt_list.append(pred_original_sample.detach() if self.jacobi == False else pred_original_sample)#*alpha_prod_t ** (0.25) + + # if self.sd_mode == "vsd": #Train LoRA + # t_lora = torch.randint(20, 980 + 1, [latents.shape[0]], dtype=torch.long, device=latents.device) + # noise_lora = torch.randn_like(latents) + # latents_noisy_lora = self.unet_sd.scheduler.add_noise(latents.detach(), noise_lora, t_lora) + # noise_pred_lora_train = self.unet_lora(latents_noisy_lora, t_lora, self.unet_sd.encode_prompt(latents_noisy, cur_prompt)).sample + # latents_train_list.append(noise_pred_lora_train) + # latents_train_gt_list.append(noise_lora) + del albedo + + # print("5:{}".format(torch.cuda.memory_allocated(0))) + imgs = torch.stack(img_list, dim=0) + result['albedo_list'] = imgs + # if self.sd_mode == "sds" or self.sd_mode == "vsd": + # imgs2 = torch.stack(img_list2, dim=0) + # result['albedo_list2'] = imgs2 + + # latents_imgs = torch.stack(latents_list, dim=0) + # latents_gt_imgs = torch.stack(latents_gt_list, dim=0) + # color_loss = 0.5 * self.mse_loss(latents_imgs, latents_gt_imgs) * self.specs["Train"]["sd_lambda"] #+ self.mse_loss(imgs, gt_color) + # if self.sd_mode == "vsd": + # latents_train_imgs = torch.stack(latents_train_list, dim=0) + # latents_train_gt_imgs = torch.stack(latents_train_gt_list, dim=0) + # color_loss = color_loss + self.mse_loss(latents_train_imgs, latents_train_gt_imgs) # Added but optimizing different params + # # color_loss = self.l1_loss(imgs, gt_color) + self.mse_loss(imgs, gt_color) + color_loss + # else: + # print(data['alpha_ctn'].min(),data['alpha_ctn'].max()) + color_loss = self.mse_loss(imgs, gt_color) # self.l1_loss(imgs, gt_color) + + # if not valid: + # color_loss *= 0 + # print("6:{}".format(torch.cuda.memory_allocated(0))) + result.update({ + 'color_gt': gt_color + }) + + result['color_loss'] = color_loss + result["reg_loss"] = torch.norm(tri_fea_1) + + result["tri0"], result["tri1"], result["tri2"] = tri_fea_0, tri_fea_1, tri_fea_2 + + return result, verts, faces def decode(self, data, triplane_feature2): if self.geo_type == "flex": @@ -88,6 +458,137 @@ def decode(self, data, triplane_feature2): _, verts, faces = self.renderer(data, pred_sdf, deformation, tet_verts, tet_indices, weight= weight) return verts[0].unsqueeze(0), faces[0].int() + @torch.no_grad() + def render_color_img(self, verts, faces, data, ctx, gt=False, mvp=None, idx = 0): + mvp = data['mvp'][idx] if mvp is None else mvp[0] + res = data['resolution_img'] + # print(mvp.shape, verts.shape, faces.shape, res) + faces = faces.int() + faces = faces[..., [2, 1, 0]] + # rasterization + verts_clip = torch.bmm( + F.pad(verts, pad=(0, 1), mode='constant', value=1.0).repeat(mvp.shape[0], 1, 1), + mvp.permute(0, 2, 1)).float() # [B, N, 4] + # assert verts_clip.shape[0] > 0 and verts_clip.shape[1] > 0, print(verts_clip.shape, verts.shape) + rast, _ = dr.rasterize(ctx, verts_clip, faces, res) + + # print(verts.shape, faces.shape) + alpha, _ = dr.interpolate(torch.ones_like(verts[0][:, :1]).unsqueeze(0), rast, faces) # [1, H, W, 1] + xyzs, _ = dr.interpolate(verts[0], rast, faces) # [1, H, W, 3] + # print(alpha.shape, xyzs.shape) + xyzs = xyzs.view(-1, 3) + mask = (alpha > 0).view(-1).detach() + # do the lighting here since we have normal from mesh now. + albedo = torch.zeros_like(xyzs, dtype=torch.float32) - 1 + if mask.any(): + # if gt==False: + # if self.arch.tri_img: + _, triplane_feature1 = self.small_fwd(data) + # elif self.arch.tri_mix: + # triplane_feature0_a, triplane_feature1_a = self.small_fwd(data) + # pc = data['gt_pcd'][idx].unsqueeze(0) + # pc_colors = data['gt_pcd_colors'][idx].unsqueeze(0) + # triplane_feature0_b = self.encoder(pc, pc_colors) + # triplane_feature1_b = self.unet1(triplane_feature0_b) # unet1 moved to trdgen main class + # reso_ = triplane_feature0_a.shape[-2] + # triplane_feature0_b = torch.nn.functional.interpolate(triplane_feature0_b, size=(reso_, reso_ * 3), mode='bilinear') + # triplane_feature1_b = torch.nn.functional.interpolate(triplane_feature1_b, size=(reso_, reso_ * 3), mode='bilinear') + # triplane_feature0 = torch.cat([triplane_feature0_a,triplane_feature0_b],dim=1) + # triplane_feature1 = torch.cat([triplane_feature1_a,triplane_feature1_b],dim=1) + # else: + # pc = data['gt_pcd'][idx].unsqueeze(0) + # pc_colors = data['gt_pcd_colors'][idx].unsqueeze(0) + # triplane_feature0 = self.encoder(pc, pc_colors) + # triplane_feature1 = self.unet1(triplane_feature0) # unet1 moved to trdgen main class + # assert torch.isnan(triplane_feature1).sum() == 0, print("nan in tri") + triplane_feature2 = self.unet2(triplane_feature1) # unet2 moved to trdgen main class + masked_albedo = self.rgbMlp(self.decoder(triplane_feature2, xyzs[mask].unsqueeze(0))).squeeze(0) + # else: + # masked_albedo = find_nearest_points(xyzs[mask].unsqueeze(0), data['gt_pcd_query'][idx].unsqueeze(0), data['gt_pcd_colors_query'][idx].unsqueeze(0)).squeeze(0) + albedo[mask] = masked_albedo.float() + albedo = albedo.view(-1, alpha.shape[1], alpha.shape[2], 3) + albedo = (albedo * 0.5 + 0.5).clip(0, 1) + + mask2 = (alpha <= 0).view(-1).detach() + xyzs[mask2] -= 1 + xyzs = xyzs.view(alpha.shape[0], alpha.shape[1], alpha.shape[2], 3) + xyzs = (xyzs * 0.5 + 0.5).clip(0, 1) + # print(albedo.shape) + return albedo, xyzs + + def visualize(self, result, epc, chunk, color_fine, rdr_img_dir, iter_all): + # After each epoch, visualize and evaluate + # epc: current index of epochs + normal = result['normal_image'][0].detach().cpu().numpy() + normal_gt = result['normal_gt'][0].detach().cpu().numpy() + alpha = (result['alpha'][0].detach().cpu().numpy() * 255).astype('uint8') + alpha_gt = (result['alpha_gt'][0].detach().cpu().numpy() * 255).astype('uint8') + + succ = True + try: + depth = trans_depth(result['depth']) + depth_gt = trans_depth(result['depth_gt']) + except: + succ = False + color_fine = color_fine[..., [2, 1, 0]].detach().cpu().numpy() + color_fine = cv2.resize(color_fine[0], alpha.shape[1:3])[None, ...] + # if result.get('color_gt') is None: + # # color_gt = color_gt[..., [2, 1, 0]].detach().cpu().numpy() + # color_fine_gt = color_fine_gt[..., [2, 1, 0]].detach().cpu().numpy() + # else: + color_fine_gt = result.get('color_gt')[0, ..., [2, 1, 0]].cpu().numpy() + color_fine_gt = cv2.resize(color_fine_gt[0], alpha.shape[1:3])[None, ...] + if succ == True: + img = np.concatenate((alpha, alpha_gt, depth, depth_gt), axis=2) + else: + img = np.concatenate((alpha, alpha_gt, alpha, alpha_gt), axis=2) + if succ == True: + cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}.png", np.concatenate((normal[0], color_fine[0], color_fine_gt[0], cv2.applyColorMap(np.repeat(depth[0],3,axis=2).astype(np.uint8), cv2.COLORMAP_HOT)/255, cv2.applyColorMap(np.repeat(depth_gt[0],3,axis=2).astype(np.uint8), cv2.COLORMAP_HOT)/255), axis=1)*255) + else: + cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}.png", np.concatenate((normal[0], color_fine[0], color_fine_gt[0]), axis=1)*255) + + + tri0 = result['tri0'][0].mean(0).unsqueeze(-1) + tri0 = (tri0 - tri0.min()) / (tri0.max() - tri0.min()) + tri0 = tri0.detach().cpu().numpy() + tri0 = np.repeat(tri0, 3, axis=2) * 255 + + tri1 = result['tri1'][0].mean(0).unsqueeze(-1) + tri1 = (tri1 - tri1.min()) / (tri1.max() - tri1.min()) + tri1 = tri1.detach().cpu().numpy() + tri1 = np.repeat(tri1, 3, axis=2) * 255 + + tri2 = result['tri2'][0].mean(0).unsqueeze(-1) + tri2 = (tri2 - tri2.min()) / (tri2.max() - tri2.min()) + tri2 = tri2.detach().cpu().numpy() + tri2 = np.repeat(tri2, 3, axis=2) * 255 + + cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}-tri-mean.jpg", cv2.applyColorMap(np.concatenate((tri0, tri1, tri2), axis=0).astype(np.uint8), cv2.COLORMAP_JET)) + + self.ticker += 1 + + i0 = self.ticker % result['tri0'][0].shape[0] + i1 = self.ticker % result['tri1'][0].shape[0] + i2 = self.ticker % result['tri2'][0].shape[0] + + tri0 = result['tri0'][0][i0].unsqueeze(-1) + tri0 = (tri0-tri0.min())/(tri0.max()-tri0.min()) + tri0 = tri0.detach().cpu().numpy() + tri0 = np.repeat(tri0, 3, axis=2) * 255 + + tri1 = result['tri1'][0][i1].unsqueeze(-1) + tri1 = (tri1-tri1.min())/(tri1.max()-tri1.min()) + tri1 = tri1.detach().cpu().numpy() + tri1 = np.repeat(tri1, 3, axis=2) * 255 + + tri2 = result['tri2'][0][i2].unsqueeze(-1) + tri2 = (tri2-tri2.min())/(tri2.max()-tri2.min()) + tri2 = tri2.detach().cpu().numpy() + tri2 = np.repeat(tri2, 3, axis=2) * 255 + + cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}-tri{i0}-{i1}-{i2}.jpg", cv2.applyColorMap(np.concatenate((tri0, tri1, tri2), axis=0).astype(np.uint8), cv2.COLORMAP_JET)) + + return img def export_mesh(self, data, out_dir, ind, device=None, tri_fea_2 = None): verts = data['verts'] @@ -107,7 +608,6 @@ def export_mesh(self, data, out_dir, ind, device=None, tri_fea_2 = None): 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() @@ -148,7 +648,6 @@ def interpolate(attr, rast, attr_idx, rast_db=None): 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() @@ -210,4 +709,3 @@ def interpolate(attr, rast, attr_idx, rast_db=None): 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/requirements.txt b/requirements.txt index 8501f40..85b88c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ gradio -huggingface-hub +huggingface-hub==0.21.0 diffusers==0.24.0 einops==0.7.0 Pillow==10.1.0 @@ -14,3 +14,7 @@ kiui trimesh xatlas pymeshlab +numpy==1.25.2 +pyarrow +accelerate +triton diff --git a/train_crm.py b/train_crm.py index ce033ca..feb99e6 100644 --- a/train_crm.py +++ b/train_crm.py @@ -3,7 +3,6 @@ import argparse import shutil import kaolin -import re import random import numpy as np @@ -15,28 +14,26 @@ import nvdiffrast.torch as dr from itertools import cycle from tqdm import tqdm -import torch.distributed as dist -from model import TrDGen, MLPDecoder, PureDecoder, TriDecoder, FullDecoder, PCFullDecoder, PC2FullDecoder +from model import CRM from util.utils import lr_schedule, nan_to_num -from util.loss import chamfer_loss, laplacian_smooth_loss +from util.loss import laplacian_smooth_loss from datasets.memory_dataset import MemoryDataset -from datasets.filesystem_dataset import FilesystemDataset from datasets.fast_dataset import FastDataset from metric.shape import vol_intersect_over_union, chamfer_distance, chamfer_distance_l1, silhouette_mask_iou # from util.common import pcd_preprocess from torch.utils.tensorboard import SummaryWriter from accelerate import Accelerator -from util import utils from util.utils import get_tri from metric.lpips.lpips import LPIPS -import gc + + def train(specs, config_path): input_specs = specs['Input'] task_mode = input_specs['task_mode'] - scale = input_specs['scale'] + # scale = input_specs['scale'] tet_grid_size = input_specs['tet_grid_size'] dataset_type = input_specs.get('dataset_type', None) @@ -49,9 +46,9 @@ def train(specs, config_path): warmup_iter = train_specs['warm_up'] scheduler_decay = train_specs['decay'] eva_iter = train_specs['eva_iter'] - xyz_noise_scale = train_specs.get('xyz_noise_scale', 0.0) - init_mdl_path = train_specs.get('init_mdl_path', None) - eva_all_epoch = train_specs.get('eva_all_epoch') + # xyz_noise_scale = train_specs.get('xyz_noise_scale', 0.0) + # init_mdl_path = train_specs.get('init_mdl_path', None) + # eva_all_epoch = train_specs.get('eva_all_epoch') lambda_nc = train_specs.get('lambda_nc', 0) grad_acc = train_specs.get('grad_acc', 1) lambda_lp = train_specs.get('lambda_lp', 0) @@ -124,13 +121,10 @@ def train(specs, config_path): if dataset_type == 'memory': dataset = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode) - chunk_num = 1 elif dataset_type == 'filesystem': dataset = FastDataset(input_specs, train_specs, glctx, device, chunk, mode='all') - # dataset_val_all = FilesystemDataset(input_specs, train_specs, glctx, device, mode='val') - chunk_num = dataset.num_chunk dataset_val = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, @@ -138,92 +132,37 @@ def train(specs, config_path): dataset_vis = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, validate=True, visual=True) - # dataloader_val = torch.utils.data.DataLoader(dataset_val, batch_size=1, - # collate_fn=dataset_val.collate) - # - # for _ in dataloader_val: - # print('@') - if accelerator.is_main_process: writer = SummaryWriter(str(exp_dir)) else: writer = None # Encoder & Decoder & 3-layer MLP HEAD - if specs['Model'] == 'MLP_only': - model = MLPDecoder(specs, exp_dir).to(device) - elif specs['Model'] == 'Pure': - model = PureDecoder(specs, exp_dir).to(device) - elif specs['Model'] == 'Tri': - model = TriDecoder(specs, exp_dir).to(device) - elif specs['Model'] == 'Full': - model = FullDecoder(specs, exp_dir).to(device) - elif specs['Model'] == 'PCFull': - model = PCFullDecoder(specs, exp_dir).to(device) - elif specs['Model'] == 'PC2Full': - model = PC2FullDecoder(specs, exp_dir).to(device) - else: - model = TrDGen(specs, exp_dir).to(device) + model = CRM(specs).to(device) - # model.load_state_dict(torch.load("/home/zhengyi/workspace/Text-to-3D/exp/10_31-17_26_34unet-pp/latest_params.pth", map_location = "cuda:"+str(accelerator.process_index))) - if init_mdl_path != None: - model.load_state_dict(torch.load(init_mdl_path, map_location = "cuda:"+str(accelerator.process_index))['model_state_dict'], strict=False) - - # dataset - # glctx = dr.RasterizeCudaContext() - - # dataset, dataset_val_all = [None] * 2 - - # if dataset_type == 'memory' or dataset_type is None: - # dataset = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode) - - # elif dataset_type == 'filesystem': - # dataset = FilesystemDataset(input_specs, train_specs, glctx, device, mode='all') - # # dataset_val_all = FilesystemDataset(input_specs, train_specs, glctx, device, mode='val') - - # chunk_num = dataset.num_chunk - - # dataset_val = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, - # validate=True) - # dataset_vis = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, - # validate=True, visual=True) - - # dataloader_val = torch.utils.data.DataLoader(dataset_val, batch_size=1, - # collate_fn=dataset_val.collate) - # - # for _ in dataloader_val: - # print('@') - - if accelerator.is_main_process: - writer = SummaryWriter(str(exp_dir)) - else: - writer = None - - - - optimizer = torch.optim.AdamW(model.get_params(l_rate))#(model.parameters(), lr=l_rate) + optimizer = torch.optim.AdamW(model.parameters(), lr=l_rate)#(model.parameters(), lr=l_rate) # DJ optimization schedule scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda x: lr_schedule(x, warmup_iter, scheduler_decay)) - for timestamp in sorted(os.listdir(exp_name), reverse=True): - if re.fullmatch('\d{1,2}_\d{1,2}-\d{1,2}_\d{1,2}_\d{1,2}_tet90', timestamp) \ - and (Path(exp_name) / timestamp / 'val_all_opt_rec' / 'best_shape_params.pth').exists(): - params = Path(exp_name) / timestamp / 'val_all_opt_rec' / 'best_shape_params.pth' - print('load previous 90 tetrahedra checkpoint') - model.load_state_dict(torch.load(params)) + # for timestamp in sorted(os.listdir(exp_name), reverse=True): + # if re.fullmatch('\d{1,2}_\d{1,2}-\d{1,2}_\d{1,2}_\d{1,2}_tet90', timestamp) \ + # and (Path(exp_name) / timestamp / 'val_all_opt_rec' / 'best_shape_params.pth').exists(): + # params = Path(exp_name) / timestamp / 'val_all_opt_rec' / 'best_shape_params.pth' + # print('load previous 90 tetrahedra checkpoint') + # model.load_state_dict(torch.load(params)) - for name, para in model.named_parameters(): - if 'encoder' in name: - para.requires_grad = False + # for name, para in model.named_parameters(): + # if 'encoder' in name: + # para.requires_grad = False - input_specs['tet_grid_size'] = 128 - tet_grid_size = input_specs['tet_grid_size'] + # input_specs['tet_grid_size'] = 128 + # tet_grid_size = input_specs['tet_grid_size'] - train_specs['batch_size'] //= 2 - batch_size = train_specs['batch_size'] + # train_specs['batch_size'] //= 2 + # batch_size = train_specs['batch_size'] - break + # break if args.resume: model.load_state_dict(checkpoint['model_state_dict']) @@ -233,97 +172,6 @@ def train(specs, config_path): lpips = LPIPS(net_type="vgg", device="cuda:" + str(accelerator.process_index)) model, optimizer, scheduler, lpips = accelerator.prepare(model, optimizer, scheduler, lpips) - # lpips = lpips.to(device) - - # verts_gt_val = dataset_val.data['gt_verts'] # load ground truth mesh for evaluation - # faces_gt_val = dataset_val.data['gt_faces'] - - # pcd_tr = torch.Tensor(dataset.pcd_tr[None, ...]).cuda() - # CYF comment - # the following shift/scale operation muted - # not seem necessary for ShapeNet pcd - # pcd_tr -= np.mean(pcd_tr, axis=0) - # bbox_length = np.sqrt(np.sum((np.max(pcd_tr, axis=0) - np.min(pcd_tr, axis=0))**2) ) - # pcd_tr /= bbox_length - # - # xyz_tr, gt_pt_tr = pcd_preprocess(pcd_tr) - - # DJ comment: pretrain SDF - # params = 'exp/net_params.pth' - # if not os.path.exists(params): - # self.pre_train_mesh(num_iterations=1000, gt_pc=sampled_pc) - # torch.save(self.state_dict(), params) - # else: - # self.load_state_dict(torch.load(params)) - - # its_per_epc = num_tr_pts // pt_b_size - - # distance between camera and origin - # radius = specs['Train']['radius'] - # mvps = random_scene(radius, num_epochs * its_per_epc) - - # no need to pretrain any more - pretrain = specs['Pretrain'] - if pretrain['mode'] is not None: - # find the most recent state dict - params = None - for timestamp in sorted(os.listdir(exp_name), reverse=True): - if re.fullmatch('\d{1,2}_\d{1,2}-\d{1,2}_\d{1,2}_\d{1,2}', timestamp) \ - and (Path(exp_name) / timestamp / 'net_params.pth').exists(): - params = Path(exp_name) / timestamp / 'net_params.pth' - break - - # !NOTICE Here! - if params: - # print(params) - model.load_state_dict(torch.load(params)) - else: - BVH = None - if pretrain['mode'] == 'sdf_gt': - # init sdf - import cubvh - BVH = cubvh.cuBVH(dataset.verts, dataset.faces) - - # CVX-H initialization - # Note: only for debug mode now; should expand dataloader for batch mode - pcd_num = dataset.data[0]['gt_pcd'].shape[0] - smpl_pcd = dataset.data[0]['gt_pcd'][random.sample(range(pcd_num), k=sample_points_num), ...] - model.pre_train_mesh(pretrain, smpl_pcd, writer, scale, BVH=BVH, device=device) - # model.pre_train_mesh(pretrain, None, writer, scale, BVH=BVH, device=device) - torch.save(model.state_dict(), exp_dir / 'net_params.pth') - - try: - tets = np.load('tets/{}_tets.npz'.format(tet_grid_size)) - except: - tets = np.load('tets/{}_tets.npz'.format(90)) - tet_verts = (torch.tensor(tets['vertices'], dtype=torch.float32, - device=device) * 2 - 1) * scale / 0.95 # covers [-scale/0.95, scale/0.95] - tet_verts = tet_verts[None, ] - tet_indices = torch.tensor(tets['indices'], dtype=torch.long, device=device) - - # # save groundtruth - # if accelerator.is_main_process: - # print('Save groundtruth') - # data = dataset_val.data - # for i in tqdm(range(len(data))): - # mesh = trimesh.Trimesh(vertices=data[i]['gt_verts'], faces=data[i]['gt_faces']) - # mesh.export(os.path.join(opt_rec_dir, f'mesh_{i}_gt.ply')) - # mesh = trimesh.PointCloud(vertices=data[i]['gt_pcd'], colors=data[i]['gt_pcd_colors']) - # mesh.export(os.path.join(opt_rec_dir, f'pcd_{i}_gt.ply')) - # - # # save val_all_groundtruth - # if dataset_val_all is not None: - # dataset_val_all.load_chunk() - # dataloader = torch.utils.data.DataLoader(dataset_val_all, batch_size=1, - # collate_fn=dataset_val_all.collate) - # for i, data in enumerate(tqdm(dataloader)): - # mesh = trimesh.Trimesh(vertices=data['gt_verts'][0].cpu(), faces=data['gt_faces'][0].cpu()) - # mesh.export(os.path.join(val_all_opt_rec_dir, f'mesh_{i}_gt.ply')) - # mesh = trimesh.PointCloud(vertices=data['gt_pcd'][0].cpu(), colors=data['gt_pcd_colors'][0].cpu()) - # mesh.export(os.path.join(val_all_opt_rec_dir, f'pcd_{i}_gt.ply')) - # - # if 'RANK' in os.environ: - # dist.barrier() dataloader_vis = torch.utils.data.DataLoader(dataset_vis, batch_size=1, collate_fn=dataset_vis.collate) @@ -389,8 +237,8 @@ def train(specs, config_path): # alpha = train_specs['lambda_color'] * np.clip(k * (epc / num_epochs - 0.5) + 0.05, 0, 0.1) # pcd_tr = dataloader.pcd_tr - for iter, data in enumerate(dataloader): - gc.collect() + for data in dataloader: + # gc.collect() model.train() # mvp = mvps[iter_all] @@ -403,8 +251,8 @@ def train(specs, config_path): # iter_all += 1 # continue # make data and tet sample size consistent - tet_verts_batch = tet_verts.repeat(data['gt_pcd'].shape[0], 1, 1) - result, verts, faces = model(data, tet_verts_batch, tet_indices, glctx, xyz_noise_scale=xyz_noise_scale) + # tet_verts_batch = tet_verts.repeat(data['gt_pcd'].shape[0], 1, 1) + result, verts, faces = model(data, glctx) lap_loss_list, chamfer_loss_list = [], [] # try: @@ -412,16 +260,12 @@ def train(specs, config_path): lap_loss_list.append(laplacian_smooth_loss(verts[i], faces[i])) pred_points = kaolin.ops.mesh.sample_points(verts[i].unsqueeze(0), faces[i], sample_points_num)[0][0] - chamfer_loss_list.append(chamfer_distance(pred_points.unsqueeze(0), data['gt_pcd'][i].unsqueeze(0)).mean()) # use dataloader; pcd_tr.cuda() + gt_points = kaolin.ops.mesh.sample_points(data['gt_verts'][i].unsqueeze(0), data['gt_faces'][i], sample_points_num)[0][0] + chamfer_loss_list.append(chamfer_distance(pred_points.unsqueeze(0), gt_points.unsqueeze(0)).mean()) # use dataloader; pcd_tr.cuda() result['lap_loss'] = sum(lap_loss_list) / len(lap_loss_list) result['chamfer_loss'] = sum(chamfer_loss_list) / len(chamfer_loss_list) - # except Exception as e: - # print(e) - # print(f'\033[91mtrain: 004 error occur\033[0m') - # result['lap_loss'] = 0. - # result['chamfer_loss'] = 0. if train_specs['tex_sup_mode'] == 'blender': reso = result["albedo_list"].shape[-2] lpips_train = result["albedo_list"].view(-1, result["albedo_list"].shape[-3], result["albedo_list"].shape[-2], result["albedo_list"].shape[-1]).permute(0,3,1,2) @@ -434,8 +278,7 @@ def train(specs, config_path): lpips_gt = lpips_gt[:,:,startx:startx+256,starty:starty+256] result['lpips_loss'] = lpips(lpips_train, lpips_gt) - else: - result['lpips_loss'] = 0 + # ) if sup_mode == "rnd": # shape supervision I: rendered silhouette and depth losses @@ -444,11 +287,11 @@ def train(specs, config_path): + lambda_nc * result['nc_loss'] + lambda_lp *result['lpips_loss'] + lambda_wzy * result["wzy_loss"] if geo_type == "flex": loss = loss + result["flex_surf_loss"] * 0.5 * 0.0 + result["flex_weight_loss"] * 0.1 * 0.1 - elif sup_mode == "pcd": - # shape supervision II: Chamfer distance loss - loss = result['chamfer_loss'] + specs['Train']['lambda_smooth'] * result['lap_loss'] - else: - raise ValueError("Error! Unrecognized supervision mode.") + # elif sup_mode == "pcd": + # # shape supervision II: Chamfer distance loss + # loss = result['chamfer_loss'] + specs['Train']['lambda_smooth'] * result['lap_loss'] + # else: + # raise ValueError("Error! Unrecognized supervision mode.") # loss.backward() @@ -527,7 +370,7 @@ def train(specs, config_path): # print(accelerator.process_index, data['prompt'], data['uuid']) model.eval() # try: - cham_dist_opt, rgb_err_opt = eval_and_save(accelerator, writer, model, tet_verts, tet_indices, + cham_dist_opt, rgb_err_opt = eval_and_save(accelerator, writer, model, sample_points_num, iter_all, dataset_val, device, opt_rec_dir, cur_rec_dir, cham_dist_opt, rgb_err_opt, glctx ) @@ -549,16 +392,16 @@ def train(specs, config_path): # try: tnew_list = [0,100,200,300,400,500,600,700,800,900,999] with torch.no_grad(): - result, verts, faces = accelerator.unwrap_model(model)(data_vis, tet_verts, tet_indices, glctx, tnew=tnew_list[(iter_all//eva_iter)%len(tnew_list)]) + result, verts, faces = accelerator.unwrap_model(model)(data_vis, glctx, tnew=tnew_list[(iter_all//eva_iter)%len(tnew_list)]) color_fine, _ = accelerator.unwrap_model(model).render_color_img(verts[0].unsqueeze(dim=0), faces[0], data_vis, glctx) - color_fine_gt, _ = accelerator.unwrap_model(model).render_color_img(verts[0].unsqueeze(dim=0), faces[0], - data_vis, glctx, gt=True) - color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], - data_vis, glctx, gt=True) - color_shape_gt2 = color_shape_gt[..., [2, 1, 0]].detach().cpu().numpy() - xyzs2 = xyzs[..., [2, 1, 0]].detach().cpu().numpy() + # color_fine_gt, _ = accelerator.unwrap_model(model).render_color_img(verts[0].unsqueeze(dim=0), faces[0], + # data_vis, glctx, gt=True) + # color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], + # data_vis, glctx, gt=True) + # color_shape_gt2 = color_shape_gt[..., [2, 1, 0]].detach().cpu().numpy() + # xyzs2 = xyzs[..., [2, 1, 0]].detach().cpu().numpy() # cv2.imwrite(exp_dir.as_posix() + f"/ep{epc}-chunk{chunk}-rotate.jpg", np.concatenate((xyzs2[0], color_shape_gt2[0]), axis=1)*255) # color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], @@ -578,24 +421,24 @@ def train(specs, config_path): # xyzs_tensor = torch.cat((xyzs_tensor1, xyzs_tensor2.flip(0)), dim = 0) # xyzs_tensor = xyzs_tensor.detach().cpu().numpy() - tri_img_dir = exp_dir / 'tri_img' - tri_img_dir.mkdir(exist_ok=True) - # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-color.jpg",color_tensor * 255) - # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-xyz.jpg",xyzs_tensor * 255) - if specs["Train"].get("random_bg", False): - color = data_vis['triview_color'][0].permute(0,3,1,2).clone() - xyzs = data_vis['triview_xyz'][0].permute(0,3,1,2).clone() - crgb = random.random() - cxyz = random.random() - for j in range(6): - mask = torch.mean(xyzs[j], dim = 0, keepdim=False) - mask = (mask == 0) - for k in range(3): - color[j][k][mask] = crgb - xyzs[j][k][mask] = cxyz + # tri_img_dir = exp_dir / 'tri_img' + # tri_img_dir.mkdir(exist_ok=True) + # # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-color.jpg",color_tensor * 255) + # # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-xyz.jpg",xyzs_tensor * 255) + # if specs["Train"].get("random_bg", False): + # color = data_vis['triview_color'][0].permute(0,3,1,2).clone() + # xyzs = data_vis['triview_xyz'][0].permute(0,3,1,2).clone() + # crgb = random.random() + # cxyz = random.random() + # for j in range(6): + # mask = torch.mean(xyzs[j], dim = 0, keepdim=False) + # mask = (mask == 0) + # for k in range(3): + # color[j][k][mask] = crgb + # xyzs[j][k][mask] = cxyz - cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-color-gt.jpg",get_tri(color, blender= True if specs["Train"].get("tex_sup_mode", "pcd-nnb") == 'blender' else False, c=crgb).permute(1,2,0)[..., [2, 1, 0]].detach().cpu().numpy() * 255) - cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-xyz-gt.jpg",get_tri(xyzs, blender= True if specs["Train"].get("tex_sup_mode", "pcd-nnb") == 'blender' else False, c=cxyz).permute(1,2,0).detach().cpu().numpy() * 255) + # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-color-gt.jpg",get_tri(color, blender= True if specs["Train"].get("tex_sup_mode", "pcd-nnb") == 'blender' else False, c=crgb).permute(1,2,0)[..., [2, 1, 0]].detach().cpu().numpy() * 255) + # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-xyz-gt.jpg",get_tri(xyzs, blender= True if specs["Train"].get("tex_sup_mode", "pcd-nnb") == 'blender' else False, c=cxyz).permute(1,2,0).detach().cpu().numpy() * 255) # color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], # data_vis, glctx, mvp = sds_scene(6)[None,...].to(device)) @@ -613,7 +456,7 @@ def train(specs, config_path): # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-sds-color.jpg",color_tensor * 255) # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-sds-xyz.jpg",xyzs_tensor * 255) - img = accelerator.unwrap_model(model).visualize(result, epc, chunk, color_fine, color_fine_gt, rdr_img_dir, iter_all) + img = accelerator.unwrap_model(model).visualize(result, epc, chunk, color_fine, rdr_img_dir, iter_all) # only show the first validation mesh writer.add_image('eval/visual', img[0], iter_all, dataformats='HWC') # except Exception as e: @@ -627,20 +470,19 @@ def train(specs, config_path): return# model -def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_points_num, iter_all, dataset, device, +def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, dataset, device, opt_rec_dir, cur_rec_dir, cham_dist_opt, rgb_err_opt, glctx, type=''): - if isinstance(dataset, FilesystemDataset): + if isinstance(dataset, FastDataset): num_chunk = dataset.num_chunk else: num_chunk = 1 - chamfer_dist_all, vol_IoU_all, lap_loss_all, verts_list_all, faces_list_all, gt_verts_list_all, gt_faces_list_all, \ - pc_list_all, pc_colors_list_all = [], [], [], [], [], [], [], [], [] + chamfer_dist_all, vol_IoU_all, lap_loss_all, verts_list_all, faces_list_all, gt_verts_list_all, gt_faces_list_all= [], [], [], [], [], [], [] chamfer_l1_all, mask_iou_all, color_loss_all, depth_loss_all, silhouette_loss_all = [], [], [], [], [] triview_color_list_all, triview_xyz_list_all = [], [] for _ in range(num_chunk): - if isinstance(dataset, FilesystemDataset): + if isinstance(dataset, FastDataset): dataset.load_chunk() # skip empty chunk if len(dataset) == 0: @@ -653,12 +495,11 @@ def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_poi # val_len = len(dataloader_val) for data_val in tqdm(dataloader): - chamfer_dist, vol_IoU, lap_loss, verts_list, faces_list, gt_verts_list, gt_faces_list, pc_list, pc_colors_list = \ - [], [], [], [], [], [], [], [], [] + chamfer_dist, vol_IoU, lap_loss, verts_list, faces_list, gt_verts_list, gt_faces_list = [], [], [], [], [], [], [] chamfer_l1, mask_iou, color_loss, depth_loss, silhouette_loss = [], [], [], [], [] triview_color_list, triview_xyz_list = [], [] with torch.no_grad(): - result, verts, faces = accelerator.unwrap_model(model)(data_val, tet_verts, tet_indices, glctx) + result, verts, faces = accelerator.unwrap_model(model)(data_val, glctx) torch.cuda.empty_cache() # result = dict((key, value.detach().cpu()) for key, value in result.items()) @@ -669,16 +510,17 @@ def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_poi for i in range(len(verts)): pred_points = kaolin.ops.mesh.sample_points(verts[i].unsqueeze(0), faces[i], sample_points_num)[0][0] + gt_points = kaolin.ops.mesh.sample_points(data_val['gt_verts'][i].unsqueeze(0), data_val['gt_faces'][i], sample_points_num)[0][0] chamfer_dist.append( chamfer_distance( - pred_points.unsqueeze(0), data_val['gt_pcd'][i].unsqueeze(0)).detach().cpu().numpy()) # use dataloader + pred_points.unsqueeze(0), gt_points.unsqueeze(0)).detach().cpu().numpy()) # use dataloader vol_IoU.append(vol_intersect_over_union(verts[i].unsqueeze(dim=0), faces[i].type(torch.LongTensor), data_val['gt_verts'][i].unsqueeze(dim=0), data_val['gt_faces'][i], device=device).detach().cpu().numpy()) lap_loss.append(laplacian_smooth_loss(verts[i], faces[i]).detach().cpu().numpy()) chamfer_l1.append( - chamfer_distance_l1(pred_points, data_val['gt_pcd'][i], device=device).detach().cpu().numpy()) + chamfer_distance_l1(pred_points, gt_points, device=device).detach().cpu().numpy()) mask_iou.append(silhouette_mask_iou(result['alpha'][i], result['alpha_gt'][i]).detach().cpu().numpy()) color_loss.append(result['color_loss'].detach().cpu().numpy()) @@ -689,8 +531,8 @@ def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_poi faces_list.append(faces[i].detach().cpu().numpy()) gt_verts_list.append(data_val['gt_verts'][i].cpu().numpy()) gt_faces_list.append(data_val['gt_faces'][i].cpu().numpy()) - pc_list.append(data_val['gt_pcd'].cpu().numpy()) - pc_colors_list.append(data_val['gt_pcd_colors'].cpu().numpy()) + # pc_list.append(data_val['gt_pcd'].cpu().numpy()) + # pc_colors_list.append(data_val['gt_pcd_colors'].cpu().numpy()) if data_val.get('triview_color') is None: triview_color_list.append(np.nan) @@ -711,8 +553,8 @@ def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_poi depth_loss = accelerator.gather_for_metrics(depth_loss) silhouette_loss = accelerator.gather_for_metrics(silhouette_loss) - pc_list = accelerator.gather_for_metrics(pc_list) - pc_colors_list = accelerator.gather_for_metrics(pc_colors_list) + # pc_list = accelerator.gather_for_metrics(pc_list) + # pc_colors_list = accelerator.gather_for_metrics(pc_colors_list) verts_list = accelerator.gather_for_metrics(verts_list) faces_list = accelerator.gather_for_metrics(faces_list) gt_verts_list = accelerator.gather_for_metrics(gt_verts_list) @@ -732,8 +574,8 @@ def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_poi depth_loss_all.extend(depth_loss) silhouette_loss_all.extend(silhouette_loss) - pc_list_all.extend(pc_list) - pc_colors_list_all.extend(pc_colors_list) + # pc_list_all.extend(pc_list) + # pc_colors_list_all.extend(pc_colors_list) verts_list_all.extend(verts_list) faces_list_all.extend(faces_list) gt_verts_list_all.extend(gt_verts_list) @@ -751,8 +593,8 @@ def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_poi depth_loss = depth_loss_all silhouette_loss = silhouette_loss_all - pc_list = pc_list_all - pc_colors_list = pc_colors_list_all + # pc_list = pc_list_all + # pc_colors_list = pc_colors_list_all verts_list = verts_list_all faces_list = faces_list_all gt_verts_list = gt_verts_list_all @@ -786,16 +628,15 @@ def eval_and_save(accelerator, writer, model, tet_verts, tet_indices, sample_poi (iter_all, metric['chamfer_dist'], cham_dist_opt, metric['color_loss'], rgb_err_opt, metric['Chamfer_L1'], metric['Mask_IoU'], metric['depth_loss'], metric['silhouette_loss']), flush=True) - if 'RANK' in os.environ: - dist.barrier() + accelerator.wait_for_everyone() # img = model.visualize(result, epc, chunk) # # only show the first validation mesh # writer.add_image('eval/visual', img[0], iter_all, dataformats='HWC') - zip_data = [(pc, pc_colors, verts, faces, gt_verts, gt_faces, triview_color, triview_xyz) - for pc, pc_colors, verts, faces, gt_verts, gt_faces, triview_color, triview_xyz in - zip(pc_list, pc_colors_list, verts_list, faces_list, gt_verts_list, gt_faces_list, triview_color_list, triview_xyz_list)] + zip_data = [(verts, faces, gt_verts, gt_faces, triview_color, triview_xyz) + for verts, faces, gt_verts, gt_faces, triview_color, triview_xyz in + zip(verts_list, faces_list, gt_verts_list, gt_faces_list, triview_color_list, triview_xyz_list)] gpu_idx = accelerator.local_process_index @@ -811,21 +652,21 @@ def save_export(mode): with accelerator.split_between_processes(zip_data) as tmp_data: for j, ele in enumerate(tmp_data): - pc, pc_colors, verts, faces, gt_verts, gt_faces, triview_color, triview_xyz = ele + verts, faces, gt_verts, gt_faces, triview_color, triview_xyz = ele # export gt if not os.path.exists(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_mesh.ply')): mesh = trimesh.Trimesh(vertices=gt_verts, faces=gt_faces) mesh.export(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_mesh.ply')) - if not os.path.exists(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_pcd.ply')): - pcd = trimesh.PointCloud(vertices=pc[0], colors=pc_colors[0]) - pcd.export(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_pcd.ply')) + # if not os.path.exists(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_pcd.ply')): + # pcd = trimesh.PointCloud(vertices=pc[0], colors=pc_colors[0]) + # pcd.export(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_pcd.ply')) # export pred data = { 'gt_verts': torch.tensor(gt_verts, device=device).unsqueeze(0), - 'gt_pcd': torch.tensor(pc, device=device), - 'gt_pcd_color': torch.tensor(pc_colors, device=device), + # 'gt_pcd': torch.tensor(pc, device=device), + # 'gt_pcd_color': torch.tensor(pc_colors, device=device), 'verts': torch.tensor(verts, device=device).unsqueeze(0), 'faces': torch.tensor(faces, device=device).unsqueeze(0), 'triview_color': torch.tensor(triview_color, device=device), @@ -863,7 +704,7 @@ def save_export(mode): arg_parser = argparse.ArgumentParser() arg_parser.add_argument( "--exp_dir", "-e", - default="config/", + default="configs/", help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", ) arg_parser.add_argument( diff --git a/util/renderer.py b/util/renderer.py index 2d1dc69..76d9ee6 100644 --- a/util/renderer.py +++ b/util/renderer.py @@ -1,7 +1,11 @@ import torch import torch.nn as nn +import torch.nn.functional as F import nvdiffrast.torch as dr + +from util.utils import safe_normalize +from util.loss import normal_consistency from util.flexicubes_geometry import FlexiCubesGeometry class Renderer(nn.Module): @@ -14,10 +18,17 @@ def __init__(self, tet_grid_size, camera_angle_num, scale, geo_type): self.geo_type = geo_type self.glctx = dr.RasterizeCudaContext() + self.l1_loss = nn.L1Loss() + self.mse_loss = nn.MSELoss() + 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): + mvp = data['mvp'] + campos = data['campos'] + h, w = data['resolution'] + persp = data['persp'] results = {} @@ -46,4 +57,95 @@ def forward(self, data, sdf, deform, verts, tets, training=False, weight = None) results["flex_surf_loss"] = flexicubes_surface_reg results["flex_weight_loss"] = flexicubes_weight_reg - return results, verts, faces \ No newline at end of file + alpha_list, alpha_ctn_list, depth_list, norm_list, nc_list = [], [], [], [], [] + for i in range(len(verts)): + alpha, alpha_ctn, depth, normal, face_normals = \ + render_mesh(self.glctx, verts[i], faces[i], mvp[i], campos[i], persp, resolution=(h, w)) + + alpha_list.append(alpha) + alpha_ctn_list.append(alpha_ctn) + depth_list.append(depth) + norm_list.append(normal) + nc_list.append(normal_consistency(face_normals, faces[i])) + + alpha = torch.stack(alpha_list, dim=0) + alpha_ctn = torch.stack(alpha_ctn_list, dim=0) + depth = torch.stack(depth_list, dim=0) + normal = torch.stack(norm_list, dim=0) + results['nc_loss'] = torch.stack(nc_list, dim=0).mean() + + results['alpha'] = alpha + results['alpha_ctn'] = alpha_ctn + results['depth'] = depth + results['normal_image'] = (normal + 1) / 2 + + # results['normal_loss'] = normal_consistency(face_normals, faces) + try:# TODO remove these lines + results['alpha_gt'] = data['alpha'] + results['alpha_ctn_gt'] = data['alpha_ctn'] + results['depth_gt'] = data['depth'] + # results['image'] = color + # results['weights_sum'] = alpha.squeeze(-1) + + # # if self.opt.lambda_2d_normal_smooth > 0 or self.opt.lambda_normal > 0: + # normal_image = dr.antialias((normal + 1) / 2, rast, verts_clip, faces).clamp(0, 1) # [B, H, W, 3] + # results['normal_image'] = normal_image + results['normal_gt'] = (data['normal'] + 1) / 2 + # regularizations + # if self.training: + + # print(results['alpha_ctn_gt'].shape, results['depth'].shape) + results['silhouette_loss'] = self.mse_loss(results['alpha_ctn'], results['alpha_ctn_gt']) + # results['depth_loss'] = self.l1_loss(results['depth'], results['depth_gt']) + results['depth_loss'] = self.mse_loss(results['depth'] * results['alpha_ctn_gt'].clone().detach(), results['depth_gt']) + except: + pass + + return results, verts, faces + +def render_mesh(ctx, verts, faces, mvp, view_pos, persp, resolution, normal_only=False): + # spp=iter_spp, num_layers=self.FLAGS.layers, msaa=True, background=None)['shaded']: + # get normals + + i0, i1, i2 = faces[:, 0], faces[:, 1], faces[:, 2] + v0, v1, v2 = verts[i0, :], verts[i1, :], verts[i2, :] + + faces = faces.int() + + face_normals = torch.cross(v1 - v0, v2 - v0) + face_normals = safe_normalize(face_normals) + + vn = torch.zeros_like(verts) + 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) + + vn = torch.where(torch.sum(vn * vn, -1, keepdim=True) > 1e-20, vn, + torch.tensor([0.0, 0.0, 1.0], dtype=torch.float32, device=vn.device)) + + # rasterization + verts_clip = torch.bmm( + F.pad(verts, pad=(0, 1), mode='constant', value=1.0).unsqueeze(0).repeat(mvp.shape[0], 1, 1), + mvp.permute(0, 2, 1)).float() # [B, N, 4] + # assert verts_clip.shape[0] > 0 and verts_clip.shape[1] > 0, print(verts_clip.shape, verts.shape) + rast, rast_db = dr.rasterize(ctx, verts_clip, faces, resolution) + + alpha = (rast[..., 3:] > 0).float() + # CYF Note: enable gradient via antialiasing + alpha_ctn = dr.antialias(alpha, rast, verts_clip, faces).clamp(0, 1) + # rast[..., 3:][rast[..., 3:] > 0] /= rast[..., 3:][rast[..., 3:] > 0] + # xyzs, _ = dr.interpolate(verts.unsqueeze(0), rast, faces) # [B, H, W, 3] + normal, _ = dr.interpolate(vn.unsqueeze(0).contiguous(), rast, faces) + normal = safe_normalize(normal) + + if normal_only: + return normal, face_normals + + xyzw = verts_clip @ torch.inverse(persp.T) + depth_ = (xyzw[..., 2] / xyzw[..., 3]).unsqueeze(-1) + + depth_, _ = dr.interpolate(depth_, rast, faces, rast_db=rast_db, + diff_attrs=None if rast_db is None else 'all') + depth = dr.antialias(depth_, rast, verts_clip, faces) + + return alpha, alpha_ctn, -depth, normal, face_normals \ No newline at end of file diff --git a/util/utils.py b/util/utils.py index ab3cad9..de61705 100644 --- a/util/utils.py +++ b/util/utils.py @@ -1,6 +1,12 @@ import numpy as np import torch import random +import json +import os + +# objaverse +DEPTH_MAX, DEPTH_MIN = 2.4, 0.6 +DEPTH_VALID_MAX, DEPTH_VALID_MIN = 2.37, 0.63 # Reworked so this matches gluPerspective / glm::perspective, using fovy @@ -192,3 +198,13 @@ def get_tri(triview_color, dim = 1, blender=True, c = 0, scale=0.95, shift = 0, color_tensor_gt = torch.cat((color_tensor1_gt, color_tensor2_gt), dim = dim) return color_tensor_gt +def load_transform(filepath): + if filepath == '': + return None + uuid2transform = {} + with open(filepath, 'r') as f: + data = json.load(f) + for item in data: + uuid = os.path.splitext(item['name'])[0] + uuid2transform[uuid] = item + return uuid2transform From 89e32457e4d477d5ed96a23f760458025e08b035 Mon Sep 17 00:00:00 2001 From: yudajiang Date: Thu, 28 Nov 2024 14:37:55 +0800 Subject: [PATCH 3/4] restruct: follow pylint standard to restruct code --- README.md | 1 + configs/specs_objaverse_lvis.json | 45 +- datasets/dataset.py | 101 +-- datasets/fast_dataset.py | 1005 ++++++++------------- datasets/memory_dataset.py | 677 ++++++-------- make_chunk.py | 51 +- make_chunk_sub.py | 49 +- metric/shape.py | 141 +-- model/archs/decoders/shape_texture_net.py | 2 +- model/archs/mlp_head.py | 15 +- model/crm/model.py | 625 ++++--------- train_crm.py | 520 ++++------- util/loss.py | 13 +- util/renderer.py | 143 ++- util/utils.py | 2 +- 15 files changed, 1189 insertions(+), 2201 deletions(-) diff --git a/README.md b/README.md index 87a66be..050b76b 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Multiprocess multi-threads chunks generation ```bash python make_chunk.py -c specs_xxxx.json -p 4 # change to proper number of process for your machine ``` +log info will be recorded in the log.log in the root directory. ### Step 2. Train Use the same config json file in **step.1** for training diff --git a/configs/specs_objaverse_lvis.json b/configs/specs_objaverse_lvis.json index 0a66f4d..936d230 100644 --- a/configs/specs_objaverse_lvis.json +++ b/configs/specs_objaverse_lvis.json @@ -2,7 +2,6 @@ "Model": "TrDGen", "Input": { - "task_mode": "batch", "mesh_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis_mesh", "render_img_dir": "/home/yudajiang/datasets/Objaverse/objaverse_lvis", "blender_transform": "/home/yudajiang/datasets/Objaverse/normalize_anno/meta_data_new.json", @@ -26,62 +25,22 @@ "resolution_triview": [256, 256] }, - "Pretrain": { - "mode": null, - "warm_up": 0, - "batch_size": 1024, - "warmup_iter": 0, - "decay": 0.0000, - "num_iter": 1000, - "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 }, "sample_points_num": 20000, - "query_sample_points_num": 60000, "batch_size": 1, - "eva_iter": 80, + "eva_iter": 100, "save_chunk": 50, - "eva_all_epoch": 0, - "tex_sup_mode": "blender", - "dep&sill_sup_mode": "blender", "lambda_smooth": 1, - "lambda_nc": 0, "lambda_lp": 0.2, "lambda_color": 2, - "lambda_l2": 0.00, - "lambda_wzy": 0.0, - "exp_uv_mesh": false, - "doub": false, - "random_bg": false, - "sd_mode": null, - "sd_cfg": 100, - "sd_lambda": 10, - "shift": 0, - "geo_type": "flex", - "init_mdl_path": null - }, - - "ArchSpecs": { - "pc_enc": "img", - "unet_type": "diffusers", - "use_3D_aware": false, - "fea_concat": false, - "mlp_bias": true, - "q_plane": false, - "gt_triimg": true + "radius": 0.5 }, "EncoderSpecs": { diff --git a/datasets/dataset.py b/datasets/dataset.py index 3168b3b..2b568a6 100644 --- a/datasets/dataset.py +++ b/datasets/dataset.py @@ -1,11 +1,13 @@ -# Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual -# property and proprietary rights in and to this material, related -# documentation and any modifications thereto. Any use, reproduction, -# disclosure or distribution of this material and related documentation -# without an express license agreement from NVIDIA CORPORATION or -# its affiliates is strictly prohibited. +''' +Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +property and proprietary rights in and to this material, related +documentation and any modifications thereto. Any use, reproduction, +disclosure or distribution of this material and related documentation +without an express license agreement from NVIDIA CORPORATION or +its affiliates is strictly prohibited. +''' import torch @@ -23,70 +25,25 @@ def __getitem__(self, itr): raise NotImplementedError def collate(self, batch): - # iter_res = batch[0]['resolution'] - # tets = batch[0]['tets'] - # points = batch[0]['points'] - # iter_spp = batch[0]['spp'] + """custom collation for non torch values like resolution, perspectives""" res = { - 'uuid': list([item['uuid'] for item in batch]), - # 'gt_pcd': torch.cat(list([item['gt_pcd'] for item in batch]), dim=0).to(self.device), - # 'gt_pcd_colors': torch.cat(list([item['gt_pcd_colors'] for item in batch])).to(self.device), - # 'gt_pcd_query': torch.cat(list([item['gt_pcd_query'] for item in batch]), dim=0).to(self.device), - # 'gt_pcd_colors_query': torch.cat(list([item['gt_pcd_colors_query'] for item in batch])).to(self.device), - 'gt_render_imgs': torch.cat(list([item['gt_render_imgs'] for item in batch]), dim=0).to(self.device), - # 'verts': torch.cat(list([item['verts'] for item in batch]), dim=0).to(self.device), - # 'tets': tets.to(self.device), - 'gt_verts': list([item['gt_verts'].to(self.device) for item in batch]), - 'gt_faces': list([item['gt_faces'].to(self.device) for item in batch]), - 'mv': torch.cat(list([item['mv'] for item in batch]), dim=0).to(self.device), - 'mvp': torch.cat(list([item['mvp'] for item in batch]), dim=0).to(self.device), - 'campos': torch.cat(list([item['campos'] for item in batch]), dim=0).to(self.device), - 'alpha': torch.cat(list([item['alpha'] for item in batch]), dim=0).to(self.device), - 'alpha_ctn': torch.cat(list([item['alpha_ctn'] for item in batch]), dim=0).to(self.device), - 'depth': torch.cat(list([item['depth'] for item in batch]), dim=0).to(self.device), - 'normal': torch.cat(list([item['normal'] for item in batch]), dim=0).to(self.device), - 'persp': batch[0]['persp'].to(self.device), - # 'time': sum(list([item['time'] for item in batch])), - 'resolution': batch[0]['resolution'], - 'resolution_img': batch[0]['resolution_img'], - 'resolution_triview': batch[0]['resolution_triview'] - # 'spp' : iter_spp, - # 'img': torch.cat(list([item['img'] for item in batch]), dim=0) + "uuid": list(item["uuid"] for item in batch), + "verts": list(item["verts"].to(self.device) for item in batch), + "faces": list(item["faces"].to(self.device) for item in batch), + "render_imgs": torch.cat(list(item["render_imgs"] for item in batch), dim=0).to(self.device), + "mv": torch.cat(list(item["mv"] for item in batch), dim=0).to(self.device), + "mvp": torch.cat(list(item["mvp"] for item in batch), dim=0).to(self.device), + # "campos": torch.cat(list(item["campos"] for item in batch), dim=0).to(self.device), + "alpha": torch.cat(list(item["alpha"] for item in batch), dim=0).to(self.device), + # "alpha_ctn": torch.cat(list(item["alpha_ctn"] for item in batch), dim=0).to(self.device), + "depth": torch.cat(list(item["depth"] for item in batch), dim=0).to(self.device), + "normal": torch.cat(list(item["normal"] for item in batch), dim=0).to(self.device), + "triview_color": torch.cat(list(item["triview_color"] for item in batch), dim=0).to(self.device), + "triview_xyz": torch.cat(list(item["triview_xyz"] for item in batch), dim=0).to(self.device), + "prompt": list(item["prompt"] for item in batch), + "persp": batch[0]["persp"].to(self.device), + "resolution": batch[0]["resolution"], + "resolution_img": batch[0]["resolution_img"], + "resolution_triview": batch[0]["resolution_triview"], } - if batch[0].get('triview_color') is not None: - res.update({ - 'triview_color': torch.cat(list([item['triview_color'] for item in batch]), dim=0).to(self.device) - }) - if batch[0].get('triview_xyz') is not None: - res.update({ - 'triview_xyz': torch.cat(list([item['triview_xyz'] for item in batch]), dim=0).to(self.device) - }) - if batch[0].get('prompt') is not None: - res.update({ - 'prompt': list([item['prompt'] for item in batch]) - }) return res - - -# class DatasetPoints(torch.utils.data.Dataset): -# """Basic dataset interface""" -# def __init__(self): -# super().__init__() -# -# def __len__(self): -# raise NotImplementedError -# -# def __getitem__(self, itr): -# raise NotImplementedError -# -# def collate(self, batch): -# iter_res = batch[0]['resolution'] -# # iter_spp = batch[0]['spp'] -# return { -# 'mv': torch.cat(list([item['mv'] for item in batch]), dim=0), -# 'mvp': torch.cat(list([item['mvp'] for item in batch]), dim=0), -# 'campos': torch.cat(list([item['campos'] for item in batch]), dim=0), -# 'resolution': iter_res, -# # 'spp' : iter_spp, -# # 'img': torch.cat(list([item['img'] for item in batch]), dim=0) -# } diff --git a/datasets/fast_dataset.py b/datasets/fast_dataset.py index 70cbc82..6f43571 100644 --- a/datasets/fast_dataset.py +++ b/datasets/fast_dataset.py @@ -1,41 +1,43 @@ +''' +Chunk Generation for Large Dataset +''' + import math import os -import shutil -from concurrent.futures import Future, ThreadPoolExecutor +from concurrent.futures import ThreadPoolExecutor from itertools import cycle from pathlib import Path -from typing import List, Optional, Dict, Tuple, Union, Type +from typing import List, Tuple import random -import torch.distributed as dist import pickle +import logging +import asyncio +import io import numpy as np import pyarrow as pa -import pyarrow.parquet as pq +from pyarrow import parquet as pq import torch import trimesh from tqdm import tqdm -from .dataset import Dataset +import aiofiles +import cv2 + from util import utils, renderer from util.utils import DEPTH_MAX, DEPTH_MIN, DEPTH_VALID_MIN, DEPTH_VALID_MAX -import json -import cv2 -from PIL import Image -import logging -import aiofiles -import asyncio -import io +from datasets.dataset import Dataset + logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO) def chunk_with_size(lst, n): - """return successive n-sized chunks from lst.""" + '''return successive n-sized chunks from lst.''' for i in range(0, len(lst), n): yield lst[i:i + n] - - + + def chunk_with_number(lst, n): - """split lst into n chunks, all chunks have near chunk size diffrence no more than 1, just like np.array_split""" + '''split lst into n chunks, all chunks have near chunk size diffrence no more than 1, just like np.array_split''' chunk_size = len(lst) // n remain = len(lst) % n start = 0 @@ -46,33 +48,34 @@ def chunk_with_number(lst, n): yield lst[start:end] start = end -async def aread_file(file_path, mode="rb"): +async def aread_file(file_path, mode='rb'): + '''read files from disk into memory''' async with aiofiles.open(file_path, mode=mode) as f: return await f.read() async def abatch_read_files(file_paths: List[str]): - # read files from disk into memory, return a list of bytes + '''read files from disk into memory (batch), return a list of bytes''' return await asyncio.gather(*[aread_file(file_path) for file_path in file_paths]) def buffer_to_cv2image(buffer): - # convert bytes to image + '''convert bytes to image''' return cv2.imdecode(np.frombuffer(buffer, dtype=np.uint8), cv2.IMREAD_UNCHANGED) def batch_buffer_to_cv2image(buffers): + '''convert bytes to image (batch)''' return [buffer_to_cv2image(buffer) for buffer in buffers] class FastDataset(Dataset): - + ''' + Torch Dataset for training + ''' def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_process=1, process_index=0): - # metadata_items: List[ImageMetadata], near: float, far: float, ray_altitude_range: List[float], - # center_pixels: bool, device: torch.device, chunk_paths: List[Path], num_chunks: int, - # scale_factor: int, disk_flush_size: int): - super(FastDataset, self).__init__(device) + super().__init__(device) self.device = device self.glctx = glctx self.mode = mode - self.cam_radius = input_specs['radius'] + # self.cam_radius = input_specs['radius'] self.fovx = np.deg2rad(45) self.res = input_specs['resolution'] self.res_img = input_specs.get('resolution_img') @@ -83,15 +86,12 @@ def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_pro self.prompt_path = input_specs.get('prompt_path', '') self.aspect = self.res[1] / self.res[0] self.pts_num = train_specs['sample_points_num'] - self.query_pts_num = train_specs['query_sample_points_num'] + # self.query_pts_num = train_specs['query_sample_points_num'] self.epoch = train_specs['num_epochs'] - # self.its_per_epc = train_specs["its_per_epc"] self.scale = input_specs['scale'] - self.render_mode = train_specs.get('tex_sup_mode') - self.dep_sill_mode = train_specs.get('dep&sill_sup_mode') + # self.render_mode = train_specs.get('tex_sup_mode') + # self.dep_sill_mode = train_specs.get('dep&sill_sup_mode') - # self.mode = input_specs['mode'] - # self.pcd_dir = input_specs['pcd_dir'] self.mesh_dir = input_specs['mesh_dir'] self.class_name = input_specs['class'] self.camera_angle_num = input_specs['camera_angle_num'] @@ -114,24 +114,16 @@ def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_pro self.uuid2transform = utils.load_transform(input_specs.get('blender_transform')) chunk_path = input_specs['chunk_path'] self.dataset_name = input_specs['dataset_name'] - class_name = input_specs['class'] + class_name_suffix = f'_reso{self.res[0]}_img{self.img_num}_fast' - class_name += class_name_suffix - + class_name = input_specs['class'] + class_name_suffix + self.num_process = num_process self.process_index = process_index if self.prompt_path != '': self.uuid2prompt = utils.load_prompt(self.prompt_path) - # # train, val, test = 7:1:2 - # mapping = { - # 'train': 1, - # 'val': 1 / 7, - # 'test': 2 / 7 - # } - - # num_chunk = math.ceil(input_specs['chunk_num'] * mapping[self.mode]) chunk_size = input_specs['chunk_size'] parquet_dir = os.path.join(chunk_path, self.dataset_name, class_name, self.mode) @@ -145,12 +137,6 @@ def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_pro self.parquet_dir = parquet_dir self.chunk_size = chunk_size - # if self.num_chunk > 0: - # print('Reusing {} chunks from previous run'.format(self.num_chunk)) - # else: - # self._write_chunks(parquet_dir, chunk_size) - # if self.mode != 'train': - # exit(0) self._parquet_paths.sort() @@ -159,8 +145,6 @@ def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_pro self._loaded_uuid = None self._loaded_verts_list = None self._loaded_faces_list = None - # self._loaded_pcd_list = None - # self._loaded_pcd_colors_list = None self._loaded_render_color_img_list = None self._loaded_render_depth_img_list = None self._loaded_render_color_cam_list = None @@ -173,6 +157,7 @@ def __init__(self, input_specs, train_specs, glctx, device, chunk, mode, num_pro self._chosen = None def load_chunk(self) -> None: + '''execute chunk generation and prepare for next task''' chosen, self._loaded_verts_list, self._loaded_faces_list, \ self._loaded_render_color_img_list, self._loaded_render_depth_img_list, \ self._loaded_render_color_cam_list, self._loaded_fovx_list, \ @@ -181,170 +166,127 @@ def load_chunk(self) -> None: self._chosen = chosen self._chunk_future = self._chunk_load_executor.submit(self._load_chunk_inner) - def get_state(self) -> str: - return self._chosen + # def get_state(self) -> str: + # return self._chosen - def set_state(self, chosen: str) -> None: - while self._chosen != chosen: - self.load_chunk() + # def set_state(self, chosen: str) -> None: + # while self._chosen != chosen: + # self.load_chunk() def __len__(self) -> int: return len(self._loaded_verts_list) def _random_scene(self, mv=None, imgs=None, depths=None): - # ============================================================================================== # Setup projection matrix - # ============================================================================================== proj_mtx = utils.perspective(self.fovx, self.res[1] / self.res[0]) - # ============================================================================================== - # Random camera & light position - # ============================================================================================== - # Random rotation/translation matrix for optimization. batch = self.camera_angle_num - if mv is None or imgs is None: - mv = torch.bmm( - utils.translate(0, 0, -self.cam_radius).repeat(batch, 1, 1), - utils.batch_random_rotation_translation(self.camera_angle_num, 0.25) - ) - depths = torch.zeros((batch,) + tuple(self.res) + (1,)) - imgs = torch.zeros((batch,) + tuple(self.res) + (3,)) - else: - img_num = len(mv) - index = random.sample(range(img_num), k=self.camera_angle_num) - - mv = mv[index] - imgs = imgs[index] - # imgs = imgs.T.view(imgs.shape[-1], self.res_img[0], self.res_img[1], 3)[index] - depths = depths[index] - # depths = depths.T.view(depths.shape[-1], self.res[0], self.res[1], 1)[index] + # if mv is None or imgs is None: + # mv = torch.bmm( + # utils.translate(0, 0, -self.cam_radius).repeat(batch, 1, 1), + # utils.batch_random_rotation_translation(self.camera_angle_num, 0.25) + # ) + # depths = torch.zeros((batch,) + tuple(self.res) + (1,)) + # imgs = torch.zeros((batch,) + tuple(self.res) + (3,)) + # else: + img_num = len(mv) + index = random.sample(range(img_num), k=self.camera_angle_num) + + mv = mv[index] + imgs = imgs[index] + depths = depths[index] mvp = torch.bmm( proj_mtx.repeat(batch, 1, 1), mv ) - campos = torch.linalg.inv(mv)[:, :3, 3] + # campos = torch.linalg.inv(mv)[:, :3, 3] - return mv.to(self.device), mvp.to(self.device), campos.to(self.device), \ - imgs.to(self.device), depths.to(self.device), proj_mtx.to(self.device), self.res + return mv.to(self.device), mvp.to(self.device), imgs.to(self.device), \ + depths.to(self.device), proj_mtx.to(self.device), self.res def __getitem__(self, idx): - # mv_list, mvp_list, campos_list, alpha_list, depth_list, norm_list, color_list = [], [], [], [], [], [], [] - # for _ in range(self.camera_angle_num): - if self.render_mode == 'blender': - mv = self._loaded_render_color_cam_list[idx] - imgs = self._loaded_render_color_img_list[idx] - depths = self._loaded_render_depth_img_list[idx] + # if self.render_mode == 'blender': + mv = self._loaded_render_color_cam_list[idx] + imgs = self._loaded_render_color_img_list[idx] + depths = self._loaded_render_depth_img_list[idx] + triview_color = self._loaded_triview_color_img_list[idx] + triview_xyz = self._loaded_triview_xyz_img_list[idx] - mv = mv.T.view(-1, 4, 4) - # imgs = imgs.T.view(imgs.shape[-1], self.res_img[0], self.res_img[1], 3) - raws = imgs.T.view(imgs.shape[-1], self.res_img[0], self.res_img[1], 4) + mv = mv.T.view(-1, 4, 4) + raws = imgs.T.view(imgs.shape[-1], self.res_img[0], self.res_img[1], 4) - imgs = raws[..., :3] - masks = raws[..., [-1]].expand(-1, -1, -1, 3) - imgs *= masks + imgs = raws[..., :3] + masks = raws[..., [-1]].expand(-1, -1, -1, 3) + imgs *= masks - depths = depths.T.view(depths.shape[-1], self.res_img[0], self.res_img[1], 1) + depths = depths.T.view(depths.shape[-1], self.res_img[0], self.res_img[1], 1) - self.fovx = self._loaded_fovx_list[idx][0] + self.fovx = self._loaded_fovx_list[idx][0] - mv, mvp, campos, imgs, depths, persp, iter_res = self._random_scene(mv, imgs, depths) - else: - mv, mvp, campos, imgs, depths, persp, iter_res = self._random_scene() + mv, mvp, imgs, depths, persp, iter_res = self._random_scene(mv, imgs, depths) + # else: + # mv, mvp, campos, imgs, depths, persp, iter_res = self._random_scene() verts = self._loaded_verts_list[idx] - if self.dataset_name == 'Objaverse': - if self.uuid2transform: - transform = self.uuid2transform[self._loaded_uuid[idx]] - transport = torch.tensor(transform['offset'], dtype=torch.float32) - scale = torch.tensor(transform['scale'], dtype=torch.float32) - verts = (verts * scale + transport) * self.scale / 0.5 - else: - transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 - verts -= transport - scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) - - verts *= self.scale / 0.5 * scale - - if self.dep_sill_mode == 'blender': - alpha = alpha_ctn = (depths > 0).float() - normal, face_normals = renderer.render_mesh( - self.glctx, verts.to(self.device), - self._loaded_faces_list[idx].to(self.device), - mvp, campos, persp, iter_res, - normal_only=True - ) - else: - alpha, alpha_ctn, depths, normal, face_normals = renderer.render_mesh( - self.glctx, verts.to(self.device), - self._loaded_faces_list[idx].to(self.device), - mvp, campos, persp, iter_res - ) - - # pcd_num = len(self._loaded_pcd_list[idx]) - # index = random.sample(range(pcd_num), k=self.pts_num) - # index_query = random.sample(range(pcd_num), k=self.query_pts_num) + # if self.dataset_name == 'Objaverse': + # if self.uuid2transform: + transform = self.uuid2transform[self._loaded_uuid[idx]] + transport = torch.tensor(transform['offset'], dtype=torch.float32) + scale = torch.tensor(transform['scale'], dtype=torch.float32) + verts = (verts * scale + transport) * self.scale / 0.5 + # else: + # transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 + # verts -= transport + # scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) + + # verts *= self.scale / 0.5 * scale + + # if self.dep_sill_mode == 'blender': + # alpha = alpha_ctn = (depths > 0).float() + # normal, face_normals = renderer.render_mesh( + # self.glctx, verts.to(self.device), + # self._loaded_faces_list[idx].to(self.device), + # mvp, campos, persp, iter_res, + # normal_only=True + # ) + # else: + alpha, depth, normal = renderer.render_mesh( + self.glctx, verts.to(self.device), + self._loaded_faces_list[idx].to(self.device), + mvp, persp, iter_res + ) + + rgbas = triview_color.T.view(triview_color.shape[-1], self.res_triview[0], self.res_triview[1], 4) + triview_color = rgbas[..., :3] + masks = rgbas[..., [-1]].expand(-1, -1, -1, 3) + triview_color *= masks + + triview_xyz = triview_xyz.T.view(triview_xyz.shape[-1], self.res_triview[0], self.res_triview[1], 3) + triview_xyz *= masks res = { - # 'verts': self.verts[None, ...], - # 'tets': self.tets, 'uuid': self._loaded_uuid[idx], - 'gt_verts': self._loaded_verts_list[idx], - 'gt_faces': self._loaded_faces_list[idx], - # 'gt_pcd': self._loaded_pcd_list[idx][None, index, ...], - # 'gt_pcd_colors': self._loaded_pcd_colors_list[idx][None, index, ...], - # 'gt_pcd_colors_query': self._loaded_pcd_colors_list[idx][None, index_query, ], - # 'gt_pcd_query': self._loaded_pcd_list[idx][None, index_query, ], - 'gt_render_imgs': imgs[None,], + 'verts': self._loaded_verts_list[idx], + 'faces': self._loaded_faces_list[idx], + 'render_imgs': imgs[None,], 'mv': mv[None, ], 'mvp': mvp[None, ], - 'campos': campos[None, ], + # 'campos': campos[None, ], 'resolution': self.res, 'resolution_img': self.res_img, 'resolution_triview': self.res_triview, 'normal': normal[None, ], - # 'spp' : iter_spp, - # 'img' : img, 'alpha': alpha[None, ], - 'alpha_ctn': alpha_ctn[None, ], - 'depth': depths[None, ], - 'persp': persp - # 'color': torch.stack(color, dim=1) + # 'alpha_ctn': alpha_ctn[None, ], + 'depth': depth[None, ], + 'persp': persp, + 'triview_color': triview_color[None,], + 'triview_xyz': triview_xyz[None,], + 'prompt': [self.uuid2prompt[self._loaded_uuid[idx]]] } - - if self.triview_color_dir != '': - triview_color = self._loaded_triview_color_img_list[idx] - # triview_color = triview_color.T.view(triview_color.shape[-1], self.res_triview[0], self.res_triview[1], 3) - rgbas = triview_color.T.view(triview_color.shape[-1], self.res_triview[0], self.res_triview[1], 4) - - imgs = rgbas[..., :3] - masks = rgbas[..., [-1]].expand(-1, -1, -1, 3) - imgs *= masks - triview_color = imgs - - res.update({ - 'triview_color': triview_color[None,], - }) - - if self.triview_xyz_dir != '': - triview_xyz = self._loaded_triview_xyz_img_list[idx] - triview_xyz = triview_xyz.T.view(triview_xyz.shape[-1], self.res_triview[0], self.res_triview[1], 3) - - triview_xyz *= masks - - res.update({ - 'triview_xyz': triview_xyz[None,], - }) - - if self.prompt_path != '': - prompt = self._loaded_prompt[idx] - res.update({ - # 'prompt': [prompt] - 'prompt': [self.uuid2prompt[self._loaded_uuid[idx]]] - }) - return res @@ -353,16 +295,10 @@ def _load_chunk_inner(self) -> Tuple[str, List[torch.FloatTensor], List[torch.Lo List[torch.FloatTensor], List[torch.FloatTensor], List[torch.FloatTensor], List[torch.FloatTensor], List[torch.FloatTensor], List[torch.FloatTensor], List[str], List[str]]: - # if 'RANK' in os.environ: - # torch.cuda.set_device(int(os.environ['LOCAL_RANK'])) next_index = next(self._chunk_index) chosen = self._parquet_paths[next_index] - # loaded_chunk = np.load(chosen, allow_pickle=True) - # dict_chunk = loaded_chunk.item() - # num_rows = len(dict_chunk['uuid']) - loaded_chunk = pq.read_table(chosen) num_rows = loaded_chunk.num_rows pandas_chunk = loaded_chunk.to_pandas() @@ -373,72 +309,60 @@ def _load_chunk_inner(self) -> Tuple[str, List[torch.FloatTensor], List[torch.Lo faces_list = [torch.LongTensor(np.stack( [pandas_chunk[f'faces_list_{j}'][i] for j in range(3)], axis=-1) ) for i in range(num_rows)] - # pcd_list = [torch.FloatTensor(np.stack( - # [pandas_chunk[f'pcd_list_{j}'][i] for j in range(3)], axis=-1) - # ) for i in range(num_rows)] - # pcd_colors_list = [torch.FloatTensor(np.stack( - # [pandas_chunk[f'pcd_colors_list_{j}'][i] for j in range(3)], axis=-1) - # ) for i in range(num_rows)] uuid = [str(pandas_chunk['uuid'][i]) for i in range(num_rows)] render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list = None, None, None, None - if self.render_mode == 'blender': - render_color_img_list = [torch.FloatTensor(np.stack( - [pandas_chunk[f'render_color_img_list_{j}'][i] for j in range(self.img_num)], axis=-1) - ) for i in range(num_rows)] + # if self.render_mode == 'blender': + render_color_img_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'render_color_img_list_{j}'][i] for j in range(self.img_num)], axis=-1) + ) for i in range(num_rows)] - render_depth_img_list = [torch.FloatTensor(np.stack( - [pandas_chunk[f'render_depth_img_list_{j}'][i] for j in range(self.img_num)], axis=-1) - ) for i in range(num_rows)] + render_depth_img_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'render_depth_img_list_{j}'][i] for j in range(self.img_num)], axis=-1) + ) for i in range(num_rows)] - render_color_cam_list = [torch.FloatTensor(np.stack( - [pandas_chunk[f'render_color_cam_list_{j}'][i] for j in range(self.img_num)], axis=-1) - ) for i in range(num_rows)] + render_color_cam_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'render_color_cam_list_{j}'][i] for j in range(self.img_num)], axis=-1) + ) for i in range(num_rows)] - fovx_list = [torch.FloatTensor(np.array(pandas_chunk[f'fovx_list'][i])) for i in range(num_rows)] + fovx_list = [torch.FloatTensor(np.array(pandas_chunk['fovx_list'][i])) for i in range(num_rows)] triview_color_img_list, triview_xyz_img_list, prompt = None, None, None - if self.triview_color_dir != '': - triview_color_img_list = [torch.FloatTensor(np.stack( - [pandas_chunk[f'triview_color_img_list_{j}'][i] for j in range(6)], axis=-1) - ) for i in range(num_rows)] + # if self.triview_color_dir != '': + triview_color_img_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'triview_color_img_list_{j}'][i] for j in range(6)], axis=-1) + ) for i in range(num_rows)] - if self.triview_xyz_dir != '': - triview_xyz_img_list = [torch.FloatTensor(np.stack( - [pandas_chunk[f'triview_xyz_img_list_{j}'][i] for j in range(6)], axis=-1) - ) for i in range(num_rows)] + # if self.triview_xyz_dir != '': + triview_xyz_img_list = [torch.FloatTensor(np.stack( + [pandas_chunk[f'triview_xyz_img_list_{j}'][i] for j in range(6)], axis=-1) + ) for i in range(num_rows)] - if self.prompt_path != '': - prompt = [str(pandas_chunk['prompt'][i]) for i in range(num_rows)] + # if self.prompt_path != '': + prompt = [str(pandas_chunk['prompt'][i]) for i in range(num_rows)] return str(chosen), verts_list, faces_list, \ render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, \ triview_color_img_list, triview_xyz_img_list, prompt, uuid - + async def aprocess_one_data(self, data: dict, data_index:int): - """ + ''' given data, read files and preprocess them, then put them into lists - """ + ''' if data_index % 100 == 0: - logging.info(f"process index {self.process_index} start {data_index}") - + logging.info('process index %d start %d', self.process_index, data_index) + gt_path = data['gt_path'] - # pcd_file = data['pcd_file'] gt_bytes = await aread_file(gt_path) - ref_mesh = trimesh.load(io.BytesIO(gt_bytes), + ref_mesh = trimesh.load(io.BytesIO(gt_bytes), file_type=Path(gt_path).suffix, force='mesh', process=False) verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) faces = torch.LongTensor(ref_mesh.faces) - - # pcd_bytes = await aread_file(pcd_file) - # load point cloud - # pcd = trimesh.load(io.BytesIO(pcd_bytes), file_type=Path(pcd_file).suffix) - - # pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) - gt_render_imgs = None - gt_render_depths = None - gt_transforms = None + + render_imgs = None + render_depths = None + transforms = None fovx = None if self.render_color_img_dir != '': render_color_img_dir = data['render_color_img_dir'] @@ -447,470 +371,318 @@ async def aprocess_one_data(self, data: dict, data_index:int): verts[:, -1] = -verts[:, -1] verts = verts[:, [0, 2, 1]] - # color, normalized to [-1, 1] - # pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] - - # if self.dataset_name == 'ShapeNet': - - # metadata = json.loads(await aread_file(render_color_cam_file, "r")) - - # verts *= self.scale / 0.5 - # # pcd_tr *= self.scale / 0.5 - # fovx = np.array([metadata['camera_angle_x']], dtype=np.float64) - # img_list, depth_list, transform_list = [], [], [] - - # assert self.img_num == len(metadata['frames']) - # image_paths = [os.path.join(render_color_img_dir, metadata['frames'][i]["file_path"]) for i in range(self.img_num)] - # bytes_images = await abatch_read_files(image_paths) - # images = batch_buffer_to_cv2image(bytes_images) - # for i, item in enumerate(metadata['frames']): - # img_name = item['file_path'] - # assert i == int(os.path.splitext(img_name)[0]) - - # c2w = torch.tensor(item['transform_matrix'], dtype=torch.float32) - - # c2w[:3, 3] *= self.scale / 0.5 - - # w2c = torch.inverse(c2w) - # # BGR -> RGB - # raw = cv2.resize(images[i], tuple(self.res_img)) - # # mask = torch.tensor(raw[:, :, [-1]], - # # dtype=torch.float32).repeat(1, 1, 3) / 255 - # img = torch.tensor(raw[:, :, [2, 1, 0, 3]], - # dtype=torch.float32) / 255 - - # # img = img * mask - - # transform_list.append(w2c.reshape(-1)) - # img_list.append(img.reshape(-1)) - - # # depth - # depth_name = f'{i:05d}_depth.png' - # dep = cv2.imread(os.path.join(render_color_img_dir, depth_name), cv2.IMREAD_UNCHANGED) - - # # reference - # # https://github.com/openai/shap-e/blob/50131012ee11c9d2617f3886c10f000d3c7a3b43/shap_e/rendering/blender/view_data.py#L57-L62 - # inf_dist = dep == 0xFFFF - # dep = np.where( - # inf_dist, - # 0., - # SHAPENET_MAX_DEPTH * (dep.astype(np.float32) / 65536), - # ) - - # dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 - - # depth_list.append(dep.reshape(-1)) - if self.dataset_name == 'Objaverse': - # transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 - # verts -= transport - # scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) - # - # verts *= self.scale / 0.5 * scale - # pcd_tr *= self.scale / 0.5 - - K, _, _, _, w2cs = pickle.load(io.BytesIO(await aread_file(render_color_cam_file))) - - fovx = np.array([2 * math.atan(K[0, 2] / K[0, 0])], dtype=np.float64) - img_list, depth_list, transform_list = [], [], [] - image_paths = [os.path.join(render_color_img_dir, f'{i:03d}.png') for i in range(len(w2cs))] - bytes_images = await abatch_read_files(image_paths) - # logging.info("read objaverss done") - images = batch_buffer_to_cv2image(bytes_images) - - depth_paths = [os.path.join(render_color_img_dir, f'{i:03d}-depth.png') for i in range(len(w2cs))] - bytes_depths = await abatch_read_files(depth_paths) - depths = batch_buffer_to_cv2image(bytes_depths) - - # select per stride imgs - assert len(w2cs) % self.img_num == 0 - stride = len(w2cs) // self.img_num - - for i, w2c in enumerate(w2cs): - if i % stride != 0: - continue - w2c = torch.tensor(np.stack((w2c[0], -w2c[1], -w2c[2], np.array([0., 0., 0., 1.])), axis=0), - dtype=torch.float32) - c2w = torch.inverse(w2c) - c2w[:3, 3] *= self.scale / 0.5 - w2c = torch.inverse(c2w) - # BGR -> RGB -> [-1, 1] - # image = buffer_to_cv2image(await aread_file(image_paths[i])) - # try: - raw = cv2.resize(images[i], tuple(self.res_img)) - # except Exception as e: - # print(f'uuid: {data["uuid"]}, prompt: {data["prompt"]}, index: {i}') - # mask = torch.tensor(raw[:, :, [-1]], - # dtype=torch.float32).repeat(1, 1, 3) / 255 - img = torch.tensor(raw[:, :, [2, 1, 0, 3]], - dtype=torch.float32) / 255 - - # img = img * mask - transform_list.append(w2c.reshape(-1)) - img_list.append(img.reshape(-1)) - - # depth - # syncdreamer - if os.path.exists(os.path.join(render_color_img_dir, f'{i:03d}-depth.png')): - # depth_name = f'{i:03d}-depth.png' - # dep = cv2.imread(os.path.join(render_color_img_dir, depth_name), cv2.IMREAD_UNCHANGED) - dep = depths[i] - - # reference - # https://github.com/liuyuan-pal/SyncDreamer/blob/232a2ec22f0277b4bd429109fb34eaf8f61b13ad/eval_mesh.py#L16-L22 - dep = dep.astype(np.float32) / 65535 * (DEPTH_MAX - DEPTH_MIN) + DEPTH_MIN - mask = (dep < DEPTH_VALID_MIN) | (dep > DEPTH_VALID_MAX) - - # cs - elif os.path.exists(os.path.join(render_color_img_dir, f'depth_{i:03d}1.png')): - depth_name = f'{i:03d}-depth.png' - depth_path = os.path.join(render_color_img_dir, f"depth_{i:03d}1.png") - - dep =(np.array(Image.open(depth_path))[:,:,0]- 120)* 0.5 / 63 - mask = np.array(Image.open(depth_path))[:,:,0] == 255 - - dep = np.where(mask, 0., dep) - - dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 - - depth_list.append(dep.reshape(-1)) - gt_render_imgs = torch.stack(img_list, dim=-1) - gt_transforms = torch.stack(transform_list, dim=-1) - gt_render_depths = torch.stack(depth_list, dim=-1) + # if self.dataset_name == 'Objaverse': + k, _, _, _, w2cs = pickle.load(io.BytesIO(await aread_file(render_color_cam_file))) - # else: - # verts -= ((verts.max(0)[0] + verts.min(0)[0]) / 2).unsqueeze(0).repeat( - # (verts.shape[0], 1)) + fovx = np.array([2 * math.atan(k[0, 2] / k[0, 0])], dtype=np.float64) + img_list, depth_list, transform_list = [], [], [] + image_paths = [os.path.join(render_color_img_dir, f'{i:03d}.png') for i in range(len(w2cs))] + bytes_images = await abatch_read_files(image_paths) + images = batch_buffer_to_cv2image(bytes_images) - # # rotate & transport - # pcd_tr = pcd_tr @ utils.rotate_x(-math.pi / 2).T[:3, :3] - # pcd_tr -= ((pcd_tr.max(0)[0] + pcd_tr.min(0)[0]) / 2).unsqueeze(0).repeat((pcd_tr.shape[0], 1)) + depth_paths = [os.path.join(render_color_img_dir, f'{i:03d}-depth.png') for i in range(len(w2cs))] + bytes_depths = await abatch_read_files(depth_paths) + depths = batch_buffer_to_cv2image(bytes_depths) - # # scale - # verts = verts / torch.max(abs(verts)) * self.scale - # pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale + # select per stride imgs + assert len(w2cs) % self.img_num == 0 + stride = len(w2cs) // self.img_num - # # color - # pcd_colors = (2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255)[..., :3] / 255 - - triview_imgs = None - triview_xyzs = None - if self.triview_color_dir != '' and self.triview_xyz_dir != '': - img_list, xyz_list = [], [] - triview_color_dir = data['triview_color_dir'] - triview_xyz_dir = data['triview_xyz_dir'] - - color_paths = [os.path.join(triview_color_dir, f'{i:03d}.png') for i in range(6)] - xyz_paths = [os.path.join(triview_xyz_dir, f'xyz_new_{i:03d}.png') for i in range(6)] - # bytes_colors = await abatch_read_files(color_paths) - # bytes_xyzs = await abatch_read_files(xyz_paths) - # logging.info("read done") - # colors = batch_buffer_to_cv2image(bytes_colors) - # xyzs = batch_buffer_to_cv2image(bytes_xyzs) - - for i in range(6): - # BGR -> RGB - color = buffer_to_cv2image(await aread_file(color_paths[i])) - xyz = buffer_to_cv2image(await aread_file(xyz_paths[i])) - # raw = cv2.resize(colors[i], self.res_triview) - # xyz = cv2.resize(xyzs[i], self.res_triview) - raw = cv2.resize(color, self.res_triview) - xyz = cv2.resize(xyz, self.res_triview) - - # mask = torch.tensor(raw[:, :, [-1]], - # dtype=torch.float32).repeat(1, 1, 3) / 255 + for i, w2c in enumerate(w2cs): + if i % stride != 0: + continue + w2c = torch.tensor(np.stack((w2c[0], -w2c[1], -w2c[2], np.array([0., 0., 0., 1.])), axis=0), + dtype=torch.float32) + c2w = torch.inverse(w2c) + c2w[:3, 3] *= self.scale / 0.5 + w2c = torch.inverse(c2w) + + raw = cv2.resize(images[i], tuple(self.res_img)) img = torch.tensor(raw[:, :, [2, 1, 0, 3]], dtype=torch.float32) / 255 - xyz = torch.tensor(xyz, dtype=torch.float32) / 255 - - # img = img * mask - # xyz = xyz * mask + transform_list.append(w2c.reshape(-1)) img_list.append(img.reshape(-1)) - xyz_list.append(xyz.reshape(-1)) - triview_imgs = torch.stack(img_list, dim=-1) - triview_xyzs = torch.stack(xyz_list, dim=-1) - + # depth + # syncdreamer + # if os.path.exists(os.path.join(render_color_img_dir, f'{i:03d}-depth.png')): + # depth_name = f'{i:03d}-depth.png' + # dep = cv2.imread(os.path.join(render_color_img_dir, depth_name), cv2.IMREAD_UNCHANGED) + dep = depths[i] + + # reference + # https://github.com/liuyuan-pal/SyncDreamer/blob/232a2ec22f0277b4bd429109fb34eaf8f61b13ad/eval_mesh.py#L16-L22 + dep = dep.astype(np.float32) / 65535 * (DEPTH_MAX - DEPTH_MIN) + DEPTH_MIN + mask = (dep < DEPTH_VALID_MIN) | (dep > DEPTH_VALID_MAX) + + # # cs + # elif os.path.exists(os.path.join(render_color_img_dir, f'depth_{i:03d}1.png')): + # depth_name = f'{i:03d}-depth.png' + # depth_path = os.path.join(render_color_img_dir, f'depth_{i:03d}1.png') + + # dep =(np.array(Image.open(depth_path))[:,:,0]- 120)* 0.5 / 63 + # mask = np.array(Image.open(depth_path))[:,:,0] == 255 + + dep = np.where(mask, 0., dep) + + dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 + + depth_list.append(dep.reshape(-1)) + render_imgs = torch.stack(img_list, dim=-1) + transforms = torch.stack(transform_list, dim=-1) + render_depths = torch.stack(depth_list, dim=-1) + + triview_imgs = None + triview_xyzs = None + # if self.triview_color_dir != '' and self.triview_xyz_dir != '': + img_list, xyz_list = [], [] + triview_color_dir = data['triview_color_dir'] + triview_xyz_dir = data['triview_xyz_dir'] + + color_paths = [os.path.join(triview_color_dir, f'{i:03d}.png') for i in range(6)] + xyz_paths = [os.path.join(triview_xyz_dir, f'xyz_new_{i:03d}.png') for i in range(6)] + + for i in range(6): + # BGR -> RGB + color = buffer_to_cv2image(await aread_file(color_paths[i])) + xyz = buffer_to_cv2image(await aread_file(xyz_paths[i])) + # raw = cv2.resize(colors[i], self.res_triview) + # xyz = cv2.resize(xyzs[i], self.res_triview) + raw = cv2.resize(color, self.res_triview) + xyz = cv2.resize(xyz, self.res_triview) + + # mask = torch.tensor(raw[:, :, [-1]], + # dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0, 3]], + dtype=torch.float32) / 255 + xyz = torch.tensor(xyz, dtype=torch.float32) / 255 + + # img = img * mask + # xyz = xyz * mask + + img_list.append(img.reshape(-1)) + xyz_list.append(xyz.reshape(-1)) + + triview_imgs = torch.stack(img_list, dim=-1) + triview_xyzs = torch.stack(xyz_list, dim=-1) + verts = verts.numpy().astype(np.float32) faces = faces.numpy().astype(np.int64) - # pcd = pcd_tr.numpy().astype(np.float32) - # pcd_colors = pcd_colors.numpy().astype(np.float32) - - gt_render_imgs = gt_render_imgs.numpy().astype(np.float32) if gt_render_imgs is not None else None - gt_render_depths = gt_render_depths.numpy().astype(np.float32) if gt_render_depths is not None else None - gt_transforms = gt_transforms.numpy().astype(np.float32) if gt_transforms is not None else None - + + render_imgs = render_imgs.numpy().astype(np.float32) if render_imgs is not None else None + render_depths = render_depths.numpy().astype(np.float32) if render_depths is not None else None + transforms = transforms.numpy().astype(np.float32) if transforms is not None else None + triview_imgs = triview_imgs.numpy().astype(np.float32) if triview_imgs is not None else None triview_xyzs = triview_xyzs.numpy().astype(np.float32) if triview_xyzs is not None else None - + if data_index % 100 == 0: - logging.info(f"process index {self.process_index} end {data_index}") - + logging.info('process index %d start %d', self.process_index, data_index) + return { - "data_index": data_index, - "uuid": data["uuid"], - "verts": verts, - "faces": faces, - # "pcd": pcd, - # "pcd_colors": pcd_colors, - - "gt_render_imgs": gt_render_imgs, - "gt_render_depths": gt_render_depths, - "gt_transforms": gt_transforms, - "fovx": fovx, - - "triview_imgs": triview_imgs, - "triview_xyzs": triview_xyzs, - "prompt": data.get('prompt') + 'data_index': data_index, + 'uuid': data['uuid'], + 'verts': verts, + 'faces': faces, + 'fovx': fovx, + 'transforms': transforms, + 'render_imgs': render_imgs, + 'render_depths': render_depths, + 'triview_imgs': triview_imgs, + 'triview_xyzs': triview_xyzs, + 'prompt': data.get('prompt') } - - - def append_data(self, data: dict, - uuid, verts_list, faces_list, - render_color_img_list, render_depth_img_list, render_color_cam_list, + + def append_data(self, data: dict, + uuid, verts_list, faces_list, + render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, triview_color_img_list, triview_xyz_img_list, prompt) -> None: + '''Collect data''' uuid.append(data['uuid']) verts_list.append(data['verts']) faces_list.append(data['faces']) - # pcd_list.append(data['pcd']) - # pcd_color_list.append(data['pcd_colors']) - if self.render_color_img_dir != '': - render_color_img_list.append(data['gt_render_imgs']) - render_depth_img_list.append(data['gt_render_depths']) - render_color_cam_list.append(data['gt_transforms']) - fovx_list.append(data['fovx']) - if self.triview_color_dir != '': - triview_color_img_list.append(data['triview_imgs']) - if self.triview_xyz_dir != '': - triview_xyz_img_list.append(data['triview_xyzs']) + # if self.render_color_img_dir != '': + render_color_img_list.append(data['render_imgs']) + render_depth_img_list.append(data['render_depths']) + render_color_cam_list.append(data['transforms']) + fovx_list.append(data['fovx']) + # if self.triview_color_dir != '': + triview_color_img_list.append(data['triview_imgs']) + # if self.triview_xyz_dir != '': + triview_xyz_img_list.append(data['triview_xyzs']) - if self.prompt_path != '': - prompt.append(data['prompt']) + # if self.prompt_path != '': + prompt.append(data['prompt']) - def prepare_metadata(self): - # multi mesh + '''Prepare all string like metadata e.g. image path, uuid, prompt, etc''' for class_name in os.listdir(self.mesh_dir): - if class_name == self.class_name or self.class_name == 'all': + if self.class_name in [class_name, 'all']: class_dir = os.path.join(self.mesh_dir, class_name) if class_name.endswith('.json'): continue - for i, object_name in enumerate(tqdm(os.listdir(class_dir))): + for object_name in tqdm(os.listdir(class_dir)): # if i > 999: # break - if self.dataset_name == 'ShapeNet' and self.class_name == 'all': - record = '/'.join([class_name, object_name]) - elif self.dataset_name == 'Objaverse': - record = os.path.splitext(object_name)[0] - # exclude no transform data - if record in self.objaverse_exclude: - continue - else: - record = object_name + # if self.dataset_name == 'ShapeNet' and self.class_name == 'all': + # record = '/'.join([class_name, object_name]) + # elif self.dataset_name == 'Objaverse': + record = os.path.splitext(object_name)[0] + # exclude no transform data + if record in self.objaverse_exclude: + continue + # else: + # record = object_name if (self.mode == 'train' and record in self.train_set) or \ (self.mode == 'val' and record in self.val_set) or \ (self.mode == 'test' and record in self.test_set) or \ (self.mode == 'all' and record in self.all_set): - # if self.dataset_name == 'ShapeNet': - # # load vertices and faces - # gt_path = os.path.join(class_dir, object_name, 'blank_model.ply') - # pcd_file = os.path.join(self.pcd_dir, class_name, object_name, - # 'models', f'pc_model_normalized.obj_mat_{self.img_num}_262144_131072.ply') - # if self.render_color_img_dir != '': - # render_color_img_dir = os.path.join(self.render_color_img_dir, class_name, object_name, - # 'img', object_name, 'models') - # render_color_cam_file = os.path.join(self.render_color_img_dir, class_name, object_name, - # 'img', object_name, 'models', 'transforms.json') - if self.dataset_name == 'Objaverse': - # load vertices and faces - gt_path = os.path.join(class_dir, object_name) - # pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') - if self.render_color_img_dir != '': - render_color_img_dir = os.path.join(self.render_color_img_dir, record) - render_color_cam_file = os.path.join(self.render_color_img_dir, record, 'meta.pkl') - if self.triview_color_dir != '': - triview_color_dir = os.path.join(self.triview_color_dir, record) - if self.triview_xyz_dir != '': - triview_xyz_dir = os.path.join(self.triview_xyz_dir, record) + # load vertices and faces + gt_path = os.path.join(class_dir, object_name) + # pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') + + render_color_img_dir = os.path.join(self.render_color_img_dir, record) + render_color_cam_file = os.path.join(self.render_color_img_dir, record, 'meta.pkl') + + triview_color_dir = os.path.join(self.triview_color_dir, record) + + triview_xyz_dir = os.path.join(self.triview_xyz_dir, record) + prompt = self.uuid2prompt.get(record, None) res = { 'gt_path': gt_path, - # 'pcd_file': pcd_file, - 'uuid': record + 'uuid': record, + 'render_color_img_dir': render_color_img_dir, + 'render_color_cam_file': render_color_cam_file, + 'triview_color_dir': triview_color_dir, + 'triview_xyz_dir': triview_xyz_dir, + 'prompt': prompt } - - if self.render_color_img_dir != '': - if os.path.exists(render_color_cam_file): - res.update({ - 'render_color_img_dir': render_color_img_dir, - 'render_color_cam_file': render_color_cam_file - }) - else: - print("dont exist render color img", render_color_cam_file) - continue - - if self.triview_color_dir != '': - if os.path.exists(triview_color_dir): - res.update({ - 'triview_color_dir': triview_color_dir - }) - else: - print("dont exist color triview", triview_color_dir) - continue - - if self.triview_xyz_dir != '': - if os.path.exists(triview_xyz_dir): - res.update({ - 'triview_xyz_dir': triview_xyz_dir - }) - else: - print("dont exist color triview", triview_xyz_dir) - continue - - if self.prompt_path != '': - prompt = self.uuid2prompt.get(record, None) - if prompt is not None: - res.update({ - 'prompt': prompt - }) - else: - print("dont exist prompt", prompt) - continue - self.metadata.append(res) self.metadata.sort(key=lambda x: x['gt_path']) - - def _write_one_chunk(self, chunk_index:int, + def write_one_chunk(self, chunk_index:int, verts_list: List[torch.FloatTensor], faces_list: List[torch.LongTensor], - # pcd_list: List[torch.FloatTensor], pcd_colors_list: List[torch.FloatTensor], - render_color_img_list: List[torch.FloatTensor], render_depth_img_list: List[torch.FloatTensor], + render_color_img_list: List[torch.FloatTensor], render_depth_img_list: List[torch.FloatTensor], render_color_cam_list: List[torch.FloatTensor], fovx_list: List[torch.DoubleTensor], triview_color_img_list: List[torch.FloatTensor], triview_xyz_img_list: List[torch.FloatTensor], uuid: List[str], prompt: List[str], parquet_writers: List[pq.ParquetWriter]): - logging.info(f"----process {self.process_index} start write index {chunk_index} {parquet_writers[chunk_index].where}----") + '''Gather one chunk data to generate a pyarrow table and save to the disk''' + logging.info('----process %d start write index %d %s----', + self.process_index, chunk_index, parquet_writers[chunk_index].where) indices = torch.randperm(len(verts_list)).tolist() shuffled_verts_list = [verts_list[i] for i in indices] shuffled_faces_list = [faces_list[i] for i in indices] - # shuffled_pcd_list = [pcd_list[i] for i in indices] - # shuffled_pcd_colors_list = [pcd_colors_list[i] for i in indices] shuffled_uuid = [uuid[i] for i in indices] - if self.render_color_img_dir != '': - shuffled_render_color_img_list = [render_color_img_list[i] for i in indices] - shuffled_render_depth_img_list = [render_depth_img_list[i] for i in indices] - shuffled_render_color_cam_list = [render_color_cam_list[i] for i in indices] - shuffled_fovx_list = [fovx_list[i] for i in indices] - if self.triview_color_dir != '': - shuffled_triview_color_img_list = [triview_color_img_list[i] for i in indices] - if self.triview_xyz_dir != '': - shuffled_triview_xyz_img_list = [triview_xyz_img_list[i] for i in indices] - if self.prompt_path != '': - shuffled_prompt = [prompt[i] for i in indices] + # if self.render_color_img_dir != '': + shuffled_render_color_img_list = [render_color_img_list[i] for i in indices] + shuffled_render_depth_img_list = [render_depth_img_list[i] for i in indices] + shuffled_render_color_cam_list = [render_color_cam_list[i] for i in indices] + shuffled_fovx_list = [fovx_list[i] for i in indices] + # if self.triview_color_dir != '': + shuffled_triview_color_img_list = [triview_color_img_list[i] for i in indices] + # if self.triview_xyz_dir != '': + shuffled_triview_xyz_img_list = [triview_xyz_img_list[i] for i in indices] + # if self.prompt_path != '': + shuffled_prompt = [prompt[i] for i in indices] columns = {} columns['uuid'] = shuffled_uuid for i in range(3): - columns['verts_list_{}'.format(i)] = [verts[:, i] for verts in shuffled_verts_list] - columns['faces_list_{}'.format(i)] = [faces[:, i] for faces in shuffled_faces_list] - # columns['pcd_list_{}'.format(i)] = [pcd[:, i] for pcd in shuffled_pcd_list] - # columns['pcd_colors_list_{}'.format(i)] = [pcd_colors[:, i] for pcd_colors in shuffled_pcd_colors_list] - - if self.render_color_img_dir != '': - for i in range(self.img_num): - columns['render_color_img_list_{}'.format(i)] = [ - render_color_img[:, i] for render_color_img in - shuffled_render_color_img_list - ] - columns['render_depth_img_list_{}'.format(i)] = [ - render_depth_img[:, i] for render_depth_img in - shuffled_render_depth_img_list - ] - columns['render_color_cam_list_{}'.format(i)] = [ - render_color_cam[:, i] for render_color_cam in - shuffled_render_color_cam_list - ] - columns['fovx_list'] = shuffled_fovx_list - - if self.triview_color_dir != '': - for i in range(6): - columns['triview_color_img_list_{}'.format(i)] = [ - triview_color_img[:, i] for triview_color_img in - shuffled_triview_color_img_list - ] - if self.triview_xyz_dir != '': - for i in range(6): - columns['triview_xyz_img_list_{}'.format(i)] = [ - triview_xyz_img[:, i] for triview_xyz_img in - shuffled_triview_xyz_img_list - ] - if self.prompt_path != '': - columns['prompt'] = shuffled_prompt + columns[f'verts_list_{i}'] = [verts[:, i] for verts in shuffled_verts_list] + columns[f'faces_list_{i}'] = [faces[:, i] for faces in shuffled_faces_list] + + # if self.render_color_img_dir != '': + for i in range(self.img_num): + columns[f'render_color_img_list_{i}'] = [ + render_color_img[:, i] for render_color_img in + shuffled_render_color_img_list + ] + columns[f'render_depth_img_list_{i}'] = [ + render_depth_img[:, i] for render_depth_img in + shuffled_render_depth_img_list + ] + columns[f'render_color_cam_list_{i}'] = [ + render_color_cam[:, i] for render_color_cam in + shuffled_render_color_cam_list + ] + columns['fovx_list'] = shuffled_fovx_list + + # if self.triview_color_dir != '': + for i in range(6): + columns[f'triview_color_img_list_{i}'.format(i)] = [ + triview_color_img[:, i] for triview_color_img in + shuffled_triview_color_img_list + ] + # if self.triview_xyz_dir != '': + for i in range(6): + columns[f'triview_xyz_img_list_{i}'.format(i)] = [ + triview_xyz_img[:, i] for triview_xyz_img in + shuffled_triview_xyz_img_list + ] + # if self.prompt_path != '': + columns['prompt'] = shuffled_prompt parquet_writers[chunk_index].write_table(pa.table(columns)) parquet_writers[chunk_index].close() - # np.save(parquet_writers[chunk_index].where, columns) - logging.info(f"____process {self.process_index}end write index {chunk_index} {parquet_writers[chunk_index].where}____") + logging.info('____process %d start write index %d %s____', + self.process_index, chunk_index, parquet_writers[chunk_index].where) - - def _write_chunks(self, chunk_path, chunk_size) -> None: - logging.info("start") + def write_chunks(self, chunk_path, chunk_size) -> None: + '''Chunk generation and save main function''' + logging.info('start') self.prepare_metadata() - logging.info("first for done") + logging.info('first for done') assert ('RANK' not in os.environ) or int(os.environ['LOCAL_RANK']) == 0 - total_chunks = list(chunk_with_size(self.metadata, chunk_size)) + total_chunks = list(chunk_with_size(self.metadata, chunk_size)) chunks_for_process = list(chunk_with_number(total_chunks, self.num_process)) current_process_chunks = chunks_for_process[self.process_index] - + parquet_writers = [] - logging.info(f'process_index:{self.process_index}, Allocating {len(current_process_chunks)} chunks, \ - with totol size of{sum([len(chunk) for chunk in current_process_chunks])} to dataset path {chunk_path}') - + logging.info('process_index: %d, Allocating %d chunks, with totol size of %d to dataset path %s', self.process_index, + len(current_process_chunks), sum([len(chunk) for chunk in current_process_chunks]), chunk_path) + j = 0 for p_index in range(self.num_process): for chunk in chunks_for_process[p_index]: - parquet_path = os.path.join(chunk_path, '{0:06d}.parquet'.format(j)) + parquet_path = os.path.join(chunk_path, f'{j:06d}.parquet') j += 1 if p_index != self.process_index: continue self._parquet_paths.append(parquet_path) - dtypes = [] dtypes.append(('uuid', pa.string())) for i in range(3): - dtypes.append(('verts_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - dtypes.append(('faces_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.int64)))) - # dtypes.append(('pcd_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - # dtypes.append(('pcd_colors_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - if self.render_color_img_dir != '': - for i in range(self.img_num): - dtypes.append(('render_color_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - dtypes.append(('render_depth_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - dtypes.append(('render_color_cam_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - dtypes.append(('fovx_list', pa.list_(pa.from_numpy_dtype(np.float64)))) - if self.triview_color_dir != '': - for i in range(6): - dtypes.append(('triview_color_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - if self.triview_xyz_dir != '': - for i in range(6): - dtypes.append(('triview_xyz_img_list_{}'.format(i), pa.list_(pa.from_numpy_dtype(np.float32)))) - if self.prompt_path != '': - dtypes.append(('prompt', pa.string())) + dtypes.append((f'verts_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append((f'faces_list_{i}', pa.list_(pa.from_numpy_dtype(np.int64)))) + # if self.render_color_img_dir != '': + for i in range(self.img_num): + dtypes.append((f'render_color_img_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append((f'render_depth_img_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append((f'render_color_cam_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) + dtypes.append(('fovx_list', pa.list_(pa.from_numpy_dtype(np.float64)))) + # if self.triview_color_dir != '': + for i in range(6): + dtypes.append((f'triview_color_img_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) + # if self.triview_xyz_dir != '': + for i in range(6): + dtypes.append((f'triview_xyz_img_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) + # if self.prompt_path != '': + dtypes.append(('prompt', pa.string())) parquet_writers.append(pq.ParquetWriter(parquet_path, pa.schema(dtypes), compression='BROTLI')) - - bar_write = tqdm(total=len(current_process_chunks)) - bar_write.set_description("write") - + bar_write.set_description('write') + def do_one_chunk(obj, chunk, chunk_index): nonlocal bar_write verts_list, faces_list = [], [] - # pcd_list, pcd_color_list = [], [], [], [] render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list = [], [], [], [] triview_color_img_list, triview_xyz_img_list = [], [] uuid, prompt = [], [] @@ -921,28 +693,25 @@ def do_one_chunk(obj, chunk, chunk_index): loop.close() for data in readed_data: obj.append_data(data, uuid, verts_list, faces_list, - # pcd_list, pcd_color_list, render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, triview_color_img_list, triview_xyz_img_list, prompt) - - obj._write_one_chunk(chunk_index, + + obj.write_one_chunk(chunk_index, verts_list, faces_list, - # pcd_list, pcd_color_list, render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list, triview_color_img_list, triview_xyz_img_list, uuid, prompt, parquet_writers) bar_write.update(1) - - + task_futures = [] with ThreadPoolExecutor(max_workers=4) as executor: for chunk_index, chunk in enumerate(tqdm(current_process_chunks)): + # For debug use # do_one_chunk(self, chunk, chunk_index) task_futures.append(executor.submit(do_one_chunk, self, chunk, chunk_index)) - - [task.result() for task in task_futures] # wait for all tasks done - # for parquet_writer in parquet_writers: - # parquet_writer.close() + # wait for all tasks done + for task in task_futures: + task.result() print('Finished writing chunks to dataset paths') diff --git a/datasets/memory_dataset.py b/datasets/memory_dataset.py index 9782713..7f8fbd4 100644 --- a/datasets/memory_dataset.py +++ b/datasets/memory_dataset.py @@ -1,33 +1,35 @@ -# Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual -# property and proprietary rights in and to this material, related -# documentation and any modifications thereto. Any use, reproduction, -# disclosure or distribution of this material and related documentation -# without an express license agreement from NVIDIA CORPORATION or -# its affiliates is strictly prohibited. -import json +''' +Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +NVIDIA CORPORATION, its affiliates and licensors retain all intellectual +property and proprietary rights in and to this material, related +documentation and any modifications thereto. Any use, reproduction, +disclosure or distribution of this material and related documentation +without an express license agreement from NVIDIA CORPORATION or +its affiliates is strictly prohibited. +''' + import random -import time -import cv2 +import os +import math import pickle +import cv2 import numpy as np import torch import trimesh -import kaolin -import os -import math from tqdm import tqdm -from PIL import Image -from .dataset import Dataset +from datasets.dataset import Dataset from util import utils, renderer from util.utils import DEPTH_MAX, DEPTH_MIN, DEPTH_VALID_MIN, DEPTH_VALID_MAX class MemoryDataset(Dataset): - def __init__(self, input_specs, train_specs, glctx, tet_grid_size, device, task_mode="debug", validate=False, visual=False): + ''' + Torch Dataset for validation and visualization + ''' + def __init__(self, input_specs, train_specs, glctx, device, validate=False, visual=False): # Init super(MemoryDataset, self).__init__(device) self.glctx = glctx @@ -40,14 +42,13 @@ def __init__(self, input_specs, train_specs, glctx, tet_grid_size, device, task_ self.res_triview = input_specs.get('resolution_triview') self.aspect = self.res[1] / self.res[0] self.pts_num = train_specs['sample_points_num'] - self.query_pts_num = train_specs['query_sample_points_num'] + # self.query_pts_num = train_specs['query_sample_points_num'] self.epoch = train_specs['num_epochs'] self.eva_iter = train_specs['eva_iter'] self.render_mode = train_specs.get('tex_sup_mode') self.dep_sill_mode = train_specs.get('dep&sill_sup_mode') self.scale = input_specs['scale'] - # self.pcd_dir = input_specs['pcd_dir'] self.mesh_dir = input_specs['mesh_dir'] self.class_name = input_specs['class'] self.camera_angle_num = input_specs['camera_angle_num'] @@ -60,400 +61,254 @@ def __init__(self, input_specs, train_specs, glctx, tet_grid_size, device, task_ self.prompt_path = input_specs.get('prompt_path', '') self.dataset_name = input_specs['dataset_name'] - if self.split_dir: - self.train_set = utils.load_item(os.path.join(self.split_dir, 'train.txt')) - self.val_set = utils.load_item(os.path.join(self.split_dir, 'val.txt')) - random.seed(2023) - self.val_list = sorted(list(self.val_set)) - self.val_list = random.sample(self.val_list, k=self.validate_num) - self.test_set = utils.load_item(os.path.join(self.split_dir, 'test.txt')) - self.objaverse_exclude = utils.load_item(os.path.join(self.split_dir, 'exclude.txt')) + # if self.split_dir: + self.train_set = utils.load_item(os.path.join(self.split_dir, 'train.txt')) + self.val_set = utils.load_item(os.path.join(self.split_dir, 'val.txt')) + random.seed(2023) + self.val_list = sorted(list(self.val_set)) + self.val_list = random.sample(self.val_list, k=self.validate_num) + self.test_set = utils.load_item(os.path.join(self.split_dir, 'test.txt')) + self.objaverse_exclude = utils.load_item(os.path.join(self.split_dir, 'exclude.txt')) self.img_num = input_specs.get('img_num', 24) self.uuid2transform = utils.load_transform(input_specs.get('blender_transform')) - if self.prompt_path != '': - self.uuid2prompt = utils.load_prompt(self.prompt_path) - - if task_mode == "debug": - # load raw vertices and faces - ref_mesh = trimesh.load(self.mesh_dir, force='mesh', process=False) - verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) - faces = torch.LongTensor(ref_mesh.faces) - - if self.pcd_dir.endswith(".usd"): - # load point cloud - pcd = kaolin.io.usd.import_pointclouds(self.pcd_dir)[0] - pcd_tr = pcd.points - pcd_colors = pcd.colors - - # scale - verts = verts / torch.max(abs(verts)) * self.scale - pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale - - self.data = [ - {'gt_verts': verts.cpu(), 'gt_faces': faces.cpu(), 'gt_pcd': pcd_tr, 'gt_pcd_colors': pcd_colors}] - - elif self.pcd_dir.endswith(".ply") and self.render_img_dir == '': - self.data = self._preprocess(verts, faces, self.pcd_dir) - - elif self.pcd_dir.endswith('.ply') and self.render_img_dir != '': - # render imgs - filename = os.path.split(self.render_img_dir)[-1] - - if self.dataset_name == 'ShapeNet': - imgdir = os.path.join(self.render_img_dir, 'img', filename, 'models') - elif self.dataset_name == 'Objaverse': - imgdir = self.render_img_dir - else: - raise RuntimeError('Not valid dataset_name') - self.data = self._preprocess(verts, faces, self.pcd_dir, imgdir=imgdir) - - else: - raise RuntimeError('Illegal point cloud format') - - elif task_mode == "batch": - # multi mesh - self.data = [] - for class_name in os.listdir(self.mesh_dir): - if class_name == self.class_name or self.class_name == 'all': - class_dir = os.path.join(self.mesh_dir, class_name) - if class_name.endswith('.json'): + # if self.prompt_path != '': + self.uuid2prompt = utils.load_prompt(self.prompt_path) + + # if task_mode == "debug": + # # load raw vertices and faces + # ref_mesh = trimesh.load(self.mesh_dir, force='mesh', process=False) + # verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) + # faces = torch.LongTensor(ref_mesh.faces) + + # if self.pcd_dir.endswith(".usd"): + # # load point cloud + # pcd = kaolin.io.usd.import_pointclouds(self.pcd_dir)[0] + # pcd_tr = pcd.points + # pcd_colors = pcd.colors + + # # scale + # verts = verts / torch.max(abs(verts)) * self.scale + # pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale + + # self.data = [ + # {'gt_verts': verts.cpu(), 'gt_faces': faces.cpu(), 'gt_pcd': pcd_tr, 'gt_pcd_colors': pcd_colors}] + + # elif self.pcd_dir.endswith(".ply") and self.render_img_dir == '': + # self.data = self._preprocess(verts, faces, self.pcd_dir) + + # elif self.pcd_dir.endswith('.ply') and self.render_img_dir != '': + # # render imgs + # filename = os.path.split(self.render_img_dir)[-1] + + # if self.dataset_name == 'ShapeNet': + # imgdir = os.path.join(self.render_img_dir, 'img', filename, 'models') + # elif self.dataset_name == 'Objaverse': + # imgdir = self.render_img_dir + # else: + # raise RuntimeError('Not valid dataset_name') + # self.data = self._preprocess(verts, faces, self.pcd_dir, imgdir=imgdir) + + # else: + # raise RuntimeError('Illegal point cloud format') + + # elif task_mode == "batch": + # multi mesh + self.data = [] + for class_name in os.listdir(self.mesh_dir): + if class_name == self.class_name or self.class_name == 'all': + class_dir = os.path.join(self.mesh_dir, class_name) + if class_name.endswith('.json'): + continue + for i, object_name in enumerate(tqdm(os.listdir(class_dir))): + # if i > 99: + # break + # if self.dataset_name == 'ShapeNet' and self.class_name == 'all': + # record = '/'.join([class_name, object_name]) + # elif self.dataset_name == 'Objaverse': + record = os.path.splitext(object_name)[0] + # exclude no transform data + if record in self.objaverse_exclude: + continue + # else: + # record = object_name + # validate set abort + if self.validate and record not in self.val_list: + continue + # train set abort + if not self.validate and record not in self.train_set: continue - for i, object_name in enumerate(tqdm(os.listdir(class_dir))): - # if i > 99: - # break - if self.dataset_name == 'ShapeNet' and self.class_name == 'all': - record = '/'.join([class_name, object_name]) - elif self.dataset_name == 'Objaverse': - record = os.path.splitext(object_name)[0] - # exclude no transform data - if record in self.objaverse_exclude: - continue - else: - record = object_name - # validate set abort - if self.validate and record not in self.val_list: - continue - # train set abort - if not self.validate and record not in self.train_set: - continue - - # if self.dataset_name == 'ShapeNet': - # # load vertices and faces - # gt_path = os.path.join(class_dir, object_name, 'blank_model.ply') - # # load pcd - # pcd_file = os.path.join(self.pcd_dir, class_name, object_name, - # 'models', - # f'pc_model_normalized.obj_mat_{self.img_num}_262144_131072.ply') - - if self.dataset_name == 'Objaverse': - # load vertices and faces - gt_path = os.path.join(class_dir, object_name) - # pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') - - # skip empty folder - if not os.path.exists(gt_path): - continue - - # # skip empty folder - # if not os.path.exists(pcd_file): - # continue - - # load raw vertices and faces - try: - ref_mesh = trimesh.load(gt_path, force='mesh', process=False) - except Exception as e: - continue - - if not hasattr(ref_mesh, 'vertices') or not hasattr(ref_mesh, 'faces'): - continue - - # # load point cloud - # pcd = trimesh.load(pcd_file) - - # if not hasattr(pcd, 'vertices') or not hasattr(pcd, 'colors'): - # print("pcd has no attr vertices or colors", pcd_file) - # continue - - # if len(pcd.vertices) < self.query_pts_num: - # print("pcd num less than query_pts_num", pcd_file) - # continue - - verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) - faces = torch.LongTensor(ref_mesh.faces) - - if self.render_img_dir == '': - pass - # res = self._preprocess(verts, faces, pcd_file, uuid=record) - else: - # if self.dataset_name == 'ShapeNet': - # imgdir = os.path.join(self.render_img_dir, class_name, object_name, 'img', object_name, 'models') - if self.dataset_name == 'Objaverse': - imgdir = os.path.join(self.render_img_dir, record) - else: - raise RuntimeError('Not valid dataset_name') - # skip empty folder - if not os.path.exists(imgdir): - continue - res = self._preprocess(verts, faces, uuid=record, imgdir=imgdir) - - res[0].update({'uuid': record}) - - if self.triview_color_dir != '' and self.triview_xyz_dir != '': - img_list, xyz_list = [], [] - triview_color_dir = os.path.join(self.triview_color_dir, record) - triview_xyz_dir = os.path.join(self.triview_xyz_dir, record) - for i in range(6): - # BGR -> RGB - raw = cv2.resize( - cv2.imread(os.path.join(triview_color_dir, f'{i:03d}.png'), cv2.IMREAD_UNCHANGED), - tuple(self.res_triview)) - xyz = cv2.resize( - cv2.imread(os.path.join(triview_xyz_dir, f'xyz_new_{i:03d}.png'), cv2.IMREAD_UNCHANGED), - tuple(self.res_triview)) - mask = torch.tensor(raw[:, :, [-1]], - dtype=torch.float32).repeat(1, 1, 3) / 255 - img = torch.tensor(raw[:, :, [2, 1, 0]], - dtype=torch.float32) / 255 - xyz = torch.tensor(xyz, dtype=torch.float32) / 255 - - img = img * mask - xyz = xyz * mask - - img_list.append(img) - xyz_list.append(xyz) - - triview_imgs = torch.stack(img_list, dim=0) - triview_xyzs = torch.stack(xyz_list, dim=0) - - res[0].update({ - 'triview_color': triview_imgs, - 'triview_xyz': triview_xyzs - }) - - if self.prompt_path != '': - res[0].update({ - 'prompt': self.uuid2prompt.get(os.path.splitext(object_name)[0]) - }) - - if res is not None: - self.data.extend(res) - else: - raise ValueError("Error! Unrecognized task mode.") + # load vertices and faces + gt_path = os.path.join(class_dir, object_name) - def _preprocess(self, verts, faces, uuid=None, imgdir=None): - # no render images or no blender mode - if imgdir is None or (self.render_mode != 'blender' and self.dep_sill_mode != 'blender'): - pass - # verts -= ((verts.max(0)[0] + verts.min(0)[0]) / 2).unsqueeze(0).repeat( - # (verts.shape[0], 1)) - - # # load point cloud - # pcd = trimesh.load(pcd_file) - # pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) - - # # rotate & transport - # pcd_tr = pcd_tr @ utils.rotate_x(-math.pi / 2).T[:3, :3] - # pcd_tr -= ((pcd_tr.max(0)[0] + pcd_tr.min(0)[0]) / 2).unsqueeze(0).repeat((pcd_tr.shape[0], 1)) - - # # color, normalized to [-1, 1] - # pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] - - # # scale - # verts = verts / torch.max(abs(verts)) * self.scale - # pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale - - # return [{ - # 'gt_verts': verts, - # 'gt_faces': faces, - # 'gt_pcd': pcd_tr, - # 'gt_pcd_colors': pcd_colors - # }] + ref_mesh = trimesh.load(gt_path, force='mesh', process=False) - else: - # # load point cloud - # pcd = trimesh.load(pcd_file) + verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) + faces = torch.LongTensor(ref_mesh.faces) - # if not hasattr(pcd, 'vertices') or not hasattr(pcd, 'colors'): - # return + imgdir = os.path.join(self.render_img_dir, record) - # if len(pcd.vertices) < self.query_pts_num: - # return + # skip empty folder + if not os.path.exists(imgdir): + continue - # pcd_tr = torch.tensor(pcd.vertices, dtype=torch.float32) + res = self._preprocess(verts, faces, uuid=record, imgdir=imgdir) + + res.update({'uuid': record}) + + # if self.triview_color_dir != '' and self.triview_xyz_dir != '': + img_list, xyz_list = [], [] + triview_color_dir = os.path.join(self.triview_color_dir, record) + triview_xyz_dir = os.path.join(self.triview_xyz_dir, record) + for i in range(6): + # BGR -> RGB + raw = cv2.resize( + cv2.imread(os.path.join(triview_color_dir, f'{i:03d}.png'), cv2.IMREAD_UNCHANGED), + tuple(self.res_triview)) + xyz = cv2.resize( + cv2.imread(os.path.join(triview_xyz_dir, f'xyz_new_{i:03d}.png'), cv2.IMREAD_UNCHANGED), + tuple(self.res_triview)) + mask = torch.tensor(raw[:, :, [-1]], + dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0]], + dtype=torch.float32) / 255 + xyz = torch.tensor(xyz, dtype=torch.float32) / 255 + + img = img * mask + xyz = xyz * mask + + img_list.append(img) + xyz_list.append(xyz) + + triview_imgs = torch.stack(img_list, dim=0) + triview_xyzs = torch.stack(xyz_list, dim=0) + + res.update({ + 'triview_color': triview_imgs, + 'triview_xyz': triview_xyzs + }) + + # if self.prompt_path != '': + res.update({ + 'prompt': self.uuid2prompt.get(os.path.splitext(object_name)[0]) + }) + + # if res is not None: + self.data.append(res) + def _preprocess(self, verts, faces, uuid=None, imgdir=None): # rotate - verts[:, -1] = -verts[:, -1] - verts = verts[:, [0, 2, 1]] - # pcd_colors = ((2 * torch.tensor(pcd.colors, dtype=torch.float32) - 255) / 255)[..., :3] - - # if self.dataset_name == 'ShapeNet': - # verts *= self.scale / 0.5 - # pcd_tr *= self.scale / 0.5 - - # with open(os.path.join(imgdir, 'transforms.json'), 'r') as f: - # metadata = json.load(f) - # self.fovx = metadata['camera_angle_x'] - # img_list, transform_list = [], [] - # depth_list = [] - # for i, data in enumerate(metadata['frames']): - # img_name = data['file_path'] - # assert i == int(os.path.splitext(img_name)[0]) - - # c2w = torch.tensor(data['transform_matrix'], dtype=torch.float32) - - # c2w[:3, 3] *= self.scale / 0.5 - - # w2c = torch.inverse(c2w) - # # BGR -> RGB -> [-1, 1] - # raw = cv2.resize( - # cv2.imread(os.path.join(imgdir, img_name), cv2.IMREAD_UNCHANGED), - # tuple(self.res_img)) - # mask = torch.tensor(raw[:, :, [-1]], - # dtype=torch.float32).repeat(1, 1, 3) / 255 - # img = torch.tensor(raw[:, :, [2, 1, 0]], - # dtype=torch.float32) / 255 - - # img = img * mask - - # transform_list.append(w2c) - # img_list.append(img) - - # # depth - # depth_name = f'{i:05d}_depth.png' - # dep = cv2.imread(os.path.join(imgdir, depth_name), cv2.IMREAD_UNCHANGED) - - # # reference - # # https://github.com/openai/shap-e/blob/50131012ee11c9d2617f3886c10f000d3c7a3b43/shap_e/rendering/blender/view_data.py#L57-L62 - # inf_dist = dep == 0xFFFF - # dep = np.where( - # inf_dist, - # 0., - # SHAPENET_MAX_DEPTH * (dep.astype(np.float32) / 65536), - # ) - - # dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 - - # depth_list.append(dep) + verts[:, -1] = -verts[:, -1] + verts = verts[:, [0, 2, 1]] - # gt_render_imgs = torch.stack(img_list) - # gt_transforms = torch.stack(transform_list) - # gt_render_depths = torch.stack(depth_list).unsqueeze(-1) + transform = self.uuid2transform[uuid] + transport = torch.tensor(transform['offset'], dtype=torch.float32) + scale = torch.tensor(transform['scale'], dtype=torch.float32) + verts = (verts * scale + transport) * self.scale / 0.5 - if self.dataset_name == 'Objaverse': - if self.uuid2transform: - transform = self.uuid2transform[uuid] - transport = torch.tensor(transform['offset'], dtype=torch.float32) - scale = torch.tensor(transform['scale'], dtype=torch.float32) - verts = (verts * scale + transport) * self.scale / 0.5 - else: - transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 - verts -= transport - scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) + with open(os.path.join(imgdir, 'meta.pkl'), 'rb') as f: + k, _, _, _, w2cs = pickle.load(f) - verts *= self.scale / 0.5 * scale - # pcd_tr *= self.scale / 0.5 + self.fovx = 2 * math.atan(k[0, 2] / k[0, 0]) - with open(os.path.join(imgdir, 'meta.pkl'), 'rb') as f: - K, _, _, _, w2cs = pickle.load(f) + img_list, transform_list = [], [] + depth_list = [] + for i, w2c in enumerate(w2cs): + img_name = f'{i:03d}.png' - self.fovx = 2 * math.atan(K[0, 2] / K[0, 0]) + w2c = torch.tensor(np.stack((w2c[0], -w2c[1], -w2c[2], np.array([0., 0., 0., 1.])), axis=0), dtype=torch.float32) + c2w = torch.inverse(w2c) + c2w[:3, 3] *= self.scale / 0.5 + w2c = torch.inverse(c2w) + # BGR -> RGB -> [-1, 1] + raw = cv2.resize( + cv2.imread(os.path.join(imgdir, img_name), cv2.IMREAD_UNCHANGED), + tuple(self.res_img)) + mask = torch.tensor(raw[:, :, [-1]], + dtype=torch.float32).repeat(1, 1, 3) / 255 + img = torch.tensor(raw[:, :, [2, 1, 0]], + dtype=torch.float32) / 255 - img_list, transform_list = [], [] - depth_list = [] - for i, w2c in enumerate(w2cs): - img_name = f'{i:03d}.png' + img = img * mask - w2c = torch.tensor(np.stack((w2c[0], -w2c[1], -w2c[2], np.array([0., 0., 0., 1.])), axis=0), dtype=torch.float32) - c2w = torch.inverse(w2c) - c2w[:3, 3] *= self.scale / 0.5 - w2c = torch.inverse(c2w) - # BGR -> RGB -> [-1, 1] - raw = cv2.resize( - cv2.imread(os.path.join(imgdir, img_name), cv2.IMREAD_UNCHANGED), - tuple(self.res_img)) - mask = torch.tensor(raw[:, :, [-1]], - dtype=torch.float32).repeat(1, 1, 3) / 255 - img = torch.tensor(raw[:, :, [2, 1, 0]], - dtype=torch.float32) / 255 + transform_list.append(w2c) + img_list.append(img) - img = img * mask + # depth + # syncdreamer + # if os.path.exists(os.path.join(imgdir, f'{i:03d}-depth.png')): + depth_name = f'{i:03d}-depth.png' + dep = cv2.imread(os.path.join(imgdir, depth_name), cv2.IMREAD_UNCHANGED) - transform_list.append(w2c) - img_list.append(img) + # reference + # https://github.com/liuyuan-pal/SyncDreamer/blob/232a2ec22f0277b4bd429109fb34eaf8f61b13ad/eval_mesh.py#L16-L22 + dep = dep.astype(np.float32) / 65535 * (DEPTH_MAX - DEPTH_MIN) + DEPTH_MIN + mask = (dep < DEPTH_VALID_MIN) | (dep > DEPTH_VALID_MAX) - # depth - # syncdreamer - if os.path.exists(os.path.join(imgdir, f'{i:03d}-depth.png')): - depth_name = f'{i:03d}-depth.png' - dep = cv2.imread(os.path.join(imgdir, depth_name), cv2.IMREAD_UNCHANGED) + # # cs + # elif os.path.exists(os.path.join(imgdir, f'depth_{i:03d}1.png')): + # depth_name = f'depth_{i:03d}1.png' + # depth_path = os.path.join(imgdir, depth_name) - # reference - # https://github.com/liuyuan-pal/SyncDreamer/blob/232a2ec22f0277b4bd429109fb34eaf8f61b13ad/eval_mesh.py#L16-L22 - dep = dep.astype(np.float32) / 65535 * (DEPTH_MAX - DEPTH_MIN) + DEPTH_MIN - mask = (dep < DEPTH_VALID_MIN) | (dep > DEPTH_VALID_MAX) + # dep =(np.array(Image.open(depth_path))[:,:,0]- 64) / 127 + # mask = np.array(Image.open(depth_path))[:,:,0] == 255 - # cs - elif os.path.exists(os.path.join(imgdir, f'depth_{i:03d}1.png')): - depth_name = f'depth_{i:03d}1.png' - depth_path = os.path.join(imgdir, depth_name) + dep = np.where(mask, 0., dep) - dep =(np.array(Image.open(depth_path))[:,:,0]- 64) / 127 - mask = np.array(Image.open(depth_path))[:,:,0] == 255 + dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 - dep = np.where(mask, 0., dep) + depth_list.append(dep) - dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 + render_imgs = torch.stack(img_list) + transforms = torch.stack(transform_list) + render_depths = torch.stack(depth_list).unsqueeze(-1) - depth_list.append(dep) - gt_render_imgs = torch.stack(img_list) - gt_transforms = torch.stack(transform_list) - gt_render_depths = torch.stack(depth_list).unsqueeze(-1) + return { + 'verts': verts, + 'faces': faces, + 'render_imgs': render_imgs, + 'transforms': transforms, + 'render_depths': render_depths + } - - return [{ - 'gt_verts': verts.cpu(), 'gt_faces': faces.cpu(), - # 'gt_pcd': pcd_tr, 'gt_pcd_colors': pcd_colors, - 'gt_render_imgs': gt_render_imgs, 'gt_transforms': gt_transforms, 'gt_render_depths': gt_render_depths}] - - def _sample_scene(self, idx, num, rotate=False): + def _sample_scene(self, num, rotate=False): batch = 1 if rotate else self.camera_angle_num proj_mtx = utils.perspective(self.fovx, self.res[1] / self.res[0]) - if self.render_mode != 'blender' and self.dep_sill_mode != 'blender': - if rotate: - ang = (idx / 20) * np.pi * 2 - mv = utils.translate(0, 0, -self.cam_radius) @ (utils.rotate_x(0.4) @ utils.rotate_y(ang)) - mv = mv.repeat(batch, 1, 1) - else: - mv = torch.bmm( - utils.translate(0, 0, -self.cam_radius).repeat(batch, 1, 1), - utils.batch_random_rotation_translation(self.camera_angle_num, 0.25) - ) - depths = torch.zeros((batch,) + tuple(self.res) + (1,)) - imgs = torch.zeros((batch,) + tuple(self.res) + (3,)) - else: - mv = self.data[num].get('gt_transforms') - img_num = len(mv) - index = random.sample(range(img_num), k=1 if rotate else self.camera_angle_num) + # if self.render_mode != 'blender' and self.dep_sill_mode != 'blender': + # if rotate: + # ang = (idx / 20) * np.pi * 2 + # mv = utils.translate(0, 0, -self.cam_radius) @ (utils.rotate_x(0.4) @ utils.rotate_y(ang)) + # mv = mv.repeat(batch, 1, 1) + # else: + # mv = torch.bmm( + # utils.translate(0, 0, -self.cam_radius).repeat(batch, 1, 1), + # utils.batch_random_rotation_translation(self.camera_angle_num, 0.25) + # ) + # depths = torch.zeros((batch,) + tuple(self.res) + (1,)) + # imgs = torch.zeros((batch,) + tuple(self.res) + (3,)) + # else: + mv = self.data[num].get('transforms') + img_num = len(mv) + index = random.sample(range(img_num), k=1 if rotate else self.camera_angle_num) - mv = mv[index] - imgs = self.data[num].get('gt_render_imgs')[index] - depths = self.data[num].get('gt_render_depths')[index] + mv = mv[index] + imgs = self.data[num].get('render_imgs')[index] + depths = self.data[num].get('render_depths')[index] mvp = torch.bmm( proj_mtx.repeat(batch, 1, 1), mv ) - campos = torch.linalg.inv(mv)[:, :3, 3] + # campos = torch.linalg.inv(mv)[:, :3, 3] - return mv.to(self.device), mvp.to(self.device), campos.to(self.device), \ - imgs.to(self.device), depths.to(self.device), proj_mtx.to(self.device), self.res + return mv.to(self.device), mvp.to(self.device), imgs.to(self.device), \ + depths.to(self.device), proj_mtx.to(self.device), self.res def __len__(self): # return self.epoch if self.validate else self.its_per_epc @@ -466,67 +321,47 @@ def __getitem__(self, idx): num = idx # rotate or random scene - mv, mvp, campos, imgs, depths, persp, iter_res = self._sample_scene(idx, num, rotate=self.visual) - - if self.dep_sill_mode == 'blender': - alpha = alpha_ctn = (depths > 0).float() - normal, face_normals = renderer.render_mesh( - self.glctx, - self.data[num]['gt_verts'].to(self.device), - self.data[num]['gt_faces'].to(self.device), - mvp, campos, persp, iter_res, - normal_only=True - ) - else: - alpha, alpha_ctn, depths, normal, face_normals = renderer.render_mesh( - self.glctx, - self.data[num]['gt_verts'].to(self.device), - self.data[num]['gt_faces'].to(self.device), - mvp, campos, persp, iter_res - ) + mv, mvp, imgs, depth, persp, iter_res = self._sample_scene(num, rotate=self.visual) + + # if self.dep_sill_mode == 'blender': + # alpha = alpha_ctn = (depths > 0).float() + # normal, face_normals = renderer.render_mesh( + # self.glctx, + # self.data[num]['gt_verts'].to(self.device), + # self.data[num]['gt_faces'].to(self.device), + # mvp, campos, persp, iter_res, + # normal_only=True + # ) + # else: + alpha, depth, normal = renderer.render_mesh( + self.glctx, + self.data[num]['verts'].to(self.device), + self.data[num]['faces'].to(self.device), + mvp, persp, iter_res + ) - # pcd_num = len(self.data[num]['gt_pcd']) - # index = random.sample(range(pcd_num), k=self.pts_num) - # index_query = random.sample(range(pcd_num), k=min(self.query_pts_num, self.pts_num)) + triview_color = self.data[num]['triview_color'] + triview_xyz = self.data[num]['triview_xyz'] + prompt = self.data[num]['prompt'] res = { 'uuid': self.data[num].get('uuid'), - 'gt_verts': self.data[num]['gt_verts'], - 'gt_faces': self.data[num]['gt_faces'], - # 'gt_pcd': self.data[num]['gt_pcd'][None, index, ...], - # 'gt_pcd_colors': self.data[num]['gt_pcd_colors'][None, index, ...], - # 'gt_pcd_colors_query': self.data[num]['gt_pcd_colors'][None, index_query, ], - # 'gt_pcd_query': self.data[num]['gt_pcd'][None, index_query, ], - 'gt_render_imgs': imgs[None, ], + 'verts': self.data[num]['verts'], + 'faces': self.data[num]['faces'], + 'render_imgs': imgs[None, ], 'mv': mv[None, ], 'mvp': mvp[None, ], - 'campos': campos[None, ], + # 'campos': campos[None, ], 'resolution': self.res, 'resolution_img': self.res_img, 'resolution_triview': self.res_triview, 'normal': normal[None, ], 'alpha': alpha[None, ], - 'alpha_ctn': alpha_ctn[None, ], - 'depth': depths[None, ], - 'persp': persp + # 'alpha_ctn': alpha_ctn[None, ], + 'depth': depth[None, ], + 'persp': persp, + 'triview_color': triview_color[None, ], + 'triview_xyz': triview_xyz[None, ], + 'prompt': [prompt] } - - if self.triview_color_dir != '': - triview_color = self.data[num]['triview_color'] - res.update({ - 'triview_color': triview_color[None, ], - }) - - if self.triview_xyz_dir != '': - triview_xyz = self.data[num]['triview_xyz'] - res.update({ - 'triview_xyz': triview_xyz[None, ], - }) - - if self.prompt_path != '': - prompt = self.data[num]['prompt'] - res.update({ - 'prompt': [prompt] - }) - return res diff --git a/make_chunk.py b/make_chunk.py index 9652112..2043b73 100644 --- a/make_chunk.py +++ b/make_chunk.py @@ -1,43 +1,54 @@ +''' +Chunk make main function +''' import os -os.environ["CUDA_HOME"] = "/usr/local/cuda-12.1" import argparse -from subprocess import Popen, PIPE +from subprocess import Popen +# Change to your cuda home path +os.environ['CUDA_HOME'] = '/usr/local/cuda-12.1' + +# Change to your /path/to/python +PYTHON = '/home/yudajiang/softwares/miniforge-pypy3/envs/crm/bin/python' def main(): + ''' + Chunk make main function + ''' arg_parser = argparse.ArgumentParser() arg_parser.add_argument( - "--exp_dir", "-e", - default="configs/", - help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", + '--exp_dir', '-e', + default='configs/', + help='This directory should include experiment specifications in "specs.json" ', ) arg_parser.add_argument( - "--config_name", "-c", - default="specs_clear.json", - help="config filename", + '--config_name', '-c', + default='specs_clear.json', + help='config filename', ) - arg_parser.add_argument( - "-p", "--num_process", + '-p', '--num_process', default=1, type=int, - help="Number of processes to use for data loading.", + help='Number of processes to use for data loading.', ) args = arg_parser.parse_args() - python = "/home/yudajiang/softwares/miniforge-pypy3/envs/crm/bin/python" p_ls = [] try: - log_f = open("log.log", "w") - for i in range(args.num_process): - p = Popen([python, 'make_chunk_sub.py', '-e', args.exp_dir, '-c', args.config_name, f'-p {args.num_process}',f"-i {i}"], stdout=log_f, stderr=log_f) - p_ls.append(p) - - [p.wait() for p in p_ls] - except: + with open('log.log', 'w', encoding='utf8') as log_f: + for i in range(args.num_process): + p = Popen([PYTHON, 'make_chunk_sub.py', '-e', args.exp_dir, '-c', args.config_name, + f'-p {args.num_process}',f"-i {i}"], stdout=log_f, stderr=log_f) + p_ls.append(p) + + for p in p_ls: + p.wait() + except KeyboardInterrupt: + # kill running processes for p in p_ls: p.kill() if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/make_chunk_sub.py b/make_chunk_sub.py index 4502f26..da08ddb 100644 --- a/make_chunk_sub.py +++ b/make_chunk_sub.py @@ -1,59 +1,58 @@ +''' +Chunk make subprocess (script for debug use) +''' import os import json -os.environ["CUDA_HOME"] = "/usr/local/cuda-12.1" import argparse -# import nvdiffrast.torch as dr -from itertools import cycle -from tqdm import tqdm -import torch.distributed as dist -from datasets.memory_dataset import MemoryDataset from datasets.fast_dataset import FastDataset -# from util.common import pcd_preprocess -from accelerate import Accelerator -from util import utils -from subprocess import Popen, PIPE + +# Change to your cuda home path +os.environ['CUDA_HOME'] = '/usr/local/cuda-12.1' def main(): + ''' + Chunk Make subprocess (for debug use) + ''' arg_parser = argparse.ArgumentParser() arg_parser.add_argument( - "--exp_dir", "-e", - default="configs/", - help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", + '--exp_dir', '-e', + default='configs/', + help='This directory should include experiment specifications in "specs.json" ', ) arg_parser.add_argument( - "--config_name", "-c", - default="specs_clear.json", - help="config filename", + '--config_name', '-c', + default='specs_clear.json', + help='config filename', ) - arg_parser.add_argument( - "-p", "--num_process", + '-p', '--num_process', default=1, type=int, - help="Number of processes to use for data loading.", + help='Number of processes to use for data loading.', ) - arg_parser.add_argument( - "-i", "--process_index", + '-i', '--process_index', default=0, type=int, - help="Index of the current process.", + help='Index of the current process.', ) args = arg_parser.parse_args() config_path = os.path.join(args.exp_dir, args.config_name) - specs = json.load(open(config_path)) + with open(config_path, encoding='utf8') as f: + specs = json.load(f) + input_specs = specs['Input'] train_specs = specs['Train'] dataset = FastDataset(input_specs, train_specs, None, None, 0, mode='all') dataset.num_process = args.num_process dataset.process_index = args.process_index - dataset._write_chunks(dataset.parquet_dir, dataset.chunk_size) + dataset.write_chunks(dataset.parquet_dir, dataset.chunk_size) if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/metric/shape.py b/metric/shape.py index d611ca1..97ee815 100644 --- a/metric/shape.py +++ b/metric/shape.py @@ -1,24 +1,18 @@ -from tqdm import tqdm -import numpy as np +''' +Reconstruction metrics +''' import torch import kaolin -import pytorch3d.loss from scipy.spatial.distance import cdist -############################################################################### -# Reconstruction metrics placed in the following block -############################################################################### - def vol_intersect_over_union(verts_pred, faces_pred, verts_gt, faces_gt, device=torch.device('cuda')): + '''volume IOU calculation''' axis = torch.linspace(-1., 1., steps=101) p_x, p_y, p_z = torch.meshgrid(axis, axis, axis, indexing='ij') points = torch.cat((p_x.unsqueeze(-1), p_y.unsqueeze(-1), p_z.unsqueeze(-1)), dim=3) points = points.view(1, -1, 3).to(device) - # CYF note: it's weird that - # 1) cuda face inputs become cpu variable internally - # 2) verts is required dim-3 but faces is dim-2 in_pred = kaolin.ops.mesh.check_sign(verts_pred, faces_pred.to(device), points) in_gt = kaolin.ops.mesh.check_sign(verts_gt, faces_gt.to(device), points) @@ -27,24 +21,12 @@ def vol_intersect_over_union(verts_pred, faces_pred, verts_gt, faces_gt, device= return intersection / union - -def cdist_pt3d(pt_pr, pt_gt, norm): - """ - CYF Note: - utilize the unified pytorch3d method to compute Chamfer distances - """ - - assert norm in [1, 2] - loss, _ = pytorch3d.loss.chamfer_distance(pt_pr, pt_gt, norm=norm, point_reduction="mean", single_directional=False) - - return loss - - def chamfer_distance(ptr_pred, ptr_gt): + '''Chamfer distance L2 calculation''' return kaolin.metrics.pointcloud.chamfer_distance(ptr_pred, ptr_gt).mean() - def chamfer_distance_l1(ptr_pred, ptr_gt, device): + '''Chamfer distance L1 calculation''' ptr_pred = ptr_pred.cpu().numpy() ptr_gt = ptr_gt.cpu().numpy() @@ -52,118 +34,9 @@ def chamfer_distance_l1(ptr_pred, ptr_gt, device): n0, n1 = mat.shape return torch.tensor(mat.min(axis=0).sum() / n1 + mat.min(axis=1).sum() / n0, dtype=torch.float32, device=device) - def silhouette_mask_iou(silhouette_pred, silhouette_gt): + '''Mask IOU calculation''' tmp = torch.stack([silhouette_pred, silhouette_gt], dim=0) inter = torch.all(tmp, dim=0).sum(dim=(1, 2, 3)) union = torch.any(tmp, dim=0).sum(dim=(1, 2, 3)) return (inter / union).mean() - - -############################################################################### -# Generative metrics placed in the following block -############################################################################### - -""" -CYF Note: -The following methods are for evaluating generative metrics, i.e., MMD, COV, 1-NNA. -They are borrowed or adapted from two code bases, i.e., LION, and Diffusion-SDF -""" - - -def mmd_cov_1nna(ref_pcds, gen_pcds, b_size): - results = {} - - # MMD and COV results - M_rs_cd = _pairwise_cdist_(ref_pcds, gen_pcds, b_size) - mmd_cd, cov_cd = lgan_mmd_cov(M_rs_cd.t()) - results["MMD-CD"] = mmd_cd - results["COV-CD"] = cov_cd - - # 1-NN results - M_rr_cd = _pairwise_cdist_(ref_pcds, ref_pcds, b_size) - M_ss_cd = _pairwise_cdist_(gen_pcds, gen_pcds, b_size) - one_nn_cd_res = knn(M_rr_cd, M_rs_cd, M_ss_cd, 1, sqrt=False) - results["1-NNA-CD"] = one_nn_cd_res['acc'] - - return results - - -def _pairwise_cdist_(ref_pcds, gen_pcds, b_size): - N_ref = ref_pcds.shape[0] - N_gen = gen_pcds.shape[0] - all_cd = [] - iterator = range(N_gen) - - with tqdm(iterator) as pbar: - for gen_b_start in pbar: - pbar.set_description("Files evaluated: {}/{}".format(gen_b_start, N_gen)) - gen_batch = gen_pcds[gen_b_start] - - cd_lst = [] - for ref_b_start in range(0, N_ref, b_size): - ref_b_end = min(N_ref, ref_b_start + b_size) - ref_batch = ref_pcds[ref_b_start: ref_b_end] - - b_size_ref = ref_batch.size(0) - gen_batch_exp = gen_batch.view(1, -1, 3).expand(b_size_ref, -1, -1) - gen_batch_exp = gen_batch_exp.contiguous() - - cd_b, _ = pytorch3d.loss.chamfer_distance(gen_batch_exp, ref_batch, norm=1, batch_reduction=None, - point_reduction="mean", single_directional=False) - cd_lst.append(cd_b) - - cd_lst = torch.cat(cd_lst, dim=0) - all_cd.append(cd_lst[:, None]) - - all_cd = torch.cat(all_cd, dim=1) # N_ref x N_gen - - return all_cd - - -def lgan_mmd_cov(all_dist): - # all dist shape = [number of generated pcds, number of ref pcds] - N_sample, N_ref = all_dist.size(0), all_dist.size(1) - min_val_fromsmp, min_idx = torch.min(all_dist, dim=1) - min_val, _ = torch.min(all_dist, dim=0) - mmd = min_val.mean() - - cov = float(min_idx.unique().view(-1).size(0)) / float(N_ref) - cov = torch.tensor(cov).to(all_dist) - - return mmd, cov, - - -# Adapted from https://github.com/xuqiantong/GAN-Metrics/blob/master/framework/metric.py -def knn(Mxx, Mxy, Myy, k, sqrt=False): - n0 = Mxx.size(0) - n1 = Myy.size(0) - label = torch.cat((torch.ones(n0), torch.zeros(n1))).to(Mxx) - - M = torch.cat((torch.cat((Mxx, Mxy), 1), torch.cat((Mxy.transpose(0, 1), Myy), 1)), 0) - if sqrt: - M = M.abs().sqrt() - INFINITY = float('inf') - val, idx = (M + torch.diag(INFINITY * torch.ones(n0 + n1).to(Mxx))).topk(k, 0, False) - - count = torch.zeros(n0 + n1).to(Mxx) - for i in range(0, k): - count = count + label.index_select(0, idx[i]) - pred = torch.ge(count, (float(k) / 2) * torch.ones(n0 + n1).to(Mxx)).float() - - s = { - 'tp': (pred * label).sum(), - 'fp': (pred * (1 - label)).sum(), - 'fn': ((1 - pred) * label).sum(), - 'tn': ((1 - pred) * (1 - label)).sum(), - } - - s.update({ - 'precision': s['tp'] / (s['tp'] + s['fp'] + 1e-10), - 'recall': s['tp'] / (s['tp'] + s['fn'] + 1e-10), - 'acc_t': s['tp'] / (s['tp'] + s['fn'] + 1e-10), - 'acc_f': s['tn'] / (s['tn'] + s['fp'] + 1e-10), - 'acc': torch.eq(label, pred).float().mean(), - }) - - return s diff --git a/model/archs/decoders/shape_texture_net.py b/model/archs/decoders/shape_texture_net.py index 5e5ddd7..c9d8d22 100644 --- a/model/archs/decoders/shape_texture_net.py +++ b/model/archs/decoders/shape_texture_net.py @@ -4,7 +4,7 @@ class TetTexNet(nn.Module): - def __init__(self, plane_reso=64, padding=0.1, fea_concat=True): + def __init__(self, plane_reso=64, padding=0.1, fea_concat=False): super().__init__() # self.c_dim = c_dim self.plane_reso = plane_reso diff --git a/model/archs/mlp_head.py b/model/archs/mlp_head.py index 33d7dcd..d6b65b5 100644 --- a/model/archs/mlp_head.py +++ b/model/archs/mlp_head.py @@ -37,4 +37,17 @@ def forward(self, input): return out - \ No newline at end of file + +class WeightMlp(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, 21, bias=bias) + + def forward(self, input): + x = F.silu(self.fc1(input)) + out = self.fc2(x) + return out diff --git a/model/crm/model.py b/model/crm/model.py index 3de135a..2c04de4 100644 --- a/model/crm/model.py +++ b/model/crm/model.py @@ -3,20 +3,17 @@ import torch.nn.functional as F import numpy as np - - -from pathlib import Path import cv2 import trimesh import nvdiffrast.torch as dr +import xatlas +# from diffusers import DDIMScheduler from model.archs.decoders.shape_texture_net import TetTexNet from model.archs.unet import UNetPP from util.renderer import Renderer from util.utils import get_tri, trans_depth -from model.archs.mlp_head import SdfMlp, RgbMlp -import xatlas -import random +from model.archs.mlp_head import SdfMlp, RgbMlp, WeightMlp class Dummy: @@ -24,7 +21,7 @@ class Dummy: class CRM(nn.Module): def __init__(self, specs): - super(CRM, self).__init__() + super().__init__() self.specs = specs # configs @@ -35,10 +32,10 @@ def __init__(self, specs): self.tet_grid_size = input_specs['tet_grid_size'] self.camera_angle_num = input_specs['camera_angle_num'] - arch_specs = specs["ArchSpecs"] - self.arch = Dummy() - self.arch.fea_concat = arch_specs["fea_concat"] - self.arch.mlp_bias = arch_specs["mlp_bias"] + # arch_specs = specs["ArchSpecs"] + # self.arch = Dummy() + # self.arch.fea_concat = arch_specs["fea_concat"] + # self.arch.mlp_bias = arch_specs["mlp_bias"] encoder_specs = specs["EncoderSpecs"] self.enc = Dummy() @@ -48,272 +45,143 @@ def __init__(self, specs): self.dec.c_dim = decoder_specs["c_dim"] self.dec.plane_resolution = decoder_specs["plane_resolution"] - self.geo_type = specs["Train"].get("geo_type", "dmtet") # "dmtet" or "flex" + # self.geo_type = specs["Train"].get("geo_type", "dmtet") # "dmtet" or "flex" - self.unet2 = UNetPP(in_channels=self.dec.c_dim) + self.unet = 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) + # mlp_chnl_s = 1 # 3 for queried triplane feature concatenation + self.decoder = TetTexNet(plane_reso=self.dec.plane_resolution) - 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) + # if self.geo_type == "flex": + self.weight_mlp = WeightMlp(self.dec.c_dim * 8) + self.sdf_mlp = SdfMlp(self.dec.c_dim) + self.rgb_mlp = RgbMlp(self.dec.c_dim) + self.renderer = Renderer(tet_grid_size=self.tet_grid_size, + camera_angle_num=self.camera_angle_num, + scale=self.input.scale) self.l1_loss = nn.L1Loss() self.mse_loss = nn.MSELoss() self.ticker = 0 - self.spob = True if specs['Pretrain']['mode'] is None else False # whether to add sphere - self.radius = specs['Pretrain']['radius'] # used when spob + # self.spob = True # whether to add sphere + self.radius = specs['Train']['radius'] # used when spob + # self.denoising = False + + # self.scheduler = DDIMScheduler.from_pretrained("stabilityai/stable-diffusion-2-1-base", subfolder="scheduler") - self.denoising = False - from diffusers import DDIMScheduler - self.scheduler = DDIMScheduler.from_pretrained("stabilityai/stable-diffusion-2-1-base", subfolder="scheduler") def small_fwd(self, data): xyzs_list = [] color_list = [] - # color0_list = [] - # print(data['triview_color'].shape) - # print(data['triview_xyz'].shape) - for i in range(len(data['gt_verts'])): + for i in range(len(data['verts'])): color = data['triview_color'][i].permute(0,3,1,2).clone() xyzs = data['triview_xyz'][i].permute(0,3,1,2).clone() if xyzs.max() > 1.1: xyzs = xyzs / 255 # print("fix 255 bug") - if self.specs["Train"].get("random_bg", False): - crgb = 0.5#random.random() - cxyz = 0.5#random.random() - # for j in range(6): - # mask = torch.mean(xyzs[j], dim = 0, keepdim=False) - # mask = (mask == 0) - # grey_image = torch.zeros_like(cxyz) - # for k in range(3): - # grey_image[j][k][mask] = cxyz - for j in range(6): - mask = torch.mean(xyzs[j], dim = 0, keepdim=False) - mask = (mask == 0) - for k in range(3): - color[j][k][mask] = crgb - xyzs[j][k][mask] = cxyz - else: - crgb = 0 - cxyz = 0 - - shift = 0 - if random.random() < 0.5: - shift = int(self.specs["Train"].get("shift", 0)) - # print(color.shape) - color_tensor1 = get_tri(color, dim=0, blender=True, c=crgb, shift=shift, rgb=True) - xyzs_tensor1 = get_tri(xyzs, dim=0, blender=True, c=cxyz, shift=shift, fix=True) # , fix = True - # print(color_tensor1.min(), color_tensor1.max(), xyzs_tensor1.min(),xyzs_tensor1.max()) - - + # if self.specs["Train"].get("random_bg", False): + # crgb = 0.5#random.random() + # cxyz = 0.5#random.random() + # for j in range(6): + # mask = torch.mean(xyzs[j], dim = 0, keepdim=False) + # mask = (mask == 0) + # for k in range(3): + # color[j][k][mask] = crgb + # xyzs[j][k][mask] = cxyz + # else: + # crgb = 0 + # cxyz = 0 + + # shift = 0 + # if random.random() < 0.5: + # shift = int(self.specs["Train"].get("shift", 0)) + + color_tensor1 = get_tri(color, dim=0, blender=True, rgb=True) + xyzs_tensor1 = get_tri(xyzs, dim=0, blender=True, fix=True) # , fix = True + + # print(color_tensor1.shape) # print(color_tensor1.shape) color_list.append(color_tensor1) xyzs_list.append(xyzs_tensor1) color_tensor = torch.stack(color_list, dim=0) - # print(color_tensor.shape) - color_tensor = torch.nn.functional.interpolate(color_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") + color_tensor = torch.nn.functional.interpolate( + color_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") xyzs_tensor = torch.stack(xyzs_list, dim=0) - xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") - - # if random.random()<0.5: - # color_tensor = torch.nn.functional.interpolate(color_tensor, [256, 256*3], mode = "bilinear") - # xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [256, 256*3], mode = "bilinear") - # color_tensor = torch.nn.functional.interpolate(color_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") - # xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") - - # reso_tmp = random.randint(32, 256) - # xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [reso_tmp, reso_tmp*3], mode = "bilinear") - # xyzs_tensor = torch.nn.functional.interpolate(xyzs_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") - + xyzs_tensor = torch.nn.functional.interpolate( + xyzs_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") + # !Notice all_tensor = torch.cat([color_tensor, xyzs_tensor], dim = 1)# *2 - 1 - # print(all_tensor.shape) - triplane_feature0 = all_tensor - triplane_feature1 = all_tensor - return triplane_feature0, triplane_feature1 - - def forward(self, data, ctx, tnew=None): - # pcd_xyz = data['gt_pcd'] - # pcd_rgb = data['gt_pcd_colors'] - # dense_pcd_xyz = data['gt_pcd_query'] - # dense_pcd_rgb = data['gt_pcd_colors_query'] - - # print(data['triview_color'].shape) - # print(data['triview_xyz'].shape) - # CYF Note: Adding noise to xyz. In real applications, - # point cloud is generated by sensors and thus noisy - # pcd_xyz += xyz_noise_scale * torch.randn(pcd_xyz.shape).to(pcd_xyz.get_device()) - # dense_pcd_xyz += xyz_noise_scale * torch.randn(dense_pcd_xyz.shape).to(dense_pcd_xyz.get_device()) - - # print(verts.shape, tets.shape) - # print(self.renderer.flexicubes.verts.shape, self.renderer.flexicubes.indices.shape) - if self.geo_type == "flex": - # use the number of data not batch size - verts = self.renderer.flexicubes.verts.unsqueeze(0).repeat(len(data['gt_verts']), 1, 1) - tets = self.renderer.flexicubes.indices - - # if self.arch.tri_img: + + # triplane_feature0 = all_tensor + # triplane_feature1 = all_tensor + # return triplane_feature0, triplane_feature1 + return all_tensor + + def forward(self, data, ctx): + # if self.geo_type == "flex": + # use the number of data not batch size + verts = self.renderer.flexicubes.verts.unsqueeze(0).repeat(len(data['verts']), 1, 1) + tets = self.renderer.flexicubes.indices + with torch.no_grad(): - tri_fea_0, tri_fea_1 = self.small_fwd(data) - - # if self.denoising == True: - # # tnew = 250 - # if tnew == None: - # tnew = torch.randint(0, 1000, [tri_fea_1.shape[0]], dtype=torch.long, device=tri_fea_1.device) - # else: - # tnew = torch.randint(tnew, tnew+1, [tri_fea_1.shape[0]], dtype=torch.long, device=tri_fea_1.device) - # noise_new = torch.randn_like(tri_fea_1) *0.5+0.5 - # reso = tri_fea_1.shape[-2] - # cache1 = tri_fea_1[:,:3,:,reso*2:] - # tri_fea_1 =self.scheduler.add_noise(tri_fea_1, noise_new, tnew) - # tri_fea_1[:,:3,:,reso*2:] = cache1 - - # if self.arch.tri_img or self.arch.tri_mix: - # if self.denoising == True: - # tri_fea_2 = self.unet2(tri_fea_1, tnew) - # else: - tri_fea_2 = self.unet2(tri_fea_1) - # else: - # reso = tri_fea_1.shape[-2:] - # reso_tmp = random.randint(64, 256)#int(torch.randint(low=64, high=256, size=(1,), dtype=torch.int)) - # tri_fea_1 = torch.nn.functional.interpolate(tri_fea_1, size=(reso_tmp, reso_tmp * 3), mode='bilinear') - # # tri_fea_1 = tri_fea_1.clamp(-1,1) - # # KL here - # tri_fea_1 = torch.nn.functional.interpolate(tri_fea_1, size=reso, mode='bilinear') - - # tri_fea_2 = self.unet2(tri_fea_1) - - assert torch.isnan(tri_fea_2).sum() == 0, print("nan in triplane feature 2") - dec_verts = self.decoder(tri_fea_2, verts) - - pred_shape = self.sdfMlp(dec_verts) + tri_input = self.small_fwd(data) + + tri_output = self.unet(tri_input) + + assert torch.isnan(tri_output).sum() == 0, print("nan in triplane feature 2") + dec_verts = self.decoder(tri_output, verts) + + pred_shape = self.sdf_mlp(dec_verts) assert torch.isnan(pred_shape).sum() == 0, print("nan in predicted shape primitives") pred_sdf, deformation = pred_shape[..., 0], pred_shape[..., 1:4] - if self.spob: - pred_sdf = pred_sdf + self.radius - torch.sqrt((verts ** 2).sum(-1)) + # if self.spob: + pred_sdf = pred_sdf + self.radius - torch.sqrt((verts ** 2).sum(-1)) for i in range(pred_sdf.shape[0]): if pred_sdf[i].min() >= 0 or pred_sdf[i].max() <= 0: - print('004occur!', pred_sdf[i].max(), pred_sdf[i].min()) + print(f'004occur at object {data["uuid"][i]}!', pred_sdf[i].max(), pred_sdf[i].min()) pred_sdf[i] -= (pred_sdf[i].min().detach() / 8 + pred_sdf[i].max().detach() * 7 / 8) 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 - # print("weight shape", weight.shape) - # Debug HOLD: SDF output - # vis = out.detach().cpu().numpy() - # print(pred_sdf.min(), pred_sdf.max(), (pred_sdf <= 0).sum(), (pred_sdf > 0).sum()) - - # valid = True - # for i in range(len(data['gt_verts'])): - # xyzs = data['triview_xyz'][i].permute(0,3,1,2) - # ma1 = 255 - # ma2 = 255 - # mb1 = 0 - # mb2 = 0 - # for j in range(6): - # a1,a2,b1,b2 = find_bounding_box(torch.mean(xyzs[j], dim = 0, keepdim=False)) - # ma1 = min(a1, ma1) - # ma2 = min(a2, ma2) - # mb1 = max(b1, mb1) - # mb2 = max(b2, mb2) - # # print(min(ma1, ma2), max(mb1, mb2)) - # if min(ma1, ma2) != 0 or max(mb1, mb2) != 255: - # valid = False - - # valid = True - - result, verts, faces = self.renderer(data, pred_sdf, deformation, verts, tets, training = self.training, weight = weight) - # if not valid: - # print("valid is false") - # result['silhouette_loss'] *= 0 - # result['depth_loss'] *= 0 - - sdf_pos = pred_sdf[pred_sdf>=0] - sdf_neg = pred_sdf[pred_sdf<0] - result["wzy_loss"] = (torch.abs(sdf_pos-1).sum() + torch.abs(sdf_neg+1).sum()) / (pred_sdf.shape[0]*pred_sdf.shape[1]) - - # if self.tex_sup_mode == "pcd-raw": - # dense_pcd_xyz = data['gt_pcd_query'] - # dense_pcd_rgb = data['gt_pcd_colors_query'] - # # print("raw texture supervision") - # dec_d_pcd = self.decoder(tri_fea_2, dense_pcd_xyz) - # pred_rgb = self.rgbMlp(dec_d_pcd) # torch.cat((dec_d_pcd, dense_pcd_xyz), dim=2) - # color_loss = self.l1_loss(pred_rgb, dense_pcd_rgb) + self.mse_loss(pred_rgb, dense_pcd_rgb) - - # elif self.tex_sup_mode == "pcd-nnb": - # dense_pcd_xyz = data['gt_pcd_query'] - # dense_pcd_rgb = data['gt_pcd_colors_query'] - # # print("nearest neighbor supervision") - # with torch.no_grad(): - # pc_list = [] - # for i in range(len(verts)): - # pred_points = kaolin.ops.mesh.sample_points(verts[i].unsqueeze(0), faces[i], dense_pcd_xyz.shape[1])[0][0] - # # print(pred_points.shape) - # pc_list.append(pred_points.unsqueeze(0)) - # pcs = torch.cat(pc_list, dim=0) - # # pcs += noise_scale * torch.randn(pcs.shape).to(pcs.get_device()) # pcs collected from model, no need to add noise - # pcs_color = find_nearest_points(pcs, dense_pcd_xyz, dense_pcd_rgb) - - # dec_d_pcd = self.decoder(tri_fea_2, pcs) - # pred_rgb = self.rgbMlp(dec_d_pcd) - # color_loss = self.l1_loss(pred_rgb, pcs_color) + self.mse_loss(pred_rgb, pcs_color) - - # if self.tex_sup_mode == 'blender': - # if self.mvdream==False and (self.sd_mode == "sds" or self.sd_mode == "vsd"): - # resolution = [512,512] - # else: + # 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.weight_mlp(grid_feat) + weight = weight * 0.1 + + result, verts, faces = self.renderer(data, pred_sdf, deformation, verts, tets, weight=weight) + + # sdf_pos = pred_sdf[pred_sdf>=0] + # sdf_neg = pred_sdf[pred_sdf<0] + # result["wzy_loss"] = (torch.abs(sdf_pos-1).sum() + torch.abs(sdf_neg+1).sum()) / (pred_sdf.shape[0]*pred_sdf.shape[1]) + resolution = data['resolution_img'] - gt_color = data['gt_render_imgs'] - result['gt_render_imgs'] = data['gt_render_imgs'] - # print(data["prompt"]) + color_gt = data['render_imgs'] + result['gt_render_imgs'] = data['render_imgs'] + img_list = [] - # if self.sd_mode == "sds" or self.sd_mode == "vsd": - # latents_list = [] - # latents_gt_list = [] - # img_list2 = [] - # if self.sd_mode == "vsd": - # latents_train_list = [] - # latents_train_gt_list = [] - # sds_bs = 4 + mvp_size = data['mvp'][0].shape[0] - for i in range(len(verts)): + for vert, face in zip(verts, faces): mvp = data['mvp'][i] - # print(mvp.shape, data['mvp'].shape) - # if self.sd_mode == "sds" or self.sd_mode == "vsd": - # azimuth = 90*random.random() - # elevation = 30*random.random() - # fov = 15+(60-15)*random.random() - # mvp2 = sds_scene_mv(sds_bs, azimuth, elevation, fov).to(data['mvp'][i].device) - # mvp = torch.cat([mvp, mvp2], dim = 0) - # # print(mvp.shape) - face = faces[i].int() + face = face.int() verts_clip = torch.bmm( - F.pad(verts[i], pad=(0, 1), mode='constant', value=1.0).unsqueeze(0).repeat(mvp.shape[0], 1, 1), + F.pad(vert, pad=(0, 1), mode='constant', value=1.0).unsqueeze(0).repeat(mvp.shape[0], 1, 1), mvp.permute(0, 2, 1)).float() # [B, N, 4] rast, rast_db = dr.rasterize(ctx, verts_clip, face, resolution) # print(verts.shape, faces.shape) - alpha, _ = dr.interpolate(torch.ones_like(verts[i][:, :1]).unsqueeze(0), rast, face) # [1, H, W, 1] - xyzs, _ = dr.interpolate(verts[i], rast, face) # [1, H, W, 3] + alpha, _ = dr.interpolate(torch.ones_like(vert[:, :1]).unsqueeze(0), rast, face) # [1, H, W, 1] + xyzs, _ = dr.interpolate(vert, rast, face) # [1, H, W, 3] # print(alpha.shape, xyzs.shape) xyzs = xyzs.view(-1, 3) mask = (alpha > 0).view(-1).detach() @@ -323,143 +191,74 @@ def forward(self, data, ctx, tnew=None): albedo = albedo.view(-1, resolution[0], resolution[1], 3) albedo[:mvp_size] = albedo[:mvp_size] - 1 albedo = albedo.view(-1, 3) - + + # print("4.0:{}".format(torch.cuda.memory_allocated(0))) + # print("4.0:{}".format(torch.cuda.memory_allocated(0))) if mask.any(): - # print(mask.sum()) - dec_d_pcd = self.decoder(tri_fea_2[i].unsqueeze(0), xyzs[mask].unsqueeze(0)) - # print("4.1:{}".format(torch.cuda.memory_allocated(0))) - masked_albedo = self.rgbMlp(dec_d_pcd) - # print("4.2:{}".format(torch.cuda.memory_allocated(0))) - # print(albedo.shape, masked_albedo.shape, mask.shape, albedo.shape) + dec_d_pcd = self.decoder(tri_output[i].unsqueeze(0), xyzs[mask].unsqueeze(0)) + masked_albedo = self.rgb_mlp(dec_d_pcd) albedo[mask] = masked_albedo.squeeze(0).float() - # print("4.3:{}".format(torch.cuda.memory_allocated(0))) + del masked_albedo albedo = albedo.view(-1, resolution[0], resolution[1], 3) albedo = (albedo * 0.5 + 0.5).clip(0, 1) - # print("4.4:{}".format(torch.cuda.memory_allocated(0))) - # if self.mvdream==False and (self.sd_mode == "sds" or self.sd_mode == "vsd"): - # img_tmp = torch.nn.functional.interpolate(albedo.permute(0,3,1,2)[:mvp_size], [256,256], mode="bilinear").permute(0,2,3,1) - # img_list.append(img_tmp) - # else: + img_list.append(albedo[:mvp_size]) - # if self.sd_mode == "sds" or self.sd_mode == "vsd": - # img_list2.append(albedo[mvp_size:]) - - # if self.sd_mode == "sds" or self.sd_mode == "vsd": - # # print(data["prompt"][i]) - # cur_prompt = data["prompt"][i] - - # latents = torch.nn.functional.interpolate(albedo.permute(0,3,1,2)[mvp_size:], [512,512] if self.mvdream == False else [256,256], mode="bilinear") - # latents = self.unet_sd.encode_imgs(latents) - # if self.mvdream == True: - # t = torch.randint(20, 980 + 1, [1], dtype=torch.long, device=latents.device) - # t = t.repeat(latents.shape[0]) - # else: - # t = torch.randint(20, 980 + 1, [latents.shape[0]], dtype=torch.long, device=latents.device) - # noise = torch.randn_like(latents) - # latents_noisy = self.unet_sd.scheduler.add_noise(latents, noise, t) - # with torch.no_grad() if self.jacobi == False else torch.enable_grad(): - # if self.mvdream == True: - # camera = get_camera(4, elevation, azimuth).to(latents.device) - # uncond = { - # "context": self.mv_model.get_learned_conditioning([""]*4).to(latents.device), - # "camera": camera, - # "num_frames": 4, - # } - # cond = { - # "context": self.mv_model.get_learned_conditioning([cur_prompt[0]]*4).to(latents.device), - # "camera": camera, - # "num_frames": 4, - # } - # noise_pred = self.mv_model.apply_model(latents_noisy, t, cond=uncond) - # noise_pred_cond = self.mv_model.apply_model(latents_noisy, t, cond=cond) - # else: - # noise_pred = self.unet_sd(latents_noisy, t, "") - # noise_pred_cond = self.unet_sd(latents_noisy, t, cur_prompt)# cur_prompt - # if self.sd_mode == "sds": - # if self.mvdream == True: - # noise_cfg = noise_pred + self.specs["Train"].get("sd_cfg", 50) * (noise_pred_cond - noise_pred) - # else: - # noise_cfg = noise_pred + self.specs["Train"].get("sd_cfg", 100) * (noise_pred_cond - noise_pred) - # elif self.sd_mode == "vsd": - # noise_pred_lora = self.unet_lora(latents_noisy, t, self.unet_sd.encode_prompt(latents_noisy, cur_prompt)).sample - # noise_cfg = noise_pred + self.specs["Train"].get("sd_cfg", 7.5) * (noise_pred_cond - noise_pred) + noise - noise_pred_lora - # alpha_prod_t = self.unet_sd.scheduler.alphas_cumprod.to(latents.device)[t].unsqueeze(-1).unsqueeze(-1).unsqueeze(-1) - # beta_prod_t = (1 - alpha_prod_t).to(latents.device) - # pred_original_sample = (latents_noisy - beta_prod_t ** (0.5) * noise_cfg) / alpha_prod_t ** (0.5) - # # cfg_rescale = True - # # if cfg_rescale == False: - # # pred_original_sample = (latents_noisy - beta_prod_t ** (0.5) * noise_cfg) / alpha_prod_t ** (0.5) - # # else: - # # pass - # latents_list.append(latents if self.jacobi == False else latents.detach())#*alpha_prod_t ** (0.25) - # latents_gt_list.append(pred_original_sample.detach() if self.jacobi == False else pred_original_sample)#*alpha_prod_t ** (0.25) - - # if self.sd_mode == "vsd": #Train LoRA - # t_lora = torch.randint(20, 980 + 1, [latents.shape[0]], dtype=torch.long, device=latents.device) - # noise_lora = torch.randn_like(latents) - # latents_noisy_lora = self.unet_sd.scheduler.add_noise(latents.detach(), noise_lora, t_lora) - # noise_pred_lora_train = self.unet_lora(latents_noisy_lora, t_lora, self.unet_sd.encode_prompt(latents_noisy, cur_prompt)).sample - # latents_train_list.append(noise_pred_lora_train) - # latents_train_gt_list.append(noise_lora) del albedo - # print("5:{}".format(torch.cuda.memory_allocated(0))) imgs = torch.stack(img_list, dim=0) result['albedo_list'] = imgs - # if self.sd_mode == "sds" or self.sd_mode == "vsd": - # imgs2 = torch.stack(img_list2, dim=0) - # result['albedo_list2'] = imgs2 - - # latents_imgs = torch.stack(latents_list, dim=0) - # latents_gt_imgs = torch.stack(latents_gt_list, dim=0) - # color_loss = 0.5 * self.mse_loss(latents_imgs, latents_gt_imgs) * self.specs["Train"]["sd_lambda"] #+ self.mse_loss(imgs, gt_color) - # if self.sd_mode == "vsd": - # latents_train_imgs = torch.stack(latents_train_list, dim=0) - # latents_train_gt_imgs = torch.stack(latents_train_gt_list, dim=0) - # color_loss = color_loss + self.mse_loss(latents_train_imgs, latents_train_gt_imgs) # Added but optimizing different params - # # color_loss = self.l1_loss(imgs, gt_color) + self.mse_loss(imgs, gt_color) + color_loss - # else: - # print(data['alpha_ctn'].min(),data['alpha_ctn'].max()) - color_loss = self.mse_loss(imgs, gt_color) # self.l1_loss(imgs, gt_color) + - # if not valid: - # color_loss *= 0 - # print("6:{}".format(torch.cuda.memory_allocated(0))) + + color_loss = self.mse_loss(imgs, color_gt) result.update({ - 'color_gt': gt_color + 'color_gt': color_gt }) result['color_loss'] = color_loss - result["reg_loss"] = torch.norm(tri_fea_1) + result["reg_loss"] = torch.norm(tri_input) - result["tri0"], result["tri1"], result["tri2"] = tri_fea_0, tri_fea_1, tri_fea_2 + result["tri_input"], result["tri_output"]= tri_input, tri_output return result, verts, faces - 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 + def decode(self, data, tri_output): + # 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) + dec_verts = self.decoder(tri_output, tet_verts) + out = self.sdf_mlp(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 + # 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.weight_mlp(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)) + # 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() + + @torch.no_grad() + def color_query(self, data, verts): + tri_input = self.small_fwd(data) + + tri_output = self.unet(tri_input) + + dec_verts = self.decoder(tri_output, verts) + colors = self.rgb_mlp(dec_verts) + return colors + @torch.no_grad() - def render_color_img(self, verts, faces, data, ctx, gt=False, mvp=None, idx = 0): + def render_color_img(self, verts, faces, data, ctx, mvp=None, idx=0): mvp = data['mvp'][idx] if mvp is None else mvp[0] res = data['resolution_img'] # print(mvp.shape, verts.shape, faces.shape, res) @@ -471,7 +270,7 @@ def render_color_img(self, verts, faces, data, ctx, gt=False, mvp=None, idx = 0) mvp.permute(0, 2, 1)).float() # [B, N, 4] # assert verts_clip.shape[0] > 0 and verts_clip.shape[1] > 0, print(verts_clip.shape, verts.shape) rast, _ = dr.rasterize(ctx, verts_clip, faces, res) - + # print(verts.shape, faces.shape) alpha, _ = dr.interpolate(torch.ones_like(verts[0][:, :1]).unsqueeze(0), rast, faces) # [1, H, W, 1] xyzs, _ = dr.interpolate(verts[0], rast, faces) # [1, H, W, 3] @@ -481,30 +280,9 @@ def render_color_img(self, verts, faces, data, ctx, gt=False, mvp=None, idx = 0) # do the lighting here since we have normal from mesh now. albedo = torch.zeros_like(xyzs, dtype=torch.float32) - 1 if mask.any(): - # if gt==False: - # if self.arch.tri_img: - _, triplane_feature1 = self.small_fwd(data) - # elif self.arch.tri_mix: - # triplane_feature0_a, triplane_feature1_a = self.small_fwd(data) - # pc = data['gt_pcd'][idx].unsqueeze(0) - # pc_colors = data['gt_pcd_colors'][idx].unsqueeze(0) - # triplane_feature0_b = self.encoder(pc, pc_colors) - # triplane_feature1_b = self.unet1(triplane_feature0_b) # unet1 moved to trdgen main class - # reso_ = triplane_feature0_a.shape[-2] - # triplane_feature0_b = torch.nn.functional.interpolate(triplane_feature0_b, size=(reso_, reso_ * 3), mode='bilinear') - # triplane_feature1_b = torch.nn.functional.interpolate(triplane_feature1_b, size=(reso_, reso_ * 3), mode='bilinear') - # triplane_feature0 = torch.cat([triplane_feature0_a,triplane_feature0_b],dim=1) - # triplane_feature1 = torch.cat([triplane_feature1_a,triplane_feature1_b],dim=1) - # else: - # pc = data['gt_pcd'][idx].unsqueeze(0) - # pc_colors = data['gt_pcd_colors'][idx].unsqueeze(0) - # triplane_feature0 = self.encoder(pc, pc_colors) - # triplane_feature1 = self.unet1(triplane_feature0) # unet1 moved to trdgen main class - # assert torch.isnan(triplane_feature1).sum() == 0, print("nan in tri") - triplane_feature2 = self.unet2(triplane_feature1) # unet2 moved to trdgen main class - masked_albedo = self.rgbMlp(self.decoder(triplane_feature2, xyzs[mask].unsqueeze(0))).squeeze(0) - # else: - # masked_albedo = find_nearest_points(xyzs[mask].unsqueeze(0), data['gt_pcd_query'][idx].unsqueeze(0), data['gt_pcd_colors_query'][idx].unsqueeze(0)).squeeze(0) + tri_input = self.small_fwd(data) + tri_output = self.unet(tri_input) # unet2 moved to trdgen main class + masked_albedo = self.rgb_mlp(self.decoder(tri_output, xyzs[mask].unsqueeze(0))).squeeze(0) albedo[mask] = masked_albedo.float() albedo = albedo.view(-1, alpha.shape[1], alpha.shape[2], 3) albedo = (albedo * 0.5 + 0.5).clip(0, 1) @@ -519,83 +297,79 @@ def render_color_img(self, verts, faces, data, ctx, gt=False, mvp=None, idx = 0) def visualize(self, result, epc, chunk, color_fine, rdr_img_dir, iter_all): # After each epoch, visualize and evaluate # epc: current index of epochs - normal = result['normal_image'][0].detach().cpu().numpy() - normal_gt = result['normal_gt'][0].detach().cpu().numpy() + normal = result['normal'][0].detach().cpu().numpy() + # normal_gt = result['normal_gt'][0].detach().cpu().numpy() alpha = (result['alpha'][0].detach().cpu().numpy() * 255).astype('uint8') alpha_gt = (result['alpha_gt'][0].detach().cpu().numpy() * 255).astype('uint8') - succ = True - try: - depth = trans_depth(result['depth']) - depth_gt = trans_depth(result['depth_gt']) - except: - succ = False + # succ = True + # try: + depth = trans_depth(result['depth']) + depth_gt = trans_depth(result['depth_gt']) + # except: + # succ = False color_fine = color_fine[..., [2, 1, 0]].detach().cpu().numpy() color_fine = cv2.resize(color_fine[0], alpha.shape[1:3])[None, ...] - # if result.get('color_gt') is None: - # # color_gt = color_gt[..., [2, 1, 0]].detach().cpu().numpy() - # color_fine_gt = color_fine_gt[..., [2, 1, 0]].detach().cpu().numpy() - # else: + color_fine_gt = result.get('color_gt')[0, ..., [2, 1, 0]].cpu().numpy() color_fine_gt = cv2.resize(color_fine_gt[0], alpha.shape[1:3])[None, ...] - if succ == True: - img = np.concatenate((alpha, alpha_gt, depth, depth_gt), axis=2) - else: - img = np.concatenate((alpha, alpha_gt, alpha, alpha_gt), axis=2) - if succ == True: - cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}.png", np.concatenate((normal[0], color_fine[0], color_fine_gt[0], cv2.applyColorMap(np.repeat(depth[0],3,axis=2).astype(np.uint8), cv2.COLORMAP_HOT)/255, cv2.applyColorMap(np.repeat(depth_gt[0],3,axis=2).astype(np.uint8), cv2.COLORMAP_HOT)/255), axis=1)*255) - else: - cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}.png", np.concatenate((normal[0], color_fine[0], color_fine_gt[0]), axis=1)*255) - - - tri0 = result['tri0'][0].mean(0).unsqueeze(-1) - tri0 = (tri0 - tri0.min()) / (tri0.max() - tri0.min()) - tri0 = tri0.detach().cpu().numpy() - tri0 = np.repeat(tri0, 3, axis=2) * 255 - - tri1 = result['tri1'][0].mean(0).unsqueeze(-1) - tri1 = (tri1 - tri1.min()) / (tri1.max() - tri1.min()) - tri1 = tri1.detach().cpu().numpy() - tri1 = np.repeat(tri1, 3, axis=2) * 255 - - tri2 = result['tri2'][0].mean(0).unsqueeze(-1) - tri2 = (tri2 - tri2.min()) / (tri2.max() - tri2.min()) - tri2 = tri2.detach().cpu().numpy() - tri2 = np.repeat(tri2, 3, axis=2) * 255 - - cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}-tri-mean.jpg", cv2.applyColorMap(np.concatenate((tri0, tri1, tri2), axis=0).astype(np.uint8), cv2.COLORMAP_JET)) + # if succ == True: + img = np.concatenate((alpha, alpha_gt, depth, depth_gt), axis=2) + # else: + # img = np.concatenate((alpha, alpha_gt, alpha, alpha_gt), axis=2) + # if succ == True: + cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}.png", + np.concatenate((normal[0], color_fine[0], color_fine_gt[0], + cv2.applyColorMap(np.repeat(depth[0],3,axis=2).astype(np.uint8), cv2.COLORMAP_HOT)/255, + cv2.applyColorMap(np.repeat(depth_gt[0],3,axis=2).astype(np.uint8), cv2.COLORMAP_HOT)/255), + axis=1)*255) + # else: + # cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}.png", + # np.concatenate((normal[0], color_fine[0], color_fine_gt[0]), axis=1)*255) - self.ticker += 1 + tri_input = result['tri_input'][0].mean(0).unsqueeze(-1) + tri_input = (tri_input - tri_input.min()) / (tri_input.max() - tri_input.min()) + tri_input = tri_input.detach().cpu().numpy() + tri_input = np.repeat(tri_input, 3, axis=2) * 255 + + tri_output = result['tri_output'][0].mean(0).unsqueeze(-1) + tri_output = (tri_output - tri_output.min()) / (tri_output.max() - tri_output.min()) + tri_output = tri_output.detach().cpu().numpy() + tri_output = np.repeat(tri_output, 3, axis=2) * 255 - i0 = self.ticker % result['tri0'][0].shape[0] - i1 = self.ticker % result['tri1'][0].shape[0] - i2 = self.ticker % result['tri2'][0].shape[0] + cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}-tri-mean.jpg", + cv2.applyColorMap(np.concatenate((tri_input, tri_output), axis=0).astype(np.uint8), cv2.COLORMAP_JET)) - tri0 = result['tri0'][0][i0].unsqueeze(-1) - tri0 = (tri0-tri0.min())/(tri0.max()-tri0.min()) - tri0 = tri0.detach().cpu().numpy() - tri0 = np.repeat(tri0, 3, axis=2) * 255 + self.ticker += 1 + + i = self.ticker % result['tri_input'][0].shape[0] + j = self.ticker % result['tri_output'][0].shape[0] - tri1 = result['tri1'][0][i1].unsqueeze(-1) - tri1 = (tri1-tri1.min())/(tri1.max()-tri1.min()) - tri1 = tri1.detach().cpu().numpy() - tri1 = np.repeat(tri1, 3, axis=2) * 255 + tri_input = result['tri_input'][0][i].unsqueeze(-1) + tri_input = (tri_input-tri_input.min())/(tri_input.max()-tri_input.min()) + tri_input = tri_input.detach().cpu().numpy() + tri_input = np.repeat(tri_input, 3, axis=2) * 255 - tri2 = result['tri2'][0][i2].unsqueeze(-1) - tri2 = (tri2-tri2.min())/(tri2.max()-tri2.min()) - tri2 = tri2.detach().cpu().numpy() - tri2 = np.repeat(tri2, 3, axis=2) * 255 + tri_output = result['tri_output'][0][j].unsqueeze(-1) + tri_output = (tri_output-tri_output.min())/(tri_output.max()-tri_output.min()) + tri_output = tri_output.detach().cpu().numpy() + tri_output = np.repeat(tri_output, 3, axis=2) * 255 - cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}-tri{i0}-{i1}-{i2}.jpg", cv2.applyColorMap(np.concatenate((tri0, tri1, tri2), axis=0).astype(np.uint8), cv2.COLORMAP_JET)) + cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}-tri{i}-{j}.jpg", + cv2.applyColorMap(np.concatenate((tri_input, tri_output), axis=0).astype(np.uint8), cv2.COLORMAP_JET)) return img - def export_mesh(self, data, out_dir, ind, device=None, tri_fea_2 = None): + def export_mesh(self, data, out_path, tri_fea=None): + '''Export mesh with vertice color for fast validation''' 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() + if tri_fea is None: + colors = self.color_query(data, verts).squeeze().detach().cpu().numpy() + else: + dec_verts = self.decoder(tri_fea, verts.unsqueeze(0)) + colors = self.rgb_mlp(dec_verts).squeeze().detach().cpu().numpy() # Expect predicted colors value range from [-1, 1] colors = (colors * 0.5 + 0.5).clip(0, 1) @@ -604,8 +378,9 @@ def export_mesh(self, data, out_dir, ind, device=None, tri_fea_2 = None): # 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') + # important, process=True leads to seg fault... + mesh = trimesh.Trimesh(verts, faces, vertex_colors=colors, process=False) + mesh.export(out_path + '.ply') def export_mesh_wt_uv(self, ctx, data, out_dir, ind, device, res, tri_fea_2=None): mesh_v = data['verts'].squeeze().cpu().numpy() @@ -708,4 +483,4 @@ def interpolate(attr, rast, attr_idx, rast_db=None): 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_path}.png', img[..., [2, 1, 0]]) diff --git a/train_crm.py b/train_crm.py index feb99e6..71760c5 100644 --- a/train_crm.py +++ b/train_crm.py @@ -1,64 +1,64 @@ +'''Main script training CRM''' import os import json import argparse import shutil -import kaolin import random +from itertools import cycle +from pathlib import Path +import time -import numpy as np +import kaolin import cv2 import trimesh import torch -from pathlib import Path -import time import nvdiffrast.torch as dr -from itertools import cycle +from accelerate import Accelerator from tqdm import tqdm +from torch.utils.tensorboard import SummaryWriter from model import CRM - from util.utils import lr_schedule, nan_to_num from util.loss import laplacian_smooth_loss from datasets.memory_dataset import MemoryDataset from datasets.fast_dataset import FastDataset from metric.shape import vol_intersect_over_union, chamfer_distance, chamfer_distance_l1, silhouette_mask_iou - -# from util.common import pcd_preprocess -from torch.utils.tensorboard import SummaryWriter -from accelerate import Accelerator -from util.utils import get_tri from metric.lpips.lpips import LPIPS -def train(specs, config_path): +def train(args): + if args.resume: + config_path = os.path.join(args.resume, args.config_name) + else: + config_path = os.path.join(args.exp_dir, args.config_name) + + with open(config_path, encoding='utf8') as f: + specs = json.load(f) + input_specs = specs['Input'] - task_mode = input_specs['task_mode'] - # scale = input_specs['scale'] - tet_grid_size = input_specs['tet_grid_size'] + # task_mode = input_specs['task_mode'] + # tet_grid_size = input_specs['tet_grid_size'] dataset_type = input_specs.get('dataset_type', None) train_specs = specs['Train'] num_epochs = train_specs['num_epochs'] - sup_mode = train_specs["mode"] + # sup_mode = train_specs['mode'] sample_points_num = train_specs['sample_points_num'] batch_size = train_specs['batch_size'] l_rate = train_specs['learning_rate']['init'] warmup_iter = train_specs['warm_up'] scheduler_decay = train_specs['decay'] eva_iter = train_specs['eva_iter'] - # xyz_noise_scale = train_specs.get('xyz_noise_scale', 0.0) - # init_mdl_path = train_specs.get('init_mdl_path', None) - # eva_all_epoch = train_specs.get('eva_all_epoch') - lambda_nc = train_specs.get('lambda_nc', 0) + # lambda_nc = train_specs.get('lambda_nc', 0) grad_acc = train_specs.get('grad_acc', 1) lambda_lp = train_specs.get('lambda_lp', 0) - lambda_wzy = train_specs.get('lambda_wzy', 0) + # lambda_wzy = train_specs.get('lambda_wzy', 0) save_chunk = train_specs.get('save_chunk') output_dirs = specs['Output'] exp_name = Path(output_dirs['exp_name']) - geo_type = specs["Train"].get("geo_type", "dmtet") + # geo_type = specs['Train'].get('geo_type', 'dmtet') if not exp_name.exists(): exp_name.mkdir(exist_ok=True) @@ -71,11 +71,11 @@ def train(specs, config_path): exp_dir.mkdir(exist_ok=True) shutil.copy(config_path, exp_dir) # - opt_rec_dir = exp_dir / "opt_rec" + opt_rec_dir = exp_dir / 'opt_rec' opt_rec_dir.mkdir(exist_ok=True) - cur_rec_dir = exp_dir / "cur_rec" + cur_rec_dir = exp_dir / 'cur_rec' cur_rec_dir.mkdir(exist_ok=True) - val_all_opt_rec_dir = exp_dir / "val_all_opt_rec" + val_all_opt_rec_dir = exp_dir / 'val_all_opt_rec' val_all_opt_rec_dir.mkdir(exist_ok=True) rdr_img_dir = exp_dir / 'rdr_img' rdr_img_dir.mkdir(exist_ok=True) @@ -109,28 +109,24 @@ def train(specs, config_path): iter_all = 0 # total number of passed training iterations accelerator = Accelerator() - # kwargs = DDPK(find_unused_parameters=True) - # accelerator = Accelerator(kwargs_handlers=[kwargs]) - # device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + device = accelerator.device # dataset glctx = dr.RasterizeCudaContext() - dataset, dataset_val_all = [None] * 2 + dataset = None if dataset_type == 'memory': - dataset = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode) + dataset = MemoryDataset(input_specs, train_specs, glctx, device) chunk_num = 1 elif dataset_type == 'filesystem': dataset = FastDataset(input_specs, train_specs, glctx, device, chunk, mode='all') chunk_num = dataset.num_chunk - dataset_val = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, - validate=True) - dataset_vis = MemoryDataset(input_specs, train_specs, glctx, tet_grid_size, device, task_mode=task_mode, - validate=True, visual=True) + dataset_val = MemoryDataset(input_specs, train_specs, glctx, device, validate=True) + dataset_vis = MemoryDataset(input_specs, train_specs, glctx, device, validate=True, visual=True) if accelerator.is_main_process: writer = SummaryWriter(str(exp_dir)) @@ -141,35 +137,16 @@ def train(specs, config_path): model = CRM(specs).to(device) optimizer = torch.optim.AdamW(model.parameters(), lr=l_rate)#(model.parameters(), lr=l_rate) - # DJ optimization schedule + # optimization schedule scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda x: lr_schedule(x, warmup_iter, scheduler_decay)) - # for timestamp in sorted(os.listdir(exp_name), reverse=True): - # if re.fullmatch('\d{1,2}_\d{1,2}-\d{1,2}_\d{1,2}_\d{1,2}_tet90', timestamp) \ - # and (Path(exp_name) / timestamp / 'val_all_opt_rec' / 'best_shape_params.pth').exists(): - # params = Path(exp_name) / timestamp / 'val_all_opt_rec' / 'best_shape_params.pth' - # print('load previous 90 tetrahedra checkpoint') - # model.load_state_dict(torch.load(params)) - - # for name, para in model.named_parameters(): - # if 'encoder' in name: - # para.requires_grad = False - - # input_specs['tet_grid_size'] = 128 - # tet_grid_size = input_specs['tet_grid_size'] - - # train_specs['batch_size'] //= 2 - # batch_size = train_specs['batch_size'] - - # break - if args.resume: model.load_state_dict(checkpoint['model_state_dict']) optimizer.load_state_dict(checkpoint['optim_state_dict']) scheduler.load_state_dict(checkpoint['scheduler_state_dict']) - lpips = LPIPS(net_type="vgg", device="cuda:" + str(accelerator.process_index)) + lpips = LPIPS(net_type='vgg', device='cuda:' + str(accelerator.process_index)) model, optimizer, scheduler, lpips = accelerator.prepare(model, optimizer, scheduler, lpips) @@ -189,20 +166,6 @@ def train(specs, config_path): chunk = tmp % chunk_num model.train() - # if chunk not in [39, 81, 136]: - # continue - - # if dataset_type == 'filesystem' and tmp % (chunk_num * eva_all_epoch) == 0 and tmp > 0: - # # try: - # all_cham_dist_opt, all_rgb_err_opt = eval_and_save( - # accelerator, writer, model, tet_verts, tet_indices, - # sample_points_num, iter_all, dataset_val_all, device, - # val_all_opt_rec_dir, cur_rec_dir, all_cham_dist_opt, all_rgb_err_opt, glctx, - # type='_all') - # # except Exception as e: - # # print(e) - # # print(f'\033[91mtest: 004 error occur\033[0m') - if (chunk % save_chunk == 0) and accelerator.is_main_process: torch.save({ 'epoch': epc, @@ -218,100 +181,69 @@ def train(specs, config_path): 'all_rgb_err_opt': all_rgb_err_opt, }, cur_rec_dir / 'previous_params.pth') - # accelerator.wait_for_everyone() - if dataset_type == 'filesystem': dataset.load_chunk() # skip empty chunk if len(dataset) == 0: continue - try: - dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, - collate_fn=dataset.collate, shuffle=True) - dataloader = accelerator.prepare(dataloader) - except: - continue - - # k = 0.1 - # alpha = train_specs['lambda_color'] * np.clip(k * (epc / num_epochs - 0.5) + 0.05, 0, 0.1) + # try: + dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, + collate_fn=dataset.collate, shuffle=True) + dataloader = accelerator.prepare(dataloader) + # except: + # continue - # pcd_tr = dataloader.pcd_tr for data in dataloader: - # gc.collect() model.train() - + # mvp = mvps[iter_all] + # pts = pcd_tr[:, itr * pt_b_size: (itr + 1) * pt_b_size].cuda() + # + # mvp = mvps[iter_all] # pts = pcd_tr[:, itr * pt_b_size: (itr + 1) * pt_b_size].cuda() # if accelerator.is_main_process: - print(f"Training@Epoch %i, Chunk %i, Itr %i" % (epc, chunk, iter_all), flush=True) + print(f'Training@Epoch {epc}, Chunk {chunk}, Itr {iter_all}', flush=True) - # print(data['uuid']) - # iter_all += 1 - # continue - # make data and tet sample size consistent - # tet_verts_batch = tet_verts.repeat(data['gt_pcd'].shape[0], 1, 1) result, verts, faces = model(data, glctx) lap_loss_list, chamfer_loss_list = [], [] - # try: - for i in range(len(verts)): - lap_loss_list.append(laplacian_smooth_loss(verts[i], faces[i])) - pred_points = kaolin.ops.mesh.sample_points(verts[i].unsqueeze(0), faces[i], sample_points_num)[0][0] - gt_points = kaolin.ops.mesh.sample_points(data['gt_verts'][i].unsqueeze(0), data['gt_faces'][i], sample_points_num)[0][0] - chamfer_loss_list.append(chamfer_distance(pred_points.unsqueeze(0), gt_points.unsqueeze(0)).mean()) # use dataloader; pcd_tr.cuda() + for vert, face, gt_vert, gt_face in zip(verts, faces, data['verts'], data['faces']): + lap_loss_list.append(laplacian_smooth_loss(vert, face)) + + pred_points = kaolin.ops.mesh.sample_points(vert.unsqueeze(0), face, sample_points_num)[0][0] + gt_points = kaolin.ops.mesh.sample_points(gt_vert.unsqueeze(0), gt_face, sample_points_num)[0][0] + chamfer_loss_list.append(chamfer_distance(pred_points.unsqueeze(0), gt_points.unsqueeze(0)).mean()) result['lap_loss'] = sum(lap_loss_list) / len(lap_loss_list) result['chamfer_loss'] = sum(chamfer_loss_list) / len(chamfer_loss_list) - if train_specs['tex_sup_mode'] == 'blender': - reso = result["albedo_list"].shape[-2] - lpips_train = result["albedo_list"].view(-1, result["albedo_list"].shape[-3], result["albedo_list"].shape[-2], result["albedo_list"].shape[-1]).permute(0,3,1,2) - lpips_gt = result["gt_render_imgs"].view(-1, result["gt_render_imgs"].shape[-3], result["gt_render_imgs"].shape[-2], result["gt_render_imgs"].shape[-1]).permute(0,3,1,2) - - if reso > 256: - startx = random.randint(0, reso-256-1) - starty = random.randint(0, reso-256-1) - lpips_train = lpips_train[:,:,startx:startx+256,starty:starty+256] - lpips_gt = lpips_gt[:,:,startx:startx+256,starty:starty+256] - - result['lpips_loss'] = lpips(lpips_train, lpips_gt) - - # ) - if sup_mode == "rnd": - # shape supervision I: rendered silhouette and depth losses - loss = result['silhouette_loss']+ result['depth_loss'] + specs['Train']['lambda_smooth'] * result['lap_loss'] \ - + train_specs['lambda_color'] * result['color_loss'] + train_specs['lambda_l2'] * result['reg_loss'] \ - + lambda_nc * result['nc_loss'] + lambda_lp *result['lpips_loss'] + lambda_wzy * result["wzy_loss"] - if geo_type == "flex": - loss = loss + result["flex_surf_loss"] * 0.5 * 0.0 + result["flex_weight_loss"] * 0.1 * 0.1 - # elif sup_mode == "pcd": - # # shape supervision II: Chamfer distance loss - # loss = result['chamfer_loss'] + specs['Train']['lambda_smooth'] * result['lap_loss'] - # else: - # raise ValueError("Error! Unrecognized supervision mode.") - - - # loss.backward() - # start = time.time() + # if train_specs['tex_sup_mode'] == 'blender': + reso = result['albedo_list'].shape[-2] + lpips_train = result['albedo_list'].view( + -1, result['albedo_list'].shape[-3], result['albedo_list'].shape[-2], result['albedo_list'].shape[-1] + ).permute(0,3,1,2) + lpips_gt = result['gt_render_imgs'].view( + -1, result['gt_render_imgs'].shape[-3], result['gt_render_imgs'].shape[-2], result['gt_render_imgs'].shape[-1] + ).permute(0,3,1,2) + + if reso > 256: + startx = random.randint(0, reso-256-1) + starty = random.randint(0, reso-256-1) + lpips_train = lpips_train[:,:,startx:startx+256,starty:starty+256] + lpips_gt = lpips_gt[:,:,startx:startx+256,starty:starty+256] + + result['lpips_loss'] = lpips(lpips_train, lpips_gt) + + # if sup_mode == 'rnd': + # shape supervision I: rendered silhouette and depth losses + loss = result['silhouette_loss']+ result['depth_loss'] + specs['Train']['lambda_smooth'] * result['lap_loss'] \ + + train_specs['lambda_color'] * result['color_loss'] + lambda_lp *result['lpips_loss'] \ + + result['flex_weight_loss'] * 0.1 * 0.1 + accelerator.backward(loss) - # print(f'backward: {time.time() - start}') - - # # 打印梯度大小 - # for name, param in model.named_parameters(): - # if param.grad is not None: - # print(f"iter {iter_all+1}, Layer {name}: Grad Max: {param.grad.data.max()}, Grad Min: {param.grad.data.min()}") - - # for name, param in model.named_parameters(): - # if param.grad is not None: - # if torch.isnan(param.grad).sum() > 0: - # print("nan", name, torch.isnan(param.grad).sum()) - # param.grad[torch.isnan(param.grad)] = 0 - # if torch.isinf(param.grad).sum() > 0: - # print("inf", name, torch.isinf(param.grad).sum()) - # param.grad[torch.isinf(param.grad)] = 0 params = [param for param in model.parameters() if param.grad is not None] if len(params) > 0: @@ -333,7 +265,10 @@ def train(specs, config_path): scheduler.step() # DJ optimization schedule torch.cuda.empty_cache() optimizer.zero_grad() - + + # normal = result['normal_image'][0].detach().cpu().numpy() + # cv2.imwrite(model.exp_dir.as_posix() + "/last_normal" +".png", normal*255) + # normal = result['normal_image'][0].detach().cpu().numpy() # cv2.imwrite(model.exp_dir.as_posix() + "/last_normal" +".png", normal*255) accelerator.wait_for_everyone() @@ -345,139 +280,67 @@ def train(specs, config_path): writer.add_scalar('train/color', result['color_loss'], iter_all) writer.add_scalar('train/lr', optimizer.param_groups[0]['lr'], iter_all) writer.add_scalar('train/lpips', result['lpips_loss'], iter_all) - writer.add_scalar('train/wzy', result['wzy_loss'], iter_all) - if geo_type == "flex": - writer.add_scalar('train/flex_weight', result['flex_weight_loss'], iter_all) - writer.add_scalar('train/flex_surf', result['flex_surf_loss'], iter_all) + # writer.add_scalar('train/wzy', result['wzy_loss'], iter_all) + # if geo_type == 'flex': + writer.add_scalar('train/flex_weight', result['flex_weight_loss'], iter_all) + writer.add_scalar('train/flex_surf', result['flex_surf_loss'], iter_all) # perform evaluation every eva_iter iteration - if iter_all % eva_iter == 0 or (iter_all < 500 and iter_all%20 ==0): - if accelerator.is_main_process and train_specs['tex_sup_mode'] == 'blender': + if iter_all % eva_iter == 0 or (iter_all < 500 and iter_all % 20 ==0): + if accelerator.is_main_process: train_img_dir = exp_dir / 'train_img' train_img_dir.mkdir(exist_ok=True) - try: - albedos = result["albedo_list2"][0] - except: - albedos = result["albedo_list"][0] + # try: + # albedos = result['albedo_list2'][0] + # except: + albedos = result['albedo_list'][0] albedo_tensor = torch.cat((albedos[0], albedos[1], albedos[2], albedos[3]), dim=1) albedo_tensor = albedo_tensor[..., [2, 1, 0]].detach().cpu().numpy() - cv2.imwrite(exp_dir.as_posix() + f"/train_img/ep{epc}-chunk{chunk}-iter{iter_all}-train-" - f"{accelerator.process_index}-" - f"{data.get('prompt',[['null']])[0][0].replace(' ', '-')}.jpg", + cv2.imwrite(exp_dir.as_posix() + f'/train_img/ep{epc}-chunk{chunk}-iter{iter_all}-train-' + f'{accelerator.process_index}-' + f'{data.get("prompt",[["null"]])[0][0].replace(" ", "-")}.jpg', albedo_tensor * 255) - # if accelerator.is_main_process: - # print(accelerator.process_index, data['prompt'], data['uuid']) + model.eval() - # try: - cham_dist_opt, rgb_err_opt = eval_and_save(accelerator, writer, model, + + cham_dist_opt, rgb_err_opt = eval_and_save(accelerator, writer, model, sample_points_num, iter_all, dataset_val, device, - opt_rec_dir, cur_rec_dir, cham_dist_opt, rgb_err_opt, glctx + opt_rec_dir, cham_dist_opt, rgb_err_opt, glctx ) - # except: - # print("eval failed, continue to train") - - # except Exception as e: - # print(e) - # print(f'\033[91mvalidation: 004 error occur\033[0m') - # try: if accelerator.is_main_process: # visualize data_vis = next(dataloader_vis) - if task_mode != 'debug': - print(data_vis['uuid'],data_vis.get('prompt')) - # print(data_vis['triview_color'].shape) - # print(data_vis['triview_xyz'].shape) - # try: - tnew_list = [0,100,200,300,400,500,600,700,800,900,999] + # if task_mode != 'debug': + print(data_vis['uuid'],data_vis.get('prompt')) + + # tnew_list = [0,100,200,300,400,500,600,700,800,900,999] with torch.no_grad(): - result, verts, faces = accelerator.unwrap_model(model)(data_vis, glctx, tnew=tnew_list[(iter_all//eva_iter)%len(tnew_list)]) + result, verts, faces = accelerator.unwrap_model(model)(data_vis, glctx) color_fine, _ = accelerator.unwrap_model(model).render_color_img(verts[0].unsqueeze(dim=0), faces[0], data_vis, glctx) - # color_fine_gt, _ = accelerator.unwrap_model(model).render_color_img(verts[0].unsqueeze(dim=0), faces[0], - # data_vis, glctx, gt=True) - # color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], - # data_vis, glctx, gt=True) - # color_shape_gt2 = color_shape_gt[..., [2, 1, 0]].detach().cpu().numpy() - # xyzs2 = xyzs[..., [2, 1, 0]].detach().cpu().numpy() - # cv2.imwrite(exp_dir.as_posix() + f"/ep{epc}-chunk{chunk}-rotate.jpg", np.concatenate((xyzs2[0], color_shape_gt2[0]), axis=1)*255) - - # color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], - # data_vis, glctx, gt=True, mvp = side_scene_()[None,...].to(device)) - - # color_shape_gt[2] = color_shape_gt[2].flip(0) - # color_shape_gt[5] = color_shape_gt[5].flip(0) - # color_tensor1 = torch.cat((color_shape_gt[0], color_shape_gt[1], color_shape_gt[2]), dim=1) - # color_tensor2 = torch.cat((color_shape_gt[3], color_shape_gt[4], color_shape_gt[5]), dim=1) - # color_tensor = torch.cat((color_tensor1, color_tensor2.flip(0)), dim = 0) - # color_tensor = color_tensor[..., [2, 1, 0]].detach().cpu().numpy() - - # xyzs[2] = xyzs[2].flip(0) - # xyzs[5] = xyzs[5].flip(0) - # xyzs_tensor1 = torch.cat((xyzs[0], xyzs[1], xyzs[2]), dim=1) - # xyzs_tensor2 = torch.cat((xyzs[3], xyzs[4], xyzs[5]), dim=1) - # xyzs_tensor = torch.cat((xyzs_tensor1, xyzs_tensor2.flip(0)), dim = 0) - # xyzs_tensor = xyzs_tensor.detach().cpu().numpy() - - # tri_img_dir = exp_dir / 'tri_img' - # tri_img_dir.mkdir(exist_ok=True) - # # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-color.jpg",color_tensor * 255) - # # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-xyz.jpg",xyzs_tensor * 255) - # if specs["Train"].get("random_bg", False): - # color = data_vis['triview_color'][0].permute(0,3,1,2).clone() - # xyzs = data_vis['triview_xyz'][0].permute(0,3,1,2).clone() - # crgb = random.random() - # cxyz = random.random() - # for j in range(6): - # mask = torch.mean(xyzs[j], dim = 0, keepdim=False) - # mask = (mask == 0) - # for k in range(3): - # color[j][k][mask] = crgb - # xyzs[j][k][mask] = cxyz - - # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-color-gt.jpg",get_tri(color, blender= True if specs["Train"].get("tex_sup_mode", "pcd-nnb") == 'blender' else False, c=crgb).permute(1,2,0)[..., [2, 1, 0]].detach().cpu().numpy() * 255) - # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-side-xyz-gt.jpg",get_tri(xyzs, blender= True if specs["Train"].get("tex_sup_mode", "pcd-nnb") == 'blender' else False, c=cxyz).permute(1,2,0).detach().cpu().numpy() * 255) - - # color_shape_gt, xyzs = accelerator.unwrap_model(model).render_color_img(data_vis['gt_verts'][0].unsqueeze(dim=0), data_vis['gt_faces'][0], - # data_vis, glctx, mvp = sds_scene(6)[None,...].to(device)) - # color_tensor1 = torch.cat((color_shape_gt[0], color_shape_gt[1], color_shape_gt[2]), dim=1) - # color_tensor2 = torch.cat((color_shape_gt[3], color_shape_gt[4], color_shape_gt[5]), dim=1) - # color_tensor = torch.cat((color_tensor1, color_tensor2), dim = 0) - # color_tensor = color_tensor[..., [2, 1, 0]].detach().cpu().numpy() - - # xyzs_tensor1 = torch.cat((xyzs[0], xyzs[1], xyzs[2]), dim=1) - # xyzs_tensor2 = torch.cat((xyzs[3], xyzs[4], xyzs[5]), dim=1) - # xyzs_tensor = torch.cat((xyzs_tensor1, xyzs_tensor2), dim = 0) - # xyzs_tensor = xyzs_tensor.detach().cpu().numpy() - - - # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-sds-color.jpg",color_tensor * 255) - # cv2.imwrite(exp_dir.as_posix() + f"/tri_img/ep{epc}-chunk{chunk}-iter{iter_all}-sds-xyz.jpg",xyzs_tensor * 255) img = accelerator.unwrap_model(model).visualize(result, epc, chunk, color_fine, rdr_img_dir, iter_all) # only show the first validation mesh writer.add_image('eval/visual', img[0], iter_all, dataformats='HWC') - # except Exception as e: - # print(e) - # print(f'\033[91mvisual: 004 error occur\033[0m') - # except: - # print("vis failed") + accelerator.wait_for_everyone() iter_all += 1 - return# model + return def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, dataset, device, - opt_rec_dir, cur_rec_dir, cham_dist_opt, rgb_err_opt, glctx, type=''): + opt_rec_dir, cham_dist_opt, rgb_err_opt, glctx): if isinstance(dataset, FastDataset): num_chunk = dataset.num_chunk else: num_chunk = 1 - chamfer_dist_all, vol_IoU_all, lap_loss_all, verts_list_all, faces_list_all, gt_verts_list_all, gt_faces_list_all= [], [], [], [], [], [], [] + chamfer_dist_all, vol_iou_all, lap_loss_all, verts_list_all, faces_list_all = [], [], [], [], [] + gt_verts_list_all, gt_faces_list_all= [], [] chamfer_l1_all, mask_iou_all, color_loss_all, depth_loss_all, silhouette_loss_all = [], [], [], [], [] triview_color_list_all, triview_xyz_list_all = [], [] @@ -493,59 +356,52 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas dataloader = accelerator.prepare(dataloader) - # val_len = len(dataloader_val) for data_val in tqdm(dataloader): - chamfer_dist, vol_IoU, lap_loss, verts_list, faces_list, gt_verts_list, gt_faces_list = [], [], [], [], [], [], [] + chamfer_dist, vol_iou, lap_loss, verts_list, faces_list, gt_verts_list, gt_faces_list = [], [], [], [], [], [], [] chamfer_l1, mask_iou, color_loss, depth_loss, silhouette_loss = [], [], [], [], [] triview_color_list, triview_xyz_list = [], [] with torch.no_grad(): result, verts, faces = accelerator.unwrap_model(model)(data_val, glctx) torch.cuda.empty_cache() - # result = dict((key, value.detach().cpu()) for key, value in result.items()) - # verts = tuple(ele.detach().cpu() for ele in verts) - # faces = tuple(ele.detach().cpu() for ele in faces) - # data_val = dict((key, [torch.tensor(ele).detach().cpu() for ele in value] if isinstance(value, list) else value. - # detach().cpu()) for key, value in data_val.items()) - - for i in range(len(verts)): - pred_points = kaolin.ops.mesh.sample_points(verts[i].unsqueeze(0), faces[i], sample_points_num)[0][0] - gt_points = kaolin.ops.mesh.sample_points(data_val['gt_verts'][i].unsqueeze(0), data_val['gt_faces'][i], sample_points_num)[0][0] + + for vert, face, alpha, gt_vert, gt_face, gt_alpha in zip( + verts, faces, result['alpha'], data_val['verts'], data_val['faces'], result['alpha_gt'] + ): + pred_points = kaolin.ops.mesh.sample_points(vert.unsqueeze(0), face, sample_points_num)[0][0] + gt_points = kaolin.ops.mesh.sample_points(gt_vert.unsqueeze(0), gt_face, sample_points_num)[0][0] chamfer_dist.append( chamfer_distance( pred_points.unsqueeze(0), gt_points.unsqueeze(0)).detach().cpu().numpy()) # use dataloader - vol_IoU.append(vol_intersect_over_union(verts[i].unsqueeze(dim=0), - faces[i].type(torch.LongTensor), - data_val['gt_verts'][i].unsqueeze(dim=0), - data_val['gt_faces'][i], device=device).detach().cpu().numpy()) - lap_loss.append(laplacian_smooth_loss(verts[i], faces[i]).detach().cpu().numpy()) + vol_iou.append(vol_intersect_over_union(vert.unsqueeze(dim=0), + face.type(torch.LongTensor), + gt_vert.unsqueeze(dim=0), + gt_face, device=device).detach().cpu().numpy()) + lap_loss.append(laplacian_smooth_loss(vert, face).detach().cpu().numpy()) chamfer_l1.append( chamfer_distance_l1(pred_points, gt_points, device=device).detach().cpu().numpy()) - mask_iou.append(silhouette_mask_iou(result['alpha'][i], result['alpha_gt'][i]).detach().cpu().numpy()) + mask_iou.append(silhouette_mask_iou(alpha, gt_alpha).detach().cpu().numpy()) color_loss.append(result['color_loss'].detach().cpu().numpy()) depth_loss.append(result['depth_loss'].detach().cpu().numpy()) silhouette_loss.append(result['silhouette_loss'].detach().cpu().numpy()) - # for multiprocess metric gather - verts_list.append(verts[i].detach().cpu().numpy()) - faces_list.append(faces[i].detach().cpu().numpy()) - gt_verts_list.append(data_val['gt_verts'][i].cpu().numpy()) - gt_faces_list.append(data_val['gt_faces'][i].cpu().numpy()) - # pc_list.append(data_val['gt_pcd'].cpu().numpy()) - # pc_colors_list.append(data_val['gt_pcd_colors'].cpu().numpy()) - - if data_val.get('triview_color') is None: - triview_color_list.append(np.nan) - else: - triview_color_list.append(data_val['triview_color'].cpu().numpy()) - - if data_val.get('triview_xyz') is None: - triview_xyz_list.append(np.nan) - else: - triview_xyz_list.append(data_val['triview_xyz'].cpu().numpy()) + verts_list.append(vert.detach().cpu().numpy()) + faces_list.append(face.detach().cpu().numpy()) + gt_verts_list.append(gt_vert.cpu().numpy()) + gt_faces_list.append(gt_face.cpu().numpy()) + + # if data_val.get('triview_color') is None: + # triview_color_list.append(np.nan) + # else: + triview_color_list.append(data_val['triview_color'].cpu().numpy()) + + # if data_val.get('triview_xyz') is None: + # triview_xyz_list.append(np.nan) + # else: + triview_xyz_list.append(data_val['triview_xyz'].cpu().numpy()) chamfer_dist = accelerator.gather_for_metrics(chamfer_dist) - vol_IoU = accelerator.gather_for_metrics(vol_IoU) + vol_iou = accelerator.gather_for_metrics(vol_iou) lap_loss = accelerator.gather_for_metrics(lap_loss) mask_iou = accelerator.gather_for_metrics(mask_iou) chamfer_l1 = accelerator.gather_for_metrics(chamfer_l1) @@ -553,8 +409,6 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas depth_loss = accelerator.gather_for_metrics(depth_loss) silhouette_loss = accelerator.gather_for_metrics(silhouette_loss) - # pc_list = accelerator.gather_for_metrics(pc_list) - # pc_colors_list = accelerator.gather_for_metrics(pc_colors_list) verts_list = accelerator.gather_for_metrics(verts_list) faces_list = accelerator.gather_for_metrics(faces_list) gt_verts_list = accelerator.gather_for_metrics(gt_verts_list) @@ -566,7 +420,7 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas torch.cuda.empty_cache() chamfer_dist_all.extend(chamfer_dist) - vol_IoU_all.extend(vol_IoU) + vol_iou_all.extend(vol_iou) lap_loss_all.extend(lap_loss) mask_iou_all.extend(mask_iou) chamfer_l1_all.extend(chamfer_l1) @@ -574,8 +428,6 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas depth_loss_all.extend(depth_loss) silhouette_loss_all.extend(silhouette_loss) - # pc_list_all.extend(pc_list) - # pc_colors_list_all.extend(pc_colors_list) verts_list_all.extend(verts_list) faces_list_all.extend(faces_list) gt_verts_list_all.extend(gt_verts_list) @@ -585,7 +437,7 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas triview_xyz_list_all.extend(triview_xyz_list) chamfer_dist = chamfer_dist_all - vol_IoU = vol_IoU_all + vol_iou = vol_iou_all lap_loss = lap_loss_all mask_iou = mask_iou_all chamfer_l1 = chamfer_l1_all @@ -593,8 +445,6 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas depth_loss = depth_loss_all silhouette_loss = silhouette_loss_all - # pc_list = pc_list_all - # pc_colors_list = pc_colors_list_all verts_list = verts_list_all faces_list = faces_list_all gt_verts_list = gt_verts_list_all @@ -605,7 +455,7 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas metric = { 'chamfer_dist': sum(chamfer_dist) / len(chamfer_dist), - 'vol_IoU': sum(vol_IoU) / len(vol_IoU), + 'vol_iou': sum(vol_iou) / len(vol_iou), 'lap_loss': sum(lap_loss) / len(lap_loss), 'Mask_IoU': sum(mask_iou) / len(mask_iou), 'Chamfer_L1': sum(chamfer_l1) / len(chamfer_l1), @@ -615,25 +465,22 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas } if accelerator.is_main_process: - writer.add_scalar(f'eval{type}/Chamfer', metric['chamfer_dist'], iter_all) - writer.add_scalar(f'eval{type}/vol_IoU', metric['vol_IoU'], iter_all) - writer.add_scalar(f'eval{type}/smooth', metric['lap_loss'], iter_all) - writer.add_scalar(f'eval{type}/Chamfer-L1', metric['Chamfer_L1'], iter_all) - writer.add_scalar(f'eval{type}/Mask-IoU', metric['Mask_IoU'], iter_all) - writer.add_scalar(f'eval{type}/color', metric['color_loss'], iter_all) - writer.add_scalar(f'eval{type}/depth', metric['depth_loss'], iter_all) - writer.add_scalar(f'eval{type}/silhouette', metric['silhouette_loss'], iter_all) - - print('ITER %i: C2-Dist, %f (%f); RGB Err, %f (%f); C1-Dist, %f; Mask_IoU, %f; DL, %f; Silh, %f' % - (iter_all, metric['chamfer_dist'], cham_dist_opt, metric['color_loss'], rgb_err_opt, - metric['Chamfer_L1'], metric['Mask_IoU'], metric['depth_loss'], metric['silhouette_loss']), flush=True) + writer.add_scalar('eval/Chamfer', metric['chamfer_dist'], iter_all) + writer.add_scalar('eval/vol_iou', metric['vol_iou'], iter_all) + writer.add_scalar('eval/smooth', metric['lap_loss'], iter_all) + writer.add_scalar('eval/Chamfer-L1', metric['Chamfer_L1'], iter_all) + writer.add_scalar('eval/Mask-IoU', metric['Mask_IoU'], iter_all) + writer.add_scalar('eval/color', metric['color_loss'], iter_all) + writer.add_scalar('eval/depth', metric['depth_loss'], iter_all) + writer.add_scalar('eval/silhouette', metric['silhouette_loss'], iter_all) + + print(f'ITER {iter_all}: C2-Dist, {metric["chamfer_dist"]:f} ({cham_dist_opt:f}); ' + f'RGB Err, {rgb_err_opt:f} ({rgb_err_opt:f}); C1-Dist, {metric["Chamfer_L1"]:f}; ' + f'Mask_IoU, {metric["Mask_IoU"]:f}; DL, {metric["depth_loss"]:f}; ' + f'Silh, {metric["silhouette_loss"]:f}' , flush=True) accelerator.wait_for_everyone() - # img = model.visualize(result, epc, chunk) - # # only show the first validation mesh - # writer.add_image('eval/visual', img[0], iter_all, dataformats='HWC') - zip_data = [(verts, faces, gt_verts, gt_faces, triview_color, triview_xyz) for verts, faces, gt_verts, gt_faces, triview_color, triview_xyz in zip(verts_list, faces_list, gt_verts_list, gt_faces_list, triview_color_list, triview_xyz_list)] @@ -646,9 +493,9 @@ def save_export(mode): shutil.move(opt_rec_dir / f'best_{mode}_params.pth', opt_rec_dir / f'2nd_{mode}_params.pth') torch.save(accelerator.unwrap_model(model).state_dict(), opt_rec_dir / f'best_{mode}_params.pth') - # export mesh ( only eval_all ) - if type != '_all' or specs['ArchSpecs']['pc_enc'] == 'mix': - return + # # export mesh ( only eval_all ) + # if type != '_all' or specs['ArchSpecs']['pc_enc'] == 'mix': + # return with accelerator.split_between_processes(zip_data) as tmp_data: for j, ele in enumerate(tmp_data): @@ -658,26 +505,17 @@ def save_export(mode): if not os.path.exists(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_mesh.ply')): mesh = trimesh.Trimesh(vertices=gt_verts, faces=gt_faces) mesh.export(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_mesh.ply')) - # if not os.path.exists(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_pcd.ply')): - # pcd = trimesh.PointCloud(vertices=pc[0], colors=pc_colors[0]) - # pcd.export(os.path.join(opt_rec_dir, f'{gpu_idx}_{j}_pcd.ply')) # export pred data = { 'gt_verts': torch.tensor(gt_verts, device=device).unsqueeze(0), - # 'gt_pcd': torch.tensor(pc, device=device), - # 'gt_pcd_color': torch.tensor(pc_colors, device=device), 'verts': torch.tensor(verts, device=device).unsqueeze(0), 'faces': torch.tensor(faces, device=device).unsqueeze(0), 'triview_color': torch.tensor(triview_color, device=device), 'triview_xyz': torch.tensor(triview_xyz, device=device), } - if accelerator.unwrap_model(model).exp_uv_mesh: - accelerator.unwrap_model(model).export_mesh_wt_uv(glctx, data, opt_rec_dir, - f'{gpu_idx}_{j}_{mode}', device) - else: - accelerator.unwrap_model(model).export_mesh(data, opt_rec_dir, - f'{gpu_idx}_{j}_{mode}', device) + + accelerator.unwrap_model(model).export_mesh(data, f'{opt_rec_dir}/{gpu_idx}_{j}_{mode}') # shpae model selection: save current best one if metric['chamfer_dist'] < cham_dist_opt: @@ -689,56 +527,32 @@ def save_export(mode): save_export('texture') rgb_err_opt = metric['color_loss'] - - # # for debug purpose, also save current model/performance - # torch.save(accelerator.unwrap_model(model).state_dict(), cur_rec_dir / 'cur_params.pth') - # for i in range(len(verts_list)): - # accelerator.unwrap_model(model).export_mesh(pc_list[i], pc_colors_list[i], - # verts_list[i][None,], faces_list[i], cur_rec_dir, i) - # print out major learning/validation information - return cham_dist_opt, rgb_err_opt -if __name__ == "__main__": +if __name__ == '__main__': arg_parser = argparse.ArgumentParser() arg_parser.add_argument( - "--exp_dir", "-e", - default="configs/", - help="This directory should include experiment specifications in 'specs.json,' and logging will be done in this directory as well.", + '--exp_dir', '-e', + default='configs/', + help='This directory should include experiment specifications in "specs.json"', ) arg_parser.add_argument( - "--config_name", "-c", - default="specs_clear.json", - help="config filename", + '--config_name', '-c', + default='specs_clear.json', + help='config filename', ) arg_parser.add_argument( - "--note", "-n", - default="", - help="extra file name added to the output dir", + '--note', '-n', + default='', + help='extra file name added to the output dir', ) arg_parser.add_argument( - "--resume", + '--resume', default=None, - help="resume training from given checkpoint", + help='resume training from given checkpoint', ) - # arg_parser.add_argument( - # "--file", "-f", - # required=True, - # help="input point cloud filepath, in csv or ply format", - # ) - # arg_parser.add_argument( - # "--outdir", "-o", - # required=True, - # help="output directory of reconstruction", - # ) - # - args = arg_parser.parse_args() - if args.resume: - config_path = os.path.join(args.resume, args.config_name) - else: - config_path = os.path.join(args.exp_dir, args.config_name) - specs = json.load(open(config_path)) + arguments = arg_parser.parse_args() # torch.cuda.set_device(1) - # os.environ["CUDA_LAUNCH_BLOCKING"] = "1" - train(specs, config_path) + # os.environ['CUDA_LAUNCH_BLOCKING'] = '1' + train(arguments) diff --git a/util/loss.py b/util/loss.py index 089e705..9dfd225 100644 --- a/util/loss.py +++ b/util/loss.py @@ -1,11 +1,12 @@ +''' +Training loss +''' import torch import kaolin def laplacian_uniform(verts, faces): - V = verts.shape[0] - F = faces.shape[0] # Neighbor indices ii = faces[:, [1, 2, 0]].contiguous().flatten() @@ -23,11 +24,6 @@ def laplacian_uniform(verts, faces): # The coalesce operation sums the duplicate indices, resulting in the correct diagonal L = torch.sparse_coo_tensor(idx, values, (V, V)).coalesce() - # CYF Note: added for genuine Laplacian loss computation - # cor_idx = torch.asarray(range(V), device=verts.device) - # cor_idx = torch.stack((cor_idx, cor_idx), dim=0) - # cor_val = torch.asarray([1./L[i, i] for i in range(V)], device=verts.device, dtype=torch.float) - # cor_mat = torch.sparse_coo_tensor(cor_idx, cor_val, (V, V)) cor_idx = torch.stack((diag_idx, diag_idx), dim=0) cor_mat_ = torch.sparse_coo_tensor(cor_idx, adj_values, (V, V)).coalesce() cor_mat = torch.sparse_coo_tensor(cor_mat_.indices(), 1. / cor_mat_.values(), (V, V)) @@ -80,7 +76,6 @@ def compute_edge_to_face_mapping(attr_idx): @torch.cuda.amp.autocast(enabled=False) def normal_consistency(face_normals, t_pos_idx): - tris_per_edge = compute_edge_to_face_mapping(t_pos_idx) # Fetch normals for both faces sharind an edge @@ -89,7 +84,7 @@ def normal_consistency(face_normals, t_pos_idx): # Compute error metric based on normal difference term = torch.clamp(torch.sum(n0 * n1, -1, keepdim=True), min=-1.0, max=1.0) - term = (1.0 - term) + term = 1.0 - term return torch.mean(torch.abs(term)) diff --git a/util/renderer.py b/util/renderer.py index 76d9ee6..2765d95 100644 --- a/util/renderer.py +++ b/util/renderer.py @@ -1,112 +1,101 @@ - +''' +Transfer sdf -> mesh -> alpha, depth, color_image, normal +''' import torch -import torch.nn as nn -import torch.nn.functional as F +from torch import nn +from torch.nn import functional as F import nvdiffrast.torch as dr from util.utils import safe_normalize -from util.loss import normal_consistency from util.flexicubes_geometry import FlexiCubesGeometry class Renderer(nn.Module): - def __init__(self, tet_grid_size, camera_angle_num, scale, geo_type): + '''Render class''' + def __init__(self, tet_grid_size, camera_angle_num, scale): 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.geo_type = geo_type self.glctx = dr.RasterizeCudaContext() self.l1_loss = nn.L1Loss() self.mse_loss = nn.MSELoss() - if self.geo_type == "flex": - self.flexicubes = FlexiCubesGeometry(grid_res = self.tet_grid_size) + # 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): - mvp = data['mvp'] - campos = data['campos'] + '''Render main function''' + mvps = data['mvp'] + # campos = data['campos'] h, w = data['resolution'] persp = data['persp'] 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 - - alpha_list, alpha_ctn_list, depth_list, norm_list, nc_list = [], [], [], [], [] - for i in range(len(verts)): - alpha, alpha_ctn, depth, normal, face_normals = \ - render_mesh(self.glctx, verts[i], faces[i], mvp[i], campos[i], persp, resolution=(h, w)) + faces = None + deform = torch.tanh(deform) / self.tet_grid_size + # 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 + + alpha_list, depth_list, norm_list = [], [], [] + for vert, face, mvp in zip(verts, faces, mvps): + alpha, depth, normal = render_mesh(self.glctx, vert, face, mvp, persp, resolution=(h, w)) alpha_list.append(alpha) - alpha_ctn_list.append(alpha_ctn) + # alpha_ctn_list.append(alpha_ctn) depth_list.append(depth) norm_list.append(normal) - nc_list.append(normal_consistency(face_normals, faces[i])) + # nc_list.append(normal_consistency(face_normals, faces[i])) alpha = torch.stack(alpha_list, dim=0) - alpha_ctn = torch.stack(alpha_ctn_list, dim=0) + # alpha_ctn = torch.stack(alpha_ctn_list, dim=0) depth = torch.stack(depth_list, dim=0) normal = torch.stack(norm_list, dim=0) - results['nc_loss'] = torch.stack(nc_list, dim=0).mean() + # results['nc_loss'] = torch.stack(nc_list, dim=0).mean() results['alpha'] = alpha - results['alpha_ctn'] = alpha_ctn + # results['alpha_ctn'] = alpha_ctn results['depth'] = depth - results['normal_image'] = (normal + 1) / 2 - - # results['normal_loss'] = normal_consistency(face_normals, faces) - try:# TODO remove these lines - results['alpha_gt'] = data['alpha'] - results['alpha_ctn_gt'] = data['alpha_ctn'] - results['depth_gt'] = data['depth'] - # results['image'] = color - # results['weights_sum'] = alpha.squeeze(-1) - - # # if self.opt.lambda_2d_normal_smooth > 0 or self.opt.lambda_normal > 0: - # normal_image = dr.antialias((normal + 1) / 2, rast, verts_clip, faces).clamp(0, 1) # [B, H, W, 3] - # results['normal_image'] = normal_image - results['normal_gt'] = (data['normal'] + 1) / 2 - # regularizations - # if self.training: - - # print(results['alpha_ctn_gt'].shape, results['depth'].shape) - results['silhouette_loss'] = self.mse_loss(results['alpha_ctn'], results['alpha_ctn_gt']) - # results['depth_loss'] = self.l1_loss(results['depth'], results['depth_gt']) - results['depth_loss'] = self.mse_loss(results['depth'] * results['alpha_ctn_gt'].clone().detach(), results['depth_gt']) - except: - pass + results['normal'] = (normal + 1) / 2 - return results, verts, faces + # try:# remove these lines + results['alpha_gt'] = data['alpha'] + # results['alpha_ctn_gt'] = data['alpha_ctn'] + results['depth_gt'] = data['depth'] + results['normal_gt'] = (data['normal'] + 1) / 2 -def render_mesh(ctx, verts, faces, mvp, view_pos, persp, resolution, normal_only=False): - # spp=iter_spp, num_layers=self.FLAGS.layers, msaa=True, background=None)['shaded']: - # get normals + results['silhouette_loss'] = self.mse_loss(results['alpha'], results['alpha_gt']) + results['depth_loss'] = self.mse_loss(results['depth'] * results['alpha_gt'].clone().detach(), results['depth_gt']) + # except: + # pass + + return results, verts, faces +def render_mesh(ctx, verts, faces, mvp, persp, resolution): + '''Rasterize single mesh and interpolate to get depth, alpha, normal''' i0, i1, i2 = faces[:, 0], faces[:, 1], faces[:, 2] v0, v1, v2 = verts[i0, :], verts[i1, :], verts[i2, :] @@ -132,14 +121,12 @@ def render_mesh(ctx, verts, faces, mvp, view_pos, persp, resolution, normal_only alpha = (rast[..., 3:] > 0).float() # CYF Note: enable gradient via antialiasing - alpha_ctn = dr.antialias(alpha, rast, verts_clip, faces).clamp(0, 1) - # rast[..., 3:][rast[..., 3:] > 0] /= rast[..., 3:][rast[..., 3:] > 0] - # xyzs, _ = dr.interpolate(verts.unsqueeze(0), rast, faces) # [B, H, W, 3] + alpha = dr.antialias(alpha, rast, verts_clip, faces).clamp(0, 1) normal, _ = dr.interpolate(vn.unsqueeze(0).contiguous(), rast, faces) normal = safe_normalize(normal) - if normal_only: - return normal, face_normals + # if normal_only: + # return normal, face_normals xyzw = verts_clip @ torch.inverse(persp.T) depth_ = (xyzw[..., 2] / xyzw[..., 3]).unsqueeze(-1) @@ -148,4 +135,4 @@ def render_mesh(ctx, verts, faces, mvp, view_pos, persp, resolution, normal_only diff_attrs=None if rast_db is None else 'all') depth = dr.antialias(depth_, rast, verts_clip, faces) - return alpha, alpha_ctn, -depth, normal, face_normals \ No newline at end of file + return alpha, -depth, normal diff --git a/util/utils.py b/util/utils.py index de61705..7ceddec 100644 --- a/util/utils.py +++ b/util/utils.py @@ -202,7 +202,7 @@ def load_transform(filepath): if filepath == '': return None uuid2transform = {} - with open(filepath, 'r') as f: + with open(filepath, 'r', encoding='utf8') as f: data = json.load(f) for item in data: uuid = os.path.splitext(item['name'])[0] From cd805f5ee8127bc6e9b0708f1085ac1969658b2a Mon Sep 17 00:00:00 2001 From: yudajiang Date: Thu, 28 Nov 2024 15:10:33 +0800 Subject: [PATCH 4/4] update: remove and add some comments --- datasets/dataset.py | 2 - datasets/fast_dataset.py | 110 +++++++------------------------------ datasets/memory_dataset.py | 91 +----------------------------- model/crm/model.py | 74 ++++--------------------- train_crm.py | 51 +---------------- util/renderer.py | 16 ------ 6 files changed, 35 insertions(+), 309 deletions(-) diff --git a/datasets/dataset.py b/datasets/dataset.py index 2b568a6..b962744 100644 --- a/datasets/dataset.py +++ b/datasets/dataset.py @@ -33,9 +33,7 @@ def collate(self, batch): "render_imgs": torch.cat(list(item["render_imgs"] for item in batch), dim=0).to(self.device), "mv": torch.cat(list(item["mv"] for item in batch), dim=0).to(self.device), "mvp": torch.cat(list(item["mvp"] for item in batch), dim=0).to(self.device), - # "campos": torch.cat(list(item["campos"] for item in batch), dim=0).to(self.device), "alpha": torch.cat(list(item["alpha"] for item in batch), dim=0).to(self.device), - # "alpha_ctn": torch.cat(list(item["alpha_ctn"] for item in batch), dim=0).to(self.device), "depth": torch.cat(list(item["depth"] for item in batch), dim=0).to(self.device), "normal": torch.cat(list(item["normal"] for item in batch), dim=0).to(self.device), "triview_color": torch.cat(list(item["triview_color"] for item in batch), dim=0).to(self.device), diff --git a/datasets/fast_dataset.py b/datasets/fast_dataset.py index 6f43571..bf22bac 100644 --- a/datasets/fast_dataset.py +++ b/datasets/fast_dataset.py @@ -166,13 +166,6 @@ def load_chunk(self) -> None: self._chosen = chosen self._chunk_future = self._chunk_load_executor.submit(self._load_chunk_inner) - # def get_state(self) -> str: - # return self._chosen - - # def set_state(self, chosen: str) -> None: - # while self._chosen != chosen: - # self.load_chunk() - def __len__(self) -> int: return len(self._loaded_verts_list) @@ -182,14 +175,6 @@ def _random_scene(self, mv=None, imgs=None, depths=None): # Random rotation/translation matrix for optimization. batch = self.camera_angle_num - # if mv is None or imgs is None: - # mv = torch.bmm( - # utils.translate(0, 0, -self.cam_radius).repeat(batch, 1, 1), - # utils.batch_random_rotation_translation(self.camera_angle_num, 0.25) - # ) - # depths = torch.zeros((batch,) + tuple(self.res) + (1,)) - # imgs = torch.zeros((batch,) + tuple(self.res) + (3,)) - # else: img_num = len(mv) index = random.sample(range(img_num), k=self.camera_angle_num) @@ -201,13 +186,11 @@ def _random_scene(self, mv=None, imgs=None, depths=None): proj_mtx.repeat(batch, 1, 1), mv ) - # campos = torch.linalg.inv(mv)[:, :3, 3] return mv.to(self.device), mvp.to(self.device), imgs.to(self.device), \ depths.to(self.device), proj_mtx.to(self.device), self.res def __getitem__(self, idx): - # if self.render_mode == 'blender': mv = self._loaded_render_color_cam_list[idx] imgs = self._loaded_render_color_img_list[idx] depths = self._loaded_render_depth_img_list[idx] @@ -226,33 +209,14 @@ def __getitem__(self, idx): self.fovx = self._loaded_fovx_list[idx][0] mv, mvp, imgs, depths, persp, iter_res = self._random_scene(mv, imgs, depths) - # else: - # mv, mvp, campos, imgs, depths, persp, iter_res = self._random_scene() verts = self._loaded_verts_list[idx] - # if self.dataset_name == 'Objaverse': - # if self.uuid2transform: transform = self.uuid2transform[self._loaded_uuid[idx]] transport = torch.tensor(transform['offset'], dtype=torch.float32) scale = torch.tensor(transform['scale'], dtype=torch.float32) verts = (verts * scale + transport) * self.scale / 0.5 - # else: - # transport = (verts.max(0)[0] + verts.min(0)[0]) / 2 - # verts -= transport - # scale = 1 / max(verts.max(0)[0] - verts.min(0)[0]) - - # verts *= self.scale / 0.5 * scale - - # if self.dep_sill_mode == 'blender': - # alpha = alpha_ctn = (depths > 0).float() - # normal, face_normals = renderer.render_mesh( - # self.glctx, verts.to(self.device), - # self._loaded_faces_list[idx].to(self.device), - # mvp, campos, persp, iter_res, - # normal_only=True - # ) - # else: + alpha, depth, normal = renderer.render_mesh( self.glctx, verts.to(self.device), self._loaded_faces_list[idx].to(self.device), @@ -274,13 +238,11 @@ def __getitem__(self, idx): 'render_imgs': imgs[None,], 'mv': mv[None, ], 'mvp': mvp[None, ], - # 'campos': campos[None, ], 'resolution': self.res, 'resolution_img': self.res_img, 'resolution_triview': self.res_triview, 'normal': normal[None, ], 'alpha': alpha[None, ], - # 'alpha_ctn': alpha_ctn[None, ], 'depth': depth[None, ], 'persp': persp, 'triview_color': triview_color[None,], @@ -312,7 +274,7 @@ def _load_chunk_inner(self) -> Tuple[str, List[torch.FloatTensor], List[torch.Lo uuid = [str(pandas_chunk['uuid'][i]) for i in range(num_rows)] render_color_img_list, render_depth_img_list, render_color_cam_list, fovx_list = None, None, None, None - # if self.render_mode == 'blender': + render_color_img_list = [torch.FloatTensor(np.stack( [pandas_chunk[f'render_color_img_list_{j}'][i] for j in range(self.img_num)], axis=-1) ) for i in range(num_rows)] @@ -328,17 +290,16 @@ def _load_chunk_inner(self) -> Tuple[str, List[torch.FloatTensor], List[torch.Lo fovx_list = [torch.FloatTensor(np.array(pandas_chunk['fovx_list'][i])) for i in range(num_rows)] triview_color_img_list, triview_xyz_img_list, prompt = None, None, None - # if self.triview_color_dir != '': + triview_color_img_list = [torch.FloatTensor(np.stack( [pandas_chunk[f'triview_color_img_list_{j}'][i] for j in range(6)], axis=-1) ) for i in range(num_rows)] - # if self.triview_xyz_dir != '': + triview_xyz_img_list = [torch.FloatTensor(np.stack( [pandas_chunk[f'triview_xyz_img_list_{j}'][i] for j in range(6)], axis=-1) ) for i in range(num_rows)] - # if self.prompt_path != '': prompt = [str(pandas_chunk['prompt'][i]) for i in range(num_rows)] return str(chosen), verts_list, faces_list, \ @@ -367,11 +328,11 @@ async def aprocess_one_data(self, data: dict, data_index:int): if self.render_color_img_dir != '': render_color_img_dir = data['render_color_img_dir'] render_color_cam_file = data['render_color_cam_file'] + # rotate verts[:, -1] = -verts[:, -1] verts = verts[:, [0, 2, 1]] - # if self.dataset_name == 'Objaverse': k, _, _, _, w2cs = pickle.load(io.BytesIO(await aread_file(render_color_cam_file))) fovx = np.array([2 * math.atan(k[0, 2] / k[0, 0])], dtype=np.float64) @@ -404,11 +365,6 @@ async def aprocess_one_data(self, data: dict, data_index:int): transform_list.append(w2c.reshape(-1)) img_list.append(img.reshape(-1)) - # depth - # syncdreamer - # if os.path.exists(os.path.join(render_color_img_dir, f'{i:03d}-depth.png')): - # depth_name = f'{i:03d}-depth.png' - # dep = cv2.imread(os.path.join(render_color_img_dir, depth_name), cv2.IMREAD_UNCHANGED) dep = depths[i] # reference @@ -416,14 +372,6 @@ async def aprocess_one_data(self, data: dict, data_index:int): dep = dep.astype(np.float32) / 65535 * (DEPTH_MAX - DEPTH_MIN) + DEPTH_MIN mask = (dep < DEPTH_VALID_MIN) | (dep > DEPTH_VALID_MAX) - # # cs - # elif os.path.exists(os.path.join(render_color_img_dir, f'depth_{i:03d}1.png')): - # depth_name = f'{i:03d}-depth.png' - # depth_path = os.path.join(render_color_img_dir, f'depth_{i:03d}1.png') - - # dep =(np.array(Image.open(depth_path))[:,:,0]- 120)* 0.5 / 63 - # mask = np.array(Image.open(depth_path))[:,:,0] == 255 - dep = np.where(mask, 0., dep) dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 @@ -435,7 +383,7 @@ async def aprocess_one_data(self, data: dict, data_index:int): triview_imgs = None triview_xyzs = None - # if self.triview_color_dir != '' and self.triview_xyz_dir != '': + img_list, xyz_list = [], [] triview_color_dir = data['triview_color_dir'] triview_xyz_dir = data['triview_xyz_dir'] @@ -444,23 +392,16 @@ async def aprocess_one_data(self, data: dict, data_index:int): xyz_paths = [os.path.join(triview_xyz_dir, f'xyz_new_{i:03d}.png') for i in range(6)] for i in range(6): - # BGR -> RGB color = buffer_to_cv2image(await aread_file(color_paths[i])) xyz = buffer_to_cv2image(await aread_file(xyz_paths[i])) - # raw = cv2.resize(colors[i], self.res_triview) - # xyz = cv2.resize(xyzs[i], self.res_triview) + raw = cv2.resize(color, self.res_triview) xyz = cv2.resize(xyz, self.res_triview) - # mask = torch.tensor(raw[:, :, [-1]], - # dtype=torch.float32).repeat(1, 1, 3) / 255 img = torch.tensor(raw[:, :, [2, 1, 0, 3]], dtype=torch.float32) / 255 xyz = torch.tensor(xyz, dtype=torch.float32) / 255 - # img = img * mask - # xyz = xyz * mask - img_list.append(img.reshape(-1)) xyz_list.append(xyz.reshape(-1)) @@ -503,17 +444,14 @@ def append_data(self, data: dict, verts_list.append(data['verts']) faces_list.append(data['faces']) - # if self.render_color_img_dir != '': render_color_img_list.append(data['render_imgs']) render_depth_img_list.append(data['render_depths']) render_color_cam_list.append(data['transforms']) fovx_list.append(data['fovx']) - # if self.triview_color_dir != '': + triview_color_img_list.append(data['triview_imgs']) - # if self.triview_xyz_dir != '': triview_xyz_img_list.append(data['triview_xyzs']) - # if self.prompt_path != '': prompt.append(data['prompt']) def prepare_metadata(self): @@ -524,17 +462,10 @@ def prepare_metadata(self): if class_name.endswith('.json'): continue for object_name in tqdm(os.listdir(class_dir)): - # if i > 999: - # break - # if self.dataset_name == 'ShapeNet' and self.class_name == 'all': - # record = '/'.join([class_name, object_name]) - # elif self.dataset_name == 'Objaverse': record = os.path.splitext(object_name)[0] - # exclude no transform data + if record in self.objaverse_exclude: continue - # else: - # record = object_name if (self.mode == 'train' and record in self.train_set) or \ (self.mode == 'val' and record in self.val_set) or \ @@ -543,7 +474,6 @@ def prepare_metadata(self): # load vertices and faces gt_path = os.path.join(class_dir, object_name) - # pcd_file = os.path.join(self.pcd_dir, record, 'pc_262144_131072.ply') render_color_img_dir = os.path.join(self.render_color_img_dir, record) render_color_cam_file = os.path.join(self.render_color_img_dir, record, 'meta.pkl') @@ -579,16 +509,16 @@ def write_one_chunk(self, chunk_index:int, shuffled_verts_list = [verts_list[i] for i in indices] shuffled_faces_list = [faces_list[i] for i in indices] shuffled_uuid = [uuid[i] for i in indices] - # if self.render_color_img_dir != '': + shuffled_render_color_img_list = [render_color_img_list[i] for i in indices] shuffled_render_depth_img_list = [render_depth_img_list[i] for i in indices] shuffled_render_color_cam_list = [render_color_cam_list[i] for i in indices] shuffled_fovx_list = [fovx_list[i] for i in indices] - # if self.triview_color_dir != '': + shuffled_triview_color_img_list = [triview_color_img_list[i] for i in indices] - # if self.triview_xyz_dir != '': + shuffled_triview_xyz_img_list = [triview_xyz_img_list[i] for i in indices] - # if self.prompt_path != '': + shuffled_prompt = [prompt[i] for i in indices] columns = {} @@ -597,7 +527,6 @@ def write_one_chunk(self, chunk_index:int, columns[f'verts_list_{i}'] = [verts[:, i] for verts in shuffled_verts_list] columns[f'faces_list_{i}'] = [faces[:, i] for faces in shuffled_faces_list] - # if self.render_color_img_dir != '': for i in range(self.img_num): columns[f'render_color_img_list_{i}'] = [ render_color_img[:, i] for render_color_img in @@ -613,19 +542,18 @@ def write_one_chunk(self, chunk_index:int, ] columns['fovx_list'] = shuffled_fovx_list - # if self.triview_color_dir != '': for i in range(6): columns[f'triview_color_img_list_{i}'.format(i)] = [ triview_color_img[:, i] for triview_color_img in shuffled_triview_color_img_list ] - # if self.triview_xyz_dir != '': + for i in range(6): columns[f'triview_xyz_img_list_{i}'.format(i)] = [ triview_xyz_img[:, i] for triview_xyz_img in shuffled_triview_xyz_img_list ] - # if self.prompt_path != '': + columns['prompt'] = shuffled_prompt parquet_writers[chunk_index].write_table(pa.table(columns)) parquet_writers[chunk_index].close() @@ -661,19 +589,19 @@ def write_chunks(self, chunk_path, chunk_size) -> None: for i in range(3): dtypes.append((f'verts_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) dtypes.append((f'faces_list_{i}', pa.list_(pa.from_numpy_dtype(np.int64)))) - # if self.render_color_img_dir != '': + for i in range(self.img_num): dtypes.append((f'render_color_img_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) dtypes.append((f'render_depth_img_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) dtypes.append((f'render_color_cam_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) dtypes.append(('fovx_list', pa.list_(pa.from_numpy_dtype(np.float64)))) - # if self.triview_color_dir != '': + for i in range(6): dtypes.append((f'triview_color_img_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) - # if self.triview_xyz_dir != '': + for i in range(6): dtypes.append((f'triview_xyz_img_list_{i}', pa.list_(pa.from_numpy_dtype(np.float32)))) - # if self.prompt_path != '': + dtypes.append(('prompt', pa.string())) parquet_writers.append(pq.ParquetWriter(parquet_path, pa.schema(dtypes), compression='BROTLI')) diff --git a/datasets/memory_dataset.py b/datasets/memory_dataset.py index 7f8fbd4..6832476 100644 --- a/datasets/memory_dataset.py +++ b/datasets/memory_dataset.py @@ -74,48 +74,8 @@ def __init__(self, input_specs, train_specs, glctx, device, validate=False, visu self.uuid2transform = utils.load_transform(input_specs.get('blender_transform')) - # if self.prompt_path != '': self.uuid2prompt = utils.load_prompt(self.prompt_path) - # if task_mode == "debug": - # # load raw vertices and faces - # ref_mesh = trimesh.load(self.mesh_dir, force='mesh', process=False) - # verts = torch.tensor(ref_mesh.vertices, dtype=torch.float32) - # faces = torch.LongTensor(ref_mesh.faces) - - # if self.pcd_dir.endswith(".usd"): - # # load point cloud - # pcd = kaolin.io.usd.import_pointclouds(self.pcd_dir)[0] - # pcd_tr = pcd.points - # pcd_colors = pcd.colors - - # # scale - # verts = verts / torch.max(abs(verts)) * self.scale - # pcd_tr = pcd_tr / torch.max(abs(pcd_tr)) * self.scale - - # self.data = [ - # {'gt_verts': verts.cpu(), 'gt_faces': faces.cpu(), 'gt_pcd': pcd_tr, 'gt_pcd_colors': pcd_colors}] - - # elif self.pcd_dir.endswith(".ply") and self.render_img_dir == '': - # self.data = self._preprocess(verts, faces, self.pcd_dir) - - # elif self.pcd_dir.endswith('.ply') and self.render_img_dir != '': - # # render imgs - # filename = os.path.split(self.render_img_dir)[-1] - - # if self.dataset_name == 'ShapeNet': - # imgdir = os.path.join(self.render_img_dir, 'img', filename, 'models') - # elif self.dataset_name == 'Objaverse': - # imgdir = self.render_img_dir - # else: - # raise RuntimeError('Not valid dataset_name') - # self.data = self._preprocess(verts, faces, self.pcd_dir, imgdir=imgdir) - - # else: - # raise RuntimeError('Illegal point cloud format') - - # elif task_mode == "batch": - # multi mesh self.data = [] for class_name in os.listdir(self.mesh_dir): if class_name == self.class_name or self.class_name == 'all': @@ -123,18 +83,11 @@ def __init__(self, input_specs, train_specs, glctx, device, validate=False, visu if class_name.endswith('.json'): continue for i, object_name in enumerate(tqdm(os.listdir(class_dir))): - # if i > 99: - # break - # if self.dataset_name == 'ShapeNet' and self.class_name == 'all': - # record = '/'.join([class_name, object_name]) - # elif self.dataset_name == 'Objaverse': record = os.path.splitext(object_name)[0] # exclude no transform data if record in self.objaverse_exclude: continue - # else: - # record = object_name - # validate set abort + if self.validate and record not in self.val_list: continue # train set abort @@ -159,12 +112,10 @@ def __init__(self, input_specs, train_specs, glctx, device, validate=False, visu res.update({'uuid': record}) - # if self.triview_color_dir != '' and self.triview_xyz_dir != '': img_list, xyz_list = [], [] triview_color_dir = os.path.join(self.triview_color_dir, record) triview_xyz_dir = os.path.join(self.triview_xyz_dir, record) for i in range(6): - # BGR -> RGB raw = cv2.resize( cv2.imread(os.path.join(triview_color_dir, f'{i:03d}.png'), cv2.IMREAD_UNCHANGED), tuple(self.res_triview)) @@ -173,6 +124,7 @@ def __init__(self, input_specs, train_specs, glctx, device, validate=False, visu tuple(self.res_triview)) mask = torch.tensor(raw[:, :, [-1]], dtype=torch.float32).repeat(1, 1, 3) / 255 + # BGR -> RGB img = torch.tensor(raw[:, :, [2, 1, 0]], dtype=torch.float32) / 255 xyz = torch.tensor(xyz, dtype=torch.float32) / 255 @@ -191,12 +143,10 @@ def __init__(self, input_specs, train_specs, glctx, device, validate=False, visu 'triview_xyz': triview_xyzs }) - # if self.prompt_path != '': res.update({ 'prompt': self.uuid2prompt.get(os.path.splitext(object_name)[0]) }) - # if res is not None: self.data.append(res) def _preprocess(self, verts, faces, uuid=None, imgdir=None): @@ -239,7 +189,6 @@ def _preprocess(self, verts, faces, uuid=None, imgdir=None): # depth # syncdreamer - # if os.path.exists(os.path.join(imgdir, f'{i:03d}-depth.png')): depth_name = f'{i:03d}-depth.png' dep = cv2.imread(os.path.join(imgdir, depth_name), cv2.IMREAD_UNCHANGED) @@ -248,14 +197,6 @@ def _preprocess(self, verts, faces, uuid=None, imgdir=None): dep = dep.astype(np.float32) / 65535 * (DEPTH_MAX - DEPTH_MIN) + DEPTH_MIN mask = (dep < DEPTH_VALID_MIN) | (dep > DEPTH_VALID_MAX) - # # cs - # elif os.path.exists(os.path.join(imgdir, f'depth_{i:03d}1.png')): - # depth_name = f'depth_{i:03d}1.png' - # depth_path = os.path.join(imgdir, depth_name) - - # dep =(np.array(Image.open(depth_path))[:,:,0]- 64) / 127 - # mask = np.array(Image.open(depth_path))[:,:,0] == 255 - dep = np.where(mask, 0., dep) dep = torch.tensor(cv2.resize(dep, tuple(self.res)), dtype=torch.float32) * self.scale / 0.5 @@ -266,7 +207,6 @@ def _preprocess(self, verts, faces, uuid=None, imgdir=None): transforms = torch.stack(transform_list) render_depths = torch.stack(depth_list).unsqueeze(-1) - return { 'verts': verts, 'faces': faces, @@ -280,19 +220,6 @@ def _sample_scene(self, num, rotate=False): proj_mtx = utils.perspective(self.fovx, self.res[1] / self.res[0]) - # if self.render_mode != 'blender' and self.dep_sill_mode != 'blender': - # if rotate: - # ang = (idx / 20) * np.pi * 2 - # mv = utils.translate(0, 0, -self.cam_radius) @ (utils.rotate_x(0.4) @ utils.rotate_y(ang)) - # mv = mv.repeat(batch, 1, 1) - # else: - # mv = torch.bmm( - # utils.translate(0, 0, -self.cam_radius).repeat(batch, 1, 1), - # utils.batch_random_rotation_translation(self.camera_angle_num, 0.25) - # ) - # depths = torch.zeros((batch,) + tuple(self.res) + (1,)) - # imgs = torch.zeros((batch,) + tuple(self.res) + (3,)) - # else: mv = self.data[num].get('transforms') img_num = len(mv) index = random.sample(range(img_num), k=1 if rotate else self.camera_angle_num) @@ -305,13 +232,11 @@ def _sample_scene(self, num, rotate=False): proj_mtx.repeat(batch, 1, 1), mv ) - # campos = torch.linalg.inv(mv)[:, :3, 3] return mv.to(self.device), mvp.to(self.device), imgs.to(self.device), \ depths.to(self.device), proj_mtx.to(self.device), self.res def __len__(self): - # return self.epoch if self.validate else self.its_per_epc return 20 if self.visual else len(self.data) def __getitem__(self, idx): @@ -323,16 +248,6 @@ def __getitem__(self, idx): # rotate or random scene mv, mvp, imgs, depth, persp, iter_res = self._sample_scene(num, rotate=self.visual) - # if self.dep_sill_mode == 'blender': - # alpha = alpha_ctn = (depths > 0).float() - # normal, face_normals = renderer.render_mesh( - # self.glctx, - # self.data[num]['gt_verts'].to(self.device), - # self.data[num]['gt_faces'].to(self.device), - # mvp, campos, persp, iter_res, - # normal_only=True - # ) - # else: alpha, depth, normal = renderer.render_mesh( self.glctx, self.data[num]['verts'].to(self.device), @@ -351,13 +266,11 @@ def __getitem__(self, idx): 'render_imgs': imgs[None, ], 'mv': mv[None, ], 'mvp': mvp[None, ], - # 'campos': campos[None, ], 'resolution': self.res, 'resolution_img': self.res_img, 'resolution_triview': self.res_triview, 'normal': normal[None, ], 'alpha': alpha[None, ], - # 'alpha_ctn': alpha_ctn[None, ], 'depth': depth[None, ], 'persp': persp, 'triview_color': triview_color[None, ], diff --git a/model/crm/model.py b/model/crm/model.py index 2c04de4..7bac25b 100644 --- a/model/crm/model.py +++ b/model/crm/model.py @@ -65,11 +65,7 @@ def __init__(self, specs): self.ticker = 0 - # self.spob = True # whether to add sphere self.radius = specs['Train']['radius'] # used when spob - # self.denoising = False - - # self.scheduler = DDIMScheduler.from_pretrained("stabilityai/stable-diffusion-2-1-base", subfolder="scheduler") def small_fwd(self, data): xyzs_list = [] @@ -80,29 +76,10 @@ def small_fwd(self, data): if xyzs.max() > 1.1: xyzs = xyzs / 255 - # print("fix 255 bug") - # if self.specs["Train"].get("random_bg", False): - # crgb = 0.5#random.random() - # cxyz = 0.5#random.random() - # for j in range(6): - # mask = torch.mean(xyzs[j], dim = 0, keepdim=False) - # mask = (mask == 0) - # for k in range(3): - # color[j][k][mask] = crgb - # xyzs[j][k][mask] = cxyz - # else: - # crgb = 0 - # cxyz = 0 - - # shift = 0 - # if random.random() < 0.5: - # shift = int(self.specs["Train"].get("shift", 0)) color_tensor1 = get_tri(color, dim=0, blender=True, rgb=True) xyzs_tensor1 = get_tri(xyzs, dim=0, blender=True, fix=True) # , fix = True - # print(color_tensor1.shape) - # print(color_tensor1.shape) color_list.append(color_tensor1) xyzs_list.append(xyzs_tensor1) color_tensor = torch.stack(color_list, dim=0) @@ -114,16 +91,10 @@ def small_fwd(self, data): xyzs_tensor, [self.enc.plane_resolution, self.enc.plane_resolution*3], mode = "bilinear") # !Notice - all_tensor = torch.cat([color_tensor, xyzs_tensor], dim = 1)# *2 - 1 - - # triplane_feature0 = all_tensor - # triplane_feature1 = all_tensor - # return triplane_feature0, triplane_feature1 + all_tensor = torch.cat([color_tensor, xyzs_tensor], dim = 1) return all_tensor def forward(self, data, ctx): - # if self.geo_type == "flex": - # use the number of data not batch size verts = self.renderer.flexicubes.verts.unsqueeze(0).repeat(len(data['verts']), 1, 1) tets = self.renderer.flexicubes.indices @@ -159,10 +130,6 @@ def forward(self, data, ctx): result, verts, faces = self.renderer(data, pred_sdf, deformation, verts, tets, weight=weight) - # sdf_pos = pred_sdf[pred_sdf>=0] - # sdf_neg = pred_sdf[pred_sdf<0] - # result["wzy_loss"] = (torch.abs(sdf_pos-1).sum() + torch.abs(sdf_neg+1).sum()) / (pred_sdf.shape[0]*pred_sdf.shape[1]) - resolution = data['resolution_img'] color_gt = data['render_imgs'] result['gt_render_imgs'] = data['render_imgs'] @@ -179,22 +146,19 @@ def forward(self, data, ctx): F.pad(vert, pad=(0, 1), mode='constant', value=1.0).unsqueeze(0).repeat(mvp.shape[0], 1, 1), mvp.permute(0, 2, 1)).float() # [B, N, 4] rast, rast_db = dr.rasterize(ctx, verts_clip, face, resolution) - # print(verts.shape, faces.shape) + alpha, _ = dr.interpolate(torch.ones_like(vert[:, :1]).unsqueeze(0), rast, face) # [1, H, W, 1] xyzs, _ = dr.interpolate(vert, rast, face) # [1, H, W, 3] - # print(alpha.shape, xyzs.shape) + xyzs = xyzs.view(-1, 3) mask = (alpha > 0).view(-1).detach() - # do the lighting here since we have normal from mesh now. + albedo = torch.zeros_like(xyzs, dtype=torch.float32) albedo = albedo.view(-1, resolution[0], resolution[1], 3) albedo[:mvp_size] = albedo[:mvp_size] - 1 albedo = albedo.view(-1, 3) - # print("4.0:{}".format(torch.cuda.memory_allocated(0))) - - # print("4.0:{}".format(torch.cuda.memory_allocated(0))) if mask.any(): dec_d_pcd = self.decoder(tri_output[i].unsqueeze(0), xyzs[mask].unsqueeze(0)) masked_albedo = self.rgb_mlp(dec_d_pcd) @@ -223,7 +187,6 @@ def forward(self, data, ctx): return result, verts, faces def decode(self, data, tri_output): - # if self.geo_type == "flex": tet_verts = self.renderer.flexicubes.verts.unsqueeze(0) tet_indices = self.renderer.flexicubes.indices @@ -231,7 +194,6 @@ def decode(self, data, tri_output): out = self.sdf_mlp(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], @@ -241,7 +203,6 @@ def decode(self, data, tri_output): 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) @@ -261,27 +222,23 @@ def color_query(self, data, verts): def render_color_img(self, verts, faces, data, ctx, mvp=None, idx=0): mvp = data['mvp'][idx] if mvp is None else mvp[0] res = data['resolution_img'] - # print(mvp.shape, verts.shape, faces.shape, res) faces = faces.int() faces = faces[..., [2, 1, 0]] # rasterization verts_clip = torch.bmm( F.pad(verts, pad=(0, 1), mode='constant', value=1.0).repeat(mvp.shape[0], 1, 1), mvp.permute(0, 2, 1)).float() # [B, N, 4] - # assert verts_clip.shape[0] > 0 and verts_clip.shape[1] > 0, print(verts_clip.shape, verts.shape) rast, _ = dr.rasterize(ctx, verts_clip, faces, res) - # print(verts.shape, faces.shape) alpha, _ = dr.interpolate(torch.ones_like(verts[0][:, :1]).unsqueeze(0), rast, faces) # [1, H, W, 1] xyzs, _ = dr.interpolate(verts[0], rast, faces) # [1, H, W, 3] - # print(alpha.shape, xyzs.shape) xyzs = xyzs.view(-1, 3) mask = (alpha > 0).view(-1).detach() - # do the lighting here since we have normal from mesh now. + albedo = torch.zeros_like(xyzs, dtype=torch.float32) - 1 if mask.any(): tri_input = self.small_fwd(data) - tri_output = self.unet(tri_input) # unet2 moved to trdgen main class + tri_output = self.unet(tri_input) masked_albedo = self.rgb_mlp(self.decoder(tri_output, xyzs[mask].unsqueeze(0))).squeeze(0) albedo[mask] = masked_albedo.float() albedo = albedo.view(-1, alpha.shape[1], alpha.shape[2], 3) @@ -291,41 +248,32 @@ def render_color_img(self, verts, faces, data, ctx, mvp=None, idx=0): xyzs[mask2] -= 1 xyzs = xyzs.view(alpha.shape[0], alpha.shape[1], alpha.shape[2], 3) xyzs = (xyzs * 0.5 + 0.5).clip(0, 1) - # print(albedo.shape) return albedo, xyzs def visualize(self, result, epc, chunk, color_fine, rdr_img_dir, iter_all): # After each epoch, visualize and evaluate # epc: current index of epochs normal = result['normal'][0].detach().cpu().numpy() - # normal_gt = result['normal_gt'][0].detach().cpu().numpy() alpha = (result['alpha'][0].detach().cpu().numpy() * 255).astype('uint8') alpha_gt = (result['alpha_gt'][0].detach().cpu().numpy() * 255).astype('uint8') - # succ = True - # try: + depth = trans_depth(result['depth']) depth_gt = trans_depth(result['depth_gt']) - # except: - # succ = False + color_fine = color_fine[..., [2, 1, 0]].detach().cpu().numpy() color_fine = cv2.resize(color_fine[0], alpha.shape[1:3])[None, ...] color_fine_gt = result.get('color_gt')[0, ..., [2, 1, 0]].cpu().numpy() color_fine_gt = cv2.resize(color_fine_gt[0], alpha.shape[1:3])[None, ...] - # if succ == True: + img = np.concatenate((alpha, alpha_gt, depth, depth_gt), axis=2) - # else: - # img = np.concatenate((alpha, alpha_gt, alpha, alpha_gt), axis=2) - # if succ == True: + cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}.png", np.concatenate((normal[0], color_fine[0], color_fine_gt[0], cv2.applyColorMap(np.repeat(depth[0],3,axis=2).astype(np.uint8), cv2.COLORMAP_HOT)/255, cv2.applyColorMap(np.repeat(depth_gt[0],3,axis=2).astype(np.uint8), cv2.COLORMAP_HOT)/255), axis=1)*255) - # else: - # cv2.imwrite(rdr_img_dir.as_posix() + f"/ep{epc}-chunk{chunk}-iter{iter_all}.png", - # np.concatenate((normal[0], color_fine[0], color_fine_gt[0]), axis=1)*255) tri_input = result['tri_input'][0].mean(0).unsqueeze(-1) tri_input = (tri_input - tri_input.min()) / (tri_input.max() - tri_input.min()) @@ -483,4 +431,4 @@ def interpolate(attr, rast, attr_idx, rast_db=None): img = img * (1 - mask) + dilate_img * mask img = img.clip(0, 255).astype(np.uint8) - cv2.imwrite(f'{out_path}.png', img[..., [2, 1, 0]]) + cv2.imwrite(f'{out_dir}.png', img[..., [2, 1, 0]]) diff --git a/train_crm.py b/train_crm.py index 71760c5..c4fa5c5 100644 --- a/train_crm.py +++ b/train_crm.py @@ -36,41 +36,33 @@ def train(args): specs = json.load(f) input_specs = specs['Input'] - # task_mode = input_specs['task_mode'] - # tet_grid_size = input_specs['tet_grid_size'] dataset_type = input_specs.get('dataset_type', None) train_specs = specs['Train'] num_epochs = train_specs['num_epochs'] - # sup_mode = train_specs['mode'] sample_points_num = train_specs['sample_points_num'] batch_size = train_specs['batch_size'] l_rate = train_specs['learning_rate']['init'] warmup_iter = train_specs['warm_up'] scheduler_decay = train_specs['decay'] eva_iter = train_specs['eva_iter'] - # lambda_nc = train_specs.get('lambda_nc', 0) grad_acc = train_specs.get('grad_acc', 1) lambda_lp = train_specs.get('lambda_lp', 0) - # lambda_wzy = train_specs.get('lambda_wzy', 0) save_chunk = train_specs.get('save_chunk') output_dirs = specs['Output'] exp_name = Path(output_dirs['exp_name']) - # geo_type = specs['Train'].get('geo_type', 'dmtet') - if not exp_name.exists(): exp_name.mkdir(exist_ok=True) - # ensure output in one folder ( higher than 60% ) if args.resume: exp_dir = Path(args.resume) else: exp_dir = exp_name / (time.strftime('%m_%d-%H_%M_%S', time.localtime(time.time() // 5 * 5)) + args.note) exp_dir.mkdir(exist_ok=True) shutil.copy(config_path, exp_dir) - # + opt_rec_dir = exp_dir / 'opt_rec' opt_rec_dir.mkdir(exist_ok=True) cur_rec_dir = exp_dir / 'cur_rec' @@ -88,8 +80,6 @@ def train(args): epc = checkpoint['epoch'] chunk = checkpoint['chunk'] chunk_num = checkpoint['chunk_num'] - # assert chunk_num == input_specs['chunk_num'] - # assert chunk == 0 start = epc * chunk_num + chunk iter_all = checkpoint['itr_all'] cham_dist_opt = checkpoint['cham_dist_opt'] # current best chamfer distance @@ -187,22 +177,13 @@ def train(args): if len(dataset) == 0: continue - # try: dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, collate_fn=dataset.collate, shuffle=True) dataloader = accelerator.prepare(dataloader) - # except: - # continue for data in dataloader: model.train() - # mvp = mvps[iter_all] - # pts = pcd_tr[:, itr * pt_b_size: (itr + 1) * pt_b_size].cuda() - # - # mvp = mvps[iter_all] - # pts = pcd_tr[:, itr * pt_b_size: (itr + 1) * pt_b_size].cuda() - # if accelerator.is_main_process: print(f'Training@Epoch {epc}, Chunk {chunk}, Itr {iter_all}', flush=True) @@ -220,7 +201,6 @@ def train(args): result['lap_loss'] = sum(lap_loss_list) / len(lap_loss_list) result['chamfer_loss'] = sum(chamfer_loss_list) / len(chamfer_loss_list) - # if train_specs['tex_sup_mode'] == 'blender': reso = result['albedo_list'].shape[-2] lpips_train = result['albedo_list'].view( -1, result['albedo_list'].shape[-3], result['albedo_list'].shape[-2], result['albedo_list'].shape[-1] @@ -237,7 +217,6 @@ def train(args): result['lpips_loss'] = lpips(lpips_train, lpips_gt) - # if sup_mode == 'rnd': # shape supervision I: rendered silhouette and depth losses loss = result['silhouette_loss']+ result['depth_loss'] + specs['Train']['lambda_smooth'] * result['lap_loss'] \ + train_specs['lambda_color'] * result['color_loss'] + lambda_lp *result['lpips_loss'] \ @@ -262,15 +241,10 @@ def train(args): if iter_all % grad_acc == 0: optimizer.step() - scheduler.step() # DJ optimization schedule + scheduler.step() torch.cuda.empty_cache() optimizer.zero_grad() - # normal = result['normal_image'][0].detach().cpu().numpy() - # cv2.imwrite(model.exp_dir.as_posix() + "/last_normal" +".png", normal*255) - - # normal = result['normal_image'][0].detach().cpu().numpy() - # cv2.imwrite(model.exp_dir.as_posix() + "/last_normal" +".png", normal*255) accelerator.wait_for_everyone() if accelerator.is_main_process: writer.add_scalar('train/silhouette', result['silhouette_loss'], iter_all) @@ -280,8 +254,6 @@ def train(args): writer.add_scalar('train/color', result['color_loss'], iter_all) writer.add_scalar('train/lr', optimizer.param_groups[0]['lr'], iter_all) writer.add_scalar('train/lpips', result['lpips_loss'], iter_all) - # writer.add_scalar('train/wzy', result['wzy_loss'], iter_all) - # if geo_type == 'flex': writer.add_scalar('train/flex_weight', result['flex_weight_loss'], iter_all) writer.add_scalar('train/flex_surf', result['flex_surf_loss'], iter_all) @@ -290,9 +262,7 @@ def train(args): if accelerator.is_main_process: train_img_dir = exp_dir / 'train_img' train_img_dir.mkdir(exist_ok=True) - # try: - # albedos = result['albedo_list2'][0] - # except: + albedos = result['albedo_list'][0] albedo_tensor = torch.cat((albedos[0], albedos[1], albedos[2], albedos[3]), dim=1) albedo_tensor = albedo_tensor[..., [2, 1, 0]].detach().cpu().numpy() @@ -312,10 +282,8 @@ def train(args): if accelerator.is_main_process: # visualize data_vis = next(dataloader_vis) - # if task_mode != 'debug': print(data_vis['uuid'],data_vis.get('prompt')) - # tnew_list = [0,100,200,300,400,500,600,700,800,900,999] with torch.no_grad(): result, verts, faces = accelerator.unwrap_model(model)(data_vis, glctx) @@ -390,14 +358,7 @@ def eval_and_save(accelerator, writer, model, sample_points_num, iter_all, datas gt_verts_list.append(gt_vert.cpu().numpy()) gt_faces_list.append(gt_face.cpu().numpy()) - # if data_val.get('triview_color') is None: - # triview_color_list.append(np.nan) - # else: triview_color_list.append(data_val['triview_color'].cpu().numpy()) - - # if data_val.get('triview_xyz') is None: - # triview_xyz_list.append(np.nan) - # else: triview_xyz_list.append(data_val['triview_xyz'].cpu().numpy()) chamfer_dist = accelerator.gather_for_metrics(chamfer_dist) @@ -493,10 +454,6 @@ def save_export(mode): shutil.move(opt_rec_dir / f'best_{mode}_params.pth', opt_rec_dir / f'2nd_{mode}_params.pth') torch.save(accelerator.unwrap_model(model).state_dict(), opt_rec_dir / f'best_{mode}_params.pth') - # # export mesh ( only eval_all ) - # if type != '_all' or specs['ArchSpecs']['pc_enc'] == 'mix': - # return - with accelerator.split_between_processes(zip_data) as tmp_data: for j, ele in enumerate(tmp_data): verts, faces, gt_verts, gt_faces, triview_color, triview_xyz = ele @@ -553,6 +510,4 @@ def save_export(mode): help='resume training from given checkpoint', ) arguments = arg_parser.parse_args() - # torch.cuda.set_device(1) - # os.environ['CUDA_LAUNCH_BLOCKING'] = '1' train(arguments) diff --git a/util/renderer.py b/util/renderer.py index 2765d95..6915525 100644 --- a/util/renderer.py +++ b/util/renderer.py @@ -17,13 +17,11 @@ def __init__(self, tet_grid_size, camera_angle_num, scale): 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() self.l1_loss = nn.L1Loss() self.mse_loss = nn.MSELoss() - # 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): @@ -36,7 +34,6 @@ def forward(self, data, sdf, deform, verts, tets, training=False, weight = None) results = {} faces = None deform = torch.tanh(deform) / self.tet_grid_size - # if self.geo_type == "flex": deform = deform * 0.5 v_deformed = verts + deform @@ -65,32 +62,23 @@ def forward(self, data, sdf, deform, verts, tets, training=False, weight = None) alpha, depth, normal = render_mesh(self.glctx, vert, face, mvp, persp, resolution=(h, w)) alpha_list.append(alpha) - # alpha_ctn_list.append(alpha_ctn) depth_list.append(depth) norm_list.append(normal) - # nc_list.append(normal_consistency(face_normals, faces[i])) alpha = torch.stack(alpha_list, dim=0) - # alpha_ctn = torch.stack(alpha_ctn_list, dim=0) depth = torch.stack(depth_list, dim=0) normal = torch.stack(norm_list, dim=0) - # results['nc_loss'] = torch.stack(nc_list, dim=0).mean() results['alpha'] = alpha - # results['alpha_ctn'] = alpha_ctn results['depth'] = depth results['normal'] = (normal + 1) / 2 - # try:# remove these lines results['alpha_gt'] = data['alpha'] - # results['alpha_ctn_gt'] = data['alpha_ctn'] results['depth_gt'] = data['depth'] results['normal_gt'] = (data['normal'] + 1) / 2 results['silhouette_loss'] = self.mse_loss(results['alpha'], results['alpha_gt']) results['depth_loss'] = self.mse_loss(results['depth'] * results['alpha_gt'].clone().detach(), results['depth_gt']) - # except: - # pass return results, verts, faces @@ -116,7 +104,6 @@ def render_mesh(ctx, verts, faces, mvp, persp, resolution): verts_clip = torch.bmm( F.pad(verts, pad=(0, 1), mode='constant', value=1.0).unsqueeze(0).repeat(mvp.shape[0], 1, 1), mvp.permute(0, 2, 1)).float() # [B, N, 4] - # assert verts_clip.shape[0] > 0 and verts_clip.shape[1] > 0, print(verts_clip.shape, verts.shape) rast, rast_db = dr.rasterize(ctx, verts_clip, faces, resolution) alpha = (rast[..., 3:] > 0).float() @@ -125,9 +112,6 @@ def render_mesh(ctx, verts, faces, mvp, persp, resolution): normal, _ = dr.interpolate(vn.unsqueeze(0).contiguous(), rast, faces) normal = safe_normalize(normal) - # if normal_only: - # return normal, face_normals - xyzw = verts_clip @ torch.inverse(persp.T) depth_ = (xyzw[..., 2] / xyzw[..., 3]).unsqueeze(-1)