You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by gi...@apache.org on 2026/09/23 21:33:36 UTC
(iceberg-rust) branch gh-pages updated: deploy: c9a25b23b7645f3af0e9dfd7e85d8cf646901c55
This is an automated email from the ASF dual-hosted git repository.
github-actions[bot] pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
The following commit(s) were added to refs/heads/gh-pages by this push:
new 589c393f0 deploy: c9a25b23b7645f3af0e9dfd7e85d8cf646901c55
589c393f0 is described below
commit 589c393f013d1baf06a6f613ddb1d41bedd9caa6
Author: github-merge-queue[bot] <gi...@users.noreply.github.com>
AuthorDate: Wed Sep 23 21:33:30 2026 +0000
deploy: c9a25b23b7645f3af0e9dfd7e85d8cf646901c55
---
api/iceberg/encryption/struct.AesGcmFileRead.html | 10 +-
api/iceberg/encryption/struct.AesGcmFileWrite.html | 12 +-
.../encryption/struct.EncryptedInputFile.html | 16 +-
.../encryption/struct.EncryptedOutputFile.html | 21 +-
.../encryption/struct.StandardKeyMetadata.html | 4 +-
api/iceberg/io/struct.LocalFsStorageFactory.html | 8 +-
api/iceberg/io/trait.FileRead.html | 2 +-
api/iceberg/io/trait.FileWrite.html | 8 +-
api/iceberg/io/trait.StorageFactory.html | 2 +-
api/iceberg/puffin/struct.PuffinWriter.html | 4 +-
api/iceberg/spec/struct.ManifestListWriter.html | 4 +-
api/iceberg/spec/struct.ManifestWriter.html | 12 +-
api/iceberg/spec/struct.ManifestWriterBuilder.html | 18 +-
api/iceberg_storage_opendal/index.html | 2 +-
api/search.index/002c557042.js | 1 +
api/search.index/00468560f6.js | 1 +
api/search.index/0071a6f6e2.js | 1 +
api/search.index/00a5e6bcb2.js | 1 -
api/search.index/00cc071d94.js | 1 -
api/search.index/0197b9104e.js | 1 -
api/search.index/01afc1ed10.js | 1 -
api/search.index/01e156bd2e.js | 1 -
api/search.index/01e1ec1253.js | 1 +
api/search.index/0265f40fbc.js | 1 +
api/search.index/0270a01d14.js | 1 +
api/search.index/02fe53f190.js | 1 -
api/search.index/03036e27c7.js | 1 +
api/search.index/0307fc9427.js | 1 -
api/search.index/036f5803b3.js | 1 +
api/search.index/0370d4cc7c.js | 1 +
api/search.index/0391a7a6d0.js | 1 -
api/search.index/03a18b59f4.js | 1 +
api/search.index/043de39544.js | 1 -
api/search.index/0458ed477e.js | 1 -
api/search.index/04e32cbf6e.js | 1 -
api/search.index/04f3af8eb1.js | 1 +
api/search.index/050f60d373.js | 1 +
api/search.index/051982de53.js | 1 -
api/search.index/0580601cd6.js | 1 -
api/search.index/0586a76b0b.js | 1 +
api/search.index/05af641484.js | 1 +
api/search.index/05d36fabac.js | 1 -
api/search.index/05e23b7e94.js | 1 +
api/search.index/05fe2bcf8e.js | 1 -
api/search.index/066bad1eee.js | 1 -
api/search.index/06e7ec3344.js | 1 -
api/search.index/073b9f3997.js | 1 +
api/search.index/07d7dab63f.js | 1 -
api/search.index/0855a8d908.js | 1 -
api/search.index/0861717c7c.js | 1 +
api/search.index/086958a9f4.js | 1 -
api/search.index/08c20bf822.js | 1 +
api/search.index/08c8b4743b.js | 1 +
api/search.index/08f94d670a.js | 1 -
api/search.index/09e25262e9.js | 1 +
api/search.index/09eb1cc16d.js | 1 +
api/search.index/0a2c4f6e7f.js | 1 -
api/search.index/0a3e6a35f1.js | 1 -
api/search.index/0abb7ba7f2.js | 1 +
api/search.index/0af0419719.js | 1 -
api/search.index/0b2aad3376.js | 1 +
api/search.index/0b34c06609.js | 1 +
api/search.index/0b775c1ddd.js | 1 +
api/search.index/0b9b542880.js | 1 +
api/search.index/0ba3963a0f.js | 1 -
api/search.index/0ba6daad9b.js | 1 -
api/search.index/0c1376fbdf.js | 1 -
api/search.index/0d1f0b5fe3.js | 1 +
api/search.index/0dc7840bcd.js | 1 -
api/search.index/0de17bcf12.js | 1 -
api/search.index/0df8d7b385.js | 1 -
api/search.index/0df9b23957.js | 1 +
api/search.index/0dff42f8c5.js | 1 -
api/search.index/0e2f350627.js | 1 -
api/search.index/0e626311a8.js | 1 -
api/search.index/0e7992d4cb.js | 1 -
api/search.index/0ebc2800e1.js | 1 +
api/search.index/0ec556d23f.js | 1 -
api/search.index/0f64c65dbf.js | 1 -
api/search.index/0f65182f67.js | 1 -
api/search.index/0f67528ff7.js | 1 -
api/search.index/0f938e891a.js | 1 -
api/search.index/0fb6a44325.js | 1 -
api/search.index/0fc0613555.js | 1 +
api/search.index/1034c841bc.js | 1 -
api/search.index/104abdc6f9.js | 1 +
api/search.index/10ee6608b7.js | 1 -
api/search.index/11405c3d1e.js | 1 +
api/search.index/11bf9ef685.js | 1 -
api/search.index/11f16a2e42.js | 1 -
api/search.index/11fd9cc749.js | 1 +
api/search.index/13b6de9f5f.js | 1 +
api/search.index/140a8e2a10.js | 1 +
api/search.index/140cc9b1f5.js | 1 +
api/search.index/1439721cd0.js | 1 -
api/search.index/143a41938d.js | 1 +
api/search.index/1441cb3093.js | 1 +
api/search.index/146efe46ac.js | 1 +
api/search.index/1486cb7cb9.js | 1 +
api/search.index/1486cba725.js | 1 +
api/search.index/1499b4011a.js | 1 -
api/search.index/14ea40eed4.js | 1 +
api/search.index/153b64ea46.js | 1 +
api/search.index/1554c50095.js | 1 -
api/search.index/15a577f2d7.js | 1 +
api/search.index/15ab902fa8.js | 1 +
api/search.index/15ac299102.js | 1 +
api/search.index/15b0fac45b.js | 1 -
api/search.index/15cf9d9898.js | 1 -
api/search.index/15d4e88f0d.js | 1 -
api/search.index/16218e36de.js | 1 +
api/search.index/164b17d87d.js | 1 -
api/search.index/167e932e08.js | 1 -
api/search.index/16c224a7d5.js | 1 -
api/search.index/172a90fc64.js | 1 -
api/search.index/175a23082a.js | 1 -
api/search.index/1777c42571.js | 1 -
api/search.index/17ca709c19.js | 1 +
api/search.index/1821041df0.js | 1 -
api/search.index/18304e2067.js | 1 +
api/search.index/18583fda18.js | 1 -
api/search.index/18694d833f.js | 1 -
api/search.index/18d0e3c33f.js | 1 -
api/search.index/193fdc053a.js | 1 -
api/search.index/19cc30d33d.js | 1 +
api/search.index/19de6a319a.js | 1 +
api/search.index/1a1a352024.js | 1 -
api/search.index/1a28b6c776.js | 1 +
api/search.index/1aa0145b25.js | 1 -
api/search.index/1b7f1f7f92.js | 1 +
api/search.index/1be2a2b877.js | 1 +
api/search.index/1c0dcb0683.js | 1 +
api/search.index/1c23bb2ea9.js | 1 +
api/search.index/1c483d17ea.js | 1 -
api/search.index/1c73eb078e.js | 1 -
api/search.index/1c767f3b4d.js | 1 -
api/search.index/1cb08eb70d.js | 1 +
api/search.index/1cf7e98668.js | 1 +
api/search.index/1d138d9776.js | 1 +
api/search.index/1e25b247eb.js | 1 -
api/search.index/1e4f3a3b22.js | 1 +
api/search.index/1ee976d785.js | 1 +
api/search.index/1eef1a3d86.js | 1 +
api/search.index/1faed6253b.js | 1 +
api/search.index/1fd2386113.js | 1 +
api/search.index/1ffab88926.js | 1 -
api/search.index/2015cf1d00.js | 1 -
api/search.index/203bddd617.js | 1 +
api/search.index/20afe5d819.js | 1 -
api/search.index/20e61b2513.js | 1 +
api/search.index/21117bbb41.js | 1 -
api/search.index/211d0950e5.js | 1 -
api/search.index/2194a61837.js | 1 -
api/search.index/2216409478.js | 1 +
api/search.index/225122cf8a.js | 1 -
api/search.index/2252572b73.js | 1 +
api/search.index/230ad59110.js | 1 -
api/search.index/235a27a73c.js | 1 -
api/search.index/236e5f6f6f.js | 1 +
api/search.index/23a01b535e.js | 1 +
api/search.index/23da842426.js | 1 +
api/search.index/23f5041bd9.js | 1 +
api/search.index/23fc1d5970.js | 1 -
api/search.index/244e367e76.js | 1 -
api/search.index/2456582a55.js | 1 -
api/search.index/2464a72671.js | 1 +
api/search.index/24b412498b.js | 1 -
api/search.index/24d547fde0.js | 1 -
api/search.index/24d869c30a.js | 1 +
api/search.index/24f3a90cdb.js | 1 +
api/search.index/25095b4293.js | 1 -
api/search.index/25587405bc.js | 1 +
api/search.index/2564cee0c6.js | 1 -
api/search.index/25768c1aba.js | 1 -
api/search.index/2630b1fbe0.js | 1 +
api/search.index/26356420ef.js | 1 +
api/search.index/2654dd4db6.js | 1 -
api/search.index/26b353e595.js | 1 -
api/search.index/26c797f9fa.js | 1 -
api/search.index/277112f060.js | 1 -
api/search.index/279c5a1571.js | 1 -
api/search.index/27bd8e6747.js | 1 +
api/search.index/27e79e69b6.js | 1 -
api/search.index/27f819abd2.js | 1 +
api/search.index/27fa81ede8.js | 1 -
api/search.index/28462c866c.js | 1 +
api/search.index/28babbc299.js | 1 -
api/search.index/293a7dd2bc.js | 1 +
api/search.index/2a20280f65.js | 1 +
api/search.index/2a61a10e77.js | 1 +
api/search.index/2a6285686c.js | 1 -
api/search.index/2a651b496d.js | 1 -
api/search.index/2a682afd80.js | 1 -
api/search.index/2a85425f57.js | 1 +
api/search.index/2aa0364307.js | 1 +
api/search.index/2ab6c9c2ea.js | 1 +
api/search.index/2af071a101.js | 1 +
api/search.index/2b952571dc.js | 1 +
api/search.index/2b978fb783.js | 1 +
api/search.index/2c0bf1b379.js | 1 +
api/search.index/2c4582ea19.js | 1 -
api/search.index/2c73c8a66c.js | 1 -
api/search.index/2ca8bd9bde.js | 1 +
api/search.index/2cae63e23b.js | 1 -
api/search.index/2cc94d27c2.js | 1 -
api/search.index/2cf8bcdf4a.js | 1 -
api/search.index/2d00f3bc93.js | 1 +
api/search.index/2d408ba00a.js | 1 +
api/search.index/2d7384baea.js | 1 -
api/search.index/2da48fd41e.js | 1 -
api/search.index/2e31da7e8a.js | 1 +
api/search.index/2e4127d8c1.js | 1 +
api/search.index/2ea74e027f.js | 1 +
api/search.index/2eb1c7c7a9.js | 1 +
api/search.index/2fb0ee98de.js | 1 -
api/search.index/303d69d850.js | 1 -
api/search.index/30e7afee14.js | 1 -
api/search.index/310108bde9.js | 1 +
api/search.index/311276ea81.js | 1 -
api/search.index/311a124897.js | 1 +
api/search.index/31567e86e8.js | 1 -
api/search.index/31f2ae3adb.js | 1 +
api/search.index/32d0ecc4d9.js | 1 -
api/search.index/32f2c8af3a.js | 1 +
api/search.index/33214e402a.js | 1 +
api/search.index/3355845a3d.js | 1 -
api/search.index/3370418625.js | 1 +
api/search.index/338cc3b0ba.js | 1 -
api/search.index/33df460cb3.js | 1 -
api/search.index/33f8f3ae64.js | 1 +
api/search.index/33fa7fd9d1.js | 1 +
api/search.index/342286ed31.js | 1 +
api/search.index/343533833c.js | 1 +
api/search.index/3471b6b5a0.js | 1 -
api/search.index/34a265a389.js | 1 -
api/search.index/34a4a8d231.js | 1 -
api/search.index/34bfdc58b1.js | 1 -
api/search.index/34c2639591.js | 1 -
api/search.index/34ddad05fc.js | 1 +
api/search.index/34e2d95be5.js | 1 +
api/search.index/34fb80b003.js | 1 +
api/search.index/35355c172d.js | 1 +
api/search.index/35aa79b3f7.js | 1 +
api/search.index/35e9a7b7f8.js | 1 +
api/search.index/35fbc95c02.js | 1 -
api/search.index/364513e953.js | 1 -
api/search.index/36b1c6a430.js | 1 +
api/search.index/36f25741b6.js | 1 +
api/search.index/371ca0fdf6.js | 1 +
api/search.index/37c17d96f6.js | 1 -
api/search.index/37c4d44a9b.js | 1 +
api/search.index/384f9657f9.js | 1 -
api/search.index/388782e00b.js | 1 -
api/search.index/3888623807.js | 1 +
api/search.index/3897310a21.js | 1 -
api/search.index/389be2b2b1.js | 1 +
api/search.index/38fad5af31.js | 1 +
api/search.index/3916dc75f9.js | 1 -
api/search.index/3939a6dfad.js | 1 -
api/search.index/399357d2c2.js | 1 -
api/search.index/39e66627fe.js | 1 -
api/search.index/39fe437b6f.js | 1 -
api/search.index/3a8b8d6297.js | 1 +
api/search.index/3ad1b3bdc6.js | 1 +
api/search.index/3ae80e1ce7.js | 1 +
api/search.index/3b27de903f.js | 1 -
api/search.index/3b6ff2d14d.js | 1 +
api/search.index/3b709fc40e.js | 1 +
api/search.index/3b746d8bb1.js | 1 -
api/search.index/3bbdd66e63.js | 1 +
api/search.index/3bf8449956.js | 1 -
api/search.index/3bfd182ccb.js | 1 +
api/search.index/3c2345b9cf.js | 1 -
api/search.index/3c676ba0e6.js | 1 -
api/search.index/3c6d66726b.js | 1 +
api/search.index/3cdf958b5d.js | 1 -
api/search.index/3d24f61296.js | 1 +
api/search.index/3d528213e6.js | 1 +
api/search.index/3d75b61e0e.js | 1 +
api/search.index/3dabb41779.js | 1 -
api/search.index/3dfe58f6e3.js | 1 -
api/search.index/3e09a9ae57.js | 1 +
api/search.index/3e200d3d8b.js | 1 +
api/search.index/3e85456181.js | 1 -
api/search.index/3efb4f5df4.js | 1 +
api/search.index/3f32b5a3d5.js | 1 +
api/search.index/3f64fdfa9f.js | 1 -
api/search.index/3fb1ff6250.js | 1 -
api/search.index/3fe3985bd6.js | 1 -
api/search.index/40245027b1.js | 1 -
api/search.index/4075e1b776.js | 1 +
api/search.index/40d7c94f3f.js | 1 -
api/search.index/40f311ab12.js | 1 +
api/search.index/40f6360f6b.js | 1 +
api/search.index/41078170fb.js | 1 -
api/search.index/4116d7f43d.js | 1 -
api/search.index/4127de4106.js | 1 +
api/search.index/4150286d7d.js | 1 +
api/search.index/4195926081.js | 1 -
api/search.index/42027106dd.js | 1 -
api/search.index/4210f18b5f.js | 1 -
api/search.index/42257979f2.js | 1 +
api/search.index/4283ba8e33.js | 1 -
api/search.index/431867dcf9.js | 1 +
api/search.index/4337d7901f.js | 1 -
api/search.index/434ae27d5a.js | 1 +
api/search.index/435e45fedf.js | 1 -
api/search.index/436010891e.js | 1 +
api/search.index/438f932df0.js | 1 -
api/search.index/43b00fadde.js | 1 +
api/search.index/43fab53e55.js | 1 -
api/search.index/441d313d25.js | 1 +
api/search.index/454140722a.js | 1 +
api/search.index/455dddcad7.js | 1 +
api/search.index/455df4e98a.js | 1 +
api/search.index/45b929ba18.js | 1 +
api/search.index/45e1ac6720.js | 1 +
api/search.index/46b06b5291.js | 1 +
api/search.index/4741b66c03.js | 1 +
api/search.index/4752a5f971.js | 1 +
api/search.index/4767cbb23b.js | 1 +
api/search.index/476fbccefd.js | 1 -
api/search.index/478e3629c1.js | 1 -
api/search.index/47d6dcf712.js | 1 -
api/search.index/47d6e8f91d.js | 1 -
api/search.index/47e49e3299.js | 1 +
api/search.index/47ee7a3642.js | 1 -
api/search.index/483a8b57ad.js | 1 +
api/search.index/487c7630ac.js | 1 -
api/search.index/49377b04e6.js | 1 -
api/search.index/49bf3c020d.js | 1 -
api/search.index/4a0d9be3e6.js | 1 +
api/search.index/4a67fb9a41.js | 1 -
api/search.index/4b1cf3d74f.js | 1 -
api/search.index/4b757e5b26.js | 1 +
api/search.index/4c82a80b13.js | 1 -
api/search.index/4ca8bcdefd.js | 1 -
api/search.index/4cb0b404d5.js | 1 -
api/search.index/4cfa0c4a28.js | 1 +
api/search.index/4d39d12d8b.js | 1 +
api/search.index/4d54b99309.js | 1 +
api/search.index/4d8b3bfec2.js | 1 +
api/search.index/4dff5675c7.js | 1 +
api/search.index/4eaa7deac4.js | 1 +
api/search.index/4eaee0847e.js | 1 -
api/search.index/4f5dd46927.js | 1 -
api/search.index/4fdff5055b.js | 1 -
api/search.index/50091c092a.js | 1 +
api/search.index/501e2cdafd.js | 1 +
api/search.index/50d376da3a.js | 1 +
api/search.index/5108e78c79.js | 1 +
api/search.index/518864e068.js | 1 +
api/search.index/51e6c0ea81.js | 1 -
api/search.index/52224d81d7.js | 1 +
api/search.index/524f49b081.js | 1 +
api/search.index/5276568752.js | 1 -
api/search.index/5310bde235.js | 1 -
api/search.index/53464c12fe.js | 1 -
api/search.index/535ea20b23.js | 1 +
api/search.index/53c12e65e8.js | 1 -
api/search.index/53ec6e8485.js | 1 +
api/search.index/541cf368d2.js | 1 -
api/search.index/542569dda6.js | 1 -
api/search.index/54416fafbc.js | 1 +
api/search.index/546e67512d.js | 1 -
api/search.index/5485d267a3.js | 1 -
api/search.index/54b1305644.js | 1 +
api/search.index/54cc3c9349.js | 1 -
api/search.index/555f432747.js | 1 +
api/search.index/5587fc39ca.js | 1 -
api/search.index/55d647b225.js | 1 -
api/search.index/55e67e3184.js | 1 -
api/search.index/567ad8a4a6.js | 1 -
api/search.index/5712b1aa4a.js | 1 -
api/search.index/575ae79d0f.js | 1 -
api/search.index/584dd87bf7.js | 1 +
api/search.index/5869694059.js | 1 -
api/search.index/586c5b0bbf.js | 1 -
api/search.index/5871e7cc09.js | 1 +
api/search.index/588d1e7469.js | 1 +
api/search.index/5945ea94cf.js | 1 +
api/search.index/594cbcd636.js | 1 -
api/search.index/5973d8d129.js | 1 +
api/search.index/5a64838915.js | 1 -
api/search.index/5ab7ed48f8.js | 1 -
api/search.index/5ae4517f95.js | 1 +
api/search.index/5af5fd48ad.js | 1 +
api/search.index/5b0eff57f1.js | 1 +
api/search.index/5b1278dac9.js | 1 -
api/search.index/5b8468ff95.js | 1 +
api/search.index/5c1143b026.js | 1 -
api/search.index/5c2705ef70.js | 1 +
api/search.index/5c3a80e3ad.js | 1 -
api/search.index/5c7c0423a8.js | 1 -
api/search.index/5d182f08f6.js | 1 +
api/search.index/5d2b0d6a17.js | 1 -
api/search.index/5e100697c0.js | 1 -
api/search.index/5e468657bf.js | 1 -
api/search.index/5e55cde44e.js | 1 +
api/search.index/5edfdb96df.js | 1 -
api/search.index/5f8adcef2a.js | 1 -
api/search.index/5fc5c841f0.js | 1 +
api/search.index/60098707e7.js | 1 +
api/search.index/60319b134c.js | 1 +
api/search.index/606c625853.js | 1 +
api/search.index/6081664311.js | 1 -
api/search.index/61338ca7e2.js | 1 +
api/search.index/617130f9fe.js | 1 +
api/search.index/61ab36a0b6.js | 1 +
api/search.index/623cde8e0a.js | 1 -
api/search.index/6286e0e5cf.js | 1 +
api/search.index/62e31a7fa5.js | 1 -
api/search.index/6315f501a9.js | 1 +
api/search.index/6354ca15dd.js | 1 +
api/search.index/63ca153dbb.js | 1 -
api/search.index/63ccabdae0.js | 1 -
api/search.index/63e139fefb.js | 1 -
api/search.index/6421290a80.js | 1 -
api/search.index/64874fb465.js | 1 +
api/search.index/6487bb2e2f.js | 1 +
api/search.index/649e04fdeb.js | 1 +
api/search.index/64f1057184.js | 1 +
api/search.index/6592b7e5ad.js | 1 -
api/search.index/65dcad4c8f.js | 1 +
api/search.index/65e70bb9c6.js | 1 -
api/search.index/669833dc2e.js | 1 -
api/search.index/66c6b8bd6e.js | 1 -
api/search.index/66f420dd66.js | 1 -
api/search.index/66fb4e4543.js | 1 +
api/search.index/671439b694.js | 1 -
api/search.index/673e34e85f.js | 1 +
api/search.index/67ad40adc2.js | 1 +
api/search.index/681f6f35b3.js | 1 +
api/search.index/682474ddf9.js | 1 +
api/search.index/684ba46bb6.js | 1 +
api/search.index/687248167c.js | 1 -
api/search.index/6894b959f1.js | 1 -
api/search.index/689bbd5a99.js | 1 -
api/search.index/6930c8e217.js | 1 +
api/search.index/6938449a0e.js | 1 +
api/search.index/696630ff75.js | 1 -
api/search.index/697262d4c6.js | 1 -
api/search.index/69737f3109.js | 1 +
api/search.index/69d906e210.js | 1 -
api/search.index/{519341af7a.js => 69e5643c77.js} | 2 +-
api/search.index/6a094e7803.js | 1 +
api/search.index/6a268d8644.js | 1 -
api/search.index/6a46df790a.js | 1 +
api/search.index/6a831626fe.js | 1 +
api/search.index/6a865a8137.js | 1 +
api/search.index/6aae4b5e8e.js | 1 -
api/search.index/6b0170c4d1.js | 1 -
api/search.index/6b50a7f552.js | 1 -
api/search.index/6c271e00c4.js | 1 +
api/search.index/6c4439efd5.js | 1 -
api/search.index/6c60ab593d.js | 1 +
api/search.index/6c65845a59.js | 1 +
api/search.index/6c828101b5.js | 1 -
api/search.index/6d194da6c2.js | 1 -
api/search.index/6d2d118ab5.js | 1 +
api/search.index/6d5956b325.js | 1 +
api/search.index/6d796172a3.js | 1 +
api/search.index/6d9a877671.js | 1 -
api/search.index/6e19bfcf4d.js | 1 +
api/search.index/6e7193fa03.js | 1 -
api/search.index/6e7684557f.js | 1 -
api/search.index/6e830b6fbe.js | 1 +
api/search.index/6e8804b3ab.js | 1 -
api/search.index/6e8917bf2d.js | 1 -
api/search.index/6ea22b4c27.js | 1 -
api/search.index/6edaa566ef.js | 1 -
api/search.index/6ee7bf0b3b.js | 1 +
api/search.index/6eed71bbdf.js | 1 +
api/search.index/6f06ed192c.js | 1 -
api/search.index/6f75f48ea8.js | 1 +
api/search.index/6f82bc4df5.js | 1 +
api/search.index/6fd7139a4f.js | 1 -
api/search.index/7016ee2d06.js | 1 -
api/search.index/705b2e359a.js | 1 +
api/search.index/7123c03011.js | 1 +
api/search.index/713a93a788.js | 1 +
api/search.index/7182aa50af.js | 1 +
api/search.index/71d42f16db.js | 1 -
api/search.index/72014d26b6.js | 1 -
api/search.index/7231fc9838.js | 1 +
api/search.index/726c1a5fdf.js | 1 +
api/search.index/7277c4ff6f.js | 1 -
api/search.index/728c74c0d4.js | 1 -
api/search.index/7296aa86d1.js | 1 -
api/search.index/7303ceeefb.js | 1 -
api/search.index/73b0df526a.js | 1 +
api/search.index/73d21d70d1.js | 1 -
api/search.index/7438820ac2.js | 1 +
api/search.index/7495a88b96.js | 1 -
api/search.index/74eeced2d9.js | 1 +
api/search.index/754ada0a66.js | 1 -
api/search.index/755ec70127.js | 1 -
api/search.index/7580d5d1bd.js | 1 +
api/search.index/75b75cc1e6.js | 1 -
api/search.index/75dd391575.js | 1 -
api/search.index/75f13bee4a.js | 1 +
api/search.index/762ae4a50c.js | 1 +
api/search.index/766097701f.js | 1 +
api/search.index/766e8a506f.js | 1 -
api/search.index/76ac07bbfe.js | 1 -
api/search.index/76bad7d6a3.js | 1 +
api/search.index/771c47584e.js | 1 +
api/search.index/773505a33c.js | 1 +
api/search.index/776a66d42c.js | 1 +
api/search.index/777de8eb15.js | 1 +
api/search.index/78151609ea.js | 1 -
api/search.index/78eada87f2.js | 1 +
api/search.index/7925474955.js | 1 -
api/search.index/7931835e85.js | 1 -
api/search.index/79a8bb8d66.js | 1 -
api/search.index/7a4a632850.js | 1 -
api/search.index/7a6a9bf1af.js | 1 -
api/search.index/7a7508b80a.js | 1 -
api/search.index/7aa8aa46ed.js | 1 -
api/search.index/7af1be5678.js | 1 -
api/search.index/7b61dc450f.js | 1 -
api/search.index/7b77097e74.js | 1 -
api/search.index/7bca65e298.js | 1 +
api/search.index/7bcea53fe9.js | 1 -
api/search.index/7c0e8d201f.js | 1 -
api/search.index/7c1447e9c0.js | 1 +
api/search.index/7c96d1c248.js | 1 +
api/search.index/7cb5ec942a.js | 1 +
api/search.index/7d58f2e922.js | 1 +
api/search.index/7de639b0d3.js | 1 +
api/search.index/7e13e215b8.js | 1 +
api/search.index/7e1eda1197.js | 1 -
api/search.index/7e25ee63c9.js | 1 -
api/search.index/7e5a3cebb5.js | 1 +
api/search.index/7e935f375d.js | 1 +
api/search.index/7ebf940269.js | 1 +
api/search.index/7ed3813a68.js | 1 +
api/search.index/7f3ab6298b.js | 1 -
api/search.index/7f76e77fc0.js | 1 +
api/search.index/7fa0bf408b.js | 1 +
api/search.index/7fd268328e.js | 1 -
api/search.index/7fdacc2c01.js | 1 +
api/search.index/7fdbc0f41a.js | 1 +
api/search.index/desc/1c5ddc544a.js | 1 -
api/search.index/desc/f805b0ea2e.js | 1 +
api/search.index/entry/01dc940117.js | 1 +
api/search.index/entry/0597216bdb.js | 1 +
api/search.index/entry/28c6c4136b.js | 1 +
api/search.index/entry/4c84476e77.js | 1 -
api/search.index/entry/7cda7732c3.js | 1 -
api/search.index/entry/f7477d93e4.js | 1 -
api/search.index/function/0d28bad0fd.js | 1 +
api/search.index/function/17d923aa6e.js | 1 +
api/search.index/function/3450b833cc.js | 1 -
api/search.index/function/f2c18fae46.js | 1 -
.../generic_inverted_index/23a38f5a76.js | 1 +
.../generic_inverted_index/4fd38067ac.js | 1 -
api/search.index/name/31643d18d4.js | 1 +
api/search.index/name/7a2dfd6649.js | 1 -
api/search.index/normalizedName/cdd0bd1f4b.js | 1 +
api/search.index/normalizedName/da61c0c7ae.js | 1 -
api/search.index/root.js | 2 +-
api/search.index/type/2a816290da.js | 1 +
api/search.index/type/d08dd1cd0b.js | 1 -
.../arrow/caching_delete_file_loader.rs.html | 379 +-
api/src/iceberg/encryption/io.rs.html | 537 ++-
api/src/iceberg/encryption/key_metadata.rs.html | 4 +-
api/src/iceberg/encryption/manager.rs.html | 30 +-
api/src/iceberg/encryption/stream.rs.html | 2322 +++++------
api/src/iceberg/io/file_io.rs.html | 4 +-
api/src/iceberg/io/storage/local_fs.rs.html | 642 +--
api/src/iceberg/io/storage/memory.rs.html | 634 +--
api/src/iceberg/puffin/reader.rs.html | 2 +-
api/src/iceberg/puffin/writer.rs.html | 635 +--
api/src/iceberg/spec/manifest/writer.rs.html | 1581 ++++----
.../spec/manifest_list/manifest_file.rs.html | 251 +-
api/src/iceberg/spec/manifest_list/writer.rs.html | 894 ++---
api/src/iceberg/transaction/append.rs.html | 1021 ++---
api/src/iceberg/transaction/snapshot.rs.html | 145 +-
.../writer/file_writer/parquet_writer.rs.html | 4070 ++++++++++----------
api/src/iceberg_storage_opendal/lib.rs.html | 424 +-
api/trait.impl/core/marker/trait.Sync.js | 4 +-
582 files changed, 7319 insertions(+), 6935 deletions(-)
diff --git a/api/iceberg/encryption/struct.AesGcmFileRead.html b/api/iceberg/encryption/struct.AesGcmFileRead.html
index 2430688a6..674a82673 100644
--- a/api/iceberg/encryption/struct.AesGcmFileRead.html
+++ b/api/iceberg/encryption/struct.AesGcmFileRead.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Transparent decryption of AGS1 stream-encrypted files."><title>AesGcmFileRead in iceberg::encryption - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-R [...]
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Transparent decryption of AGS1 stream-encrypted files."><title>AesGcmFileRead in iceberg::encryption - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-R [...]
<p>Implements the <a href="../io/trait.FileRead.html" title="trait iceberg::io::FileRead"><code>FileRead</code></a> trait, providing random-access reads over
encrypted data. Each <code>read()</code> call determines which encrypted blocks
overlap the requested plaintext range, reads and decrypts them, then
@@ -13,7 +13,7 @@ returns the requested plaintext bytes.</p>
)<span class="question-mark">?</span>;
<span class="comment">// Read plaintext bytes transparently
-</span><span class="kw">let </span>plaintext = reader.read(<span class="number">0</span>..<span class="number">1024</span>).<span class="kw">await</span><span class="question-mark">?</span>;</code></pre></div></div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-AesGcmFileRead" class="impl"><a class="src ri [...]
+</span><span class="kw">let </span>plaintext = reader.read(<span class="number">0</span>..<span class="number">1024</span>).<span class="kw">await</span><span class="question-mark">?</span>;</code></pre></div></div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-AesGcmFileRead" class="impl"><a class="src ri [...]
inner: <a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="../io/trait.FileRead.html" title="trait iceberg::io::FileRead">FileRead</a>>,
cipher: <a class="struct" href="https://doc.rust-lang.org/nightly/alloc/sync/struct.Arc.html" title="struct alloc::sync::Arc">Arc</a><<a class="struct" href="struct.AesGcmCipher.html" title="struct iceberg::encryption::AesGcmCipher">AesGcmCipher</a>>,
aad_prefix: <a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><[<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u8.html">u8</a>]>,
@@ -29,11 +29,11 @@ when blocks are decrypted (GCM authentication will fail on corrupt data).</p>
<li><code>aad_prefix</code> - AAD prefix from the file’s <code>StandardKeyMetadata</code></li>
<li><code>encrypted_file_length</code> - Total byte length of the encrypted file</li>
</ul>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.plaintext_length" class="method"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#198-200">Source</a><h4 class="code-header">pub fn <a href="#method.plaintext_length" class="fn">plaintext_length</a>(&self) -> <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u64.html">u64</a></h4></section></summary><div class="docblock"><p>Returns the plaintex [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.calculate_plaintext_length" class="method"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#206-237">Source</a><h4 class="code-header">pub fn <a href="#method.calculate_plaintext_length" class="fn">calculate_plaintext_length</a>(encrypted_file_length: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u64.html">u64</a>) -> <a class="type" href="../t [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.plaintext_length" class="method"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#191-193">Source</a><h4 class="code-header">pub fn <a href="#method.plaintext_length" class="fn">plaintext_length</a>(&self) -> <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u64.html">u64</a></h4></section></summary><div class="docblock"><p>Returns the plaintex [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.calculate_plaintext_length" class="method"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#199-230">Source</a><h4 class="code-header">pub fn <a href="#method.calculate_plaintext_length" class="fn">calculate_plaintext_length</a>(encrypted_file_length: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u64.html">u64</a>) -> <a class="type" href="../t [...]
<p>This is a static calculation matching Java’s
<code>AesGcmInputStream.calculatePlaintextLength()</code>.</p>
-</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-FileRead-for-AesGcmFileRead" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#255-349">Source</a><a href="#impl-FileRead-for-AesGcmFileRead" class="anchor">§</a><h3 clas [...]
+</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-FileRead-for-AesGcmFileRead" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#248-347">Source</a><a href="#impl-FileRead-for-AesGcmFileRead" class="anchor">§</a><h3 clas [...]
&'life0 self,
range: <a class="struct" href="https://doc.rust-lang.org/nightly/core/ops/range/struct.Range.html" title="struct core::ops::range::Range">Range</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u64.html">u64</a>>,
) -> <a class="struct" href="https://doc.rust-lang.org/nightly/core/pin/struct.Pin.html" title="struct core::pin::Pin">Pin</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a><Output = <a class="type" href="../type.Result.html" title="type iceberg: [...]
diff --git a/api/iceberg/encryption/struct.AesGcmFileWrite.html b/api/iceberg/encryption/struct.AesGcmFileWrite.html
index b066a304a..44ed4f0d3 100644
--- a/api/iceberg/encryption/struct.AesGcmFileWrite.html
+++ b/api/iceberg/encryption/struct.AesGcmFileWrite.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Transparent encryption of AGS1 stream-encrypted files."><title>AesGcmFileWrite in iceberg::encryption - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans- [...]
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Transparent encryption of AGS1 stream-encrypted files."><title>AesGcmFileWrite in iceberg::encryption - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans- [...]
<p>Implements the <a href="../io/trait.FileWrite.html" title="trait iceberg::io::FileWrite"><code>FileWrite</code></a> trait, buffering plaintext and emitting
encrypted AGS1 blocks. This is the streaming write counterpart to
<a href="struct.AesGcmFileRead.html" title="struct iceberg::encryption::AesGcmFileRead"><code>AesGcmFileRead</code></a>.</p>
@@ -11,22 +11,22 @@ encrypted AGS1 blocks. This is the streaming write counterpart to
);
writer.write(plaintext_chunk).<span class="kw">await</span><span class="question-mark">?</span>;
-writer.close().<span class="kw">await</span><span class="question-mark">?</span>;</code></pre></div></div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-AesGcmFileWrite" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#391-460">Source</a><a href="#impl-AesGcmFileWrite [...]
+writer.close().<span class="kw">await</span><span class="question-mark">?</span>;</code></pre></div></div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-AesGcmFileWrite" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#389-458">Source</a><a href="#impl-AesGcmFileWrite [...]
inner: <a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="../io/trait.FileWrite.html" title="trait iceberg::io::FileWrite">FileWrite</a>>,
cipher: <a class="struct" href="https://doc.rust-lang.org/nightly/alloc/sync/struct.Arc.html" title="struct alloc::sync::Arc">Arc</a><<a class="struct" href="struct.AesGcmCipher.html" title="struct iceberg::encryption::AesGcmCipher">AesGcmCipher</a>>,
aad_prefix: impl <a class="trait" href="https://doc.rust-lang.org/nightly/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><[<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u8.html">u8</a>]>>,
) -> Self</h4></section></summary><div class="docblock"><p>Creates a new <code>AesGcmFileWrite</code> for encrypting to AGS1 format.</p>
<p>No I/O is performed until <code>write()</code> or <code>close()</code> is called.</p>
-</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-FileWrite-for-AesGcmFileWrite" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#463-521">Source</a><a href="#impl-FileWrite-for-AesGcmFileWrite" class="anchor">§</a><h3 [...]
+</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-FileWrite-for-AesGcmFileWrite" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#461-519">Source</a><a href="#impl-FileWrite-for-AesGcmFileWrite" class="anchor">§</a><h3 [...]
&'life0 mut self,
bs: Bytes,
) -> <a class="struct" href="https://doc.rust-lang.org/nightly/core/pin/struct.Pin.html" title="struct core::pin::Pin">Pin</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a><Output = <a class="type" href="../type.Result.html" title="type iceberg: [...]
Self: 'async_trait,
- 'life0: 'async_trait,</div></h4></section></summary><div class='docblock'>Write bytes to file. <a href="../io/trait.FileWrite.html#tymethod.write">Read more</a></div></details><details class="toggle method-toggle" open><summary><section id="method.close" class="method trait-impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#492-520">Source</a><a href="#method.close" class="anchor">§</a><h4 class="code-header">fn <a href="../io/trait.FileWrite.html#tymeth [...]
+ 'life0: 'async_trait,</div></h4></section></summary><div class='docblock'>Write bytes to file. <a href="../io/trait.FileWrite.html#tymethod.write">Read more</a></div></details><details class="toggle method-toggle" open><summary><section id="method.close" class="method trait-impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#490-518">Source</a><a href="#method.close" class="anchor">§</a><h4 class="code-header">fn <a href="../io/trait.FileWrite.html#tymeth [...]
&'life0 mut self,
-) -> <a class="struct" href="https://doc.rust-lang.org/nightly/core/pin/struct.Pin.html" title="struct core::pin::Pin">Pin</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a><Output = <a class="type" href="../type.Result.html" title="type iceberg: [...]
+) -> <a class="struct" href="https://doc.rust-lang.org/nightly/core/pin/struct.Pin.html" title="struct core::pin::Pin">Pin</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a><Output = <a class="type" href="../type.Result.html" title="type iceberg: [...]
Self: 'async_trait,
- 'life0: 'async_trait,</div></h4></section></summary><div class='docblock'>Close file. <a href="../io/trait.FileWrite.html#tymethod.close">Read more</a></div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-AesGcmFileWrite" class="impl"><a href="#impl-Freeze-for-AesGcmFileWrite" class="anc [...]
+ 'life0: 'async_trait,</div></h4></section></summary><div class='docblock'>Close the file and return its stored size, including encryption overhead for encrypted files. <a href="../io/trait.FileWrite.html#tymethod.close">Read more</a></div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-A [...]
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/nightly/src/core/any.rs.html#142">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href [...]
T: CastFrom<U>,</div></h4></section></summary><div class='docblock'>Casts <code>self</code> to type <code>T</code>. The <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics">semantics of numeric casting</a> with the <code>as</code> operator are followed, so <code><T as As>::as_::<U></code> can be used in the same way as <code>T as U</code> for numeric conversions. <a>Read more</a></div></details></div></details><details class="toggle [...]
T: <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a>,</div></h3></section></summary><div class="impl-items"><section id="method.as_any" class="method trait-impl"><a href="#method.as_any" class="anchor">§</a><h4 class="code-header">fn <a class="fn">as_any</a>(&self) -> &(dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a> + 'static)</h4 [...]
diff --git a/api/iceberg/encryption/struct.EncryptedInputFile.html b/api/iceberg/encryption/struct.EncryptedInputFile.html
index b7c04a609..69d8e945a 100644
--- a/api/iceberg/encryption/struct.EncryptedInputFile.html
+++ b/api/iceberg/encryption/struct.EncryptedInputFile.html
@@ -1,15 +1,15 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="An AGS1 stream-encrypted input file wrapping a plain `InputFile`."><title>EncryptedInputFile in iceberg::encryption - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.w [...]
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="An AGS1 stream-encrypted input file wrapping a plain `InputFile`."><title>EncryptedInputFile in iceberg::encryption - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.w [...]
<p>Transparently decrypts on read.</p>
-</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-EncryptedInputFile" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#38-94">Source</a><a href="#impl-EncryptedInputFile" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.EncryptedInputFile [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.location" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#48-50">Source</a><h4 class="code-header">pub fn <a href="#method.location" class="fn">location</a>(&self) -> &<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.str.html">str</a></h4></section></summary><div class="docblock"><p>Absolute path of the file.</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.exists" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#53-55">Source</a><h4 class="code-header">pub async fn <a href="#method.exists" class="fn">exists</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.bool.html">bool</a>></h4></s [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.metadata" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#60-66">Source</a><h4 class="code-header">pub async fn <a href="#method.metadata" class="fn">metadata</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="../io/struct.FileMetadata.html" title="struct iceberg::io::FileMetadata">Fil [...]
+</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-EncryptedInputFile" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#39-107">Source</a><a href="#impl-EncryptedInputFile" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.EncryptedInputFil [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.location" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#49-51">Source</a><h4 class="code-header">pub fn <a href="#method.location" class="fn">location</a>(&self) -> &<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.str.html">str</a></h4></section></summary><div class="docblock"><p>Absolute path of the file.</p>
+</div></details><details class="toggle method-toggle" open><summary><section id="method.exists" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#54-56">Source</a><h4 class="code-header">pub async fn <a href="#method.exists" class="fn">exists</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.bool.html">bool</a>></h4></s [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.metadata" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#61-66">Source</a><h4 class="code-header">pub fn <a href="#method.metadata" class="fn">metadata</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="../io/struct.FileMetadata.html" title="struct iceberg::io::FileMetadata">FileMetad [...]
<p>The returned size is the <strong>plaintext</strong> size.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.read" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#69-73">Source</a><h4 class="code-header">pub async fn <a href="#method.read" class="fn">read</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><Bytes></h4></section></summary><div class="docblock"><p>Read and returns whole content of file (decrypted pla [...]
</div></details><details class="toggle method-toggle" open><summary><section id="method.reader" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#76-83">Source</a><h4 class="code-header">pub async fn <a href="#method.reader" class="fn">reader</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.key_metadata" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#86-88">Source</a><h4 class="code-header">pub fn <a href="#method.key_metadata" class="fn">key_metadata</a>(&self) -> &<a class="struct" href="struct.StandardKeyMetadata.html" title="struct iceberg::encryption::StandardKeyMetadata">StandardKeyMetadata</a></h4></section></summary><div class="do [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.into_inner" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#91-93">Source</a><h4 class="code-header">pub fn <a href="#method.into_inner" class="fn">into_inner</a>(self) -> <a class="struct" href="../io/struct.InputFile.html" title="struct iceberg::io::InputFile">InputFile</a></h4></section></summary><div class="docblock"><p>Consumes self and returns the underly [...]
-</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Debug-for-EncryptedInputFile" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#96-102">Source</a><a href="#impl-Debug-for-EncryptedInputFile" class="anchor">§</a><h3 class=" [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.key_metadata" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#99-101">Source</a><h4 class="code-header">pub fn <a href="#method.key_metadata" class="fn">key_metadata</a>(&self) -> &<a class="struct" href="struct.StandardKeyMetadata.html" title="struct iceberg::encryption::StandardKeyMetadata">StandardKeyMetadata</a></h4></section></summary><div class="d [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.into_inner" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#104-106">Source</a><h4 class="code-header">pub fn <a href="#method.into_inner" class="fn">into_inner</a>(self) -> <a class="struct" href="../io/struct.InputFile.html" title="struct iceberg::io::InputFile">InputFile</a></h4></section></summary><div class="docblock"><p>Consumes self and returns the under [...]
+</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Debug-for-EncryptedInputFile" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#109-115">Source</a><a href="#impl-Debug-for-EncryptedInputFile" class="anchor">§</a><h3 class= [...]
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/nightly/src/core/any.rs.html#142">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href [...]
T: CastFrom<U>,</div></h4></section></summary><div class='docblock'>Casts <code>self</code> to type <code>T</code>. The <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics">semantics of numeric casting</a> with the <code>as</code> operator are followed, so <code><T as As>::as_::<U></code> can be used in the same way as <code>T as U</code> for numeric conversions. <a>Read more</a></div></details></div></details><details class="toggle [...]
T: <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a>,</div></h3></section></summary><div class="impl-items"><section id="method.as_any" class="method trait-impl"><a href="#method.as_any" class="anchor">§</a><h4 class="code-header">fn <a class="fn">as_any</a>(&self) -> &(dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a> + 'static)</h4 [...]
diff --git a/api/iceberg/encryption/struct.EncryptedOutputFile.html b/api/iceberg/encryption/struct.EncryptedOutputFile.html
index 67bb7737e..dbe864f06 100644
--- a/api/iceberg/encryption/struct.EncryptedOutputFile.html
+++ b/api/iceberg/encryption/struct.EncryptedOutputFile.html
@@ -1,13 +1,16 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="An AGS1 stream-encrypted output file wrapping a plain `OutputFile`."><title>EncryptedOutputFile in iceberg::encryption - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35d [...]
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="An AGS1 stream-encrypted output file wrapping a plain `OutputFile`."><title>EncryptedOutputFile in iceberg::encryption - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35d [...]
<p>Transparently encrypts on write.</p>
-</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-EncryptedOutputFile" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#112-157">Source</a><a href="#impl-EncryptedOutputFile" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.EncryptedOutpu [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.key_metadata" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#122-124">Source</a><h4 class="code-header">pub fn <a href="#method.key_metadata" class="fn">key_metadata</a>(&self) -> &<a class="struct" href="struct.StandardKeyMetadata.html" title="struct iceberg::encryption::StandardKeyMetadata">StandardKeyMetadata</a></h4></section></summary><div class=" [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.location" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#127-129">Source</a><h4 class="code-header">pub fn <a href="#method.location" class="fn">location</a>(&self) -> &<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.str.html">str</a></h4></section></summary><div class="docblock"><p>Absolute path of the file.</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.writer" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#132-139">Source</a><h4 class="code-header">pub async fn <a href="#method.writer" class="fn">writer</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct all [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.write" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#142-146">Source</a><h4 class="code-header">pub async fn <a href="#method.write" class="fn">write</a>(&self, bs: Bytes) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>> [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.delete" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#149-151">Source</a><h4 class="code-header">pub async fn <a href="#method.delete" class="fn">delete</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>></h4></s [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.into_inner" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#154-156">Source</a><h4 class="code-header">pub fn <a href="#method.into_inner" class="fn">into_inner</a>(self) -> <a class="struct" href="../io/struct.OutputFile.html" title="struct iceberg::io::OutputFile">OutputFile</a></h4></section></summary><div class="docblock"><p>Consumes self and returns the un [...]
-</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Debug-for-EncryptedOutputFile" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#159-165">Source</a><a href="#impl-Debug-for-EncryptedOutputFile" class="anchor">§</a><h3 clas [...]
+</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-EncryptedOutputFile" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#125-175">Source</a><a href="#impl-EncryptedOutputFile" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.EncryptedOutpu [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.key_metadata_with_saved_file_metadata" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#135-142">Source</a><h4 class="code-header">pub fn <a href="#method.key_metadata_with_saved_file_metadata" class="fn">key_metadata_with_saved_file_metadata</a>(
+ &self,
+ file_metadata: &<a class="struct" href="../io/struct.FileMetadata.html" title="struct iceberg::io::FileMetadata">FileMetadata</a>,
+) -> <a class="struct" href="struct.StandardKeyMetadata.html" title="struct iceberg::encryption::StandardKeyMetadata">StandardKeyMetadata</a></h4></section></summary><div class="docblock"><p>Returns key metadata using the encrypted size returned by <a href="../io/trait.FileWrite.html#tymethod.close" title="method iceberg::io::FileWrite::close"><code>FileWrite::close</code></a> or <a href="struct.EncryptedOutputFile.html#method.write" title="method iceberg::encryption::EncryptedOutputF [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.location" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#145-147">Source</a><h4 class="code-header">pub fn <a href="#method.location" class="fn">location</a>(&self) -> &<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.str.html">str</a></h4></section></summary><div class="docblock"><p>Absolute path of the file.</p>
+</div></details><details class="toggle method-toggle" open><summary><section id="method.writer" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#150-157">Source</a><h4 class="code-header">pub async fn <a href="#method.writer" class="fn">writer</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct all [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.write" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#160-164">Source</a><h4 class="code-header">pub async fn <a href="#method.write" class="fn">write</a>(&self, bs: Bytes) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="../io/struct.FileMetadata.html" title="struct iceberg::io::FileMetadata" [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.delete" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#167-169">Source</a><h4 class="code-header">pub async fn <a href="#method.delete" class="fn">delete</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>></h4></s [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.into_inner" class="method"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#172-174">Source</a><h4 class="code-header">pub fn <a href="#method.into_inner" class="fn">into_inner</a>(self) -> <a class="struct" href="../io/struct.OutputFile.html" title="struct iceberg::io::OutputFile">OutputFile</a></h4></section></summary><div class="docblock"><p>Consumes self and returns the un [...]
+</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Debug-for-EncryptedOutputFile" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/io.rs.html#177-183">Source</a><a href="#impl-Debug-for-EncryptedOutputFile" class="anchor">§</a><h3 clas [...]
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/nightly/src/core/any.rs.html#142">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href [...]
T: CastFrom<U>,</div></h4></section></summary><div class='docblock'>Casts <code>self</code> to type <code>T</code>. The <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics">semantics of numeric casting</a> with the <code>as</code> operator are followed, so <code><T as As>::as_::<U></code> can be used in the same way as <code>T as U</code> for numeric conversions. <a>Read more</a></div></details></div></details><details class="toggle [...]
T: <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a>,</div></h3></section></summary><div class="impl-items"><section id="method.as_any" class="method trait-impl"><a href="#method.as_any" class="anchor">§</a><h4 class="code-header">fn <a class="fn">as_any</a>(&self) -> &(dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a> + 'static)</h4 [...]
diff --git a/api/iceberg/encryption/struct.StandardKeyMetadata.html b/api/iceberg/encryption/struct.StandardKeyMetadata.html
index fed4001d5..77ac613a0 100644
--- a/api/iceberg/encryption/struct.StandardKeyMetadata.html
+++ b/api/iceberg/encryption/struct.StandardKeyMetadata.html
@@ -5,10 +5,10 @@ serialization.</p>
<p>Wire format: <code>[version byte (0x01)] [Avro binary datum]</code></p>
</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-StandardKeyMetadata" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#60-108">Source</a><a href="#impl-StandardKeyMetadata" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.Stand [...]
</div></details><details class="toggle method-toggle" open><summary><section id="method.with_aad_prefix" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#73-76">Source</a><h4 class="code-header">pub fn <a href="#method.with_aad_prefix" class="fn">with_aad_prefix</a>(self, aad_prefix: &[<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u8.html">u8</a>]) -> Self</h4></section></summary><div class="docblock"><p>A [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.with_file_length" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#79-82">Source</a><h4 class="code-header">pub fn <a href="#method.with_file_length" class="fn">with_file_length</a>(self, length: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u64.html">u64</a>) -> Self</h4></section></summary><div class="docblock"><p>Adds a [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.with_file_length" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#79-82">Source</a><h4 class="code-header">pub fn <a href="#method.with_file_length" class="fn">with_file_length</a>(self, length: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u64.html">u64</a>) -> Self</h4></section></summary><div class="docblock"><p>Sets th [...]
</div></details><details class="toggle method-toggle" open><summary><section id="method.encryption_key" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#85-87">Source</a><h4 class="code-header">pub fn <a href="#method.encryption_key" class="fn">encryption_key</a>(&self) -> &<a class="struct" href="struct.SecureKey.html" title="struct iceberg::encryption::SecureKey">SecureKey</a></h4></section></summary><div class="docblock"><p>Ret [...]
</div></details><details class="toggle method-toggle" open><summary><section id="method.aad_prefix" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#90-92">Source</a><h4 class="code-header">pub fn <a href="#method.aad_prefix" class="fn">aad_prefix</a>(&self) -> <a class="enum" href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html" title="enum core::option::Option">Option</a><&[<a class="primitive" href="https://d [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.file_length" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#95-97">Source</a><h4 class="code-header">pub fn <a href="#method.file_length" class="fn">file_length</a>(&self) -> <a class="enum" href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="primitive" href="https://doc. [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.file_length" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#95-97">Source</a><h4 class="code-header">pub fn <a href="#method.file_length" class="fn">file_length</a>(&self) -> <a class="enum" href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="primitive" href="https://doc. [...]
</div></details><details class="toggle method-toggle" open><summary><section id="method.encode" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#100-102">Source</a><h4 class="code-header">pub fn <a href="#method.encode" class="fn">encode</a>(&self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct [...]
</div></details><details class="toggle method-toggle" open><summary><section id="method.decode" class="method"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#105-107">Source</a><h4 class="code-header">pub fn <a href="#method.decode" class="fn">decode</a>(bytes: &[<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.u8.html">u8</a>]) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><Self& [...]
</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Clone-for-StandardKeyMetadata" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/key_metadata.rs.html#37">Source</a><a href="#impl-Clone-for-StandardKeyMetadata" class="anchor">§</a><h3 [...]
diff --git a/api/iceberg/io/struct.LocalFsStorageFactory.html b/api/iceberg/io/struct.LocalFsStorageFactory.html
index 58f428629..dcbf4448a 100644
--- a/api/iceberg/io/struct.LocalFsStorageFactory.html
+++ b/api/iceberg/io/struct.LocalFsStorageFactory.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Factory for creating `LocalFsStorage` instances."><title>LocalFsStorageFactory in iceberg::io - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular- [...]
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Factory for creating `LocalFsStorage` instances."><title>LocalFsStorageFactory in iceberg::io - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular- [...]
<p>This factory implements <code>StorageFactory</code> and creates <code>LocalFsStorage</code>
instances for the “file” scheme.</p>
<h2 id="example"><a class="doc-anchor" href="#example">§</a>Example</h2>
@@ -6,9 +6,9 @@ instances for the “file” scheme.</p>
<span class="kw">let </span>factory = LocalFsStorageFactory;
<span class="kw">let </span>config = StorageConfig::new();
-<span class="kw">let </span>storage = factory.build(<span class="kw-2">&</span>config)<span class="question-mark">?</span>;</code></pre></div></div></details><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Clone-for-LocalFsStorageFactory" class="impl"><a class="src rightside" href="../../s [...]
- __D: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/de/trait.Deserializer.html" title="trait serde_core::de::Deserializer">Deserializer</a><'de>,</div></h4></section></summary><div class='docblock'>Deserialize this value from the given Serde deserializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/de/trait.Deserialize.html#tymethod.deserialize">Read more</a></div></details></div></details><details class="toggle implementors-toggle" open><summar [...]
- __S: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serializer.html" title="trait serde_core::ser::Serializer">Serializer</a>,</div></h4></section></summary><div class='docblock'>Serialize this value into the given Serde serializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serialize.html#tymethod.serialize">Read more</a></div></details></div></details><details class="toggle implementors-toggle" open><summary><section id="impl-St [...]
+<span class="kw">let </span>storage = factory.build(<span class="kw-2">&</span>config)<span class="question-mark">?</span>;</code></pre></div></div></details><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Clone-for-LocalFsStorageFactory" class="impl"><a class="src rightside" href="../../s [...]
+ __D: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/de/trait.Deserializer.html" title="trait serde_core::de::Deserializer">Deserializer</a><'de>,</div></h4></section></summary><div class='docblock'>Deserialize this value from the given Serde deserializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/de/trait.Deserialize.html#tymethod.deserialize">Read more</a></div></details></div></details><details class="toggle implementors-toggle" open><summar [...]
+ __S: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serializer.html" title="trait serde_core::ser::Serializer">Serializer</a>,</div></h4></section></summary><div class='docblock'>Serialize this value into the given Serde serializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serialize.html#tymethod.serialize">Read more</a></div></details></div></details><details class="toggle implementors-toggle" open><summary><section id="impl-St [...]
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/nightly/src/core/any.rs.html#142">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href [...]
T: CastFrom<U>,</div></h4></section></summary><div class='docblock'>Casts <code>self</code> to type <code>T</code>. The <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics">semantics of numeric casting</a> with the <code>as</code> operator are followed, so <code><T as As>::as_::<U></code> can be used in the same way as <code>T as U</code> for numeric conversions. <a>Read more</a></div></details></div></details><details class="toggle [...]
T: <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a>,</div></h3></section></summary><div class="impl-items"><section id="method.as_any" class="method trait-impl"><a href="#method.as_any" class="anchor">§</a><h4 class="code-header">fn <a class="fn">as_any</a>(&self) -> &(dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a> + 'static)</h4 [...]
diff --git a/api/iceberg/io/trait.FileRead.html b/api/iceberg/io/trait.FileRead.html
index 5ab980b7a..a1b08ac69 100644
--- a/api/iceberg/io/trait.FileRead.html
+++ b/api/iceberg/io/trait.FileRead.html
@@ -21,4 +21,4 @@ out how to handle the object safety.</p>
Self: 'async_trait,
'life0: 'async_trait,</div></h4></section></summary><div class="docblock"><p>Read file content with given range.</p>
<p>TODO: we can support reading non-contiguous bytes in the future.</p>
-</div></details></div><h2 id="implementors" class="section-header">Implementors<a href="#implementors" class="anchor">§</a></h2><div id="implementors-list"><div class="negative-marker"></div><section id="impl-FileRead-for-AesGcmFileRead" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#255-349">Source</a><a href="#impl-FileRead-for-AesGcmFileRead" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="trait.FileRead.html" title="tra [...]
\ No newline at end of file
+</div></details></div><h2 id="implementors" class="section-header">Implementors<a href="#implementors" class="anchor">§</a></h2><div id="implementors-list"><div class="negative-marker"></div><section id="impl-FileRead-for-AesGcmFileRead" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#248-347">Source</a><a href="#impl-FileRead-for-AesGcmFileRead" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="trait.FileRead.html" title="tra [...]
\ No newline at end of file
diff --git a/api/iceberg/io/trait.FileWrite.html b/api/iceberg/io/trait.FileWrite.html
index c87689404..4496467c3 100644
--- a/api/iceberg/io/trait.FileWrite.html
+++ b/api/iceberg/io/trait.FileWrite.html
@@ -11,7 +11,7 @@
'life0: 'async_trait</span>;
<span class="item-spacer"></span> fn <a href="#tymethod.close" class="fn">close</a><'life0, 'async_trait>(
&'life0 mut self,
- ) -> <a class="struct" href="https://doc.rust-lang.org/nightly/core/pin/struct.Pin.html" title="struct core::pin::Pin">Pin</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a><Output = <a class="type" href="../type.Result.html" title="type iceb [...]
+ ) -> <a class="struct" href="https://doc.rust-lang.org/nightly/core/pin/struct.Pin.html" title="struct core::pin::Pin">Pin</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a><Output = <a class="type" href="../type.Result.html" title="type iceb [...]
<span class="where">where Self: 'async_trait,
'life0: 'async_trait</span>;
}</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Trait for writing file.</p>
@@ -27,8 +27,8 @@ out how to handle the object safety.</p>
<p>TODO: we can support writing non-contiguous bytes in the future.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="tymethod.close" class="method"><a class="src rightside" href="../../src/iceberg/io/file_io.rs.html#381">Source</a><h4 class="code-header">fn <a href="#tymethod.close" class="fn">close</a><'life0, 'async_trait>(
&'life0 mut self,
-) -> <a class="struct" href="https://doc.rust-lang.org/nightly/core/pin/struct.Pin.html" title="struct core::pin::Pin">Pin</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a><Output = <a class="type" href="../type.Result.html" title="type iceberg: [...]
+) -> <a class="struct" href="https://doc.rust-lang.org/nightly/core/pin/struct.Pin.html" title="struct core::pin::Pin">Pin</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a><Output = <a class="type" href="../type.Result.html" title="type iceberg: [...]
Self: 'async_trait,
- 'life0: 'async_trait,</div></h4></section></summary><div class="docblock"><p>Close file.</p>
+ 'life0: 'async_trait,</div></h4></section></summary><div class="docblock"><p>Close the file and return its stored size, including encryption overhead for encrypted files.</p>
<p>Calling close on closed file will generate an error.</p>
-</div></details></div><h2 id="implementors" class="section-header">Implementors<a href="#implementors" class="anchor">§</a></h2><div id="implementors-list"><div class="negative-marker"></div><section id="impl-FileWrite-for-AesGcmFileWrite" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#463-521">Source</a><a href="#impl-FileWrite-for-AesGcmFileWrite" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="trait.FileWrite.html" title [...]
\ No newline at end of file
+</div></details></div><h2 id="implementors" class="section-header">Implementors<a href="#implementors" class="anchor">§</a></h2><div id="implementors-list"><div class="negative-marker"></div><section id="impl-FileWrite-for-AesGcmFileWrite" class="impl"><a class="src rightside" href="../../src/iceberg/encryption/stream.rs.html#461-519">Source</a><a href="#impl-FileWrite-for-AesGcmFileWrite" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="trait.FileWrite.html" title [...]
\ No newline at end of file
diff --git a/api/iceberg/io/trait.StorageFactory.html b/api/iceberg/io/trait.StorageFactory.html
index 1f3c4b917..c03b4b5fd 100644
--- a/api/iceberg/io/trait.StorageFactory.html
+++ b/api/iceberg/io/trait.StorageFactory.html
@@ -34,4 +34,4 @@ if the storage could not be created.</p>
S: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serializer.html" title="trait serde_core::ser::Serializer">Serializer</a>,</div></h4></section></summary><div class='docblock'>Serialize this value into the given Serde serializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serialize.html#tymethod.serialize">Read more</a></div></details></div></details><details class="toggle implementors-toggle" open><summary><section id="impl-Seri [...]
S: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serializer.html" title="trait serde_core::ser::Serializer">Serializer</a>,</div></h4></section></summary><div class='docblock'>Serialize this value into the given Serde serializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serialize.html#tymethod.serialize">Read more</a></div></details></div></details><details class="toggle implementors-toggle" open><summary><section id="impl-Seri [...]
S: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serializer.html" title="trait serde_core::ser::Serializer">Serializer</a>,</div></h4></section></summary><div class='docblock'>Serialize this value into the given Serde serializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serialize.html#tymethod.serialize">Read more</a></div></details></div></details><details class="toggle implementors-toggle" open><summary><section id="impl-Seri [...]
- S: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serializer.html" title="trait serde_core::ser::Serializer">Serializer</a>,</div></h4></section></summary><div class='docblock'>Serialize this value into the given Serde serializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serialize.html#tymethod.serialize">Read more</a></div></details></div></details></div><h2 id="implementors" class="section-header">Implementors<a href="#impleme [...]
\ No newline at end of file
+ S: <a class="trait" href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serializer.html" title="trait serde_core::ser::Serializer">Serializer</a>,</div></h4></section></summary><div class='docblock'>Serialize this value into the given Serde serializer. <a href="https://docs.rs/serde_core/1.0.228/serde_core/ser/trait.Serialize.html#tymethod.serialize">Read more</a></div></details></div></details></div><h2 id="implementors" class="section-header">Implementors<a href="#impleme [...]
\ No newline at end of file
diff --git a/api/iceberg/puffin/struct.PuffinWriter.html b/api/iceberg/puffin/struct.PuffinWriter.html
index 13c2c2c8b..cdb13f625 100644
--- a/api/iceberg/puffin/struct.PuffinWriter.html
+++ b/api/iceberg/puffin/struct.PuffinWriter.html
@@ -1,5 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Puffin writer"><title>PuffinWriter in iceberg::puffin - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf [...]
-</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-PuffinWriter" class="impl"><a class="src rightside" href="../../src/iceberg/puffin/writer.rs.html#41-175">Source</a><a href="#impl-PuffinWriter" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.PuffinWriter.html" title="str [...]
+</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-PuffinWriter" class="impl"><a class="src rightside" href="../../src/iceberg/puffin/writer.rs.html#41-174">Source</a><a href="#impl-PuffinWriter" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.PuffinWriter.html" title="str [...]
output_file: &<a class="struct" href="../io/struct.OutputFile.html" title="struct iceberg::io::OutputFile">OutputFile</a>,
properties: <a class="struct" href="https://doc.rust-lang.org/nightly/std/collections/hash/map/struct.HashMap.html" title="struct std::collections::hash::map::HashMap">HashMap</a><<a class="struct" href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>, <a class="struct" href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
compress_footer: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.bool.html">bool</a>,
@@ -17,7 +17,7 @@ an unencrypted writer would produce.</p>
blob: <a class="struct" href="struct.Blob.html" title="struct iceberg::puffin::Blob">Blob</a>,
compression_codec: <a class="enum" href="../compression/enum.CompressionCodec.html" title="enum iceberg::compression::CompressionCodec">CompressionCodec</a>,
) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>></h4></section></summary><div class="docblock"><p>Adds blob to Puffin file</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.close" class="method"><a class="src rightside" href="../../src/iceberg/puffin/writer.rs.html#121-126">Source</a><h4 class="code-header">pub async fn <a href="#method.close" class="fn">close</a>(self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>></h4></section>< [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.close" class="method"><a class="src rightside" href="../../src/iceberg/puffin/writer.rs.html#121-125">Source</a><h4 class="code-header">pub async fn <a href="#method.close" class="fn">close</a>(self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="../io/struct.FileMetadata.html" title="struct iceberg::io::FileMetadata">IoFileMetadata< [...]
</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-PuffinWriter" class="impl"><a href="#impl-Freeze-for-PuffinWriter" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Freeze.html" title="trait core::marker::Freeze" [...]
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/nightly/src/core/any.rs.html#142">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href [...]
T: CastFrom<U>,</div></h4></section></summary><div class='docblock'>Casts <code>self</code> to type <code>T</code>. The <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics">semantics of numeric casting</a> with the <code>as</code> operator are followed, so <code><T as As>::as_::<U></code> can be used in the same way as <code>T as U</code> for numeric conversions. <a>Read more</a></div></details></div></details><details class="toggle [...]
diff --git a/api/iceberg/spec/struct.ManifestListWriter.html b/api/iceberg/spec/struct.ManifestListWriter.html
index 0ae72105d..7311c6bad 100644
--- a/api/iceberg/spec/struct.ManifestListWriter.html
+++ b/api/iceberg/spec/struct.ManifestListWriter.html
@@ -1,5 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="A manifest list writer."><title>ManifestListWriter in iceberg::spec - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-Me [...]
-</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-ManifestListWriter" class="impl"><a class="src rightside" href="../../src/iceberg/spec/manifest_list/writer.rs.html#51-281">Source</a><a href="#impl-ManifestListWriter" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.Manif [...]
+</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-ManifestListWriter" class="impl"><a class="src rightside" href="../../src/iceberg/spec/manifest_list/writer.rs.html#51-280">Source</a><a href="#impl-ManifestListWriter" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.Manif [...]
</div></details><details class="toggle method-toggle" open><summary><section id="method.v1" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest_list/writer.rs.html#58-74">Source</a><h4 class="code-header">pub fn <a href="#method.v1" class="fn">v1</a>(
writer: <a class="struct" href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a><dyn <a class="trait" href="../io/trait.FileWrite.html" title="trait iceberg::io::FileWrite">FileWrite</a>>,
snapshot_id: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.i64.html">i64</a>,
@@ -25,7 +25,7 @@
<p>If V3 Manifests are added and the <code>first_row_id</code> of any data manifest is unassigned,
it will be assigned based on the <code>next_row_id</code> of the writer, and the <code>next_row_id</code> of the writer will be updated accordingly.
If <code>first_row_id</code> is already assigned, it will be validated against the <code>next_row_id</code> of the writer.</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.close" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest_list/writer.rs.html#200-205">Source</a><h4 class="code-header">pub async fn <a href="#method.close" class="fn">close</a>(self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>></h4 [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.close" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest_list/writer.rs.html#200-204">Source</a><h4 class="code-header">pub async fn <a href="#method.close" class="fn">close</a>(self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="../io/struct.FileMetadata.html" title="struct iceberg::io::FileMetadata">Fil [...]
</div></details></div></details></div><h2 id="trait-implementations" class="section-header">Trait Implementations<a href="#trait-implementations" class="anchor">§</a></h2><div id="trait-implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Debug-for-ManifestListWriter" class="impl"><a class="src rightside" href="../../src/iceberg/spec/manifest_list/writer.rs.html#42-49">Source</a><a href="#impl-Debug-for-ManifestListWriter" class="anchor">§</a> [...]
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/nightly/src/core/any.rs.html#142">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href [...]
T: CastFrom<U>,</div></h4></section></summary><div class='docblock'>Casts <code>self</code> to type <code>T</code>. The <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics">semantics of numeric casting</a> with the <code>as</code> operator are followed, so <code><T as As>::as_::<U></code> can be used in the same way as <code>T as U</code> for numeric conversions. <a>Read more</a></div></details></div></details><details class="toggle [...]
diff --git a/api/iceberg/spec/struct.ManifestWriter.html b/api/iceberg/spec/struct.ManifestWriter.html
index d1e409d5f..6c47e53a8 100644
--- a/api/iceberg/spec/struct.ManifestWriter.html
+++ b/api/iceberg/spec/struct.ManifestWriter.html
@@ -1,12 +1,12 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="A manifest writer."><title>ManifestWriter in iceberg::spec - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItali [...]
-</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-ManifestWriter" class="impl"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#220-526">Source</a><a href="#impl-ManifestWriter" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.ManifestWriter.ht [...]
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="A manifest writer."><title>ManifestWriter in iceberg::spec - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItali [...]
+</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-ManifestWriter" class="impl"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#208-513">Source</a><a href="#impl-ManifestWriter" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.ManifestWriter.ht [...]
&mut self,
data_file: <a class="struct" href="struct.DataFile.html" title="struct iceberg::spec::DataFile">DataFile</a>,
sequence_number: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.i64.html">i64</a>,
) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>></h4></section></summary><div class="docblock"><p>Add file as an added entry with a specific sequence number. The entry’s snapshot ID will be this manifest’s snapshot ID. The entry’s data sequence
number will be the provided data sequence number. The entry’s file sequence number will be
assigned at commit.</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.add_delete_file" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#347-363">Source</a><h4 class="code-header">pub fn <a href="#method.add_delete_file" class="fn">add_delete_file</a>(
+</div></details><details class="toggle method-toggle" open><summary><section id="method.add_delete_file" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#333-349">Source</a><h4 class="code-header">pub fn <a href="#method.add_delete_file" class="fn">add_delete_file</a>(
&mut self,
data_file: <a class="struct" href="struct.DataFile.html" title="struct iceberg::spec::DataFile">DataFile</a>,
sequence_number: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.i64.html">i64</a>,
@@ -14,7 +14,7 @@ assigned at commit.</p>
) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>></h4></section></summary><div class="docblock"><p>Add a file as delete manifest entry. The entry’s snapshot ID will be this manifest’s snapshot ID.
However, the original data and file sequence numbers of the file must be preserved when
the file is marked as deleted.</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.add_existing_file" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#380-397">Source</a><h4 class="code-header">pub fn <a href="#method.add_existing_file" class="fn">add_existing_file</a>(
+</div></details><details class="toggle method-toggle" open><summary><section id="method.add_existing_file" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#366-383">Source</a><h4 class="code-header">pub fn <a href="#method.add_existing_file" class="fn">add_existing_file</a>(
&mut self,
data_file: <a class="struct" href="struct.DataFile.html" title="struct iceberg::spec::DataFile">DataFile</a>,
snapshot_id: <a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.i64.html">i64</a>,
@@ -22,8 +22,8 @@ the file is marked as deleted.</p>
file_sequence_number: <a class="enum" href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.i64.html">i64</a>>,
) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.unit.html">()</a>></h4></section></summary><div class="docblock"><p>Add an file as existing manifest entry. The original data and file sequence numbers, snapshot ID,
which were assigned at commit, must be preserved when adding an existing entry.</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.write_manifest_file" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#434-525">Source</a><h4 class="code-header">pub async fn <a href="#method.write_manifest_file" class="fn">write_manifest_file</a>(self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="struct.ManifestFile.html" title="struct [...]
-</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-ManifestWriter" class="impl"><a href="#impl-Freeze-for-ManifestWriter" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Freeze.html" title="trait core::marker::Fre [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.write_manifest_file" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#420-512">Source</a><h4 class="code-header">pub async fn <a href="#method.write_manifest_file" class="fn">write_manifest_file</a>(self) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><<a class="struct" href="struct.ManifestFile.html" title="struct [...]
+</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-ManifestWriter" class="impl"><a href="#impl-Freeze-for-ManifestWriter" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Freeze.html" title="trait core::marker::Fre [...]
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/nightly/src/core/any.rs.html#142">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href [...]
T: CastFrom<U>,</div></h4></section></summary><div class='docblock'>Casts <code>self</code> to type <code>T</code>. The <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics">semantics of numeric casting</a> with the <code>as</code> operator are followed, so <code><T as As>::as_::<U></code> can be used in the same way as <code>T as U</code> for numeric conversions. <a>Read more</a></div></details></div></details><details class="toggle [...]
T: <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a>,</div></h3></section></summary><div class="impl-items"><section id="method.as_any" class="method trait-impl"><a href="#method.as_any" class="anchor">§</a><h4 class="code-header">fn <a class="fn">as_any</a>(&self) -> &(dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a> + 'static)</h4 [...]
diff --git a/api/iceberg/spec/struct.ManifestWriterBuilder.html b/api/iceberg/spec/struct.ManifestWriterBuilder.html
index 5c7c3c1df..a7874f344 100644
--- a/api/iceberg/spec/struct.ManifestWriterBuilder.html
+++ b/api/iceberg/spec/struct.ManifestWriterBuilder.html
@@ -1,23 +1,23 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="The builder used to create a `ManifestWriter`."><title>ManifestWriterBuilder in iceberg::spec - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular- [...]
-</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-ManifestWriterBuilder" class="impl"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#57-194">Source</a><a href="#impl-ManifestWriterBuilder" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.Mani [...]
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="The builder used to create a `ManifestWriter`."><title>ManifestWriterBuilder in iceberg::spec - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular- [...]
+</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-ManifestWriterBuilder" class="impl"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#79-184">Source</a><a href="#impl-ManifestWriterBuilder" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.Mani [...]
output: <a class="struct" href="../io/struct.OutputFile.html" title="struct iceberg::io::OutputFile">OutputFile</a>,
snapshot_id: <a class="enum" href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.i64.html">i64</a>>,
schema: <a class="type" href="type.SchemaRef.html" title="type iceberg::spec::SchemaRef">SchemaRef</a>,
partition_spec: <a class="struct" href="struct.PartitionSpec.html" title="struct iceberg::spec::PartitionSpec">PartitionSpec</a>,
) -> Self</h4></section></summary><div class="docblock"><p>Create a new builder for unencrypted manifests.</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.new_from_encrypted" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#79-95">Source</a><h4 class="code-header">pub fn <a href="#method.new_from_encrypted" class="fn">new_from_encrypted</a>(
+</div></details><details class="toggle method-toggle" open><summary><section id="method.new_from_encrypted" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#100-114">Source</a><h4 class="code-header">pub fn <a href="#method.new_from_encrypted" class="fn">new_from_encrypted</a>(
encrypted_output: <a class="struct" href="../encryption/struct.EncryptedOutputFile.html" title="struct iceberg::encryption::EncryptedOutputFile">EncryptedOutputFile</a>,
snapshot_id: <a class="enum" href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.i64.html">i64</a>>,
schema: <a class="type" href="type.SchemaRef.html" title="type iceberg::spec::SchemaRef">SchemaRef</a>,
partition_spec: <a class="struct" href="struct.PartitionSpec.html" title="struct iceberg::spec::PartitionSpec">PartitionSpec</a>,
) -> <a class="type" href="../type.Result.html" title="type iceberg::Result">Result</a><Self></h4></section></summary><div class="docblock"><p>Create a new builder from an <a href="../encryption/struct.EncryptedOutputFile.html" title="struct iceberg::encryption::EncryptedOutputFile"><code>EncryptedOutputFile</code></a>.</p>
<p>Use this when writing manifests with transparent encryption.</p>
-</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v1" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#98-114">Source</a><h4 class="code-header">pub fn <a href="#method.build_v1" class="fn">build_v1</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p>Build a <a href="struct. [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v2_data" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#117-134">Source</a><h4 class="code-header">pub fn <a href="#method.build_v2_data" class="fn">build_v2_data</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p>Build a [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v2_deletes" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#137-153">Source</a><h4 class="code-header">pub fn <a href="#method.build_v2_deletes" class="fn">build_v2_deletes</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v3_data" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#156-174">Source</a><h4 class="code-header">pub fn <a href="#method.build_v3_data" class="fn">build_v3_data</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p>Build a [...]
-</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v3_deletes" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#177-193">Source</a><h4 class="code-header">pub fn <a href="#method.build_v3_deletes" class="fn">build_v3_deletes</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p [...]
-</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-ManifestWriterBuilder" class="impl"><a href="#impl-Freeze-for-ManifestWriterBuilder" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Freeze.html" title="trait cor [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v1" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#117-126">Source</a><h4 class="code-header">pub fn <a href="#method.build_v1" class="fn">build_v1</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p>Build a <a href="struct [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v2_data" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#129-139">Source</a><h4 class="code-header">pub fn <a href="#method.build_v2_data" class="fn">build_v2_data</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p>Build a [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v2_deletes" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#142-151">Source</a><h4 class="code-header">pub fn <a href="#method.build_v2_deletes" class="fn">build_v2_deletes</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v3_data" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#154-171">Source</a><h4 class="code-header">pub fn <a href="#method.build_v3_data" class="fn">build_v3_data</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p>Build a [...]
+</div></details><details class="toggle method-toggle" open><summary><section id="method.build_v3_deletes" class="method"><a class="src rightside" href="../../src/iceberg/spec/manifest/writer.rs.html#174-183">Source</a><h4 class="code-header">pub fn <a href="#method.build_v3_deletes" class="fn">build_v3_deletes</a>(self) -> <a class="struct" href="struct.ManifestWriter.html" title="struct iceberg::spec::ManifestWriter">ManifestWriter</a></h4></section></summary><div class="docblock"><p [...]
+</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-ManifestWriterBuilder" class="impl"><a href="#impl-Freeze-for-ManifestWriterBuilder" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Freeze.html" title="trait cor [...]
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/nightly/src/core/any.rs.html#142">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href [...]
T: CastFrom<U>,</div></h4></section></summary><div class='docblock'>Casts <code>self</code> to type <code>T</code>. The <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics">semantics of numeric casting</a> with the <code>as</code> operator are followed, so <code><T as As>::as_::<U></code> can be used in the same way as <code>T as U</code> for numeric conversions. <a>Read more</a></div></details></div></details><details class="toggle [...]
T: <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a>,</div></h3></section></summary><div class="impl-items"><section id="method.as_any" class="method trait-impl"><a href="#method.as_any" class="anchor">§</a><h4 class="code-header">fn <a class="fn">as_any</a>(&self) -> &(dyn <a class="trait" href="https://doc.rust-lang.org/nightly/core/any/trait.Any.html" title="trait core::any::Any">Any</a> + 'static)</h4 [...]
diff --git a/api/iceberg_storage_opendal/index.html b/api/iceberg_storage_opendal/index.html
index cf733cd5a..2678b00b9 100644
--- a/api/iceberg_storage_opendal/index.html
+++ b/api/iceberg_storage_opendal/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="OpenDAL-based storage implementation for Apache Iceberg."><title>iceberg_storage_opendal - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48 [...]
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="OpenDAL-based storage implementation for Apache Iceberg."><title>iceberg_storage_opendal - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48 [...]
<p>This crate provides <a href="enum.OpenDalStorage.html" title="enum iceberg_storage_opendal::OpenDalStorage"><code>OpenDalStorage</code></a> and <a href="enum.OpenDalStorageFactory.html" title="enum iceberg_storage_opendal::OpenDalStorageFactory"><code>OpenDalStorageFactory</code></a>,
which implement the <a href="../iceberg/io/storage/trait.Storage.html" title="trait iceberg::io::storage::Storage"><code>Storage</code></a> and
<a href="../iceberg/io/storage/trait.StorageFactory.html" title="trait iceberg::io::storage::StorageFactory"><code>StorageFactory</code></a> traits from the <code>iceberg</code> crate
diff --git a/api/search.index/002c557042.js b/api/search.index/002c557042.js
new file mode 100644
index 000000000..ea3f909e9
--- /dev/null
+++ b/api/search.index/002c557042.js
@@ -0,0 +1 @@
+rn_("BQLBAAAcsyAZ/B5jc6HOAACGIRUByAAAFVAhbBwcQcMAAFMeVB6eH0ggFYHHAAAc9CHwICMDwQCgwQAAIYPFAAAfZQEEIQAA+wNob3JnBAD9FYQHyQAAHvvGAAAh7ckAAB4qyAAAHS7MAAAhHgGuFgAA")
\ No newline at end of file
diff --git a/api/search.index/00468560f6.js b/api/search.index/00468560f6.js
new file mode 100644
index 000000000..b8904f64d
--- /dev/null
+++ b/api/search.index/00468560f6.js
@@ -0,0 +1 @@
+rn_("BQLCAACiXhyiYBxzeSHSAACrIfAhGwLJAAAgsmxyJQHFAAAmtSG6IWI4IT0hpQHBAAAUziBmzyGlAcIAABT1IGbVIfuJocMAAKofMcUAADIenB+dH/MCwgAN80gdAACeAf4BFQHLAAAWECJk+iH7/QFBAQ==")
\ No newline at end of file
diff --git a/api/search.index/0071a6f6e2.js b/api/search.index/0071a6f6e2.js
new file mode 100644
index 000000000..a0f6986a0
--- /dev/null
+++ b/api/search.index/0071a6f6e2.js
@@ -0,0 +1 @@
+rn_("JQHKAAAW+yFkISHCIRsCxQAAHEBjcgUCwAAAN9Yf1x8HIaLHHG9wIwUCywAAIYRwc/SyIAAAMwETABMAYwADxQAAHBtkZWkB+gQAAA==")
\ No newline at end of file
diff --git a/api/search.index/00a5e6bcb2.js b/api/search.index/00a5e6bcb2.js
deleted file mode 100644
index 65f25a482..000000000
--- a/api/search.index/00a5e6bcb2.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAVNx4UQiFjcxUBwgAAEvkhbeUhI4cCxwAAIf9hayMOAskAACHtYWMBBiEAACvABGBqJo2GRMQAAB4K+4Y=")
\ No newline at end of file
diff --git a/api/search.index/00cc071d94.js b/api/search.index/00cc071d94.js
deleted file mode 100644
index 93f68477c..000000000
--- a/api/search.index/00cc071d94.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AULioh8AAMkgAABgIQAAYgArAsAAAByhaXQVAsMAABaTIRIdIWJydiAjiALDAAAgx2ZzFQHEAAAQih9zHh/zAwJmcOK3GwAAWhwAAOUeAAAQAC8B/QBIScUAAB0iwwAAGozEAAAeUg==")
\ No newline at end of file
diff --git a/api/search.index/0197b9104e.js b/api/search.index/0197b9104e.js
deleted file mode 100644
index 1b104420d..000000000
--- a/api/search.index/0197b9104e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHGAAAg0h8UIXJ4H0MBwARK0QAAIZjCAAAfsccAAB5e5zUKAACACgAAkRoAAHIcAAD/HAAAUCAAAF8gAABPIQAAAQARAA==")
\ No newline at end of file
diff --git a/api/search.index/01afc1ed10.js b/api/search.index/01afc1ed10.js
deleted file mode 100644
index c49cdd360..000000000
--- a/api/search.index/01afc1ed10.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("9YHCAAATfRu8FCHCAABgH9ghQwCTwgAAE6DAAAAPguyUEAAArxAAAIkaAACUGgAAghsAADQeAADNHgAAAR8AADgfAABtHwAArh8AAFMhAABhIQAABQABEAAAAKHCAAA8GqvAIIzEAAAWk8UAAByZa8AEhOAAAAT4")
\ No newline at end of file
diff --git a/api/search.index/01e156bd2e.js b/api/search.index/01e156bd2e.js
deleted file mode 100644
index b738caf7b..000000000
--- a/api/search.index/01e156bd2e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHAAAAUiyBjrx/zAwFzAR0fAAATAALHAAAgSWZyAZUQAAArAsMAABsQYWehwwAAFx4hwwAAFh5kIQWMwAAAIs0cGiEpJSHTIeMA/SGBAMQAACDw6nAaAAA/HAAAHx0AAEceAABRHwAAWx8AAJsgAADtIAAATCEAAFkhAACUIQAAARERAQEAKwLCAAAdJGZz+wJjbg==")
\ No newline at end of file
diff --git a/api/search.index/01e1ec1253.js b/api/search.index/01e1ec1253.js
new file mode 100644
index 000000000..fc339f41a
--- /dev/null
+++ b/api/search.index/01e1ec1253.js
@@ -0,0 +1 @@
+rn_("QcEAALUQyRvTIEghscIAAKMbpQHFAAAVbiFj9yAVAckAABa1IWI4IVOFwghA4AAAHTXzggJkaWOBA8cAACFeaGl0")
\ No newline at end of file
diff --git a/api/search.index/0265f40fbc.js b/api/search.index/0265f40fbc.js
new file mode 100644
index 000000000..aedbed82c
--- /dev/null
+++ b/api/search.index/0265f40fbc.js
@@ -0,0 +1 @@
+rn_("BQLAAAAXHiEipBYoHW95ocYAACUdAUThkB8AAOQfAAAzcwDDCIjDAAAb6ckAACFo5HgMAADNDgAAuxMAAMcUAAANHAAAIgAAFYHCAAAi2yDzIVEM+wJrdA==")
\ No newline at end of file
diff --git a/api/search.index/0270a01d14.js b/api/search.index/0270a01d14.js
new file mode 100644
index 000000000..ad1cb695f
--- /dev/null
+++ b/api/search.index/0270a01d14.js
@@ -0,0 +1 @@
+rn_("RQHFAAAVbiFj9yD4IP8gACFlAsAAABT+IORqHGN07w5iDzUdPR1bHlwe4cUAAGQcJQHFAAAmtSG6IWI4IT0hpQHBAAAUziBmzyGlAcIAABT1IGbVIfuJMcUAADIenB+dH/MDwgAJ80gdAACeAf4BFQHCAAAU6R9jOB8jgQLBAAAccGVsIwADzgAAId/HAAAfnmVmcvPuDgAAZhICAOcDAMIOSMQAABxj4VQMAABrDgAABxuGyQAAH2k=")
\ No newline at end of file
diff --git a/api/search.index/02fe53f190.js b/api/search.index/02fe53f190.js
deleted file mode 100644
index a1940ac7e..000000000
--- a/api/search.index/02fe53f190.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHKAAAWQiF2aCEFhsAAACU4HLwhJTkcZh8VgcUAABz0IfEgI4ECyQAAIQVhczWEwAAAo+IbNBw1HBodUcIAAKcTqBNpGpofhCGhxAAAYyATAQLgAAAaaG1z5KMQAADvFAAALR0AAAAfAAAuHwAABRAQBQLAAAAVNxyi4Bt1eQUCwAAAFIUfG/QhY3V3HwD+wECIG8sAACDCOzAAAAEAACoAEABwDAIArw4SAIITAwCsFgEADRwAAJ0cAQDmHAEASx4BAIcfAAC+HwAASyAAAPEgAAD/IAAABSEAABYhAACGIQAAG4nBAAAfsQ==")
\ No newline at end of file
diff --git a/api/search.index/03036e27c7.js b/api/search.index/03036e27c7.js
new file mode 100644
index 000000000..6e0618c8c
--- /dev/null
+++ b/api/search.index/03036e27c7.js
@@ -0,0 +1 @@
+rn_("BQLAAAAVNh4UQSFjcxUBwgAAEvkhbeQhI4cCxwAAIf9hayMOAskAACHtYWMBBSEAACvABGBpOESaDsQAAB4J+4Y=")
\ No newline at end of file
diff --git a/api/search.index/0307fc9427.js b/api/search.index/0307fc9427.js
deleted file mode 100644
index ef469ed60..000000000
--- a/api/search.index/0307fc9427.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("pQHFAAAVbyFj+CAVAckAABa2IWI5IaODwgxAzwAAIeDgAAAdNhUByQAAFuYhZJ0hE4TACEzJAAAhqMsAACG3xwAAIYv7AmZsFQHaAAAWECJk+iH7gw==")
\ No newline at end of file
diff --git a/api/search.index/036f5803b3.js b/api/search.index/036f5803b3.js
new file mode 100644
index 000000000..5e64efe98
--- /dev/null
+++ b/api/search.index/036f5803b3.js
@@ -0,0 +1 @@
+rn_("VQHAAACm/SFkRCFFIaohzCHNISUBygAAFv4hZEUhzSEFAsEAABetHxNoH2Vw84ECaXIVhMQAABHSIKwf8wYBZvOuGwAAjQECASUBywAAFv0hZEQhzCGh1AAA2SFbxAAMyAAAIOP7/REBAg==")
\ No newline at end of file
diff --git a/api/search.index/0370d4cc7c.js b/api/search.index/0370d4cc7c.js
new file mode 100644
index 000000000..46d3cc8cd
--- /dev/null
+++ b/api/search.index/0370d4cc7c.js
@@ -0,0 +1 @@
+rn_("McEAADwhgSGCIRUBwAAAHnghcL8T84OKCQLQAAAhd+YAABs3aXAF/cMCABoAABiRIRy7IRJzIBhyISMFAsUAAB8WYnABoRYAAPsDYW11")
\ No newline at end of file
diff --git a/api/search.index/0391a7a6d0.js b/api/search.index/0391a7a6d0.js
deleted file mode 100644
index 3b52364a1..000000000
--- a/api/search.index/0391a7a6d0.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHFAAAYQyFj6h7PITUBxAAAFu8hZNUg1iCxISuJwgAAHMxjAAPEAAAgtmF0deSuEwAAXBUAAD8dAADKHgAA6B4AAAIRAKHGAAAVH1WCwAAAFRQfnRrKHMscEB8RH/sCZnQbisUAAB5NIcAAAOgbSiChxAAAex9jAcAIQsMAACFH5UwbAAAgHwAAuR8AAOkfAACcIQAA6SEAANAAATUBxAAAFuchZFIgUyCeIRcZA/0niQfCAAAdIcMAACEZxAAAHunBAAAanMgAACEkxwAAId/npBAAAAERAAB7GgAAjxsAAGoeAABZIAAAJSEAANMhAAAEEAAAKwLAAAAMc3Bz")
\ No newline at end of file
diff --git a/api/search.index/03a18b59f4.js b/api/search.index/03a18b59f4.js
new file mode 100644
index 000000000..181f7e2ac
--- /dev/null
+++ b/api/search.index/03a18b59f4.js
@@ -0,0 +1 @@
+rn_("JQHEAAAWCyJklSHyISHJAABEHS0eYwADxwAAIUJjZWzpUwoAAEkMAABtDQAAAA8AAI4PAADNEAAAwxQAAHQbAADpHgAAziEAABMQIAAA")
\ No newline at end of file
diff --git a/api/search.index/043de39544.js b/api/search.index/043de39544.js
deleted file mode 100644
index 13efd9994..000000000
--- a/api/search.index/043de39544.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("wcoAAIMgockAAMMgJYTFAAAhmx8HIesdWiD7hhUDxgAAMbkf6R+cIRbPIRjfIWlzdGoepQHBAACkYyBtLh8TBALBAAAfmmly5OYcAABLHgAAhx8AAL4fAAAWIQAAEQAA+wJjbsHFAADnHQUCwwAAwyofFf4ecHPzAMMIYPOeDgAAmAApDA==")
\ No newline at end of file
diff --git a/api/search.index/0458ed477e.js b/api/search.index/0458ed477e.js
deleted file mode 100644
index 0f80b557d..000000000
--- a/api/search.index/0458ed477e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcEAALUQyhvUIEkhscIAAKMbpQHFAAAVbyFj+CAVAckAABa2IWI5IVOFwghA4AAAHTbzggJkaWOBA8cAACFfaGl0")
\ No newline at end of file
diff --git a/api/search.index/04e32cbf6e.js b/api/search.index/04e32cbf6e.js
deleted file mode 100644
index c6753b3bb..000000000
--- a/api/search.index/04e32cbf6e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYPAAAAVLRwmiSAbIQWDwAAAElscFVweQcAAABwHXwzfDgUP4wAEwAAADuE1OGRt+CEAAABqAQMC5gBkAMQJRABKDw==")
\ No newline at end of file
diff --git a/api/search.index/04f3af8eb1.js b/api/search.index/04f3af8eb1.js
new file mode 100644
index 000000000..5c02b5479
--- /dev/null
+++ b/api/search.index/04f3af8eb1.js
@@ -0,0 +1 @@
+rn_("QcMAAJgbmRszHdAfscoAAMggFQLBAAAf7iGiOx5jciUcscUAAOEcMcIAAOsUFB8VH/MA/QBBB+EyDwAAzx4AADA=")
\ No newline at end of file
diff --git a/api/search.index/050f60d373.js b/api/search.index/050f60d373.js
new file mode 100644
index 000000000..2cf281492
--- /dev/null
+++ b/api/search.index/050f60d373.js
@@ -0,0 +1 @@
+rn_("IccAACQh0iEVAcYAABVMIXJYH0HHAAAYH98g4CBcIfMAAmZs47UTAACLFQAAlR8AAOofAAAGAPOBAm1zIcEAAMwcGSEFAsAAACHeFM4gF7wfbHP7AmVsocMAAH0au/0BSQHJAAAe08UAACFk")
\ No newline at end of file
diff --git a/api/search.index/051982de53.js b/api/search.index/051982de53.js
deleted file mode 100644
index d41ef2700..000000000
--- a/api/search.index/051982de53.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAATWB8QSRxhcwUCwwAAp2Yhop8gZHNTAcAIBsQAAB/C0qQaAAC4BQLAAAATGh4QoxphcwUCwAAAFO8e4PcbaXMFAsMAAKcoIaLAH2Rz8wDACIbjsxMAAGMVAAD9IAAA3yEAABQA")
\ No newline at end of file
diff --git a/api/search.index/0580601cd6.js b/api/search.index/0580601cd6.js
deleted file mode 100644
index 61f101a0b..000000000
--- a/api/search.index/0580601cd6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHEAAAWCyJkliHyISMAAscAACFDY2zkAA8AAI4PAAB0GwAA6h4AAM8hAAACAABRwQAApxOoE2kamh+EIVsD4AAACk9la3k=")
\ No newline at end of file
diff --git a/api/search.index/0586a76b0b.js b/api/search.index/0586a76b0b.js
new file mode 100644
index 000000000..93faa383c
--- /dev/null
+++ b/api/search.index/0586a76b0b.js
@@ -0,0 +1 @@
+rn_("IcAAAOcbSSChxAAAeh9jAMAIQsMAACFG68ATAABiFQAAWBoAAEwbAACmHAAAqBwAALQcAAAfHwAAuB8AAOgfAACbIQAA6CEAAAANAAAAAQ==")
\ No newline at end of file
diff --git a/api/search.index/05af641484.js b/api/search.index/05af641484.js
new file mode 100644
index 000000000..75e87b64a
--- /dev/null
+++ b/api/search.index/05af641484.js
@@ -0,0 +1 @@
+rn_("IcgAAO0fEiEhwwAA/xCKGhUBzQAAFg4iZPYhWwPMAAAhXm9yczUBwAAAFvchZOAcuCHUIRsCwwAAINlscvsDZWlt")
\ No newline at end of file
diff --git a/api/search.index/05d36fabac.js b/api/search.index/05d36fabac.js
deleted file mode 100644
index d569220c5..000000000
--- a/api/search.index/05d36fabac.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLDAAAiqBopHiONG/sea241AcEAABh8IGKoED0dYx9FAsIAAGFNHE4cTxxJHvweDR8lHB+8IGlzVB9VH3MgtCDzAgJrbwFyIAAA+4o=")
\ No newline at end of file
diff --git a/api/search.index/05e23b7e94.js b/api/search.index/05e23b7e94.js
new file mode 100644
index 000000000..6a013ffc8
--- /dev/null
+++ b/api/search.index/05e23b7e94.js
@@ -0,0 +1 @@
+rn_("FQHRAAAWAyJk2CEVAdgAABYRImQCIhUB0AAAFgkiZOohFQHIAAAW/CFkwyEVAccAABb4IWS5IfODAnJzFQHMAAAW+yFkwiEVAcQAABYAImTTIROJAsMAACHUY2wVAcgAABb3IWS4IRUBygAAFggiZOMhFQHKAAAWByJk4iH7hRUBxgAAFuchZJ4h84EDZW1u+wJkb/OGwAYoFQHIAAAWiyFk0h8VAcwAABYFImTgIROJAsMAACFwZGsVAckAABblIWScIROEwAhMyQAAIafLAAAhtscAACGKGwLTAAAh32ZsFQHaAAAWECJk+iH7g2dNAP4AH6QdMvLIrzrLAAAhFnvKZeKYywAAIRjCAAAcLTTdrQX8AckfAAAFAsEAABTGIRXRIXFzIwIDxAAAIO7CAAAeCmFydu+aFgAAWRoAADocAAAcHQAAQh0AACUeAABCHgAAUh4AAOweAABOHwAAWR8AANMfAADHIAAA0CA [...]
\ No newline at end of file
diff --git a/api/search.index/05fe2bcf8e.js b/api/search.index/05fe2bcf8e.js
deleted file mode 100644
index e3b9cb059..000000000
--- a/api/search.index/05fe2bcf8e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHDAAAWAyJk2SETAALDAAAbe3N06/MOAABoDwAAcQ8AAM4cAAA6HgAAayAAAKkgAAC5IAAAvSAAAOYgAAAtIQAAsCEAAAAxEIAQgAUCwAAAFiEfEZAbYm+hwgAAhxtlAcEAAKQQIW2QHJEckhyTHM0gziAVgsUAABTFIE4eGwLBAAAe63V54wL9AwEDxAAAIOrDAAAe7OiwEwAAbBoAAGwbAADWHAAAnB8AALwfAADXHwAACCEAAIshAAADEAAQACUBzwAAFhIiZPUhDyJFAccAABivIWesIa0h8CHxIQFG5c4cAABrIAAAqSAAALkgAAC9IAAAsCEAABCAEBUByAAAEFsgcxgfocQAAEIc+wJvcncBAv0kyADFAAAhIOX+DgAAjQ8AACkcAAC3HAAAvxwAABUhAAAQABB3AQD+QAIAScAAAB9qOjAAAAEAAAAAABgAEAAAAIkQmxB4G30bORw5HgMfBB8IHw4fZh+ [...]
\ No newline at end of file
diff --git a/api/search.index/066bad1eee.js b/api/search.index/066bad1eee.js
deleted file mode 100644
index 7bde5b9e8..000000000
--- a/api/search.index/066bad1eee.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAVNx4UQiFjcxUBwgAAEvkhbeUhI4cCxwAAIf9hayMOAskAACHtYWMBBiEAACvABGBqJo2GRMQAAB4KawPgAAAfajFlaQ==")
\ No newline at end of file
diff --git a/api/search.index/06e7ec3344.js b/api/search.index/06e7ec3344.js
deleted file mode 100644
index 8674b17bf..000000000
--- a/api/search.index/06e7ec3344.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQPGAAARnCEWzyEY3yFpc3QrAsMAACEWY27zBQFzAV8bAAAVAc8AABYEImTeIRUByQAAFt0hZIohFQHMAAAW/iFkziEVAcwAABb9IWTNIfuF84PAAIYr/QA4CMUAACFDzAAAIe7BAAAUyKUCxQAAFmogGDwhYncnHPuZ")
\ No newline at end of file
diff --git a/api/search.index/073b9f3997.js b/api/search.index/073b9f3997.js
new file mode 100644
index 000000000..86912d16b
--- /dev/null
+++ b/api/search.index/073b9f3997.js
@@ -0,0 +1 @@
+rn_("wcoAAIIgockAAMIgJYTFAAAhmh8GIeodWSD7hhUDxgAAMbgf6B+bIRbOIRjeIWlzdGkepQHBAACkYiBtLR8TBALBAAAfmWly5OUcAABKHgAAhh8AAL0fAAAVIQAAEQAA+wJjbsHFAADmHQUCwwAAwykfFf0ecHPzAMMIYPOeDgAAmAApDA==")
\ No newline at end of file
diff --git a/api/search.index/07d7dab63f.js b/api/search.index/07d7dab63f.js
deleted file mode 100644
index f3970990d..000000000
--- a/api/search.index/07d7dab63f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHLAAAWESJkAiIbAtIAACIBYXMhxQAAsBvvIQEEAcgAACEqcIn9GwAApYHIAAAV8CBbH6WBxAAAFYUfnRzzAAJjdOGAEAAA9BsAADEVgcgAABXvIFofKwLNAAAhTmFyBQLLAAAUxyEV0iFxc/MIAXCJ8R4AAKWBxwAAFXcgHR6lAc0AABTcIWYMIiMAwADCwAAAHfbHAAAg/QF/EAAA8wLABM3hqBYAAKEaAAAR+4c=")
\ No newline at end of file
diff --git a/api/search.index/0855a8d908.js b/api/search.index/0855a8d908.js
deleted file mode 100644
index 21caf2056..000000000
--- a/api/search.index/0855a8d908.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("NQHFAAAWtSBisxxsHm0eFQLAAAAXZSEVUCFmdNMcBQLAAAAkshxrHha9IW9yoc8AAMghFYLGAAAUZSA1HXcFAcILyMIAABzoxAAAIZXkkBAAAMETAACKHAAAqR8AAJwgAAACACAlhMIAABHTIDofrR/7AmVs")
\ No newline at end of file
diff --git a/api/search.index/0861717c7c.js b/api/search.index/0861717c7c.js
new file mode 100644
index 000000000..3b02ac58d
--- /dev/null
+++ b/api/search.index/0861717c7c.js
@@ -0,0 +1 @@
+rn_("ocIAAGAcBYbAAAARwxAaqR8FAsQAABdLIBnQIGNwAQEB4QAAFLlz6PEOAAC6EAAAVxwAAF4cAACWHAAAnhwAAG0eAAC/HwAAniAAAAgREREQS8ACgcMAACGFxwAAHxk1AccAABOoH2Z7HEUfRh8hwwAAmhy8IaWBwgAAE3gbtxRLwAKEygAAIErFAAAdQ6HHAABbIAUCwQAAtrUfELkQY3ZBxwAAJyEoIWUhZiEBAP7A5iVPwgAAIWTDAAAdKTCuTSKDej5ilkl7wRxdnkEbDsHzXvnjfv/HAAAd8XIonYZwwwAAGjZByConF2sah3hnxQAAHuQmknski0bEaXUJOzAAAAEAAAkCBgDhBAAA/QUOAQMPAACPEAAAmhH2AOcUAAA=")
\ No newline at end of file
diff --git a/api/search.index/086958a9f4.js b/api/search.index/086958a9f4.js
deleted file mode 100644
index def8769c2..000000000
--- a/api/search.index/086958a9f4.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHSAAAWCiJk7CEVAdQAABYLImTyIRUBzwAAFhIiZA8iI4wCxgAAIfFscIcDhP0o0ATKAAAhoNMAACHwygAAIaE=")
\ No newline at end of file
diff --git a/api/search.index/08c20bf822.js b/api/search.index/08c20bf822.js
new file mode 100644
index 000000000..a94b8620f
--- /dev/null
+++ b/api/search.index/08c20bf822.js
@@ -0,0 +1 @@
+rn_("JQHPAAAWEiJk9SEPIiUBxwAAGK4hZ6wh8SHzhgJscEUBwQAAEWkfdm0gASECIUIhJQLBAACmhiElJh/cIGVzsRRAHCHAAABYGrQcOwPGAAAgTmRvdgEAAswAACGD0gAAIcFhcAGnFgAAGwLCAAAb42RtFQHGAAAg0R8TIXJ3H/MDAXABkRoAABuJwwAAHQ0VAcMAABYRImQCIvMCiAFqGgAAdwcA/TVBAsYAAB9N+lcMAABrAqEAEwABAAEACwCEDB0BEwE1hMAAABOZIG8gcCADIQECAdUAACHZbQE6DwAARYHAAABIUx9UH3IgsyBcHBsfYR+7IDHAAAA/HkAeHCE1AcYAABBaIHMOHxcfuh8FhsEAABDoGzJDHEQcSyD7/SkABPsCZXlhwwAACBwJHOIe4x5HH0gf0cQAAM4bBQLAAAA/oSG9Ib4hN20gASECIWFyIwQDwAAAIIHEAAAg3mVwcwGSGgAA84ECYmO [...]
\ No newline at end of file
diff --git a/api/search.index/08c8b4743b.js b/api/search.index/08c8b4743b.js
new file mode 100644
index 000000000..0a390a3ca
--- /dev/null
+++ b/api/search.index/08c8b4743b.js
@@ -0,0 +1 @@
+rn_("YcAAAAgcCRziHuMeRx9IHyHDAACNG/oeIcIAAKgaKB4BAgHEAAAcNWjj+w4AAIYPAAD1GwAADxwAACEH8wD9ACUC6MgUAADOGwAAUx4AAB4fAACeHwAA6R8AAEggAACKIAAAGCEAAAQQAAAA")
\ No newline at end of file
diff --git a/api/search.index/08f94d670a.js b/api/search.index/08f94d670a.js
deleted file mode 100644
index 82c61d252..000000000
--- a/api/search.index/08f94d670a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQPGAAAxuR/pH5whFs8hGN8haXN0ah6xyQAAySAhxAAAXRxiH6UBwQAApGMgbS4fEwQCwQAAH5ppcuTmHAAASx4AAIcfAAC+HwAAFiEAABEAAPMA/RQhAOHdGwAAVh8AAAE=")
\ No newline at end of file
diff --git a/api/search.index/09e25262e9.js b/api/search.index/09e25262e9.js
new file mode 100644
index 000000000..056e4b630
--- /dev/null
+++ b/api/search.index/09e25262e9.js
@@ -0,0 +1 @@
+rn_("AUuJqCAAABsCxwAAIHFveQUCwAAAwxccEgQdZWwFAsAAABYmHhNoG3J1NQHFAAAWpyBjgRpeH7EgocYAACwdRw8A/kQHMALPAAAhbc4AACHsxQAAIhLS9SEAABo=")
\ No newline at end of file
diff --git a/api/search.index/09eb1cc16d.js b/api/search.index/09eb1cc16d.js
new file mode 100644
index 000000000..fdf658548
--- /dev/null
+++ b/api/search.index/09eb1cc16d.js
@@ -0,0 +1 @@
+rn_("YcIAAJsQeBt9GzgeAh/LHwEAAsQAACFM4AAAENByc+b0DgAAeg8AAEEeAABYHwAAfyAAAB4hAAB2IQAAAgAAAFvAAIXCAAAd8g==")
\ No newline at end of file
diff --git a/api/search.index/0a2c4f6e7f.js b/api/search.index/0a2c4f6e7f.js
deleted file mode 100644
index be4ce20e0..000000000
--- a/api/search.index/0a2c4f6e7f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQPGAAASgR8ZciEakSFhZXOlkMAAACK7E8cUaw0VAcQAABa5IGa3HBWQwwAAFNQgfhvzAojynBAAAC4E+wNob3I1AcEAABh8IGKoED0dYx9FAsIAAGFNHE4cTxxJHvweDR8lHB+8IGlzVB9VH3MgtCBBxAAAjhyPHEoe/R4hwwAAUx+RITHEAADGHMccqCAhxgAAACIGIvMCAWTlLx4AACUfAABjIQAAfyEAANQhAADiIQAAEQEA+wJkbjUBxQAAFlshYsQcxRx/H/uJlwEB/QQpBMAAABprwwAAIdXqiA8AAIEaAACxGgAAsRsAADocAABFHQAAUh0AAC4eAAAJHwAAXx8AALIgAAAAEgAgAABhwwAAghaDFoQWhRasGq0aFQHKAACkmiFtfiElAcYAAKQ6IW38IJchM4HACEjMAAAhdFOBlsEAACH0WwPAAAAPgWdubxUBwAAAEpUaeY8ODwjAgvbLAAAgtMEAABa [...]
\ No newline at end of file
diff --git a/api/search.index/0a3e6a35f1.js b/api/search.index/0a3e6a35f1.js
deleted file mode 100644
index e25a14952..000000000
--- a/api/search.index/0a3e6a35f1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAASuxwSuRxidBsCwQAAIV9heRUBywAAFlshYn8fKwLKAAAgknFz8wACZXTodg4AAJYTAADLFAAA6xsAAFAcAADaHgAAgh8AAOcgAABiIQAAgBgIAAA=")
\ No newline at end of file
diff --git a/api/search.index/0abb7ba7f2.js b/api/search.index/0abb7ba7f2.js
new file mode 100644
index 000000000..838e872bd
--- /dev/null
+++ b/api/search.index/0abb7ba7f2.js
@@ -0,0 +1 @@
+rn_("ocQAAAUeJQHIAAAW/CFkIiHDISUBxgAAFvghZP0guSHzAIj5fQ8AAAMLrAEOAccBWwABAEIAiwElAc8AABYSImT1IQ8idQHAAAAmtyHmIWQAHQEdAh1RIFIgFyGdITHIAADOH88fUyH7AmVzRQHHAAAYriFnqyGsIfAh8SEBRuXNHAAAaiAAAKggAAC4IAAAvCAAAK8hAAAQgBAVAcYAABBaIHMXHyOBAsEAABvoYWShxAAAQRz7Am9y9x4A/STYB8UAACEf5/4OAAB+DwAAjQ8AACgcAAC2HAAAvhwAABQhAACtIQAAEQABABMAAsEAAA8BZWyCqwEAAA==")
\ No newline at end of file
diff --git a/api/search.index/0af0419719.js b/api/search.index/0af0419719.js
deleted file mode 100644
index 087c638a0..000000000
--- a/api/search.index/0af0419719.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUE7MAAAAQAALgAJAHUMAgDLDgEAphAAAGgVIgCaHAAAQh0AABseAQAnHwAA3SAAAFUBwQAAFt0hZGYPZw/mHZkfiiEFAsAAAFCAD5YalxrfG04hFyUdc3R7/RSgANEAACGG")
\ No newline at end of file
diff --git a/api/search.index/0b2aad3376.js b/api/search.index/0b2aad3376.js
new file mode 100644
index 000000000..00cc014bc
--- /dev/null
+++ b/api/search.index/0b2aad3376.js
@@ -0,0 +1 @@
+rn_("JQLDAAAVlB8WoiF0d8IflyAVgccAABz0IfAgIwTBAKDBAAAhg8UAAB9lAQQhAAAbAswAACEeY3QVAsMAABZjHxZkH2JvfxoTgQLNAAAg3mFjAUI7MAAAAQAA6wACAIkTAACZF+oAhw4A/TGQB8sAAB9iwwAAFoHIAAAdMNAAACF2OzAAAAEAAO4ABABkCgEATQwAAG8N6gAHEQAAAQD9ABUBwgAAE43CAAATjsMAABaMxgAAHCHtOwoAABMMAACqEwAAtxMAAIEWAACXFgAAgxsAAC8cAABDHQAARR0AABkfAABkIAAAxCAAAB0hAACgAAEAAQAA+wJydzHAAACHG4gb6B4rwAxExQAAIgFteWFyo8QAABwhFQLBAAAXYh8SixBhcmMK8wCLAZQBAAA=")
\ No newline at end of file
diff --git a/api/search.index/0b34c06609.js b/api/search.index/0b34c06609.js
new file mode 100644
index 000000000..dd33044ca
--- /dev/null
+++ b/api/search.index/0b34c06609.js
@@ -0,0 +1 @@
+rn_("FQHKAAAWQSF2ZyEFhsAAACU3HLshJTgcZR8VgcUAABz0IfAgI4ECyQAAIQRhczWEwAAAo+EbMxw0HBkdUcIAAKcTqBNpGpkfgyGhxAAAYiATAQLgAAAaaG1z5KMQAADvFAAALB0AAP8eAAAtHwAABRAQBQLAAAAVNhyi3xt1eQUCwAAAFIQfG/QhY3V3HwD+wECIG8sAACDBOzAAAAEAACoAEABwDAIArw4SAIITAwCsFgEADBwAAJwcAQDlHAEASh4BAIYfAAC9HwAASiAAAPAgAAD+IAAABCEAABUhAACFIQAAG4nBAAAfsA==")
\ No newline at end of file
diff --git a/api/search.index/0b775c1ddd.js b/api/search.index/0b775c1ddd.js
new file mode 100644
index 000000000..dcc161b3a
--- /dev/null
+++ b/api/search.index/0b775c1ddd.js
@@ -0,0 +1 @@
+rn_("BQLAAAATVx8QSBxhcwUCwwAAp2Uhop4gZHNTAMAIBsQAAB/B0qQaAAC4AQABwAAADvZw4zoKAAAQDAAAyRAAAOMbAAABMKHWAADZITHGAAABH58fKiEFAsAAABKJIBFHIXR68wCEAaMgAAAxwQAAMR8yH3Ah8wICaXPk8RwAACseAACHHwAA1B8AANYgAAAhAQAlAcwAABYFImR8IeAhFQHCAAAS+SFt5CEjhwLHAAAh/2FrBQLAAACw7xAZ7SFsd/cBAv0NFALgAAAfZOJmDAAAIhkAAAUhAAABACUBwgAAF/YgbXIbcxxDAf0CRQTCAAAd8McAAB9tyAAAH8zDAAAglIO1HwAAAQMCxwAAIfPCAAAd72JkiRkZAAC3DQD9kVHAzAAAIcvgAAAOaeE6DwAAZA8AAAE=")
\ No newline at end of file
diff --git a/api/search.index/0b9b542880.js b/api/search.index/0b9b542880.js
new file mode 100644
index 000000000..8b96290f3
--- /dev/null
+++ b/api/search.index/0b9b542880.js
@@ -0,0 +1 @@
+rn_("FQHGAAAWryFmFCHzAwFzAeoUAABFhMAAAKOVG4ocixzWHtceFQHDAAAQlBtzICGhwQAA/BzzAgNpbnP1gRMAACoDuAWqALQEBYnAAAAXjCERviAFicQAABLVIRHPISOFAuAAACFUZGYFAsQAABbEIROoIW90GwLNAAAh6GhvNwGDwA5pwgAAIOfXAAAiDMMAACE+xAAAIVWhxQAAGh0VAckAABZAIWIRH/OCAmZ3QwCHxwAAHCDDAAAhQvPuBAAAJgRnCiHEAAAeIXYhFYLBAAASoRNoDPsCY3ShxgAAVxwhygAAUh+QIQUCwAAAoOIOIQARgB9uclsDyAAAIXFhZXMFAsIAAC6rIfAhFYsgc3TzAP4ATgoMgwgFAAA=")
\ No newline at end of file
diff --git a/api/search.index/0ba3963a0f.js b/api/search.index/0ba3963a0f.js
deleted file mode 100644
index e1fe2da59..000000000
--- a/api/search.index/0ba3963a0f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocQAAAYeJQHIAAAW/CFkIyHEISUBxgAAFvghZP4guiHzAIj5fQ8AAAMLrQEOAccBWwABAEIAiwElAc8AABYSImT1IQ8idQHAAAAmuCHnIWQBHQIdAx1SIFMgGCGeITHIAADPH9AfVCH7AmVzRQHHAAAYryFnrCGtIfAh8SEBRuXOHAAAayAAAKkgAAC5IAAAvSAAALAhAAAQgBAVAcYAABBbIHMYHyOBAsEAABvpYWShxAAAQhz7Am9y9x4A/STYB8UAACEg5/4OAAB+DwAAjQ8AACkcAAC3HAAAvxwAABUhAACuIQAAEQABABMAAsEAAA8BZWyCqwEAAA==")
\ No newline at end of file
diff --git a/api/search.index/0ba6daad9b.js b/api/search.index/0ba6daad9b.js
deleted file mode 100644
index c5addb495..000000000
--- a/api/search.index/0ba6daad9b.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQQBxQAAH31yidQbAAAFAssAABTHIRXSIXFzEwQCxQAAIONwcuFhHgAA8R4AAIghyAAABB83IfMBwBDAOzAAAAEAAOwAAwCSFekAKx4AAKsfAQA=")
\ No newline at end of file
diff --git a/api/search.index/0c1376fbdf.js b/api/search.index/0c1376fbdf.js
deleted file mode 100644
index 9cdff9fc4..000000000
--- a/api/search.index/0c1376fbdf.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQLDAAATqhwVKh5ub48hMcYAAIEaXx+yICHIAADXHMgfQcYAAIAaOx1dH14fJQHAAAAWLRxtnA4qHtcGAP4CBDQDxgAAG5HEAAAhLPL7BAAAixU=")
\ No newline at end of file
diff --git a/api/search.index/0d1f0b5fe3.js b/api/search.index/0d1f0b5fe3.js
new file mode 100644
index 000000000..2d4ad8796
--- /dev/null
+++ b/api/search.index/0d1f0b5fe3.js
@@ -0,0 +1 @@
+rn_("FQHKAAAWQSF2ZyEFhsAAACU3HLshJTgcZR8VgcUAABz0IfAgI4ECyQAAIQRhczWEwAAAo+EbMxw0HBkdUcIAAKcTqBNpGpkfgyEVwcCACAAA4tccU48axxvIG4cgpyHkVR6MIAWFwAAAG8EgGGAgocQAAGIgEwEC4AAAGmhtc+SjEAAA7xQAACwdAAD/HgAALR8AAAUQEAUCwAAAFTYcot8bdXkFAsAAABSEHxv0IWN19z8A/sBAqDvgAAAQijswAAABAAAqABAAcAwCAK8OEgCCEwMArBYBAAwcAACcHAEA5RwBAEoeAQCGHwAAvR8AAEogAADwIAAA/iAAAAQhAAAVIQAAhSEAAA==")
\ No newline at end of file
diff --git a/api/search.index/0dc7840bcd.js b/api/search.index/0dc7840bcd.js
deleted file mode 100644
index 568c360a9..000000000
--- a/api/search.index/0dc7840bcd.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAXdyEyMhwzHCIfb3khxgAAQh6AIPMCAmx04qMTAADjFAAAuRsAABMAIcYAAPghCyJTAQPAAAAgwmRladj+IAAAEYckDgElBCHDAAClEEocBQLAAAATWB8QSRxhcwUCwwAAp2Yhop8gZHNTAcAIBsQAAB/C0qQaAAC4BQLAAAATGh4QoxphcwUCwAAAFO8e4PcbaXMFAsMAAKcoIaLAH2Rz8wTACIbjsxMAAGMVAAD9IAAA3yEAABQAFQHAAAAWBCJk3iErAsMAABtbaXMFAsMAAKdcIKKXHGhzVwMA/aBQgsQAABw2wwAAIavp8wQAADMJAAD7DgAAhg8AAJIQAAD2GwAAEBwAACscAAAoIQAAZiEAAAAhAHARdf3BIBAZAACmbh4bzCAc8iAUYxwc8yDpDuoO6w7sDjcPOA85D3v9EYEAwAAAE40=")
\ No newline at end of file
diff --git a/api/search.index/0de17bcf12.js b/api/search.index/0de17bcf12.js
deleted file mode 100644
index ca3cd90c4..000000000
--- a/api/search.index/0de17bcf12.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQPAAAAWSiG1Uh0RTiAzZXHQIEHIAABwIXMhiSGQIUHCAABnIHQgtyDBIAUCwAAAHPMhHcwhYWgHHIL9HwAexgAAIY/HAAAhkscAACGZ1AAAIgHJAAAh2MsAACG8KwLBAAAhUm9yIcUAAB8c+iAFAsAAABwJHyAjHpkhY2QhxwAAUyFhIQUCwQAAHOIgE+AcbW4BRvqwHAAAAQBWAhAAWwAMAEsAoQCBAHAAdy4A/daJE8IAACCPwQAAIE3CAAAgkMcAACE87uUOAAAlDwAAjxYAAKEWAACHGgAAjhoAAJMaAACcGgAAxhsAACccAADEHAAA0BwAAEEdAADsHQAAfx8AABYAAAABEAEA")
\ No newline at end of file
diff --git a/api/search.index/0df8d7b385.js b/api/search.index/0df8d7b385.js
deleted file mode 100644
index 50e695793..000000000
--- a/api/search.index/0df8d7b385.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcAAAHca9RxlAcEAABOmGnQID4UQhhCHEIgQQRolAcAAABNmIGqzGlsgpYLDAAAhUSFuIXshMcAAAJ8WoBZxG6WCxAAAFB4hgx8FAsYAABe9IRWVIWZ0+wJhZiHCAACNHO8d8wEDYWRyOzAAAAEAAHgBBgCrEwIA9xRjAIQaAQC0GlsAcB5ZAO8fWQArAsAAAB+wZHoVAcYAABYRImQCIvMBgQFjDwAAGwLgAAATn2NxIcYAAPUdpSDxwgAANxv3CQD9HEkDwQAAFpnDAAActvmHFgAAAQCPAgYDBwLrAAQABQCjAPvAAEU=")
\ No newline at end of file
diff --git a/api/search.index/0df9b23957.js b/api/search.index/0df9b23957.js
new file mode 100644
index 000000000..53fc65797
--- /dev/null
+++ b/api/search.index/0df9b23957.js
@@ -0,0 +1 @@
+rn_("McsAADIdXh5fHkWEwAAAo5UbihyLHNYe1x4VAcMAABCUG3MgIaHBAAD8HPMBA2luc/WBEwAAKgO4BaoAtAQhwAAApCG/IQWJwAAApTwfEv4eFQHEAAATaCBuYRsFAsAAABU7HyYAHzcfbG4FAsAAABPBIWMIHAkc4h7jHkcfSB9sdQUDwwAAGJghErYgGIghY3V3IwQCxQAAH3FicAGHGgAAMccAADwhgSGCIfsCbHT7ifMA/TSAAuVWCgAAMwwAAOkbAABJHQAAVR4AAI4gAAAABVB7/RAQBsIAABxi")
\ No newline at end of file
diff --git a/api/search.index/0dff42f8c5.js b/api/search.index/0dff42f8c5.js
deleted file mode 100644
index 7c4ecfac7..000000000
--- a/api/search.index/0dff42f8c5.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHCAAAQxRNzkRDEE1UBwQAAE6MWY8YOxw7IDrkc/h6hwwAAFx4hwwAAFh5kIQWMwAAAIs0cGiEpJSHTIeMA/SGBAMQAACDw6nAaAAA/HAAAHx0AAEceAABRHwAAWx8AAJsgAADtIAAATCEAAFkhAACUIQAAARERAQEAI4MCwgAAHSRmcyUBwQAAMAweDR7cH3OGH8YgFQHAAAAUnhp0JRv7A2NvcxWEwwAAE7sgCh/zAwF00iocAADa+/0BAUg=")
\ No newline at end of file
diff --git a/api/search.index/0e2f350627.js b/api/search.index/0e2f350627.js
deleted file mode 100644
index 0d18de67d..000000000
--- a/api/search.index/0e2f350627.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAATWB8QSRxhcwUCwwAAp2Yhop8gZHNTAMAIBsQAAB/C0qQaAAC4AQABwAAADvZw4zoKAAAQDAAAyRAAAOQbAAABMKHWAADaITHGAAACH6AfKyEFAsAAABKKIBFIIXR68wCEAaQgAAAxwQAAMh8zH3Eh8wICaXPk8hwAACweAACIHwAA1R8AANcgAAAhAQAlAcwAABYFImR9IeEhFQHCAAAS+SFt5SEjhwLHAAAh/2FrBQLAAACw7xAZ7SFsd/cBAv0NFALgAAAfZeJmDAAAIhkAAAYhAAABACUBwgAAF/cgbXIbdBxDAf0CRQTCAAAd8ccAAB9uyAAAH83DAAAglYO2HwAAAQMCxwAAIfPCAAAd8GJkiRkZAAC3DQD9kVHAzAAAIczgAAAOaeE6DwAAZA8AAAE=")
\ No newline at end of file
diff --git a/api/search.index/0e626311a8.js b/api/search.index/0e626311a8.js
deleted file mode 100644
index 4e805b524..000000000
--- a/api/search.index/0e626311a8.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("oc0AACYhFQHBAAAUGR50bx/zggJlcwEBAc8AACDedItYCgAAUcIAAI8ayBvJG4ggqCEVAcUAAKAGHHNgGzWBwQAAFTYeSAx9DBIbBQLAAAAUjRoSaRtma/vABCT/AP0QSUDgAAAMcw==")
\ No newline at end of file
diff --git a/api/search.index/0e7992d4cb.js b/api/search.index/0e7992d4cb.js
deleted file mode 100644
index f93762aee..000000000
--- a/api/search.index/0e7992d4cb.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("RQHCAACm/SFkRSFGIc0hziEhyQAA5h55IQWRwQAAEZcbEl4cy8EBwcQAABqMwgAAG0nDAAAag6HEAABjIBMAAuAAABpobXPkoxAAAO8UAAAtHQAAAB8AAC4fAAAFEBDbwQSFwQAAH3rIAAAcKw==")
\ No newline at end of file
diff --git a/api/search.index/0ebc2800e1.js b/api/search.index/0ebc2800e1.js
new file mode 100644
index 000000000..ebc58f16f
--- /dev/null
+++ b/api/search.index/0ebc2800e1.js
@@ -0,0 +1 @@
+rn_("AUDhTRoAAPYdAAAIBQLBAAAU4iAlCx+3IHFzBQLLAAAUxiEV0SFxc6HEAAC7HAFFidkeAABnBwH9EaEDywAAIObGAAAfCueZEwAAzRQAAHwcAADoHAAAYB4AAPAeAAAjHwAALx8AABOIiAE=")
\ No newline at end of file
diff --git a/api/search.index/0ec556d23f.js b/api/search.index/0ec556d23f.js
deleted file mode 100644
index e59731b60..000000000
--- a/api/search.index/0ec556d23f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQQBxQAAIG9yiREdAAClAsIAAKR9IKOmIGJz1BwxxwAAMx1fHmAe+wNla3QVAsIAAB/uIaI8HmNyJhwrAsMAABypYXShxgAAkyDzBQFw4sMbAACLHwAA3x8AAAVQFQHEAAASvhxykBrzAAFmAcUUAAC/AcAEJ+AAABo1")
\ No newline at end of file
diff --git a/api/search.index/0f64c65dbf.js b/api/search.index/0f64c65dbf.js
deleted file mode 100644
index eb91de90d..000000000
--- a/api/search.index/0f64c65dbf.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQD9ABUBwgAAE43CAAATjsMAABaMxgAAHCLtOwoAABMMAACqEwAAtxMAAIEWAACXFgAAgxsAADAcAABEHQAARh0AABofAABlIAAAxSAAAB4hAACgAAEAAQAA")
\ No newline at end of file
diff --git a/api/search.index/0f65182f67.js b/api/search.index/0f65182f67.js
deleted file mode 100644
index e613a0b3e..000000000
--- a/api/search.index/0f65182f67.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHGAAAWsCFmFSHzAwFzAeoUAABFhMAAAKOVG4scjBzXHtgeFQHDAAAQlBtzISGhwQAA/RzzAgNpbnP1gRMAACoDuQWqALQEBYnAAAAXjSERvyAFicQAABLWIRHQISOFAuAAACFVZGYFAsQAABbFIROpIW90GwLNAAAh6WhvNwGDwA5pwgAAIOjXAAAiDMMAACE/xAAAIVahxQAAGx0VAckAABZBIWISH/OCAmZ3QwCHxwAAHCHDAAAhQ/PuBAAAJgRnCiHEAAAfIXchFYLBAAASoRNoDPsCY3ShxgAAWBwhygAAUx+RIQUCwAAAoOIOIQARgR9uclsDyAAAIXJhZXMFAsIAAC6sIfAhFYwgc3TzAP4ATgoMgwgFAAA=")
\ No newline at end of file
diff --git a/api/search.index/0f67528ff7.js b/api/search.index/0f67528ff7.js
deleted file mode 100644
index 8804985bc..000000000
--- a/api/search.index/0f67528ff7.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcQAANccyB/BxgAAgyAlAdEAABYKImSnIewhG4ngAAATgAFG+AUfAABjAQQASQAFAIcAdQAFABMAwAMIxAAAIW/IAAAeUzowAAABAAAAAAAsABAAAADRDtIO0w7UDtUO1g7XDtgO2Q7aDtsO3A6NFq4arxobGxwbcxuGGyUcLxx1HHYcsxy6HAYdGx0cHTMdXx5gHmwebR4SH3cfeR/aH6EgoiD4IPkgACEBITkhPiEVAdQAABYLImTyISUBzwAAFhIiZPUhDyIhxwAArSHxIfOLAmxwGwLCAAAbamJyocIAAEobBYPAAAAaYSAqYiChISHSAACsIfAhGwLJAAAgs2xyFQHLAAAWECJk+iH7iSHFAACmHMcfIccAAGAgoCEJlMgAACFQ0AAAIcHzggJmbPuD8wD9KPAFOzAAAAEAABgABgBXCgAANAwTAI8TAACeEwAA2RQAADAdAADb/ZAARMAAACH/ocYAAMoh8wG [...]
\ No newline at end of file
diff --git a/api/search.index/0f938e891a.js b/api/search.index/0f938e891a.js
deleted file mode 100644
index b56d96801..000000000
--- a/api/search.index/0f938e891a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHFAAAYQyFj6h7PITUBxAAAFu8hZNUg1iCxISuJwgAAHMxjAAPEAAAgtmF0deSuEwAAXBUAAD8dAADKHgAA6B4AAAIRAKHGAAAVH1WCwAAAFRQfnRrKHMscEB8RH/sCZnQbisUAAB5NIcAAAOgbSiChxAAAex9jAcAIQsMAACFH5UwbAAAgHwAAuR8AAOkfAACcIQAA6SEAANAAATUBxAAAFuchZFIgUyCeIRcZAP0niQfCAAAdIcMAACEZxAAAHunBAAAanMgAACEkxwAAId/npBAAAAERAAB7GgAAjxsAAGoeAABZIAAAJSEAANMhAAAEEAAA")
\ No newline at end of file
diff --git a/api/search.index/0fb6a44325.js b/api/search.index/0fb6a44325.js
deleted file mode 100644
index 20df784d2..000000000
--- a/api/search.index/0fb6a44325.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHSAAAWCiJk7CEVAdQAABYLImTyIRUBzwAAFhIiZA8iI4wCxgAAIfFscIcDg/0o0ATKAAAhoNMAACHwygAAIaEFAsIAABPlHBrZIGRuRQHEAACm/SFkRSFGIc0hziH7A2Fpcg==")
\ No newline at end of file
diff --git a/api/search.index/0fc0613555.js b/api/search.index/0fc0613555.js
new file mode 100644
index 000000000..c2568174b
--- /dev/null
+++ b/api/search.index/0fc0613555.js
@@ -0,0 +1 @@
+rn_("JQHFAAAWayBiLhwFHSUB0AAAFgkiZKMh6iElAcgAABb8IWQiIcMhJQHHAAAW+CFk/SC5IfODAnJzJQHMAAAW+yFkISHCISUBxAAAFgAiZGIh0yETiQLDAAAh1GNsFQHIAAAW9yFkuCEVAcoAABYIImTjIRUBygAAFgciZOIh+4UVAcYAABbnIWSeIfOBA2VtbvsCZG83BwD9HJARwwAAG4PGAAAdOwH4DgAA")
\ No newline at end of file
diff --git a/api/search.index/1034c841bc.js b/api/search.index/1034c841bc.js
deleted file mode 100644
index 45c9a4783..000000000
--- a/api/search.index/1034c841bc.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JYTCAAATuyC2FAofRQHFAAAVbyFj+CD5IAAhASFlAsAAABT/IORrHGN07w5iDzYdPh1cHl0e4cUAAGUcJQHFAAAmtiG7IWI5IT4hpQHBAAAUzyBm0CGlAcIAABT2IGbWIfuJMcUAADMenR+eH/MDwgAJ80kdAACeAf4BFQHCAAAU6h9jOR8jgQLBAAAccWVsIwADzgAAIeDHAAAfn2VmcvPuDgAAZxICAOcDAMIOSMQAABxk4VQMAABrDgAAB5v9EEFAyQAAH2rDAAAhlQ==")
\ No newline at end of file
diff --git a/api/search.index/104abdc6f9.js b/api/search.index/104abdc6f9.js
new file mode 100644
index 000000000..180ea8ce2
--- /dev/null
+++ b/api/search.index/104abdc6f9.js
@@ -0,0 +1 @@
+rn_("IcYAAKQhvyETggLSAAAhsWR1BQLAAAATVx8QSBxhcwUCwwAAp2Uhop4gZHNTAMAIBsQAAB/B0qQaAAC4AUDjOgoAABAMAADJEAAA4xsAAAEw+wJ5eiHGAAAAIgYi8wQBZOUuHgAAJB8AAGIhAAB+IQAA0yEAAOEhAAARAQATBQLDAAAh1GNsgrEaAAAbisEAABo2BQLAAAATGR4QoxphcwUCwAAAFO4e4PYbaXMFAsMAAKcnIaK/H2RzFQLBAAAVdyETsh9mdxYZI4ICwwAAIXlpbAWDwAAAE4YW0C0P+wJydLcPAP0hOA3gAAATjeWHAwAAsxMAAGMVAAA3GwAA/CAAAN4hAABBRgA=")
\ No newline at end of file
diff --git a/api/search.index/10ee6608b7.js b/api/search.index/10ee6608b7.js
deleted file mode 100644
index 80d372ad7..000000000
--- a/api/search.index/10ee6608b7.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcAAAMQbxRsGHAccFQLDAAAWkyESHSFicnYgI4cCwwAAIMdmcxsCxgAAHK5hchUBxAAAEIofcx4fswDACOjHAAAcr8IAABOK+jEKAAABAAARLgBXAAEAkAASAIsCJgA=")
\ No newline at end of file
diff --git a/api/search.index/11405c3d1e.js b/api/search.index/11405c3d1e.js
new file mode 100644
index 000000000..458414358
--- /dev/null
+++ b/api/search.index/11405c3d1e.js
@@ -0,0 +1 @@
+rn_("BQLDAAAWIB8RkBtibzUBwQAAGHsgYqgQPB1iH0UCwgAAYUwcTRxOHEge+x4MHyUbH7sgaXNTH1QfciCzIPMAAmtvAXEgAAAVgccAABXpILsf8wADb3N04U0aAAD2HQAACAUCwQAAFOIgJQsftyBxcwUCywAAFMYhFdEhcXMBBAHDAAAh22bnDR4AAFMgAACGIAAAjSAAAJEgAACWIAAAcyEAAAwiAABgAAABIcMAAIYTiRZFAcQAACaLIechZDcasBrSH54hu/0JQAjFAAAfCrWCwQAAorscXxUBRInZHgAAKwLCAAAfGXJ4FQHQAAAWESJkAiKxxwAAmyD7AmRyFQHFAAAWZyBiJBwFAsAAABRKIBwfIWN0BQLAAAAWSSERTSAzcQcBhMAwYcIAACCOwQAAIEzEAAAg+cIAACCPKwLFAAAfsGN0G4nFAAAgV5cCAv0EgRbOAAAhYcsAACD6xwAAH7EBdQ8AABsCwgA [...]
\ No newline at end of file
diff --git a/api/search.index/11bf9ef685.js b/api/search.index/11bf9ef685.js
deleted file mode 100644
index 594fdd8b5..000000000
--- a/api/search.index/11bf9ef685.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcMAAJgbmRs0HdEfscoAAMkgFQLBAAAf7iGiPB5jciYcscUAAOIcMcIAAOsUFR8WH/MA/QBBB+EyDwAA0B4AADA=")
\ No newline at end of file
diff --git a/api/search.index/11f16a2e42.js b/api/search.index/11f16a2e42.js
deleted file mode 100644
index 24d98af38..000000000
--- a/api/search.index/11f16a2e42.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McYAAIwh6CEQIvMAAWToNxoAALAaAADTHwAAaiEAAIchAACfIQAAwSEAAMohAAD6IQAAAAEQAQATggLOAAAhX2R2")
\ No newline at end of file
diff --git a/api/search.index/11fd9cc749.js b/api/search.index/11fd9cc749.js
new file mode 100644
index 000000000..af507d4f7
--- /dev/null
+++ b/api/search.index/11fd9cc749.js
@@ -0,0 +1 @@
+rn_("FQHBAACkah9t7R3zAoSCxxwAAKUBwQAApA8hbcwg8weE9ZsfAAA7AAEAMAGDAGsDxQAAHv9jb3BFhMMAABFdIfMgdSGEIbYhE4gCwgAAIPRzdAUCwwAAJocgpyGkLx9tcwWFwAAAGuMgF2gfBQLAAAAVMB4W/h5jbCUBxQAAFuUhZJwh3yETg8AIRMsAACE2wgAAIYChxgAA6x13LgDAOu/FAAAeMc8AACE3zQAAIVHCAAAbSDswAAABAABVABsAagwEAO0OAAA7DyYAnRYBALAbAAAbHAAApRwAAN0cAAA5HQAA9B0AAMYfAACkIAAAsiAAAEMhAABKIQAATCEAAIshAAC3IQAA3CEAAOUhAgDvIQAA9yEBAPshAwAAIgAAAyIIAA4iAAAQIgIAVQPAAAAW1B4kmxNUGqpHH2FvdmAM9w55DyYbXRwxwQAAPCGBIYIhFQHAAAAeeCFwvxPzgYr7A2FsdA==")
\ No newline at end of file
diff --git a/api/search.index/13b6de9f5f.js b/api/search.index/13b6de9f5f.js
new file mode 100644
index 000000000..c3f15d02f
--- /dev/null
+++ b/api/search.index/13b6de9f5f.js
@@ -0,0 +1 @@
+rn_("AULioR8AAMggAABfIQAAYgArAsAAABygaXQVAsMAABaSIRIcIWJydSAjiALDAAAgxmZzFQHEAAAQiR9zHR/zAwJmcOK3GwAAWRwAAOQeAAAQAC8B/QBIScUAAB0hwwAAGozEAAAeUQ==")
\ No newline at end of file
diff --git a/api/search.index/140a8e2a10.js b/api/search.index/140a8e2a10.js
new file mode 100644
index 000000000..13699662b
--- /dev/null
+++ b/api/search.index/140a8e2a10.js
@@ -0,0 +1 @@
+rn_("NQHMAAAW5iFkUSBSIJ0hJQHIAAAW/SFkRCHMIUUBxQAAFrchZAAdAR0CHRch84ECZnQlAcgAABYHImSWH+IhlwEAwAZoxQAAIg7HAAAgy/KKEAAAbBE=")
\ No newline at end of file
diff --git a/api/search.index/140cc9b1f5.js b/api/search.index/140cc9b1f5.js
new file mode 100644
index 000000000..824774d7c
--- /dev/null
+++ b/api/search.index/140cc9b1f5.js
@@ -0,0 +1 @@
+rn_("JQHFAAAYQiFj6R7OITUBxAAAFu8hZNQg1SCwISuJwgAAHMtjAAPEAAAgtWF0deSuEwAAXBUAAD4dAADJHgAA5x4AAAIRAKHGAAAUH1WCwAAAFRMfnRrJHMocDx8QH/sCZnQbisUAAB5MIcAAAOcbSSChxAAAeh9jAcAIQsMAACFG5UwbAAAfHwAAuB8AAOgfAACbIQAA6CEAANAAATUBxAAAFuYhZFEgUiCdIRcZAP0niQfCAAAdIMMAACEYxAAAHujBAAAanMgAACEjxwAAId7npBAAAAERAAB7GgAAjxsAAGkeAABYIAAAJCEAANIhAAAEEAAA")
\ No newline at end of file
diff --git a/api/search.index/1439721cd0.js b/api/search.index/1439721cd0.js
deleted file mode 100644
index 4cafcf687..000000000
--- a/api/search.index/1439721cd0.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("YcMAAIIWgxaEFoUWrBqtGgUCwAAAEfQhGxMfZG4VAcoAAKSaIW1+ISUBxgAApDohbfwglyEzgcAISMwAACF0+5ZBwwAA7B/tH+wgEiGhygAA0R7zAMAgBehfDgAAmRAAAKIQAACSEwAAnRMAAIIaAABCHAAA4BwAAG8hAACQAAAQAA==")
\ No newline at end of file
diff --git a/api/search.index/143a41938d.js b/api/search.index/143a41938d.js
new file mode 100644
index 000000000..1c64d96e1
--- /dev/null
+++ b/api/search.index/143a41938d.js
@@ -0,0 +1 @@
+rn_("JZDDAAAk0yBIIX4bNh2lAcMAABQiH2aoIaUBxgAAFIAgZsQhU4ED4AAADyxvc3QhwgAAkxY1HLMA/UhQAMAAACCL9JwQAAAuBL4FJwE=")
\ No newline at end of file
diff --git a/api/search.index/1441cb3093.js b/api/search.index/1441cb3093.js
new file mode 100644
index 000000000..e69ecf1f7
--- /dev/null
+++ b/api/search.index/1441cb3093.js
@@ -0,0 +1 @@
+rn_("AUU7MAAAAQAADwECAIoWAQAkGQ0BpQHDAAAw3BtVH1Yfc08exQHAAAAU8SBi+hDzgQJkbfsCcnYBAQHCAAAdN2L5+g4AAIsABgvbBAEAFQDyAHQA5AABBwHDAAAh22bnDR4AAFMgAACGIAAAjSAAAJEgAACWIAAAcyEAAAwiAABgAAABGwLFAAAfr2N0O8AAxA/AYTVVQcEAALUQyRvTIEghscIAAKMbpQHFAAAVbiFj9yAVAckAABa1IWI4IVOFwghA4AAAHTXzggJkafOBAml0+4c=")
\ No newline at end of file
diff --git a/api/search.index/146efe46ac.js b/api/search.index/146efe46ac.js
new file mode 100644
index 000000000..7597fcbf1
--- /dev/null
+++ b/api/search.index/146efe46ac.js
@@ -0,0 +1 @@
+rn_("9YHCAAATfRu8FCHCAABfH9chQwCTwgAAE6DAAAAPguyUEAAArxAAAIkaAACUGgAAghsAADMeAADMHgAAAB8AADcfAABsHwAArR8AAFIhAABgIQAABQABEAAAAKHCAAA8GqvAIIzEAAAWk8UAAByYa8AEhOAAAAT4")
\ No newline at end of file
diff --git a/api/search.index/1486cb7cb9.js b/api/search.index/1486cb7cb9.js
new file mode 100644
index 000000000..6b5458b11
--- /dev/null
+++ b/api/search.index/1486cb7cb9.js
@@ -0,0 +1 @@
+rn_("QcgAAG8hciGIIY8hQcIAAGYgcyC2IMAgAQMCxwAAIfPCAAAd72JkiRkZAAAbA8wAACHLwgAAH2RhaGlVAcAAABu7IWMiDCMMNhp4GnkaAUiJ6BwAABUB0QAAFgMiZNghFQHYAAAWESJkAiIVAdAAABYJImTqIRUByAAAFvwhZMMhFQHHAAAW+CFkuSHzgwJycxUBzAAAFvshZMIhFQHEAAAWACJk0yETiQLDAAAh1GNsFQHIAAAW9yFkuCEVAcoAABYIImTjIRUBygAAFgciZOIh+4UVAcYAABbnIWSeIfOBA2VtbvsCZG/zhsAGKBUByAAAFoshZNIfFQHMAAAWBSJk4CETiQLDAAAhcGRrFQHJAAAW5SFknCEThMAITMkAACGnywAAIbbHAAAhihsC0wAAId9mbBUB2gAAFhAiZPoh+4NnTQD+AB+kHTLyyK86ywAAIRZ7ymXimMsAACEYwgAAHC003a0F/AHJHwA [...]
\ No newline at end of file
diff --git a/api/search.index/1486cba725.js b/api/search.index/1486cba725.js
new file mode 100644
index 000000000..421ddbf1a
--- /dev/null
+++ b/api/search.index/1486cba725.js
@@ -0,0 +1 @@
+rn_("BQLAAAASuhwSuBxidBsCwQAAIV5heRUBywAAFlohYn4fKwLKAAAgkXFz8wACZXTodg4AAJYTAADLFAAA6hsAAE8cAADZHgAAgR8AAOYgAABhIQAAgBgIAAA=")
\ No newline at end of file
diff --git a/api/search.index/1499b4011a.js b/api/search.index/1499b4011a.js
deleted file mode 100644
index 19fa13bed..000000000
--- a/api/search.index/1499b4011a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BZjAAADjphvHkR8hzAAArCHwIfMAAm9yAUYKAAAhxgAAJSHTIRUBwgAAFg4iZPYh8wABbQF8EwAABYrAAACh0RwYriEBQeV1GgAASxwAAB8eAAAoHgAAmx8AAAchAAARAAAVAcoAABYDImTZIccGAf2DCQPEAAAhdcIAAByhwQAAHNA6MAAAAQAAAAAAIAAQAAAApxqpGgscDBwkHDgcqxysHPYc9xz4HPkc+hz7HPwc6x0bH2Efuh+/H1ogeCB5IHogeyDDIMQg2iAMIQ0hDiEXIbwhFQHCAAAS+SFt5SEjhwLHAAAh/2FrIwsCyQAAIe1hYwEGIQAAO/0IQITBAAAe7McAACFgFf3AEQEQAAATVRqklxYXMBwauh8hDGcFAP0ScQTFAAAfIcEAABsdwAAAG5Djbw8AALkUAAAeGwAAxh8AABEA")
\ No newline at end of file
diff --git a/api/search.index/14ea40eed4.js b/api/search.index/14ea40eed4.js
new file mode 100644
index 000000000..3071b3225
--- /dev/null
+++ b/api/search.index/14ea40eed4.js
@@ -0,0 +1 @@
+rn_("AUDpLAwAAJgQAACREwAA7hQAAHoaAACNHAAApxwAAAUeAABJHgAA/B4AABAAAQEANQHBAAAW7yFk1CDVILAh+wJlbg==")
\ No newline at end of file
diff --git a/api/search.index/153b64ea46.js b/api/search.index/153b64ea46.js
new file mode 100644
index 000000000..18665707d
--- /dev/null
+++ b/api/search.index/153b64ea46.js
@@ -0,0 +1 @@
+rn_("AQCQxAAAG3TlWAwAAIAOAABlGwAAiR8AAKAfAAB+IAAACRAAIcIAAJYQvRyhxgAAeBxBwwAAOB10H2gg4yAFAsEAABWgHxaMIGZuNQHAAAAUVyFwTR+QIGshBYnAAAAXjSERvyChxAAAOSEFicQAABLWIRHQISOFAuAAACFWZGYFAsQAABbFIROpIW90GwLNAAAh6WhvZzYBwA/rxAAAHsvCAAAg6NcAACINwwAAIT/mthAAANAeAADYHgAAeyAAANIgAAD7IAAAliEAACEAAAAFAsAAABT3IRMdIWZypQHDAAAesiFjdhyhwQAAExtjgQPDAAAc9GFpbncPAP0SsQfHAAAcs8IAABozOjAAAAEAAAAAACsAEAAAABQMFQwWDK8TyRTeFDQajRqQGqoaqxozG2EbkhuTG90bcBxyHJMcwBwIHiYeHR8iHzkfgh+DH5AfkR+SH5MfrB/cH90f5B/lH+Yf5x+AIMYgziD [...]
\ No newline at end of file
diff --git a/api/search.index/1554c50095.js b/api/search.index/1554c50095.js
deleted file mode 100644
index 5ff685042..000000000
--- a/api/search.index/1554c50095.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUDhTRoAAPcdAAAIBQLBAAAU4yAlDB+4IHFzBQLLAAAUxyEV0iFxc6HEAAC8HAFFidoeAABnBwH9EaEDywAAIOfGAAAfC+eZEwAAzRQAAH0cAADpHAAAYR4AAPEeAAAkHwAAMB8AABOIiAE=")
\ No newline at end of file
diff --git a/api/search.index/15a577f2d7.js b/api/search.index/15a577f2d7.js
new file mode 100644
index 000000000..53a72ac18
--- /dev/null
+++ b/api/search.index/15a577f2d7.js
@@ -0,0 +1 @@
+rn_("FQHBAACkah9t7R3zAoSCxxwAAKUBwQAApA8hbcwg8weE9ZsfAAA7AAEAMAGDAGsDxQAAHv9jb3BFhMMAABFdIfMgdSGEIbYhE4gCwgAAIPRzdEHAAAC1EMkb0yBIIQUCwwAAJocgpyGkLx9tcwWFwAAAGuMgF2gfBQLAAAAVMB4W/h5jbCUBxQAAFuUhZJwh3yETg8AIRMsAACE2wgAAIYAVhsAAAKZpIanJIWcbGwLHAAAfBXJzocYAAOsdAQD99PhHSjbpgCRpKlcWgg/l9pykbJS6QonFAAAeMc8AACE3VQLiQvRIKiQQZ10P0c8XEl9oJqLNAAAhUXq1aNlkwgAAG0jCAAATujswAAABAABVABsAagwEAO0OAAA7DyYAnRYBALAbAAAbHAAApRwAAN0cAAA5HQAA9B0AAMYfAACkIAAAsiAAAEMhAABKIQAATCEAAIshAAC3IQAA3CEAAOUhAgDvIQAA9yEBAPs [...]
\ No newline at end of file
diff --git a/api/search.index/15ab902fa8.js b/api/search.index/15ab902fa8.js
new file mode 100644
index 000000000..83cd18a98
--- /dev/null
+++ b/api/search.index/15ab902fa8.js
@@ -0,0 +1 @@
+rn_("BQPAAAAV2SAeXiEo7R8SIWVpbaHFAAChGhWEwwAAE7ogCR8FAsMAABrXIR3zIWV0IwQCxQAAIOpicAFAHQAAFQHAAAAWUR5ishPzgQJudBMAAsYAAB9zY3LhKRsAAEkhAACABQLAAAAUyh8SOR1wdQWGwQAAQmYfZx98H24gpk8e84ECcXNRyQAAQh3sHu0e0CApIQUCxAAAIXQgCCEVQyFlchMHAsEAAB5OYnLhRRwAACcdAAAQocQAAKUWAUSJ6hsAACHJAACIIBoh+wJjeDHGAACLIechECIjAALBAAAd72Fk6DcaAACwGgAA0h8AAGkhAACGIQAAniEAAMAhAADJIQAA+iEAAAABEAEAMcYAAEMcRBxLIAUCwAAAo58aR+sf7B/rIBEhbW5rA8IAABxxYW9yBQLBAAAm2yDzIRSKG2NpAQD+wGesD8sAAB+BT2td0Mk/T5TB3l7b04vtdO+B7BDNAAAiAQMacvw [...]
\ No newline at end of file
diff --git a/api/search.index/15ac299102.js b/api/search.index/15ac299102.js
new file mode 100644
index 000000000..00bf1456a
--- /dev/null
+++ b/api/search.index/15ac299102.js
@@ -0,0 +1 @@
+rn_("JQHCAAAQxRNzkRDEEwEGAsQAACF0yAAAIa1hcuYjHAAA9RwAABofAAC+HwAAdyAAAAshAAAWIQAABgAyAFUBwAAAE6MWY8YOxw7IDrgc/R4BAAHQAAAhonTSNwoAAOxbwABiywAAH24VgcUAABz0IfAgAUDsmxAAAHgbAAB9GwAAOB4AAAIfAAAHHwAADR8AALMfAADLHwAANiEAADwhAACBIQAAriEAAAAAEAEBAQBrA8kAACEEYXJzMcAAAAseDB7bH1HIAAAHH7MftB83Ia4hocQAAEUdZwEB/VEAB8QAACB2xAAAIUrDAAAhYTswAAABAAAzABYA0hALAJwTAADYFAAAmBoDABAbAACLGwAA5BsCAEMcAQAcHgEAPh4AADQfAgA+HwYAhR8AAKkfAADDHwEASyAAAF8gAADFIAAAJSEBAJ8hAACrIQEA8CEBAAUCwAAAEtQeFNMeZGcVAcAAABSeGnQlGxUCwQA [...]
\ No newline at end of file
diff --git a/api/search.index/15b0fac45b.js b/api/search.index/15b0fac45b.js
deleted file mode 100644
index f7eaaded0..000000000
--- a/api/search.index/15b0fac45b.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAXdyEyMhwzHCIfb3khxgAAQh6AIKHEAADCHLMBwAHBxAAAHULmoxMAAOMUAAD1FAAAuRsAAN8cAABeIAAAsyEAABMQAAAFicUAADg9IYIhgyEUwiEFAsAAABRNH2IMHQ0d9SAKIQshsiFveSUBygAAFgsiZJYh8iEFjMAAABIaIRnTIRMIAsIAACFkZmnkmyAAAO0gAABMIQAAWSEAAJQhAAABAQAxxQAAoiG+Ib8hNYTAAAATmiBwIHEgBCExwgAAQB5BHh0hQcEAAEofSx9MH14hBQLAAAAlbSCTIRKZIHV58wH9AgED6DEcAAAHHQAA8B4AAIkfAAB2IAAA9CAAAHYhAACFIQAAtyEAAAQAAAAA+wJlbPMAA3B0dQFWGgAAxQHBAAAVeR93yxslAcAAAKSaIW07H34h+wJkblUBwwAAEH8gc8EcCR7dH94fxyArhcMAAB96McUAANofoSCiICUBxAAAFhI [...]
\ No newline at end of file
diff --git a/api/search.index/15cf9d9898.js b/api/search.index/15cf9d9898.js
deleted file mode 100644
index 9de376e24..000000000
--- a/api/search.index/15cf9d9898.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAADkphtyRgqlgcAAABW2IMoeI4YCwQAAIEppcysCwAAAGjJpbqUBwwAAMN0bVh9XH3NQHsUCwAAAFPIgG9AgYm36ECHEAACxFEEcfwH9DFACyQAAIIw7A8sAACFfZXN0")
\ No newline at end of file
diff --git a/api/search.index/15d4e88f0d.js b/api/search.index/15d4e88f0d.js
deleted file mode 100644
index 02af8737e..000000000
--- a/api/search.index/15d4e88f0d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcgAAHAhcyGJIZAhQcIAAGcgdCC3IMEgBQLAAAAc8yEdzCFhaAUCwAAAGdghF/sgbnIHHYL9HwAexgAAIY/HAAAhkscAACGZ1AAAIgHLAAAhvCsCwQAAIVJvcg==")
\ No newline at end of file
diff --git a/api/search.index/16218e36de.js b/api/search.index/16218e36de.js
new file mode 100644
index 000000000..a78530ef0
--- /dev/null
+++ b/api/search.index/16218e36de.js
@@ -0,0 +1 @@
+rn_("FYLBAACmySGhEKHEAAAPIfMAAW3j8hAAAI8cAACjHAAAzCAAAAMRMcAAAJ8WoBZxGwUCxwAAF7whFZQhZnQhwgAAjBzuHfMEA2FkcjswAAABAAB4AQYAqxMCAPcUYwCEGgEAtBpbAG8eWQDuH1kA2/0NIADgAAAcIA==")
\ No newline at end of file
diff --git a/api/search.index/164b17d87d.js b/api/search.index/164b17d87d.js
deleted file mode 100644
index dfde28dd2..000000000
--- a/api/search.index/164b17d87d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("YcUAADMdXx5gHtofoSCiICHFAAClIcAhBf3AAQFBAAATlSAX/SCv4CATGR4BRjswAAABAACzAAIAcB5ZAO8fWQA1AcsAABTcIWZ0IQwiDSL7AnFyGwLHAAAfIGVuFQHBAAA0VB5VHp8fY64WFQHOAAAWESJkAiLzgQJwdyUBwgAAFhIiZPUhDyIxwwAACiELIbIhFQHBAACkmiFtfiEzhgPJAAAhwml0dvsCcnQbAscAAB/UYXIFAsAAABMrHRjNH3J1BQLAAAAa0CAQ9h1lc1UBwgAAF/cgbWkbcht5G3obdBxFiMMAABcOH6IT4RTiFK4cG8AChMYAAB9uxQAAH8wlAcIAACQfH+ofY/QdOR8FicAAABeOIRHAIKHEAAA6IQWJxAAAEtchEdEhI4UC4AAAIVdkZgUCxAAAFsYhE6ohb3QbAs0AACHqaG83AwHADmvCAAAg6dcAACINwwAAIUDEAAAhWNL8IAAAmyM [...]
\ No newline at end of file
diff --git a/api/search.index/167e932e08.js b/api/search.index/167e932e08.js
deleted file mode 100644
index 1a56715cd..000000000
--- a/api/search.index/167e932e08.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHPAAAWEiJk9SEPIkUBxwAAGK8hZ6whrSHwIfEhAUblzhwAAGsgAACpIAAAuSAAAL0gAACwIQAAEIAQFQHIAAAQWyBzGB+hxAAAQhz7Am9ydwEA/STIAMUAACEg5f4OAACNDwAAKRwAALccAAC/HAAAFSEAABAAEA==")
\ No newline at end of file
diff --git a/api/search.index/16c224a7d5.js b/api/search.index/16c224a7d5.js
deleted file mode 100644
index d8950e9c3..000000000
--- a/api/search.index/16c224a7d5.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("VQHAAACm/SFkRSFGIashzSHOISUBygAAFv4hZEYhziEFAsEAABeuHxNpH2Vw84ECaXIVhMQAABHTIK0f8wYBZvOuGwAAjgECASUBywAAFv0hZEUhzSGh1AAA2iFbxAAMyAAAIOT7/REBAg==")
\ No newline at end of file
diff --git a/api/search.index/172a90fc64.js b/api/search.index/172a90fc64.js
deleted file mode 100644
index 40f13c1ee..000000000
--- a/api/search.index/172a90fc64.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McUAABsdHB15HxUBxgAAFrAhZhUhFQHFAAAWQSFiEh8VAcAAABSLIGOvH/MDAnN3AR0fAAChxgAAyiFnBQD9NAAXyAAAHxPHAAAgScIAAB7UOzAAAAEAAD8AFgB1DAIAyw4BAIEPAACVEAAAoRAAAKYQAACGEwAAsRMAAOoUAABoFSIAiRYAAI8aAADIGwEAyxsDAJocAAAiHQAAQh0AABseAQAnHwAAiCAAAN0gAACoIQAA")
\ No newline at end of file
diff --git a/api/search.index/175a23082a.js b/api/search.index/175a23082a.js
deleted file mode 100644
index b949bb3a4..000000000
--- a/api/search.index/175a23082a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocYAALcbBQLAAABkkhYgGyEbIhsjGyQbFCUbaHQFAsEAABI+GhFNH3J0QcIAAI4cjxxKHv0e9YHCAAATfRu8FKHDAAA8GvsCbnQFAsAAALPiHCSRFh8bZnUFmMAAABjTHrW0G6ddAP7AzCEPwQAAEMbKAAAeOcIAABycwwAAGj/BAAAQxzswAAABAABmAgUA5QQAAAcI6QAEDwAAkRLpAIUYkAA=")
\ No newline at end of file
diff --git a/api/search.index/1777c42571.js b/api/search.index/1777c42571.js
deleted file mode 100644
index 1dcf40057..000000000
--- a/api/search.index/1777c42571.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUuJqSAAABsCxwAAIHJveQUCwAAAwxgcEgUdZWwFAsAAABYnHhNoG3J1NQHFAAAWqCBjgRpfH7IgocYAAC0dpwcA/gQHMALPAAAhbsUAACIS0vUhAAAa")
\ No newline at end of file
diff --git a/api/search.index/17ca709c19.js b/api/search.index/17ca709c19.js
new file mode 100644
index 000000000..de3774a24
--- /dev/null
+++ b/api/search.index/17ca709c19.js
@@ -0,0 +1 @@
+rn_("JQHGAAAW3CFkmB+JIUWEwAAAo5UbihyLHNYe1x4VAcMAABCUG3MgIaHBAAD8HPMAA2luc/WBEwAAKgO4BaoAtAQlAcQAABYLImSVIfIhIwMCxwAAIUJjbOQADwAAjg8AAHQbAADpHgAAziEAAAIAAAUDwgAAEoAfGXEhGpAhYWVzK4zAAAAcICsCxQAAHeVlcgECAcMAACHbZucNHgAAUyAAAIYgAACNIAAAkSAAAJYgAABzIQAADCIAAGAAAAGhxwAAGh53BwD9EzEFxgAAHjjQAAAhouI3CgAAIwsAAOYdAAAAMA==")
\ No newline at end of file
diff --git a/api/search.index/1821041df0.js b/api/search.index/1821041df0.js
deleted file mode 100644
index 231c3fae2..000000000
--- a/api/search.index/1821041df0.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcYAAAAiBiLzBAFk5S8eAAAlHwAAYyEAAH8hAADUIQAA4iEAABEBABMDAsMAACHVY2z2sRoAAAEAiAELAekA2wA=")
\ No newline at end of file
diff --git a/api/search.index/18304e2067.js b/api/search.index/18304e2067.js
new file mode 100644
index 000000000..71676e47d
--- /dev/null
+++ b/api/search.index/18304e2067.js
@@ -0,0 +1 @@
+rn_("JQHHAAAW3CFkmB+JISHBAAD3DiYb+wJsbQEBAsYAAB08xQAAIUFhduV4HAAAJR0AAAIeAAA8HwAAkiAAAGchAAAREREhwAAAZQxAGqHIAACzIQEEAsYAACC36AAAHfZyc+F8HAAALx8AAIEhxgAAhyCnIfMBwgBC840bAABtA1wB+wJtbvuT")
\ No newline at end of file
diff --git a/api/search.index/18583fda18.js b/api/search.index/18583fda18.js
deleted file mode 100644
index 60a7e1622..000000000
--- a/api/search.index/18583fda18.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYTAAAASIh1vDFHIAAAIH7QftR84Ia8hIwMDxAAAIHfEAAAhS2FncuvSEAAAmBoAAOUbAAAdHgAAPx4AADUfAAA/HwAAxB8AAGAgAACgIQAArCEAAPAhAACzIQJhABEVAcYAABa5IGa3HPMCAXPy9Q4AANwB+wJsdPMAAmFr8o0DAADwDw==")
\ No newline at end of file
diff --git a/api/search.index/18694d833f.js b/api/search.index/18694d833f.js
deleted file mode 100644
index b27e018bf..000000000
--- a/api/search.index/18694d833f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHQAAAWCSJk6yEVAcgAABb8IWTEIRUBxwAAFvghZLoh84MCcnMVAcwAABb7IWTDIRUBxAAAFgAiZNQhE4kCwwAAIdVjbBUByAAAFvchZLkhFQHKAAAWCCJk5CEVAcoAABYHImTjIfuFFQHGAAAW6CFknyHzgQNlbW77AmRv+8AGKA==")
\ No newline at end of file
diff --git a/api/search.index/18d0e3c33f.js b/api/search.index/18d0e3c33f.js
deleted file mode 100644
index 6cc9fc567..000000000
--- a/api/search.index/18d0e3c33f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcIAAM8eBh+hwwAANRsFAsAAABbGHxosIWhv+4mhyAAABh4hxQAA5h55ISHGAAARG3Ih5wUA/oAEog3CAAAU18wAACCXxQAAH2HlEgkAAOcOAAChEwAADxwAAMYcAACoIAAAAQAQNQHLAAAW5yFkUiBTIJ4hGwLDAAATjG50JQHIAAAW/SFkRSHNIUUBxQAAFrghZAEdAh0DHRgh84ECZnQFAsAAABXMIEQ6HEUdLh4JH2Nz8wCCgvsFAAClgcAAABW2IMoeI4YCwQAAIEppcysCwAAAGjJpbkOCA8sAACDQyQAAIIxkb3MVgsIAABGnFlcMu/0QQQHBAAAOfwFA5HYOAADrGwAA2h4AAIIfAADnIAAAiIAAFQHAAAAUiyBjrx/zAwFzAR0fAAATAgLHAAAgSWZyAZUQAADzAgJpcwGgEAAAodAAAOAgQwHAA4DDAAAe08wAAB/J4UcKAAAXDAAAASUByAAAFgciZJc [...]
\ No newline at end of file
diff --git a/api/search.index/193fdc053a.js b/api/search.index/193fdc053a.js
deleted file mode 100644
index f5a91d363..000000000
--- a/api/search.index/193fdc053a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQIBwgAAG0h05WoMAACdFgAAOh0AAEQhAABLIQAATSEAAEEAABUBxQAAFrogYrocMcQAAHEachqyHwUCwQAAErscErkcYnQVAcwAABZbIWJ/H/MAAmV09ZYTAAA1AQEAhAcSBQUCwAAAxuUfFPYbY24FAsEAACK4HAEe4GscZG1blsEAAB1CBQLBAAAWIR8RkBtibysCwgAAIVBhchUBwwAAqLQhd1cgRcLCgiAAADRQIFEgTyGq2iEldh+WIBV3H4AbgRuHHIgcK4bDAAAeAAUDwQAApNEeMX8bhhxhICTPHgYfZWx4FQLDAAAf7iGiPB5jciYcFQHEAAASvhxykBrzAAFmAcUUAAD7AmRuAYL9CQAYxgAAIY/UAAAiAcEAACDBxwAAIZArAsEAACFSb3IhxwAAUyFhIWMEA8UAAB9+YmVwAZMaAAAxwgAA/xwAHV8g+wJjdBuJyAAAH9FlgcUAABXwIEceSB5RH1I [...]
\ No newline at end of file
diff --git a/api/search.index/19cc30d33d.js b/api/search.index/19cc30d33d.js
new file mode 100644
index 000000000..55180a261
--- /dev/null
+++ b/api/search.index/19cc30d33d.js
@@ -0,0 +1 @@
+rn_("FYHCAAATAh+6IHUBwAAAFiIcYlkMWgxpD2oPaw9sD20PAUA7MAAAAQAAkAABAIUYkAArisMAABwvAUTioR8AAMggAABfIQAAYgBbwAHAxwAAIbJBwgAApRamFrscvBzzAII7MAAAAQAA7QADAHsMAACVD+kAXxUCAPv9CGAE")
\ No newline at end of file
diff --git a/api/search.index/19de6a319a.js b/api/search.index/19de6a319a.js
new file mode 100644
index 000000000..4dbb231cb
--- /dev/null
+++ b/api/search.index/19de6a319a.js
@@ -0,0 +1 @@
+rn_("dQPGAAAxShxLHB4eEs8cotAcaWxypxoKHAscqhyrHMIgwyChxQAAqBYlAc0AABDbH3OFH8UgFQHRAAAWAyJk2CEVAdgAABYRImQCIvOHAnJ2JQLHAAAm2h/aIBJHHWJyjBuhHCHHAACLG6kf1wcA/gAJpAzLAAAfGgEKHgAABQLBAAAUxiEV0SFxc4MA/kACkAjEAAAg7sUAACHcxQAAH7zCAAAeCjswAAABAAAqABQAZg8BAJoWAABZGg0AOhwDABwdAQBCHQAA5R0AACUeAABCHgMAUh4AAOweAQBOHwEAWR8AAJgfAADTHwAAxyAAANAgAAAjIQAAKSEAAIkhAADFAsAAACeQIGshEB4bZnM4GiHFAABcHGEfIcEAAMATphwBRuI5HgAA5SAAACwhAAAQgLMB/SABA8QAABwd51IMAABbDgAAkBYAAEMaAABiGwAAJx8AAM4fAABTIQAAEQAhEAEAkMQAABt05Vg [...]
\ No newline at end of file
diff --git a/api/search.index/1a1a352024.js b/api/search.index/1a1a352024.js
deleted file mode 100644
index 337dc09f0..000000000
--- a/api/search.index/1a1a352024.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("RQHDAACmByJklx+YH+Mh5CGhwwAABg8FAsAAABKKIBFIIXR68wCEAaQgAAAxwQAAMh8zH3Eh8wECaXPlhBsAAPIcAAAsHgAAiB8AANUfAADXIAAAAhAQ+wNlbnM=")
\ No newline at end of file
diff --git a/api/search.index/1a28b6c776.js b/api/search.index/1a28b6c776.js
new file mode 100644
index 000000000..4867a195b
--- /dev/null
+++ b/api/search.index/1a28b6c776.js
@@ -0,0 +1 @@
+rn_("BQLEAAAhdCAIIRVDIWVyEwUCwQAAHk5icuR1GwAARRwAAHocAAAnHQAA7CEAABEAAKHGAACSICMBAsMAABxyZnDkwhsAAAEeAAA7HwAAih8AAN4fAAAABVD7Am50")
\ No newline at end of file
diff --git a/api/search.index/1aa0145b25.js b/api/search.index/1aa0145b25.js
deleted file mode 100644
index e23bc700e..000000000
--- a/api/search.index/1aa0145b25.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAXHyEipBYpHW95ocYAACYdAUThkR8AAOUfAAAzcwHDCIjDAAAb6skAACFp5HgMAADNDgAAuxMAAMcUAAAOHAAAIgAA")
\ No newline at end of file
diff --git a/api/search.index/1b7f1f7f92.js b/api/search.index/1b7f1f7f92.js
new file mode 100644
index 000000000..3bfea71a6
--- /dev/null
+++ b/api/search.index/1b7f1f7f92.js
@@ -0,0 +1 @@
+rn_("McMAAOAUyyDyIHX9wiAQGQAApm0eG8sgHPEgFGIcHPIg6Q7qDusO7A43DzgPOQ+hxAAAah8jAMAIQsMAAByT4AAAEQbmig8AABccAADtHQAASR8AAFUhAABXIQAAXSEAACMCAAC7wATKwgAAG27AAAAcog==")
\ No newline at end of file
diff --git a/api/search.index/1be2a2b877.js b/api/search.index/1be2a2b877.js
new file mode 100644
index 000000000..213a461ea
--- /dev/null
+++ b/api/search.index/1be2a2b877.js
@@ -0,0 +1 @@
+rn_("pQHDAAAUgCBmxCGhwgAAhxuhxAAADyHzAAFt4/IQAACPHAAAoxwAAMwgAAADERsCwAAAEKFkbhWCxQAAFMQgTR4bAsEAAB7qdXlnAQH9A0EDxAAAIOnAAAAfvMMAAB7r7ZsTAACwEwAAVBoAAGwaAABqGwAAbBsAANUcAAAqHQAACR4AAJsfAAC7HwAA1h8AAAchAACKIQAAAAMBAAABANHEAADOGwUCwAAAP6EhvSG+ITdtIAEhAiFhciMEA8AAACCBxAAAIN5lcHMBkhoAAPcAAP0WBQDJAAAf2PKjAQAA9hQ=")
\ No newline at end of file
diff --git a/api/search.index/1c0dcb0683.js b/api/search.index/1c0dcb0683.js
new file mode 100644
index 000000000..f410434db
--- /dev/null
+++ b/api/search.index/1c0dcb0683.js
@@ -0,0 +1 @@
+rn_("FQHDAAAWAyJk2CETAALDAAAbe3N06/MOAABoDwAAcQ8AAM0cAAA5HgAAaiAAAKggAAC4IAAAvCAAAOUgAAAsIQAAryEAAAAxEIAQgAUCwAAAFiAfEZAbYm+hwgAAhxtlAcEAAKQPIW2PHJAckRySHMwgzSAVgsUAABTEIE0eGwLBAAAe6nV54wL9AwEDxAAAIOnDAAAe6+iwEwAAbBoAAGwbAADVHAAAmx8AALsfAADWHwAAByEAAIohAAADEAAQACUBzwAAFhIiZPUhDyJFAccAABiuIWerIawh8CHxIQFG5c0cAABqIAAAqCAAALggAAC8IAAAryEAABCAEBUByAAAEFogcxcfocQAAEEc+wJvcncBAv0kyADFAAAhH+X+DgAAjQ8AACgcAAC2HAAAvhwAABQhAAAQABB3AQD+QAIAScAAAB9pOjAAAAEAAAAAABgAEAAAAIkQmxB4G30bOBw4HgIfAx8HHw0fZR+ [...]
\ No newline at end of file
diff --git a/api/search.index/1c23bb2ea9.js b/api/search.index/1c23bb2ea9.js
new file mode 100644
index 000000000..da8075af1
--- /dev/null
+++ b/api/search.index/1c23bb2ea9.js
@@ -0,0 +1 @@
+rn_("QcgAAG8hciGIIY8hQcIAAGYgcyC2IMAgBQLAAAAc8yEdyyFhaAccgv0fAB7GAAAhjscAACGRxwAAIZjUAAAiAckAACHXywAAIbsrAsEAACFRb3I=")
\ No newline at end of file
diff --git a/api/search.index/1c483d17ea.js b/api/search.index/1c483d17ea.js
deleted file mode 100644
index 551f8cd03..000000000
--- a/api/search.index/1c483d17ea.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHFAAAYQyFj6h7PITUBxAAAFu8hZNUg1iCxIQUCwAAAEswcJiwcCB5icvuJYwADxAAAILZhdHXkrhMAAFwVAAA/HQAAyh4AAOgeAAACEQChxgAAFR9VgsAAABUUH50ayhzLHBAfER/7AmZ0G4rFAAAeTQWRwAAAIWUMQBoi9w4mGxUBwAAAFt4cZFAMG4zAAAAanCHAAABOCsYUIcAAAOgbSiChxAAAex9jAMAIQsMAACFH5UwbAAAgHwAAuR8AAOkfAACcIQAA6SEAANAAAfsCZG4FAsEAABPpHiJIHAsfcnUVkMAAABTKG00KG8QAMMoAACFgwgAAEKAVAcEAABYEImTeIROJAsMAACGrbW81AcMAABbnIWRSIFMgniFrwBEBwQAAGj8BAP03qUd0zaFcE8IAAB0hwwAAIRlv7JK7e3gdK/6HWT7dpX4Mg92HD3LLJHWSyAAAISRSLmid5jZ0fVzGxwAAId/BAAA [...]
\ No newline at end of file
diff --git a/api/search.index/1c73eb078e.js b/api/search.index/1c73eb078e.js
deleted file mode 100644
index c4362bed3..000000000
--- a/api/search.index/1c73eb078e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHGAAAWayBmKRwJAtAAACFUzQAAIOZlbaUCxgAAFmogGDwhYncnHPMBwIJA4mIMAACUDgAABR4AABMAK8GAIMAAAB+xbEQ579U=")
\ No newline at end of file
diff --git a/api/search.index/1c767f3b4d.js b/api/search.index/1c767f3b4d.js
deleted file mode 100644
index 97c169bef..000000000
--- a/api/search.index/1c767f3b4d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHHAAAUDyFspiEbAsIAABwPY3QrAsoAACGlbW6xxAAAYhsFwMAAyAAAFaMcGl4gFiMe2/2BSAHLAAAgo8cAAB4k")
\ No newline at end of file
diff --git a/api/search.index/1cb08eb70d.js b/api/search.index/1cb08eb70d.js
new file mode 100644
index 000000000..4b1c948cc
--- /dev/null
+++ b/api/search.index/1cb08eb70d.js
@@ -0,0 +1 @@
+rn_("ocUAAG8fBYbAAAAkGx+7IBJ+FnHBAABMHE0cThxIHvseDB/tIaHJAAAlIfMAA2dpc/VuDwAA5Q8BAB4BQQArAsoAACGXdHmjAP0YEALIAAAg5MUAACHt8i4JAABJEg==")
\ No newline at end of file
diff --git a/api/search.index/1cf7e98668.js b/api/search.index/1cf7e98668.js
new file mode 100644
index 000000000..83492463e
--- /dev/null
+++ b/api/search.index/1cf7e98668.js
@@ -0,0 +1 @@
+rn_("BQLAAAAXzR4TMR5lcBUBxQAAFzUhc9cgKwLCAAAeBG10McYAACQeVCBVIKHKAAClIAGEA8MAACBe0wAAIe7HAAAhTmNlbEHDAACAGjodXB9dH/uF+8AAxPMAA2FlcwH/IQAA")
\ No newline at end of file
diff --git a/api/search.index/1d138d9776.js b/api/search.index/1d138d9776.js
new file mode 100644
index 000000000..8cc8c42c2
--- /dev/null
+++ b/api/search.index/1d138d9776.js
@@ -0,0 +1 @@
+rn_("BQPAAAAV2SAeXiEo7R8SIWVpbaHFAAChGhWEwwAAE7ogCR8FAsMAABrXIR3zIWV0IwQCxQAAIOpicAFAHQAAFQHAAAAWUR5ishPzgQJudBMAAsYAAB9zY3LhKRsAAEkhAACABQLAAAAUyh8SOR1wdQWGwQAAQmYfZx98H24gpk8e84ECcXNRyQAAQh3sHu0e0CApIQUCxAAAIXQgCCEVQyFlchMHAsEAAB5OYnLhRRwAACcdAAAQocQAAKUWAUSJ6hsAACHJAACIIBohW8QCBMoAAB/LMcYAAIsh5yEQIiMAAsEAAB3vYWToNxoAALAaAADSHwAAaSEAAIYhAACeIQAAwCEAAMkhAAD6IQAAAAEQAQAxxgAAQxxEHEsgBQLAAACjnxpH6x/sH+sgESFtbmsDwgAAHHFhb3IFAsEAACbbIPMhFIobY2kBAP7Ab6wfywAAH4FPa13QyT9PlMHeXtvTi+1QLsdw9MQAACF [...]
\ No newline at end of file
diff --git a/api/search.index/1e25b247eb.js b/api/search.index/1e25b247eb.js
deleted file mode 100644
index 8fb7ccb0e..000000000
--- a/api/search.index/1e25b247eb.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAXdyEyMhwzHCIfb3kFAsAAACVCHoAgFE8gaXmhxAAAwhyzAcABwcQAAB1C5qMTAADjFAAA9RQAALkbAADfHAAAXiAAALMhAAATEAAA")
\ No newline at end of file
diff --git a/api/search.index/1e4f3a3b22.js b/api/search.index/1e4f3a3b22.js
new file mode 100644
index 000000000..daa5d7331
--- /dev/null
+++ b/api/search.index/1e4f3a3b22.js
@@ -0,0 +1 @@
+rn_("JQHFAAAYQiFj6R7OITUBxAAAFu8hZNQg1SCwIQUCwAAAEsscJiscBx5icvuJYwADxAAAILVhdHXkrhMAAFwVAAA+HQAAyR4AAOceAAACEQChxgAAFB9VgsAAABUTH50ayRzKHA8fEB/7AmZ0G4rFAAAeTAWRwAAAIWUMQBoi9w4mGxUBwAAAFt0cZFAMG4zAAAAanCHAAABOCsYUIcAAAOcbSSChxAAAeh9jAMAIQsMAACFG5UwbAAAfHwAAuB8AAOgfAACbIQAA6CEAANAAAfsCZG4FAsEAABPoHiJHHAofcnUVkMAAABTJG00KG8QAMMoAACFfwgAAEKAVAcEAABYEImTdIROJAsMAACGqbW81AcMAABbmIWRRIFIgnSFrwBEBwQAAGj8BAP03qUdqeM5bZsIAAB0gwwAAIRhFChbURls7dcpFOaEJw204EmZc7XLLJHWSyAAAISMG3vAtAhhAq+FDxwAAId7BAAA [...]
\ No newline at end of file
diff --git a/api/search.index/1ee976d785.js b/api/search.index/1ee976d785.js
new file mode 100644
index 000000000..2227672eb
--- /dev/null
+++ b/api/search.index/1ee976d785.js
@@ -0,0 +1 @@
+rn_("ocMAABYeIcMAABUeYyEFjMAAACLMHBkhKSQh0iHjAP0hgQDEAAAg7+6ADwAAcBoAAJYaAADeGwAAPhwAAB4dAABGHgAAUB8AAFofAACaIAAA7CAAAEshAABNIQAAWCEAAJMhAAAAEBEREBABAA==")
\ No newline at end of file
diff --git a/api/search.index/1eef1a3d86.js b/api/search.index/1eef1a3d86.js
new file mode 100644
index 000000000..1231615b8
--- /dev/null
+++ b/api/search.index/1eef1a3d86.js
@@ -0,0 +1 @@
+rn_("QcAAAMMbxBsFHAYcFQLDAAAWkiESHCFicnUgI4cCwwAAIMZmcxsCxgAAHK1hchUBxAAAEIkfcx0fswDACOjHAAAcrsIAABOK+jEKAAABAAARLgBXAAEAjwASAIsCJgA=")
\ No newline at end of file
diff --git a/api/search.index/1faed6253b.js b/api/search.index/1faed6253b.js
new file mode 100644
index 000000000..863e480fa
--- /dev/null
+++ b/api/search.index/1faed6253b.js
@@ -0,0 +1 @@
+rn_("AUL5nRAAAAcGAgSiAFAAAQCPAQsAnQIlAscAABdbIRUbIWJmch/LIRUBxAAAEzcdYosaE4ECxAAAG3xxcysCxAAAFpBjchUBwQAAFgQiZN0hE4sCwwAAIaptbysCxQAAIR5sdAXAwABkAADEgiBAkBOhIb0hviEYzh4BAAHGAAAfc3KJKRsAAAUCwQAAFGYfFcofcXPzgwJyc78H/RHBQcYAACHe")
\ No newline at end of file
diff --git a/api/search.index/1fd2386113.js b/api/search.index/1fd2386113.js
new file mode 100644
index 000000000..d63c56fd9
--- /dev/null
+++ b/api/search.index/1fd2386113.js
@@ -0,0 +1 @@
+rn_("BQLAAAAVrRwiqhYfHmRmG4rGAAAf0yHCAABfH9ch8wKQ7JQQAACvEAAAiRoAAJQaAACCGwAAMx4AAMweAAAAHwAANx8AAGwfAACtHwAAUiEAAGAhAAAFAAEQAAAAGwLgAAAgv2lzJQHCAAAWEiJk9SEPIqHCAAB4HDHDAAAJIQohsSElAsMAABaSIRIcIWJyiB91IBUBwQAApJkhbX0hNQHEAAAQfiBz3B/dH8Yg9wAE/gBIAAvJAAAhwQGNIQAA84ECaW77AnJ0+wNhb3I=")
\ No newline at end of file
diff --git a/api/search.index/1ffab88926.js b/api/search.index/1ffab88926.js
deleted file mode 100644
index 98f676b1c..000000000
--- a/api/search.index/1ffab88926.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAACkax9t7h3zAoSCyBwAAKUBwQAApBAhbc0g8weE9ZwfAAA7AAEAMAGDAGsDxQAAHwBjb3BFhMMAABFeIfQgdiGFIbchE4gCwgAAIPVzdAUCwwAAJoggqCGkMB9tcwWFwAAAGuQgF2kfBQLAAAAVMR4W/x5jbCUBxQAAFuYhZJ0h4CETg8AIRMsAACE3wgAAIYGhxgAA7B13LgDAOu/FAAAeMs8AACE4zQAAIVLCAAAbSDswAAABAABVABsAagwEAO0OAAA7DyYAnRYBALAbAAAcHAAAphwAAN4cAAA6HQAA9R0AAMcfAAClIAAAsyAAAEQhAABLIQAATSEAAIwhAAC4IQAA3SEAAOYhAgDvIQAA9yEBAPshAwAAIgAAAyIIAA4iAAAQIgIAVQPAAAAW1R4kmxNUGqpIH2FvdmAM9w55DyYbXhwxwQAAPSGCIYMhFQHAAAAeeSFwvxPzgYr7A2FsdA==")
\ No newline at end of file
diff --git a/api/search.index/2015cf1d00.js b/api/search.index/2015cf1d00.js
deleted file mode 100644
index 31551b9ee..000000000
--- a/api/search.index/2015cf1d00.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAAAWBCJk3iETjALDAAAhq21vBQLFAAAUZx8Vyx9xc/uJpQHJAAAURyFm6SElAckAABbdIWSZH4ohJQHMAAAW/iFkRiHOISUBzAAAFv0hZEUhzSH7hQUCwAAAF3chMjIcMxwiH295IcYAAEIegCDzAgJsdOKjEwAA4xQAALkbAAATADWBwQAAI3gbOR63FLgUwiAhxgAA+CELIucPAP0cMQ7HAAAg4sIAAB4V/F0OAABCDAEAywCTBREAhwAkAA4AAQAlAAQA")
\ No newline at end of file
diff --git a/api/search.index/203bddd617.js b/api/search.index/203bddd617.js
new file mode 100644
index 000000000..628dbedc1
--- /dev/null
+++ b/api/search.index/203bddd617.js
@@ -0,0 +1 @@
+rn_("JQHAAAATZSBqsxpaIKWCwwAAIVAhbSF6IaWCxwAAFB0hgh8rAsAAAB+vZHohxgAA9B2kIPHCAAA3G7cJAf0cSQPAAAATn8EAABaZwwAAHLX5hxYAAAEAjwIFAwcC6wAEAAUAowA=")
\ No newline at end of file
diff --git a/api/search.index/20afe5d819.js b/api/search.index/20afe5d819.js
deleted file mode 100644
index 3de15dd1e..000000000
--- a/api/search.index/20afe5d819.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUHqmxAAAHgbAAB9GwAAOR4AAAMfAAAIHwAADh8AALQfAADMHwAANyEAAK8hAAAAABABAQBBwgAAnBPYFCYhJyGxxwAANR+lAcIAABfSIG2sG6HHAACrH6HDAAB5G/MAwIwBAcQQAAD7jg==")
\ No newline at end of file
diff --git a/api/search.index/20e61b2513.js b/api/search.index/20e61b2513.js
new file mode 100644
index 000000000..d7345c72c
--- /dev/null
+++ b/api/search.index/20e61b2513.js
@@ -0,0 +1 @@
+rn_("BQLAAAATBB4V1yBtdKHHAABUIPuDg4PADkrMAAAhpM0AACGAwAAAGzTPAAAhv8MAAB0EdQPGAAAxShxLHB4eEs8cotAcaWxypxoKHAscqhyrHMIgwyChxQAAqBZRxgAABB+0IEAhtSG6IRMAAsQAACFuYmPpjRYAAK4aAAAbGwAAshwAAGseAAARHwAA9yAAAP8gAAA4IQAAPSEAAAEQEBEAocIAAEob8wICbnLyjxMAAKAJJQHMAAAQ2x9zhR/FIPuGFQHRAAAWAyJk2CEVAdgAABYRImQCIvOHAnJ24cUAAE4aNQLHAAAm2h/aIBJHHWJyjBuhHNggFcHBACgAAKSzIRKiIRa5H7If4cMAANEU+wJudAUDwgAAuLUfp0UfFuQeZW11KwLKAAAfGm9yIccAAIsbqR/zAP4ASbQcOzAAAAEAAE0AAwCEBEkAkg8CAAoeAAA=")
\ No newline at end of file
diff --git a/api/search.index/21117bbb41.js b/api/search.index/21117bbb41.js
deleted file mode 100644
index 1b57ff4a9..000000000
--- a/api/search.index/21117bbb41.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHEAAAaaSF3DhwVAcQAABpoIXcNHPsCY3RBwQAAiRA5HGYfQiFVAsEAAKTCHBVCHWJz9RT2FN8cXiCzIaHFAAAAIRUBwAAAFP8gYz4dFQHJAAAWuyFiPiHzh8IIQPsCb3ZxwQAA4hvjGxYe7B6KIJogZCH7/RBBAg==")
\ No newline at end of file
diff --git a/api/search.index/211d0950e5.js b/api/search.index/211d0950e5.js
deleted file mode 100644
index d62df5cb1..000000000
--- a/api/search.index/211d0950e5.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("oc0AACYhocIAAIcbZQHBAACkECFtkByRHJIckxzNIM4gFYLFAAAUxSBOHhsCwQAAHut1eeME/QMBA8QAACDqwwAAHuzosBMAAGwaAABsGwAA1hwAAJwfAAC8HwAA1x8AAAghAACLIQAAAxAAEAAFAsAAACOvEyceFBwhaXIlAsEAABQrHRQZHm90JxtvH8cDAP06QALGAAAhXMcAABxB+CkJAAAIFQEAzQBqAAoA3wF6AA==")
\ No newline at end of file
diff --git a/api/search.index/2194a61837.js b/api/search.index/2194a61837.js
deleted file mode 100644
index b143c2507..000000000
--- a/api/search.index/2194a61837.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McUAABsdHB15HwEAAcUAACIFZPuSDgAAAQCvC9cA2QIOAOYAFAB/AgQAZAAbAsEAAB7UaHkVAcYAABawIWYVIRUBxQAAFkEhYhIfFQHAAAAUiyBjrx/zAwJzdwEdHwAApQHDAAAUIx9mqSEhwAAALA/zHaUBxgAAFIEgZsUhBYPAAACkyiFVCB+0H7UfOCGvIccDAP0kYAbLAAAhbc4AACGm81AKAACdCmAJZwcA/TQAF8gAAB8TxwAAIEk7MAAAAQAAQwAYAOoEAQAECQEAdQwCAMsOAQCBDwAAlRAAAKEQAACmEAAAhhMAALETAADqFAAAaBUiAIkWAACPGgAAyBsBAMsbAwCaHAAAIh0AAEIdAAAbHgEAJx8AAIggAADdIAAAqCEAAA==")
\ No newline at end of file
diff --git a/api/search.index/2216409478.js b/api/search.index/2216409478.js
new file mode 100644
index 000000000..e3a9198dc
--- /dev/null
+++ b/api/search.index/2216409478.js
@@ -0,0 +1 @@
+rn_("QcMAAOsf7B/rIBEh8wABbOhfDgAAmRAAAKIQAACSEwAAnRMAAIIaAABBHAAA3xwAAG4hAACQAAAQAFUBwgAAEH4gc8AcCB7cH90fxiA7A8EAABpXZWdsBQLAAAATeR8awCFpbjv9AUkAwwAAIOHUAAAhrQ==")
\ No newline at end of file
diff --git a/api/search.index/225122cf8a.js b/api/search.index/225122cf8a.js
deleted file mode 100644
index d945f975d..000000000
--- a/api/search.index/225122cf8a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQLDAAAVlR8WoyF0d8MfmCAVAsMAABZkHxZlH2JvfxobAs0AACDfYWMhwwAA7RRNHvuDwcEAAOcdAUE7MAAAAQAAkQACAAIPAAAJEZAA8wCSggYPAAABQTswAAABAADrAAIAiRMAAJkX6gArlMAAABCMJQHCAAAW+CFk/iC6IROBAsMAACGubW4BAQHDAAAb3mbjNRsAAKYbAAC2HAAAPyEAABUBJQHIAAAWCSJkpCHrIaHPAADKIfOEAmZzFQHEAACgxBtzMhsbAsEAABaBYnIVAcAAABYRImQCIvsCZHIFAsAAAEdQHVEdgB/OHxtjH25yt68A/XG5B8gAAB0x0AAAIXdR5sDqgTswAAABAADuAAQAZAoBAE0MAABvDeoABxEAAA==")
\ No newline at end of file
diff --git a/api/search.index/2252572b73.js b/api/search.index/2252572b73.js
new file mode 100644
index 000000000..c10c0420a
--- /dev/null
+++ b/api/search.index/2252572b73.js
@@ -0,0 +1 @@
+rn_("McYAAIsh5yEQIiMAAsEAAB3vYWTpNxoAALAaAAB5HwAA0h8AAGkhAACGIQAAniEAAMAhAADJIQAA+iEAAAAAEQAQ")
\ No newline at end of file
diff --git a/api/search.index/230ad59110.js b/api/search.index/230ad59110.js
deleted file mode 100644
index 37ccbc2e5..000000000
--- a/api/search.index/230ad59110.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocIAAGEcBYbAAAARwxAaqh8FAsQAABdMIBnRIGNwAQEB4QAAFLlz6PEOAAC6EAAAWBwAAF8cAACXHAAAnxwAAG4eAADAHwAAnyAAAAgREREQS8ACgcMAACGGxwAAHxohxgAApSHAIROCAtIAACGyZHUhxgAAACIGIvMEAWTlLx4AACUfAABjIQAAfyEAANQhAADiIQAAEQEAEwUCwwAAIdVjbIKxGgAAG4rBAAAaNhUCwQAAFXghE7MfZncWGSOCAsMAACF6aWwFg8AAABOGFtAtD/sCcnT7A2FydRUBwQAAFgQiZN4hE4wCwwAAIattbwUCxQAAFGcfFcsfcXP7iaUByQAAFEchZukhJQHJAAAW3SFkmR+KISUBzAAAFv4hZEYhziElAcwAABb9IWRFIc0h+4XnAQH9BDAOxwAAIOLCAAAeFeJdDgAAnxoAAGsbAAABADUBxgAAE6kfZnwcRh9HHzuOwAAADl4hwwA [...]
\ No newline at end of file
diff --git a/api/search.index/235a27a73c.js b/api/search.index/235a27a73c.js
deleted file mode 100644
index d8f832764..000000000
--- a/api/search.index/235a27a73c.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocMAABceIcMAABYeZCEFjMAAACLNHBohKSUh0yHjAP0hgQDEAAAg8O6ADwAAcBoAAJYaAADfGwAAPxwAAB8dAABHHgAAUR8AAFsfAACbIAAA7SAAAEwhAABOIQAAWSEAAJQhAAAAEBEREBABAA==")
\ No newline at end of file
diff --git a/api/search.index/236e5f6f6f.js b/api/search.index/236e5f6f6f.js
new file mode 100644
index 000000000..87fcfd0df
--- /dev/null
+++ b/api/search.index/236e5f6f6f.js
@@ -0,0 +1 @@
+rn_("ocYAALcbBQLAAABkkhYgGyEbIhsjGyQbFCUbaHQFAsEAABI+GhFMH3J0QcIAAI0cjhxJHvwe9YHCAAATfRu8FKHDAAA8GvsCbnQFAsAAALPhHCSRFh8bZnUFmMAAABjSHrW0G6ddAP7AzCEPwQAAEMbKAAAeOMIAABybwwAAGj/BAAAQxzswAAABAABmAgUA5QQAAAcI6QAEDwAAkRLpAIUYkAA=")
\ No newline at end of file
diff --git a/api/search.index/23a01b535e.js b/api/search.index/23a01b535e.js
new file mode 100644
index 000000000..8d884018b
--- /dev/null
+++ b/api/search.index/23a01b535e.js
@@ -0,0 +1 @@
+rn_("UcIAAIsbQxxEHKkfSyABAwHFAAAfZ3KJmhsAABsCzgAAIVxhchWQwwAAFEghNh3zBIjyiBoAACcBAQgBxQAAIOJyiWAeAAChyAAAJx/nAQDAhKTJAAAfyQHoGwAAO5bMAAAfbhUBwAAAIAARgB9u+QSlkMAAABojH+IOAQCEwQAAE7HldAwAAMkOAACMEwAAahwAAG8fAADeIAAAAQUQBQLAAAAgjBzuHSqBH+YgbHIhxgAAgR/mIKHDAADzEDUBwAAAEh0bbW8PcA/FHzHGAAAOHQ8dYx8XAQH9AlADwQAAE5PFAAAfZMcAACIB6KIOAAB/GgAAGhsAAIUbAAC3HAAAMB0AAAAeAAB1HwAAlSAAAKAAAQAABYPAAAAfZCEY5h63AQD9OEBAwgAAFOfk7wQAABYJAACXEAAAhBgAAKwcAAAKAACvD8EWp8MAACBxwAAAIa3BAAAaVQ==")
\ No newline at end of file
diff --git a/api/search.index/23da842426.js b/api/search.index/23da842426.js
new file mode 100644
index 000000000..c356983f8
--- /dev/null
+++ b/api/search.index/23da842426.js
@@ -0,0 +1 @@
+rn_("YcAAAAgcCRziHuMeRx9IHyHDAACNG/oeIcIAAKgaKB7zAMCAROjIFAAAzhsAAFMeAAAeHwAAnh8AAOkfAABIIAAAiiAAABghAAAEEAAAAAFDOzAAAAEAAJEAAgAfHAAAVB2QAKHEAAC3G9v9CgEEHu8aPYY=")
\ No newline at end of file
diff --git a/api/search.index/23f5041bd9.js b/api/search.index/23f5041bd9.js
new file mode 100644
index 000000000..4945764ec
--- /dev/null
+++ b/api/search.index/23f5041bd9.js
@@ -0,0 +1 @@
+rn_("AQQBxQAAH3xyidMbAAAFAssAABTGIRXRIXFzEwQCxQAAIOJwcuFgHgAA8B4AAIghyAAAAx82IfMBwBDAOzAAAAEAAOwAAwCSFekAKh4AAKofAQA=")
\ No newline at end of file
diff --git a/api/search.index/23fc1d5970.js b/api/search.index/23fc1d5970.js
deleted file mode 100644
index a02fd101f..000000000
--- a/api/search.index/23fc1d5970.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHHAAAWCSJkpCHrISUBxQAAGEMhY+oezyE1AcQAABbvIWTVINYgsSEricIAABzMYwADxAAAILZhdHXkrhMAAFwVAAA/HQAAyh4AAOgeAAACEQChxgAAFR9VgsAAABUUH50ayhzLHBAfER/7AmZ0G4rFAAAeTSHAAADoG0ogocQAAHsfYwHACELDAAAhR+VMGwAAIB8AALkfAADpHwAAnCEAAOkhAADQAAE1AcQAABbnIWRSIFMgniEXGQL9J4kHwgAAHSHDAAAhGcQAAB7pwQAAGpzIAAAhJMcAACHf56QQAAABEQAAexoAAI8bAABqHgAAWSAAACUhAADTIQAABBAAAGMAA8oAACG8Y2hp4iIMAAA2GgAAeBoAABAQ")
\ No newline at end of file
diff --git a/api/search.index/244e367e76.js b/api/search.index/244e367e76.js
deleted file mode 100644
index 8a615f797..000000000
--- a/api/search.index/244e367e76.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYnAAAATHCERjxAhwgAASBwLHxWBwAAAGL8f3xQbAsEAAB7pbXL7AnJ1IcQAAM8eBh8lAcQAABYKImSnIewh8wIBYgGBIQAAGwLDAAAe/ml0wcMAACofJQHFAAAW5iFknSHgIdMBwAhMywAAITf6lBMAAAEAAAMBAOkEBwETANUCXwCUAKUBwQAAEE4fc9EeEwICwgAAHTlpbuSvEwAAcxwAACceAACRHwAA5R8AAAADMPsDZWx4AUXiOh4AAOYgAAAtIQAAEIDvAQXEAAATtzhhaW9y")
\ No newline at end of file
diff --git a/api/search.index/2456582a55.js b/api/search.index/2456582a55.js
deleted file mode 100644
index 4c7d54879..000000000
--- a/api/search.index/2456582a55.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("dQHBAAAzlRaWFs0fZmcMThpPGlAaURpSGlMaBQLAAAATJR12Oxw8HD0cPhwdHR4dJCFqcBUBxAAAEzgdYosaGwLEAAAbfHFz+4pBwgAAJh0nHZMglCAxyAAA7SDuIEwhRYTCAAARXiH0IHYhhSG3ITsDyQAAIZZwdHUjhAPAAAAfO8IAACD1aXN084ECaW6hxAAABh4lAcgAABb8IWQjIcQhJQHHAAAW+CFk/iC6IfOBwADgO8AQoMAAAByJ2/0FAAnEAAAWkA==")
\ No newline at end of file
diff --git a/api/search.index/2464a72671.js b/api/search.index/2464a72671.js
new file mode 100644
index 000000000..e36aa197d
--- /dev/null
+++ b/api/search.index/2464a72671.js
@@ -0,0 +1 @@
+rn_("IcQAANYcxx/BxgAAgiAlAdEAABYKImSmIeshG4ngAAATgAFG+AQfAABjAQQASQAFAIcAdQAFABMAwAMIxAAAIW7IAAAeUjowAAABAAAAAAAsABAAAADRDtIO0w7UDtUO1g7XDtgO2Q7aDtsO3A6NFq4arxobGxwbcxuGGyQcLhx0HHUcshy5HAUdGh0bHTIdXh5fHmsebB4RH3YfeB/ZH6AgoSD3IPgg/yAAITghPSEVAdQAABYLImTyISUBzwAAFhIiZPUhDyIhxwAArCHxIfOLAmxwGwLCAAAbamJyocIAAEobBYPAAAAaYCAqYSCgISHSAACrIfAhGwLJAAAgsmxyFQHLAAAWECJk+iH7iSHFAAClHMYfIccAAF8gnyEJlMgAACFP0AAAIcDzggJmbPuD8wD9KPAFOzAAAAEAABgABgBXCgAANAwTAI8TAACeEwAA2RQAAC8dAADb/ZAARMAAACH/ocYAAMkh8wG [...]
\ No newline at end of file
diff --git a/api/search.index/24b412498b.js b/api/search.index/24b412498b.js
deleted file mode 100644
index 13656eb6d..000000000
--- a/api/search.index/24b412498b.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McAAAN0bVh9XH6HGAACTIDHFAADPH9AfVCHTAMAKSMMAABxz5cMbAAACHgAAUB4AADwfAACLHwAA3x8AAAAQVbHGAAC2HzvBAoDgAAAQuQ==")
\ No newline at end of file
diff --git a/api/search.index/24d547fde0.js b/api/search.index/24d547fde0.js
deleted file mode 100644
index f0f00a704..000000000
--- a/api/search.index/24d547fde0.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("UcIAAIsbRBxFHKofTCABAwHFAAAfaHKJmhsAABsCzgAAIV1hchWQwwAAFEkhNx3zBIjyiBoAACcBAQgBxQAAIONyiWEeAAChyAAAKB/nAQDAhKTJAAAfygHpGwAA+4Y=")
\ No newline at end of file
diff --git a/api/search.index/24d869c30a.js b/api/search.index/24d869c30a.js
new file mode 100644
index 000000000..a4ee701be
--- /dev/null
+++ b/api/search.index/24d869c30a.js
@@ -0,0 +1 @@
+rn_("AQD9ABUBwgAAE43CAAATjsMAABaMxgAAHCHtOwoAABMMAACqEwAAtxMAAIEWAACXFgAAgxsAAC8cAABDHQAARR0AABkfAABkIAAAxCAAAB0hAACgAAEAAQAA")
\ No newline at end of file
diff --git a/api/search.index/24f3a90cdb.js b/api/search.index/24f3a90cdb.js
new file mode 100644
index 000000000..0c53b1ecd
--- /dev/null
+++ b/api/search.index/24f3a90cdb.js
@@ -0,0 +1 @@
+rn_("FQHCAACinhxz5xQlAcAAACQeH+kfY/MdOB8jAQLGAAAh7G1z4akQAADoIAAAEAWJwAAAF40hEb8gocQAADkhBYnEAAAS1iER0CEjhQLgAAAhVmRmBQLEAAAWxSETqSFvdBsCzQAAIelobzcDAcAOa8IAACDo1wAAIg3DAAAhP8QAACFX0vsgAACbIwL9EAEDwwAAIR3BAAAcveAAAB+J+Y0aAAADAE0BkwAjAIoCZQABAMMB+wJlbPsCaXI=")
\ No newline at end of file
diff --git a/api/search.index/25095b4293.js b/api/search.index/25095b4293.js
deleted file mode 100644
index 9e02f78fe..000000000
--- a/api/search.index/25095b4293.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("YcIAAJsQeBt9GzkeAx/MHwEAAsQAACFN4AAAENByc+b0DgAAeg8AAEIeAABZHwAAgCAAAB8hAAB3IQAAAgAAAFvAAIXCAAAd8w==")
\ No newline at end of file
diff --git a/api/search.index/25587405bc.js b/api/search.index/25587405bc.js
new file mode 100644
index 000000000..0c0046d72
--- /dev/null
+++ b/api/search.index/25587405bc.js
@@ -0,0 +1 @@
+rn_("BYnAAAAXjSERvyAFicQAABLWIRHQISOFAuAAACFWZGYFAsQAABbFIROpIW90GwLNAAAh6WhvNwGEwA5pwgAAIOjXAAAiDcMAACE/xAAAIVcTgQLIAAAh7GVsBYnAAAAXjCERviAFicQAABLVIRHPISOFAuAAACFUZGYFAsQAABbEIROoIW90GwLNAAAh6GhvNwGGwA5pwgAAIOfXAAAiDMMAACE+xAAAIVVjAP0lgADFAAAcKsgAAB/TAYQPAAA=")
\ No newline at end of file
diff --git a/api/search.index/2564cee0c6.js b/api/search.index/2564cee0c6.js
deleted file mode 100644
index f0eb67f63..000000000
--- a/api/search.index/2564cee0c6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYPBAAASXBwVXR4Fg8EAABJbHBVcHmv8DgDgAAAQriHEAABlIMUg8wGCOjAAAAEAAAAAAD4AEAAAAAkPCg8LDwwPDQ8ODw8PEA8RDxIPEw8UDxUPFg8XDxgPGQ8aDxsPHA8dDx4PHw8gDyEPIg8jD4obtBu1G7YbIxw3HLAcsRwPHRAdNR1OHlIeBR8HHxcfZB9yH34fyR/bH2ggaiBsIG0gdSC1ILog2yDrIAkhQSFbIZMhtiG7IZMABMQAACFExQAAHFplcnV2mGgKAAA=")
\ No newline at end of file
diff --git a/api/search.index/25768c1aba.js b/api/search.index/25768c1aba.js
deleted file mode 100644
index 0be37e223..000000000
--- a/api/search.index/25768c1aba.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcEAAJoQxRAxwQAA6xQVHxYfxQLDAAAnkSBsIRAeG2ZzOBohwAAAwBOnHCUBwAAAE2YgarMaWyClgsMAACFRIW4heyFjAQPBAAAfsGlsc/mHFgAAAQCPAgYDBwLrAAQABQCjAN8D/S1ABMIAABuR")
\ No newline at end of file
diff --git a/api/search.index/2630b1fbe0.js b/api/search.index/2630b1fbe0.js
new file mode 100644
index 000000000..b301ca525
--- /dev/null
+++ b/api/search.index/2630b1fbe0.js
@@ -0,0 +1 @@
+rn_("pQHDAAAUgCBmxCEjgYbAAAAbagUCwQAAEx8hFA0fbnIlAc8AABYSImT1IQ8iIccAAKwh8SHziwJscK8B/QOICcMAAB4pyAAAIIvCAAAhqg==")
\ No newline at end of file
diff --git a/api/search.index/26356420ef.js b/api/search.index/26356420ef.js
new file mode 100644
index 000000000..0b4f3240a
--- /dev/null
+++ b/api/search.index/26356420ef.js
@@ -0,0 +1 @@
+rn_("FYTDAAATuiAJH/MEAXTSKRwAANoxwgAAxhtHHU4eFQHRAAAWDiJk9iEhwgAAYSCgIfsCYXIlAcAAABDPIHOOGsUbAQUBxAAAIUpy4T4eAAA+HwAABvOBAmNnIcEAAIkcqB8lhMIAABHSIDkfrB/7AmVsGwLHAAAhhWlyNQHNAAAWBiJkfiF/IeEhBQLDAAATICGg1h5uc/OBAmxtBQLEAABB2h90INogCCEVQyFlcvcLAsIL6cYAACE10wAAIew7MAAAAQAANAAYAN8QDwBvGwEAdRsBAIwbAACuGwAAuhsHAEUcAQBWHAAAehwBAKEcAAAnHQAAOx0AAD0eAABFHwEA2B8AAO0fAACIIAAA0SAAANcgAQD2IAAAEiEAABohAADZIQEA7CEAABsCwQAAFpRhZA==")
\ No newline at end of file
diff --git a/api/search.index/2654dd4db6.js b/api/search.index/2654dd4db6.js
deleted file mode 100644
index e8d1a7d2d..000000000
--- a/api/search.index/2654dd4db6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHFAAAWaCBiJRwFAsAAABRLIBwgIWN0BQLAAAAWSiERTiAzcQcBhMAwYcIAACCPwQAAIE3EAAAg+sIAACCQKwLFAAAfsWN0G4nFAAAgWJcCAP0EgRbOAAAhYssAACD7xwAAH7IBdQ8AACMAAsMAACHcZmfnDh4AAFQgAACHIAAAjiAAAJIgAACXIAAAdCEAAAwiAABgAAAB")
\ No newline at end of file
diff --git a/api/search.index/26b353e595.js b/api/search.index/26b353e595.js
deleted file mode 100644
index 57ee3ecfa..000000000
--- a/api/search.index/26b353e595.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHAAABEDyHIIckh7iFspiEVAcIAABL5IW3lISOFAscAACH/YWsVAcUAAEQPIcghySHuIWymIfsCcnNBwwAAGR/gIOEgXSExxgAAAh+gHyshBQLAAAASiiARSCF0evMAhAGkIAAAMcEAADIfMx9xIfMCAmlz5PIcAAAsHgAAiB8AANUfAADXIAAAIQEAJQHMAAAWBSJkfSHhISGHAscAACH/CmFr5wEC/Q0UAMkAACHt4SIZAAAGIQAAECUBwgAAF/cgbXIbdBxHAAH9AkUEwgAAHfHHAAAfbsgAAB/NwwAAIJWDth8AADMDA9UAACHbZWltgmQPAAAxxAAAxhzHHKggBQLAAAASaxsceCFtcCHGAAAAIgYi8wABZOUvHgAAJR8AAGMhAAB/IQAA1CEAAOIhAAARAQDzAQFjAXUOAAD7wAQGJQHGAAAWCCJkmB/kISMAAsYAACBZc3X1TgwAAAEACwJqBsgFBQLEAAA [...]
\ No newline at end of file
diff --git a/api/search.index/26c797f9fa.js b/api/search.index/26c797f9fa.js
deleted file mode 100644
index 0f391cbec..000000000
--- a/api/search.index/26c797f9fa.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("pQLAAAAVJh6geBplc3wWMcUAAG4gAiEDIfsCanAFjMEAABTzIBzAIfuKpQHCAAAWQiF2aCExzAAAoiG+Ib8hOwPhAAAhtGlucyOBAsEAACEsYXT7AmFy")
\ No newline at end of file
diff --git a/api/search.index/277112f060.js b/api/search.index/277112f060.js
deleted file mode 100644
index d8931d0a5..000000000
--- a/api/search.index/277112f060.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLDAAAWIR8RkBtibzUBwQAAGHwgYqgQPR1jH0UCwgAAYU0cThxPHEke/B4NHyUcH7wgaXNUH1UfcyC0IPMAAmtvAXIgAAAVgccAABXqILwf8wADb3N04U0aAAD3HQAACAUCwQAAFOMgJQwfuCBxcwUCywAAFMchFdIhcXMBBAHDAAAh3GbnDh4AAFQgAACHIAAAjiAAAJIgAACXIAAAdCEAAAwiAABgAAABIcMAAIYTiRZFAcQAACaMIeghZDcasBrTH58hu/0JQAjFAAAfC7WCwQAAorwcXxUBRInaHgAAKwLCAAAfGnJ4FQHQAAAWESJkAiKxxwAAnCD7AmRyFQHFAAAWaCBiJRwFAsAAABRLIBwgIWN0BQLAAAAWSiERTiAzcQcBhMAwYcIAACCPwQAAIE3EAAAg+sIAACCQKwLFAAAfsWN0G4nFAAAgWJcCAv0EgRbOAAAhYssAACD7xwAAH7IBdQ8AABsCwgA [...]
\ No newline at end of file
diff --git a/api/search.index/279c5a1571.js b/api/search.index/279c5a1571.js
deleted file mode 100644
index b14ed790c..000000000
--- a/api/search.index/279c5a1571.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAVjhYZNR5hbQUCwAAAGTQeGgEfY2wFAsAAABPCIaPjHmx1McgAAD0hgiGDIfOCiSOBlMAAABqD0wD90RABxQAAH2rLAAAfbdEAACFTAbkQAAA=")
\ No newline at end of file
diff --git a/api/search.index/27bd8e6747.js b/api/search.index/27bd8e6747.js
new file mode 100644
index 000000000..4c6006bff
--- /dev/null
+++ b/api/search.index/27bd8e6747.js
@@ -0,0 +1 @@
+rn_("NQHAAABDohZaGyscBx53PhqzIbQhAQICxgAAHTzFAAAhQWF25XgcAAAlHQAAAh4AADwfAACSIAAAZyEAABEREQWJxQAAODwhgSGCIRTBIQUCwAAAFEwfYgsdDB30IAkhCiGxIW95JQHKAAAWCyJklSHyIQWMwAAAEhkhGdIhEwgCwgAAIWNmaeSaIAAA7CAAAEshAABYIQAAkyEAAAEBADHFAAChIb0hviE1hMAAABOZIG8gcCADITHCAAA/HkAeHCFBwQAASR9KH0sfXSEFAsAAACVsIJIhEpggdXnzAf0CAQPoMBwAAAYdAADvHgAAiB8AAHUgAADzIAAAdSEAAIQhAAC2IQAABAAAAAD7AmVs8wADcHR1AVYaAADFAcEAABV4H3fKGyUBwAAApJkhbToffSH7AmRuVQHEAAAQfiBzwBwIHtwf3R/GIDHFAADZH6AgoSAlAcQAABYSImT1IQ8i8wECcHcB1R4AAOc [...]
\ No newline at end of file
diff --git a/api/search.index/27e79e69b6.js b/api/search.index/27e79e69b6.js
deleted file mode 100644
index 3a6bf7f18..000000000
--- a/api/search.index/27e79e69b6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("UcgAAAgftB+1HzghryEjAgPEAAAgd8QAACFLYWdy69IQAACYGgAA5RsAAB0eAAA/HgAANR8AAD8fAADEHwAAYCAAAKAhAACsIQAA8CEAALMhAmEAEQ==")
\ No newline at end of file
diff --git a/api/search.index/27f819abd2.js b/api/search.index/27f819abd2.js
new file mode 100644
index 000000000..8d12605f0
--- /dev/null
+++ b/api/search.index/27f819abd2.js
@@ -0,0 +1 @@
+rn_("IcAAAKQhvyGhxgAAPB8VAcQAABNoIG5hGwUCwAAAE8EhYwgcCRziHuMeRx9IH2x1McgAADwhgSGCIfuJ1wEA/TSAAsUAAB875FYKAAAzDAAA6RsAAEkdAABVHgAAAAVQGwLCAAAcYmV0")
\ No newline at end of file
diff --git a/api/search.index/27fa81ede8.js b/api/search.index/27fa81ede8.js
deleted file mode 100644
index 38ced2fc6..000000000
--- a/api/search.index/27fa81ede8.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHHAACotCF3VyAxwAAAnxagFnEbAUXioh8AAMkgAABgIQAAYgAbAsUAAB8DbnQhwwAAWxU2IaWCxAAAFB4hgx8xxQAAAyIHIggioc0AAHshBQLGAAAXvSEVlSFmdPMA/ADUAVEKAABBxgAA+yH8IQkiCiLzBAFk5V4eAAAiIQAApCEAAKchAADDIQAA6yEAAAEAESHCAACNHO8d9wsA/YsBB+EAABuVOzAAAAEAAIsBEgAoCQAAMAwAAM8QAACrEwIA9xRjAH4WAACEGgEAtBpbACEeAQBwHlkAlx8BAO8fWQCDIAMApiABAEghAACBIQAA2SEAAOMhAQA=")
\ No newline at end of file
diff --git a/api/search.index/28462c866c.js b/api/search.index/28462c866c.js
new file mode 100644
index 000000000..778039e9c
--- /dev/null
+++ b/api/search.index/28462c866c.js
@@ -0,0 +1 @@
+rn_("JQHHAAAWCSJkoyHqISUBxQAAGEIhY+keziE1AcQAABbvIWTUINUgsCEricIAABzLYwADxAAAILVhdHXkrhMAAFwVAAA+HQAAyR4AAOceAAACEQChxgAAFB9VgsAAABUTH50ayRzKHA8fEB/7AmZ0G4rFAAAeTCHAAADnG0kgocQAAHofYwHACELDAAAhRuVMGwAAHx8AALgfAADoHwAAmyEAAOghAADQAAE1AcQAABbmIWRRIFIgnSEXGQL9J4kHwgAAHSDDAAAhGMQAAB7owQAAGpzIAAAhI8cAACHe56QQAAABEQAAexoAAI8bAABpHgAAWCAAACQhAADSIQAABBAAAGMAA8oAACG7Y2hp4iIMAAA2GgAAeBoAABAQ")
\ No newline at end of file
diff --git a/api/search.index/28babbc299.js b/api/search.index/28babbc299.js
deleted file mode 100644
index 41fb19408..000000000
--- a/api/search.index/28babbc299.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("RQHCAACglRxznQ7iHOMc5Bw1AsAAABWFGxWGG3J3aQygDqEOGwLgAAAO0G54BQLAAAAaTyAyjRCOEFwhY3L7A2Vpcw==")
\ No newline at end of file
diff --git a/api/search.index/293a7dd2bc.js b/api/search.index/293a7dd2bc.js
new file mode 100644
index 000000000..ca7ae2a29
--- /dev/null
+++ b/api/search.index/293a7dd2bc.js
@@ -0,0 +1 @@
+rn_("UcIAAIsbQxxEHKkfSyABAwHFAAAfZ3KJmhsAABsCzgAAIVxhchWQwwAAFEghNh3zBIjyiBoAACcBAQgBxQAAIOJyiWAeAAChyAAAJx/nAQDAhKTJAAAfyQHoGwAA+4Y=")
\ No newline at end of file
diff --git a/api/search.index/2a20280f65.js b/api/search.index/2a20280f65.js
new file mode 100644
index 000000000..13ad24834
--- /dev/null
+++ b/api/search.index/2a20280f65.js
@@ -0,0 +1 @@
+rn_("JQHFAAAYQiFj6R7OITUBxAAAFu8hZNQg1SCwISuJwgAAHMtjAAPEAAAgtWF0deSuEwAAXBUAAD4dAADJHgAA5x4AAAIRAKHGAAAUH1WCwAAAFRMfnRrJHMocDx8QH/sCZnQbisUAAB5MIcAAAOcbSSChxAAAeh9jAcAIQsMAACFG5UwbAAAfHwAAuB8AAOgfAACbIQAA6CEAANAAATUBxAAAFuYhZFEgUiCdIRcZA/0niQfCAAAdIMMAACEYxAAAHujBAAAanMgAACEjxwAAId7npBAAAAERAAB7GgAAjxsAAGkeAABYIAAAJCEAANIhAAAEEAAAKwLAAAAMc3Bz")
\ No newline at end of file
diff --git a/api/search.index/2a61a10e77.js b/api/search.index/2a61a10e77.js
new file mode 100644
index 000000000..1734c3494
--- /dev/null
+++ b/api/search.index/2a61a10e77.js
@@ -0,0 +1 @@
+rn_("BQPGAAASgB8ZcSEakCFhZXOlkMAAACK7E8cUaw0VAcQAABa4IGa2HBWQwwAAFNMgfhvzAojynBAAAC4E+wNob3I1AcEAABh7IGKoEDwdYh9FAsIAAGFMHE0cThxIHvseDB8lGx+7IGlzUx9UH3IgsyBBxAAAjRyOHEke/B4hwwAAUh+QITHEAADFHMYcpyAhxgAAACIGIvMCAWTlLh4AACQfAABiIQAAfiEAANMhAADhIQAAEQEA+wJkbjUBxQAAFlohYsMcxBx+H/uJlwEB/QQpBMAAABprwwAAIdTqiA8AAIEaAACxGgAAsRsAADkcAABEHQAAUR0AAC0eAAAIHwAAXh8AALEgAAAAEgAgAABhwwAAghaDFoQWhRasGq0aFQHKAACkmSFtfSElAcYAAKQ5IW37IJYhM4HACEjMAAAhc1OBlsEAACH0WwPAAAAPgWdubxUBwAAAEpUaeY8ODwjAgvbLAAAgs8EAABa [...]
\ No newline at end of file
diff --git a/api/search.index/2a6285686c.js b/api/search.index/2a6285686c.js
deleted file mode 100644
index 433a84fee..000000000
--- a/api/search.index/2a6285686c.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYnAAAAXjiERwCAFicQAABLXIRHRISOFAuAAACFXZGYFAsQAABbGIROqIW90GwLNAAAh6mhvNwGGwA5pwgAAIOnXAAAiDcMAACFAxAAAIVgFicAAABeNIRG/IAWJxAAAEtYhEdAhI4UC4AAAIVVkZgUCxAAAFsUhE6khb3QbAs0AACHpaG83AYbADmnCAAAg6NcAACIMwwAAIT/EAAAhVmMA/SWAAMUAABwryAAAH9QBhA8AAA==")
\ No newline at end of file
diff --git a/api/search.index/2a651b496d.js b/api/search.index/2a651b496d.js
deleted file mode 100644
index c80a6af81..000000000
--- a/api/search.index/2a651b496d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQPGAAAxuR/pH5whFs8hGN8haXN0ah6xyQAAySAhxAAAXRxiH6UBwQAApGMgbS4fEwQCwQAAH5ppcuTmHAAASx4AAIcfAAC+HwAAFiEAABEAAPMA/RQhAOTdGwAACRwAAOMeAABIHwAAVh8AAAEREA==")
\ No newline at end of file
diff --git a/api/search.index/2a682afd80.js b/api/search.index/2a682afd80.js
deleted file mode 100644
index f68adbe6b..000000000
--- a/api/search.index/2a682afd80.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYTAAAASmhyEEKUBxAAApr0gZr8cawPFAAAcqWVvcgUCwQAAEoIaHN0gZm4FAsQAABGnHBViH2lz+wJsbwUCxQAAEikeE/sea24bAsoAAB/IY3U3AgD9FQIG4QAAGn3CAAAgZsYAAByo6S4KAABmCgAAMQwAANAQAAD3EAAAcRoAALMaAABjHAAAsh8AAFsgAAAgECEAAA==")
\ No newline at end of file
diff --git a/api/search.index/2a85425f57.js b/api/search.index/2a85425f57.js
new file mode 100644
index 000000000..1be84c7d0
--- /dev/null
+++ b/api/search.index/2a85425f57.js
@@ -0,0 +1 @@
+rn_("AUHqmxAAAHgbAAB9GwAAOB4AAAIfAAAHHwAADR8AALMfAADLHwAANiEAAK4hAAAAABABAQBFAcIAABRhIXScE9gUJSEmIbHHAAA0H6UBwgAAF9EgbawboccAAKofocMAAHkb8wDAjAEBxBAAAPuO")
\ No newline at end of file
diff --git a/api/search.index/2aa0364307.js b/api/search.index/2aa0364307.js
new file mode 100644
index 000000000..f34fb242d
--- /dev/null
+++ b/api/search.index/2aa0364307.js
@@ -0,0 +1 @@
+rn_("BQLAAAAXdiEyMRwyHCEfb3kFAsAAACVBHn8gFE4gaXmhxAAAwRxXAQDABcHGAAAcKsQAAB1B58gQAACjEwAA4xQAAPUUAAC5GwAA3hwAAF0gAACyIQAAATEAAAFEOzAAAAEAAA8BAgCKFgEAJBkNAfuD")
\ No newline at end of file
diff --git a/api/search.index/2ab6c9c2ea.js b/api/search.index/2ab6c9c2ea.js
new file mode 100644
index 000000000..b2a5bc65b
--- /dev/null
+++ b/api/search.index/2ab6c9c2ea.js
@@ -0,0 +1 @@
+rn_("BQLAAAATVx8QSBxhcwUCwwAAp2Uhop4gZHNTAcAIBsQAAB/B0qQaAAC4BQLAAAATGR4QoxphcwUCwAAAFO4e4PYbaXMFAsMAAKcnIaK/H2Rz8wDACIbjsxMAAGMVAAD8IAAA3iEAABQA")
\ No newline at end of file
diff --git a/api/search.index/2af071a101.js b/api/search.index/2af071a101.js
new file mode 100644
index 000000000..cbc1cbb4e
--- /dev/null
+++ b/api/search.index/2af071a101.js
@@ -0,0 +1 @@
+rn_("AUHqmxAAAHgbAAB9GwAAOB4AAAIfAAAHHwAADR8AALMfAADLHwAANiEAAK4hAAAAABABAQBBwgAAnBPYFCUhJiGxxwAANB+lAcIAABfRIG2sG6HHAACqH6HDAAB5G/MAwIwBAcQQAAD7jg==")
\ No newline at end of file
diff --git a/api/search.index/2b952571dc.js b/api/search.index/2b952571dc.js
new file mode 100644
index 000000000..0a9ffd36c
--- /dev/null
+++ b/api/search.index/2b952571dc.js
@@ -0,0 +1 @@
+rn_("FQHGAAAWaiBmKBwJAtAAACFTzQAAIOVlbaUCxgAAFmkgGDshYncmHPMBwIJA4mIMAACUDgAABB4AABMAK8GAIMAAAB+wNPuAsAM=")
\ No newline at end of file
diff --git a/api/search.index/2b978fb783.js b/api/search.index/2b978fb783.js
new file mode 100644
index 000000000..a1eb10a5e
--- /dev/null
+++ b/api/search.index/2b978fb783.js
@@ -0,0 +1 @@
+rn_("BQLAAAAXdiEyMRwyHCEfb3khxgAAQR5/IPMCAmx04qMTAADjFAAAuRsAABMAIcYAAPghCyJTAQPAAAAgwWRladj9IAAAEYckDgEmBCHDAAClEEkcBQLAAAATVx8QSBxhcwUCwwAAp2Uhop4gZHNTAcAIBsQAAB/B0qQaAAC4BQLAAAATGR4QoxphcwUCwAAAFO4e4PYbaXMFAsMAAKcnIaK/H2Rz8wTACIbjsxMAAGMVAAD8IAAA3iEAABQAFQHAAAAWBCJk3SErAsMAABtbaXMFAsMAAKdbIKKWHGhzVwMA/aBQgsQAABw1wwAAIarp8wQAADMJAAD7DgAAhg8AAJIQAAD1GwAADxwAACocAAAnIQAAZSEAAAAhAHARdf3BIBAZAACmbR4byyAc8SAUYhwc8iDpDuoO6w7sDjcPOA85D3v9EYEAwAAAE40=")
\ No newline at end of file
diff --git a/api/search.index/2c0bf1b379.js b/api/search.index/2c0bf1b379.js
new file mode 100644
index 000000000..ed2accb82
--- /dev/null
+++ b/api/search.index/2c0bf1b379.js
@@ -0,0 +1 @@
+rn_("FYTDAAATuiAJH/MEAXTSKRwAANoxwgAAxhtHHU4eFQHRAAAWDiJk9iEhwgAAYSCgIfsCYXIlAcAAABDPIHOOGsUbAQUBxAAAIUpy4T4eAAA+HwAABvOBAmNnIcEAAIkcqB8lhMIAABHSIDkfrB/7AmVsGwLHAAAhhWlyNQHNAAAWBiJkfiF/IeEhBQLDAAATICGg1h5uc/OBAmxtBQLEAABB2h90INogCCEVQyFlcvcLAMIL6cYAACE10wAAIew7MAAAAQAANAAYAN8QDwBvGwEAdRsBAIwbAACuGwAAuhsHAEUcAQBWHAAAehwBAKEcAAAnHQAAOx0AAD0eAABFHwEA2B8AAO0fAACIIAAA0SAAANcgAQD2IAAAEiEAABohAADZIQEA7CEAAA==")
\ No newline at end of file
diff --git a/api/search.index/2c4582ea19.js b/api/search.index/2c4582ea19.js
deleted file mode 100644
index a581eb0d4..000000000
--- a/api/search.index/2c4582ea19.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McMAAB8f6h+LIAUCwwAAGtghHfMhZXQjBALFAAAg62JwAUEdAAAVAsMAABnlIKVwH2RzdxsjAALFAAAeUmJ0AbITAAD7Am50W4vEAAAhbQ==")
\ No newline at end of file
diff --git a/api/search.index/2c73c8a66c.js b/api/search.index/2c73c8a66c.js
deleted file mode 100644
index 194501741..000000000
--- a/api/search.index/2c73c8a66c.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ZQHBAAAl5h55IWznDugODxzGHMccqCAVAcAAACIwHEQdcoIPVQPBAAC14hy6ySBDmBuZGzQd0R9vc3QyDzMPNA81D9AebwHEEGTKAAAhYsEAACFi")
\ No newline at end of file
diff --git a/api/search.index/2ca8bd9bde.js b/api/search.index/2ca8bd9bde.js
new file mode 100644
index 000000000..4c5f0c4da
--- /dev/null
+++ b/api/search.index/2ca8bd9bde.js
@@ -0,0 +1 @@
+rn_("BQLAAAAsqyHwIciQH29yFQHCAAAWDiJk9iHzAAFtAXwTAAAFisAAAKHQHBitIQFB5XUaAABKHAAAHh4AACceAACaHwAABiEAABEAABUBygAAFgMiZNghxwYB/YMJA8QAACF0wgAAHKDBAAAczzowAAABAAAAAAAgABAAAACnGqkaChwLHCMcNxyqHKsc9Rz2HPcc+Bz5HPoc+xzqHRofYB+5H74fWSB3IHggeSB6IMIgwyDZIAshDCENIRYhuyEVAcIAABL5IW3kISOHAscAACH/YWsjCwLJAAAh7WFjAQUhAAA7/QhAhMEAAB7rxwAAIV9TAAPBAAAbHWltdOJvDwAAHhsAAMUfAAAQAA==")
\ No newline at end of file
diff --git a/api/search.index/2cae63e23b.js b/api/search.index/2cae63e23b.js
deleted file mode 100644
index cb870f29b..000000000
--- a/api/search.index/2cae63e23b.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHHAACotCF3VyAxwAAAnxagFnEbpYLEAAAUHiGDHwUCxgAAF70hFZUhZnT7AmFmIcIAAI0c7x3zAf0JAAU7MAAAAQAAeAEGAKsTAgD3FGMAhBoBALQaWwBwHlkA7x9ZAA==")
\ No newline at end of file
diff --git a/api/search.index/2cc94d27c2.js b/api/search.index/2cc94d27c2.js
deleted file mode 100644
index 71604d3e2..000000000
--- a/api/search.index/2cc94d27c2.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcEAAJoQxRAxwQAA6xQVHxYfAQEBxAAAHDZo4/sOAACGDwAA9hsAABAcAAAhB8UCwwAAJ5EgbCEQHhtmczgaQcAAAMATYhWnHKkcJQHAAAATZiBqsxpbIKWCwwAAIVEhbiF7IWMBA8EAAB+waWxz+YcWAAABAI8CBgMHAusABAAFAKMA3wf9LVAEwgAAG5E=")
\ No newline at end of file
diff --git a/api/search.index/2cf8bcdf4a.js b/api/search.index/2cf8bcdf4a.js
deleted file mode 100644
index a1af455f6..000000000
--- a/api/search.index/2cf8bcdf4a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUU7MAAAAQAADwECAIoWAQAkGQ0BpQHDAAAw3RtWH1cfc1AexQHAAAAU8iBi+hDzgQJkbfsCcnYBAQHCAAAdOGL5+g4AAIsABgvcBAEAFQDyAHQA5AABBwHDAAAh3GbnDh4AAFQgAACHIAAAjiAAAJIgAACXIAAAdCEAAAwiAABgAAABGwLFAAAfsGN0O8AAxGI83o4KQcEAALUQyhvUIEkhscIAAKMbpQHFAAAVbyFj+CAVAckAABa2IWI5IVOFwghA4AAAHTbzggJkafOBAml0+4c=")
\ No newline at end of file
diff --git a/api/search.index/2d00f3bc93.js b/api/search.index/2d00f3bc93.js
new file mode 100644
index 000000000..f48f82da1
--- /dev/null
+++ b/api/search.index/2d00f3bc93.js
@@ -0,0 +1 @@
+rn_("FQHFAAAWaiBmKBwVAcIAABYDImTYIfsCaXQJAtAAACFTzQAAIOVlbaUCxgAAFmkgGDshYncmHHMAwILAwwAAG3vuYgwAAJQOAADzDgAAaA8AAHEPAADNHAAABB4AADkeAABqIAAAqCAAALggAAC8IAAA5SAAACwhAACvIQAAEwAxAQgBCAA=")
\ No newline at end of file
diff --git a/api/search.index/2d408ba00a.js b/api/search.index/2d408ba00a.js
new file mode 100644
index 000000000..3dee3c29c
--- /dev/null
+++ b/api/search.index/2d408ba00a.js
@@ -0,0 +1 @@
+rn_("JQLDAAAXWyEVGyFiZnIfyyEVAcYAABVMIXJYH0HHAAAYH98g4CBcIfMDAmZs47UTAACLFQAAlR8AAOofAAAGADWBxQAAFd0gpRpdG14b+wNhZnA=")
\ No newline at end of file
diff --git a/api/search.index/2d7384baea.js b/api/search.index/2d7384baea.js
deleted file mode 100644
index adb8da6f6..000000000
--- a/api/search.index/2d7384baea.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUE7MAAAAQAA6QABAK8W6QBBwgAAUB1RHYAfzh8VAdAAABbvIWSxIRUB0gAAFg4iZPYhFQHPAAAWBiJk4iHzBgJjcOS6GwAA2R8AANIgAAD3IAAA2iEAAIAAEKUBwAAAEPkhNWEcFQHMAAAW5yFkniEVAccAABa4IWQYIfsCcnMxzQAAzx/QH1Qha8QCBMEAACD7+/0ZQQg=")
\ No newline at end of file
diff --git a/api/search.index/2da48fd41e.js b/api/search.index/2da48fd41e.js
deleted file mode 100644
index 8cc41f83a..000000000
--- a/api/search.index/2da48fd41e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHIAAAWCyJkliHyISsCxgAAHeZlbRvAACrFAAAfb8kAAB80QcMAABseHB4nH90gBYzAAAASGiEZ0yETBwLCAAAhZGZp5JsgAADtIAAATCEAAFkhAACUIQAAAQEA+wJhciUCwgAAF1whFRwhYmZzH8whMcUAAKIhviG/ITWEwAAAE5ogcCBxIAQhMcIAAEAeQR4dIUHBAABKH0sfTB9eIQUCwAAAJW0gkyESmSB1efcAAf0CAQfiAAAPdugxHAAABx0AAPAeAACJHwAAdiAAAPQgAAB2IQAAhSEAALchAAAEAAAAAPsDZWxvFYjEAAAUKx0nGzUBywAAFu8hZNUg1iCxISsC4AAAG5ducBuRwQAAHF4VAcIAABYOImT2IcUBwQAAoJUbc4MgVQLDAACkwhwVQh1ic/UU9hTfHF4gsyH7AnR6FQHGAAAVTSFyWR9BxwAAGR/gIOEgXSHzAwJmbOO1EwAAixUAAJYfAAD [...]
\ No newline at end of file
diff --git a/api/search.index/2e31da7e8a.js b/api/search.index/2e31da7e8a.js
new file mode 100644
index 000000000..e70232285
--- /dev/null
+++ b/api/search.index/2e31da7e8a.js
@@ -0,0 +1 @@
+rn_("FQHHAAAUDiFspSEbAsIAABwOY3QrAsoAACGkbW6xxAAAYhsFwMAAyAAAFaIcGl0gFiIe2/2BSAHLAAAgoscAAB4j")
\ No newline at end of file
diff --git a/api/search.index/2e4127d8c1.js b/api/search.index/2e4127d8c1.js
new file mode 100644
index 000000000..900dda349
--- /dev/null
+++ b/api/search.index/2e4127d8c1.js
@@ -0,0 +1 @@
+rn_("BYnAAAATGyERjxAhwgAARxwKHxWBwAAAGL4f3xQbAsEAAB7obXL7AnJ1IcQAAM4eBR8lAcQAABYKImSmIesh8wIBYgGAIQAAGwLDAAAe/Wl0wcMAACkfJQHFAAAW5SFknCHfIdMBwAhMywAAITb6lBMAAAEAAAMBAOkEBgETANUCXwCUAKUBwQAAEE0fc9AeEwICwgAAHThpbuSvEwAAchwAACYeAACQHwAA5B8AAAADMPsDZWx4AUXiOR4AAOUgAAAsIQAAEIDvAQXEAAATtzhhaW9y")
\ No newline at end of file
diff --git a/api/search.index/2ea74e027f.js b/api/search.index/2ea74e027f.js
new file mode 100644
index 000000000..ce52c1f84
--- /dev/null
+++ b/api/search.index/2ea74e027f.js
@@ -0,0 +1 @@
+rn_("AUPh6hsAANkeAACIGwLGAAAhcWl0McMAAJcWmBYZHzUBwAAAFu8hZNQg1SCwIQUCwAAAGcsfJAAfNx9lcDHCAADUH9Uf1iAVAcIAABL5IW3kISOHAscAACH/YWtjAgPJAAAh7WFjawEFIQAAI4SGxQAAIJQzAMAGgMMAAB3lASAfAAAhyQAAiCAaIdcDAMQCLcQAAB87AaIhAAA=")
\ No newline at end of file
diff --git a/api/search.index/2eb1c7c7a9.js b/api/search.index/2eb1c7c7a9.js
new file mode 100644
index 000000000..afb44df1f
--- /dev/null
+++ b/api/search.index/2eb1c7c7a9.js
@@ -0,0 +1 @@
+rn_("BYnAAAAXjCERviAFicQAABLVIRHPISOFAuAAACFUZGYFAsQAABbEIROoIW90GwLNAAAh6GhvNwGDwA5pwgAAIOfXAAAiDMMAACE+xAAAIVU=")
\ No newline at end of file
diff --git a/api/search.index/2fb0ee98de.js b/api/search.index/2fb0ee98de.js
deleted file mode 100644
index e6d28a28b..000000000
--- a/api/search.index/2fb0ee98de.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUWIEBwAAKHPAACHIaHUAADKIfOBAmdzJQLLAAAXXCEVHCFiZnMfzCEFAsAAABCjIRYsHWV0BQLDAAAcbSEfpiFjZvuf")
\ No newline at end of file
diff --git a/api/search.index/303d69d850.js b/api/search.index/303d69d850.js
deleted file mode 100644
index 81f0a5d1c..000000000
--- a/api/search.index/303d69d850.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McsAADMdXx5gHkWEwAAAo5UbixyMHNce2B4VAcMAABCUG3MhIaHBAAD9HPMBA2luc/WBEwAAKgO5BaoAtAQhwAAApSHAIQWJwAAApT0fEv8eFQHEAAATaSBuYRsFAsAAABU8HyYBHzgfbG4FAsAAABPCIWMJHAoc4x7kHkgfSR9sdQUDwwAAGJkhErcgGIkhY3V3IwQCxQAAH3JicAGHGgAAMccAAD0hgiGDIfsCbHT7ifMA/TSAAuVWCgAAMwwAAOobAABKHQAAVh4AAI8gAAAABVB7/RAQBsIAABxj")
\ No newline at end of file
diff --git a/api/search.index/30e7afee14.js b/api/search.index/30e7afee14.js
deleted file mode 100644
index d9504b776..000000000
--- a/api/search.index/30e7afee14.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcMAAKIWWhssHAgeJQHFAAAYQyFj6h7PIRUBwwAAGmkhdw4cJQHPAAAWEiJk9SEPIiUBxwAAGK8hZ60h8SHzgwJscDUBwwAAFu8hZNUg1iCxIfsCa3IFlMAAAEU/HEAcHx0gHRG5HCHGAAAsHAgeIcIAALsczBz7wAGge/0BQEHBAAAhXxUBwQAApGsfbe4d8wKEgsgcAAClAcEAAKQQIW3NIPMHhPWcHwAAOwABADABgwChwgAAyhxVAcEAABRHIWa5H+kfnCHpIeohUwb9AIEHyAAAISTFAAAhz8cAACHfAWoeAAChzAAAJiEFAsAAALXJIBYDH250JQHEAAAW+yFkIiHDIfOCAmJpFQHGAAAWWyFifx/zBAFjg7EbAAAhywAAkiCXICHDAABdHGIf+8ACUDUBwQAApGMgbQAfLh8vHxMEA8EAAB+ayQAAIWhpcnflDRwAAOYcAABLHgAAhx8AAL4fAAAWIQAAARA [...]
\ No newline at end of file
diff --git a/api/search.index/310108bde9.js b/api/search.index/310108bde9.js
new file mode 100644
index 000000000..27ae20751
--- /dev/null
+++ b/api/search.index/310108bde9.js
@@ -0,0 +1 @@
+rn_("FQHSAAAWCiJk6yEVAdQAABYLImTyIRUBzwAAFhIiZA8iI4wCxgAAIfFscIcDg/0o0ATKAAAhn9MAACHwygAAIaAFAsIAABPkHBrYIGRuRQHEAACm/SFkRCFFIcwhzSH7A2Fpcg==")
\ No newline at end of file
diff --git a/api/search.index/311276ea81.js b/api/search.index/311276ea81.js
deleted file mode 100644
index ad736b852..000000000
--- a/api/search.index/311276ea81.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHCAAAQxRNzkRDEEwEGAsQAACF1yAAAIa5hcuYkHAAA9hwAABsfAAC/HwAAeCAAAAwhAAAXIQAABgAyAFUBwAAAE6MWY8YOxw7IDrkc/h4BAAHQAAAho3TSNwoAAOxbwABiywAAH28VgcUAABz0IfEgAUDsmxAAAHgbAAB9GwAAOR4AAAMfAAAIHwAADh8AALQfAADMHwAANyEAAD0hAACCIQAAryEAAAAAEAEBAQBrA8kAACEFYXJzMcAAAAweDR7cH1HIAAAIH7QftR84Ia8hocQAAEYdZwEB/VEAB8QAACB3xAAAIUvDAAAhYjswAAABAAAzABYA0hALAJwTAADYFAAAmBoDABAbAACLGwAA5RsCAEQcAQAdHgEAPx4AADUfAgA/HwYAhh8AAKofAADEHwEATCAAAGAgAADGIAAAJiEBAKAhAACsIQEA8CEBAAUCwAAAEtUeFNQeZGcVAcAAABSeGnQlGxUCwQA [...]
\ No newline at end of file
diff --git a/api/search.index/311a124897.js b/api/search.index/311a124897.js
new file mode 100644
index 000000000..05bcd36b5
--- /dev/null
+++ b/api/search.index/311a124897.js
@@ -0,0 +1 @@
+rn_("ockAAMIgFYTFAAARBiFZIPuGMcUAAEoeSx69H/OFAnN2BQLAAAAV4SAX0B9mdCUBxAAAFgAiZGIh0yEThgLDAAAh1GNsKwLHAAAheWFyKwLFAAAeFG1wFYTDAACh/BwNHXv9ADgIwQAAIRgxxAAAzh/PH1MhBQLAAACiIB4U3iBpdAUCwAAAP6EhvSG+ITdtIAEhAiFhckHDAACzHCQeVCBVIBUBwQAAFpchdIEgpwMA/TSQAskAACGlwwAAGzPnuBMAAJIaAABqHwAAeh8AAGIgAAAPIQAAOSEAAJkhAAAQERERFQHIAAAW9yFkuCEVAcoAABYIImTjIRUBygAAFgciZOIh+4UVAcYAABbnIWSeIfOBA2VtbgGC/QkAGMYAACGO1AAAIgHBAAAgwMcAACGPKwLBAAAhUW9yIccAAFIhYCFjBAPFAAAffWJlcOGTGgAA6x0AAAEVAcYAACDRHxMhcncf8wIBcOSRGgA [...]
\ No newline at end of file
diff --git a/api/search.index/31567e86e8.js b/api/search.index/31567e86e8.js
deleted file mode 100644
index c5e4f6b07..000000000
--- a/api/search.index/31567e86e8.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("YcAAAAkcChzjHuQeSB9JHyHDAACNG/seIcIAAKgaKR7zAsCAROjIFAAAzxsAAFQeAAAfHwAAnx8AAOofAABJIAAAiyAAABkhAAAEEAAAAA==")
\ No newline at end of file
diff --git a/api/search.index/31f2ae3adb.js b/api/search.index/31f2ae3adb.js
new file mode 100644
index 000000000..b47e2d65a
--- /dev/null
+++ b/api/search.index/31f2ae3adb.js
@@ -0,0 +1 @@
+rn_("JQHEAAAWCyJklSHyISMAAscAACFCY2zkAA8AAI4PAAB0GwAA6R4AAM4hAAACAABRwQAApxOoE2kamR+DIVsD4AAACk9la3k=")
\ No newline at end of file
diff --git a/api/search.index/32d0ecc4d9.js b/api/search.index/32d0ecc4d9.js
deleted file mode 100644
index 5956090d0..000000000
--- a/api/search.index/32d0ecc4d9.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAXdyEyMhwzHCIfb3kFAsAAACVCHoAgFE8gaXmhxAAAwhxXAQDABcHGAAAcK8QAAB1C58gQAACjEwAA4xQAAPUUAAC5GwAA3xwAAF4gAACzIQAAATEAAAFEOzAAAAEAAA8BAgCKFgEAJBkNAfuD")
\ No newline at end of file
diff --git a/api/search.index/32f2c8af3a.js b/api/search.index/32f2c8af3a.js
new file mode 100644
index 000000000..1a67e4838
--- /dev/null
+++ b/api/search.index/32f2c8af3a.js
@@ -0,0 +1 @@
+rn_("BQPGAAARmyEWziEY3iFpc3QjhgLDAAAhFWNuFQHPAAAWBCJk3SEVAckAABbcIWSJIRUBzAAAFv4hZM0hFQHMAAAW/SFkzCH7hfOEwACG+5g=")
\ No newline at end of file
diff --git a/api/search.index/33214e402a.js b/api/search.index/33214e402a.js
new file mode 100644
index 000000000..699185bd3
--- /dev/null
+++ b/api/search.index/33214e402a.js
@@ -0,0 +1 @@
+rn_("JQHIAAAWCyJklSHyISsCxgAAHeVlbRvAACrFAAAfbskAAB8zQcMAABoeGx4mH9wgBYzAAAASGSEZ0iETBwLCAAAhY2Zp5JogAADsIAAASyEAAFghAACTIQAAAQEA+wJhciUCwgAAF1shFRshYmZyH8shMcUAAKEhvSG+ITWEwAAAE5kgbyBwIAMhMcIAAD8eQB4cIUHBAABJH0ofSx9dIQUCwAAAJWwgkiESmCB1efcAAf0CAQfiAAAPdugwHAAABh0AAO8eAACIHwAAdSAAAPMgAAB1IQAAhCEAALYhAAAEAAAAAPsDZWxvFYjEAAAUKh0nGzUBywAAFu8hZNQg1SCwISsC4AAAG5ducBuRwQAAHF0VAcIAABYOImT2IcUBwQAAoJUbc4IgVQLDAACkwRwVQR1ic/UU9hTeHF0gsiH7AnR6FQHGAAAVTCFyWB9BxwAAGB/fIOAgXCHzAwJmbOO1EwAAixUAAJUfAAD [...]
\ No newline at end of file
diff --git a/api/search.index/3355845a3d.js b/api/search.index/3355845a3d.js
deleted file mode 100644
index 00bf67b10..000000000
--- a/api/search.index/3355845a3d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHGAAAW3SFkmR+KIQECAcMAACHcZucOHgAAVCAAAIcgAACOIAAAkiAAAJcgAAB0IQAADCIAAGAAAAGTAP0SAQHCAAAcIcYAAB45hOcdAAA=")
\ No newline at end of file
diff --git a/api/search.index/3370418625.js b/api/search.index/3370418625.js
new file mode 100644
index 000000000..8bae049a8
--- /dev/null
+++ b/api/search.index/3370418625.js
@@ -0,0 +1 @@
+rn_("BQLAAAAXdiEyMRwyHCEfb3khxgAAQR5/IKHEAADBHLMBwAHBxAAAHUHmoxMAAOMUAAD1FAAAuRsAAN4cAABdIAAAsiEAABMQAAAFicUAADg8IYEhgiEUwSEFAsAAABRMH2ILHQwd9CAJIQohsSFveSUBygAAFgsiZJUh8iEFjMAAABIZIRnSIRMIAsIAACFjZmnkmiAAAOwgAABLIQAAWCEAAJMhAAABAQAxxQAAoSG9Ib4hNYTAAAATmSBvIHAgAyExwgAAPx5AHhwhQcEAAEkfSh9LH10hBQLAAAAlbCCSIRKYIHV58wH9AgED6DAcAAAGHQAA7x4AAIgfAAB1IAAA8yAAAHUhAACEIQAAtiEAAAQAAAAA+wJlbPMAA3B0dQFWGgAAxQHBAAAVeB93yhslAcAAAKSZIW06H30h+wJkblUBwwAAEH4gc8AcCB7cH90fxiArhcMAAB95McUAANkfoCChICUBxAAAFhI [...]
\ No newline at end of file
diff --git a/api/search.index/338cc3b0ba.js b/api/search.index/338cc3b0ba.js
deleted file mode 100644
index 574bb88ec..000000000
--- a/api/search.index/338cc3b0ba.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAACkax9t7h3zAoSCyBwAAKUBwQAApBAhbc0g8weE9ZwfAAA7AAEAMAGDAGsDxQAAHwBjb3BFhMMAABFeIfQgdiGFIbchE4gCwgAAIPVzdEHAAAC1EMob1CBJIQUCwwAAJoggqCGkMB9tcwWFwAAAGuQgF2kfBQLAAAAVMR4W/x5jbCUBxQAAFuYhZJ0h4CETg8AIRMsAACE3wgAAIYEVhsAAAKZqIanKIWcbGwLHAAAfBnJzocYAAOwdAQD99PhHf3xKCUlIP27wJjm22tKKNCKWu+rFAAAeMs8AACE4Vuk5+r5oaGi98Gu86HyfXa2AzMPNAAAhUhfGtLmVwgAAG0jCAAATujswAAABAABVABsAagwEAO0OAAA7DyYAnRYBALAbAAAcHAAAphwAAN4cAAA6HQAA9R0AAMcfAAClIAAAsyAAAEQhAABLIQAATSEAAIwhAAC4IQAA3SEAAOYhAgDvIQAA9yEBAPs [...]
\ No newline at end of file
diff --git a/api/search.index/33df460cb3.js b/api/search.index/33df460cb3.js
deleted file mode 100644
index e5bc14273..000000000
--- a/api/search.index/33df460cb3.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYTGAAARKB66HwUDwAAAHNwgE3oaJ5Yf6x9hb3IBTImpIAAABQLAAADDGBwSBR1lbAUCwAAAFiceE2gbcnWhxgAALR2vA/4EBTACzwAAIW7LAAAgqAFFiBAcAAChzwAAhyGh1AAAyiHzgQJncwUCwAAAEKMhFiwdZXQFAsMAABxtIR+mIWNm+5ulAsEAABUmHqB4GmVzfBYFjMEAABTzIBzAIfuKpQHCAAAWQiF2aCETggLhAAAhtG5z+wJhcgUCwAAApaQcHLIgcnUFAsEAABjZIBhhH3d4FQHFAAAXNiFz2CArAsIAAB4FbXQxxgAAJR5VIFYgocoAAKYgAYUDwwAAIF/TAAAh7scAACFPY2Vs+8AAxPMAgwH/IQAAAU+JLSEAAAkCzwAAIWzLAAAgpWRuBQLAAAAW+h4SZxtldKHDAABlG/sCZWwbAuAAABs0aXMFAsMAABbGHxosIWhvBQLHAAATpCAWKyFrbRs [...]
\ No newline at end of file
diff --git a/api/search.index/33f8f3ae64.js b/api/search.index/33f8f3ae64.js
new file mode 100644
index 000000000..fa9d67995
--- /dev/null
+++ b/api/search.index/33f8f3ae64.js
@@ -0,0 +1 @@
+rn_("BQLAAAAXHiEipBYoHW95ocYAACUdAUThkB8AAOQfAAAzcwHDCIjDAAAb6ckAACFo5HgMAADNDgAAuxMAAMcUAAANHAAAIgAA")
\ No newline at end of file
diff --git a/api/search.index/33fa7fd9d1.js b/api/search.index/33fa7fd9d1.js
new file mode 100644
index 000000000..8a21d2c55
--- /dev/null
+++ b/api/search.index/33fa7fd9d1.js
@@ -0,0 +1 @@
+rn_("IcEAAJoQxRAxwQAA6xQUHxUfAQEBxAAAHDVo4/sOAACGDwAA9RsAAA8cAAAhB8UCwwAAJ5AgayEQHhtmczgaQcAAAMATYhWmHKgcJQHAAAATZSBqsxpaIKWCwwAAIVAhbSF6IWMBA8EAAB+vaWxz+YcWAAABAI8CBQMHAusABAAFAKMA3wf9LVAEwgAAG5E=")
\ No newline at end of file
diff --git a/api/search.index/342286ed31.js b/api/search.index/342286ed31.js
new file mode 100644
index 000000000..582240097
--- /dev/null
+++ b/api/search.index/342286ed31.js
@@ -0,0 +1 @@
+rn_("AQAB4QAAFLlz6PEOAAC6EAAAVxwAAF4cAACWHAAAnhwAAG0eAAC/HwAAniAAAAgREREQKwLMAAAfcmhyocQAAFsgIccAADQezR5RxgAAtyHmIf0h/iEEIgFG4jkeAADlIAAALCEAABCA8wQBZuFDGgAAJx8AAAEFA8MAAB7LIRJmIBhvIXR1dyMFAsUAAB8GYnABjxYAAFsDwgAAIYVhaGx3CgD9HJwEwwAAIe3HAAAfGcIAAB4x7XkEAAD2GwAAAB0AAPUdAABMIAAAUSAAAIsgAAAXIQAAKyEAAEQhAACdIQAAqiEAAMwhAADdIQAAFSABAAEAEA==")
\ No newline at end of file
diff --git a/api/search.index/343533833c.js b/api/search.index/343533833c.js
new file mode 100644
index 000000000..b20ca6d00
--- /dev/null
+++ b/api/search.index/343533833c.js
@@ -0,0 +1 @@
+rn_("YcMAAIIWgxaEFoUWrBqtGgUCwAAAEfQhGxIfZG4VAcoAAKSZIW19ISUBxgAApDkhbfsgliEzgcAISMwAACFz+5Y=")
\ No newline at end of file
diff --git a/api/search.index/3471b6b5a0.js b/api/search.index/3471b6b5a0.js
deleted file mode 100644
index 1e6a7e1d9..000000000
--- a/api/search.index/3471b6b5a0.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAXzh4TMh5lcBUBxQAAFzYhc9ggKwLCAAAeBW10McYAACUeVSBWIKHKAACmIAGEA8MAACBf0wAAIe7HAAAhT2NlbEHDAACAGjsdXR9eH/uF+8AAxPMAA2FlcwH/IQAA")
\ No newline at end of file
diff --git a/api/search.index/34a265a389.js b/api/search.index/34a265a389.js
deleted file mode 100644
index 5623df97c..000000000
--- a/api/search.index/34a265a389.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcgAAO4fEyEhwwAA/xCKGhUBzQAAFg4iZPYhWwPMAAAhX29yczUBwAAAFvchZOEcuSHVIRsCwwAAINpscvsDZWlt")
\ No newline at end of file
diff --git a/api/search.index/34a4a8d231.js b/api/search.index/34a4a8d231.js
deleted file mode 100644
index 4a3291194..000000000
--- a/api/search.index/34a4a8d231.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQLDAAAXXCEVHCFiZnMfzCEVAcYAABVNIXJZH0HHAAAZH+Ag4SBdIfMDAmZs47UTAACLFQAAlh8AAOsfAAAGADWBxQAAFd4gpRpdG14b+wNhZnA=")
\ No newline at end of file
diff --git a/api/search.index/34bfdc58b1.js b/api/search.index/34bfdc58b1.js
deleted file mode 100644
index 3f7857914..000000000
--- a/api/search.index/34bfdc58b1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHPAAAWEiJk9SEPIiUBxwAAGK8hZ60h8SHzhgJscDHBAABuIAIhAyEhwQAAWBq1HAGBAswAACGE0gAAIcJhcBUBxgAAINIfFCFyeB/zAwFwAZEaAAAbicMAAB0OtwMA/TRBAsYAAB9O9IMPAACFDB0BEwE=")
\ No newline at end of file
diff --git a/api/search.index/34c2639591.js b/api/search.index/34c2639591.js
deleted file mode 100644
index 40f51d2f8..000000000
--- a/api/search.index/34c2639591.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHFAAAWayBmKRwVAcIAABYDImTZIfsCaXQJAtAAACFUzQAAIOZlbaUCxgAAFmogGDwhYncnHHMAwILAwwAAG3vuYgwAAJQOAADzDgAAaA8AAHEPAADOHAAABR4AADoeAABrIAAAqSAAALkgAAC9IAAA5iAAAC0hAACwIQAAEwAxAQgBCAA=")
\ No newline at end of file
diff --git a/api/search.index/34ddad05fc.js b/api/search.index/34ddad05fc.js
new file mode 100644
index 000000000..31a724b7b
--- /dev/null
+++ b/api/search.index/34ddad05fc.js
@@ -0,0 +1 @@
+rn_("FQHSAAAWCiJk6yEVAdQAABYLImTyIRUBzwAAFhIiZA8iI4wCxgAAIfFscIcDhP0o0ATKAAAhn9MAACHwygAAIaA=")
\ No newline at end of file
diff --git a/api/search.index/34e2d95be5.js b/api/search.index/34e2d95be5.js
new file mode 100644
index 000000000..2d42a7cfb
--- /dev/null
+++ b/api/search.index/34e2d95be5.js
@@ -0,0 +1 @@
+rn_("McUAAHMbdBx1HCUBxgAAFhAiZMAh+iHzgQJldyHAAAAZHlcfJZDCAAAk0yBIIX4bNh1BxQAATx1QHX8fzR/7/QAgCw==")
\ No newline at end of file
diff --git a/api/search.index/34fb80b003.js b/api/search.index/34fb80b003.js
new file mode 100644
index 000000000..afcead07e
--- /dev/null
+++ b/api/search.index/34fb80b003.js
@@ -0,0 +1 @@
+rn_("QcgAAEYeRx5QH1EfBQLGAACiDx8wPh0/HececnMxxQAAMxw0HBkd+8AChGHIAABCHkMeRB5FHk4fTx8FAsgAADNvIHAgAyE4WCFZIZMhcHT7AmFyMcwAANQf1R/WIKcCAP04gAPgAAAPhMIAABtHwQAAGmcBrg4AALHCAAD3EPuD")
\ No newline at end of file
diff --git a/api/search.index/35355c172d.js b/api/search.index/35355c172d.js
new file mode 100644
index 000000000..9461f0f3c
--- /dev/null
+++ b/api/search.index/35355c172d.js
@@ -0,0 +1 @@
+rn_("RQHAAAAziRsiHZEhdMMbxBsFHAYcIcIAAF8f1yHzA5DslBAAAK8QAACJGgAAlBoAAIIbAAAzHgAAzB4AAAAfAAA3HwAAbB8AAK0fAABSIQAAYCEAAAUAARAAAAAVAsMAABaSIRIcIWJydSAjhwLDAAAgxmZzOwPGAAAcrWFvciHBAACTFjUcBQLAAAAhhhOJFhl5H250FQHEAAAQiR9zHR9BwAAASgobDBwM1B6hxQAA/yAVAcAAABT+IGM9HRUByQAAFrohYj0h84PCCECrxAQhxwAAH8vCAAATqiUBygAAFgUiZHwh4CGlAcYAAKa8IGa+HBUBzwAAFq8hZhQh8wACcnMBHyEAAKvAAqHDAAAeNcsAAB/Y9wsA/TGJB8cAAByuwgAAE4o7MAAAAQAABwETAI0BAgCwAeoA3AQAAPAEAAD8BAcA9AgAADEKAQBIDAAAfQwAAI4TAACXEwAAEhsAADIbAABgGwAAtxs [...]
\ No newline at end of file
diff --git a/api/search.index/35aa79b3f7.js b/api/search.index/35aa79b3f7.js
new file mode 100644
index 000000000..ca38e5d08
--- /dev/null
+++ b/api/search.index/35aa79b3f7.js
@@ -0,0 +1 @@
+rn_("McAAAAYFBwU3HSHGAAAAIgYi8wABZOUuHgAAJB8AAGIhAAB+IQAA0yEAAOEhAAARAQATAALgAAAWjGNs+AsFAABfCQsALggQBnEBMAIBAPMAAmV54WQMAACYDgAAAQ==")
\ No newline at end of file
diff --git a/api/search.index/35e9a7b7f8.js b/api/search.index/35e9a7b7f8.js
new file mode 100644
index 000000000..e05f89a8f
--- /dev/null
+++ b/api/search.index/35e9a7b7f8.js
@@ -0,0 +1 @@
+rn_("JYTCAAATuiC2FAkfRQHFAAAVbiFj9yD4IP8gACFlAsAAABT+IORqHGN07w5iDzUdPR1bHlwe4cUAAGQcJQHFAAAmtSG6IWI4IT0hpQHBAAAUziBmzyGlAcIAABT1IGbVIfuJMcUAADIenB+dH/MDwgAJ80gdAACeAf4BFQHCAAAU6R9jOB8jgQLBAAAccGVsIwADzgAAId/HAAAfnmVmcvPuDgAAZhICAOcDAMIOSMQAABxj4VQMAABrDgAAB5v9EEFAyQAAH2nDAAAhlA==")
\ No newline at end of file
diff --git a/api/search.index/35fbc95c02.js b/api/search.index/35fbc95c02.js
deleted file mode 100644
index 9432c001f..000000000
--- a/api/search.index/35fbc95c02.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLBAAASghoc3SBmbgUCxAAAEaccFWIfaXP7AmxvBQLFAAASKR4T+x5rbhsCygAAH8hjdTMA/QUABsYAAByoxgAAHKnhLgoAAGYKAAAgIcAAAJMWNhxrA9YAACINYWVz")
\ No newline at end of file
diff --git a/api/search.index/364513e953.js b/api/search.index/364513e953.js
deleted file mode 100644
index d00c5308c..000000000
--- a/api/search.index/364513e953.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQQBxgAAH3RyiSkbAAAbAsEAABCdYXkBQOR2DgAA6xsAANoeAACCHwAA5yAAAIiAACHFAAB2H5YgFQHDAAAWAyJk2SETAgLDAAAbe3N04fMOAABxDwAAAwGIAsYAACC46AAAHfdyc6HKAADaIRUBwAAAFIsgY68f8wMBcwEdHwAAEwECxwAAIElmcgGVEAAAocMAABceIcMAABYeZCEFjMAAACLNHBohKSUh0yHjAP0hgQDEAAAg8OpwGgAAPxwAAB8dAABHHgAAUR8AAFsfAACbIAAA7SAAAEwhAABZIQAAlCEAAAEREQEBACsCwgAAHSRmc/sCY24BBQHFAAAgb3KJER0AAKHGAACTIPMFAXDiwxsAAIsfAADfHwAABVD7AmxyMcQAAFAgUSBPIbc/AP00ZRfHAAAdOcQAAB935OgEAAD1CAAAoBAAAIAbAACHHAAAEgEQ")
\ No newline at end of file
diff --git a/api/search.index/36b1c6a430.js b/api/search.index/36b1c6a430.js
new file mode 100644
index 000000000..e02727079
--- /dev/null
+++ b/api/search.index/36b1c6a430.js
@@ -0,0 +1 @@
+rn_("BQLAAAAXdiEyMRwyHCEfb3kFAsAAACVBHn8gFE4gaXmhxAAAwRyzAcABwcQAAB1B5qMTAADjFAAA9RQAALkbAADeHAAAXSAAALIhAAATEAAA")
\ No newline at end of file
diff --git a/api/search.index/36f25741b6.js b/api/search.index/36f25741b6.js
new file mode 100644
index 000000000..549edfe98
--- /dev/null
+++ b/api/search.index/36f25741b6.js
@@ -0,0 +1 @@
+rn_("FQHRAAAWAyJk2CEVAdgAABYRImQCIhUB0AAAFgkiZOohFQHIAAAW/CFkwyEVAccAABb4IWS5IfODAnJzFQHMAAAW+yFkwiEVAcQAABYAImTTIROJAsMAACHUY2wVAcgAABb3IWS4IRUBygAAFggiZOMhFQHKAAAWByJk4iH7hRUBxgAAFuchZJ4h84EDZW1u+wJkb/OGwAYoFQHIAAAWiyFk0h8VAcwAABYFImTgIROJAsMAACFwZGsVAckAABblIWScIROEwAhMyQAAIafLAAAhtscAACGKGwLTAAAh32ZsFQHaAAAWECJk+iH7g2dNAP4AH6QdMvLIrzrLAAAhFnvKZeKYywAAIRjCAAAcLTTdrQX8AckfAAAFAsEAABTGIRXRIXFzIwIDxAAAIO7CAAAeCmFydu+aFgAAWRoAADocAAAcHQAAQh0AACUeAABCHgAAUh4AAOweAABOHwAAWR8AANMfAADHIAAA0CA [...]
\ No newline at end of file
diff --git a/api/search.index/371ca0fdf6.js b/api/search.index/371ca0fdf6.js
new file mode 100644
index 000000000..b1072a114
--- /dev/null
+++ b/api/search.index/371ca0fdf6.js
@@ -0,0 +1 @@
+rn_("AUE7MAAAAQAALgAJAHUMAgDLDgEAphAAAGgVIgCZHAAAQR0AABoeAQAmHwAA3CAAAFUBwQAAFtwhZGYPZw/lHZgfiSEFAsAAAFCAD5YalxreG00hFyQdc3R7/RSgANEAACGF")
\ No newline at end of file
diff --git a/api/search.index/37c17d96f6.js b/api/search.index/37c17d96f6.js
deleted file mode 100644
index 367f26d4b..000000000
--- a/api/search.index/37c17d96f6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("NQHMAAAW5yFkUiBTIJ4hJQHIAAAW/SFkRSHNIUUBxQAAFrghZAEdAh0DHRgh84ECZnQlAcgAABYHImSXH+MhlwEAwAZoxQAAIg7HAAAgzPKKEAAAbBE=")
\ No newline at end of file
diff --git a/api/search.index/37c4d44a9b.js b/api/search.index/37c4d44a9b.js
new file mode 100644
index 000000000..005621707
--- /dev/null
+++ b/api/search.index/37c4d44a9b.js
@@ -0,0 +1 @@
+rn_("ocMAABYeIcMAABUeYyEFjMAAACLMHBkhKSQh0iHjAP0hgQDEAAAg7+pwGgAAPhwAAB4dAABGHgAAUB8AAFofAACaIAAA7CAAAEshAABYIQAAkyEAAAEREQEBACOCAsIAAB0jZnMrAskAAB+8ZnQ=")
\ No newline at end of file
diff --git a/api/search.index/384f9657f9.js b/api/search.index/384f9657f9.js
deleted file mode 100644
index 19c86206a..000000000
--- a/api/search.index/384f9657f9.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("odYAANohMcYAAAIfoB8rIQUCwAAAEoogEUghdHrzAIQBpCAAADHBAAAyHzMfcSHzAgJpc+TyHAAALB4AAIgfAADVHwAA1yAAACEBACUBzAAAFgUiZH0h4SEVAcIAABL5IW3lISOHAscAACH/YWvnAQL9DRQAyQAAIe3hIhkAAAYhAAAQJQHCAAAX9yBtcht0HEMB/QJFBMIAAB3xxwAAH27IAAAfzcMAACCVg7YfAABzAP0QUQDgAAAOaeE6DwAAZA8AAAEFAsEAABjDHxOVH2F0QcAAAC8MuhPFExkeAUI7MAAAAQAA6QABAJIV6QAbicEAAByqAUA7MAAAAQAA6gACAHsMAACVD+kAGwLBAAAgu2R0ZwMA/SBhFsMAAB8jxAAAHirFAAAhozowAAABAAAAAAAkABAAAAD0BDQJNQn2DpEQnRC9E74TxBO2FKQWMxqVGqYaSBuYG5kbMhwzHAwdDR0pHTQd1B4KHyI [...]
\ No newline at end of file
diff --git a/api/search.index/388782e00b.js b/api/search.index/388782e00b.js
deleted file mode 100644
index 82fb737c0..000000000
--- a/api/search.index/388782e00b.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHPAAAWEiJk9SEPIiUBxwAAGK8hZ60h8SHzhgJscEUBwQAAEWofdm4gAiEDIUMhJQLBAACmhyElJx/dIGVzsRRBHCHAAABYGrUcOwPGAAAgT2RvdgEAAswAACGE0gAAIcJhcAGnFgAAGwLCAAAb5GRtFQHGAAAg0h8UIXJ4H/MDAXABkRoAABuJwwAAHQ4VAcMAABYRImQCIvMCiAFqGgAAdwcA/TVBAsYAAB9O+lcMAABrAqEAEwABAAEACwCFDB0BEwE1hMAAABOaIHAgcSAEIQECAdUAACHabQE6DwAARYHAAABIVB9VH3MgtCBdHBwfYh+8IDHAAABAHkEeHSE1AcYAABBbIHMPHxgfux8FhsEAABDpGzJEHEUcTCD7/SkABPsCZXlhwwAACRwKHOMe5B5IH0kf0cQAAM8bBQLAAAA/oiG+Ib8hN24gAiEDIWFyIwQDwAAAIILEAAAg32VwcwGSGgAA84ECYmO [...]
\ No newline at end of file
diff --git a/api/search.index/3888623807.js b/api/search.index/3888623807.js
new file mode 100644
index 000000000..9030f27fd
--- /dev/null
+++ b/api/search.index/3888623807.js
@@ -0,0 +1 @@
+rn_("AQQBxgAAH3NyiSkbAAAbAsEAABCdYXkBQOR2DgAA6hsAANkeAACBHwAA5iAAAIiAACHFAAB1H5UgFQHDAAAWAyJk2CETAgLDAAAbe3N04fMOAABxDwAAAwGIAsYAACC36AAAHfZyc6HKAADZIRUBwAAAFIogY64f8wMBcwEcHwAAEwECxwAAIEhmcgGVEAAAocMAABYeIcMAABUeYyEFjMAAACLMHBkhKSQh0iHjAP0hgQDEAAAg7+pwGgAAPhwAAB4dAABGHgAAUB8AAFofAACaIAAA7CAAAEshAABYIQAAkyEAAAEREQEBACsCwgAAHSNmc/sCY24BBQHFAAAgbnKJEB0AAKHGAACSIPMFAXDiwhsAAIofAADeHwAABVD7AmxyMcQAAE8gUCBOIbc/AP00ZRfHAAAdOMQAAB925OgEAAD1CAAAoBAAAIAbAACGHAAAEgEQ")
\ No newline at end of file
diff --git a/api/search.index/3897310a21.js b/api/search.index/3897310a21.js
deleted file mode 100644
index 255bbbf57..000000000
--- a/api/search.index/3897310a21.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAVrhwiqhYgHmRmG4rGAAAf1CHCAABgH9gh8wKQ7JQQAACvEAAAiRoAAJQaAACCGwAANB4AAM0eAAABHwAAOB8AAG0fAACuHwAAUyEAAGEhAAAFAAEQAAAAGwLgAAAgwGlzJQHCAAAWEiJk9SEPIqHCAAB5HDHDAAAKIQshsiElAsMAABaTIRIdIWJyiR92IBUBwQAApJohbX4hNQHEAAAQfyBz3R/eH8cg9wAE/gBIAAvJAAAhwgGOIQAA84ECaW77AnJ0+wNhb3I=")
\ No newline at end of file
diff --git a/api/search.index/389be2b2b1.js b/api/search.index/389be2b2b1.js
new file mode 100644
index 000000000..e8ba05258
--- /dev/null
+++ b/api/search.index/389be2b2b1.js
@@ -0,0 +1 @@
+rn_("BQLDAAAa1yEd8yFldCMGAsUAACDqYnABQB0AAPMFAWMBSSEAAAXAwYCCAAASmxYSnBYTlRoFAsAAABxyIBlJHmNz+wJlcwUCxQAAGesgGhohY2VLh8EAABxbxAAAHlwFAsAAABSiEB5tIW9yBQPIAAASgB8ZcSEakCFhZXNLwAJByAAAHkjLAAAffzHAAACOA3QE2AT3GAD+QgegA8YAABqUzQAAIHHEAAATpuMZAAAAIgAAAIYBAACMAQAAMBA=")
\ No newline at end of file
diff --git a/api/search.index/38fad5af31.js b/api/search.index/38fad5af31.js
new file mode 100644
index 000000000..441f45409
--- /dev/null
+++ b/api/search.index/38fad5af31.js
@@ -0,0 +1 @@
+rn_("BQLAAAAVNh4UQSFjcxUBwgAAEvkhbeQhI4cCxwAAIf9hayMOAskAACHtYWMBBSEAACvABGBpOESaDsQAAB4JawPgAAAfaTFlaQ==")
\ No newline at end of file
diff --git a/api/search.index/3916dc75f9.js b/api/search.index/3916dc75f9.js
deleted file mode 100644
index ba04c6bb5..000000000
--- a/api/search.index/3916dc75f9.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQAB4QAAFLlz6PEOAAC6EAAAWBwAAF8cAACXHAAAnxwAAG4eAADAHwAAnyAAAAgREREQKwLMAAAfc2hyocQAAFwgIccAADUezh5RxgAAuCHnIf0h/iEEIgFG4joeAADmIAAALSEAABCA8wQBZuFDGgAAKB8AAAEFA8MAAB7MIRJnIBhwIXR1dyMFAsUAAB8HYnABjxYAAFsDwgAAIYZhaGx3CgD9HJwEwwAAIe3HAAAfGsIAAB4y7XkEAAD3GwAAAR0AAPYdAABNIAAAUiAAAIwgAAAYIQAALCEAAEUhAACeIQAAqyEAAM0hAADeIQAAFSABAAEAEA==")
\ No newline at end of file
diff --git a/api/search.index/3939a6dfad.js b/api/search.index/3939a6dfad.js
deleted file mode 100644
index a677289f6..000000000
--- a/api/search.index/3939a6dfad.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQUBwwAAIdxm5w4eAABUIAAAhyAAAI4gAACSIAAAlyAAAHQhAAAMIgAAYAAAAbHIAACcIPMAAmRu9aUTAABDAQEAxgdlAg==")
\ No newline at end of file
diff --git a/api/search.index/399357d2c2.js b/api/search.index/399357d2c2.js
deleted file mode 100644
index 17ae127cc..000000000
--- a/api/search.index/399357d2c2.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("YcMAAIIWgxaEFoUWrBqtGgUCwAAAEfQhGxMfZG4VAcoAAKSaIW1+ISUBxgAApDohbfwglyEzgcAISMwAACF0+5Y=")
\ No newline at end of file
diff --git a/api/search.index/39e66627fe.js b/api/search.index/39e66627fe.js
deleted file mode 100644
index 5ef2457d0..000000000
--- a/api/search.index/39e66627fe.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcIAAJwclSExwQAAbiACIQMhIcEAAFgatRwBgQLMAAAhhNIAACHCYXCnAQL9NEEAxAAAHQ7GAAAfTvSDDwAAhQwdARMB+wJlcw==")
\ No newline at end of file
diff --git a/api/search.index/39fe437b6f.js b/api/search.index/39fe437b6f.js
deleted file mode 100644
index 0420fe02d..000000000
--- a/api/search.index/39fe437b6f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYPBAAASXBwVXR4Fg8EAABJbHBVcHmv8DgDgAAAQrgEAkMQAABt05VgMAACADgAAZRsAAIofAAChHwAAfyAAAAkQAAUCwQAAIJYQvhwTRCFmc6HGAAB5HEHDAAA5HXUfaSDkIAUCwQAAFaEfFo0gZm41AcAAABRYIXBOH5EgbCEFicAAABeOIRHAIKHEAAA6IQWJxAAAEtchEdEhI4UC4AAAIVdkZgUCxAAAFsYhE6ohb3QbAs0AACHqaG9nNgHAD+vEAAAezMIAACDp1wAAIg3DAAAhQOa2EAAA0R4AANkeAAB8IAAA0yAAAPwgAACXIQAAIQAAACHOAACsIfAhIcQAAGUgxSBTAP0QAAfBAAAhHsQAACCMOjAAAAEAAAAAAD4AEAAAAAkPCg8LDwwPDQ8ODw8PEA8RDxIPEw8UDxUPFg8XDxgPGQ8aDxsPHA8dDx4PHw8gDyEPIg8jD4obtBu1G7YbIxw3HLAcsRw [...]
\ No newline at end of file
diff --git a/api/search.index/3a8b8d6297.js b/api/search.index/3a8b8d6297.js
new file mode 100644
index 000000000..eac8a35a1
--- /dev/null
+++ b/api/search.index/3a8b8d6297.js
@@ -0,0 +1 @@
+rn_("BYnEAAA4PCGBIYIhFMEhG4PFAAAfaQUDwAAAE2EhFEwfYgsdDB30IAkhCiGxIWVveSUBygAAFgsiZJUh8iEhwwAAJh/cIAWMwAAAEhkhGdIhEwcCwgAAIWNmaeSaIAAA7CAAAEshAABYIQAAkyEAAAEBAPsCYXIxxQAAoSG9Ib4hNYTAAAATmSBvIHAgAyExwgAAPx5AHhwhQcEAAEkfSh9LH10hBQLAAAAlbCCSIRKYIHV58wH9AgED6DAcAAAGHQAA7x4AAIgfAAB1IAAA8yAAAHUhAACEIQAAtiEAAAQAAAAA+wJlbPMAA3B0dfVWGgAAtQMBAFgBdwAFg8AAADUBH58fKiEVTSEFAsAAABKJIBFHIXR68wCEAaMgAAAxwQAAMR8yH3Ah8wICaXPlhBsAAPEcAAArHgAAhx8AANQfAADWIAAAAhAQxQHBAAAVeB93yhslAcAAAKSZIW06H30h+wJkblHIAAAHH7M [...]
\ No newline at end of file
diff --git a/api/search.index/3ad1b3bdc6.js b/api/search.index/3ad1b3bdc6.js
new file mode 100644
index 000000000..3c8a07466
--- /dev/null
+++ b/api/search.index/3ad1b3bdc6.js
@@ -0,0 +1 @@
+rn_("FYTAAAASIR1vDFHIAAAHH7MftB83Ia4hIwMDxAAAIHbEAAAhSmFncuvSEAAAmBoAAOQbAAAcHgAAPh4AADQfAAA+HwAAwx8AAF8gAACfIQAAqyEAAPAhAACzIQJhABEVAcYAABa4IGa2HPMCAXPy9Q4AANwB+wJsdPMAAmFr8o0DAADwDw==")
\ No newline at end of file
diff --git a/api/search.index/3ae80e1ce7.js b/api/search.index/3ae80e1ce7.js
new file mode 100644
index 000000000..70becec6d
--- /dev/null
+++ b/api/search.index/3ae80e1ce7.js
@@ -0,0 +1 @@
+rn_("FQHBAACkah9t7R3zAoSCxxwAAKUBwQAApA8hbcwg8weE9ZsfAAA7AAEAMAGDAGsDxQAAHv9jb3BFhMMAABFdIfMgdSGEIbYhE4gCwgAAIPRzdAUCwwAAJocgpyGkLx9tcwWFwAAAGuMgF2gfBQLAAAAVMB4W/h5jbCUBxQAAFuUhZJwh3yETg8AIRMsAACE2wgAAIYChxgAA6x13LgDAOm/FAAAeMc8AACE3zQAAIVE7MAAAAQAASgAVAO0OAAA7DyYAsBsAABscAAClHAAA3RwAAPQdAADGHwAApCAAALIgAACLIQAAtyEAANwhAADlIQIA7yEAAPchAQD7IQMAACIAAAMiCAAOIgAAECICAA==")
\ No newline at end of file
diff --git a/api/search.index/3b27de903f.js b/api/search.index/3b27de903f.js
deleted file mode 100644
index cb36db8d9..000000000
--- a/api/search.index/3b27de903f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ockAAMMgFYTFAAARByFaIPuGMcUAAEseTB6+H/OFAnN2BQLAAAAV4iAX0R9mdCUBxAAAFgAiZGMh1CEThgLDAAAh1WNsKwLHAAAhemFyKwLFAAAeFW1wFYTDAACh/RwOHXv9ADgIwQAAIRkxxAAAzx/QH1QhBQLAAACiIR4U3yBpdAUCwAAAP6IhviG/ITduIAIhAyFhckHDAAC0HCUeVSBWIBUBwQAAFpghdIIgpwMA/TSQAskAACGmwwAAGzPnuBMAAJIaAABrHwAAex8AAGMgAAAQIQAAOiEAAJohAAAQERERFQHIAAAW9yFkuSEVAcoAABYIImTkIRUBygAAFgciZOMh+4UVAcYAABboIWSfIfOBA2VtbgGC/QkAGMYAACGP1AAAIgHBAAAgwccAACGQKwLBAAAhUm9yIccAAFMhYSFjBAPFAAAffmJlcOGTGgAA7B0AAAEVAcYAACDSHxQhcngf8wIBcOSRGgA [...]
\ No newline at end of file
diff --git a/api/search.index/3b6ff2d14d.js b/api/search.index/3b6ff2d14d.js
new file mode 100644
index 000000000..a5007aacb
--- /dev/null
+++ b/api/search.index/3b6ff2d14d.js
@@ -0,0 +1 @@
+rn_("AQEBwgAAHTdi+foOAACLAAYL2wQBABUA8gB0AOQAAQcBwwAAIdtm5w0eAABTIAAAhiAAAI0gAACRIAAAliAAAHMhAAAMIgAAYAAAARsCxQAAH69jdPsCbnM=")
\ No newline at end of file
diff --git a/api/search.index/3b709fc40e.js b/api/search.index/3b709fc40e.js
new file mode 100644
index 000000000..7f08f8e95
--- /dev/null
+++ b/api/search.index/3b709fc40e.js
@@ -0,0 +1 @@
+rn_("IcIAAJsclCExwQAAbSABIQIhIcEAAFgatBwBgQLMAAAhg9IAACHBYXCnAQL9NEEAxAAAHQ3GAAAfTfSDDwAAhAwdARMB+wJlcw==")
\ No newline at end of file
diff --git a/api/search.index/3b746d8bb1.js b/api/search.index/3b746d8bb1.js
deleted file mode 100644
index edbad8ad2..000000000
--- a/api/search.index/3b746d8bb1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAWfCAR6x5maQEFgsMAACDF/A8dAAABAD4BtwBfAAQBBABJAAUAhwB1AAUAJQHDAABAxBvFGwYcBxxzMhtgG/sDb3V5")
\ No newline at end of file
diff --git a/api/search.index/3bbdd66e63.js b/api/search.index/3bbdd66e63.js
new file mode 100644
index 000000000..6a341cda8
--- /dev/null
+++ b/api/search.index/3bbdd66e63.js
@@ -0,0 +1 @@
+rn_("AUDhTRoAAPYdAAAIBQLBAAAU4iAlCx+3IHFzBQLLAAAUxiEV0SFxc6HEAAC7HAFFidkeAABnBwL9EaEDywAAIObGAAAfCueZEwAAzRQAAHwcAADoHAAAYB4AAPAeAAAjHwAALx8AABOIiAEbg8IAACFV")
\ No newline at end of file
diff --git a/api/search.index/3bf8449956.js b/api/search.index/3bf8449956.js
deleted file mode 100644
index 09f53be4e..000000000
--- a/api/search.index/3bf8449956.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHRAAAWECJk+iEjhALLAAAhwWZ3NQHFAAAWtSBisxxsHm0eFQLAAAAXZSEVUCFmdNMcBQLAAAAkshxrHha9IW9yoc8AAMghFYLGAAAUZSA1HXcFAcILyMIAABzoxAAAIZXkkBAAAMETAACKHAAAqR8AAJwgAAACACAlhMIAABHTIDofrR/7AmVsWwPHAAAhhmlydQ==")
\ No newline at end of file
diff --git a/api/search.index/3bfd182ccb.js b/api/search.index/3bfd182ccb.js
new file mode 100644
index 000000000..72e09a55c
--- /dev/null
+++ b/api/search.index/3bfd182ccb.js
@@ -0,0 +1 @@
+rn_("YcMAAIIWgxaEFoUWrBqtGgUCwAAAEfQhGxIfZG4VAcoAAKSZIW19ISUBxgAApDkhbfsgliEzgcAISMwAACFz+5ZBwwAA6x/sH+sgESGhygAA0B7zAMAgBehfDgAAmRAAAKIQAACSEwAAnRMAAIIaAABBHAAA3xwAAG4hAACQAAAQAA==")
\ No newline at end of file
diff --git a/api/search.index/3c2345b9cf.js b/api/search.index/3c2345b9cf.js
deleted file mode 100644
index 2fe265bd0..000000000
--- a/api/search.index/3c2345b9cf.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JZDDAAAk1CBJIX4bNx2lAcMAABQjH2apIaUBxgAAFIEgZsUhU4ED4AAADyxvc3QhwgAAkxY2HLMA/UhQAMAAACCM9JwQAAAuBL4FJwE=")
\ No newline at end of file
diff --git a/api/search.index/3c676ba0e6.js b/api/search.index/3c676ba0e6.js
deleted file mode 100644
index da6d96e04..000000000
--- a/api/search.index/3c676ba0e6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McUAANofoSCiICUBwgAAFhIiZPUhDyIVAcgAAKSaIW1+IfOBAnJ0JQHGAACkOiFt/CCXIbMAwghIzAAAIXQ7MAAAAQAAkgADAAIPAAAJEZAA1h4AAA==")
\ No newline at end of file
diff --git a/api/search.index/3c6d66726b.js b/api/search.index/3c6d66726b.js
new file mode 100644
index 000000000..26a2bb7fd
--- /dev/null
+++ b/api/search.index/3c6d66726b.js
@@ -0,0 +1 @@
+rn_("AUuJqCAAABsDwgAAIN7HAAAgcW9yeQUCwAAAwxccEgQdZWwFAsAAABYmHhNoG3J1ocIAACAeNQHEAAAWpyBjgRpeH7EgGwLgAAAWjnN0ocYAACwdRzsA/kRHOALPAAAhbc4AACHsxQAAIhLFAAAgWNL1IQAAGg==")
\ No newline at end of file
diff --git a/api/search.index/3cdf958b5d.js b/api/search.index/3cdf958b5d.js
deleted file mode 100644
index a80c27605..000000000
--- a/api/search.index/3cdf958b5d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("RQHEAACm/SFkRSFGIc0hziEbhcwAACDZFQHBAAAWBCJk3iETggLDAAAhq21vK4XCAAAbexUBxQAAFmsgZikcFQHCAAAWAyJk2SH7Aml0ocIAADweodYAANohMcYAAAIfoB8rIQUCwAAAEoogEUghdHrzAIQBpCAAADHBAAAyHzMfcSHzAgJpc+TyHAAALB4AAIgfAADVHwAA1yAAACEBACUBzAAAFgUiZH0h4SEVAcIAABL5IW3lISOHAscAACH/YWvnAQL9DRQAyQAAIe3hIhkAAAYhAAAQJQHCAAAX9yBtcht0HEMB/QJFBMIAAB3xxwAAH27IAAAfzcMAACCVg7YfAABzAP0QUQDgAAAOaeE6DwAAZA8AAAErAsEAABN7b3QBg8ACCswAACGlxgAAINjPAAAhwPMCAXeDkg8AACUBxAAAFgsiZJYh8iEJAtAAACFUzQAAIOZlbQEDAcIAABycajswAAABAADqAAI [...]
\ No newline at end of file
diff --git a/api/search.index/3d24f61296.js b/api/search.index/3d24f61296.js
new file mode 100644
index 000000000..77fa6c658
--- /dev/null
+++ b/api/search.index/3d24f61296.js
@@ -0,0 +1 @@
+rn_("BQLAAAA0Cx/KH7cgEjkdcHUhwwAAZCDEIKUBxgAAoFUfc08eUcIAAGYfZx98H24g4iDzgYZVAcEAALibIGSlE+gU6RSuHBMfocQAAGkh+wJhYwFCOzAAAAEAAOsAAgCTEAAAxhPqAPMAAW07MAAAAQAA7QADADkKAAAkC+sAZxoAADUBwAAANTIdXh5fHneNEI4QWyElgsEAADEaGzAdMR2XEKwc+/5ACsgB")
\ No newline at end of file
diff --git a/api/search.index/3d528213e6.js b/api/search.index/3d528213e6.js
new file mode 100644
index 000000000..4c754f36b
--- /dev/null
+++ b/api/search.index/3d528213e6.js
@@ -0,0 +1 @@
+rn_("FYTAAAASmRyEEKUBxAAAprwgZr4cawPFAAAcqGVvcgUCwQAAEoIaHNwgZm4FAsQAABGmHBVhH2lz+wJsbwUCxQAAEigeE/oea24bAsoAAB/HY3U3AgD9FQIG4QAAGn3CAAAgZcYAAByn6S4KAABmCgAAMQwAANAQAAD3EAAAcRoAALMaAABiHAAAsR8AAFogAAAgECEAAA==")
\ No newline at end of file
diff --git a/api/search.index/3d75b61e0e.js b/api/search.index/3d75b61e0e.js
new file mode 100644
index 000000000..0859fb498
--- /dev/null
+++ b/api/search.index/3d75b61e0e.js
@@ -0,0 +1 @@
+rn_("McYAAAEfnx8qIQUCwAAAEokgEUchdHrzAIQBoyAAADHBAAAxHzIfcCHzAgJpc+TxHAAAKx4AAIcfAADUHwAA1iAAACEBACUBzAAAFgUiZHwh4CEVAcIAABL5IW3kISOHAscAACH/YWvnAQD9DRQAyQAAIe3hIhkAAAUhAAAQ")
\ No newline at end of file
diff --git a/api/search.index/3dabb41779.js b/api/search.index/3dabb41779.js
deleted file mode 100644
index a18f6423c..000000000
--- a/api/search.index/3dabb41779.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcQAAFAdUR2AH84fFQHRAAAWECJk+iEFicQAADg9IYIhgyEUwiEbg8UAAB9qYcIAAAwdDR31IAohCyGyIQUCwAAAQo4cjxxKHv0eE00fa3BhwQAA5w7oDg8cxhzHHKggVQPBAAC14hy6ySBDmBuZGzQd0R9vc3QyDzMPNA81D9AeW8QARMEAACFiBZHEAAARlxsSXhy/Af2RQEDgAAAKTCUByAAAFgsiZJYh8iEjgQLGAAAd5mVtIcMAACcf3SAFjMAAABIaIRnTIRMHAsIAACFkZmnkmyAAAO0gAABMIQAAWSEAAJQhAAABAQD7AmFyMcUAAKIhviG/ITWEwAAAE5ogcCBxIAQhMcIAAEAeQR4dIUHBAABKH0sfTB9eIQUCwAAAJW0gkyESmSB1efMB/QIBA+gxHAAABx0AAPAeAACJHwAAdiAAAPQgAAB2IQAAhSEAALchAAAEAAAAAPsCZWwVAcIAABYOImT2IQF [...]
\ No newline at end of file
diff --git a/api/search.index/3dfe58f6e3.js b/api/search.index/3dfe58f6e3.js
deleted file mode 100644
index 6b551a5aa..000000000
--- a/api/search.index/3dfe58f6e3.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQEBwgAAHThi+foOAACLAAYL3AQBABUA8gB0AOQAAQcBwwAAIdxm5w4eAABUIAAAhyAAAI4gAACSIAAAlyAAAHQhAAAMIgAAYAAAARsCxQAAH7BjdPsCbnM=")
\ No newline at end of file
diff --git a/api/search.index/3e09a9ae57.js b/api/search.index/3e09a9ae57.js
new file mode 100644
index 000000000..628556dbe
--- /dev/null
+++ b/api/search.index/3e09a9ae57.js
@@ -0,0 +1 @@
+rn_("AQQBxQAAIG5yiRAdAAClAsIAAKR8IKOlIGJz0xwxxwAAMh1eHl8e+wNla3QVAsIAAB/uIaI7HmNyJRwrAsMAAByoYXShxgAAkiDzBQFw4sIbAACKHwAA3h8AAAVQFQHEAAASvRxykBrzAAFmAcUUAAC/AcAEJ+AAABo1")
\ No newline at end of file
diff --git a/api/search.index/3e200d3d8b.js b/api/search.index/3e200d3d8b.js
new file mode 100644
index 000000000..2990a3e21
--- /dev/null
+++ b/api/search.index/3e200d3d8b.js
@@ -0,0 +1 @@
+rn_("BYPBAAASWxwVXB4Fg8EAABJaHBVbHmv8DgDgAAAQriHEAABkIMQg8wGCOjAAAAEAAAAAAD4AEAAAAAkPCg8LDwwPDQ8ODw8PEA8RDxIPEw8UDxUPFg8XDxgPGQ8aDxsPHA8dDx4PHw8gDyEPIg8jD4obtBu1G7YbIhw2HK8csBwOHQ8dNB1NHlEeBB8GHxYfYx9xH30fyB/aH2cgaSBrIGwgdCC0ILkg2iDqIAghQCFaIZIhtSG6IZMABMQAACFDxQAAHFllcnV2mGgKAAA=")
\ No newline at end of file
diff --git a/api/search.index/3e85456181.js b/api/search.index/3e85456181.js
deleted file mode 100644
index be5fa42af..000000000
--- a/api/search.index/3e85456181.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("pQHDAAAUgSBmxSEjgYbAAAAbagUCwQAAEyAhFA4fbnIlAc8AABYSImT1IQ8iIccAAK0h8SHziwJscK8B/QOICcMAAB4qyAAAIIzCAAAhqw==")
\ No newline at end of file
diff --git a/api/search.index/3efb4f5df4.js b/api/search.index/3efb4f5df4.js
new file mode 100644
index 000000000..77046609b
--- /dev/null
+++ b/api/search.index/3efb4f5df4.js
@@ -0,0 +1 @@
+rn_("McAAANwbVR9WH6HGAACSIDHFAADOH88fUyHTAMAKSMMAABxy5cIbAAABHgAATx4AADsfAACKHwAA3h8AAAAQVbHGAAC1HzvBAoDgAAAQuQ==")
\ No newline at end of file
diff --git a/api/search.index/3f32b5a3d5.js b/api/search.index/3f32b5a3d5.js
new file mode 100644
index 000000000..9c6afbd63
--- /dev/null
+++ b/api/search.index/3f32b5a3d5.js
@@ -0,0 +1 @@
+rn_("ocYAABQfBQLIAAAXYCETUSFlcGWCwAAAFRMfiQ+dGskcyhwPHxAfAQCEwQAAE7HldAwAAMkOAACMEwAAahwAAG8fAADeIAAAAQUQQcIAALccAB51H5Ug+wJkbb8B/WEABsIAABwd")
\ No newline at end of file
diff --git a/api/search.index/3f64fdfa9f.js b/api/search.index/3f64fdfa9f.js
deleted file mode 100644
index b7c0ac46a..000000000
--- a/api/search.index/3f64fdfa9f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("pQHNAAAU3CFmDCIjhsAAwsAAAB32xwAAIP0hwwAA7hSoHKUCxAAApH0go6YgYnPUHKHHAAD9HBUBygAApJohbX4hJQHGAACkOiFt/CCXIfOGAmZwFYHEAAAVNh4SG2vABEjCAAAWlHcJAP01wArCAAAQj8kAAB87zAAAIJLy5wQAAGIW")
\ No newline at end of file
diff --git a/api/search.index/3fb1ff6250.js b/api/search.index/3fb1ff6250.js
deleted file mode 100644
index 88faa27db..000000000
--- a/api/search.index/3fb1ff6250.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocgAALQhAQQBxQAAH31yidQbAAABAAFnFDm2lHDyIAwAAHQPBYnAAAAXjSERvyAVAcIAAFOPGsgbyRuIIKghcI0gIcgAAAQfNyEFicQAABLWIRHQISOCAuAAACFVZGYTgYbEAAAgwvMAgvJcDAAAwBQFAsAAAB3pIRTQHm1uBQLEAAAWxSETqSFvdGsDzAAAIbNhaG9n7QDCH+vHAAAe2cIAACDo1wAAIgzDAAAhPzswAAABAAAKARQA7AQAAAYJCwD1EAEAkhXpABgZAACNGwAAdxwBAC8dAAA5HQAAKx4AAMweAAD7HgAAUx8AAHUfAACrHwEAVyAAAGkgAADkIAAAISEAAJEhAAATAP0QgQLBAAATsQUZgt5T4AAAISzldAwAAMkOAACMEwAAaxwAAHAfAADfIAAAAQUQ")
\ No newline at end of file
diff --git a/api/search.index/3fe3985bd6.js b/api/search.index/3fe3985bd6.js
deleted file mode 100644
index bc1733de2..000000000
--- a/api/search.index/3fe3985bd6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcIAANMe8iA1AcMAAB6zIWN3HHgczB4xwQAAExsUG/EdbwH9AaEEwwAAHPXGAAAfygUCwAAAP6IhviG/ITduIAIhAyFhciMDA8AAACCCxAAAIN9lcHMBkhoAAPsCYXk=")
\ No newline at end of file
diff --git a/api/search.index/40245027b1.js b/api/search.index/40245027b1.js
deleted file mode 100644
index 39ed7e5f9..000000000
--- a/api/search.index/40245027b1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcYAAPsh/CEJIgoi8wIBZOfCHAAAXh4AACIhAABtIQAApCEAAKchAADDIQAA6yEAABAQABErAsUAAB7ZZnQlgsQAABRlIIobNR0hwAAA5A4kDyHGAADcIPMhu/1kAQDgAAAKOBUBxQAAFmggYiUcBQLAAAAUSyAcICFjdAUCwAAAFkohEU4gM3EHAYTAMGHCAAAgj8EAACBNxAAAIPrCAAAgkCsCxQAAH7FjdBuJxQAAIFiXAgL9BIEWzgAAIWLLAAAg+8cAAB+yAXUPAAD7A2V1eQ==")
\ No newline at end of file
diff --git a/api/search.index/4075e1b776.js b/api/search.index/4075e1b776.js
new file mode 100644
index 000000000..5129016b8
--- /dev/null
+++ b/api/search.index/4075e1b776.js
@@ -0,0 +1 @@
+rn_("FYbCAACmaSGpySFnG2HAAAAxDDIMcRpyGmIcsR9RxgAABB+0IEAhtSG6IfMAAWLmjRYAABsbAACyHAAAax4AABEfAAA4IQAAPSEAAAEBAADzBAFy8o8TAACgCQUCwAAAFJQhErYUb3kFicAAABP9HhRPIfHGAAChHyUBxAAAFgoiZKYh6yHzAgJiaQGAIQAAMcMAAB4f6R+KIBUCxQAAGeQgpW8fZHN3G/uJlwEA/TQBRMsAACCNxgAAIWTDAAAaNfVXGgAAewIhAUUBdgAlgsMAADEaGzAdMR2XEKwcpQHBAAAUziBmzyEBAgHDAAAg9WbjshQAAOccAAApHwAA1SEAADAx+4k1AcMAACgDHzYhZyoeqh+rH0HHAAB1G3YbehzsIQWKwAAAJBkb+R40Mh6cH50fdQHBAAAWIhxiWQxaDGkPag9rD2wPbQ8BAwHFAAAh5WTkFRsAALEcAABqHgAAnCEAAN8hAAAwAAA [...]
\ No newline at end of file
diff --git a/api/search.index/40d7c94f3f.js b/api/search.index/40d7c94f3f.js
deleted file mode 100644
index 0e14498b8..000000000
--- a/api/search.index/40d7c94f3f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAAAWBCJk3iEThgLDAAAhq21vFQHMAAAWsCFmFSEbmMEAACFNIcgAAIIf5yDbBMkAACDyYXFzdBuKwgAAHLY=")
\ No newline at end of file
diff --git a/api/search.index/40f311ab12.js b/api/search.index/40f311ab12.js
new file mode 100644
index 000000000..8e1d89a1a
--- /dev/null
+++ b/api/search.index/40f311ab12.js
@@ -0,0 +1 @@
+rn_("YcAAAAgcCRziHuMeRx9IHyHDAACNG/oeIcIAAKgaKB7zAsCAROjIFAAAzhsAAFMeAAAeHwAAnh8AAOkfAABIIAAAiiAAABghAAAEEAAAAA==")
\ No newline at end of file
diff --git a/api/search.index/40f6360f6b.js b/api/search.index/40f6360f6b.js
new file mode 100644
index 000000000..932cc5907
--- /dev/null
+++ b/api/search.index/40f6360f6b.js
@@ -0,0 +1 @@
+rn_("ocIAAEUdccEAAAMfBx+zH7QfNiE3Ia4hocIAACUhsccAADQfpQHCAAAX0SBtrBuhxwAAqh+hwwAAeRvzAMCMAQHEEAAA+44rAsUAAB08Y3QzAAPFAAAhQWFyducdDAAAPBoAAHgcAAAlHQAAAh4AADwfAACSIAAAZyEAAAERERE=")
\ No newline at end of file
diff --git a/api/search.index/41078170fb.js b/api/search.index/41078170fb.js
deleted file mode 100644
index b970ddbe4..000000000
--- a/api/search.index/41078170fb.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAA0DB/LH7ggEjodcHUhwwAAZSDFIKUBxgAAoFYfc1AeUcIAAGcfaB99H28g4yDzgYZVAcEAALicIGSlE+gU6RSvHBQfocQAAGoh+wJhYwFCOzAAAAEAAOsAAgCTEAAAxhPqAPMAAW07MAAAAQAA7QADADkKAAAkC+sAZxoAADUBwAAANTMdXx5gHneNEI4QXCElgsEAADEaGzEdMh2XEK0c+/5ACsgB")
\ No newline at end of file
diff --git a/api/search.index/4116d7f43d.js b/api/search.index/4116d7f43d.js
deleted file mode 100644
index ce21f48f2..000000000
--- a/api/search.index/4116d7f43d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUPh6xsAANoeAACIGwLGAAAhcml0McMAAJcWmBYaHzUBwAAAFu8hZNUg1iCxIQUCwAAAGcwfJAEfOB9lcDHCAADVH9Yf1yAVAcIAABL5IW3lISOHAscAACH/YWtjAgPJAAAh7WFjawEGIQAAI4SGxQAAIJUzAMAGgMMAAB3mASEfAAAhyQAAiSAbIdcDAMQCLcQAAB88AaMhAAA=")
\ No newline at end of file
diff --git a/api/search.index/4127de4106.js b/api/search.index/4127de4106.js
new file mode 100644
index 000000000..ea44175be
--- /dev/null
+++ b/api/search.index/4127de4106.js
@@ -0,0 +1 @@
+rn_("YcIAAJIQKhwnISghZSFmISUB0AAAFgoiZKYh6yEBAgLIAAAhKcUAAB9ncHLhmhsAAPwbAACI+wJicjv9AUEB4AAAE4DOAAAhXA==")
\ No newline at end of file
diff --git a/api/search.index/4150286d7d.js b/api/search.index/4150286d7d.js
new file mode 100644
index 000000000..ba9d63aab
--- /dev/null
+++ b/api/search.index/4150286d7d.js
@@ -0,0 +1 @@
+rn_("McMAAIkbIh2RIaWEwgAAEVch3Q4xxwAAbBttG9UcNYTGAAARHx97GnwajxsBRjswAAABAACzAAIAbx5ZAO4fWQA1AcsAABTbIWZzIQwiDSL7AnFyYcQAAIITgxOEE4UTrBatFvcDAP0U4AzEAAAbdDowAAABAAAAAAAfABAAAABYDIAOgQ6CDoMOhA6FDoYOhw6IDokOBhFoGmUbZhujG6QbpRvDG8Qb5xsFHAYcTR+JH6Afrx9JIH4gkCBrIfQh")
\ No newline at end of file
diff --git a/api/search.index/4195926081.js b/api/search.index/4195926081.js
deleted file mode 100644
index 676496c1c..000000000
--- a/api/search.index/4195926081.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHFAAAVTSFyWR8lAcMAABb3IWThHLkh+4ZBxwAAGR/gIOEgXSEBBgLEAAAhdcgAACGuYXLmJBwAAPYcAAAbHwAAvx8AAHggAAAMIQAAFyEAAAYAMgAhxgAAsyDmIaMAwQaAywAAIXrBAAATkOUVGwAAshwAAGseAAB4IQAAnSEAAOAhAAAwAAAVAsAAAOJRHORKHWt2kxMVAcsAAKi0IXdXIPvAAIlzAP0hSADCAAAWjOfyBAAALwkAAIoTAAC1EwAA3xQAAIsVAACWHwAA6x8AAAMABgA=")
\ No newline at end of file
diff --git a/api/search.index/42027106dd.js b/api/search.index/42027106dd.js
deleted file mode 100644
index 228d6eed3..000000000
--- a/api/search.index/42027106dd.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHFAAAWuiBiuhwFAsEAABK7HBK5HGJ08wABdOKWEwAAyxQAAFAcAAABACHFAAC4HAEeRcLCgiAAADRQIFEgTyGq2iEldh+WIBV3H4AbgRuHHIgcK4bDAAAeADHDAAB/G4YcYSAVAsQAAB/uIaI8HmNyJhwFicAAADP/HAAdXyAZ0R/3HAD9NJgTxgAAHj7CAAAcieKeEAAA3hAAAI4bAAAQAA==")
\ No newline at end of file
diff --git a/api/search.index/4210f18b5f.js b/api/search.index/4210f18b5f.js
deleted file mode 100644
index 87bfa7dcb..000000000
--- a/api/search.index/4210f18b5f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYTDAAATuyAKH/MEAXTSKhwAANoxwgAAxxtIHU8eFQHRAAAWDiJk9iEhwgAAYiChIfsCYXIlAcAAABDQIHOOGsYbAQUBxAAAIUty4T8eAAA/HwAABvOBAmNnIcEAAIocqR8lhMIAABHTIDofrR/7AmVsGwLHAAAhhmlyNQHNAAAWBiJkfyGAIeIhBQLDAAATISGg1x5uc/OBAmxtBQLEAABB2x91INsgCSEVRCFlcvcLAMAL6cYAACE2OzAAAAEAADQAFwDfEA8AbxsBAHUbAQCMGwAArhsAALobCABGHAEAVxwAAHscAQCiHAAAKB0AADwdAAA+HgAARh8BANkfAADuHwAAiSAAANIgAADYIAEA9yAAABMhAAAbIQAA2iEBAA==")
\ No newline at end of file
diff --git a/api/search.index/42257979f2.js b/api/search.index/42257979f2.js
new file mode 100644
index 000000000..d8f9fc28d
--- /dev/null
+++ b/api/search.index/42257979f2.js
@@ -0,0 +1 @@
+rn_("QcYAAPsh/CEJIgoi8wIBZOfBHAAAXR4AACEhAABsIQAAoyEAAKYhAADCIQAA6iEAABAQABErAsUAAB7YZnQlgsQAABRkIIobNB0hwAAA5A4kDyHGAADbIPMhu/1kAQDgAAAKOBUBxQAAFmcgYiQcBQLAAAAUSiAcHyFjdAUCwAAAFkkhEU0gM3EHAYTAMGHCAAAgjsEAACBMxAAAIPnCAAAgjysCxQAAH7BjdBuJxQAAIFeXAgL9BIEWzgAAIWHLAAAg+scAAB+xAXUPAAD7A2V1eQ==")
\ No newline at end of file
diff --git a/api/search.index/4283ba8e33.js b/api/search.index/4283ba8e33.js
deleted file mode 100644
index 20df69e91..000000000
--- a/api/search.index/4283ba8e33.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHKAAAWQiF2aCEFhsAAACU4HLwhJTkcZh8VgcUAABz0IfEgI4ECyQAAIQVhczWEwAAAo+IbNBw1HBodUcIAAKcTqBNpGpofhCEVwcCACAAA4tgcU48ayBvJG4ggqCHkVh6NIAWFwAAAG8IgGGEgocQAAGMgEwEC4AAAGmhtc+SjEAAA7xQAAC0dAAAAHwAALh8AAAUQEAUCwAAAFTccouAbdXkFAsAAABSFHxv0IWN19z8A/sBAqDvgAAAQijswAAABAAAqABAAcAwCAK8OEgCCEwMArBYBAA0cAACdHAEA5hwBAEseAQCHHwAAvh8AAEsgAADxIAAA/yAAAAUhAAAWIQAAhiEAAA==")
\ No newline at end of file
diff --git a/api/search.index/431867dcf9.js b/api/search.index/431867dcf9.js
new file mode 100644
index 000000000..ace468f4c
--- /dev/null
+++ b/api/search.index/431867dcf9.js
@@ -0,0 +1 @@
+rn_("BYPAAAAVLBwmiCAaIQWDwAAAElocFVseQcAAABwHXwzfDgUP4wAEwAAADuE1OGRt+CEAAABqAQMC5gBkAMQJRABJDw==")
\ No newline at end of file
diff --git a/api/search.index/4337d7901f.js b/api/search.index/4337d7901f.js
deleted file mode 100644
index 7702b727d..000000000
--- a/api/search.index/4337d7901f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocMAABceIcMAABYeZCEFjMAAACLNHBohKSUh0yHjAP0hgQDEAAAg8OpwGgAAPxwAAB8dAABHHgAAUR8AAFsfAACbIAAA7SAAAEwhAABZIQAAlCEAAAEREQEBAEMA/SEABsEAABuRwgAAHSTDAAAangElGwAA")
\ No newline at end of file
diff --git a/api/search.index/434ae27d5a.js b/api/search.index/434ae27d5a.js
new file mode 100644
index 000000000..d2e18531b
--- /dev/null
+++ b/api/search.index/434ae27d5a.js
@@ -0,0 +1 @@
+rn_("BQPAAACiFh4SMB4XtBxhb3IxwwAAFR6ZIGMhBYzAAAAizBwZISkkIdIhIccAADMezB4FAsYAABkRIRkSIWN2BQLAAAAUkhMdZSBvcgUCwAAAFO8gHM0fY2z3CwD9PaEOxAAAGobJAAAeNsMAABORyQAAHjc6MAAAAQAAAAAAHQAQAAAAlQGWAZcBcASAD3AalhqXGt4bPhw/HB4dHx1GHkceUB9RH1ofWx9vIHAgmiDsIO0gAyFLIU0hWCFZIZMh")
\ No newline at end of file
diff --git a/api/search.index/435e45fedf.js b/api/search.index/435e45fedf.js
deleted file mode 100644
index e77289ead..000000000
--- a/api/search.index/435e45fedf.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("oc4AAHsfBcjCYEAAAKdcIBO9IUJfHGAclxyYHKJhHHWBxgAAFXUheCB5IHogeyAMIQ0hDiEhxgAAsyDmIfMCAmR25RUbAACyHAAAax4AAHghAACdIQAA4CEAADAAAMHKAADlHwUCwgAA4tgc5FYea3bhygAA3x+hxAAAkhv7wAhD+wJlbSHSAACsIfAhWwPNAAAhYGxvcqHDAAD1EAFCOzAAAAEAAOsAAgCTEAAAxhPqAAFA458OAACqFgAAZRwAACAeAAAAUCUBxQAAJrYhuyFiOSE+IaUBwQAAFM8gZtAhpQHCAAAU9iBm1iH7iaHDAACrHzHFAAAzHp0fnh/zAcIADfVHGwAAAgKeAf4BAwBVAcIAABNpIG40GmEbkhuTGyMf+wNlbHhVAcQAALicIGSlE+gU6RSvHBQfGwLMAAAhpnJ0FQHBAACkax9t7h3zAoSCyBwAAKUBwQAApBAhbc0g8weE9ZwfAAA7AAE [...]
\ No newline at end of file
diff --git a/api/search.index/436010891e.js b/api/search.index/436010891e.js
new file mode 100644
index 000000000..c96f63e1a
--- /dev/null
+++ b/api/search.index/436010891e.js
@@ -0,0 +1 @@
+rn_("AYPAAgrMAAAhpMYAACDXzwAAIb/zAQF3g5IPAAAVAcAAABkxHWbxBDUBwgAAHrIhY3YcdxzLHnv9FUAAwQAAIE4=")
\ No newline at end of file
diff --git a/api/search.index/438f932df0.js b/api/search.index/438f932df0.js
deleted file mode 100644
index 972e9d233..000000000
--- a/api/search.index/438f932df0.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcUAAF0cYh8hwQAAwBOnHAFG4joeAADmIAAALSEAABCAswL9IAEDxAAAHB7nUgwAAFsOAACQFgAAQxoAAGIbAAAoHwAAzx8AAFQhAAARACEQ")
\ No newline at end of file
diff --git a/api/search.index/43b00fadde.js b/api/search.index/43b00fadde.js
new file mode 100644
index 000000000..e8592d883
--- /dev/null
+++ b/api/search.index/43b00fadde.js
@@ -0,0 +1 @@
+rn_("FQPGAAAxuB/oH5shFs4hGN4haXN0aR6xyQAAyCAhxAAAXBxhH6UBwQAApGIgbS0fEwQCwQAAH5lpcuTlHAAASh4AAIYfAAC9HwAAFSEAABEAAPMA/RQhAOHcGwAAVR8AAAE=")
\ No newline at end of file
diff --git a/api/search.index/43fab53e55.js b/api/search.index/43fab53e55.js
deleted file mode 100644
index b9c9d2f3a..000000000
--- a/api/search.index/43fab53e55.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcEAAJoQxRDFAsMAACeRIGwhEB4bZnM4GiUBwAAAE2YgarMaWyClgsMAACFRIW4heyHzAQJsc/mHFgAAAQCPAgYDBwLrAAQABQCjAPsDYWZ08wCE4aUWAAC8HAAAETHKAAAsHi0eiB/7AmN0")
\ No newline at end of file
diff --git a/api/search.index/441d313d25.js b/api/search.index/441d313d25.js
new file mode 100644
index 000000000..10b18e1ab
--- /dev/null
+++ b/api/search.index/441d313d25.js
@@ -0,0 +1 @@
+rn_("RQHCAACglBxznQ7hHOIc4xw1AsAAABWFGxWGG3J3aQygDqEOGwLgAAAO0G54BQLAAAAaTiAyjRCOEFshY3L7A2Vpcw==")
\ No newline at end of file
diff --git a/api/search.index/454140722a.js b/api/search.index/454140722a.js
new file mode 100644
index 000000000..36d2a6961
--- /dev/null
+++ b/api/search.index/454140722a.js
@@ -0,0 +1 @@
+rn_("FQHHAACosyF3ViAxwAAAnxagFnEbAUXioR8AAMggAABfIQAAYgAbAsUAAB8CbnQhwwAAWxU1IaWCxAAAFB0hgh8xxQAAAyIHIggioc0AAHohBQLGAAAXvCEVlCFmdPMA/ADUAVEKAABBxgAA+yH8IQkiCiLzBAFk5V0eAAAhIQAAoyEAAKYhAADCIQAA6iEAAAEAESHCAACMHO4d9wsA/YsBB+EAABuVOzAAAAEAAIsBEgAoCQAAMAwAAM8QAACrEwIA9xRjAH4WAACEGgEAtBpbACAeAQBvHlkAlh8BAO4fWQCCIAMApSABAEchAACAIQAA2CEAAOIhAQA=")
\ No newline at end of file
diff --git a/api/search.index/455dddcad7.js b/api/search.index/455dddcad7.js
new file mode 100644
index 000000000..ff5e8490a
--- /dev/null
+++ b/api/search.index/455dddcad7.js
@@ -0,0 +1 @@
+rn_("FQHFAAAVTCFyWB8lAcMAABb3IWTgHLgh+4ZBxwAAGB/fIOAgXCEBBgLEAAAhdMgAACGtYXLmIxwAAPUcAAAaHwAAvh8AAHcgAAALIQAAFiEAAAYAMgAhxgAAsiDlIaMAwQaAywAAIXnBAAATkOUVGwAAsRwAAGoeAAB3IQAAnCEAAN8hAAAwAAAVAsAAAOJQHORJHWt2kxMVAcsAAKizIXdWIPvAAIlzAP0hSADCAAAWjOfyBAAALwkAAIoTAAC1EwAA3xQAAIsVAACVHwAA6h8AAAMABgA=")
\ No newline at end of file
diff --git a/api/search.index/455df4e98a.js b/api/search.index/455df4e98a.js
new file mode 100644
index 000000000..6d8546ca0
--- /dev/null
+++ b/api/search.index/455df4e98a.js
@@ -0,0 +1 @@
+rn_("IcEAAJoQxRDFAsMAACeQIGshEB4bZnM4GiUBwAAAE2UgarMaWiClgsMAACFQIW0heiHzAQJsc/mHFgAAAQCPAgUDBwLrAAQABQCjAPsDYWZ08wCE4aUWAAC7HAAAETHKAAArHiwehx/7AmN0")
\ No newline at end of file
diff --git a/api/search.index/45b929ba18.js b/api/search.index/45b929ba18.js
new file mode 100644
index 000000000..75ac6c65b
--- /dev/null
+++ b/api/search.index/45b929ba18.js
@@ -0,0 +1 @@
+rn_("FQHBAAAWBCJk3SETiALDAAAhqm1vFQPAAAAWSSG1UR0RTSAzZXHPIEHIAABvIXIhiCGPIUHCAABmIHMgtiDAIAUCwAAAHPMhHcshYWgHHIL9HwAexgAAIY7HAAAhkccAACGY1AAAIgHJAAAh18sAACG7KwLBAAAhUW9yIcUAAB4c+SAhwQAAIh6YISHHAABSIWAhBQLBAAAc4SAT3xxtbgFG+q8cAAABAFYCEABbAAwASwChAIEAcAB3LgD91okTwgAAII7BAAAgTMIAACCPxwAAITvs5Q4AACUPAACPFgAAoRYAAIcaAACOGgAAkxoAAMUbAAAmHAAAwxwAAEAdAADrHQAAfh8AABYAAAARAQABBQHEAAAhSnLkPh4AAD4fAADEHwAAXyAAAJ8hAAAGAAD7AmNnFQHDAAAWESJkAiLzAIgBahoAAPsDbG9y")
\ No newline at end of file
diff --git a/api/search.index/45e1ac6720.js b/api/search.index/45e1ac6720.js
new file mode 100644
index 000000000..a7aa02e7b
--- /dev/null
+++ b/api/search.index/45e1ac6720.js
@@ -0,0 +1 @@
+rn_("JQHFAAAYQiFj6R7OITUBxAAAFu8hZNQg1SCwISuJwgAAHMtjAAPEAAAgtWF0deSuEwAAXBUAAD4dAADJHgAA5x4AAAIRAKHGAAAUH1WCwAAAFRMfnRrJHMocDx8QH/sCZnQbisUAAB5MIcAAAOcbSSChxAAAeh9jAcAIQsMAACFG5UwbAAAfHwAAuB8AAOgfAACbIQAA6CEAANAAATUBxAAAFuYhZFEgUiCdIRcZAf0niQfCAAAdIMMAACEYxAAAHujBAAAanMgAACEjxwAAId7npBAAAAERAAB7GgAAjxsAAGkeAABYIAAAJCEAANIhAAAEEAAAIcIAAPIOiBNhwwAAkhYgGyEbIhsjGyQb0wD9EVACwAAADF7BAAAWjuHjBAAADAcAAA8=")
\ No newline at end of file
diff --git a/api/search.index/46b06b5291.js b/api/search.index/46b06b5291.js
new file mode 100644
index 000000000..759d745f9
--- /dev/null
+++ b/api/search.index/46b06b5291.js
@@ -0,0 +1 @@
+rn_("BQLBAAAYwh8TlB9hdEHAAAAvDLoTxRMYHhUB0QAAFgMiZNghFQHYAAAWESJkAiIVAdAAABYJImTqIRUByAAAFvwhZMMhFQHHAAAW+CFkuSHzgwJycxUBzAAAFvshZMIhFQHEAAAWACJk0yETiQLDAAAh1GNsFQHIAAAW9yFkuCEVAcoAABYIImTjIRUBygAAFgciZOIh+4UVAcYAABbnIWSeIfOBA2VtbvsCZG/zhsAGKBUByAAAFoshZNIfFQHMAAAWBSJk4CETiQLDAAAhcGRrFQHJAAAW5SFknCEThMAITMkAACGnywAAIbbHAAAhihsC0wAAId9mbBUB2gAAFhAiZPoh+4NnTQD+AB+kHTLyyK86ywAAIRZ7ymXimMsAACEYwgAAHC003a0F/AHJHwAABQLBAAAUxiEV0SFxcyMCA8QAACDuwgAAHgphcnbvmhYAAFkaAAA6HAAAHB0AAEIdAAAlHgAAQh4AAFI [...]
\ No newline at end of file
diff --git a/api/search.index/4741b66c03.js b/api/search.index/4741b66c03.js
new file mode 100644
index 000000000..7f3709779
--- /dev/null
+++ b/api/search.index/4741b66c03.js
@@ -0,0 +1 @@
+rn_("JQLDAAAVlB8WoiF0d8IflyAVAsMAABZjHxZkH2JvfxobAs0AACDeYWMhwwAA7RRMHvuDwcEAAOYdAUE7MAAAAQAAkQACAAIPAAAJEZAA8wCSggYPAAABQTswAAABAADrAAIAiRMAAJkX6gArlMAAABCMJQHCAAAW+CFk/SC5IROBAsMAACGtbW4BAQHDAAAb3WbjNRsAAKYbAAC1HAAAPiEAABUBJQHIAAAWCSJkoyHqIaHPAADJIfOEAmZzFQHEAACgwxtzMhsbAsEAABaBYnIVAcAAABYRImQCIvsCZHIFAsAAAEdPHVAdfx/NHxtiH25yt68A/XG5B8gAAB0w0AAAIXZihuDlzzswAAABAADuAAQAZAoBAE0MAABvDeoABxEAAA==")
\ No newline at end of file
diff --git a/api/search.index/4752a5f971.js b/api/search.index/4752a5f971.js
new file mode 100644
index 000000000..cd4270f8e
--- /dev/null
+++ b/api/search.index/4752a5f971.js
@@ -0,0 +1 @@
+rn_("AQIBwgAAHJtqOzAAAAEAAOoAAgAEDwAAkRLpAAEAAeIAABujc+6QDgAAExsAAN8bAABMHAAAoBwAACAdAADwHQAASB4AAOoeAAD7HgAADB8AADEfAACYIAAAcCEAAO0hAAAREgAAAAEAAGvABgTMAAAgVw==")
\ No newline at end of file
diff --git a/api/search.index/4767cbb23b.js b/api/search.index/4767cbb23b.js
new file mode 100644
index 000000000..5a39c81b8
--- /dev/null
+++ b/api/search.index/4767cbb23b.js
@@ -0,0 +1 @@
+rn_("BQLAAAASiSBRzxB+FqUgpiBHIXR6IcQAABsfuyDzAIYBoyAAAKHGAAACHgEGAdMAACHsd+S6GwAA2B8AANEgAAD2IAAA2SEAAHAAEDHOAADOH88fUyFb/ABkwAAAIflFAcUAABYFImRCGvEdfCHgIQFB55AOAABMHAAASB4AAPseAAAMHwAAMR8AAHAhAADtIQAAEgABAKHJAAAlIRUBxAAAE3QfbskUocQAAHwglz8A/XaZAsMAABTIxQAAHgE6MAAAAQAAAAAALQAQAAAAeARuD34TfxOpE5sWcxp0GqgaaRtyG3kbehuEG6wbrRtQHFEcUhxTHFQcVRxzHNMc1BzXHNgc2RzaHNsc3BzxHPIc8xwoHiseLB5TH1Qfhx/UH9UfciCzINYg5CE=")
\ No newline at end of file
diff --git a/api/search.index/476fbccefd.js b/api/search.index/476fbccefd.js
deleted file mode 100644
index 3dfd8f996..000000000
--- a/api/search.index/476fbccefd.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("YcIAAJIQKxwoISkhZiFnISUB0AAAFgoiZKch7CEBAgLIAAAhKsUAAB9ocHLhmhsAAP0bAACI+wJicjv9AUEB4AAAE4DOAAAhXQ==")
\ No newline at end of file
diff --git a/api/search.index/478e3629c1.js b/api/search.index/478e3629c1.js
deleted file mode 100644
index 9af59473a..000000000
--- a/api/search.index/478e3629c1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAASiiBRzxB+FqYgpyBIIXR6IcQAABwfvCDzAIYBpCAAAKHGAAADHgFG5LobAADZHwAA0iAAAPcgAADaIQAAgAAQMc4AAM8f0B9UIVv8AGTAAAAh+UUBxQAAFgUiZEIa8h19IeEhAUHnkA4AAE0cAABJHgAA/B4AAA0fAAAyHwAAcSEAAO0hAAASAAEAockAACYhFQHEAAATdR9uyRShxAAAfSCXPwD9dpkCwwAAFMjFAAAeAjowAAABAAAAAAAtABAAAAB4BG4PfhN/E6kTmxZzGnQaqBppG3IbeRt6G4QbrButG1EcUhxTHFQcVRxWHHQc1BzVHNgc2RzaHNsc3BzdHPIc8xz0HCkeLB4tHlQfVR+IH9Uf1h9zILQg1yDlIQ==")
\ No newline at end of file
diff --git a/api/search.index/47d6dcf712.js b/api/search.index/47d6dcf712.js
deleted file mode 100644
index 8c46a758b..000000000
--- a/api/search.index/47d6dcf712.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYnEAAA4PSGCIYMhFMIhG4PFAAAfagUDwAAAE2IhFE0fYgwdDR31IAohCyGyIWVveSUBygAAFgsiZJYh8iEhwwAAJx/dIAWMwAAAEhohGdMhEwcCwgAAIWRmaeSbIAAA7SAAAEwhAABZIQAAlCEAAAEBAPsCYXIxxQAAoiG+Ib8hNYTAAAATmiBwIHEgBCExwgAAQB5BHh0hQcEAAEofSx9MH14hBQLAAAAlbSCTIRKZIHV58wH9AgED6DEcAAAHHQAA8B4AAIkfAAB2IAAA9CAAAHYhAACFIQAAtyEAAAQAAAAA+wJlbPMAA3B0dfVWGgAAtgMBAFgBdwAFg8AAADUCH6AfKyEVTiEFAsAAABKKIBFIIXR68wCEAaQgAAAxwQAAMh8zH3Eh8wICaXPlhBsAAPIcAAAsHgAAiB8AANUfAADXIAAAAhAQxQHBAAAVeR93yxslAcAAAKSaIW07H34h+wJkblHIAAAIH7Q [...]
\ No newline at end of file
diff --git a/api/search.index/47d6e8f91d.js b/api/search.index/47d6e8f91d.js
deleted file mode 100644
index f7c304ea4..000000000
--- a/api/search.index/47d6e8f91d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("NQHAAABDohZaGywcCB53Phq0IbUhAQICxgAAHT3FAAAhQmF25XkcAAAmHQAAAx4AAD0fAACTIAAAaCEAABEREQWJxQAAOD0hgiGDIRTCIQUCwAAAFE0fYgwdDR31IAohCyGyIW95JQHKAAAWCyJkliHyIQWMwAAAEhohGdMhEwgCwgAAIWRmaeSbIAAA7SAAAEwhAABZIQAAlCEAAAEBADHFAACiIb4hvyE1hMAAABOaIHAgcSAEITHCAABAHkEeHSFBwQAASh9LH0wfXiEFAsAAACVtIJMhEpkgdXnzAf0CAQPoMRwAAAcdAADwHgAAiR8AAHYgAAD0IAAAdiEAAIUhAAC3IQAABAAAAAD7AmVs8wADcHR1AVYaAADFAcEAABV5H3fLGyUBwAAApJohbTsffiH7AmRuVQHEAAAQfyBzwRwJHt0f3h/HIDHFAADaH6EgoiAlAcQAABYSImT1IQ8i8wECcHcB1h4AAOc [...]
\ No newline at end of file
diff --git a/api/search.index/47e49e3299.js b/api/search.index/47e49e3299.js
new file mode 100644
index 000000000..ad98b1128
--- /dev/null
+++ b/api/search.index/47e49e3299.js
@@ -0,0 +1 @@
+rn_("IcYAAAAiBiLzBAFk5S4eAAAkHwAAYiEAAH4hAADTIQAA4SEAABEBABMDAsMAACHUY2z2sRoAAAEAhwELAekA2wA=")
\ No newline at end of file
diff --git a/api/search.index/47ee7a3642.js b/api/search.index/47ee7a3642.js
deleted file mode 100644
index b475a1646..000000000
--- a/api/search.index/47ee7a3642.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocQAABseJQLDAAAXXCEVHCFiZnMfzCEVAcYAABVNIXJZH0HHAAAZH+Ag4SBdIfMDAmZs47UTAACLFQAAlh8AAOsfAAAGADWBxQAAFd4gpRpdG14b+/0hgAQ=")
\ No newline at end of file
diff --git a/api/search.index/483a8b57ad.js b/api/search.index/483a8b57ad.js
new file mode 100644
index 000000000..2789a9f51
--- /dev/null
+++ b/api/search.index/483a8b57ad.js
@@ -0,0 +1 @@
+rn_("YcUAADIdXh5fHtkfoCChICHFAACkIb8hBf3AAQFBAAATlCAX/CCv3yATGB4BRjswAAABAACzAAIAbx5ZAO4fWQA1AcsAABTbIWZzIQwiDSL7AnFyGwLHAAAfH2VuFQHBAAA0Ux5UHp4fY64WFQHOAAAWESJkAiLzgQJwdyUBwgAAFhIiZPUhDyIxwwAACSEKIbEhFQHBAACkmSFtfSEzhgPJAAAhwWl0dvsCcnQbAscAAB/TYXIFAsAAABMqHRjMH3J1BQLAAAAazyAQ9R1lc1UBwgAAF/YgbWkbcht5G3obcxxFiMMAABcNH6IT4RTiFK0cG8AChMYAAB9txQAAH8slAcAAACQeH+kfY/MdOB8jgQLGAAAh7G1zBYnAAAAXjSERvyChxAAAOSEFicQAABLWIRHQISOFAuAAACFWZGYFAsQAABbFIROpIW90GwLNAAAh6WhvNwMBwA5rwgAAIOjXAAAiDcMAACE/xAA [...]
\ No newline at end of file
diff --git a/api/search.index/487c7630ac.js b/api/search.index/487c7630ac.js
deleted file mode 100644
index 499bbe1a1..000000000
--- a/api/search.index/487c7630ac.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocoAAEgfFQHBAAAWESJkAiJByAAAUB1RHYAfzh/7gyHDAACbE1QapYLBAAAhUSFuIXsh+wNhcnehxQAAGx0VAckAABZBIWISH/OCAmZ3BQLAAAAXIRwV1R5ydNcCAP5ARBAKwwAAIUPDAAATuvvuBAAAJgRMA5cCggACBO8GvAA4AS8AYgE=")
\ No newline at end of file
diff --git a/api/search.index/49377b04e6.js b/api/search.index/49377b04e6.js
deleted file mode 100644
index 549cdabed..000000000
--- a/api/search.index/49377b04e6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ockAAMMgIcEAAJsfByEjBQPEAAAhdcgAACGuYWly6SQcAAD2HAAA6x0AABsfAABhHwAAvx8AAFogAAB4IAAADCEAABchAAAGAAADIGuHwgAAG+o=")
\ No newline at end of file
diff --git a/api/search.index/49bf3c020d.js b/api/search.index/49bf3c020d.js
deleted file mode 100644
index cbd066e4d..000000000
--- a/api/search.index/49bf3c020d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHRAAAWECJk+iEFicQAADg9IYIhgyEUwiEbg8UAAB9qYcIAAAwdDR31IAohCyGyIQUCwAAAQo4cjxxKHv0eE00fa3BrA8IAACFiZW95JQHKAAAWCyJkliHyISHDAAAnH90gBYzAAAASGiEZ0yETBwLCAAAhZGZp5JsgAADtIAAATCEAAFkhAACUIQAAAQEA+wJhcjHFAACiIb4hvyE1hMAAABOaIHAgcSAEITHCAABAHkEeHSFBwQAASh9LH0wfXiEFAsAAACVtIJMhEpkgdXnzAf0CAQPoMRwAAAcdAADwHgAAiR8AAHYgAAD0IAAAdiEAAIUhAAC3IQAABAAAAAD7AmVsFQHCAAAWDiJk9iHzAP0AkAz2fBMAANoGtgMBAFgBdwAFAsAAAKDRHBNLIWZzG4rHAAAhrjHDAAAvHVMfkSEFg8AAADUCH6AfKyEVTiEFisAAABPVIRHQHAUCwAAAEoogEUghdHrzAIQ [...]
\ No newline at end of file
diff --git a/api/search.index/4a0d9be3e6.js b/api/search.index/4a0d9be3e6.js
new file mode 100644
index 000000000..496e1edef
--- /dev/null
+++ b/api/search.index/4a0d9be3e6.js
@@ -0,0 +1 @@
+rn_("JQHFAAAWayBiLhwFHSUB0AAAFgkiZKMh6iElAcgAABb8IWQiIcMhJQHHAAAW+CFk/SC5IfODAnJzJQHMAAAW+yFkISHCISUBxAAAFgAiZGIh0yETiQLDAAAh1GNsFQHIAAAW9yFkuCEVAcoAABYIImTjIRUBygAAFgciZOIh+4UVAcYAABbnIWSeIfOBA2VtbvsCZG83BwD9HJARwwAAG4PGAAAdOwH4DgAAAQABwgAAHTdi+foOAACLAAYL2wQBABUA8gB0AOQA8wABdNKkIQAAGwWJwAAApTwfEv4eAQcBwwAAIdtm5w0eAABTIAAAhiAAAI0gAACRIAAAliAAAHMhAAAMIgAAYAAAARsCxQAAH69jdBUBxAAAE2ggbmEbBQLAAAAVOx8mAB83H2xuBQLAAAATwSFjCBwJHOIe4x5HH0gfbHUFA8MAABiYIRK2IBiIIWN1dyMEAsUAAB9xYnABhxoAADHHAAA8IYE [...]
\ No newline at end of file
diff --git a/api/search.index/4a67fb9a41.js b/api/search.index/4a67fb9a41.js
deleted file mode 100644
index 8702072a0..000000000
--- a/api/search.index/4a67fb9a41.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHQAAAW7yFksSEVAdIAABYOImT2IRUBzwAAFgYiZOIh84YCY3AVAcwAABbnIWSeIRUBxwAAFrghZBgh+wJycysCwQAAIPtjePuH")
\ No newline at end of file
diff --git a/api/search.index/4b1cf3d74f.js b/api/search.index/4b1cf3d74f.js
deleted file mode 100644
index 5a8b34ba6..000000000
--- a/api/search.index/4b1cf3d74f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQPAAAAWSiG1Uh0RTiAzZXHQICHFAAAfHPogIcEAACMemSEhxwAAUyFhIQUCwQAAHOIgE+AcbW4BRvqwHAAAAQBWAhAAWwAMAEsAoQCBAHAAdyYA/daJE8IAACCPwQAAIE1v1xOaT8IAACCQxwAAITzs5Q4AACUPAACPFgAAoRYAAIcaAACOGgAAkxoAAMYbAAAnHAAAxBwAAEEdAADsHQAAfx8AABYAAAARAQABBQHEAAAhS3LkPx4AAD8fAADFHwAAYCAAAKAhAAAGAAA7wBIgwAAAFpk=")
\ No newline at end of file
diff --git a/api/search.index/4b757e5b26.js b/api/search.index/4b757e5b26.js
new file mode 100644
index 000000000..b176e989e
--- /dev/null
+++ b/api/search.index/4b757e5b26.js
@@ -0,0 +1 @@
+rn_("FQHBAAAWBCJk3SETjALDAAAhqm1vBQLFAAAUZh8Vyh9xc/uJpQHJAAAURiFm6CElAckAABbcIWSYH4khJQHMAAAW/iFkRSHNISUBzAAAFv0hZEQhzCH7hQUCwAAAF3YhMjEcMhwhH295IcYAAEEefyDzAgJsdOKjEwAA4xQAALkbAAATADWBwQAAI3gbOB63FLgUwSAhxgAA+CELIucPAP0cMQ7HAAAg4cIAAB4U/F0OAABCDAEAywCSBREAhwAkAA4AAQAmAAQA")
\ No newline at end of file
diff --git a/api/search.index/4c82a80b13.js b/api/search.index/4c82a80b13.js
deleted file mode 100644
index 6a372a075..000000000
--- a/api/search.index/4c82a80b13.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHAAAATZiBqsxpbIKWCwwAAIVEhbiF7IaWCxwAAFB4hgx8rAsAAAB+wZHohxgAA9R2lIPHCAAA3G7cJAf0cSQPAAAATn8EAABaZwwAAHLb5hxYAAAEAjwIGAwcC6wAEAAUAowA=")
\ No newline at end of file
diff --git a/api/search.index/4ca8bcdefd.js b/api/search.index/4ca8bcdefd.js
deleted file mode 100644
index a8087dde2..000000000
--- a/api/search.index/4ca8bcdefd.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("RQHAAAAziRsjHZIhdMQbxRsGHAccIcIAAGAf2CHzA5DslBAAAK8QAACJGgAAlBoAAIIbAAA0HgAAzR4AAAEfAAA4HwAAbR8AAK4fAABTIQAAYSEAAAUAARAAAAAVAsMAABaTIRIdIWJydiAjhwLDAAAgx2ZzOwPGAAAcrmFvciHBAACTFjYcBQLAAAAhhhOJFhl6H250FQHEAAAQih9zHh9BwAAASgobDBwM1R6hxQAAACEVAcAAABT/IGM+HRUByQAAFrshYj4h84PCCECrxAQhxwAAH8zCAAATqiUBygAAFgUiZH0h4SGlAcYAAKa9IGa/HBUBzwAAFrAhZhUh8wACcnMBICEAAKvAAqHDAAAeNssAAB/Z9wsA/TGJB8cAAByvwgAAE4o7MAAAAQAABwETAI0BAgCwAeoA3AQAAPAEAAD8BAcA9AgAADEKAQBIDAAAfQwAAI4TAACXEwAAEhsAADIbAABgGwAAtxs [...]
\ No newline at end of file
diff --git a/api/search.index/4cb0b404d5.js b/api/search.index/4cb0b404d5.js
deleted file mode 100644
index 211e43ec7..000000000
--- a/api/search.index/4cb0b404d5.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McUAADMdXx5gHkWIxAAAFw4fohPhFOIUrhwlAcAAABNmIGqzGlsgpYLDAAAhUSFuIXsh8wUCbHP5hxYAAAEAjwIGAwcC6wAEAAUAowAFAsAAABQBIhY0H2N01wIA/RMREMMAACDyygAAINDkjRAAAPoQAACSFgAAIBsAAFwhAAATBAA=")
\ No newline at end of file
diff --git a/api/search.index/4cfa0c4a28.js b/api/search.index/4cfa0c4a28.js
new file mode 100644
index 000000000..4805b15d4
--- /dev/null
+++ b/api/search.index/4cfa0c4a28.js
@@ -0,0 +1 @@
+rn_("AUDhTRoAAPYdAAAIBQLBAAAU4iAlCx+3IHFzBQLLAAAUxiEV0SFxc6HEAAC7HAFFidkeAABnBwD9EaEDywAAIObGAAAfCueZEwAAzRQAAHwcAADoHAAAYB4AAPAeAAAjHwAALx8AABOIiAEbA9MAACGXwQAAHKJlaGk=")
\ No newline at end of file
diff --git a/api/search.index/4d39d12d8b.js b/api/search.index/4d39d12d8b.js
new file mode 100644
index 000000000..58ecae5d2
--- /dev/null
+++ b/api/search.index/4d39d12d8b.js
@@ -0,0 +1 @@
+rn_("FYTGAAARJx65HwUDwAAAHNsgE3oaJ5Uf6h9hb3IBTImoIAAABQLAAADDFxwSBB1lbAUCwAAAFiYeE2gbcnWhxgAALB1PB/5EBTACzwAAIW3OAAAh7MsAACCnAUWIDxwAAKHPAACGIaHUAADJIfOBAmdzBQLAAAAQoiEWKx1ldAUCwwAAHGwhH6UhY2b7m6UCwQAAFSUeoHgaZXN8FgWMwQAAFPIgHL8h+4qlAcIAABZBIXZnIROCAuEAACGzbnP7AmFyBQLAAACloxwcsSBydQUCwQAAGNggGGAfd3gVAcUAABc1IXPXICsCwgAAHgRtdDHGAAAkHlQgVSChygAApSABhQPDAAAgXtMAACHuxwAAIU5jZWz7wADE8wCDAf8hAAABT4ksIQAACQLPAAAha8sAACCkZG4FAsAAABb5HhJnG2V0ocMAAGUb+wJlbBsC4AAAGzRpcwUCwwAAFsUfGishaG8FAscAABOjIBY [...]
\ No newline at end of file
diff --git a/api/search.index/4d54b99309.js b/api/search.index/4d54b99309.js
new file mode 100644
index 000000000..0396a3d41
--- /dev/null
+++ b/api/search.index/4d54b99309.js
@@ -0,0 +1 @@
+rn_("NQHFAAAWtCBishxrHmweFQLAAAAXZCEVTyFmdNIcBQLAAAAksRxqHha8IW9yoc8AAMchFYLGAAAUZCA0HXcFAcILyMIAABznxAAAIZTkkBAAAMETAACJHAAAqB8AAJsgAAACACAlhMIAABHSIDkfrB/7AmVs")
\ No newline at end of file
diff --git a/api/search.index/4d8b3bfec2.js b/api/search.index/4d8b3bfec2.js
new file mode 100644
index 000000000..2357b0da8
--- /dev/null
+++ b/api/search.index/4d8b3bfec2.js
@@ -0,0 +1 @@
+rn_("FQHHAACosyF3ViAxwAAAnxagFnEbpYLEAAAUHSGCHwUCxgAAF7whFZQhZnT7AmFmIcIAAIwc7h3zAf0JAAU7MAAAAQAAeAEGAKsTAgD3FGMAhBoBALQaWwBvHlkA7h9ZAA==")
\ No newline at end of file
diff --git a/api/search.index/4dff5675c7.js b/api/search.index/4dff5675c7.js
new file mode 100644
index 000000000..d168a959c
--- /dev/null
+++ b/api/search.index/4dff5675c7.js
@@ -0,0 +1 @@
+rn_("AUE7MAAAAQAA6QABAK8W6QBBwgAATx1QHX8fzR8VAdAAABbvIWSwIRUB0gAAFg4iZPYhFQHPAAAWBiJk4SEzBsICCNMAACHs5LobAADYHwAA0SAAAPYgAADZIQAAcAAQpQHAAAAQ+SE1YBwVAcwAABbmIWSdIRUBxwAAFrchZBch+wJyczHNAADOH88fUyFrxAIEwQAAIPr7/RlBCA==")
\ No newline at end of file
diff --git a/api/search.index/4eaa7deac4.js b/api/search.index/4eaa7deac4.js
new file mode 100644
index 000000000..d5060f990
--- /dev/null
+++ b/api/search.index/4eaa7deac4.js
@@ -0,0 +1 @@
+rn_("IcEAAJoQxRAxwQAA6xQUHxUfxQLDAAAnkCBrIRAeG2ZzOBohwAAAwBOmHCUBwAAAE2UgarMaWiClgsMAACFQIW0heiFjAQPBAAAfr2lsc/mHFgAAAQCPAgUDBwLrAAQABQCjAN8D/S1ABMIAABuR")
\ No newline at end of file
diff --git a/api/search.index/4eaee0847e.js b/api/search.index/4eaee0847e.js
deleted file mode 100644
index 33212f1c0..000000000
--- a/api/search.index/4eaee0847e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLBAAAYwx8TlR9hdEHAAAAvDLoTxRMZHhUB0QAAFgMiZNkhFQHYAAAWESJkAiIVAdAAABYJImTrIRUByAAAFvwhZMQhFQHHAAAW+CFkuiHzgwJycxUBzAAAFvshZMMhFQHEAAAWACJk1CETiQLDAAAh1WNsFQHIAAAW9yFkuSEVAcoAABYIImTkIRUBygAAFgciZOMh+4UVAcYAABboIWSfIfOBA2VtbvsCZG/zhsAGKBUByAAAFowhZNMfFQHMAAAWBSJk4SETiQLDAAAhcWRrFQHJAAAW5iFknSEThMAITMkAACGoywAAIbfHAAAhixsC0wAAIeBmbBUB2gAAFhAiZPoh+4NnTQD+AB+kHWiUuVnxywAAIRdKZ/uaQcsAACEZwgAAHC4IaVip9AHKHwAABQLBAAAUxyEV0iFxcyMCA8QAACDvwgAAHgthcnbvmhYAAFkaAAA7HAAAHR0AAEMdAAAmHgAAQx4AAFM [...]
\ No newline at end of file
diff --git a/api/search.index/4f5dd46927.js b/api/search.index/4f5dd46927.js
deleted file mode 100644
index 6c7d58941..000000000
--- a/api/search.index/4f5dd46927.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McMAAOAUzCDzIHX9wiAQGQAApm4eG8wgHPIgFGMcHPMg6Q7qDusO7A43DzgPOQ+hxAAAax8jAMAIQsMAAByU4AAAEQbmig8AABgcAADuHQAASh8AAFYhAABYIQAAXiEAACMCAAC7wATKwgAAG27AAAAcow==")
\ No newline at end of file
diff --git a/api/search.index/4fdff5055b.js b/api/search.index/4fdff5055b.js
deleted file mode 100644
index b92ba0e99..000000000
--- a/api/search.index/4fdff5055b.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAAAWBCJk3iETiALDAAAhq21vFQPAAAAWSiG1Uh0RTiAzZXHQIEHIAABwIXMhiSGQIUHCAABnIHQgtyDBIAUCwAAAHPMhHcwhYWgHHIL9HwAexgAAIY/HAAAhkscAACGZ1AAAIgHJAAAh2MsAACG8KwLBAAAhUm9yIcUAAB8c+iAhwQAAIx6ZISHHAABTIWEhBQLBAAAc4iAT4BxtbgFG+rAcAAABAFYCEABbAAwASwChAIEAcAB3LgD91okTwgAAII/BAAAgTcIAACCQxwAAITzs5Q4AACUPAACPFgAAoRYAAIcaAACOGgAAkxoAAMYbAAAnHAAAxBwAAEEdAADsHQAAfx8AABYAAAARAQABBQHEAAAhS3LkPx4AAD8fAADFHwAAYCAAAKAhAAAGAAD7AmNnFQHDAAAWESJkAiLzAIgBahoAAPsDbG9y")
\ No newline at end of file
diff --git a/api/search.index/50091c092a.js b/api/search.index/50091c092a.js
new file mode 100644
index 000000000..c48526a1a
--- /dev/null
+++ b/api/search.index/50091c092a.js
@@ -0,0 +1 @@
+rn_("FQHFAAAWZyBiJBwFAsAAABRKIBwfIWN0BQLAAAAWSSERTSAzcQcBhMAwYcIAACCOwQAAIEzEAAAg+cIAACCPKwLFAAAfsGN0G4nFAAAgVxcFAP0UgRbgAAAMH84AACFhywAAIPrHAAAfsQF1DwAA")
\ No newline at end of file
diff --git a/api/search.index/501e2cdafd.js b/api/search.index/501e2cdafd.js
new file mode 100644
index 000000000..27a599283
--- /dev/null
+++ b/api/search.index/501e2cdafd.js
@@ -0,0 +1 @@
+rn_("BQLBAAASghoc3CBmbgUCxAAAEaYcFWEfaXP7AmxvBQLFAAASKB4T+h5rbhsCygAAH8djdTMA/QUABsYAABynxgAAHKjhLgoAAGYKAAAgIcAAAJMWNRxrA9YAACINYWVz")
\ No newline at end of file
diff --git a/api/search.index/50d376da3a.js b/api/search.index/50d376da3a.js
new file mode 100644
index 000000000..e45b77175
--- /dev/null
+++ b/api/search.index/50d376da3a.js
@@ -0,0 +1 @@
+rn_("AQICwwAAHyLCAAAgumZp5bYUAACVGgAAMRwAAAkfAAAhHwAAqCEAAAAQASUBxAAAFmsgYi4cBR0rAsEAAB8gZXJByAAAPhw/HB4dHx0FAsYAABkjIaLJHHBy8wACbnSClBwAAEUBxQAApv0hZEQhRSHMIc0hFQHBAAAWBCJk3SETgwLDAAAhqm1vIcMAAOwUKx37A2F0dyUBzwAAFgkiZKMh6iElAcEAABbcIWSYH4khUcEAAIAPlhqXGt4bTSH7AmNlCQLgAAAPic8AACFgZnPvAf0RQUDNAAAhXGHIAAA6HDscPBw9HBwdHR0FAscAADjsIO0gSyEalSF0dSUByAAAFvwhZCIhwyElAccAABb4IWT9ILkh84ECcnP7Amdy+wJhcgFFOzAAAAEAAJEAAgAfHAAAVB2QAKHCAAAFHkcCAP0BDgzHAAAfwsIAACGUxQAAIXbCAAAflAGAEwAAAUiJfBwAABWExAAAEdI [...]
\ No newline at end of file
diff --git a/api/search.index/5108e78c79.js b/api/search.index/5108e78c79.js
new file mode 100644
index 000000000..3db0c0312
--- /dev/null
+++ b/api/search.index/5108e78c79.js
@@ -0,0 +1 @@
+rn_("FQHBAADkphtyRgqlgcAAABW1IMkeI4YCwQAAIElpcysCwAAAGjJpbqUBwwAAMNwbVR9WH3NPHsUCwAAAFPEgG88gYm36ECHEAACxFEAcfwH9DFACyQAAIIs7A8sAACFeZXN0")
\ No newline at end of file
diff --git a/api/search.index/518864e068.js b/api/search.index/518864e068.js
new file mode 100644
index 000000000..606d745e1
--- /dev/null
+++ b/api/search.index/518864e068.js
@@ -0,0 +1 @@
+rn_("IcIAAM4eBR+hwwAANRsFAsAAABbFHxorIWhv+4mhyAAABR4hxQAA5R54ISHGAAARG3Eh5wUA/oAEog3CAAAU18wAACCWxQAAH2DlEgkAAOcOAAChEwAADhwAAMUcAACnIAAAAQAQNQHLAAAW5iFkUSBSIJ0hGwLDAAATjG50JQHIAAAW/SFkRCHMIUUBxQAAFrchZAAdAR0CHRch84ECZnQFAsAAABXLIEQ5HEQdLR4IH2Nz8wCCgvsFAAClgcAAABW1IMkeI4YCwQAAIElpcysCwAAAGjJpbkOCA8sAACDPyQAAIItkb3MVgsIAABGnFlcMu/0QQQHBAAAOfwFA5HYOAADqGwAA2R4AAIEfAADmIAAAiIAAFQHAAAAUiiBjrh/zAwFzARwfAAATAgLHAAAgSGZyAZUQAADzAgJpcwGgEAAAodAAAN8gQwHAA4DDAAAe0swAAB/I4UcKAAAXDAAAASUByAAAFgciZJY [...]
\ No newline at end of file
diff --git a/api/search.index/51e6c0ea81.js b/api/search.index/51e6c0ea81.js
deleted file mode 100644
index d96587f1c..000000000
--- a/api/search.index/51e6c0ea81.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("oc4AAIchQcMAAFQeVR6fH0kgFYHHAAAc9CHxICMDwQCgwQAAIYTFAAAfZgEFIQAA+wJobzMAA8wAACEfY2V0Aa4WAAA=")
\ No newline at end of file
diff --git a/api/search.index/52224d81d7.js b/api/search.index/52224d81d7.js
new file mode 100644
index 000000000..83b30e962
--- /dev/null
+++ b/api/search.index/52224d81d7.js
@@ -0,0 +1 @@
+rn_("FQHBAAAWBCJk3SEThgLDAAAhqm1vFQHMAAAWryFmFCEbmMEAACFMIcgAAIEf5iDbBMkAACDxYXFzdBuKwgAAHLU=")
\ No newline at end of file
diff --git a/api/search.index/524f49b081.js b/api/search.index/524f49b081.js
new file mode 100644
index 000000000..ac31735fc
--- /dev/null
+++ b/api/search.index/524f49b081.js
@@ -0,0 +1 @@
+rn_("AQIBwgAAG0h05WoMAACdFgAAOR0AAEMhAABKIQAATCEAAEEAABUBxQAAFrkgYrkcMcQAAHEachqxHwUCwQAAErocErgcYnQVAcwAABZaIWJ+H/MAAmV09ZYTAAA1AQEAgwcSBQUCwAAAxuQfFPUbY24FAsEAACK3HAAe4GocZG1blsEAAB1BBQLBAAAWIB8RkBtibysCwgAAIU9hchUBwwAAqLMhd1YgRcLCgiAAADRPIFAgTiGq2SEldR+VIBV2H4AbgRuGHIccK4bDAAAd/wUDwQAApNAeMX8bhRxgICTOHgUfZWx4FQLDAAAf7iGiOx5jciUcFQHEAAASvRxykBrzAAFmAcUUAAD7AmRuAYL9CQAYxgAAIY7UAAAiAcEAACDAxwAAIY8rAsEAACFRb3IhxwAAUiFgIWMEA8UAAB99YmVwAZMaAAAxwgAA/hz/HF4g+wJjdBuJyAAAH9BlgcUAABXvIEYeRx5QH1E [...]
\ No newline at end of file
diff --git a/api/search.index/5276568752.js b/api/search.index/5276568752.js
deleted file mode 100644
index 7b44e3f80..000000000
--- a/api/search.index/5276568752.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("dQHFAAAYOCFnmBqZGpoamxrlG+Yb5xsbAuAAABqcY2dFwsGCIAAANFAgUSBPIaraISV2H5YgFXcfgBuBG4cciBwjAALFAAAc3mRzAVAMAAAxxAAAAB7mHnkh+44=")
\ No newline at end of file
diff --git a/api/search.index/5310bde235.js b/api/search.index/5310bde235.js
deleted file mode 100644
index 06124d934..000000000
--- a/api/search.index/5310bde235.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McYAAIwh6CEQIiMAAsEAAB3wYWTpNxoAALAaAAB6HwAA0x8AAGohAACHIQAAnyEAAMEhAADKIQAA+iEAAAAAEQAQ")
\ No newline at end of file
diff --git a/api/search.index/53464c12fe.js b/api/search.index/53464c12fe.js
deleted file mode 100644
index f135893da..000000000
--- a/api/search.index/53464c12fe.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHFAAAWaCBiJRwFAsAAABRLIBwgIWN0BQLAAAAWSiERTiAzcQcBhMAwYcIAACCPwQAAIE3EAAAg+sIAACCQKwLFAAAfsWN0G4nFAAAgWBcFAP0UgRbgAAAMH84AACFiywAAIPvHAAAfsgF1DwAA")
\ No newline at end of file
diff --git a/api/search.index/535ea20b23.js b/api/search.index/535ea20b23.js
new file mode 100644
index 000000000..082592087
--- /dev/null
+++ b/api/search.index/535ea20b23.js
@@ -0,0 +1 @@
+rn_("AQL9AgMCwwAAHSnGAAAdQ8IAAByayAAAHxk7MAAAAQAA9wACAAMPAACaEfYAFQLDAAAh2B57IBN0H2luyRRb/QBBCcoAACEWwwAAE7Y=")
\ No newline at end of file
diff --git a/api/search.index/53c12e65e8.js b/api/search.index/53c12e65e8.js
deleted file mode 100644
index 8f7baceaf..000000000
--- a/api/search.index/53c12e65e8.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYbCAACmaiGpyiFnG2HAAAAxDDIMcRpyGmMcsh9RxgAABR+1IEEhtiG7IfMAAWLmjRYAABsbAACzHAAAbB4AABIfAAA5IQAAPiEAAAEBAADzBAFy8o8TAAChCQUCwAAAFJUhErYUb3kFicAAABP+HhRQIfHGAACiHyUBxAAAFgoiZKch7CHzAgJiaQGBIQAAMcMAAB8f6h+LIBUCxQAAGeUgpXAfZHN3G/uJlwEA/TQBRMsAACCOxgAAIWXDAAAaNfVXGgAAfAIhAUUBdgAlgsMAADEaGzEdMh2XEK0cpQHBAAAUzyBm0CEBAgHDAAAg9mbjshQAAOgcAAAqHwAA1iEAADAx+4k1AcMAACgEHzchZyseqx+sHzHHAAB1G3YbexwFisAAACQZG/oeNDMenR+eH3UBwQAAFiMcYlkMWgxpD2oPaw9sD20PAQMBxQAAIeZk5BUbAACyHAAAax4AAJ0hAADgIQAAMAAAKwL [...]
\ No newline at end of file
diff --git a/api/search.index/53ec6e8485.js b/api/search.index/53ec6e8485.js
new file mode 100644
index 000000000..405c91ebf
--- /dev/null
+++ b/api/search.index/53ec6e8485.js
@@ -0,0 +1 @@
+rn_("FQPAAAAWSSG1UR0RTSAzZXHPICHFAAAeHPkgIcEAACIemCEhxwAAUiFgIQUCwQAAHOEgE98cbW4BRvqvHAAAAQBWAhAAWwAMAEsAoQCBAHAAdyYA/daJE8IAACCOwQAAIEwcI7suqcIAACCPxwAAITvs5Q4AACUPAACPFgAAoRYAAIcaAACOGgAAkxoAAMUbAAAmHAAAwxwAAEAdAADrHQAAfh8AABYAAAARAQABBQHEAAAhSnLkPh4AAD4fAADEHwAAXyAAAJ8hAAAGAAA7wBIgwAAAFpk=")
\ No newline at end of file
diff --git a/api/search.index/541cf368d2.js b/api/search.index/541cf368d2.js
deleted file mode 100644
index b476d2b74..000000000
--- a/api/search.index/541cf368d2.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQLDAAAVlR8WoyF0d8MfmCAVgccAABz0IfEgIwTBAKDBAAAhhMUAAB9mAQUhAAAbAswAACEfY3QVAsMAABZkHxZlH2JvfxoTgQLNAAAg32FjAUI7MAAAAQAA6wACAIkTAACZF+oAhw4A/TGQB8sAAB9jwwAAFoHIAAAdMdAAACF3OzAAAAEAAO4ABABkCgEATQwAAG8N6gAHEQAAAQD9ABUBwgAAE43CAAATjsMAABaMxgAAHCLtOwoAABMMAACqEwAAtxMAAIEWAACXFgAAgxsAADAcAABEHQAARh0AABofAABlIAAAxSAAAB4hAACgAAEAAQAA+wJydzHAAACHG4gb6R4rwAxExQAAIgFcEUOwJsQAABwiFQLBAAAXYx8SixBhcmMK8wCLAZQBAAA=")
\ No newline at end of file
diff --git a/api/search.index/542569dda6.js b/api/search.index/542569dda6.js
deleted file mode 100644
index 0f0f73654..000000000
--- a/api/search.index/542569dda6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAsrCHwIciRH29yFQHCAAAWDiJk9iHzAAFtAXwTAAAFisAAAKHRHBiuIQFB5XUaAABLHAAAHx4AACgeAACbHwAAByEAABEAABUBygAAFgMiZNkhxwYB/YMJA8QAACF1wgAAHKHBAAAc0DowAAABAAAAAAAgABAAAACnGqkaCxwMHCQcOByrHKwc9hz3HPgc+Rz6HPsc/BzrHRsfYR+6H78fWiB4IHkgeiB7IMMgxCDaIAwhDSEOIRchvCEVAcIAABL5IW3lISOHAscAACH/YWsjCwLJAAAh7WFjAQYhAAA7/QhAhMEAAB7sxwAAIWBTAAPBAAAbHWltdOJvDwAAHhsAAMYfAAAQAA==")
\ No newline at end of file
diff --git a/api/search.index/54416fafbc.js b/api/search.index/54416fafbc.js
new file mode 100644
index 000000000..998829d12
--- /dev/null
+++ b/api/search.index/54416fafbc.js
@@ -0,0 +1 @@
+rn_("ocgAALMhAQQBxQAAH3xyidMbAAABAAE7vdZuY3DyIAwAAHQPBYnAAAAXjCERviAVAcIAAFOPGscbyBuHIKchcIwgIcgAAAMfNiEFicQAABLVIRHPISOCAuAAACFUZGYTgYbEAAAgwfMAgvJcDAAAvxQFAsAAAB3oIRTPHm1uBQLEAAAWxCETqCFvdGsDzAAAIbJhaG9n7QDCH+vHAAAe2MIAACDn1wAAIgzDAAAhPjswAAABAAAKARQA7AQAAAYJCwD1EAEAkhXpABgZAACNGwAAdhwBAC4dAAA4HQAAKh4AAMseAAD6HgAAUh8AAHQfAACqHwEAViAAAGggAADjIAAAICEAAJAhAAATAP0QgQLBAAATsSq2ycLq4AAAISvldAwAAMkOAACMEwAAahwAAG8fAADeIAAAAQUQ")
\ No newline at end of file
diff --git a/api/search.index/546e67512d.js b/api/search.index/546e67512d.js
deleted file mode 100644
index 0eee5bc66..000000000
--- a/api/search.index/546e67512d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AYPAAgrMAAAhpcYAACDYzwAAIcDzAQF3g5IPAAAVAcAAABkyHWbxBDUBwgAAHrMhY3cceBzMHnv9FUAAwQAAIE8=")
\ No newline at end of file
diff --git a/api/search.index/5485d267a3.js b/api/search.index/5485d267a3.js
deleted file mode 100644
index ea6ea84b1..000000000
--- a/api/search.index/5485d267a3.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcUAAKUhwCEFA8AAABOVIBf9IBMZHmFpeaUBzQAAFNwhZgwiBQLAAAATKx0YzR9ydUUBwgAAF/cgbXIbeRt6G3QcFQHCAAAU6h9jOR8lAcIAABK+HHKQGnEc84ECZWwlAcUAABngIWamHMcfBQLBAAAR8R0Xyh9pcCHHAABgIKAhCZTIAAAhUNAAACHB84ECZmwrAssAACGEcnQBAP7ATLULcTYqnAcdSG3b5nMWPGEVIZwzaoXHAAAfbhBRkI/1wAAAHfZMH9uRt9IAACHCxwAAH59GdTvH+X/51HAsGI1eSTT77g4AAJEBRgTiAYAESARHAAEAAQCdAQIA")
\ No newline at end of file
diff --git a/api/search.index/54b1305644.js b/api/search.index/54b1305644.js
new file mode 100644
index 000000000..38abfc629
--- /dev/null
+++ b/api/search.index/54b1305644.js
@@ -0,0 +1 @@
+rn_("FQHBAAAZuB9zng5VAcQAABfDH2w7IW8hciGIIY8hAUD4pxMAAAEAwQZdAYEBBwFLAeoBYcAAAJIWIBshGyIbIxskG/MAwCwEhS0PAAA=")
\ No newline at end of file
diff --git a/api/search.index/54cc3c9349.js b/api/search.index/54cc3c9349.js
deleted file mode 100644
index 5e632495b..000000000
--- a/api/search.index/54cc3c9349.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYHCAAATAx+7IHUBwAAAFiMcYlkMWgxpD2oPaw9sD20PAUA7MAAAAQAAkAABAIUYkAArisMAABwwAUTioh8AAMkgAABgIQAAYgBbwAHAxwAAIbNBwgAApRamFrwcvRzzAII7MAAAAQAA7QADAHsMAACVD+kAXxUCAPv9CGAE")
\ No newline at end of file
diff --git a/api/search.index/555f432747.js b/api/search.index/555f432747.js
new file mode 100644
index 000000000..26567af01
--- /dev/null
+++ b/api/search.index/555f432747.js
@@ -0,0 +1 @@
+rn_("BQPGAAARmyEWziEY3iFpc3QrAsMAACEVY27zBQFzAV8bAAAVAc8AABYEImTdIRUByQAAFtwhZIkhFQHMAAAW/iFkzSEVAcwAABb9IWTMIfuF84PAAIYr/QA4CMUAACFCzAAAIe7BAAAUyKUCxQAAFmkgGDshYncmHPuZ")
\ No newline at end of file
diff --git a/api/search.index/5587fc39ca.js b/api/search.index/5587fc39ca.js
deleted file mode 100644
index 11a545503..000000000
--- a/api/search.index/5587fc39ca.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAACl/RwY0R9sbgGC/QkAGMYAACGP1AAAIgHBAAAgwccAACGQKwLBAAAhUm9yIccAAFMhYSFjBAPFAAAffmJlcAGTGgAAYcIAAP8cAB1QIFEgXyBPIfsCY3T7iQ==")
\ No newline at end of file
diff --git a/api/search.index/55d647b225.js b/api/search.index/55d647b225.js
deleted file mode 100644
index ad74866b1..000000000
--- a/api/search.index/55d647b225.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McYAAAIfoB8rIQUCwAAAEoogEUghdHrzAIQBpCAAADHBAAAyHzMfcSHzAgJpc+TyHAAALB4AAIgfAADVHwAA1yAAACEBACUBzAAAFgUiZH0h4SEVAcIAABL5IW3lISOHAscAACH/YWvnAQD9DRQAyQAAIe3hIhkAAAYhAAAQ")
\ No newline at end of file
diff --git a/api/search.index/55e67e3184.js b/api/search.index/55e67e3184.js
deleted file mode 100644
index a376c4aa0..000000000
--- a/api/search.index/55e67e3184.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHRAAAWECJk+iFBxAAAjhyPHEoe/R4VAcIAABYOImT2IfMAAW0BfBMAAAWKwAAAodEcGK4hIcMAAFMfkSEFisAAABPVIRHQHAFB5msaAAB1GgAASxwAAB8eAAAoHgAAmx8AAAchAAABEAAAFQHKAAAWAyJk2SExxAAAxhzHHKggIcYAAAAiBiLzAgFk5S8eAAAlHwAAYyEAAH8hAADUIQAA4iEAABEBAPsCZG41AcUAABZbIWLEHMUcfx/7iUf/AP2nKRfEAAAhdcIAAByhywAAIcE6MAAAAQAAAAAANQAQAAAAiA//EOAUgRqKGqcaqRqxGrIasRuyG7MbCxwMHCQcOBw6HKscrBz2HPcc+Bz5HPoc+xz8HEUdUh1THVQd6x0uHgkfGx9fH2Efuh+/H1ogeCB5IHogeyCyIMMgxCDMINog8yAMIQ0hDiEXIbwh")
\ No newline at end of file
diff --git a/api/search.index/567ad8a4a6.js b/api/search.index/567ad8a4a6.js
deleted file mode 100644
index 844d5f227..000000000
--- a/api/search.index/567ad8a4a6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcgAAHAhcyGJIZAhQcIAAGcgdCC3IMEgAQMCxwAAIfPCAAAd8GJkiRkZAAAbA8wAACHMwgAAH2VhaGlVAcAAABu8IWMiDCMMNhp4GnkaAUiJ6RwAABUB0QAAFgMiZNkhFQHYAAAWESJkAiIVAdAAABYJImTrIRUByAAAFvwhZMQhFQHHAAAW+CFkuiHzgwJycxUBzAAAFvshZMMhFQHEAAAWACJk1CETiQLDAAAh1WNsFQHIAAAW9yFkuSEVAcoAABYIImTkIRUBygAAFgciZOMh+4UVAcYAABboIWSfIfOBA2VtbvsCZG/zhsAGKBUByAAAFowhZNMfFQHMAAAWBSJk4SETiQLDAAAhcWRrFQHJAAAW5iFknSEThMAITMkAACGoywAAIbfHAAAhixsC0wAAIeBmbBUB2gAAFhAiZPoh+4NnTQD+AB+kHWiUuVnxywAAIRdKZ/uaQcsAACEZwgAAHC4IaVip9AHKHwA [...]
\ No newline at end of file
diff --git a/api/search.index/5712b1aa4a.js b/api/search.index/5712b1aa4a.js
deleted file mode 100644
index ce14e7fc0..000000000
--- a/api/search.index/5712b1aa4a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHRAAAWAyJk2SEVAdgAABYRImQCIhUB0AAAFgkiZOshFQHIAAAW/CFkxCEVAccAABb4IWS6IfODAnJzFQHMAAAW+yFkwyEVAcQAABYAImTUIROJAsMAACHVY2wVAcgAABb3IWS5IRUBygAAFggiZOQhFQHKAAAWByJk4yH7hRUBxgAAFughZJ8h84EDZW1u+wJkb/OGwAYoFQHIAAAWjCFk0x8VAcwAABYFImThIROJAsMAACFxZGsVAckAABbmIWSdIROEwAhMyQAAIajLAAAht8cAACGLGwLTAAAh4GZsFQHaAAAWECJk+iH7g2dNAP4AH6QdaJS5WfHLAAAhF0pn+5pBywAAIRnCAAAcLghpWKn0AcofAAA1AsAAAKwmIUOiFlobLBwIHmt3Phq0IbUhocIAAIcbZQHBAACkECFtkByRHJIckxzNIM4gFYLFAAAUxSBOHhsCwQAAHut1eeME/QMBA8QAACDqwwA [...]
\ No newline at end of file
diff --git a/api/search.index/575ae79d0f.js b/api/search.index/575ae79d0f.js
deleted file mode 100644
index 2b9270d6c..000000000
--- a/api/search.index/575ae79d0f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAAAWBCJk3iETjALDAAAhq21vBQLFAAAUZx8Vyx9xc/uJpQHJAAAURyFm6SElAckAABbdIWSZH4ohJQHMAAAW/iFkRiHOISUBzAAAFv0hZEUhzSH7hecBAf0EMA7HAAAg4sIAAB4V4l0OAACfGgAAaxsAAAEAVQHGAAATqR9mfBxGH0cf7h8TISUBxAAAFgsiZJYh8iEjAgLHAAAhQ2Ns5AAPAACODwAAdBsAAOoeAADPIQAAAgAAe4/AAAAOXg==")
\ No newline at end of file
diff --git a/api/search.index/584dd87bf7.js b/api/search.index/584dd87bf7.js
new file mode 100644
index 000000000..998419cd3
--- /dev/null
+++ b/api/search.index/584dd87bf7.js
@@ -0,0 +1 @@
+rn_("BYbAAAAVqRqpqhwVAcsAABCJH3MdHwX9wATgAAAAZIITgxOEE4UTrBatFjZ7Gnwajxs3bBttG9Ucot0OpQHEAAAQfiBz3B8TiALCAAAfiGZzpQHGAACkfCBi0xwVAcUAABBPHHOOG/OBAm5zocMAAKkQMcsAACseLB6HHwWJwAAAEtYhEdAh8wMBcPJIHQAAngEjgwLgAAAhVmRmVQHEAAAcdSFwGxyLIechECIRIhUBwwAApFMeY64WFQHEAAAUHh9j8x0zAMAIYMgAAB8f8ioKAABqDP8AxAwFyQAAHxwJAtAAACF1xgAAHUhmbCuDxgAAHNIFmMAAACSBE6sWG4YfFQHAAAAXZCFm0hzzBgFzg5sgAAD3fQD+QE8kDc8AACDHAa8BAAA=")
\ No newline at end of file
diff --git a/api/search.index/5869694059.js b/api/search.index/5869694059.js
deleted file mode 100644
index ca29ac449..000000000
--- a/api/search.index/5869694059.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("YcAAAAkcChzjHuQeSB9JHyHDAACNG/seIcIAAKgaKR4BAgHEAAAcNmjj+w4AAIYPAAD2GwAAEBwAACEH8wD9ACUC6MgUAADPGwAAVB4AAB8fAACfHwAA6h8AAEkgAACLIAAAGSEAAAQQAAAA")
\ No newline at end of file
diff --git a/api/search.index/586c5b0bbf.js b/api/search.index/586c5b0bbf.js
deleted file mode 100644
index 5e192ae90..000000000
--- a/api/search.index/586c5b0bbf.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("UcIAAIsbRBxFHKofTCABAwHFAAAfaHKJmhsAABsCzgAAIV1hchWQwwAAFEkhNx3zBIjyiBoAACcBAQgBxQAAIONyiWEeAAChyAAAKB/nAQDAhKTJAAAfygHpGwAAO5bMAAAfbxUBwAAAIAARgR9u+QSlkMAAABokH+IOAQCEwQAAE7HldAwAAMkOAACMEwAAaxwAAHAfAADfIAAAAQUQBQLAAAAgjRzvHSqCH+cgbHIhxgAAgh/nIKHDAADzEDUBwAAAEh0bbW8PcA/GHzHGAAAPHRAdZB8XAQH9AlADwQAAE5PFAAAfZccAACIB6KIOAAB/GgAAGhsAAIUbAAC4HAAAMR0AAAEeAAB2HwAAliAAAKAAAQAABYPAAAAfZSEY5x63AQD9OEBAwgAAFOfk7wQAABYJAACXEAAAhBgAAK0cAAAKAACvD8EWp8MAACBywAAAIa7BAAAaVQ==")
\ No newline at end of file
diff --git a/api/search.index/5871e7cc09.js b/api/search.index/5871e7cc09.js
new file mode 100644
index 000000000..42c579dd1
--- /dev/null
+++ b/api/search.index/5871e7cc09.js
@@ -0,0 +1 @@
+rn_("AQUBwwAAIdtm5w0eAABTIAAAhiAAAI0gAACRIAAAliAAAHMhAAAMIgAAYAAAAbHIAACbIPMAAmRu9aUTAABDAQEAxQdlAg==")
\ No newline at end of file
diff --git a/api/search.index/588d1e7469.js b/api/search.index/588d1e7469.js
new file mode 100644
index 000000000..3dbfbead0
--- /dev/null
+++ b/api/search.index/588d1e7469.js
@@ -0,0 +1 @@
+rn_("FQHAAABEDiHHIcgh7iFspSEVAcIAABL5IW3kISOFAscAACH/YWsVAcUAAEQOIcchyCHuIWylIfsCcnNBwwAAGB/fIOAgXCExxgAAAR+fHyohBQLAAAASiSARRyF0evMAhAGjIAAAMcEAADEfMh9wIfMCAmlz5PEcAAArHgAAhx8AANQfAADWIAAAIQEAJQHMAAAWBSJkfCHgISGHAscAACH/CmFr5wEC/Q0UAMkAACHt4SIZAAAFIQAAECUBwgAAF/YgbXIbcxxHAAH9AkUEwgAAHfDHAAAfbcgAAB/MwwAAIJSDtR8AADMDA9UAACHaZWltgmQPAAAxxAAAxRzGHKcgBQLAAAASaxscdyFtcCHGAAAAIgYi8wABZOUuHgAAJB8AAGIhAAB+IQAA0yEAAOEhAAARAQDzAQFjAXUOAAD7wAQGJQHGAAAWCCJklx/jISMAAsYAACBYc3X1TgwAAAEACwJqBsgFBQLEAAA [...]
\ No newline at end of file
diff --git a/api/search.index/5945ea94cf.js b/api/search.index/5945ea94cf.js
new file mode 100644
index 000000000..d972832f5
--- /dev/null
+++ b/api/search.index/5945ea94cf.js
@@ -0,0 +1 @@
+rn_("JQHPAAAWEiJk9SEPIkUBxwAAGK4hZ6shrCHwIfEhAUblzRwAAGogAACoIAAAuCAAALwgAACvIQAAEIAQFQHIAAAQWiBzFx+hxAAAQRz7Am9ydwEA/STIAMUAACEf5f4OAACNDwAAKBwAALYcAAC+HAAAFCEAABAAEA==")
\ No newline at end of file
diff --git a/api/search.index/594cbcd636.js b/api/search.index/594cbcd636.js
deleted file mode 100644
index 5e7fb49e5..000000000
--- a/api/search.index/594cbcd636.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McAAAAYFBwU4HSHGAAAAIgYi8wABZOUvHgAAJR8AAGMhAAB/IQAA1CEAAOIhAAARAQATAALgAAAWjGNs+AsFAABfCQsALggRBnEBMAIBAPMAAmV54WQMAACYDgAAAQ==")
\ No newline at end of file
diff --git a/api/search.index/5973d8d129.js b/api/search.index/5973d8d129.js
new file mode 100644
index 000000000..0fac2a916
--- /dev/null
+++ b/api/search.index/5973d8d129.js
@@ -0,0 +1 @@
+rn_("FQHRAAAWECJk+iEjhALLAAAhwGZ3NQHFAAAWtCBishxrHmweFQLAAAAXZCEVTyFmdNIcBQLAAAAksRxqHha8IW9yoc8AAMchFYLGAAAUZCA0HXcFAcILyMIAABznxAAAIZTkkBAAAMETAACJHAAAqB8AAJsgAAACACAlhMIAABHSIDkfrB/7AmVsWwPHAAAhhWlydQ==")
\ No newline at end of file
diff --git a/api/search.index/5a64838915.js b/api/search.index/5a64838915.js
deleted file mode 100644
index c13ed8a31..000000000
--- a/api/search.index/5a64838915.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("NQHAAAASHRttbw9wD8YfMcYAAA8dEB1kHxcBAP0CUAPBAAATk8UAAB9lxwAAIgHuog4AAH8aAAAaGwAAhRsAAB8cAAC4HAAAMR0AAAEeAAAzHgAAdh8AAJ0fAACWIAAA+iAAAFEhAABuIQAAoAAAEAAQAAB1gcwAABV1IXggeSB6IHsgDCENIQ4hO8AIoMoAACDa")
\ No newline at end of file
diff --git a/api/search.index/5ab7ed48f8.js b/api/search.index/5ab7ed48f8.js
deleted file mode 100644
index 1e2241aa0..000000000
--- a/api/search.index/5ab7ed48f8.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAACkax9t7h3zAoSCyBwAAKUBwQAApBAhbc0g8weE9ZwfAAA7AAEAMAGDAGsDxQAAHwBjb3BFhMMAABFeIfQgdiGFIbchE4gCwgAAIPVzdAUCwwAAJoggqCGkMB9tcwWFwAAAGuQgF2kfBQLAAAAVMR4W/x5jbCUBxQAAFuYhZJ0h4CETg8AIRMsAACE3wgAAIYGhxgAA7B13LgDAOm/FAAAeMs8AACE4zQAAIVI7MAAAAQAASgAVAO0OAAA7DyYAsBsAABwcAACmHAAA3hwAAPUdAADHHwAApSAAALMgAACMIQAAuCEAAN0hAADmIQIA7yEAAPchAQD7IQMAACIAAAMiCAAOIgAAECICAA==")
\ No newline at end of file
diff --git a/api/search.index/5ae4517f95.js b/api/search.index/5ae4517f95.js
new file mode 100644
index 000000000..525981adb
--- /dev/null
+++ b/api/search.index/5ae4517f95.js
@@ -0,0 +1 @@
+rn_("IcAAAHca9BxlAcEAABOmGnQID4UQhhCHEIgQQRolAcAAABNlIGqzGlogpYLDAAAhUCFtIXohMcAAAJ8WoBZxG6WCxAAAFB0hgh8FAsYAABe8IRWUIWZ0+wJhZiHCAACMHO4d8wEDYWRyOzAAAAEAAHgBBgCrEwIA9xRjAIQaAQC0GlsAbx5ZAO4fWQArAsAAAB+vZHoVAcYAABYRImQCIvMBgQFjDwAAGwLgAAATn2NxIcYAAPQdpCDxwgAANxv3CQD9HEkDwQAAFpnDAAActfmHFgAAAQCPAgUDBwLrAAQABQCjAPvAAEU=")
\ No newline at end of file
diff --git a/api/search.index/5af5fd48ad.js b/api/search.index/5af5fd48ad.js
new file mode 100644
index 000000000..9d7241103
--- /dev/null
+++ b/api/search.index/5af5fd48ad.js
@@ -0,0 +1 @@
+rn_("FQHBAAAWBCJk3SETjALDAAAhqm1vBQLFAAAUZh8Vyh9xc/uJpQHJAAAURiFm6CElAckAABbcIWSYH4khJQHMAAAW/iFkRSHNISUBzAAAFv0hZEQhzCH7hecBAf0EMA7HAAAg4cIAAB4U4l0OAACfGgAAaxsAAAEAVQHGAAATqB9mexxFH0Yf7R8SISUBxAAAFgsiZJUh8iEjAgLHAAAhQmNs5AAPAACODwAAdBsAAOkeAADOIQAAAgAAe4/AAAAOXg==")
\ No newline at end of file
diff --git a/api/search.index/5b0eff57f1.js b/api/search.index/5b0eff57f1.js
new file mode 100644
index 000000000..e3b4faac3
--- /dev/null
+++ b/api/search.index/5b0eff57f1.js
@@ -0,0 +1 @@
+rn_("dQHFAAAYNyFnmBqZGpoamxrkG+Ub5hsbAuAAABqcY2dFwsGCIAAANE8gUCBOIarZISV1H5UgFXYfgBuBG4YchxwjAALFAAAc3WRzAVAMAAAxxAAA/x3lHngh+44=")
\ No newline at end of file
diff --git a/api/search.index/5b1278dac9.js b/api/search.index/5b1278dac9.js
deleted file mode 100644
index 88fe86a5f..000000000
--- a/api/search.index/5b1278dac9.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHRAAAWAyJk2SEVAdgAABYRImQCIhUB0AAAFgkiZOshFQHIAAAW/CFkxCEVAccAABb4IWS6IfODAnJzFQHMAAAW+yFkwyEVAcQAABYAImTUIROJAsMAACHVY2wVAcgAABb3IWS5IRUBygAAFggiZOQhFQHKAAAWByJk4yH7hRUBxgAAFughZJ8h84EDZW1u+wJkb/OGwAYoFQHIAAAWjCFk0x8VAcwAABYFImThIROJAsMAACFxZGsVAckAABbmIWSdIROEwAhMyQAAIajLAAAht8cAACGLGwLTAAAh4GZsFQHaAAAWECJk+iH7g2dNAP4AH6QdaJS5WfHLAAAhF0pn+5pBywAAIRnCAAAcLghpWKn0AcofAAAFAsEAABTHIRXSIXFzIwIDxAAAIO/CAAAeC2Fydu+aFgAAWRoAADscAAAdHQAAQx0AACYeAABDHgAAUx4AAO0eAABPHwAAWh8AANQfAADIIAAA0SA [...]
\ No newline at end of file
diff --git a/api/search.index/5b8468ff95.js b/api/search.index/5b8468ff95.js
new file mode 100644
index 000000000..d2bdf1711
--- /dev/null
+++ b/api/search.index/5b8468ff95.js
@@ -0,0 +1 @@
+rn_("FQHFAAAVTCFyWB8lAcMAABb3IWTgHLgh+4ZBxwAAGB/fIOAgXCEBBgLEAAAhdMgAACGtYXLmIxwAAPUcAAAaHwAAvh8AAHcgAAALIQAAFiEAAAYAMgAhxgAAsiDlIaMAwQaAywAAIXnBAAATkOUVGwAAsRwAAGoeAAB3IQAAnCEAAN8hAAAwAAAVAcsAAKizIXdWIPsCbHRzAP0hSADCAAAWjOS1EwAA3xQAAIsVAACVHwAA6h8AAABgAA==")
\ No newline at end of file
diff --git a/api/search.index/5c1143b026.js b/api/search.index/5c1143b026.js
deleted file mode 100644
index 91f518e50..000000000
--- a/api/search.index/5c1143b026.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("wcoAAIMgockAAMMgJYTFAAAhmx8HIesdWiD7hhUDxgAAIekfnCEWzyEY3yFpc3RqHqUBwQAApGMgbS4fEwQCwQAAH5ppcuTmHAAASx4AAIcfAAC+HwAAFiEAABEAAPsCY27BxQAA5x0FAsMAAMMqHxX+HnBz8wDDCGDyNg8AACkMFQHBAABEDyHIIckh7iFspiH7AmN0")
\ No newline at end of file
diff --git a/api/search.index/5c2705ef70.js b/api/search.index/5c2705ef70.js
new file mode 100644
index 000000000..fce5214a3
--- /dev/null
+++ b/api/search.index/5c2705ef70.js
@@ -0,0 +1 @@
+rn_("FQHRAAAWECJk+iFBxAAAjRyOHEke/B4VAcIAABYOImT2IfMAAW0BfBMAAAWKwAAAodAcGK0hIcMAAFIfkCEFisAAABPUIRHPHAFB5msaAAB1GgAAShwAAB4eAAAnHgAAmh8AAAYhAAABEAAAFQHKAAAWAyJk2CExxAAAxRzGHKcgIcYAAAAiBiLzAgFk5S4eAAAkHwAAYiEAAH4hAADTIQAA4SEAABEBAPsCZG41AcUAABZaIWLDHMQcfh/7iUf/AP2nKRfEAAAhdMIAABygywAAIcA6MAAAAQAAAAAANQAQAAAAiA//EOAUgRqKGqcaqRqxGrIasRuyG7MbChwLHCMcNxw5HKocqxz1HPYc9xz4HPkc+hz7HEQdUR1SHVMd6h0tHggfGh9eH2AfuR++H1kgdyB4IHkgeiCxIMIgwyDLINkg8iALIQwhDSEWIbsh")
\ No newline at end of file
diff --git a/api/search.index/5c3a80e3ad.js b/api/search.index/5c3a80e3ad.js
deleted file mode 100644
index 443482a2a..000000000
--- a/api/search.index/5c3a80e3ad.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocwAAHsh0cIAAM8bIcIAAIETqxYrAnKWqobRbnVbA8wAACHqbG11JQHIAAAW9yFk4Ry5ISUBygAAFggiZJgf5CElAcoAABYHImSXH+Mh+4UFAsQAABbGIROqIW90JQHGAAAW6CFksBqfIe8H/ZFwCcsAAB/JygAAH4c=")
\ No newline at end of file
diff --git a/api/search.index/5c7c0423a8.js b/api/search.index/5c7c0423a8.js
deleted file mode 100644
index 45fe47d87..000000000
--- a/api/search.index/5c7c0423a8.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McUAAHMbdRx2HCUBxgAAFhAiZMEh+iHzgQJldyHAAAAaHlgfJZDCAAAk1CBJIX4bNx1BxQAAUB1RHYAfzh/7/QAgCw==")
\ No newline at end of file
diff --git a/api/search.index/5d182f08f6.js b/api/search.index/5d182f08f6.js
new file mode 100644
index 000000000..f79940a04
--- /dev/null
+++ b/api/search.index/5d182f08f6.js
@@ -0,0 +1 @@
+rn_("ccEAAAMfBx+zH7QfNiE3Ia4hocIAACUhsccAADQfpQHCAAAX0SBtrBuhxwAAqh+hwwAAeRvzAMCMAQHEEAAA84OO")
\ No newline at end of file
diff --git a/api/search.index/5d2b0d6a17.js b/api/search.index/5d2b0d6a17.js
deleted file mode 100644
index c4ddc1e02..000000000
--- a/api/search.index/5d2b0d6a17.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUHqmxAAAHgbAAB9GwAAOR4AAAMfAAAIHwAADh8AALQfAADMHwAANyEAAK8hAAAAABABAQBFAcIAABRiIXScE9gUJiEnIbHHAAA1H6UBwgAAF9IgbawboccAAKsfocMAAHkb8wDAjAEBxBAAAPuO")
\ No newline at end of file
diff --git a/api/search.index/5e100697c0.js b/api/search.index/5e100697c0.js
deleted file mode 100644
index 199c0a205..000000000
--- a/api/search.index/5e100697c0.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocYAABUfBQLIAAAXYSETUiFlcGWCwAAAFRQfiQ+dGsocyxwQHxEfAQCEwQAAE7HldAwAAMkOAACMEwAAaxwAAHAfAADfIAAAAQUQQcIAALgcAR52H5Yg+wJkbb8B/WEABsIAABwe")
\ No newline at end of file
diff --git a/api/search.index/5e468657bf.js b/api/search.index/5e468657bf.js
deleted file mode 100644
index 218610908..000000000
--- a/api/search.index/5e468657bf.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ockAAIchFQHDAAAWESJkAiLzAogBahoAAFMAj8MAABvkwAAAIUPSwg4AAKExxgAARBxFHEwgBQLAAACsyCFG7B/tH+wgEiFjZqHDAACfGvsCbW7r/QFABcIAABxy")
\ No newline at end of file
diff --git a/api/search.index/5e55cde44e.js b/api/search.index/5e55cde44e.js
new file mode 100644
index 000000000..fed85e908
--- /dev/null
+++ b/api/search.index/5e55cde44e.js
@@ -0,0 +1 @@
+rn_("McUAANkfoCChICUBwgAAFhIiZPUhDyIVAcgAAKSZIW19IfOBAnJ0JQHGAACkOSFt+yCWIbMAwghIzAAAIXM7MAAAAQAAkgADAAIPAAAJEZAA1R4AAA==")
\ No newline at end of file
diff --git a/api/search.index/5edfdb96df.js b/api/search.index/5edfdb96df.js
deleted file mode 100644
index a15c1b3cf..000000000
--- a/api/search.index/5edfdb96df.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHKAAAW+yFkIiHDIRsCxQAAHEFjcgUCwAAAN9cf2B8IIaLIHG9wIwUCywAAIYVwc/SzIAAAMwESABMAYwADxQAAHBxkZWkB+gQAAA==")
\ No newline at end of file
diff --git a/api/search.index/5f8adcef2a.js b/api/search.index/5f8adcef2a.js
deleted file mode 100644
index a68b1b7c0..000000000
--- a/api/search.index/5f8adcef2a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocIAAGEcBYbAAAARwxAaqh8FAsQAABdMIBnRIGNwAQEB4QAAFLlz6PEOAAC6EAAAWBwAAF8cAACXHAAAnxwAAG4eAADAHwAAnyAAAAgREREQS8ACgcMAACGGxwAAHxo1AccAABOpH2Z8HEYfRx8hwwAAmxy9IaWBwgAAE3gbtxRLwAKEygAAIEvFAAAdRKHHAABcIAUCwQAAtrYfELkQY3ZBxwAAKCEpIWYhZyEBAP7A5iVPwgAAIWXDAAAdKhxd2GUcGDu1H1cAlR4ffV9dbOi3T7GKIIHHAAAd8niMb35NwwAAGjZmGIK5kQ/FeB5yxQAAHuU288arpUojWHRtOzAAAAEAAAkCBgDhBAAA/QUOAQMPAACPEAAAmhH2AOcUAAA=")
\ No newline at end of file
diff --git a/api/search.index/5fc5c841f0.js b/api/search.index/5fc5c841f0.js
new file mode 100644
index 000000000..414f6197f
--- /dev/null
+++ b/api/search.index/5fc5c841f0.js
@@ -0,0 +1 @@
+rn_("pQHFAAAVbiFj9yAVAckAABa1IWI4IaODwgxAzwAAId/gAAAdNRUByQAAFuUhZJwhE4TACEzJAAAhp8sAACG2xwAAIYr7AmZsFQHaAAAWECJk+iH7gw==")
\ No newline at end of file
diff --git a/api/search.index/60098707e7.js b/api/search.index/60098707e7.js
new file mode 100644
index 000000000..274654a78
--- /dev/null
+++ b/api/search.index/60098707e7.js
@@ -0,0 +1 @@
+rn_("QcMAAKIWWhsrHAceJQHFAAAYQiFj6R7OIRUBwwAAGmghdw0cJQHPAAAWEiJk9SEPIiUBxwAAGK4hZ6wh8SHzgwJscDUBwwAAFu8hZNQg1SCwIfsCa3IFlMAAAEU+HD8cHh0fHRG4HCHGAAArHAceIcIAALocyxz7wAGge/0BQEHBAAAhXhUBwQAApGofbe0d8wKEgsccAAClAcEAAKQPIW3MIPMHhPWbHwAAOwABADABgwChwgAAyRxVAcEAABRGIWa4H+gfmyHoIekhUwb9AIEHyAAAISPFAAAhzscAACHeAWkeAAChzAAAJSEFAsAAALXIIBYCH250JQHEAAAW+yFkISHCIfOCAmJpFQHGAAAWWiFifh/zBAFjg7EbAAAhywAAkSCWICHDAABcHGEf+8ACUDUBwQAApGIgbf8eLR8uHxMEA8EAAB+ZyQAAIWdpcnflDBwAAOUcAABKHgAAhh8AAL0fAAAVIQAAARA [...]
\ No newline at end of file
diff --git a/api/search.index/60319b134c.js b/api/search.index/60319b134c.js
new file mode 100644
index 000000000..09bdc13b1
--- /dev/null
+++ b/api/search.index/60319b134c.js
@@ -0,0 +1 @@
+rn_("BQLBAAAUxiEV0SFxcyMBA8QAACDuwgAAHgphcnbvmhYAAFkaAAA6HAAAHB0AAEIdAAAlHgAAQh4AAFIeAADsHgAATh8AAFkfAADTHwAAxyAAANAgAAAjIQAAKSEAAA0xADARAAAA")
\ No newline at end of file
diff --git a/api/search.index/606c625853.js b/api/search.index/606c625853.js
new file mode 100644
index 000000000..401eec527
--- /dev/null
+++ b/api/search.index/606c625853.js
@@ -0,0 +1 @@
+rn_("IcMAAGEgoCEFAsQAACF0IAghFUMhZXIzBcABKMEAAB5O5HUbAABFHAAAehwAACcdAADsIQAAEQAAMcAAANwbVR9WH6HGAACSIDHFAADOH88fUyHTAcAKSMMAABxy5cIbAAABHgAATx4AADsfAACKHwAA3h8AAAAQVfsCbnQ=")
\ No newline at end of file
diff --git a/api/search.index/6081664311.js b/api/search.index/6081664311.js
deleted file mode 100644
index 8a379fd01..000000000
--- a/api/search.index/6081664311.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McEAAD0hgiGDIRUBwAAAHnkhcL8T84OKCQLQAAAheOYAABs3aXAF/cMCABoAABiSIRy8IRJ0IBhzISMFAsUAAB8XYnABoRYAAPsDYW11")
\ No newline at end of file
diff --git a/api/search.index/61338ca7e2.js b/api/search.index/61338ca7e2.js
new file mode 100644
index 000000000..dcde370be
--- /dev/null
+++ b/api/search.index/61338ca7e2.js
@@ -0,0 +1 @@
+rn_("BQLBAAAVoB8WjCBmbjUBwAAAFFchcE0fkCBrIQWJwAAAF40hEb8gocQAADkhBYnEAAAS1iER0CEjhQLgAAAhVmRmBQLEAAAWxSETqSFvdBsCzQAAIelob2c2AMAP68QAAB7LwgAAIOjXAAAiDcMAACE/5rYQAADQHgAA2B4AAHsgAADSIAAA+yAAAJYhAAAhAAAA")
\ No newline at end of file
diff --git a/api/search.index/617130f9fe.js b/api/search.index/617130f9fe.js
new file mode 100644
index 000000000..21aecb81f
--- /dev/null
+++ b/api/search.index/617130f9fe.js
@@ -0,0 +1 @@
+rn_("RQHEAACm/SFkRCFFIcwhzSEbhcwAACDYFQHBAAAWBCJk3SETggLDAAAhqm1vK4XCAAAbexUBxQAAFmogZigcFQHCAAAWAyJk2CH7Aml0ocIAADseodYAANkhMcYAAAEfnx8qIQUCwAAAEokgEUchdHrzAIQBoyAAADHBAAAxHzIfcCHzAgJpc+TxHAAAKx4AAIcfAADUHwAA1iAAACEBACUBzAAAFgUiZHwh4CEVAcIAABL5IW3kISOHAscAACH/YWvnAQL9DRQAyQAAIe3hIhkAAAUhAAAQJQHCAAAX9iBtchtzHEMB/QJFBMIAAB3wxwAAH23IAAAfzMMAACCUg7UfAABzAP0QUQDgAAAOaeE6DwAAZA8AAAErAsEAABN7b3QBg8ACCswAACGkxgAAINfPAAAhv/MCAXeDkg8AACUBxAAAFgsiZJUh8iEJAtAAACFTzQAAIOVlbQEDAcIAABybajswAAABAADqAAI [...]
\ No newline at end of file
diff --git a/api/search.index/61ab36a0b6.js b/api/search.index/61ab36a0b6.js
new file mode 100644
index 000000000..5eacdd45d
--- /dev/null
+++ b/api/search.index/61ab36a0b6.js
@@ -0,0 +1 @@
+rn_("FQHGAAAg0R8TIXJ3H0MBwARK0QAAIZfCAAAfsMcAAB5d5zUKAACACgAAkRoAAHEcAAD+HAAATyAAAF4gAABOIQAAAQARAA==")
\ No newline at end of file
diff --git a/api/search.index/623cde8e0a.js b/api/search.index/623cde8e0a.js
deleted file mode 100644
index 739a649f4..000000000
--- a/api/search.index/623cde8e0a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHFAAAWbCBiLxwGHSUB0AAAFgkiZKQh6yElAcgAABb8IWQjIcQhJQHHAAAW+CFk/iC6IfODAnJzJQHMAAAW+yFkIiHDISUBxAAAFgAiZGMh1CETiQLDAAAh1WNsFQHIAAAW9yFkuSEVAcoAABYIImTkIRUBygAAFgciZOMh+4UVAcYAABboIWSfIfOBA2VtbvsCZG83BwD9HJARwwAAG4PGAAAdPAH4DgAA")
\ No newline at end of file
diff --git a/api/search.index/6286e0e5cf.js b/api/search.index/6286e0e5cf.js
new file mode 100644
index 000000000..76c883cd1
--- /dev/null
+++ b/api/search.index/6286e0e5cf.js
@@ -0,0 +1 @@
+rn_("oc4AAIYhQcMAAFMeVB6eH0ggFYHHAAAc9CHwICMDwQCgwQAAIYPFAAAfZQEEIQAA+wJobzMAA8wAACEeY2V0Aa4WAAA=")
\ No newline at end of file
diff --git a/api/search.index/62e31a7fa5.js b/api/search.index/62e31a7fa5.js
deleted file mode 100644
index 9537a0510..000000000
--- a/api/search.index/62e31a7fa5.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("RQHFAAAVbyFj+CD5IAAhASFlAsAAABT/IORrHGN07w5iDzYdPh1cHl0e4cUAAGUcJQHFAAAmtiG7IWI5IT4hpQHBAAAUzyBm0CGlAcIAABT2IGbWIfuJMcUAADMenR+eH/MDwgAJ80kdAACeAf4BFQHCAAAU6h9jOR8jgQLBAAAccWVsIwADzgAAIeDHAAAfn2VmcvPuDgAAZxICAOcDAMIOSMQAABxk4VQMAABrDgAABxuGyQAAH2o=")
\ No newline at end of file
diff --git a/api/search.index/6315f501a9.js b/api/search.index/6315f501a9.js
new file mode 100644
index 000000000..c9f3ab686
--- /dev/null
+++ b/api/search.index/6315f501a9.js
@@ -0,0 +1 @@
+rn_("FQHBAAAWBCJk3SETggLDAAAhqm1vQcYAAPsh/CEJIgoiEwACwgAAGIRkcjowAAABAAAAAAAiABAAAAAzCjQKqxCsEK0QCBG7FMEcwhwpHV0e0h6hH6Ifox+kH6Ufph+nH3wgfSDIIMkgyiDxICEhIiFfIWwhoyGmIcIhwyHqIeshIcIAAOQOJA9bwAFgxAAAHfJr/REBAcIAABt7zgAAIN0=")
\ No newline at end of file
diff --git a/api/search.index/6354ca15dd.js b/api/search.index/6354ca15dd.js
new file mode 100644
index 000000000..2593d66be
--- /dev/null
+++ b/api/search.index/6354ca15dd.js
@@ -0,0 +1 @@
+rn_("BQLAAAAVjhYZNB5hbQUCwAAAGTMeGgAfY2wFAsAAABPBIaPiHmx1McgAADwhgSGCIfOCiSOBlMAAABqD0wD90RABxQAAH2nLAAAfbNEAACFSAbkQAAA=")
\ No newline at end of file
diff --git a/api/search.index/63ca153dbb.js b/api/search.index/63ca153dbb.js
deleted file mode 100644
index 61eb7b808..000000000
--- a/api/search.index/63ca153dbb.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcAAAKUhwCGhxgAAPR8VAcQAABNpIG5hGwUCwAAAE8IhYwkcChzjHuQeSB9JH2x1McgAAD0hgiGDIfuJ1wEA/TSAAsUAAB885FYKAAAzDAAA6hsAAEodAABWHgAAAAVQGwLCAAAcY2V0")
\ No newline at end of file
diff --git a/api/search.index/63ccabdae0.js b/api/search.index/63ccabdae0.js
deleted file mode 100644
index 13adbdfbc..000000000
--- a/api/search.index/63ccabdae0.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUuJqSAAABsDwgAAIN/HAAAgcm9yeQUCwAAAwxgcEgUdZWwFAsAAABYnHhNoG3J1ocIAACEeNQHEAAAWqCBjgRpfH7IgGwLgAAAWjnN0ocYAAC0dpx0A/gRHOALPAAAhbsUAACISxQAAIFnS9SEAABo=")
\ No newline at end of file
diff --git a/api/search.index/63e139fefb.js b/api/search.index/63e139fefb.js
deleted file mode 100644
index 397760c3d..000000000
--- a/api/search.index/63e139fefb.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQIBwgAAHLRt5rgTAABrHwAAex8AAGMgAAAQIQAAOiEAAJohAAAREREQpQHGAACkfSBi1BwVAcUAABBQHHOOG/vAAMQbA8kAACDQ4AAAHfZhZXM=")
\ No newline at end of file
diff --git a/api/search.index/6421290a80.js b/api/search.index/6421290a80.js
deleted file mode 100644
index cdb7e6601..000000000
--- a/api/search.index/6421290a80.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ccEAAAQfCB+0H7UfNyE4Ia8hocIAACYhsccAADUfpQHCAAAX0iBtrBuhxwAAqx+hwwAAeRvzAMCMAQHEEAAA84OO")
\ No newline at end of file
diff --git a/api/search.index/64874fb465.js b/api/search.index/64874fb465.js
new file mode 100644
index 000000000..4e4e0ee78
--- /dev/null
+++ b/api/search.index/64874fb465.js
@@ -0,0 +1 @@
+rn_("IcAAAJoQxRAFicUAADg8IYEhgiEUwSEFAsAAABRMH2ILHQwd9CAJIQohsSFveSUBygAAFgsiZJUh8iEFjMAAABIZIRnSIRMIAsIAACFjZmnkmiAAAOwgAABLIQAAWCEAAJMhAAABAQAxxQAAoSG9Ib4hNYTAAAATmSBvIHAgAyExwgAAPx5AHhwhQcEAAEkfSh9LH10hBQLAAAAlbCCSIRKYIHV58wH9AgED6DAcAAAGHQAA7x4AAIgfAAB1IAAA8yAAAHUhAACEIQAAtiEAAAQAAAAA+wJlbPMAA3B0dQFWGgAAxQHBAAAVeB93yhslAcAAAKSZIW06H30h+wJkblUBxAAAEH4gc8AcCB7cH90fxiAxxQAA2R+gIKEgJQHEAAAWEiJk9SEPIvMBAnB3AdUeAADnHAL+QEwFC8cAACCXwQAAG4TFAAAhTeHaFAAAjCEAADH7Aml5")
\ No newline at end of file
diff --git a/api/search.index/6487bb2e2f.js b/api/search.index/6487bb2e2f.js
new file mode 100644
index 000000000..5af711138
--- /dev/null
+++ b/api/search.index/6487bb2e2f.js
@@ -0,0 +1 @@
+rn_("ZQHBAAAl5R54IWznDugODhzFHMYcpyAVAcAAACIvHEMdcoIPVQPBAAC14Ry6yCBDmBuZGzMd0B9vc3QyDzMPNA81D88ebwHEEGTKAAAhYcEAACFh")
\ No newline at end of file
diff --git a/api/search.index/649e04fdeb.js b/api/search.index/649e04fdeb.js
new file mode 100644
index 000000000..021d12053
--- /dev/null
+++ b/api/search.index/649e04fdeb.js
@@ -0,0 +1 @@
+rn_("scIAAKMbpQHFAAAVbiFj9yAVAckAABa1IWI4IVOFwghA4AAAHTXzgQJkaRWEwQAAp0UdKBsTAALgAAAfr2Fz9c4QAAC1CY4AIgQ+AiHBAAB3GvQcfwD+QAIAisAAABDITYs7/sI=")
\ No newline at end of file
diff --git a/api/search.index/64f1057184.js b/api/search.index/64f1057184.js
new file mode 100644
index 000000000..45523a30e
--- /dev/null
+++ b/api/search.index/64f1057184.js
@@ -0,0 +1 @@
+rn_("FQHFAAAWZyBiJBwFAsAAABRKIBwfIWN0JQHMAAAWCiJkpiHrIQFDiT4bAAD7AmFm8wABdAEfDAAABQLAAAAWSSERTSAzcQcBhMAwYcIAACCOwQAAIEzEAAAg+cIAACCPKwLFAAAfsGN0G4nFAAAgVzcFAP0UgRbOAAAhYcsAACD6xwAAH7EBdQ8AAA==")
\ No newline at end of file
diff --git a/api/search.index/6592b7e5ad.js b/api/search.index/6592b7e5ad.js
deleted file mode 100644
index 35c2c9833..000000000
--- a/api/search.index/6592b7e5ad.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocMAABceIcMAABYeZCEFjMAAACLNHBohKSUh0yHjAP0hgQDEAAAg8OpwGgAAPxwAAB8dAABHHgAAUR8AAFsfAACbIAAA7SAAAEwhAABZIQAAlCEAAAEREQEBACOCAsIAAB0kZnMrAskAAB+9ZnQ=")
\ No newline at end of file
diff --git a/api/search.index/65dcad4c8f.js b/api/search.index/65dcad4c8f.js
new file mode 100644
index 000000000..3026311a0
--- /dev/null
+++ b/api/search.index/65dcad4c8f.js
@@ -0,0 +1 @@
+rn_("FQPAAAAWSSG1UR0RTSAzZXHPIEHIAABvIXIhiCGPIUHCAABmIHMgtiDAIAUCwAAAHPMhHcshYWgHHIL9HwAexgAAIY7HAAAhkccAACGY1AAAIgHJAAAh18sAACG7KwLBAAAhUW9yIcUAAB4c+SAFAsAAABwIHyAiHpghY2QhxwAAUiFgIQUCwQAAHOEgE98cbW4BRvqvHAAAAQBWAhAAWwAMAEsAoQCBAHAAdy4A/daJE8IAACCOwQAAIEzCAAAgj8cAACE77uUOAAAlDwAAjxYAAKEWAACHGgAAjhoAAJMaAACcGgAAxRsAACYcAADDHAAAzxwAAEAdAADrHQAAfh8AABYAAAABEAEA")
\ No newline at end of file
diff --git a/api/search.index/65e70bb9c6.js b/api/search.index/65e70bb9c6.js
deleted file mode 100644
index 9d0087035..000000000
--- a/api/search.index/65e70bb9c6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAXHyEipBYpHW95JQHPAAAWEiJk9SEPIiUBxwAAGK8hZ60h8SHzhQJscCUBxAAAFvshZCIhwyETggLGAAAfA2Jp8wACaXQB4iAAAAUCwAAApSYdFSUdYXIBQOloDwAAzhwAADoeAABrIAAAqSAAALkgAAC9IAAA5iAAAC0hAACwIQAAARCAEIAjAQLAAAAfanZ54m4gAAACIQAAQyEAAAEAIcUAACcf3SChxgAAhyHDAf0VAALEAAAg3sQAABtrOjAAAAEAAAAAABMAEAAAAHwMsRSlGl0bXhtBHDYeGR+FH3cgtiDeIOAg4SDqIO8g8CBdIXUhASIhwAAAWBq1HFsExAAAHErGAAAgT2Rtb3YBBITBAAAfTuGRHwAA5R8AADMBAALMAAAhhNIAACHCYXABpxYAABsCwgAAG+RkbRUBxgAAINIfFCFyeB/zAwFwAZEaAAAbicMAAB0OFQHDAAAWESJkAiLzAYg [...]
\ No newline at end of file
diff --git a/api/search.index/669833dc2e.js b/api/search.index/669833dc2e.js
deleted file mode 100644
index cd70932f2..000000000
--- a/api/search.index/669833dc2e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAATBR4V2CBtdKHHAABVIPuDg4PADkrMAAAhpc0AACGBwAAAGzTPAAAhwMMAAB0FdQPGAAAxSxxMHB8eEtAcotEcaWxypxoLHAwcqxysHMMgxCChxQAAqBZRxgAABR+1IEEhtiG7IRMAAsQAACFvYmPpjRYAAK4aAAAbGwAAsxwAAGweAAASHwAA+CAAAAAhAAA5IQAAPiEAAAEQEBEAocIAAEob8wICbnLyjxMAAKEJJQHMAAAQ3B9zhh/GIPuGFQHRAAAWAyJk2SEVAdgAABYRImQCIvOHAnJ24cUAAE4aNQLHAAAm2x/bIBJIHWJyjBuiHNkgFcHBACgAAKS0IRKjIRa6H7Mf4cMAANEU+wJudAUDwgAAuLYfp0YfFuUeZW11KwLKAAAfG29yIccAAIsbqh/zAP4ASbQcOzAAAAEAAE0AAwCEBEkAkg8CAAseAAA=")
\ No newline at end of file
diff --git a/api/search.index/66c6b8bd6e.js b/api/search.index/66c6b8bd6e.js
deleted file mode 100644
index c95c5ba70..000000000
--- a/api/search.index/66c6b8bd6e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcMAAOwf7R/sIBIh8wABbOhfDgAAmRAAAKIQAACSEwAAnRMAAIIaAABCHAAA4BwAAG8hAACQAAAQAFUBwgAAEH8gc8EcCR7dH94fxyA7A8EAABpXZWdsBQLAAAATeh8awSFpbjv9AUkAwwAAIOLUAAAhrg==")
\ No newline at end of file
diff --git a/api/search.index/66f420dd66.js b/api/search.index/66f420dd66.js
deleted file mode 100644
index 0c9a94772..000000000
--- a/api/search.index/66f420dd66.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQPAAAAV2iAeXyEo7h8TIWVpbaHFAAChGhWEwwAAE7sgCh8FAsMAABrYIR3zIWV0IwQCxQAAIOticAFBHQAAFQHAAAAWUh5ishPzgQJudBMAAsYAAB90Y3LhKRsAAEohAACABQLAAAAUyx8SOh1wdQWGwQAAQmcfaB99H28gplAe84ECcXNRyQAAQx3tHu4e0SAqIQUCxAAAIXUgCSEVRCFlchMHAsEAAB5PYnLhRhwAACgdAAAQocQAAKUWAUSJ6xsAACHJAACJIBsh+wJjeDHGAACMIeghECIjAALBAAAd8GFk6DcaAACwGgAA0x8AAGohAACHIQAAnyEAAMEhAADKIQAA+iEAAAABEAEAMcYAAEQcRRxMIAUCwAAAo58aR+wf7R/sIBIhbW5rA8IAABxyYW9yBQLBAAAm3CDzIRSKG2NpAQD+wGesD8sAAB+CXQljtoQRkzInIml5NVryFymccLDNAAAiAQMacvw [...]
\ No newline at end of file
diff --git a/api/search.index/66fb4e4543.js b/api/search.index/66fb4e4543.js
new file mode 100644
index 000000000..cc92371ca
--- /dev/null
+++ b/api/search.index/66fb4e4543.js
@@ -0,0 +1 @@
+rn_("JQHCAAAQxRNzkRDEE1UBwQAAE6MWY8YOxw7IDrgc/R6hwwAAFh4hwwAAFR5jIQWMwAAAIswcGSEpJCHSIeMA/SGBAMQAACDv6nAaAAA+HAAAHh0AAEYeAABQHwAAWh8AAJogAADsIAAASyEAAFghAACTIQAAARERAQEAI4MCwgAAHSNmcyUBwQAAMAseDB7bH3OFH8UgFQHAAAAUnhp0JRv7A2NvcxWEwwAAE7ogCR/zAwF00ikcAADa+/0BAUg=")
\ No newline at end of file
diff --git a/api/search.index/671439b694.js b/api/search.index/671439b694.js
deleted file mode 100644
index 174bff49e..000000000
--- a/api/search.index/671439b694.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUDhTRoAAPcdAAAIBQLBAAAU4yAlDB+4IHFzBQLLAAAUxyEV0iFxc6HEAAC8HAFFidoeAABnBwL9EaEDywAAIOfGAAAfC+eZEwAAzRQAAH0cAADpHAAAYR4AAPEeAAAkHwAAMB8AABOIiAEbg8IAACFW")
\ No newline at end of file
diff --git a/api/search.index/673e34e85f.js b/api/search.index/673e34e85f.js
new file mode 100644
index 000000000..fd6e49000
--- /dev/null
+++ b/api/search.index/673e34e85f.js
@@ -0,0 +1 @@
+rn_("AUWIDxwAAKHPAACGIaHUAADJIfOBAmdzJQLLAAAXWyEVGyFiZnIfyyEFAsAAABCiIRYrHWV0BQLDAAAcbCEfpSFjZvuf")
\ No newline at end of file
diff --git a/api/search.index/67ad40adc2.js b/api/search.index/67ad40adc2.js
new file mode 100644
index 000000000..6d688d993
--- /dev/null
+++ b/api/search.index/67ad40adc2.js
@@ -0,0 +1 @@
+rn_("BZjAAADjphvHkB8hzAAAqyHwIfMAAm9yAUYKAAAhxgAAJCHSIRUBwgAAFg4iZPYh8wABbQF8EwAABYrAAACh0BwYrSEBQeV1GgAAShwAAB4eAAAnHgAAmh8AAAYhAAARAAAVAcoAABYDImTYIccGAf2DCQPEAAAhdMIAABygwQAAHM86MAAAAQAAAAAAIAAQAAAApxqpGgocCxwjHDccqhyrHPUc9hz3HPgc+Rz6HPsc6h0aH2AfuR++H1kgdyB4IHkgeiDCIMMg2SALIQwhDSEWIbshFQHCAAAS+SFt5CEjhwLHAAAh/2FrIwsCyQAAIe1hYwEFIQAAO/0IQITBAAAe68cAACFfFf3AEQEQAAATVRqklxYXLxwauR8hDGcFAP0ScQTFAAAfIMEAABsdwAAAG5Djbw8AALkUAAAeGwAAxR8AABEA")
\ No newline at end of file
diff --git a/api/search.index/681f6f35b3.js b/api/search.index/681f6f35b3.js
new file mode 100644
index 000000000..6de71625d
--- /dev/null
+++ b/api/search.index/681f6f35b3.js
@@ -0,0 +1 @@
+rn_("BQLAAAAWeyAR6h5maQEFgsMAACDE/A4dAAABAD4BtwBfAAQBBABJAAUAhwB1AAUAJQHDAABAwxvEGwUcBhxzMhtgG/sDb3V5")
\ No newline at end of file
diff --git a/api/search.index/682474ddf9.js b/api/search.index/682474ddf9.js
new file mode 100644
index 000000000..4af2eec8a
--- /dev/null
+++ b/api/search.index/682474ddf9.js
@@ -0,0 +1 @@
+rn_("NQHAAAASHRttbw9wD8UfMcYAAA4dDx1jHxcBAP0CUAPBAAATk8UAAB9kxwAAIgHuog4AAH8aAAAaGwAAhRsAAB4cAAC3HAAAMB0AAAAeAAAyHgAAdR8AAJwfAACVIAAA+SAAAFAhAABtIQAAoAAAEAAQAAB1gcwAABV0IXcgeCB5IHogCyEMIQ0hO8AIoMoAACDZ")
\ No newline at end of file
diff --git a/api/search.index/684ba46bb6.js b/api/search.index/684ba46bb6.js
new file mode 100644
index 000000000..ed7a4a0dc
--- /dev/null
+++ b/api/search.index/684ba46bb6.js
@@ -0,0 +1 @@
+rn_("FQHRAAAWECJk+iEFicQAADg8IYEhgiEUwSEbg8UAAB9pYcIAAAsdDB30IAkhCiGxIQUCwAAAQo0cjhxJHvweE0wfa3BrA8IAACFhZW95JQHKAAAWCyJklSHyISHDAAAmH9wgBYzAAAASGSEZ0iETBwLCAAAhY2Zp5JogAADsIAAASyEAAFghAACTIQAAAQEA+wJhcjHFAAChIb0hviE1hMAAABOZIG8gcCADITHCAAA/HkAeHCFBwQAASR9KH0sfXSEFAsAAACVsIJIhEpggdXnzAf0CAQPoMBwAAAYdAADvHgAAiB8AAHUgAADzIAAAdSEAAIQhAAC2IQAABAAAAAD7AmVsFQHCAAAWDiJk9iHzAP0AkAz2fBMAANoGtQMBAFgBdwAFAsAAAKDQHBNKIWZzG4rHAAAhrTHDAAAuHVIfkCEFg8AAADUBH58fKiEVTSEFisAAABPUIRHPHAUCwAAAEokgEUchdHrzAIQ [...]
\ No newline at end of file
diff --git a/api/search.index/687248167c.js b/api/search.index/687248167c.js
deleted file mode 100644
index 2cc5590b1..000000000
--- a/api/search.index/687248167c.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQIBwgAAHJxqOzAAAAEAAOoAAgAEDwAAkRLpAAEAAeIAABujc+6QDgAAExsAAOAbAABNHAAAoRwAACEdAADxHQAASR4AAOseAAD8HgAADR8AADIfAACZIAAAcSEAAO0hAAAREgAAAAEAAGvABgTMAAAgWA==")
\ No newline at end of file
diff --git a/api/search.index/6894b959f1.js b/api/search.index/6894b959f1.js
deleted file mode 100644
index 01ccf6dfd..000000000
--- a/api/search.index/6894b959f1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQPGAAARnCEWzyEY3yFpc3QjhgLDAAAhFmNuFQHPAAAWBCJk3iEVAckAABbdIWSKIRUBzAAAFv4hZM4hFQHMAAAW/SFkzSH7hfOEwACG+5g=")
\ No newline at end of file
diff --git a/api/search.index/689bbd5a99.js b/api/search.index/689bbd5a99.js
deleted file mode 100644
index a64593069..000000000
--- a/api/search.index/689bbd5a99.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcMAAGIgoSEFAsQAACF1IAkhFUQhZXIzBcABKMEAAB5P43UbAABGHAAAexwAACgdAAARADHAAADdG1YfVx+hxgAAkyAxxQAAzx/QH1Qh0wHACkjDAAAcc+XDGwAAAh4AAFAeAAA8HwAAix8AAN8fAAAAEFX7Am50")
\ No newline at end of file
diff --git a/api/search.index/6930c8e217.js b/api/search.index/6930c8e217.js
new file mode 100644
index 000000000..bd6818b3d
--- /dev/null
+++ b/api/search.index/6930c8e217.js
@@ -0,0 +1 @@
+rn_("RQHCAACm/SFkRCFFIcwhzSEhyQAA5R54IQWRwQAAEZcbEl0cy8EBwcQAABqMwgAAG0nDAAAag6HEAABiIBMAAuAAABpobXPkoxAAAO8UAAAsHQAA/x4AAC0fAAAFEBDbwQSFwQAAH3nIAAAcKg==")
\ No newline at end of file
diff --git a/api/search.index/6938449a0e.js b/api/search.index/6938449a0e.js
new file mode 100644
index 000000000..b408fd34b
--- /dev/null
+++ b/api/search.index/6938449a0e.js
@@ -0,0 +1 @@
+rn_("BYnAAAAXjSERvyAFicQAABLWIRHQISOFAuAAACFWZGYFAsQAABbFIROpIW90GwLNAAAh6WhvNwGGwA5pwgAAIOjXAAAiDcMAACE/xAAAIVcFicAAABeMIRG+IAWJxAAAEtUhEc8hI4UC4AAAIVRkZgUCxAAAFsQhE6ghb3QbAs0AACHoaG83AYbADmnCAAAg59cAACIMwwAAIT7EAAAhVTvACgjIAAAf0w==")
\ No newline at end of file
diff --git a/api/search.index/696630ff75.js b/api/search.index/696630ff75.js
deleted file mode 100644
index 6612f7027..000000000
--- a/api/search.index/696630ff75.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLBAAAUxyEV0iFxcyMBA8QAACDvwgAAHgthcnbvmhYAAFkaAAA7HAAAHR0AAEMdAAAmHgAAQx4AAFMeAADtHgAATx8AAFofAADUHwAAyCAAANEgAAAkIQAAKiEAAA0xADARAAAA")
\ No newline at end of file
diff --git a/api/search.index/697262d4c6.js b/api/search.index/697262d4c6.js
deleted file mode 100644
index 42d1b8e56..000000000
--- a/api/search.index/697262d4c6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("scYAALEbpYLIAAAUHiGDHyHGAAD1HaUgM4IDwwAAHLZkaXLzAAJpczswAAABAAB8AQQAHQfpADYJAAAgHAAAVR2QAAUCwAAAJ20frh8TaR9lcKWCywAAFB4hgx/zAYQ7MAAAAQAAkQACACAcAABVHZAAxQLAAAAZEx8VeR9jd8sb+wJnaTHPAAAKIQshsiEVAcUAABa6IGK6HAUCwQAAErscErkcYnTzAAF04pYTAADLFAAAUBwAAAEAIcUAALgcAR5FwsKCIAAANFAgUSBPIaraISV2H5YgFXcfgBuBG4cciBwrhsMAAB4AMcMAAH8bhhxhIBUCxAAAH+4hojweY3ImHAWJwAAAM/8cAB1fIBnRH/ccAv00mBPGAAAePsIAAByJ4p4QAADeEAAAjhsAABAA+4ahxAAAmiETAALgAAAh9G1z6WsaAAB1GgAASxwAAP0cAAAfHgAAKB4AADsfAACbHwAAByEAAH4hAAA [...]
\ No newline at end of file
diff --git a/api/search.index/69737f3109.js b/api/search.index/69737f3109.js
new file mode 100644
index 000000000..b19f56bd7
--- /dev/null
+++ b/api/search.index/69737f3109.js
@@ -0,0 +1 @@
+rn_("UcYAAAQftCBAIbUhuiHzAAFi5o0WAAAbGwAAshwAAGseAAARHwAAOCEAAD0hAAABAQAA8wMBcvKPEwAAoAkrAsEAAB+yaXI=")
\ No newline at end of file
diff --git a/api/search.index/69d906e210.js b/api/search.index/69d906e210.js
deleted file mode 100644
index 5a28c9633..000000000
--- a/api/search.index/69d906e210.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHFAAAWaCBiJRwFAsAAABRLIBwgIWN0JQHMAAAWCiJkpyHsIQFDiT4bAAD7AmFm8wABdAEfDAAABQLAAAAWSiERTiAzcQcBhMAwYcIAACCPwQAAIE3EAAAg+sIAACCQKwLFAAAfsWN0G4nFAAAgWDcFAP0UgRbOAAAhYssAACD7xwAAH7IBdQ8AAA==")
\ No newline at end of file
diff --git a/api/search.index/519341af7a.js b/api/search.index/69e5643c77.js
similarity index 67%
rename from api/search.index/519341af7a.js
rename to api/search.index/69e5643c77.js
index 33b9d5c93..104fe8d4c 100644
--- a/api/search.index/519341af7a.js
+++ b/api/search.index/69e5643c77.js
@@ -1 +1 @@
-rn_("AUE7MAAAAQAADwECAIoWAQAkGQ0BFQHGAAAWESJkAiLzAYEBYw8AADMAxAJU4AAAE5/GAAAhbccAAB8JASQMAAA=")
\ No newline at end of file
+rn_("AUE7MAAAAQAADwECAIoWAQAkGQ0BFQHGAAAWESJkAiLzAYEBYw8AADMAxAJU4AAAE5/GAAAhbMcAAB8IASQMAAA=")
\ No newline at end of file
diff --git a/api/search.index/6a094e7803.js b/api/search.index/6a094e7803.js
new file mode 100644
index 000000000..7b4529bbe
--- /dev/null
+++ b/api/search.index/6a094e7803.js
@@ -0,0 +1 @@
+rn_("ocIAAGAcBYbAAAARwxAaqR8FAsQAABdLIBnQIGNwAQEB4QAAFLlz6PEOAAC6EAAAVxwAAF4cAACWHAAAnhwAAG0eAAC/HwAAniAAAAgREREQS8ACgcMAACGFxwAAHxkhxgAApCG/IROCAtIAACGxZHUhxgAAACIGIvMEAWTlLh4AACQfAABiIQAAfiEAANMhAADhIQAAEQEAEwUCwwAAIdRjbIKxGgAAG4rBAAAaNhUCwQAAFXchE7IfZncWGSOCAsMAACF5aWwFg8AAABOGFtAtD/sCcnT7A2FydRUBwQAAFgQiZN0hE4wCwwAAIaptbwUCxQAAFGYfFcofcXP7iaUByQAAFEYhZughJQHJAAAW3CFkmB+JISUBzAAAFv4hZEUhzSElAcwAABb9IWREIcwh+4XnAQH9BDAOxwAAIOHCAAAeFOJdDgAAnxoAAGsbAAABADUBxgAAE6gfZnscRR9GHzuOwAAADl4hwwA [...]
\ No newline at end of file
diff --git a/api/search.index/6a268d8644.js b/api/search.index/6a268d8644.js
deleted file mode 100644
index 1164f913a..000000000
--- a/api/search.index/6a268d8644.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYnAAAAXjiERwCAFicQAABLXIRHRISOFAuAAACFXZGYFAsQAABbGIROqIW90GwLNAAAh6mhvNwGGwA5pwgAAIOnXAAAiDcMAACFAxAAAIVgFicAAABeNIRG/IAWJxAAAEtYhEdAhI4UC4AAAIVVkZgUCxAAAFsUhE6khb3QbAs0AACHpaG83AYbADmnCAAAg6NcAACIMwwAAIT/EAAAhVjvACgjIAAAf1A==")
\ No newline at end of file
diff --git a/api/search.index/6a46df790a.js b/api/search.index/6a46df790a.js
new file mode 100644
index 000000000..a586ab395
--- /dev/null
+++ b/api/search.index/6a46df790a.js
@@ -0,0 +1 @@
+rn_("oc4AAHofBcjCYEAAAKdbIBO8IUJeHF8clhyXHKJgHHWBxgAAFXQhdyB4IHkgeiALIQwhDSEhxgAAsiDlIfMCAmR25RUbAACxHAAAah4AAHchAACcIQAA3yEAADAAAMHKAADkHwUCwgAA4tcc5FUea3bhygAA3h+hxAAAkhv7wAhD+wJlbSHSAACrIfAhWwPNAAAhX2xvcqHDAAD1EAFCOzAAAAEAAOsAAgCTEAAAxhPqAAFA458OAACqFgAAZBwAAB8eAAAAUCUBxQAAJrUhuiFiOCE9IaUBwQAAFM4gZs8hpQHCAAAU9SBm1SH7iaHDAACqHzHFAAAyHpwfnR/zAcIADfVHGwAAAQKeAf4BAwBVAcIAABNoIG40GmEbkhuTGyIf+wNlbHhVAcQAALibIGSlE+gU6RSuHBMfGwLMAAAhpXJ0FQHBAACkah9t7R3zAoSCxxwAAKUBwQAApA8hbcwg8weE9ZsfAAA7AAE [...]
\ No newline at end of file
diff --git a/api/search.index/6a831626fe.js b/api/search.index/6a831626fe.js
new file mode 100644
index 000000000..f46d37b3e
--- /dev/null
+++ b/api/search.index/6a831626fe.js
@@ -0,0 +1 @@
+rn_("BQLAAAAXHiEipBYoHW95JQHPAAAWEiJk9SEPIiUBxwAAGK4hZ6wh8SHzhQJscCUBxAAAFvshZCEhwiETggLGAAAfAmJp8wACaXQB4SAAAAUCwAAApSUdFSQdYXIBQOloDwAAzRwAADkeAABqIAAAqCAAALggAAC8IAAA5SAAACwhAACvIQAAARCAEIAjAQLAAAAfaXZ54m0gAAABIQAAQiEAAAEAIcUAACYf3CChxgAAhiHDAf0VAALEAAAg3cQAABtrOjAAAAEAAAAAABMAEAAAAHwMsRSlGl0bXhtAHDUeGB+EH3YgtSDdIN8g4CDpIO4g7yBcIXQhASIhwAAAWBq0HFsExAAAHEnGAAAgTmRtb3YBBITBAAAfTeGQHwAA5B8AADMBAALMAAAhg9IAACHBYXABpxYAABsCwgAAG+NkbRUBxgAAINEfEyFydx/zAwFwAZEaAAAbicMAAB0NFQHDAAAWESJkAiLzAYg [...]
\ No newline at end of file
diff --git a/api/search.index/6a865a8137.js b/api/search.index/6a865a8137.js
new file mode 100644
index 000000000..6a7afcb08
--- /dev/null
+++ b/api/search.index/6a865a8137.js
@@ -0,0 +1 @@
+rn_("McUAABodGx14HxUBxgAAFq8hZhQhFQHFAAAWQCFiER8VAcAAABSKIGOuH/MDAnN3ARwfAAChxgAAySFnBQD9NAAXyAAAHxLHAAAgSMIAAB7TOzAAAAEAAD8AFgB1DAIAyw4BAIEPAACVEAAAoRAAAKYQAACGEwAAsRMAAOoUAABoFSIAiRYAAI8aAADHGwEAyhsDAJkcAAAhHQAAQR0AABoeAQAmHwAAhyAAANwgAACnIQAA")
\ No newline at end of file
diff --git a/api/search.index/6aae4b5e8e.js b/api/search.index/6aae4b5e8e.js
deleted file mode 100644
index 404b3390e..000000000
--- a/api/search.index/6aae4b5e8e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHRAAAWAyJk2SEVAdgAABYRImQCIhUB0AAAFgkiZOshFQHIAAAW/CFkxCEVAccAABb4IWS6IfODAnJzFQHMAAAW+yFkwyEVAcQAABYAImTUIROJAsMAACHVY2wVAcgAABb3IWS5IRUBygAAFggiZOQhFQHKAAAWByJk4yH7hRUBxgAAFughZJ8h84EDZW1u+wJkb/OGwAYoFQHIAAAWjCFk0x8VAcwAABYFImThIROJAsMAACFxZGsVAckAABbmIWSdIROEwAhMyQAAIajLAAAht8cAACGLGwLTAAAh4GZsFQHaAAAWECJk+iH7g2dNAP4AH6QdaJS5WfHLAAAhF0pn+5pBywAAIRnCAAAcLghpWKn0AcofAAAFAsEAABTHIRXSIXFzIwIDxAAAIO/CAAAeC2Fydu+aFgAAWRoAADscAAAdHQAAQx0AACYeAABDHgAAUx4AAO0eAABPHwAAWh8AANQfAADIIAAA0SA [...]
\ No newline at end of file
diff --git a/api/search.index/6b0170c4d1.js b/api/search.index/6b0170c4d1.js
deleted file mode 100644
index dc7905f8c..000000000
--- a/api/search.index/6b0170c4d1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHEAAAWCyJkliHyISHJAABFHS4eYwADxwAAIUNjZWzpUwoAAEkMAABtDQAAAA8AAI4PAADNEAAAwxQAAHQbAADqHgAAzyEAABMQIAAA")
\ No newline at end of file
diff --git a/api/search.index/6b50a7f552.js b/api/search.index/6b50a7f552.js
deleted file mode 100644
index 92209e42e..000000000
--- a/api/search.index/6b50a7f552.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYLBAACmyiGhEKHEAAAQIfMAAW3j8hAAAJAcAACkHAAAzSAAAAMRMcAAAJ8WoBZxGwUCxwAAF70hFZUhZnQhwgAAjRzvHfMEA2FkcjswAAABAAB4AQYAqxMCAPcUYwCEGgEAtBpbAHAeWQDvH1kA2/0NIADgAAAcIQ==")
\ No newline at end of file
diff --git a/api/search.index/6c271e00c4.js b/api/search.index/6c271e00c4.js
new file mode 100644
index 000000000..4813dad5b
--- /dev/null
+++ b/api/search.index/6c271e00c4.js
@@ -0,0 +1 @@
+rn_("ocwAAHoh0cIAAM4bIcIAAIETqxYrAi6xx8epbnVbA8wAACHpbG11JQHIAAAW9yFk4By4ISUBygAAFggiZJcf4yElAcoAABYHImSWH+Ih+4UFAsQAABbFIROpIW90JQHGAAAW5yFksBqeIe8H/ZFwCcsAAB/IygAAH4Y=")
\ No newline at end of file
diff --git a/api/search.index/6c4439efd5.js b/api/search.index/6c4439efd5.js
deleted file mode 100644
index 083ec8d16..000000000
--- a/api/search.index/6c4439efd5.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcgAAEceSB5RH1IfBQLGAACiEB8wPx1AHegecnMxxQAANBw1HBod+8AChGHIAABDHkQeRR5GHk8fUB8FAsgAADNwIHEgBCE4WSFaIZQhcHT7AmFyMcwAANUf1h/XIKcCAP04gAPgAAAPhMIAABtHwQAAGmcBrg4AALHCAAD3EPuD")
\ No newline at end of file
diff --git a/api/search.index/6c60ab593d.js b/api/search.index/6c60ab593d.js
new file mode 100644
index 000000000..0396bd5d0
--- /dev/null
+++ b/api/search.index/6c60ab593d.js
@@ -0,0 +1 @@
+rn_("ockAAIYhFQHDAAAWESJkAiLzAogBahoAAFMAj8MAABvjwAAAIULSwg4AAKExxgAAQxxEHEsgBQLAAACsxyFG6x/sH+sgESFjZqHDAACfGvsCbW7r/QFABcIAABxx")
\ No newline at end of file
diff --git a/api/search.index/6c65845a59.js b/api/search.index/6c65845a59.js
new file mode 100644
index 000000000..056ad1fde
--- /dev/null
+++ b/api/search.index/6c65845a59.js
@@ -0,0 +1 @@
+rn_("FQHLAAAWESJkAiIbAtIAACIBYXMhxQAAsBvvIQEEAcgAACEpcIn8GwAApYHIAAAV7yBaH6WBxAAAFYQfnBzzAAJjdOGAEAAA8xsAADEVgcgAABXuIFkfKwLNAAAhTWFyBQLLAAAUxiEV0SFxc/MIAXCJ8B4AAKWBxwAAFXYgHB6lAc0AABTbIWYMIiMAwADCwAAAHfXHAAAg/AF/EAAA8wLABM3hqBYAAKEaAAAR+4c=")
\ No newline at end of file
diff --git a/api/search.index/6c828101b5.js b/api/search.index/6c828101b5.js
deleted file mode 100644
index 5a76dda3b..000000000
--- a/api/search.index/6c828101b5.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcAAAJoQxRAFicUAADg9IYIhgyEUwiEFAsAAABRNH2IMHQ0d9SAKIQshsiFveSUBygAAFgsiZJYh8iEFjMAAABIaIRnTIRMIAsIAACFkZmnkmyAAAO0gAABMIQAAWSEAAJQhAAABAQAxxQAAoiG+Ib8hNYTAAAATmiBwIHEgBCExwgAAQB5BHh0hQcEAAEofSx9MH14hBQLAAAAlbSCTIRKZIHV58wH9AgED6DEcAAAHHQAA8B4AAIkfAAB2IAAA9CAAAHYhAACFIQAAtyEAAAQAAAAA+wJlbPMAA3B0dQFWGgAAxQHBAAAVeR93yxslAcAAAKSaIW07H34h+wJkblUBxAAAEH8gc8EcCR7dH94fxyAxxQAA2h+hIKIgJQHEAAAWEiJk9SEPIvMBAnB3AdYeAADnHAL+QEwFC8cAACCYwQAAG4TFAAAhTuHaFAAAjSEAADH7Aml5")
\ No newline at end of file
diff --git a/api/search.index/6d194da6c2.js b/api/search.index/6d194da6c2.js
deleted file mode 100644
index d809b2e25..000000000
--- a/api/search.index/6d194da6c2.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHGAAAW3SFkmR+KIUWEwAAAo5UbixyMHNce2B4VAcMAABCUG3MhIaHBAAD9HPMAA2luc/WBEwAAKgO5BaoAtAQlAcQAABYLImSWIfIhIwMCxwAAIUNjbOQADwAAjg8AAHQbAADqHgAAzyEAAAIAAAUDwgAAEoEfGXIhGpEhYWVzK4zAAAAcISsCxQAAHeZlcgECAcMAACHcZucOHgAAVCAAAIcgAACOIAAAkiAAAJcgAAB0IQAADCIAAGAAAAGhxwAAGx53BwD9EzEFxgAAHjnQAAAho+I3CgAAIwsAAOcdAAAAMA==")
\ No newline at end of file
diff --git a/api/search.index/6d2d118ab5.js b/api/search.index/6d2d118ab5.js
new file mode 100644
index 000000000..c81eb3af8
--- /dev/null
+++ b/api/search.index/6d2d118ab5.js
@@ -0,0 +1 @@
+rn_("oc0AACUhFQHBAAAUGB50bh/zggJlcwEBAc8AACDddItYCgAAUcIAAI8axxvIG4cgpyEVAcUAAKAFHHNgGzWBwQAAFTUeSAx9DBIbBQLAAAAUjRoSaRtma/vABCT/AP0QSUDgAAAMcw==")
\ No newline at end of file
diff --git a/api/search.index/6d5956b325.js b/api/search.index/6d5956b325.js
new file mode 100644
index 000000000..a8a496487
--- /dev/null
+++ b/api/search.index/6d5956b325.js
@@ -0,0 +1 @@
+rn_("BQLAAACl/BwY0B9sbgGC/QkAGMYAACGO1AAAIgHBAAAgwMcAACGPKwLBAAAhUW9yIccAAFIhYCFjBAPFAAAffWJlcAGTGgAAYcIAAP4c/xxPIFAgXiBOIfsCY3T7iQ==")
\ No newline at end of file
diff --git a/api/search.index/6d796172a3.js b/api/search.index/6d796172a3.js
new file mode 100644
index 000000000..5a6910eb6
--- /dev/null
+++ b/api/search.index/6d796172a3.js
@@ -0,0 +1 @@
+rn_("wcoAAIIgockAAMIgJYTFAAAhmh8GIeodWSD7hhUDxgAAIegfmyEWziEY3iFpc3RpHqUBwQAApGIgbS0fEwQCwQAAH5lpcuTlHAAASh4AAIYfAAC9HwAAFSEAABEAAPsCY27BxQAA5h0FAsMAAMMpHxX9HnBz8wDDCGDyNg8AACkMFQHBAABEDiHHIcgh7iFspSH7AmN0")
\ No newline at end of file
diff --git a/api/search.index/6d9a877671.js b/api/search.index/6d9a877671.js
deleted file mode 100644
index 7477b5fe1..000000000
--- a/api/search.index/6d9a877671.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHFAAAWbCBiLxwGHSUB0AAAFgkiZKQh6yElAcgAABb8IWQjIcQhJQHHAAAW+CFk/iC6IfODAnJzJQHMAAAW+yFkIiHDISUBxAAAFgAiZGMh1CETiQLDAAAh1WNsFQHIAAAW9yFkuSEVAcoAABYIImTkIRUBygAAFgciZOMh+4UVAcYAABboIWSfIfOBA2VtbvsCZG83BwD9HJARwwAAG4PGAAAdPAH4DgAAAQABwgAAHThi+foOAACLAAYL3AQBABUA8gB0AOQA8wABdNKlIQAAGwWJwAAApT0fEv8eAQcBwwAAIdxm5w4eAABUIAAAhyAAAI4gAACSIAAAlyAAAHQhAAAMIgAAYAAAARsCxQAAH7BjdBUBxAAAE2kgbmEbBQLAAAAVPB8mAR84H2xuBQLAAAATwiFjCRwKHOMe5B5IH0kfbHUFA8MAABiZIRK3IBiJIWN1dyMEAsUAAB9yYnABhxoAADHHAAA9IYI [...]
\ No newline at end of file
diff --git a/api/search.index/6e19bfcf4d.js b/api/search.index/6e19bfcf4d.js
new file mode 100644
index 000000000..5de18dc76
--- /dev/null
+++ b/api/search.index/6e19bfcf4d.js
@@ -0,0 +1 @@
+rn_("McYAAIsh5yEQIvMAAWToNxoAALAaAADSHwAAaSEAAIYhAACeIQAAwCEAAMkhAAD6IQAAAAEQAQATggLOAAAhXmR2")
\ No newline at end of file
diff --git a/api/search.index/6e7193fa03.js b/api/search.index/6e7193fa03.js
deleted file mode 100644
index 21f49b813..000000000
--- a/api/search.index/6e7193fa03.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHCAAAQGR5zMxqhzwAA4CAFAsAAABWhHxaNIGZuAQMBxAAAHTpy4UQaAACVIAAAgJ8D/RFBQcEAABOKxgAAIP0=")
\ No newline at end of file
diff --git a/api/search.index/6e7684557f.js b/api/search.index/6e7684557f.js
deleted file mode 100644
index 85af750d8..000000000
--- a/api/search.index/6e7684557f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocIAAEYdccEAAAQfCB+0H7UfNyE4Ia8hocIAACYhsccAADUfpQHCAAAX0iBtrBuhxwAAqx+hwwAAeRvzAMCMAQHEEAAA+44rAsUAAB09Y3QzAAPFAAAhQmFyducdDAAAPBoAAHkcAAAmHQAAAx4AAD0fAACTIAAAaCEAAAERERE=")
\ No newline at end of file
diff --git a/api/search.index/6e830b6fbe.js b/api/search.index/6e830b6fbe.js
new file mode 100644
index 000000000..d133321ff
--- /dev/null
+++ b/api/search.index/6e830b6fbe.js
@@ -0,0 +1 @@
+rn_("UcgAAAcfsx+0HzchriEjAgPEAAAgdsQAACFKYWdy69IQAACYGgAA5BsAABweAAA+HgAANB8AAD4fAADDHwAAXyAAAJ8hAACrIQAA8CEAALMhAmEAEQ==")
\ No newline at end of file
diff --git a/api/search.index/6e8804b3ab.js b/api/search.index/6e8804b3ab.js
deleted file mode 100644
index 7b104a231..000000000
--- a/api/search.index/6e8804b3ab.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQPAAAAV2iAeXyEo7h8TIWVpbaHFAAChGhWEwwAAE7sgCh8FAsMAABrYIR3zIWV0IwQCxQAAIOticAFBHQAAFQHAAAAWUh5ishPzgQJudBMAAsYAAB90Y3LhKRsAAEohAACABQLAAAAUyx8SOh1wdQWGwQAAQmcfaB99H28gplAe84ECcXNRyQAAQx3tHu4e0SAqIQUCxAAAIXUgCSEVRCFlchMHAsEAAB5PYnLhRhwAACgdAAAQocQAAKUWAUSJ6xsAACHJAACJIBshW8QCBMoAAB/MMcYAAIwh6CEQIiMAAsEAAB3wYWToNxoAALAaAADTHwAAaiEAAIchAACfIQAAwSEAAMohAAD6IQAAAAEQAQAxxgAARBxFHEwgBQLAAACjnxpH7B/tH+wgEiFtbmsDwgAAHHJhb3IFAsEAACbcIPMhFIobY2kBAP7Ab6wfywAAH4JdCWO2hBGTMiciaXk1WvJoMBJq5sQAACF [...]
\ No newline at end of file
diff --git a/api/search.index/6e8917bf2d.js b/api/search.index/6e8917bf2d.js
deleted file mode 100644
index 6c3dde293..000000000
--- a/api/search.index/6e8917bf2d.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLEAAAhdSAJIRVEIWVyEwUCwQAAHk9icuN1GwAARhwAAHscAAAoHQAAEQChxgAAkyAjAQLDAAAcc2Zw5MMbAAACHgAAPB8AAIsfAADfHwAAAAVQ+wJudA==")
\ No newline at end of file
diff --git a/api/search.index/6ea22b4c27.js b/api/search.index/6ea22b4c27.js
deleted file mode 100644
index 72b4d4538..000000000
--- a/api/search.index/6ea22b4c27.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IccAACUh0yEVAcYAABVNIXJZH0HHAAAZH+Ag4SBdIfMAAmZs47UTAACLFQAAlh8AAOsfAAAGAPOBAm1zIcEAAM0cGiEFAsAAACHeFM8gF70fbHP7AmVsocMAAH0au/0BSQHJAAAe1MUAACFl")
\ No newline at end of file
diff --git a/api/search.index/6edaa566ef.js b/api/search.index/6edaa566ef.js
deleted file mode 100644
index 22c79e388..000000000
--- a/api/search.index/6edaa566ef.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("scIAAKMbpQHFAAAVbyFj+CAVAckAABa2IWI5IVOFwghA4AAAHTbzgQJkaRWEwQAAp0YdKBsTAALgAAAfsGFz9c4QAAC1CY4AIwQ+AiHBAAB3GvUcfwD+QAIAisAAABDILK5j4js=")
\ No newline at end of file
diff --git a/api/search.index/6ee7bf0b3b.js b/api/search.index/6ee7bf0b3b.js
new file mode 100644
index 000000000..d3a4e17b5
--- /dev/null
+++ b/api/search.index/6ee7bf0b3b.js
@@ -0,0 +1 @@
+rn_("McUAADIdXh5fHkWIxAAAFw0fohPhFOIUrRwlAcAAABNlIGqzGlogpYLDAAAhUCFtIXoh8wUCbHP5hxYAAAEAjwIFAwcC6wAEAAUAowAFAsAAABQBIhYzH2N01wIA/RMREMMAACDxygAAIM/kjRAAAPoQAACSFgAAIBsAAFshAAATBAA=")
\ No newline at end of file
diff --git a/api/search.index/6eed71bbdf.js b/api/search.index/6eed71bbdf.js
new file mode 100644
index 000000000..7f13c2ae3
--- /dev/null
+++ b/api/search.index/6eed71bbdf.js
@@ -0,0 +1 @@
+rn_("ocMAABYeIcMAABUeYyEFjMAAACLMHBkhKSQh0iHjAP0hgQDEAAAg7+pwGgAAPhwAAB4dAABGHgAAUB8AAFofAACaIAAA7CAAAEshAABYIQAAkyEAAAEREQEBAEMA/SEABsEAABuRwgAAHSPDAAAangElGwAA")
\ No newline at end of file
diff --git a/api/search.index/6f06ed192c.js b/api/search.index/6f06ed192c.js
deleted file mode 100644
index 5860efcd5..000000000
--- a/api/search.index/6f06ed192c.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYTDAAATuyAKH/MEAXTSKhwAANoxwgAAxxtIHU8eFQHRAAAWDiJk9iEhwgAAYiChIfsCYXIlAcAAABDQIHOOGsYbAQUBxAAAIUty4T8eAAA/HwAABvOBAmNnIcEAAIocqR8lhMIAABHTIDofrR/7AmVsGwLHAAAhhmlyNQHNAAAWBiJkfyGAIeIhBQLDAAATISGg1x5uc/OBAmxtBQLEAABB2x91INsgCSEVRCFlcvcLAsAL6cYAACE2OzAAAAEAADQAFwDfEA8AbxsBAHUbAQCMGwAArhsAALobCABGHAEAVxwAAHscAQCiHAAAKB0AADwdAAA+HgAARh8BANkfAADuHwAAiSAAANIgAADYIAEA9yAAABMhAAAbIQAA2iEBABsCwQAAFpRhZA==")
\ No newline at end of file
diff --git a/api/search.index/6f75f48ea8.js b/api/search.index/6f75f48ea8.js
new file mode 100644
index 000000000..aa8936bec
--- /dev/null
+++ b/api/search.index/6f75f48ea8.js
@@ -0,0 +1 @@
+rn_("FQHDAAAg0R8TIXJ3HwUCwQAAFMYhFdEhcXMjBgLEAAAg7mFy5kIdAABCHgAA7B4AAE4fAABZHwAA0CAAACkhAAADEQAA+wJwdiUByAAAMAseDB7bH3OFH8Ug4cIAAGQc+wJmc/uKNQHAAAAUziBmviDPIdAhKwLAAAAe/nJzFYHIAAAV6SC7HxUB0QAAFhEiZAIi8wECZHMB+Q4AABOBAsoAACF4Y2kBAQHDAAAg9WbjshQAAOccAAApHwAA1SEAADAxocIAADwfFQHKAAAWCyJk8iExyAAAWCFZIZMhMcMAAG8gcCADIfsDcHR1JQHGAAAWEiJk9SEPIlMEA8UAACFNZW1zAYwhAADzgQJpbvsCcnTXAQD9CUgBxQAAIe/h1CAAALAhAAAQ")
\ No newline at end of file
diff --git a/api/search.index/6f82bc4df5.js b/api/search.index/6f82bc4df5.js
new file mode 100644
index 000000000..f795944fe
--- /dev/null
+++ b/api/search.index/6f82bc4df5.js
@@ -0,0 +1 @@
+rn_("scYAALEbpYLIAAAUHSGCHyHGAAD0HaQgM4IDwwAAHLVkaXLzAAJpczswAAABAAB8AQQAHQfpADYJAAAfHAAAVB2QAAUCwAAAJ2wfrR8TaB9lcKWCywAAFB0hgh/zAYQ7MAAAAQAAkQACAB8cAABUHZAAxQLAAAAZEh8VeB9jd8ob+wJnaTHPAAAJIQohsSEVAcUAABa5IGK5HAUCwQAAErocErgcYnTzAAF04pYTAADLFAAATxwAAAEAIcUAALccAB5FwsKCIAAANE8gUCBOIarZISV1H5UgFXYfgBuBG4YchxwrhsMAAB3/McMAAH8bhRxgIBUCxAAAH+4hojseY3IlHAWJwAAAM/4c/xxeIBnQH/ccAv00mBPGAAAePcIAAByI4p4QAADeEAAAjhsAABAA+4ahxAAAmSETAALgAAAh9G1z6WsaAAB1GgAAShwAAPwcAAAeHgAAJx4AADofAACaHwAABiEAAH0hAAA [...]
\ No newline at end of file
diff --git a/api/search.index/6fd7139a4f.js b/api/search.index/6fd7139a4f.js
deleted file mode 100644
index 593caaba4..000000000
--- a/api/search.index/6fd7139a4f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("QcgAAHAhcyGJIZAhQcIAAGcgdCC3IMEgBQLAAAAc8yEdzCFhaAccgv0fAB7GAAAhj8cAACGSxwAAIZnUAAAiAckAACHYywAAIbwrAsEAACFSb3I=")
\ No newline at end of file
diff --git a/api/search.index/7016ee2d06.js b/api/search.index/7016ee2d06.js
deleted file mode 100644
index 8a1d7faa7..000000000
--- a/api/search.index/7016ee2d06.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLBAAAVoR8WjSBmbjUBwAAAFFghcE4fkSBsIQWJwAAAF44hEcAgocQAADohBYnEAAAS1yER0SEjhQLgAAAhV2RmBQLEAAAWxiETqiFvdBsCzQAAIepob2c2AMAP68QAAB7MwgAAIOnXAAAiDcMAACFA5rYQAADRHgAA2R4AAHwgAADTIAAA/CAAAJchAAAhAAAA")
\ No newline at end of file
diff --git a/api/search.index/705b2e359a.js b/api/search.index/705b2e359a.js
new file mode 100644
index 000000000..a770447a7
--- /dev/null
+++ b/api/search.index/705b2e359a.js
@@ -0,0 +1 @@
+rn_("JQHGAAAW3CFkmB+JIQECAcMAACHbZucNHgAAUyAAAIYgAACNIAAAkSAAAJYgAABzIQAADCIAAGAAAAGTAP0SAQHCAAAcIMYAAB44hOYdAAA=")
\ No newline at end of file
diff --git a/api/search.index/7123c03011.js b/api/search.index/7123c03011.js
new file mode 100644
index 000000000..7bb7b2295
--- /dev/null
+++ b/api/search.index/7123c03011.js
@@ -0,0 +1 @@
+rn_("ocIAAH8WFQHEAAAWaiBmKBxrA8AAABo1ZW9yZQHBAAAWAyJkzxB+FqUgpiBHIdghKwLBAAAgiXR6ocQAAH0aIcQAABsfuyB3AQD9MCEEygAAIRgBoyAAAA==")
\ No newline at end of file
diff --git a/api/search.index/713a93a788.js b/api/search.index/713a93a788.js
new file mode 100644
index 000000000..5ecf6968d
--- /dev/null
+++ b/api/search.index/713a93a788.js
@@ -0,0 +1 @@
+rn_("JQHPAAAWEiJk9SEPIiUBxwAAGK4hZ6wh8SHzhgJscDHBAABtIAEhAiEhwQAAWBq0HAGBAswAACGD0gAAIcFhcBUBxgAAINEfEyFydx/zAwFwAZEaAAAbicMAAB0NtwMA/TRBAsYAAB9N9IMPAACEDB0BEwE=")
\ No newline at end of file
diff --git a/api/search.index/7182aa50af.js b/api/search.index/7182aa50af.js
new file mode 100644
index 000000000..cc7ba60e1
--- /dev/null
+++ b/api/search.index/7182aa50af.js
@@ -0,0 +1 @@
+rn_("FYHHAAAV6SC7H/MAiOFNGgAA9h0AAAgFAsEAABTiICULH7cgcXMFAssAABTGIRXRIXFzocQAALscAUWJ2R4AABUB0QAAFhEiZAIi5w4A/RmhA8sAACDmxgAAHwrq+Q4AAIcTAACZEwAAvBMAAM0UAAB8HAAA6BwAAGAeAADwHgAAIx8AAC8fAAAAEDiIgBA=")
\ No newline at end of file
diff --git a/api/search.index/71d42f16db.js b/api/search.index/71d42f16db.js
deleted file mode 100644
index c3cf4e3c3..000000000
--- a/api/search.index/71d42f16db.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLCAACiXxyiYRxzeSHSAACsIfAhGwLJAAAgs2xyJQHFAAAmtiG7IWI5IT4hpQHBAAAUzyBm0CGlAcIAABT2IGbWIfuJocMAAKsfMcUAADMenR+eH/MCwgAN80kdAACeAf4BFQHLAAAWECJk+iH7/QFBAQ==")
\ No newline at end of file
diff --git a/api/search.index/72014d26b6.js b/api/search.index/72014d26b6.js
deleted file mode 100644
index f16a98a1a..000000000
--- a/api/search.index/72014d26b6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAAAWBCJk3iETggLDAAAhq21vQcYAAPsh/CEJIgoiEwACwgAAGIRkcjowAAABAAAAAAAiABAAAAAzCjQKqxCsEK0QCBG7FMIcwxwqHV4e0x6iH6MfpB+lH6Yfpx+oH30gfiDJIMogyyDyICIhIyFgIW0hpCGnIcMhxCHrIewhIcIAAOQOJA9bwAFgxAAAHfNr/REBAcIAABt7zgAAIN4=")
\ No newline at end of file
diff --git a/api/search.index/7231fc9838.js b/api/search.index/7231fc9838.js
new file mode 100644
index 000000000..16b43444e
--- /dev/null
+++ b/api/search.index/7231fc9838.js
@@ -0,0 +1 @@
+rn_("pQHNAAAU2yFmDCIjhsAAwsAAAB31xwAAIPwhwwAA7hSnHKUCxAAApHwgo6UgYnPTHKHHAAD8HBUBygAApJkhbX0hJQHGAACkOSFt+yCWIfOGAmZwFYHEAAAVNR4SG2vABEjCAAAWlHcJAP01wArCAAAQj8kAAB86zAAAIJHy5wQAAGIW")
\ No newline at end of file
diff --git a/api/search.index/726c1a5fdf.js b/api/search.index/726c1a5fdf.js
new file mode 100644
index 000000000..b2fcadbdd
--- /dev/null
+++ b/api/search.index/726c1a5fdf.js
@@ -0,0 +1 @@
+rn_("ockAAMIgIcEAAJofBiEjBQPEAAAhdMgAACGtYWly6SMcAAD1HAAA6h0AABofAABgHwAAvh8AAFkgAAB3IAAACyEAABYhAAAGAAADIGuHwgAAG+k=")
\ No newline at end of file
diff --git a/api/search.index/7277c4ff6f.js b/api/search.index/7277c4ff6f.js
deleted file mode 100644
index 77902d3d6..000000000
--- a/api/search.index/7277c4ff6f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcAAAOgbSiChxAAAex9jAMAIQsMAACFH68ATAABiFQAAWBoAAEwbAACnHAAAqRwAALUcAAAgHwAAuR8AAOkfAACcIQAA6SEAAAANAAAAAQ==")
\ No newline at end of file
diff --git a/api/search.index/728c74c0d4.js b/api/search.index/728c74c0d4.js
deleted file mode 100644
index 4062cb37e..000000000
--- a/api/search.index/728c74c0d4.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("pQHDAAAUgSBmxSGhwgAAhxuhxAAAECHzAAFt4/IQAACQHAAApBwAAM0gAAADERsCwAAAEKFkbhWCxQAAFMUgTh4bAsEAAB7rdXlnAQH9A0EDxAAAIOrAAAAfvcMAAB7s7ZsTAACwEwAAVBoAAGwaAABqGwAAbBsAANYcAAArHQAACh4AAJwfAAC8HwAA1x8AAAghAACLIQAAAAMBAAABANHEAADPGwUCwAAAP6IhviG/ITduIAIhAyFhciMEA8AAACCCxAAAIN9lcHMBkhoAAPcAAP0WBQDJAAAf2fKjAQAA9hQ=")
\ No newline at end of file
diff --git a/api/search.index/7296aa86d1.js b/api/search.index/7296aa86d1.js
deleted file mode 100644
index f8c1e49dd..000000000
--- a/api/search.index/7296aa86d1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYnAAAAXjSERvyAFicQAABLWIRHQISOFAuAAACFVZGYFAsQAABbFIROpIW90GwLNAAAh6WhvNwGDwA5pwgAAIOjXAAAiDMMAACE/xAAAIVY=")
\ No newline at end of file
diff --git a/api/search.index/7303ceeefb.js b/api/search.index/7303ceeefb.js
deleted file mode 100644
index 28af0300b..000000000
--- a/api/search.index/7303ceeefb.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUL5nRAAAAcGAgSiAFAAAQCQAQsAnQIlAscAABdcIRUcIWJmcx/MIRUBxAAAEzgdYosaE4ECxAAAG3xxcysCxAAAFpBjchUBwQAAFgQiZN4hE4sCwwAAIattbysCxQAAIR9sdAXAwABkAADEgyBAkBOiIb4hvyEYzx4BAAHGAAAfdHKJKRsAAAUCwQAAFGcfFcsfcXPzgwJyc78H/RHBQcYAACHf")
\ No newline at end of file
diff --git a/api/search.index/73b0df526a.js b/api/search.index/73b0df526a.js
new file mode 100644
index 000000000..1edde3dea
--- /dev/null
+++ b/api/search.index/73b0df526a.js
@@ -0,0 +1 @@
+rn_("QcgAAG8hciGIIY8hQcIAAGYgcyC2IMAgBQLAAAAc8yEdyyFhaAUCwAAAGdchF/ogbnIHHYL9HwAexgAAIY7HAAAhkccAACGY1AAAIgHLAAAhuysCwQAAIVFvcg==")
\ No newline at end of file
diff --git a/api/search.index/73d21d70d1.js b/api/search.index/73d21d70d1.js
deleted file mode 100644
index 8badb4128..000000000
--- a/api/search.index/73d21d70d1.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHFAAAVTSFyWR8lAcMAABb3IWThHLkh+4ZBxwAAGR/gIOEgXSEBBgLEAAAhdcgAACGuYXLmJBwAAPYcAAAbHwAAvx8AAHggAAAMIQAAFyEAAAYAMgAhxgAAsyDmIaMAwQaAywAAIXrBAAATkOUVGwAAshwAAGseAAB4IQAAnSEAAOAhAAAwAAAVAcsAAKi0IXdXIPsCbHRzAP0hSADCAAAWjOS1EwAA3xQAAIsVAACWHwAA6x8AAABgAA==")
\ No newline at end of file
diff --git a/api/search.index/7438820ac2.js b/api/search.index/7438820ac2.js
new file mode 100644
index 000000000..0fed1c203
--- /dev/null
+++ b/api/search.index/7438820ac2.js
@@ -0,0 +1 @@
+rn_("IcUAAFwcYR8hwQAAwBOmHAFG4jkeAADlIAAALCEAABCAswL9IAEDxAAAHB3nUgwAAFsOAACQFgAAQxoAAGIbAAAnHwAAzh8AAFMhAAARACEQ")
\ No newline at end of file
diff --git a/api/search.index/7495a88b96.js b/api/search.index/7495a88b96.js
deleted file mode 100644
index 1e6f13bc9..000000000
--- a/api/search.index/7495a88b96.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("IcYAAKUhwCETggLSAAAhsmR1BQLAAAATWB8QSRxhcwUCwwAAp2Yhop8gZHNTAMAIBsQAAB/C0qQaAAC4AUDjOgoAABAMAADJEAAA5BsAAAEw+wJ5eiHGAAAAIgYi8wQBZOUvHgAAJR8AAGMhAAB/IQAA1CEAAOIhAAARAQATBQLDAAAh1WNsgrEaAAAbisEAABo2BQLAAAATGh4QoxphcwUCwAAAFO8e4PcbaXMFAsMAAKcoIaLAH2RzFQLBAAAVeCETsx9mdxYZI4ICwwAAIXppbAWDwAAAE4YW0C0P+wJydLcPAP0hOA3gAAATjeWHAwAAsxMAAGMVAAA3GwAA/SAAAN8hAABBRgA=")
\ No newline at end of file
diff --git a/api/search.index/74eeced2d9.js b/api/search.index/74eeced2d9.js
new file mode 100644
index 000000000..5abd69907
--- /dev/null
+++ b/api/search.index/74eeced2d9.js
@@ -0,0 +1 @@
+rn_("QcQAAE8dUB1/H80fFQHRAAAWECJk+iEFicQAADg8IYEhgiEUwSEbg8UAAB9pYcIAAAsdDB30IAkhCiGxIQUCwAAAQo0cjhxJHvweE0wfa3BhwQAA5w7oDg4cxRzGHKcgVQPBAAC14Ry6yCBDmBuZGzMd0B9vc3QyDzMPNA81D88eW8QARMEAACFhBZHEAAARlxsSXRy/Af2RQEDgAAAKTCUByAAAFgsiZJUh8iEjgQLGAAAd5WVtIcMAACYf3CAFjMAAABIZIRnSIRMHAsIAACFjZmnkmiAAAOwgAABLIQAAWCEAAJMhAAABAQD7AmFyMcUAAKEhvSG+ITWEwAAAE5kgbyBwIAMhMcIAAD8eQB4cIUHBAABJH0ofSx9dIQUCwAAAJWwgkiESmCB1efMB/QIBA+gwHAAABh0AAO8eAACIHwAAdSAAAPMgAAB1IQAAhCEAALYhAAAEAAAAAPsCZWwVAcIAABYOImT2IQF [...]
\ No newline at end of file
diff --git a/api/search.index/754ada0a66.js b/api/search.index/754ada0a66.js
deleted file mode 100644
index d7f4b5ed6..000000000
--- a/api/search.index/754ada0a66.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("dQPGAAAxSxxMHB8eEtAcotEcaWxypxoLHAwcqxysHMMgxCChxQAAqBYlAc0AABDcH3OGH8YgFQHRAAAWAyJk2SEVAdgAABYRImQCIvOHAnJ2JQLHAAAm2x/bIBJIHWJyjBuiHCHHAACLG6of1wcA/gAJpAzLAAAfGwELHgAABQLBAAAUxyEV0iFxc4MA/kACkAjEAAAg78UAACHdxQAAH73CAAAeCzswAAABAAAqABQAZg8BAJoWAABZGg0AOxwDAB0dAQBDHQAA5h0AACYeAABDHgMAUx4AAO0eAQBPHwEAWh8AAJkfAADUHwAAyCAAANEgAAAkIQAAKiEAAIohAADFAsAAACeRIGwhEB4bZnM4GiHFAABdHGIfIcEAAMATpxwBRuI6HgAA5iAAAC0hAAAQgLMB/SABA8QAABwe51IMAABbDgAAkBYAAEMaAABiGwAAKB8AAM8fAABUIQAAEQAhEAEAkMQAABt05Vg [...]
\ No newline at end of file
diff --git a/api/search.index/755ec70127.js b/api/search.index/755ec70127.js
deleted file mode 100644
index 8b7d783a2..000000000
--- a/api/search.index/755ec70127.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocIAAH8WFQHEAAAWayBmKRxrA8AAABo1ZW9yZQHBAAAWAyJkzxB+FqYgpyBIIdkhKwLBAAAginR6ocQAAH0aIcQAABwfvCB3AQD9MCEEygAAIRkBpCAAAA==")
\ No newline at end of file
diff --git a/api/search.index/7580d5d1bd.js b/api/search.index/7580d5d1bd.js
new file mode 100644
index 000000000..0635e3fbc
--- /dev/null
+++ b/api/search.index/7580d5d1bd.js
@@ -0,0 +1 @@
+rn_("FQHCAAAQGB5zMxqhzwAA3yAFAsAAABWgHxaMIGZuAQMBxAAAHTly4UQaAACUIAAAgJ8D/RFBQcEAABOKxgAAIPw=")
\ No newline at end of file
diff --git a/api/search.index/75b75cc1e6.js b/api/search.index/75b75cc1e6.js
deleted file mode 100644
index 91da0a47d..000000000
--- a/api/search.index/75b75cc1e6.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLAAAAXHyEipBYpHW95ocYAACYdAUThkR8AAOUfAAAzcwDDCIjDAAAb6skAACFp5HgMAADNDgAAuxMAAMcUAAAOHAAAIgAAFYHCAAAi3CDzIVEM+wJrdA==")
\ No newline at end of file
diff --git a/api/search.index/75dd391575.js b/api/search.index/75dd391575.js
deleted file mode 100644
index 4faac6caa..000000000
--- a/api/search.index/75dd391575.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("McMAAIkbIx2SIaWEwgAAEVgh3Q4xxwAAbBttG9YcNYTGAAARIB97GnwajxsBRjswAAABAACzAAIAcB5ZAO8fWQA1AcsAABTcIWZ0IQwiDSL7AnFyYcQAAIITgxOEE4UTrBatFvcDAP0U4AzEAAAbdDowAAABAAAAAAAfABAAAABYDIAOgQ6CDoMOhA6FDoYOhw6IDokOBhFoGmUbZhujG6QbpRvEG8Ub6BsGHAccTh+KH6EfsB9KIH8gkSBsIfQh")
\ No newline at end of file
diff --git a/api/search.index/75f13bee4a.js b/api/search.index/75f13bee4a.js
new file mode 100644
index 000000000..4e4bcd29c
--- /dev/null
+++ b/api/search.index/75f13bee4a.js
@@ -0,0 +1 @@
+rn_("FQLDAAATqRwVKR5ub44hMcYAAIEaXh+xICHIAADWHMcfQcYAAIAaOh1cH10fJQHAAAAWLBxtnA4pHtcGAP4CBDQDxgAAG5HEAAAhK/L7BAAAixU=")
\ No newline at end of file
diff --git a/api/search.index/762ae4a50c.js b/api/search.index/762ae4a50c.js
new file mode 100644
index 000000000..c8ca911e2
--- /dev/null
+++ b/api/search.index/762ae4a50c.js
@@ -0,0 +1 @@
+rn_("FQHRAAAWAyJk2CEVAdgAABYRImQCIhUB0AAAFgkiZOohFQHIAAAW/CFkwyEVAccAABb4IWS5IfODAnJzFQHMAAAW+yFkwiEVAcQAABYAImTTIROJAsMAACHUY2wVAcgAABb3IWS4IRUBygAAFggiZOMhFQHKAAAWByJk4iH7hRUBxgAAFuchZJ4h84EDZW1u+wJkb/OGwAYoFQHIAAAWiyFk0h8VAcwAABYFImTgIROJAsMAACFwZGsVAckAABblIWScIROEwAhMyQAAIafLAAAhtscAACGKGwLTAAAh32ZsFQHaAAAWECJk+iH7g2dNAP4AH6QdMvLIrzrLAAAhFnvKZeKYywAAIRjCAAAcLTTdrQX8AckfAAA1AsAAAKwlIUOiFlobKxwHHmt3PhqzIbQhocIAAIcbZQHBAACkDyFtjxyQHJEckhzMIM0gFYLFAAAUxCBNHhsCwQAAHup1eeME/QMBA8QAACDpwwA [...]
\ No newline at end of file
diff --git a/api/search.index/766097701f.js b/api/search.index/766097701f.js
new file mode 100644
index 000000000..0e90a3323
--- /dev/null
+++ b/api/search.index/766097701f.js
@@ -0,0 +1 @@
+rn_("IcIAANIe8SA1AcMAAB6yIWN2HHccyx4xwQAAExsUG/AdbwH9AaEEwwAAHPTGAAAfyQUCwAAAP6EhvSG+ITdtIAEhAiFhciMDA8AAACCBxAAAIN5lcHMBkhoAAPsCYXk=")
\ No newline at end of file
diff --git a/api/search.index/766e8a506f.js b/api/search.index/766e8a506f.js
deleted file mode 100644
index fd16e6878..000000000
--- a/api/search.index/766e8a506f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQCQxAAAG3TlWAwAAIAOAABlGwAAih8AAKEfAAB/IAAACRAAIcIAAJYQvhyhxgAAeRxBwwAAOR11H2kg5CAFAsEAABWhHxaNIGZuNQHAAAAUWCFwTh+RIGwhBYnAAAAXjiERwCChxAAAOiEFicQAABLXIRHRISOFAuAAACFXZGYFAsQAABbGIROqIW90GwLNAAAh6mhvZzYBwA/rxAAAHszCAAAg6dcAACINwwAAIUDmthAAANEeAADZHgAAfCAAANMgAAD8IAAAlyEAACEAAAAFAsAAABT3IRMeIWZypQHDAAAesyFjdxyhwQAAExtjgQPDAAAc9WFpbncPAP0SsQfHAAActMIAABozOjAAAAEAAAAAACsAEAAAABQMFQwWDK8TyRTeFDQajRqQGqoaqxozG2EbkhuTG94bcRxzHJQcwRwJHiceHh8jHzofgx+EH5Efkh+TH5QfrR/dH94f5R/mH+cf6B+BIMcgzyD [...]
\ No newline at end of file
diff --git a/api/search.index/76ac07bbfe.js b/api/search.index/76ac07bbfe.js
deleted file mode 100644
index a17a5f54d..000000000
--- a/api/search.index/76ac07bbfe.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BYbAAAAVqRqpqxwVAcsAABCKH3MeHwX9wATgAAAAZIITgxOEE4UTrBatFjZ7Gnwajxs3bBttG9Ycot0OpQHEAAAQfyBz3R8TiALCAAAfiWZzpQHGAACkfSBi1BwVAcUAABBQHHOOG/OBAm5zocMAAKkQMcsAACweLR6IHwWJwAAAEtchEdEh8wMBcPJJHQAAngEjgwLgAAAhV2RmVQHEAAAcdiFwHByMIeghECIRIhUBwwAApFQeY64WFQHEAAAUHx9j9B0zAMAIYMgAAB8g8ioKAABqDP8AxAwFyQAAHx0JAtAAACF2xgAAHUlmbCuDxgAAHNMFmMAAACSBE6sWG4cfFQHAAAAXZSFm0xzzBgFzg5wgAAD3fQD+QE8kDc8AACDIAa8BAAA=")
\ No newline at end of file
diff --git a/api/search.index/76bad7d6a3.js b/api/search.index/76bad7d6a3.js
new file mode 100644
index 000000000..fba148e70
--- /dev/null
+++ b/api/search.index/76bad7d6a3.js
@@ -0,0 +1 @@
+rn_("FQHQAAAWCSJk6iEVAcgAABb8IWTDIRUBxwAAFvghZLkh84MCcnMVAcwAABb7IWTCIRUBxAAAFgAiZNMhE4kCwwAAIdRjbBUByAAAFvchZLghFQHKAAAWCCJk4yEVAcoAABYHImTiIfuFFQHGAAAW5yFkniHzgQNlbW77AmRv+8AGKA==")
\ No newline at end of file
diff --git a/api/search.index/771c47584e.js b/api/search.index/771c47584e.js
new file mode 100644
index 000000000..5f8c482ba
--- /dev/null
+++ b/api/search.index/771c47584e.js
@@ -0,0 +1 @@
+rn_("ocQAABoeJQLDAAAXWyEVGyFiZnIfyyEVAcYAABVMIXJYH0HHAAAYH98g4CBcIfMDAmZs47UTAACLFQAAlR8AAOofAAAGADWBxQAAFd0gpRpdG14b+/0hgAQ=")
\ No newline at end of file
diff --git a/api/search.index/773505a33c.js b/api/search.index/773505a33c.js
new file mode 100644
index 000000000..30598f773
--- /dev/null
+++ b/api/search.index/773505a33c.js
@@ -0,0 +1 @@
+rn_("ocoAAEcfFQHBAAAWESJkAiJByAAATx1QHX8fzR/7gyHDAACbE1QapYLBAAAhUCFtIXoh+wNhcnehxQAAGh0VAckAABZAIWIRH/OCAmZ3BQLAAAAXIBwV1B5ydNcCAP5ARBAKwwAAIULDAAATuvvuBAAAJgRMA5cCggACBO8GvAA3AS8AYgE=")
\ No newline at end of file
diff --git a/api/search.index/776a66d42c.js b/api/search.index/776a66d42c.js
new file mode 100644
index 000000000..8f704082e
--- /dev/null
+++ b/api/search.index/776a66d42c.js
@@ -0,0 +1 @@
+rn_("FQHEAAAaaCF3DRwVAcQAABpnIXcMHPsCY3RBwQAAiRA4HGUfQSFVAsEAAKTBHBVBHWJz9RT2FN4cXSCyIaHFAAD/IBUBwAAAFP4gYz0dFQHJAAAWuiFiPSHzh8IIQPsCb3ZxwQAA4RviGxUe6x6JIJkgYyH7/RBBAg==")
\ No newline at end of file
diff --git a/api/search.index/777de8eb15.js b/api/search.index/777de8eb15.js
new file mode 100644
index 000000000..394034c5d
--- /dev/null
+++ b/api/search.index/777de8eb15.js
@@ -0,0 +1 @@
+rn_("FQHAAAAUiiBjrh/zAwFzARwfAAATAALHAAAgSGZyAZUQAAArAsMAABsQYWehwwAAFh4hwwAAFR5jIQWMwAAAIswcGSEpJCHSIeMA/SGBAMQAACDv6nAaAAA+HAAAHh0AAEYeAABQHwAAWh8AAJogAADsIAAASyEAAFghAACTIQAAARERAQEAKwLCAAAdI2Zz+wJjbg==")
\ No newline at end of file
diff --git a/api/search.index/78151609ea.js b/api/search.index/78151609ea.js
deleted file mode 100644
index 2b25bbb6a..000000000
--- a/api/search.index/78151609ea.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQPAAACiFx4SMR4XtRxhb3IxwwAAFh6aIGQhBYzAAAAizRwaISklIdMhIccAADQezR4FAsYAABkSIRkTIWN2BQLAAAAUkhMdZiBvcgUCwAAAFPAgHM4fY2z3CwD9PaEOxAAAGobJAAAeN8MAABORyQAAHjg6MAAAAQAAAAAAHQAQAAAAlQGWAZcBcASAD3AalhqXGt8bPxxAHB8dIB1HHkgeUR9SH1sfXB9wIHEgmyDtIO4gBCFMIU4hWSFaIZQh")
\ No newline at end of file
diff --git a/api/search.index/78eada87f2.js b/api/search.index/78eada87f2.js
new file mode 100644
index 000000000..217c34380
--- /dev/null
+++ b/api/search.index/78eada87f2.js
@@ -0,0 +1 @@
+rn_("odYAANkhMcYAAAEfnx8qIQUCwAAAEokgEUchdHrzAIQBoyAAADHBAAAxHzIfcCHzAgJpc+TxHAAAKx4AAIcfAADUHwAA1iAAACEBACUBzAAAFgUiZHwh4CEVAcIAABL5IW3kISOHAscAACH/YWvnAQL9DRQAyQAAIe3hIhkAAAUhAAAQJQHCAAAX9iBtchtzHEMB/QJFBMIAAB3wxwAAH23IAAAfzMMAACCUg7UfAABzAP0QUQDgAAAOaeE6DwAAZA8AAAEFAsEAABjCHxOUH2F0QcAAAC8MuhPFExgeAUI7MAAAAQAA6QABAJIV6QAbicEAABypAUA7MAAAAQAA6gACAHsMAACVD+kAGwLBAAAgumR0ZwMA/SBhFsMAAB8ixAAAHinFAAAhojowAAABAAAAAAAkABAAAAD0BDQJNQn2DpEQnRC9E74TxBO2FKQWMxqVGqYaSBuYG5kbMRwyHAsdDB0oHTMd0x4JHyE [...]
\ No newline at end of file
diff --git a/api/search.index/7925474955.js b/api/search.index/7925474955.js
deleted file mode 100644
index caca99aea..000000000
--- a/api/search.index/7925474955.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQICwwAAHyPCAAAgu2Zp5bYUAACVGgAAMhwAAAofAAAiHwAAqSEAAAAQASUBxAAAFmwgYi8cBh0rAsEAAB8hZXJByAAAPxxAHB8dIB0FAsYAABkkIaLKHHBy8wACbnSClRwAAEUBxQAApv0hZEUhRiHNIc4hFQHBAAAWBCJk3iETgwLDAAAhq21vIcMAAOwULB37A2F0dyUBzwAAFgkiZKQh6yElAcEAABbdIWSZH4ohUcEAAIAPlhqXGt8bTiH7AmNlCQLgAAAPic8AACFhZnPvAf0RQUDNAAAhXWHIAAA7HDwcPRw+HB0dHh0FAscAADjtIO4gTCEaliF0dSUByAAAFvwhZCMhxCElAccAABb4IWT+ILoh84ECcnP7Amdy+wJhcgFFOzAAAAEAAJEAAgAgHAAAVR2QAKHCAAAGHkcCAP0BDgzHAAAfw8IAACGVxQAAIXfCAAAflQGAEwAAAUiJfRwAABWExAAAEdM [...]
\ No newline at end of file
diff --git a/api/search.index/7931835e85.js b/api/search.index/7931835e85.js
deleted file mode 100644
index b89911c03..000000000
--- a/api/search.index/7931835e85.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHDAAAg0h8UIXJ4HwUCwQAAFMchFdIhcXMjBgLEAAAg72Fy5kMdAABDHgAA7R4AAE8fAABaHwAA0SAAACohAAADEQAA+wJwdiUByAAAMAweDR7cH3OGH8Yg4cIAAGUc+wJmc/uKNQHAAAAUzyBmvyDQIdEhKwLAAAAe/3JzFYHIAAAV6iC8HxUB0QAAFhEiZAIi8wECZHMB+Q4AABOBAsoAACF5Y2kBAQHDAAAg9mbjshQAAOgcAAAqHwAA1iEAADAxocIAAD0fFQHKAAAWCyJk8iExyAAAWSFaIZQhMcMAAHAgcSAEIfsDcHR1JQHGAAAWEiJk9SEPIlMEA8UAACFOZW1zAY0hAADzgQJpbvsCcnTXAQD9CUgBxQAAIe/h1SAAALEhAAAQ")
\ No newline at end of file
diff --git a/api/search.index/79a8bb8d66.js b/api/search.index/79a8bb8d66.js
deleted file mode 100644
index 45d56af4d..000000000
--- a/api/search.index/79a8bb8d66.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("UcYAAAUftSBBIbYhuyHzAAFi5o0WAAAbGwAAsxwAAGweAAASHwAAOSEAAD4hAAABAQAA8wMBcvKPEwAAoQkrAsEAAB+zaXI=")
\ No newline at end of file
diff --git a/api/search.index/7a4a632850.js b/api/search.index/7a4a632850.js
deleted file mode 100644
index b7ec13ca6..000000000
--- a/api/search.index/7a4a632850.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLDAAAa2CEd8yFldCMGAsUAACDrYnABQR0AAPMFAWMBSiEAAAXAwYCCAAASmxYSnBYTlRoFAsAAABxzIBlKHmNz+wJlcwUCxQAAGewgGhshY2VLh8EAABxcxAAAHl0FAsAAABSiEB5uIW9yBQPIAAASgR8ZciEakSFhZXNLwAJByAAAHknLAAAfgDHAAACOA3QE2AT3GAD+QgegA8YAABqUzQAAIHLEAAATpuMZAAAAIgAAAIYBAACMAQAAMBA=")
\ No newline at end of file
diff --git a/api/search.index/7a6a9bf1af.js b/api/search.index/7a6a9bf1af.js
deleted file mode 100644
index 060ca832f..000000000
--- a/api/search.index/7a6a9bf1af.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("ocUAAHAfBYbAAAAkHB+8IBJ+FnHBAABNHE4cTxxJHvweDR/tIaHJAAAmIfMAA2dpc/VuDwAA5g8BAB4BQQArAsoAACGYdHmjAP0YEALIAAAg5cUAACHt8i4JAABJEg==")
\ No newline at end of file
diff --git a/api/search.index/7a7508b80a.js b/api/search.index/7a7508b80a.js
deleted file mode 100644
index 858c6ea35..000000000
--- a/api/search.index/7a7508b80a.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHHAAAW3SFkmR+KISHBAAD3DiYb+wJsbQEBAsYAAB09xQAAIUJhduV5HAAAJh0AAAMeAAA9HwAAkyAAAGghAAAREREhwAAAZQxAGqHIAAC0IQEEAsYAACC46AAAHfdyc+F9HAAAMB8AAIEhxgAAiCCoIfMBwgBC840bAABuA1wB+wJtbvuT")
\ No newline at end of file
diff --git a/api/search.index/7aa8aa46ed.js b/api/search.index/7aa8aa46ed.js
deleted file mode 100644
index 70c03950a..000000000
--- a/api/search.index/7aa8aa46ed.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("BQLBAAActCAZ/R5jc6HOAACHIRUByAAAFVEhbB0cQcMAAFQeVR6fH0kgFYHHAAAc9CHxICMDwQCgwQAAIYTFAAAfZgEFIQAA+wNob3JnBAD9FYQHyQAAHvzGAAAh7ckAAB4ryAAAHS/MAAAhHwGuFgAA")
\ No newline at end of file
diff --git a/api/search.index/7af1be5678.js b/api/search.index/7af1be5678.js
deleted file mode 100644
index 4c26f2f5f..000000000
--- a/api/search.index/7af1be5678.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQLJAAAXXCEVHCFiZnMfzCHFAsAAACeRIGwhEB4bZnM4GjHNAAAKIQshsiHzgQJkchUBxQAAFrogYrocBQLBAAASuxwSuRxidPMAAXTilhMAAMsUAABQHAAAAQAhxQAAuBwBHkXCwoIgAAA0UCBRIE8hqtohJXYfliAVdx+AG4EbhxyIHCuGwwAAHgAxwwAAfxuGHGEgFQLEAAAf7iGiPB5jciYcBYnAAAAz/xwAHV8gGdEf9xwC/TSYE8YAAB4+wgAAHIninhAAAN4QAACOGwAAEAD7A2VpdA==")
\ No newline at end of file
diff --git a/api/search.index/7b61dc450f.js b/api/search.index/7b61dc450f.js
deleted file mode 100644
index 356f8e90a..000000000
--- a/api/search.index/7b61dc450f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AQL9AgMCwwAAHSrGAAAdRMIAABybyAAAHxo7MAAAAQAA9wACAAMPAACaEfYAFQLDAAAh2R58IBN1H2luyRRb/QBBCcoAACEXwwAAE7Y=")
\ No newline at end of file
diff --git a/api/search.index/7b77097e74.js b/api/search.index/7b77097e74.js
deleted file mode 100644
index f051032dd..000000000
--- a/api/search.index/7b77097e74.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("JQHFAAAYQyFj6h7PITUBxAAAFu8hZNUg1iCxISuJwgAAHMxjAAPEAAAgtmF0deSuEwAAXBUAAD8dAADKHgAA6B4AAAIRAKHGAAAVH1WCwAAAFRQfnRrKHMscEB8RH/sCZnQbisUAAB5NIcAAAOgbSiChxAAAex9jAcAIQsMAACFH5UwbAAAgHwAAuR8AAOkfAACcIQAA6SEAANAAATUBxAAAFuchZFIgUyCeIRcZAf0niQfCAAAdIcMAACEZxAAAHunBAAAanMgAACEkxwAAId/npBAAAAERAAB7GgAAjxsAAGoeAABZIAAAJSEAANMhAAAEEAAAIcIAAPIOiBNhwwAAkhYgGyEbIhsjGyQb0wD9EVACwAAADF7BAAAWjuHjBAAADAcAAA8=")
\ No newline at end of file
diff --git a/api/search.index/7bca65e298.js b/api/search.index/7bca65e298.js
new file mode 100644
index 000000000..efbbceeb6
--- /dev/null
+++ b/api/search.index/7bca65e298.js
@@ -0,0 +1 @@
+rn_("FQHQAAAW7yFksCEVAdIAABYOImT2IRUBzwAAFgYiZOEh84YCY3AVAcwAABbmIWSdIRUBxwAAFrchZBch+wJycysCwQAAIPpjePuH")
\ No newline at end of file
diff --git a/api/search.index/7bcea53fe9.js b/api/search.index/7bcea53fe9.js
deleted file mode 100644
index 114169501..000000000
--- a/api/search.index/7bcea53fe9.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHCAACinxxz5xQlAcAAACQfH+ofY/QdOR/zAQFz4akQAADpIAAAEAWJwAAAF44hEcAgocQAADohBYnEAAAS1yER0SEjhQLgAAAhV2RmBQLEAAAWxiETqiFvdBsCzQAAIepobzcDAcAOa8IAACDp1wAAIg3DAAAhQMQAACFY0vwgAACbIwL9EAEDwwAAIR7BAAAcvuAAAB+K+Y0aAAADAE4BkwAjAIoCZQABAMMB+wJlbPsCaXI=")
\ No newline at end of file
diff --git a/api/search.index/7c0e8d201f.js b/api/search.index/7c0e8d201f.js
deleted file mode 100644
index 5e745a8cd..000000000
--- a/api/search.index/7c0e8d201f.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FQHBAAAZuR9zng5VAcQAABfEH2w8IXAhcyGJIZAhAUD4pxMAAAEAwQZeAYEBBwFLAeoBYcAAAJIWIBshGyIbIxskG/MAwCwEhS0PAAA=")
\ No newline at end of file
diff --git a/api/search.index/7c1447e9c0.js b/api/search.index/7c1447e9c0.js
new file mode 100644
index 000000000..ac4a09860
--- /dev/null
+++ b/api/search.index/7c1447e9c0.js
@@ -0,0 +1 @@
+rn_("FQHFAAAWuSBiuRwFAsEAABK6HBK4HGJ08wABdOKWEwAAyxQAAE8cAAABACHFAAC3HAAeRcLCgiAAADRPIFAgTiGq2SEldR+VIBV2H4AbgRuGHIccK4bDAAAd/zHDAAB/G4UcYCAVAsQAAB/uIaI7HmNyJRwFicAAADP+HP8cXiAZ0B/3HAD9NJgTxgAAHj3CAAAciOKeEAAA3hAAAI4bAAAQAA==")
\ No newline at end of file
diff --git a/api/search.index/7c96d1c248.js b/api/search.index/7c96d1c248.js
new file mode 100644
index 000000000..829f31eb6
--- /dev/null
+++ b/api/search.index/7c96d1c248.js
@@ -0,0 +1 @@
+rn_("FQPGAAAxuB/oH5shFs4hGN4haXN0aR6xyQAAyCAhxAAAXBxhH6UBwQAApGIgbS0fEwQCwQAAH5lpcuTlHAAASh4AAIYfAAC9HwAAFSEAABEAAPMA/RQhAOTcGwAACBwAAOIeAABHHwAAVR8AAAEREA==")
\ No newline at end of file
diff --git a/api/search.index/7cb5ec942a.js b/api/search.index/7cb5ec942a.js
new file mode 100644
index 000000000..545edcd06
--- /dev/null
+++ b/api/search.index/7cb5ec942a.js
@@ -0,0 +1 @@
+rn_("IcUAAKQhvyEFA8AAABOUIBf8IBMYHmFpeaUBzQAAFNshZgwiBQLAAAATKh0YzB9ydUUBwgAAF/YgbXIbeRt6G3McFQHCAAAU6R9jOB8lAcIAABK9HHKQGnAc84ECZWwlAcUAABnfIWalHMYfBQLBAAAR8B0XyR9pcCHHAABfIJ8hCZTIAAAhT9AAACHA84ECZmwrAssAACGDcnQBAP7ATLULXViIyqIMXbWe5GVfRIeoDRN9sbzHAAAfbX1r6QPQwAAAHfVt9Wyiq9IAACHBxwAAH54NfzToaBjToOoxMiUGZvr77g4AAJEBRgTiAYAERwRHAAEAAQCdAQIA")
\ No newline at end of file
diff --git a/api/search.index/7d58f2e922.js b/api/search.index/7d58f2e922.js
new file mode 100644
index 000000000..ed4d31edb
--- /dev/null
+++ b/api/search.index/7d58f2e922.js
@@ -0,0 +1 @@
+rn_("BYPBAAASWxwVXB4Fg8EAABJaHBVbHmv8DgDgAAAQrgEAkMQAABt05VgMAACADgAAZRsAAIkfAACgHwAAfiAAAAkQAAUCwQAAIJYQvRwTQyFmc6HGAAB4HEHDAAA4HXQfaCDjIAUCwQAAFaAfFowgZm41AcAAABRXIXBNH5AgayEFicAAABeNIRG/IKHEAAA5IQWJxAAAEtYhEdAhI4UC4AAAIVZkZgUCxAAAFsUhE6khb3QbAs0AACHpaG9nNgHAD+vEAAAey8IAACDo1wAAIg3DAAAhP+a2EAAA0B4AANgeAAB7IAAA0iAAAPsgAACWIQAAIQAAACHOAACrIfAhIcQAAGQgxCBTAP0QAAfBAAAhHcQAACCLOjAAAAEAAAAAAD4AEAAAAAkPCg8LDwwPDQ8ODw8PEA8RDxIPEw8UDxUPFg8XDxgPGQ8aDxsPHA8dDx4PHw8gDyEPIg8jD4obtBu1G7YbIhw2HK8csBw [...]
\ No newline at end of file
diff --git a/api/search.index/7de639b0d3.js b/api/search.index/7de639b0d3.js
new file mode 100644
index 000000000..3b7641d52
--- /dev/null
+++ b/api/search.index/7de639b0d3.js
@@ -0,0 +1 @@
+rn_("McMAAB4f6R+KIAUCwwAAGtchHfMhZXQjBALFAAAg6mJwAUAdAAAVAsMAABnkIKVvH2RzdxsjAALFAAAeUWJ0AbITAAD7Am50W4vEAAAhbA==")
\ No newline at end of file
diff --git a/api/search.index/7e13e215b8.js b/api/search.index/7e13e215b8.js
new file mode 100644
index 000000000..243e5e275
--- /dev/null
+++ b/api/search.index/7e13e215b8.js
@@ -0,0 +1 @@
+rn_("FQHFAAAWZyBiJBwFAsAAABRKIBwfIWN0BQLAAAAWSSERTSAzcQcBhMAwYcIAACCOwQAAIEzEAAAg+cIAACCPKwLFAAAfsGN0G4nFAAAgV5cCAP0EgRbOAAAhYcsAACD6xwAAH7EBdQ8AACMAAsMAACHbZmfnDR4AAFMgAACGIAAAjSAAAJEgAACWIAAAcyEAAAwiAABgAAAB")
\ No newline at end of file
diff --git a/api/search.index/7e1eda1197.js b/api/search.index/7e1eda1197.js
deleted file mode 100644
index 32f0dc561..000000000
--- a/api/search.index/7e1eda1197.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUDpLAwAAJgQAACREwAA7hQAAHoaAACOHAAAqBwAAAYeAABKHgAA/R4AABAAAQEANQHBAAAW7yFk1SDWILEh+wJlbg==")
\ No newline at end of file
diff --git a/api/search.index/7e25ee63c9.js b/api/search.index/7e25ee63c9.js
deleted file mode 100644
index 86d7819a5..000000000
--- a/api/search.index/7e25ee63c9.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("FYHHAAAV6iC8H/MAiOFNGgAA9x0AAAgFAsEAABTjICUMH7ggcXMFAssAABTHIRXSIXFzocQAALwcAUWJ2h4AABUB0QAAFhEiZAIi5w4A/RmhA8sAACDnxgAAHwvq+Q4AAIcTAACZEwAAvBMAAM0UAAB9HAAA6RwAAGEeAADxHgAAJB8AADAfAAAAEDiIgBA=")
\ No newline at end of file
diff --git a/api/search.index/7e5a3cebb5.js b/api/search.index/7e5a3cebb5.js
new file mode 100644
index 000000000..6a9b402fc
--- /dev/null
+++ b/api/search.index/7e5a3cebb5.js
@@ -0,0 +1 @@
+rn_("AQIBwgAAHLNt5rgTAABqHwAAeh8AAGIgAAAPIQAAOSEAAJkhAAAREREQpQHGAACkfCBi0xwVAcUAABBPHHOOG/vAAMQbA8kAACDP4AAAHfVhZXM=")
\ No newline at end of file
diff --git a/api/search.index/7e935f375d.js b/api/search.index/7e935f375d.js
new file mode 100644
index 000000000..cca5635ef
--- /dev/null
+++ b/api/search.index/7e935f375d.js
@@ -0,0 +1 @@
+rn_("dQHBAAAzlRaWFswfZmcMThpPGlAaURpSGlMaBQLAAAATJB12Ohw7HDwcPRwcHR0dIyFqcBUBxAAAEzcdYosaGwLEAAAbfHFz+4pBwgAAJR0mHZIgkyAxyAAA7CDtIEshRYTCAAARXSHzIHUhhCG2ITsDyQAAIZVwdHUjhAPAAAAfOsIAACD0aXN084ECaW6hxAAABR4lAcgAABb8IWQiIcMhJQHHAAAW+CFk/SC5IfOBwADgO8AQoMAAAByI2/0FAAnEAAAWkA==")
\ No newline at end of file
diff --git a/api/search.index/7ebf940269.js b/api/search.index/7ebf940269.js
new file mode 100644
index 000000000..8256fad2d
--- /dev/null
+++ b/api/search.index/7ebf940269.js
@@ -0,0 +1 @@
+rn_("oc0AACUhocIAAIcbZQHBAACkDyFtjxyQHJEckhzMIM0gFYLFAAAUxCBNHhsCwQAAHup1eeME/QMBA8QAACDpwwAAHuvosBMAAGwaAABsGwAA1RwAAJsfAAC7HwAA1h8AAAchAACKIQAAAxAAEAAFAsAAACOvEyYeFBshaXIlAsEAABQqHRQYHm90JxtuH8cDAP06QALGAAAhW8cAABxA+CkJAAAHFQEAzQBqAAoA3wF6AA==")
\ No newline at end of file
diff --git a/api/search.index/7ed3813a68.js b/api/search.index/7ed3813a68.js
new file mode 100644
index 000000000..d25f1c0f8
--- /dev/null
+++ b/api/search.index/7ed3813a68.js
@@ -0,0 +1 @@
+rn_("RQHDAACmByJklh+XH+Ih4yGhwwAABg8FAsAAABKJIBFHIXR68wCEAaMgAAAxwQAAMR8yH3Ah8wECaXPlhBsAAPEcAAArHgAAhx8AANQfAADWIAAAAhAQ+wNlbnM=")
\ No newline at end of file
diff --git a/api/search.index/7f3ab6298b.js b/api/search.index/7f3ab6298b.js
deleted file mode 100644
index 8495882c3..000000000
--- a/api/search.index/7f3ab6298b.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("AUDhTRoAAPcdAAAIBQLBAAAU4yAlDB+4IHFzBQLLAAAUxyEV0iFxc6HEAAC8HAFFidoeAABnBwD9EaEDywAAIOfGAAAfC+eZEwAAzRQAAH0cAADpHAAAYR4AAPEeAAAkHwAAMB8AABOIiAEbA9MAACGYwQAAHKNlaGk=")
\ No newline at end of file
diff --git a/api/search.index/7f76e77fc0.js b/api/search.index/7f76e77fc0.js
new file mode 100644
index 000000000..7c4a28ed1
--- /dev/null
+++ b/api/search.index/7f76e77fc0.js
@@ -0,0 +1 @@
+rn_("BQLDAAAiqBooHiONG/oea241AcEAABh7IGKoEDwdYh9FAsIAAGFMHE0cThxIHvseDB8lGx+7IGlzUx9UH3IgsyDzAgJrbwFxIAAA+4o=")
\ No newline at end of file
diff --git a/api/search.index/7fa0bf408b.js b/api/search.index/7fa0bf408b.js
new file mode 100644
index 000000000..942c1c04d
--- /dev/null
+++ b/api/search.index/7fa0bf408b.js
@@ -0,0 +1 @@
+rn_("JQLJAAAXWyEVGyFiZnIfyyHFAsAAACeQIGshEB4bZnM4GjHNAAAJIQohsSHzgQJkchUBxQAAFrkgYrkcBQLBAAASuhwSuBxidPMAAXTilhMAAMsUAABPHAAAAQAhxQAAtxwAHkXCwoIgAAA0TyBQIE4hqtkhJXUflSAVdh+AG4EbhhyHHCuGwwAAHf8xwwAAfxuFHGAgFQLEAAAf7iGiOx5jciUcBYnAAAAz/hz/HF4gGdAf9xwC/TSYE8YAAB49wgAAHIjinhAAAN4QAACOGwAAEAD7A2VpdA==")
\ No newline at end of file
diff --git a/api/search.index/7fd268328e.js b/api/search.index/7fd268328e.js
deleted file mode 100644
index 7f6284300..000000000
--- a/api/search.index/7fd268328e.js
+++ /dev/null
@@ -1 +0,0 @@
-rn_("YcAAAAkcChzjHuQeSB9JHyHDAACNG/seIcIAAKgaKR7zAMCAROjIFAAAzxsAAFQeAAAfHwAAnx8AAOofAABJIAAAiyAAABkhAAAEEAAAAAFDOzAAAAEAAJEAAgAgHAAAVR2QAKHEAAC3G9v9CgEEEO5mCLc=")
\ No newline at end of file
diff --git a/api/search.index/7fdacc2c01.js b/api/search.index/7fdacc2c01.js
new file mode 100644
index 000000000..2b27a8188
--- /dev/null
+++ b/api/search.index/7fdacc2c01.js
@@ -0,0 +1 @@
+rn_("McUAABodGx14HwEAAcUAACIFZPuSDgAAAQCvC9cA2AIOAOYAFAB/AgQAZAAbAsEAAB7TaHkVAcYAABavIWYUIRUBxQAAFkAhYhEfFQHAAAAUiiBjrh/zAwJzdwEcHwAApQHDAAAUIh9mqCEhwAAALA/yHaUBxgAAFIAgZsQhBYPAAACkySFVBx+zH7QfNyGuIccDAP0kYAbLAAAhbM4AACGl81AKAACdCl8JZwcA/TQAF8gAAB8SxwAAIEg7MAAAAQAAQwAYAOoEAQAECQEAdQwCAMsOAQCBDwAAlRAAAKEQAACmEAAAhhMAALETAADqFAAAaBUiAIkWAACPGgAAxxsBAMobAwCZHAAAIR0AAEEdAAAaHgEAJh8AAIcgAADcIAAApyEAAA==")
\ No newline at end of file
diff --git a/api/search.index/7fdbc0f41a.js b/api/search.index/7fdbc0f41a.js
new file mode 100644
index 000000000..9001681b2
--- /dev/null
+++ b/api/search.index/7fdbc0f41a.js
@@ -0,0 +1 @@
+rn_("pQLAAAAVJR6geBplc3wWMcUAAG0gASECIfsCanAFjMEAABTyIBy/IfuKpQHCAAAWQSF2ZyExzAAAoSG9Ib4hOwPhAAAhs2lucyOBAsEAACErYXT7AmFy")
\ No newline at end of file
diff --git a/api/search.index/desc/1c5ddc544a.js b/api/search.index/desc/1c5ddc544a.js
deleted file mode 100644
index 0c498d935..000000000
--- a/api/search.index/desc/1c5ddc544a.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("BkThe catalog type that this builder creates.AkThe associated writer type.B`The associated file writer type.AlReturn type of this visitor.0BkReturn type of this visitor on arrow field.BlReturn type of this visitor on arrow schema.BaLocal filesystem storage factory.B`HuggingFace Hub storage factory.B`HuggingFace Hub storage variant.CgMatch fields by their ID stored in Arrow field metadataAjContains the success valueCoOr predicate, for example, <code>a > 10 OR b < 20</code>.EnAn [...]
\ No newline at end of file
diff --git a/api/search.index/desc/f805b0ea2e.js b/api/search.index/desc/f805b0ea2e.js
new file mode 100644
index 000000000..9e91102d4
--- /dev/null
+++ b/api/search.index/desc/f805b0ea2e.js
@@ -0,0 +1 @@
+rd_("BkThe catalog type that this builder creates.AkThe associated writer type.B`The associated file writer type.AlReturn type of this visitor.0BkReturn type of this visitor on arrow field.BlReturn type of this visitor on arrow schema.BaLocal filesystem storage factory.B`HuggingFace Hub storage factory.B`HuggingFace Hub storage variant.CgMatch fields by their ID stored in Arrow field metadataAjContains the success valueCoOr predicate, for example, <code>a > 10 OR b < 20</code>.EnAn [...]
\ No newline at end of file
diff --git a/api/search.index/entry/01dc940117.js b/api/search.index/entry/01dc940117.js
new file mode 100644
index 000000000..673c0e29e
--- /dev/null
+++ b/api/search.index/entry/01dc940117.js
@@ -0,0 +1 @@
+rd_("Ba[8335,13,8336,3882,8539,2604,0,0]Ba[8335,13,8336,3677,5777,2604,0,0]Ba[8335,13,8336,3974,7480,2604,0,0]Ba[8335,13,8336,4351,7037,2604,0,0]Ba[8335,13,8336,4272,4245,2604,0,0]Ba[8335,13,8336,3120,7202,2604,0,0]Ba[8335,13,8336,3120,5773,2604,0,0]Ba[8335,13,8336,3120,7948,2604,0,0]Ba[8335,13,8336,3120,8419,2604,0,0]Ba[8335,13,8336,3120,8376,2604,0,0]Ba[8335,13,8336,3120,8647,2604,0,0]Ba[8335,13,8336,3120,8658,2604,0,0]Ba[8335,13,8336,3120,8052,2604,0,0]Ba[8335,13,8336,3120,8061,2604,0 [...]
\ No newline at end of file
diff --git a/api/search.index/entry/0597216bdb.js b/api/search.index/entry/0597216bdb.js
new file mode 100644
index 000000000..89155cfc3
--- /dev/null
+++ b/api/search.index/entry/0597216bdb.js
@@ -0,0 +1 @@
+rd_("An[3957,17,3958,3878,7345,0,0,0]An[3957,17,3794,3794,8296,0,0,0]An[3957,17,6940,6940,7941,0,0,0]An[3957,17,2347,4234,7225,0,0,0]An[3957,17,2347,4234,8514,0,0,0]An[3957,17,2661,3761,8038,0,0,0]0An[3957,15,1532,1532,7950,0,0,0]An[8479,15,8480,8480,8382,0,0,0]0An[8479,15,8480,8480,7360,0,0,0]An[3957,15,2661,3124,7348,0,0,0]3An[3957,15,3958,3092,3183,0,0,0]An[3957,15,1532,5346,5027,0,0,0]An[3957,15,1532,5346,7342,0,0,0]54An[8269,15,8270,3884,7224,0,0,0]An[3957,15,2347,7464,7204,0,0,0]An [...]
\ No newline at end of file
diff --git a/api/search.index/entry/28c6c4136b.js b/api/search.index/entry/28c6c4136b.js
new file mode 100644
index 000000000..46dd36634
--- /dev/null
+++ b/api/search.index/entry/28c6c4136b.js
@@ -0,0 +1 @@
+rd_("Ba[3957,13,2347,5058,7477,5025,0,0]Ba[3957,13,2347,5058,8293,5025,0,0]Ba[3957,13,2347,5058,7476,5025,0,0]Ba[3957,13,2347,5058,7346,5025,0,0]Ba[3957,13,2347,3091,7206,5025,0,0]Ba[3957,13,2347,3091,7353,5025,0,0]Ba[3957,13,2347,4320,7742,5025,0,0]Ba[3957,13,2347,4319,4256,5025,0,0]Ba[3957,13,2347,7302,7040,5025,0,0]Ba[3957,13,2347,7302,8145,5025,0,0]Ba[3957,13,2347,7302,7029,5025,0,0]Ba[3957,13,2347,7303,7042,5025,0,0]Ba[3957,13,2347,7112,6800,5025,0,0]Ba[3957,13,2347,7112,6798,5025,0 [...]
\ No newline at end of file
diff --git a/api/search.index/entry/4c84476e77.js b/api/search.index/entry/4c84476e77.js
deleted file mode 100644
index dd9d1a75b..000000000
--- a/api/search.index/entry/4c84476e77.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("Ba[3957,13,2347,5058,7478,5025,0,0]Ba[3957,13,2347,5058,8294,5025,0,0]Ba[3957,13,2347,5058,7477,5025,0,0]Ba[3957,13,2347,5058,7347,5025,0,0]Ba[3957,13,2347,3091,7207,5025,0,0]Ba[3957,13,2347,3091,7354,5025,0,0]Ba[3957,13,2347,4320,7743,5025,0,0]Ba[3957,13,2347,4319,4256,5025,0,0]Ba[3957,13,2347,7303,7040,5025,0,0]Ba[3957,13,2347,7303,8146,5025,0,0]Ba[3957,13,2347,7303,7029,5025,0,0]Ba[3957,13,2347,7304,7042,5025,0,0]Ba[3957,13,2347,7113,6800,5025,0,0]Ba[3957,13,2347,7113,6798,5025,0 [...]
\ No newline at end of file
diff --git a/api/search.index/entry/7cda7732c3.js b/api/search.index/entry/7cda7732c3.js
deleted file mode 100644
index d3e6da225..000000000
--- a/api/search.index/entry/7cda7732c3.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("Ba[8336,13,8337,3882,8540,2604,0,0]Ba[8336,13,8337,3677,5777,2604,0,0]Ba[8336,13,8337,3974,7481,2604,0,0]Ba[8336,13,8337,4351,7037,2604,0,0]Ba[8336,13,8337,4272,4245,2604,0,0]Ba[8336,13,8337,3120,7203,2604,0,0]Ba[8336,13,8337,3120,5773,2604,0,0]Ba[8336,13,8337,3120,7949,2604,0,0]Ba[8336,13,8337,3120,8420,2604,0,0]Ba[8336,13,8337,3120,8377,2604,0,0]Ba[8336,13,8337,3120,8648,2604,0,0]Ba[8336,13,8337,3120,8659,2604,0,0]Ba[8336,13,8337,3120,8053,2604,0,0]Ba[8336,13,8337,3120,8062,2604,0 [...]
\ No newline at end of file
diff --git a/api/search.index/entry/f7477d93e4.js b/api/search.index/entry/f7477d93e4.js
deleted file mode 100644
index 29ee0a87a..000000000
--- a/api/search.index/entry/f7477d93e4.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("An[3957,17,3958,3878,7346,0,0,0]An[3957,17,3794,3794,8297,0,0,0]An[3957,17,6940,6940,7942,0,0,0]An[3957,17,2347,4234,7226,0,0,0]An[3957,17,2347,4234,8515,0,0,0]An[3957,17,2661,3761,8039,0,0,0]0An[3957,15,1532,1532,7951,0,0,0]An[8480,15,8481,8481,8383,0,0,0]0An[8480,15,8481,8481,7361,0,0,0]An[3957,15,2661,3124,7349,0,0,0]3An[3957,15,3958,3092,3183,0,0,0]An[3957,15,1532,5346,5027,0,0,0]An[3957,15,1532,5346,7343,0,0,0]54An[8270,15,8271,3884,7225,0,0,0]An[3957,15,2347,7465,7205,0,0,0]An [...]
\ No newline at end of file
diff --git a/api/search.index/function/0d28bad0fd.js b/api/search.index/function/0d28bad0fd.js
new file mode 100644
index 000000000..d854fc779
--- /dev/null
+++ b/api/search.index/function/0d28bad0fd.js
@@ -0,0 +1 @@
+rd_("Bf[\"{{{BIMb{BGAn}}{BIMb{BGAn}}}JAb}\",[]]Bf[\"{{{BIMb{CLGn}}{BIMb{CLGn}}}JAb}\",[]]Bf[\"{{{BIMb{CIGj}}{BIMb{CIGj}}}JAb}\",[]]Bf[\"{{{BIMb{BGCf}}{BIMb{BGCf}}}JAb}\",[]]Bf[\"{{{BIMb{BMDn}}{BIMb{BMDn}}}JAb}\",[]]Bf[\"{{{BIMb{CLJb}}{BIMb{CLJb}}}JAb}\",[]]Bf[\"{{{BIMb{CEDf}}{BIMb{CEDf}}}JAb}\",[]]Bf[\"{{{BIMb{BMEd}}{BIMb{BMEd}}}JAb}\",[]]Bf[\"{{{BIMb{BGDl}}{BIMb{BGDl}}}JAb}\",[]]Bf[\"{{{BIMb{CIEn}}{BIMb{CIEn}}}JAb}\",[]]Cg[\"{{{BIMb{{CNAb{c}}}}{BIMb{{CNAb{c}}}}}JAbBGD`}\",[\"T\"]]Cg[\"{ [...]
\ No newline at end of file
diff --git a/api/search.index/function/17d923aa6e.js b/api/search.index/function/17d923aa6e.js
new file mode 100644
index 000000000..0a6e2a9ee
--- /dev/null
+++ b/api/search.index/function/17d923aa6e.js
@@ -0,0 +1 @@
+rd_("El[\"{{{BIMb{AHNf}}{BIMb{c}}{BIMb{I@he}}{BIMb{g}}}AHMn{}{{DBHd{c}}}{{CJGj{c}}}}\",[\"P\",\"V\",\"A\"]]El[\"{{{BIMb{BMDj}}{BIMb{c}}{BIMb{I@he}}{BIMb{g}}}AHMn{}{{DBHd{c}}}{{CJGj{c}}}}\",[\"P\",\"V\",\"A\"]]Af[\"{{CLJdJAb}CLJd}\",[]]Af[\"{{CNLhJAb}CNLh}\",[]]Bl[\"{{CHFnc}CHFn{{CFOl{}{{ILn{HNj}}}}}}\",[\"\"]]Af[\"{{CNLhIKd}CNLh}\",[]]Ag[\"{{DCF`DBJb}DCF`}\",[]]o[\"{{}BIMb}\",[]]00n[\"{{}HNl}\",[]]Ba[\"{{D@NjD@Nl}{{AHMn{D@Nj}}}}\",[]]Co[\"{{{BIMb{BAAh}}{BIMb{INj}}}{{AHMn{{CEn{{AHLn{AMNj} [...]
\ No newline at end of file
diff --git a/api/search.index/function/3450b833cc.js b/api/search.index/function/3450b833cc.js
deleted file mode 100644
index 0bf544078..000000000
--- a/api/search.index/function/3450b833cc.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("Bf[\"{{{BIMb{BGAn}}{BIMb{BGAn}}}JAb}\",[]]Bf[\"{{{BIMb{CLH`}}{BIMb{CLH`}}}JAb}\",[]]Bf[\"{{{BIMb{CIGl}}{BIMb{CIGl}}}JAb}\",[]]Bf[\"{{{BIMb{BGCf}}{BIMb{BGCf}}}JAb}\",[]]Bf[\"{{{BIMb{BMDn}}{BIMb{BMDn}}}JAb}\",[]]Bf[\"{{{BIMb{CLJd}}{BIMb{CLJd}}}JAb}\",[]]Bf[\"{{{BIMb{CEDf}}{BIMb{CEDf}}}JAb}\",[]]Bf[\"{{{BIMb{BMEd}}{BIMb{BMEd}}}JAb}\",[]]Bf[\"{{{BIMb{BGDl}}{BIMb{BGDl}}}JAb}\",[]]Bf[\"{{{BIMb{CIF`}}{BIMb{CIF`}}}JAb}\",[]]Cg[\"{{{BIMb{{CNAd{c}}}}{BIMb{{CNAd{c}}}}}JAbBGD`}\",[\"T\"]]Cg[\"{ [...]
\ No newline at end of file
diff --git a/api/search.index/function/f2c18fae46.js b/api/search.index/function/f2c18fae46.js
deleted file mode 100644
index ba8d6b95a..000000000
--- a/api/search.index/function/f2c18fae46.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("Ao[\"{{{BABf{c}}}AMNjBADl}\",[\"T\"]]El[\"{{{BIMb{AHNf}}{BIMb{c}}{BIMb{I@he}}{BIMb{g}}}AHMn{}{{DBHf{c}}}{{CJGl{c}}}}\",[\"P\",\"V\",\"A\"]]El[\"{{{BIMb{BMDj}}{BIMb{c}}{BIMb{I@he}}{BIMb{g}}}AHMn{}{{DBHf{c}}}{{CJGl{c}}}}\",[\"P\",\"V\",\"A\"]]Af[\"{{CLJfJAb}CLJf}\",[]]Af[\"{{CNLjJAb}CNLj}\",[]]Bl[\"{{CHG`c}CHG`{{CFOl{}{{ILn{HNj}}}}}}\",[\"\"]]Af[\"{{CNLjIKd}CNLj}\",[]]Ag[\"{{DCFbDBJd}DCFb}\",[]]o[\"{{}BIMb}\",[]]00n[\"{{}HNl}\",[]]Ba[\"{{D@NlD@Nn}{{AHMn{D@Nl}}}}\",[]]Co[\"{{{BIMb{BAAh [...]
\ No newline at end of file
diff --git a/api/search.index/generic_inverted_index/23a38f5a76.js b/api/search.index/generic_inverted_index/23a38f5a76.js
new file mode 100644
index 000000000..99e6fdda5
--- /dev/null
+++ b/api/search.index/generic_inverted_index/23a38f5a76.js
@@ -0,0 +1 @@
+rb_("REhjADswAAABAADZAQQABwjpAEAJ6QDCFAAAIBsEADswAAABAABoAhgAzgQAAAAGAAANBhoAKQYTAD4GAABABgQARwYAAEsGCABWBhAAaAYAAGoGDgB6BgAAfAYEAIIGBwCLBgAAjQYBAJAGBwCZBiYAwQYhAOQGDADyBhkACRGQAJES6QC/FAIAOzAAAAEAAKoDFQCcAukAJAsFACsLKgBXC7gAbw0wAKENuADLDgEAmhEmAMIRAADEEQAAxxEAAMkRFwDiEQEA5REDAOoRDAD4ESkAIxIgAEUSQQCIEgAAihIGAFYgAAA7MAAAAQAAcAIZAJgAAgB2BAEAiQQAAIsEAACgBAAAyQQAAAkFAQAECQEAKgsAABkMAQBzDgEAFw8AAC0PBADxEAAA6REAAH0TAADGEy8A9xO5ACQZDQG0GgYAvxpQAGMcAABcHwEAKCEAAGUhAQA7MAAAAQAACgInAIQEAACMBAAAzAQ [...]
\ No newline at end of file
diff --git a/api/search.index/generic_inverted_index/4fd38067ac.js b/api/search.index/generic_inverted_index/4fd38067ac.js
deleted file mode 100644
index 7ad271b1c..000000000
--- a/api/search.index/generic_inverted_index/4fd38067ac.js
+++ /dev/null
@@ -1 +0,0 @@
-rb_("REhjADswAAABAADZAQQABwjpAEAJ6QDCFAAAIBsEADswAAABAABoAhgAzgQAAAAGAAANBhoAKQYTAD4GAABABgQARwYAAEsGCABWBhAAaAYAAGoGDgB6BgAAfAYEAIIGBwCLBgAAjQYBAJAGBwCZBiYAwQYhAOQGDADyBhkACRGQAJES6QC/FAIAOzAAAAEAAKoDFQCcAukAJAsFACsLKgBXC7gAbw0wAKENuADLDgEAmhEmAMIRAADEEQAAxxEAAMkRFwDiEQEA5REDAOoRDAD4ESkAIxIgAEUSQQCIEgAAihIGAFcgAAA7MAAAAQAAcAIZAJgAAgB2BAEAiQQAAIsEAACgBAAAyQQAAAkFAQAECQEAKgsAABkMAQBzDgEAFw8AAC0PBADxEAAA6REAAH0TAADGEy8A9xO5ACQZDQG0GgYAvxpQAGQcAABdHwEAKSEAAGYhAQA7MAAAAQAACgInAIQEAACMBAAAzAQ [...]
\ No newline at end of file
diff --git a/api/search.index/name/31643d18d4.js b/api/search.index/name/31643d18d4.js
new file mode 100644
index 000000000..d71b4e74e
--- /dev/null
+++ b/api/search.index/name/31643d18d4.js
@@ -0,0 +1 @@
+rd_("aC0aR00aT000aU0b()b->bAsbEqbFsbHf00bIdbInbOkbOr00bS3000bV0bV100bV2bV3b[]beq0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bhfbidbio000bop00bor000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bs30btobu8bv1bv2bv3cAnd00cAnycArccBoxcDaycErrcGcs [...]
\ No newline at end of file
diff --git a/api/search.index/name/7a2dfd6649.js b/api/search.index/name/7a2dfd6649.js
deleted file mode 100644
index 79f6f52c9..000000000
--- a/api/search.index/name/7a2dfd6649.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("aC0aR00aT000aU0b()b->bAsbEqbFsbHf00bIdbInbOkbOr00bS3000bV0bV100bV2bV3b[]beq0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bhfbidbio000bop00bor000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bs30btobu8bv1bv2bv3cAnd00cAnycArccBoxcDaycErrcGcs [...]
\ No newline at end of file
diff --git a/api/search.index/normalizedName/cdd0bd1f4b.js b/api/search.index/normalizedName/cdd0bd1f4b.js
new file mode 100644
index 000000000..655dab89e
--- /dev/null
+++ b/api/search.index/normalizedName/cdd0bd1f4b.js
@@ -0,0 +1 @@
+rd_("ac0ar00at000au0b()b->basbeqbfsbhf00bidbinbokbor00bs3000bv0bv100bv2bv3b[]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<:9bio000bop00888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888877btobu8765cand00canycarccboxcdaycerrcgcs00cint0clz4clzoc [...]
\ No newline at end of file
diff --git a/api/search.index/normalizedName/da61c0c7ae.js b/api/search.index/normalizedName/da61c0c7ae.js
deleted file mode 100644
index 5ebf05b5b..000000000
--- a/api/search.index/normalizedName/da61c0c7ae.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("ac0ar00at000au0b()b->basbeqbfsbhf00bidbinbokbor00bs3000bv0bv100bv2bv3b[]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<:9bio000bop00888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888877btobu8765cand00canycarccboxcdaycerrcgcs00cint0clz4clzoc [...]
\ No newline at end of file
diff --git a/api/search.index/root.js b/api/search.index/root.js
index 3c17f1b60..46bf5bc22 100644
--- a/api/search.index/root.js
+++ b/api/search.index/root.js
@@ -1 +1 @@
-rr_('{"normalizedName":{"I":"VYLAAAAUtxOJARwHXwzfDgUPJQHAAAAwjwN1BNkENNcE4Q4lAcAAABDhDjacFvkhRQHAAAASYQxymgGPA3UE2QR1/MBEAgAAQRwHXwzfDgUPENcEEeAOHgAfACAAigGuEGofmCEVAcAAACGlEEocbpsBBQLAAAATWB8QSRxhcwEBAcUAABuwZDswAAABAADrAAMA4gQAAPcEAABACekABQLDAACnZiGinyBkc0UBwgAAFYIaYy4KLwowCmYKFQHAAAASYQxymgEUAcJ0ZAAAFmVmYXVsdBwcZPoEdhsAAf4IThwAJ/qB7ejEAAAfwnMA0qQaAAC4FQHRAAAWAyJk2SEVAdYAABYRImQCIjHAAACLEDwePR7zgQJmcGUBwwAAFgsiZA8hliHIIckh7iHyIUUBwwAAFgUiZEIa8h19IeEhIwACxAAAIHJhbvSJGwAAmgE8BDMA+4YJAtA [...]
\ No newline at end of file
+rr_('{"normalizedName":{"I":"VYLAAAAUtxOJARwHXwzfDgUPJQHAAAAwjwN1BNkENNcE4Q4lAcAAABDhDjacFvkhRQHAAAASYQxymgGPA3UE2QR1/MBEAgAAQRwHXwzfDgUPENcEEeAOHgAfACAAigGuEGkflyEVAcAAACGlEEkcbpsBBQLAAAATVx8QSBxhcwEBAcUAABuwZDswAAABAADrAAMA4gQAAPcEAABACekABQLDAACnZSGiniBkc0UBwgAAFYIaYy4KLwowCmYKFQHAAAASYQxymgEUAcJ0ZAAAFmVmYXVsdBscZPoEdhsAAf4IThwARUFAcirEAAAfwXMA0qQaAAC4FQHRAAAWAyJk2CEVAdYAABYRImQCIjHAAACLEDsePB7zgQJmcGUBwwAAFgsiZA4hlSHHIcgh7iHyIUUBwwAAFgUiZEIa8R18IeAhIwACxAAAIHFhbvSJGwAAmQE8BDMA+4YJAtA [...]
\ No newline at end of file
diff --git a/api/search.index/type/2a816290da.js b/api/search.index/type/2a816290da.js
new file mode 100644
index 000000000..116c15602
--- /dev/null
+++ b/api/search.index/type/2a816290da.js
@@ -0,0 +1 @@
+rd_("Ec[\"AAAAAAAAAAABDxwAAAKoIAAALCEAAAAAAAAAAAH4CAAA\",\"AAAAAAAAAAABDxwAAAKoIAAALCEAAA==\"]Bg[\"AAAAAAAAAAAAAAAAAXcKAAABeAoAAA==\",\"\"]Og[\"AAAAAAAAAAAAOjAAAAEAAAAAABEAEAAAAIUQ5BRQHFEc1xzYHEkdSh1VHlYeih+LH5AfkR/eH98f5B/lHwP1CAAAFQwAALMOAAA7MAAAAQAAJgAOAIAEAADNDgAAhhACAOUUAQCqGgEAkhsBAFIcAwDZHAMASx0DAFceAwCMHwMAkh8BAOAfAwDmHwEABPYIAAD3CAAAFgwAALQOAAAFgQQAAIIEAAC+DgAAzg4AAM8OAAA=\",\"\"]Gg[\"AAAAAAAAAAAAAAA6MAAAAQAAAAAAEgAQAAAAhxCIEOYUqhqrGpIbkxtUHFUc2xzcHE0dTh1ZHloejh+PH+If4x8B9wgAAAO [...]
\ No newline at end of file
diff --git a/api/search.index/type/d08dd1cd0b.js b/api/search.index/type/d08dd1cd0b.js
deleted file mode 100644
index 399ab6a49..000000000
--- a/api/search.index/type/d08dd1cd0b.js
+++ /dev/null
@@ -1 +0,0 @@
-rd_("Ec[\"AAAAAAAAAAABEBwAAAKpIAAALSEAAAAAAAAAAAH4CAAA\",\"AAAAAAAAAAABEBwAAAKpIAAALSEAAA==\"]Bg[\"AAAAAAAAAAAAAAAAAXcKAAABeAoAAA==\",\"\"]Og[\"AAAAAAAAAAAAOjAAAAEAAAAAABEAEAAAAIUQ5BRRHFIc2BzZHEodSx1WHlceix+MH5Efkh/fH+Af5R/mHwP1CAAAFQwAALMOAAA7MAAAAQAAJgAOAIAEAADNDgAAhhACAOUUAQCqGgEAkhsBAFMcAwDaHAMATB0DAFgeAwCNHwMAkx8BAOEfAwDnHwEABPYIAAD3CAAAFgwAALQOAAAFgQQAAIIEAAC+DgAAzg4AAM8OAAA=\",\"\"]Gg[\"AAAAAAAAAAAAAAA6MAAAAQAAAAAAEgAQAAAAhxCIEOYUqhqrGpIbkxtVHFYc3BzdHE4dTx1aHlsejx+QH+Mf5B8B9wgAAAO [...]
\ No newline at end of file
diff --git a/api/src/iceberg/arrow/caching_delete_file_loader.rs.html b/api/src/iceberg/arrow/caching_delete_file_loader.rs.html
index ff0c59f49..db3f51b6b 100644
--- a/api/src/iceberg/arrow/caching_delete_file_loader.rs.html
+++ b/api/src/iceberg/arrow/caching_delete_file_loader.rs.html
@@ -1621,193 +1621,196 @@
<a href=#1621 id=1621 data-nosnippet>1621</a> <span class="kw">let </span>key_metadata = StandardKeyMetadata::try_new(<span class="string">b"0123456789abcdef"</span>)
<a href=#1622 id=1622 data-nosnippet>1622</a> .unwrap()
<a href=#1623 id=1623 data-nosnippet>1623</a> .with_aad_prefix(<span class="string">b"test-aad-prefix!"</span>);
-<a href=#1624 id=1624 data-nosnippet>1624</a> <span class="kw">let </span>encoded_key_metadata = key_metadata.encode().unwrap();
-<a href=#1625 id=1625 data-nosnippet>1625</a>
-<a href=#1626 id=1626 data-nosnippet>1626</a> <span class="kw">let </span>blob = encode_dv_blob([<span class="number">2u64</span>, <span class="number">4</span>]);
-<a href=#1627 id=1627 data-nosnippet>1627</a> <span class="kw">let </span>plaintext_size = blob.len() <span class="kw">as </span>i64;
-<a href=#1628 id=1628 data-nosnippet>1628</a> <span class="kw">let </span>dv_path = <span class="macro">format!</span>(<span class="string">"{table_location}/deletes.puffin"</span>);
-<a href=#1629 id=1629 data-nosnippet>1629</a> <span class="kw">let </span>output = EncryptedOutputFile::new(file_io.new_output(<span class="kw-2">&</span>dv_path).unwrap(), key_metadata);
-<a href=#1630 id=1630 data-nosnippet>1630</a> output.write(Bytes::from(blob)).<span class="kw">await</span>.unwrap();
-<a href=#1631 id=1631 data-nosnippet>1631</a>
-<a href=#1632 id=1632 data-nosnippet>1632</a> <span class="comment">// content_offset / content_size_in_bytes are in the plaintext coordinate space, distinct
-<a href=#1633 id=1633 data-nosnippet>1633</a> // from the ciphertext's on-disk size (header, nonce, and tag overhead).
-<a href=#1634 id=1634 data-nosnippet>1634</a> </span><span class="kw">let </span>file_size = std::fs::metadata(<span class="kw-2">&</span>dv_path).unwrap().len();
-<a href=#1635 id=1635 data-nosnippet>1635</a> <span class="kw">let </span>data_file_path = <span class="macro">format!</span>(<span class="string">"{table_location}/data-1.parquet"</span>);
-<a href=#1636 id=1636 data-nosnippet>1636</a> <span class="kw">let </span>dv = dv_task(
-<a href=#1637 id=1637 data-nosnippet>1637</a> dv_path.clone(),
-<a href=#1638 id=1638 data-nosnippet>1638</a> file_size,
-<a href=#1639 id=1639 data-nosnippet>1639</a> data_file_path.clone(),
-<a href=#1640 id=1640 data-nosnippet>1640</a> <span class="number">0</span>,
-<a href=#1641 id=1641 data-nosnippet>1641</a> plaintext_size,
-<a href=#1642 id=1642 data-nosnippet>1642</a> <span class="number">2</span>,
-<a href=#1643 id=1643 data-nosnippet>1643</a> <span class="prelude-val">Some</span>(encoded_key_metadata),
-<a href=#1644 id=1644 data-nosnippet>1644</a> );
-<a href=#1645 id=1645 data-nosnippet>1645</a>
-<a href=#1646 id=1646 data-nosnippet>1646</a> <span class="kw">let </span>schema = Arc::new(
-<a href=#1647 id=1647 data-nosnippet>1647</a> Schema::builder()
-<a href=#1648 id=1648 data-nosnippet>1648</a> .with_fields(<span class="macro">vec!</span>[
-<a href=#1649 id=1649 data-nosnippet>1649</a> NestedField::optional(<span class="number">1</span>, <span class="string">"x"</span>, Type::Primitive(PrimitiveType::Long)).into(),
-<a href=#1650 id=1650 data-nosnippet>1650</a> ])
-<a href=#1651 id=1651 data-nosnippet>1651</a> .build()
-<a href=#1652 id=1652 data-nosnippet>1652</a> .unwrap(),
-<a href=#1653 id=1653 data-nosnippet>1653</a> );
-<a href=#1654 id=1654 data-nosnippet>1654</a>
-<a href=#1655 id=1655 data-nosnippet>1655</a> <span class="kw">let </span>loader = CachingDeleteFileLoader::new(file_io, <span class="number">10</span>, Runtime::current());
-<a href=#1656 id=1656 data-nosnippet>1656</a> <span class="kw">let </span>delete_filter = loader.load_deletes(<span class="kw-2">&</span>[dv], schema).<span class="kw">await</span>.unwrap().unwrap();
+<a href=#1624 id=1624 data-nosnippet>1624</a>
+<a href=#1625 id=1625 data-nosnippet>1625</a> <span class="kw">let </span>blob = encode_dv_blob([<span class="number">2u64</span>, <span class="number">4</span>]);
+<a href=#1626 id=1626 data-nosnippet>1626</a> <span class="kw">let </span>plaintext_size = blob.len() <span class="kw">as </span>i64;
+<a href=#1627 id=1627 data-nosnippet>1627</a> <span class="kw">let </span>dv_path = <span class="macro">format!</span>(<span class="string">"{table_location}/deletes.puffin"</span>);
+<a href=#1628 id=1628 data-nosnippet>1628</a> <span class="kw">let </span>output = EncryptedOutputFile::new(file_io.new_output(<span class="kw-2">&</span>dv_path).unwrap(), key_metadata);
+<a href=#1629 id=1629 data-nosnippet>1629</a> <span class="kw">let </span>file_metadata = output.write(Bytes::from(blob)).<span class="kw">await</span>.unwrap();
+<a href=#1630 id=1630 data-nosnippet>1630</a> <span class="kw">let </span>encoded_key_metadata = output
+<a href=#1631 id=1631 data-nosnippet>1631</a> .key_metadata_with_saved_file_metadata(<span class="kw-2">&</span>file_metadata)
+<a href=#1632 id=1632 data-nosnippet>1632</a> .encode()
+<a href=#1633 id=1633 data-nosnippet>1633</a> .unwrap();
+<a href=#1634 id=1634 data-nosnippet>1634</a>
+<a href=#1635 id=1635 data-nosnippet>1635</a> <span class="comment">// content_offset / content_size_in_bytes are in the plaintext coordinate space, distinct
+<a href=#1636 id=1636 data-nosnippet>1636</a> // from the ciphertext's on-disk size (header, nonce, and tag overhead).
+<a href=#1637 id=1637 data-nosnippet>1637</a> </span><span class="kw">let </span>file_size = std::fs::metadata(<span class="kw-2">&</span>dv_path).unwrap().len();
+<a href=#1638 id=1638 data-nosnippet>1638</a> <span class="kw">let </span>data_file_path = <span class="macro">format!</span>(<span class="string">"{table_location}/data-1.parquet"</span>);
+<a href=#1639 id=1639 data-nosnippet>1639</a> <span class="kw">let </span>dv = dv_task(
+<a href=#1640 id=1640 data-nosnippet>1640</a> dv_path.clone(),
+<a href=#1641 id=1641 data-nosnippet>1641</a> file_size,
+<a href=#1642 id=1642 data-nosnippet>1642</a> data_file_path.clone(),
+<a href=#1643 id=1643 data-nosnippet>1643</a> <span class="number">0</span>,
+<a href=#1644 id=1644 data-nosnippet>1644</a> plaintext_size,
+<a href=#1645 id=1645 data-nosnippet>1645</a> <span class="number">2</span>,
+<a href=#1646 id=1646 data-nosnippet>1646</a> <span class="prelude-val">Some</span>(encoded_key_metadata),
+<a href=#1647 id=1647 data-nosnippet>1647</a> );
+<a href=#1648 id=1648 data-nosnippet>1648</a>
+<a href=#1649 id=1649 data-nosnippet>1649</a> <span class="kw">let </span>schema = Arc::new(
+<a href=#1650 id=1650 data-nosnippet>1650</a> Schema::builder()
+<a href=#1651 id=1651 data-nosnippet>1651</a> .with_fields(<span class="macro">vec!</span>[
+<a href=#1652 id=1652 data-nosnippet>1652</a> NestedField::optional(<span class="number">1</span>, <span class="string">"x"</span>, Type::Primitive(PrimitiveType::Long)).into(),
+<a href=#1653 id=1653 data-nosnippet>1653</a> ])
+<a href=#1654 id=1654 data-nosnippet>1654</a> .build()
+<a href=#1655 id=1655 data-nosnippet>1655</a> .unwrap(),
+<a href=#1656 id=1656 data-nosnippet>1656</a> );
<a href=#1657 id=1657 data-nosnippet>1657</a>
-<a href=#1658 id=1658 data-nosnippet>1658</a> <span class="kw">let </span>delete_vector = delete_filter
-<a href=#1659 id=1659 data-nosnippet>1659</a> .get_delete_vector_for_path(<span class="kw-2">&</span>data_file_path)
-<a href=#1660 id=1660 data-nosnippet>1660</a> .expect(<span class="string">"a delete vector should be indexed for the referenced data file"</span>);
-<a href=#1661 id=1661 data-nosnippet>1661</a> <span class="kw">let </span><span class="kw-2">mut </span>positions: Vec<u64> = delete_vector.lock().unwrap().iter().collect();
-<a href=#1662 id=1662 data-nosnippet>1662</a> positions.sort_unstable();
-<a href=#1663 id=1663 data-nosnippet>1663</a> <span class="macro">assert_eq!</span>(positions, <span class="macro">vec!</span>[<span class="number">2</span>, <span class="number">4</span>]);
-<a href=#1664 id=1664 data-nosnippet>1664</a> }
-<a href=#1665 id=1665 data-nosnippet>1665</a>
-<a href=#1666 id=1666 data-nosnippet>1666</a> <span class="attr">#[tokio::test]
-<a href=#1667 id=1667 data-nosnippet>1667</a> </span><span class="kw">async fn </span>test_load_deletes_rejects_deletion_vector_cardinality_mismatch() {
-<a href=#1668 id=1668 data-nosnippet>1668</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#1669 id=1669 data-nosnippet>1669</a> <span class="kw">let </span>table_location = tmp_dir.path().to_str().unwrap().to_string();
-<a href=#1670 id=1670 data-nosnippet>1670</a> <span class="kw">let </span>file_io = FileIO::new_with_fs();
-<a href=#1671 id=1671 data-nosnippet>1671</a>
-<a href=#1672 id=1672 data-nosnippet>1672</a> <span class="kw">let </span>blob = encode_dv_blob([<span class="number">0u64</span>, <span class="number">1</span>, <span class="number">5</span>]);
-<a href=#1673 id=1673 data-nosnippet>1673</a> <span class="kw">let </span>dv_path = <span class="macro">format!</span>(<span class="string">"{table_location}/deletes.puffin"</span>);
-<a href=#1674 id=1674 data-nosnippet>1674</a> std::fs::write(<span class="kw-2">&</span>dv_path, <span class="kw-2">&</span>blob).unwrap();
-<a href=#1675 id=1675 data-nosnippet>1675</a>
-<a href=#1676 id=1676 data-nosnippet>1676</a> <span class="kw">let </span>data_file_path = <span class="macro">format!</span>(<span class="string">"{table_location}/data-1.parquet"</span>);
-<a href=#1677 id=1677 data-nosnippet>1677</a> <span class="comment">// record_count says 2 positions, but the blob decodes to 3.
-<a href=#1678 id=1678 data-nosnippet>1678</a> </span><span class="kw">let </span>dv = dv_task(
-<a href=#1679 id=1679 data-nosnippet>1679</a> dv_path.clone(),
-<a href=#1680 id=1680 data-nosnippet>1680</a> std::fs::metadata(<span class="kw-2">&</span>dv_path).unwrap().len(),
-<a href=#1681 id=1681 data-nosnippet>1681</a> data_file_path,
-<a href=#1682 id=1682 data-nosnippet>1682</a> <span class="number">0</span>,
-<a href=#1683 id=1683 data-nosnippet>1683</a> blob.len() <span class="kw">as </span>i64,
-<a href=#1684 id=1684 data-nosnippet>1684</a> <span class="number">2</span>,
-<a href=#1685 id=1685 data-nosnippet>1685</a> <span class="prelude-val">None</span>,
-<a href=#1686 id=1686 data-nosnippet>1686</a> );
-<a href=#1687 id=1687 data-nosnippet>1687</a>
-<a href=#1688 id=1688 data-nosnippet>1688</a> <span class="kw">let </span>schema = Arc::new(
-<a href=#1689 id=1689 data-nosnippet>1689</a> Schema::builder()
-<a href=#1690 id=1690 data-nosnippet>1690</a> .with_fields(<span class="macro">vec!</span>[
-<a href=#1691 id=1691 data-nosnippet>1691</a> NestedField::optional(<span class="number">1</span>, <span class="string">"x"</span>, Type::Primitive(PrimitiveType::Long)).into(),
-<a href=#1692 id=1692 data-nosnippet>1692</a> ])
-<a href=#1693 id=1693 data-nosnippet>1693</a> .build()
-<a href=#1694 id=1694 data-nosnippet>1694</a> .unwrap(),
-<a href=#1695 id=1695 data-nosnippet>1695</a> );
-<a href=#1696 id=1696 data-nosnippet>1696</a>
-<a href=#1697 id=1697 data-nosnippet>1697</a> <span class="kw">let </span>loader = CachingDeleteFileLoader::new(file_io, <span class="number">10</span>, Runtime::current());
-<a href=#1698 id=1698 data-nosnippet>1698</a> <span class="kw">let </span>err = loader
-<a href=#1699 id=1699 data-nosnippet>1699</a> .load_deletes(<span class="kw-2">&</span>[dv], schema)
-<a href=#1700 id=1700 data-nosnippet>1700</a> .<span class="kw">await
-<a href=#1701 id=1701 data-nosnippet>1701</a> </span>.unwrap()
-<a href=#1702 id=1702 data-nosnippet>1702</a> .unwrap_err();
-<a href=#1703 id=1703 data-nosnippet>1703</a>
-<a href=#1704 id=1704 data-nosnippet>1704</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
-<a href=#1705 id=1705 data-nosnippet>1705</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"expected 2 from record_count"</span>));
-<a href=#1706 id=1706 data-nosnippet>1706</a> }
-<a href=#1707 id=1707 data-nosnippet>1707</a>
-<a href=#1708 id=1708 data-nosnippet>1708</a> <span class="comment">// A well-formed deletion-vector task, for tests that then clear or corrupt one field.
-<a href=#1709 id=1709 data-nosnippet>1709</a> </span><span class="kw">fn </span>valid_dv_task() -> FileScanTaskDeleteFile {
-<a href=#1710 id=1710 data-nosnippet>1710</a> dv_task(
-<a href=#1711 id=1711 data-nosnippet>1711</a> <span class="string">"deletes.puffin"</span>.to_string(),
-<a href=#1712 id=1712 data-nosnippet>1712</a> <span class="number">100</span>,
-<a href=#1713 id=1713 data-nosnippet>1713</a> <span class="string">"data.parquet"</span>.to_string(),
-<a href=#1714 id=1714 data-nosnippet>1714</a> <span class="number">4</span>,
-<a href=#1715 id=1715 data-nosnippet>1715</a> <span class="number">40</span>,
-<a href=#1716 id=1716 data-nosnippet>1716</a> <span class="number">2</span>,
-<a href=#1717 id=1717 data-nosnippet>1717</a> <span class="prelude-val">None</span>,
-<a href=#1718 id=1718 data-nosnippet>1718</a> )
-<a href=#1719 id=1719 data-nosnippet>1719</a> }
-<a href=#1720 id=1720 data-nosnippet>1720</a>
-<a href=#1721 id=1721 data-nosnippet>1721</a> <span class="attr">#[test]
-<a href=#1722 id=1722 data-nosnippet>1722</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_missing_content_offset() {
-<a href=#1723 id=1723 data-nosnippet>1723</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
-<a href=#1724 id=1724 data-nosnippet>1724</a> task.content_offset = <span class="prelude-val">None</span>;
-<a href=#1725 id=1725 data-nosnippet>1725</a>
-<a href=#1726 id=1726 data-nosnippet>1726</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
-<a href=#1727 id=1727 data-nosnippet>1727</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
-<a href=#1728 id=1728 data-nosnippet>1728</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"missing content_offset"</span>));
-<a href=#1729 id=1729 data-nosnippet>1729</a> }
-<a href=#1730 id=1730 data-nosnippet>1730</a>
-<a href=#1731 id=1731 data-nosnippet>1731</a> <span class="attr">#[test]
-<a href=#1732 id=1732 data-nosnippet>1732</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_missing_content_size() {
-<a href=#1733 id=1733 data-nosnippet>1733</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
-<a href=#1734 id=1734 data-nosnippet>1734</a> task.content_size_in_bytes = <span class="prelude-val">None</span>;
-<a href=#1735 id=1735 data-nosnippet>1735</a>
-<a href=#1736 id=1736 data-nosnippet>1736</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
-<a href=#1737 id=1737 data-nosnippet>1737</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
-<a href=#1738 id=1738 data-nosnippet>1738</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"missing content_size_in_bytes"</span>));
-<a href=#1739 id=1739 data-nosnippet>1739</a> }
-<a href=#1740 id=1740 data-nosnippet>1740</a>
-<a href=#1741 id=1741 data-nosnippet>1741</a> <span class="attr">#[test]
-<a href=#1742 id=1742 data-nosnippet>1742</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_missing_referenced_data_file() {
-<a href=#1743 id=1743 data-nosnippet>1743</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
-<a href=#1744 id=1744 data-nosnippet>1744</a> task.referenced_data_file = <span class="prelude-val">None</span>;
-<a href=#1745 id=1745 data-nosnippet>1745</a>
-<a href=#1746 id=1746 data-nosnippet>1746</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
-<a href=#1747 id=1747 data-nosnippet>1747</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
-<a href=#1748 id=1748 data-nosnippet>1748</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"missing referenced_data_file"</span>));
-<a href=#1749 id=1749 data-nosnippet>1749</a> }
-<a href=#1750 id=1750 data-nosnippet>1750</a>
-<a href=#1751 id=1751 data-nosnippet>1751</a> <span class="attr">#[test]
-<a href=#1752 id=1752 data-nosnippet>1752</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_missing_record_count() {
-<a href=#1753 id=1753 data-nosnippet>1753</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
-<a href=#1754 id=1754 data-nosnippet>1754</a> task.record_count = <span class="prelude-val">None</span>;
-<a href=#1755 id=1755 data-nosnippet>1755</a>
-<a href=#1756 id=1756 data-nosnippet>1756</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
-<a href=#1757 id=1757 data-nosnippet>1757</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
-<a href=#1758 id=1758 data-nosnippet>1758</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"missing record_count"</span>));
-<a href=#1759 id=1759 data-nosnippet>1759</a> }
-<a href=#1760 id=1760 data-nosnippet>1760</a>
-<a href=#1761 id=1761 data-nosnippet>1761</a> <span class="attr">#[test]
-<a href=#1762 id=1762 data-nosnippet>1762</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_negative_content_offset() {
-<a href=#1763 id=1763 data-nosnippet>1763</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
-<a href=#1764 id=1764 data-nosnippet>1764</a> task.content_offset = <span class="prelude-val">Some</span>(-<span class="number">1</span>);
-<a href=#1765 id=1765 data-nosnippet>1765</a>
-<a href=#1766 id=1766 data-nosnippet>1766</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
-<a href=#1767 id=1767 data-nosnippet>1767</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
-<a href=#1768 id=1768 data-nosnippet>1768</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"negative content_offset"</span>));
-<a href=#1769 id=1769 data-nosnippet>1769</a> }
-<a href=#1770 id=1770 data-nosnippet>1770</a>
-<a href=#1771 id=1771 data-nosnippet>1771</a> <span class="attr">#[test]
-<a href=#1772 id=1772 data-nosnippet>1772</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_negative_content_size() {
-<a href=#1773 id=1773 data-nosnippet>1773</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
-<a href=#1774 id=1774 data-nosnippet>1774</a> task.content_size_in_bytes = <span class="prelude-val">Some</span>(-<span class="number">1</span>);
-<a href=#1775 id=1775 data-nosnippet>1775</a>
-<a href=#1776 id=1776 data-nosnippet>1776</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
-<a href=#1777 id=1777 data-nosnippet>1777</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
-<a href=#1778 id=1778 data-nosnippet>1778</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"negative content_size_in_bytes"</span>));
-<a href=#1779 id=1779 data-nosnippet>1779</a> }
-<a href=#1780 id=1780 data-nosnippet>1780</a>
-<a href=#1781 id=1781 data-nosnippet>1781</a> <span class="attr">#[test]
-<a href=#1782 id=1782 data-nosnippet>1782</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_accepts_valid_coordinates() {
-<a href=#1783 id=1783 data-nosnippet>1783</a> <span class="kw">let </span>(start, len, data_file_path, record_count) =
-<a href=#1784 id=1784 data-nosnippet>1784</a> CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>valid_dv_task()).unwrap();
-<a href=#1785 id=1785 data-nosnippet>1785</a> <span class="macro">assert_eq!</span>(start, <span class="number">4</span>);
-<a href=#1786 id=1786 data-nosnippet>1786</a> <span class="macro">assert_eq!</span>(len, <span class="number">40</span>);
-<a href=#1787 id=1787 data-nosnippet>1787</a> <span class="macro">assert_eq!</span>(data_file_path, <span class="string">"data.parquet"</span>);
-<a href=#1788 id=1788 data-nosnippet>1788</a> <span class="macro">assert_eq!</span>(record_count, <span class="number">2</span>);
-<a href=#1789 id=1789 data-nosnippet>1789</a> }
-<a href=#1790 id=1790 data-nosnippet>1790</a>
-<a href=#1791 id=1791 data-nosnippet>1791</a> <span class="attr">#[test]
-<a href=#1792 id=1792 data-nosnippet>1792</a> </span><span class="kw">fn </span>test_validate_deletion_vector_cardinality_accepts_matching_count() {
-<a href=#1793 id=1793 data-nosnippet>1793</a> <span class="kw">let </span><span class="kw-2">mut </span>dv = DeleteVector::default();
-<a href=#1794 id=1794 data-nosnippet>1794</a> dv.insert(<span class="number">1</span>);
-<a href=#1795 id=1795 data-nosnippet>1795</a> dv.insert(<span class="number">2</span>);
-<a href=#1796 id=1796 data-nosnippet>1796</a>
-<a href=#1797 id=1797 data-nosnippet>1797</a> CachingDeleteFileLoader::validate_deletion_vector_cardinality(<span class="kw-2">&</span>dv, <span class="number">2</span>, <span class="string">"deletes.puffin"</span>)
-<a href=#1798 id=1798 data-nosnippet>1798</a> .unwrap();
-<a href=#1799 id=1799 data-nosnippet>1799</a> }
-<a href=#1800 id=1800 data-nosnippet>1800</a>
-<a href=#1801 id=1801 data-nosnippet>1801</a> <span class="attr">#[test]
-<a href=#1802 id=1802 data-nosnippet>1802</a> </span><span class="kw">fn </span>test_validate_deletion_vector_cardinality_rejects_mismatched_count() {
-<a href=#1803 id=1803 data-nosnippet>1803</a> <span class="kw">let </span><span class="kw-2">mut </span>dv = DeleteVector::default();
-<a href=#1804 id=1804 data-nosnippet>1804</a> dv.insert(<span class="number">1</span>);
-<a href=#1805 id=1805 data-nosnippet>1805</a>
-<a href=#1806 id=1806 data-nosnippet>1806</a> <span class="kw">let </span>err =
-<a href=#1807 id=1807 data-nosnippet>1807</a> CachingDeleteFileLoader::validate_deletion_vector_cardinality(<span class="kw-2">&</span>dv, <span class="number">2</span>, <span class="string">"deletes.puffin"</span>)
-<a href=#1808 id=1808 data-nosnippet>1808</a> .unwrap_err();
-<a href=#1809 id=1809 data-nosnippet>1809</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
-<a href=#1810 id=1810 data-nosnippet>1810</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"expected 2 from record_count"</span>));
-<a href=#1811 id=1811 data-nosnippet>1811</a> }
-<a href=#1812 id=1812 data-nosnippet>1812</a>}
+<a href=#1658 id=1658 data-nosnippet>1658</a> <span class="kw">let </span>loader = CachingDeleteFileLoader::new(file_io, <span class="number">10</span>, Runtime::current());
+<a href=#1659 id=1659 data-nosnippet>1659</a> <span class="kw">let </span>delete_filter = loader.load_deletes(<span class="kw-2">&</span>[dv], schema).<span class="kw">await</span>.unwrap().unwrap();
+<a href=#1660 id=1660 data-nosnippet>1660</a>
+<a href=#1661 id=1661 data-nosnippet>1661</a> <span class="kw">let </span>delete_vector = delete_filter
+<a href=#1662 id=1662 data-nosnippet>1662</a> .get_delete_vector_for_path(<span class="kw-2">&</span>data_file_path)
+<a href=#1663 id=1663 data-nosnippet>1663</a> .expect(<span class="string">"a delete vector should be indexed for the referenced data file"</span>);
+<a href=#1664 id=1664 data-nosnippet>1664</a> <span class="kw">let </span><span class="kw-2">mut </span>positions: Vec<u64> = delete_vector.lock().unwrap().iter().collect();
+<a href=#1665 id=1665 data-nosnippet>1665</a> positions.sort_unstable();
+<a href=#1666 id=1666 data-nosnippet>1666</a> <span class="macro">assert_eq!</span>(positions, <span class="macro">vec!</span>[<span class="number">2</span>, <span class="number">4</span>]);
+<a href=#1667 id=1667 data-nosnippet>1667</a> }
+<a href=#1668 id=1668 data-nosnippet>1668</a>
+<a href=#1669 id=1669 data-nosnippet>1669</a> <span class="attr">#[tokio::test]
+<a href=#1670 id=1670 data-nosnippet>1670</a> </span><span class="kw">async fn </span>test_load_deletes_rejects_deletion_vector_cardinality_mismatch() {
+<a href=#1671 id=1671 data-nosnippet>1671</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#1672 id=1672 data-nosnippet>1672</a> <span class="kw">let </span>table_location = tmp_dir.path().to_str().unwrap().to_string();
+<a href=#1673 id=1673 data-nosnippet>1673</a> <span class="kw">let </span>file_io = FileIO::new_with_fs();
+<a href=#1674 id=1674 data-nosnippet>1674</a>
+<a href=#1675 id=1675 data-nosnippet>1675</a> <span class="kw">let </span>blob = encode_dv_blob([<span class="number">0u64</span>, <span class="number">1</span>, <span class="number">5</span>]);
+<a href=#1676 id=1676 data-nosnippet>1676</a> <span class="kw">let </span>dv_path = <span class="macro">format!</span>(<span class="string">"{table_location}/deletes.puffin"</span>);
+<a href=#1677 id=1677 data-nosnippet>1677</a> std::fs::write(<span class="kw-2">&</span>dv_path, <span class="kw-2">&</span>blob).unwrap();
+<a href=#1678 id=1678 data-nosnippet>1678</a>
+<a href=#1679 id=1679 data-nosnippet>1679</a> <span class="kw">let </span>data_file_path = <span class="macro">format!</span>(<span class="string">"{table_location}/data-1.parquet"</span>);
+<a href=#1680 id=1680 data-nosnippet>1680</a> <span class="comment">// record_count says 2 positions, but the blob decodes to 3.
+<a href=#1681 id=1681 data-nosnippet>1681</a> </span><span class="kw">let </span>dv = dv_task(
+<a href=#1682 id=1682 data-nosnippet>1682</a> dv_path.clone(),
+<a href=#1683 id=1683 data-nosnippet>1683</a> std::fs::metadata(<span class="kw-2">&</span>dv_path).unwrap().len(),
+<a href=#1684 id=1684 data-nosnippet>1684</a> data_file_path,
+<a href=#1685 id=1685 data-nosnippet>1685</a> <span class="number">0</span>,
+<a href=#1686 id=1686 data-nosnippet>1686</a> blob.len() <span class="kw">as </span>i64,
+<a href=#1687 id=1687 data-nosnippet>1687</a> <span class="number">2</span>,
+<a href=#1688 id=1688 data-nosnippet>1688</a> <span class="prelude-val">None</span>,
+<a href=#1689 id=1689 data-nosnippet>1689</a> );
+<a href=#1690 id=1690 data-nosnippet>1690</a>
+<a href=#1691 id=1691 data-nosnippet>1691</a> <span class="kw">let </span>schema = Arc::new(
+<a href=#1692 id=1692 data-nosnippet>1692</a> Schema::builder()
+<a href=#1693 id=1693 data-nosnippet>1693</a> .with_fields(<span class="macro">vec!</span>[
+<a href=#1694 id=1694 data-nosnippet>1694</a> NestedField::optional(<span class="number">1</span>, <span class="string">"x"</span>, Type::Primitive(PrimitiveType::Long)).into(),
+<a href=#1695 id=1695 data-nosnippet>1695</a> ])
+<a href=#1696 id=1696 data-nosnippet>1696</a> .build()
+<a href=#1697 id=1697 data-nosnippet>1697</a> .unwrap(),
+<a href=#1698 id=1698 data-nosnippet>1698</a> );
+<a href=#1699 id=1699 data-nosnippet>1699</a>
+<a href=#1700 id=1700 data-nosnippet>1700</a> <span class="kw">let </span>loader = CachingDeleteFileLoader::new(file_io, <span class="number">10</span>, Runtime::current());
+<a href=#1701 id=1701 data-nosnippet>1701</a> <span class="kw">let </span>err = loader
+<a href=#1702 id=1702 data-nosnippet>1702</a> .load_deletes(<span class="kw-2">&</span>[dv], schema)
+<a href=#1703 id=1703 data-nosnippet>1703</a> .<span class="kw">await
+<a href=#1704 id=1704 data-nosnippet>1704</a> </span>.unwrap()
+<a href=#1705 id=1705 data-nosnippet>1705</a> .unwrap_err();
+<a href=#1706 id=1706 data-nosnippet>1706</a>
+<a href=#1707 id=1707 data-nosnippet>1707</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1708 id=1708 data-nosnippet>1708</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"expected 2 from record_count"</span>));
+<a href=#1709 id=1709 data-nosnippet>1709</a> }
+<a href=#1710 id=1710 data-nosnippet>1710</a>
+<a href=#1711 id=1711 data-nosnippet>1711</a> <span class="comment">// A well-formed deletion-vector task, for tests that then clear or corrupt one field.
+<a href=#1712 id=1712 data-nosnippet>1712</a> </span><span class="kw">fn </span>valid_dv_task() -> FileScanTaskDeleteFile {
+<a href=#1713 id=1713 data-nosnippet>1713</a> dv_task(
+<a href=#1714 id=1714 data-nosnippet>1714</a> <span class="string">"deletes.puffin"</span>.to_string(),
+<a href=#1715 id=1715 data-nosnippet>1715</a> <span class="number">100</span>,
+<a href=#1716 id=1716 data-nosnippet>1716</a> <span class="string">"data.parquet"</span>.to_string(),
+<a href=#1717 id=1717 data-nosnippet>1717</a> <span class="number">4</span>,
+<a href=#1718 id=1718 data-nosnippet>1718</a> <span class="number">40</span>,
+<a href=#1719 id=1719 data-nosnippet>1719</a> <span class="number">2</span>,
+<a href=#1720 id=1720 data-nosnippet>1720</a> <span class="prelude-val">None</span>,
+<a href=#1721 id=1721 data-nosnippet>1721</a> )
+<a href=#1722 id=1722 data-nosnippet>1722</a> }
+<a href=#1723 id=1723 data-nosnippet>1723</a>
+<a href=#1724 id=1724 data-nosnippet>1724</a> <span class="attr">#[test]
+<a href=#1725 id=1725 data-nosnippet>1725</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_missing_content_offset() {
+<a href=#1726 id=1726 data-nosnippet>1726</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
+<a href=#1727 id=1727 data-nosnippet>1727</a> task.content_offset = <span class="prelude-val">None</span>;
+<a href=#1728 id=1728 data-nosnippet>1728</a>
+<a href=#1729 id=1729 data-nosnippet>1729</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
+<a href=#1730 id=1730 data-nosnippet>1730</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1731 id=1731 data-nosnippet>1731</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"missing content_offset"</span>));
+<a href=#1732 id=1732 data-nosnippet>1732</a> }
+<a href=#1733 id=1733 data-nosnippet>1733</a>
+<a href=#1734 id=1734 data-nosnippet>1734</a> <span class="attr">#[test]
+<a href=#1735 id=1735 data-nosnippet>1735</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_missing_content_size() {
+<a href=#1736 id=1736 data-nosnippet>1736</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
+<a href=#1737 id=1737 data-nosnippet>1737</a> task.content_size_in_bytes = <span class="prelude-val">None</span>;
+<a href=#1738 id=1738 data-nosnippet>1738</a>
+<a href=#1739 id=1739 data-nosnippet>1739</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
+<a href=#1740 id=1740 data-nosnippet>1740</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1741 id=1741 data-nosnippet>1741</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"missing content_size_in_bytes"</span>));
+<a href=#1742 id=1742 data-nosnippet>1742</a> }
+<a href=#1743 id=1743 data-nosnippet>1743</a>
+<a href=#1744 id=1744 data-nosnippet>1744</a> <span class="attr">#[test]
+<a href=#1745 id=1745 data-nosnippet>1745</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_missing_referenced_data_file() {
+<a href=#1746 id=1746 data-nosnippet>1746</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
+<a href=#1747 id=1747 data-nosnippet>1747</a> task.referenced_data_file = <span class="prelude-val">None</span>;
+<a href=#1748 id=1748 data-nosnippet>1748</a>
+<a href=#1749 id=1749 data-nosnippet>1749</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
+<a href=#1750 id=1750 data-nosnippet>1750</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1751 id=1751 data-nosnippet>1751</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"missing referenced_data_file"</span>));
+<a href=#1752 id=1752 data-nosnippet>1752</a> }
+<a href=#1753 id=1753 data-nosnippet>1753</a>
+<a href=#1754 id=1754 data-nosnippet>1754</a> <span class="attr">#[test]
+<a href=#1755 id=1755 data-nosnippet>1755</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_missing_record_count() {
+<a href=#1756 id=1756 data-nosnippet>1756</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
+<a href=#1757 id=1757 data-nosnippet>1757</a> task.record_count = <span class="prelude-val">None</span>;
+<a href=#1758 id=1758 data-nosnippet>1758</a>
+<a href=#1759 id=1759 data-nosnippet>1759</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
+<a href=#1760 id=1760 data-nosnippet>1760</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1761 id=1761 data-nosnippet>1761</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"missing record_count"</span>));
+<a href=#1762 id=1762 data-nosnippet>1762</a> }
+<a href=#1763 id=1763 data-nosnippet>1763</a>
+<a href=#1764 id=1764 data-nosnippet>1764</a> <span class="attr">#[test]
+<a href=#1765 id=1765 data-nosnippet>1765</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_negative_content_offset() {
+<a href=#1766 id=1766 data-nosnippet>1766</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
+<a href=#1767 id=1767 data-nosnippet>1767</a> task.content_offset = <span class="prelude-val">Some</span>(-<span class="number">1</span>);
+<a href=#1768 id=1768 data-nosnippet>1768</a>
+<a href=#1769 id=1769 data-nosnippet>1769</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
+<a href=#1770 id=1770 data-nosnippet>1770</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1771 id=1771 data-nosnippet>1771</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"negative content_offset"</span>));
+<a href=#1772 id=1772 data-nosnippet>1772</a> }
+<a href=#1773 id=1773 data-nosnippet>1773</a>
+<a href=#1774 id=1774 data-nosnippet>1774</a> <span class="attr">#[test]
+<a href=#1775 id=1775 data-nosnippet>1775</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_rejects_negative_content_size() {
+<a href=#1776 id=1776 data-nosnippet>1776</a> <span class="kw">let </span><span class="kw-2">mut </span>task = valid_dv_task();
+<a href=#1777 id=1777 data-nosnippet>1777</a> task.content_size_in_bytes = <span class="prelude-val">Some</span>(-<span class="number">1</span>);
+<a href=#1778 id=1778 data-nosnippet>1778</a>
+<a href=#1779 id=1779 data-nosnippet>1779</a> <span class="kw">let </span>err = CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>task).unwrap_err();
+<a href=#1780 id=1780 data-nosnippet>1780</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1781 id=1781 data-nosnippet>1781</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"negative content_size_in_bytes"</span>));
+<a href=#1782 id=1782 data-nosnippet>1782</a> }
+<a href=#1783 id=1783 data-nosnippet>1783</a>
+<a href=#1784 id=1784 data-nosnippet>1784</a> <span class="attr">#[test]
+<a href=#1785 id=1785 data-nosnippet>1785</a> </span><span class="kw">fn </span>test_validate_deletion_vector_task_accepts_valid_coordinates() {
+<a href=#1786 id=1786 data-nosnippet>1786</a> <span class="kw">let </span>(start, len, data_file_path, record_count) =
+<a href=#1787 id=1787 data-nosnippet>1787</a> CachingDeleteFileLoader::validate_deletion_vector_task(<span class="kw-2">&</span>valid_dv_task()).unwrap();
+<a href=#1788 id=1788 data-nosnippet>1788</a> <span class="macro">assert_eq!</span>(start, <span class="number">4</span>);
+<a href=#1789 id=1789 data-nosnippet>1789</a> <span class="macro">assert_eq!</span>(len, <span class="number">40</span>);
+<a href=#1790 id=1790 data-nosnippet>1790</a> <span class="macro">assert_eq!</span>(data_file_path, <span class="string">"data.parquet"</span>);
+<a href=#1791 id=1791 data-nosnippet>1791</a> <span class="macro">assert_eq!</span>(record_count, <span class="number">2</span>);
+<a href=#1792 id=1792 data-nosnippet>1792</a> }
+<a href=#1793 id=1793 data-nosnippet>1793</a>
+<a href=#1794 id=1794 data-nosnippet>1794</a> <span class="attr">#[test]
+<a href=#1795 id=1795 data-nosnippet>1795</a> </span><span class="kw">fn </span>test_validate_deletion_vector_cardinality_accepts_matching_count() {
+<a href=#1796 id=1796 data-nosnippet>1796</a> <span class="kw">let </span><span class="kw-2">mut </span>dv = DeleteVector::default();
+<a href=#1797 id=1797 data-nosnippet>1797</a> dv.insert(<span class="number">1</span>);
+<a href=#1798 id=1798 data-nosnippet>1798</a> dv.insert(<span class="number">2</span>);
+<a href=#1799 id=1799 data-nosnippet>1799</a>
+<a href=#1800 id=1800 data-nosnippet>1800</a> CachingDeleteFileLoader::validate_deletion_vector_cardinality(<span class="kw-2">&</span>dv, <span class="number">2</span>, <span class="string">"deletes.puffin"</span>)
+<a href=#1801 id=1801 data-nosnippet>1801</a> .unwrap();
+<a href=#1802 id=1802 data-nosnippet>1802</a> }
+<a href=#1803 id=1803 data-nosnippet>1803</a>
+<a href=#1804 id=1804 data-nosnippet>1804</a> <span class="attr">#[test]
+<a href=#1805 id=1805 data-nosnippet>1805</a> </span><span class="kw">fn </span>test_validate_deletion_vector_cardinality_rejects_mismatched_count() {
+<a href=#1806 id=1806 data-nosnippet>1806</a> <span class="kw">let </span><span class="kw-2">mut </span>dv = DeleteVector::default();
+<a href=#1807 id=1807 data-nosnippet>1807</a> dv.insert(<span class="number">1</span>);
+<a href=#1808 id=1808 data-nosnippet>1808</a>
+<a href=#1809 id=1809 data-nosnippet>1809</a> <span class="kw">let </span>err =
+<a href=#1810 id=1810 data-nosnippet>1810</a> CachingDeleteFileLoader::validate_deletion_vector_cardinality(<span class="kw-2">&</span>dv, <span class="number">2</span>, <span class="string">"deletes.puffin"</span>)
+<a href=#1811 id=1811 data-nosnippet>1811</a> .unwrap_err();
+<a href=#1812 id=1812 data-nosnippet>1812</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1813 id=1813 data-nosnippet>1813</a> <span class="macro">assert!</span>(err.message().contains(<span class="string">"expected 2 from record_count"</span>));
+<a href=#1814 id=1814 data-nosnippet>1814</a> }
+<a href=#1815 id=1815 data-nosnippet>1815</a>}
</code></pre></div></section></main></body></html>
\ No newline at end of file
diff --git a/api/src/iceberg/encryption/io.rs.html b/api/src/iceberg/encryption/io.rs.html
index bf9fba277..7ac970cfe 100644
--- a/api/src/iceberg/encryption/io.rs.html
+++ b/api/src/iceberg/encryption/io.rs.html
@@ -23,43 +23,43 @@
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">super</span>::crypto::AesGcmCipher;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">super</span>::key_metadata::StandardKeyMetadata;
-<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">super</span>::stream::{AesGcmFileRead, AesGcmFileWrite};
+<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">super</span>::stream::{AesGcmFileRead, AesGcmFileWrite, MIN_STREAM_LENGTH};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span><span class="kw">crate</span>::Result;
-<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::io::{FileMetadata, FileRead, FileWrite, InputFile, OutputFile};
-<a href=#29 id=29 data-nosnippet>29</a>
-<a href=#30 id=30 data-nosnippet>30</a><span class="doccomment">/// An AGS1 stream-encrypted input file wrapping a plain [`InputFile`].
-<a href=#31 id=31 data-nosnippet>31</a>///
-<a href=#32 id=32 data-nosnippet>32</a>/// Transparently decrypts on read.
-<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">pub struct </span>EncryptedInputFile {
-<a href=#34 id=34 data-nosnippet>34</a> inner: InputFile,
-<a href=#35 id=35 data-nosnippet>35</a> key_metadata: StandardKeyMetadata,
-<a href=#36 id=36 data-nosnippet>36</a>}
-<a href=#37 id=37 data-nosnippet>37</a>
-<a href=#38 id=38 data-nosnippet>38</a><span class="kw">impl </span>EncryptedInputFile {
-<a href=#39 id=39 data-nosnippet>39</a> <span class="doccomment">/// Creates a new encrypted input file.
-<a href=#40 id=40 data-nosnippet>40</a> </span><span class="kw">pub fn </span>new(inner: InputFile, key_metadata: StandardKeyMetadata) -> <span class="self">Self </span>{
-<a href=#41 id=41 data-nosnippet>41</a> <span class="self">Self </span>{
-<a href=#42 id=42 data-nosnippet>42</a> inner,
-<a href=#43 id=43 data-nosnippet>43</a> key_metadata,
-<a href=#44 id=44 data-nosnippet>44</a> }
-<a href=#45 id=45 data-nosnippet>45</a> }
-<a href=#46 id=46 data-nosnippet>46</a>
-<a href=#47 id=47 data-nosnippet>47</a> <span class="doccomment">/// Absolute path of the file.
-<a href=#48 id=48 data-nosnippet>48</a> </span><span class="kw">pub fn </span>location(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="kw-2">&</span>str {
-<a href=#49 id=49 data-nosnippet>49</a> <span class="self">self</span>.inner.location()
-<a href=#50 id=50 data-nosnippet>50</a> }
-<a href=#51 id=51 data-nosnippet>51</a>
-<a href=#52 id=52 data-nosnippet>52</a> <span class="doccomment">/// Check if file exists.
-<a href=#53 id=53 data-nosnippet>53</a> </span><span class="kw">pub async fn </span>exists(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><bool> {
-<a href=#54 id=54 data-nosnippet>54</a> <span class="self">self</span>.inner.exists().<span class="kw">await
-<a href=#55 id=55 data-nosnippet>55</a> </span>}
-<a href=#56 id=56 data-nosnippet>56</a>
-<a href=#57 id=57 data-nosnippet>57</a> <span class="doccomment">/// Fetch and returns metadata of file.
-<a href=#58 id=58 data-nosnippet>58</a> ///
-<a href=#59 id=59 data-nosnippet>59</a> /// The returned size is the **plaintext** size.
-<a href=#60 id=60 data-nosnippet>60</a> </span><span class="kw">pub async fn </span>metadata(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><FileMetadata> {
-<a href=#61 id=61 data-nosnippet>61</a> <span class="kw">let </span>raw_meta = <span class="self">self</span>.inner.metadata().<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">let </span>plaintext_size = AesGcmFileRead::calculate_plaintext_length(raw_meta.size)<span class="question-mark">?</span>;
+<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::error::invalid_data;
+<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::io::{FileMetadata, FileRead, FileWrite, InputFile, OutputFile};
+<a href=#30 id=30 data-nosnippet>30</a>
+<a href=#31 id=31 data-nosnippet>31</a><span class="doccomment">/// An AGS1 stream-encrypted input file wrapping a plain [`InputFile`].
+<a href=#32 id=32 data-nosnippet>32</a>///
+<a href=#33 id=33 data-nosnippet>33</a>/// Transparently decrypts on read.
+<a href=#34 id=34 data-nosnippet>34</a></span><span class="kw">pub struct </span>EncryptedInputFile {
+<a href=#35 id=35 data-nosnippet>35</a> inner: InputFile,
+<a href=#36 id=36 data-nosnippet>36</a> key_metadata: StandardKeyMetadata,
+<a href=#37 id=37 data-nosnippet>37</a>}
+<a href=#38 id=38 data-nosnippet>38</a>
+<a href=#39 id=39 data-nosnippet>39</a><span class="kw">impl </span>EncryptedInputFile {
+<a href=#40 id=40 data-nosnippet>40</a> <span class="doccomment">/// Creates a new encrypted input file.
+<a href=#41 id=41 data-nosnippet>41</a> </span><span class="kw">pub fn </span>new(inner: InputFile, key_metadata: StandardKeyMetadata) -> <span class="self">Self </span>{
+<a href=#42 id=42 data-nosnippet>42</a> <span class="self">Self </span>{
+<a href=#43 id=43 data-nosnippet>43</a> inner,
+<a href=#44 id=44 data-nosnippet>44</a> key_metadata,
+<a href=#45 id=45 data-nosnippet>45</a> }
+<a href=#46 id=46 data-nosnippet>46</a> }
+<a href=#47 id=47 data-nosnippet>47</a>
+<a href=#48 id=48 data-nosnippet>48</a> <span class="doccomment">/// Absolute path of the file.
+<a href=#49 id=49 data-nosnippet>49</a> </span><span class="kw">pub fn </span>location(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="kw-2">&</span>str {
+<a href=#50 id=50 data-nosnippet>50</a> <span class="self">self</span>.inner.location()
+<a href=#51 id=51 data-nosnippet>51</a> }
+<a href=#52 id=52 data-nosnippet>52</a>
+<a href=#53 id=53 data-nosnippet>53</a> <span class="doccomment">/// Check if file exists.
+<a href=#54 id=54 data-nosnippet>54</a> </span><span class="kw">pub async fn </span>exists(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><bool> {
+<a href=#55 id=55 data-nosnippet>55</a> <span class="self">self</span>.inner.exists().<span class="kw">await
+<a href=#56 id=56 data-nosnippet>56</a> </span>}
+<a href=#57 id=57 data-nosnippet>57</a>
+<a href=#58 id=58 data-nosnippet>58</a> <span class="doccomment">/// Returns file metadata from the declared encrypted length without performing I/O.
+<a href=#59 id=59 data-nosnippet>59</a> ///
+<a href=#60 id=60 data-nosnippet>60</a> /// The returned size is the **plaintext** size.
+<a href=#61 id=61 data-nosnippet>61</a> </span><span class="kw">pub fn </span>metadata(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><FileMetadata> {
+<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">let </span>plaintext_size = AesGcmFileRead::calculate_plaintext_length(<span class="self">self</span>.encrypted_length()<span class="question-mark">?</span>)<span class="question-mark">?</span>;
<a href=#63 id=63 data-nosnippet>63</a> <span class="prelude-val">Ok</span>(FileMetadata {
<a href=#64 id=64 data-nosnippet>64</a> size: plaintext_size,
<a href=#65 id=65 data-nosnippet>65</a> })
@@ -67,157 +67,346 @@
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a> <span class="doccomment">/// Read and returns whole content of file (decrypted plaintext).
<a href=#69 id=69 data-nosnippet>69</a> </span><span class="kw">pub async fn </span>read(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><Bytes> {
-<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">let </span>meta = <span class="self">self</span>.metadata().<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">let </span>meta = <span class="self">self</span>.metadata()<span class="question-mark">?</span>;
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">let </span>reader = <span class="self">self</span>.reader().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#72 id=72 data-nosnippet>72</a> reader.read(<span class="number">0</span>..meta.size).<span class="kw">await
<a href=#73 id=73 data-nosnippet>73</a> </span>}
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a> <span class="doccomment">/// Creates a reader that transparently decrypts on each read.
<a href=#76 id=76 data-nosnippet>76</a> </span><span class="kw">pub async fn </span>reader(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><Box<<span class="kw">dyn </span>FileRead>> {
-<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">let </span>raw_meta = <span class="self">self</span>.inner.metadata().<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">let </span>encrypted_length = <span class="self">self</span>.encrypted_length()<span class="question-mark">?</span>;
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">let </span>raw_reader = <span class="self">self</span>.inner.reader().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">let </span>cipher = build_cipher(<span class="kw-2">&</span><span class="self">self</span>.key_metadata)<span class="question-mark">?</span>;
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">let </span>aad_prefix: Box<[u8]> = <span class="self">self</span>.key_metadata.aad_prefix().unwrap_or_default().into();
-<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">let </span>decrypting = AesGcmFileRead::new(raw_reader, cipher, aad_prefix, raw_meta.size)<span class="question-mark">?</span>;
+<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">let </span>decrypting = AesGcmFileRead::new(raw_reader, cipher, aad_prefix, encrypted_length)<span class="question-mark">?</span>;
<a href=#82 id=82 data-nosnippet>82</a> <span class="prelude-val">Ok</span>(Box::new(decrypting))
<a href=#83 id=83 data-nosnippet>83</a> }
<a href=#84 id=84 data-nosnippet>84</a>
-<a href=#85 id=85 data-nosnippet>85</a> <span class="doccomment">/// Returns a reference to the file's key metadata.
-<a href=#86 id=86 data-nosnippet>86</a> </span><span class="kw">pub fn </span>key_metadata(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="kw-2">&</span>StandardKeyMetadata {
-<a href=#87 id=87 data-nosnippet>87</a> <span class="kw-2">&</span><span class="self">self</span>.key_metadata
-<a href=#88 id=88 data-nosnippet>88</a> }
-<a href=#89 id=89 data-nosnippet>89</a>
-<a href=#90 id=90 data-nosnippet>90</a> <span class="doccomment">/// Consumes self and returns the underlying plain input file.
-<a href=#91 id=91 data-nosnippet>91</a> </span><span class="kw">pub fn </span>into_inner(<span class="self">self</span>) -> InputFile {
-<a href=#92 id=92 data-nosnippet>92</a> <span class="self">self</span>.inner
-<a href=#93 id=93 data-nosnippet>93</a> }
-<a href=#94 id=94 data-nosnippet>94</a>}
-<a href=#95 id=95 data-nosnippet>95</a>
-<a href=#96 id=96 data-nosnippet>96</a><span class="kw">impl </span>std::fmt::Debug <span class="kw">for </span>EncryptedInputFile {
-<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">fn </span>fmt(<span class="kw-2">&</span><span class="self">self</span>, f: <span class="kw-2">&mut </span>std::fmt::Formatter<<span class="lifetime">'_</span>>) -> std::fmt::Result {
-<a href=#98 id=98 data-nosnippet>98</a> f.debug_struct(<span class="string">"EncryptedInputFile"</span>)
-<a href=#99 id=99 data-nosnippet>99</a> .field(<span class="string">"path"</span>, <span class="kw-2">&</span><span class="self">self</span>.inner.location())
-<a href=#100 id=100 data-nosnippet>100</a> .finish_non_exhaustive()
+<a href=#85 id=85 data-nosnippet>85</a> <span class="comment">// A storage stat would hide truncation; require the original length from key metadata.
+<a href=#86 id=86 data-nosnippet>86</a> </span><span class="kw">fn </span>encrypted_length(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><u64> {
+<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">let </span>length = <span class="self">self</span>.key_metadata.file_length().ok_or_else(|| {
+<a href=#88 id=88 data-nosnippet>88</a> <span class="macro">invalid_data!</span>(<span class="string">"AGS1 key metadata is missing the encrypted file length"</span>)
+<a href=#89 id=89 data-nosnippet>89</a> })<span class="question-mark">?</span>;
+<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">if </span>length < u64::from(MIN_STREAM_LENGTH) {
+<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#92 id=92 data-nosnippet>92</a> <span class="string">"Invalid encrypted file length: {length} is less than {MIN_STREAM_LENGTH}"
+<a href=#93 id=93 data-nosnippet>93</a> </span>));
+<a href=#94 id=94 data-nosnippet>94</a> }
+<a href=#95 id=95 data-nosnippet>95</a> <span class="prelude-val">Ok</span>(length)
+<a href=#96 id=96 data-nosnippet>96</a> }
+<a href=#97 id=97 data-nosnippet>97</a>
+<a href=#98 id=98 data-nosnippet>98</a> <span class="doccomment">/// Returns a reference to the file's key metadata.
+<a href=#99 id=99 data-nosnippet>99</a> </span><span class="kw">pub fn </span>key_metadata(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="kw-2">&</span>StandardKeyMetadata {
+<a href=#100 id=100 data-nosnippet>100</a> <span class="kw-2">&</span><span class="self">self</span>.key_metadata
<a href=#101 id=101 data-nosnippet>101</a> }
-<a href=#102 id=102 data-nosnippet>102</a>}
-<a href=#103 id=103 data-nosnippet>103</a>
-<a href=#104 id=104 data-nosnippet>104</a><span class="doccomment">/// An AGS1 stream-encrypted output file wrapping a plain [`OutputFile`].
-<a href=#105 id=105 data-nosnippet>105</a>///
-<a href=#106 id=106 data-nosnippet>106</a>/// Transparently encrypts on write.
-<a href=#107 id=107 data-nosnippet>107</a></span><span class="kw">pub struct </span>EncryptedOutputFile {
-<a href=#108 id=108 data-nosnippet>108</a> inner: OutputFile,
-<a href=#109 id=109 data-nosnippet>109</a> key_metadata: StandardKeyMetadata,
-<a href=#110 id=110 data-nosnippet>110</a>}
-<a href=#111 id=111 data-nosnippet>111</a>
-<a href=#112 id=112 data-nosnippet>112</a><span class="kw">impl </span>EncryptedOutputFile {
-<a href=#113 id=113 data-nosnippet>113</a> <span class="doccomment">/// Creates a new encrypted output file.
-<a href=#114 id=114 data-nosnippet>114</a> </span><span class="kw">pub fn </span>new(inner: OutputFile, key_metadata: StandardKeyMetadata) -> <span class="self">Self </span>{
-<a href=#115 id=115 data-nosnippet>115</a> <span class="self">Self </span>{
-<a href=#116 id=116 data-nosnippet>116</a> inner,
-<a href=#117 id=117 data-nosnippet>117</a> key_metadata,
-<a href=#118 id=118 data-nosnippet>118</a> }
-<a href=#119 id=119 data-nosnippet>119</a> }
-<a href=#120 id=120 data-nosnippet>120</a>
-<a href=#121 id=121 data-nosnippet>121</a> <span class="doccomment">/// Returns a reference to the file's key metadata.
-<a href=#122 id=122 data-nosnippet>122</a> </span><span class="kw">pub fn </span>key_metadata(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="kw-2">&</span>StandardKeyMetadata {
-<a href=#123 id=123 data-nosnippet>123</a> <span class="kw-2">&</span><span class="self">self</span>.key_metadata
-<a href=#124 id=124 data-nosnippet>124</a> }
-<a href=#125 id=125 data-nosnippet>125</a>
-<a href=#126 id=126 data-nosnippet>126</a> <span class="doccomment">/// Absolute path of the file.
-<a href=#127 id=127 data-nosnippet>127</a> </span><span class="kw">pub fn </span>location(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="kw-2">&</span>str {
-<a href=#128 id=128 data-nosnippet>128</a> <span class="self">self</span>.inner.location()
-<a href=#129 id=129 data-nosnippet>129</a> }
-<a href=#130 id=130 data-nosnippet>130</a>
-<a href=#131 id=131 data-nosnippet>131</a> <span class="doccomment">/// Creates a writer that transparently encrypts on each write.
-<a href=#132 id=132 data-nosnippet>132</a> </span><span class="kw">pub async fn </span>writer(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><Box<<span class="kw">dyn </span>FileWrite>> {
-<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">let </span>raw_writer = <span class="self">self</span>.inner.writer().<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">let </span>cipher = build_cipher(<span class="kw-2">&</span><span class="self">self</span>.key_metadata)<span class="question-mark">?</span>;
-<a href=#135 id=135 data-nosnippet>135</a> <span class="kw">let </span>aad_prefix: Box<[u8]> = <span class="self">self</span>.key_metadata.aad_prefix().unwrap_or_default().into();
-<a href=#136 id=136 data-nosnippet>136</a> <span class="prelude-val">Ok</span>(Box::new(AesGcmFileWrite::new(
-<a href=#137 id=137 data-nosnippet>137</a> raw_writer, cipher, aad_prefix,
-<a href=#138 id=138 data-nosnippet>138</a> )))
-<a href=#139 id=139 data-nosnippet>139</a> }
-<a href=#140 id=140 data-nosnippet>140</a>
-<a href=#141 id=141 data-nosnippet>141</a> <span class="doccomment">/// Write bytes to file (transparently encrypted).
-<a href=#142 id=142 data-nosnippet>142</a> </span><span class="kw">pub async fn </span>write(<span class="kw-2">&</span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
-<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = <span class="self">self</span>.writer().<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#144 id=144 data-nosnippet>144</a> writer.write(bs).<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#145 id=145 data-nosnippet>145</a> writer.close().<span class="kw">await
-<a href=#146 id=146 data-nosnippet>146</a> </span>}
-<a href=#147 id=147 data-nosnippet>147</a>
-<a href=#148 id=148 data-nosnippet>148</a> <span class="doccomment">/// Deletes the underlying file.
-<a href=#149 id=149 data-nosnippet>149</a> </span><span class="kw">pub async fn </span>delete(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
-<a href=#150 id=150 data-nosnippet>150</a> <span class="self">self</span>.inner.delete().<span class="kw">await
-<a href=#151 id=151 data-nosnippet>151</a> </span>}
-<a href=#152 id=152 data-nosnippet>152</a>
-<a href=#153 id=153 data-nosnippet>153</a> <span class="doccomment">/// Consumes self and returns the underlying plain output file.
-<a href=#154 id=154 data-nosnippet>154</a> </span><span class="kw">pub fn </span>into_inner(<span class="self">self</span>) -> OutputFile {
-<a href=#155 id=155 data-nosnippet>155</a> <span class="self">self</span>.inner
-<a href=#156 id=156 data-nosnippet>156</a> }
-<a href=#157 id=157 data-nosnippet>157</a>}
+<a href=#102 id=102 data-nosnippet>102</a>
+<a href=#103 id=103 data-nosnippet>103</a> <span class="doccomment">/// Consumes self and returns the underlying plain input file.
+<a href=#104 id=104 data-nosnippet>104</a> </span><span class="kw">pub fn </span>into_inner(<span class="self">self</span>) -> InputFile {
+<a href=#105 id=105 data-nosnippet>105</a> <span class="self">self</span>.inner
+<a href=#106 id=106 data-nosnippet>106</a> }
+<a href=#107 id=107 data-nosnippet>107</a>}
+<a href=#108 id=108 data-nosnippet>108</a>
+<a href=#109 id=109 data-nosnippet>109</a><span class="kw">impl </span>std::fmt::Debug <span class="kw">for </span>EncryptedInputFile {
+<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">fn </span>fmt(<span class="kw-2">&</span><span class="self">self</span>, f: <span class="kw-2">&mut </span>std::fmt::Formatter<<span class="lifetime">'_</span>>) -> std::fmt::Result {
+<a href=#111 id=111 data-nosnippet>111</a> f.debug_struct(<span class="string">"EncryptedInputFile"</span>)
+<a href=#112 id=112 data-nosnippet>112</a> .field(<span class="string">"path"</span>, <span class="kw-2">&</span><span class="self">self</span>.inner.location())
+<a href=#113 id=113 data-nosnippet>113</a> .finish_non_exhaustive()
+<a href=#114 id=114 data-nosnippet>114</a> }
+<a href=#115 id=115 data-nosnippet>115</a>}
+<a href=#116 id=116 data-nosnippet>116</a>
+<a href=#117 id=117 data-nosnippet>117</a><span class="doccomment">/// An AGS1 stream-encrypted output file wrapping a plain [`OutputFile`].
+<a href=#118 id=118 data-nosnippet>118</a>///
+<a href=#119 id=119 data-nosnippet>119</a>/// Transparently encrypts on write.
+<a href=#120 id=120 data-nosnippet>120</a></span><span class="kw">pub struct </span>EncryptedOutputFile {
+<a href=#121 id=121 data-nosnippet>121</a> inner: OutputFile,
+<a href=#122 id=122 data-nosnippet>122</a> key_metadata: StandardKeyMetadata,
+<a href=#123 id=123 data-nosnippet>123</a>}
+<a href=#124 id=124 data-nosnippet>124</a>
+<a href=#125 id=125 data-nosnippet>125</a><span class="kw">impl </span>EncryptedOutputFile {
+<a href=#126 id=126 data-nosnippet>126</a> <span class="doccomment">/// Creates a new encrypted output file.
+<a href=#127 id=127 data-nosnippet>127</a> </span><span class="kw">pub fn </span>new(inner: OutputFile, key_metadata: StandardKeyMetadata) -> <span class="self">Self </span>{
+<a href=#128 id=128 data-nosnippet>128</a> <span class="self">Self </span>{
+<a href=#129 id=129 data-nosnippet>129</a> inner,
+<a href=#130 id=130 data-nosnippet>130</a> key_metadata,
+<a href=#131 id=131 data-nosnippet>131</a> }
+<a href=#132 id=132 data-nosnippet>132</a> }
+<a href=#133 id=133 data-nosnippet>133</a>
+<a href=#134 id=134 data-nosnippet>134</a> <span class="doccomment">/// Returns key metadata using the encrypted size returned by [`FileWrite::close`] or [`Self::write`].
+<a href=#135 id=135 data-nosnippet>135</a> </span><span class="kw">pub fn </span>key_metadata_with_saved_file_metadata(
+<a href=#136 id=136 data-nosnippet>136</a> <span class="kw-2">&</span><span class="self">self</span>,
+<a href=#137 id=137 data-nosnippet>137</a> file_metadata: <span class="kw-2">&</span>FileMetadata,
+<a href=#138 id=138 data-nosnippet>138</a> ) -> StandardKeyMetadata {
+<a href=#139 id=139 data-nosnippet>139</a> <span class="self">self</span>.key_metadata
+<a href=#140 id=140 data-nosnippet>140</a> .clone()
+<a href=#141 id=141 data-nosnippet>141</a> .with_file_length(file_metadata.size)
+<a href=#142 id=142 data-nosnippet>142</a> }
+<a href=#143 id=143 data-nosnippet>143</a>
+<a href=#144 id=144 data-nosnippet>144</a> <span class="doccomment">/// Absolute path of the file.
+<a href=#145 id=145 data-nosnippet>145</a> </span><span class="kw">pub fn </span>location(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="kw-2">&</span>str {
+<a href=#146 id=146 data-nosnippet>146</a> <span class="self">self</span>.inner.location()
+<a href=#147 id=147 data-nosnippet>147</a> }
+<a href=#148 id=148 data-nosnippet>148</a>
+<a href=#149 id=149 data-nosnippet>149</a> <span class="doccomment">/// Creates a writer that transparently encrypts on each write.
+<a href=#150 id=150 data-nosnippet>150</a> </span><span class="kw">pub async fn </span>writer(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><Box<<span class="kw">dyn </span>FileWrite>> {
+<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">let </span>raw_writer = <span class="self">self</span>.inner.writer().<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">let </span>cipher = build_cipher(<span class="kw-2">&</span><span class="self">self</span>.key_metadata)<span class="question-mark">?</span>;
+<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">let </span>aad_prefix: Box<[u8]> = <span class="self">self</span>.key_metadata.aad_prefix().unwrap_or_default().into();
+<a href=#154 id=154 data-nosnippet>154</a> <span class="prelude-val">Ok</span>(Box::new(AesGcmFileWrite::new(
+<a href=#155 id=155 data-nosnippet>155</a> raw_writer, cipher, aad_prefix,
+<a href=#156 id=156 data-nosnippet>156</a> )))
+<a href=#157 id=157 data-nosnippet>157</a> }
<a href=#158 id=158 data-nosnippet>158</a>
-<a href=#159 id=159 data-nosnippet>159</a><span class="kw">impl </span>std::fmt::Debug <span class="kw">for </span>EncryptedOutputFile {
-<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">fn </span>fmt(<span class="kw-2">&</span><span class="self">self</span>, f: <span class="kw-2">&mut </span>std::fmt::Formatter<<span class="lifetime">'_</span>>) -> std::fmt::Result {
-<a href=#161 id=161 data-nosnippet>161</a> f.debug_struct(<span class="string">"EncryptedOutputFile"</span>)
-<a href=#162 id=162 data-nosnippet>162</a> .field(<span class="string">"path"</span>, <span class="kw-2">&</span><span class="self">self</span>.inner.location())
-<a href=#163 id=163 data-nosnippet>163</a> .finish_non_exhaustive()
-<a href=#164 id=164 data-nosnippet>164</a> }
-<a href=#165 id=165 data-nosnippet>165</a>}
-<a href=#166 id=166 data-nosnippet>166</a>
-<a href=#167 id=167 data-nosnippet>167</a><span class="kw">fn </span>build_cipher(metadata: <span class="kw-2">&</span>StandardKeyMetadata) -> <span class="prelude-ty">Result</span><Arc<AesGcmCipher>> {
-<a href=#168 id=168 data-nosnippet>168</a> <span class="kw">let </span>key = metadata.encryption_key().clone();
-<a href=#169 id=169 data-nosnippet>169</a> <span class="prelude-val">Ok</span>(Arc::new(AesGcmCipher::new(key)))
-<a href=#170 id=170 data-nosnippet>170</a>}
-<a href=#171 id=171 data-nosnippet>171</a>
-<a href=#172 id=172 data-nosnippet>172</a><span class="attr">#[cfg(test)]
-<a href=#173 id=173 data-nosnippet>173</a></span><span class="kw">mod </span>tests {
-<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
-<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">use </span><span class="kw">crate</span>::io::FileIO;
+<a href=#159 id=159 data-nosnippet>159</a> <span class="doccomment">/// Write bytes to the file and return its encrypted size.
+<a href=#160 id=160 data-nosnippet>160</a> </span><span class="kw">pub async fn </span>write(<span class="kw-2">&</span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><FileMetadata> {
+<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = <span class="self">self</span>.writer().<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#162 id=162 data-nosnippet>162</a> writer.write(bs).<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#163 id=163 data-nosnippet>163</a> writer.close().<span class="kw">await
+<a href=#164 id=164 data-nosnippet>164</a> </span>}
+<a href=#165 id=165 data-nosnippet>165</a>
+<a href=#166 id=166 data-nosnippet>166</a> <span class="doccomment">/// Deletes the underlying file.
+<a href=#167 id=167 data-nosnippet>167</a> </span><span class="kw">pub async fn </span>delete(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
+<a href=#168 id=168 data-nosnippet>168</a> <span class="self">self</span>.inner.delete().<span class="kw">await
+<a href=#169 id=169 data-nosnippet>169</a> </span>}
+<a href=#170 id=170 data-nosnippet>170</a>
+<a href=#171 id=171 data-nosnippet>171</a> <span class="doccomment">/// Consumes self and returns the underlying plain output file.
+<a href=#172 id=172 data-nosnippet>172</a> </span><span class="kw">pub fn </span>into_inner(<span class="self">self</span>) -> OutputFile {
+<a href=#173 id=173 data-nosnippet>173</a> <span class="self">self</span>.inner
+<a href=#174 id=174 data-nosnippet>174</a> }
+<a href=#175 id=175 data-nosnippet>175</a>}
<a href=#176 id=176 data-nosnippet>176</a>
-<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">fn </span>key_metadata() -> StandardKeyMetadata {
-<a href=#178 id=178 data-nosnippet>178</a> StandardKeyMetadata::try_new(<span class="string">b"0123456789abcdef"</span>)
-<a href=#179 id=179 data-nosnippet>179</a> .unwrap()
-<a href=#180 id=180 data-nosnippet>180</a> .with_aad_prefix(<span class="string">b"test-aad-prefix!"</span>)
-<a href=#181 id=181 data-nosnippet>181</a> }
-<a href=#182 id=182 data-nosnippet>182</a>
-<a href=#183 id=183 data-nosnippet>183</a> <span class="attr">#[tokio::test]
-<a href=#184 id=184 data-nosnippet>184</a> </span><span class="kw">async fn </span>test_write_read_roundtrip() {
-<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
-<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">let </span>path = <span class="string">"memory:///test/io_roundtrip.bin"</span>;
-<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">let </span>plaintext = <span class="string">b"Hello from EncryptedInputFile/EncryptedOutputFile!"</span>;
-<a href=#188 id=188 data-nosnippet>188</a>
-<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
-<a href=#190 id=190 data-nosnippet>190</a> output.write(Bytes::from(plaintext.to_vec())).<span class="kw">await</span>.unwrap();
-<a href=#191 id=191 data-nosnippet>191</a>
-<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">let </span>input = EncryptedInputFile::new(fileio.new_input(path).unwrap(), key_metadata());
-<a href=#193 id=193 data-nosnippet>193</a> <span class="kw">let </span>content = input.read().<span class="kw">await</span>.unwrap();
-<a href=#194 id=194 data-nosnippet>194</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>content[..], plaintext);
-<a href=#195 id=195 data-nosnippet>195</a> }
-<a href=#196 id=196 data-nosnippet>196</a>
-<a href=#197 id=197 data-nosnippet>197</a> <span class="attr">#[tokio::test]
-<a href=#198 id=198 data-nosnippet>198</a> </span><span class="kw">async fn </span>test_metadata_returns_plaintext_size() {
-<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
-<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">let </span>path = <span class="string">"memory:///test/io_metadata.bin"</span>;
-<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">let </span>plaintext = <span class="string">b"some bytes to measure"</span>;
-<a href=#202 id=202 data-nosnippet>202</a>
-<a href=#203 id=203 data-nosnippet>203</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
-<a href=#204 id=204 data-nosnippet>204</a> output.write(Bytes::from(plaintext.to_vec())).<span class="kw">await</span>.unwrap();
-<a href=#205 id=205 data-nosnippet>205</a>
-<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">let </span>raw_size = fileio
-<a href=#207 id=207 data-nosnippet>207</a> .new_input(path)
-<a href=#208 id=208 data-nosnippet>208</a> .unwrap()
-<a href=#209 id=209 data-nosnippet>209</a> .metadata()
-<a href=#210 id=210 data-nosnippet>210</a> .<span class="kw">await
-<a href=#211 id=211 data-nosnippet>211</a> </span>.unwrap()
-<a href=#212 id=212 data-nosnippet>212</a> .size;
-<a href=#213 id=213 data-nosnippet>213</a> <span class="macro">assert!</span>(
-<a href=#214 id=214 data-nosnippet>214</a> raw_size > plaintext.len() <span class="kw">as </span>u64,
-<a href=#215 id=215 data-nosnippet>215</a> <span class="string">"encrypted file should be larger than plaintext (header + nonce + tag)"
-<a href=#216 id=216 data-nosnippet>216</a> </span>);
-<a href=#217 id=217 data-nosnippet>217</a>
-<a href=#218 id=218 data-nosnippet>218</a> <span class="kw">let </span>input = EncryptedInputFile::new(fileio.new_input(path).unwrap(), key_metadata());
-<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">let </span>meta = input.metadata().<span class="kw">await</span>.unwrap();
-<a href=#220 id=220 data-nosnippet>220</a> <span class="macro">assert_eq!</span>(meta.size, plaintext.len() <span class="kw">as </span>u64);
-<a href=#221 id=221 data-nosnippet>221</a> }
-<a href=#222 id=222 data-nosnippet>222</a>}
+<a href=#177 id=177 data-nosnippet>177</a><span class="kw">impl </span>std::fmt::Debug <span class="kw">for </span>EncryptedOutputFile {
+<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">fn </span>fmt(<span class="kw-2">&</span><span class="self">self</span>, f: <span class="kw-2">&mut </span>std::fmt::Formatter<<span class="lifetime">'_</span>>) -> std::fmt::Result {
+<a href=#179 id=179 data-nosnippet>179</a> f.debug_struct(<span class="string">"EncryptedOutputFile"</span>)
+<a href=#180 id=180 data-nosnippet>180</a> .field(<span class="string">"path"</span>, <span class="kw-2">&</span><span class="self">self</span>.inner.location())
+<a href=#181 id=181 data-nosnippet>181</a> .finish_non_exhaustive()
+<a href=#182 id=182 data-nosnippet>182</a> }
+<a href=#183 id=183 data-nosnippet>183</a>}
+<a href=#184 id=184 data-nosnippet>184</a>
+<a href=#185 id=185 data-nosnippet>185</a><span class="kw">fn </span>build_cipher(metadata: <span class="kw-2">&</span>StandardKeyMetadata) -> <span class="prelude-ty">Result</span><Arc<AesGcmCipher>> {
+<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">let </span>key = metadata.encryption_key().clone();
+<a href=#187 id=187 data-nosnippet>187</a> <span class="prelude-val">Ok</span>(Arc::new(AesGcmCipher::new(key)))
+<a href=#188 id=188 data-nosnippet>188</a>}
+<a href=#189 id=189 data-nosnippet>189</a>
+<a href=#190 id=190 data-nosnippet>190</a><span class="attr">#[cfg(test)]
+<a href=#191 id=191 data-nosnippet>191</a></span><span class="kw">mod </span>tests {
+<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
+<a href=#193 id=193 data-nosnippet>193</a> <span class="kw">use </span><span class="kw">crate</span>::ErrorKind;
+<a href=#194 id=194 data-nosnippet>194</a> <span class="kw">use </span><span class="kw">crate</span>::encryption::stream::{
+<a href=#195 id=195 data-nosnippet>195</a> CIPHER_BLOCK_SIZE, GCM_STREAM_HEADER_LENGTH, PLAIN_BLOCK_SIZE,
+<a href=#196 id=196 data-nosnippet>196</a> };
+<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">use </span><span class="kw">crate</span>::io::FileIO;
+<a href=#198 id=198 data-nosnippet>198</a>
+<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">fn </span>key_metadata() -> StandardKeyMetadata {
+<a href=#200 id=200 data-nosnippet>200</a> StandardKeyMetadata::try_new(<span class="string">b"0123456789abcdef"</span>)
+<a href=#201 id=201 data-nosnippet>201</a> .unwrap()
+<a href=#202 id=202 data-nosnippet>202</a> .with_aad_prefix(<span class="string">b"test-aad-prefix!"</span>)
+<a href=#203 id=203 data-nosnippet>203</a> }
+<a href=#204 id=204 data-nosnippet>204</a>
+<a href=#205 id=205 data-nosnippet>205</a> <span class="attr">#[tokio::test]
+<a href=#206 id=206 data-nosnippet>206</a> </span><span class="kw">async fn </span>test_write_read_roundtrip() {
+<a href=#207 id=207 data-nosnippet>207</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
+<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">let </span>path = <span class="string">"memory:///test/io_roundtrip.bin"</span>;
+<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">let </span>plaintext = <span class="string">b"Hello from EncryptedInputFile/EncryptedOutputFile!"</span>;
+<a href=#210 id=210 data-nosnippet>210</a>
+<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
+<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">let </span>file_metadata = output.write(Bytes::from(plaintext.to_vec())).<span class="kw">await</span>.unwrap();
+<a href=#213 id=213 data-nosnippet>213</a>
+<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">let </span>input = EncryptedInputFile::new(
+<a href=#215 id=215 data-nosnippet>215</a> fileio.new_input(path).unwrap(),
+<a href=#216 id=216 data-nosnippet>216</a> output.key_metadata_with_saved_file_metadata(<span class="kw-2">&</span>file_metadata),
+<a href=#217 id=217 data-nosnippet>217</a> );
+<a href=#218 id=218 data-nosnippet>218</a> <span class="kw">let </span>content = input.read().<span class="kw">await</span>.unwrap();
+<a href=#219 id=219 data-nosnippet>219</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>content[..], plaintext);
+<a href=#220 id=220 data-nosnippet>220</a> }
+<a href=#221 id=221 data-nosnippet>221</a>
+<a href=#222 id=222 data-nosnippet>222</a> <span class="attr">#[tokio::test]
+<a href=#223 id=223 data-nosnippet>223</a> </span><span class="kw">async fn </span>test_metadata_returns_plaintext_size() {
+<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
+<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">let </span>path = <span class="string">"memory:///test/io_metadata.bin"</span>;
+<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">let </span>plaintext = <span class="string">b"some bytes to measure"</span>;
+<a href=#227 id=227 data-nosnippet>227</a>
+<a href=#228 id=228 data-nosnippet>228</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
+<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>file_metadata = output.write(Bytes::from(plaintext.to_vec())).<span class="kw">await</span>.unwrap();
+<a href=#230 id=230 data-nosnippet>230</a>
+<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">let </span>raw_size = fileio
+<a href=#232 id=232 data-nosnippet>232</a> .new_input(path)
+<a href=#233 id=233 data-nosnippet>233</a> .unwrap()
+<a href=#234 id=234 data-nosnippet>234</a> .metadata()
+<a href=#235 id=235 data-nosnippet>235</a> .<span class="kw">await
+<a href=#236 id=236 data-nosnippet>236</a> </span>.unwrap()
+<a href=#237 id=237 data-nosnippet>237</a> .size;
+<a href=#238 id=238 data-nosnippet>238</a> <span class="macro">assert!</span>(
+<a href=#239 id=239 data-nosnippet>239</a> raw_size > plaintext.len() <span class="kw">as </span>u64,
+<a href=#240 id=240 data-nosnippet>240</a> <span class="string">"encrypted file should be larger than plaintext (header + nonce + tag)"
+<a href=#241 id=241 data-nosnippet>241</a> </span>);
+<a href=#242 id=242 data-nosnippet>242</a>
+<a href=#243 id=243 data-nosnippet>243</a> <span class="comment">// A missing path proves the size comes from the key metadata rather than a stat call.
+<a href=#244 id=244 data-nosnippet>244</a> </span><span class="kw">let </span>input = EncryptedInputFile::new(
+<a href=#245 id=245 data-nosnippet>245</a> fileio.new_input(<span class="string">"memory:///does-not-exist"</span>).unwrap(),
+<a href=#246 id=246 data-nosnippet>246</a> output.key_metadata_with_saved_file_metadata(<span class="kw-2">&</span>file_metadata),
+<a href=#247 id=247 data-nosnippet>247</a> );
+<a href=#248 id=248 data-nosnippet>248</a> <span class="kw">let </span>meta = input.metadata().unwrap();
+<a href=#249 id=249 data-nosnippet>249</a> <span class="macro">assert_eq!</span>(meta.size, plaintext.len() <span class="kw">as </span>u64);
+<a href=#250 id=250 data-nosnippet>250</a> }
+<a href=#251 id=251 data-nosnippet>251</a>
+<a href=#252 id=252 data-nosnippet>252</a> <span class="attr">#[tokio::test]
+<a href=#253 id=253 data-nosnippet>253</a> </span><span class="kw">async fn </span>test_missing_file_length_is_rejected() {
+<a href=#254 id=254 data-nosnippet>254</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
+<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">let </span>path = <span class="string">"memory:///test/missing_length.bin"</span>;
+<a href=#256 id=256 data-nosnippet>256</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
+<a href=#257 id=257 data-nosnippet>257</a> output.write(Bytes::from_static(<span class="string">b"data"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">let </span>input = EncryptedInputFile::new(fileio.new_input(path).unwrap(), key_metadata());
+<a href=#259 id=259 data-nosnippet>259</a>
+<a href=#260 id=260 data-nosnippet>260</a> <span class="kw">for </span>err <span class="kw">in </span>[
+<a href=#261 id=261 data-nosnippet>261</a> input.metadata().err().unwrap(),
+<a href=#262 id=262 data-nosnippet>262</a> input.reader().<span class="kw">await</span>.err().unwrap(),
+<a href=#263 id=263 data-nosnippet>263</a> input.read().<span class="kw">await</span>.unwrap_err(),
+<a href=#264 id=264 data-nosnippet>264</a> ] {
+<a href=#265 id=265 data-nosnippet>265</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#266 id=266 data-nosnippet>266</a> <span class="macro">assert!</span>(
+<a href=#267 id=267 data-nosnippet>267</a> err.to_string()
+<a href=#268 id=268 data-nosnippet>268</a> .contains(<span class="string">"missing the encrypted file length"</span>)
+<a href=#269 id=269 data-nosnippet>269</a> );
+<a href=#270 id=270 data-nosnippet>270</a> }
+<a href=#271 id=271 data-nosnippet>271</a> }
+<a href=#272 id=272 data-nosnippet>272</a>
+<a href=#273 id=273 data-nosnippet>273</a> <span class="attr">#[tokio::test]
+<a href=#274 id=274 data-nosnippet>274</a> </span><span class="kw">async fn </span>test_invalid_file_length_is_rejected() {
+<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
+<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">for </span>length <span class="kw">in </span>[
+<a href=#277 id=277 data-nosnippet>277</a> <span class="number">0</span>,
+<a href=#278 id=278 data-nosnippet>278</a> u64::from(GCM_STREAM_HEADER_LENGTH),
+<a href=#279 id=279 data-nosnippet>279</a> u64::from(MIN_STREAM_LENGTH - <span class="number">1</span>),
+<a href=#280 id=280 data-nosnippet>280</a> ] {
+<a href=#281 id=281 data-nosnippet>281</a> <span class="kw">let </span>input = EncryptedInputFile::new(
+<a href=#282 id=282 data-nosnippet>282</a> fileio
+<a href=#283 id=283 data-nosnippet>283</a> .new_input(<span class="string">"memory:///test/invalid_length.bin"</span>)
+<a href=#284 id=284 data-nosnippet>284</a> .unwrap(),
+<a href=#285 id=285 data-nosnippet>285</a> key_metadata().with_file_length(length),
+<a href=#286 id=286 data-nosnippet>286</a> );
+<a href=#287 id=287 data-nosnippet>287</a> <span class="macro">assert_eq!</span>(
+<a href=#288 id=288 data-nosnippet>288</a> input.metadata().err().unwrap().kind(),
+<a href=#289 id=289 data-nosnippet>289</a> ErrorKind::DataInvalid
+<a href=#290 id=290 data-nosnippet>290</a> );
+<a href=#291 id=291 data-nosnippet>291</a> <span class="macro">assert_eq!</span>(
+<a href=#292 id=292 data-nosnippet>292</a> input.reader().<span class="kw">await</span>.err().unwrap().kind(),
+<a href=#293 id=293 data-nosnippet>293</a> ErrorKind::DataInvalid
+<a href=#294 id=294 data-nosnippet>294</a> );
+<a href=#295 id=295 data-nosnippet>295</a> }
+<a href=#296 id=296 data-nosnippet>296</a> }
+<a href=#297 id=297 data-nosnippet>297</a>
+<a href=#298 id=298 data-nosnippet>298</a> <span class="attr">#[tokio::test]
+<a href=#299 id=299 data-nosnippet>299</a> </span><span class="kw">async fn </span>test_oversized_file_length_is_rejected() {
+<a href=#300 id=300 data-nosnippet>300</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
+<a href=#301 id=301 data-nosnippet>301</a> <span class="kw">let </span>path = <span class="string">"memory:///test/oversized_length.bin"</span>;
+<a href=#302 id=302 data-nosnippet>302</a> <span class="kw">let </span>plaintext = Bytes::from_static(<span class="string">b"some bytes to measure"</span>);
+<a href=#303 id=303 data-nosnippet>303</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
+<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">let </span>file_metadata = output.write(plaintext.clone()).<span class="kw">await</span>.unwrap();
+<a href=#305 id=305 data-nosnippet>305</a>
+<a href=#306 id=306 data-nosnippet>306</a> <span class="comment">// A declared length is trusted without a stat, so an inflated one is only caught once a
+<a href=#307 id=307 data-nosnippet>307</a> // read runs off the end of the real file. Both a minimal overstatement and one spanning a
+<a href=#308 id=308 data-nosnippet>308</a> // whole extra block must fail rather than silently return short plaintext.
+<a href=#309 id=309 data-nosnippet>309</a> </span><span class="kw">for </span>excess <span class="kw">in </span>[<span class="number">1</span>, u64::from(CIPHER_BLOCK_SIZE)] {
+<a href=#310 id=310 data-nosnippet>310</a> <span class="kw">let </span>input = EncryptedInputFile::new(
+<a href=#311 id=311 data-nosnippet>311</a> fileio.new_input(path).unwrap(),
+<a href=#312 id=312 data-nosnippet>312</a> key_metadata().with_file_length(file_metadata.size + excess),
+<a href=#313 id=313 data-nosnippet>313</a> );
+<a href=#314 id=314 data-nosnippet>314</a>
+<a href=#315 id=315 data-nosnippet>315</a> <span class="kw">let </span>inflated_size = input.metadata().unwrap().size;
+<a href=#316 id=316 data-nosnippet>316</a> <span class="macro">assert!</span>(inflated_size > plaintext.len() <span class="kw">as </span>u64);
+<a href=#317 id=317 data-nosnippet>317</a>
+<a href=#318 id=318 data-nosnippet>318</a> <span class="macro">assert_eq!</span>(
+<a href=#319 id=319 data-nosnippet>319</a> input.read().<span class="kw">await</span>.unwrap_err().kind(),
+<a href=#320 id=320 data-nosnippet>320</a> ErrorKind::DataInvalid
+<a href=#321 id=321 data-nosnippet>321</a> );
+<a href=#322 id=322 data-nosnippet>322</a>
+<a href=#323 id=323 data-nosnippet>323</a> <span class="comment">// Not even the bytes that genuinely are on disk can be read back.
+<a href=#324 id=324 data-nosnippet>324</a> </span><span class="kw">let </span>reader = input.reader().<span class="kw">await</span>.unwrap();
+<a href=#325 id=325 data-nosnippet>325</a> <span class="macro">assert_eq!</span>(
+<a href=#326 id=326 data-nosnippet>326</a> reader
+<a href=#327 id=327 data-nosnippet>327</a> .read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64)
+<a href=#328 id=328 data-nosnippet>328</a> .<span class="kw">await
+<a href=#329 id=329 data-nosnippet>329</a> </span>.unwrap_err()
+<a href=#330 id=330 data-nosnippet>330</a> .kind(),
+<a href=#331 id=331 data-nosnippet>331</a> ErrorKind::DataInvalid
+<a href=#332 id=332 data-nosnippet>332</a> );
+<a href=#333 id=333 data-nosnippet>333</a> }
+<a href=#334 id=334 data-nosnippet>334</a> }
+<a href=#335 id=335 data-nosnippet>335</a>
+<a href=#336 id=336 data-nosnippet>336</a> <span class="attr">#[tokio::test]
+<a href=#337 id=337 data-nosnippet>337</a> </span><span class="kw">async fn </span>test_truncated_file_is_rejected() {
+<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
+<a href=#339 id=339 data-nosnippet>339</a> <span class="kw">let </span>path = <span class="string">"memory:///test/truncated.bin"</span>;
+<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">let </span>plaintext = Bytes::from(<span class="macro">vec!</span>[<span class="number">42</span>; <span class="number">2 </span>* PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + <span class="number">17</span>]);
+<a href=#341 id=341 data-nosnippet>341</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
+<a href=#342 id=342 data-nosnippet>342</a> <span class="kw">let </span>file_metadata = output.write(plaintext.clone()).<span class="kw">await</span>.unwrap();
+<a href=#343 id=343 data-nosnippet>343</a> <span class="kw">let </span>metadata = key_metadata().with_file_length(file_metadata.size);
+<a href=#344 id=344 data-nosnippet>344</a> <span class="kw">let </span>ciphertext = fileio.new_input(path).unwrap().read().<span class="kw">await</span>.unwrap();
+<a href=#345 id=345 data-nosnippet>345</a> <span class="kw">let </span>truncated_length = (GCM_STREAM_HEADER_LENGTH + CIPHER_BLOCK_SIZE) <span class="kw">as </span>usize;
+<a href=#346 id=346 data-nosnippet>346</a> fileio
+<a href=#347 id=347 data-nosnippet>347</a> .new_output(path)
+<a href=#348 id=348 data-nosnippet>348</a> .unwrap()
+<a href=#349 id=349 data-nosnippet>349</a> .write(ciphertext.slice(..truncated_length))
+<a href=#350 id=350 data-nosnippet>350</a> .<span class="kw">await
+<a href=#351 id=351 data-nosnippet>351</a> </span>.unwrap();
+<a href=#352 id=352 data-nosnippet>352</a>
+<a href=#353 id=353 data-nosnippet>353</a> <span class="kw">let </span>input = EncryptedInputFile::new(fileio.new_input(path).unwrap(), metadata);
+<a href=#354 id=354 data-nosnippet>354</a> <span class="macro">assert_eq!</span>(input.metadata().unwrap().size, plaintext.len() <span class="kw">as </span>u64);
+<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">let </span>reader = input.reader().<span class="kw">await</span>.unwrap();
+<a href=#356 id=356 data-nosnippet>356</a> <span class="macro">assert_eq!</span>(
+<a href=#357 id=357 data-nosnippet>357</a> reader.read(<span class="number">0</span>..u64::from(PLAIN_BLOCK_SIZE)).<span class="kw">await</span>.unwrap(),
+<a href=#358 id=358 data-nosnippet>358</a> plaintext.slice(..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize)
+<a href=#359 id=359 data-nosnippet>359</a> );
+<a href=#360 id=360 data-nosnippet>360</a> <span class="macro">assert_eq!</span>(
+<a href=#361 id=361 data-nosnippet>361</a> input.read().<span class="kw">await</span>.unwrap_err().kind(),
+<a href=#362 id=362 data-nosnippet>362</a> ErrorKind::DataInvalid
+<a href=#363 id=363 data-nosnippet>363</a> );
+<a href=#364 id=364 data-nosnippet>364</a> }
+<a href=#365 id=365 data-nosnippet>365</a>
+<a href=#366 id=366 data-nosnippet>366</a> <span class="attr">#[tokio::test]
+<a href=#367 id=367 data-nosnippet>367</a> </span><span class="kw">async fn </span>test_truncated_empty_file_is_rejected() {
+<a href=#368 id=368 data-nosnippet>368</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
+<a href=#369 id=369 data-nosnippet>369</a> <span class="kw">let </span>path = <span class="string">"memory:///test/truncated_empty.bin"</span>;
+<a href=#370 id=370 data-nosnippet>370</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
+<a href=#371 id=371 data-nosnippet>371</a> <span class="kw">let </span>file_metadata = output.write(Bytes::new()).<span class="kw">await</span>.unwrap();
+<a href=#372 id=372 data-nosnippet>372</a> <span class="kw">let </span>metadata = key_metadata().with_file_length(file_metadata.size);
+<a href=#373 id=373 data-nosnippet>373</a> <span class="kw">let </span>ciphertext = fileio.new_input(path).unwrap().read().<span class="kw">await</span>.unwrap();
+<a href=#374 id=374 data-nosnippet>374</a> fileio
+<a href=#375 id=375 data-nosnippet>375</a> .new_output(path)
+<a href=#376 id=376 data-nosnippet>376</a> .unwrap()
+<a href=#377 id=377 data-nosnippet>377</a> .write(ciphertext.slice(..GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>usize))
+<a href=#378 id=378 data-nosnippet>378</a> .<span class="kw">await
+<a href=#379 id=379 data-nosnippet>379</a> </span>.unwrap();
+<a href=#380 id=380 data-nosnippet>380</a> <span class="kw">let </span>input = EncryptedInputFile::new(fileio.new_input(path).unwrap(), metadata);
+<a href=#381 id=381 data-nosnippet>381</a> <span class="macro">assert_eq!</span>(
+<a href=#382 id=382 data-nosnippet>382</a> input.read().<span class="kw">await</span>.unwrap_err().kind(),
+<a href=#383 id=383 data-nosnippet>383</a> ErrorKind::DataInvalid
+<a href=#384 id=384 data-nosnippet>384</a> );
+<a href=#385 id=385 data-nosnippet>385</a> }
+<a href=#386 id=386 data-nosnippet>386</a>
+<a href=#387 id=387 data-nosnippet>387</a> <span class="attr">#[tokio::test]
+<a href=#388 id=388 data-nosnippet>388</a> </span><span class="kw">async fn </span>test_close_returns_encrypted_size() {
+<a href=#389 id=389 data-nosnippet>389</a> <span class="kw">let </span>fileio = FileIO::new_with_memory();
+<a href=#390 id=390 data-nosnippet>390</a> <span class="kw">let </span>path = <span class="string">"memory:///test/streaming.bin"</span>;
+<a href=#391 id=391 data-nosnippet>391</a> <span class="kw">let </span>output = EncryptedOutputFile::new(fileio.new_output(path).unwrap(), key_metadata());
+<a href=#392 id=392 data-nosnippet>392</a> <span class="kw">for </span>plaintext <span class="kw">in </span>[
+<a href=#393 id=393 data-nosnippet>393</a> Bytes::from(<span class="macro">vec!</span>[<span class="number">42</span>; PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + <span class="number">17</span>]),
+<a href=#394 id=394 data-nosnippet>394</a> Bytes::new(),
+<a href=#395 id=395 data-nosnippet>395</a> ] {
+<a href=#396 id=396 data-nosnippet>396</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = output.writer().<span class="kw">await</span>.unwrap();
+<a href=#397 id=397 data-nosnippet>397</a> <span class="kw">for </span>chunk <span class="kw">in </span>plaintext.chunks(<span class="number">1024</span>) {
+<a href=#398 id=398 data-nosnippet>398</a> writer.write(Bytes::copy_from_slice(chunk)).<span class="kw">await</span>.unwrap();
+<a href=#399 id=399 data-nosnippet>399</a> }
+<a href=#400 id=400 data-nosnippet>400</a> <span class="kw">let </span>metadata = writer.close().<span class="kw">await</span>.unwrap();
+<a href=#401 id=401 data-nosnippet>401</a> <span class="kw">let </span>size = fileio
+<a href=#402 id=402 data-nosnippet>402</a> .new_input(path)
+<a href=#403 id=403 data-nosnippet>403</a> .unwrap()
+<a href=#404 id=404 data-nosnippet>404</a> .metadata()
+<a href=#405 id=405 data-nosnippet>405</a> .<span class="kw">await
+<a href=#406 id=406 data-nosnippet>406</a> </span>.unwrap()
+<a href=#407 id=407 data-nosnippet>407</a> .size;
+<a href=#408 id=408 data-nosnippet>408</a> <span class="macro">assert_eq!</span>(metadata.size, size);
+<a href=#409 id=409 data-nosnippet>409</a> }
+<a href=#410 id=410 data-nosnippet>410</a> }
+<a href=#411 id=411 data-nosnippet>411</a>}
</code></pre></div></section></main></body></html>
\ No newline at end of file
diff --git a/api/src/iceberg/encryption/key_metadata.rs.html b/api/src/iceberg/encryption/key_metadata.rs.html
index c14a2421b..45e937e17 100644
--- a/api/src/iceberg/encryption/key_metadata.rs.html
+++ b/api/src/iceberg/encryption/key_metadata.rs.html
@@ -75,7 +75,7 @@
<a href=#75 id=75 data-nosnippet>75</a> <span class="self">self
<a href=#76 id=76 data-nosnippet>76</a> </span>}
<a href=#77 id=77 data-nosnippet>77</a>
-<a href=#78 id=78 data-nosnippet>78</a> <span class="doccomment">/// Adds a file length.
+<a href=#78 id=78 data-nosnippet>78</a> <span class="doccomment">/// Sets the encrypted file length in bytes, required for AGS1 truncation protection.
<a href=#79 id=79 data-nosnippet>79</a> </span><span class="kw">pub fn </span>with_file_length(<span class="kw-2">mut </span><span class="self">self</span>, length: u64) -> <span class="self">Self </span>{
<a href=#80 id=80 data-nosnippet>80</a> <span class="self">self</span>.file_length = <span class="prelude-val">Some</span>(length);
<a href=#81 id=81 data-nosnippet>81</a> <span class="self">self
@@ -91,7 +91,7 @@
<a href=#91 id=91 data-nosnippet>91</a> <span class="self">self</span>.aad_prefix.as_deref()
<a href=#92 id=92 data-nosnippet>92</a> }
<a href=#93 id=93 data-nosnippet>93</a>
-<a href=#94 id=94 data-nosnippet>94</a> <span class="doccomment">/// Returns the optional file length.
+<a href=#94 id=94 data-nosnippet>94</a> <span class="doccomment">/// Returns the optional encrypted file length in bytes; AGS1 readers require it to be set.
<a href=#95 id=95 data-nosnippet>95</a> </span><span class="kw">pub fn </span>file_length(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Option</span><u64> {
<a href=#96 id=96 data-nosnippet>96</a> <span class="self">self</span>.file_length
<a href=#97 id=97 data-nosnippet>97</a> }
diff --git a/api/src/iceberg/encryption/manager.rs.html b/api/src/iceberg/encryption/manager.rs.html
index a90476c7e..8de795946 100644
--- a/api/src/iceberg/encryption/manager.rs.html
+++ b/api/src/iceberg/encryption/manager.rs.html
@@ -670,18 +670,22 @@
<a href=#670 id=670 data-nosnippet>670</a> <span class="kw">let </span>encrypted_output = mgr.encrypt(output);
<a href=#671 id=671 data-nosnippet>671</a>
<a href=#672 id=672 data-nosnippet>672</a> <span class="kw">let </span>plaintext = <span class="string">b"Hello, encrypted Iceberg round-trip!"</span>;
-<a href=#673 id=673 data-nosnippet>673</a> <span class="kw">let </span>serialized_metadata = encrypted_output.key_metadata().encode().unwrap();
-<a href=#674 id=674 data-nosnippet>674</a> encrypted_output
-<a href=#675 id=675 data-nosnippet>675</a> .write(bytes::Bytes::from(plaintext.to_vec()))
-<a href=#676 id=676 data-nosnippet>676</a> .<span class="kw">await
-<a href=#677 id=677 data-nosnippet>677</a> </span>.unwrap();
-<a href=#678 id=678 data-nosnippet>678</a>
-<a href=#679 id=679 data-nosnippet>679</a> <span class="kw">let </span>input = io.new_input(path).unwrap();
-<a href=#680 id=680 data-nosnippet>680</a> <span class="kw">let </span>parsed_metadata = StandardKeyMetadata::decode(<span class="kw-2">&</span>serialized_metadata).unwrap();
-<a href=#681 id=681 data-nosnippet>681</a> <span class="kw">let </span>decrypted_file = EncryptedInputFile::new(input, parsed_metadata);
+<a href=#673 id=673 data-nosnippet>673</a> <span class="kw">let </span>file_metadata = encrypted_output
+<a href=#674 id=674 data-nosnippet>674</a> .write(bytes::Bytes::from(plaintext.to_vec()))
+<a href=#675 id=675 data-nosnippet>675</a> .<span class="kw">await
+<a href=#676 id=676 data-nosnippet>676</a> </span>.unwrap();
+<a href=#677 id=677 data-nosnippet>677</a>
+<a href=#678 id=678 data-nosnippet>678</a> <span class="kw">let </span>serialized_metadata = encrypted_output
+<a href=#679 id=679 data-nosnippet>679</a> .key_metadata_with_saved_file_metadata(<span class="kw-2">&</span>file_metadata)
+<a href=#680 id=680 data-nosnippet>680</a> .encode()
+<a href=#681 id=681 data-nosnippet>681</a> .unwrap();
<a href=#682 id=682 data-nosnippet>682</a>
-<a href=#683 id=683 data-nosnippet>683</a> <span class="kw">let </span>content = decrypted_file.read().<span class="kw">await</span>.unwrap();
-<a href=#684 id=684 data-nosnippet>684</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>content[..], plaintext);
-<a href=#685 id=685 data-nosnippet>685</a> }
-<a href=#686 id=686 data-nosnippet>686</a>}
+<a href=#683 id=683 data-nosnippet>683</a> <span class="kw">let </span>input = io.new_input(path).unwrap();
+<a href=#684 id=684 data-nosnippet>684</a> <span class="kw">let </span>parsed_metadata = StandardKeyMetadata::decode(<span class="kw-2">&</span>serialized_metadata).unwrap();
+<a href=#685 id=685 data-nosnippet>685</a> <span class="kw">let </span>decrypted_file = EncryptedInputFile::new(input, parsed_metadata);
+<a href=#686 id=686 data-nosnippet>686</a>
+<a href=#687 id=687 data-nosnippet>687</a> <span class="kw">let </span>content = decrypted_file.read().<span class="kw">await</span>.unwrap();
+<a href=#688 id=688 data-nosnippet>688</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>content[..], plaintext);
+<a href=#689 id=689 data-nosnippet>689</a> }
+<a href=#690 id=690 data-nosnippet>690</a>}
</code></pre></div></section></main></body></html>
\ No newline at end of file
diff --git a/api/src/iceberg/encryption/stream.rs.html b/api/src/iceberg/encryption/stream.rs.html
index eece2d2ea..5629a2ec3 100644
--- a/api/src/iceberg/encryption/stream.rs.html
+++ b/api/src/iceberg/encryption/stream.rs.html
@@ -50,7 +50,7 @@
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">use </span><span class="kw">super</span>::AesGcmCipher;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">use </span><span class="kw">crate</span>::error::invalid_data;
-<a href=#53 id=53 data-nosnippet>53</a><span class="kw">use </span><span class="kw">crate</span>::io::{FileRead, FileWrite};
+<a href=#53 id=53 data-nosnippet>53</a><span class="kw">use </span><span class="kw">crate</span>::io::{FileMetadata, FileRead, FileWrite};
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">use </span>crate::{Error, ErrorKind, <span class="prelude-ty">Result</span>};
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="doccomment">/// Default plaintext block size (1 MiB), matching Java's `Ciphers.PLAIN_BLOCK_SIZE`.
@@ -72,651 +72,651 @@
<a href=#72 id=72 data-nosnippet>72</a></span><span class="kw">pub const </span>GCM_STREAM_HEADER_LENGTH: u32 = <span class="number">8</span>;
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a><span class="doccomment">/// Minimum valid AGS1 stream length (header + one empty block).
-<a href=#75 id=75 data-nosnippet>75</a></span><span class="attr">#[cfg(test)]
-<a href=#76 id=76 data-nosnippet>76</a></span><span class="kw">pub const </span>MIN_STREAM_LENGTH: u32 = GCM_STREAM_HEADER_LENGTH + NONCE_LENGTH + GCM_TAG_LENGTH;
-<a href=#77 id=77 data-nosnippet>77</a>
-<a href=#78 id=78 data-nosnippet>78</a><span class="doccomment">/// Constructs the per-block AAD for AGS1 stream encryption.
-<a href=#79 id=79 data-nosnippet>79</a>///
-<a href=#80 id=80 data-nosnippet>80</a>/// Format: `aad_prefix || block_index (4 bytes, little-endian)`
-<a href=#81 id=81 data-nosnippet>81</a>///
-<a href=#82 id=82 data-nosnippet>82</a>/// This matches Java's `Ciphers.streamBlockAAD()`.
-<a href=#83 id=83 data-nosnippet>83</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>stream_block_aad(aad_prefix: <span class="kw-2">&</span>[u8], block_index: u32) -> Vec<u8> {
-<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">let </span>index_bytes = block_index.to_le_bytes();
-<a href=#85 id=85 data-nosnippet>85</a> <span class="kw">if </span>aad_prefix.is_empty() {
-<a href=#86 id=86 data-nosnippet>86</a> index_bytes.to_vec()
-<a href=#87 id=87 data-nosnippet>87</a> } <span class="kw">else </span>{
-<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">let </span><span class="kw-2">mut </span>aad = Vec::with_capacity(aad_prefix.len() + <span class="number">4</span>);
-<a href=#89 id=89 data-nosnippet>89</a> aad.extend_from_slice(aad_prefix);
-<a href=#90 id=90 data-nosnippet>90</a> aad.extend_from_slice(<span class="kw-2">&</span>index_bytes);
-<a href=#91 id=91 data-nosnippet>91</a> aad
-<a href=#92 id=92 data-nosnippet>92</a> }
-<a href=#93 id=93 data-nosnippet>93</a>}
-<a href=#94 id=94 data-nosnippet>94</a>
-<a href=#95 id=95 data-nosnippet>95</a><span class="doccomment">/// Transparent decryption of AGS1 stream-encrypted files.
-<a href=#96 id=96 data-nosnippet>96</a>///
-<a href=#97 id=97 data-nosnippet>97</a>/// Implements the [`FileRead`] trait, providing random-access reads over
-<a href=#98 id=98 data-nosnippet>98</a>/// encrypted data. Each `read()` call determines which encrypted blocks
-<a href=#99 id=99 data-nosnippet>99</a>/// overlap the requested plaintext range, reads and decrypts them, then
-<a href=#100 id=100 data-nosnippet>100</a>/// returns the requested plaintext bytes.
-<a href=#101 id=101 data-nosnippet>101</a>///
-<a href=#102 id=102 data-nosnippet>102</a>/// # Usage
-<a href=#103 id=103 data-nosnippet>103</a>///
-<a href=#104 id=104 data-nosnippet>104</a>/// ```ignore
-<a href=#105 id=105 data-nosnippet>105</a>/// // (ignored: requires async runtime and concrete FileRead/FileWrite impls)
-<a href=#106 id=106 data-nosnippet>106</a>/// let reader = AesGcmFileRead::new(
-<a href=#107 id=107 data-nosnippet>107</a>/// inner_reader, // Box<dyn FileRead> for the encrypted file
-<a href=#108 id=108 data-nosnippet>108</a>/// cipher, // Arc<AesGcmCipher> with the DEK
-<a href=#109 id=109 data-nosnippet>109</a>/// aad_prefix.to_vec(),
-<a href=#110 id=110 data-nosnippet>110</a>/// encrypted_file_length,
-<a href=#111 id=111 data-nosnippet>111</a>/// )?;
-<a href=#112 id=112 data-nosnippet>112</a>///
-<a href=#113 id=113 data-nosnippet>113</a>/// // Read plaintext bytes transparently
-<a href=#114 id=114 data-nosnippet>114</a>/// let plaintext = reader.read(0..1024).await?;
-<a href=#115 id=115 data-nosnippet>115</a>/// ```
-<a href=#116 id=116 data-nosnippet>116</a></span><span class="kw">pub struct </span>AesGcmFileRead {
-<a href=#117 id=117 data-nosnippet>117</a> <span class="doccomment">/// The underlying encrypted file reader.
-<a href=#118 id=118 data-nosnippet>118</a> </span>inner: Box<<span class="kw">dyn </span>FileRead>,
-<a href=#119 id=119 data-nosnippet>119</a> <span class="doccomment">/// The AES-GCM cipher holding the DEK.
-<a href=#120 id=120 data-nosnippet>120</a> </span>cipher: Arc<AesGcmCipher>,
-<a href=#121 id=121 data-nosnippet>121</a> <span class="doccomment">/// AAD prefix from the key metadata.
-<a href=#122 id=122 data-nosnippet>122</a> </span>aad_prefix: Box<[u8]>,
-<a href=#123 id=123 data-nosnippet>123</a> <span class="doccomment">/// Total plaintext stream size in bytes.
-<a href=#124 id=124 data-nosnippet>124</a> </span>plain_stream_size: u64,
-<a href=#125 id=125 data-nosnippet>125</a> <span class="doccomment">/// Total number of encrypted blocks.
-<a href=#126 id=126 data-nosnippet>126</a> </span>num_blocks: u64,
-<a href=#127 id=127 data-nosnippet>127</a> <span class="doccomment">/// Size of the last cipher block (may be smaller than `CIPHER_BLOCK_SIZE`).
-<a href=#128 id=128 data-nosnippet>128</a> </span>last_cipher_block_size: u32,
-<a href=#129 id=129 data-nosnippet>129</a>}
-<a href=#130 id=130 data-nosnippet>130</a>
-<a href=#131 id=131 data-nosnippet>131</a><span class="kw">impl </span>AesGcmFileRead {
-<a href=#132 id=132 data-nosnippet>132</a> <span class="doccomment">/// Creates a new `AesGcmFileRead` for decrypting an AGS1 stream.
-<a href=#133 id=133 data-nosnippet>133</a> ///
-<a href=#134 id=134 data-nosnippet>134</a> /// Computes the plaintext size and block layout from the encrypted file
-<a href=#135 id=135 data-nosnippet>135</a> /// length. No I/O is performed; header validation happens implicitly
-<a href=#136 id=136 data-nosnippet>136</a> /// when blocks are decrypted (GCM authentication will fail on corrupt data).
-<a href=#137 id=137 data-nosnippet>137</a> ///
-<a href=#138 id=138 data-nosnippet>138</a> /// # Arguments
-<a href=#139 id=139 data-nosnippet>139</a> ///
-<a href=#140 id=140 data-nosnippet>140</a> /// * `inner` - Reader for the underlying encrypted file
-<a href=#141 id=141 data-nosnippet>141</a> /// * `cipher` - AES-GCM cipher initialized with the file's DEK
-<a href=#142 id=142 data-nosnippet>142</a> /// * `aad_prefix` - AAD prefix from the file's `StandardKeyMetadata`
-<a href=#143 id=143 data-nosnippet>143</a> /// * `encrypted_file_length` - Total byte length of the encrypted file
-<a href=#144 id=144 data-nosnippet>144</a> </span><span class="kw">pub fn </span>new(
-<a href=#145 id=145 data-nosnippet>145</a> inner: Box<<span class="kw">dyn </span>FileRead>,
-<a href=#146 id=146 data-nosnippet>146</a> cipher: Arc<AesGcmCipher>,
-<a href=#147 id=147 data-nosnippet>147</a> aad_prefix: Box<[u8]>,
-<a href=#148 id=148 data-nosnippet>148</a> encrypted_file_length: u64,
-<a href=#149 id=149 data-nosnippet>149</a> ) -> <span class="prelude-ty">Result</span><<span class="self">Self</span>> {
-<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">let </span>plain_stream_size = <span class="self">Self</span>::calculate_plaintext_length(encrypted_file_length)<span class="question-mark">?</span>;
-<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">let </span>stream_length = encrypted_file_length - GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64;
-<a href=#152 id=152 data-nosnippet>152</a>
-<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">if </span>stream_length == <span class="number">0 </span>{
-<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="self">Self </span>{
-<a href=#155 id=155 data-nosnippet>155</a> inner,
-<a href=#156 id=156 data-nosnippet>156</a> cipher,
-<a href=#157 id=157 data-nosnippet>157</a> aad_prefix,
-<a href=#158 id=158 data-nosnippet>158</a> plain_stream_size: <span class="number">0</span>,
-<a href=#159 id=159 data-nosnippet>159</a> num_blocks: <span class="number">0</span>,
-<a href=#160 id=160 data-nosnippet>160</a> last_cipher_block_size: <span class="number">0</span>,
-<a href=#161 id=161 data-nosnippet>161</a> });
-<a href=#162 id=162 data-nosnippet>162</a> }
-<a href=#163 id=163 data-nosnippet>163</a>
-<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">let </span>num_full_blocks = stream_length / CIPHER_BLOCK_SIZE <span class="kw">as </span>u64;
-<a href=#165 id=165 data-nosnippet>165</a> <span class="kw">let </span>cipher_bytes_in_last_block = (stream_length % CIPHER_BLOCK_SIZE <span class="kw">as </span>u64) <span class="kw">as </span>u32;
-<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">let </span>full_blocks_only = cipher_bytes_in_last_block == <span class="number">0</span>;
-<a href=#167 id=167 data-nosnippet>167</a>
-<a href=#168 id=168 data-nosnippet>168</a> <span class="kw">let </span>num_blocks = <span class="kw">if </span>full_blocks_only {
-<a href=#169 id=169 data-nosnippet>169</a> num_full_blocks
-<a href=#170 id=170 data-nosnippet>170</a> } <span class="kw">else </span>{
-<a href=#171 id=171 data-nosnippet>171</a> num_full_blocks + <span class="number">1
-<a href=#172 id=172 data-nosnippet>172</a> </span>};
+<a href=#75 id=75 data-nosnippet>75</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>MIN_STREAM_LENGTH: u32 = GCM_STREAM_HEADER_LENGTH + NONCE_LENGTH + GCM_TAG_LENGTH;
+<a href=#76 id=76 data-nosnippet>76</a>
+<a href=#77 id=77 data-nosnippet>77</a><span class="doccomment">/// Constructs the per-block AAD for AGS1 stream encryption.
+<a href=#78 id=78 data-nosnippet>78</a>///
+<a href=#79 id=79 data-nosnippet>79</a>/// Format: `aad_prefix || block_index (4 bytes, little-endian)`
+<a href=#80 id=80 data-nosnippet>80</a>///
+<a href=#81 id=81 data-nosnippet>81</a>/// This matches Java's `Ciphers.streamBlockAAD()`.
+<a href=#82 id=82 data-nosnippet>82</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>stream_block_aad(aad_prefix: <span class="kw-2">&</span>[u8], block_index: u32) -> Vec<u8> {
+<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">let </span>index_bytes = block_index.to_le_bytes();
+<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">if </span>aad_prefix.is_empty() {
+<a href=#85 id=85 data-nosnippet>85</a> index_bytes.to_vec()
+<a href=#86 id=86 data-nosnippet>86</a> } <span class="kw">else </span>{
+<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">let </span><span class="kw-2">mut </span>aad = Vec::with_capacity(aad_prefix.len() + <span class="number">4</span>);
+<a href=#88 id=88 data-nosnippet>88</a> aad.extend_from_slice(aad_prefix);
+<a href=#89 id=89 data-nosnippet>89</a> aad.extend_from_slice(<span class="kw-2">&</span>index_bytes);
+<a href=#90 id=90 data-nosnippet>90</a> aad
+<a href=#91 id=91 data-nosnippet>91</a> }
+<a href=#92 id=92 data-nosnippet>92</a>}
+<a href=#93 id=93 data-nosnippet>93</a>
+<a href=#94 id=94 data-nosnippet>94</a><span class="doccomment">/// Transparent decryption of AGS1 stream-encrypted files.
+<a href=#95 id=95 data-nosnippet>95</a>///
+<a href=#96 id=96 data-nosnippet>96</a>/// Implements the [`FileRead`] trait, providing random-access reads over
+<a href=#97 id=97 data-nosnippet>97</a>/// encrypted data. Each `read()` call determines which encrypted blocks
+<a href=#98 id=98 data-nosnippet>98</a>/// overlap the requested plaintext range, reads and decrypts them, then
+<a href=#99 id=99 data-nosnippet>99</a>/// returns the requested plaintext bytes.
+<a href=#100 id=100 data-nosnippet>100</a>///
+<a href=#101 id=101 data-nosnippet>101</a>/// # Usage
+<a href=#102 id=102 data-nosnippet>102</a>///
+<a href=#103 id=103 data-nosnippet>103</a>/// ```ignore
+<a href=#104 id=104 data-nosnippet>104</a>/// // (ignored: requires async runtime and concrete FileRead/FileWrite impls)
+<a href=#105 id=105 data-nosnippet>105</a>/// let reader = AesGcmFileRead::new(
+<a href=#106 id=106 data-nosnippet>106</a>/// inner_reader, // Box<dyn FileRead> for the encrypted file
+<a href=#107 id=107 data-nosnippet>107</a>/// cipher, // Arc<AesGcmCipher> with the DEK
+<a href=#108 id=108 data-nosnippet>108</a>/// aad_prefix.to_vec(),
+<a href=#109 id=109 data-nosnippet>109</a>/// encrypted_file_length,
+<a href=#110 id=110 data-nosnippet>110</a>/// )?;
+<a href=#111 id=111 data-nosnippet>111</a>///
+<a href=#112 id=112 data-nosnippet>112</a>/// // Read plaintext bytes transparently
+<a href=#113 id=113 data-nosnippet>113</a>/// let plaintext = reader.read(0..1024).await?;
+<a href=#114 id=114 data-nosnippet>114</a>/// ```
+<a href=#115 id=115 data-nosnippet>115</a></span><span class="kw">pub struct </span>AesGcmFileRead {
+<a href=#116 id=116 data-nosnippet>116</a> <span class="doccomment">/// The underlying encrypted file reader.
+<a href=#117 id=117 data-nosnippet>117</a> </span>inner: Box<<span class="kw">dyn </span>FileRead>,
+<a href=#118 id=118 data-nosnippet>118</a> <span class="doccomment">/// The AES-GCM cipher holding the DEK.
+<a href=#119 id=119 data-nosnippet>119</a> </span>cipher: Arc<AesGcmCipher>,
+<a href=#120 id=120 data-nosnippet>120</a> <span class="doccomment">/// AAD prefix from the key metadata.
+<a href=#121 id=121 data-nosnippet>121</a> </span>aad_prefix: Box<[u8]>,
+<a href=#122 id=122 data-nosnippet>122</a> <span class="doccomment">/// Total plaintext stream size in bytes.
+<a href=#123 id=123 data-nosnippet>123</a> </span>plain_stream_size: u64,
+<a href=#124 id=124 data-nosnippet>124</a> <span class="doccomment">/// Total number of encrypted blocks.
+<a href=#125 id=125 data-nosnippet>125</a> </span>num_blocks: u64,
+<a href=#126 id=126 data-nosnippet>126</a> <span class="doccomment">/// Size of the last cipher block (may be smaller than `CIPHER_BLOCK_SIZE`).
+<a href=#127 id=127 data-nosnippet>127</a> </span>last_cipher_block_size: u32,
+<a href=#128 id=128 data-nosnippet>128</a>}
+<a href=#129 id=129 data-nosnippet>129</a>
+<a href=#130 id=130 data-nosnippet>130</a><span class="kw">impl </span>AesGcmFileRead {
+<a href=#131 id=131 data-nosnippet>131</a> <span class="doccomment">/// Creates a new `AesGcmFileRead` for decrypting an AGS1 stream.
+<a href=#132 id=132 data-nosnippet>132</a> ///
+<a href=#133 id=133 data-nosnippet>133</a> /// Computes the plaintext size and block layout from the encrypted file
+<a href=#134 id=134 data-nosnippet>134</a> /// length. No I/O is performed; header validation happens implicitly
+<a href=#135 id=135 data-nosnippet>135</a> /// when blocks are decrypted (GCM authentication will fail on corrupt data).
+<a href=#136 id=136 data-nosnippet>136</a> ///
+<a href=#137 id=137 data-nosnippet>137</a> /// # Arguments
+<a href=#138 id=138 data-nosnippet>138</a> ///
+<a href=#139 id=139 data-nosnippet>139</a> /// * `inner` - Reader for the underlying encrypted file
+<a href=#140 id=140 data-nosnippet>140</a> /// * `cipher` - AES-GCM cipher initialized with the file's DEK
+<a href=#141 id=141 data-nosnippet>141</a> /// * `aad_prefix` - AAD prefix from the file's `StandardKeyMetadata`
+<a href=#142 id=142 data-nosnippet>142</a> /// * `encrypted_file_length` - Total byte length of the encrypted file
+<a href=#143 id=143 data-nosnippet>143</a> </span><span class="kw">pub fn </span>new(
+<a href=#144 id=144 data-nosnippet>144</a> inner: Box<<span class="kw">dyn </span>FileRead>,
+<a href=#145 id=145 data-nosnippet>145</a> cipher: Arc<AesGcmCipher>,
+<a href=#146 id=146 data-nosnippet>146</a> aad_prefix: Box<[u8]>,
+<a href=#147 id=147 data-nosnippet>147</a> encrypted_file_length: u64,
+<a href=#148 id=148 data-nosnippet>148</a> ) -> <span class="prelude-ty">Result</span><<span class="self">Self</span>> {
+<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">if </span>encrypted_file_length < u64::from(MIN_STREAM_LENGTH) {
+<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#151 id=151 data-nosnippet>151</a> <span class="string">"Invalid encrypted file length: {encrypted_file_length} is less than {MIN_STREAM_LENGTH}"
+<a href=#152 id=152 data-nosnippet>152</a> </span>));
+<a href=#153 id=153 data-nosnippet>153</a> }
+<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span>plain_stream_size = <span class="self">Self</span>::calculate_plaintext_length(encrypted_file_length)<span class="question-mark">?</span>;
+<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span>stream_length = encrypted_file_length - GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64;
+<a href=#156 id=156 data-nosnippet>156</a>
+<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span>num_full_blocks = stream_length / CIPHER_BLOCK_SIZE <span class="kw">as </span>u64;
+<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">let </span>cipher_bytes_in_last_block = (stream_length % CIPHER_BLOCK_SIZE <span class="kw">as </span>u64) <span class="kw">as </span>u32;
+<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">let </span>full_blocks_only = cipher_bytes_in_last_block == <span class="number">0</span>;
+<a href=#160 id=160 data-nosnippet>160</a>
+<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">let </span>num_blocks = <span class="kw">if </span>full_blocks_only {
+<a href=#162 id=162 data-nosnippet>162</a> num_full_blocks
+<a href=#163 id=163 data-nosnippet>163</a> } <span class="kw">else </span>{
+<a href=#164 id=164 data-nosnippet>164</a> num_full_blocks + <span class="number">1
+<a href=#165 id=165 data-nosnippet>165</a> </span>};
+<a href=#166 id=166 data-nosnippet>166</a>
+<a href=#167 id=167 data-nosnippet>167</a> <span class="kw">if </span>num_blocks > u32::MAX <span class="kw">as </span>u64 {
+<a href=#168 id=168 data-nosnippet>168</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#169 id=169 data-nosnippet>169</a> <span class="string">"AGS1 format supports at most {} blocks (~4 TiB per file), but file requires {num_blocks} blocks"</span>,
+<a href=#170 id=170 data-nosnippet>170</a> u32::MAX
+<a href=#171 id=171 data-nosnippet>171</a> ));
+<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a>
-<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">if </span>num_blocks > u32::MAX <span class="kw">as </span>u64 {
-<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
-<a href=#176 id=176 data-nosnippet>176</a> <span class="string">"AGS1 format supports at most {} blocks (~4 TiB per file), but file requires {num_blocks} blocks"</span>,
-<a href=#177 id=177 data-nosnippet>177</a> u32::MAX
-<a href=#178 id=178 data-nosnippet>178</a> ));
-<a href=#179 id=179 data-nosnippet>179</a> }
-<a href=#180 id=180 data-nosnippet>180</a>
-<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">let </span>last_cipher_block_size = <span class="kw">if </span>full_blocks_only {
-<a href=#182 id=182 data-nosnippet>182</a> CIPHER_BLOCK_SIZE
-<a href=#183 id=183 data-nosnippet>183</a> } <span class="kw">else </span>{
-<a href=#184 id=184 data-nosnippet>184</a> cipher_bytes_in_last_block
-<a href=#185 id=185 data-nosnippet>185</a> };
-<a href=#186 id=186 data-nosnippet>186</a>
-<a href=#187 id=187 data-nosnippet>187</a> <span class="prelude-val">Ok</span>(<span class="self">Self </span>{
-<a href=#188 id=188 data-nosnippet>188</a> inner,
-<a href=#189 id=189 data-nosnippet>189</a> cipher,
-<a href=#190 id=190 data-nosnippet>190</a> aad_prefix,
-<a href=#191 id=191 data-nosnippet>191</a> plain_stream_size,
-<a href=#192 id=192 data-nosnippet>192</a> num_blocks,
-<a href=#193 id=193 data-nosnippet>193</a> last_cipher_block_size,
-<a href=#194 id=194 data-nosnippet>194</a> })
-<a href=#195 id=195 data-nosnippet>195</a> }
-<a href=#196 id=196 data-nosnippet>196</a>
-<a href=#197 id=197 data-nosnippet>197</a> <span class="doccomment">/// Returns the plaintext stream size in bytes.
-<a href=#198 id=198 data-nosnippet>198</a> </span><span class="kw">pub fn </span>plaintext_length(<span class="kw-2">&</span><span class="self">self</span>) -> u64 {
-<a href=#199 id=199 data-nosnippet>199</a> <span class="self">self</span>.plain_stream_size
-<a href=#200 id=200 data-nosnippet>200</a> }
-<a href=#201 id=201 data-nosnippet>201</a>
-<a href=#202 id=202 data-nosnippet>202</a> <span class="doccomment">/// Calculates the plaintext length from an encrypted file's total length.
-<a href=#203 id=203 data-nosnippet>203</a> ///
-<a href=#204 id=204 data-nosnippet>204</a> /// This is a static calculation matching Java's
-<a href=#205 id=205 data-nosnippet>205</a> /// `AesGcmInputStream.calculatePlaintextLength()`.
-<a href=#206 id=206 data-nosnippet>206</a> </span><span class="kw">pub fn </span>calculate_plaintext_length(encrypted_file_length: u64) -> <span class="prelude-ty">Result</span><u64> {
-<a href=#207 id=207 data-nosnippet>207</a> <span class="kw">if </span>encrypted_file_length < GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64 {
-<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
-<a href=#209 id=209 data-nosnippet>209</a> <span class="string">"Encrypted file too short: {encrypted_file_length} bytes (minimum {GCM_STREAM_HEADER_LENGTH})"
-<a href=#210 id=210 data-nosnippet>210</a> </span>));
-<a href=#211 id=211 data-nosnippet>211</a> }
-<a href=#212 id=212 data-nosnippet>212</a>
-<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>stream_length = encrypted_file_length - GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64;
-<a href=#214 id=214 data-nosnippet>214</a>
-<a href=#215 id=215 data-nosnippet>215</a> <span class="kw">if </span>stream_length == <span class="number">0 </span>{
-<a href=#216 id=216 data-nosnippet>216</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="number">0</span>);
-<a href=#217 id=217 data-nosnippet>217</a> }
-<a href=#218 id=218 data-nosnippet>218</a>
-<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">let </span>num_full_blocks = stream_length / CIPHER_BLOCK_SIZE <span class="kw">as </span>u64;
-<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span>cipher_bytes_in_last_block = stream_length % CIPHER_BLOCK_SIZE <span class="kw">as </span>u64;
-<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">let </span>full_blocks_only = cipher_bytes_in_last_block == <span class="number">0</span>;
-<a href=#222 id=222 data-nosnippet>222</a>
-<a href=#223 id=223 data-nosnippet>223</a> <span class="kw">let </span>plain_bytes_in_last_block = <span class="kw">if </span>full_blocks_only {
-<a href=#224 id=224 data-nosnippet>224</a> <span class="number">0
-<a href=#225 id=225 data-nosnippet>225</a> </span>} <span class="kw">else </span>{
-<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">if </span>cipher_bytes_in_last_block < (NONCE_LENGTH + GCM_TAG_LENGTH) <span class="kw">as </span>u64 {
-<a href=#227 id=227 data-nosnippet>227</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
-<a href=#228 id=228 data-nosnippet>228</a> <span class="string">"Truncated encrypted file: last block is {} bytes (minimum {})"</span>,
-<a href=#229 id=229 data-nosnippet>229</a> cipher_bytes_in_last_block,
-<a href=#230 id=230 data-nosnippet>230</a> NONCE_LENGTH + GCM_TAG_LENGTH
-<a href=#231 id=231 data-nosnippet>231</a> ));
-<a href=#232 id=232 data-nosnippet>232</a> }
-<a href=#233 id=233 data-nosnippet>233</a> cipher_bytes_in_last_block - NONCE_LENGTH <span class="kw">as </span>u64 - GCM_TAG_LENGTH <span class="kw">as </span>u64
-<a href=#234 id=234 data-nosnippet>234</a> };
-<a href=#235 id=235 data-nosnippet>235</a>
-<a href=#236 id=236 data-nosnippet>236</a> <span class="prelude-val">Ok</span>(num_full_blocks * PLAIN_BLOCK_SIZE <span class="kw">as </span>u64 + plain_bytes_in_last_block)
-<a href=#237 id=237 data-nosnippet>237</a> }
-<a href=#238 id=238 data-nosnippet>238</a>
-<a href=#239 id=239 data-nosnippet>239</a> <span class="doccomment">/// Returns the encrypted byte offset for a given block index.
-<a href=#240 id=240 data-nosnippet>240</a> </span><span class="kw">fn </span>encrypted_block_offset(block_index: u64) -> u64 {
-<a href=#241 id=241 data-nosnippet>241</a> block_index * CIPHER_BLOCK_SIZE <span class="kw">as </span>u64 + GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64
-<a href=#242 id=242 data-nosnippet>242</a> }
-<a href=#243 id=243 data-nosnippet>243</a>
-<a href=#244 id=244 data-nosnippet>244</a> <span class="doccomment">/// Returns the cipher block size for a given block index.
-<a href=#245 id=245 data-nosnippet>245</a> </span><span class="kw">fn </span>cipher_block_size(<span class="kw-2">&</span><span class="self">self</span>, block_index: u64) -> u32 {
-<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">if </span>block_index == <span class="self">self</span>.num_blocks - <span class="number">1 </span>{
-<a href=#247 id=247 data-nosnippet>247</a> <span class="self">self</span>.last_cipher_block_size
-<a href=#248 id=248 data-nosnippet>248</a> } <span class="kw">else </span>{
-<a href=#249 id=249 data-nosnippet>249</a> CIPHER_BLOCK_SIZE
-<a href=#250 id=250 data-nosnippet>250</a> }
-<a href=#251 id=251 data-nosnippet>251</a> }
-<a href=#252 id=252 data-nosnippet>252</a>}
-<a href=#253 id=253 data-nosnippet>253</a>
-<a href=#254 id=254 data-nosnippet>254</a><span class="attr">#[async_trait::async_trait]
-<a href=#255 id=255 data-nosnippet>255</a></span><span class="kw">impl </span>FileRead <span class="kw">for </span>AesGcmFileRead {
-<a href=#256 id=256 data-nosnippet>256</a> <span class="doccomment">/// Reads and decrypts a plaintext byte range from the encrypted AGS1 stream.
-<a href=#257 id=257 data-nosnippet>257</a> ///
-<a href=#258 id=258 data-nosnippet>258</a> /// The caller specifies a range in **plaintext** coordinates (e.g. "bytes 0..1024
-<a href=#259 id=259 data-nosnippet>259</a> /// of the original file"). This method translates that into the encrypted file
-<a href=#260 id=260 data-nosnippet>260</a> /// layout and performs the following steps:
-<a href=#261 id=261 data-nosnippet>261</a> ///
-<a href=#262 id=262 data-nosnippet>262</a> /// 1. **Map to blocks** — divides the plaintext range by `PLAIN_BLOCK_SIZE` to
-<a href=#263 id=263 data-nosnippet>263</a> /// find which encrypted blocks (`first_block..=last_block`) contain the
-<a href=#264 id=264 data-nosnippet>264</a> /// requested data.
-<a href=#265 id=265 data-nosnippet>265</a> ///
-<a href=#266 id=266 data-nosnippet>266</a> /// 2. **Single I/O read** — calculates the contiguous byte range in the
-<a href=#267 id=267 data-nosnippet>267</a> /// encrypted file that covers all needed blocks (including the 8-byte AGS1
-<a href=#268 id=268 data-nosnippet>268</a> /// header offset, 12-byte nonces, and 16-byte GCM tags) and fetches them in
-<a href=#269 id=269 data-nosnippet>269</a> /// one call to the inner `FileRead`.
+<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">let </span>last_cipher_block_size = <span class="kw">if </span>full_blocks_only {
+<a href=#175 id=175 data-nosnippet>175</a> CIPHER_BLOCK_SIZE
+<a href=#176 id=176 data-nosnippet>176</a> } <span class="kw">else </span>{
+<a href=#177 id=177 data-nosnippet>177</a> cipher_bytes_in_last_block
+<a href=#178 id=178 data-nosnippet>178</a> };
+<a href=#179 id=179 data-nosnippet>179</a>
+<a href=#180 id=180 data-nosnippet>180</a> <span class="prelude-val">Ok</span>(<span class="self">Self </span>{
+<a href=#181 id=181 data-nosnippet>181</a> inner,
+<a href=#182 id=182 data-nosnippet>182</a> cipher,
+<a href=#183 id=183 data-nosnippet>183</a> aad_prefix,
+<a href=#184 id=184 data-nosnippet>184</a> plain_stream_size,
+<a href=#185 id=185 data-nosnippet>185</a> num_blocks,
+<a href=#186 id=186 data-nosnippet>186</a> last_cipher_block_size,
+<a href=#187 id=187 data-nosnippet>187</a> })
+<a href=#188 id=188 data-nosnippet>188</a> }
+<a href=#189 id=189 data-nosnippet>189</a>
+<a href=#190 id=190 data-nosnippet>190</a> <span class="doccomment">/// Returns the plaintext stream size in bytes.
+<a href=#191 id=191 data-nosnippet>191</a> </span><span class="kw">pub fn </span>plaintext_length(<span class="kw-2">&</span><span class="self">self</span>) -> u64 {
+<a href=#192 id=192 data-nosnippet>192</a> <span class="self">self</span>.plain_stream_size
+<a href=#193 id=193 data-nosnippet>193</a> }
+<a href=#194 id=194 data-nosnippet>194</a>
+<a href=#195 id=195 data-nosnippet>195</a> <span class="doccomment">/// Calculates the plaintext length from an encrypted file's total length.
+<a href=#196 id=196 data-nosnippet>196</a> ///
+<a href=#197 id=197 data-nosnippet>197</a> /// This is a static calculation matching Java's
+<a href=#198 id=198 data-nosnippet>198</a> /// `AesGcmInputStream.calculatePlaintextLength()`.
+<a href=#199 id=199 data-nosnippet>199</a> </span><span class="kw">pub fn </span>calculate_plaintext_length(encrypted_file_length: u64) -> <span class="prelude-ty">Result</span><u64> {
+<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">if </span>encrypted_file_length < GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64 {
+<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#202 id=202 data-nosnippet>202</a> <span class="string">"Encrypted file too short: {encrypted_file_length} bytes (minimum {GCM_STREAM_HEADER_LENGTH})"
+<a href=#203 id=203 data-nosnippet>203</a> </span>));
+<a href=#204 id=204 data-nosnippet>204</a> }
+<a href=#205 id=205 data-nosnippet>205</a>
+<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">let </span>stream_length = encrypted_file_length - GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64;
+<a href=#207 id=207 data-nosnippet>207</a>
+<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">if </span>stream_length == <span class="number">0 </span>{
+<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="number">0</span>);
+<a href=#210 id=210 data-nosnippet>210</a> }
+<a href=#211 id=211 data-nosnippet>211</a>
+<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">let </span>num_full_blocks = stream_length / CIPHER_BLOCK_SIZE <span class="kw">as </span>u64;
+<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>cipher_bytes_in_last_block = stream_length % CIPHER_BLOCK_SIZE <span class="kw">as </span>u64;
+<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">let </span>full_blocks_only = cipher_bytes_in_last_block == <span class="number">0</span>;
+<a href=#215 id=215 data-nosnippet>215</a>
+<a href=#216 id=216 data-nosnippet>216</a> <span class="kw">let </span>plain_bytes_in_last_block = <span class="kw">if </span>full_blocks_only {
+<a href=#217 id=217 data-nosnippet>217</a> <span class="number">0
+<a href=#218 id=218 data-nosnippet>218</a> </span>} <span class="kw">else </span>{
+<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">if </span>cipher_bytes_in_last_block < (NONCE_LENGTH + GCM_TAG_LENGTH) <span class="kw">as </span>u64 {
+<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#221 id=221 data-nosnippet>221</a> <span class="string">"Truncated encrypted file: last block is {} bytes (minimum {})"</span>,
+<a href=#222 id=222 data-nosnippet>222</a> cipher_bytes_in_last_block,
+<a href=#223 id=223 data-nosnippet>223</a> NONCE_LENGTH + GCM_TAG_LENGTH
+<a href=#224 id=224 data-nosnippet>224</a> ));
+<a href=#225 id=225 data-nosnippet>225</a> }
+<a href=#226 id=226 data-nosnippet>226</a> cipher_bytes_in_last_block - NONCE_LENGTH <span class="kw">as </span>u64 - GCM_TAG_LENGTH <span class="kw">as </span>u64
+<a href=#227 id=227 data-nosnippet>227</a> };
+<a href=#228 id=228 data-nosnippet>228</a>
+<a href=#229 id=229 data-nosnippet>229</a> <span class="prelude-val">Ok</span>(num_full_blocks * PLAIN_BLOCK_SIZE <span class="kw">as </span>u64 + plain_bytes_in_last_block)
+<a href=#230 id=230 data-nosnippet>230</a> }
+<a href=#231 id=231 data-nosnippet>231</a>
+<a href=#232 id=232 data-nosnippet>232</a> <span class="doccomment">/// Returns the encrypted byte offset for a given block index.
+<a href=#233 id=233 data-nosnippet>233</a> </span><span class="kw">fn </span>encrypted_block_offset(block_index: u64) -> u64 {
+<a href=#234 id=234 data-nosnippet>234</a> block_index * CIPHER_BLOCK_SIZE <span class="kw">as </span>u64 + GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64
+<a href=#235 id=235 data-nosnippet>235</a> }
+<a href=#236 id=236 data-nosnippet>236</a>
+<a href=#237 id=237 data-nosnippet>237</a> <span class="doccomment">/// Returns the cipher block size for a given block index.
+<a href=#238 id=238 data-nosnippet>238</a> </span><span class="kw">fn </span>cipher_block_size(<span class="kw-2">&</span><span class="self">self</span>, block_index: u64) -> u32 {
+<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">if </span>block_index == <span class="self">self</span>.num_blocks - <span class="number">1 </span>{
+<a href=#240 id=240 data-nosnippet>240</a> <span class="self">self</span>.last_cipher_block_size
+<a href=#241 id=241 data-nosnippet>241</a> } <span class="kw">else </span>{
+<a href=#242 id=242 data-nosnippet>242</a> CIPHER_BLOCK_SIZE
+<a href=#243 id=243 data-nosnippet>243</a> }
+<a href=#244 id=244 data-nosnippet>244</a> }
+<a href=#245 id=245 data-nosnippet>245</a>}
+<a href=#246 id=246 data-nosnippet>246</a>
+<a href=#247 id=247 data-nosnippet>247</a><span class="attr">#[async_trait::async_trait]
+<a href=#248 id=248 data-nosnippet>248</a></span><span class="kw">impl </span>FileRead <span class="kw">for </span>AesGcmFileRead {
+<a href=#249 id=249 data-nosnippet>249</a> <span class="doccomment">/// Reads and decrypts a plaintext byte range from the encrypted AGS1 stream.
+<a href=#250 id=250 data-nosnippet>250</a> ///
+<a href=#251 id=251 data-nosnippet>251</a> /// The caller specifies a range in **plaintext** coordinates (e.g. "bytes 0..1024
+<a href=#252 id=252 data-nosnippet>252</a> /// of the original file"). This method translates that into the encrypted file
+<a href=#253 id=253 data-nosnippet>253</a> /// layout and performs the following steps:
+<a href=#254 id=254 data-nosnippet>254</a> ///
+<a href=#255 id=255 data-nosnippet>255</a> /// 1. **Map to blocks** — divides the plaintext range by `PLAIN_BLOCK_SIZE` to
+<a href=#256 id=256 data-nosnippet>256</a> /// find which encrypted blocks (`first_block..=last_block`) contain the
+<a href=#257 id=257 data-nosnippet>257</a> /// requested data.
+<a href=#258 id=258 data-nosnippet>258</a> ///
+<a href=#259 id=259 data-nosnippet>259</a> /// 2. **Single I/O read** — calculates the contiguous byte range in the
+<a href=#260 id=260 data-nosnippet>260</a> /// encrypted file that covers all needed blocks (including the 8-byte AGS1
+<a href=#261 id=261 data-nosnippet>261</a> /// header offset, 12-byte nonces, and 16-byte GCM tags) and fetches them in
+<a href=#262 id=262 data-nosnippet>262</a> /// one call to the inner `FileRead`.
+<a href=#263 id=263 data-nosnippet>263</a> ///
+<a href=#264 id=264 data-nosnippet>264</a> /// 3. **Decrypt per block** — iterates over each cipher block in the response,
+<a href=#265 id=265 data-nosnippet>265</a> /// decrypts it with AES-GCM using the per-block AAD (`aad_prefix || block_index`),
+<a href=#266 id=266 data-nosnippet>266</a> /// and slices out only the plaintext bytes that overlap the requested range.
+<a href=#267 id=267 data-nosnippet>267</a> ///
+<a href=#268 id=268 data-nosnippet>268</a> /// 4. **Assemble result** — concatenates the slices into a single `Bytes` buffer
+<a href=#269 id=269 data-nosnippet>269</a> /// matching exactly `range.end - range.start` bytes.
<a href=#270 id=270 data-nosnippet>270</a> ///
-<a href=#271 id=271 data-nosnippet>271</a> /// 3. **Decrypt per block** — iterates over each cipher block in the response,
-<a href=#272 id=272 data-nosnippet>272</a> /// decrypts it with AES-GCM using the per-block AAD (`aad_prefix || block_index`),
-<a href=#273 id=273 data-nosnippet>273</a> /// and slices out only the plaintext bytes that overlap the requested range.
-<a href=#274 id=274 data-nosnippet>274</a> ///
-<a href=#275 id=275 data-nosnippet>275</a> /// 4. **Assemble result** — concatenates the slices into a single `Bytes` buffer
-<a href=#276 id=276 data-nosnippet>276</a> /// matching exactly `range.end - range.start` bytes.
-<a href=#277 id=277 data-nosnippet>277</a> ///
-<a href=#278 id=278 data-nosnippet>278</a> /// Because each block is independently encrypted with its own nonce and AAD,
-<a href=#279 id=279 data-nosnippet>279</a> /// arbitrary random-access reads are supported without decrypting the entire
-<a href=#280 id=280 data-nosnippet>280</a> /// file. GCM authentication is verified per-block, so any tampering is detected
-<a href=#281 id=281 data-nosnippet>281</a> /// at the granularity of individual blocks.
-<a href=#282 id=282 data-nosnippet>282</a> </span><span class="kw">async fn </span>read(<span class="kw-2">&</span><span class="self">self</span>, range: Range<u64>) -> <span class="prelude-ty">Result</span><Bytes> {
-<a href=#283 id=283 data-nosnippet>283</a> <span class="kw">if </span>range.start == range.end {
-<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(Bytes::new());
-<a href=#285 id=285 data-nosnippet>285</a> }
-<a href=#286 id=286 data-nosnippet>286</a>
-<a href=#287 id=287 data-nosnippet>287</a> <span class="kw">if </span>range.start > range.end {
-<a href=#288 id=288 data-nosnippet>288</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
-<a href=#289 id=289 data-nosnippet>289</a> <span class="string">"Invalid read range: start ({}) is greater than end ({})"</span>,
-<a href=#290 id=290 data-nosnippet>290</a> range.start,
-<a href=#291 id=291 data-nosnippet>291</a> range.end
-<a href=#292 id=292 data-nosnippet>292</a> ));
-<a href=#293 id=293 data-nosnippet>293</a> }
-<a href=#294 id=294 data-nosnippet>294</a>
-<a href=#295 id=295 data-nosnippet>295</a> <span class="kw">if </span>range.end > <span class="self">self</span>.plain_stream_size {
-<a href=#296 id=296 data-nosnippet>296</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
-<a href=#297 id=297 data-nosnippet>297</a> <span class="string">"Read range {}..{} exceeds plaintext size {}"</span>,
-<a href=#298 id=298 data-nosnippet>298</a> range.start,
-<a href=#299 id=299 data-nosnippet>299</a> range.end,
-<a href=#300 id=300 data-nosnippet>300</a> <span class="self">self</span>.plain_stream_size
-<a href=#301 id=301 data-nosnippet>301</a> ));
-<a href=#302 id=302 data-nosnippet>302</a> }
-<a href=#303 id=303 data-nosnippet>303</a>
-<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">if </span><span class="self">self</span>.num_blocks == <span class="number">0 </span>{
-<a href=#305 id=305 data-nosnippet>305</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(Bytes::new());
-<a href=#306 id=306 data-nosnippet>306</a> }
-<a href=#307 id=307 data-nosnippet>307</a>
-<a href=#308 id=308 data-nosnippet>308</a> <span class="kw">let </span>first_block = range.start / PLAIN_BLOCK_SIZE <span class="kw">as </span>u64;
-<a href=#309 id=309 data-nosnippet>309</a> <span class="kw">let </span>last_block = (range.end - <span class="number">1</span>) / PLAIN_BLOCK_SIZE <span class="kw">as </span>u64;
-<a href=#310 id=310 data-nosnippet>310</a>
-<a href=#311 id=311 data-nosnippet>311</a> <span class="comment">// Read all needed encrypted blocks in a single I/O call
-<a href=#312 id=312 data-nosnippet>312</a> </span><span class="kw">let </span>encrypted_start = <span class="self">Self</span>::encrypted_block_offset(first_block);
-<a href=#313 id=313 data-nosnippet>313</a> <span class="kw">let </span>encrypted_end =
-<a href=#314 id=314 data-nosnippet>314</a> <span class="self">Self</span>::encrypted_block_offset(last_block) + <span class="self">self</span>.cipher_block_size(last_block) <span class="kw">as </span>u64;
+<a href=#271 id=271 data-nosnippet>271</a> /// Because each block is independently encrypted with its own nonce and AAD,
+<a href=#272 id=272 data-nosnippet>272</a> /// arbitrary random-access reads are supported without decrypting the entire
+<a href=#273 id=273 data-nosnippet>273</a> /// file. GCM authentication is verified per-block, so any tampering is detected
+<a href=#274 id=274 data-nosnippet>274</a> /// at the granularity of individual blocks.
+<a href=#275 id=275 data-nosnippet>275</a> </span><span class="kw">async fn </span>read(<span class="kw-2">&</span><span class="self">self</span>, range: Range<u64>) -> <span class="prelude-ty">Result</span><Bytes> {
+<a href=#276 id=276 data-nosnippet>276</a> <span class="comment">// An empty stream still has one block whose GCM tag must be verified, so an empty read
+<a href=#277 id=277 data-nosnippet>277</a> // cannot short-circuit there: that is what detects a file truncated to just its header.
+<a href=#278 id=278 data-nosnippet>278</a> </span><span class="kw">if </span>range.start == range.end && <span class="self">self</span>.plain_stream_size != <span class="number">0 </span>{
+<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(Bytes::new());
+<a href=#280 id=280 data-nosnippet>280</a> }
+<a href=#281 id=281 data-nosnippet>281</a>
+<a href=#282 id=282 data-nosnippet>282</a> <span class="kw">if </span>range.start > range.end {
+<a href=#283 id=283 data-nosnippet>283</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#284 id=284 data-nosnippet>284</a> <span class="string">"Invalid read range: start ({}) is greater than end ({})"</span>,
+<a href=#285 id=285 data-nosnippet>285</a> range.start,
+<a href=#286 id=286 data-nosnippet>286</a> range.end
+<a href=#287 id=287 data-nosnippet>287</a> ));
+<a href=#288 id=288 data-nosnippet>288</a> }
+<a href=#289 id=289 data-nosnippet>289</a>
+<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">if </span>range.end > <span class="self">self</span>.plain_stream_size {
+<a href=#291 id=291 data-nosnippet>291</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#292 id=292 data-nosnippet>292</a> <span class="string">"Read range {}..{} exceeds plaintext size {}"</span>,
+<a href=#293 id=293 data-nosnippet>293</a> range.start,
+<a href=#294 id=294 data-nosnippet>294</a> range.end,
+<a href=#295 id=295 data-nosnippet>295</a> <span class="self">self</span>.plain_stream_size
+<a href=#296 id=296 data-nosnippet>296</a> ));
+<a href=#297 id=297 data-nosnippet>297</a> }
+<a href=#298 id=298 data-nosnippet>298</a>
+<a href=#299 id=299 data-nosnippet>299</a> <span class="kw">let </span>first_block = range.start / PLAIN_BLOCK_SIZE <span class="kw">as </span>u64;
+<a href=#300 id=300 data-nosnippet>300</a> <span class="kw">let </span>last_block = range.end.saturating_sub(<span class="number">1</span>) / PLAIN_BLOCK_SIZE <span class="kw">as </span>u64;
+<a href=#301 id=301 data-nosnippet>301</a>
+<a href=#302 id=302 data-nosnippet>302</a> <span class="comment">// Read all needed encrypted blocks in a single I/O call
+<a href=#303 id=303 data-nosnippet>303</a> </span><span class="kw">let </span>encrypted_start = <span class="self">Self</span>::encrypted_block_offset(first_block);
+<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">let </span>encrypted_end =
+<a href=#305 id=305 data-nosnippet>305</a> <span class="self">Self</span>::encrypted_block_offset(last_block) + <span class="self">self</span>.cipher_block_size(last_block) <span class="kw">as </span>u64;
+<a href=#306 id=306 data-nosnippet>306</a>
+<a href=#307 id=307 data-nosnippet>307</a> <span class="kw">let </span>all_encrypted = <span class="self">self</span>.inner.read(encrypted_start..encrypted_end).<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#308 id=308 data-nosnippet>308</a> <span class="kw">if </span>all_encrypted.len() <span class="kw">as </span>u64 != encrypted_end - encrypted_start {
+<a href=#309 id=309 data-nosnippet>309</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#310 id=310 data-nosnippet>310</a> <span class="string">"Invalid encrypted read length: expected {} bytes, got {}"</span>,
+<a href=#311 id=311 data-nosnippet>311</a> encrypted_end - encrypted_start,
+<a href=#312 id=312 data-nosnippet>312</a> all_encrypted.len()
+<a href=#313 id=313 data-nosnippet>313</a> ));
+<a href=#314 id=314 data-nosnippet>314</a> }
<a href=#315 id=315 data-nosnippet>315</a>
-<a href=#316 id=316 data-nosnippet>316</a> <span class="kw">let </span>all_encrypted = <span class="self">self</span>.inner.read(encrypted_start..encrypted_end).<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#317 id=317 data-nosnippet>317</a>
-<a href=#318 id=318 data-nosnippet>318</a> <span class="comment">// Decrypt each block and extract the requested plaintext range
-<a href=#319 id=319 data-nosnippet>319</a> </span><span class="kw">let </span>result_len = (range.end - range.start) <span class="kw">as </span>usize;
-<a href=#320 id=320 data-nosnippet>320</a> <span class="kw">let </span><span class="kw-2">mut </span>result = BytesMut::with_capacity(result_len);
-<a href=#321 id=321 data-nosnippet>321</a> <span class="kw">let </span><span class="kw-2">mut </span>encrypted_offset = <span class="number">0usize</span>;
-<a href=#322 id=322 data-nosnippet>322</a>
-<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">for </span>block_idx <span class="kw">in </span>first_block..=last_block {
-<a href=#324 id=324 data-nosnippet>324</a> <span class="kw">let </span>block_size = <span class="self">self</span>.cipher_block_size(block_idx) <span class="kw">as </span>usize;
-<a href=#325 id=325 data-nosnippet>325</a> <span class="kw">let </span>cipher_block = <span class="kw-2">&</span>all_encrypted[encrypted_offset..encrypted_offset + block_size];
-<a href=#326 id=326 data-nosnippet>326</a> encrypted_offset += block_size;
-<a href=#327 id=327 data-nosnippet>327</a>
-<a href=#328 id=328 data-nosnippet>328</a> <span class="kw">let </span>aad = stream_block_aad(<span class="kw-2">&</span><span class="self">self</span>.aad_prefix, block_idx <span class="kw">as </span>u32);
-<a href=#329 id=329 data-nosnippet>329</a> <span class="kw">let </span>decrypted = <span class="self">self</span>.cipher.decrypt(cipher_block, <span class="prelude-val">Some</span>(<span class="kw-2">&</span>aad))<span class="question-mark">?</span>;
-<a href=#330 id=330 data-nosnippet>330</a>
-<a href=#331 id=331 data-nosnippet>331</a> <span class="comment">// Calculate which slice of this decrypted block we need
-<a href=#332 id=332 data-nosnippet>332</a> </span><span class="kw">let </span>block_plain_start = block_idx * PLAIN_BLOCK_SIZE <span class="kw">as </span>u64;
-<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">let </span>slice_start = <span class="kw">if </span>block_idx == first_block {
-<a href=#334 id=334 data-nosnippet>334</a> (range.start - block_plain_start) <span class="kw">as </span>usize
-<a href=#335 id=335 data-nosnippet>335</a> } <span class="kw">else </span>{
-<a href=#336 id=336 data-nosnippet>336</a> <span class="number">0
-<a href=#337 id=337 data-nosnippet>337</a> </span>};
-<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">let </span>slice_end = <span class="kw">if </span>block_idx == last_block {
-<a href=#339 id=339 data-nosnippet>339</a> (range.end - block_plain_start) <span class="kw">as </span>usize
-<a href=#340 id=340 data-nosnippet>340</a> } <span class="kw">else </span>{
-<a href=#341 id=341 data-nosnippet>341</a> decrypted.len()
-<a href=#342 id=342 data-nosnippet>342</a> };
-<a href=#343 id=343 data-nosnippet>343</a>
-<a href=#344 id=344 data-nosnippet>344</a> result.extend_from_slice(<span class="kw-2">&</span>decrypted[slice_start..slice_end]);
-<a href=#345 id=345 data-nosnippet>345</a> }
-<a href=#346 id=346 data-nosnippet>346</a>
-<a href=#347 id=347 data-nosnippet>347</a> <span class="prelude-val">Ok</span>(result.freeze())
-<a href=#348 id=348 data-nosnippet>348</a> }
-<a href=#349 id=349 data-nosnippet>349</a>}
-<a href=#350 id=350 data-nosnippet>350</a>
-<a href=#351 id=351 data-nosnippet>351</a><span class="doccomment">/// Transparent encryption of AGS1 stream-encrypted files.
-<a href=#352 id=352 data-nosnippet>352</a>///
-<a href=#353 id=353 data-nosnippet>353</a>/// Implements the [`FileWrite`] trait, buffering plaintext and emitting
-<a href=#354 id=354 data-nosnippet>354</a>/// encrypted AGS1 blocks. This is the streaming write counterpart to
-<a href=#355 id=355 data-nosnippet>355</a>/// [`AesGcmFileRead`].
+<a href=#316 id=316 data-nosnippet>316</a> <span class="comment">// Decrypt each block and extract the requested plaintext range
+<a href=#317 id=317 data-nosnippet>317</a> </span><span class="kw">let </span>result_len = (range.end - range.start) <span class="kw">as </span>usize;
+<a href=#318 id=318 data-nosnippet>318</a> <span class="kw">let </span><span class="kw-2">mut </span>result = BytesMut::with_capacity(result_len);
+<a href=#319 id=319 data-nosnippet>319</a> <span class="kw">let </span><span class="kw-2">mut </span>encrypted_offset = <span class="number">0usize</span>;
+<a href=#320 id=320 data-nosnippet>320</a>
+<a href=#321 id=321 data-nosnippet>321</a> <span class="kw">for </span>block_idx <span class="kw">in </span>first_block..=last_block {
+<a href=#322 id=322 data-nosnippet>322</a> <span class="kw">let </span>block_size = <span class="self">self</span>.cipher_block_size(block_idx) <span class="kw">as </span>usize;
+<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">let </span>cipher_block = <span class="kw-2">&</span>all_encrypted[encrypted_offset..encrypted_offset + block_size];
+<a href=#324 id=324 data-nosnippet>324</a> encrypted_offset += block_size;
+<a href=#325 id=325 data-nosnippet>325</a>
+<a href=#326 id=326 data-nosnippet>326</a> <span class="kw">let </span>aad = stream_block_aad(<span class="kw-2">&</span><span class="self">self</span>.aad_prefix, block_idx <span class="kw">as </span>u32);
+<a href=#327 id=327 data-nosnippet>327</a> <span class="kw">let </span>decrypted = <span class="self">self</span>.cipher.decrypt(cipher_block, <span class="prelude-val">Some</span>(<span class="kw-2">&</span>aad))<span class="question-mark">?</span>;
+<a href=#328 id=328 data-nosnippet>328</a>
+<a href=#329 id=329 data-nosnippet>329</a> <span class="comment">// Calculate which slice of this decrypted block we need
+<a href=#330 id=330 data-nosnippet>330</a> </span><span class="kw">let </span>block_plain_start = block_idx * PLAIN_BLOCK_SIZE <span class="kw">as </span>u64;
+<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">let </span>slice_start = <span class="kw">if </span>block_idx == first_block {
+<a href=#332 id=332 data-nosnippet>332</a> (range.start - block_plain_start) <span class="kw">as </span>usize
+<a href=#333 id=333 data-nosnippet>333</a> } <span class="kw">else </span>{
+<a href=#334 id=334 data-nosnippet>334</a> <span class="number">0
+<a href=#335 id=335 data-nosnippet>335</a> </span>};
+<a href=#336 id=336 data-nosnippet>336</a> <span class="kw">let </span>slice_end = <span class="kw">if </span>block_idx == last_block {
+<a href=#337 id=337 data-nosnippet>337</a> (range.end - block_plain_start) <span class="kw">as </span>usize
+<a href=#338 id=338 data-nosnippet>338</a> } <span class="kw">else </span>{
+<a href=#339 id=339 data-nosnippet>339</a> decrypted.len()
+<a href=#340 id=340 data-nosnippet>340</a> };
+<a href=#341 id=341 data-nosnippet>341</a>
+<a href=#342 id=342 data-nosnippet>342</a> result.extend_from_slice(<span class="kw-2">&</span>decrypted[slice_start..slice_end]);
+<a href=#343 id=343 data-nosnippet>343</a> }
+<a href=#344 id=344 data-nosnippet>344</a>
+<a href=#345 id=345 data-nosnippet>345</a> <span class="prelude-val">Ok</span>(result.freeze())
+<a href=#346 id=346 data-nosnippet>346</a> }
+<a href=#347 id=347 data-nosnippet>347</a>}
+<a href=#348 id=348 data-nosnippet>348</a>
+<a href=#349 id=349 data-nosnippet>349</a><span class="doccomment">/// Transparent encryption of AGS1 stream-encrypted files.
+<a href=#350 id=350 data-nosnippet>350</a>///
+<a href=#351 id=351 data-nosnippet>351</a>/// Implements the [`FileWrite`] trait, buffering plaintext and emitting
+<a href=#352 id=352 data-nosnippet>352</a>/// encrypted AGS1 blocks. This is the streaming write counterpart to
+<a href=#353 id=353 data-nosnippet>353</a>/// [`AesGcmFileRead`].
+<a href=#354 id=354 data-nosnippet>354</a>///
+<a href=#355 id=355 data-nosnippet>355</a>/// # Usage
<a href=#356 id=356 data-nosnippet>356</a>///
-<a href=#357 id=357 data-nosnippet>357</a>/// # Usage
-<a href=#358 id=358 data-nosnippet>358</a>///
-<a href=#359 id=359 data-nosnippet>359</a>/// ```ignore
-<a href=#360 id=360 data-nosnippet>360</a>/// // (ignored: requires async runtime and concrete FileRead/FileWrite impls)
-<a href=#361 id=361 data-nosnippet>361</a>/// let writer = AesGcmFileWrite::new(
-<a href=#362 id=362 data-nosnippet>362</a>/// inner_writer, // Box<dyn FileWrite> for the output file
-<a href=#363 id=363 data-nosnippet>363</a>/// cipher, // Arc<AesGcmCipher> with the DEK
-<a href=#364 id=364 data-nosnippet>364</a>/// aad_prefix.to_vec(),
-<a href=#365 id=365 data-nosnippet>365</a>/// );
-<a href=#366 id=366 data-nosnippet>366</a>///
-<a href=#367 id=367 data-nosnippet>367</a>/// writer.write(plaintext_chunk).await?;
-<a href=#368 id=368 data-nosnippet>368</a>/// writer.close().await?;
-<a href=#369 id=369 data-nosnippet>369</a>/// ```
-<a href=#370 id=370 data-nosnippet>370</a></span><span class="kw">pub struct </span>AesGcmFileWrite {
-<a href=#371 id=371 data-nosnippet>371</a> <span class="doccomment">/// The underlying output writer.
-<a href=#372 id=372 data-nosnippet>372</a> </span>inner: Box<<span class="kw">dyn </span>FileWrite>,
-<a href=#373 id=373 data-nosnippet>373</a> <span class="doccomment">/// The AES-GCM cipher holding the DEK.
-<a href=#374 id=374 data-nosnippet>374</a> </span>cipher: Arc<AesGcmCipher>,
-<a href=#375 id=375 data-nosnippet>375</a> <span class="doccomment">/// AAD prefix from the key metadata.
-<a href=#376 id=376 data-nosnippet>376</a> </span>aad_prefix: Box<[u8]>,
-<a href=#377 id=377 data-nosnippet>377</a> <span class="doccomment">/// Plaintext buffer accumulating data before block encryption.
-<a href=#378 id=378 data-nosnippet>378</a> </span>buffer: Vec<u8>,
-<a href=#379 id=379 data-nosnippet>379</a> <span class="doccomment">/// Current block index for AAD construction.
-<a href=#380 id=380 data-nosnippet>380</a> </span>block_index: u32,
-<a href=#381 id=381 data-nosnippet>381</a> <span class="doccomment">/// Whether the AGS1 header has been written.
-<a href=#382 id=382 data-nosnippet>382</a> </span>header_written: bool,
-<a href=#383 id=383 data-nosnippet>383</a> <span class="doccomment">/// Whether close() has been called.
-<a href=#384 id=384 data-nosnippet>384</a> </span>closed: bool,
-<a href=#385 id=385 data-nosnippet>385</a> <span class="doccomment">/// Whether the writer is in a poisoned state due to a failed inner write.
-<a href=#386 id=386 data-nosnippet>386</a> /// Once poisoned, all subsequent operations are rejected because the inner
-<a href=#387 id=387 data-nosnippet>387</a> /// writer may have received partial data.
-<a href=#388 id=388 data-nosnippet>388</a> </span>poisoned: bool,
-<a href=#389 id=389 data-nosnippet>389</a>}
-<a href=#390 id=390 data-nosnippet>390</a>
-<a href=#391 id=391 data-nosnippet>391</a><span class="kw">impl </span>AesGcmFileWrite {
-<a href=#392 id=392 data-nosnippet>392</a> <span class="doccomment">/// Creates a new `AesGcmFileWrite` for encrypting to AGS1 format.
-<a href=#393 id=393 data-nosnippet>393</a> ///
-<a href=#394 id=394 data-nosnippet>394</a> /// No I/O is performed until `write()` or `close()` is called.
-<a href=#395 id=395 data-nosnippet>395</a> </span><span class="kw">pub fn </span>new(
-<a href=#396 id=396 data-nosnippet>396</a> inner: Box<<span class="kw">dyn </span>FileWrite>,
-<a href=#397 id=397 data-nosnippet>397</a> cipher: Arc<AesGcmCipher>,
-<a href=#398 id=398 data-nosnippet>398</a> aad_prefix: <span class="kw">impl </span>Into<Box<[u8]>>,
-<a href=#399 id=399 data-nosnippet>399</a> ) -> <span class="self">Self </span>{
-<a href=#400 id=400 data-nosnippet>400</a> <span class="self">Self </span>{
-<a href=#401 id=401 data-nosnippet>401</a> inner,
-<a href=#402 id=402 data-nosnippet>402</a> cipher,
-<a href=#403 id=403 data-nosnippet>403</a> aad_prefix: aad_prefix.into(),
-<a href=#404 id=404 data-nosnippet>404</a> buffer: Vec::new(),
-<a href=#405 id=405 data-nosnippet>405</a> block_index: <span class="number">0</span>,
-<a href=#406 id=406 data-nosnippet>406</a> header_written: <span class="bool-val">false</span>,
-<a href=#407 id=407 data-nosnippet>407</a> closed: <span class="bool-val">false</span>,
-<a href=#408 id=408 data-nosnippet>408</a> poisoned: <span class="bool-val">false</span>,
-<a href=#409 id=409 data-nosnippet>409</a> }
-<a href=#410 id=410 data-nosnippet>410</a> }
-<a href=#411 id=411 data-nosnippet>411</a>
-<a href=#412 id=412 data-nosnippet>412</a> <span class="doccomment">/// Writes the AGS1 header (magic + plain block size) to the inner writer.
-<a href=#413 id=413 data-nosnippet>413</a> </span><span class="kw">async fn </span>write_header(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
-<a href=#414 id=414 data-nosnippet>414</a> <span class="kw">let </span><span class="kw-2">mut </span>header = Vec::with_capacity(GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>usize);
-<a href=#415 id=415 data-nosnippet>415</a> header.extend_from_slice(<span class="kw-2">&</span>GCM_STREAM_MAGIC);
-<a href=#416 id=416 data-nosnippet>416</a> header.extend_from_slice(<span class="kw-2">&</span>PLAIN_BLOCK_SIZE.to_le_bytes());
-<a href=#417 id=417 data-nosnippet>417</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(e) = <span class="self">self</span>.inner.write(Bytes::from(header)).<span class="kw">await </span>{
-<a href=#418 id=418 data-nosnippet>418</a> <span class="self">self</span>.poisoned = <span class="bool-val">true</span>;
-<a href=#419 id=419 data-nosnippet>419</a> <span class="kw">return </span><span class="prelude-val">Err</span>(e);
-<a href=#420 id=420 data-nosnippet>420</a> }
-<a href=#421 id=421 data-nosnippet>421</a> <span class="self">self</span>.header_written = <span class="bool-val">true</span>;
-<a href=#422 id=422 data-nosnippet>422</a> <span class="prelude-val">Ok</span>(())
-<a href=#423 id=423 data-nosnippet>423</a> }
-<a href=#424 id=424 data-nosnippet>424</a>
-<a href=#425 id=425 data-nosnippet>425</a> <span class="doccomment">/// Encrypts a plaintext block and writes it to the inner writer.
-<a href=#426 id=426 data-nosnippet>426</a> </span><span class="kw">async fn </span>encrypt_and_write_block(<span class="kw-2">&mut </span><span class="self">self</span>, block_data: <span class="kw-2">&</span>[u8]) -> <span class="prelude-ty">Result</span><()> {
-<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">let </span>aad = stream_block_aad(<span class="kw-2">&</span><span class="self">self</span>.aad_prefix, <span class="self">self</span>.block_index);
-<a href=#428 id=428 data-nosnippet>428</a> <span class="kw">let </span>encrypted = <span class="self">self</span>.cipher.encrypt(block_data, <span class="prelude-val">Some</span>(<span class="kw-2">&</span>aad))<span class="question-mark">?</span>;
-<a href=#429 id=429 data-nosnippet>429</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(e) = <span class="self">self</span>.inner.write(Bytes::from(encrypted)).<span class="kw">await </span>{
-<a href=#430 id=430 data-nosnippet>430</a> <span class="self">self</span>.poisoned = <span class="bool-val">true</span>;
-<a href=#431 id=431 data-nosnippet>431</a> <span class="kw">return </span><span class="prelude-val">Err</span>(e);
-<a href=#432 id=432 data-nosnippet>432</a> }
-<a href=#433 id=433 data-nosnippet>433</a> <span class="self">self</span>.block_index = <span class="self">self</span>.block_index.checked_add(<span class="number">1</span>).ok_or_else(|| {
-<a href=#434 id=434 data-nosnippet>434</a> <span class="macro">invalid_data!</span>(
-<a href=#435 id=435 data-nosnippet>435</a> <span class="string">"AGS1 block index overflow: file exceeds the maximum supported size (~4 TiB)"
-<a href=#436 id=436 data-nosnippet>436</a> </span>)
-<a href=#437 id=437 data-nosnippet>437</a> })<span class="question-mark">?</span>;
-<a href=#438 id=438 data-nosnippet>438</a> <span class="prelude-val">Ok</span>(())
-<a href=#439 id=439 data-nosnippet>439</a> }
-<a href=#440 id=440 data-nosnippet>440</a>
-<a href=#441 id=441 data-nosnippet>441</a> <span class="doccomment">/// Encrypts the first `PLAIN_BLOCK_SIZE` bytes of the buffer in-place
-<a href=#442 id=442 data-nosnippet>442</a> /// and drains them, avoiding a 1 MiB temporary copy.
-<a href=#443 id=443 data-nosnippet>443</a> </span><span class="kw">async fn </span>encrypt_and_drain_block(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
-<a href=#444 id=444 data-nosnippet>444</a> <span class="kw">let </span>aad = stream_block_aad(<span class="kw-2">&</span><span class="self">self</span>.aad_prefix, <span class="self">self</span>.block_index);
-<a href=#445 id=445 data-nosnippet>445</a> <span class="kw">let </span>encrypted = <span class="self">self
-<a href=#446 id=446 data-nosnippet>446</a> </span>.cipher
-<a href=#447 id=447 data-nosnippet>447</a> .encrypt(<span class="kw-2">&</span><span class="self">self</span>.buffer[..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize], <span class="prelude-val">Some</span>(<span class="kw-2">&</span>aad))<span class="question-mark">?</span>;
-<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(e) = <span class="self">self</span>.inner.write(Bytes::from(encrypted)).<span class="kw">await </span>{
-<a href=#449 id=449 data-nosnippet>449</a> <span class="self">self</span>.poisoned = <span class="bool-val">true</span>;
-<a href=#450 id=450 data-nosnippet>450</a> <span class="kw">return </span><span class="prelude-val">Err</span>(e);
-<a href=#451 id=451 data-nosnippet>451</a> }
-<a href=#452 id=452 data-nosnippet>452</a> <span class="self">self</span>.block_index = <span class="self">self</span>.block_index.checked_add(<span class="number">1</span>).ok_or_else(|| {
-<a href=#453 id=453 data-nosnippet>453</a> <span class="macro">invalid_data!</span>(
-<a href=#454 id=454 data-nosnippet>454</a> <span class="string">"AGS1 block index overflow: file exceeds the maximum supported size (~4 TiB)"
-<a href=#455 id=455 data-nosnippet>455</a> </span>)
-<a href=#456 id=456 data-nosnippet>456</a> })<span class="question-mark">?</span>;
-<a href=#457 id=457 data-nosnippet>457</a> <span class="self">self</span>.buffer.drain(..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize);
-<a href=#458 id=458 data-nosnippet>458</a> <span class="prelude-val">Ok</span>(())
-<a href=#459 id=459 data-nosnippet>459</a> }
-<a href=#460 id=460 data-nosnippet>460</a>}
-<a href=#461 id=461 data-nosnippet>461</a>
-<a href=#462 id=462 data-nosnippet>462</a><span class="attr">#[async_trait::async_trait]
-<a href=#463 id=463 data-nosnippet>463</a></span><span class="kw">impl </span>FileWrite <span class="kw">for </span>AesGcmFileWrite {
-<a href=#464 id=464 data-nosnippet>464</a> <span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
-<a href=#465 id=465 data-nosnippet>465</a> <span class="kw">if </span><span class="self">self</span>.closed {
-<a href=#466 id=466 data-nosnippet>466</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(
-<a href=#467 id=467 data-nosnippet>467</a> ErrorKind::Unexpected,
-<a href=#468 id=468 data-nosnippet>468</a> <span class="string">"Cannot write to a closed AesGcmFileWrite"</span>,
-<a href=#469 id=469 data-nosnippet>469</a> ));
-<a href=#470 id=470 data-nosnippet>470</a> }
-<a href=#471 id=471 data-nosnippet>471</a> <span class="kw">if </span><span class="self">self</span>.poisoned {
-<a href=#472 id=472 data-nosnippet>472</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(
-<a href=#473 id=473 data-nosnippet>473</a> ErrorKind::Unexpected,
-<a href=#474 id=474 data-nosnippet>474</a> <span class="string">"AesGcmFileWrite is in a poisoned state due to a previous write failure"</span>,
-<a href=#475 id=475 data-nosnippet>475</a> ));
-<a href=#476 id=476 data-nosnippet>476</a> }
-<a href=#477 id=477 data-nosnippet>477</a>
-<a href=#478 id=478 data-nosnippet>478</a> <span class="kw">if </span>!<span class="self">self</span>.header_written {
-<a href=#479 id=479 data-nosnippet>479</a> <span class="self">self</span>.write_header().<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#480 id=480 data-nosnippet>480</a> }
+<a href=#357 id=357 data-nosnippet>357</a>/// ```ignore
+<a href=#358 id=358 data-nosnippet>358</a>/// // (ignored: requires async runtime and concrete FileRead/FileWrite impls)
+<a href=#359 id=359 data-nosnippet>359</a>/// let writer = AesGcmFileWrite::new(
+<a href=#360 id=360 data-nosnippet>360</a>/// inner_writer, // Box<dyn FileWrite> for the output file
+<a href=#361 id=361 data-nosnippet>361</a>/// cipher, // Arc<AesGcmCipher> with the DEK
+<a href=#362 id=362 data-nosnippet>362</a>/// aad_prefix.to_vec(),
+<a href=#363 id=363 data-nosnippet>363</a>/// );
+<a href=#364 id=364 data-nosnippet>364</a>///
+<a href=#365 id=365 data-nosnippet>365</a>/// writer.write(plaintext_chunk).await?;
+<a href=#366 id=366 data-nosnippet>366</a>/// writer.close().await?;
+<a href=#367 id=367 data-nosnippet>367</a>/// ```
+<a href=#368 id=368 data-nosnippet>368</a></span><span class="kw">pub struct </span>AesGcmFileWrite {
+<a href=#369 id=369 data-nosnippet>369</a> <span class="doccomment">/// The underlying output writer.
+<a href=#370 id=370 data-nosnippet>370</a> </span>inner: Box<<span class="kw">dyn </span>FileWrite>,
+<a href=#371 id=371 data-nosnippet>371</a> <span class="doccomment">/// The AES-GCM cipher holding the DEK.
+<a href=#372 id=372 data-nosnippet>372</a> </span>cipher: Arc<AesGcmCipher>,
+<a href=#373 id=373 data-nosnippet>373</a> <span class="doccomment">/// AAD prefix from the key metadata.
+<a href=#374 id=374 data-nosnippet>374</a> </span>aad_prefix: Box<[u8]>,
+<a href=#375 id=375 data-nosnippet>375</a> <span class="doccomment">/// Plaintext buffer accumulating data before block encryption.
+<a href=#376 id=376 data-nosnippet>376</a> </span>buffer: Vec<u8>,
+<a href=#377 id=377 data-nosnippet>377</a> <span class="doccomment">/// Current block index for AAD construction.
+<a href=#378 id=378 data-nosnippet>378</a> </span>block_index: u32,
+<a href=#379 id=379 data-nosnippet>379</a> <span class="doccomment">/// Whether the AGS1 header has been written.
+<a href=#380 id=380 data-nosnippet>380</a> </span>header_written: bool,
+<a href=#381 id=381 data-nosnippet>381</a> <span class="doccomment">/// Whether close() has been called.
+<a href=#382 id=382 data-nosnippet>382</a> </span>closed: bool,
+<a href=#383 id=383 data-nosnippet>383</a> <span class="doccomment">/// Whether the writer is in a poisoned state due to a failed inner write.
+<a href=#384 id=384 data-nosnippet>384</a> /// Once poisoned, all subsequent operations are rejected because the inner
+<a href=#385 id=385 data-nosnippet>385</a> /// writer may have received partial data.
+<a href=#386 id=386 data-nosnippet>386</a> </span>poisoned: bool,
+<a href=#387 id=387 data-nosnippet>387</a>}
+<a href=#388 id=388 data-nosnippet>388</a>
+<a href=#389 id=389 data-nosnippet>389</a><span class="kw">impl </span>AesGcmFileWrite {
+<a href=#390 id=390 data-nosnippet>390</a> <span class="doccomment">/// Creates a new `AesGcmFileWrite` for encrypting to AGS1 format.
+<a href=#391 id=391 data-nosnippet>391</a> ///
+<a href=#392 id=392 data-nosnippet>392</a> /// No I/O is performed until `write()` or `close()` is called.
+<a href=#393 id=393 data-nosnippet>393</a> </span><span class="kw">pub fn </span>new(
+<a href=#394 id=394 data-nosnippet>394</a> inner: Box<<span class="kw">dyn </span>FileWrite>,
+<a href=#395 id=395 data-nosnippet>395</a> cipher: Arc<AesGcmCipher>,
+<a href=#396 id=396 data-nosnippet>396</a> aad_prefix: <span class="kw">impl </span>Into<Box<[u8]>>,
+<a href=#397 id=397 data-nosnippet>397</a> ) -> <span class="self">Self </span>{
+<a href=#398 id=398 data-nosnippet>398</a> <span class="self">Self </span>{
+<a href=#399 id=399 data-nosnippet>399</a> inner,
+<a href=#400 id=400 data-nosnippet>400</a> cipher,
+<a href=#401 id=401 data-nosnippet>401</a> aad_prefix: aad_prefix.into(),
+<a href=#402 id=402 data-nosnippet>402</a> buffer: Vec::new(),
+<a href=#403 id=403 data-nosnippet>403</a> block_index: <span class="number">0</span>,
+<a href=#404 id=404 data-nosnippet>404</a> header_written: <span class="bool-val">false</span>,
+<a href=#405 id=405 data-nosnippet>405</a> closed: <span class="bool-val">false</span>,
+<a href=#406 id=406 data-nosnippet>406</a> poisoned: <span class="bool-val">false</span>,
+<a href=#407 id=407 data-nosnippet>407</a> }
+<a href=#408 id=408 data-nosnippet>408</a> }
+<a href=#409 id=409 data-nosnippet>409</a>
+<a href=#410 id=410 data-nosnippet>410</a> <span class="doccomment">/// Writes the AGS1 header (magic + plain block size) to the inner writer.
+<a href=#411 id=411 data-nosnippet>411</a> </span><span class="kw">async fn </span>write_header(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
+<a href=#412 id=412 data-nosnippet>412</a> <span class="kw">let </span><span class="kw-2">mut </span>header = Vec::with_capacity(GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>usize);
+<a href=#413 id=413 data-nosnippet>413</a> header.extend_from_slice(<span class="kw-2">&</span>GCM_STREAM_MAGIC);
+<a href=#414 id=414 data-nosnippet>414</a> header.extend_from_slice(<span class="kw-2">&</span>PLAIN_BLOCK_SIZE.to_le_bytes());
+<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(e) = <span class="self">self</span>.inner.write(Bytes::from(header)).<span class="kw">await </span>{
+<a href=#416 id=416 data-nosnippet>416</a> <span class="self">self</span>.poisoned = <span class="bool-val">true</span>;
+<a href=#417 id=417 data-nosnippet>417</a> <span class="kw">return </span><span class="prelude-val">Err</span>(e);
+<a href=#418 id=418 data-nosnippet>418</a> }
+<a href=#419 id=419 data-nosnippet>419</a> <span class="self">self</span>.header_written = <span class="bool-val">true</span>;
+<a href=#420 id=420 data-nosnippet>420</a> <span class="prelude-val">Ok</span>(())
+<a href=#421 id=421 data-nosnippet>421</a> }
+<a href=#422 id=422 data-nosnippet>422</a>
+<a href=#423 id=423 data-nosnippet>423</a> <span class="doccomment">/// Encrypts a plaintext block and writes it to the inner writer.
+<a href=#424 id=424 data-nosnippet>424</a> </span><span class="kw">async fn </span>encrypt_and_write_block(<span class="kw-2">&mut </span><span class="self">self</span>, block_data: <span class="kw-2">&</span>[u8]) -> <span class="prelude-ty">Result</span><()> {
+<a href=#425 id=425 data-nosnippet>425</a> <span class="kw">let </span>aad = stream_block_aad(<span class="kw-2">&</span><span class="self">self</span>.aad_prefix, <span class="self">self</span>.block_index);
+<a href=#426 id=426 data-nosnippet>426</a> <span class="kw">let </span>encrypted = <span class="self">self</span>.cipher.encrypt(block_data, <span class="prelude-val">Some</span>(<span class="kw-2">&</span>aad))<span class="question-mark">?</span>;
+<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(e) = <span class="self">self</span>.inner.write(Bytes::from(encrypted)).<span class="kw">await </span>{
+<a href=#428 id=428 data-nosnippet>428</a> <span class="self">self</span>.poisoned = <span class="bool-val">true</span>;
+<a href=#429 id=429 data-nosnippet>429</a> <span class="kw">return </span><span class="prelude-val">Err</span>(e);
+<a href=#430 id=430 data-nosnippet>430</a> }
+<a href=#431 id=431 data-nosnippet>431</a> <span class="self">self</span>.block_index = <span class="self">self</span>.block_index.checked_add(<span class="number">1</span>).ok_or_else(|| {
+<a href=#432 id=432 data-nosnippet>432</a> <span class="macro">invalid_data!</span>(
+<a href=#433 id=433 data-nosnippet>433</a> <span class="string">"AGS1 block index overflow: file exceeds the maximum supported size (~4 TiB)"
+<a href=#434 id=434 data-nosnippet>434</a> </span>)
+<a href=#435 id=435 data-nosnippet>435</a> })<span class="question-mark">?</span>;
+<a href=#436 id=436 data-nosnippet>436</a> <span class="prelude-val">Ok</span>(())
+<a href=#437 id=437 data-nosnippet>437</a> }
+<a href=#438 id=438 data-nosnippet>438</a>
+<a href=#439 id=439 data-nosnippet>439</a> <span class="doccomment">/// Encrypts the first `PLAIN_BLOCK_SIZE` bytes of the buffer in-place
+<a href=#440 id=440 data-nosnippet>440</a> /// and drains them, avoiding a 1 MiB temporary copy.
+<a href=#441 id=441 data-nosnippet>441</a> </span><span class="kw">async fn </span>encrypt_and_drain_block(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
+<a href=#442 id=442 data-nosnippet>442</a> <span class="kw">let </span>aad = stream_block_aad(<span class="kw-2">&</span><span class="self">self</span>.aad_prefix, <span class="self">self</span>.block_index);
+<a href=#443 id=443 data-nosnippet>443</a> <span class="kw">let </span>encrypted = <span class="self">self
+<a href=#444 id=444 data-nosnippet>444</a> </span>.cipher
+<a href=#445 id=445 data-nosnippet>445</a> .encrypt(<span class="kw-2">&</span><span class="self">self</span>.buffer[..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize], <span class="prelude-val">Some</span>(<span class="kw-2">&</span>aad))<span class="question-mark">?</span>;
+<a href=#446 id=446 data-nosnippet>446</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(e) = <span class="self">self</span>.inner.write(Bytes::from(encrypted)).<span class="kw">await </span>{
+<a href=#447 id=447 data-nosnippet>447</a> <span class="self">self</span>.poisoned = <span class="bool-val">true</span>;
+<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">return </span><span class="prelude-val">Err</span>(e);
+<a href=#449 id=449 data-nosnippet>449</a> }
+<a href=#450 id=450 data-nosnippet>450</a> <span class="self">self</span>.block_index = <span class="self">self</span>.block_index.checked_add(<span class="number">1</span>).ok_or_else(|| {
+<a href=#451 id=451 data-nosnippet>451</a> <span class="macro">invalid_data!</span>(
+<a href=#452 id=452 data-nosnippet>452</a> <span class="string">"AGS1 block index overflow: file exceeds the maximum supported size (~4 TiB)"
+<a href=#453 id=453 data-nosnippet>453</a> </span>)
+<a href=#454 id=454 data-nosnippet>454</a> })<span class="question-mark">?</span>;
+<a href=#455 id=455 data-nosnippet>455</a> <span class="self">self</span>.buffer.drain(..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize);
+<a href=#456 id=456 data-nosnippet>456</a> <span class="prelude-val">Ok</span>(())
+<a href=#457 id=457 data-nosnippet>457</a> }
+<a href=#458 id=458 data-nosnippet>458</a>}
+<a href=#459 id=459 data-nosnippet>459</a>
+<a href=#460 id=460 data-nosnippet>460</a><span class="attr">#[async_trait::async_trait]
+<a href=#461 id=461 data-nosnippet>461</a></span><span class="kw">impl </span>FileWrite <span class="kw">for </span>AesGcmFileWrite {
+<a href=#462 id=462 data-nosnippet>462</a> <span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
+<a href=#463 id=463 data-nosnippet>463</a> <span class="kw">if </span><span class="self">self</span>.closed {
+<a href=#464 id=464 data-nosnippet>464</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(
+<a href=#465 id=465 data-nosnippet>465</a> ErrorKind::Unexpected,
+<a href=#466 id=466 data-nosnippet>466</a> <span class="string">"Cannot write to a closed AesGcmFileWrite"</span>,
+<a href=#467 id=467 data-nosnippet>467</a> ));
+<a href=#468 id=468 data-nosnippet>468</a> }
+<a href=#469 id=469 data-nosnippet>469</a> <span class="kw">if </span><span class="self">self</span>.poisoned {
+<a href=#470 id=470 data-nosnippet>470</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(
+<a href=#471 id=471 data-nosnippet>471</a> ErrorKind::Unexpected,
+<a href=#472 id=472 data-nosnippet>472</a> <span class="string">"AesGcmFileWrite is in a poisoned state due to a previous write failure"</span>,
+<a href=#473 id=473 data-nosnippet>473</a> ));
+<a href=#474 id=474 data-nosnippet>474</a> }
+<a href=#475 id=475 data-nosnippet>475</a>
+<a href=#476 id=476 data-nosnippet>476</a> <span class="kw">if </span>!<span class="self">self</span>.header_written {
+<a href=#477 id=477 data-nosnippet>477</a> <span class="self">self</span>.write_header().<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#478 id=478 data-nosnippet>478</a> }
+<a href=#479 id=479 data-nosnippet>479</a>
+<a href=#480 id=480 data-nosnippet>480</a> <span class="self">self</span>.buffer.extend_from_slice(<span class="kw-2">&</span>bs);
<a href=#481 id=481 data-nosnippet>481</a>
-<a href=#482 id=482 data-nosnippet>482</a> <span class="self">self</span>.buffer.extend_from_slice(<span class="kw-2">&</span>bs);
-<a href=#483 id=483 data-nosnippet>483</a>
-<a href=#484 id=484 data-nosnippet>484</a> <span class="comment">// Flush full blocks
-<a href=#485 id=485 data-nosnippet>485</a> </span><span class="kw">while </span><span class="self">self</span>.buffer.len() >= PLAIN_BLOCK_SIZE <span class="kw">as </span>usize {
-<a href=#486 id=486 data-nosnippet>486</a> <span class="self">self</span>.encrypt_and_drain_block().<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#487 id=487 data-nosnippet>487</a> }
-<a href=#488 id=488 data-nosnippet>488</a>
-<a href=#489 id=489 data-nosnippet>489</a> <span class="prelude-val">Ok</span>(())
-<a href=#490 id=490 data-nosnippet>490</a> }
-<a href=#491 id=491 data-nosnippet>491</a>
-<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
-<a href=#493 id=493 data-nosnippet>493</a> <span class="kw">if </span><span class="self">self</span>.closed {
-<a href=#494 id=494 data-nosnippet>494</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(
-<a href=#495 id=495 data-nosnippet>495</a> ErrorKind::Unexpected,
-<a href=#496 id=496 data-nosnippet>496</a> <span class="string">"AesGcmFileWrite already closed"</span>,
-<a href=#497 id=497 data-nosnippet>497</a> ));
-<a href=#498 id=498 data-nosnippet>498</a> }
-<a href=#499 id=499 data-nosnippet>499</a> <span class="kw">if </span><span class="self">self</span>.poisoned {
-<a href=#500 id=500 data-nosnippet>500</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(
-<a href=#501 id=501 data-nosnippet>501</a> ErrorKind::Unexpected,
-<a href=#502 id=502 data-nosnippet>502</a> <span class="string">"AesGcmFileWrite is in a poisoned state due to a previous write failure"</span>,
-<a href=#503 id=503 data-nosnippet>503</a> ));
-<a href=#504 id=504 data-nosnippet>504</a> }
-<a href=#505 id=505 data-nosnippet>505</a>
-<a href=#506 id=506 data-nosnippet>506</a> <span class="kw">if </span>!<span class="self">self</span>.header_written {
-<a href=#507 id=507 data-nosnippet>507</a> <span class="self">self</span>.write_header().<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#508 id=508 data-nosnippet>508</a> }
-<a href=#509 id=509 data-nosnippet>509</a>
-<a href=#510 id=510 data-nosnippet>510</a> <span class="comment">// Write the final block if there's remaining data, or if this is an empty file
-<a href=#511 id=511 data-nosnippet>511</a> // (block_index == 0). Skip writing a spurious empty block when the plaintext was
-<a href=#512 id=512 data-nosnippet>512</a> // exactly block-aligned (buffer empty, blocks already written).
-<a href=#513 id=513 data-nosnippet>513</a> </span><span class="kw">if </span>!<span class="self">self</span>.buffer.is_empty() || <span class="self">self</span>.block_index == <span class="number">0 </span>{
-<a href=#514 id=514 data-nosnippet>514</a> <span class="kw">let </span>final_block = std::mem::take(<span class="kw-2">&mut </span><span class="self">self</span>.buffer);
-<a href=#515 id=515 data-nosnippet>515</a> <span class="self">self</span>.encrypt_and_write_block(<span class="kw-2">&</span>final_block).<span class="kw">await</span><span class="question-mark">?</span>;
-<a href=#516 id=516 data-nosnippet>516</a> }
-<a href=#517 id=517 data-nosnippet>517</a> <span class="self">self</span>.closed = <span class="bool-val">true</span>;
-<a href=#518 id=518 data-nosnippet>518</a>
-<a href=#519 id=519 data-nosnippet>519</a> <span class="self">self</span>.inner.close().<span class="kw">await
-<a href=#520 id=520 data-nosnippet>520</a> </span>}
-<a href=#521 id=521 data-nosnippet>521</a>}
-<a href=#522 id=522 data-nosnippet>522</a>
-<a href=#523 id=523 data-nosnippet>523</a><span class="attr">#[cfg(test)]
-<a href=#524 id=524 data-nosnippet>524</a></span><span class="kw">mod </span>tests {
-<a href=#525 id=525 data-nosnippet>525</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
-<a href=#526 id=526 data-nosnippet>526</a>
-<a href=#527 id=527 data-nosnippet>527</a> <span class="doccomment">/// Encrypts plaintext into AGS1 format for testing.
-<a href=#528 id=528 data-nosnippet>528</a> ///
-<a href=#529 id=529 data-nosnippet>529</a> /// Mirrors Java's `AesGcmOutputStream` behavior:
-<a href=#530 id=530 data-nosnippet>530</a> /// - Always writes header + at least one block (even for empty input)
-<a href=#531 id=531 data-nosnippet>531</a> /// - Full blocks are `PLAIN_BLOCK_SIZE` bytes; last block may be shorter
-<a href=#532 id=532 data-nosnippet>532</a> </span><span class="kw">fn </span>encrypt_ags1(plaintext: <span class="kw-2">&</span>[u8], cipher: <span class="kw-2">&</span>AesGcmCipher, aad_prefix: <span class="kw-2">&</span>[u8]) -> Vec<u8> {
-<a href=#533 id=533 data-nosnippet>533</a> <span class="kw">let </span><span class="kw-2">mut </span>result = Vec::new();
-<a href=#534 id=534 data-nosnippet>534</a>
-<a href=#535 id=535 data-nosnippet>535</a> <span class="comment">// Write header: "AGS1" + PLAIN_BLOCK_SIZE (LE)
-<a href=#536 id=536 data-nosnippet>536</a> </span>result.extend_from_slice(<span class="kw-2">&</span>GCM_STREAM_MAGIC);
-<a href=#537 id=537 data-nosnippet>537</a> result.extend_from_slice(<span class="kw-2">&</span>PLAIN_BLOCK_SIZE.to_le_bytes());
-<a href=#538 id=538 data-nosnippet>538</a>
-<a href=#539 id=539 data-nosnippet>539</a> <span class="comment">// Write blocks
-<a href=#540 id=540 data-nosnippet>540</a> </span><span class="kw">let </span><span class="kw-2">mut </span>offset = <span class="number">0</span>;
-<a href=#541 id=541 data-nosnippet>541</a> <span class="kw">let </span><span class="kw-2">mut </span>block_index = <span class="number">0u32</span>;
-<a href=#542 id=542 data-nosnippet>542</a>
-<a href=#543 id=543 data-nosnippet>543</a> <span class="kw">loop </span>{
-<a href=#544 id=544 data-nosnippet>544</a> <span class="kw">let </span>remaining = plaintext.len() - offset;
-<a href=#545 id=545 data-nosnippet>545</a> <span class="kw">let </span>block_size = std::cmp::min(remaining, PLAIN_BLOCK_SIZE <span class="kw">as </span>usize);
-<a href=#546 id=546 data-nosnippet>546</a>
-<a href=#547 id=547 data-nosnippet>547</a> <span class="comment">// Block 0 is always written (even if empty); subsequent empty blocks are skipped
-<a href=#548 id=548 data-nosnippet>548</a> </span><span class="kw">if </span>block_size == <span class="number">0 </span>&& block_index > <span class="number">0 </span>{
-<a href=#549 id=549 data-nosnippet>549</a> <span class="kw">break</span>;
-<a href=#550 id=550 data-nosnippet>550</a> }
-<a href=#551 id=551 data-nosnippet>551</a>
-<a href=#552 id=552 data-nosnippet>552</a> <span class="kw">let </span>block_data = <span class="kw-2">&</span>plaintext[offset..offset + block_size];
-<a href=#553 id=553 data-nosnippet>553</a> <span class="kw">let </span>aad = stream_block_aad(aad_prefix, block_index);
-<a href=#554 id=554 data-nosnippet>554</a> <span class="kw">let </span>encrypted = cipher.encrypt(block_data, <span class="prelude-val">Some</span>(<span class="kw-2">&</span>aad)).unwrap();
-<a href=#555 id=555 data-nosnippet>555</a> result.extend_from_slice(<span class="kw-2">&</span>encrypted);
-<a href=#556 id=556 data-nosnippet>556</a>
-<a href=#557 id=557 data-nosnippet>557</a> offset += block_size;
-<a href=#558 id=558 data-nosnippet>558</a> block_index += <span class="number">1</span>;
-<a href=#559 id=559 data-nosnippet>559</a>
-<a href=#560 id=560 data-nosnippet>560</a> <span class="comment">// A partial block is always the last
-<a href=#561 id=561 data-nosnippet>561</a> </span><span class="kw">if </span>block_size < PLAIN_BLOCK_SIZE <span class="kw">as </span>usize {
-<a href=#562 id=562 data-nosnippet>562</a> <span class="kw">break</span>;
-<a href=#563 id=563 data-nosnippet>563</a> }
-<a href=#564 id=564 data-nosnippet>564</a> }
-<a href=#565 id=565 data-nosnippet>565</a>
-<a href=#566 id=566 data-nosnippet>566</a> result
-<a href=#567 id=567 data-nosnippet>567</a> }
-<a href=#568 id=568 data-nosnippet>568</a>
-<a href=#569 id=569 data-nosnippet>569</a> <span class="doccomment">/// Helper to create an AesGcmCipher from raw key bytes.
-<a href=#570 id=570 data-nosnippet>570</a> </span><span class="kw">fn </span>make_cipher(key: <span class="kw-2">&</span>[u8]) -> AesGcmCipher {
-<a href=#571 id=571 data-nosnippet>571</a> <span class="kw">use </span><span class="kw">super</span>::<span class="kw">super</span>::SecureKey;
-<a href=#572 id=572 data-nosnippet>572</a> <span class="kw">let </span>secure_key = SecureKey::new(key).unwrap();
-<a href=#573 id=573 data-nosnippet>573</a> AesGcmCipher::new(secure_key)
-<a href=#574 id=574 data-nosnippet>574</a> }
-<a href=#575 id=575 data-nosnippet>575</a>
-<a href=#576 id=576 data-nosnippet>576</a> <span class="doccomment">/// Helper to create an in-memory FileRead from bytes.
-<a href=#577 id=577 data-nosnippet>577</a> </span><span class="kw">fn </span>memory_reader(data: Vec<u8>) -> Box<<span class="kw">dyn </span>FileRead> {
-<a href=#578 id=578 data-nosnippet>578</a> Box::new(MemoryFileRead(Bytes::from(data)))
-<a href=#579 id=579 data-nosnippet>579</a> }
-<a href=#580 id=580 data-nosnippet>580</a>
-<a href=#581 id=581 data-nosnippet>581</a> <span class="doccomment">/// Simple in-memory FileRead for tests.
-<a href=#582 id=582 data-nosnippet>582</a> </span><span class="kw">struct </span>MemoryFileRead(Bytes);
-<a href=#583 id=583 data-nosnippet>583</a>
-<a href=#584 id=584 data-nosnippet>584</a> <span class="attr">#[async_trait::async_trait]
-<a href=#585 id=585 data-nosnippet>585</a> </span><span class="kw">impl </span>FileRead <span class="kw">for </span>MemoryFileRead {
-<a href=#586 id=586 data-nosnippet>586</a> <span class="kw">async fn </span>read(<span class="kw-2">&</span><span class="self">self</span>, range: Range<u64>) -> <span class="prelude-ty">Result</span><Bytes> {
-<a href=#587 id=587 data-nosnippet>587</a> <span class="kw">let </span>start = range.start <span class="kw">as </span>usize;
-<a href=#588 id=588 data-nosnippet>588</a> <span class="kw">let </span>end = range.end <span class="kw">as </span>usize;
-<a href=#589 id=589 data-nosnippet>589</a> <span class="kw">if </span>end > <span class="self">self</span>.<span class="number">0</span>.len() {
-<a href=#590 id=590 data-nosnippet>590</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
-<a href=#591 id=591 data-nosnippet>591</a> <span class="string">"Range {}..{} out of bounds for {} bytes"</span>,
-<a href=#592 id=592 data-nosnippet>592</a> start,
-<a href=#593 id=593 data-nosnippet>593</a> end,
-<a href=#594 id=594 data-nosnippet>594</a> <span class="self">self</span>.<span class="number">0</span>.len()
-<a href=#595 id=595 data-nosnippet>595</a> ));
-<a href=#596 id=596 data-nosnippet>596</a> }
-<a href=#597 id=597 data-nosnippet>597</a> <span class="prelude-val">Ok</span>(<span class="self">self</span>.<span class="number">0</span>.slice(start..end))
-<a href=#598 id=598 data-nosnippet>598</a> }
-<a href=#599 id=599 data-nosnippet>599</a> }
-<a href=#600 id=600 data-nosnippet>600</a>
-<a href=#601 id=601 data-nosnippet>601</a> <span class="attr">#[tokio::test]
-<a href=#602 id=602 data-nosnippet>602</a> </span><span class="kw">async fn </span>test_empty_file_roundtrip() {
-<a href=#603 id=603 data-nosnippet>603</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#604 id=604 data-nosnippet>604</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
-<a href=#605 id=605 data-nosnippet>605</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#482 id=482 data-nosnippet>482</a> <span class="comment">// Flush full blocks
+<a href=#483 id=483 data-nosnippet>483</a> </span><span class="kw">while </span><span class="self">self</span>.buffer.len() >= PLAIN_BLOCK_SIZE <span class="kw">as </span>usize {
+<a href=#484 id=484 data-nosnippet>484</a> <span class="self">self</span>.encrypt_and_drain_block().<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#485 id=485 data-nosnippet>485</a> }
+<a href=#486 id=486 data-nosnippet>486</a>
+<a href=#487 id=487 data-nosnippet>487</a> <span class="prelude-val">Ok</span>(())
+<a href=#488 id=488 data-nosnippet>488</a> }
+<a href=#489 id=489 data-nosnippet>489</a>
+<a href=#490 id=490 data-nosnippet>490</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><FileMetadata> {
+<a href=#491 id=491 data-nosnippet>491</a> <span class="kw">if </span><span class="self">self</span>.closed {
+<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(
+<a href=#493 id=493 data-nosnippet>493</a> ErrorKind::Unexpected,
+<a href=#494 id=494 data-nosnippet>494</a> <span class="string">"AesGcmFileWrite already closed"</span>,
+<a href=#495 id=495 data-nosnippet>495</a> ));
+<a href=#496 id=496 data-nosnippet>496</a> }
+<a href=#497 id=497 data-nosnippet>497</a> <span class="kw">if </span><span class="self">self</span>.poisoned {
+<a href=#498 id=498 data-nosnippet>498</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(
+<a href=#499 id=499 data-nosnippet>499</a> ErrorKind::Unexpected,
+<a href=#500 id=500 data-nosnippet>500</a> <span class="string">"AesGcmFileWrite is in a poisoned state due to a previous write failure"</span>,
+<a href=#501 id=501 data-nosnippet>501</a> ));
+<a href=#502 id=502 data-nosnippet>502</a> }
+<a href=#503 id=503 data-nosnippet>503</a>
+<a href=#504 id=504 data-nosnippet>504</a> <span class="kw">if </span>!<span class="self">self</span>.header_written {
+<a href=#505 id=505 data-nosnippet>505</a> <span class="self">self</span>.write_header().<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#506 id=506 data-nosnippet>506</a> }
+<a href=#507 id=507 data-nosnippet>507</a>
+<a href=#508 id=508 data-nosnippet>508</a> <span class="comment">// Write the final block if there's remaining data, or if this is an empty file
+<a href=#509 id=509 data-nosnippet>509</a> // (block_index == 0). Skip writing a spurious empty block when the plaintext was
+<a href=#510 id=510 data-nosnippet>510</a> // exactly block-aligned (buffer empty, blocks already written).
+<a href=#511 id=511 data-nosnippet>511</a> </span><span class="kw">if </span>!<span class="self">self</span>.buffer.is_empty() || <span class="self">self</span>.block_index == <span class="number">0 </span>{
+<a href=#512 id=512 data-nosnippet>512</a> <span class="kw">let </span>final_block = std::mem::take(<span class="kw-2">&mut </span><span class="self">self</span>.buffer);
+<a href=#513 id=513 data-nosnippet>513</a> <span class="self">self</span>.encrypt_and_write_block(<span class="kw-2">&</span>final_block).<span class="kw">await</span><span class="question-mark">?</span>;
+<a href=#514 id=514 data-nosnippet>514</a> }
+<a href=#515 id=515 data-nosnippet>515</a> <span class="self">self</span>.closed = <span class="bool-val">true</span>;
+<a href=#516 id=516 data-nosnippet>516</a>
+<a href=#517 id=517 data-nosnippet>517</a> <span class="self">self</span>.inner.close().<span class="kw">await
+<a href=#518 id=518 data-nosnippet>518</a> </span>}
+<a href=#519 id=519 data-nosnippet>519</a>}
+<a href=#520 id=520 data-nosnippet>520</a>
+<a href=#521 id=521 data-nosnippet>521</a><span class="attr">#[cfg(test)]
+<a href=#522 id=522 data-nosnippet>522</a></span><span class="kw">mod </span>tests {
+<a href=#523 id=523 data-nosnippet>523</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
+<a href=#524 id=524 data-nosnippet>524</a>
+<a href=#525 id=525 data-nosnippet>525</a> <span class="doccomment">/// Encrypts plaintext into AGS1 format for testing.
+<a href=#526 id=526 data-nosnippet>526</a> ///
+<a href=#527 id=527 data-nosnippet>527</a> /// Mirrors Java's `AesGcmOutputStream` behavior:
+<a href=#528 id=528 data-nosnippet>528</a> /// - Always writes header + at least one block (even for empty input)
+<a href=#529 id=529 data-nosnippet>529</a> /// - Full blocks are `PLAIN_BLOCK_SIZE` bytes; last block may be shorter
+<a href=#530 id=530 data-nosnippet>530</a> </span><span class="kw">fn </span>encrypt_ags1(plaintext: <span class="kw-2">&</span>[u8], cipher: <span class="kw-2">&</span>AesGcmCipher, aad_prefix: <span class="kw-2">&</span>[u8]) -> Vec<u8> {
+<a href=#531 id=531 data-nosnippet>531</a> <span class="kw">let </span><span class="kw-2">mut </span>result = Vec::new();
+<a href=#532 id=532 data-nosnippet>532</a>
+<a href=#533 id=533 data-nosnippet>533</a> <span class="comment">// Write header: "AGS1" + PLAIN_BLOCK_SIZE (LE)
+<a href=#534 id=534 data-nosnippet>534</a> </span>result.extend_from_slice(<span class="kw-2">&</span>GCM_STREAM_MAGIC);
+<a href=#535 id=535 data-nosnippet>535</a> result.extend_from_slice(<span class="kw-2">&</span>PLAIN_BLOCK_SIZE.to_le_bytes());
+<a href=#536 id=536 data-nosnippet>536</a>
+<a href=#537 id=537 data-nosnippet>537</a> <span class="comment">// Write blocks
+<a href=#538 id=538 data-nosnippet>538</a> </span><span class="kw">let </span><span class="kw-2">mut </span>offset = <span class="number">0</span>;
+<a href=#539 id=539 data-nosnippet>539</a> <span class="kw">let </span><span class="kw-2">mut </span>block_index = <span class="number">0u32</span>;
+<a href=#540 id=540 data-nosnippet>540</a>
+<a href=#541 id=541 data-nosnippet>541</a> <span class="kw">loop </span>{
+<a href=#542 id=542 data-nosnippet>542</a> <span class="kw">let </span>remaining = plaintext.len() - offset;
+<a href=#543 id=543 data-nosnippet>543</a> <span class="kw">let </span>block_size = std::cmp::min(remaining, PLAIN_BLOCK_SIZE <span class="kw">as </span>usize);
+<a href=#544 id=544 data-nosnippet>544</a>
+<a href=#545 id=545 data-nosnippet>545</a> <span class="comment">// Block 0 is always written (even if empty); subsequent empty blocks are skipped
+<a href=#546 id=546 data-nosnippet>546</a> </span><span class="kw">if </span>block_size == <span class="number">0 </span>&& block_index > <span class="number">0 </span>{
+<a href=#547 id=547 data-nosnippet>547</a> <span class="kw">break</span>;
+<a href=#548 id=548 data-nosnippet>548</a> }
+<a href=#549 id=549 data-nosnippet>549</a>
+<a href=#550 id=550 data-nosnippet>550</a> <span class="kw">let </span>block_data = <span class="kw-2">&</span>plaintext[offset..offset + block_size];
+<a href=#551 id=551 data-nosnippet>551</a> <span class="kw">let </span>aad = stream_block_aad(aad_prefix, block_index);
+<a href=#552 id=552 data-nosnippet>552</a> <span class="kw">let </span>encrypted = cipher.encrypt(block_data, <span class="prelude-val">Some</span>(<span class="kw-2">&</span>aad)).unwrap();
+<a href=#553 id=553 data-nosnippet>553</a> result.extend_from_slice(<span class="kw-2">&</span>encrypted);
+<a href=#554 id=554 data-nosnippet>554</a>
+<a href=#555 id=555 data-nosnippet>555</a> offset += block_size;
+<a href=#556 id=556 data-nosnippet>556</a> block_index += <span class="number">1</span>;
+<a href=#557 id=557 data-nosnippet>557</a>
+<a href=#558 id=558 data-nosnippet>558</a> <span class="comment">// A partial block is always the last
+<a href=#559 id=559 data-nosnippet>559</a> </span><span class="kw">if </span>block_size < PLAIN_BLOCK_SIZE <span class="kw">as </span>usize {
+<a href=#560 id=560 data-nosnippet>560</a> <span class="kw">break</span>;
+<a href=#561 id=561 data-nosnippet>561</a> }
+<a href=#562 id=562 data-nosnippet>562</a> }
+<a href=#563 id=563 data-nosnippet>563</a>
+<a href=#564 id=564 data-nosnippet>564</a> result
+<a href=#565 id=565 data-nosnippet>565</a> }
+<a href=#566 id=566 data-nosnippet>566</a>
+<a href=#567 id=567 data-nosnippet>567</a> <span class="doccomment">/// Helper to create an AesGcmCipher from raw key bytes.
+<a href=#568 id=568 data-nosnippet>568</a> </span><span class="kw">fn </span>make_cipher(key: <span class="kw-2">&</span>[u8]) -> AesGcmCipher {
+<a href=#569 id=569 data-nosnippet>569</a> <span class="kw">use </span><span class="kw">super</span>::<span class="kw">super</span>::SecureKey;
+<a href=#570 id=570 data-nosnippet>570</a> <span class="kw">let </span>secure_key = SecureKey::new(key).unwrap();
+<a href=#571 id=571 data-nosnippet>571</a> AesGcmCipher::new(secure_key)
+<a href=#572 id=572 data-nosnippet>572</a> }
+<a href=#573 id=573 data-nosnippet>573</a>
+<a href=#574 id=574 data-nosnippet>574</a> <span class="doccomment">/// Helper to create an in-memory FileRead from bytes.
+<a href=#575 id=575 data-nosnippet>575</a> </span><span class="kw">fn </span>memory_reader(data: Vec<u8>) -> Box<<span class="kw">dyn </span>FileRead> {
+<a href=#576 id=576 data-nosnippet>576</a> Box::new(MemoryFileRead(Bytes::from(data)))
+<a href=#577 id=577 data-nosnippet>577</a> }
+<a href=#578 id=578 data-nosnippet>578</a>
+<a href=#579 id=579 data-nosnippet>579</a> <span class="doccomment">/// Simple in-memory FileRead for tests.
+<a href=#580 id=580 data-nosnippet>580</a> </span><span class="kw">struct </span>MemoryFileRead(Bytes);
+<a href=#581 id=581 data-nosnippet>581</a>
+<a href=#582 id=582 data-nosnippet>582</a> <span class="attr">#[async_trait::async_trait]
+<a href=#583 id=583 data-nosnippet>583</a> </span><span class="kw">impl </span>FileRead <span class="kw">for </span>MemoryFileRead {
+<a href=#584 id=584 data-nosnippet>584</a> <span class="kw">async fn </span>read(<span class="kw-2">&</span><span class="self">self</span>, range: Range<u64>) -> <span class="prelude-ty">Result</span><Bytes> {
+<a href=#585 id=585 data-nosnippet>585</a> <span class="kw">let </span>start = range.start <span class="kw">as </span>usize;
+<a href=#586 id=586 data-nosnippet>586</a> <span class="kw">let </span>end = range.end <span class="kw">as </span>usize;
+<a href=#587 id=587 data-nosnippet>587</a> <span class="kw">if </span>end > <span class="self">self</span>.<span class="number">0</span>.len() {
+<a href=#588 id=588 data-nosnippet>588</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(
+<a href=#589 id=589 data-nosnippet>589</a> <span class="string">"Range {}..{} out of bounds for {} bytes"</span>,
+<a href=#590 id=590 data-nosnippet>590</a> start,
+<a href=#591 id=591 data-nosnippet>591</a> end,
+<a href=#592 id=592 data-nosnippet>592</a> <span class="self">self</span>.<span class="number">0</span>.len()
+<a href=#593 id=593 data-nosnippet>593</a> ));
+<a href=#594 id=594 data-nosnippet>594</a> }
+<a href=#595 id=595 data-nosnippet>595</a> <span class="prelude-val">Ok</span>(<span class="self">self</span>.<span class="number">0</span>.slice(start..end))
+<a href=#596 id=596 data-nosnippet>596</a> }
+<a href=#597 id=597 data-nosnippet>597</a> }
+<a href=#598 id=598 data-nosnippet>598</a>
+<a href=#599 id=599 data-nosnippet>599</a> <span class="attr">#[tokio::test]
+<a href=#600 id=600 data-nosnippet>600</a> </span><span class="kw">async fn </span>test_empty_file_roundtrip() {
+<a href=#601 id=601 data-nosnippet>601</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#602 id=602 data-nosnippet>602</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
+<a href=#603 id=603 data-nosnippet>603</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#604 id=604 data-nosnippet>604</a>
+<a href=#605 id=605 data-nosnippet>605</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="string">b""</span>, <span class="kw-2">&</span>cipher, aad_prefix);
<a href=#606 id=606 data-nosnippet>606</a>
-<a href=#607 id=607 data-nosnippet>607</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="string">b""</span>, <span class="kw-2">&</span>cipher, aad_prefix);
-<a href=#608 id=608 data-nosnippet>608</a>
-<a href=#609 id=609 data-nosnippet>609</a> <span class="comment">// Verify minimum length: header(8) + nonce(12) + tag(16) = 36
-<a href=#610 id=610 data-nosnippet>610</a> </span><span class="macro">assert_eq!</span>(encrypted.len(), MIN_STREAM_LENGTH <span class="kw">as </span>usize);
-<a href=#611 id=611 data-nosnippet>611</a>
-<a href=#612 id=612 data-nosnippet>612</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#613 id=613 data-nosnippet>613</a> memory_reader(encrypted.clone()),
-<a href=#614 id=614 data-nosnippet>614</a> Arc::new(make_cipher(key)),
-<a href=#615 id=615 data-nosnippet>615</a> aad_prefix.as_slice().into(),
-<a href=#616 id=616 data-nosnippet>616</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#617 id=617 data-nosnippet>617</a> )
-<a href=#618 id=618 data-nosnippet>618</a> .unwrap();
+<a href=#607 id=607 data-nosnippet>607</a> <span class="comment">// Verify minimum length: header(8) + nonce(12) + tag(16) = 36
+<a href=#608 id=608 data-nosnippet>608</a> </span><span class="macro">assert_eq!</span>(encrypted.len(), MIN_STREAM_LENGTH <span class="kw">as </span>usize);
+<a href=#609 id=609 data-nosnippet>609</a>
+<a href=#610 id=610 data-nosnippet>610</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#611 id=611 data-nosnippet>611</a> memory_reader(encrypted.clone()),
+<a href=#612 id=612 data-nosnippet>612</a> Arc::new(make_cipher(key)),
+<a href=#613 id=613 data-nosnippet>613</a> aad_prefix.as_slice().into(),
+<a href=#614 id=614 data-nosnippet>614</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#615 id=615 data-nosnippet>615</a> )
+<a href=#616 id=616 data-nosnippet>616</a> .unwrap();
+<a href=#617 id=617 data-nosnippet>617</a>
+<a href=#618 id=618 data-nosnippet>618</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), <span class="number">0</span>);
<a href=#619 id=619 data-nosnippet>619</a>
-<a href=#620 id=620 data-nosnippet>620</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), <span class="number">0</span>);
-<a href=#621 id=621 data-nosnippet>621</a>
-<a href=#622 id=622 data-nosnippet>622</a> <span class="comment">// Reading empty range should return empty bytes
-<a href=#623 id=623 data-nosnippet>623</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..<span class="number">0</span>).<span class="kw">await</span>.unwrap();
-<a href=#624 id=624 data-nosnippet>624</a> <span class="macro">assert!</span>(result.is_empty());
-<a href=#625 id=625 data-nosnippet>625</a> }
-<a href=#626 id=626 data-nosnippet>626</a>
-<a href=#627 id=627 data-nosnippet>627</a> <span class="attr">#[tokio::test]
-<a href=#628 id=628 data-nosnippet>628</a> </span><span class="kw">async fn </span>test_small_file_roundtrip() {
-<a href=#629 id=629 data-nosnippet>629</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#630 id=630 data-nosnippet>630</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
-<a href=#631 id=631 data-nosnippet>631</a> <span class="kw">let </span>plaintext = <span class="string">b"Hello, Iceberg encryption!"</span>;
-<a href=#632 id=632 data-nosnippet>632</a> <span class="kw">let </span>cipher = make_cipher(key);
-<a href=#633 id=633 data-nosnippet>633</a>
-<a href=#634 id=634 data-nosnippet>634</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
-<a href=#635 id=635 data-nosnippet>635</a>
-<a href=#636 id=636 data-nosnippet>636</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#637 id=637 data-nosnippet>637</a> memory_reader(encrypted.clone()),
-<a href=#638 id=638 data-nosnippet>638</a> Arc::new(make_cipher(key)),
-<a href=#639 id=639 data-nosnippet>639</a> aad_prefix.as_slice().into(),
-<a href=#640 id=640 data-nosnippet>640</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#641 id=641 data-nosnippet>641</a> )
-<a href=#642 id=642 data-nosnippet>642</a> .unwrap();
-<a href=#643 id=643 data-nosnippet>643</a>
-<a href=#644 id=644 data-nosnippet>644</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
-<a href=#645 id=645 data-nosnippet>645</a>
-<a href=#646 id=646 data-nosnippet>646</a> <span class="comment">// Read entire file
-<a href=#647 id=647 data-nosnippet>647</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#648 id=648 data-nosnippet>648</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], plaintext);
-<a href=#649 id=649 data-nosnippet>649</a> }
-<a href=#650 id=650 data-nosnippet>650</a>
-<a href=#651 id=651 data-nosnippet>651</a> <span class="attr">#[tokio::test]
-<a href=#652 id=652 data-nosnippet>652</a> </span><span class="kw">async fn </span>test_partial_read() {
-<a href=#653 id=653 data-nosnippet>653</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#654 id=654 data-nosnippet>654</a> <span class="kw">let </span>aad_prefix = <span class="string">b"aad-prefix-here!"</span>;
-<a href=#655 id=655 data-nosnippet>655</a> <span class="kw">let </span>plaintext = <span class="string">b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</span>;
-<a href=#656 id=656 data-nosnippet>656</a> <span class="kw">let </span>cipher = make_cipher(key);
-<a href=#657 id=657 data-nosnippet>657</a>
-<a href=#658 id=658 data-nosnippet>658</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
-<a href=#659 id=659 data-nosnippet>659</a>
-<a href=#660 id=660 data-nosnippet>660</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#661 id=661 data-nosnippet>661</a> memory_reader(encrypted.clone()),
-<a href=#662 id=662 data-nosnippet>662</a> Arc::new(make_cipher(key)),
-<a href=#663 id=663 data-nosnippet>663</a> aad_prefix.as_slice().into(),
-<a href=#664 id=664 data-nosnippet>664</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#665 id=665 data-nosnippet>665</a> )
-<a href=#666 id=666 data-nosnippet>666</a> .unwrap();
+<a href=#620 id=620 data-nosnippet>620</a> <span class="comment">// Reading empty range should return empty bytes
+<a href=#621 id=621 data-nosnippet>621</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..<span class="number">0</span>).<span class="kw">await</span>.unwrap();
+<a href=#622 id=622 data-nosnippet>622</a> <span class="macro">assert!</span>(result.is_empty());
+<a href=#623 id=623 data-nosnippet>623</a> }
+<a href=#624 id=624 data-nosnippet>624</a>
+<a href=#625 id=625 data-nosnippet>625</a> <span class="attr">#[tokio::test]
+<a href=#626 id=626 data-nosnippet>626</a> </span><span class="kw">async fn </span>test_short_ciphertext_read_is_rejected() {
+<a href=#627 id=627 data-nosnippet>627</a> <span class="kw">struct </span>ShortRead;
+<a href=#628 id=628 data-nosnippet>628</a>
+<a href=#629 id=629 data-nosnippet>629</a> <span class="attr">#[async_trait::async_trait]
+<a href=#630 id=630 data-nosnippet>630</a> </span><span class="kw">impl </span>FileRead <span class="kw">for </span>ShortRead {
+<a href=#631 id=631 data-nosnippet>631</a> <span class="kw">async fn </span>read(<span class="kw-2">&</span><span class="self">self</span>, range: Range<u64>) -> <span class="prelude-ty">Result</span><Bytes> {
+<a href=#632 id=632 data-nosnippet>632</a> <span class="kw">let </span>len = (range.end - range.start).saturating_sub(<span class="number">1</span>) <span class="kw">as </span>usize;
+<a href=#633 id=633 data-nosnippet>633</a> <span class="prelude-val">Ok</span>(Bytes::from(<span class="macro">vec!</span>[<span class="number">0</span>; len]))
+<a href=#634 id=634 data-nosnippet>634</a> }
+<a href=#635 id=635 data-nosnippet>635</a> }
+<a href=#636 id=636 data-nosnippet>636</a>
+<a href=#637 id=637 data-nosnippet>637</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#638 id=638 data-nosnippet>638</a> Box::new(ShortRead),
+<a href=#639 id=639 data-nosnippet>639</a> Arc::new(make_cipher(<span class="string">b"0123456789abcdef"</span>)),
+<a href=#640 id=640 data-nosnippet>640</a> Box::default(),
+<a href=#641 id=641 data-nosnippet>641</a> u64::from(MIN_STREAM_LENGTH) + <span class="number">10</span>,
+<a href=#642 id=642 data-nosnippet>642</a> )
+<a href=#643 id=643 data-nosnippet>643</a> .unwrap();
+<a href=#644 id=644 data-nosnippet>644</a> <span class="kw">let </span>err = reader.read(<span class="number">0</span>..<span class="number">10</span>).<span class="kw">await</span>.unwrap_err();
+<a href=#645 id=645 data-nosnippet>645</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#646 id=646 data-nosnippet>646</a> <span class="macro">assert!</span>(err.to_string().contains(<span class="string">"Invalid encrypted read length"</span>));
+<a href=#647 id=647 data-nosnippet>647</a> }
+<a href=#648 id=648 data-nosnippet>648</a>
+<a href=#649 id=649 data-nosnippet>649</a> <span class="attr">#[tokio::test]
+<a href=#650 id=650 data-nosnippet>650</a> </span><span class="kw">async fn </span>test_oversized_declared_length_is_rejected() {
+<a href=#651 id=651 data-nosnippet>651</a> <span class="comment">// Object stores clamp reads at EOF rather than failing, unlike the in-memory FileIO.
+<a href=#652 id=652 data-nosnippet>652</a> </span><span class="kw">struct </span>ClampingRead(Bytes);
+<a href=#653 id=653 data-nosnippet>653</a>
+<a href=#654 id=654 data-nosnippet>654</a> <span class="attr">#[async_trait::async_trait]
+<a href=#655 id=655 data-nosnippet>655</a> </span><span class="kw">impl </span>FileRead <span class="kw">for </span>ClampingRead {
+<a href=#656 id=656 data-nosnippet>656</a> <span class="kw">async fn </span>read(<span class="kw-2">&</span><span class="self">self</span>, range: Range<u64>) -> <span class="prelude-ty">Result</span><Bytes> {
+<a href=#657 id=657 data-nosnippet>657</a> <span class="kw">let </span>start = (range.start <span class="kw">as </span>usize).min(<span class="self">self</span>.<span class="number">0</span>.len());
+<a href=#658 id=658 data-nosnippet>658</a> <span class="kw">let </span>end = (range.end <span class="kw">as </span>usize).min(<span class="self">self</span>.<span class="number">0</span>.len());
+<a href=#659 id=659 data-nosnippet>659</a> <span class="prelude-val">Ok</span>(<span class="self">self</span>.<span class="number">0</span>.slice(start..end))
+<a href=#660 id=660 data-nosnippet>660</a> }
+<a href=#661 id=661 data-nosnippet>661</a> }
+<a href=#662 id=662 data-nosnippet>662</a>
+<a href=#663 id=663 data-nosnippet>663</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#664 id=664 data-nosnippet>664</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
+<a href=#665 id=665 data-nosnippet>665</a> <span class="kw">let </span>plaintext = <span class="string">b"some bytes to measure"</span>;
+<a href=#666 id=666 data-nosnippet>666</a> <span class="kw">let </span>encrypted = write_through_ags1(plaintext, key, aad_prefix).<span class="kw">await</span>;
<a href=#667 id=667 data-nosnippet>667</a>
-<a href=#668 id=668 data-nosnippet>668</a> <span class="comment">// Read a slice from the middle
-<a href=#669 id=669 data-nosnippet>669</a> </span><span class="kw">let </span>result = reader.read(<span class="number">10</span>..<span class="number">20</span>).<span class="kw">await</span>.unwrap();
-<a href=#670 id=670 data-nosnippet>670</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[<span class="number">10</span>..<span class="number">20</span>]);
-<a href=#671 id=671 data-nosnippet>671</a>
-<a href=#672 id=672 data-nosnippet>672</a> <span class="comment">// Read first byte
-<a href=#673 id=673 data-nosnippet>673</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..<span class="number">1</span>).<span class="kw">await</span>.unwrap();
-<a href=#674 id=674 data-nosnippet>674</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[<span class="number">0</span>..<span class="number">1</span>]);
-<a href=#675 id=675 data-nosnippet>675</a>
-<a href=#676 id=676 data-nosnippet>676</a> <span class="comment">// Read last byte
-<a href=#677 id=677 data-nosnippet>677</a> </span><span class="kw">let </span>last = plaintext.len() <span class="kw">as </span>u64;
-<a href=#678 id=678 data-nosnippet>678</a> <span class="kw">let </span>result = reader.read(last - <span class="number">1</span>..last).<span class="kw">await</span>.unwrap();
-<a href=#679 id=679 data-nosnippet>679</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[plaintext.len() - <span class="number">1</span>..]);
-<a href=#680 id=680 data-nosnippet>680</a> }
-<a href=#681 id=681 data-nosnippet>681</a>
-<a href=#682 id=682 data-nosnippet>682</a> <span class="attr">#[tokio::test]
-<a href=#683 id=683 data-nosnippet>683</a> </span><span class="kw">async fn </span>test_multi_block_roundtrip() {
-<a href=#684 id=684 data-nosnippet>684</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#685 id=685 data-nosnippet>685</a> <span class="kw">let </span>aad_prefix = <span class="string">b"multi-block-aad!"</span>;
-<a href=#686 id=686 data-nosnippet>686</a>
-<a href=#687 id=687 data-nosnippet>687</a> <span class="comment">// 1.5 blocks of data
-<a href=#688 id=688 data-nosnippet>688</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + PLAIN_BLOCK_SIZE <span class="kw">as </span>usize / <span class="number">2</span>;
-<a href=#689 id=689 data-nosnippet>689</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
-<a href=#690 id=690 data-nosnippet>690</a> <span class="kw">let </span>cipher = make_cipher(key);
-<a href=#691 id=691 data-nosnippet>691</a>
-<a href=#692 id=692 data-nosnippet>692</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
-<a href=#693 id=693 data-nosnippet>693</a>
-<a href=#694 id=694 data-nosnippet>694</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#695 id=695 data-nosnippet>695</a> memory_reader(encrypted.clone()),
-<a href=#696 id=696 data-nosnippet>696</a> Arc::new(make_cipher(key)),
-<a href=#697 id=697 data-nosnippet>697</a> aad_prefix.as_slice().into(),
-<a href=#698 id=698 data-nosnippet>698</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#699 id=699 data-nosnippet>699</a> )
-<a href=#700 id=700 data-nosnippet>700</a> .unwrap();
-<a href=#701 id=701 data-nosnippet>701</a>
-<a href=#702 id=702 data-nosnippet>702</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
-<a href=#703 id=703 data-nosnippet>703</a>
-<a href=#704 id=704 data-nosnippet>704</a> <span class="comment">// Read entire file
-<a href=#705 id=705 data-nosnippet>705</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#706 id=706 data-nosnippet>706</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
-<a href=#707 id=707 data-nosnippet>707</a> }
-<a href=#708 id=708 data-nosnippet>708</a>
-<a href=#709 id=709 data-nosnippet>709</a> <span class="attr">#[tokio::test]
-<a href=#710 id=710 data-nosnippet>710</a> </span><span class="kw">async fn </span>test_cross_block_read() {
-<a href=#711 id=711 data-nosnippet>711</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#712 id=712 data-nosnippet>712</a> <span class="kw">let </span>aad_prefix = <span class="string">b"cross-block-aad!"</span>;
-<a href=#713 id=713 data-nosnippet>713</a>
-<a href=#714 id=714 data-nosnippet>714</a> <span class="comment">// 2.5 blocks of data
-<a href=#715 id=715 data-nosnippet>715</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize * <span class="number">2 </span>+ PLAIN_BLOCK_SIZE <span class="kw">as </span>usize / <span class="number">2</span>;
-<a href=#716 id=716 data-nosnippet>716</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
+<a href=#668 id=668 data-nosnippet>668</a> <span class="comment">// A declared length larger than the real file must be rejected rather than yielding
+<a href=#669 id=669 data-nosnippet>669</a> // truncated plaintext, whether it overstates by one byte or by a whole extra block.
+<a href=#670 id=670 data-nosnippet>670</a> </span><span class="kw">for </span>excess <span class="kw">in </span>[<span class="number">1</span>, u64::from(CIPHER_BLOCK_SIZE)] {
+<a href=#671 id=671 data-nosnippet>671</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#672 id=672 data-nosnippet>672</a> Box::new(ClampingRead(Bytes::from(encrypted.clone()))),
+<a href=#673 id=673 data-nosnippet>673</a> Arc::new(make_cipher(key)),
+<a href=#674 id=674 data-nosnippet>674</a> aad_prefix.to_vec().into_boxed_slice(),
+<a href=#675 id=675 data-nosnippet>675</a> encrypted.len() <span class="kw">as </span>u64 + excess,
+<a href=#676 id=676 data-nosnippet>676</a> )
+<a href=#677 id=677 data-nosnippet>677</a> .unwrap();
+<a href=#678 id=678 data-nosnippet>678</a>
+<a href=#679 id=679 data-nosnippet>679</a> <span class="kw">let </span>err = reader
+<a href=#680 id=680 data-nosnippet>680</a> .read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64)
+<a href=#681 id=681 data-nosnippet>681</a> .<span class="kw">await
+<a href=#682 id=682 data-nosnippet>682</a> </span>.expect_err(<span class="string">"an inflated declared length must not read back as plaintext"</span>);
+<a href=#683 id=683 data-nosnippet>683</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#684 id=684 data-nosnippet>684</a> <span class="macro">assert!</span>(err.to_string().contains(<span class="string">"Invalid encrypted read length"</span>));
+<a href=#685 id=685 data-nosnippet>685</a> }
+<a href=#686 id=686 data-nosnippet>686</a> }
+<a href=#687 id=687 data-nosnippet>687</a>
+<a href=#688 id=688 data-nosnippet>688</a> <span class="attr">#[tokio::test]
+<a href=#689 id=689 data-nosnippet>689</a> </span><span class="kw">async fn </span>test_small_file_roundtrip() {
+<a href=#690 id=690 data-nosnippet>690</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#691 id=691 data-nosnippet>691</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
+<a href=#692 id=692 data-nosnippet>692</a> <span class="kw">let </span>plaintext = <span class="string">b"Hello, Iceberg encryption!"</span>;
+<a href=#693 id=693 data-nosnippet>693</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#694 id=694 data-nosnippet>694</a>
+<a href=#695 id=695 data-nosnippet>695</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#696 id=696 data-nosnippet>696</a>
+<a href=#697 id=697 data-nosnippet>697</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#698 id=698 data-nosnippet>698</a> memory_reader(encrypted.clone()),
+<a href=#699 id=699 data-nosnippet>699</a> Arc::new(make_cipher(key)),
+<a href=#700 id=700 data-nosnippet>700</a> aad_prefix.as_slice().into(),
+<a href=#701 id=701 data-nosnippet>701</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#702 id=702 data-nosnippet>702</a> )
+<a href=#703 id=703 data-nosnippet>703</a> .unwrap();
+<a href=#704 id=704 data-nosnippet>704</a>
+<a href=#705 id=705 data-nosnippet>705</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
+<a href=#706 id=706 data-nosnippet>706</a>
+<a href=#707 id=707 data-nosnippet>707</a> <span class="comment">// Read entire file
+<a href=#708 id=708 data-nosnippet>708</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#709 id=709 data-nosnippet>709</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], plaintext);
+<a href=#710 id=710 data-nosnippet>710</a> }
+<a href=#711 id=711 data-nosnippet>711</a>
+<a href=#712 id=712 data-nosnippet>712</a> <span class="attr">#[tokio::test]
+<a href=#713 id=713 data-nosnippet>713</a> </span><span class="kw">async fn </span>test_partial_read() {
+<a href=#714 id=714 data-nosnippet>714</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#715 id=715 data-nosnippet>715</a> <span class="kw">let </span>aad_prefix = <span class="string">b"aad-prefix-here!"</span>;
+<a href=#716 id=716 data-nosnippet>716</a> <span class="kw">let </span>plaintext = <span class="string">b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</span>;
<a href=#717 id=717 data-nosnippet>717</a> <span class="kw">let </span>cipher = make_cipher(key);
<a href=#718 id=718 data-nosnippet>718</a>
-<a href=#719 id=719 data-nosnippet>719</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#719 id=719 data-nosnippet>719</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
<a href=#720 id=720 data-nosnippet>720</a>
<a href=#721 id=721 data-nosnippet>721</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
<a href=#722 id=722 data-nosnippet>722</a> memory_reader(encrypted.clone()),
@@ -726,509 +726,589 @@
<a href=#726 id=726 data-nosnippet>726</a> )
<a href=#727 id=727 data-nosnippet>727</a> .unwrap();
<a href=#728 id=728 data-nosnippet>728</a>
-<a href=#729 id=729 data-nosnippet>729</a> <span class="comment">// Read across block boundary (last 100 bytes of block 0 + first 100 bytes of block 1)
-<a href=#730 id=730 data-nosnippet>730</a> </span><span class="kw">let </span>boundary = PLAIN_BLOCK_SIZE <span class="kw">as </span>u64;
-<a href=#731 id=731 data-nosnippet>731</a> <span class="kw">let </span>result = reader.read(boundary - <span class="number">100</span>..boundary + <span class="number">100</span>).<span class="kw">await</span>.unwrap();
-<a href=#732 id=732 data-nosnippet>732</a> <span class="macro">assert_eq!</span>(
-<a href=#733 id=733 data-nosnippet>733</a> <span class="kw-2">&</span>result[..],
-<a href=#734 id=734 data-nosnippet>734</a> <span class="kw-2">&</span>plaintext[(boundary - <span class="number">100</span>) <span class="kw">as </span>usize..(boundary + <span class="number">100</span>) <span class="kw">as </span>usize]
-<a href=#735 id=735 data-nosnippet>735</a> );
+<a href=#729 id=729 data-nosnippet>729</a> <span class="comment">// Read a slice from the middle
+<a href=#730 id=730 data-nosnippet>730</a> </span><span class="kw">let </span>result = reader.read(<span class="number">10</span>..<span class="number">20</span>).<span class="kw">await</span>.unwrap();
+<a href=#731 id=731 data-nosnippet>731</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[<span class="number">10</span>..<span class="number">20</span>]);
+<a href=#732 id=732 data-nosnippet>732</a>
+<a href=#733 id=733 data-nosnippet>733</a> <span class="comment">// Read first byte
+<a href=#734 id=734 data-nosnippet>734</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..<span class="number">1</span>).<span class="kw">await</span>.unwrap();
+<a href=#735 id=735 data-nosnippet>735</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[<span class="number">0</span>..<span class="number">1</span>]);
<a href=#736 id=736 data-nosnippet>736</a>
-<a href=#737 id=737 data-nosnippet>737</a> <span class="comment">// Read across two block boundaries (spans blocks 0, 1, and 2)
-<a href=#738 id=738 data-nosnippet>738</a> </span><span class="kw">let </span>result = reader.read(boundary - <span class="number">50</span>..boundary * <span class="number">2 </span>+ <span class="number">50</span>).<span class="kw">await</span>.unwrap();
-<a href=#739 id=739 data-nosnippet>739</a> <span class="macro">assert_eq!</span>(
-<a href=#740 id=740 data-nosnippet>740</a> <span class="kw-2">&</span>result[..],
-<a href=#741 id=741 data-nosnippet>741</a> <span class="kw-2">&</span>plaintext[(boundary - <span class="number">50</span>) <span class="kw">as </span>usize..(boundary * <span class="number">2 </span>+ <span class="number">50</span>) <span class="kw">as </span>usize]
-<a href=#742 id=742 data-nosnippet>742</a> );
-<a href=#743 id=743 data-nosnippet>743</a> }
-<a href=#744 id=744 data-nosnippet>744</a>
-<a href=#745 id=745 data-nosnippet>745</a> <span class="attr">#[tokio::test]
-<a href=#746 id=746 data-nosnippet>746</a> </span><span class="kw">async fn </span>test_exact_block_size() {
-<a href=#747 id=747 data-nosnippet>747</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#748 id=748 data-nosnippet>748</a> <span class="kw">let </span>aad_prefix = <span class="string">b"exact-block-aad!"</span>;
-<a href=#749 id=749 data-nosnippet>749</a>
-<a href=#750 id=750 data-nosnippet>750</a> <span class="comment">// Exactly 1 block
-<a href=#751 id=751 data-nosnippet>751</a> </span><span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize)
-<a href=#752 id=752 data-nosnippet>752</a> .map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8)
-<a href=#753 id=753 data-nosnippet>753</a> .collect();
-<a href=#754 id=754 data-nosnippet>754</a> <span class="kw">let </span>cipher = make_cipher(key);
-<a href=#755 id=755 data-nosnippet>755</a>
-<a href=#756 id=756 data-nosnippet>756</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
-<a href=#757 id=757 data-nosnippet>757</a>
-<a href=#758 id=758 data-nosnippet>758</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#759 id=759 data-nosnippet>759</a> memory_reader(encrypted.clone()),
-<a href=#760 id=760 data-nosnippet>760</a> Arc::new(make_cipher(key)),
-<a href=#761 id=761 data-nosnippet>761</a> aad_prefix.as_slice().into(),
-<a href=#762 id=762 data-nosnippet>762</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#763 id=763 data-nosnippet>763</a> )
-<a href=#764 id=764 data-nosnippet>764</a> .unwrap();
-<a href=#765 id=765 data-nosnippet>765</a>
-<a href=#766 id=766 data-nosnippet>766</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), PLAIN_BLOCK_SIZE <span class="kw">as </span>u64);
-<a href=#767 id=767 data-nosnippet>767</a>
-<a href=#768 id=768 data-nosnippet>768</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#769 id=769 data-nosnippet>769</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
-<a href=#770 id=770 data-nosnippet>770</a> }
-<a href=#771 id=771 data-nosnippet>771</a>
-<a href=#772 id=772 data-nosnippet>772</a> <span class="attr">#[tokio::test]
-<a href=#773 id=773 data-nosnippet>773</a> </span><span class="kw">async fn </span>test_block_size_plus_one() {
-<a href=#774 id=774 data-nosnippet>774</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#775 id=775 data-nosnippet>775</a> <span class="kw">let </span>aad_prefix = <span class="string">b"block-plus-one!!"</span>;
-<a href=#776 id=776 data-nosnippet>776</a>
-<a href=#777 id=777 data-nosnippet>777</a> <span class="comment">// 1 block + 1 byte
-<a href=#778 id=778 data-nosnippet>778</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + <span class="number">1</span>;
-<a href=#779 id=779 data-nosnippet>779</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
-<a href=#780 id=780 data-nosnippet>780</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#737 id=737 data-nosnippet>737</a> <span class="comment">// Read last byte
+<a href=#738 id=738 data-nosnippet>738</a> </span><span class="kw">let </span>last = plaintext.len() <span class="kw">as </span>u64;
+<a href=#739 id=739 data-nosnippet>739</a> <span class="kw">let </span>result = reader.read(last - <span class="number">1</span>..last).<span class="kw">await</span>.unwrap();
+<a href=#740 id=740 data-nosnippet>740</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[plaintext.len() - <span class="number">1</span>..]);
+<a href=#741 id=741 data-nosnippet>741</a> }
+<a href=#742 id=742 data-nosnippet>742</a>
+<a href=#743 id=743 data-nosnippet>743</a> <span class="attr">#[tokio::test]
+<a href=#744 id=744 data-nosnippet>744</a> </span><span class="kw">async fn </span>test_multi_block_roundtrip() {
+<a href=#745 id=745 data-nosnippet>745</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#746 id=746 data-nosnippet>746</a> <span class="kw">let </span>aad_prefix = <span class="string">b"multi-block-aad!"</span>;
+<a href=#747 id=747 data-nosnippet>747</a>
+<a href=#748 id=748 data-nosnippet>748</a> <span class="comment">// 1.5 blocks of data
+<a href=#749 id=749 data-nosnippet>749</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + PLAIN_BLOCK_SIZE <span class="kw">as </span>usize / <span class="number">2</span>;
+<a href=#750 id=750 data-nosnippet>750</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
+<a href=#751 id=751 data-nosnippet>751</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#752 id=752 data-nosnippet>752</a>
+<a href=#753 id=753 data-nosnippet>753</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#754 id=754 data-nosnippet>754</a>
+<a href=#755 id=755 data-nosnippet>755</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#756 id=756 data-nosnippet>756</a> memory_reader(encrypted.clone()),
+<a href=#757 id=757 data-nosnippet>757</a> Arc::new(make_cipher(key)),
+<a href=#758 id=758 data-nosnippet>758</a> aad_prefix.as_slice().into(),
+<a href=#759 id=759 data-nosnippet>759</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#760 id=760 data-nosnippet>760</a> )
+<a href=#761 id=761 data-nosnippet>761</a> .unwrap();
+<a href=#762 id=762 data-nosnippet>762</a>
+<a href=#763 id=763 data-nosnippet>763</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
+<a href=#764 id=764 data-nosnippet>764</a>
+<a href=#765 id=765 data-nosnippet>765</a> <span class="comment">// Read entire file
+<a href=#766 id=766 data-nosnippet>766</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#767 id=767 data-nosnippet>767</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#768 id=768 data-nosnippet>768</a> }
+<a href=#769 id=769 data-nosnippet>769</a>
+<a href=#770 id=770 data-nosnippet>770</a> <span class="attr">#[tokio::test]
+<a href=#771 id=771 data-nosnippet>771</a> </span><span class="kw">async fn </span>test_cross_block_read() {
+<a href=#772 id=772 data-nosnippet>772</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#773 id=773 data-nosnippet>773</a> <span class="kw">let </span>aad_prefix = <span class="string">b"cross-block-aad!"</span>;
+<a href=#774 id=774 data-nosnippet>774</a>
+<a href=#775 id=775 data-nosnippet>775</a> <span class="comment">// 2.5 blocks of data
+<a href=#776 id=776 data-nosnippet>776</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize * <span class="number">2 </span>+ PLAIN_BLOCK_SIZE <span class="kw">as </span>usize / <span class="number">2</span>;
+<a href=#777 id=777 data-nosnippet>777</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
+<a href=#778 id=778 data-nosnippet>778</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#779 id=779 data-nosnippet>779</a>
+<a href=#780 id=780 data-nosnippet>780</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
<a href=#781 id=781 data-nosnippet>781</a>
-<a href=#782 id=782 data-nosnippet>782</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
-<a href=#783 id=783 data-nosnippet>783</a>
-<a href=#784 id=784 data-nosnippet>784</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#785 id=785 data-nosnippet>785</a> memory_reader(encrypted.clone()),
-<a href=#786 id=786 data-nosnippet>786</a> Arc::new(make_cipher(key)),
-<a href=#787 id=787 data-nosnippet>787</a> aad_prefix.as_slice().into(),
-<a href=#788 id=788 data-nosnippet>788</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#789 id=789 data-nosnippet>789</a> )
-<a href=#790 id=790 data-nosnippet>790</a> .unwrap();
-<a href=#791 id=791 data-nosnippet>791</a>
-<a href=#792 id=792 data-nosnippet>792</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), size <span class="kw">as </span>u64);
-<a href=#793 id=793 data-nosnippet>793</a>
-<a href=#794 id=794 data-nosnippet>794</a> <span class="comment">// Read the last byte (in block 1)
-<a href=#795 id=795 data-nosnippet>795</a> </span><span class="kw">let </span>result = reader.read(size <span class="kw">as </span>u64 - <span class="number">1</span>..size <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#796 id=796 data-nosnippet>796</a> <span class="macro">assert_eq!</span>(result[<span class="number">0</span>], plaintext[size - <span class="number">1</span>]);
+<a href=#782 id=782 data-nosnippet>782</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#783 id=783 data-nosnippet>783</a> memory_reader(encrypted.clone()),
+<a href=#784 id=784 data-nosnippet>784</a> Arc::new(make_cipher(key)),
+<a href=#785 id=785 data-nosnippet>785</a> aad_prefix.as_slice().into(),
+<a href=#786 id=786 data-nosnippet>786</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#787 id=787 data-nosnippet>787</a> )
+<a href=#788 id=788 data-nosnippet>788</a> .unwrap();
+<a href=#789 id=789 data-nosnippet>789</a>
+<a href=#790 id=790 data-nosnippet>790</a> <span class="comment">// Read across block boundary (last 100 bytes of block 0 + first 100 bytes of block 1)
+<a href=#791 id=791 data-nosnippet>791</a> </span><span class="kw">let </span>boundary = PLAIN_BLOCK_SIZE <span class="kw">as </span>u64;
+<a href=#792 id=792 data-nosnippet>792</a> <span class="kw">let </span>result = reader.read(boundary - <span class="number">100</span>..boundary + <span class="number">100</span>).<span class="kw">await</span>.unwrap();
+<a href=#793 id=793 data-nosnippet>793</a> <span class="macro">assert_eq!</span>(
+<a href=#794 id=794 data-nosnippet>794</a> <span class="kw-2">&</span>result[..],
+<a href=#795 id=795 data-nosnippet>795</a> <span class="kw-2">&</span>plaintext[(boundary - <span class="number">100</span>) <span class="kw">as </span>usize..(boundary + <span class="number">100</span>) <span class="kw">as </span>usize]
+<a href=#796 id=796 data-nosnippet>796</a> );
<a href=#797 id=797 data-nosnippet>797</a>
-<a href=#798 id=798 data-nosnippet>798</a> <span class="comment">// Read all
-<a href=#799 id=799 data-nosnippet>799</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..size <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#800 id=800 data-nosnippet>800</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
-<a href=#801 id=801 data-nosnippet>801</a> }
-<a href=#802 id=802 data-nosnippet>802</a>
-<a href=#803 id=803 data-nosnippet>803</a> <span class="attr">#[tokio::test]
-<a href=#804 id=804 data-nosnippet>804</a> </span><span class="kw">async fn </span>test_block_size_minus_one() {
-<a href=#805 id=805 data-nosnippet>805</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#806 id=806 data-nosnippet>806</a> <span class="kw">let </span>aad_prefix = <span class="string">b"block-minus-one!"</span>;
-<a href=#807 id=807 data-nosnippet>807</a>
-<a href=#808 id=808 data-nosnippet>808</a> <span class="comment">// 1 block - 1 byte
-<a href=#809 id=809 data-nosnippet>809</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize - <span class="number">1</span>;
-<a href=#810 id=810 data-nosnippet>810</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
-<a href=#811 id=811 data-nosnippet>811</a> <span class="kw">let </span>cipher = make_cipher(key);
-<a href=#812 id=812 data-nosnippet>812</a>
-<a href=#813 id=813 data-nosnippet>813</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
-<a href=#814 id=814 data-nosnippet>814</a>
-<a href=#815 id=815 data-nosnippet>815</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#816 id=816 data-nosnippet>816</a> memory_reader(encrypted.clone()),
-<a href=#817 id=817 data-nosnippet>817</a> Arc::new(make_cipher(key)),
-<a href=#818 id=818 data-nosnippet>818</a> aad_prefix.as_slice().into(),
-<a href=#819 id=819 data-nosnippet>819</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#820 id=820 data-nosnippet>820</a> )
-<a href=#821 id=821 data-nosnippet>821</a> .unwrap();
-<a href=#822 id=822 data-nosnippet>822</a>
-<a href=#823 id=823 data-nosnippet>823</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), size <span class="kw">as </span>u64);
-<a href=#824 id=824 data-nosnippet>824</a>
-<a href=#825 id=825 data-nosnippet>825</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..size <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#826 id=826 data-nosnippet>826</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
-<a href=#827 id=827 data-nosnippet>827</a> }
+<a href=#798 id=798 data-nosnippet>798</a> <span class="comment">// Read across two block boundaries (spans blocks 0, 1, and 2)
+<a href=#799 id=799 data-nosnippet>799</a> </span><span class="kw">let </span>result = reader.read(boundary - <span class="number">50</span>..boundary * <span class="number">2 </span>+ <span class="number">50</span>).<span class="kw">await</span>.unwrap();
+<a href=#800 id=800 data-nosnippet>800</a> <span class="macro">assert_eq!</span>(
+<a href=#801 id=801 data-nosnippet>801</a> <span class="kw-2">&</span>result[..],
+<a href=#802 id=802 data-nosnippet>802</a> <span class="kw-2">&</span>plaintext[(boundary - <span class="number">50</span>) <span class="kw">as </span>usize..(boundary * <span class="number">2 </span>+ <span class="number">50</span>) <span class="kw">as </span>usize]
+<a href=#803 id=803 data-nosnippet>803</a> );
+<a href=#804 id=804 data-nosnippet>804</a> }
+<a href=#805 id=805 data-nosnippet>805</a>
+<a href=#806 id=806 data-nosnippet>806</a> <span class="attr">#[tokio::test]
+<a href=#807 id=807 data-nosnippet>807</a> </span><span class="kw">async fn </span>test_exact_block_size() {
+<a href=#808 id=808 data-nosnippet>808</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#809 id=809 data-nosnippet>809</a> <span class="kw">let </span>aad_prefix = <span class="string">b"exact-block-aad!"</span>;
+<a href=#810 id=810 data-nosnippet>810</a>
+<a href=#811 id=811 data-nosnippet>811</a> <span class="comment">// Exactly 1 block
+<a href=#812 id=812 data-nosnippet>812</a> </span><span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize)
+<a href=#813 id=813 data-nosnippet>813</a> .map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8)
+<a href=#814 id=814 data-nosnippet>814</a> .collect();
+<a href=#815 id=815 data-nosnippet>815</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#816 id=816 data-nosnippet>816</a>
+<a href=#817 id=817 data-nosnippet>817</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#818 id=818 data-nosnippet>818</a>
+<a href=#819 id=819 data-nosnippet>819</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#820 id=820 data-nosnippet>820</a> memory_reader(encrypted.clone()),
+<a href=#821 id=821 data-nosnippet>821</a> Arc::new(make_cipher(key)),
+<a href=#822 id=822 data-nosnippet>822</a> aad_prefix.as_slice().into(),
+<a href=#823 id=823 data-nosnippet>823</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#824 id=824 data-nosnippet>824</a> )
+<a href=#825 id=825 data-nosnippet>825</a> .unwrap();
+<a href=#826 id=826 data-nosnippet>826</a>
+<a href=#827 id=827 data-nosnippet>827</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), PLAIN_BLOCK_SIZE <span class="kw">as </span>u64);
<a href=#828 id=828 data-nosnippet>828</a>
-<a href=#829 id=829 data-nosnippet>829</a> <span class="attr">#[tokio::test]
-<a href=#830 id=830 data-nosnippet>830</a> </span><span class="kw">async fn </span>test_wrong_aad_fails() {
-<a href=#831 id=831 data-nosnippet>831</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#832 id=832 data-nosnippet>832</a> <span class="kw">let </span>aad_prefix = <span class="string">b"correct-aad-here"</span>;
-<a href=#833 id=833 data-nosnippet>833</a> <span class="kw">let </span>plaintext = <span class="string">b"sensitive data here"</span>;
-<a href=#834 id=834 data-nosnippet>834</a> <span class="kw">let </span>cipher = make_cipher(key);
-<a href=#835 id=835 data-nosnippet>835</a>
-<a href=#836 id=836 data-nosnippet>836</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#829 id=829 data-nosnippet>829</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#830 id=830 data-nosnippet>830</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#831 id=831 data-nosnippet>831</a> }
+<a href=#832 id=832 data-nosnippet>832</a>
+<a href=#833 id=833 data-nosnippet>833</a> <span class="attr">#[tokio::test]
+<a href=#834 id=834 data-nosnippet>834</a> </span><span class="kw">async fn </span>test_block_size_plus_one() {
+<a href=#835 id=835 data-nosnippet>835</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#836 id=836 data-nosnippet>836</a> <span class="kw">let </span>aad_prefix = <span class="string">b"block-plus-one!!"</span>;
<a href=#837 id=837 data-nosnippet>837</a>
-<a href=#838 id=838 data-nosnippet>838</a> <span class="comment">// Try to decrypt with wrong AAD
-<a href=#839 id=839 data-nosnippet>839</a> </span><span class="kw">let </span><span class="kw-2">mut </span>bad_aad = aad_prefix.to_vec();
-<a href=#840 id=840 data-nosnippet>840</a> bad_aad[<span class="number">0</span>] ^= <span class="number">0xFF</span>;
-<a href=#841 id=841 data-nosnippet>841</a>
-<a href=#842 id=842 data-nosnippet>842</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#843 id=843 data-nosnippet>843</a> memory_reader(encrypted.clone()),
-<a href=#844 id=844 data-nosnippet>844</a> Arc::new(make_cipher(key)),
-<a href=#845 id=845 data-nosnippet>845</a> bad_aad.as_slice().into(),
-<a href=#846 id=846 data-nosnippet>846</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#847 id=847 data-nosnippet>847</a> )
-<a href=#848 id=848 data-nosnippet>848</a> .unwrap();
-<a href=#849 id=849 data-nosnippet>849</a>
-<a href=#850 id=850 data-nosnippet>850</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>;
-<a href=#851 id=851 data-nosnippet>851</a> <span class="macro">assert!</span>(result.is_err(), <span class="string">"Decryption with wrong AAD should fail"</span>);
-<a href=#852 id=852 data-nosnippet>852</a> }
-<a href=#853 id=853 data-nosnippet>853</a>
-<a href=#854 id=854 data-nosnippet>854</a> <span class="attr">#[tokio::test]
-<a href=#855 id=855 data-nosnippet>855</a> </span><span class="kw">async fn </span>test_wrong_key_fails() {
-<a href=#856 id=856 data-nosnippet>856</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#857 id=857 data-nosnippet>857</a> <span class="kw">let </span>wrong_key = <span class="string">b"fedcba9876543210"</span>;
-<a href=#858 id=858 data-nosnippet>858</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
-<a href=#859 id=859 data-nosnippet>859</a> <span class="kw">let </span>plaintext = <span class="string">b"sensitive data"</span>;
-<a href=#860 id=860 data-nosnippet>860</a> <span class="kw">let </span>cipher = make_cipher(key);
-<a href=#861 id=861 data-nosnippet>861</a>
-<a href=#862 id=862 data-nosnippet>862</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#838 id=838 data-nosnippet>838</a> <span class="comment">// 1 block + 1 byte
+<a href=#839 id=839 data-nosnippet>839</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + <span class="number">1</span>;
+<a href=#840 id=840 data-nosnippet>840</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
+<a href=#841 id=841 data-nosnippet>841</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#842 id=842 data-nosnippet>842</a>
+<a href=#843 id=843 data-nosnippet>843</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#844 id=844 data-nosnippet>844</a>
+<a href=#845 id=845 data-nosnippet>845</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#846 id=846 data-nosnippet>846</a> memory_reader(encrypted.clone()),
+<a href=#847 id=847 data-nosnippet>847</a> Arc::new(make_cipher(key)),
+<a href=#848 id=848 data-nosnippet>848</a> aad_prefix.as_slice().into(),
+<a href=#849 id=849 data-nosnippet>849</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#850 id=850 data-nosnippet>850</a> )
+<a href=#851 id=851 data-nosnippet>851</a> .unwrap();
+<a href=#852 id=852 data-nosnippet>852</a>
+<a href=#853 id=853 data-nosnippet>853</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), size <span class="kw">as </span>u64);
+<a href=#854 id=854 data-nosnippet>854</a>
+<a href=#855 id=855 data-nosnippet>855</a> <span class="comment">// Read the last byte (in block 1)
+<a href=#856 id=856 data-nosnippet>856</a> </span><span class="kw">let </span>result = reader.read(size <span class="kw">as </span>u64 - <span class="number">1</span>..size <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#857 id=857 data-nosnippet>857</a> <span class="macro">assert_eq!</span>(result[<span class="number">0</span>], plaintext[size - <span class="number">1</span>]);
+<a href=#858 id=858 data-nosnippet>858</a>
+<a href=#859 id=859 data-nosnippet>859</a> <span class="comment">// Read all
+<a href=#860 id=860 data-nosnippet>860</a> </span><span class="kw">let </span>result = reader.read(<span class="number">0</span>..size <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#861 id=861 data-nosnippet>861</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#862 id=862 data-nosnippet>862</a> }
<a href=#863 id=863 data-nosnippet>863</a>
-<a href=#864 id=864 data-nosnippet>864</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#865 id=865 data-nosnippet>865</a> memory_reader(encrypted.clone()),
-<a href=#866 id=866 data-nosnippet>866</a> Arc::new(make_cipher(wrong_key)),
-<a href=#867 id=867 data-nosnippet>867</a> aad_prefix.as_slice().into(),
-<a href=#868 id=868 data-nosnippet>868</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#869 id=869 data-nosnippet>869</a> )
-<a href=#870 id=870 data-nosnippet>870</a> .unwrap();
-<a href=#871 id=871 data-nosnippet>871</a>
-<a href=#872 id=872 data-nosnippet>872</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>;
-<a href=#873 id=873 data-nosnippet>873</a> <span class="macro">assert!</span>(result.is_err(), <span class="string">"Decryption with wrong key should fail"</span>);
-<a href=#874 id=874 data-nosnippet>874</a> }
+<a href=#864 id=864 data-nosnippet>864</a> <span class="attr">#[tokio::test]
+<a href=#865 id=865 data-nosnippet>865</a> </span><span class="kw">async fn </span>test_block_size_minus_one() {
+<a href=#866 id=866 data-nosnippet>866</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#867 id=867 data-nosnippet>867</a> <span class="kw">let </span>aad_prefix = <span class="string">b"block-minus-one!"</span>;
+<a href=#868 id=868 data-nosnippet>868</a>
+<a href=#869 id=869 data-nosnippet>869</a> <span class="comment">// 1 block - 1 byte
+<a href=#870 id=870 data-nosnippet>870</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize - <span class="number">1</span>;
+<a href=#871 id=871 data-nosnippet>871</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
+<a href=#872 id=872 data-nosnippet>872</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#873 id=873 data-nosnippet>873</a>
+<a href=#874 id=874 data-nosnippet>874</a> <span class="kw">let </span>encrypted = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
<a href=#875 id=875 data-nosnippet>875</a>
-<a href=#876 id=876 data-nosnippet>876</a> <span class="attr">#[tokio::test]
-<a href=#877 id=877 data-nosnippet>877</a> </span><span class="kw">async fn </span>test_out_of_bounds_read() {
-<a href=#878 id=878 data-nosnippet>878</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#879 id=879 data-nosnippet>879</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
-<a href=#880 id=880 data-nosnippet>880</a> <span class="kw">let </span>plaintext = <span class="string">b"short data"</span>;
-<a href=#881 id=881 data-nosnippet>881</a> <span class="kw">let </span>cipher = make_cipher(key);
-<a href=#882 id=882 data-nosnippet>882</a>
-<a href=#883 id=883 data-nosnippet>883</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
-<a href=#884 id=884 data-nosnippet>884</a>
-<a href=#885 id=885 data-nosnippet>885</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#886 id=886 data-nosnippet>886</a> memory_reader(encrypted.clone()),
-<a href=#887 id=887 data-nosnippet>887</a> Arc::new(make_cipher(key)),
-<a href=#888 id=888 data-nosnippet>888</a> aad_prefix.as_slice().into(),
-<a href=#889 id=889 data-nosnippet>889</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#890 id=890 data-nosnippet>890</a> )
-<a href=#891 id=891 data-nosnippet>891</a> .unwrap();
-<a href=#892 id=892 data-nosnippet>892</a>
-<a href=#893 id=893 data-nosnippet>893</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64 + <span class="number">1</span>).<span class="kw">await</span>;
-<a href=#894 id=894 data-nosnippet>894</a> <span class="macro">assert!</span>(result.is_err(), <span class="string">"Reading past end should fail"</span>);
-<a href=#895 id=895 data-nosnippet>895</a> }
+<a href=#876 id=876 data-nosnippet>876</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#877 id=877 data-nosnippet>877</a> memory_reader(encrypted.clone()),
+<a href=#878 id=878 data-nosnippet>878</a> Arc::new(make_cipher(key)),
+<a href=#879 id=879 data-nosnippet>879</a> aad_prefix.as_slice().into(),
+<a href=#880 id=880 data-nosnippet>880</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#881 id=881 data-nosnippet>881</a> )
+<a href=#882 id=882 data-nosnippet>882</a> .unwrap();
+<a href=#883 id=883 data-nosnippet>883</a>
+<a href=#884 id=884 data-nosnippet>884</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), size <span class="kw">as </span>u64);
+<a href=#885 id=885 data-nosnippet>885</a>
+<a href=#886 id=886 data-nosnippet>886</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..size <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#887 id=887 data-nosnippet>887</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#888 id=888 data-nosnippet>888</a> }
+<a href=#889 id=889 data-nosnippet>889</a>
+<a href=#890 id=890 data-nosnippet>890</a> <span class="attr">#[tokio::test]
+<a href=#891 id=891 data-nosnippet>891</a> </span><span class="kw">async fn </span>test_wrong_aad_fails() {
+<a href=#892 id=892 data-nosnippet>892</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#893 id=893 data-nosnippet>893</a> <span class="kw">let </span>aad_prefix = <span class="string">b"correct-aad-here"</span>;
+<a href=#894 id=894 data-nosnippet>894</a> <span class="kw">let </span>plaintext = <span class="string">b"sensitive data here"</span>;
+<a href=#895 id=895 data-nosnippet>895</a> <span class="kw">let </span>cipher = make_cipher(key);
<a href=#896 id=896 data-nosnippet>896</a>
-<a href=#897 id=897 data-nosnippet>897</a> <span class="attr">#[tokio::test]
-<a href=#898 id=898 data-nosnippet>898</a> </span><span class="kw">async fn </span>test_calculate_plaintext_length() {
-<a href=#899 id=899 data-nosnippet>899</a> <span class="comment">// Empty file: header only (not valid per Java, but handled)
-<a href=#900 id=900 data-nosnippet>900</a> </span><span class="macro">assert_eq!</span>(
-<a href=#901 id=901 data-nosnippet>901</a> AesGcmFileRead::calculate_plaintext_length(GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64).unwrap(),
-<a href=#902 id=902 data-nosnippet>902</a> <span class="number">0
-<a href=#903 id=903 data-nosnippet>903</a> </span>);
-<a href=#904 id=904 data-nosnippet>904</a>
-<a href=#905 id=905 data-nosnippet>905</a> <span class="comment">// Empty file with one empty block: header(8) + nonce(12) + tag(16) = 36
-<a href=#906 id=906 data-nosnippet>906</a> </span><span class="macro">assert_eq!</span>(
-<a href=#907 id=907 data-nosnippet>907</a> AesGcmFileRead::calculate_plaintext_length(MIN_STREAM_LENGTH <span class="kw">as </span>u64).unwrap(),
-<a href=#908 id=908 data-nosnippet>908</a> <span class="number">0
-<a href=#909 id=909 data-nosnippet>909</a> </span>);
+<a href=#897 id=897 data-nosnippet>897</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#898 id=898 data-nosnippet>898</a>
+<a href=#899 id=899 data-nosnippet>899</a> <span class="comment">// Try to decrypt with wrong AAD
+<a href=#900 id=900 data-nosnippet>900</a> </span><span class="kw">let </span><span class="kw-2">mut </span>bad_aad = aad_prefix.to_vec();
+<a href=#901 id=901 data-nosnippet>901</a> bad_aad[<span class="number">0</span>] ^= <span class="number">0xFF</span>;
+<a href=#902 id=902 data-nosnippet>902</a>
+<a href=#903 id=903 data-nosnippet>903</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#904 id=904 data-nosnippet>904</a> memory_reader(encrypted.clone()),
+<a href=#905 id=905 data-nosnippet>905</a> Arc::new(make_cipher(key)),
+<a href=#906 id=906 data-nosnippet>906</a> bad_aad.as_slice().into(),
+<a href=#907 id=907 data-nosnippet>907</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#908 id=908 data-nosnippet>908</a> )
+<a href=#909 id=909 data-nosnippet>909</a> .unwrap();
<a href=#910 id=910 data-nosnippet>910</a>
-<a href=#911 id=911 data-nosnippet>911</a> <span class="comment">// One full block: header(8) + cipher_block(1048604) = 1048612
-<a href=#912 id=912 data-nosnippet>912</a> </span><span class="kw">let </span>one_full = GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64 + CIPHER_BLOCK_SIZE <span class="kw">as </span>u64;
-<a href=#913 id=913 data-nosnippet>913</a> <span class="macro">assert_eq!</span>(
-<a href=#914 id=914 data-nosnippet>914</a> AesGcmFileRead::calculate_plaintext_length(one_full).unwrap(),
-<a href=#915 id=915 data-nosnippet>915</a> PLAIN_BLOCK_SIZE <span class="kw">as </span>u64
-<a href=#916 id=916 data-nosnippet>916</a> );
-<a href=#917 id=917 data-nosnippet>917</a>
-<a href=#918 id=918 data-nosnippet>918</a> <span class="comment">// One full block + 1 byte: need partial second block
-<a href=#919 id=919 data-nosnippet>919</a> // Second block = nonce(12) + 1 byte ciphertext + tag(16) = 29
-<a href=#920 id=920 data-nosnippet>920</a> </span><span class="kw">let </span>one_full_plus_one = one_full + NONCE_LENGTH <span class="kw">as </span>u64 + <span class="number">1 </span>+ GCM_TAG_LENGTH <span class="kw">as </span>u64;
-<a href=#921 id=921 data-nosnippet>921</a> <span class="macro">assert_eq!</span>(
-<a href=#922 id=922 data-nosnippet>922</a> AesGcmFileRead::calculate_plaintext_length(one_full_plus_one).unwrap(),
-<a href=#923 id=923 data-nosnippet>923</a> PLAIN_BLOCK_SIZE <span class="kw">as </span>u64 + <span class="number">1
-<a href=#924 id=924 data-nosnippet>924</a> </span>);
-<a href=#925 id=925 data-nosnippet>925</a> }
-<a href=#926 id=926 data-nosnippet>926</a>
-<a href=#927 id=927 data-nosnippet>927</a> <span class="attr">#[tokio::test]
-<a href=#928 id=928 data-nosnippet>928</a> </span><span class="kw">async fn </span>test_stream_block_aad() {
-<a href=#929 id=929 data-nosnippet>929</a> <span class="comment">// With prefix
-<a href=#930 id=930 data-nosnippet>930</a> </span><span class="kw">let </span>aad = stream_block_aad(<span class="string">b"prefix"</span>, <span class="number">0</span>);
-<a href=#931 id=931 data-nosnippet>931</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[..<span class="number">6</span>], <span class="string">b"prefix"</span>);
-<a href=#932 id=932 data-nosnippet>932</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[<span class="number">6</span>..], <span class="kw-2">&</span><span class="number">0u32</span>.to_le_bytes());
-<a href=#933 id=933 data-nosnippet>933</a>
-<a href=#934 id=934 data-nosnippet>934</a> <span class="kw">let </span>aad = stream_block_aad(<span class="string">b"prefix"</span>, <span class="number">1</span>);
-<a href=#935 id=935 data-nosnippet>935</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[..<span class="number">6</span>], <span class="string">b"prefix"</span>);
-<a href=#936 id=936 data-nosnippet>936</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[<span class="number">6</span>..], <span class="kw-2">&</span><span class="number">1u32</span>.to_le_bytes());
-<a href=#937 id=937 data-nosnippet>937</a>
-<a href=#938 id=938 data-nosnippet>938</a> <span class="comment">// Without prefix
-<a href=#939 id=939 data-nosnippet>939</a> </span><span class="kw">let </span>aad = stream_block_aad(<span class="string">b""</span>, <span class="number">42</span>);
-<a href=#940 id=940 data-nosnippet>940</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[..], <span class="kw-2">&</span><span class="number">42u32</span>.to_le_bytes());
-<a href=#941 id=941 data-nosnippet>941</a> }
-<a href=#942 id=942 data-nosnippet>942</a>
-<a href=#943 id=943 data-nosnippet>943</a> <span class="attr">#[tokio::test]
-<a href=#944 id=944 data-nosnippet>944</a> </span><span class="kw">async fn </span>test_encrypted_file_too_short() {
-<a href=#945 id=945 data-nosnippet>945</a> <span class="kw">let </span>result = AesGcmFileRead::new(
-<a href=#946 id=946 data-nosnippet>946</a> memory_reader(<span class="macro">vec!</span>[<span class="number">0</span>; <span class="number">4</span>]),
-<a href=#947 id=947 data-nosnippet>947</a> Arc::new(make_cipher(<span class="string">b"0123456789abcdef"</span>)),
-<a href=#948 id=948 data-nosnippet>948</a> [].into(),
-<a href=#949 id=949 data-nosnippet>949</a> <span class="number">4</span>,
-<a href=#950 id=950 data-nosnippet>950</a> );
-<a href=#951 id=951 data-nosnippet>951</a> <span class="macro">assert!</span>(result.is_err());
-<a href=#952 id=952 data-nosnippet>952</a> }
+<a href=#911 id=911 data-nosnippet>911</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>;
+<a href=#912 id=912 data-nosnippet>912</a> <span class="macro">assert!</span>(result.is_err(), <span class="string">"Decryption with wrong AAD should fail"</span>);
+<a href=#913 id=913 data-nosnippet>913</a> }
+<a href=#914 id=914 data-nosnippet>914</a>
+<a href=#915 id=915 data-nosnippet>915</a> <span class="attr">#[tokio::test]
+<a href=#916 id=916 data-nosnippet>916</a> </span><span class="kw">async fn </span>test_wrong_key_fails() {
+<a href=#917 id=917 data-nosnippet>917</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#918 id=918 data-nosnippet>918</a> <span class="kw">let </span>wrong_key = <span class="string">b"fedcba9876543210"</span>;
+<a href=#919 id=919 data-nosnippet>919</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
+<a href=#920 id=920 data-nosnippet>920</a> <span class="kw">let </span>plaintext = <span class="string">b"sensitive data"</span>;
+<a href=#921 id=921 data-nosnippet>921</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#922 id=922 data-nosnippet>922</a>
+<a href=#923 id=923 data-nosnippet>923</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#924 id=924 data-nosnippet>924</a>
+<a href=#925 id=925 data-nosnippet>925</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#926 id=926 data-nosnippet>926</a> memory_reader(encrypted.clone()),
+<a href=#927 id=927 data-nosnippet>927</a> Arc::new(make_cipher(wrong_key)),
+<a href=#928 id=928 data-nosnippet>928</a> aad_prefix.as_slice().into(),
+<a href=#929 id=929 data-nosnippet>929</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#930 id=930 data-nosnippet>930</a> )
+<a href=#931 id=931 data-nosnippet>931</a> .unwrap();
+<a href=#932 id=932 data-nosnippet>932</a>
+<a href=#933 id=933 data-nosnippet>933</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>;
+<a href=#934 id=934 data-nosnippet>934</a> <span class="macro">assert!</span>(result.is_err(), <span class="string">"Decryption with wrong key should fail"</span>);
+<a href=#935 id=935 data-nosnippet>935</a> }
+<a href=#936 id=936 data-nosnippet>936</a>
+<a href=#937 id=937 data-nosnippet>937</a> <span class="attr">#[tokio::test]
+<a href=#938 id=938 data-nosnippet>938</a> </span><span class="kw">async fn </span>test_out_of_bounds_read() {
+<a href=#939 id=939 data-nosnippet>939</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#940 id=940 data-nosnippet>940</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
+<a href=#941 id=941 data-nosnippet>941</a> <span class="kw">let </span>plaintext = <span class="string">b"short data"</span>;
+<a href=#942 id=942 data-nosnippet>942</a> <span class="kw">let </span>cipher = make_cipher(key);
+<a href=#943 id=943 data-nosnippet>943</a>
+<a href=#944 id=944 data-nosnippet>944</a> <span class="kw">let </span>encrypted = encrypt_ags1(plaintext, <span class="kw-2">&</span>cipher, aad_prefix);
+<a href=#945 id=945 data-nosnippet>945</a>
+<a href=#946 id=946 data-nosnippet>946</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#947 id=947 data-nosnippet>947</a> memory_reader(encrypted.clone()),
+<a href=#948 id=948 data-nosnippet>948</a> Arc::new(make_cipher(key)),
+<a href=#949 id=949 data-nosnippet>949</a> aad_prefix.as_slice().into(),
+<a href=#950 id=950 data-nosnippet>950</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#951 id=951 data-nosnippet>951</a> )
+<a href=#952 id=952 data-nosnippet>952</a> .unwrap();
<a href=#953 id=953 data-nosnippet>953</a>
-<a href=#954 id=954 data-nosnippet>954</a> <span class="comment">// --- AesGcmFileWrite tests ---
-<a href=#955 id=955 data-nosnippet>955</a>
-<a href=#956 id=956 data-nosnippet>956</a> </span><span class="doccomment">/// Shared-buffer FileWrite for testing AesGcmFileWrite output.
-<a href=#957 id=957 data-nosnippet>957</a> </span><span class="kw">struct </span>SharedMemoryWrite {
-<a href=#958 id=958 data-nosnippet>958</a> buffer: Arc<std::sync::Mutex<Vec<u8>>>,
-<a href=#959 id=959 data-nosnippet>959</a> }
-<a href=#960 id=960 data-nosnippet>960</a>
-<a href=#961 id=961 data-nosnippet>961</a> <span class="doccomment">/// FileWrite that fails after a configured number of successful writes.
-<a href=#962 id=962 data-nosnippet>962</a> </span><span class="kw">struct </span>FailingFileWrite {
-<a href=#963 id=963 data-nosnippet>963</a> writes_before_failure: usize,
-<a href=#964 id=964 data-nosnippet>964</a> write_count: usize,
-<a href=#965 id=965 data-nosnippet>965</a> }
-<a href=#966 id=966 data-nosnippet>966</a>
-<a href=#967 id=967 data-nosnippet>967</a> <span class="attr">#[async_trait::async_trait]
-<a href=#968 id=968 data-nosnippet>968</a> </span><span class="kw">impl </span>FileWrite <span class="kw">for </span>FailingFileWrite {
-<a href=#969 id=969 data-nosnippet>969</a> <span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, _bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
-<a href=#970 id=970 data-nosnippet>970</a> <span class="kw">if </span><span class="self">self</span>.write_count >= <span class="self">self</span>.writes_before_failure {
-<a href=#971 id=971 data-nosnippet>971</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(ErrorKind::Unexpected, <span class="string">"simulated write failure"</span>));
-<a href=#972 id=972 data-nosnippet>972</a> }
-<a href=#973 id=973 data-nosnippet>973</a> <span class="self">self</span>.write_count += <span class="number">1</span>;
-<a href=#974 id=974 data-nosnippet>974</a> <span class="prelude-val">Ok</span>(())
-<a href=#975 id=975 data-nosnippet>975</a> }
-<a href=#976 id=976 data-nosnippet>976</a>
-<a href=#977 id=977 data-nosnippet>977</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
-<a href=#978 id=978 data-nosnippet>978</a> <span class="prelude-val">Ok</span>(())
-<a href=#979 id=979 data-nosnippet>979</a> }
-<a href=#980 id=980 data-nosnippet>980</a> }
-<a href=#981 id=981 data-nosnippet>981</a>
-<a href=#982 id=982 data-nosnippet>982</a> <span class="attr">#[async_trait::async_trait]
-<a href=#983 id=983 data-nosnippet>983</a> </span><span class="kw">impl </span>FileWrite <span class="kw">for </span>SharedMemoryWrite {
-<a href=#984 id=984 data-nosnippet>984</a> <span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
-<a href=#985 id=985 data-nosnippet>985</a> <span class="self">self</span>.buffer.lock().unwrap().extend_from_slice(<span class="kw-2">&</span>bs);
-<a href=#986 id=986 data-nosnippet>986</a> <span class="prelude-val">Ok</span>(())
-<a href=#987 id=987 data-nosnippet>987</a> }
-<a href=#988 id=988 data-nosnippet>988</a>
-<a href=#989 id=989 data-nosnippet>989</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
-<a href=#990 id=990 data-nosnippet>990</a> <span class="prelude-val">Ok</span>(())
-<a href=#991 id=991 data-nosnippet>991</a> }
-<a href=#992 id=992 data-nosnippet>992</a> }
-<a href=#993 id=993 data-nosnippet>993</a>
-<a href=#994 id=994 data-nosnippet>994</a> <span class="doccomment">/// Helper: one-shot encrypt through AesGcmFileWrite, return encrypted bytes.
-<a href=#995 id=995 data-nosnippet>995</a> </span><span class="kw">async fn </span>write_through_ags1(plaintext: <span class="kw-2">&</span>[u8], key: <span class="kw-2">&</span>[u8], aad_prefix: <span class="kw-2">&</span>[u8]) -> Vec<u8> {
-<a href=#996 id=996 data-nosnippet>996</a> <span class="kw">let </span>buffer = Arc::new(std::sync::Mutex::new(Vec::new()));
-<a href=#997 id=997 data-nosnippet>997</a> <span class="kw">let </span>inner: Box<<span class="kw">dyn </span>FileWrite> = Box::new(SharedMemoryWrite {
-<a href=#998 id=998 data-nosnippet>998</a> buffer: buffer.clone(),
-<a href=#999 id=999 data-nosnippet>999</a> });
-<a href=#1000 id=1000 data-nosnippet>1000</a> <span class="kw">let </span>cipher = Arc::new(make_cipher(key));
-<a href=#1001 id=1001 data-nosnippet>1001</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = AesGcmFileWrite::new(inner, cipher, aad_prefix.to_vec());
-<a href=#1002 id=1002 data-nosnippet>1002</a>
-<a href=#1003 id=1003 data-nosnippet>1003</a> writer.write(Bytes::from(plaintext.to_vec())).<span class="kw">await</span>.unwrap();
-<a href=#1004 id=1004 data-nosnippet>1004</a> writer.close().<span class="kw">await</span>.unwrap();
-<a href=#1005 id=1005 data-nosnippet>1005</a>
-<a href=#1006 id=1006 data-nosnippet>1006</a> buffer.lock().unwrap().clone()
-<a href=#1007 id=1007 data-nosnippet>1007</a> }
-<a href=#1008 id=1008 data-nosnippet>1008</a>
-<a href=#1009 id=1009 data-nosnippet>1009</a> <span class="attr">#[tokio::test]
-<a href=#1010 id=1010 data-nosnippet>1010</a> </span><span class="kw">async fn </span>test_write_empty_roundtrip() {
-<a href=#1011 id=1011 data-nosnippet>1011</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#1012 id=1012 data-nosnippet>1012</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
-<a href=#1013 id=1013 data-nosnippet>1013</a>
-<a href=#1014 id=1014 data-nosnippet>1014</a> <span class="kw">let </span>encrypted = write_through_ags1(<span class="string">b""</span>, key, aad_prefix).<span class="kw">await</span>;
-<a href=#1015 id=1015 data-nosnippet>1015</a>
-<a href=#1016 id=1016 data-nosnippet>1016</a> <span class="comment">// Should produce header + one empty encrypted block
-<a href=#1017 id=1017 data-nosnippet>1017</a> </span><span class="macro">assert_eq!</span>(encrypted.len(), MIN_STREAM_LENGTH <span class="kw">as </span>usize);
-<a href=#1018 id=1018 data-nosnippet>1018</a>
-<a href=#1019 id=1019 data-nosnippet>1019</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#1020 id=1020 data-nosnippet>1020</a> memory_reader(encrypted.clone()),
-<a href=#1021 id=1021 data-nosnippet>1021</a> Arc::new(make_cipher(key)),
-<a href=#1022 id=1022 data-nosnippet>1022</a> aad_prefix.as_slice().into(),
-<a href=#1023 id=1023 data-nosnippet>1023</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#1024 id=1024 data-nosnippet>1024</a> )
-<a href=#1025 id=1025 data-nosnippet>1025</a> .unwrap();
-<a href=#1026 id=1026 data-nosnippet>1026</a>
-<a href=#1027 id=1027 data-nosnippet>1027</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), <span class="number">0</span>);
-<a href=#1028 id=1028 data-nosnippet>1028</a> }
-<a href=#1029 id=1029 data-nosnippet>1029</a>
-<a href=#1030 id=1030 data-nosnippet>1030</a> <span class="attr">#[tokio::test]
-<a href=#1031 id=1031 data-nosnippet>1031</a> </span><span class="kw">async fn </span>test_write_small_roundtrip() {
-<a href=#1032 id=1032 data-nosnippet>1032</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#1033 id=1033 data-nosnippet>1033</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
-<a href=#1034 id=1034 data-nosnippet>1034</a> <span class="kw">let </span>plaintext = <span class="string">b"Hello, Iceberg encryption!"</span>;
-<a href=#1035 id=1035 data-nosnippet>1035</a>
-<a href=#1036 id=1036 data-nosnippet>1036</a> <span class="kw">let </span>encrypted = write_through_ags1(plaintext, key, aad_prefix).<span class="kw">await</span>;
-<a href=#1037 id=1037 data-nosnippet>1037</a>
-<a href=#1038 id=1038 data-nosnippet>1038</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#1039 id=1039 data-nosnippet>1039</a> memory_reader(encrypted.clone()),
-<a href=#1040 id=1040 data-nosnippet>1040</a> Arc::new(make_cipher(key)),
-<a href=#1041 id=1041 data-nosnippet>1041</a> aad_prefix.as_slice().into(),
-<a href=#1042 id=1042 data-nosnippet>1042</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#1043 id=1043 data-nosnippet>1043</a> )
-<a href=#1044 id=1044 data-nosnippet>1044</a> .unwrap();
-<a href=#1045 id=1045 data-nosnippet>1045</a>
-<a href=#1046 id=1046 data-nosnippet>1046</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
-<a href=#1047 id=1047 data-nosnippet>1047</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#1048 id=1048 data-nosnippet>1048</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], plaintext);
-<a href=#1049 id=1049 data-nosnippet>1049</a> }
-<a href=#1050 id=1050 data-nosnippet>1050</a>
-<a href=#1051 id=1051 data-nosnippet>1051</a> <span class="attr">#[tokio::test]
-<a href=#1052 id=1052 data-nosnippet>1052</a> </span><span class="kw">async fn </span>test_write_multi_block_roundtrip() {
-<a href=#1053 id=1053 data-nosnippet>1053</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#1054 id=1054 data-nosnippet>1054</a> <span class="kw">let </span>aad_prefix = <span class="string">b"multi-block-aad!"</span>;
-<a href=#1055 id=1055 data-nosnippet>1055</a>
-<a href=#1056 id=1056 data-nosnippet>1056</a> <span class="comment">// 1.5 blocks of data
-<a href=#1057 id=1057 data-nosnippet>1057</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + PLAIN_BLOCK_SIZE <span class="kw">as </span>usize / <span class="number">2</span>;
-<a href=#1058 id=1058 data-nosnippet>1058</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
-<a href=#1059 id=1059 data-nosnippet>1059</a>
-<a href=#1060 id=1060 data-nosnippet>1060</a> <span class="kw">let </span>encrypted = write_through_ags1(<span class="kw-2">&</span>plaintext, key, aad_prefix).<span class="kw">await</span>;
+<a href=#954 id=954 data-nosnippet>954</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64 + <span class="number">1</span>).<span class="kw">await</span>;
+<a href=#955 id=955 data-nosnippet>955</a> <span class="macro">assert!</span>(result.is_err(), <span class="string">"Reading past end should fail"</span>);
+<a href=#956 id=956 data-nosnippet>956</a> }
+<a href=#957 id=957 data-nosnippet>957</a>
+<a href=#958 id=958 data-nosnippet>958</a> <span class="attr">#[tokio::test]
+<a href=#959 id=959 data-nosnippet>959</a> </span><span class="kw">async fn </span>test_calculate_plaintext_length() {
+<a href=#960 id=960 data-nosnippet>960</a> <span class="comment">// Empty file: header only (not valid per Java, but handled)
+<a href=#961 id=961 data-nosnippet>961</a> </span><span class="macro">assert_eq!</span>(
+<a href=#962 id=962 data-nosnippet>962</a> AesGcmFileRead::calculate_plaintext_length(GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64).unwrap(),
+<a href=#963 id=963 data-nosnippet>963</a> <span class="number">0
+<a href=#964 id=964 data-nosnippet>964</a> </span>);
+<a href=#965 id=965 data-nosnippet>965</a>
+<a href=#966 id=966 data-nosnippet>966</a> <span class="comment">// Empty file with one empty block: header(8) + nonce(12) + tag(16) = 36
+<a href=#967 id=967 data-nosnippet>967</a> </span><span class="macro">assert_eq!</span>(
+<a href=#968 id=968 data-nosnippet>968</a> AesGcmFileRead::calculate_plaintext_length(MIN_STREAM_LENGTH <span class="kw">as </span>u64).unwrap(),
+<a href=#969 id=969 data-nosnippet>969</a> <span class="number">0
+<a href=#970 id=970 data-nosnippet>970</a> </span>);
+<a href=#971 id=971 data-nosnippet>971</a>
+<a href=#972 id=972 data-nosnippet>972</a> <span class="comment">// One full block: header(8) + cipher_block(1048604) = 1048612
+<a href=#973 id=973 data-nosnippet>973</a> </span><span class="kw">let </span>one_full = GCM_STREAM_HEADER_LENGTH <span class="kw">as </span>u64 + CIPHER_BLOCK_SIZE <span class="kw">as </span>u64;
+<a href=#974 id=974 data-nosnippet>974</a> <span class="macro">assert_eq!</span>(
+<a href=#975 id=975 data-nosnippet>975</a> AesGcmFileRead::calculate_plaintext_length(one_full).unwrap(),
+<a href=#976 id=976 data-nosnippet>976</a> PLAIN_BLOCK_SIZE <span class="kw">as </span>u64
+<a href=#977 id=977 data-nosnippet>977</a> );
+<a href=#978 id=978 data-nosnippet>978</a>
+<a href=#979 id=979 data-nosnippet>979</a> <span class="comment">// One full block + 1 byte: need partial second block
+<a href=#980 id=980 data-nosnippet>980</a> // Second block = nonce(12) + 1 byte ciphertext + tag(16) = 29
+<a href=#981 id=981 data-nosnippet>981</a> </span><span class="kw">let </span>one_full_plus_one = one_full + NONCE_LENGTH <span class="kw">as </span>u64 + <span class="number">1 </span>+ GCM_TAG_LENGTH <span class="kw">as </span>u64;
+<a href=#982 id=982 data-nosnippet>982</a> <span class="macro">assert_eq!</span>(
+<a href=#983 id=983 data-nosnippet>983</a> AesGcmFileRead::calculate_plaintext_length(one_full_plus_one).unwrap(),
+<a href=#984 id=984 data-nosnippet>984</a> PLAIN_BLOCK_SIZE <span class="kw">as </span>u64 + <span class="number">1
+<a href=#985 id=985 data-nosnippet>985</a> </span>);
+<a href=#986 id=986 data-nosnippet>986</a> }
+<a href=#987 id=987 data-nosnippet>987</a>
+<a href=#988 id=988 data-nosnippet>988</a> <span class="attr">#[tokio::test]
+<a href=#989 id=989 data-nosnippet>989</a> </span><span class="kw">async fn </span>test_stream_block_aad() {
+<a href=#990 id=990 data-nosnippet>990</a> <span class="comment">// With prefix
+<a href=#991 id=991 data-nosnippet>991</a> </span><span class="kw">let </span>aad = stream_block_aad(<span class="string">b"prefix"</span>, <span class="number">0</span>);
+<a href=#992 id=992 data-nosnippet>992</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[..<span class="number">6</span>], <span class="string">b"prefix"</span>);
+<a href=#993 id=993 data-nosnippet>993</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[<span class="number">6</span>..], <span class="kw-2">&</span><span class="number">0u32</span>.to_le_bytes());
+<a href=#994 id=994 data-nosnippet>994</a>
+<a href=#995 id=995 data-nosnippet>995</a> <span class="kw">let </span>aad = stream_block_aad(<span class="string">b"prefix"</span>, <span class="number">1</span>);
+<a href=#996 id=996 data-nosnippet>996</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[..<span class="number">6</span>], <span class="string">b"prefix"</span>);
+<a href=#997 id=997 data-nosnippet>997</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[<span class="number">6</span>..], <span class="kw-2">&</span><span class="number">1u32</span>.to_le_bytes());
+<a href=#998 id=998 data-nosnippet>998</a>
+<a href=#999 id=999 data-nosnippet>999</a> <span class="comment">// Without prefix
+<a href=#1000 id=1000 data-nosnippet>1000</a> </span><span class="kw">let </span>aad = stream_block_aad(<span class="string">b""</span>, <span class="number">42</span>);
+<a href=#1001 id=1001 data-nosnippet>1001</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>aad[..], <span class="kw-2">&</span><span class="number">42u32</span>.to_le_bytes());
+<a href=#1002 id=1002 data-nosnippet>1002</a> }
+<a href=#1003 id=1003 data-nosnippet>1003</a>
+<a href=#1004 id=1004 data-nosnippet>1004</a> <span class="attr">#[test]
+<a href=#1005 id=1005 data-nosnippet>1005</a> </span><span class="kw">fn </span>test_encrypted_file_too_short() {
+<a href=#1006 id=1006 data-nosnippet>1006</a> <span class="kw">for </span>length <span class="kw">in </span><span class="number">0</span>..MIN_STREAM_LENGTH {
+<a href=#1007 id=1007 data-nosnippet>1007</a> <span class="kw">let </span>result = AesGcmFileRead::new(
+<a href=#1008 id=1008 data-nosnippet>1008</a> memory_reader(<span class="macro">vec!</span>[<span class="number">0</span>; length <span class="kw">as </span>usize]),
+<a href=#1009 id=1009 data-nosnippet>1009</a> Arc::new(make_cipher(<span class="string">b"0123456789abcdef"</span>)),
+<a href=#1010 id=1010 data-nosnippet>1010</a> [].into(),
+<a href=#1011 id=1011 data-nosnippet>1011</a> u64::from(length),
+<a href=#1012 id=1012 data-nosnippet>1012</a> );
+<a href=#1013 id=1013 data-nosnippet>1013</a> <span class="kw">let </span>err = result
+<a href=#1014 id=1014 data-nosnippet>1014</a> .err()
+<a href=#1015 id=1015 data-nosnippet>1015</a> .expect(<span class="string">"a stream must contain an authenticated block"</span>);
+<a href=#1016 id=1016 data-nosnippet>1016</a> <span class="macro">assert_eq!</span>(err.kind(), ErrorKind::DataInvalid);
+<a href=#1017 id=1017 data-nosnippet>1017</a> <span class="macro">assert!</span>(err.to_string().contains(<span class="string">"Invalid encrypted file length"</span>));
+<a href=#1018 id=1018 data-nosnippet>1018</a> }
+<a href=#1019 id=1019 data-nosnippet>1019</a> }
+<a href=#1020 id=1020 data-nosnippet>1020</a>
+<a href=#1021 id=1021 data-nosnippet>1021</a> <span class="comment">// --- AesGcmFileWrite tests ---
+<a href=#1022 id=1022 data-nosnippet>1022</a>
+<a href=#1023 id=1023 data-nosnippet>1023</a> </span><span class="doccomment">/// Shared-buffer FileWrite for testing AesGcmFileWrite output.
+<a href=#1024 id=1024 data-nosnippet>1024</a> </span><span class="kw">struct </span>SharedMemoryWrite {
+<a href=#1025 id=1025 data-nosnippet>1025</a> buffer: Arc<std::sync::Mutex<Vec<u8>>>,
+<a href=#1026 id=1026 data-nosnippet>1026</a> }
+<a href=#1027 id=1027 data-nosnippet>1027</a>
+<a href=#1028 id=1028 data-nosnippet>1028</a> <span class="doccomment">/// FileWrite that fails after a configured number of successful writes.
+<a href=#1029 id=1029 data-nosnippet>1029</a> </span><span class="kw">struct </span>FailingFileWrite {
+<a href=#1030 id=1030 data-nosnippet>1030</a> writes_before_failure: usize,
+<a href=#1031 id=1031 data-nosnippet>1031</a> write_count: usize,
+<a href=#1032 id=1032 data-nosnippet>1032</a> }
+<a href=#1033 id=1033 data-nosnippet>1033</a>
+<a href=#1034 id=1034 data-nosnippet>1034</a> <span class="attr">#[async_trait::async_trait]
+<a href=#1035 id=1035 data-nosnippet>1035</a> </span><span class="kw">impl </span>FileWrite <span class="kw">for </span>FailingFileWrite {
+<a href=#1036 id=1036 data-nosnippet>1036</a> <span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, _bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
+<a href=#1037 id=1037 data-nosnippet>1037</a> <span class="kw">if </span><span class="self">self</span>.write_count >= <span class="self">self</span>.writes_before_failure {
+<a href=#1038 id=1038 data-nosnippet>1038</a> <span class="kw">return </span><span class="prelude-val">Err</span>(Error::new(ErrorKind::Unexpected, <span class="string">"simulated write failure"</span>));
+<a href=#1039 id=1039 data-nosnippet>1039</a> }
+<a href=#1040 id=1040 data-nosnippet>1040</a> <span class="self">self</span>.write_count += <span class="number">1</span>;
+<a href=#1041 id=1041 data-nosnippet>1041</a> <span class="prelude-val">Ok</span>(())
+<a href=#1042 id=1042 data-nosnippet>1042</a> }
+<a href=#1043 id=1043 data-nosnippet>1043</a>
+<a href=#1044 id=1044 data-nosnippet>1044</a> <span class="comment">// A poisoned AesGcmFileWrite must reject close() before delegating, so reaching this is a
+<a href=#1045 id=1045 data-nosnippet>1045</a> // bug. Returning an error rather than panicking surfaces it as a failed assertion on the
+<a href=#1046 id=1046 data-nosnippet>1046</a> // expected "poisoned" message.
+<a href=#1047 id=1047 data-nosnippet>1047</a> </span><span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><FileMetadata> {
+<a href=#1048 id=1048 data-nosnippet>1048</a> <span class="prelude-val">Err</span>(Error::new(
+<a href=#1049 id=1049 data-nosnippet>1049</a> ErrorKind::Unexpected,
+<a href=#1050 id=1050 data-nosnippet>1050</a> <span class="string">"FailingFileWrite::close called unexpectedly"</span>,
+<a href=#1051 id=1051 data-nosnippet>1051</a> ))
+<a href=#1052 id=1052 data-nosnippet>1052</a> }
+<a href=#1053 id=1053 data-nosnippet>1053</a> }
+<a href=#1054 id=1054 data-nosnippet>1054</a>
+<a href=#1055 id=1055 data-nosnippet>1055</a> <span class="attr">#[async_trait::async_trait]
+<a href=#1056 id=1056 data-nosnippet>1056</a> </span><span class="kw">impl </span>FileWrite <span class="kw">for </span>SharedMemoryWrite {
+<a href=#1057 id=1057 data-nosnippet>1057</a> <span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
+<a href=#1058 id=1058 data-nosnippet>1058</a> <span class="self">self</span>.buffer.lock().unwrap().extend_from_slice(<span class="kw-2">&</span>bs);
+<a href=#1059 id=1059 data-nosnippet>1059</a> <span class="prelude-val">Ok</span>(())
+<a href=#1060 id=1060 data-nosnippet>1060</a> }
<a href=#1061 id=1061 data-nosnippet>1061</a>
-<a href=#1062 id=1062 data-nosnippet>1062</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#1063 id=1063 data-nosnippet>1063</a> memory_reader(encrypted.clone()),
-<a href=#1064 id=1064 data-nosnippet>1064</a> Arc::new(make_cipher(key)),
-<a href=#1065 id=1065 data-nosnippet>1065</a> aad_prefix.as_slice().into(),
-<a href=#1066 id=1066 data-nosnippet>1066</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#1067 id=1067 data-nosnippet>1067</a> )
-<a href=#1068 id=1068 data-nosnippet>1068</a> .unwrap();
-<a href=#1069 id=1069 data-nosnippet>1069</a>
-<a href=#1070 id=1070 data-nosnippet>1070</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
-<a href=#1071 id=1071 data-nosnippet>1071</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#1072 id=1072 data-nosnippet>1072</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
-<a href=#1073 id=1073 data-nosnippet>1073</a> }
-<a href=#1074 id=1074 data-nosnippet>1074</a>
-<a href=#1075 id=1075 data-nosnippet>1075</a> <span class="attr">#[tokio::test]
-<a href=#1076 id=1076 data-nosnippet>1076</a> </span><span class="kw">async fn </span>test_write_cross_block_accumulation() {
-<a href=#1077 id=1077 data-nosnippet>1077</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#1078 id=1078 data-nosnippet>1078</a> <span class="kw">let </span>aad_prefix = <span class="string">b"cross-block-aad!"</span>;
-<a href=#1079 id=1079 data-nosnippet>1079</a>
-<a href=#1080 id=1080 data-nosnippet>1080</a> <span class="kw">let </span>buffer = Arc::new(std::sync::Mutex::new(Vec::new()));
-<a href=#1081 id=1081 data-nosnippet>1081</a> <span class="kw">let </span>inner: Box<<span class="kw">dyn </span>FileWrite> = Box::new(SharedMemoryWrite {
-<a href=#1082 id=1082 data-nosnippet>1082</a> buffer: buffer.clone(),
-<a href=#1083 id=1083 data-nosnippet>1083</a> });
-<a href=#1084 id=1084 data-nosnippet>1084</a> <span class="kw">let </span>cipher = Arc::new(make_cipher(key));
-<a href=#1085 id=1085 data-nosnippet>1085</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = AesGcmFileWrite::new(inner, cipher, aad_prefix.to_vec());
-<a href=#1086 id=1086 data-nosnippet>1086</a>
-<a href=#1087 id=1087 data-nosnippet>1087</a> <span class="comment">// Write 1.5 blocks in 1000-byte chunks
-<a href=#1088 id=1088 data-nosnippet>1088</a> </span><span class="kw">let </span>total_size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + PLAIN_BLOCK_SIZE <span class="kw">as </span>usize / <span class="number">2</span>;
-<a href=#1089 id=1089 data-nosnippet>1089</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..total_size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
-<a href=#1090 id=1090 data-nosnippet>1090</a> <span class="kw">let </span>chunk_size = <span class="number">1000</span>;
-<a href=#1091 id=1091 data-nosnippet>1091</a> <span class="kw">for </span>chunk <span class="kw">in </span>plaintext.chunks(chunk_size) {
-<a href=#1092 id=1092 data-nosnippet>1092</a> writer.write(Bytes::from(chunk.to_vec())).<span class="kw">await</span>.unwrap();
-<a href=#1093 id=1093 data-nosnippet>1093</a> }
-<a href=#1094 id=1094 data-nosnippet>1094</a> writer.close().<span class="kw">await</span>.unwrap();
-<a href=#1095 id=1095 data-nosnippet>1095</a>
-<a href=#1096 id=1096 data-nosnippet>1096</a> <span class="kw">let </span>encrypted = buffer.lock().unwrap().clone();
-<a href=#1097 id=1097 data-nosnippet>1097</a>
-<a href=#1098 id=1098 data-nosnippet>1098</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#1099 id=1099 data-nosnippet>1099</a> memory_reader(encrypted.clone()),
-<a href=#1100 id=1100 data-nosnippet>1100</a> Arc::new(make_cipher(key)),
-<a href=#1101 id=1101 data-nosnippet>1101</a> aad_prefix.as_slice().into(),
-<a href=#1102 id=1102 data-nosnippet>1102</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#1103 id=1103 data-nosnippet>1103</a> )
-<a href=#1104 id=1104 data-nosnippet>1104</a> .unwrap();
-<a href=#1105 id=1105 data-nosnippet>1105</a>
-<a href=#1106 id=1106 data-nosnippet>1106</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
-<a href=#1107 id=1107 data-nosnippet>1107</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#1108 id=1108 data-nosnippet>1108</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#1062 id=1062 data-nosnippet>1062</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><FileMetadata> {
+<a href=#1063 id=1063 data-nosnippet>1063</a> <span class="prelude-val">Ok</span>(FileMetadata {
+<a href=#1064 id=1064 data-nosnippet>1064</a> size: <span class="self">self</span>.buffer.lock().unwrap().len() <span class="kw">as </span>u64,
+<a href=#1065 id=1065 data-nosnippet>1065</a> })
+<a href=#1066 id=1066 data-nosnippet>1066</a> }
+<a href=#1067 id=1067 data-nosnippet>1067</a> }
+<a href=#1068 id=1068 data-nosnippet>1068</a>
+<a href=#1069 id=1069 data-nosnippet>1069</a> <span class="doccomment">/// Helper: one-shot encrypt through AesGcmFileWrite, return encrypted bytes.
+<a href=#1070 id=1070 data-nosnippet>1070</a> </span><span class="kw">async fn </span>write_through_ags1(plaintext: <span class="kw-2">&</span>[u8], key: <span class="kw-2">&</span>[u8], aad_prefix: <span class="kw-2">&</span>[u8]) -> Vec<u8> {
+<a href=#1071 id=1071 data-nosnippet>1071</a> <span class="kw">let </span>buffer = Arc::new(std::sync::Mutex::new(Vec::new()));
+<a href=#1072 id=1072 data-nosnippet>1072</a> <span class="kw">let </span>inner: Box<<span class="kw">dyn </span>FileWrite> = Box::new(SharedMemoryWrite {
+<a href=#1073 id=1073 data-nosnippet>1073</a> buffer: buffer.clone(),
+<a href=#1074 id=1074 data-nosnippet>1074</a> });
+<a href=#1075 id=1075 data-nosnippet>1075</a> <span class="kw">let </span>cipher = Arc::new(make_cipher(key));
+<a href=#1076 id=1076 data-nosnippet>1076</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = AesGcmFileWrite::new(inner, cipher, aad_prefix.to_vec());
+<a href=#1077 id=1077 data-nosnippet>1077</a>
+<a href=#1078 id=1078 data-nosnippet>1078</a> writer.write(Bytes::from(plaintext.to_vec())).<span class="kw">await</span>.unwrap();
+<a href=#1079 id=1079 data-nosnippet>1079</a> <span class="kw">let </span>metadata = writer.close().<span class="kw">await</span>.unwrap();
+<a href=#1080 id=1080 data-nosnippet>1080</a>
+<a href=#1081 id=1081 data-nosnippet>1081</a> <span class="kw">let </span>encrypted = buffer.lock().unwrap().clone();
+<a href=#1082 id=1082 data-nosnippet>1082</a> <span class="macro">assert_eq!</span>(
+<a href=#1083 id=1083 data-nosnippet>1083</a> metadata.size,
+<a href=#1084 id=1084 data-nosnippet>1084</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#1085 id=1085 data-nosnippet>1085</a> <span class="string">"close() must report the full ciphertext length"
+<a href=#1086 id=1086 data-nosnippet>1086</a> </span>);
+<a href=#1087 id=1087 data-nosnippet>1087</a> encrypted
+<a href=#1088 id=1088 data-nosnippet>1088</a> }
+<a href=#1089 id=1089 data-nosnippet>1089</a>
+<a href=#1090 id=1090 data-nosnippet>1090</a> <span class="attr">#[tokio::test]
+<a href=#1091 id=1091 data-nosnippet>1091</a> </span><span class="kw">async fn </span>test_write_empty_roundtrip() {
+<a href=#1092 id=1092 data-nosnippet>1092</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#1093 id=1093 data-nosnippet>1093</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
+<a href=#1094 id=1094 data-nosnippet>1094</a>
+<a href=#1095 id=1095 data-nosnippet>1095</a> <span class="kw">let </span>encrypted = write_through_ags1(<span class="string">b""</span>, key, aad_prefix).<span class="kw">await</span>;
+<a href=#1096 id=1096 data-nosnippet>1096</a>
+<a href=#1097 id=1097 data-nosnippet>1097</a> <span class="comment">// Should produce header + one empty encrypted block
+<a href=#1098 id=1098 data-nosnippet>1098</a> </span><span class="macro">assert_eq!</span>(encrypted.len(), MIN_STREAM_LENGTH <span class="kw">as </span>usize);
+<a href=#1099 id=1099 data-nosnippet>1099</a>
+<a href=#1100 id=1100 data-nosnippet>1100</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#1101 id=1101 data-nosnippet>1101</a> memory_reader(encrypted.clone()),
+<a href=#1102 id=1102 data-nosnippet>1102</a> Arc::new(make_cipher(key)),
+<a href=#1103 id=1103 data-nosnippet>1103</a> aad_prefix.as_slice().into(),
+<a href=#1104 id=1104 data-nosnippet>1104</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#1105 id=1105 data-nosnippet>1105</a> )
+<a href=#1106 id=1106 data-nosnippet>1106</a> .unwrap();
+<a href=#1107 id=1107 data-nosnippet>1107</a>
+<a href=#1108 id=1108 data-nosnippet>1108</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), <span class="number">0</span>);
<a href=#1109 id=1109 data-nosnippet>1109</a> }
<a href=#1110 id=1110 data-nosnippet>1110</a>
<a href=#1111 id=1111 data-nosnippet>1111</a> <span class="attr">#[tokio::test]
-<a href=#1112 id=1112 data-nosnippet>1112</a> </span><span class="kw">async fn </span>test_write_exact_block_size() {
+<a href=#1112 id=1112 data-nosnippet>1112</a> </span><span class="kw">async fn </span>test_write_small_roundtrip() {
<a href=#1113 id=1113 data-nosnippet>1113</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#1114 id=1114 data-nosnippet>1114</a> <span class="kw">let </span>aad_prefix = <span class="string">b"exact-block-aad!"</span>;
-<a href=#1115 id=1115 data-nosnippet>1115</a>
-<a href=#1116 id=1116 data-nosnippet>1116</a> <span class="comment">// Exactly 1 block
-<a href=#1117 id=1117 data-nosnippet>1117</a> </span><span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize)
-<a href=#1118 id=1118 data-nosnippet>1118</a> .map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8)
-<a href=#1119 id=1119 data-nosnippet>1119</a> .collect();
-<a href=#1120 id=1120 data-nosnippet>1120</a>
-<a href=#1121 id=1121 data-nosnippet>1121</a> <span class="kw">let </span>encrypted = write_through_ags1(<span class="kw-2">&</span>plaintext, key, aad_prefix).<span class="kw">await</span>;
-<a href=#1122 id=1122 data-nosnippet>1122</a>
-<a href=#1123 id=1123 data-nosnippet>1123</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#1124 id=1124 data-nosnippet>1124</a> memory_reader(encrypted.clone()),
-<a href=#1125 id=1125 data-nosnippet>1125</a> Arc::new(make_cipher(key)),
-<a href=#1126 id=1126 data-nosnippet>1126</a> aad_prefix.as_slice().into(),
-<a href=#1127 id=1127 data-nosnippet>1127</a> encrypted.len() <span class="kw">as </span>u64,
-<a href=#1128 id=1128 data-nosnippet>1128</a> )
-<a href=#1129 id=1129 data-nosnippet>1129</a> .unwrap();
-<a href=#1130 id=1130 data-nosnippet>1130</a>
-<a href=#1131 id=1131 data-nosnippet>1131</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), PLAIN_BLOCK_SIZE <span class="kw">as </span>u64);
-<a href=#1132 id=1132 data-nosnippet>1132</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#1133 id=1133 data-nosnippet>1133</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
-<a href=#1134 id=1134 data-nosnippet>1134</a> }
-<a href=#1135 id=1135 data-nosnippet>1135</a>
-<a href=#1136 id=1136 data-nosnippet>1136</a> <span class="attr">#[tokio::test]
-<a href=#1137 id=1137 data-nosnippet>1137</a> </span><span class="kw">async fn </span>test_write_block_aligned_no_spurious_empty_block() {
-<a href=#1138 id=1138 data-nosnippet>1138</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#1139 id=1139 data-nosnippet>1139</a> <span class="kw">let </span>aad_prefix = <span class="string">b"block-align-aad!"</span>;
+<a href=#1114 id=1114 data-nosnippet>1114</a> <span class="kw">let </span>aad_prefix = <span class="string">b"test-aad-prefix!"</span>;
+<a href=#1115 id=1115 data-nosnippet>1115</a> <span class="kw">let </span>plaintext = <span class="string">b"Hello, Iceberg encryption!"</span>;
+<a href=#1116 id=1116 data-nosnippet>1116</a>
+<a href=#1117 id=1117 data-nosnippet>1117</a> <span class="kw">let </span>encrypted = write_through_ags1(plaintext, key, aad_prefix).<span class="kw">await</span>;
+<a href=#1118 id=1118 data-nosnippet>1118</a>
+<a href=#1119 id=1119 data-nosnippet>1119</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#1120 id=1120 data-nosnippet>1120</a> memory_reader(encrypted.clone()),
+<a href=#1121 id=1121 data-nosnippet>1121</a> Arc::new(make_cipher(key)),
+<a href=#1122 id=1122 data-nosnippet>1122</a> aad_prefix.as_slice().into(),
+<a href=#1123 id=1123 data-nosnippet>1123</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#1124 id=1124 data-nosnippet>1124</a> )
+<a href=#1125 id=1125 data-nosnippet>1125</a> .unwrap();
+<a href=#1126 id=1126 data-nosnippet>1126</a>
+<a href=#1127 id=1127 data-nosnippet>1127</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
+<a href=#1128 id=1128 data-nosnippet>1128</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#1129 id=1129 data-nosnippet>1129</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], plaintext);
+<a href=#1130 id=1130 data-nosnippet>1130</a> }
+<a href=#1131 id=1131 data-nosnippet>1131</a>
+<a href=#1132 id=1132 data-nosnippet>1132</a> <span class="attr">#[tokio::test]
+<a href=#1133 id=1133 data-nosnippet>1133</a> </span><span class="kw">async fn </span>test_write_multi_block_roundtrip() {
+<a href=#1134 id=1134 data-nosnippet>1134</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#1135 id=1135 data-nosnippet>1135</a> <span class="kw">let </span>aad_prefix = <span class="string">b"multi-block-aad!"</span>;
+<a href=#1136 id=1136 data-nosnippet>1136</a>
+<a href=#1137 id=1137 data-nosnippet>1137</a> <span class="comment">// 1.5 blocks of data
+<a href=#1138 id=1138 data-nosnippet>1138</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + PLAIN_BLOCK_SIZE <span class="kw">as </span>usize / <span class="number">2</span>;
+<a href=#1139 id=1139 data-nosnippet>1139</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
<a href=#1140 id=1140 data-nosnippet>1140</a>
-<a href=#1141 id=1141 data-nosnippet>1141</a> <span class="comment">// Write exactly one block of plaintext — close() should NOT add
-<a href=#1142 id=1142 data-nosnippet>1142</a> // a trailing empty encrypted block (28 bytes: 12-byte nonce + 16-byte tag).
-<a href=#1143 id=1143 data-nosnippet>1143</a> </span><span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize)
-<a href=#1144 id=1144 data-nosnippet>1144</a> .map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8)
-<a href=#1145 id=1145 data-nosnippet>1145</a> .collect();
-<a href=#1146 id=1146 data-nosnippet>1146</a>
-<a href=#1147 id=1147 data-nosnippet>1147</a> <span class="kw">let </span>encrypted_via_writer = write_through_ags1(<span class="kw-2">&</span>plaintext, key, aad_prefix).<span class="kw">await</span>;
-<a href=#1148 id=1148 data-nosnippet>1148</a> <span class="kw">let </span>encrypted_via_reference = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>make_cipher(key), aad_prefix);
-<a href=#1149 id=1149 data-nosnippet>1149</a>
-<a href=#1150 id=1150 data-nosnippet>1150</a> <span class="comment">// Both should be the same length — no extra 28-byte empty block
-<a href=#1151 id=1151 data-nosnippet>1151</a> </span><span class="macro">assert_eq!</span>(
-<a href=#1152 id=1152 data-nosnippet>1152</a> encrypted_via_writer.len(),
-<a href=#1153 id=1153 data-nosnippet>1153</a> encrypted_via_reference.len(),
-<a href=#1154 id=1154 data-nosnippet>1154</a> <span class="string">"Writer output should match reference encryption length (no spurious trailing block)"
-<a href=#1155 id=1155 data-nosnippet>1155</a> </span>);
-<a href=#1156 id=1156 data-nosnippet>1156</a>
-<a href=#1157 id=1157 data-nosnippet>1157</a> <span class="comment">// Verify roundtrip
-<a href=#1158 id=1158 data-nosnippet>1158</a> </span><span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#1159 id=1159 data-nosnippet>1159</a> memory_reader(encrypted_via_writer.clone()),
-<a href=#1160 id=1160 data-nosnippet>1160</a> Arc::new(make_cipher(key)),
-<a href=#1161 id=1161 data-nosnippet>1161</a> aad_prefix.as_slice().into(),
-<a href=#1162 id=1162 data-nosnippet>1162</a> encrypted_via_writer.len() <span class="kw">as </span>u64,
-<a href=#1163 id=1163 data-nosnippet>1163</a> )
-<a href=#1164 id=1164 data-nosnippet>1164</a> .unwrap();
-<a href=#1165 id=1165 data-nosnippet>1165</a>
-<a href=#1166 id=1166 data-nosnippet>1166</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), PLAIN_BLOCK_SIZE <span class="kw">as </span>u64);
-<a href=#1167 id=1167 data-nosnippet>1167</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#1168 id=1168 data-nosnippet>1168</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
-<a href=#1169 id=1169 data-nosnippet>1169</a> }
-<a href=#1170 id=1170 data-nosnippet>1170</a>
-<a href=#1171 id=1171 data-nosnippet>1171</a> <span class="attr">#[tokio::test]
-<a href=#1172 id=1172 data-nosnippet>1172</a> </span><span class="kw">async fn </span>test_write_two_blocks_aligned_no_spurious_empty_block() {
-<a href=#1173 id=1173 data-nosnippet>1173</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
-<a href=#1174 id=1174 data-nosnippet>1174</a> <span class="kw">let </span>aad_prefix = <span class="string">b"2blk-align-aad!!"</span>;
-<a href=#1175 id=1175 data-nosnippet>1175</a>
-<a href=#1176 id=1176 data-nosnippet>1176</a> <span class="comment">// Exactly 2 blocks
-<a href=#1177 id=1177 data-nosnippet>1177</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize * <span class="number">2</span>;
-<a href=#1178 id=1178 data-nosnippet>1178</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
-<a href=#1179 id=1179 data-nosnippet>1179</a>
-<a href=#1180 id=1180 data-nosnippet>1180</a> <span class="kw">let </span>encrypted_via_writer = write_through_ags1(<span class="kw-2">&</span>plaintext, key, aad_prefix).<span class="kw">await</span>;
-<a href=#1181 id=1181 data-nosnippet>1181</a> <span class="kw">let </span>encrypted_via_reference = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>make_cipher(key), aad_prefix);
-<a href=#1182 id=1182 data-nosnippet>1182</a>
-<a href=#1183 id=1183 data-nosnippet>1183</a> <span class="macro">assert_eq!</span>(
-<a href=#1184 id=1184 data-nosnippet>1184</a> encrypted_via_writer.len(),
-<a href=#1185 id=1185 data-nosnippet>1185</a> encrypted_via_reference.len(),
-<a href=#1186 id=1186 data-nosnippet>1186</a> <span class="string">"Writer output should match reference encryption length (no spurious trailing block)"
-<a href=#1187 id=1187 data-nosnippet>1187</a> </span>);
-<a href=#1188 id=1188 data-nosnippet>1188</a>
-<a href=#1189 id=1189 data-nosnippet>1189</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
-<a href=#1190 id=1190 data-nosnippet>1190</a> memory_reader(encrypted_via_writer.clone()),
-<a href=#1191 id=1191 data-nosnippet>1191</a> Arc::new(make_cipher(key)),
-<a href=#1192 id=1192 data-nosnippet>1192</a> aad_prefix.as_slice().into(),
-<a href=#1193 id=1193 data-nosnippet>1193</a> encrypted_via_writer.len() <span class="kw">as </span>u64,
-<a href=#1194 id=1194 data-nosnippet>1194</a> )
-<a href=#1195 id=1195 data-nosnippet>1195</a> .unwrap();
+<a href=#1141 id=1141 data-nosnippet>1141</a> <span class="kw">let </span>encrypted = write_through_ags1(<span class="kw-2">&</span>plaintext, key, aad_prefix).<span class="kw">await</span>;
+<a href=#1142 id=1142 data-nosnippet>1142</a>
+<a href=#1143 id=1143 data-nosnippet>1143</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#1144 id=1144 data-nosnippet>1144</a> memory_reader(encrypted.clone()),
+<a href=#1145 id=1145 data-nosnippet>1145</a> Arc::new(make_cipher(key)),
+<a href=#1146 id=1146 data-nosnippet>1146</a> aad_prefix.as_slice().into(),
+<a href=#1147 id=1147 data-nosnippet>1147</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#1148 id=1148 data-nosnippet>1148</a> )
+<a href=#1149 id=1149 data-nosnippet>1149</a> .unwrap();
+<a href=#1150 id=1150 data-nosnippet>1150</a>
+<a href=#1151 id=1151 data-nosnippet>1151</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
+<a href=#1152 id=1152 data-nosnippet>1152</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#1153 id=1153 data-nosnippet>1153</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#1154 id=1154 data-nosnippet>1154</a> }
+<a href=#1155 id=1155 data-nosnippet>1155</a>
+<a href=#1156 id=1156 data-nosnippet>1156</a> <span class="attr">#[tokio::test]
+<a href=#1157 id=1157 data-nosnippet>1157</a> </span><span class="kw">async fn </span>test_write_cross_block_accumulation() {
+<a href=#1158 id=1158 data-nosnippet>1158</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#1159 id=1159 data-nosnippet>1159</a> <span class="kw">let </span>aad_prefix = <span class="string">b"cross-block-aad!"</span>;
+<a href=#1160 id=1160 data-nosnippet>1160</a>
+<a href=#1161 id=1161 data-nosnippet>1161</a> <span class="kw">let </span>buffer = Arc::new(std::sync::Mutex::new(Vec::new()));
+<a href=#1162 id=1162 data-nosnippet>1162</a> <span class="kw">let </span>inner: Box<<span class="kw">dyn </span>FileWrite> = Box::new(SharedMemoryWrite {
+<a href=#1163 id=1163 data-nosnippet>1163</a> buffer: buffer.clone(),
+<a href=#1164 id=1164 data-nosnippet>1164</a> });
+<a href=#1165 id=1165 data-nosnippet>1165</a> <span class="kw">let </span>cipher = Arc::new(make_cipher(key));
+<a href=#1166 id=1166 data-nosnippet>1166</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = AesGcmFileWrite::new(inner, cipher, aad_prefix.to_vec());
+<a href=#1167 id=1167 data-nosnippet>1167</a>
+<a href=#1168 id=1168 data-nosnippet>1168</a> <span class="comment">// Write 1.5 blocks in 1000-byte chunks
+<a href=#1169 id=1169 data-nosnippet>1169</a> </span><span class="kw">let </span>total_size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize + PLAIN_BLOCK_SIZE <span class="kw">as </span>usize / <span class="number">2</span>;
+<a href=#1170 id=1170 data-nosnippet>1170</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..total_size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
+<a href=#1171 id=1171 data-nosnippet>1171</a> <span class="kw">let </span>chunk_size = <span class="number">1000</span>;
+<a href=#1172 id=1172 data-nosnippet>1172</a> <span class="kw">for </span>chunk <span class="kw">in </span>plaintext.chunks(chunk_size) {
+<a href=#1173 id=1173 data-nosnippet>1173</a> writer.write(Bytes::from(chunk.to_vec())).<span class="kw">await</span>.unwrap();
+<a href=#1174 id=1174 data-nosnippet>1174</a> }
+<a href=#1175 id=1175 data-nosnippet>1175</a> writer.close().<span class="kw">await</span>.unwrap();
+<a href=#1176 id=1176 data-nosnippet>1176</a>
+<a href=#1177 id=1177 data-nosnippet>1177</a> <span class="kw">let </span>encrypted = buffer.lock().unwrap().clone();
+<a href=#1178 id=1178 data-nosnippet>1178</a>
+<a href=#1179 id=1179 data-nosnippet>1179</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#1180 id=1180 data-nosnippet>1180</a> memory_reader(encrypted.clone()),
+<a href=#1181 id=1181 data-nosnippet>1181</a> Arc::new(make_cipher(key)),
+<a href=#1182 id=1182 data-nosnippet>1182</a> aad_prefix.as_slice().into(),
+<a href=#1183 id=1183 data-nosnippet>1183</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#1184 id=1184 data-nosnippet>1184</a> )
+<a href=#1185 id=1185 data-nosnippet>1185</a> .unwrap();
+<a href=#1186 id=1186 data-nosnippet>1186</a>
+<a href=#1187 id=1187 data-nosnippet>1187</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), plaintext.len() <span class="kw">as </span>u64);
+<a href=#1188 id=1188 data-nosnippet>1188</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..plaintext.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#1189 id=1189 data-nosnippet>1189</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#1190 id=1190 data-nosnippet>1190</a> }
+<a href=#1191 id=1191 data-nosnippet>1191</a>
+<a href=#1192 id=1192 data-nosnippet>1192</a> <span class="attr">#[tokio::test]
+<a href=#1193 id=1193 data-nosnippet>1193</a> </span><span class="kw">async fn </span>test_write_exact_block_size() {
+<a href=#1194 id=1194 data-nosnippet>1194</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#1195 id=1195 data-nosnippet>1195</a> <span class="kw">let </span>aad_prefix = <span class="string">b"exact-block-aad!"</span>;
<a href=#1196 id=1196 data-nosnippet>1196</a>
-<a href=#1197 id=1197 data-nosnippet>1197</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), size <span class="kw">as </span>u64);
-<a href=#1198 id=1198 data-nosnippet>1198</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..size <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#1199 id=1199 data-nosnippet>1199</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
-<a href=#1200 id=1200 data-nosnippet>1200</a> }
+<a href=#1197 id=1197 data-nosnippet>1197</a> <span class="comment">// Exactly 1 block
+<a href=#1198 id=1198 data-nosnippet>1198</a> </span><span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize)
+<a href=#1199 id=1199 data-nosnippet>1199</a> .map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8)
+<a href=#1200 id=1200 data-nosnippet>1200</a> .collect();
<a href=#1201 id=1201 data-nosnippet>1201</a>
-<a href=#1202 id=1202 data-nosnippet>1202</a> <span class="attr">#[tokio::test]
-<a href=#1203 id=1203 data-nosnippet>1203</a> </span><span class="kw">async fn </span>test_write_poisoned_after_inner_write_failure() {
-<a href=#1204 id=1204 data-nosnippet>1204</a> <span class="kw">let </span>cipher = Arc::new(make_cipher(<span class="string">b"0123456789abcdef"</span>));
-<a href=#1205 id=1205 data-nosnippet>1205</a> <span class="comment">// Fail on the second write (first write is the header, second is block data)
-<a href=#1206 id=1206 data-nosnippet>1206</a> </span><span class="kw">let </span>inner: Box<<span class="kw">dyn </span>FileWrite> = Box::new(FailingFileWrite {
-<a href=#1207 id=1207 data-nosnippet>1207</a> writes_before_failure: <span class="number">1</span>,
-<a href=#1208 id=1208 data-nosnippet>1208</a> write_count: <span class="number">0</span>,
-<a href=#1209 id=1209 data-nosnippet>1209</a> });
-<a href=#1210 id=1210 data-nosnippet>1210</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = AesGcmFileWrite::new(inner, cipher, <span class="string">b"aad-prefix-here!"</span>.to_vec());
+<a href=#1202 id=1202 data-nosnippet>1202</a> <span class="kw">let </span>encrypted = write_through_ags1(<span class="kw-2">&</span>plaintext, key, aad_prefix).<span class="kw">await</span>;
+<a href=#1203 id=1203 data-nosnippet>1203</a>
+<a href=#1204 id=1204 data-nosnippet>1204</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#1205 id=1205 data-nosnippet>1205</a> memory_reader(encrypted.clone()),
+<a href=#1206 id=1206 data-nosnippet>1206</a> Arc::new(make_cipher(key)),
+<a href=#1207 id=1207 data-nosnippet>1207</a> aad_prefix.as_slice().into(),
+<a href=#1208 id=1208 data-nosnippet>1208</a> encrypted.len() <span class="kw">as </span>u64,
+<a href=#1209 id=1209 data-nosnippet>1209</a> )
+<a href=#1210 id=1210 data-nosnippet>1210</a> .unwrap();
<a href=#1211 id=1211 data-nosnippet>1211</a>
-<a href=#1212 id=1212 data-nosnippet>1212</a> <span class="comment">// First write triggers header (succeeds) + block encrypt+write (fails)
-<a href=#1213 id=1213 data-nosnippet>1213</a> </span><span class="kw">let </span>data = <span class="macro">vec!</span>[<span class="number">0u8</span>; PLAIN_BLOCK_SIZE <span class="kw">as </span>usize];
-<a href=#1214 id=1214 data-nosnippet>1214</a> <span class="kw">let </span>result = writer.write(Bytes::from(data)).<span class="kw">await</span>;
-<a href=#1215 id=1215 data-nosnippet>1215</a> <span class="macro">assert!</span>(result.is_err());
+<a href=#1212 id=1212 data-nosnippet>1212</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), PLAIN_BLOCK_SIZE <span class="kw">as </span>u64);
+<a href=#1213 id=1213 data-nosnippet>1213</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#1214 id=1214 data-nosnippet>1214</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#1215 id=1215 data-nosnippet>1215</a> }
<a href=#1216 id=1216 data-nosnippet>1216</a>
-<a href=#1217 id=1217 data-nosnippet>1217</a> <span class="comment">// Subsequent write should be rejected as poisoned
-<a href=#1218 id=1218 data-nosnippet>1218</a> </span><span class="kw">let </span>result = writer.write(Bytes::from(<span class="string">b"more data"</span>.to_vec())).<span class="kw">await</span>;
-<a href=#1219 id=1219 data-nosnippet>1219</a> <span class="macro">assert!</span>(result.is_err());
-<a href=#1220 id=1220 data-nosnippet>1220</a> <span class="macro">assert!</span>(
-<a href=#1221 id=1221 data-nosnippet>1221</a> result.unwrap_err().to_string().contains(<span class="string">"poisoned"</span>),
-<a href=#1222 id=1222 data-nosnippet>1222</a> <span class="string">"expected poisoned error"
-<a href=#1223 id=1223 data-nosnippet>1223</a> </span>);
-<a href=#1224 id=1224 data-nosnippet>1224</a>
-<a href=#1225 id=1225 data-nosnippet>1225</a> <span class="comment">// Close should also be rejected
-<a href=#1226 id=1226 data-nosnippet>1226</a> </span><span class="kw">let </span>result = writer.close().<span class="kw">await</span>;
-<a href=#1227 id=1227 data-nosnippet>1227</a> <span class="macro">assert!</span>(result.is_err());
-<a href=#1228 id=1228 data-nosnippet>1228</a> <span class="macro">assert!</span>(
-<a href=#1229 id=1229 data-nosnippet>1229</a> result.unwrap_err().to_string().contains(<span class="string">"poisoned"</span>),
-<a href=#1230 id=1230 data-nosnippet>1230</a> <span class="string">"expected poisoned error on close"
-<a href=#1231 id=1231 data-nosnippet>1231</a> </span>);
-<a href=#1232 id=1232 data-nosnippet>1232</a> }
-<a href=#1233 id=1233 data-nosnippet>1233</a>}
+<a href=#1217 id=1217 data-nosnippet>1217</a> <span class="attr">#[tokio::test]
+<a href=#1218 id=1218 data-nosnippet>1218</a> </span><span class="kw">async fn </span>test_write_block_aligned_no_spurious_empty_block() {
+<a href=#1219 id=1219 data-nosnippet>1219</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#1220 id=1220 data-nosnippet>1220</a> <span class="kw">let </span>aad_prefix = <span class="string">b"block-align-aad!"</span>;
+<a href=#1221 id=1221 data-nosnippet>1221</a>
+<a href=#1222 id=1222 data-nosnippet>1222</a> <span class="comment">// Write exactly one block of plaintext — close() should NOT add
+<a href=#1223 id=1223 data-nosnippet>1223</a> // a trailing empty encrypted block (28 bytes: 12-byte nonce + 16-byte tag).
+<a href=#1224 id=1224 data-nosnippet>1224</a> </span><span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>usize)
+<a href=#1225 id=1225 data-nosnippet>1225</a> .map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8)
+<a href=#1226 id=1226 data-nosnippet>1226</a> .collect();
+<a href=#1227 id=1227 data-nosnippet>1227</a>
+<a href=#1228 id=1228 data-nosnippet>1228</a> <span class="kw">let </span>encrypted_via_writer = write_through_ags1(<span class="kw-2">&</span>plaintext, key, aad_prefix).<span class="kw">await</span>;
+<a href=#1229 id=1229 data-nosnippet>1229</a> <span class="kw">let </span>encrypted_via_reference = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>make_cipher(key), aad_prefix);
+<a href=#1230 id=1230 data-nosnippet>1230</a>
+<a href=#1231 id=1231 data-nosnippet>1231</a> <span class="comment">// Both should be the same length — no extra 28-byte empty block
+<a href=#1232 id=1232 data-nosnippet>1232</a> </span><span class="macro">assert_eq!</span>(
+<a href=#1233 id=1233 data-nosnippet>1233</a> encrypted_via_writer.len(),
+<a href=#1234 id=1234 data-nosnippet>1234</a> encrypted_via_reference.len(),
+<a href=#1235 id=1235 data-nosnippet>1235</a> <span class="string">"Writer output should match reference encryption length (no spurious trailing block)"
+<a href=#1236 id=1236 data-nosnippet>1236</a> </span>);
+<a href=#1237 id=1237 data-nosnippet>1237</a>
+<a href=#1238 id=1238 data-nosnippet>1238</a> <span class="comment">// Verify roundtrip
+<a href=#1239 id=1239 data-nosnippet>1239</a> </span><span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#1240 id=1240 data-nosnippet>1240</a> memory_reader(encrypted_via_writer.clone()),
+<a href=#1241 id=1241 data-nosnippet>1241</a> Arc::new(make_cipher(key)),
+<a href=#1242 id=1242 data-nosnippet>1242</a> aad_prefix.as_slice().into(),
+<a href=#1243 id=1243 data-nosnippet>1243</a> encrypted_via_writer.len() <span class="kw">as </span>u64,
+<a href=#1244 id=1244 data-nosnippet>1244</a> )
+<a href=#1245 id=1245 data-nosnippet>1245</a> .unwrap();
+<a href=#1246 id=1246 data-nosnippet>1246</a>
+<a href=#1247 id=1247 data-nosnippet>1247</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), PLAIN_BLOCK_SIZE <span class="kw">as </span>u64);
+<a href=#1248 id=1248 data-nosnippet>1248</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..PLAIN_BLOCK_SIZE <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#1249 id=1249 data-nosnippet>1249</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#1250 id=1250 data-nosnippet>1250</a> }
+<a href=#1251 id=1251 data-nosnippet>1251</a>
+<a href=#1252 id=1252 data-nosnippet>1252</a> <span class="attr">#[tokio::test]
+<a href=#1253 id=1253 data-nosnippet>1253</a> </span><span class="kw">async fn </span>test_write_two_blocks_aligned_no_spurious_empty_block() {
+<a href=#1254 id=1254 data-nosnippet>1254</a> <span class="kw">let </span>key = <span class="string">b"0123456789abcdef"</span>;
+<a href=#1255 id=1255 data-nosnippet>1255</a> <span class="kw">let </span>aad_prefix = <span class="string">b"2blk-align-aad!!"</span>;
+<a href=#1256 id=1256 data-nosnippet>1256</a>
+<a href=#1257 id=1257 data-nosnippet>1257</a> <span class="comment">// Exactly 2 blocks
+<a href=#1258 id=1258 data-nosnippet>1258</a> </span><span class="kw">let </span>size = PLAIN_BLOCK_SIZE <span class="kw">as </span>usize * <span class="number">2</span>;
+<a href=#1259 id=1259 data-nosnippet>1259</a> <span class="kw">let </span>plaintext: Vec<u8> = (<span class="number">0</span>..size).map(|i| (i % <span class="number">256</span>) <span class="kw">as </span>u8).collect();
+<a href=#1260 id=1260 data-nosnippet>1260</a>
+<a href=#1261 id=1261 data-nosnippet>1261</a> <span class="kw">let </span>encrypted_via_writer = write_through_ags1(<span class="kw-2">&</span>plaintext, key, aad_prefix).<span class="kw">await</span>;
+<a href=#1262 id=1262 data-nosnippet>1262</a> <span class="kw">let </span>encrypted_via_reference = encrypt_ags1(<span class="kw-2">&</span>plaintext, <span class="kw-2">&</span>make_cipher(key), aad_prefix);
+<a href=#1263 id=1263 data-nosnippet>1263</a>
+<a href=#1264 id=1264 data-nosnippet>1264</a> <span class="macro">assert_eq!</span>(
+<a href=#1265 id=1265 data-nosnippet>1265</a> encrypted_via_writer.len(),
+<a href=#1266 id=1266 data-nosnippet>1266</a> encrypted_via_reference.len(),
+<a href=#1267 id=1267 data-nosnippet>1267</a> <span class="string">"Writer output should match reference encryption length (no spurious trailing block)"
+<a href=#1268 id=1268 data-nosnippet>1268</a> </span>);
+<a href=#1269 id=1269 data-nosnippet>1269</a>
+<a href=#1270 id=1270 data-nosnippet>1270</a> <span class="kw">let </span>reader = AesGcmFileRead::new(
+<a href=#1271 id=1271 data-nosnippet>1271</a> memory_reader(encrypted_via_writer.clone()),
+<a href=#1272 id=1272 data-nosnippet>1272</a> Arc::new(make_cipher(key)),
+<a href=#1273 id=1273 data-nosnippet>1273</a> aad_prefix.as_slice().into(),
+<a href=#1274 id=1274 data-nosnippet>1274</a> encrypted_via_writer.len() <span class="kw">as </span>u64,
+<a href=#1275 id=1275 data-nosnippet>1275</a> )
+<a href=#1276 id=1276 data-nosnippet>1276</a> .unwrap();
+<a href=#1277 id=1277 data-nosnippet>1277</a>
+<a href=#1278 id=1278 data-nosnippet>1278</a> <span class="macro">assert_eq!</span>(reader.plaintext_length(), size <span class="kw">as </span>u64);
+<a href=#1279 id=1279 data-nosnippet>1279</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..size <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#1280 id=1280 data-nosnippet>1280</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>result[..], <span class="kw-2">&</span>plaintext[..]);
+<a href=#1281 id=1281 data-nosnippet>1281</a> }
+<a href=#1282 id=1282 data-nosnippet>1282</a>
+<a href=#1283 id=1283 data-nosnippet>1283</a> <span class="attr">#[tokio::test]
+<a href=#1284 id=1284 data-nosnippet>1284</a> </span><span class="kw">async fn </span>test_write_poisoned_after_inner_write_failure() {
+<a href=#1285 id=1285 data-nosnippet>1285</a> <span class="kw">let </span>cipher = Arc::new(make_cipher(<span class="string">b"0123456789abcdef"</span>));
+<a href=#1286 id=1286 data-nosnippet>1286</a> <span class="comment">// Fail on the second write (first write is the header, second is block data)
+<a href=#1287 id=1287 data-nosnippet>1287</a> </span><span class="kw">let </span>inner: Box<<span class="kw">dyn </span>FileWrite> = Box::new(FailingFileWrite {
+<a href=#1288 id=1288 data-nosnippet>1288</a> writes_before_failure: <span class="number">1</span>,
+<a href=#1289 id=1289 data-nosnippet>1289</a> write_count: <span class="number">0</span>,
+<a href=#1290 id=1290 data-nosnippet>1290</a> });
+<a href=#1291 id=1291 data-nosnippet>1291</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = AesGcmFileWrite::new(inner, cipher, <span class="string">b"aad-prefix-here!"</span>.to_vec());
+<a href=#1292 id=1292 data-nosnippet>1292</a>
+<a href=#1293 id=1293 data-nosnippet>1293</a> <span class="comment">// First write triggers header (succeeds) + block encrypt+write (fails)
+<a href=#1294 id=1294 data-nosnippet>1294</a> </span><span class="kw">let </span>data = <span class="macro">vec!</span>[<span class="number">0u8</span>; PLAIN_BLOCK_SIZE <span class="kw">as </span>usize];
+<a href=#1295 id=1295 data-nosnippet>1295</a> <span class="kw">let </span>result = writer.write(Bytes::from(data)).<span class="kw">await</span>;
+<a href=#1296 id=1296 data-nosnippet>1296</a> <span class="macro">assert!</span>(result.is_err());
+<a href=#1297 id=1297 data-nosnippet>1297</a>
+<a href=#1298 id=1298 data-nosnippet>1298</a> <span class="comment">// Subsequent write should be rejected as poisoned
+<a href=#1299 id=1299 data-nosnippet>1299</a> </span><span class="kw">let </span>result = writer.write(Bytes::from(<span class="string">b"more data"</span>.to_vec())).<span class="kw">await</span>;
+<a href=#1300 id=1300 data-nosnippet>1300</a> <span class="macro">assert!</span>(result.is_err());
+<a href=#1301 id=1301 data-nosnippet>1301</a> <span class="macro">assert!</span>(
+<a href=#1302 id=1302 data-nosnippet>1302</a> result.unwrap_err().to_string().contains(<span class="string">"poisoned"</span>),
+<a href=#1303 id=1303 data-nosnippet>1303</a> <span class="string">"expected poisoned error"
+<a href=#1304 id=1304 data-nosnippet>1304</a> </span>);
+<a href=#1305 id=1305 data-nosnippet>1305</a>
+<a href=#1306 id=1306 data-nosnippet>1306</a> <span class="comment">// Close should also be rejected
+<a href=#1307 id=1307 data-nosnippet>1307</a> </span><span class="kw">let </span>err = writer.close().<span class="kw">await</span>.err().expect(<span class="string">"close should fail"</span>);
+<a href=#1308 id=1308 data-nosnippet>1308</a> <span class="macro">assert!</span>(
+<a href=#1309 id=1309 data-nosnippet>1309</a> err.to_string().contains(<span class="string">"poisoned"</span>),
+<a href=#1310 id=1310 data-nosnippet>1310</a> <span class="string">"expected poisoned error on close"
+<a href=#1311 id=1311 data-nosnippet>1311</a> </span>);
+<a href=#1312 id=1312 data-nosnippet>1312</a> }
+<a href=#1313 id=1313 data-nosnippet>1313</a>}
</code></pre></div></section></main></body></html>
\ No newline at end of file
diff --git a/api/src/iceberg/io/file_io.rs.html b/api/src/iceberg/io/file_io.rs.html
index bc9c68bba..1e05eaf8a 100644
--- a/api/src/iceberg/io/file_io.rs.html
+++ b/api/src/iceberg/io/file_io.rs.html
@@ -375,10 +375,10 @@
<a href=#375 id=375 data-nosnippet>375</a> /// TODO: we can support writing non-contiguous bytes in the future.
<a href=#376 id=376 data-nosnippet>376</a> </span><span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><()>;
<a href=#377 id=377 data-nosnippet>377</a>
-<a href=#378 id=378 data-nosnippet>378</a> <span class="doccomment">/// Close file.
+<a href=#378 id=378 data-nosnippet>378</a> <span class="doccomment">/// Close the file and return its stored size, including encryption overhead for encrypted files.
<a href=#379 id=379 data-nosnippet>379</a> ///
<a href=#380 id=380 data-nosnippet>380</a> /// Calling close on closed file will generate an error.
-<a href=#381 id=381 data-nosnippet>381</a> </span><span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()>;
+<a href=#381 id=381 data-nosnippet>381</a> </span><span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><FileMetadata>;
<a href=#382 id=382 data-nosnippet>382</a>}
<a href=#383 id=383 data-nosnippet>383</a>
<a href=#384 id=384 data-nosnippet>384</a><span class="doccomment">/// Output file is used for writing to files..
diff --git a/api/src/iceberg/io/storage/local_fs.rs.html b/api/src/iceberg/io/storage/local_fs.rs.html
index cdc93db88..d0d636768 100644
--- a/api/src/iceberg/io/storage/local_fs.rs.html
+++ b/api/src/iceberg/io/storage/local_fs.rs.html
@@ -249,336 +249,344 @@
<a href=#249 id=249 data-nosnippet>249</a></span><span class="attr">#[derive(Debug)]
<a href=#250 id=250 data-nosnippet>250</a></span><span class="kw">pub struct </span>LocalFsFileWrite {
<a href=#251 id=251 data-nosnippet>251</a> file: <span class="prelude-ty">Option</span><fs::File>,
-<a href=#252 id=252 data-nosnippet>252</a>}
-<a href=#253 id=253 data-nosnippet>253</a>
-<a href=#254 id=254 data-nosnippet>254</a><span class="kw">impl </span>LocalFsFileWrite {
-<a href=#255 id=255 data-nosnippet>255</a> <span class="doccomment">/// Create a new `LocalFsFileWrite` for the given file.
-<a href=#256 id=256 data-nosnippet>256</a> </span><span class="kw">pub fn </span>new(file: fs::File) -> <span class="self">Self </span>{
-<a href=#257 id=257 data-nosnippet>257</a> <span class="self">Self </span>{ file: <span class="prelude-val">Some</span>(file) }
-<a href=#258 id=258 data-nosnippet>258</a> }
-<a href=#259 id=259 data-nosnippet>259</a>}
-<a href=#260 id=260 data-nosnippet>260</a>
-<a href=#261 id=261 data-nosnippet>261</a><span class="attr">#[async_trait]
-<a href=#262 id=262 data-nosnippet>262</a></span><span class="kw">impl </span>FileWrite <span class="kw">for </span>LocalFsFileWrite {
-<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
-<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">let </span>file = <span class="self">self
-<a href=#265 id=265 data-nosnippet>265</a> </span>.file
-<a href=#266 id=266 data-nosnippet>266</a> .as_mut()
-<a href=#267 id=267 data-nosnippet>267</a> .ok_or_else(|| <span class="macro">invalid_data!</span>(<span class="string">"Cannot write to closed file"</span>))<span class="question-mark">?</span>;
-<a href=#268 id=268 data-nosnippet>268</a>
-<a href=#269 id=269 data-nosnippet>269</a> file.write_all(<span class="kw-2">&</span>bs).map_err(|e| {
-<a href=#270 id=270 data-nosnippet>270</a> Error::new(
-<a href=#271 id=271 data-nosnippet>271</a> ErrorKind::Unexpected,
-<a href=#272 id=272 data-nosnippet>272</a> <span class="macro">format!</span>(<span class="string">"Failed to write to file: {e}"</span>),
-<a href=#273 id=273 data-nosnippet>273</a> )
-<a href=#274 id=274 data-nosnippet>274</a> })<span class="question-mark">?</span>;
-<a href=#275 id=275 data-nosnippet>275</a>
-<a href=#276 id=276 data-nosnippet>276</a> <span class="prelude-val">Ok</span>(())
-<a href=#277 id=277 data-nosnippet>277</a> }
-<a href=#278 id=278 data-nosnippet>278</a>
-<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
-<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">let </span>file = <span class="self">self
-<a href=#281 id=281 data-nosnippet>281</a> </span>.file
-<a href=#282 id=282 data-nosnippet>282</a> .take()
-<a href=#283 id=283 data-nosnippet>283</a> .ok_or_else(|| <span class="macro">invalid_data!</span>(<span class="string">"File already closed"</span>))<span class="question-mark">?</span>;
-<a href=#284 id=284 data-nosnippet>284</a>
-<a href=#285 id=285 data-nosnippet>285</a> file.sync_all()
-<a href=#286 id=286 data-nosnippet>286</a> .map_err(|e| Error::new(ErrorKind::Unexpected, <span class="macro">format!</span>(<span class="string">"Failed to sync file: {e}"</span>)))<span class="question-mark">?</span>;
-<a href=#287 id=287 data-nosnippet>287</a>
-<a href=#288 id=288 data-nosnippet>288</a> <span class="prelude-val">Ok</span>(())
-<a href=#289 id=289 data-nosnippet>289</a> }
-<a href=#290 id=290 data-nosnippet>290</a>}
-<a href=#291 id=291 data-nosnippet>291</a>
-<a href=#292 id=292 data-nosnippet>292</a><span class="doccomment">/// Factory for creating `LocalFsStorage` instances.
-<a href=#293 id=293 data-nosnippet>293</a>///
-<a href=#294 id=294 data-nosnippet>294</a>/// This factory implements `StorageFactory` and creates `LocalFsStorage`
-<a href=#295 id=295 data-nosnippet>295</a>/// instances for the "file" scheme.
-<a href=#296 id=296 data-nosnippet>296</a>///
-<a href=#297 id=297 data-nosnippet>297</a>/// # Example
-<a href=#298 id=298 data-nosnippet>298</a>///
-<a href=#299 id=299 data-nosnippet>299</a>/// ```rust,ignore
-<a href=#300 id=300 data-nosnippet>300</a>/// use iceberg::io::{StorageConfig, StorageFactory, LocalFsStorageFactory};
-<a href=#301 id=301 data-nosnippet>301</a>///
-<a href=#302 id=302 data-nosnippet>302</a>/// let factory = LocalFsStorageFactory;
-<a href=#303 id=303 data-nosnippet>303</a>/// let config = StorageConfig::new();
-<a href=#304 id=304 data-nosnippet>304</a>/// let storage = factory.build(&config)?;
-<a href=#305 id=305 data-nosnippet>305</a>/// ```
-<a href=#306 id=306 data-nosnippet>306</a></span><span class="attr">#[derive(Clone, Debug, Default, Serialize, Deserialize)]
-<a href=#307 id=307 data-nosnippet>307</a></span><span class="kw">pub struct </span>LocalFsStorageFactory;
-<a href=#308 id=308 data-nosnippet>308</a>
-<a href=#309 id=309 data-nosnippet>309</a><span class="attr">#[typetag::serde]
-<a href=#310 id=310 data-nosnippet>310</a></span><span class="kw">impl </span>StorageFactory <span class="kw">for </span>LocalFsStorageFactory {
-<a href=#311 id=311 data-nosnippet>311</a> <span class="kw">fn </span>build(<span class="kw-2">&</span><span class="self">self</span>, _config: <span class="kw-2">&</span>StorageConfig) -> <span class="prelude-ty">Result</span><Arc<<span class="kw">dyn </span>Storage>> {
-<a href=#312 id=312 data-nosnippet>312</a> <span class="prelude-val">Ok</span>(Arc::new(LocalFsStorage::new()))
-<a href=#313 id=313 data-nosnippet>313</a> }
-<a href=#314 id=314 data-nosnippet>314</a>}
+<a href=#252 id=252 data-nosnippet>252</a> bytes_written: u64,
+<a href=#253 id=253 data-nosnippet>253</a>}
+<a href=#254 id=254 data-nosnippet>254</a>
+<a href=#255 id=255 data-nosnippet>255</a><span class="kw">impl </span>LocalFsFileWrite {
+<a href=#256 id=256 data-nosnippet>256</a> <span class="doccomment">/// Create a new `LocalFsFileWrite` for the given file.
+<a href=#257 id=257 data-nosnippet>257</a> </span><span class="kw">pub fn </span>new(file: fs::File) -> <span class="self">Self </span>{
+<a href=#258 id=258 data-nosnippet>258</a> <span class="self">Self </span>{
+<a href=#259 id=259 data-nosnippet>259</a> file: <span class="prelude-val">Some</span>(file),
+<a href=#260 id=260 data-nosnippet>260</a> bytes_written: <span class="number">0</span>,
+<a href=#261 id=261 data-nosnippet>261</a> }
+<a href=#262 id=262 data-nosnippet>262</a> }
+<a href=#263 id=263 data-nosnippet>263</a>}
+<a href=#264 id=264 data-nosnippet>264</a>
+<a href=#265 id=265 data-nosnippet>265</a><span class="attr">#[async_trait]
+<a href=#266 id=266 data-nosnippet>266</a></span><span class="kw">impl </span>FileWrite <span class="kw">for </span>LocalFsFileWrite {
+<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">async fn </span>write(<span class="kw-2">&mut </span><span class="self">self</span>, bs: Bytes) -> <span class="prelude-ty">Result</span><()> {
+<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">let </span>file = <span class="self">self
+<a href=#269 id=269 data-nosnippet>269</a> </span>.file
+<a href=#270 id=270 data-nosnippet>270</a> .as_mut()
+<a href=#271 id=271 data-nosnippet>271</a> .ok_or_else(|| <span class="macro">invalid_data!</span>(<span class="string">"Cannot write to closed file"</span>))<span class="question-mark">?</span>;
+<a href=#272 id=272 data-nosnippet>272</a>
+<a href=#273 id=273 data-nosnippet>273</a> file.write_all(<span class="kw-2">&</span>bs).map_err(|e| {
+<a href=#274 id=274 data-nosnippet>274</a> Error::new(
+<a href=#275 id=275 data-nosnippet>275</a> ErrorKind::Unexpected,
+<a href=#276 id=276 data-nosnippet>276</a> <span class="macro">format!</span>(<span class="string">"Failed to write to file: {e}"</span>),
+<a href=#277 id=277 data-nosnippet>277</a> )
+<a href=#278 id=278 data-nosnippet>278</a> })<span class="question-mark">?</span>;
+<a href=#279 id=279 data-nosnippet>279</a> <span class="self">self</span>.bytes_written += bs.len() <span class="kw">as </span>u64;
+<a href=#280 id=280 data-nosnippet>280</a>
+<a href=#281 id=281 data-nosnippet>281</a> <span class="prelude-val">Ok</span>(())
+<a href=#282 id=282 data-nosnippet>282</a> }
+<a href=#283 id=283 data-nosnippet>283</a>
+<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><FileMetadata> {
+<a href=#285 id=285 data-nosnippet>285</a> <span class="kw">let </span>file = <span class="self">self
+<a href=#286 id=286 data-nosnippet>286</a> </span>.file
+<a href=#287 id=287 data-nosnippet>287</a> .take()
+<a href=#288 id=288 data-nosnippet>288</a> .ok_or_else(|| <span class="macro">invalid_data!</span>(<span class="string">"File already closed"</span>))<span class="question-mark">?</span>;
+<a href=#289 id=289 data-nosnippet>289</a>
+<a href=#290 id=290 data-nosnippet>290</a> file.sync_all()
+<a href=#291 id=291 data-nosnippet>291</a> .map_err(|e| Error::new(ErrorKind::Unexpected, <span class="macro">format!</span>(<span class="string">"Failed to sync file: {e}"</span>)))<span class="question-mark">?</span>;
+<a href=#292 id=292 data-nosnippet>292</a>
+<a href=#293 id=293 data-nosnippet>293</a> <span class="prelude-val">Ok</span>(FileMetadata {
+<a href=#294 id=294 data-nosnippet>294</a> size: <span class="self">self</span>.bytes_written,
+<a href=#295 id=295 data-nosnippet>295</a> })
+<a href=#296 id=296 data-nosnippet>296</a> }
+<a href=#297 id=297 data-nosnippet>297</a>}
+<a href=#298 id=298 data-nosnippet>298</a>
+<a href=#299 id=299 data-nosnippet>299</a><span class="doccomment">/// Factory for creating `LocalFsStorage` instances.
+<a href=#300 id=300 data-nosnippet>300</a>///
+<a href=#301 id=301 data-nosnippet>301</a>/// This factory implements `StorageFactory` and creates `LocalFsStorage`
+<a href=#302 id=302 data-nosnippet>302</a>/// instances for the "file" scheme.
+<a href=#303 id=303 data-nosnippet>303</a>///
+<a href=#304 id=304 data-nosnippet>304</a>/// # Example
+<a href=#305 id=305 data-nosnippet>305</a>///
+<a href=#306 id=306 data-nosnippet>306</a>/// ```rust,ignore
+<a href=#307 id=307 data-nosnippet>307</a>/// use iceberg::io::{StorageConfig, StorageFactory, LocalFsStorageFactory};
+<a href=#308 id=308 data-nosnippet>308</a>///
+<a href=#309 id=309 data-nosnippet>309</a>/// let factory = LocalFsStorageFactory;
+<a href=#310 id=310 data-nosnippet>310</a>/// let config = StorageConfig::new();
+<a href=#311 id=311 data-nosnippet>311</a>/// let storage = factory.build(&config)?;
+<a href=#312 id=312 data-nosnippet>312</a>/// ```
+<a href=#313 id=313 data-nosnippet>313</a></span><span class="attr">#[derive(Clone, Debug, Default, Serialize, Deserialize)]
+<a href=#314 id=314 data-nosnippet>314</a></span><span class="kw">pub struct </span>LocalFsStorageFactory;
<a href=#315 id=315 data-nosnippet>315</a>
-<a href=#316 id=316 data-nosnippet>316</a><span class="attr">#[cfg(test)]
-<a href=#317 id=317 data-nosnippet>317</a></span><span class="kw">mod </span>tests {
-<a href=#318 id=318 data-nosnippet>318</a> <span class="kw">use </span>tempfile::TempDir;
-<a href=#319 id=319 data-nosnippet>319</a>
-<a href=#320 id=320 data-nosnippet>320</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
-<a href=#321 id=321 data-nosnippet>321</a>
-<a href=#322 id=322 data-nosnippet>322</a> <span class="attr">#[test]
-<a href=#323 id=323 data-nosnippet>323</a> </span><span class="kw">fn </span>test_normalize_path() {
-<a href=#324 id=324 data-nosnippet>324</a> <span class="comment">// Test file:/// prefix
-<a href=#325 id=325 data-nosnippet>325</a> </span><span class="macro">assert_eq!</span>(
-<a href=#326 id=326 data-nosnippet>326</a> LocalFsStorage::normalize_path(<span class="string">"file:///path/to/file"</span>),
-<a href=#327 id=327 data-nosnippet>327</a> PathBuf::from(<span class="string">"/path/to/file"</span>)
-<a href=#328 id=328 data-nosnippet>328</a> );
-<a href=#329 id=329 data-nosnippet>329</a>
-<a href=#330 id=330 data-nosnippet>330</a> <span class="comment">// Test file:// prefix (without leading slash in path)
-<a href=#331 id=331 data-nosnippet>331</a> </span><span class="macro">assert_eq!</span>(
-<a href=#332 id=332 data-nosnippet>332</a> LocalFsStorage::normalize_path(<span class="string">"file://path/to/file"</span>),
-<a href=#333 id=333 data-nosnippet>333</a> PathBuf::from(<span class="string">"/path/to/file"</span>)
-<a href=#334 id=334 data-nosnippet>334</a> );
-<a href=#335 id=335 data-nosnippet>335</a>
-<a href=#336 id=336 data-nosnippet>336</a> <span class="comment">// Test file:/ prefix
-<a href=#337 id=337 data-nosnippet>337</a> </span><span class="macro">assert_eq!</span>(
-<a href=#338 id=338 data-nosnippet>338</a> LocalFsStorage::normalize_path(<span class="string">"file:/path/to/file"</span>),
-<a href=#339 id=339 data-nosnippet>339</a> PathBuf::from(<span class="string">"/path/to/file"</span>)
-<a href=#340 id=340 data-nosnippet>340</a> );
-<a href=#341 id=341 data-nosnippet>341</a>
-<a href=#342 id=342 data-nosnippet>342</a> <span class="comment">// Test bare path
-<a href=#343 id=343 data-nosnippet>343</a> </span><span class="macro">assert_eq!</span>(
-<a href=#344 id=344 data-nosnippet>344</a> LocalFsStorage::normalize_path(<span class="string">"/path/to/file"</span>),
-<a href=#345 id=345 data-nosnippet>345</a> PathBuf::from(<span class="string">"/path/to/file"</span>)
-<a href=#346 id=346 data-nosnippet>346</a> );
-<a href=#347 id=347 data-nosnippet>347</a> }
+<a href=#316 id=316 data-nosnippet>316</a><span class="attr">#[typetag::serde]
+<a href=#317 id=317 data-nosnippet>317</a></span><span class="kw">impl </span>StorageFactory <span class="kw">for </span>LocalFsStorageFactory {
+<a href=#318 id=318 data-nosnippet>318</a> <span class="kw">fn </span>build(<span class="kw-2">&</span><span class="self">self</span>, _config: <span class="kw-2">&</span>StorageConfig) -> <span class="prelude-ty">Result</span><Arc<<span class="kw">dyn </span>Storage>> {
+<a href=#319 id=319 data-nosnippet>319</a> <span class="prelude-val">Ok</span>(Arc::new(LocalFsStorage::new()))
+<a href=#320 id=320 data-nosnippet>320</a> }
+<a href=#321 id=321 data-nosnippet>321</a>}
+<a href=#322 id=322 data-nosnippet>322</a>
+<a href=#323 id=323 data-nosnippet>323</a><span class="attr">#[cfg(test)]
+<a href=#324 id=324 data-nosnippet>324</a></span><span class="kw">mod </span>tests {
+<a href=#325 id=325 data-nosnippet>325</a> <span class="kw">use </span>tempfile::TempDir;
+<a href=#326 id=326 data-nosnippet>326</a>
+<a href=#327 id=327 data-nosnippet>327</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
+<a href=#328 id=328 data-nosnippet>328</a>
+<a href=#329 id=329 data-nosnippet>329</a> <span class="attr">#[test]
+<a href=#330 id=330 data-nosnippet>330</a> </span><span class="kw">fn </span>test_normalize_path() {
+<a href=#331 id=331 data-nosnippet>331</a> <span class="comment">// Test file:/// prefix
+<a href=#332 id=332 data-nosnippet>332</a> </span><span class="macro">assert_eq!</span>(
+<a href=#333 id=333 data-nosnippet>333</a> LocalFsStorage::normalize_path(<span class="string">"file:///path/to/file"</span>),
+<a href=#334 id=334 data-nosnippet>334</a> PathBuf::from(<span class="string">"/path/to/file"</span>)
+<a href=#335 id=335 data-nosnippet>335</a> );
+<a href=#336 id=336 data-nosnippet>336</a>
+<a href=#337 id=337 data-nosnippet>337</a> <span class="comment">// Test file:// prefix (without leading slash in path)
+<a href=#338 id=338 data-nosnippet>338</a> </span><span class="macro">assert_eq!</span>(
+<a href=#339 id=339 data-nosnippet>339</a> LocalFsStorage::normalize_path(<span class="string">"file://path/to/file"</span>),
+<a href=#340 id=340 data-nosnippet>340</a> PathBuf::from(<span class="string">"/path/to/file"</span>)
+<a href=#341 id=341 data-nosnippet>341</a> );
+<a href=#342 id=342 data-nosnippet>342</a>
+<a href=#343 id=343 data-nosnippet>343</a> <span class="comment">// Test file:/ prefix
+<a href=#344 id=344 data-nosnippet>344</a> </span><span class="macro">assert_eq!</span>(
+<a href=#345 id=345 data-nosnippet>345</a> LocalFsStorage::normalize_path(<span class="string">"file:/path/to/file"</span>),
+<a href=#346 id=346 data-nosnippet>346</a> PathBuf::from(<span class="string">"/path/to/file"</span>)
+<a href=#347 id=347 data-nosnippet>347</a> );
<a href=#348 id=348 data-nosnippet>348</a>
-<a href=#349 id=349 data-nosnippet>349</a> <span class="attr">#[tokio::test]
-<a href=#350 id=350 data-nosnippet>350</a> </span><span class="kw">async fn </span>test_local_fs_storage_write_read() {
-<a href=#351 id=351 data-nosnippet>351</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#352 id=352 data-nosnippet>352</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#353 id=353 data-nosnippet>353</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
-<a href=#354 id=354 data-nosnippet>354</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
-<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
-<a href=#356 id=356 data-nosnippet>356</a>
-<a href=#357 id=357 data-nosnippet>357</a> <span class="comment">// Write
-<a href=#358 id=358 data-nosnippet>358</a> </span>storage.write(path_str, content.clone()).<span class="kw">await</span>.unwrap();
-<a href=#359 id=359 data-nosnippet>359</a>
-<a href=#360 id=360 data-nosnippet>360</a> <span class="comment">// Read
-<a href=#361 id=361 data-nosnippet>361</a> </span><span class="kw">let </span>read_content = storage.read(path_str).<span class="kw">await</span>.unwrap();
-<a href=#362 id=362 data-nosnippet>362</a> <span class="macro">assert_eq!</span>(read_content, content);
-<a href=#363 id=363 data-nosnippet>363</a> }
-<a href=#364 id=364 data-nosnippet>364</a>
-<a href=#365 id=365 data-nosnippet>365</a> <span class="attr">#[tokio::test]
-<a href=#366 id=366 data-nosnippet>366</a> </span><span class="kw">async fn </span>test_local_fs_storage_exists() {
-<a href=#367 id=367 data-nosnippet>367</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#368 id=368 data-nosnippet>368</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#369 id=369 data-nosnippet>369</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
-<a href=#370 id=370 data-nosnippet>370</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#349 id=349 data-nosnippet>349</a> <span class="comment">// Test bare path
+<a href=#350 id=350 data-nosnippet>350</a> </span><span class="macro">assert_eq!</span>(
+<a href=#351 id=351 data-nosnippet>351</a> LocalFsStorage::normalize_path(<span class="string">"/path/to/file"</span>),
+<a href=#352 id=352 data-nosnippet>352</a> PathBuf::from(<span class="string">"/path/to/file"</span>)
+<a href=#353 id=353 data-nosnippet>353</a> );
+<a href=#354 id=354 data-nosnippet>354</a> }
+<a href=#355 id=355 data-nosnippet>355</a>
+<a href=#356 id=356 data-nosnippet>356</a> <span class="attr">#[tokio::test]
+<a href=#357 id=357 data-nosnippet>357</a> </span><span class="kw">async fn </span>test_local_fs_storage_write_read() {
+<a href=#358 id=358 data-nosnippet>358</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#359 id=359 data-nosnippet>359</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#360 id=360 data-nosnippet>360</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
+<a href=#361 id=361 data-nosnippet>361</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#362 id=362 data-nosnippet>362</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
+<a href=#363 id=363 data-nosnippet>363</a>
+<a href=#364 id=364 data-nosnippet>364</a> <span class="comment">// Write
+<a href=#365 id=365 data-nosnippet>365</a> </span>storage.write(path_str, content.clone()).<span class="kw">await</span>.unwrap();
+<a href=#366 id=366 data-nosnippet>366</a>
+<a href=#367 id=367 data-nosnippet>367</a> <span class="comment">// Read
+<a href=#368 id=368 data-nosnippet>368</a> </span><span class="kw">let </span>read_content = storage.read(path_str).<span class="kw">await</span>.unwrap();
+<a href=#369 id=369 data-nosnippet>369</a> <span class="macro">assert_eq!</span>(read_content, content);
+<a href=#370 id=370 data-nosnippet>370</a> }
<a href=#371 id=371 data-nosnippet>371</a>
-<a href=#372 id=372 data-nosnippet>372</a> <span class="comment">// File doesn't exist initially
-<a href=#373 id=373 data-nosnippet>373</a> </span><span class="macro">assert!</span>(!storage.exists(path_str).<span class="kw">await</span>.unwrap());
-<a href=#374 id=374 data-nosnippet>374</a>
-<a href=#375 id=375 data-nosnippet>375</a> <span class="comment">// Write file
-<a href=#376 id=376 data-nosnippet>376</a> </span>storage.write(path_str, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#377 id=377 data-nosnippet>377</a>
-<a href=#378 id=378 data-nosnippet>378</a> <span class="comment">// File exists now
-<a href=#379 id=379 data-nosnippet>379</a> </span><span class="macro">assert!</span>(storage.exists(path_str).<span class="kw">await</span>.unwrap());
-<a href=#380 id=380 data-nosnippet>380</a> }
+<a href=#372 id=372 data-nosnippet>372</a> <span class="attr">#[tokio::test]
+<a href=#373 id=373 data-nosnippet>373</a> </span><span class="kw">async fn </span>test_local_fs_storage_exists() {
+<a href=#374 id=374 data-nosnippet>374</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#375 id=375 data-nosnippet>375</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#376 id=376 data-nosnippet>376</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
+<a href=#377 id=377 data-nosnippet>377</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#378 id=378 data-nosnippet>378</a>
+<a href=#379 id=379 data-nosnippet>379</a> <span class="comment">// File doesn't exist initially
+<a href=#380 id=380 data-nosnippet>380</a> </span><span class="macro">assert!</span>(!storage.exists(path_str).<span class="kw">await</span>.unwrap());
<a href=#381 id=381 data-nosnippet>381</a>
-<a href=#382 id=382 data-nosnippet>382</a> <span class="attr">#[tokio::test]
-<a href=#383 id=383 data-nosnippet>383</a> </span><span class="kw">async fn </span>test_local_fs_storage_metadata() {
-<a href=#384 id=384 data-nosnippet>384</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#385 id=385 data-nosnippet>385</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#386 id=386 data-nosnippet>386</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
-<a href=#387 id=387 data-nosnippet>387</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
-<a href=#388 id=388 data-nosnippet>388</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
-<a href=#389 id=389 data-nosnippet>389</a>
-<a href=#390 id=390 data-nosnippet>390</a> storage.write(path_str, content.clone()).<span class="kw">await</span>.unwrap();
-<a href=#391 id=391 data-nosnippet>391</a>
-<a href=#392 id=392 data-nosnippet>392</a> <span class="kw">let </span>metadata = storage.metadata(path_str).<span class="kw">await</span>.unwrap();
-<a href=#393 id=393 data-nosnippet>393</a> <span class="macro">assert_eq!</span>(metadata.size, content.len() <span class="kw">as </span>u64);
-<a href=#394 id=394 data-nosnippet>394</a> }
-<a href=#395 id=395 data-nosnippet>395</a>
-<a href=#396 id=396 data-nosnippet>396</a> <span class="attr">#[tokio::test]
-<a href=#397 id=397 data-nosnippet>397</a> </span><span class="kw">async fn </span>test_local_fs_storage_delete() {
-<a href=#398 id=398 data-nosnippet>398</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#399 id=399 data-nosnippet>399</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#400 id=400 data-nosnippet>400</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
-<a href=#401 id=401 data-nosnippet>401</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#382 id=382 data-nosnippet>382</a> <span class="comment">// Write file
+<a href=#383 id=383 data-nosnippet>383</a> </span>storage.write(path_str, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#384 id=384 data-nosnippet>384</a>
+<a href=#385 id=385 data-nosnippet>385</a> <span class="comment">// File exists now
+<a href=#386 id=386 data-nosnippet>386</a> </span><span class="macro">assert!</span>(storage.exists(path_str).<span class="kw">await</span>.unwrap());
+<a href=#387 id=387 data-nosnippet>387</a> }
+<a href=#388 id=388 data-nosnippet>388</a>
+<a href=#389 id=389 data-nosnippet>389</a> <span class="attr">#[tokio::test]
+<a href=#390 id=390 data-nosnippet>390</a> </span><span class="kw">async fn </span>test_local_fs_storage_metadata() {
+<a href=#391 id=391 data-nosnippet>391</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#392 id=392 data-nosnippet>392</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#393 id=393 data-nosnippet>393</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
+<a href=#394 id=394 data-nosnippet>394</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
+<a href=#396 id=396 data-nosnippet>396</a>
+<a href=#397 id=397 data-nosnippet>397</a> storage.write(path_str, content.clone()).<span class="kw">await</span>.unwrap();
+<a href=#398 id=398 data-nosnippet>398</a>
+<a href=#399 id=399 data-nosnippet>399</a> <span class="kw">let </span>metadata = storage.metadata(path_str).<span class="kw">await</span>.unwrap();
+<a href=#400 id=400 data-nosnippet>400</a> <span class="macro">assert_eq!</span>(metadata.size, content.len() <span class="kw">as </span>u64);
+<a href=#401 id=401 data-nosnippet>401</a> }
<a href=#402 id=402 data-nosnippet>402</a>
-<a href=#403 id=403 data-nosnippet>403</a> storage.write(path_str, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#404 id=404 data-nosnippet>404</a> <span class="macro">assert!</span>(storage.exists(path_str).<span class="kw">await</span>.unwrap());
-<a href=#405 id=405 data-nosnippet>405</a>
-<a href=#406 id=406 data-nosnippet>406</a> storage.delete(path_str).<span class="kw">await</span>.unwrap();
-<a href=#407 id=407 data-nosnippet>407</a> <span class="macro">assert!</span>(!storage.exists(path_str).<span class="kw">await</span>.unwrap());
-<a href=#408 id=408 data-nosnippet>408</a> }
+<a href=#403 id=403 data-nosnippet>403</a> <span class="attr">#[tokio::test]
+<a href=#404 id=404 data-nosnippet>404</a> </span><span class="kw">async fn </span>test_local_fs_storage_delete() {
+<a href=#405 id=405 data-nosnippet>405</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#406 id=406 data-nosnippet>406</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#407 id=407 data-nosnippet>407</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
+<a href=#408 id=408 data-nosnippet>408</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
<a href=#409 id=409 data-nosnippet>409</a>
-<a href=#410 id=410 data-nosnippet>410</a> <span class="attr">#[tokio::test]
-<a href=#411 id=411 data-nosnippet>411</a> </span><span class="kw">async fn </span>test_local_fs_storage_delete_prefix() {
-<a href=#412 id=412 data-nosnippet>412</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#413 id=413 data-nosnippet>413</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#414 id=414 data-nosnippet>414</a> <span class="kw">let </span>dir_path = tmp_dir.path().join(<span class="string">"subdir"</span>);
-<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">let </span>file1 = dir_path.join(<span class="string">"file1.txt"</span>);
-<a href=#416 id=416 data-nosnippet>416</a> <span class="kw">let </span>file2 = dir_path.join(<span class="string">"file2.txt"</span>);
-<a href=#417 id=417 data-nosnippet>417</a>
-<a href=#418 id=418 data-nosnippet>418</a> <span class="comment">// Create files in subdirectory
-<a href=#419 id=419 data-nosnippet>419</a> </span>storage
-<a href=#420 id=420 data-nosnippet>420</a> .write(file1.to_str().unwrap(), Bytes::from(<span class="string">"1"</span>))
-<a href=#421 id=421 data-nosnippet>421</a> .<span class="kw">await
-<a href=#422 id=422 data-nosnippet>422</a> </span>.unwrap();
-<a href=#423 id=423 data-nosnippet>423</a> storage
-<a href=#424 id=424 data-nosnippet>424</a> .write(file2.to_str().unwrap(), Bytes::from(<span class="string">"2"</span>))
-<a href=#425 id=425 data-nosnippet>425</a> .<span class="kw">await
-<a href=#426 id=426 data-nosnippet>426</a> </span>.unwrap();
-<a href=#427 id=427 data-nosnippet>427</a>
-<a href=#428 id=428 data-nosnippet>428</a> <span class="comment">// Delete prefix (directory)
-<a href=#429 id=429 data-nosnippet>429</a> </span>storage
-<a href=#430 id=430 data-nosnippet>430</a> .delete_prefix(dir_path.to_str().unwrap())
-<a href=#431 id=431 data-nosnippet>431</a> .<span class="kw">await
-<a href=#432 id=432 data-nosnippet>432</a> </span>.unwrap();
-<a href=#433 id=433 data-nosnippet>433</a>
-<a href=#434 id=434 data-nosnippet>434</a> <span class="comment">// Directory should be deleted
-<a href=#435 id=435 data-nosnippet>435</a> </span><span class="macro">assert!</span>(!dir_path.exists());
-<a href=#436 id=436 data-nosnippet>436</a> }
-<a href=#437 id=437 data-nosnippet>437</a>
-<a href=#438 id=438 data-nosnippet>438</a> <span class="attr">#[tokio::test]
-<a href=#439 id=439 data-nosnippet>439</a> </span><span class="kw">async fn </span>test_local_fs_storage_reader() {
-<a href=#440 id=440 data-nosnippet>440</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#441 id=441 data-nosnippet>441</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#442 id=442 data-nosnippet>442</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
-<a href=#443 id=443 data-nosnippet>443</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
-<a href=#444 id=444 data-nosnippet>444</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
-<a href=#445 id=445 data-nosnippet>445</a>
-<a href=#446 id=446 data-nosnippet>446</a> storage.write(path_str, content.clone()).<span class="kw">await</span>.unwrap();
-<a href=#447 id=447 data-nosnippet>447</a>
-<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">let </span>reader = storage.reader(path_str).<span class="kw">await</span>.unwrap();
-<a href=#449 id=449 data-nosnippet>449</a> <span class="kw">let </span>read_content = reader.read(<span class="number">0</span>..content.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#450 id=450 data-nosnippet>450</a> <span class="macro">assert_eq!</span>(read_content, content);
-<a href=#451 id=451 data-nosnippet>451</a>
-<a href=#452 id=452 data-nosnippet>452</a> <span class="comment">// Test partial read
-<a href=#453 id=453 data-nosnippet>453</a> </span><span class="kw">let </span>partial = reader.read(<span class="number">0</span>..<span class="number">5</span>).<span class="kw">await</span>.unwrap();
-<a href=#454 id=454 data-nosnippet>454</a> <span class="macro">assert_eq!</span>(partial, Bytes::from(<span class="string">"Hello"</span>));
-<a href=#455 id=455 data-nosnippet>455</a> }
-<a href=#456 id=456 data-nosnippet>456</a>
-<a href=#457 id=457 data-nosnippet>457</a> <span class="attr">#[tokio::test]
-<a href=#458 id=458 data-nosnippet>458</a> </span><span class="kw">async fn </span>test_local_fs_storage_writer() {
-<a href=#459 id=459 data-nosnippet>459</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#460 id=460 data-nosnippet>460</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#461 id=461 data-nosnippet>461</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
-<a href=#462 id=462 data-nosnippet>462</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#410 id=410 data-nosnippet>410</a> storage.write(path_str, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#411 id=411 data-nosnippet>411</a> <span class="macro">assert!</span>(storage.exists(path_str).<span class="kw">await</span>.unwrap());
+<a href=#412 id=412 data-nosnippet>412</a>
+<a href=#413 id=413 data-nosnippet>413</a> storage.delete(path_str).<span class="kw">await</span>.unwrap();
+<a href=#414 id=414 data-nosnippet>414</a> <span class="macro">assert!</span>(!storage.exists(path_str).<span class="kw">await</span>.unwrap());
+<a href=#415 id=415 data-nosnippet>415</a> }
+<a href=#416 id=416 data-nosnippet>416</a>
+<a href=#417 id=417 data-nosnippet>417</a> <span class="attr">#[tokio::test]
+<a href=#418 id=418 data-nosnippet>418</a> </span><span class="kw">async fn </span>test_local_fs_storage_delete_prefix() {
+<a href=#419 id=419 data-nosnippet>419</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#420 id=420 data-nosnippet>420</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#421 id=421 data-nosnippet>421</a> <span class="kw">let </span>dir_path = tmp_dir.path().join(<span class="string">"subdir"</span>);
+<a href=#422 id=422 data-nosnippet>422</a> <span class="kw">let </span>file1 = dir_path.join(<span class="string">"file1.txt"</span>);
+<a href=#423 id=423 data-nosnippet>423</a> <span class="kw">let </span>file2 = dir_path.join(<span class="string">"file2.txt"</span>);
+<a href=#424 id=424 data-nosnippet>424</a>
+<a href=#425 id=425 data-nosnippet>425</a> <span class="comment">// Create files in subdirectory
+<a href=#426 id=426 data-nosnippet>426</a> </span>storage
+<a href=#427 id=427 data-nosnippet>427</a> .write(file1.to_str().unwrap(), Bytes::from(<span class="string">"1"</span>))
+<a href=#428 id=428 data-nosnippet>428</a> .<span class="kw">await
+<a href=#429 id=429 data-nosnippet>429</a> </span>.unwrap();
+<a href=#430 id=430 data-nosnippet>430</a> storage
+<a href=#431 id=431 data-nosnippet>431</a> .write(file2.to_str().unwrap(), Bytes::from(<span class="string">"2"</span>))
+<a href=#432 id=432 data-nosnippet>432</a> .<span class="kw">await
+<a href=#433 id=433 data-nosnippet>433</a> </span>.unwrap();
+<a href=#434 id=434 data-nosnippet>434</a>
+<a href=#435 id=435 data-nosnippet>435</a> <span class="comment">// Delete prefix (directory)
+<a href=#436 id=436 data-nosnippet>436</a> </span>storage
+<a href=#437 id=437 data-nosnippet>437</a> .delete_prefix(dir_path.to_str().unwrap())
+<a href=#438 id=438 data-nosnippet>438</a> .<span class="kw">await
+<a href=#439 id=439 data-nosnippet>439</a> </span>.unwrap();
+<a href=#440 id=440 data-nosnippet>440</a>
+<a href=#441 id=441 data-nosnippet>441</a> <span class="comment">// Directory should be deleted
+<a href=#442 id=442 data-nosnippet>442</a> </span><span class="macro">assert!</span>(!dir_path.exists());
+<a href=#443 id=443 data-nosnippet>443</a> }
+<a href=#444 id=444 data-nosnippet>444</a>
+<a href=#445 id=445 data-nosnippet>445</a> <span class="attr">#[tokio::test]
+<a href=#446 id=446 data-nosnippet>446</a> </span><span class="kw">async fn </span>test_local_fs_storage_reader() {
+<a href=#447 id=447 data-nosnippet>447</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#449 id=449 data-nosnippet>449</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
+<a href=#450 id=450 data-nosnippet>450</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#451 id=451 data-nosnippet>451</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
+<a href=#452 id=452 data-nosnippet>452</a>
+<a href=#453 id=453 data-nosnippet>453</a> storage.write(path_str, content.clone()).<span class="kw">await</span>.unwrap();
+<a href=#454 id=454 data-nosnippet>454</a>
+<a href=#455 id=455 data-nosnippet>455</a> <span class="kw">let </span>reader = storage.reader(path_str).<span class="kw">await</span>.unwrap();
+<a href=#456 id=456 data-nosnippet>456</a> <span class="kw">let </span>read_content = reader.read(<span class="number">0</span>..content.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#457 id=457 data-nosnippet>457</a> <span class="macro">assert_eq!</span>(read_content, content);
+<a href=#458 id=458 data-nosnippet>458</a>
+<a href=#459 id=459 data-nosnippet>459</a> <span class="comment">// Test partial read
+<a href=#460 id=460 data-nosnippet>460</a> </span><span class="kw">let </span>partial = reader.read(<span class="number">0</span>..<span class="number">5</span>).<span class="kw">await</span>.unwrap();
+<a href=#461 id=461 data-nosnippet>461</a> <span class="macro">assert_eq!</span>(partial, Bytes::from(<span class="string">"Hello"</span>));
+<a href=#462 id=462 data-nosnippet>462</a> }
<a href=#463 id=463 data-nosnippet>463</a>
-<a href=#464 id=464 data-nosnippet>464</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path_str).<span class="kw">await</span>.unwrap();
-<a href=#465 id=465 data-nosnippet>465</a> writer.write(Bytes::from(<span class="string">"Hello, "</span>)).<span class="kw">await</span>.unwrap();
-<a href=#466 id=466 data-nosnippet>466</a> writer.write(Bytes::from(<span class="string">"World!"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#467 id=467 data-nosnippet>467</a> writer.close().<span class="kw">await</span>.unwrap();
-<a href=#468 id=468 data-nosnippet>468</a>
-<a href=#469 id=469 data-nosnippet>469</a> <span class="kw">let </span>content = storage.read(path_str).<span class="kw">await</span>.unwrap();
-<a href=#470 id=470 data-nosnippet>470</a> <span class="macro">assert_eq!</span>(content, Bytes::from(<span class="string">"Hello, World!"</span>));
-<a href=#471 id=471 data-nosnippet>471</a> }
-<a href=#472 id=472 data-nosnippet>472</a>
-<a href=#473 id=473 data-nosnippet>473</a> <span class="attr">#[tokio::test]
-<a href=#474 id=474 data-nosnippet>474</a> </span><span class="kw">async fn </span>test_local_fs_file_write_double_close() {
-<a href=#475 id=475 data-nosnippet>475</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#476 id=476 data-nosnippet>476</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#477 id=477 data-nosnippet>477</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
-<a href=#478 id=478 data-nosnippet>478</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
-<a href=#479 id=479 data-nosnippet>479</a>
-<a href=#480 id=480 data-nosnippet>480</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path_str).<span class="kw">await</span>.unwrap();
-<a href=#481 id=481 data-nosnippet>481</a> writer.write(Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#482 id=482 data-nosnippet>482</a> writer.close().<span class="kw">await</span>.unwrap();
-<a href=#483 id=483 data-nosnippet>483</a>
-<a href=#484 id=484 data-nosnippet>484</a> <span class="comment">// Second close should fail
-<a href=#485 id=485 data-nosnippet>485</a> </span><span class="kw">let </span>result = writer.close().<span class="kw">await</span>;
-<a href=#486 id=486 data-nosnippet>486</a> <span class="macro">assert!</span>(result.is_err());
-<a href=#487 id=487 data-nosnippet>487</a> }
-<a href=#488 id=488 data-nosnippet>488</a>
-<a href=#489 id=489 data-nosnippet>489</a> <span class="attr">#[tokio::test]
-<a href=#490 id=490 data-nosnippet>490</a> </span><span class="kw">async fn </span>test_local_fs_file_write_after_close() {
-<a href=#491 id=491 data-nosnippet>491</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#493 id=493 data-nosnippet>493</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
-<a href=#494 id=494 data-nosnippet>494</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
-<a href=#495 id=495 data-nosnippet>495</a>
-<a href=#496 id=496 data-nosnippet>496</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path_str).<span class="kw">await</span>.unwrap();
-<a href=#497 id=497 data-nosnippet>497</a> writer.close().<span class="kw">await</span>.unwrap();
-<a href=#498 id=498 data-nosnippet>498</a>
-<a href=#499 id=499 data-nosnippet>499</a> <span class="comment">// Write after close should fail
-<a href=#500 id=500 data-nosnippet>500</a> </span><span class="kw">let </span>result = writer.write(Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>;
-<a href=#501 id=501 data-nosnippet>501</a> <span class="macro">assert!</span>(result.is_err());
-<a href=#502 id=502 data-nosnippet>502</a> }
+<a href=#464 id=464 data-nosnippet>464</a> <span class="attr">#[tokio::test]
+<a href=#465 id=465 data-nosnippet>465</a> </span><span class="kw">async fn </span>test_local_fs_storage_writer() {
+<a href=#466 id=466 data-nosnippet>466</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#467 id=467 data-nosnippet>467</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#468 id=468 data-nosnippet>468</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
+<a href=#469 id=469 data-nosnippet>469</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#470 id=470 data-nosnippet>470</a>
+<a href=#471 id=471 data-nosnippet>471</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path_str).<span class="kw">await</span>.unwrap();
+<a href=#472 id=472 data-nosnippet>472</a> writer.write(Bytes::from(<span class="string">"Hello, "</span>)).<span class="kw">await</span>.unwrap();
+<a href=#473 id=473 data-nosnippet>473</a> writer.write(Bytes::from(<span class="string">"World!"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#474 id=474 data-nosnippet>474</a> <span class="kw">let </span>metadata = writer.close().<span class="kw">await</span>.unwrap();
+<a href=#475 id=475 data-nosnippet>475</a>
+<a href=#476 id=476 data-nosnippet>476</a> <span class="kw">let </span>content = storage.read(path_str).<span class="kw">await</span>.unwrap();
+<a href=#477 id=477 data-nosnippet>477</a> <span class="macro">assert_eq!</span>(content, Bytes::from(<span class="string">"Hello, World!"</span>));
+<a href=#478 id=478 data-nosnippet>478</a> <span class="macro">assert_eq!</span>(metadata.size, content.len() <span class="kw">as </span>u64);
+<a href=#479 id=479 data-nosnippet>479</a> }
+<a href=#480 id=480 data-nosnippet>480</a>
+<a href=#481 id=481 data-nosnippet>481</a> <span class="attr">#[tokio::test]
+<a href=#482 id=482 data-nosnippet>482</a> </span><span class="kw">async fn </span>test_local_fs_file_write_double_close() {
+<a href=#483 id=483 data-nosnippet>483</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#484 id=484 data-nosnippet>484</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#485 id=485 data-nosnippet>485</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
+<a href=#486 id=486 data-nosnippet>486</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#487 id=487 data-nosnippet>487</a>
+<a href=#488 id=488 data-nosnippet>488</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path_str).<span class="kw">await</span>.unwrap();
+<a href=#489 id=489 data-nosnippet>489</a> writer.write(Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#490 id=490 data-nosnippet>490</a> writer.close().<span class="kw">await</span>.unwrap();
+<a href=#491 id=491 data-nosnippet>491</a>
+<a href=#492 id=492 data-nosnippet>492</a> <span class="comment">// Second close should fail
+<a href=#493 id=493 data-nosnippet>493</a> </span><span class="kw">let </span>result = writer.close().<span class="kw">await</span>;
+<a href=#494 id=494 data-nosnippet>494</a> <span class="macro">assert!</span>(result.is_err());
+<a href=#495 id=495 data-nosnippet>495</a> }
+<a href=#496 id=496 data-nosnippet>496</a>
+<a href=#497 id=497 data-nosnippet>497</a> <span class="attr">#[tokio::test]
+<a href=#498 id=498 data-nosnippet>498</a> </span><span class="kw">async fn </span>test_local_fs_file_write_after_close() {
+<a href=#499 id=499 data-nosnippet>499</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#500 id=500 data-nosnippet>500</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#501 id=501 data-nosnippet>501</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"test.txt"</span>);
+<a href=#502 id=502 data-nosnippet>502</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
<a href=#503 id=503 data-nosnippet>503</a>
-<a href=#504 id=504 data-nosnippet>504</a> <span class="attr">#[test]
-<a href=#505 id=505 data-nosnippet>505</a> </span><span class="kw">fn </span>test_local_fs_storage_factory() {
-<a href=#506 id=506 data-nosnippet>506</a> <span class="kw">let </span>factory = LocalFsStorageFactory;
-<a href=#507 id=507 data-nosnippet>507</a> <span class="kw">let </span>config = StorageConfig::new();
-<a href=#508 id=508 data-nosnippet>508</a> <span class="kw">let </span>storage = factory.build(<span class="kw-2">&</span>config).unwrap();
-<a href=#509 id=509 data-nosnippet>509</a>
-<a href=#510 id=510 data-nosnippet>510</a> <span class="comment">// Verify we got a valid storage instance
-<a href=#511 id=511 data-nosnippet>511</a> </span><span class="macro">assert!</span>(<span class="macro">format!</span>(<span class="string">"{storage:?}"</span>).contains(<span class="string">"LocalFsStorage"</span>));
-<a href=#512 id=512 data-nosnippet>512</a> }
-<a href=#513 id=513 data-nosnippet>513</a>
-<a href=#514 id=514 data-nosnippet>514</a> <span class="attr">#[tokio::test]
-<a href=#515 id=515 data-nosnippet>515</a> </span><span class="kw">async fn </span>test_local_fs_creates_parent_directories() {
-<a href=#516 id=516 data-nosnippet>516</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#517 id=517 data-nosnippet>517</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#518 id=518 data-nosnippet>518</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"a/b/c/test.txt"</span>);
-<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
-<a href=#520 id=520 data-nosnippet>520</a>
-<a href=#521 id=521 data-nosnippet>521</a> <span class="comment">// Write should create parent directories
-<a href=#522 id=522 data-nosnippet>522</a> </span>storage.write(path_str, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#523 id=523 data-nosnippet>523</a>
-<a href=#524 id=524 data-nosnippet>524</a> <span class="macro">assert!</span>(path.exists());
-<a href=#525 id=525 data-nosnippet>525</a> }
-<a href=#526 id=526 data-nosnippet>526</a>
-<a href=#527 id=527 data-nosnippet>527</a> <span class="attr">#[tokio::test]
-<a href=#528 id=528 data-nosnippet>528</a> </span><span class="kw">async fn </span>test_local_fs_storage_delete_stream() {
-<a href=#529 id=529 data-nosnippet>529</a> <span class="kw">use </span>futures::stream;
-<a href=#530 id=530 data-nosnippet>530</a>
-<a href=#531 id=531 data-nosnippet>531</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
-<a href=#532 id=532 data-nosnippet>532</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#533 id=533 data-nosnippet>533</a>
-<a href=#534 id=534 data-nosnippet>534</a> <span class="comment">// Create multiple files
-<a href=#535 id=535 data-nosnippet>535</a> </span><span class="kw">let </span>file1 = tmp_dir.path().join(<span class="string">"file1.txt"</span>);
-<a href=#536 id=536 data-nosnippet>536</a> <span class="kw">let </span>file2 = tmp_dir.path().join(<span class="string">"file2.txt"</span>);
-<a href=#537 id=537 data-nosnippet>537</a> <span class="kw">let </span>file3 = tmp_dir.path().join(<span class="string">"file3.txt"</span>);
+<a href=#504 id=504 data-nosnippet>504</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path_str).<span class="kw">await</span>.unwrap();
+<a href=#505 id=505 data-nosnippet>505</a> <span class="macro">assert_eq!</span>(writer.close().<span class="kw">await</span>.unwrap().size, <span class="number">0</span>);
+<a href=#506 id=506 data-nosnippet>506</a>
+<a href=#507 id=507 data-nosnippet>507</a> <span class="comment">// Write after close should fail
+<a href=#508 id=508 data-nosnippet>508</a> </span><span class="kw">let </span>result = writer.write(Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>;
+<a href=#509 id=509 data-nosnippet>509</a> <span class="macro">assert!</span>(result.is_err());
+<a href=#510 id=510 data-nosnippet>510</a> }
+<a href=#511 id=511 data-nosnippet>511</a>
+<a href=#512 id=512 data-nosnippet>512</a> <span class="attr">#[test]
+<a href=#513 id=513 data-nosnippet>513</a> </span><span class="kw">fn </span>test_local_fs_storage_factory() {
+<a href=#514 id=514 data-nosnippet>514</a> <span class="kw">let </span>factory = LocalFsStorageFactory;
+<a href=#515 id=515 data-nosnippet>515</a> <span class="kw">let </span>config = StorageConfig::new();
+<a href=#516 id=516 data-nosnippet>516</a> <span class="kw">let </span>storage = factory.build(<span class="kw-2">&</span>config).unwrap();
+<a href=#517 id=517 data-nosnippet>517</a>
+<a href=#518 id=518 data-nosnippet>518</a> <span class="comment">// Verify we got a valid storage instance
+<a href=#519 id=519 data-nosnippet>519</a> </span><span class="macro">assert!</span>(<span class="macro">format!</span>(<span class="string">"{storage:?}"</span>).contains(<span class="string">"LocalFsStorage"</span>));
+<a href=#520 id=520 data-nosnippet>520</a> }
+<a href=#521 id=521 data-nosnippet>521</a>
+<a href=#522 id=522 data-nosnippet>522</a> <span class="attr">#[tokio::test]
+<a href=#523 id=523 data-nosnippet>523</a> </span><span class="kw">async fn </span>test_local_fs_creates_parent_directories() {
+<a href=#524 id=524 data-nosnippet>524</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#525 id=525 data-nosnippet>525</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#526 id=526 data-nosnippet>526</a> <span class="kw">let </span>path = tmp_dir.path().join(<span class="string">"a/b/c/test.txt"</span>);
+<a href=#527 id=527 data-nosnippet>527</a> <span class="kw">let </span>path_str = path.to_str().unwrap();
+<a href=#528 id=528 data-nosnippet>528</a>
+<a href=#529 id=529 data-nosnippet>529</a> <span class="comment">// Write should create parent directories
+<a href=#530 id=530 data-nosnippet>530</a> </span>storage.write(path_str, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#531 id=531 data-nosnippet>531</a>
+<a href=#532 id=532 data-nosnippet>532</a> <span class="macro">assert!</span>(path.exists());
+<a href=#533 id=533 data-nosnippet>533</a> }
+<a href=#534 id=534 data-nosnippet>534</a>
+<a href=#535 id=535 data-nosnippet>535</a> <span class="attr">#[tokio::test]
+<a href=#536 id=536 data-nosnippet>536</a> </span><span class="kw">async fn </span>test_local_fs_storage_delete_stream() {
+<a href=#537 id=537 data-nosnippet>537</a> <span class="kw">use </span>futures::stream;
<a href=#538 id=538 data-nosnippet>538</a>
-<a href=#539 id=539 data-nosnippet>539</a> storage
-<a href=#540 id=540 data-nosnippet>540</a> .write(file1.to_str().unwrap(), Bytes::from(<span class="string">"1"</span>))
-<a href=#541 id=541 data-nosnippet>541</a> .<span class="kw">await
-<a href=#542 id=542 data-nosnippet>542</a> </span>.unwrap();
-<a href=#543 id=543 data-nosnippet>543</a> storage
-<a href=#544 id=544 data-nosnippet>544</a> .write(file2.to_str().unwrap(), Bytes::from(<span class="string">"2"</span>))
-<a href=#545 id=545 data-nosnippet>545</a> .<span class="kw">await
-<a href=#546 id=546 data-nosnippet>546</a> </span>.unwrap();
+<a href=#539 id=539 data-nosnippet>539</a> <span class="kw">let </span>tmp_dir = TempDir::new().unwrap();
+<a href=#540 id=540 data-nosnippet>540</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#541 id=541 data-nosnippet>541</a>
+<a href=#542 id=542 data-nosnippet>542</a> <span class="comment">// Create multiple files
+<a href=#543 id=543 data-nosnippet>543</a> </span><span class="kw">let </span>file1 = tmp_dir.path().join(<span class="string">"file1.txt"</span>);
+<a href=#544 id=544 data-nosnippet>544</a> <span class="kw">let </span>file2 = tmp_dir.path().join(<span class="string">"file2.txt"</span>);
+<a href=#545 id=545 data-nosnippet>545</a> <span class="kw">let </span>file3 = tmp_dir.path().join(<span class="string">"file3.txt"</span>);
+<a href=#546 id=546 data-nosnippet>546</a>
<a href=#547 id=547 data-nosnippet>547</a> storage
-<a href=#548 id=548 data-nosnippet>548</a> .write(file3.to_str().unwrap(), Bytes::from(<span class="string">"3"</span>))
+<a href=#548 id=548 data-nosnippet>548</a> .write(file1.to_str().unwrap(), Bytes::from(<span class="string">"1"</span>))
<a href=#549 id=549 data-nosnippet>549</a> .<span class="kw">await
<a href=#550 id=550 data-nosnippet>550</a> </span>.unwrap();
-<a href=#551 id=551 data-nosnippet>551</a>
-<a href=#552 id=552 data-nosnippet>552</a> <span class="comment">// Verify files exist
-<a href=#553 id=553 data-nosnippet>553</a> </span><span class="macro">assert!</span>(storage.exists(file1.to_str().unwrap()).<span class="kw">await</span>.unwrap());
-<a href=#554 id=554 data-nosnippet>554</a> <span class="macro">assert!</span>(storage.exists(file2.to_str().unwrap()).<span class="kw">await</span>.unwrap());
-<a href=#555 id=555 data-nosnippet>555</a> <span class="macro">assert!</span>(storage.exists(file3.to_str().unwrap()).<span class="kw">await</span>.unwrap());
-<a href=#556 id=556 data-nosnippet>556</a>
-<a href=#557 id=557 data-nosnippet>557</a> <span class="comment">// Delete multiple files using stream
-<a href=#558 id=558 data-nosnippet>558</a> </span><span class="kw">let </span>paths = <span class="macro">vec!</span>[
-<a href=#559 id=559 data-nosnippet>559</a> file1.to_str().unwrap().to_string(),
-<a href=#560 id=560 data-nosnippet>560</a> file2.to_str().unwrap().to_string(),
-<a href=#561 id=561 data-nosnippet>561</a> ];
-<a href=#562 id=562 data-nosnippet>562</a> <span class="kw">let </span>path_stream = stream::iter(paths).boxed();
-<a href=#563 id=563 data-nosnippet>563</a> storage.delete_stream(path_stream).<span class="kw">await</span>.unwrap();
+<a href=#551 id=551 data-nosnippet>551</a> storage
+<a href=#552 id=552 data-nosnippet>552</a> .write(file2.to_str().unwrap(), Bytes::from(<span class="string">"2"</span>))
+<a href=#553 id=553 data-nosnippet>553</a> .<span class="kw">await
+<a href=#554 id=554 data-nosnippet>554</a> </span>.unwrap();
+<a href=#555 id=555 data-nosnippet>555</a> storage
+<a href=#556 id=556 data-nosnippet>556</a> .write(file3.to_str().unwrap(), Bytes::from(<span class="string">"3"</span>))
+<a href=#557 id=557 data-nosnippet>557</a> .<span class="kw">await
+<a href=#558 id=558 data-nosnippet>558</a> </span>.unwrap();
+<a href=#559 id=559 data-nosnippet>559</a>
+<a href=#560 id=560 data-nosnippet>560</a> <span class="comment">// Verify files exist
+<a href=#561 id=561 data-nosnippet>561</a> </span><span class="macro">assert!</span>(storage.exists(file1.to_str().unwrap()).<span class="kw">await</span>.unwrap());
+<a href=#562 id=562 data-nosnippet>562</a> <span class="macro">assert!</span>(storage.exists(file2.to_str().unwrap()).<span class="kw">await</span>.unwrap());
+<a href=#563 id=563 data-nosnippet>563</a> <span class="macro">assert!</span>(storage.exists(file3.to_str().unwrap()).<span class="kw">await</span>.unwrap());
<a href=#564 id=564 data-nosnippet>564</a>
-<a href=#565 id=565 data-nosnippet>565</a> <span class="comment">// Verify deleted files no longer exist
-<a href=#566 id=566 data-nosnippet>566</a> </span><span class="macro">assert!</span>(!storage.exists(file1.to_str().unwrap()).<span class="kw">await</span>.unwrap());
-<a href=#567 id=567 data-nosnippet>567</a> <span class="macro">assert!</span>(!storage.exists(file2.to_str().unwrap()).<span class="kw">await</span>.unwrap());
-<a href=#568 id=568 data-nosnippet>568</a>
-<a href=#569 id=569 data-nosnippet>569</a> <span class="comment">// Verify file3 still exists
-<a href=#570 id=570 data-nosnippet>570</a> </span><span class="macro">assert!</span>(storage.exists(file3.to_str().unwrap()).<span class="kw">await</span>.unwrap());
-<a href=#571 id=571 data-nosnippet>571</a> }
+<a href=#565 id=565 data-nosnippet>565</a> <span class="comment">// Delete multiple files using stream
+<a href=#566 id=566 data-nosnippet>566</a> </span><span class="kw">let </span>paths = <span class="macro">vec!</span>[
+<a href=#567 id=567 data-nosnippet>567</a> file1.to_str().unwrap().to_string(),
+<a href=#568 id=568 data-nosnippet>568</a> file2.to_str().unwrap().to_string(),
+<a href=#569 id=569 data-nosnippet>569</a> ];
+<a href=#570 id=570 data-nosnippet>570</a> <span class="kw">let </span>path_stream = stream::iter(paths).boxed();
+<a href=#571 id=571 data-nosnippet>571</a> storage.delete_stream(path_stream).<span class="kw">await</span>.unwrap();
<a href=#572 id=572 data-nosnippet>572</a>
-<a href=#573 id=573 data-nosnippet>573</a> <span class="attr">#[tokio::test]
-<a href=#574 id=574 data-nosnippet>574</a> </span><span class="kw">async fn </span>test_local_fs_storage_delete_stream_empty() {
-<a href=#575 id=575 data-nosnippet>575</a> <span class="kw">use </span>futures::stream;
+<a href=#573 id=573 data-nosnippet>573</a> <span class="comment">// Verify deleted files no longer exist
+<a href=#574 id=574 data-nosnippet>574</a> </span><span class="macro">assert!</span>(!storage.exists(file1.to_str().unwrap()).<span class="kw">await</span>.unwrap());
+<a href=#575 id=575 data-nosnippet>575</a> <span class="macro">assert!</span>(!storage.exists(file2.to_str().unwrap()).<span class="kw">await</span>.unwrap());
<a href=#576 id=576 data-nosnippet>576</a>
-<a href=#577 id=577 data-nosnippet>577</a> <span class="kw">let </span>storage = LocalFsStorage::new();
-<a href=#578 id=578 data-nosnippet>578</a>
-<a href=#579 id=579 data-nosnippet>579</a> <span class="comment">// Delete with empty stream should succeed
-<a href=#580 id=580 data-nosnippet>580</a> </span><span class="kw">let </span>path_stream = stream::iter(Vec::<String>::new()).boxed();
-<a href=#581 id=581 data-nosnippet>581</a> storage.delete_stream(path_stream).<span class="kw">await</span>.unwrap();
-<a href=#582 id=582 data-nosnippet>582</a> }
-<a href=#583 id=583 data-nosnippet>583</a>}
+<a href=#577 id=577 data-nosnippet>577</a> <span class="comment">// Verify file3 still exists
+<a href=#578 id=578 data-nosnippet>578</a> </span><span class="macro">assert!</span>(storage.exists(file3.to_str().unwrap()).<span class="kw">await</span>.unwrap());
+<a href=#579 id=579 data-nosnippet>579</a> }
+<a href=#580 id=580 data-nosnippet>580</a>
+<a href=#581 id=581 data-nosnippet>581</a> <span class="attr">#[tokio::test]
+<a href=#582 id=582 data-nosnippet>582</a> </span><span class="kw">async fn </span>test_local_fs_storage_delete_stream_empty() {
+<a href=#583 id=583 data-nosnippet>583</a> <span class="kw">use </span>futures::stream;
+<a href=#584 id=584 data-nosnippet>584</a>
+<a href=#585 id=585 data-nosnippet>585</a> <span class="kw">let </span>storage = LocalFsStorage::new();
+<a href=#586 id=586 data-nosnippet>586</a>
+<a href=#587 id=587 data-nosnippet>587</a> <span class="comment">// Delete with empty stream should succeed
+<a href=#588 id=588 data-nosnippet>588</a> </span><span class="kw">let </span>path_stream = stream::iter(Vec::<String>::new()).boxed();
+<a href=#589 id=589 data-nosnippet>589</a> storage.delete_stream(path_stream).<span class="kw">await</span>.unwrap();
+<a href=#590 id=590 data-nosnippet>590</a> }
+<a href=#591 id=591 data-nosnippet>591</a>}
</code></pre></div></section></main></body></html>
\ No newline at end of file
diff --git a/api/src/iceberg/io/storage/memory.rs.html b/api/src/iceberg/io/storage/memory.rs.html
index d86987f1d..272601b3e 100644
--- a/api/src/iceberg/io/storage/memory.rs.html
+++ b/api/src/iceberg/io/storage/memory.rs.html
@@ -311,7 +311,7 @@
<a href=#311 id=311 data-nosnippet>311</a> <span class="prelude-val">Ok</span>(())
<a href=#312 id=312 data-nosnippet>312</a> }
<a href=#313 id=313 data-nosnippet>313</a>
-<a href=#314 id=314 data-nosnippet>314</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><()> {
+<a href=#314 id=314 data-nosnippet>314</a> <span class="kw">async fn </span>close(<span class="kw-2">&mut </span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><FileMetadata> {
<a href=#315 id=315 data-nosnippet>315</a> <span class="kw">if </span><span class="self">self</span>.closed {
<a href=#316 id=316 data-nosnippet>316</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">invalid_data!</span>(<span class="string">"File already closed"</span>));
<a href=#317 id=317 data-nosnippet>317</a> }
@@ -323,322 +323,324 @@
<a href=#323 id=323 data-nosnippet>323</a> )
<a href=#324 id=324 data-nosnippet>324</a> })<span class="question-mark">?</span>;
<a href=#325 id=325 data-nosnippet>325</a>
-<a href=#326 id=326 data-nosnippet>326</a> data.insert(
-<a href=#327 id=327 data-nosnippet>327</a> <span class="self">self</span>.path.clone(),
-<a href=#328 id=328 data-nosnippet>328</a> Bytes::from(std::mem::take(<span class="kw-2">&mut </span><span class="self">self</span>.buffer)),
-<a href=#329 id=329 data-nosnippet>329</a> );
-<a href=#330 id=330 data-nosnippet>330</a> <span class="self">self</span>.closed = <span class="bool-val">true</span>;
-<a href=#331 id=331 data-nosnippet>331</a> <span class="prelude-val">Ok</span>(())
-<a href=#332 id=332 data-nosnippet>332</a> }
-<a href=#333 id=333 data-nosnippet>333</a>}
-<a href=#334 id=334 data-nosnippet>334</a>
-<a href=#335 id=335 data-nosnippet>335</a><span class="attr">#[cfg(test)]
-<a href=#336 id=336 data-nosnippet>336</a></span><span class="kw">mod </span>tests {
-<a href=#337 id=337 data-nosnippet>337</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
-<a href=#338 id=338 data-nosnippet>338</a>
-<a href=#339 id=339 data-nosnippet>339</a> <span class="attr">#[test]
-<a href=#340 id=340 data-nosnippet>340</a> </span><span class="kw">fn </span>test_normalize_path() {
-<a href=#341 id=341 data-nosnippet>341</a> <span class="comment">// Test memory:// prefix
-<a href=#342 id=342 data-nosnippet>342</a> </span><span class="macro">assert_eq!</span>(
-<a href=#343 id=343 data-nosnippet>343</a> MemoryStorage::normalize_path(<span class="string">"memory://path/to/file"</span>),
-<a href=#344 id=344 data-nosnippet>344</a> <span class="string">"path/to/file"
-<a href=#345 id=345 data-nosnippet>345</a> </span>);
-<a href=#346 id=346 data-nosnippet>346</a>
-<a href=#347 id=347 data-nosnippet>347</a> <span class="comment">// Test memory:/ prefix
-<a href=#348 id=348 data-nosnippet>348</a> </span><span class="macro">assert_eq!</span>(
-<a href=#349 id=349 data-nosnippet>349</a> MemoryStorage::normalize_path(<span class="string">"memory:/path/to/file"</span>),
-<a href=#350 id=350 data-nosnippet>350</a> <span class="string">"path/to/file"
-<a href=#351 id=351 data-nosnippet>351</a> </span>);
-<a href=#352 id=352 data-nosnippet>352</a>
-<a href=#353 id=353 data-nosnippet>353</a> <span class="comment">// Test leading slash
-<a href=#354 id=354 data-nosnippet>354</a> </span><span class="macro">assert_eq!</span>(
-<a href=#355 id=355 data-nosnippet>355</a> MemoryStorage::normalize_path(<span class="string">"/path/to/file"</span>),
-<a href=#356 id=356 data-nosnippet>356</a> <span class="string">"path/to/file"
-<a href=#357 id=357 data-nosnippet>357</a> </span>);
-<a href=#358 id=358 data-nosnippet>358</a>
-<a href=#359 id=359 data-nosnippet>359</a> <span class="comment">// Test bare path
-<a href=#360 id=360 data-nosnippet>360</a> </span><span class="macro">assert_eq!</span>(
-<a href=#361 id=361 data-nosnippet>361</a> MemoryStorage::normalize_path(<span class="string">"path/to/file"</span>),
-<a href=#362 id=362 data-nosnippet>362</a> <span class="string">"path/to/file"
-<a href=#363 id=363 data-nosnippet>363</a> </span>);
-<a href=#364 id=364 data-nosnippet>364</a>
-<a href=#365 id=365 data-nosnippet>365</a> <span class="comment">// Test multiple leading slashes
-<a href=#366 id=366 data-nosnippet>366</a> </span><span class="macro">assert_eq!</span>(
-<a href=#367 id=367 data-nosnippet>367</a> MemoryStorage::normalize_path(<span class="string">"///path/to/file"</span>),
-<a href=#368 id=368 data-nosnippet>368</a> <span class="string">"path/to/file"
-<a href=#369 id=369 data-nosnippet>369</a> </span>);
-<a href=#370 id=370 data-nosnippet>370</a>
-<a href=#371 id=371 data-nosnippet>371</a> <span class="comment">// Test memory:// with leading slash in path
-<a href=#372 id=372 data-nosnippet>372</a> </span><span class="macro">assert_eq!</span>(
-<a href=#373 id=373 data-nosnippet>373</a> MemoryStorage::normalize_path(<span class="string">"memory:///path/to/file"</span>),
-<a href=#374 id=374 data-nosnippet>374</a> <span class="string">"path/to/file"
-<a href=#375 id=375 data-nosnippet>375</a> </span>);
-<a href=#376 id=376 data-nosnippet>376</a> }
-<a href=#377 id=377 data-nosnippet>377</a>
-<a href=#378 id=378 data-nosnippet>378</a> <span class="attr">#[tokio::test]
-<a href=#379 id=379 data-nosnippet>379</a> </span><span class="kw">async fn </span>test_memory_storage_write_read() {
-<a href=#380 id=380 data-nosnippet>380</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#381 id=381 data-nosnippet>381</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#382 id=382 data-nosnippet>382</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
-<a href=#383 id=383 data-nosnippet>383</a>
-<a href=#384 id=384 data-nosnippet>384</a> <span class="comment">// Write
-<a href=#385 id=385 data-nosnippet>385</a> </span>storage.write(path, content.clone()).<span class="kw">await</span>.unwrap();
-<a href=#386 id=386 data-nosnippet>386</a>
-<a href=#387 id=387 data-nosnippet>387</a> <span class="comment">// Read
-<a href=#388 id=388 data-nosnippet>388</a> </span><span class="kw">let </span>read_content = storage.read(path).<span class="kw">await</span>.unwrap();
-<a href=#389 id=389 data-nosnippet>389</a> <span class="macro">assert_eq!</span>(read_content, content);
-<a href=#390 id=390 data-nosnippet>390</a> }
-<a href=#391 id=391 data-nosnippet>391</a>
-<a href=#392 id=392 data-nosnippet>392</a> <span class="attr">#[tokio::test]
-<a href=#393 id=393 data-nosnippet>393</a> </span><span class="kw">async fn </span>test_memory_storage_exists() {
-<a href=#394 id=394 data-nosnippet>394</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#396 id=396 data-nosnippet>396</a>
-<a href=#397 id=397 data-nosnippet>397</a> <span class="comment">// File doesn't exist initially
-<a href=#398 id=398 data-nosnippet>398</a> </span><span class="macro">assert!</span>(!storage.exists(path).<span class="kw">await</span>.unwrap());
-<a href=#399 id=399 data-nosnippet>399</a>
-<a href=#400 id=400 data-nosnippet>400</a> <span class="comment">// Write file
-<a href=#401 id=401 data-nosnippet>401</a> </span>storage.write(path, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#402 id=402 data-nosnippet>402</a>
-<a href=#403 id=403 data-nosnippet>403</a> <span class="comment">// File exists now
-<a href=#404 id=404 data-nosnippet>404</a> </span><span class="macro">assert!</span>(storage.exists(path).<span class="kw">await</span>.unwrap());
-<a href=#405 id=405 data-nosnippet>405</a> }
-<a href=#406 id=406 data-nosnippet>406</a>
-<a href=#407 id=407 data-nosnippet>407</a> <span class="attr">#[tokio::test]
-<a href=#408 id=408 data-nosnippet>408</a> </span><span class="kw">async fn </span>test_memory_storage_metadata() {
-<a href=#409 id=409 data-nosnippet>409</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#410 id=410 data-nosnippet>410</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#411 id=411 data-nosnippet>411</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
-<a href=#412 id=412 data-nosnippet>412</a>
-<a href=#413 id=413 data-nosnippet>413</a> storage.write(path, content.clone()).<span class="kw">await</span>.unwrap();
-<a href=#414 id=414 data-nosnippet>414</a>
-<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">let </span>metadata = storage.metadata(path).<span class="kw">await</span>.unwrap();
-<a href=#416 id=416 data-nosnippet>416</a> <span class="macro">assert_eq!</span>(metadata.size, content.len() <span class="kw">as </span>u64);
-<a href=#417 id=417 data-nosnippet>417</a> }
-<a href=#418 id=418 data-nosnippet>418</a>
-<a href=#419 id=419 data-nosnippet>419</a> <span class="attr">#[tokio::test]
-<a href=#420 id=420 data-nosnippet>420</a> </span><span class="kw">async fn </span>test_memory_storage_delete() {
-<a href=#421 id=421 data-nosnippet>421</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#422 id=422 data-nosnippet>422</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#423 id=423 data-nosnippet>423</a>
-<a href=#424 id=424 data-nosnippet>424</a> storage.write(path, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#425 id=425 data-nosnippet>425</a> <span class="macro">assert!</span>(storage.exists(path).<span class="kw">await</span>.unwrap());
-<a href=#426 id=426 data-nosnippet>426</a>
-<a href=#427 id=427 data-nosnippet>427</a> storage.delete(path).<span class="kw">await</span>.unwrap();
-<a href=#428 id=428 data-nosnippet>428</a> <span class="macro">assert!</span>(!storage.exists(path).<span class="kw">await</span>.unwrap());
-<a href=#429 id=429 data-nosnippet>429</a> }
-<a href=#430 id=430 data-nosnippet>430</a>
-<a href=#431 id=431 data-nosnippet>431</a> <span class="attr">#[tokio::test]
-<a href=#432 id=432 data-nosnippet>432</a> </span><span class="kw">async fn </span>test_memory_storage_delete_prefix() {
-<a href=#433 id=433 data-nosnippet>433</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#434 id=434 data-nosnippet>434</a>
-<a href=#435 id=435 data-nosnippet>435</a> <span class="comment">// Create multiple files
-<a href=#436 id=436 data-nosnippet>436</a> </span>storage
-<a href=#437 id=437 data-nosnippet>437</a> .write(<span class="string">"memory://dir/file1.txt"</span>, Bytes::from(<span class="string">"1"</span>))
-<a href=#438 id=438 data-nosnippet>438</a> .<span class="kw">await
-<a href=#439 id=439 data-nosnippet>439</a> </span>.unwrap();
-<a href=#440 id=440 data-nosnippet>440</a> storage
-<a href=#441 id=441 data-nosnippet>441</a> .write(<span class="string">"memory://dir/file2.txt"</span>, Bytes::from(<span class="string">"2"</span>))
-<a href=#442 id=442 data-nosnippet>442</a> .<span class="kw">await
-<a href=#443 id=443 data-nosnippet>443</a> </span>.unwrap();
-<a href=#444 id=444 data-nosnippet>444</a> storage
-<a href=#445 id=445 data-nosnippet>445</a> .write(<span class="string">"memory://other/file.txt"</span>, Bytes::from(<span class="string">"3"</span>))
-<a href=#446 id=446 data-nosnippet>446</a> .<span class="kw">await
-<a href=#447 id=447 data-nosnippet>447</a> </span>.unwrap();
-<a href=#448 id=448 data-nosnippet>448</a>
-<a href=#449 id=449 data-nosnippet>449</a> <span class="comment">// Delete prefix
-<a href=#450 id=450 data-nosnippet>450</a> </span>storage.delete_prefix(<span class="string">"memory://dir"</span>).<span class="kw">await</span>.unwrap();
-<a href=#451 id=451 data-nosnippet>451</a>
-<a href=#452 id=452 data-nosnippet>452</a> <span class="comment">// Files in dir should be deleted
-<a href=#453 id=453 data-nosnippet>453</a> </span><span class="macro">assert!</span>(!storage.exists(<span class="string">"memory://dir/file1.txt"</span>).<span class="kw">await</span>.unwrap());
-<a href=#454 id=454 data-nosnippet>454</a> <span class="macro">assert!</span>(!storage.exists(<span class="string">"memory://dir/file2.txt"</span>).<span class="kw">await</span>.unwrap());
-<a href=#455 id=455 data-nosnippet>455</a>
-<a href=#456 id=456 data-nosnippet>456</a> <span class="comment">// File in other dir should still exist
-<a href=#457 id=457 data-nosnippet>457</a> </span><span class="macro">assert!</span>(storage.exists(<span class="string">"memory://other/file.txt"</span>).<span class="kw">await</span>.unwrap());
-<a href=#458 id=458 data-nosnippet>458</a> }
-<a href=#459 id=459 data-nosnippet>459</a>
-<a href=#460 id=460 data-nosnippet>460</a> <span class="attr">#[tokio::test]
-<a href=#461 id=461 data-nosnippet>461</a> </span><span class="kw">async fn </span>test_memory_storage_reader() {
-<a href=#462 id=462 data-nosnippet>462</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#463 id=463 data-nosnippet>463</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#464 id=464 data-nosnippet>464</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
-<a href=#465 id=465 data-nosnippet>465</a>
-<a href=#466 id=466 data-nosnippet>466</a> storage.write(path, content.clone()).<span class="kw">await</span>.unwrap();
-<a href=#467 id=467 data-nosnippet>467</a>
-<a href=#468 id=468 data-nosnippet>468</a> <span class="kw">let </span>reader = storage.reader(path).<span class="kw">await</span>.unwrap();
-<a href=#469 id=469 data-nosnippet>469</a> <span class="kw">let </span>read_content = reader.read(<span class="number">0</span>..content.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
-<a href=#470 id=470 data-nosnippet>470</a> <span class="macro">assert_eq!</span>(read_content, content);
-<a href=#471 id=471 data-nosnippet>471</a>
-<a href=#472 id=472 data-nosnippet>472</a> <span class="comment">// Test partial read
-<a href=#473 id=473 data-nosnippet>473</a> </span><span class="kw">let </span>partial = reader.read(<span class="number">0</span>..<span class="number">5</span>).<span class="kw">await</span>.unwrap();
-<a href=#474 id=474 data-nosnippet>474</a> <span class="macro">assert_eq!</span>(partial, Bytes::from(<span class="string">"Hello"</span>));
-<a href=#475 id=475 data-nosnippet>475</a> }
-<a href=#476 id=476 data-nosnippet>476</a>
-<a href=#477 id=477 data-nosnippet>477</a> <span class="attr">#[tokio::test]
-<a href=#478 id=478 data-nosnippet>478</a> </span><span class="kw">async fn </span>test_memory_storage_writer() {
-<a href=#479 id=479 data-nosnippet>479</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#480 id=480 data-nosnippet>480</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#481 id=481 data-nosnippet>481</a>
-<a href=#482 id=482 data-nosnippet>482</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path).<span class="kw">await</span>.unwrap();
-<a href=#483 id=483 data-nosnippet>483</a> writer.write(Bytes::from(<span class="string">"Hello, "</span>)).<span class="kw">await</span>.unwrap();
-<a href=#484 id=484 data-nosnippet>484</a> writer.write(Bytes::from(<span class="string">"World!"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#485 id=485 data-nosnippet>485</a> writer.close().<span class="kw">await</span>.unwrap();
-<a href=#486 id=486 data-nosnippet>486</a>
-<a href=#487 id=487 data-nosnippet>487</a> <span class="kw">let </span>content = storage.read(path).<span class="kw">await</span>.unwrap();
-<a href=#488 id=488 data-nosnippet>488</a> <span class="macro">assert_eq!</span>(content, Bytes::from(<span class="string">"Hello, World!"</span>));
-<a href=#489 id=489 data-nosnippet>489</a> }
-<a href=#490 id=490 data-nosnippet>490</a>
-<a href=#491 id=491 data-nosnippet>491</a> <span class="attr">#[tokio::test]
-<a href=#492 id=492 data-nosnippet>492</a> </span><span class="kw">async fn </span>test_memory_file_write_double_close() {
-<a href=#493 id=493 data-nosnippet>493</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#494 id=494 data-nosnippet>494</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#495 id=495 data-nosnippet>495</a>
-<a href=#496 id=496 data-nosnippet>496</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path).<span class="kw">await</span>.unwrap();
-<a href=#497 id=497 data-nosnippet>497</a> writer.write(Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
-<a href=#498 id=498 data-nosnippet>498</a> writer.close().<span class="kw">await</span>.unwrap();
-<a href=#499 id=499 data-nosnippet>499</a>
-<a href=#500 id=500 data-nosnippet>500</a> <span class="comment">// Second close should fail
-<a href=#501 id=501 data-nosnippet>501</a> </span><span class="kw">let </span>result = writer.close().<span class="kw">await</span>;
-<a href=#502 id=502 data-nosnippet>502</a> <span class="macro">assert!</span>(result.is_err());
-<a href=#503 id=503 data-nosnippet>503</a> }
-<a href=#504 id=504 data-nosnippet>504</a>
-<a href=#505 id=505 data-nosnippet>505</a> <span class="attr">#[tokio::test]
-<a href=#506 id=506 data-nosnippet>506</a> </span><span class="kw">async fn </span>test_memory_file_write_after_close() {
-<a href=#507 id=507 data-nosnippet>507</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#508 id=508 data-nosnippet>508</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#509 id=509 data-nosnippet>509</a>
-<a href=#510 id=510 data-nosnippet>510</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path).<span class="kw">await</span>.unwrap();
-<a href=#511 id=511 data-nosnippet>511</a> writer.close().<span class="kw">await</span>.unwrap();
-<a href=#512 id=512 data-nosnippet>512</a>
-<a href=#513 id=513 data-nosnippet>513</a> <span class="comment">// Write after close should fail
-<a href=#514 id=514 data-nosnippet>514</a> </span><span class="kw">let </span>result = writer.write(Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>;
-<a href=#515 id=515 data-nosnippet>515</a> <span class="macro">assert!</span>(result.is_err());
-<a href=#516 id=516 data-nosnippet>516</a> }
-<a href=#517 id=517 data-nosnippet>517</a>
-<a href=#518 id=518 data-nosnippet>518</a> <span class="attr">#[tokio::test]
-<a href=#519 id=519 data-nosnippet>519</a> </span><span class="kw">async fn </span>test_memory_file_read_out_of_bounds() {
-<a href=#520 id=520 data-nosnippet>520</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#521 id=521 data-nosnippet>521</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
-<a href=#522 id=522 data-nosnippet>522</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello"</span>);
-<a href=#523 id=523 data-nosnippet>523</a>
-<a href=#524 id=524 data-nosnippet>524</a> storage.write(path, content).<span class="kw">await</span>.unwrap();
+<a href=#326 id=326 data-nosnippet>326</a> <span class="kw">let </span>size = <span class="self">self</span>.buffer.len() <span class="kw">as </span>u64;
+<a href=#327 id=327 data-nosnippet>327</a> data.insert(
+<a href=#328 id=328 data-nosnippet>328</a> <span class="self">self</span>.path.clone(),
+<a href=#329 id=329 data-nosnippet>329</a> Bytes::from(std::mem::take(<span class="kw-2">&mut </span><span class="self">self</span>.buffer)),
+<a href=#330 id=330 data-nosnippet>330</a> );
+<a href=#331 id=331 data-nosnippet>331</a> <span class="self">self</span>.closed = <span class="bool-val">true</span>;
+<a href=#332 id=332 data-nosnippet>332</a> <span class="prelude-val">Ok</span>(FileMetadata { size })
+<a href=#333 id=333 data-nosnippet>333</a> }
+<a href=#334 id=334 data-nosnippet>334</a>}
+<a href=#335 id=335 data-nosnippet>335</a>
+<a href=#336 id=336 data-nosnippet>336</a><span class="attr">#[cfg(test)]
+<a href=#337 id=337 data-nosnippet>337</a></span><span class="kw">mod </span>tests {
+<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
+<a href=#339 id=339 data-nosnippet>339</a>
+<a href=#340 id=340 data-nosnippet>340</a> <span class="attr">#[test]
+<a href=#341 id=341 data-nosnippet>341</a> </span><span class="kw">fn </span>test_normalize_path() {
+<a href=#342 id=342 data-nosnippet>342</a> <span class="comment">// Test memory:// prefix
+<a href=#343 id=343 data-nosnippet>343</a> </span><span class="macro">assert_eq!</span>(
+<a href=#344 id=344 data-nosnippet>344</a> MemoryStorage::normalize_path(<span class="string">"memory://path/to/file"</span>),
+<a href=#345 id=345 data-nosnippet>345</a> <span class="string">"path/to/file"
+<a href=#346 id=346 data-nosnippet>346</a> </span>);
+<a href=#347 id=347 data-nosnippet>347</a>
+<a href=#348 id=348 data-nosnippet>348</a> <span class="comment">// Test memory:/ prefix
+<a href=#349 id=349 data-nosnippet>349</a> </span><span class="macro">assert_eq!</span>(
+<a href=#350 id=350 data-nosnippet>350</a> MemoryStorage::normalize_path(<span class="string">"memory:/path/to/file"</span>),
+<a href=#351 id=351 data-nosnippet>351</a> <span class="string">"path/to/file"
+<a href=#352 id=352 data-nosnippet>352</a> </span>);
+<a href=#353 id=353 data-nosnippet>353</a>
+<a href=#354 id=354 data-nosnippet>354</a> <span class="comment">// Test leading slash
+<a href=#355 id=355 data-nosnippet>355</a> </span><span class="macro">assert_eq!</span>(
+<a href=#356 id=356 data-nosnippet>356</a> MemoryStorage::normalize_path(<span class="string">"/path/to/file"</span>),
+<a href=#357 id=357 data-nosnippet>357</a> <span class="string">"path/to/file"
+<a href=#358 id=358 data-nosnippet>358</a> </span>);
+<a href=#359 id=359 data-nosnippet>359</a>
+<a href=#360 id=360 data-nosnippet>360</a> <span class="comment">// Test bare path
+<a href=#361 id=361 data-nosnippet>361</a> </span><span class="macro">assert_eq!</span>(
+<a href=#362 id=362 data-nosnippet>362</a> MemoryStorage::normalize_path(<span class="string">"path/to/file"</span>),
+<a href=#363 id=363 data-nosnippet>363</a> <span class="string">"path/to/file"
+<a href=#364 id=364 data-nosnippet>364</a> </span>);
+<a href=#365 id=365 data-nosnippet>365</a>
+<a href=#366 id=366 data-nosnippet>366</a> <span class="comment">// Test multiple leading slashes
+<a href=#367 id=367 data-nosnippet>367</a> </span><span class="macro">assert_eq!</span>(
+<a href=#368 id=368 data-nosnippet>368</a> MemoryStorage::normalize_path(<span class="string">"///path/to/file"</span>),
+<a href=#369 id=369 data-nosnippet>369</a> <span class="string">"path/to/file"
+<a href=#370 id=370 data-nosnippet>370</a> </span>);
+<a href=#371 id=371 data-nosnippet>371</a>
+<a href=#372 id=372 data-nosnippet>372</a> <span class="comment">// Test memory:// with leading slash in path
+<a href=#373 id=373 data-nosnippet>373</a> </span><span class="macro">assert_eq!</span>(
+<a href=#374 id=374 data-nosnippet>374</a> MemoryStorage::normalize_path(<span class="string">"memory:///path/to/file"</span>),
+<a href=#375 id=375 data-nosnippet>375</a> <span class="string">"path/to/file"
+<a href=#376 id=376 data-nosnippet>376</a> </span>);
+<a href=#377 id=377 data-nosnippet>377</a> }
+<a href=#378 id=378 data-nosnippet>378</a>
+<a href=#379 id=379 data-nosnippet>379</a> <span class="attr">#[tokio::test]
+<a href=#380 id=380 data-nosnippet>380</a> </span><span class="kw">async fn </span>test_memory_storage_write_read() {
+<a href=#381 id=381 data-nosnippet>381</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#382 id=382 data-nosnippet>382</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#383 id=383 data-nosnippet>383</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
+<a href=#384 id=384 data-nosnippet>384</a>
+<a href=#385 id=385 data-nosnippet>385</a> <span class="comment">// Write
+<a href=#386 id=386 data-nosnippet>386</a> </span>storage.write(path, content.clone()).<span class="kw">await</span>.unwrap();
+<a href=#387 id=387 data-nosnippet>387</a>
+<a href=#388 id=388 data-nosnippet>388</a> <span class="comment">// Read
+<a href=#389 id=389 data-nosnippet>389</a> </span><span class="kw">let </span>read_content = storage.read(path).<span class="kw">await</span>.unwrap();
+<a href=#390 id=390 data-nosnippet>390</a> <span class="macro">assert_eq!</span>(read_content, content);
+<a href=#391 id=391 data-nosnippet>391</a> }
+<a href=#392 id=392 data-nosnippet>392</a>
+<a href=#393 id=393 data-nosnippet>393</a> <span class="attr">#[tokio::test]
+<a href=#394 id=394 data-nosnippet>394</a> </span><span class="kw">async fn </span>test_memory_storage_exists() {
+<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#396 id=396 data-nosnippet>396</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#397 id=397 data-nosnippet>397</a>
+<a href=#398 id=398 data-nosnippet>398</a> <span class="comment">// File doesn't exist initially
+<a href=#399 id=399 data-nosnippet>399</a> </span><span class="macro">assert!</span>(!storage.exists(path).<span class="kw">await</span>.unwrap());
+<a href=#400 id=400 data-nosnippet>400</a>
+<a href=#401 id=401 data-nosnippet>401</a> <span class="comment">// Write file
+<a href=#402 id=402 data-nosnippet>402</a> </span>storage.write(path, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#403 id=403 data-nosnippet>403</a>
+<a href=#404 id=404 data-nosnippet>404</a> <span class="comment">// File exists now
+<a href=#405 id=405 data-nosnippet>405</a> </span><span class="macro">assert!</span>(storage.exists(path).<span class="kw">await</span>.unwrap());
+<a href=#406 id=406 data-nosnippet>406</a> }
+<a href=#407 id=407 data-nosnippet>407</a>
+<a href=#408 id=408 data-nosnippet>408</a> <span class="attr">#[tokio::test]
+<a href=#409 id=409 data-nosnippet>409</a> </span><span class="kw">async fn </span>test_memory_storage_metadata() {
+<a href=#410 id=410 data-nosnippet>410</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#411 id=411 data-nosnippet>411</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#412 id=412 data-nosnippet>412</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
+<a href=#413 id=413 data-nosnippet>413</a>
+<a href=#414 id=414 data-nosnippet>414</a> storage.write(path, content.clone()).<span class="kw">await</span>.unwrap();
+<a href=#415 id=415 data-nosnippet>415</a>
+<a href=#416 id=416 data-nosnippet>416</a> <span class="kw">let </span>metadata = storage.metadata(path).<span class="kw">await</span>.unwrap();
+<a href=#417 id=417 data-nosnippet>417</a> <span class="macro">assert_eq!</span>(metadata.size, content.len() <span class="kw">as </span>u64);
+<a href=#418 id=418 data-nosnippet>418</a> }
+<a href=#419 id=419 data-nosnippet>419</a>
+<a href=#420 id=420 data-nosnippet>420</a> <span class="attr">#[tokio::test]
+<a href=#421 id=421 data-nosnippet>421</a> </span><span class="kw">async fn </span>test_memory_storage_delete() {
+<a href=#422 id=422 data-nosnippet>422</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#423 id=423 data-nosnippet>423</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#424 id=424 data-nosnippet>424</a>
+<a href=#425 id=425 data-nosnippet>425</a> storage.write(path, Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#426 id=426 data-nosnippet>426</a> <span class="macro">assert!</span>(storage.exists(path).<span class="kw">await</span>.unwrap());
+<a href=#427 id=427 data-nosnippet>427</a>
+<a href=#428 id=428 data-nosnippet>428</a> storage.delete(path).<span class="kw">await</span>.unwrap();
+<a href=#429 id=429 data-nosnippet>429</a> <span class="macro">assert!</span>(!storage.exists(path).<span class="kw">await</span>.unwrap());
+<a href=#430 id=430 data-nosnippet>430</a> }
+<a href=#431 id=431 data-nosnippet>431</a>
+<a href=#432 id=432 data-nosnippet>432</a> <span class="attr">#[tokio::test]
+<a href=#433 id=433 data-nosnippet>433</a> </span><span class="kw">async fn </span>test_memory_storage_delete_prefix() {
+<a href=#434 id=434 data-nosnippet>434</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#435 id=435 data-nosnippet>435</a>
+<a href=#436 id=436 data-nosnippet>436</a> <span class="comment">// Create multiple files
+<a href=#437 id=437 data-nosnippet>437</a> </span>storage
+<a href=#438 id=438 data-nosnippet>438</a> .write(<span class="string">"memory://dir/file1.txt"</span>, Bytes::from(<span class="string">"1"</span>))
+<a href=#439 id=439 data-nosnippet>439</a> .<span class="kw">await
+<a href=#440 id=440 data-nosnippet>440</a> </span>.unwrap();
+<a href=#441 id=441 data-nosnippet>441</a> storage
+<a href=#442 id=442 data-nosnippet>442</a> .write(<span class="string">"memory://dir/file2.txt"</span>, Bytes::from(<span class="string">"2"</span>))
+<a href=#443 id=443 data-nosnippet>443</a> .<span class="kw">await
+<a href=#444 id=444 data-nosnippet>444</a> </span>.unwrap();
+<a href=#445 id=445 data-nosnippet>445</a> storage
+<a href=#446 id=446 data-nosnippet>446</a> .write(<span class="string">"memory://other/file.txt"</span>, Bytes::from(<span class="string">"3"</span>))
+<a href=#447 id=447 data-nosnippet>447</a> .<span class="kw">await
+<a href=#448 id=448 data-nosnippet>448</a> </span>.unwrap();
+<a href=#449 id=449 data-nosnippet>449</a>
+<a href=#450 id=450 data-nosnippet>450</a> <span class="comment">// Delete prefix
+<a href=#451 id=451 data-nosnippet>451</a> </span>storage.delete_prefix(<span class="string">"memory://dir"</span>).<span class="kw">await</span>.unwrap();
+<a href=#452 id=452 data-nosnippet>452</a>
+<a href=#453 id=453 data-nosnippet>453</a> <span class="comment">// Files in dir should be deleted
+<a href=#454 id=454 data-nosnippet>454</a> </span><span class="macro">assert!</span>(!storage.exists(<span class="string">"memory://dir/file1.txt"</span>).<span class="kw">await</span>.unwrap());
+<a href=#455 id=455 data-nosnippet>455</a> <span class="macro">assert!</span>(!storage.exists(<span class="string">"memory://dir/file2.txt"</span>).<span class="kw">await</span>.unwrap());
+<a href=#456 id=456 data-nosnippet>456</a>
+<a href=#457 id=457 data-nosnippet>457</a> <span class="comment">// File in other dir should still exist
+<a href=#458 id=458 data-nosnippet>458</a> </span><span class="macro">assert!</span>(storage.exists(<span class="string">"memory://other/file.txt"</span>).<span class="kw">await</span>.unwrap());
+<a href=#459 id=459 data-nosnippet>459</a> }
+<a href=#460 id=460 data-nosnippet>460</a>
+<a href=#461 id=461 data-nosnippet>461</a> <span class="attr">#[tokio::test]
+<a href=#462 id=462 data-nosnippet>462</a> </span><span class="kw">async fn </span>test_memory_storage_reader() {
+<a href=#463 id=463 data-nosnippet>463</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#464 id=464 data-nosnippet>464</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#465 id=465 data-nosnippet>465</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello, World!"</span>);
+<a href=#466 id=466 data-nosnippet>466</a>
+<a href=#467 id=467 data-nosnippet>467</a> storage.write(path, content.clone()).<span class="kw">await</span>.unwrap();
+<a href=#468 id=468 data-nosnippet>468</a>
+<a href=#469 id=469 data-nosnippet>469</a> <span class="kw">let </span>reader = storage.reader(path).<span class="kw">await</span>.unwrap();
+<a href=#470 id=470 data-nosnippet>470</a> <span class="kw">let </span>read_content = reader.read(<span class="number">0</span>..content.len() <span class="kw">as </span>u64).<span class="kw">await</span>.unwrap();
+<a href=#471 id=471 data-nosnippet>471</a> <span class="macro">assert_eq!</span>(read_content, content);
+<a href=#472 id=472 data-nosnippet>472</a>
+<a href=#473 id=473 data-nosnippet>473</a> <span class="comment">// Test partial read
+<a href=#474 id=474 data-nosnippet>474</a> </span><span class="kw">let </span>partial = reader.read(<span class="number">0</span>..<span class="number">5</span>).<span class="kw">await</span>.unwrap();
+<a href=#475 id=475 data-nosnippet>475</a> <span class="macro">assert_eq!</span>(partial, Bytes::from(<span class="string">"Hello"</span>));
+<a href=#476 id=476 data-nosnippet>476</a> }
+<a href=#477 id=477 data-nosnippet>477</a>
+<a href=#478 id=478 data-nosnippet>478</a> <span class="attr">#[tokio::test]
+<a href=#479 id=479 data-nosnippet>479</a> </span><span class="kw">async fn </span>test_memory_storage_writer() {
+<a href=#480 id=480 data-nosnippet>480</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#481 id=481 data-nosnippet>481</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#482 id=482 data-nosnippet>482</a>
+<a href=#483 id=483 data-nosnippet>483</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path).<span class="kw">await</span>.unwrap();
+<a href=#484 id=484 data-nosnippet>484</a> writer.write(Bytes::from(<span class="string">"Hello, "</span>)).<span class="kw">await</span>.unwrap();
+<a href=#485 id=485 data-nosnippet>485</a> writer.write(Bytes::from(<span class="string">"World!"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#486 id=486 data-nosnippet>486</a> <span class="kw">let </span>metadata = writer.close().<span class="kw">await</span>.unwrap();
+<a href=#487 id=487 data-nosnippet>487</a>
+<a href=#488 id=488 data-nosnippet>488</a> <span class="kw">let </span>content = storage.read(path).<span class="kw">await</span>.unwrap();
+<a href=#489 id=489 data-nosnippet>489</a> <span class="macro">assert_eq!</span>(content, Bytes::from(<span class="string">"Hello, World!"</span>));
+<a href=#490 id=490 data-nosnippet>490</a> <span class="macro">assert_eq!</span>(metadata.size, content.len() <span class="kw">as </span>u64);
+<a href=#491 id=491 data-nosnippet>491</a> }
+<a href=#492 id=492 data-nosnippet>492</a>
+<a href=#493 id=493 data-nosnippet>493</a> <span class="attr">#[tokio::test]
+<a href=#494 id=494 data-nosnippet>494</a> </span><span class="kw">async fn </span>test_memory_file_write_double_close() {
+<a href=#495 id=495 data-nosnippet>495</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#496 id=496 data-nosnippet>496</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#497 id=497 data-nosnippet>497</a>
+<a href=#498 id=498 data-nosnippet>498</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path).<span class="kw">await</span>.unwrap();
+<a href=#499 id=499 data-nosnippet>499</a> writer.write(Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>.unwrap();
+<a href=#500 id=500 data-nosnippet>500</a> writer.close().<span class="kw">await</span>.unwrap();
+<a href=#501 id=501 data-nosnippet>501</a>
+<a href=#502 id=502 data-nosnippet>502</a> <span class="comment">// Second close should fail
+<a href=#503 id=503 data-nosnippet>503</a> </span><span class="kw">let </span>result = writer.close().<span class="kw">await</span>;
+<a href=#504 id=504 data-nosnippet>504</a> <span class="macro">assert!</span>(result.is_err());
+<a href=#505 id=505 data-nosnippet>505</a> }
+<a href=#506 id=506 data-nosnippet>506</a>
+<a href=#507 id=507 data-nosnippet>507</a> <span class="attr">#[tokio::test]
+<a href=#508 id=508 data-nosnippet>508</a> </span><span class="kw">async fn </span>test_memory_file_write_after_close() {
+<a href=#509 id=509 data-nosnippet>509</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#510 id=510 data-nosnippet>510</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#511 id=511 data-nosnippet>511</a>
+<a href=#512 id=512 data-nosnippet>512</a> <span class="kw">let </span><span class="kw-2">mut </span>writer = storage.writer(path).<span class="kw">await</span>.unwrap();
+<a href=#513 id=513 data-nosnippet>513</a> <span class="macro">assert_eq!</span>(writer.close().<span class="kw">await</span>.unwrap().size, <span class="number">0</span>);
+<a href=#514 id=514 data-nosnippet>514</a>
+<a href=#515 id=515 data-nosnippet>515</a> <span class="comment">// Write after close should fail
+<a href=#516 id=516 data-nosnippet>516</a> </span><span class="kw">let </span>result = writer.write(Bytes::from(<span class="string">"test"</span>)).<span class="kw">await</span>;
+<a href=#517 id=517 data-nosnippet>517</a> <span class="macro">assert!</span>(result.is_err());
+<a href=#518 id=518 data-nosnippet>518</a> }
+<a href=#519 id=519 data-nosnippet>519</a>
+<a href=#520 id=520 data-nosnippet>520</a> <span class="attr">#[tokio::test]
+<a href=#521 id=521 data-nosnippet>521</a> </span><span class="kw">async fn </span>test_memory_file_read_out_of_bounds() {
+<a href=#522 id=522 data-nosnippet>522</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#523 id=523 data-nosnippet>523</a> <span class="kw">let </span>path = <span class="string">"memory://test/file.txt"</span>;
+<a href=#524 id=524 data-nosnippet>524</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"Hello"</span>);
<a href=#525 id=525 data-nosnippet>525</a>
-<a href=#526 id=526 data-nosnippet>526</a> <span class="kw">let </span>reader = storage.reader(path).<span class="kw">await</span>.unwrap();
-<a href=#527 id=527 data-nosnippet>527</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..<span class="number">100</span>).<span class="kw">await</span>;
-<a href=#528 id=528 data-nosnippet>528</a> <span class="macro">assert!</span>(result.is_err());
-<a href=#529 id=529 data-nosnippet>529</a> }
-<a href=#530 id=530 data-nosnippet>530</a>
-<a href=#531 id=531 data-nosnippet>531</a> <span class="attr">#[test]
-<a href=#532 id=532 data-nosnippet>532</a> </span><span class="kw">fn </span>test_memory_storage_serialization() {
-<a href=#533 id=533 data-nosnippet>533</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#534 id=534 data-nosnippet>534</a>
-<a href=#535 id=535 data-nosnippet>535</a> <span class="comment">// Serialize
-<a href=#536 id=536 data-nosnippet>536</a> </span><span class="kw">let </span>serialized = serde_json::to_string(<span class="kw-2">&</span>storage).unwrap();
-<a href=#537 id=537 data-nosnippet>537</a>
-<a href=#538 id=538 data-nosnippet>538</a> <span class="comment">// Deserialize
-<a href=#539 id=539 data-nosnippet>539</a> </span><span class="kw">let </span>deserialized: MemoryStorage = serde_json::from_str(<span class="kw-2">&</span>serialized).unwrap();
-<a href=#540 id=540 data-nosnippet>540</a>
-<a href=#541 id=541 data-nosnippet>541</a> <span class="comment">// Deserialized storage should be empty (new instance)
-<a href=#542 id=542 data-nosnippet>542</a> </span><span class="macro">assert!</span>(deserialized.data.read().unwrap().is_empty());
-<a href=#543 id=543 data-nosnippet>543</a> }
-<a href=#544 id=544 data-nosnippet>544</a>
-<a href=#545 id=545 data-nosnippet>545</a> <span class="attr">#[test]
-<a href=#546 id=546 data-nosnippet>546</a> </span><span class="kw">fn </span>test_memory_storage_factory() {
-<a href=#547 id=547 data-nosnippet>547</a> <span class="kw">let </span>factory = MemoryStorageFactory;
-<a href=#548 id=548 data-nosnippet>548</a> <span class="kw">let </span>config = StorageConfig::new();
-<a href=#549 id=549 data-nosnippet>549</a> <span class="kw">let </span>storage = factory.build(<span class="kw-2">&</span>config).unwrap();
-<a href=#550 id=550 data-nosnippet>550</a>
-<a href=#551 id=551 data-nosnippet>551</a> <span class="comment">// Verify we got a valid storage instance
-<a href=#552 id=552 data-nosnippet>552</a> </span><span class="macro">assert!</span>(<span class="macro">format!</span>(<span class="string">"{storage:?}"</span>).contains(<span class="string">"MemoryStorage"</span>));
-<a href=#553 id=553 data-nosnippet>553</a> }
-<a href=#554 id=554 data-nosnippet>554</a>
-<a href=#555 id=555 data-nosnippet>555</a> <span class="attr">#[test]
-<a href=#556 id=556 data-nosnippet>556</a> </span><span class="kw">fn </span>test_memory_storage_factory_serialization() {
-<a href=#557 id=557 data-nosnippet>557</a> <span class="kw">let </span>factory = MemoryStorageFactory;
-<a href=#558 id=558 data-nosnippet>558</a>
-<a href=#559 id=559 data-nosnippet>559</a> <span class="comment">// Serialize
-<a href=#560 id=560 data-nosnippet>560</a> </span><span class="kw">let </span>serialized = serde_json::to_string(<span class="kw-2">&</span>factory).unwrap();
-<a href=#561 id=561 data-nosnippet>561</a>
-<a href=#562 id=562 data-nosnippet>562</a> <span class="comment">// Deserialize
-<a href=#563 id=563 data-nosnippet>563</a> </span><span class="kw">let </span>deserialized: MemoryStorageFactory = serde_json::from_str(<span class="kw-2">&</span>serialized).unwrap();
-<a href=#564 id=564 data-nosnippet>564</a>
-<a href=#565 id=565 data-nosnippet>565</a> <span class="comment">// Verify the deserialized factory works
-<a href=#566 id=566 data-nosnippet>566</a> </span><span class="kw">let </span>config = StorageConfig::new();
-<a href=#567 id=567 data-nosnippet>567</a> <span class="kw">let </span>storage = deserialized.build(<span class="kw-2">&</span>config).unwrap();
-<a href=#568 id=568 data-nosnippet>568</a> <span class="macro">assert!</span>(<span class="macro">format!</span>(<span class="string">"{storage:?}"</span>).contains(<span class="string">"MemoryStorage"</span>));
-<a href=#569 id=569 data-nosnippet>569</a> }
-<a href=#570 id=570 data-nosnippet>570</a>
-<a href=#571 id=571 data-nosnippet>571</a> <span class="attr">#[tokio::test]
-<a href=#572 id=572 data-nosnippet>572</a> </span><span class="kw">async fn </span>test_path_normalization_consistency() {
-<a href=#573 id=573 data-nosnippet>573</a> <span class="kw">let </span>storage = MemoryStorage::new();
-<a href=#574 id=574 data-nosnippet>574</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"test content"</span>);
-<a href=#575 id=575 data-nosnippet>575</a>
-<a href=#576 id=576 data-nosnippet>576</a> <span class="comment">// Write with one format
-<a href=#577 id=577 data-nosnippet>577</a> </span>storage
-<a href=#578 id=578 data-nosnippet>578</a> .write(<span class="string">"memory://path/to/file"</span>, content.clone())
-<a href=#579 id=579 data-nosnippet>579</a> .<span class="kw">await
-<a href=#580 id=580 data-nosnippet>580</a> </span>.unwrap();
-<a href=#581 id=581 data-nosnippet>581</a>
-<a href=#582 id=582 data-nosnippet>582</a> <span class="comment">// Read with different formats - all should work
-<a href=#583 id=583 data-nosnippet>583</a> </span><span class="macro">assert_eq!</span>(
-<a href=#584 id=584 data-nosnippet>584</a> storage.read(<span class="string">"memory://path/to/file"</span>).<span class="kw">await</span>.unwrap(),
-<a href=#585 id=585 data-nosnippet>585</a> content
-<a href=#586 id=586 data-nosnippet>586</a> );
-<a href=#587 id=587 data-nosnippet>587</a> <span class="macro">assert_eq!</span>(storage.read(<span class="string">"memory:/path/to/file"</span>).<span class="kw">await</span>.unwrap(), content);
-<a href=#588 id=588 data-nosnippet>588</a> <span class="macro">assert_eq!</span>(storage.read(<span class="string">"/path/to/file"</span>).<span class="kw">await</span>.unwrap(), content);
-<a href=#589 id=589 data-nosnippet>589</a> <span class="macro">assert_eq!</span>(storage.read(<span class="string">"path/to/file"</span>).<span class="kw">await</span>.unwrap(), content);
-<a href=#590 id=590 data-nosnippet>590</a> }
-<a href=#591 id=591 data-nosnippet>591</a>
-<a href=#592 id=592 data-nosnippet>592</a> <span class="attr">#[tokio::test]
-<a href=#593 id=593 data-nosnippet>593</a> </span><span class="kw">async fn </span>test_memory_storage_delete_stream() {
-<a href=#594 id=594 data-nosnippet>594</a> <span class="kw">use </span>futures::stream;
-<a href=#595 id=595 data-nosnippet>595</a>
-<a href=#596 id=596 data-nosnippet>596</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#526 id=526 data-nosnippet>526</a> storage.write(path, content).<span class="kw">await</span>.unwrap();
+<a href=#527 id=527 data-nosnippet>527</a>
+<a href=#528 id=528 data-nosnippet>528</a> <span class="kw">let </span>reader = storage.reader(path).<span class="kw">await</span>.unwrap();
+<a href=#529 id=529 data-nosnippet>529</a> <span class="kw">let </span>result = reader.read(<span class="number">0</span>..<span class="number">100</span>).<span class="kw">await</span>;
+<a href=#530 id=530 data-nosnippet>530</a> <span class="macro">assert!</span>(result.is_err());
+<a href=#531 id=531 data-nosnippet>531</a> }
+<a href=#532 id=532 data-nosnippet>532</a>
+<a href=#533 id=533 data-nosnippet>533</a> <span class="attr">#[test]
+<a href=#534 id=534 data-nosnippet>534</a> </span><span class="kw">fn </span>test_memory_storage_serialization() {
+<a href=#535 id=535 data-nosnippet>535</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#536 id=536 data-nosnippet>536</a>
+<a href=#537 id=537 data-nosnippet>537</a> <span class="comment">// Serialize
+<a href=#538 id=538 data-nosnippet>538</a> </span><span class="kw">let </span>serialized = serde_json::to_string(<span class="kw-2">&</span>storage).unwrap();
+<a href=#539 id=539 data-nosnippet>539</a>
+<a href=#540 id=540 data-nosnippet>540</a> <span class="comment">// Deserialize
+<a href=#541 id=541 data-nosnippet>541</a> </span><span class="kw">let </span>deserialized: MemoryStorage = serde_json::from_str(<span class="kw-2">&</span>serialized).unwrap();
+<a href=#542 id=542 data-nosnippet>542</a>
+<a href=#543 id=543 data-nosnippet>543</a> <span class="comment">// Deserialized storage should be empty (new instance)
+<a href=#544 id=544 data-nosnippet>544</a> </span><span class="macro">assert!</span>(deserialized.data.read().unwrap().is_empty());
+<a href=#545 id=545 data-nosnippet>545</a> }
+<a href=#546 id=546 data-nosnippet>546</a>
+<a href=#547 id=547 data-nosnippet>547</a> <span class="attr">#[test]
+<a href=#548 id=548 data-nosnippet>548</a> </span><span class="kw">fn </span>test_memory_storage_factory() {
+<a href=#549 id=549 data-nosnippet>549</a> <span class="kw">let </span>factory = MemoryStorageFactory;
+<a href=#550 id=550 data-nosnippet>550</a> <span class="kw">let </span>config = StorageConfig::new();
+<a href=#551 id=551 data-nosnippet>551</a> <span class="kw">let </span>storage = factory.build(<span class="kw-2">&</span>config).unwrap();
+<a href=#552 id=552 data-nosnippet>552</a>
+<a href=#553 id=553 data-nosnippet>553</a> <span class="comment">// Verify we got a valid storage instance
+<a href=#554 id=554 data-nosnippet>554</a> </span><span class="macro">assert!</span>(<span class="macro">format!</span>(<span class="string">"{storage:?}"</span>).contains(<span class="string">"MemoryStorage"</span>));
+<a href=#555 id=555 data-nosnippet>555</a> }
+<a href=#556 id=556 data-nosnippet>556</a>
+<a href=#557 id=557 data-nosnippet>557</a> <span class="attr">#[test]
+<a href=#558 id=558 data-nosnippet>558</a> </span><span class="kw">fn </span>test_memory_storage_factory_serialization() {
+<a href=#559 id=559 data-nosnippet>559</a> <span class="kw">let </span>factory = MemoryStorageFactory;
+<a href=#560 id=560 data-nosnippet>560</a>
+<a href=#561 id=561 data-nosnippet>561</a> <span class="comment">// Serialize
+<a href=#562 id=562 data-nosnippet>562</a> </span><span class="kw">let </span>serialized = serde_json::to_string(<span class="kw-2">&</span>factory).unwrap();
+<a href=#563 id=563 data-nosnippet>563</a>
+<a href=#564 id=564 data-nosnippet>564</a> <span class="comment">// Deserialize
+<a href=#565 id=565 data-nosnippet>565</a> </span><span class="kw">let </span>deserialized: MemoryStorageFactory = serde_json::from_str(<span class="kw-2">&</span>serialized).unwrap();
+<a href=#566 id=566 data-nosnippet>566</a>
+<a href=#567 id=567 data-nosnippet>567</a> <span class="comment">// Verify the deserialized factory works
+<a href=#568 id=568 data-nosnippet>568</a> </span><span class="kw">let </span>config = StorageConfig::new();
+<a href=#569 id=569 data-nosnippet>569</a> <span class="kw">let </span>storage = deserialized.build(<span class="kw-2">&</span>config).unwrap();
+<a href=#570 id=570 data-nosnippet>570</a> <span class="macro">assert!</span>(<span class="macro">format!</span>(<span class="string">"{storage:?}"</span>).contains(<span class="string">"MemoryStorage"</span>));
+<a href=#571 id=571 data-nosnippet>571</a> }
+<a href=#572 id=572 data-nosnippet>572</a>
+<a href=#573 id=573 data-nosnippet>573</a> <span class="attr">#[tokio::test]
+<a href=#574 id=574 data-nosnippet>574</a> </span><span class="kw">async fn </span>test_path_normalization_consistency() {
+<a href=#575 id=575 data-nosnippet>575</a> <span class="kw">let </span>storage = MemoryStorage::new();
+<a href=#576 id=576 data-nosnippet>576</a> <span class="kw">let </span>content = Bytes::from(<span class="string">"test content"</span>);
+<a href=#577 id=577 data-nosnippet>577</a>
+<a href=#578 id=578 data-nosnippet>578</a> <span class="comment">// Write with one format
+<a href=#579 id=579 data-nosnippet>579</a> </span>storage
+<a href=#580 id=580 data-nosnippet>580</a> .write(<span class="string">"memory://path/to/file"</span>, content.clone())
+<a href=#581 id=581 data-nosnippet>581</a> .<span class="kw">await
+<a href=#582 id=582 data-nosnippet>582</a> </span>.unwrap();
+<a href=#583 id=583 data-nosnippet>583</a>
+<a href=#584 id=584 data-nosnippet>584</a> <span class="comment">// Read with different formats - all should work
+<a href=#585 id=585 data-nosnippet>585</a> </span><span class="macro">assert_eq!</span>(
+<a href=#586 id=586 data-nosnippet>586</a> storage.read(<span class="string">"memory://path/to/file"</span>).<span class="kw">await</span>.unwrap(),
+<a href=#587 id=587 data-nosnippet>587</a> content
+<a href=#588 id=588 data-nosnippet>588</a> );
+<a href=#589 id=589 data-nosnippet>589</a> <span class="macro">assert_eq!</span>(storage.read(<span class="string">"memory:/path/to/file"</span>).<span class="kw">await</span>.unwrap(), content);
+<a href=#590 id=590 data-nosnippet>590</a> <span class="macro">assert_eq!</span>(storage.read(<span class="string">"/path/to/file"</span>).<span class="kw">await</span>.unwrap(), content);
+<a href=#591 id=591 data-nosnippet>591</a> <span class="macro">assert_eq!</span>(storage.read(<span class="string">"path/to/file"</span>).<span class="kw">await</span>.unwrap(), content);
+<a href=#592 id=592 data-nosnippet>592</a> }
+<a href=#593 id=593 data-nosnippet>593</a>
+<a href=#594 id=594 data-nosnippet>594</a> <span class="attr">#[tokio::test]
+<a href=#595 id=595 data-nosnippet>595</a> </span><span class="kw">async fn </span>test_memory_storage_delete_stream() {
+<a href=#596 id=596 data-nosnippet>596</a> <span class="kw">use </span>futures::stream;
<a href=#597 id=597 data-nosnippet>597</a>
-<a href=#598 id=598 data-nosnippet>598</a> <span class="comment">// Create multiple files
-<a href=#599 id=599 data-nosnippet>599</a> </span>storage
-<a href=#600 id=600 data-nosnippet>600</a> .write(<span class="string">"memory://file1.txt"</span>, Bytes::from(<span class="string">"1"</span>))
-<a href=#601 id=601 data-nosnippet>601</a> .<span class="kw">await
-<a href=#602 id=602 data-nosnippet>602</a> </span>.unwrap();
-<a href=#603 id=603 data-nosnippet>603</a> storage
-<a href=#604 id=604 data-nosnippet>604</a> .write(<span class="string">"memory://file2.txt"</span>, Bytes::from(<span class="string">"2"</span>))
-<a href=#605 id=605 data-nosnippet>605</a> .<span class="kw">await
-<a href=#606 id=606 data-nosnippet>606</a> </span>.unwrap();
-<a href=#607 id=607 data-nosnippet>607</a> storage
-<a href=#608 id=608 data-nosnippet>608</a> .write(<span class="string">"memory://file3.txt"</span>, Bytes::from(<span class="string">"3"</span>))
... 9294 lines suppressed ...