From 1ac22fa7bb23285cdc01bddac99c328009444d58 Mon Sep 17 00:00:00 2001 From: matheus23 Date: Thu, 9 Jul 2026 07:17:38 +0000 Subject: [PATCH] deploy: d11761dac543d52c328a0f82c23ae8cf47438788 --- pr/720/docs/bench/fn.connect_client.html | 2 +- pr/720/docs/bench/fn.drain_stream.html | 2 +- pr/720/docs/bench/fn.send_data_on_stream.html | 2 +- pr/720/docs/bench/fn.server_endpoint.html | 2 +- pr/720/docs/noq/congestion/struct.Cubic.html | 6 +- .../noq/congestion/struct.CubicConfig.html | 8 +- .../congestion/trait.ControllerFactory.html | 2 +- pr/720/docs/noq/enum.ClosePathError.html | 6 +- pr/720/docs/noq/enum.ConnectionError.html | 6 +- pr/720/docs/noq/enum.PathError.html | 6 +- pr/720/docs/noq/enum.ReadError.html | 6 +- pr/720/docs/noq/enum.ReadExactError.html | 6 +- pr/720/docs/noq/enum.ReadToEndError.html | 6 +- pr/720/docs/noq/enum.ResetError.html | 6 +- pr/720/docs/noq/enum.SendDatagramError.html | 6 +- pr/720/docs/noq/enum.StoppedError.html | 6 +- pr/720/docs/noq/enum.WriteError.html | 6 +- pr/720/docs/noq/struct.AcceptBi.html | 6 +- pr/720/docs/noq/struct.AcceptUni.html | 6 +- pr/720/docs/noq/struct.Closed.html | 4 +- pr/720/docs/noq/struct.ClosedStream.html | 2 +- pr/720/docs/noq/struct.Connection.html | 45 +- pr/720/docs/noq/struct.OnClosed.html | 4 +- pr/720/docs/noq/struct.OpenBi.html | 6 +- pr/720/docs/noq/struct.OpenUni.html | 6 +- pr/720/docs/noq/struct.ReadDatagram.html | 6 +- pr/720/docs/noq/struct.RecvStream.html | 27 +- pr/720/docs/noq/struct.SendDatagram.html | 6 +- pr/720/docs/noq/struct.SendStream.html | 24 +- pr/720/docs/noq/struct.Stopped.html | 6 +- .../docs/noq/struct.UnorderedRecvStream.html | 14 +- .../docs/noq/struct.WeakConnectionHandle.html | 10 +- pr/720/docs/noq/trait.NetworkChangeHint.html | 4 +- .../noq_proto/congestion/struct.Cubic.html | 8 +- .../congestion/struct.CubicConfig.html | 6 +- .../congestion/trait.Controller.html | 2 +- .../congestion/trait.ControllerFactory.html | 2 +- .../docs/noq_proto/enum.ClosePathError.html | 6 +- .../docs/noq_proto/enum.ConnectionError.html | 6 +- pr/720/docs/noq_proto/enum.Event.html | 4 +- pr/720/docs/noq_proto/enum.PathError.html | 6 +- pr/720/docs/noq_proto/enum.PathEvent.html | 2 +- .../docs/noq_proto/enum.ProtectedHeader.html | 2 +- pr/720/docs/noq_proto/struct.Connection.html | 68 +- .../struct.MultipathNotNegotiated.html | 4 +- .../docs/noq_proto/struct.TransportError.html | 2 +- .../noq_proto/trait.NetworkChangeHint.html | 4 +- .../docs/noq_udp/struct.UdpSocketState.html | 31 +- pr/720/docs/search.index/000adb4f555c.js | 1 - pr/720/docs/search.index/000ba6d7fd92.js | 1 - pr/720/docs/search.index/00142191e584.js | 1 - pr/720/docs/search.index/002e6e153d4b.js | 1 + pr/720/docs/search.index/0050c343edd2.js | 1 + pr/720/docs/search.index/006213420b7c.js | 1 + pr/720/docs/search.index/00be37f9a7bf.js | 1 + pr/720/docs/search.index/00c65b35b354.js | 1 + pr/720/docs/search.index/00de4b7c33fb.js | 1 + pr/720/docs/search.index/00e5308c2fbf.js | 1 + pr/720/docs/search.index/00ee768feb28.js | 1 - pr/720/docs/search.index/014f131aa095.js | 1 - pr/720/docs/search.index/0154adb96fb6.js | 1 + pr/720/docs/search.index/01ce2d730344.js | 1 + pr/720/docs/search.index/01ff1ca5c170.js | 1 + pr/720/docs/search.index/023324239cca.js | 1 - pr/720/docs/search.index/027e427e88a7.js | 1 - pr/720/docs/search.index/02acd92cbf01.js | 1 + pr/720/docs/search.index/02c3ae86743f.js | 1 + pr/720/docs/search.index/02cee3b0c9d6.js | 1 - pr/720/docs/search.index/03352c8d2282.js | 1 - pr/720/docs/search.index/048b2390409c.js | 1 + pr/720/docs/search.index/04cf39152c9a.js | 1 + pr/720/docs/search.index/04d8cce59752.js | 1 - pr/720/docs/search.index/051bae6da550.js | 1 + pr/720/docs/search.index/05284f2042e8.js | 1 - pr/720/docs/search.index/0536332d465c.js | 1 - pr/720/docs/search.index/058e2bfdda25.js | 1 - pr/720/docs/search.index/05ba80c533eb.js | 1 - pr/720/docs/search.index/05f2b00cde6a.js | 1 + pr/720/docs/search.index/05fe6673879d.js | 1 + pr/720/docs/search.index/0620fd046b92.js | 1 - pr/720/docs/search.index/06738305d393.js | 1 - pr/720/docs/search.index/06f31413a772.js | 1 - pr/720/docs/search.index/073ff5c952c1.js | 1 + pr/720/docs/search.index/0756dab3ae0d.js | 1 + pr/720/docs/search.index/0766b076163c.js | 1 + pr/720/docs/search.index/07aa85ef4d97.js | 1 - pr/720/docs/search.index/07c9dcfddcef.js | 1 + pr/720/docs/search.index/08410bada6e3.js | 1 - pr/720/docs/search.index/0867d8c9f05d.js | 1 - pr/720/docs/search.index/086dd93914d3.js | 1 + pr/720/docs/search.index/08723cac4615.js | 1 + pr/720/docs/search.index/08f0fa1cddd0.js | 1 - pr/720/docs/search.index/090b2c6b7f03.js | 1 + pr/720/docs/search.index/0a7259509e70.js | 1 + pr/720/docs/search.index/0a99e2bd71de.js | 1 - pr/720/docs/search.index/0b8e51928cc4.js | 1 + pr/720/docs/search.index/0d2ad13042cb.js | 1 + pr/720/docs/search.index/0d7d4a89683f.js | 1 + pr/720/docs/search.index/0d7f8c5032c4.js | 1 + pr/720/docs/search.index/0d89aabcdae7.js | 1 + pr/720/docs/search.index/0d9f9f9c3b24.js | 1 + pr/720/docs/search.index/0ded295865bc.js | 1 + pr/720/docs/search.index/0e276ddba088.js | 1 - pr/720/docs/search.index/0e2c4243bbb8.js | 1 - pr/720/docs/search.index/0e517afb84fa.js | 1 + pr/720/docs/search.index/0e8345b033a7.js | 1 + pr/720/docs/search.index/0ea74f411a20.js | 1 + pr/720/docs/search.index/0ed1801265ff.js | 1 - pr/720/docs/search.index/0f5552078702.js | 1 + pr/720/docs/search.index/0fa6c5affaaa.js | 1 + pr/720/docs/search.index/0fdf431ad34e.js | 1 + pr/720/docs/search.index/0fe80180cdfe.js | 1 + pr/720/docs/search.index/103a5d03a0ae.js | 1 - pr/720/docs/search.index/105593ddf996.js | 1 - pr/720/docs/search.index/10a7deb028db.js | 1 + pr/720/docs/search.index/10ce52a8a445.js | 1 + pr/720/docs/search.index/1110623e8ce9.js | 1 + pr/720/docs/search.index/11349ef54c1b.js | 1 - pr/720/docs/search.index/1153acfed1a0.js | 1 + pr/720/docs/search.index/11a0ed9e6082.js | 1 - pr/720/docs/search.index/11b0b034f6ac.js | 1 + pr/720/docs/search.index/11b42c6b0cf2.js | 1 - pr/720/docs/search.index/11e47b81ccfd.js | 1 + pr/720/docs/search.index/11f92487829f.js | 1 + pr/720/docs/search.index/121d0e5bbae7.js | 1 - pr/720/docs/search.index/1227057cb7dc.js | 1 - pr/720/docs/search.index/129a3202b537.js | 1 + pr/720/docs/search.index/1311b0a01323.js | 1 + pr/720/docs/search.index/135b5f2dd6d8.js | 1 - pr/720/docs/search.index/13e8cca7fdb1.js | 1 + pr/720/docs/search.index/1405631e8d2d.js | 1 + pr/720/docs/search.index/143fb6edbe65.js | 1 + pr/720/docs/search.index/1440b866445a.js | 1 - pr/720/docs/search.index/1453bc07b5d6.js | 1 + pr/720/docs/search.index/1461c0534145.js | 1 - pr/720/docs/search.index/1520bb97adae.js | 1 + pr/720/docs/search.index/153142114305.js | 1 + pr/720/docs/search.index/15497ca32227.js | 1 + pr/720/docs/search.index/1573b4768191.js | 1 - pr/720/docs/search.index/15b4edd8a8f5.js | 1 + pr/720/docs/search.index/15f7949486b1.js | 1 + pr/720/docs/search.index/16096c00710e.js | 1 - pr/720/docs/search.index/1631657485c6.js | 1 + pr/720/docs/search.index/163ee1b5b3a8.js | 1 + pr/720/docs/search.index/1654af6eb785.js | 1 + pr/720/docs/search.index/169f211e0328.js | 1 - pr/720/docs/search.index/16a23e4d7f90.js | 1 - pr/720/docs/search.index/16a2da4da53d.js | 1 + pr/720/docs/search.index/16a948641b54.js | 1 + pr/720/docs/search.index/16e70f825de2.js | 1 + pr/720/docs/search.index/16ed99e26abc.js | 1 - pr/720/docs/search.index/1703dcd812f8.js | 1 + pr/720/docs/search.index/1727786f31fa.js | 1 - pr/720/docs/search.index/175137e32580.js | 1 + pr/720/docs/search.index/178c38e077ae.js | 1 - pr/720/docs/search.index/178ca3667736.js | 1 - pr/720/docs/search.index/17a621e31f68.js | 1 + pr/720/docs/search.index/17aebfe0bb9d.js | 1 + pr/720/docs/search.index/17df49c14c76.js | 1 + pr/720/docs/search.index/182999809797.js | 1 - pr/720/docs/search.index/1834499c14e5.js | 1 - pr/720/docs/search.index/1858dd5f6144.js | 1 + pr/720/docs/search.index/18aeef727410.js | 1 - pr/720/docs/search.index/19b75bdc92f3.js | 1 - pr/720/docs/search.index/19c9dbfd629e.js | 1 - pr/720/docs/search.index/1a313ca338b0.js | 1 + pr/720/docs/search.index/1a45b3f127a1.js | 1 - pr/720/docs/search.index/1a4760f711b7.js | 1 - pr/720/docs/search.index/1a65a2901852.js | 1 - pr/720/docs/search.index/1a661bac4231.js | 1 + pr/720/docs/search.index/1b5ac0a0d3eb.js | 1 - pr/720/docs/search.index/1b8e9adbdcdb.js | 1 + pr/720/docs/search.index/1bb2d6c36549.js | 1 + pr/720/docs/search.index/1bb2d6d431c6.js | 1 - pr/720/docs/search.index/1bcbe3047453.js | 1 - pr/720/docs/search.index/1be2131faf3c.js | 1 - pr/720/docs/search.index/1be4871c7cfc.js | 1 - pr/720/docs/search.index/1c67c4cae9f3.js | 1 + pr/720/docs/search.index/1ca61b2e06ca.js | 1 + pr/720/docs/search.index/1cb57e2db032.js | 1 + pr/720/docs/search.index/1d073aeac2ba.js | 1 + pr/720/docs/search.index/1d276fafa4c6.js | 1 - pr/720/docs/search.index/1da0089589f8.js | 1 + pr/720/docs/search.index/1db6f0fddb6f.js | 1 - pr/720/docs/search.index/1dbb8572c4de.js | 1 - pr/720/docs/search.index/1e619d7f9016.js | 1 - pr/720/docs/search.index/1e76f3f2f3ae.js | 1 - pr/720/docs/search.index/1edda76fba5c.js | 1 - pr/720/docs/search.index/1fee3e0237a8.js | 1 - pr/720/docs/search.index/20173a2c01e8.js | 1 - pr/720/docs/search.index/20f76c7fa42e.js | 1 - pr/720/docs/search.index/21ba71cbe90a.js | 1 + pr/720/docs/search.index/21d8ee2846b8.js | 1 + pr/720/docs/search.index/21fc35579d6a.js | 1 - pr/720/docs/search.index/21fc60b1602f.js | 1 - pr/720/docs/search.index/2239713765f5.js | 1 - pr/720/docs/search.index/226ac74944f5.js | 1 + pr/720/docs/search.index/228447d4f222.js | 1 - pr/720/docs/search.index/22d00b1c59e3.js | 1 - pr/720/docs/search.index/233ca4e57e96.js | 1 + pr/720/docs/search.index/235afbc24e7c.js | 1 - pr/720/docs/search.index/23762464f5f4.js | 1 + pr/720/docs/search.index/23a40eca4762.js | 1 - pr/720/docs/search.index/23b208bab09b.js | 1 + pr/720/docs/search.index/2424bb274ca9.js | 1 - pr/720/docs/search.index/243cde139a13.js | 1 - pr/720/docs/search.index/24443483573e.js | 1 + pr/720/docs/search.index/245720643b05.js | 1 - pr/720/docs/search.index/24cf76e66d9a.js | 1 + pr/720/docs/search.index/2539e79c2dcd.js | 1 + pr/720/docs/search.index/254b3dc1eadd.js | 1 - pr/720/docs/search.index/255778576e99.js | 1 + pr/720/docs/search.index/25672b9a3070.js | 1 - pr/720/docs/search.index/2602dc5a7bc0.js | 1 - pr/720/docs/search.index/269ae53d56fe.js | 1 + pr/720/docs/search.index/26b19c61c64e.js | 1 - pr/720/docs/search.index/2713334de97c.js | 1 - pr/720/docs/search.index/271b78f43c84.js | 1 + pr/720/docs/search.index/2725d533e78b.js | 1 - pr/720/docs/search.index/275265ed50a5.js | 1 - pr/720/docs/search.index/2797aa38226c.js | 1 + pr/720/docs/search.index/27dc20cd64df.js | 1 - pr/720/docs/search.index/28e08809acf2.js | 1 + pr/720/docs/search.index/2909ad8af809.js | 1 + pr/720/docs/search.index/29212c997b44.js | 1 - pr/720/docs/search.index/2923606a2790.js | 1 - pr/720/docs/search.index/29503497fefb.js | 1 - pr/720/docs/search.index/29a4091c28ec.js | 1 - pr/720/docs/search.index/2a13341e5a7f.js | 1 + pr/720/docs/search.index/2aa572615107.js | 1 - pr/720/docs/search.index/2abad999474c.js | 1 + pr/720/docs/search.index/2b35b1fa753b.js | 1 - pr/720/docs/search.index/2b3dd3c328d1.js | 1 + pr/720/docs/search.index/2b9e99969beb.js | 1 - pr/720/docs/search.index/2bb7edc74135.js | 1 + pr/720/docs/search.index/2bc95fa13920.js | 1 - pr/720/docs/search.index/2be35184ddea.js | 1 - pr/720/docs/search.index/2c10172e8da1.js | 1 - pr/720/docs/search.index/2caa3300cc72.js | 1 + pr/720/docs/search.index/2ccce52d6bb9.js | 1 - pr/720/docs/search.index/2d153fd624bd.js | 1 + pr/720/docs/search.index/2d6225cca40e.js | 1 + pr/720/docs/search.index/2d9a6dddfba0.js | 1 - pr/720/docs/search.index/2dc983a2ccc0.js | 1 + pr/720/docs/search.index/2eec7becf814.js | 1 - pr/720/docs/search.index/2f9af585d36b.js | 1 + pr/720/docs/search.index/2fe26730b02a.js | 1 + pr/720/docs/search.index/3012000b3b33.js | 1 - pr/720/docs/search.index/3041b5b08137.js | 1 + pr/720/docs/search.index/3067b7ed1d8a.js | 1 - pr/720/docs/search.index/306b2c075538.js | 1 + pr/720/docs/search.index/30db8ea8ec7f.js | 1 + pr/720/docs/search.index/313cbeca05af.js | 1 - pr/720/docs/search.index/32222f9e344c.js | 1 - pr/720/docs/search.index/3247e5fdd14a.js | 1 + pr/720/docs/search.index/325a13350a7a.js | 1 - pr/720/docs/search.index/327aa5bf1162.js | 1 + pr/720/docs/search.index/330ed03d9762.js | 1 - pr/720/docs/search.index/332ba6c0b552.js | 1 + pr/720/docs/search.index/337314d00c2a.js | 1 - pr/720/docs/search.index/33a323740d96.js | 1 + pr/720/docs/search.index/33aa3ee11527.js | 1 + pr/720/docs/search.index/33ee246893ce.js | 1 - pr/720/docs/search.index/33f1a0a10f2d.js | 1 + pr/720/docs/search.index/340fac1d0ace.js | 1 + pr/720/docs/search.index/3461ae96092e.js | 1 + pr/720/docs/search.index/34d17abef16f.js | 1 - pr/720/docs/search.index/35454983f2d7.js | 1 + pr/720/docs/search.index/3545cf7f836f.js | 1 - pr/720/docs/search.index/358b5f8021f2.js | 1 - pr/720/docs/search.index/358dcb9f0de5.js | 1 - pr/720/docs/search.index/36ce02943eb1.js | 1 - pr/720/docs/search.index/36f320f1ba81.js | 1 + pr/720/docs/search.index/378b1aab08c9.js | 1 - pr/720/docs/search.index/378be24803ea.js | 1 + pr/720/docs/search.index/38509af683de.js | 1 + pr/720/docs/search.index/388d28ec6ee7.js | 1 - pr/720/docs/search.index/398edce99fb2.js | 1 + pr/720/docs/search.index/39cd5ed38a87.js | 1 + pr/720/docs/search.index/3a72e593e0b3.js | 1 + pr/720/docs/search.index/3a8f25986add.js | 1 - pr/720/docs/search.index/3ad93ce64a37.js | 1 - pr/720/docs/search.index/3aff0f2fea02.js | 1 + pr/720/docs/search.index/3b0d86fd7fb4.js | 1 - pr/720/docs/search.index/3b2c7cca574a.js | 1 - pr/720/docs/search.index/3b43efdb153b.js | 1 + pr/720/docs/search.index/3b53b2390177.js | 1 + pr/720/docs/search.index/3b91ca3f9acb.js | 1 + pr/720/docs/search.index/3bfe87876fca.js | 1 - pr/720/docs/search.index/3c0a881cec02.js | 1 + pr/720/docs/search.index/3c4d6a050636.js | 1 - pr/720/docs/search.index/3d9548e24189.js | 1 - pr/720/docs/search.index/3d985c0366b5.js | 1 - pr/720/docs/search.index/3e4ccfb55bfa.js | 1 + pr/720/docs/search.index/3e66de6aea10.js | 1 - pr/720/docs/search.index/3e70f6735510.js | 1 + pr/720/docs/search.index/3e7e25ece402.js | 1 + pr/720/docs/search.index/3e845aeac648.js | 1 + pr/720/docs/search.index/3ea7fcccf5b3.js | 1 - pr/720/docs/search.index/3ebb6f16d447.js | 1 - pr/720/docs/search.index/3f573bc8125f.js | 1 + .../{7ce496ab7c6d.js => 3f5aea27f45d.js} | 2 +- pr/720/docs/search.index/3f5c2e66fd15.js | 1 + pr/720/docs/search.index/3f639926587b.js | 1 - pr/720/docs/search.index/4084c65e327d.js | 1 + pr/720/docs/search.index/40fbc4e3aee2.js | 1 - pr/720/docs/search.index/4167a805d71e.js | 1 + pr/720/docs/search.index/4167ad16be7b.js | 1 + pr/720/docs/search.index/4177e23c85bd.js | 1 - pr/720/docs/search.index/41e0f1bd02bf.js | 1 + pr/720/docs/search.index/4273cf82f9c4.js | 1 + pr/720/docs/search.index/428750539964.js | 1 + pr/720/docs/search.index/42d2406e1020.js | 1 + pr/720/docs/search.index/42d3b763f13b.js | 1 - pr/720/docs/search.index/42daba1cef63.js | 1 + pr/720/docs/search.index/4331b9640b27.js | 1 + pr/720/docs/search.index/433c3dda6c7f.js | 1 + pr/720/docs/search.index/43819ce322e0.js | 1 - pr/720/docs/search.index/4471911fea22.js | 1 - pr/720/docs/search.index/448b5003b9dc.js | 1 + pr/720/docs/search.index/44bfb2b21a2e.js | 1 + pr/720/docs/search.index/454c52ea575e.js | 1 - pr/720/docs/search.index/458f9d447ca8.js | 1 - pr/720/docs/search.index/45b43961206f.js | 1 - pr/720/docs/search.index/45ccc7ad5291.js | 1 - pr/720/docs/search.index/45d9dd3f98fe.js | 1 - pr/720/docs/search.index/46205e713ecc.js | 1 + pr/720/docs/search.index/46221eeede87.js | 1 - pr/720/docs/search.index/46349ba99789.js | 1 + pr/720/docs/search.index/46dda721da8a.js | 1 - pr/720/docs/search.index/46fb88136a2a.js | 1 + pr/720/docs/search.index/4715969cb3bf.js | 1 - pr/720/docs/search.index/47f9564a89e4.js | 1 + pr/720/docs/search.index/482faea55872.js | 1 - pr/720/docs/search.index/48cb78020f8e.js | 1 - pr/720/docs/search.index/491826f98ad3.js | 1 - pr/720/docs/search.index/493e1a0b131a.js | 1 - pr/720/docs/search.index/49737cee27c8.js | 1 - pr/720/docs/search.index/4a6b146615f8.js | 1 + pr/720/docs/search.index/4ae5903ada8f.js | 1 - pr/720/docs/search.index/4b0efb148f32.js | 1 + pr/720/docs/search.index/4b3652259c76.js | 1 + pr/720/docs/search.index/4b5efd7b6a23.js | 1 - pr/720/docs/search.index/4b7dc887fedc.js | 1 + pr/720/docs/search.index/4bbac020109f.js | 1 + pr/720/docs/search.index/4c6ccd5ef6f9.js | 1 - pr/720/docs/search.index/4cb2932fc572.js | 1 + pr/720/docs/search.index/4cbe7f17ed91.js | 1 + pr/720/docs/search.index/4cc81ce44b1f.js | 1 + pr/720/docs/search.index/4dd22e56451b.js | 1 - pr/720/docs/search.index/4e14ce064f55.js | 1 + pr/720/docs/search.index/4e73de40c9f5.js | 1 - pr/720/docs/search.index/4ea9347ec9c1.js | 1 - pr/720/docs/search.index/4ea99a0432f7.js | 1 - pr/720/docs/search.index/4f020f79d021.js | 1 - pr/720/docs/search.index/4f3d19b6424b.js | 1 + pr/720/docs/search.index/4fbe24f6d57c.js | 1 - pr/720/docs/search.index/5012ed2e4dc3.js | 1 - pr/720/docs/search.index/504ca52d3ae9.js | 1 - pr/720/docs/search.index/508290633409.js | 1 - pr/720/docs/search.index/5106fdea4a6c.js | 1 - pr/720/docs/search.index/512b2221e6e7.js | 1 + pr/720/docs/search.index/51d0879dcf6d.js | 1 - pr/720/docs/search.index/5219aed485bd.js | 1 - pr/720/docs/search.index/52703ee3070c.js | 1 - pr/720/docs/search.index/52ddf1446ab6.js | 1 - pr/720/docs/search.index/53cea0b9a841.js | 1 + pr/720/docs/search.index/53ffd91bdfe9.js | 1 - pr/720/docs/search.index/5450ecaeec3d.js | 1 - pr/720/docs/search.index/5516462dd4eb.js | 1 + pr/720/docs/search.index/5525682f4073.js | 1 - pr/720/docs/search.index/563edf471dd7.js | 1 + pr/720/docs/search.index/56cab5b365ee.js | 1 + pr/720/docs/search.index/56f51737f884.js | 1 - pr/720/docs/search.index/5718d5014774.js | 1 - pr/720/docs/search.index/579722880242.js | 1 + pr/720/docs/search.index/57b5a794dbfd.js | 1 - pr/720/docs/search.index/5877afb34948.js | 1 - pr/720/docs/search.index/59718cd9c46f.js | 1 - pr/720/docs/search.index/598f05b02570.js | 1 - pr/720/docs/search.index/59d3892a5c9c.js | 1 - pr/720/docs/search.index/5a454e6b8e3d.js | 1 + pr/720/docs/search.index/5a5e2d8166b8.js | 1 - pr/720/docs/search.index/5a649cef0a96.js | 1 + pr/720/docs/search.index/5a7dfa305296.js | 1 - pr/720/docs/search.index/5b1f64117211.js | 1 - pr/720/docs/search.index/5b2d763cb01a.js | 1 + pr/720/docs/search.index/5b3c708e7c7f.js | 1 + pr/720/docs/search.index/5bff1c7ebbc7.js | 1 - pr/720/docs/search.index/5c06b39c26ac.js | 1 - pr/720/docs/search.index/5c14c7898b88.js | 1 - pr/720/docs/search.index/5c4ef8f443b9.js | 1 + pr/720/docs/search.index/5ce895e7e8e7.js | 1 + pr/720/docs/search.index/5d6612847f3a.js | 1 - pr/720/docs/search.index/5d7b5c402287.js | 1 - pr/720/docs/search.index/5d86574c4361.js | 1 + pr/720/docs/search.index/5e453f313503.js | 1 + pr/720/docs/search.index/5e4bf3861ee8.js | 1 - pr/720/docs/search.index/5e4f7698639b.js | 1 - pr/720/docs/search.index/5e924f1d2e1a.js | 1 + pr/720/docs/search.index/5e927132f915.js | 1 + pr/720/docs/search.index/5f09f98d1a04.js | 1 + pr/720/docs/search.index/5f2c5d55a404.js | 1 + pr/720/docs/search.index/6024cbf2ac8d.js | 1 - pr/720/docs/search.index/60287e11cc71.js | 1 - pr/720/docs/search.index/607b24e31083.js | 1 - pr/720/docs/search.index/60e98a5178e4.js | 1 - pr/720/docs/search.index/60eabdb6a059.js | 1 - pr/720/docs/search.index/61108dfc4c35.js | 1 + pr/720/docs/search.index/617ee73e3969.js | 1 - pr/720/docs/search.index/619b1251040a.js | 1 + pr/720/docs/search.index/61b0c96080da.js | 1 + pr/720/docs/search.index/62d9bdfe377f.js | 1 - pr/720/docs/search.index/630085df3b42.js | 1 + pr/720/docs/search.index/6327cdc02f4b.js | 1 - pr/720/docs/search.index/6344cc548748.js | 1 - pr/720/docs/search.index/642891ddd2e0.js | 1 - pr/720/docs/search.index/643b6936a58b.js | 1 - pr/720/docs/search.index/644655b6a37b.js | 1 - pr/720/docs/search.index/6483b5e7deef.js | 1 - pr/720/docs/search.index/64c2c1e2630c.js | 1 - pr/720/docs/search.index/64ddaa20de73.js | 1 - pr/720/docs/search.index/652e095d3b43.js | 1 - pr/720/docs/search.index/65a7280005a0.js | 1 + pr/720/docs/search.index/66141220346d.js | 1 + pr/720/docs/search.index/6648973ff739.js | 1 + pr/720/docs/search.index/66753853a13a.js | 1 - pr/720/docs/search.index/66fc142f300b.js | 1 - pr/720/docs/search.index/674efefd99bd.js | 1 + pr/720/docs/search.index/68343b5d5132.js | 1 + pr/720/docs/search.index/686d69560250.js | 1 + pr/720/docs/search.index/68a60c89df9d.js | 1 + pr/720/docs/search.index/6957822f864f.js | 1 - pr/720/docs/search.index/6971cfa6cb7c.js | 1 + pr/720/docs/search.index/69b1257472c5.js | 1 - pr/720/docs/search.index/6a398dfc8494.js | 1 + pr/720/docs/search.index/6af8c712a209.js | 1 + pr/720/docs/search.index/6b013a6e0b24.js | 1 + pr/720/docs/search.index/6b063349b342.js | 1 + pr/720/docs/search.index/6b2a45acfbf1.js | 1 - pr/720/docs/search.index/6b7ac8f4866d.js | 1 - pr/720/docs/search.index/6b95550a6642.js | 1 - pr/720/docs/search.index/6be7775146ac.js | 1 - pr/720/docs/search.index/6c223b5d689a.js | 1 - pr/720/docs/search.index/6c2c4dc5a026.js | 1 - pr/720/docs/search.index/6cc5a584e86e.js | 1 - pr/720/docs/search.index/6d172713b950.js | 1 - pr/720/docs/search.index/6d3e4d35925e.js | 1 - pr/720/docs/search.index/6d5bf0cc001d.js | 1 - pr/720/docs/search.index/6d8907ef9d8d.js | 1 + pr/720/docs/search.index/6dc536e1c4d1.js | 1 - pr/720/docs/search.index/6e058b4cb634.js | 1 - pr/720/docs/search.index/6e3afbd9ac87.js | 1 - pr/720/docs/search.index/6e9d4bfea4fb.js | 1 - pr/720/docs/search.index/6f49c791ea73.js | 1 + pr/720/docs/search.index/6f69eae96848.js | 1 + pr/720/docs/search.index/6f97b59b2ed3.js | 1 + pr/720/docs/search.index/6fb57124e92e.js | 1 - pr/720/docs/search.index/7062e3671fca.js | 1 + pr/720/docs/search.index/716b8677ab3a.js | 1 + pr/720/docs/search.index/71a0950cf629.js | 1 + pr/720/docs/search.index/71b075553573.js | 1 - pr/720/docs/search.index/7230b78ac5d0.js | 1 + pr/720/docs/search.index/7253c52cbe08.js | 1 + pr/720/docs/search.index/72b333c2cba0.js | 1 + pr/720/docs/search.index/73a29e4be1d7.js | 1 + pr/720/docs/search.index/74b35500777b.js | 1 + pr/720/docs/search.index/754a85f8c0e5.js | 1 + pr/720/docs/search.index/7557654d6c60.js | 1 + pr/720/docs/search.index/758d161430bc.js | 1 - pr/720/docs/search.index/758e54a129f0.js | 1 + pr/720/docs/search.index/758efd32c564.js | 1 + pr/720/docs/search.index/7617c97acd1f.js | 1 + pr/720/docs/search.index/7668997d4899.js | 1 + pr/720/docs/search.index/768ee4759e5c.js | 1 - pr/720/docs/search.index/776081052934.js | 1 + pr/720/docs/search.index/776540b8ab1a.js | 1 - pr/720/docs/search.index/779759506437.js | 1 - pr/720/docs/search.index/77c18862fa4c.js | 1 - pr/720/docs/search.index/77cafdb357d2.js | 1 + pr/720/docs/search.index/77cff9841c95.js | 1 - pr/720/docs/search.index/7811abcc9a5f.js | 1 - pr/720/docs/search.index/781f5efba775.js | 1 + pr/720/docs/search.index/78bdd7950dc0.js | 1 + pr/720/docs/search.index/78d93f5ae36e.js | 1 + pr/720/docs/search.index/7906e11d0aff.js | 1 - pr/720/docs/search.index/7907354f6eb1.js | 1 + pr/720/docs/search.index/795c95422e5f.js | 1 + pr/720/docs/search.index/79ad745a1e86.js | 1 + pr/720/docs/search.index/79dce85c194a.js | 1 + pr/720/docs/search.index/7cdfc41c47d8.js | 1 - pr/720/docs/search.index/7d274ea31c09.js | 1 + pr/720/docs/search.index/7d5fb1732d0e.js | 1 - pr/720/docs/search.index/7e26bb2f5dee.js | 1 + pr/720/docs/search.index/7e6d6e61a59f.js | 1 - pr/720/docs/search.index/7f0296d1eeab.js | 1 + pr/720/docs/search.index/7f48b0bba760.js | 1 + pr/720/docs/search.index/7f80dc322a83.js | 1 + pr/720/docs/search.index/7f8b0b9bd765.js | 1 + pr/720/docs/search.index/7ff31f82574b.js | 1 + pr/720/docs/search.index/desc/5c696247fc77.js | 1 - pr/720/docs/search.index/desc/8802f729d4c0.js | 1 + .../docs/search.index/entry/1d4df8beee4b.js | 1 + .../docs/search.index/entry/5dd52a43d8d0.js | 1 - .../search.index/function/29b54df1056d.js | 1 + .../search.index/function/dc6a9ddb2aa5.js | 1 - .../generic_inverted_index/5e274bd1d1e0.js | 1 - .../generic_inverted_index/af191f824100.js | 1 + .../name/{b64d8369dc91.js => a216655cbdda.js} | 2 +- .../{977a3ccfe9de.js => 0f19d05307c5.js} | 2 +- pr/720/docs/search.index/root.js | 2 +- pr/720/docs/search.index/type/3e16039ef44b.js | 1 + pr/720/docs/search.index/type/77cc909be087.js | 1 - pr/720/docs/src/noq/connection.rs.html | 2325 ++-- pr/720/docs/src/noq/recv_stream.rs.html | 992 +- pr/720/docs/src/noq/send_stream.rs.html | 471 +- .../src/noq_proto/congestion/cubic.rs.html | 333 +- .../docs/src/noq_proto/connection/mod.rs.html | 10783 ++++++++-------- .../src/noq_proto/connection/paths.rs.html | 2 +- .../src/noq_proto/connection/spaces.rs.html | 1463 ++- .../src/noq_proto/connection/stats.rs.html | 32 +- pr/720/docs/src/noq_proto/packet.rs.html | 2 +- pr/720/docs/src/noq_udp/cmsg/mod.rs.html | 5 +- pr/720/docs/src/noq_udp/unix.rs.html | 2464 ++-- 524 files changed, 9944 insertions(+), 9810 deletions(-) delete mode 100644 pr/720/docs/search.index/000adb4f555c.js delete mode 100644 pr/720/docs/search.index/000ba6d7fd92.js delete mode 100644 pr/720/docs/search.index/00142191e584.js create mode 100644 pr/720/docs/search.index/002e6e153d4b.js create mode 100644 pr/720/docs/search.index/0050c343edd2.js create mode 100644 pr/720/docs/search.index/006213420b7c.js create mode 100644 pr/720/docs/search.index/00be37f9a7bf.js create mode 100644 pr/720/docs/search.index/00c65b35b354.js create mode 100644 pr/720/docs/search.index/00de4b7c33fb.js create mode 100644 pr/720/docs/search.index/00e5308c2fbf.js delete mode 100644 pr/720/docs/search.index/00ee768feb28.js delete mode 100644 pr/720/docs/search.index/014f131aa095.js create mode 100644 pr/720/docs/search.index/0154adb96fb6.js create mode 100644 pr/720/docs/search.index/01ce2d730344.js create mode 100644 pr/720/docs/search.index/01ff1ca5c170.js delete mode 100644 pr/720/docs/search.index/023324239cca.js delete mode 100644 pr/720/docs/search.index/027e427e88a7.js create mode 100644 pr/720/docs/search.index/02acd92cbf01.js create mode 100644 pr/720/docs/search.index/02c3ae86743f.js delete mode 100644 pr/720/docs/search.index/02cee3b0c9d6.js delete mode 100644 pr/720/docs/search.index/03352c8d2282.js create mode 100644 pr/720/docs/search.index/048b2390409c.js create mode 100644 pr/720/docs/search.index/04cf39152c9a.js delete mode 100644 pr/720/docs/search.index/04d8cce59752.js create mode 100644 pr/720/docs/search.index/051bae6da550.js delete mode 100644 pr/720/docs/search.index/05284f2042e8.js delete mode 100644 pr/720/docs/search.index/0536332d465c.js delete mode 100644 pr/720/docs/search.index/058e2bfdda25.js delete mode 100644 pr/720/docs/search.index/05ba80c533eb.js create mode 100644 pr/720/docs/search.index/05f2b00cde6a.js create mode 100644 pr/720/docs/search.index/05fe6673879d.js delete mode 100644 pr/720/docs/search.index/0620fd046b92.js delete mode 100644 pr/720/docs/search.index/06738305d393.js delete mode 100644 pr/720/docs/search.index/06f31413a772.js create mode 100644 pr/720/docs/search.index/073ff5c952c1.js create mode 100644 pr/720/docs/search.index/0756dab3ae0d.js create mode 100644 pr/720/docs/search.index/0766b076163c.js delete mode 100644 pr/720/docs/search.index/07aa85ef4d97.js create mode 100644 pr/720/docs/search.index/07c9dcfddcef.js delete mode 100644 pr/720/docs/search.index/08410bada6e3.js delete mode 100644 pr/720/docs/search.index/0867d8c9f05d.js create mode 100644 pr/720/docs/search.index/086dd93914d3.js create mode 100644 pr/720/docs/search.index/08723cac4615.js delete mode 100644 pr/720/docs/search.index/08f0fa1cddd0.js create mode 100644 pr/720/docs/search.index/090b2c6b7f03.js create mode 100644 pr/720/docs/search.index/0a7259509e70.js delete mode 100644 pr/720/docs/search.index/0a99e2bd71de.js create mode 100644 pr/720/docs/search.index/0b8e51928cc4.js create mode 100644 pr/720/docs/search.index/0d2ad13042cb.js create mode 100644 pr/720/docs/search.index/0d7d4a89683f.js create mode 100644 pr/720/docs/search.index/0d7f8c5032c4.js create mode 100644 pr/720/docs/search.index/0d89aabcdae7.js create mode 100644 pr/720/docs/search.index/0d9f9f9c3b24.js create mode 100644 pr/720/docs/search.index/0ded295865bc.js delete mode 100644 pr/720/docs/search.index/0e276ddba088.js delete mode 100644 pr/720/docs/search.index/0e2c4243bbb8.js create mode 100644 pr/720/docs/search.index/0e517afb84fa.js create mode 100644 pr/720/docs/search.index/0e8345b033a7.js create mode 100644 pr/720/docs/search.index/0ea74f411a20.js delete mode 100644 pr/720/docs/search.index/0ed1801265ff.js create mode 100644 pr/720/docs/search.index/0f5552078702.js create mode 100644 pr/720/docs/search.index/0fa6c5affaaa.js create mode 100644 pr/720/docs/search.index/0fdf431ad34e.js create mode 100644 pr/720/docs/search.index/0fe80180cdfe.js delete mode 100644 pr/720/docs/search.index/103a5d03a0ae.js delete mode 100644 pr/720/docs/search.index/105593ddf996.js create mode 100644 pr/720/docs/search.index/10a7deb028db.js create mode 100644 pr/720/docs/search.index/10ce52a8a445.js create mode 100644 pr/720/docs/search.index/1110623e8ce9.js delete mode 100644 pr/720/docs/search.index/11349ef54c1b.js create mode 100644 pr/720/docs/search.index/1153acfed1a0.js delete mode 100644 pr/720/docs/search.index/11a0ed9e6082.js create mode 100644 pr/720/docs/search.index/11b0b034f6ac.js delete mode 100644 pr/720/docs/search.index/11b42c6b0cf2.js create mode 100644 pr/720/docs/search.index/11e47b81ccfd.js create mode 100644 pr/720/docs/search.index/11f92487829f.js delete mode 100644 pr/720/docs/search.index/121d0e5bbae7.js delete mode 100644 pr/720/docs/search.index/1227057cb7dc.js create mode 100644 pr/720/docs/search.index/129a3202b537.js create mode 100644 pr/720/docs/search.index/1311b0a01323.js delete mode 100644 pr/720/docs/search.index/135b5f2dd6d8.js create mode 100644 pr/720/docs/search.index/13e8cca7fdb1.js create mode 100644 pr/720/docs/search.index/1405631e8d2d.js create mode 100644 pr/720/docs/search.index/143fb6edbe65.js delete mode 100644 pr/720/docs/search.index/1440b866445a.js create mode 100644 pr/720/docs/search.index/1453bc07b5d6.js delete mode 100644 pr/720/docs/search.index/1461c0534145.js create mode 100644 pr/720/docs/search.index/1520bb97adae.js create mode 100644 pr/720/docs/search.index/153142114305.js create mode 100644 pr/720/docs/search.index/15497ca32227.js delete mode 100644 pr/720/docs/search.index/1573b4768191.js create mode 100644 pr/720/docs/search.index/15b4edd8a8f5.js create mode 100644 pr/720/docs/search.index/15f7949486b1.js delete mode 100644 pr/720/docs/search.index/16096c00710e.js create mode 100644 pr/720/docs/search.index/1631657485c6.js create mode 100644 pr/720/docs/search.index/163ee1b5b3a8.js create mode 100644 pr/720/docs/search.index/1654af6eb785.js delete mode 100644 pr/720/docs/search.index/169f211e0328.js delete mode 100644 pr/720/docs/search.index/16a23e4d7f90.js create mode 100644 pr/720/docs/search.index/16a2da4da53d.js create mode 100644 pr/720/docs/search.index/16a948641b54.js create mode 100644 pr/720/docs/search.index/16e70f825de2.js delete mode 100644 pr/720/docs/search.index/16ed99e26abc.js create mode 100644 pr/720/docs/search.index/1703dcd812f8.js delete mode 100644 pr/720/docs/search.index/1727786f31fa.js create mode 100644 pr/720/docs/search.index/175137e32580.js delete mode 100644 pr/720/docs/search.index/178c38e077ae.js delete mode 100644 pr/720/docs/search.index/178ca3667736.js create mode 100644 pr/720/docs/search.index/17a621e31f68.js create mode 100644 pr/720/docs/search.index/17aebfe0bb9d.js create mode 100644 pr/720/docs/search.index/17df49c14c76.js delete mode 100644 pr/720/docs/search.index/182999809797.js delete mode 100644 pr/720/docs/search.index/1834499c14e5.js create mode 100644 pr/720/docs/search.index/1858dd5f6144.js delete mode 100644 pr/720/docs/search.index/18aeef727410.js delete mode 100644 pr/720/docs/search.index/19b75bdc92f3.js delete mode 100644 pr/720/docs/search.index/19c9dbfd629e.js create mode 100644 pr/720/docs/search.index/1a313ca338b0.js delete mode 100644 pr/720/docs/search.index/1a45b3f127a1.js delete mode 100644 pr/720/docs/search.index/1a4760f711b7.js delete mode 100644 pr/720/docs/search.index/1a65a2901852.js create mode 100644 pr/720/docs/search.index/1a661bac4231.js delete mode 100644 pr/720/docs/search.index/1b5ac0a0d3eb.js create mode 100644 pr/720/docs/search.index/1b8e9adbdcdb.js create mode 100644 pr/720/docs/search.index/1bb2d6c36549.js delete mode 100644 pr/720/docs/search.index/1bb2d6d431c6.js delete mode 100644 pr/720/docs/search.index/1bcbe3047453.js delete mode 100644 pr/720/docs/search.index/1be2131faf3c.js delete mode 100644 pr/720/docs/search.index/1be4871c7cfc.js create mode 100644 pr/720/docs/search.index/1c67c4cae9f3.js create mode 100644 pr/720/docs/search.index/1ca61b2e06ca.js create mode 100644 pr/720/docs/search.index/1cb57e2db032.js create mode 100644 pr/720/docs/search.index/1d073aeac2ba.js delete mode 100644 pr/720/docs/search.index/1d276fafa4c6.js create mode 100644 pr/720/docs/search.index/1da0089589f8.js delete mode 100644 pr/720/docs/search.index/1db6f0fddb6f.js delete mode 100644 pr/720/docs/search.index/1dbb8572c4de.js delete mode 100644 pr/720/docs/search.index/1e619d7f9016.js delete mode 100644 pr/720/docs/search.index/1e76f3f2f3ae.js delete mode 100644 pr/720/docs/search.index/1edda76fba5c.js delete mode 100644 pr/720/docs/search.index/1fee3e0237a8.js delete mode 100644 pr/720/docs/search.index/20173a2c01e8.js delete mode 100644 pr/720/docs/search.index/20f76c7fa42e.js create mode 100644 pr/720/docs/search.index/21ba71cbe90a.js create mode 100644 pr/720/docs/search.index/21d8ee2846b8.js delete mode 100644 pr/720/docs/search.index/21fc35579d6a.js delete mode 100644 pr/720/docs/search.index/21fc60b1602f.js delete mode 100644 pr/720/docs/search.index/2239713765f5.js create mode 100644 pr/720/docs/search.index/226ac74944f5.js delete mode 100644 pr/720/docs/search.index/228447d4f222.js delete mode 100644 pr/720/docs/search.index/22d00b1c59e3.js create mode 100644 pr/720/docs/search.index/233ca4e57e96.js delete mode 100644 pr/720/docs/search.index/235afbc24e7c.js create mode 100644 pr/720/docs/search.index/23762464f5f4.js delete mode 100644 pr/720/docs/search.index/23a40eca4762.js create mode 100644 pr/720/docs/search.index/23b208bab09b.js delete mode 100644 pr/720/docs/search.index/2424bb274ca9.js delete mode 100644 pr/720/docs/search.index/243cde139a13.js create mode 100644 pr/720/docs/search.index/24443483573e.js delete mode 100644 pr/720/docs/search.index/245720643b05.js create mode 100644 pr/720/docs/search.index/24cf76e66d9a.js create mode 100644 pr/720/docs/search.index/2539e79c2dcd.js delete mode 100644 pr/720/docs/search.index/254b3dc1eadd.js create mode 100644 pr/720/docs/search.index/255778576e99.js delete mode 100644 pr/720/docs/search.index/25672b9a3070.js delete mode 100644 pr/720/docs/search.index/2602dc5a7bc0.js create mode 100644 pr/720/docs/search.index/269ae53d56fe.js delete mode 100644 pr/720/docs/search.index/26b19c61c64e.js delete mode 100644 pr/720/docs/search.index/2713334de97c.js create mode 100644 pr/720/docs/search.index/271b78f43c84.js delete mode 100644 pr/720/docs/search.index/2725d533e78b.js delete mode 100644 pr/720/docs/search.index/275265ed50a5.js create mode 100644 pr/720/docs/search.index/2797aa38226c.js delete mode 100644 pr/720/docs/search.index/27dc20cd64df.js create mode 100644 pr/720/docs/search.index/28e08809acf2.js create mode 100644 pr/720/docs/search.index/2909ad8af809.js delete mode 100644 pr/720/docs/search.index/29212c997b44.js delete mode 100644 pr/720/docs/search.index/2923606a2790.js delete mode 100644 pr/720/docs/search.index/29503497fefb.js delete mode 100644 pr/720/docs/search.index/29a4091c28ec.js create mode 100644 pr/720/docs/search.index/2a13341e5a7f.js delete mode 100644 pr/720/docs/search.index/2aa572615107.js create mode 100644 pr/720/docs/search.index/2abad999474c.js delete mode 100644 pr/720/docs/search.index/2b35b1fa753b.js create mode 100644 pr/720/docs/search.index/2b3dd3c328d1.js delete mode 100644 pr/720/docs/search.index/2b9e99969beb.js create mode 100644 pr/720/docs/search.index/2bb7edc74135.js delete mode 100644 pr/720/docs/search.index/2bc95fa13920.js delete mode 100644 pr/720/docs/search.index/2be35184ddea.js delete mode 100644 pr/720/docs/search.index/2c10172e8da1.js create mode 100644 pr/720/docs/search.index/2caa3300cc72.js delete mode 100644 pr/720/docs/search.index/2ccce52d6bb9.js create mode 100644 pr/720/docs/search.index/2d153fd624bd.js create mode 100644 pr/720/docs/search.index/2d6225cca40e.js delete mode 100644 pr/720/docs/search.index/2d9a6dddfba0.js create mode 100644 pr/720/docs/search.index/2dc983a2ccc0.js delete mode 100644 pr/720/docs/search.index/2eec7becf814.js create mode 100644 pr/720/docs/search.index/2f9af585d36b.js create mode 100644 pr/720/docs/search.index/2fe26730b02a.js delete mode 100644 pr/720/docs/search.index/3012000b3b33.js create mode 100644 pr/720/docs/search.index/3041b5b08137.js delete mode 100644 pr/720/docs/search.index/3067b7ed1d8a.js create mode 100644 pr/720/docs/search.index/306b2c075538.js create mode 100644 pr/720/docs/search.index/30db8ea8ec7f.js delete mode 100644 pr/720/docs/search.index/313cbeca05af.js delete mode 100644 pr/720/docs/search.index/32222f9e344c.js create mode 100644 pr/720/docs/search.index/3247e5fdd14a.js delete mode 100644 pr/720/docs/search.index/325a13350a7a.js create mode 100644 pr/720/docs/search.index/327aa5bf1162.js delete mode 100644 pr/720/docs/search.index/330ed03d9762.js create mode 100644 pr/720/docs/search.index/332ba6c0b552.js delete mode 100644 pr/720/docs/search.index/337314d00c2a.js create mode 100644 pr/720/docs/search.index/33a323740d96.js create mode 100644 pr/720/docs/search.index/33aa3ee11527.js delete mode 100644 pr/720/docs/search.index/33ee246893ce.js create mode 100644 pr/720/docs/search.index/33f1a0a10f2d.js create mode 100644 pr/720/docs/search.index/340fac1d0ace.js create mode 100644 pr/720/docs/search.index/3461ae96092e.js delete mode 100644 pr/720/docs/search.index/34d17abef16f.js create mode 100644 pr/720/docs/search.index/35454983f2d7.js delete mode 100644 pr/720/docs/search.index/3545cf7f836f.js delete mode 100644 pr/720/docs/search.index/358b5f8021f2.js delete mode 100644 pr/720/docs/search.index/358dcb9f0de5.js delete mode 100644 pr/720/docs/search.index/36ce02943eb1.js create mode 100644 pr/720/docs/search.index/36f320f1ba81.js delete mode 100644 pr/720/docs/search.index/378b1aab08c9.js create mode 100644 pr/720/docs/search.index/378be24803ea.js create mode 100644 pr/720/docs/search.index/38509af683de.js delete mode 100644 pr/720/docs/search.index/388d28ec6ee7.js create mode 100644 pr/720/docs/search.index/398edce99fb2.js create mode 100644 pr/720/docs/search.index/39cd5ed38a87.js create mode 100644 pr/720/docs/search.index/3a72e593e0b3.js delete mode 100644 pr/720/docs/search.index/3a8f25986add.js delete mode 100644 pr/720/docs/search.index/3ad93ce64a37.js create mode 100644 pr/720/docs/search.index/3aff0f2fea02.js delete mode 100644 pr/720/docs/search.index/3b0d86fd7fb4.js delete mode 100644 pr/720/docs/search.index/3b2c7cca574a.js create mode 100644 pr/720/docs/search.index/3b43efdb153b.js create mode 100644 pr/720/docs/search.index/3b53b2390177.js create mode 100644 pr/720/docs/search.index/3b91ca3f9acb.js delete mode 100644 pr/720/docs/search.index/3bfe87876fca.js create mode 100644 pr/720/docs/search.index/3c0a881cec02.js delete mode 100644 pr/720/docs/search.index/3c4d6a050636.js delete mode 100644 pr/720/docs/search.index/3d9548e24189.js delete mode 100644 pr/720/docs/search.index/3d985c0366b5.js create mode 100644 pr/720/docs/search.index/3e4ccfb55bfa.js delete mode 100644 pr/720/docs/search.index/3e66de6aea10.js create mode 100644 pr/720/docs/search.index/3e70f6735510.js create mode 100644 pr/720/docs/search.index/3e7e25ece402.js create mode 100644 pr/720/docs/search.index/3e845aeac648.js delete mode 100644 pr/720/docs/search.index/3ea7fcccf5b3.js delete mode 100644 pr/720/docs/search.index/3ebb6f16d447.js create mode 100644 pr/720/docs/search.index/3f573bc8125f.js rename pr/720/docs/search.index/{7ce496ab7c6d.js => 3f5aea27f45d.js} (55%) create mode 100644 pr/720/docs/search.index/3f5c2e66fd15.js delete mode 100644 pr/720/docs/search.index/3f639926587b.js create mode 100644 pr/720/docs/search.index/4084c65e327d.js delete mode 100644 pr/720/docs/search.index/40fbc4e3aee2.js create mode 100644 pr/720/docs/search.index/4167a805d71e.js create mode 100644 pr/720/docs/search.index/4167ad16be7b.js delete mode 100644 pr/720/docs/search.index/4177e23c85bd.js create mode 100644 pr/720/docs/search.index/41e0f1bd02bf.js create mode 100644 pr/720/docs/search.index/4273cf82f9c4.js create mode 100644 pr/720/docs/search.index/428750539964.js create mode 100644 pr/720/docs/search.index/42d2406e1020.js delete mode 100644 pr/720/docs/search.index/42d3b763f13b.js create mode 100644 pr/720/docs/search.index/42daba1cef63.js create mode 100644 pr/720/docs/search.index/4331b9640b27.js create mode 100644 pr/720/docs/search.index/433c3dda6c7f.js delete mode 100644 pr/720/docs/search.index/43819ce322e0.js delete mode 100644 pr/720/docs/search.index/4471911fea22.js create mode 100644 pr/720/docs/search.index/448b5003b9dc.js create mode 100644 pr/720/docs/search.index/44bfb2b21a2e.js delete mode 100644 pr/720/docs/search.index/454c52ea575e.js delete mode 100644 pr/720/docs/search.index/458f9d447ca8.js delete mode 100644 pr/720/docs/search.index/45b43961206f.js delete mode 100644 pr/720/docs/search.index/45ccc7ad5291.js delete mode 100644 pr/720/docs/search.index/45d9dd3f98fe.js create mode 100644 pr/720/docs/search.index/46205e713ecc.js delete mode 100644 pr/720/docs/search.index/46221eeede87.js create mode 100644 pr/720/docs/search.index/46349ba99789.js delete mode 100644 pr/720/docs/search.index/46dda721da8a.js create mode 100644 pr/720/docs/search.index/46fb88136a2a.js delete mode 100644 pr/720/docs/search.index/4715969cb3bf.js create mode 100644 pr/720/docs/search.index/47f9564a89e4.js delete mode 100644 pr/720/docs/search.index/482faea55872.js delete mode 100644 pr/720/docs/search.index/48cb78020f8e.js delete mode 100644 pr/720/docs/search.index/491826f98ad3.js delete mode 100644 pr/720/docs/search.index/493e1a0b131a.js delete mode 100644 pr/720/docs/search.index/49737cee27c8.js create mode 100644 pr/720/docs/search.index/4a6b146615f8.js delete mode 100644 pr/720/docs/search.index/4ae5903ada8f.js create mode 100644 pr/720/docs/search.index/4b0efb148f32.js create mode 100644 pr/720/docs/search.index/4b3652259c76.js delete mode 100644 pr/720/docs/search.index/4b5efd7b6a23.js create mode 100644 pr/720/docs/search.index/4b7dc887fedc.js create mode 100644 pr/720/docs/search.index/4bbac020109f.js delete mode 100644 pr/720/docs/search.index/4c6ccd5ef6f9.js create mode 100644 pr/720/docs/search.index/4cb2932fc572.js create mode 100644 pr/720/docs/search.index/4cbe7f17ed91.js create mode 100644 pr/720/docs/search.index/4cc81ce44b1f.js delete mode 100644 pr/720/docs/search.index/4dd22e56451b.js create mode 100644 pr/720/docs/search.index/4e14ce064f55.js delete mode 100644 pr/720/docs/search.index/4e73de40c9f5.js delete mode 100644 pr/720/docs/search.index/4ea9347ec9c1.js delete mode 100644 pr/720/docs/search.index/4ea99a0432f7.js delete mode 100644 pr/720/docs/search.index/4f020f79d021.js create mode 100644 pr/720/docs/search.index/4f3d19b6424b.js delete mode 100644 pr/720/docs/search.index/4fbe24f6d57c.js delete mode 100644 pr/720/docs/search.index/5012ed2e4dc3.js delete mode 100644 pr/720/docs/search.index/504ca52d3ae9.js delete mode 100644 pr/720/docs/search.index/508290633409.js delete mode 100644 pr/720/docs/search.index/5106fdea4a6c.js create mode 100644 pr/720/docs/search.index/512b2221e6e7.js delete mode 100644 pr/720/docs/search.index/51d0879dcf6d.js delete mode 100644 pr/720/docs/search.index/5219aed485bd.js delete mode 100644 pr/720/docs/search.index/52703ee3070c.js delete mode 100644 pr/720/docs/search.index/52ddf1446ab6.js create mode 100644 pr/720/docs/search.index/53cea0b9a841.js delete mode 100644 pr/720/docs/search.index/53ffd91bdfe9.js delete mode 100644 pr/720/docs/search.index/5450ecaeec3d.js create mode 100644 pr/720/docs/search.index/5516462dd4eb.js delete mode 100644 pr/720/docs/search.index/5525682f4073.js create mode 100644 pr/720/docs/search.index/563edf471dd7.js create mode 100644 pr/720/docs/search.index/56cab5b365ee.js delete mode 100644 pr/720/docs/search.index/56f51737f884.js delete mode 100644 pr/720/docs/search.index/5718d5014774.js create mode 100644 pr/720/docs/search.index/579722880242.js delete mode 100644 pr/720/docs/search.index/57b5a794dbfd.js delete mode 100644 pr/720/docs/search.index/5877afb34948.js delete mode 100644 pr/720/docs/search.index/59718cd9c46f.js delete mode 100644 pr/720/docs/search.index/598f05b02570.js delete mode 100644 pr/720/docs/search.index/59d3892a5c9c.js create mode 100644 pr/720/docs/search.index/5a454e6b8e3d.js delete mode 100644 pr/720/docs/search.index/5a5e2d8166b8.js create mode 100644 pr/720/docs/search.index/5a649cef0a96.js delete mode 100644 pr/720/docs/search.index/5a7dfa305296.js delete mode 100644 pr/720/docs/search.index/5b1f64117211.js create mode 100644 pr/720/docs/search.index/5b2d763cb01a.js create mode 100644 pr/720/docs/search.index/5b3c708e7c7f.js delete mode 100644 pr/720/docs/search.index/5bff1c7ebbc7.js delete mode 100644 pr/720/docs/search.index/5c06b39c26ac.js delete mode 100644 pr/720/docs/search.index/5c14c7898b88.js create mode 100644 pr/720/docs/search.index/5c4ef8f443b9.js create mode 100644 pr/720/docs/search.index/5ce895e7e8e7.js delete mode 100644 pr/720/docs/search.index/5d6612847f3a.js delete mode 100644 pr/720/docs/search.index/5d7b5c402287.js create mode 100644 pr/720/docs/search.index/5d86574c4361.js create mode 100644 pr/720/docs/search.index/5e453f313503.js delete mode 100644 pr/720/docs/search.index/5e4bf3861ee8.js delete mode 100644 pr/720/docs/search.index/5e4f7698639b.js create mode 100644 pr/720/docs/search.index/5e924f1d2e1a.js create mode 100644 pr/720/docs/search.index/5e927132f915.js create mode 100644 pr/720/docs/search.index/5f09f98d1a04.js create mode 100644 pr/720/docs/search.index/5f2c5d55a404.js delete mode 100644 pr/720/docs/search.index/6024cbf2ac8d.js delete mode 100644 pr/720/docs/search.index/60287e11cc71.js delete mode 100644 pr/720/docs/search.index/607b24e31083.js delete mode 100644 pr/720/docs/search.index/60e98a5178e4.js delete mode 100644 pr/720/docs/search.index/60eabdb6a059.js create mode 100644 pr/720/docs/search.index/61108dfc4c35.js delete mode 100644 pr/720/docs/search.index/617ee73e3969.js create mode 100644 pr/720/docs/search.index/619b1251040a.js create mode 100644 pr/720/docs/search.index/61b0c96080da.js delete mode 100644 pr/720/docs/search.index/62d9bdfe377f.js create mode 100644 pr/720/docs/search.index/630085df3b42.js delete mode 100644 pr/720/docs/search.index/6327cdc02f4b.js delete mode 100644 pr/720/docs/search.index/6344cc548748.js delete mode 100644 pr/720/docs/search.index/642891ddd2e0.js delete mode 100644 pr/720/docs/search.index/643b6936a58b.js delete mode 100644 pr/720/docs/search.index/644655b6a37b.js delete mode 100644 pr/720/docs/search.index/6483b5e7deef.js delete mode 100644 pr/720/docs/search.index/64c2c1e2630c.js delete mode 100644 pr/720/docs/search.index/64ddaa20de73.js delete mode 100644 pr/720/docs/search.index/652e095d3b43.js create mode 100644 pr/720/docs/search.index/65a7280005a0.js create mode 100644 pr/720/docs/search.index/66141220346d.js create mode 100644 pr/720/docs/search.index/6648973ff739.js delete mode 100644 pr/720/docs/search.index/66753853a13a.js delete mode 100644 pr/720/docs/search.index/66fc142f300b.js create mode 100644 pr/720/docs/search.index/674efefd99bd.js create mode 100644 pr/720/docs/search.index/68343b5d5132.js create mode 100644 pr/720/docs/search.index/686d69560250.js create mode 100644 pr/720/docs/search.index/68a60c89df9d.js delete mode 100644 pr/720/docs/search.index/6957822f864f.js create mode 100644 pr/720/docs/search.index/6971cfa6cb7c.js delete mode 100644 pr/720/docs/search.index/69b1257472c5.js create mode 100644 pr/720/docs/search.index/6a398dfc8494.js create mode 100644 pr/720/docs/search.index/6af8c712a209.js create mode 100644 pr/720/docs/search.index/6b013a6e0b24.js create mode 100644 pr/720/docs/search.index/6b063349b342.js delete mode 100644 pr/720/docs/search.index/6b2a45acfbf1.js delete mode 100644 pr/720/docs/search.index/6b7ac8f4866d.js delete mode 100644 pr/720/docs/search.index/6b95550a6642.js delete mode 100644 pr/720/docs/search.index/6be7775146ac.js delete mode 100644 pr/720/docs/search.index/6c223b5d689a.js delete mode 100644 pr/720/docs/search.index/6c2c4dc5a026.js delete mode 100644 pr/720/docs/search.index/6cc5a584e86e.js delete mode 100644 pr/720/docs/search.index/6d172713b950.js delete mode 100644 pr/720/docs/search.index/6d3e4d35925e.js delete mode 100644 pr/720/docs/search.index/6d5bf0cc001d.js create mode 100644 pr/720/docs/search.index/6d8907ef9d8d.js delete mode 100644 pr/720/docs/search.index/6dc536e1c4d1.js delete mode 100644 pr/720/docs/search.index/6e058b4cb634.js delete mode 100644 pr/720/docs/search.index/6e3afbd9ac87.js delete mode 100644 pr/720/docs/search.index/6e9d4bfea4fb.js create mode 100644 pr/720/docs/search.index/6f49c791ea73.js create mode 100644 pr/720/docs/search.index/6f69eae96848.js create mode 100644 pr/720/docs/search.index/6f97b59b2ed3.js delete mode 100644 pr/720/docs/search.index/6fb57124e92e.js create mode 100644 pr/720/docs/search.index/7062e3671fca.js create mode 100644 pr/720/docs/search.index/716b8677ab3a.js create mode 100644 pr/720/docs/search.index/71a0950cf629.js delete mode 100644 pr/720/docs/search.index/71b075553573.js create mode 100644 pr/720/docs/search.index/7230b78ac5d0.js create mode 100644 pr/720/docs/search.index/7253c52cbe08.js create mode 100644 pr/720/docs/search.index/72b333c2cba0.js create mode 100644 pr/720/docs/search.index/73a29e4be1d7.js create mode 100644 pr/720/docs/search.index/74b35500777b.js create mode 100644 pr/720/docs/search.index/754a85f8c0e5.js create mode 100644 pr/720/docs/search.index/7557654d6c60.js delete mode 100644 pr/720/docs/search.index/758d161430bc.js create mode 100644 pr/720/docs/search.index/758e54a129f0.js create mode 100644 pr/720/docs/search.index/758efd32c564.js create mode 100644 pr/720/docs/search.index/7617c97acd1f.js create mode 100644 pr/720/docs/search.index/7668997d4899.js delete mode 100644 pr/720/docs/search.index/768ee4759e5c.js create mode 100644 pr/720/docs/search.index/776081052934.js delete mode 100644 pr/720/docs/search.index/776540b8ab1a.js delete mode 100644 pr/720/docs/search.index/779759506437.js delete mode 100644 pr/720/docs/search.index/77c18862fa4c.js create mode 100644 pr/720/docs/search.index/77cafdb357d2.js delete mode 100644 pr/720/docs/search.index/77cff9841c95.js delete mode 100644 pr/720/docs/search.index/7811abcc9a5f.js create mode 100644 pr/720/docs/search.index/781f5efba775.js create mode 100644 pr/720/docs/search.index/78bdd7950dc0.js create mode 100644 pr/720/docs/search.index/78d93f5ae36e.js delete mode 100644 pr/720/docs/search.index/7906e11d0aff.js create mode 100644 pr/720/docs/search.index/7907354f6eb1.js create mode 100644 pr/720/docs/search.index/795c95422e5f.js create mode 100644 pr/720/docs/search.index/79ad745a1e86.js create mode 100644 pr/720/docs/search.index/79dce85c194a.js delete mode 100644 pr/720/docs/search.index/7cdfc41c47d8.js create mode 100644 pr/720/docs/search.index/7d274ea31c09.js delete mode 100644 pr/720/docs/search.index/7d5fb1732d0e.js create mode 100644 pr/720/docs/search.index/7e26bb2f5dee.js delete mode 100644 pr/720/docs/search.index/7e6d6e61a59f.js create mode 100644 pr/720/docs/search.index/7f0296d1eeab.js create mode 100644 pr/720/docs/search.index/7f48b0bba760.js create mode 100644 pr/720/docs/search.index/7f80dc322a83.js create mode 100644 pr/720/docs/search.index/7f8b0b9bd765.js create mode 100644 pr/720/docs/search.index/7ff31f82574b.js delete mode 100644 pr/720/docs/search.index/desc/5c696247fc77.js create mode 100644 pr/720/docs/search.index/desc/8802f729d4c0.js create mode 100644 pr/720/docs/search.index/entry/1d4df8beee4b.js delete mode 100644 pr/720/docs/search.index/entry/5dd52a43d8d0.js create mode 100644 pr/720/docs/search.index/function/29b54df1056d.js delete mode 100644 pr/720/docs/search.index/function/dc6a9ddb2aa5.js delete mode 100644 pr/720/docs/search.index/generic_inverted_index/5e274bd1d1e0.js create mode 100644 pr/720/docs/search.index/generic_inverted_index/af191f824100.js rename pr/720/docs/search.index/name/{b64d8369dc91.js => a216655cbdda.js} (52%) rename pr/720/docs/search.index/normalizedName/{977a3ccfe9de.js => 0f19d05307c5.js} (53%) create mode 100644 pr/720/docs/search.index/type/3e16039ef44b.js delete mode 100644 pr/720/docs/search.index/type/77cc909be087.js diff --git a/pr/720/docs/bench/fn.connect_client.html b/pr/720/docs/bench/fn.connect_client.html index 8d6adbccf..8d7d3562c 100644 --- a/pr/720/docs/bench/fn.connect_client.html +++ b/pr/720/docs/bench/fn.connect_client.html @@ -2,5 +2,5 @@ server_addr: SocketAddr, server_cert: CertificateDer<'_>, opt: Opt, -) -> Result<(Endpoint, Connection)>
Expand description

Create a client endpoint and client connection

+) -> Result<(Endpoint, Connection)>
Expand description

Create a client endpoint and client connection

\ No newline at end of file diff --git a/pr/720/docs/bench/fn.drain_stream.html b/pr/720/docs/bench/fn.drain_stream.html index 0da4068d3..3c1afc29e 100644 --- a/pr/720/docs/bench/fn.drain_stream.html +++ b/pr/720/docs/bench/fn.drain_stream.html @@ -1,4 +1,4 @@ drain_stream in bench - Rust

drain_stream

Function drain_stream 

Source
pub async fn drain_stream(
-    stream: RecvStream,
+    stream: RecvStream,
     read_unordered: bool,
 ) -> Result<usize>
\ No newline at end of file diff --git a/pr/720/docs/bench/fn.send_data_on_stream.html b/pr/720/docs/bench/fn.send_data_on_stream.html index 3e3c0fdb2..1982b23de 100644 --- a/pr/720/docs/bench/fn.send_data_on_stream.html +++ b/pr/720/docs/bench/fn.send_data_on_stream.html @@ -1,4 +1,4 @@ send_data_on_stream in bench - Rust

send_data_on_stream

Function send_data_on_stream 

Source
pub async fn send_data_on_stream(
-    stream: &mut SendStream,
+    stream: &mut SendStream,
     stream_size: u64,
 ) -> Result<()>
\ No newline at end of file diff --git a/pr/720/docs/bench/fn.server_endpoint.html b/pr/720/docs/bench/fn.server_endpoint.html index f1d25c09c..2b7bac5c1 100644 --- a/pr/720/docs/bench/fn.server_endpoint.html +++ b/pr/720/docs/bench/fn.server_endpoint.html @@ -3,5 +3,5 @@ cert: CertificateDer<'static>, key: PrivateKeyDer<'static>, opt: &Opt, -) -> (SocketAddr, Endpoint)
Expand description

Creates a server endpoint which runs on the given runtime

+) -> (SocketAddr, Endpoint)
Expand description

Creates a server endpoint which runs on the given runtime

\ No newline at end of file diff --git a/pr/720/docs/noq/congestion/struct.Cubic.html b/pr/720/docs/noq/congestion/struct.Cubic.html index 306b802bf..af3f73a9a 100644 --- a/pr/720/docs/noq/congestion/struct.Cubic.html +++ b/pr/720/docs/noq/congestion/struct.Cubic.html @@ -8,7 +8,7 @@ _pn: u64, app_limited: bool, rtt: &RttEstimator, -)
Packet deliveries were confirmed Read more
Source§

fn on_congestion_event( +)

Packet deliveries were confirmed Read more
Source§

fn on_congestion_event( &mut self, now: Instant, sent: Instant, @@ -16,9 +16,9 @@ is_ecn: bool, _lost_bytes: u64, _largest_lost_pn: u64, -)

Packets were deemed lost or marked congested Read more
Source§

fn on_spurious_congestion_event(&mut self)

Packets were incorrectly deemed lost Read more
Source§

fn on_mtu_update(&mut self, new_mtu: u16)

The known MTU for the current network path has been updated
Source§

fn window(&self) -> u64

Number of ack-eliciting bytes that may be in flight
Source§

fn metrics(&self) -> ControllerMetrics

Retrieve implementation-specific metrics used to populate qlog traces when they are enabled +)
Packets were deemed lost or marked congested Read more
Source§

fn on_spurious_congestion_event(&mut self)

Packets were incorrectly deemed lost Read more
Source§

fn on_mtu_update(&mut self, new_mtu: u16)

The known MTU for the current network path has been updated
Source§

fn window(&self) -> u64

Number of ack-eliciting bytes that may be in flight
Source§

fn metrics(&self) -> ControllerMetrics

Retrieve implementation-specific metrics used to populate qlog traces when they are enabled This is also used to alter the pacing of the connection with -pacing_rate and send_quantum
Source§

fn clone_box(&self) -> Box<dyn Controller>

Duplicate the controller’s state
Source§

fn initial_window(&self) -> u64

Initial congestion window
Source§

fn into_any(self: Box<Cubic>) -> Box<dyn Any>

Returns Self for use in down-casting to extract implementation details
Source§

fn on_sent(&mut self, now: Instant, bytes: u64, largest_pn: u64)

One or more packets were just sent
Source§

fn on_packet_sent(&mut self, now: Instant, bytes: u16, pn: u64)

One packet was just sent
Source§

fn on_end_acks( +pacing_rate and send_quantum

Source§

fn clone_box(&self) -> Box<dyn Controller>

Duplicate the controller’s state
Source§

fn initial_window(&self) -> u64

Initial congestion window
Source§

fn into_any(self: Box<Cubic>) -> Box<dyn Any>

Returns Self for use in down-casting to extract implementation details
Source§

fn on_sent(&mut self, now: Instant, bytes: u64, largest_pn: u64)

One or more packets were just sent
Source§

fn on_packet_sent(&mut self, now: Instant, bytes: u16, pn: u64)

One packet was just sent
Source§

fn on_end_acks( &mut self, now: Instant, in_flight: u64, diff --git a/pr/720/docs/noq/congestion/struct.CubicConfig.html b/pr/720/docs/noq/congestion/struct.CubicConfig.html index 794cb2b54..69ea107af 100644 --- a/pr/720/docs/noq/congestion/struct.CubicConfig.html +++ b/pr/720/docs/noq/congestion/struct.CubicConfig.html @@ -1,11 +1,11 @@ -CubicConfig in noq::congestion - Rust

CubicConfig

Struct CubicConfig 

Source
pub struct CubicConfig { /* private fields */ }
Expand description

Configuration for the Cubic congestion controller

-

Implementations§

Source§

impl CubicConfig

Source

pub fn initial_window(&mut self, value: u64) -> &mut CubicConfig

Default limit on the amount of outstanding data in bytes.

+CubicConfig in noq::congestion - Rust

CubicConfig

Struct CubicConfig 

Source
pub struct CubicConfig { /* private fields */ }
Expand description

Configuration for the Cubic congestion controller

+

Implementations§

Source§

impl CubicConfig

Source

pub fn initial_window(&mut self, value: u64) -> &mut CubicConfig

Default limit on the amount of outstanding data in bytes.

Recommended value: min(10 * max_datagram_size, max(2 * max_datagram_size, 14720))

-

Trait Implementations§

Source§

impl Clone for CubicConfig

Source§

fn clone(&self) -> CubicConfig

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl ControllerFactory for CubicConfig

Trait Implementations§

Source§

impl Clone for CubicConfig

Source§

fn clone(&self) -> CubicConfig

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl ControllerFactory for CubicConfig

Source§

fn build( self: Arc<CubicConfig>, now: Instant, current_mtu: u16, -) -> Box<dyn Controller>

Construct a fresh Controller
Source§

impl Debug for CubicConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for CubicConfig

Source§

fn default() -> CubicConfig

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +) -> Box<dyn Controller>

Construct a fresh Controller
Source§

impl Debug for CubicConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for CubicConfig

Source§

fn default() -> CubicConfig

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/congestion/trait.ControllerFactory.html b/pr/720/docs/noq/congestion/trait.ControllerFactory.html index f9b43c998..9d63539e7 100644 --- a/pr/720/docs/noq/congestion/trait.ControllerFactory.html +++ b/pr/720/docs/noq/congestion/trait.ControllerFactory.html @@ -7,4 +7,4 @@ ) -> Box<dyn Controller>; }
Expand description

Constructs controllers on demand

Required Methods§

Source

fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller>

Construct a fresh Controller

-

Implementors§

\ No newline at end of file +

Implementors§

\ No newline at end of file diff --git a/pr/720/docs/noq/enum.ClosePathError.html b/pr/720/docs/noq/enum.ClosePathError.html index a89f719fe..db98e5d95 100644 --- a/pr/720/docs/noq/enum.ClosePathError.html +++ b/pr/720/docs/noq/enum.ClosePathError.html @@ -1,4 +1,4 @@ -ClosePathError in noq - Rust

ClosePathError

Enum ClosePathError 

Source
pub enum ClosePathError {
+ClosePathError in noq - Rust

ClosePathError

Enum ClosePathError 

Source
pub enum ClosePathError {
     MultipathNotNegotiated,
     ClosedPath,
     LastOpenPath,
@@ -7,8 +7,8 @@
 
§

ClosedPath

The path is already closed or was never opened

§

LastOpenPath

Cannot close the last remaining open path via the local API.

Use Connection::close to end the connection instead.

-

Trait Implementations§

Source§

impl Clone for ClosePathError

Source§

fn clone(&self) -> ClosePathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosePathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for ClosePathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for ClosePathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for ClosePathError

Source§

fn eq(&self, other: &ClosePathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ClosePathError

Source§

impl StructuralPartialEq for ClosePathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ClosePathError

Source§

fn clone(&self) -> ClosePathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosePathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for ClosePathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for ClosePathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for ClosePathError

Source§

fn eq(&self, other: &ClosePathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ClosePathError

Source§

impl StructuralPartialEq for ClosePathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.ConnectionError.html b/pr/720/docs/noq/enum.ConnectionError.html index e2d18c99d..96292ddfb 100644 --- a/pr/720/docs/noq/enum.ConnectionError.html +++ b/pr/720/docs/noq/enum.ConnectionError.html @@ -1,4 +1,4 @@ -ConnectionError in noq - Rust

ConnectionError

Enum ConnectionError 

Source
pub enum ConnectionError {
+ConnectionError in noq - Rust

ConnectionError

Enum ConnectionError 

Source
pub enum ConnectionError {
     VersionMismatch,
     TransportError(Error),
     ConnectionClosed(ConnectionClose),
@@ -20,8 +20,8 @@ and §

LocallyClosed

The local application closed the connection

§

CidsExhausted

The connection could not be created because not enough of the CID space is available

Try using longer connection IDs.

-

Trait Implementations§

Source§

impl Clone for ConnectionError

Source§

fn clone(&self) -> ConnectionError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConnectionError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for ConnectionError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for ConnectionError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Close> for ConnectionError

Source§

fn from(x: Close) -> ConnectionError

Converts to this type from the input type.
Source§

impl From<CloseReason> for ConnectionError

Source§

fn from(value: CloseReason) -> ConnectionError

Converts to this type from the input type.
Source§

impl From<ConnectionError> for ReadError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for ResetError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for SendDatagramError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for StoppedError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for WriteError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: Error) -> ConnectionError

Converts to this type from the input type.
Source§

impl PartialEq for ConnectionError

Source§

fn eq(&self, other: &ConnectionError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ConnectionError

Source§

impl StructuralPartialEq for ConnectionError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ConnectionError

Source§

fn clone(&self) -> ConnectionError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConnectionError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for ConnectionError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for ConnectionError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Close> for ConnectionError

Source§

fn from(x: Close) -> ConnectionError

Converts to this type from the input type.
Source§

impl From<CloseReason> for ConnectionError

Source§

fn from(value: CloseReason) -> ConnectionError

Converts to this type from the input type.
Source§

impl From<ConnectionError> for ReadError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for ResetError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for SendDatagramError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for StoppedError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for WriteError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: Error) -> ConnectionError

Converts to this type from the input type.
Source§

impl PartialEq for ConnectionError

Source§

fn eq(&self, other: &ConnectionError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ConnectionError

Source§

impl StructuralPartialEq for ConnectionError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.PathError.html b/pr/720/docs/noq/enum.PathError.html index e00abdbba..5dd66afdc 100644 --- a/pr/720/docs/noq/enum.PathError.html +++ b/pr/720/docs/noq/enum.PathError.html @@ -1,4 +1,4 @@ -PathError in noq - Rust

PathError

Enum PathError 

Source
pub enum PathError {
+PathError in noq - Rust

PathError

Enum PathError 

Source
pub enum PathError {
     MultipathNotNegotiated,
     ServerSideNotAllowed,
     MaxPathIdReached,
@@ -12,8 +12,8 @@
 
§

RemoteCidsExhausted

No remote CIDs available to open a new path

§

ValidationFailed

Path could not be validated and will be abandoned

§

InvalidRemoteAddress(SocketAddr)

The remote address for the path is not supported by the endpoint

-

Trait Implementations§

Source§

impl Clone for PathError

Source§

fn clone(&self) -> PathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for PathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for PathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for PathError

Source§

fn eq(&self, other: &PathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Copy for PathError

Source§

impl Eq for PathError

Source§

impl StructuralPartialEq for PathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for PathError

Source§

fn clone(&self) -> PathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for PathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for PathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for PathError

Source§

fn eq(&self, other: &PathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Copy for PathError

Source§

impl Eq for PathError

Source§

impl StructuralPartialEq for PathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.ReadError.html b/pr/720/docs/noq/enum.ReadError.html index 42be837cb..88b271964 100644 --- a/pr/720/docs/noq/enum.ReadError.html +++ b/pr/720/docs/noq/enum.ReadError.html @@ -1,4 +1,4 @@ -ReadError in noq - Rust

ReadError

Enum ReadError 

Source
pub enum ReadError {
+ReadError in noq - Rust

ReadError

Enum ReadError 

Source
pub enum ReadError {
     Reset(VarInt),
     ConnectionLost(ConnectionError),
     ClosedStream,
@@ -11,8 +11,8 @@
 
§

ZeroRttRejected

This was a 0-RTT stream and the server rejected it

Can only occur on clients for 0-RTT streams, which can be opened using Connecting::into_0rtt().

-

Trait Implementations§

Source§

impl Clone for ReadError

Source§

fn clone(&self) -> ReadError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ReadError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ReadError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ReadError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for ReadError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ReadError> for Error

Source§

fn from(x: ReadError) -> Self

Converts to this type from the input type.
Source§

impl From<ReadError> for ReadExactError

Source§

fn from(source: ReadError) -> Self

Converts to this type from the input type.
Source§

impl From<ReadError> for ReadToEndError

Source§

fn from(source: ReadError) -> Self

Converts to this type from the input type.
Source§

impl From<ResetError> for ReadError

Source§

fn from(e: ResetError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ReadError

Source§

fn eq(&self, other: &ReadError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ReadError

Source§

impl StructuralPartialEq for ReadError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ReadError

Source§

fn clone(&self) -> ReadError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ReadError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ReadError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ReadError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for ReadError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ReadError> for Error

Source§

fn from(x: ReadError) -> Self

Converts to this type from the input type.
Source§

impl From<ReadError> for ReadExactError

Source§

fn from(source: ReadError) -> Self

Converts to this type from the input type.
Source§

impl From<ReadError> for ReadToEndError

Source§

fn from(source: ReadError) -> Self

Converts to this type from the input type.
Source§

impl From<ResetError> for ReadError

Source§

fn from(e: ResetError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ReadError

Source§

fn eq(&self, other: &ReadError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ReadError

Source§

impl StructuralPartialEq for ReadError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.ReadExactError.html b/pr/720/docs/noq/enum.ReadExactError.html index 6b0f809bf..25a972416 100644 --- a/pr/720/docs/noq/enum.ReadExactError.html +++ b/pr/720/docs/noq/enum.ReadExactError.html @@ -1,11 +1,11 @@ -ReadExactError in noq - Rust

ReadExactError

Enum ReadExactError 

Source
pub enum ReadExactError {
+ReadExactError in noq - Rust

ReadExactError

Enum ReadExactError 

Source
pub enum ReadExactError {
     FinishedEarly(usize),
     ReadError(ReadError),
 }
Expand description

Errors that arise from reading from a stream.

Variants§

§

FinishedEarly(usize)

The stream finished before all bytes were read

§

ReadError(ReadError)

A read error occurred

-

Trait Implementations§

Source§

impl Clone for ReadExactError

Source§

fn clone(&self) -> ReadExactError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ReadExactError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ReadExactError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ReadExactError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ReadError> for ReadExactError

Source§

fn from(source: ReadError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ReadExactError

Source§

fn eq(&self, other: &ReadExactError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ReadExactError

Source§

impl StructuralPartialEq for ReadExactError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ReadExactError

Source§

fn clone(&self) -> ReadExactError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ReadExactError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ReadExactError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ReadExactError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ReadError> for ReadExactError

Source§

fn from(source: ReadError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ReadExactError

Source§

fn eq(&self, other: &ReadExactError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ReadExactError

Source§

impl StructuralPartialEq for ReadExactError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.ReadToEndError.html b/pr/720/docs/noq/enum.ReadToEndError.html index 27a7cf695..020e7d73d 100644 --- a/pr/720/docs/noq/enum.ReadToEndError.html +++ b/pr/720/docs/noq/enum.ReadToEndError.html @@ -1,11 +1,11 @@ -ReadToEndError in noq - Rust

ReadToEndError

Enum ReadToEndError 

Source
pub enum ReadToEndError {
+ReadToEndError in noq - Rust

ReadToEndError

Enum ReadToEndError 

Source
pub enum ReadToEndError {
     Read(ReadError),
     TooLong,
 }
Expand description

Variants§

§

Read(ReadError)

An error occurred during reading

§

TooLong

The stream is larger than the user-supplied limit

-

Trait Implementations§

Source§

impl Clone for ReadToEndError

Source§

fn clone(&self) -> ReadToEndError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ReadToEndError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ReadToEndError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ReadToEndError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ReadError> for ReadToEndError

Source§

fn from(source: ReadError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ReadToEndError

Source§

fn eq(&self, other: &ReadToEndError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ReadToEndError

Source§

impl StructuralPartialEq for ReadToEndError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ReadToEndError

Source§

fn clone(&self) -> ReadToEndError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ReadToEndError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ReadToEndError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ReadToEndError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ReadError> for ReadToEndError

Source§

fn from(source: ReadError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ReadToEndError

Source§

fn eq(&self, other: &ReadToEndError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ReadToEndError

Source§

impl StructuralPartialEq for ReadToEndError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.ResetError.html b/pr/720/docs/noq/enum.ResetError.html index 54175d61d..7449ff613 100644 --- a/pr/720/docs/noq/enum.ResetError.html +++ b/pr/720/docs/noq/enum.ResetError.html @@ -1,4 +1,4 @@ -ResetError in noq - Rust

ResetError

Enum ResetError 

Source
pub enum ResetError {
+ResetError in noq - Rust

ResetError

Enum ResetError 

Source
pub enum ResetError {
     ConnectionLost(ConnectionError),
     ZeroRttRejected,
 }
Expand description

Errors that arise while waiting for a stream to be reset

@@ -6,8 +6,8 @@
§

ZeroRttRejected

This was a 0-RTT stream and the server rejected it

Can only occur on clients for 0-RTT streams, which can be opened using Connecting::into_0rtt().

-

Trait Implementations§

Source§

impl Clone for ResetError

Source§

fn clone(&self) -> ResetError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ResetError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ResetError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ResetError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for ResetError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ResetError> for Error

Source§

fn from(x: ResetError) -> Self

Converts to this type from the input type.
Source§

impl From<ResetError> for ReadError

Source§

fn from(e: ResetError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ResetError

Source§

fn eq(&self, other: &ResetError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ResetError

Source§

impl StructuralPartialEq for ResetError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ResetError

Source§

fn clone(&self) -> ResetError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ResetError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ResetError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ResetError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for ResetError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<ResetError> for Error

Source§

fn from(x: ResetError) -> Self

Converts to this type from the input type.
Source§

impl From<ResetError> for ReadError

Source§

fn from(e: ResetError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ResetError

Source§

fn eq(&self, other: &ResetError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ResetError

Source§

impl StructuralPartialEq for ResetError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.SendDatagramError.html b/pr/720/docs/noq/enum.SendDatagramError.html index 166bb1057..1e24ac1a8 100644 --- a/pr/720/docs/noq/enum.SendDatagramError.html +++ b/pr/720/docs/noq/enum.SendDatagramError.html @@ -1,4 +1,4 @@ -SendDatagramError in noq - Rust

SendDatagramError

Enum SendDatagramError 

Source
pub enum SendDatagramError {
+SendDatagramError in noq - Rust

SendDatagramError

Enum SendDatagramError 

Source
pub enum SendDatagramError {
     UnsupportedByPeer,
     Disabled,
     TooLarge,
@@ -10,8 +10,8 @@
 

Indicates that the path MTU minus overhead or the limit advertised by the peer has been exceeded.

§

ConnectionLost(ConnectionError)

The connection was lost

-

Trait Implementations§

Source§

impl Clone for SendDatagramError

Source§

fn clone(&self) -> SendDatagramError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SendDatagramError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for SendDatagramError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for SendDatagramError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for SendDatagramError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for SendDatagramError

Source§

fn eq(&self, other: &SendDatagramError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for SendDatagramError

Source§

impl StructuralPartialEq for SendDatagramError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for SendDatagramError

Source§

fn clone(&self) -> SendDatagramError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SendDatagramError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for SendDatagramError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for SendDatagramError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for SendDatagramError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for SendDatagramError

Source§

fn eq(&self, other: &SendDatagramError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for SendDatagramError

Source§

impl StructuralPartialEq for SendDatagramError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.StoppedError.html b/pr/720/docs/noq/enum.StoppedError.html index 30261742b..d7797d926 100644 --- a/pr/720/docs/noq/enum.StoppedError.html +++ b/pr/720/docs/noq/enum.StoppedError.html @@ -1,4 +1,4 @@ -StoppedError in noq - Rust

StoppedError

Enum StoppedError 

Source
pub enum StoppedError {
+StoppedError in noq - Rust

StoppedError

Enum StoppedError 

Source
pub enum StoppedError {
     ConnectionLost(ConnectionError),
     ZeroRttRejected,
 }
Expand description

Errors that arise while monitoring for a send stream stop from the peer

@@ -6,8 +6,8 @@
§

ZeroRttRejected

This was a 0-RTT stream and the server rejected it

Can only occur on clients for 0-RTT streams, which can be opened using Connecting::into_0rtt().

-

Trait Implementations§

Source§

impl Clone for StoppedError

Source§

fn clone(&self) -> StoppedError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for StoppedError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for StoppedError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for StoppedError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for StoppedError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<StoppedError> for Error

Source§

fn from(x: StoppedError) -> Self

Converts to this type from the input type.
Source§

impl From<StoppedError> for WriteError

Source§

fn from(x: StoppedError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for StoppedError

Source§

fn eq(&self, other: &StoppedError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for StoppedError

Source§

impl StructuralPartialEq for StoppedError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for StoppedError

Source§

fn clone(&self) -> StoppedError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for StoppedError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for StoppedError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for StoppedError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for StoppedError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<StoppedError> for Error

Source§

fn from(x: StoppedError) -> Self

Converts to this type from the input type.
Source§

impl From<StoppedError> for WriteError

Source§

fn from(x: StoppedError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for StoppedError

Source§

fn eq(&self, other: &StoppedError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for StoppedError

Source§

impl StructuralPartialEq for StoppedError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/enum.WriteError.html b/pr/720/docs/noq/enum.WriteError.html index 247aeb25c..2a4703263 100644 --- a/pr/720/docs/noq/enum.WriteError.html +++ b/pr/720/docs/noq/enum.WriteError.html @@ -1,4 +1,4 @@ -WriteError in noq - Rust

WriteError

Enum WriteError 

Source
pub enum WriteError {
+WriteError in noq - Rust

WriteError

Enum WriteError 

Source
pub enum WriteError {
     Stopped(VarInt),
     ConnectionLost(ConnectionError),
     ClosedStream,
@@ -11,8 +11,8 @@
 
§

ZeroRttRejected

This was a 0-RTT stream and the server rejected it

Can only occur on clients for 0-RTT streams, which can be opened using Connecting::into_0rtt().

-

Trait Implementations§

Source§

impl Clone for WriteError

Source§

fn clone(&self) -> WriteError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WriteError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for WriteError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for WriteError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ClosedStream> for WriteError

Source§

fn from(_: ClosedStream) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for WriteError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<StoppedError> for WriteError

Source§

fn from(x: StoppedError) -> Self

Converts to this type from the input type.
Source§

impl From<WriteError> for Error

Source§

fn from(x: WriteError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for WriteError

Source§

fn eq(&self, other: &WriteError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for WriteError

Source§

impl StructuralPartialEq for WriteError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for WriteError

Source§

fn clone(&self) -> WriteError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WriteError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for WriteError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for WriteError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ClosedStream> for WriteError

Source§

fn from(_: ClosedStream) -> Self

Converts to this type from the input type.
Source§

impl From<ConnectionError> for WriteError

Source§

fn from(source: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<StoppedError> for WriteError

Source§

fn from(x: StoppedError) -> Self

Converts to this type from the input type.
Source§

impl From<WriteError> for Error

Source§

fn from(x: WriteError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for WriteError

Source§

fn eq(&self, other: &WriteError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for WriteError

Source§

impl StructuralPartialEq for WriteError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/struct.AcceptBi.html b/pr/720/docs/noq/struct.AcceptBi.html index f55b681ac..e8bf70633 100644 --- a/pr/720/docs/noq/struct.AcceptBi.html +++ b/pr/720/docs/noq/struct.AcceptBi.html @@ -1,6 +1,6 @@ -AcceptBi in noq - Rust

AcceptBi

Struct AcceptBi 

Source
pub struct AcceptBi<'a> { /* private fields */ }
Expand description

Future produced by Connection::accept_bi

-

Trait Implementations§

Source§

impl Future for AcceptBi<'_>

Source§

type Output = Result<(SendStream, RecvStream), ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering -the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for AcceptBi<'a>
where +AcceptBi in noq - Rust

AcceptBi

Struct AcceptBi 

Source
pub struct AcceptBi<'a> { /* private fields */ }
Expand description

Future produced by Connection::accept_bi

+

Trait Implementations§

Source§

impl Future for AcceptBi<'_>

Source§

type Output = Result<(SendStream, RecvStream), ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for AcceptBi<'a>
where PinnedFieldsOf<__Origin<'__pin, 'a>>: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for AcceptBi<'a>

§

impl<'a> !RefUnwindSafe for AcceptBi<'a>

§

impl<'a> Send for AcceptBi<'a>

§

impl<'a> Sync for AcceptBi<'a>

§

impl<'a> !UnwindSafe for AcceptBi<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.AcceptUni.html b/pr/720/docs/noq/struct.AcceptUni.html index 37056003a..64df14e68 100644 --- a/pr/720/docs/noq/struct.AcceptUni.html +++ b/pr/720/docs/noq/struct.AcceptUni.html @@ -1,6 +1,6 @@ -AcceptUni in noq - Rust

AcceptUni

Struct AcceptUni 

Source
pub struct AcceptUni<'a> { /* private fields */ }
Expand description

Future produced by Connection::accept_uni

-

Trait Implementations§

Source§

impl Future for AcceptUni<'_>

Source§

type Output = Result<RecvStream, ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering -the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for AcceptUni<'a>
where +AcceptUni in noq - Rust

AcceptUni

Struct AcceptUni 

Source
pub struct AcceptUni<'a> { /* private fields */ }
Expand description

Future produced by Connection::accept_uni

+

Trait Implementations§

Source§

impl Future for AcceptUni<'_>

Source§

type Output = Result<RecvStream, ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for AcceptUni<'a>
where PinnedFieldsOf<__Origin<'__pin, 'a>>: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for AcceptUni<'a>

§

impl<'a> !RefUnwindSafe for AcceptUni<'a>

§

impl<'a> Send for AcceptUni<'a>

§

impl<'a> Sync for AcceptUni<'a>

§

impl<'a> !UnwindSafe for AcceptUni<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.Closed.html b/pr/720/docs/noq/struct.Closed.html index 395ba0fba..f2a00f9e9 100644 --- a/pr/720/docs/noq/struct.Closed.html +++ b/pr/720/docs/noq/struct.Closed.html @@ -1,4 +1,4 @@ -Closed in noq - Rust

Closed

Struct Closed 

Source
#[non_exhaustive]
pub struct Closed { +Closed in noq - Rust

Closed

Struct Closed 

Source
#[non_exhaustive]
pub struct Closed { pub reason: ConnectionError, pub stats: ConnectionStats, pub path_stats: Vec<(PathId, PathStats)>, @@ -10,7 +10,7 @@

This includes paths that haven’t been discarded at close time, plus any already-discarded paths whose final stats had been retained because a Path or WeakPathHandle handle was kept alive.

-

Trait Implementations§

Source§

impl Clone for Closed

Source§

fn clone(&self) -> Closed

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Closed

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Closed

§

impl !RefUnwindSafe for Closed

§

impl Send for Closed

§

impl Sync for Closed

§

impl Unpin for Closed

§

impl !UnwindSafe for Closed

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for Closed

Source§

fn clone(&self) -> Closed

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Closed

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Closed

§

impl !RefUnwindSafe for Closed

§

impl Send for Closed

§

impl Sync for Closed

§

impl Unpin for Closed

§

impl !UnwindSafe for Closed

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/struct.ClosedStream.html b/pr/720/docs/noq/struct.ClosedStream.html index 03556400a..e1af73e02 100644 --- a/pr/720/docs/noq/struct.ClosedStream.html +++ b/pr/720/docs/noq/struct.ClosedStream.html @@ -1,5 +1,5 @@ ClosedStream in noq - Rust

ClosedStream

Struct ClosedStream 

Source
pub struct ClosedStream { /* private fields */ }
Expand description

Error indicating that a stream has not been opened or has already been finished or reset

-

Trait Implementations§

Source§

impl Clone for ClosedStream

Source§

fn clone(&self) -> ClosedStream

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosedStream

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for ClosedStream

Source§

fn default() -> ClosedStream

Returns the “default value” for a type. Read more
Source§

impl Display for ClosedStream

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for ClosedStream

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ClosedStream> for WriteError

Source§

fn from(_: ClosedStream) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ClosedStream

Source§

fn eq(&self, other: &ClosedStream) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +

Trait Implementations§

Source§

impl Clone for ClosedStream

Source§

fn clone(&self) -> ClosedStream

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosedStream

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for ClosedStream

Source§

fn default() -> ClosedStream

Returns the “default value” for a type. Read more
Source§

impl Display for ClosedStream

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for ClosedStream

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ClosedStream> for WriteError

Source§

fn from(_: ClosedStream) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ClosedStream

Source§

fn eq(&self, other: &ClosedStream) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for ClosedStream

Source§

impl StructuralPartialEq for ClosedStream

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.Connection.html b/pr/720/docs/noq/struct.Connection.html index 7e973b82d..92186c035 100644 --- a/pr/720/docs/noq/struct.Connection.html +++ b/pr/720/docs/noq/struct.Connection.html @@ -1,4 +1,4 @@ -Connection in noq - Rust

Connection

Struct Connection 

Source
pub struct Connection(/* private fields */);
Expand description

A QUIC connection.

+Connection in noq - Rust

Connection

Struct Connection 

Source
pub struct Connection(/* private fields */);
Expand description

A QUIC connection.

If all references to a connection (including every clone of the Connection handle, streams of incoming streams, and the various stream types) have been dropped, then the connection will be automatically closed with an error_code of 0 and an empty reason. You can also close the @@ -8,7 +8,7 @@ receiving CONNECTION_CLOSE the peer may drop any stream data not yet de application. Connection::close() describes in more detail how to gracefully close a connection without losing application data.

May be cloned to obtain another handle to the same connection.

-

Implementations§

Source§

impl Connection

Source

pub fn weak_handle(&self) -> WeakConnectionHandle

Returns a weak reference to the inner connection struct.

+

Implementations§

Source§

impl Connection

Source

pub fn weak_handle(&self) -> WeakConnectionHandle

Returns a weak reference to the inner connection struct.

Source

pub fn open_uni(&self) -> OpenUni<'_>

Initiate a new outgoing unidirectional stream.

Streams are cheap and instantaneous to open unless blocked by flow control. As a consequence, the peer won’t be notified that a stream has been opened until the stream is @@ -133,20 +133,29 @@ at most this size is guaranteed not to cause older datagrams to be dropped.

Source

pub fn stats(&self) -> ConnectionStats

Returns connection statistics

Source

pub fn path_stats(&self, path_id: PathId) -> Option<PathStats>

Returns path statistics

Source

pub fn congestion_state(&self, path_id: PathId) -> Option<Box<dyn Controller>>

Current state of the congestion control algorithm, for debugging purposes

-
Source

pub fn handshake_data(&self) -> Option<Box<dyn Any>>

Parameters negotiated during the handshake

+
Source

pub async fn authenticated(&self) -> Result<(), ConnectionError>

Succeeds when an incoming connection is proven not to be a replay attack.

+

Only interesting for Connections obtained from Connecting::into_0rtt. On 1-RTT +connections, always completes immediately. Contrast +handshake_confirmed, which waits longer on clients e.g. to +confirm client authentication.

+

For incoming connections, reads from RecvStreams are guaranteed not to arise from replay +attacks after this succeeds, even for streams accepted or read during 0-RTT. For outgoing +connections, streams opened after this succeeds will never be discarded by the server due to +0-RTT rejection.

+
Source

pub fn handshake_data(&self) -> Option<Box<dyn Any>>

Parameters negotiated during the handshake

Guaranteed to return Some on fully established connections or after Connecting::handshake_data() succeeds. See that method’s documentations for details on the returned value.

-
Source

pub fn peer_identity(&self) -> Option<Box<dyn Any>>

Cryptographic identity of the peer

+
Source

pub fn peer_identity(&self) -> Option<Box<dyn Any>>

Cryptographic identity of the peer

The dynamic type returned is determined by the configured Session. For the default rustls session, the return value can be downcast to a Vec<[rustls::pki_types::CertificateDer]>

-
Source

pub fn stable_id(&self) -> usize

A stable identifier for this connection

+
Source

pub fn stable_id(&self) -> usize

A stable identifier for this connection

Peer addresses and connection IDs can change, but this value will remain fixed for the lifetime of the connection.

-
Source

pub fn force_key_update(&self)

Update traffic keys spontaneously

+
Source

pub fn force_key_update(&self)

Update traffic keys spontaneously

This primarily exists for testing purposes.

-
Source

pub fn export_keying_material( +

Source

pub fn export_keying_material( &self, output: &mut [u8], label: &[u8], @@ -157,17 +166,17 @@ arguments and output buffers of equal length, they will get the same sequence of bytes in output. These bytes are cryptographically strong and pseudorandom, and are suitable for use as keying material.

See RFC5705 for more information.

-

Source

pub fn set_max_concurrent_uni_streams(&self, count: VarInt)

Modify the number of remotely initiated unidirectional streams that may be concurrently open

+
Source

pub fn set_max_concurrent_uni_streams(&self, count: VarInt)

Modify the number of remotely initiated unidirectional streams that may be concurrently open

No streams may be opened by the peer unless fewer than count are already open. Large counts increase both minimum and worst-case memory consumption.

-
Source

pub fn set_send_window(&self, send_window: u64)

Source

pub fn set_receive_window(&self, receive_window: VarInt)

Source

pub fn set_max_concurrent_bi_streams(&self, count: VarInt)

Modify the number of remotely initiated bidirectional streams that may be concurrently open

+
Source

pub fn set_send_window(&self, send_window: u64)

Source

pub fn set_receive_window(&self, receive_window: VarInt)

Source

pub fn set_max_concurrent_bi_streams(&self, count: VarInt)

Modify the number of remotely initiated bidirectional streams that may be concurrently open

No streams may be opened by the peer unless fewer than count are already open. Large counts increase both minimum and worst-case memory consumption.

-
Source

pub fn observed_external_addr(&self) -> ObservedExternalAddr

Track changes on our external address as reported by the peer.

-
Source

pub fn is_multipath_enabled(&self) -> bool

Is multipath enabled?

-
Source

pub fn add_nat_traversal_address( +

Source

pub fn observed_external_addr(&self) -> ObservedExternalAddr

Track changes on our external address as reported by the peer.

+
Source

pub fn is_multipath_enabled(&self) -> bool

Is multipath enabled?

+
Source

pub fn add_nat_traversal_address( &self, address: SocketAddr, ) -> Result<(), Error>

Registers one address at which this endpoint might be reachable

@@ -175,7 +184,7 @@ strong and pseudorandom, and are suitable for use as keying material.

ADD_ADDRESS frames. This allows clients to obtain server address candidates to initiate NAT traversal attempts. Clients provide their own reachable addresses in REACH_OUT frames when Self::initiate_nat_traversal_round is called.

-
Source

pub fn remove_nat_traversal_address( +

Source

pub fn remove_nat_traversal_address( &self, address: SocketAddr, ) -> Result<(), Error>

Removes one or more addresses from the set of addresses at which this endpoint is reachable

@@ -184,13 +193,13 @@ clients in REMOVE_ADDRESS frames. This allows clients to stop using server address candidates that are no longer valid for NAT traversal.

For clients, removed addresses will no longer be advertised in REACH_OUT frames.

Addresses not present in the set will be silently ignored.

-
Source

pub fn get_local_nat_traversal_addresses( +

Source

pub fn get_local_nat_traversal_addresses( &self, ) -> Result<Vec<SocketAddr>, Error>

Get the current local nat traversal addresses

-
Source

pub fn get_remote_nat_traversal_addresses( +

Source

pub fn get_remote_nat_traversal_addresses( &self, ) -> Result<Vec<SocketAddr>, Error>

Get the currently advertised nat traversal addresses by the server

-
Source

pub fn initiate_nat_traversal_round(&self) -> Result<Vec<SocketAddr>, Error>

Initiates a new nat traversal round

+
Source

pub fn initiate_nat_traversal_round(&self) -> Result<Vec<SocketAddr>, Error>

Initiates a new nat traversal round

A nat traversal round involves advertising the client’s local addresses in REACH_OUT frames, and initiating probing of the known remote addresses. When a new round is initiated, the previous one is cancelled, and paths that have not been opened are closed.

diff --git a/pr/720/docs/noq/struct.OnClosed.html b/pr/720/docs/noq/struct.OnClosed.html index 320b394ab..165915f41 100644 --- a/pr/720/docs/noq/struct.OnClosed.html +++ b/pr/720/docs/noq/struct.OnClosed.html @@ -1,6 +1,6 @@ -OnClosed in noq - Rust

OnClosed

Struct OnClosed 

Source
pub struct OnClosed { /* private fields */ }
Expand description

Future returned by Connection::on_closed

+OnClosed in noq - Rust

OnClosed

Struct OnClosed 

Source
pub struct OnClosed { /* private fields */ }
Expand description

Future returned by Connection::on_closed

Resolves to Closed.

-

Trait Implementations§

Source§

impl Drop for OnClosed

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl Future for OnClosed

Source§

type Output = Closed

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering +

Trait Implementations§

Source§

impl Drop for OnClosed

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl Future for OnClosed

Source§

type Output = Closed

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering the current task for wakeup if the value is not yet available. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.OpenBi.html b/pr/720/docs/noq/struct.OpenBi.html index 64efa41b2..73e2525e9 100644 --- a/pr/720/docs/noq/struct.OpenBi.html +++ b/pr/720/docs/noq/struct.OpenBi.html @@ -1,6 +1,6 @@ -OpenBi in noq - Rust

OpenBi

Struct OpenBi 

Source
pub struct OpenBi<'a> { /* private fields */ }
Expand description

Future produced by Connection::open_bi

-

Trait Implementations§

Source§

impl Future for OpenBi<'_>

Source§

type Output = Result<(SendStream, RecvStream), ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering -the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for OpenBi<'a>
where +OpenBi in noq - Rust

OpenBi

Struct OpenBi 

Source
pub struct OpenBi<'a> { /* private fields */ }
Expand description

Future produced by Connection::open_bi

+

Trait Implementations§

Source§

impl Future for OpenBi<'_>

Source§

type Output = Result<(SendStream, RecvStream), ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for OpenBi<'a>
where PinnedFieldsOf<__Origin<'__pin, 'a>>: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for OpenBi<'a>

§

impl<'a> !RefUnwindSafe for OpenBi<'a>

§

impl<'a> Send for OpenBi<'a>

§

impl<'a> Sync for OpenBi<'a>

§

impl<'a> !UnwindSafe for OpenBi<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.OpenUni.html b/pr/720/docs/noq/struct.OpenUni.html index 303258138..fb726045a 100644 --- a/pr/720/docs/noq/struct.OpenUni.html +++ b/pr/720/docs/noq/struct.OpenUni.html @@ -1,6 +1,6 @@ -OpenUni in noq - Rust

OpenUni

Struct OpenUni 

Source
pub struct OpenUni<'a> { /* private fields */ }
Expand description

Future produced by Connection::open_uni

-

Trait Implementations§

Source§

impl Future for OpenUni<'_>

Source§

type Output = Result<SendStream, ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering -the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for OpenUni<'a>
where +OpenUni in noq - Rust

OpenUni

Struct OpenUni 

Source
pub struct OpenUni<'a> { /* private fields */ }
Expand description

Future produced by Connection::open_uni

+

Trait Implementations§

Source§

impl Future for OpenUni<'_>

Source§

type Output = Result<SendStream, ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for OpenUni<'a>
where PinnedFieldsOf<__Origin<'__pin, 'a>>: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for OpenUni<'a>

§

impl<'a> !RefUnwindSafe for OpenUni<'a>

§

impl<'a> Send for OpenUni<'a>

§

impl<'a> Sync for OpenUni<'a>

§

impl<'a> !UnwindSafe for OpenUni<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.ReadDatagram.html b/pr/720/docs/noq/struct.ReadDatagram.html index fd1f86a4d..d8ac1914a 100644 --- a/pr/720/docs/noq/struct.ReadDatagram.html +++ b/pr/720/docs/noq/struct.ReadDatagram.html @@ -1,6 +1,6 @@ -ReadDatagram in noq - Rust

ReadDatagram

Struct ReadDatagram 

Source
pub struct ReadDatagram<'a> { /* private fields */ }
Expand description

Future produced by Connection::read_datagram

-

Trait Implementations§

Source§

impl Future for ReadDatagram<'_>

Source§

type Output = Result<Bytes, ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering -the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for ReadDatagram<'a>
where +ReadDatagram in noq - Rust

ReadDatagram

Struct ReadDatagram 

Source
pub struct ReadDatagram<'a> { /* private fields */ }
Expand description

Future produced by Connection::read_datagram

+

Trait Implementations§

Source§

impl Future for ReadDatagram<'_>

Source§

type Output = Result<Bytes, ConnectionError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for ReadDatagram<'a>
where PinnedFieldsOf<__Origin<'__pin, 'a>>: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for ReadDatagram<'a>

§

impl<'a> !RefUnwindSafe for ReadDatagram<'a>

§

impl<'a> Send for ReadDatagram<'a>

§

impl<'a> Sync for ReadDatagram<'a>

§

impl<'a> !UnwindSafe for ReadDatagram<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.RecvStream.html b/pr/720/docs/noq/struct.RecvStream.html index d281e6142..9bb97ca13 100644 --- a/pr/720/docs/noq/struct.RecvStream.html +++ b/pr/720/docs/noq/struct.RecvStream.html @@ -20,7 +20,7 @@ logging the StreamId. For example, even if a sender first transmits on bidirectional stream 1, the first stream yielded by Connection::accept_bi on the receiver will be bidirectional stream 0.

-

Implementations§

Source§

impl RecvStream

Source

pub async fn read(&mut self, buf: &mut [u8]) -> Result<Option<usize>, ReadError>

Read data contiguously from the stream.

+

Implementations§

Source§

impl RecvStream

Source

pub async fn read(&mut self, buf: &mut [u8]) -> Result<Option<usize>, ReadError>

Read data contiguously from the stream.

Yields the number of bytes read into buf on success, or None if the stream was finished.

This operation is cancel-safe.

Source

pub async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError>

Read an exact number of bytes contiguously from the stream.

@@ -71,21 +71,26 @@ arbitrary data.

Source

pub fn stop(&mut self, error_code: VarInt) -> Result<(), ClosedStream>

Stop accepting data

Discards unread data and notifies the peer to stop transmitting. Once stopped, further attempts to operate on a stream will yield ClosedStream errors.

-
Source

pub fn is_0rtt(&self) -> bool

Check if this stream has been opened during 0-RTT.

-

In which case any non-idempotent request should be considered dangerous at the application -level. Because read data is subject to replay attacks.

-
Source

pub fn id(&self) -> StreamId

Get the identity of this stream

-
Source

pub fn bytes_read(&self) -> Result<u64, ClosedStream>

Returns the number of bytes read from this stream.

+
Source

pub fn is_0rtt(&self) -> bool

Check if this stream predates completion of the handshake on an incoming connection.

+

True only if the stream was accepted before the handshake completed, which is only possible +if you successfully called Connecting::into_0rtt and the +client chose to send 0-RTT data.

+

Under those conditions, depending on cryptographic layer configuration, 0-RTT application +data may be a replay attack. To guard against this, applications should not execute +non-idempotent operations until +Connection::authenticated succeeds.

+
Source

pub fn id(&self) -> StreamId

Get the identity of this stream

+
Source

pub fn bytes_read(&self) -> Result<u64, ClosedStream>

Returns the number of bytes read from this stream.

This is the offset of the next byte to be read, i.e. the length of the contiguous prefix of the stream consumed by the application.

-
Source

pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError>

Completes when the stream has been reset by the peer or otherwise closed

+
Source

pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError>

Completes when the stream has been reset by the peer or otherwise closed

Yields Some with the reset error code when the stream is reset by the peer. Yields None when the stream was previously stop()ed, or when the stream was finish()ed by the peer and all data has been received, after which it is no longer meaningful for the stream to be reset.

This operation is cancel-safe.

-
Source

pub fn into_unordered(self) -> UnorderedRecvStream

Converts this stream into an unordered stream.

-

Trait Implementations§

Source§

impl AsyncRead for RecvStream

Available on crate feature futures-io only.
Source

pub fn into_unordered(self) -> UnorderedRecvStream

Converts this stream into an unordered stream.

+

Trait Implementations§

Source§

impl AsyncRead for RecvStream

Available on crate feature futures-io only.
Source§

fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], @@ -94,11 +99,11 @@ which it is no longer meaningful for the stream to be reset.

cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll<Result<usize, Error>>

Attempt to read from the AsyncRead into bufs using vectored -IO operations. Read more
Source§

impl AsyncRead for RecvStream

Source§

fn poll_read( +IO operations. Read more

Source§

impl AsyncRead for RecvStream

Source§

fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, -) -> Poll<Result<()>>

Attempts to read from the AsyncRead into buf. Read more
Source§

impl Debug for RecvStream

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for RecvStream

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +) -> Poll<Result<()>>

Attempts to read from the AsyncRead into buf. Read more

Source§

impl Debug for RecvStream

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for RecvStream

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<R> AsyncReadExt for R
where R: AsyncRead + ?Sized,

§

fn chain<R>(self, next: R) -> Chain<Self, R>
where Self: Sized, diff --git a/pr/720/docs/noq/struct.SendDatagram.html b/pr/720/docs/noq/struct.SendDatagram.html index 8627d156b..7409ceb2e 100644 --- a/pr/720/docs/noq/struct.SendDatagram.html +++ b/pr/720/docs/noq/struct.SendDatagram.html @@ -1,6 +1,6 @@ -SendDatagram in noq - Rust

SendDatagram

Struct SendDatagram 

Source
pub struct SendDatagram<'a> { /* private fields */ }
Expand description

Future produced by Connection::send_datagram_wait

-

Trait Implementations§

Source§

impl Future for SendDatagram<'_>

Source§

type Output = Result<(), SendDatagramError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering -the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for SendDatagram<'a>
where +SendDatagram in noq - Rust

SendDatagram

Struct SendDatagram 

Source
pub struct SendDatagram<'a> { /* private fields */ }
Expand description

Future produced by Connection::send_datagram_wait

+

Trait Implementations§

Source§

impl Future for SendDatagram<'_>

Source§

type Output = Result<(), SendDatagramError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin, 'a> Unpin for SendDatagram<'a>
where PinnedFieldsOf<__Origin<'__pin, 'a>>: Unpin,

Auto Trait Implementations§

§

impl<'a> !Freeze for SendDatagram<'a>

§

impl<'a> !RefUnwindSafe for SendDatagram<'a>

§

impl<'a> Send for SendDatagram<'a>

§

impl<'a> Sync for SendDatagram<'a>

§

impl<'a> !UnwindSafe for SendDatagram<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.SendStream.html b/pr/720/docs/noq/struct.SendStream.html index a5fe05f59..d38e5c3df 100644 --- a/pr/720/docs/noq/struct.SendStream.html +++ b/pr/720/docs/noq/struct.SendStream.html @@ -8,7 +8,7 @@ ready will always result in no data being written to the stream. This is true of succeed immediately when any progress is made, and is not true of methods which might need to perform multiple writes internally before succeeding. Each write method documents whether it is cancel-safe.

-

Implementations§

Source§

impl SendStream

Source

pub async fn write(&mut self, buf: &[u8]) -> Result<usize, WriteError>

Write a buffer into this stream, returning how many bytes were written

+

Implementations§

Source§

impl SendStream

Source

pub async fn write(&mut self, buf: &[u8]) -> Result<usize, WriteError>

Write a buffer into this stream, returning how many bytes were written

Unless this method errors, it waits until some amount of buf can be written into this stream, and then writes as much as it can without waiting again. Due to congestion and flow control, this may be shorter than buf.len(). On success this yields the length of the @@ -77,7 +77,7 @@ the priority of a stream with pending data may only take effect after that data transmitted. Using many different priority levels per connection may have a negative impact on performance.

Source

pub fn priority(&self) -> Result<i32, ClosedStream>

Get the priority of the send stream

-
Source

pub fn stopped(&self) -> Stopped

Completes when the peer stops the stream or reads the stream to completion

+
Source

pub fn stopped(&self) -> Stopped

Completes when the peer stops the stream or reads the stream to completion

Yields Some with the stop error code if the peer stops the stream. Yields None if the local side finish()es the stream and then the peer acknowledges receipt of all stream data (although not necessarily the processing of it), after which the peer @@ -85,8 +85,10 @@ closing the stream is no longer meaningful.

For a variety of reasons, the peer may not send acknowledgements immediately upon receiving data. As such, relying on stopped to know when the peer has read a stream to completion may introduce more latency than using an application-level response of some sort.

-
Source

pub fn id(&self) -> StreamId

Get the identity of this stream

-
Source

pub fn poll_write( +

Clients may wish to await this after finishing a unidirectional 0-RTT stream to reliably +determine whether the stream was rejected.

+

Source

pub fn id(&self) -> StreamId

Get the identity of this stream

+
Source

pub fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], @@ -95,22 +97,22 @@ may introduce more latency than using an application-level response of some sort

If the stream is not ready for writing, the method returns Poll::Pending and arranges for the current task (via cx.waker().wake_by_ref()) to receive a notification when the stream becomes writable or is closed.

-

Trait Implementations§

Source§

impl AsyncWrite for SendStream

Available on crate feature futures-io only.

Trait Implementations§

Source§

impl AsyncWrite for SendStream

Available on crate feature futures-io only.
Source§

fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], -) -> Poll<Result<usize>>

Attempt to write bytes from buf into the object. Read more
Source§

fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>>

Attempt to flush the object, ensuring that any buffered data reach -their destination. Read more
Source§

fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>>

Attempt to close the object. Read more
§

fn poll_write_vectored( +) -> Poll<Result<usize>>

Attempt to write bytes from buf into the object. Read more
Source§

fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>>

Attempt to flush the object, ensuring that any buffered data reach +their destination. Read more
Source§

fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>>

Attempt to close the object. Read more
§

fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll<Result<usize, Error>>

Attempt to write bytes from bufs into the object using vectored -IO operations. Read more
Source§

impl AsyncWrite for SendStream

Source§

fn poll_write( +IO operations. Read more

Source§

impl AsyncWrite for SendStream

Source§

fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], -) -> Poll<Result<usize>>

Attempt to write bytes from buf into the object. Read more
Source§

fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>>

Attempts to flush the object, ensuring that any buffered data reach -their destination. Read more
Source§

fn poll_shutdown( +) -> Poll<Result<usize>>

Attempt to write bytes from buf into the object. Read more
Source§

fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>>

Attempts to flush the object, ensuring that any buffered data reach +their destination. Read more
Source§

fn poll_shutdown( self: Pin<&mut Self>, _cx: &mut Context<'_>, ) -> Poll<Result<()>>

Initiates or attempts to shut down this writer, returning success when @@ -119,7 +121,7 @@ the I/O connection has completely shut down. Read more
Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll<Result<usize, Error>>

Like poll_write, except that it writes from a slice of buffers. Read more
§

fn is_write_vectored(&self) -> bool

Determines if this writer has an efficient poll_write_vectored -implementation. Read more

Source§

impl Debug for SendStream

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for SendStream

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +implementation. Read more

Source§

impl Debug for SendStream

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for SendStream

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<W> AsyncWriteExt for W
where W: AsyncWrite + ?Sized,

§

fn write<'a>(&'a mut self, src: &'a [u8]) -> Write<'a, Self>
where Self: Unpin,

Writes a buffer into this writer, returning how many bytes were diff --git a/pr/720/docs/noq/struct.Stopped.html b/pr/720/docs/noq/struct.Stopped.html index c50e0d5de..cb6b75f5f 100644 --- a/pr/720/docs/noq/struct.Stopped.html +++ b/pr/720/docs/noq/struct.Stopped.html @@ -1,6 +1,6 @@ -Stopped in noq - Rust

Stopped

Struct Stopped 

Source
pub struct Stopped { /* private fields */ }
Expand description

Future returned from SendStream::stopped.

-

Trait Implementations§

Source§

impl Debug for Stopped

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Future for Stopped

Source§

type Output = Result<Option<VarInt>, StoppedError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering -the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin> Unpin for Stopped
where +Stopped in noq - Rust

Stopped

Struct Stopped 

Source
pub struct Stopped { /* private fields */ }
Expand description

Future returned from SendStream::stopped.

+

Trait Implementations§

Source§

impl Debug for Stopped

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Future for Stopped

Source§

type Output = Result<Option<VarInt>, StoppedError>

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering +the current task for wakeup if the value is not yet available. Read more
Source§

impl<'__pin> Unpin for Stopped
where PinnedFieldsOf<__Origin<'__pin>>: Unpin,

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq/struct.UnorderedRecvStream.html b/pr/720/docs/noq/struct.UnorderedRecvStream.html index de57b1482..0d935d96f 100644 --- a/pr/720/docs/noq/struct.UnorderedRecvStream.html +++ b/pr/720/docs/noq/struct.UnorderedRecvStream.html @@ -1,11 +1,11 @@ -UnorderedRecvStream in noq - Rust

UnorderedRecvStream

Struct UnorderedRecvStream 

Source
pub struct UnorderedRecvStream { /* private fields */ }
Expand description

A stream that can be used to receive data out-of-order.

+UnorderedRecvStream in noq - Rust

UnorderedRecvStream

Struct UnorderedRecvStream 

Source
pub struct UnorderedRecvStream { /* private fields */ }
Expand description

A stream that can be used to receive data out-of-order.

Obtained by converting a RecvStream via RecvStream::into_unordered.

This variant of RecvStream allows reading chunks of data exclusively out of order. Once you have done an unordered read, ordered reads are no longer possible since data may have been consumed out of order.

The stream state related fns like Self::id, Self::is_0rtt, Self::stop, and Self::received_reset behave exactly as on RecvStream.

-

Implementations§

Source§

impl UnorderedRecvStream

Source

pub async fn read_chunk( +

Implementations§

Source§

impl UnorderedRecvStream

Source

pub async fn read_chunk( &mut self, max_length: usize, ) -> Result<Option<Chunk>, ReadError>

Reads the next segment of data.

@@ -15,20 +15,20 @@ field can be used to determine ordering in the caller. Unordered reads are less to head-of-line blocking within a stream, but require the application to manage reassembling the original data.

This operation is cancel-safe.

-
Source

pub fn id(&self) -> StreamId

Get the identity of this stream

-
Source

pub fn is_0rtt(&self) -> bool

Check if this stream has been opened during 0-RTT.

+
Source

pub fn id(&self) -> StreamId

Get the identity of this stream

+
Source

pub fn is_0rtt(&self) -> bool

Check if this stream has been opened during 0-RTT.

In which case any non-idempotent request should be considered dangerous at the application level. Because read data is subject to replay attacks.

-
Source

pub fn stop(&mut self, error_code: VarInt) -> Result<(), ClosedStream>

Stop accepting data

+
Source

pub fn stop(&mut self, error_code: VarInt) -> Result<(), ClosedStream>

Stop accepting data

Discards unread data and notifies the peer to stop transmitting. Once stopped, further attempts to operate on a stream will yield ClosedStream errors.

-
Source

pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError>

Completes when the stream has been reset by the peer or otherwise closed

+
Source

pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError>

Completes when the stream has been reset by the peer or otherwise closed

Yields Some with the reset error code when the stream is reset by the peer. Yields None when the stream was previously stop()ed, or when the stream was finish()ed by the peer and all data has been received, after which it is no longer meaningful for the stream to be reset.

This operation is cancel-safe.

-

Trait Implementations§

Source§

impl Debug for UnorderedRecvStream

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Debug for UnorderedRecvStream

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/pr/720/docs/noq/struct.WeakConnectionHandle.html b/pr/720/docs/noq/struct.WeakConnectionHandle.html index bcd745c5d..b98be7dbd 100644 --- a/pr/720/docs/noq/struct.WeakConnectionHandle.html +++ b/pr/720/docs/noq/struct.WeakConnectionHandle.html @@ -1,10 +1,10 @@ -WeakConnectionHandle in noq - Rust

WeakConnectionHandle

Struct WeakConnectionHandle 

Source
pub struct WeakConnectionHandle(/* private fields */);
Expand description

A handle to some connection internals, use with care.

+WeakConnectionHandle in noq - Rust

WeakConnectionHandle

Struct WeakConnectionHandle 

Source
pub struct WeakConnectionHandle(/* private fields */);
Expand description

A handle to some connection internals, use with care.

This contains a weak reference to the connection so will not itself keep the connection alive.

-

Implementations§

Source§

impl WeakConnectionHandle

Source

pub fn is_alive(&self) -> bool

Returns true if the Connection associated with this handle is still alive.

-
Source

pub fn upgrade(&self) -> Option<Connection>

Upgrade the handle to a full Connection

-
Source

pub fn is_same_connection(&self, other: &Self) -> bool

Returns true if the two WeakConnectionHandle point at the same connection.

-

Trait Implementations§

Source§

impl Clone for WeakConnectionHandle

Source§

fn clone(&self) -> WeakConnectionHandle

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WeakConnectionHandle

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Implementations§

Source§

impl WeakConnectionHandle

Source

pub fn is_alive(&self) -> bool

Returns true if the Connection associated with this handle is still alive.

+
Source

pub fn upgrade(&self) -> Option<Connection>

Upgrade the handle to a full Connection

+
Source

pub fn is_same_connection(&self, other: &Self) -> bool

Returns true if the two WeakConnectionHandle point at the same connection.

+

Trait Implementations§

Source§

impl Clone for WeakConnectionHandle

Source§

fn clone(&self) -> WeakConnectionHandle

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WeakConnectionHandle

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq/trait.NetworkChangeHint.html b/pr/720/docs/noq/trait.NetworkChangeHint.html index 28de0681a..2670519f1 100644 --- a/pr/720/docs/noq/trait.NetworkChangeHint.html +++ b/pr/720/docs/noq/trait.NetworkChangeHint.html @@ -1,4 +1,4 @@ -NetworkChangeHint in noq - Rust

NetworkChangeHint

Trait NetworkChangeHint 

Source
pub trait NetworkChangeHint: Debug + 'static {
+NetworkChangeHint in noq - Rust

NetworkChangeHint

Trait NetworkChangeHint 

Source
pub trait NetworkChangeHint: Debug + 'static {
     // Required method
     fn is_path_recoverable(
         &self,
@@ -6,7 +6,7 @@
         network_path: FourTuple,
     ) -> bool;
 }
Expand description

Hints when the caller identifies a network change.

-

Required Methods§

Source

fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool

Inform the connection if a path may recover after a network change.

+

Required Methods§

Source

fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool

Inform the connection if a path may recover after a network change.

After network changes, paths may not be recoverable. In this case, waiting for the path to become idle may take longer than what is desirable. If Self::is_path_recoverable returns false, a multipath-enabled, client-side connection will establish a new path to diff --git a/pr/720/docs/noq_proto/congestion/struct.Cubic.html b/pr/720/docs/noq_proto/congestion/struct.Cubic.html index 5ef9f2957..fe6482b9d 100644 --- a/pr/720/docs/noq_proto/congestion/struct.Cubic.html +++ b/pr/720/docs/noq_proto/congestion/struct.Cubic.html @@ -1,6 +1,6 @@ Cubic in noq_proto::congestion - Rust

Cubic

Struct Cubic 

Source
pub struct Cubic { /* private fields */ }
Expand description

The RFC8312 congestion controller, as widely used for TCP

Implementations§

Source§

impl Cubic

Source

pub fn new(config: Arc<CubicConfig>, _now: Instant, current_mtu: u16) -> Self

Construct a state using the given config and current time now

-

Trait Implementations§

Source§

impl Clone for Cubic

Source§

fn clone(&self) -> Cubic

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Controller for Cubic

Trait Implementations§

Source§

impl Clone for Cubic

Source§

fn clone(&self) -> Cubic

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Controller for Cubic

Source§

fn on_ack( &mut self, now: Instant, sent: Instant, @@ -8,7 +8,7 @@ _pn: u64, app_limited: bool, rtt: &RttEstimator, -)

Packet deliveries were confirmed Read more
Source§

fn on_congestion_event( +)

Packet deliveries were confirmed Read more
Source§

fn on_congestion_event( &mut self, now: Instant, sent: Instant, @@ -16,9 +16,9 @@ is_ecn: bool, _lost_bytes: u64, _largest_lost_pn: u64, -)

Packets were deemed lost or marked congested Read more
Source§

fn on_spurious_congestion_event(&mut self)

Packets were incorrectly deemed lost Read more
Source§

fn on_mtu_update(&mut self, new_mtu: u16)

The known MTU for the current network path has been updated
Source§

fn window(&self) -> u64

Number of ack-eliciting bytes that may be in flight
Source§

fn metrics(&self) -> ControllerMetrics

Retrieve implementation-specific metrics used to populate qlog traces when they are enabled +)

Packets were deemed lost or marked congested Read more
Source§

fn on_spurious_congestion_event(&mut self)

Packets were incorrectly deemed lost Read more
Source§

fn on_mtu_update(&mut self, new_mtu: u16)

The known MTU for the current network path has been updated
Source§

fn window(&self) -> u64

Number of ack-eliciting bytes that may be in flight
Source§

fn metrics(&self) -> ControllerMetrics

Retrieve implementation-specific metrics used to populate qlog traces when they are enabled This is also used to alter the pacing of the connection with -pacing_rate and send_quantum
Source§

fn clone_box(&self) -> Box<dyn Controller>

Duplicate the controller’s state
Source§

fn initial_window(&self) -> u64

Initial congestion window
Source§

fn into_any(self: Box<Self>) -> Box<dyn Any>

Returns Self for use in down-casting to extract implementation details
Source§

fn on_sent(&mut self, now: Instant, bytes: u64, largest_pn: u64)

One or more packets were just sent
Source§

fn on_packet_sent(&mut self, now: Instant, bytes: u16, pn: u64)

One packet was just sent
Source§

fn on_end_acks( +pacing_rate and send_quantum

Source§

fn clone_box(&self) -> Box<dyn Controller>

Duplicate the controller’s state
Source§

fn initial_window(&self) -> u64

Initial congestion window
Source§

fn into_any(self: Box<Self>) -> Box<dyn Any>

Returns Self for use in down-casting to extract implementation details
Source§

fn on_sent(&mut self, now: Instant, bytes: u64, largest_pn: u64)

One or more packets were just sent
Source§

fn on_packet_sent(&mut self, now: Instant, bytes: u16, pn: u64)

One packet was just sent
Source§

fn on_end_acks( &mut self, now: Instant, in_flight: u64, diff --git a/pr/720/docs/noq_proto/congestion/struct.CubicConfig.html b/pr/720/docs/noq_proto/congestion/struct.CubicConfig.html index bc951a1ad..26c47c13d 100644 --- a/pr/720/docs/noq_proto/congestion/struct.CubicConfig.html +++ b/pr/720/docs/noq_proto/congestion/struct.CubicConfig.html @@ -1,7 +1,7 @@ -CubicConfig in noq_proto::congestion - Rust

CubicConfig

Struct CubicConfig 

Source
pub struct CubicConfig { /* private fields */ }
Expand description

Configuration for the Cubic congestion controller

-

Implementations§

Source§

impl CubicConfig

Source

pub fn initial_window(&mut self, value: u64) -> &mut Self

Default limit on the amount of outstanding data in bytes.

+CubicConfig in noq_proto::congestion - Rust

CubicConfig

Struct CubicConfig 

Source
pub struct CubicConfig { /* private fields */ }
Expand description

Configuration for the Cubic congestion controller

+

Implementations§

Source§

impl CubicConfig

Source

pub fn initial_window(&mut self, value: u64) -> &mut Self

Default limit on the amount of outstanding data in bytes.

Recommended value: min(10 * max_datagram_size, max(2 * max_datagram_size, 14720))

-

Trait Implementations§

Source§

impl Clone for CubicConfig

Source§

fn clone(&self) -> CubicConfig

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl ControllerFactory for CubicConfig

Source§

fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller>

Construct a fresh Controller
Source§

impl Debug for CubicConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for CubicConfig

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for CubicConfig

Source§

fn clone(&self) -> CubicConfig

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl ControllerFactory for CubicConfig

Source§

fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller>

Construct a fresh Controller
Source§

impl Debug for CubicConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for CubicConfig

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq_proto/congestion/trait.Controller.html b/pr/720/docs/noq_proto/congestion/trait.Controller.html index 98717e8f2..218f8b13c 100644 --- a/pr/720/docs/noq_proto/congestion/trait.Controller.html +++ b/pr/720/docs/noq_proto/congestion/trait.Controller.html @@ -104,4 +104,4 @@ BBR’s offload budget).

Source

fn metrics(&self) -> ControllerMetrics

Retrieve implementation-specific metrics used to populate qlog traces when they are enabled This is also used to alter the pacing of the connection with pacing_rate and send_quantum

-

Implementors§

\ No newline at end of file +

Implementors§

\ No newline at end of file diff --git a/pr/720/docs/noq_proto/congestion/trait.ControllerFactory.html b/pr/720/docs/noq_proto/congestion/trait.ControllerFactory.html index 197911365..bd2fdcb55 100644 --- a/pr/720/docs/noq_proto/congestion/trait.ControllerFactory.html +++ b/pr/720/docs/noq_proto/congestion/trait.ControllerFactory.html @@ -7,4 +7,4 @@ ) -> Box<dyn Controller>; }

Expand description

Constructs controllers on demand

Required Methods§

Source

fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller>

Construct a fresh Controller

-

Implementors§

\ No newline at end of file +

Implementors§

\ No newline at end of file diff --git a/pr/720/docs/noq_proto/enum.ClosePathError.html b/pr/720/docs/noq_proto/enum.ClosePathError.html index 6a15fa4de..5ad7bd404 100644 --- a/pr/720/docs/noq_proto/enum.ClosePathError.html +++ b/pr/720/docs/noq_proto/enum.ClosePathError.html @@ -1,4 +1,4 @@ -ClosePathError in noq_proto - Rust

ClosePathError

Enum ClosePathError 

Source
pub enum ClosePathError {
+ClosePathError in noq_proto - Rust

ClosePathError

Enum ClosePathError 

Source
pub enum ClosePathError {
     MultipathNotNegotiated,
     ClosedPath,
     LastOpenPath,
@@ -7,8 +7,8 @@
 
§

ClosedPath

The path is already closed or was never opened

§

LastOpenPath

Cannot close the last remaining open path via the local API.

Use Connection::close to end the connection instead.

-

Trait Implementations§

Source§

impl Clone for ClosePathError

Source§

fn clone(&self) -> ClosePathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosePathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ClosePathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ClosePathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for ClosePathError

Source§

fn eq(&self, other: &ClosePathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ClosePathError

Source§

impl StructuralPartialEq for ClosePathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ClosePathError

Source§

fn clone(&self) -> ClosePathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosePathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ClosePathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ClosePathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for ClosePathError

Source§

fn eq(&self, other: &ClosePathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ClosePathError

Source§

impl StructuralPartialEq for ClosePathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq_proto/enum.ConnectionError.html b/pr/720/docs/noq_proto/enum.ConnectionError.html index 2aceb6c78..2d3c09c4c 100644 --- a/pr/720/docs/noq_proto/enum.ConnectionError.html +++ b/pr/720/docs/noq_proto/enum.ConnectionError.html @@ -1,4 +1,4 @@ -ConnectionError in noq_proto - Rust

ConnectionError

Enum ConnectionError 

Source
pub enum ConnectionError {
+ConnectionError in noq_proto - Rust

ConnectionError

Enum ConnectionError 

Source
pub enum ConnectionError {
     VersionMismatch,
     TransportError(TransportError),
     ConnectionClosed(ConnectionClose),
@@ -20,8 +20,8 @@ and §

LocallyClosed

The local application closed the connection

§

CidsExhausted

The connection could not be created because not enough of the CID space is available

Try using longer connection IDs.

-

Trait Implementations§

Source§

impl Clone for ConnectionError

Source§

fn clone(&self) -> ConnectionError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConnectionError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ConnectionError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ConnectionError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for Error

Source§

fn from(x: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ConnectionError

Source§

fn eq(&self, other: &ConnectionError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Eq for ConnectionError

Source§

impl StructuralPartialEq for ConnectionError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for ConnectionError

Source§

fn clone(&self) -> ConnectionError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ConnectionError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ConnectionError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ConnectionError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<ConnectionError> for Error

Source§

fn from(x: ConnectionError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for ConnectionError

Source§

fn eq(&self, other: &ConnectionError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Eq for ConnectionError

Source§

impl StructuralPartialEq for ConnectionError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq_proto/enum.Event.html b/pr/720/docs/noq_proto/enum.Event.html index 777cb313c..2cffbad19 100644 --- a/pr/720/docs/noq_proto/enum.Event.html +++ b/pr/720/docs/noq_proto/enum.Event.html @@ -1,4 +1,4 @@ -Event in noq_proto - Rust

Event

Enum Event 

Source
pub enum Event {
+Event in noq_proto - Rust

Event

Enum Event 

Source
pub enum Event {
     HandshakeDataReady,
     Connected,
     HandshakeConfirmed,
@@ -25,7 +25,7 @@ fail with §

DatagramsUnblocked

One or more application datagrams have been sent after blocking

§

Path(PathEvent)

(Multi)Path events

§

NatTraversal(Event)

n0’s nat traversal events

-

Trait Implementations§

Source§

impl Debug for Event

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<PathEvent> for Event

Source§

fn from(source: PathEvent) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl !Freeze for Event

§

impl !RefUnwindSafe for Event

§

impl Send for Event

§

impl Sync for Event

§

impl Unpin for Event

§

impl !UnwindSafe for Event

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Debug for Event

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<PathEvent> for Event

Source§

fn from(source: PathEvent) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl !Freeze for Event

§

impl !RefUnwindSafe for Event

§

impl Send for Event

§

impl Sync for Event

§

impl Unpin for Event

§

impl !UnwindSafe for Event

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/pr/720/docs/noq_proto/enum.PathError.html b/pr/720/docs/noq_proto/enum.PathError.html index 4e23616be..60f325aeb 100644 --- a/pr/720/docs/noq_proto/enum.PathError.html +++ b/pr/720/docs/noq_proto/enum.PathError.html @@ -1,4 +1,4 @@ -PathError in noq_proto - Rust

PathError

Enum PathError 

Source
pub enum PathError {
+PathError in noq_proto - Rust

PathError

Enum PathError 

Source
pub enum PathError {
     MultipathNotNegotiated,
     ServerSideNotAllowed,
     MaxPathIdReached,
@@ -12,8 +12,8 @@
 
§

RemoteCidsExhausted

No remote CIDs available to open a new path

§

ValidationFailed

Path could not be validated and will be abandoned

§

InvalidRemoteAddress(SocketAddr)

The remote address for the path is not supported by the endpoint

-

Trait Implementations§

Source§

impl Clone for PathError

Source§

fn clone(&self) -> PathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for PathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for PathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for PathError

Source§

fn eq(&self, other: &PathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, -and should not be overridden without very good reason.
Source§

impl Copy for PathError

Source§

impl Eq for PathError

Source§

impl StructuralPartialEq for PathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Clone for PathError

Source§

fn clone(&self) -> PathError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for PathError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for PathError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for PathError

Source§

fn eq(&self, other: &PathError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +and should not be overridden without very good reason.
Source§

impl Copy for PathError

Source§

impl Eq for PathError

Source§

impl StructuralPartialEq for PathError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq_proto/enum.PathEvent.html b/pr/720/docs/noq_proto/enum.PathEvent.html index 974664047..df8050899 100644 --- a/pr/720/docs/noq_proto/enum.PathEvent.html +++ b/pr/720/docs/noq_proto/enum.PathEvent.html @@ -41,7 +41,7 @@ changes the status.

Fields

This variant is marked as non-exhaustive
Non-exhaustive enum variants could have additional fields added in future. Therefore, non-exhaustive enum variants cannot be constructed in external crates and cannot be matched against.
§id: PathId

Path over which the observed address was reported, PathId::ZERO when multipath is not negotiated

§addr: SocketAddr

The address observed by the remote over this path

-

Trait Implementations§

Source§

impl Clone for PathEvent

Source§

fn clone(&self) -> PathEvent

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathEvent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<PathEvent> for Event

Source§

fn from(source: PathEvent) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for PathEvent

Source§

fn eq(&self, other: &PathEvent) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +

Trait Implementations§

Source§

impl Clone for PathEvent

Source§

fn clone(&self) -> PathEvent

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathEvent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<PathEvent> for Event

Source§

fn from(source: PathEvent) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for PathEvent

Source§

fn eq(&self, other: &PathEvent) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for PathEvent

Source§

impl StructuralPartialEq for PathEvent

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq_proto/enum.ProtectedHeader.html b/pr/720/docs/noq_proto/enum.ProtectedHeader.html index 311db83fc..769763f4e 100644 --- a/pr/720/docs/noq_proto/enum.ProtectedHeader.html +++ b/pr/720/docs/noq_proto/enum.ProtectedHeader.html @@ -42,7 +42,7 @@

§src_cid: ConnectionId

Source Connection ID

Implementations§

Source§

impl ProtectedHeader

Source

pub fn dst_cid(&self) -> ConnectionId

The destination Connection ID of the packet

Source

pub fn decode( - buf: &mut Cursor<BytesMut>, + buf: &mut Cursor<impl AsRef<[u8]>>, cid_parser: &(impl ConnectionIdParser + ?Sized), supported_versions: &[u32], grease_quic_bit: bool, diff --git a/pr/720/docs/noq_proto/struct.Connection.html b/pr/720/docs/noq_proto/struct.Connection.html index 798231c09..245114083 100644 --- a/pr/720/docs/noq_proto/struct.Connection.html +++ b/pr/720/docs/noq_proto/struct.Connection.html @@ -33,7 +33,7 @@ increasing time. Specifically, calling Instant may be interleaved in any order with a call to handle_event at that same instant; however events or timeouts with different instants must not be interleaved.

-

Implementations§

Source§

impl Connection

Source

pub fn poll_timeout(&mut self) -> Option<Instant>

Returns the next time at which handle_timeout should be called

+

Implementations§

Source§

impl Connection

Source

pub fn poll_timeout(&mut self) -> Option<Instant>

Returns the next time at which handle_timeout should be called

The value returned may change after:

  • the application performed some I/O on the connection
  • @@ -131,38 +131,38 @@ single Transmit using GSO. This must be at least 1.

    Will execute protocol logic upon receipt of a connection event, in turn preparing signals (including application Events, EndpointEvents and outgoing datagrams) that should be extracted through the relevant methods.

    -
Source

pub fn handle_timeout(&mut self, now: Instant)

Process timer expirations

+
Source

pub fn handle_timeout(&mut self, now: Instant)

Process timer expirations

Executes protocol logic, potentially preparing signals (including application Events, EndpointEvents and outgoing datagrams) that should be extracted through the relevant methods.

It is most efficient to call this immediately after the system clock reaches the latest Instant that was output by poll_timeout; however spurious extra calls will simply no-op and therefore are safe.

-
Source

pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes)

Close a connection immediately

+
Source

pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes)

Close a connection immediately

This does not ensure delivery of outstanding data. It is the application’s responsibility to call this only when all important communications have been completed, e.g. by calling SendStream::finish on outstanding streams and waiting for the corresponding StreamEvent::Finished event.

If Streams::send_streams returns 0, all outstanding stream data has been delivered. There may still be data from the peer that has not been received.

-
Source

pub fn datagrams(&mut self) -> Datagrams<'_>

Control datagrams

-
Source

pub fn stats(&mut self) -> ConnectionStats

Returns connection statistics

-
Source

pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats>

Returns path statistics

-
Source

pub fn ping(&mut self)

Ping the remote endpoint

+
Source

pub fn datagrams(&mut self) -> Datagrams<'_>

Control datagrams

+
Source

pub fn stats(&mut self) -> ConnectionStats

Returns connection statistics

+
Source

pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats>

Returns path statistics

+
Source

pub fn ping(&mut self)

Ping the remote endpoint

Causes an ACK-eliciting packet to be transmitted on the connection.

-
Source

pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath>

Ping the remote endpoint over a specific path

+
Source

pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath>

Ping the remote endpoint over a specific path

Causes an ACK-eliciting packet to be transmitted on the path.

-
Source

pub fn force_key_update(&mut self)

Update traffic keys spontaneously

+
Source

pub fn force_key_update(&mut self)

Update traffic keys spontaneously

This can be useful for testing key updates, as they otherwise only happen infrequently.

-
Source

pub fn crypto_session(&self) -> &dyn Session

Get a session reference

-
Source

pub fn is_handshaking(&self) -> bool

Whether the connection is in the process of being established

+
Source

pub fn crypto_session(&self) -> &dyn Session

Get a session reference

+
Source

pub fn is_handshaking(&self) -> bool

Whether the connection is in the process of being established

If this returns false, the connection may be either established or closed, signaled by the emission of a Connected or ConnectionLost event respectively. Note that locally-initiated closes via close() do not emit a ConnectionLost event.

For an established connection this essentially means the handshake is completed, but not necessarily yet confirmed.

-
Source

pub fn is_closed(&self) -> bool

Whether the connection is closed

+
Source

pub fn is_closed(&self) -> bool

Whether the connection is closed

Closed connections cannot transport any further data. A connection becomes closed when either peer application intentionally closes it, or when either transport layer detects an error such as a time-out or certificate validation failure.

@@ -170,24 +170,24 @@ error such as a time-out or certificate validation failure.

connection is closed by the peer or due to an error. When the local application closes the connection via close(), no ConnectionLost event is emitted; instead, pending operations fail with ConnectionError::LocallyClosed.

-
Source

pub fn is_drained(&self) -> bool

Whether there is no longer any need to keep the connection around

+
Source

pub fn is_drained(&self) -> bool

Whether there is no longer any need to keep the connection around

Closed connections become drained after a brief timeout to absorb any remaining in-flight packets from the peer. All drained connections have been closed.

-
Source

pub fn accepted_0rtt(&self) -> bool

For clients, if the peer accepted the 0-RTT data packets

+
Source

pub fn accepted_0rtt(&self) -> bool

For clients, if the peer accepted the 0-RTT data packets

The value is meaningless until after the handshake completes.

-
Source

pub fn has_0rtt(&self) -> bool

Whether 0-RTT is/was possible during the handshake

-
Source

pub fn has_pending_retransmits(&self) -> bool

Whether there are any pending retransmits

-
Source

pub fn side(&self) -> Side

Look up whether we’re the client or server of this Connection

-
Source

pub fn path_observed_address( +

Source

pub fn has_0rtt(&self) -> bool

Whether 0-RTT is/was possible during the handshake

+
Source

pub fn has_pending_retransmits(&self) -> bool

Whether there are any pending retransmits

+
Source

pub fn side(&self) -> Side

Look up whether we’re the client or server of this Connection

+
Source

pub fn path_observed_address( &self, path_id: PathId, ) -> Result<Option<SocketAddr>, ClosedPath>

Get the address observed by the remote over the given path

-
Source

pub fn rtt(&self, path_id: PathId) -> Option<Duration>

Current best estimate of this connection’s latency (round-trip-time)

-
Source

pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller>

Current state of this connection’s congestion controller, for debugging purposes

-
Source

pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt)

Modify the number of remotely initiated streams that may be concurrently open

+
Source

pub fn rtt(&self, path_id: PathId) -> Option<Duration>

Current best estimate of this connection’s latency (round-trip-time)

+
Source

pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller>

Current state of this connection’s congestion controller, for debugging purposes

+
Source

pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt)

Modify the number of remotely initiated streams that may be concurrently open

No streams may be opened by the peer unless fewer than count are already open. Large counts increase both minimum and worst-case memory consumption.

-
Source

pub fn set_max_concurrent_paths( +

Source

pub fn set_max_concurrent_paths( &mut self, now: Instant, count: NonZeroU32, @@ -198,16 +198,16 @@ actively reduce paths they must be closed using TransportConfig) this can not enable multipath and will fail.

-

Source

pub fn max_concurrent_streams(&self, dir: Dir) -> u64

Current number of remotely initiated streams that may be concurrently open

+
Source

pub fn max_concurrent_streams(&self, dir: Dir) -> u64

Current number of remotely initiated streams that may be concurrently open

If the target for this limit is reduced using set_max_concurrent_streams, it will not change immediately, even if fewer streams are open. Instead, it will decrement by one for each time a remotely initiated stream of matching directionality is closed.

-
Source

pub fn set_send_window(&mut self, send_window: u64)

Source

pub fn set_receive_window(&mut self, receive_window: VarInt)

Source

pub fn is_multipath_negotiated(&self) -> bool

Whether the Multipath for QUIC extension is enabled.

+
Source

pub fn set_send_window(&mut self, send_window: u64)

Source

pub fn set_receive_window(&mut self, receive_window: VarInt)

Source

pub fn is_multipath_negotiated(&self) -> bool

Whether the Multipath for QUIC extension is enabled.

Multipath is only enabled after the handshake is completed and if it was enabled by both peers.

-
Source

pub fn handle_network_change( +

Source

pub fn handle_network_change( &mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant, @@ -222,26 +222,26 @@ paths as non recoverable when necessary accelerates connectivity re-establishmen allow it altogether.

The optional hint allows callers to indicate when paths are non-recoverable and should be migrated to new a PathId.

-

Source

pub fn current_mtu(&self) -> u16

Storage size required for the largest packet that can be transmitted on all currently +

Source

pub fn current_mtu(&self) -> u16

Storage size required for the largest packet that can be transmitted on all currently available paths

Buffers passed to Connection::poll_transmit should be at least this large.

When multipath is enabled, this value is the minimum MTU across all available paths.

-
Source

pub fn add_nat_traversal_address( +

Source

pub fn add_nat_traversal_address( &mut self, address: SocketAddr, ) -> Result<(), Error>

Add addresses the local endpoint considers are reachable for nat traversal.

-
Source

pub fn remove_nat_traversal_address( +

Source

pub fn remove_nat_traversal_address( &mut self, address: SocketAddr, ) -> Result<(), Error>

Removes an address the endpoing no longer considers reachable for nat traversal

Addresses not present in the set will be silently ignored.

-
Source

pub fn get_local_nat_traversal_addresses( +

Source

pub fn get_local_nat_traversal_addresses( &self, ) -> Result<Vec<SocketAddr>, Error>

Get the current local nat traversal addresses

-
Source

pub fn get_remote_nat_traversal_addresses( +

Source

pub fn get_remote_nat_traversal_addresses( &self, ) -> Result<Vec<SocketAddr>, Error>

Get the currently advertised nat traversal addresses by the server

-
Source

pub fn initiate_nat_traversal_round( +

Source

pub fn initiate_nat_traversal_round( &mut self, now: Instant, ) -> Result<Vec<SocketAddr>, Error>

Initiates a new nat traversal round

@@ -252,7 +252,7 @@ round is initiated, the previous one is cancelled.

4-tuple.

Returns the server addresses that are now being probed. If addresses fail due to spurious errors, these might succeed later and not be returned in this set.

-

Trait Implementations§

Source§

impl Debug for Connection

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Connection

§

impl !RefUnwindSafe for Connection

§

impl Send for Connection

§

impl Sync for Connection

§

impl Unpin for Connection

§

impl !UnwindSafe for Connection

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Debug for Connection

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Connection

§

impl !RefUnwindSafe for Connection

§

impl Send for Connection

§

impl Sync for Connection

§

impl Unpin for Connection

§

impl !UnwindSafe for Connection

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/pr/720/docs/noq_proto/struct.MultipathNotNegotiated.html b/pr/720/docs/noq_proto/struct.MultipathNotNegotiated.html index f29dba612..ed149f13d 100644 --- a/pr/720/docs/noq_proto/struct.MultipathNotNegotiated.html +++ b/pr/720/docs/noq_proto/struct.MultipathNotNegotiated.html @@ -1,5 +1,5 @@ -MultipathNotNegotiated in noq_proto - Rust

MultipathNotNegotiated

Struct MultipathNotNegotiated 

Source
pub struct MultipathNotNegotiated { /* private fields */ }
Expand description

Error when the multipath extension was not negotiated, but attempted to be used.

-

Trait Implementations§

Source§

impl Clone for MultipathNotNegotiated

Source§

fn clone(&self) -> MultipathNotNegotiated

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MultipathNotNegotiated

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for MultipathNotNegotiated

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for MultipathNotNegotiated

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl Copy for MultipathNotNegotiated

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +MultipathNotNegotiated in noq_proto - Rust

MultipathNotNegotiated

Struct MultipathNotNegotiated 

Source
pub struct MultipathNotNegotiated { /* private fields */ }
Expand description

Error when the multipath extension was not negotiated, but attempted to be used.

+

Trait Implementations§

Source§

impl Clone for MultipathNotNegotiated

Source§

fn clone(&self) -> MultipathNotNegotiated

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MultipathNotNegotiated

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for MultipathNotNegotiated

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for MultipathNotNegotiated

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl Copy for MultipathNotNegotiated

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where diff --git a/pr/720/docs/noq_proto/struct.TransportError.html b/pr/720/docs/noq_proto/struct.TransportError.html index 28f2e309d..ec68600a5 100644 --- a/pr/720/docs/noq_proto/struct.TransportError.html +++ b/pr/720/docs/noq_proto/struct.TransportError.html @@ -11,7 +11,7 @@
§reason: String

Human-readable explanation of the reason

§crypto: Option<Arc<dyn Error + Send + Sync>>

An underlying crypto (e.g. TLS) layer error

Implementations§

Source§

impl Error

Source

pub fn new(code: Code, reason: String) -> Self

Construct an error with a code and a reason

-

Trait Implementations§

Source§

impl Clone for Error

Source§

fn clone(&self) -> Error

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Error

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Error

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for Error

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Error> for ConnectionClose

Source§

fn from(x: TransportError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for TransportError

Source§

fn from(e: Error) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Error

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, +

Trait Implementations§

Source§

impl Clone for Error

Source§

fn clone(&self) -> Error

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Error

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Error

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for Error

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Error> for ConnectionClose

Source§

fn from(x: TransportError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for ConnectionError

Source§

fn from(source: TransportError) -> Self

Converts to this type from the input type.
Source§

impl From<Error> for TransportError

Source§

fn from(e: Error) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Error

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for Error

Auto Trait Implementations§

§

impl Freeze for Error

§

impl !RefUnwindSafe for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl !UnwindSafe for Error

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where diff --git a/pr/720/docs/noq_proto/trait.NetworkChangeHint.html b/pr/720/docs/noq_proto/trait.NetworkChangeHint.html index bfa02d1ca..53d229812 100644 --- a/pr/720/docs/noq_proto/trait.NetworkChangeHint.html +++ b/pr/720/docs/noq_proto/trait.NetworkChangeHint.html @@ -1,4 +1,4 @@ -NetworkChangeHint in noq_proto - Rust

NetworkChangeHint

Trait NetworkChangeHint 

Source
pub trait NetworkChangeHint: Debug + 'static {
+NetworkChangeHint in noq_proto - Rust

NetworkChangeHint

Trait NetworkChangeHint 

Source
pub trait NetworkChangeHint: Debug + 'static {
     // Required method
     fn is_path_recoverable(
         &self,
@@ -6,7 +6,7 @@
         network_path: FourTuple,
     ) -> bool;
 }
Expand description

Hints when the caller identifies a network change.

-

Required Methods§

Source

fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool

Inform the connection if a path may recover after a network change.

+

Required Methods§

Source

fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool

Inform the connection if a path may recover after a network change.

After network changes, paths may not be recoverable. In this case, waiting for the path to become idle may take longer than what is desirable. If Self::is_path_recoverable returns false, a multipath-enabled, client-side connection will establish a new path to diff --git a/pr/720/docs/noq_udp/struct.UdpSocketState.html b/pr/720/docs/noq_udp/struct.UdpSocketState.html index 7260f13fb..a6e6cf01f 100644 --- a/pr/720/docs/noq_udp/struct.UdpSocketState.html +++ b/pr/720/docs/noq_udp/struct.UdpSocketState.html @@ -1,7 +1,7 @@ -UdpSocketState in noq_udp - Rust

UdpSocketState

Struct UdpSocketState 

Source
pub struct UdpSocketState { /* private fields */ }
Expand description

Tokio-compatible UDP socket with some useful specializations.

+UdpSocketState in noq_udp - Rust

UdpSocketState

Struct UdpSocketState 

Source
pub struct UdpSocketState { /* private fields */ }
Expand description

Tokio-compatible UDP socket with some useful specializations.

Unlike a standard tokio UDP socket, this allows ECN bits to be read and written on some platforms.

-

Implementations§

Source§

impl UdpSocketState

Source

pub fn new(sock: UdpSockRef<'_>) -> Result<Self>

Source

pub fn send( +

Implementations§

Source§

impl UdpSocketState

Source

pub fn new(sock: UdpSockRef<'_>) -> Result<Self>

Source

pub fn send( &self, socket: UdpSockRef<'_>, transmit: &Transmit<'_>, @@ -13,38 +13,37 @@ employ retransmits and timeouts anyway in order to deal with UDP’s unreliable Thus, logging is most likely the only thing you can do with these errors.

If you would like to handle these errors yourself, use UdpSocketState::try_send instead.

-

Source

pub fn try_send( +

Source

pub fn try_send( &self, socket: UdpSockRef<'_>, transmit: &Transmit<'_>, ) -> Result<()>

Sends a Transmit on the given socket without any additional error handling.

-
Source

pub fn recv( +

Source

pub fn recv( &self, socket: UdpSockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta], -) -> Result<usize>

Source

pub fn max_gso_segments(&self) -> NonZeroUsize

The maximum amount of segments which can be transmitted if a platform -supports Generic Send Offload (GSO).

-

This is 1 if the platform doesn’t support GSO. Subject to change if errors are detected -while using GSO.

-
Source

pub fn gro_segments(&self) -> NonZeroUsize

The number of segments to read when GRO is enabled. Used as a factor to -compute the receive buffer size.

+) -> Result<usize>

Source

pub fn max_gso_segments(&self) -> NonZeroUsize

Maximum number of segments to transmit if Generic Send Offload (GSO) is enabled.

+

This is 1 if the platform doesn’t support GSO.

+

Subject to change if errors are detected while using GSO.

+
Source

pub fn gro_segments(&self) -> NonZeroUsize

The number of segments to read when GRO is enabled.

+

Used as a factor to compute the receive buffer size.

Returns 1 if the platform doesn’t support GRO.

-
Source

pub fn set_send_buffer_size( +

Source

pub fn set_send_buffer_size( &self, socket: UdpSockRef<'_>, bytes: usize, ) -> Result<()>

Resize the send buffer of socket to bytes

-
Source

pub fn set_recv_buffer_size( +

Source

pub fn set_recv_buffer_size( &self, socket: UdpSockRef<'_>, bytes: usize, ) -> Result<()>

Resize the receive buffer of socket to bytes

-
Source

pub fn send_buffer_size(&self, socket: UdpSockRef<'_>) -> Result<usize>

Get the size of the socket send buffer

-
Source

pub fn recv_buffer_size(&self, socket: UdpSockRef<'_>) -> Result<usize>

Get the size of the socket receive buffer

-
Source

pub fn may_fragment(&self) -> bool

Whether transmitted datagrams might get fragmented by the IP layer

+
Source

pub fn send_buffer_size(&self, socket: UdpSockRef<'_>) -> Result<usize>

Get the size of the socket send buffer

+
Source

pub fn recv_buffer_size(&self, socket: UdpSockRef<'_>) -> Result<usize>

Get the size of the socket receive buffer

+
Source

pub fn may_fragment(&self) -> bool

Whether transmitted datagrams might get fragmented by the IP layer

Returns false on targets which employ e.g. the IPV6_DONTFRAG socket option.

-

Trait Implementations§

Source§

impl Debug for UdpSocketState

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where +

Trait Implementations§

Source§

impl Debug for UdpSocketState

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for UdpSocketState

§

impl RefUnwindSafe for UdpSocketState

§

impl Send for UdpSocketState

§

impl Sync for UdpSocketState

§

impl Unpin for UdpSocketState

§

impl UnwindSafe for UdpSocketState

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

diff --git a/pr/720/docs/search.index/000adb4f555c.js b/pr/720/docs/search.index/000adb4f555c.js deleted file mode 100644 index c9fd43c43..000000000 --- a/pr/720/docs/search.index/000adb4f555c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9K4QAAABAAEAAQDzAgFz9UYJAAABAAEAAQCKBgEGAPQDEgAAAQABAAEAAQEAOzAAAAEAAAYAAQDCFAYA8wYBZfRvFAAAAQA0AAEAEwYDsEAUmwABsGAThwCJYXJ183sQAAB5AgEA84ACYWUBAwD0thEAAAEAAQABAAECAPTIDwAAAQBRBAEAAYICoBAAABNdsEAS+gABYXMBgAKgAAAADBewcBCMAAFyc+cHAACHoHAAABICkQVBOjAAAAEAAAAAAAwAEAAAAOcB6AHpAeoBeAfhB+IHTwlVDAcQCBAJEBwR") \ No newline at end of file diff --git a/pr/720/docs/search.index/000ba6d7fd92.js b/pr/720/docs/search.index/000ba6d7fd92.js deleted file mode 100644 index 3eb2b3070..000000000 --- a/pr/720/docs/search.index/000ba6d7fd92.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQECsCAM8QABsAAMaQABZXPyYwcAAAEAAQUA8x4TAAABAAEA8wQBcvTkDwAAAQDvAAEAE4ACoLAAABReYXPzgAJiYw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/00142191e584.js b/pr/720/docs/search.index/00142191e584.js deleted file mode 100644 index ddad680f2..000000000 --- a/pr/720/docs/search.index/00142191e584.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9AoRAAABAJIBAQABAAD08g8AAAEA9QAHASOCArBQE1UAAWVzAQIA9CUTAAABAJIAAQABAwD0WxMAAAEAmAABAPOFAmJ1AQIA9HURAAABAHwBAQDzgAJpbPMAA2J0dTowAAABAAAAAAAPABAAAAByB/sH/Af9B/4HGxDhEK8TMRR+FH8UgxSQFJEUtxS7FAEMAPMUFAAAAQABAAGAArAACRkAAaAgAAANA2RuAQYA9CMTAAABAJIAAQDzAwFi9AgRAAABAJIBAQCXBgAAh7BAD/AAAaBwAAASp7CQE1MAATgJAzowAAABAAAAAAAkABAAAADBBcIFwwXEBTQHNQczDPgM+Qz6DP4M/wwADegP6Q88ED0QQRBCEF8QYBBhEGIQYxBkEGUQqBCtENkQ2hCPE7MT2hN0FIAUoxS0FA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/002e6e153d4b.js b/pr/720/docs/search.index/002e6e153d4b.js new file mode 100644 index 000000000..5b16d64da --- /dev/null +++ b/pr/720/docs/search.index/002e6e153d4b.js @@ -0,0 +1 @@ +rn_("AQMBsAAM8wNGc/QpDAAAAQABAAEAAQIA9CcMAAABADoFAQAjAAKgQAAADO9lcvK4BAAAAQABgAOgQAAAE96wMBL5AAGgYAAAESBhc3QBAgGgQAAAFGZl8ooUAAABAPOABGxucnY=") \ No newline at end of file diff --git a/pr/720/docs/search.index/0050c343edd2.js b/pr/720/docs/search.index/0050c343edd2.js new file mode 100644 index 000000000..22baa8444 --- /dev/null +++ b/pr/720/docs/search.index/0050c343edd2.js @@ -0,0 +1 @@ +rn_("AYACsAARfwABsAARgQABNDYBCwA7MAAAAQAABgABAB8UBgAjgAKggAAAFEllbyMCA6BgAAAT3rBAFLoAAWVucAEjDAAA8wACYXYB3gYAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/006213420b7c.js b/pr/720/docs/search.index/006213420b7c.js new file mode 100644 index 000000000..52570b719 --- /dev/null +++ b/pr/720/docs/search.index/006213420b7c.js @@ -0,0 +1 @@ +rn_("AQcA9AQSAAABAAEAAQAjAQKgcAAAEgNhcgF4BwAAAQMAOzAAAAEAAAgAAgCiDwYAXxMBAPMAAmN0OzAAAAEAAFcAJwCoBAsAbwUAAA4JAQAnDAEALwwCAO8MAAD7DAIADQ0BAMwPAADRDwEA1A8BAN4PAABmEAIAbRABAHIQAQCXEAAADxEAABURAABiEQEAbxEBAIMRAQCHEQIA5xEBAPoRAgAAEgAAthIAAL8SAQDEEgEADRMBAB0TAQAiEwEARBMBAFQTAwBaEwEAuxMBAM8TAAA7FAAAZBQEAG0UAgA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/00be37f9a7bf.js b/pr/720/docs/search.index/00be37f9a7bf.js new file mode 100644 index 000000000..1888b7fa9 --- /dev/null +++ b/pr/720/docs/search.index/00be37f9a7bf.js @@ -0,0 +1 @@ +rn_("AQIA9awRAAABAAEAAQABAAGAArBgExcAAaAgAAARAG95AQABoMAAABQ8afRwEwAACAAcABsAAQUA9KkUAAABAAEAAQATgAKwcBSCAAFlaQECAPT+EAAAAQCbAAEAAQIBoEAAABNHcjswAAABAAAHAAIA/BABAJQRBQDzgAJhb2cDAACGsIATRgBasKATvQABDDAGOzAAAAEAAAgAAwAcDAAAxxEDAK0SAwDzggJlaSMAAqCAAAAUuWZo8voIAACfCgEFAPMfEwAAAQABAAEBADswAAABAAAFAAIA/wsDAPcRAQBTAAOwMBRXAAFlcHL05A8AAAEA7wABAAEAA7BAFB0AAaFAAAAUjqBQAAAR7WJjZgEIBwAA84ACbW4BAYSgsAAAE9uwQBC3AAGwwBQKAAGgYAAAEZMUIAT27wYAAGAJAQA7AS4BFwEBBQA7MAAAAQAABQABAN0SBQABBwD1ZxMAAAEAAQABAAEAI4ACoFAAABFkYW/zAIUgSQI7MAAAAQAACAAEAE0HAAB+BwUABA0AAJwRAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/00c65b35b354.js b/pr/720/docs/search.index/00c65b35b354.js new file mode 100644 index 000000000..edad2f551 --- /dev/null +++ b/pr/720/docs/search.index/00c65b35b354.js @@ -0,0 +1 @@ +rn_("AQAA9K4QAAABAAEAAQDzAgFz9UYJAAABAAEAAQCKBgEGAPQEEgAAAQABAAEAAQEAOzAAAAEAAAYAAQDDFAYA8wYBZfRwFAAAAQA0AAEAEwYDsEAUnAABsGATiACJYXJ183sQAAB6AgEA84ACYWUBAwD0txEAAAEAAQABAAECAPTIDwAAAQBSBAEAAYICoBAAABNesEAS+wABYXMBgAKgAAAADBewcBCMAAFyc+cHAACHoHAAABIDkQVBOjAAAAEAAAAAAAwAEAAAAOcB6AHpAeoBeAfhB+IHTwlVDAcQCBAJEBwR") \ No newline at end of file diff --git a/pr/720/docs/search.index/00de4b7c33fb.js b/pr/720/docs/search.index/00de4b7c33fb.js new file mode 100644 index 000000000..782e5bdff --- /dev/null +++ b/pr/720/docs/search.index/00de4b7c33fb.js @@ -0,0 +1 @@ +rn_("AQEA9fQHAAABAAEAAQABAAEAAqAwAAARHKCQAAATlDBo9QMSAACZAQEAAQABABOAAqAwAAAPzGRyIwKEsBAI9wNAsCAMAwEMoDAAAA/0EgAY9ZwFAAAtAAEAAQABADOAhLCgEtEAAbBAD9YAARBJAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/00e5308c2fbf.js b/pr/720/docs/search.index/00e5308c2fbf.js new file mode 100644 index 000000000..03edd102d --- /dev/null +++ b/pr/720/docs/search.index/00e5308c2fbf.js @@ -0,0 +1 @@ +rn_("AQIBsEAUfQABdDswAAABAAANAAYA/xIDAGwTAQDcEwEA8xMBAHIUAQCaFAEAE4ACsDATMwFJaXABBQDzsRMAAAEAAQATgAKgMAAAFAxleVMBA7BwFBgAAWJlcwFAEAAAE4ADsDAUjwABsCAG+wABZWxz") \ No newline at end of file diff --git a/pr/720/docs/search.index/00ee768feb28.js b/pr/720/docs/search.index/00ee768feb28.js deleted file mode 100644 index b0a390133..000000000 --- a/pr/720/docs/search.index/00ee768feb28.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYQCoCAAABEnoDAAABGNaXQBAQA7MAAAAQAAjQACAHMHAAB1CYwA8wACZWz1twQAAMACzQlVAgEAAQIAOzAAAAEAAO4AAgAMDAAAGA3tAMcAAACFsLATQwABsBATyQABsDANFgABFDACOzAAAAEAABoBCwDgAQYAowUAAM0F7QBCBwcAQxACAJwRDQDLEQIApBIBACsTAQB+EwEAFBQCAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/014f131aa095.js b/pr/720/docs/search.index/014f131aa095.js deleted file mode 100644 index b567c3b10..000000000 --- a/pr/720/docs/search.index/014f131aa095.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYA9L4TAAABAAEAAQABDwD0qBQAAAEAAQABAPOHAmhtAQAA9A4TAAABAAEAAQDzBAFk9LESAAABAAEAAQAjh4SwoBRWAAGwQBMMAAGwcBP/AAEVgAABAAGgQAAAEJdlOzAAAAEAAAcAAgBsBwUA+QcBABOAArBQEE0AAWRyAQkA9eATAAABAAEAeAABALcCAICGsCASvAABVFDsruw9EUkB") \ No newline at end of file diff --git a/pr/720/docs/search.index/0154adb96fb6.js b/pr/720/docs/search.index/0154adb96fb6.js new file mode 100644 index 000000000..7c4490ff7 --- /dev/null +++ b/pr/720/docs/search.index/0154adb96fb6.js @@ -0,0 +1 @@ +rn_("AQUAOzAAAAEAAAcAAwDMEQIAfxMBABUUAgABBADzzxEAAAEAAQAjAAKgYAAAEv5hcvPvEAAAAQDKAQGAAqEQAAAUpLCAFJoAAWl1NwQAgoexUBTBAAGgAAAAEM+wcBPfAAGhMAAAFLUKQBsTgAKwEBMKAAFpcg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/01ce2d730344.js b/pr/720/docs/search.index/01ce2d730344.js new file mode 100644 index 000000000..00b9a1e33 --- /dev/null +++ b/pr/720/docs/search.index/01ce2d730344.js @@ -0,0 +1 @@ +rn_("AQMBoAAAABPmcwH5EAAAAQMA9IgQAAABAAEAAQATgAKwUBCMAAFhaQGAArBwFLEAAbBwFD0AAWVyAYACoLAAABR0oDAAABEmbG6XAgAAhqAgAAASoKAgAAAI+LAwDgYAARCRBTowAAABAAAAAAARABAAAACeBNYE1wTYBNkEaQmxD7IPsw+0D04TiBMMFBEUHRQeFDkUOhQBAgA6MAAAAQAAAAAACgAQAAAAUQlSCSIQchNzE6MTpBNOFKcUvxTAFAEAADswAAABAAAGAAIAjxMAAPcTBQABAgGwMBNfAAFjOjAAAAEAAAAAABMAEAAAAPsMzA9mEGcQaBBtEG4QchBzEA8RgxGHEYgRiREAElQTVRM7FGQUZRQBAwDzyRMAAGoAAQATgQKwQBFvAAFhZROAAqCwAAAUe2FlAQEBsEAUZwABZfUrFAAAAQABAAEAAQATgAKgEAAADA9hb4cPAADIsDAJCQdusEAUbQABoIAAABKbQEyICfPyBwAAJQQ/AAGAAqCAAAATeaCQAAATUWFrAQMA88ESAAABAAEAI4CEsSAUvQABoAAAAAksoDAAAA/TBAQGAQgA9cUUAAABAAEAAQABABOKArBAFJwAAWFyk4CEoMAAABNNoQAAABQaAUAGAQMBoEAAABH6ZfMFDQAAFAQBAAEFAPS/EwAAAQABAAEAo4CEoIAAABM5sAATdAABEQAGAQYA9KkUAAABAAEAAQDzCAFt9K0SAAABAAEAAQABAgA7MAAAAQAABQABAJMUBQDzDQFtOzAAAAEAAAUAAQBPFAUAAQQA9w0NAAABAKgFDgABAJEAAQABAwGAE4EAEPhzOzAAAAEAAAUAAQBhEwUAI4ICoJAAABRjaXMBBQGgUAAAFCho8rsSAAABABOAArAwE3QAAW50AYACoIAAABOUsEAR8wABYWUBgAKgEAAAERugAAAAEWFucgEJAaBAAAAUZmXyihQAAAEAI4ACoJAAABPMaWzHIwAACqAwAAARHLBQEygAAbDwFLMAAbBwE5EAAaDQAAAUbzBiY2VoaWtub3Y7MAAAAQAAHwAMAA4MAADzEAMAIBEAAAMSBACNEwEAnBMDANMTAQAaFAAAHxQGAD0UAQBJFAAAYBQBAAECAqCwAAAUWaCwAAAUWmNz89AQAAABAF8AAQECsFAR8wABoMAAABQoaGny0xMAAAEA84ACZWkBAQGwkBONAAFz9LIQAAABAAEAAQABAwGgAAAAEO5zAVUQAADzgANoaXQBAQGgUAAAEwxjAc8MAAABBQGwgBRgAAF2OzAAAAEAAAcAAgDSEQMAwxMDAAEBAPR1EAAAAQC0AAEA44CEsHAR9wABDggA97UHANCwkBKZAAGgUAAAERSgoAAAE7CgEAAAB05AP70pOzAAAAEAAD0AGADGBAAAyAQAAJkFAgAVBwMA+wsDANIMAQDADwIAzg8AAPgPAAABEAEAIxABADMRCACKEQAA2xIBAOQSAQDoEgEASRMBAGcTBAC9EwEAxxMBAMwTAABDFAQAShQDALkUAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/01ff1ca5c170.js b/pr/720/docs/search.index/01ff1ca5c170.js new file mode 100644 index 000000000..980b456e5 --- /dev/null +++ b/pr/720/docs/search.index/01ff1ca5c170.js @@ -0,0 +1 @@ +rn_("AQIA9LERAAABAAEAAQABAQDzzxEAAAEAAQATgAJWyrWzZe5lcwEKAPTDEwAAAQABAAEAAYACsCAUPwABoGAAABOQb3YBgAKwMBLGAAGgAAAAE0hjZPOAhQUQBg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/023324239cca.js b/pr/720/docs/search.index/023324239cca.js deleted file mode 100644 index f5b4e02ac..000000000 --- a/pr/720/docs/search.index/023324239cca.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABsIAUPAABcPI4FAAAAQBDBQOgIAAAEWCgQAAAErVkZXPz+A8AAFADAQABAgA7MAAAAQAAEwABACUQEwATgYSgUAAAERCgEAAADCagIAAADPAcQAAzgAOwUBOEAAFhZm4=") \ No newline at end of file diff --git a/pr/720/docs/search.index/027e427e88a7.js b/pr/720/docs/search.index/027e427e88a7.js deleted file mode 100644 index 24fc65d69..000000000 --- a/pr/720/docs/search.index/027e427e88a7.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMAOzAAAAEAAI0AAgD3EAAACBKMAAEAAbBwE8wAAWXy4g8AAAEA8wABc/RNEAAAAQBNBAEAM4ADoGAAABGqZGlv") \ No newline at end of file diff --git a/pr/720/docs/search.index/02acd92cbf01.js b/pr/720/docs/search.index/02acd92cbf01.js new file mode 100644 index 000000000..4d25369ff --- /dev/null +++ b/pr/720/docs/search.index/02acd92cbf01.js @@ -0,0 +1 @@ +rn_("AQMAOzAAAAEAAI0AAgBzBwAAdQmMAAGEArBwFDkAAaBAAAARGGlzAQcA8/EQAAABABYBI4ACoLAAABLXYXQBAAOwMAkhAAGwMBOaAAGgIAAAB3RhZG8BFwIAADcDAICGoMAAABQxsAAUBAABAJgV") \ No newline at end of file diff --git a/pr/720/docs/search.index/02c3ae86743f.js b/pr/720/docs/search.index/02c3ae86743f.js new file mode 100644 index 000000000..1a9a74380 --- /dev/null +++ b/pr/720/docs/search.index/02c3ae86743f.js @@ -0,0 +1 @@ +rn_("AQEBoEAAABGKc/U1DAAAKwVKAQEAAQATggKgIAAADQxlcgECAPTuDwAAAQD3AAEAI4ECoBAAAAw0ZWkTgAKg8AAAFClucjMAA7AwCSYAAWVvdAHeEQAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/02cee3b0c9d6.js b/pr/720/docs/search.index/02cee3b0c9d6.js deleted file mode 100644 index d6583727a..000000000 --- a/pr/720/docs/search.index/02cee3b0c9d6.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEAOjAAAAEAAAAAAAkAEAAAAN8P4A/WEJIR8BLxEvETeBSuFK8UAYACsOAT6wABsDAUAwABZHDDgISxQBTAAAGgkAAAE68CgAk=") \ No newline at end of file diff --git a/pr/720/docs/search.index/03352c8d2282.js b/pr/720/docs/search.index/03352c8d2282.js deleted file mode 100644 index d59d97ef2..000000000 --- a/pr/720/docs/search.index/03352c8d2282.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA8/kPAAABAAEAAYmEoIAAABS3oEAAABRhoGAAABSDoJAAABS7AoAKE4EDoKAAABPxsNAUWgABY2l1M4ADsMAUuQABYXR1") \ No newline at end of file diff --git a/pr/720/docs/search.index/048b2390409c.js b/pr/720/docs/search.index/048b2390409c.js new file mode 100644 index 000000000..0398e5a98 --- /dev/null +++ b/pr/720/docs/search.index/048b2390409c.js @@ -0,0 +1 @@ +rn_("AQABoLAAABPPYvNZEwAALgEBAAGAAqAgAAAPz6AwAAAT22Fy8wABdAF9BwAAAQQBoEAAABRmZfKKFAAAAQABBQA7MAAAAQAACwAFAFkQBQDREgEAAhQBAFkUAAB4FAAA4wGEoDAAAA/NhQACOzAAAAEAAAsABQCmBQIAvAYEAFcMAQCMEQAA4xIAAGOAA6AAAAATWGRucg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/04cf39152c9a.js b/pr/720/docs/search.index/04cf39152c9a.js new file mode 100644 index 000000000..6e42558d1 --- /dev/null +++ b/pr/720/docs/search.index/04cf39152c9a.js @@ -0,0 +1 @@ +rn_("AQEA9yMRAAABAAEA2AIBAIsABQABAgD0shAAAAEAAQABABOAAqDQAAAUdGNz84ACZW8jgQKwAAdSAAFsdCOAA7AABbMAAbCgFAoAAWRydA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/04d8cce59752.js b/pr/720/docs/search.index/04d8cce59752.js deleted file mode 100644 index 0ef8456ba..000000000 --- a/pr/720/docs/search.index/04d8cce59752.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9CkTAAABAFoBAQDzBAFzOzAAAAEAAA0AAgCmEwcAnRQFAEcAAAWGoIAAABOGsQAUrAABsEAS4wABsIAUvAABsFATKwABFQAW9JYOAAABAAEAAQBDAISgIAAACSug0AAAE5KgMAAACQsVAATzAwIAAAEAcAU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/051bae6da550.js b/pr/720/docs/search.index/051bae6da550.js new file mode 100644 index 000000000..8db1d997a --- /dev/null +++ b/pr/720/docs/search.index/051bae6da550.js @@ -0,0 +1 @@ +rn_("AQIBsEATuwABZfLCBgAAAQABBADzbxAAAAEAAQBDAAOwQBMdAAGxABQCAAFlZnA7MAAAAQAAJAAGABkCAADRBgwA3wYMAKIPBgAQEQAAXxMBAGOAA7AwDBEABWFlaQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/05284f2042e8.js b/pr/720/docs/search.index/05284f2042e8.js deleted file mode 100644 index b54d19436..000000000 --- a/pr/720/docs/search.index/05284f2042e8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMA88ASAAABAAEAI4ECsSAUvAABY2sBBAGgQAAAEfll8wUNAAAUBAEAAQAAOzAAAAEAAAUAAgDzEAMAjBMBAHOAhKAwAAAUOggwAQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/0536332d465c.js b/pr/720/docs/search.index/0536332d465c.js deleted file mode 100644 index fb689ce1e..000000000 --- a/pr/720/docs/search.index/0536332d465c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQBoFAAABRecwGgEgAAAYICsEASxwABsEASyQABNDYBCwDzyBMAAGoAAQABBgD0tRQAAAEACgABAPMCAXIBERQAAPMDAWU7MAAAAQAABQACAH8QAwAwEQEA84QDYWVpY4ADoFAAABSYY2V0") \ No newline at end of file diff --git a/pr/720/docs/search.index/058e2bfdda25.js b/pr/720/docs/search.index/058e2bfdda25.js deleted file mode 100644 index d12c3a1de..000000000 --- a/pr/720/docs/search.index/058e2bfdda25.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIAOzAAAAEAAAUAAgB/DAMAGhMBAAECAPN7EQAAAQABAAEGAPSoFAAAAQABAAEA8wYBbfSsEgAAAQABAAEA84ACbnbzgAJhaQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/05ba80c533eb.js b/pr/720/docs/search.index/05ba80c533eb.js deleted file mode 100644 index f95eb14c0..000000000 --- a/pr/720/docs/search.index/05ba80c533eb.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBsDATXgABY/OGEQAAAQABAAEDAYATgAAQ+HM7MAAAAQAABQABAGATBQAjggKgkAAAFGJpcwcBAIDFsFATJwABoKAAABPLsHATkAABoNAAABRugAEYCPOAAmRy") \ No newline at end of file diff --git a/pr/720/docs/search.index/05f2b00cde6a.js b/pr/720/docs/search.index/05f2b00cde6a.js new file mode 100644 index 000000000..e0789e345 --- /dev/null +++ b/pr/720/docs/search.index/05f2b00cde6a.js @@ -0,0 +1 @@ +rn_("AQYA9BYRAAABAL8AAQATgQOgAAAAEV+xIBSlAAFhZG4BBQD0iBAAAAEAAQABAAEUAPXFFAAAAQABAAEAAQABBQGwgBRgAAF2OzAAAAEAAAcAAgDSEQMAwxMDACOAArBwEfcAAWJkVwIAAYawwBONAAGgoAAAE7CgkAAAE3kF4AI7MAAAAQAABQACABUHAwABEAEAAQYA89USAAABAK0AAQABoGAAAA/tcgGQBAAA1wEAgMWgMAAADA0AAIoK") \ No newline at end of file diff --git a/pr/720/docs/search.index/05fe6673879d.js b/pr/720/docs/search.index/05fe6673879d.js new file mode 100644 index 000000000..3bbd5f910 --- /dev/null +++ b/pr/720/docs/search.index/05fe6673879d.js @@ -0,0 +1 @@ +rn_("AQMA82YQAAABAAEAAYACoLAAABQosDATdAABbnRDAAOgIAAAERuwUBHzAAFlaGk7MAAAAQAABgADAA4MAAAEEgMA0xMBAPOAAmRy") \ No newline at end of file diff --git a/pr/720/docs/search.index/0620fd046b92.js b/pr/720/docs/search.index/0620fd046b92.js deleted file mode 100644 index 8c385345b..000000000 --- a/pr/720/docs/search.index/0620fd046b92.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQkBoIAAABS4ZgGYEwAAAQIA9dwQAAABAAEAXwIBAPMAAml1OjAAAAEAAAAAAAcAEAAAALYQ7xLeE98TDhQPFC8UMBQBCAD1QhQAAAEAAQABAAEA8wIBZvWaEAAAAQABAAEAAQATgAKwoBSOAAFydPMCAmFz88oQAAABAAEAAQQBsEAUZgABZfUqFAAAAQABAAEAAQABAgA7MAAAAQAACwACANQTBQCSFAUA8wMBbTswAAABAAANAAQA0AwAAG0RAADpEgUAThQFAPOBAmNl84ACYWU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/06738305d393.js b/pr/720/docs/search.index/06738305d393.js deleted file mode 100644 index 0409fdfb2..000000000 --- a/pr/720/docs/search.index/06738305d393.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9F4MAAABACIIAQAjgAKwABAjAAFlaQGJArAgFHEAAaAwAAAUe2lwEwADoCAAABMtoIAAABNCZWl19RAMAAA6AAEAAQABAAGGArCQFJkAAaAAAAASuWJkAYACsDATIQABoDAAABD4cnbXAAAAhaAwAAAQbKAwAAATeRABEzowAAABAAAAAAAKABAAAAD7CPwI/QgtCS4JHwyHEI4QSBFJEf0SY4ADsBAI7wABZG10") \ No newline at end of file diff --git a/pr/720/docs/search.index/06f31413a772.js b/pr/720/docs/search.index/06f31413a772.js deleted file mode 100644 index b7794ba79..000000000 --- a/pr/720/docs/search.index/06f31413a772.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEAOzAAAAEAAAYAAQBkEQYAAQAA9x8JAAABAF0HAQBzAAEAFQEBggKgIAAAESegMAAAEY1pdPOAA2FncwEBAaBAAAAUOmXyaBQAAAEAI4ACsFAT7wABZnPzgAJpbw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/073ff5c952c1.js b/pr/720/docs/search.index/073ff5c952c1.js new file mode 100644 index 000000000..6d8a44489 --- /dev/null +++ b/pr/720/docs/search.index/073ff5c952c1.js @@ -0,0 +1 @@ +rn_("AQMAOzAAAAEAAEQAAgAeCQAAhAxDAAEFAPTEEAAAAQABAAEAE4ACsLATpQABYWwBBAD0sQ8AAAEAAQABAHMABKAQAAAQeGJwcnY7MAAAAQAACgACAGURBgC7EQMAAYACsIAREwIksOAUDQABaXIBAwGwQBFiAAFlAZUOAAABBQA7MAAAAQAABgABAF8QBgABAwA7MAAAAQAABQABANcMBQDzAAJwczowAAABAAAAAAANABAAAACpBaoFwQYSCVkMZgwGEQcRtxK4Eg8TEBMRExITVwAAAIWwUBC2AjqwUA/QANOgQAAAEY1IgAM7MAAAAQAADwAGAKIEAABoBQMAvQ8AAOMRAwCyEgMA5hIBANMAhKBgAAAM6xAIBvOvAQAAAQAaCw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/0756dab3ae0d.js b/pr/720/docs/search.index/0756dab3ae0d.js new file mode 100644 index 000000000..81d17f2be --- /dev/null +++ b/pr/720/docs/search.index/0756dab3ae0d.js @@ -0,0 +1 @@ +rn_("AYkCsCAUcgABoDAAABR8aXATAAOgIAAAEy6ggAAAE0NlaXX1EAwAADoAAQABAAEAAYYCsJAUmgABoAAAABK6YmQBgAKwMBMiAAGgMAAAEPhydtcAAACFoDAAABBsoDAAABN6EAETOjAAAAEAAAAAAAkAEAAAAPsI/Aj9CC0JLgmHEI4QSRFKEf4S") \ No newline at end of file diff --git a/pr/720/docs/search.index/0766b076163c.js b/pr/720/docs/search.index/0766b076163c.js new file mode 100644 index 000000000..55665fd68 --- /dev/null +++ b/pr/720/docs/search.index/0766b076163c.js @@ -0,0 +1 @@ +rn_("AQACoKAAABM4oDAAAAzOYWkBehMAAAEAAbAwEUsAAW7yWAcAAAEAAQEA89QHAADZBwEAEwADsCAQGAMgoFAAABCoZWlz9VsEAAABAAEAAQABAAGEArCgFBsAAbCgFB0AAWNy8wEBdPTtEQAA6wABAAEAAQMBsGAUawABZjswAAABAAAHAAMACAwDAIsTAQATFAEA84ACYWXzgIQAKAU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/07aa85ef4d97.js b/pr/720/docs/search.index/07aa85ef4d97.js deleted file mode 100644 index 88e45aab4..000000000 --- a/pr/720/docs/search.index/07aa85ef4d97.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9OgPAAABAPAAAQCDAISgQAAADPuwcBNxAAGwIAx4AAEQBQI7MAAAAQAACQADALsEAwB/BQIAzhECAAGAAqAgAAARJbAgFDwAAWR0AYQCsLAUjgABsAAT3gABYXPTgISgsAAAFHNAKAQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/07c9dcfddcef.js b/pr/720/docs/search.index/07c9dcfddcef.js new file mode 100644 index 000000000..398fecdf1 --- /dev/null +++ b/pr/720/docs/search.index/07c9dcfddcef.js @@ -0,0 +1 @@ +rn_("AQMAOzAAAAEAAAUAAQDdEgUAAQQBoFAAABQoaPK7EgAAAQABAAKwQBO7AAGgoAAAFEhlcjowAAABAAAAAAAHABAAAADCBsMGYQdiB+4P7w/mEOcQ84ADZ2lz") \ No newline at end of file diff --git a/pr/720/docs/search.index/08410bada6e3.js b/pr/720/docs/search.index/08410bada6e3.js deleted file mode 100644 index bb89e3d92..000000000 --- a/pr/720/docs/search.index/08410bada6e3.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQA9HQUAAAMACMAEQABAgGwQBK+AAFlAcsPAAABgAKgkAAAFDagkAAAFDcyM5cCAADGoCAAAAx0oGAAABFEsGANCAABAWQAAzswAAABAAAKAAMAGQcFAEAMAAB6EwMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/0867d8c9f05d.js b/pr/720/docs/search.index/0867d8c9f05d.js deleted file mode 100644 index 99d831a68..000000000 --- a/pr/720/docs/search.index/0867d8c9f05d.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYYCoAAAABNXoAAAABNYZHIBgAKgcAAAE+qgMAAAERhmdAELAaBAAAAUOmXyaBQAAAEAI4ECsFAQ7wABY3YBAAGwgBQ8AAFw8jgUAAABAEMGA6AgAAARYKBAAAAStWRlc/P4DwAAUAMBAPMABGlyc3Y7MAAAAQAADwAFAPQGBQDcEgUACRMBAIMTAABzFAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/086dd93914d3.js b/pr/720/docs/search.index/086dd93914d3.js new file mode 100644 index 000000000..e1482e6f3 --- /dev/null +++ b/pr/720/docs/search.index/086dd93914d3.js @@ -0,0 +1 @@ +rn_("AQIA9AoRAAABAJMBAQABAAD08g8AAAEA9QAIASOCArBQE1YAAWVzAQIA9CYTAAABAJIAAQABAwD0XBMAAAEAmAABAPOFAmJ1AQIA9HYRAAABAHwBAQDzgAJpbPMAA2J0dTowAAABAAAAAAAPABAAAAByB/sH/Af9B/4HGxDhELATMhR/FIAUhBSRFJIUuBS8FAEMAPMVFAAAAQABAAGAArAACRkAAaAgAAANA2RuAQYA9CQTAAABAJIAAQDzAwFi9AgRAAABAJMBAQCXBgAAh7BAD/AAAaBwAAASqLCQE1QAATgJAzowAAABAAAAAAAkABAAAADBBcIFwwXEBTQHNQczDPgM+Qz6DP4M/wwADegP6Q88ED0QQRBCEF8QYBBhEGIQYxBkEGUQqBCtENkQ2hCQE7QT2xN1FIEUpBS1FA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/08723cac4615.js b/pr/720/docs/search.index/08723cac4615.js new file mode 100644 index 000000000..9e65d7450 --- /dev/null +++ b/pr/720/docs/search.index/08723cac4615.js @@ -0,0 +1 @@ +rn_("AQIA9awRAAABAAEAAQABAAGAArBgExcAAaAgAAARAG95AQABoMAAABQ8afRwEwAACAAcABsAAQMA9JUTAAABAAEAAQABBQD0qRQAAAEAAQABABOAArBwFIIAAWVpAQIA9P4QAAABAJsAAQABAgGgQAAAE0dyOzAAAAEAAAcAAgD8EAEAlBEFAPOAAmFvZwcAAIewgBNGAFqwoBO9AAEMMAc7MAAAAQAADgAEAJUEBQAcDAAAxxEDAK0SAwCnAACAhaDwAAAT0LBQEE8AAaCQAAARi5SBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/08f0fa1cddd0.js b/pr/720/docs/search.index/08f0fa1cddd0.js deleted file mode 100644 index 29675be49..000000000 --- a/pr/720/docs/search.index/08f0fa1cddd0.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYADoIAAABLWsFAS/AA8sHAULwABYWNzAQABoIAAABS4ZvL6CAAAngoBBwD1ZhMAAAEAAQABAAEAI4ACoFAAABFjYW/zAAJmczswAAABAAAIAAQATQcAAH4HBQAEDQAAmxEAAPOAAmR5") \ No newline at end of file diff --git a/pr/720/docs/search.index/090b2c6b7f03.js b/pr/720/docs/search.index/090b2c6b7f03.js new file mode 100644 index 000000000..e3b316dff --- /dev/null +++ b/pr/720/docs/search.index/090b2c6b7f03.js @@ -0,0 +1 @@ +rn_("AYACsRAUnAABsBAMUwABZW8BBQA7MAAAAQAADQABAJ0RDQABAgDzBxAAAAEAAQABAgD0AxAAAAEAAQABAAEDADswAAABAAAIAAEAuRAIAIcHAACHsKATxwABsNAUXQABoFAAABQojBQROzAAAAEAAAYAAwBWBwAA6hADALsSAQDzgAJsdBOAA6AgAAAMzrCgFEEAAWFkbg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/0a7259509e70.js b/pr/720/docs/search.index/0a7259509e70.js new file mode 100644 index 000000000..681a79bcb --- /dev/null +++ b/pr/720/docs/search.index/0a7259509e70.js @@ -0,0 +1 @@ +rn_("AQIAOzAAAAEAAAUAAQCTFAUA8w0BbTswAAABAAAFAAEATxQFACMDA7BAEsQAAbAAE4gAiWVmczswAAABAAAYAAYANBEHAOgSAQBnEwQAQxQEAEoUAwC5FAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/0a99e2bd71de.js b/pr/720/docs/search.index/0a99e2bd71de.js deleted file mode 100644 index 5cdee67e1..000000000 --- a/pr/720/docs/search.index/0a99e2bd71de.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBoEAAABQ6ZfJoFAAAAQABAAD0DhMAAAEAAQABAPMEAWT0sRIAAAEAAQABAKcAAAKFsKAUVgABsEATDAABsHAT/wABFYgAASgUAAABAAGwgBQ8AAFw8jgUAAABAEMAA6AgAAARYKBAAAAStWRlc/P4DwAAUAMBAPOAAmVp") \ No newline at end of file diff --git a/pr/720/docs/search.index/0b8e51928cc4.js b/pr/720/docs/search.index/0b8e51928cc4.js new file mode 100644 index 000000000..ae066424a --- /dev/null +++ b/pr/720/docs/search.index/0b8e51928cc4.js @@ -0,0 +1 @@ +rn_("AQYA9I8RAAABAAEAAQABAgA7MAAAAQAACgAEAI8QBQDTEgEANBMBAFoUAADzgAJmbgEBADswAAABAAAIAAIAog8GAF8TAQDzgAJkbgEBAPMuBwAAAQABAAGGAqAAAAATWKAAAAATWWRy8wEBdgGEEwAAQwADsIAS6AABsLAUjAABa2xyOzAAAAEAAAwAAwAlBwgABg0BAEgQAQABAgD19AcAAAEAAQABAAEA8wCEFEEAAYAAAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/0d2ad13042cb.js b/pr/720/docs/search.index/0d2ad13042cb.js new file mode 100644 index 000000000..e88f2f314 --- /dev/null +++ b/pr/720/docs/search.index/0d2ad13042cb.js @@ -0,0 +1 @@ +rn_("AQMBgBOBABD4czswAAABAAAFAAEAYRMFACOCAqCQAAAUY2lzAQEA9CYTAAABAJIAAQAjgAKwoBQNAAFjbgGEArCgFBsAAbCgFB0AAWNyAQIAOzAAAAEAAAYAAQBfEAYAE4ICoCAAABP/ZXUBAgDzzxEAAAEAAQABgAKwIBQ/AAGgYAAAE5BvdmOBA6AQAAATSGFjcwEDADswAAABAAAFAAEA1wwFAAEBAPMbCQAAAQABAAEBAPT+EAAAAQCbAAEAU4ADoMAAABRvbnB1AYACsDAQHAABoWAAABSoYWUBgQKwQBLIAAGwQBLKAAE0NgEFAaBQAAAUKGjyuxIAAAEAAQUA9HUQAAABALQAAQBzgISwMBN0AAEBoAQBCADzcBMAAAgAHAATgAKwQBHzAAFhZQEKAPPJEwAAagABAAEAAaAgAAAQl3IBYREAAAEAAPTNEwAAAQBKAAEApwEAgIWgMAAAEPugEAAAERsJICEBCQGgQAAAFGZl8ooUAAABAEOAhKAgAAAUdKCQAAATzKEwAAAUiRBJAAECAPRcEwAAAQCYAAEAE4ACsEATKAABaXkBAQKgMAAAEv6gQAAAE0dncjswAAABAAAHAAIA/BABAJQRBQABgAKwABPnAAGwABPpAAE0NgEGAPS2FAAAAQAKAAEA8wICcnYBEhQAAPMCAWU7MAAAAQAABQACAH8QAwAxEQEA84ACZHTn1x8AEaAwAAARHLDwFLMAAbBwE5EAATBhYmNlaGlrbG5vcHJzdHV2OzAAAAEAABkBRQDDBAAAqQUBALEFAACzBQEAwQYAACQHAABKBwIAWgcAAGwHBQBzBwAA1AcAAPkHAQD/CAEABQkBABIJAABxCQEAdQmMAP8LAwAODAAAEgwDACAMAABZDAAAZgwAAK0PAQDYDwUAWBAAAIUQAQCZEAAAphABAO8QAQDzEAMABhEBACARAAA+EQEAXxEAAHwRAgCrEQAAyxEAAO0RAADxEQEA9xEBAAMSBACoEgAAtxIBALoSAADGEgEA2BICAA8TAwAkEwEAMRMBADoTAQBAEwEAQxMAAEYTAABYEwAAbhMBAI0TAQCcEwQAtxMBAMoTAQDNEwEA0xMBAN4TAAAYFAIAHxQGAD0UAQBJFAAAYBQBAIwUAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/0d7d4a89683f.js b/pr/720/docs/search.index/0d7d4a89683f.js new file mode 100644 index 000000000..1e4538d62 --- /dev/null +++ b/pr/720/docs/search.index/0d7d4a89683f.js @@ -0,0 +1 @@ +rn_("AQEA9UoJAAABAAEAAQABAPMAAWnysxQAAAEAAQQCoCAAABHeoDAAABKpYmgByg8AAKcAAIDFoBAAAAzusBAUnAABoDAAABB8BBAoAQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/0d7f8c5032c4.js b/pr/720/docs/search.index/0d7f8c5032c4.js new file mode 100644 index 000000000..e108f55b9 --- /dev/null +++ b/pr/720/docs/search.index/0d7f8c5032c4.js @@ -0,0 +1 @@ +rn_("AQABsIAT7AABdAEUCQAAAQkA884SAAABAAEA84ACY2cBgwKgkAAAFDegkAAAFDgyMwGAAqBQAAAUY6CAAAAThGNl8wACc3TyQAcAAAEAAQABoLAAABPPYvNZEwAALgEBACOAAqAAAAATWGRyI4ACoFAAABQpY2XzgAJpeQEGAPVAEQAAAQABAAEAAQABAQGwQBRnAAFl9SsUAAABAAEAAQABAPcAAICFoBAAAAwPKWAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/0d89aabcdae7.js b/pr/720/docs/search.index/0d89aabcdae7.js new file mode 100644 index 000000000..d526e19eb --- /dev/null +++ b/pr/720/docs/search.index/0d89aabcdae7.js @@ -0,0 +1 @@ +rn_("AQIBsEAUfQABdDswAAABAAANAAYA/xIDAGwTAQDcEwEA8xMBAHIUAQCaFAEAE4ACsDATMwFJaXABBQDzsRMAAAEAAQATgAKgMAAAFAxleVMAA7BwFBgAAWJlcwFAEAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/0d9f9f9c3b24.js b/pr/720/docs/search.index/0d9f9f9c3b24.js new file mode 100644 index 000000000..dd689a05d --- /dev/null +++ b/pr/720/docs/search.index/0d9f9f9c3b24.js @@ -0,0 +1 @@ +rn_("AQEAOjAAAAEAAAAAAAcAEAAAAFITUxPuE+8TJhQnFHYUdxTzBgFpAXETAABDgAOwABSxAAGwUBNGAFpkZm4BAAGwQBMdAAFlOzAAAAEAAA0AAgDRBgwAEBEAACOAAqAwAAAMEWFlNwAAgMWwUBOaAAGwEBQ/AAGwYBOhAAEAApgI") \ No newline at end of file diff --git a/pr/720/docs/search.index/0ded295865bc.js b/pr/720/docs/search.index/0ded295865bc.js new file mode 100644 index 000000000..fb36ec67f --- /dev/null +++ b/pr/720/docs/search.index/0ded295865bc.js @@ -0,0 +1 @@ +rn_("AQACoCAAABOTsDAR6wABaXTy9xIAAAEAAQMAOzAAAAEAAAYAAQBlEQYAAQgA9P0TAAABAIsABQATAQOwkBRkAAGwUBNCAWZnbHA7MAAAAQAAEgAJAGkQAgDuEQEALxMBAFITAQCJEwEA7hMBACYUAQA1FAEAdhQBAAGAArAwEecAAbAwEekAAXJ2AQQBsAAStwABZDswAAABAAAFAAIA4xEDAOYSAQC3BQABh7BQErkBF7BgE0AAAZQJAzowAAABAAAAAAALABAAAADfDOAM4QybDpwODBGPEZARkRGSETYTcRMjgAKgEAAADN5ubwEDAPNmEAAAAQABACOAAqAAAAAMDmRyYwGEoFAAABGMoDAAABCkFAEQ8pgHAAABABOAA7BgEtsAAbAAD6sAAWNnchOAA6CwAAAUGqBAAAAOmmVvcw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/0e276ddba088.js b/pr/720/docs/search.index/0e276ddba088.js deleted file mode 100644 index fdbea5899..000000000 --- a/pr/720/docs/search.index/0e276ddba088.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQwA9MITAAABAAEAAQABBgDzchEAAAEAAQABggKwYBNIAAGw0BRoAAFpchOAArAQDOkAAWVpFwMAg4ixMBSJAAGgYAAAEXGgUAAAEQWwkBMYAAGwQBEBAAG0EAfzAAFh9D0JAAABAAgIAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/0e2c4243bbb8.js b/pr/720/docs/search.index/0e2c4243bbb8.js deleted file mode 100644 index 64d321b06..000000000 --- a/pr/720/docs/search.index/0e2c4243bbb8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9D0JAAABAAgIAQABCQGggAAAFLhmAZgTAAABAgD13BAAAAEAAQBfAgEA8wACaXU6MAAAAQAAAAAABwAQAAAAthDvEt4T3xMOFA8ULxQwFAEIAPVCFAAAAQABAAEAAQDzAgFm9ZoQAAABAAEAAQABABOAArCgFI4AAXJ08wACYXPzyhAAAAEAAQDzgAJ0dg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/0e517afb84fa.js b/pr/720/docs/search.index/0e517afb84fa.js new file mode 100644 index 000000000..a635d8b56 --- /dev/null +++ b/pr/720/docs/search.index/0e517afb84fa.js @@ -0,0 +1 @@ +rn_("AQIAOjAAAAEAAAAAAAgAEAAAABoMGwypD6oP6g/bEAARkROSEwEAAPQ3CQAAAQABAAEAAQUBsDATGwABaPMKFAAAAQBwABODArAwEM0AAWNwAQMA9OgPAAABAPAAAQABgQKgAAAAEYqgEAAAD8dldfOAAmFyAQAA9L8RAAABAAEAAQABgAKgkAAAE/SwUBKlAAFid/OAAmR0E4ACsJATNAABbnLzAAJldPTEEAAAAQABAAEAAQEA9XoMAAABAAEAAQABABOAArCwE/AAAWFvIwACsEAM/AABZXQ7MAAAAQAACQAEAL8EAQCCBQEAXAwBALERAwABAgA7MAAAAQAACQACAOMHBwAVEwEAAYACsJATfwABoKAAABPzZXYTgAKxgBTFAAFjbQGCArBAFB0AAaBQAAAR7WJmE4ACoEAAABRIZHMjgAKg0AAAFJljbvOAhBEBQAEFAbBAE1oAAWUBpBIAAEOCA6EAAAAUp6DQAAAUeWttcxOAArBgEOQAAWFyAQUAOzAAAAEAAI0AAgD3EAAACRKMAAGCA7AgExcAAbAgEH0AAbBAEXoAAWtsc1OAA7AgFH0AAWt0dQGJhKCAAAAUuKBAAAAUYqBgAAAUhKCQAAAUvAKAChOCA6CgAAAT8rDQFFsAAWNpdQEBAPS7EQAAAQABAAEAQ4ADsXAUwwABoNAAABQxY29zI4ACsGAQ4gABaW8BAAD0JAwAAAEAUwABACOBAqDgAAAUTmV5AQ0AOjAAAAEAAAAAAAcAEAAAAFITUxPuE+8TJhQnFHYUdxQBgQKwQBNyAAGgwAAAFDBlbwECADowAAABAAAAAAAIABAAAADfD+APkxHxEvIS8hN5FK8UsBTzAQFvOzAAAAEAAAkABABcCQEAnxADAOIQAQDwEwEA84ADbW5yAQAAOzAAAAEAAAYAAgCPEwAA9xMFAEOAA7BAFG0AAaAgAAAM+2VycyMAArAwE9MAAWNy8r0TAAABAAGBArCAEx0AAaEAAAAUeGNmAQsA9HsTAAABAAEAAQABgAKgAAAAEJWgAAAAEJY0NvMCAXYBAg0AAPMAAmRsARcJAADX/jkAkrCgFBsAAbBwEd8AAbCAEvsAAaCwAAATNp3dfzswAAABAAAXAAsAqwEBALsEAwB/BQIA+wYBAAUHAgA1DAAA9w8AAGARAADPEQIAqhICAF8UAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/0e8345b033a7.js b/pr/720/docs/search.index/0e8345b033a7.js new file mode 100644 index 000000000..2c410bf98 --- /dev/null +++ b/pr/720/docs/search.index/0e8345b033a7.js @@ -0,0 +1 @@ +rn_("AYECoBAAABNIoHAAABOQYWMBhwKwABPnAAGwABPpAAE0NlMAhKCQAAATcLCwFA0AAYEACfUkBwAANgA/CRIBIAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/0ea74f411a20.js b/pr/720/docs/search.index/0ea74f411a20.js new file mode 100644 index 000000000..98279d8dd --- /dev/null +++ b/pr/720/docs/search.index/0ea74f411a20.js @@ -0,0 +1 @@ +rn_("AQAA9AoRAAABAJMBAQAjgQKgYAAAE0NiaQEAAPTyDwAAAQD1AAgBI4ICsFATVgABZXMBiQKwIBRyAAGgMAAAFHxpcAECAPQmEwAAAQCSAAEAAQMA9FwTAAABAJgAAQDzhQJidQECAPR2EQAAAQB8AQEA84ACaWy3AQAAhaAgAAATLhIBDDowAAABAAAAAAAUABAAAAByB/sH/Af9B/4HEAxKDEsMTAxNDBsQ4RCwEzIUfxSAFIQUkRSSFLgUvBQBBQDzFRQAAAEAAQBDhgOwkBSaAAGgAAAAErpiZHcBgAKwAAkZAAGwIA0DA2lkbgEDAPPwDwAAAQAHAQECAPYaDAAAAQCOAwEA5wMBAAEAAPQ3CQAAAQABAAEAAQAAOzAAAAEAAAYAAgCPEwAA9xMFACOBArBAFG0AAWVz84ADZXh5AQAA9DMJAAABAAEAAQAjgAKwIBMiAAFyeAcNAADIoJAAABNxsFAQHAABsMATuwABoBAAABFysEAM5gABAEeACzowAAABAAAAAAAJABAAAABwBXEF7AztDAEN7A9GEEcQGRMaEwEGAPQkEwAAAQCSAAEA8wMBYvQIEQAAAQCTAQEAtwwAAImgcAAAEqiwkBNUAAGwYBA+AAGgMAAAE3o4iRM6MAAAAQAAAAAALwAQAAAAwQXCBcMFxAU0BzUH+wj8CP0ILQkuCR8MMwz4DPkM+gz+DP8MAA3oD+kPPBA9EEEQQhBfEGAQYRBiEGMQZBBlEIcQjhCoEK0Q2RDaEEkRShH+EpATtBPbE3UUgRSkFLUU") \ No newline at end of file diff --git a/pr/720/docs/search.index/0ed1801265ff.js b/pr/720/docs/search.index/0ed1801265ff.js deleted file mode 100644 index d7b381034..000000000 --- a/pr/720/docs/search.index/0ed1801265ff.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABoEAAABCtdPfzDAAARgPwAgEAuwCfAAEA8wABczswAAABAAAcAAgAtAQCACkMAwDwDwEAtxABAPgQAQDoEQEAphMHAJ0UBQAjgAKxEBSkAAFhdA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/0f5552078702.js b/pr/720/docs/search.index/0f5552078702.js new file mode 100644 index 000000000..6a4a4d951 --- /dev/null +++ b/pr/720/docs/search.index/0f5552078702.js @@ -0,0 +1 @@ +rn_("AQQA9HUUAAAMACMAEQABAgGwQBK/AAFlAcsPAAABgAKgkAAAFDegkAAAFDgyM5cCAADGoCAAAAx0oGAAABFFsGANCAABAWQAAzswAAABAAAKAAMAGQcFAEAMAAB7EwMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/0fa6c5affaaa.js b/pr/720/docs/search.index/0fa6c5affaaa.js new file mode 100644 index 000000000..d7494ad43 --- /dev/null +++ b/pr/720/docs/search.index/0fa6c5affaaa.js @@ -0,0 +1 @@ +rn_("AQAAOzAAAAEAAAYAAgCPEwAA9xMFACOIArBAFG0AAWVzAQQBsDATXwABY/OHEQAAAQABAAEFADswAAABAAAIAAMA/RECAAMTBAAqFAAA8wEDY2Vw88sMAAABAAEAAQIA9hgJAABYABMHAQC4AAEA84ACbnI=") \ No newline at end of file diff --git a/pr/720/docs/search.index/0fdf431ad34e.js b/pr/720/docs/search.index/0fdf431ad34e.js new file mode 100644 index 000000000..4b80a41d9 --- /dev/null +++ b/pr/720/docs/search.index/0fdf431ad34e.js @@ -0,0 +1 @@ +rn_("AQIA9CYTAAABAJIAAQABAwD0XBMAAAEAmAABAPMFAmJ1OjAAAAEAAAAAAAcAEAAAAIUQhhA+ET8R8RHyETETMhMBAgD0dhEAAAEAfAEBAAEFAPN8EQAAAQABAAEEAPTMEgAAAQCpAAEA84CEEQkA") \ No newline at end of file diff --git a/pr/720/docs/search.index/0fe80180cdfe.js b/pr/720/docs/search.index/0fe80180cdfe.js new file mode 100644 index 000000000..3db4026d0 --- /dev/null +++ b/pr/720/docs/search.index/0fe80180cdfe.js @@ -0,0 +1 @@ +rn_("AQEAOjAAAAEAAAAAAAgAEAAAAAkJdxAjESQRJRH9E/4TiRSOFAEBAqBAAAAUb6AwAAARKWVo9wEJAAAuAC8DAQCCBaECAQABAgD02BEAAAEAAQABABOBArAgEdwAAWFz84ACbm8BAgD0shAAAAEAAQABABMAAqDQAAAUdGNz8iMQAAABAPOAA2Vpbw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/103a5d03a0ae.js b/pr/720/docs/search.index/103a5d03a0ae.js deleted file mode 100644 index 0f4ce5587..000000000 --- a/pr/720/docs/search.index/103a5d03a0ae.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9AUUAAABAE4AAQDzAwFj8gcTAAABACOAArBwFLwAAWhvAYICsAAS4wABsAAR6gABZXNDAAOgoAAAFFmgIAAAE5JlaXTy9hIAAAEAAQIAOzAAAAEAAAYAAQBkEQYAAQIBoEAAABQ6ZfJoFAAAAQDzgAJpbwEIAPT8EwAAAQCLAAUAEwEDsJAUYwABsFATQQFmZ2xwOzAAAAEAABIACQBpEAIA7REBAC4TAQBREwEAiBMBAO0TAQAlFAEANBQBAHUUAQABgAKwQBK4ARegIAAAEShhaQEDAPPXEgAAAQABACOBArAwFAwAAWNpAQAA9CkTAAABAFoBAQDzAwFzOzAAAAEAAA8AAwDoEQEAphMHAJ0UBQABAwD15hEAAAEAJQEBAGEB84ACcnYBAAA7MAAAAQAABQACALYSAQAOEwMA8wIBZDswAAABAAAJAAMA4hEDALESAwDlEgEAI4ACoJAAABRYaW8TgAKw8BSsAAFsbwEFAPR0FAAADAAjABEAI4ACoGAAABOGZ3MjgAKwkBRWAAFibPfHAACNsGAUjgABsHAT/wABsGATPwABsFATKwABtckXOjAAAAEAAAAAACIAEAAAALUFAQkvCV4MXwzfDOAM4QyWDpcOmA6ZDpsOnA78D/0P/g//DwAQ0BDREAwRLxGOEY8RkBGREeARNRNOE08TcBMoFIEUghQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/105593ddf996.js b/pr/720/docs/search.index/105593ddf996.js deleted file mode 100644 index 419958851..000000000 --- a/pr/720/docs/search.index/105593ddf996.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA9T8RAAABAAEAAQABACOBArCQFAcAAWF0Q4ADsRAUiQABsIATyQABY290EwACsAAUXAABbnL2DQIAAAEAewIBAKwCXAw=") \ No newline at end of file diff --git a/pr/720/docs/search.index/10a7deb028db.js b/pr/720/docs/search.index/10a7deb028db.js new file mode 100644 index 000000000..b8847bb97 --- /dev/null +++ b/pr/720/docs/search.index/10a7deb028db.js @@ -0,0 +1 @@ +rn_("AQEBsIATbgABdfJECQAAAQAjgAKwEAlCAAEzNgEGAPPxEAAAAQAWAROAArAAD7YAAW91AQIA81EHAADvAQEAAQMA884SAAABAAEAI4ACsAARxQABaGkBAAA7MAAAAQAAEwABAIQHEwAjgAKgMAAADN1hZfOAAnJ0E4ACsDATvQABYWwBAAGggAAAFLlm8voIAACfCgEHAPVnEwAAAQABAAEAAQAjgAKgUAAAEWRhb/MCAmZzOzAAAAEAAAgABABNBwAAfgcFAAQNAACcEQAAE4ACoEAAAAwNYW8BAwGwQBR9AAF08twTAAABACOFAqBAAAAUDGJzIwADsEARAwABoFAAABFxYWJm9wcJAAABAEgAeAcBAGMAAQATgQKgUAAAEgBndAGAAqBAAAAR7aAgAAAT62FpAQIA9D0JAAABAAkIAQABAgDzUAwAAAEAAQATgAOwEAk7AAGwMBQdAAFpdXkBAgA7MAAAAQAACwACANUTBQCTFAUA8wgBbTswAAABAAAMAAMAbhEAAOoSBQBPFAUAAYECoIAAABLXoHAAABQwYXPzgAJucrfbAQCNoUAAABSOoCAAAAk/sFAQAQABN5UPOzAAAAEAADUCBQD+AQAAJAIyAQgHAAB1BwAAAgr/AA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/10ce52a8a445.js b/pr/720/docs/search.index/10ce52a8a445.js new file mode 100644 index 000000000..3dcda7b55 --- /dev/null +++ b/pr/720/docs/search.index/10ce52a8a445.js @@ -0,0 +1 @@ +rn_("AQMBoAAAABNOc/TODwAA+QMBAAQAAQECsGAUPwABsEAUfQABZHQ7MAAAAQAADQAGAP8SAwBsEwEA3BMBAPMTAQByFAEAmhQBAAEBA7BwEgEAAbCAEtsAAYATgQAQ+G1uczswAAABAAALAAIA8QgFAGETBQCjgISwsBPKAAGxcBS9AAEIQIIBAIWgcAAAEqCwMBSxAAGgcAAAEQ+xABQ/AAGwABNCAWYGIQHyeAUAAAEAAQEAOzAAAAEAAAYAAQDDFAYA8wYBZfRwFAAAAQA0AAEAEwEDsEAUnAABsGATiACJYXJ183sQAAB6AgEAdwQAAIegEAAABa2wMBMzAUmgQAAAETMRwQw7MAAAAQAABgACAI8TAAD3EwUA") \ No newline at end of file diff --git a/pr/720/docs/search.index/1110623e8ce9.js b/pr/720/docs/search.index/1110623e8ce9.js new file mode 100644 index 000000000..7e9732757 --- /dev/null +++ b/pr/720/docs/search.index/1110623e8ce9.js @@ -0,0 +1 @@ +rn_("AYACsIATCgABsKAThQABaXQBgAKw4BSHAAGwQBBTAAFscgEGAPTqEAAAAQABAAEARwUAAIeg0AAAFF+wUBBRAAGgAAAAE4ew8BQ5AAEFkQPy9A8AALAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/11349ef54c1b.js b/pr/720/docs/search.index/11349ef54c1b.js deleted file mode 100644 index c2f04a25d..000000000 --- a/pr/720/docs/search.index/11349ef54c1b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQACoDAAABEcoJAAABOTMGj1AhIAAJkBAQABAAEAE4ACoDAAAA/MZHIjAISwEAj3A0CwIAwDAQygMAAAD/QSABj1nAUAAC0AAQABAAEAAQIA9LUUAAABAAoAAQABAgDzbxAAAAEAAQDzgAJpcgEBArBAEWEAAaBQAAATeGVz85UOAADiAgEAAQsA9qITAAABAKoAWQAYAAEA84ACbHTTgISgkAAAE1ABRAQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1153acfed1a0.js b/pr/720/docs/search.index/1153acfed1a0.js new file mode 100644 index 000000000..078e514e7 --- /dev/null +++ b/pr/720/docs/search.index/1153acfed1a0.js @@ -0,0 +1 @@ +rn_("AQQAOjAAAAEAAAAAAAcAEAAAANgP2Q+mEKcQJBMlE7cTuBMBBAD02g8AAAEAAQABAAEAAqAQAAAMg7BQFAQAAWlv8ikJAAABAPOAA2Vpbw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/11a0ed9e6082.js b/pr/720/docs/search.index/11a0ed9e6082.js deleted file mode 100644 index 1c950b176..000000000 --- a/pr/720/docs/search.index/11a0ed9e6082.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9UMQAAABAAEAXwIBAAEEAaAAAAAQ4XP1/gwAAAEAAQBBAwEAAQIA9asRAAABAAEAAQABAAGAArBgExYAAaAgAAARAG95AQABoMAAABQ7afRvEwAACAAcABsAAQUA9KgUAAABAAEAAQATgAKwcBSBAAFlaQECAPT+EAAAAQCaAAEAAQIBoEAAABNGcjswAAABAAAHAAIA/BABAJMRBQDzgAJhb2cDAACGsIATRQBasKATvAABDDAGOzAAAAEAAAgAAwAcDAAAxhEDAKwSAwDzggJlaUcBAACFsHATzAABoIAAABS4oEAAAA/3sEAE9PoIAADoBgEAtQMBgQKgIAAAEPqwUBK8AAFhbwEEAaAAAAAT5XMB+RAAAGMEA7BQEWsAAWNlc/YCCQAAAQABACwAAQBxCQEAADswAAABAAAkAAgAQgcHAEMQAgCcEQ0AyxECAKQSAQArEwEAfhMBABQUAgABBQDzHhMAAAEAAQABAQA7MAAAAQAABQACAP8LAwD2EQEAUwADsDAUVgABZXBy9OQPAAABAO8AAQABAAOwQBQcAAGhQAAAFI2gUAAAEexiY2YBCAcAAOOAhLFAFLUAAQIwEAEBhKCwAAAT2rBAELcAAbDAFAkAAaBgAAARkhQgBPbvBgAAYAkBADoBLgEXAQEDADswAAABAAAFAAEA3BIFAAEAAaCgAAAUR3L07g8AAAEA9wABAPOBAmdzAQcA9WYTAAABAAEAAQABAAGAAqBAAAARY7BQEUoAAWNp84ACYW8BAAGgIAAAEYNy8zQMAACBA3ABE4ACgAVyAB0ncngBAwKwQBMhAAGgMAAAE3lld/KOEAAAuwATgwKgcAAAE7NnbwECAPUAEwAAAQDyAH4AAQATgAKwMBMyAUlpcAEGAPOwEwAAAQABAPMFAmJzAUAQAAABAgD0HhAAAAEAAQABACOAAqBgAAASoGJj918BAM2wYBDfAAGgkAAAEqHATnIVOjAAAAEAAAAAABgAEAAAABoCGwKEBIUEhgQSB00Hfgd/B4AHgQeCB4MH+gt0DAQNOxBNEE4QGxGbEZsUnBSwFLEU") \ No newline at end of file diff --git a/pr/720/docs/search.index/11b0b034f6ac.js b/pr/720/docs/search.index/11b0b034f6ac.js new file mode 100644 index 000000000..13c2ce077 --- /dev/null +++ b/pr/720/docs/search.index/11b0b034f6ac.js @@ -0,0 +1 @@ +rn_("AQABoCAAAAzrbQGEBQAAAQAA9A8TAAABAAEAAQDzBAFk9LISAAABAAEAAQAjhISwoBRXAAGwQBMNAAGwcBQAAAEVgAAzgAOw0BRBAAFhZWk=") \ No newline at end of file diff --git a/pr/720/docs/search.index/11b42c6b0cf2.js b/pr/720/docs/search.index/11b42c6b0cf2.js deleted file mode 100644 index 740326da5..000000000 --- a/pr/720/docs/search.index/11b42c6b0cf2.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA9DsHAAABAAEAAQABAQGgQAAAEYlz9TUMAAAqBUoBAQABABOCAqAgAAANDGVyI4ADoEAAAAw0sDAJJgABZW90AQAA9DcHAAABAAEAAQABAgD0pBMAAAEADwABABOAArBAFFwAAWJ284ACb3gBCgD14BMAAAEAAQB4AAEAAYECoCAAABD6sFASvAABYW8BBAGgAAAAE+VzAfkQAABjAwOwUBFrAAFjZXP2AgkAAAEAAQAsAAEAcQkBAQA7MAAAAQAABQABANcMBQAjgAKwMBNBAWZydPMAhgHAB/LxAQAA/AU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/11e47b81ccfd.js b/pr/720/docs/search.index/11e47b81ccfd.js new file mode 100644 index 000000000..fb0cbbcbe --- /dev/null +++ b/pr/720/docs/search.index/11e47b81ccfd.js @@ -0,0 +1 @@ +rn_("AYADsAAT5wABsAAT6QABsHAUYAABNDZhAQQA9LYUAAABAAoAAQAjgQKgQAAAEV9tcAECADswAAABAAAOAAQAagcBAAgNAQBPEQkAjREAAAEBADswAAABAAAIAAMA1xIAAE0TAADDFAYAAQEAOzAAAAEAAAoAAwBzEQIAvxMDAKkUAwAjgAKgMAAAEFhkZ9cDAADGoIAAABKxQEaACDswAAABAAAYAAkA9Q8BABYRAQBLEQEAWxEDANIRBQDDEwMAEhQAAHAUAQClFAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/11f92487829f.js b/pr/720/docs/search.index/11f92487829f.js new file mode 100644 index 000000000..dcd0d2d27 --- /dev/null +++ b/pr/720/docs/search.index/11f92487829f.js @@ -0,0 +1 @@ +rn_("AQMBoEAAABQ7ZfJpFAAAAQABAAD0DxMAAAEAAQABAPMEAWT0shIAAAEAAQABAKcAAAKFsKAUVwABsEATDQABsHAUAAABFYgAASkUAAABAAGwgBQ9AAFw8jkUAAABAAEAAaAQAAARYWUBIBEAAFMAA6BAAAAStmRlc/P4DwAAUQMBAPOAAmVp") \ No newline at end of file diff --git a/pr/720/docs/search.index/121d0e5bbae7.js b/pr/720/docs/search.index/121d0e5bbae7.js deleted file mode 100644 index 72a50666c..000000000 --- a/pr/720/docs/search.index/121d0e5bbae7.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsRAUmwABsBAMUwABZW8BBQA7MAAAAQAADQABAJwRDQABAgDzBxAAAAEAAQABAgD0AxAAAAEAAQABAAEDADswAAABAAAIAAEAuRAIAIcHAACHsKATxgABsNAUXAABoFAAABQnjBQROzAAAAEAAAYAAwBWBwAA6hADALoSAQDzgAJsdBOAA6AgAAAMzrCgFEAAAWFkbg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1227057cb7dc.js b/pr/720/docs/search.index/1227057cb7dc.js deleted file mode 100644 index 57a34a0a1..000000000 --- a/pr/720/docs/search.index/1227057cb7dc.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEAOzAAAAEAAAcAAQBTCQcAAQIA90wQAADbALkCAQABAHgAAQATgAKwMBDpAKRpdPMAAXPyjhQAAAEAM4ADsRAT/wABZG5w") \ No newline at end of file diff --git a/pr/720/docs/search.index/129a3202b537.js b/pr/720/docs/search.index/129a3202b537.js new file mode 100644 index 000000000..312229493 --- /dev/null +++ b/pr/720/docs/search.index/129a3202b537.js @@ -0,0 +1 @@ +rn_("AYACsHAS2wABoLAAABQaZW8jAQOwcBIBAAGAE4EAEPhtbnM7MAAAAQAAGgAGAGoHAQDxCAUACA0BAE8RCQCNEQAAYRMFAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1311b0a01323.js b/pr/720/docs/search.index/1311b0a01323.js new file mode 100644 index 000000000..25f0b7269 --- /dev/null +++ b/pr/720/docs/search.index/1311b0a01323.js @@ -0,0 +1 @@ +rn_("AQIBoQAAABSBZPJgBwAACgIBBgGgMAAAEfB0AbATAAABAwGwUBL5AAFl9RMJAABUAwEAEQQBAAEBAaEAAAAUdWTysgUAAD4CFwcAAIewoBL3AAGg4AAAFEiwEAWzAAEegArzYgQAAAEAAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/135b5f2dd6d8.js b/pr/720/docs/search.index/135b5f2dd6d8.js deleted file mode 100644 index b2d60dff6..000000000 --- a/pr/720/docs/search.index/135b5f2dd6d8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYA9BITAAABAJkBAQATAgKwYBMUAAFmbfLiDAAAAQAjggKwQBNDAAFlbAEFAPQFFAAAAQBOAAEA8wMBY/IHEwAAAQABgQKgAAAACSygMAAAD9NzdBOAAqAQAAAHTm5404CEsHAUvAABkEAB") \ No newline at end of file diff --git a/pr/720/docs/search.index/13e8cca7fdb1.js b/pr/720/docs/search.index/13e8cca7fdb1.js new file mode 100644 index 000000000..7702bcb2c --- /dev/null +++ b/pr/720/docs/search.index/13e8cca7fdb1.js @@ -0,0 +1 @@ +rn_("AQAA9CoTAAABAFoBAQDzBAFzOzAAAAEAAA0AAgCnEwcAnhQFAEcAAAWGoIAAABOHsQAUrQABsEAS5AABsIAUvQABsFATLAABFQAW9JYOAAABAAEAAQBDAISgIAAACSug0AAAE5OgMAAACQsVAATzAwIAAAEAcAU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1405631e8d2d.js b/pr/720/docs/search.index/1405631e8d2d.js new file mode 100644 index 000000000..a6c279ef4 --- /dev/null +++ b/pr/720/docs/search.index/1405631e8d2d.js @@ -0,0 +1 @@ +rn_("AQQA9goNAAABAD8DAQAvAQEAAQoA89USAAABAK0AAQEA9x8JAAABAF0HAQBzAAEAFgEjgAKwYBPwAAFpbwECAPTIDAAAAQBOBgEAAQUA9AYUAAABAE4AAQD3CAAAiLCQE70AAaAgAAAMyrCQEfsAAQTcAzowAAABAAAAAAAIABAAAACVBRAJEQljDGQMARECEQgTCRM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/143fb6edbe65.js b/pr/720/docs/search.index/143fb6edbe65.js new file mode 100644 index 000000000..9ece54c8b --- /dev/null +++ b/pr/720/docs/search.index/143fb6edbe65.js @@ -0,0 +1 @@ +rn_("AQACoDAAABEcoJAAABOUMGj1AxIAAJkBAQABAAEAE4ACoDAAAA/MZHIjAISwEAj3A0CwIAwDAQygMAAAD/QSABj1nAUAAC0AAQABAAEAAQIA9LYUAAABAAoAAQABAgDzbxAAAAEAAQDzgAJpcgEBArBAEWIAAaBQAAATeWVz85UOAADjAgEAAQsA9qMTAAABAKoAWQAYAAEA84ACbHTTgISgkAAAE1EBRAQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1440b866445a.js b/pr/720/docs/search.index/1440b866445a.js deleted file mode 100644 index f72ecf30a..000000000 --- a/pr/720/docs/search.index/1440b866445a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9iARAAABAJQDAQAKAAEAAQAAOzAAAAEAAAYAAgCOEwAA9hMFACOIArBAFGwAAWVzAQ0BsEAUZgABZfUqFAAAAQABAAEAAQABBQA7MAAAAQAACAADAPwRAgACEwQAKRQAANcBAACFBbqAxTPrFIQC88sMAAABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/1453bc07b5d6.js b/pr/720/docs/search.index/1453bc07b5d6.js new file mode 100644 index 000000000..5dcd3eb88 --- /dev/null +++ b/pr/720/docs/search.index/1453bc07b5d6.js @@ -0,0 +1 @@ +rn_("AQABsKAS0wABZTswAAABAAAJAAIA4wcHABUTAQABAAGgIAAADOttAYQFAAABgAKwoBLRAAGwQA/WAAFsbwEAAPQPEwAAAQABAAEA8wQBZPSyEgAAAQABAAEAIwKEsKAUVwABsEATDQABsHAUAAABFYAAASkUAAABAAGwgBQ9AAFw8jkUAAABAAEAAaAQAAARYWUBIBEAAFMAA6BAAAAStmRlc/P4DwAAUQMBAPOBAmVp1wIAAIawIBKXAAGw0BRBAAEXAQL0owQAAAEAAQDHAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1461c0534145.js b/pr/720/docs/search.index/1461c0534145.js deleted file mode 100644 index af435e1e5..000000000 --- a/pr/720/docs/search.index/1461c0534145.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIAOzAAAAEAABYACQBZEAUAaxEBAPwRAgDQEgEAAhMEAAEUAQApFAAAWBQAAHcUAAATgAKw8BS8AAFmZyOAArBQE7wAAW1uAQUA8wEUAAABAHUA8wQBYwGLEQAAAQEBsHAUXAABcDswAAABAAAJAAIA1QcHANIQAQABAgA7MAAAAQAACwACANQTBQCSFAUA8wEBbTswAAABAAANAAQA0AwAAG0RAADpEgUAThQFABMAAqAwAAAM1GVz8gASAAABAAGCArBwFDgAAaBAAAARGGlz9wEAgIawkBQaAAGQSQg=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1520bb97adae.js b/pr/720/docs/search.index/1520bb97adae.js new file mode 100644 index 000000000..55f6a35ca --- /dev/null +++ b/pr/720/docs/search.index/1520bb97adae.js @@ -0,0 +1 @@ +rn_("AYQCsCARhQEioJAAABQqbXABgAKgMAAAERCgUAAAE89jchcBAACGsCATmgABoGAAABM4sMAUXQABoGAAABHhEEAPOzAAAAEAABIABgDNBAgA3xEBAPsSAQDsEwEAQRQBAL0UAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/153142114305.js b/pr/720/docs/search.index/153142114305.js new file mode 100644 index 000000000..9fd0b24c6 --- /dev/null +++ b/pr/720/docs/search.index/153142114305.js @@ -0,0 +1 @@ +rn_("AQACoCAAABOTsDAR6wABaXTy9xIAAAEAAQMAOzAAAAEAAAYAAQBlEQYAAQgA9P0TAAABAIsABQATAQOwkBRkAAGwUBNCAWZnbHA7MAAAAQAAEgAJAGkQAgDuEQEALxMBAFITAQCJEwEA7hMBACYUAQA1FAEAdhQBAAGAArAwEecAAbAwEekAAXJ2AQQBsAAStwABZDswAAABAAAFAAIA4xEDAOYSAQC3BQABh7BQErkBF7BgE0AAAZQJAzowAAABAAAAAAALABAAAADfDOAM4QybDpwODBGPEZARkRGSETYTcRMjgAKgEAAADN5ubwEDAPNmEAAAAQABACOAAqAAAAAMDmRyYwCEoFAAABGMoDAAABCkFAEQ8pgHAAABAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/15497ca32227.js b/pr/720/docs/search.index/15497ca32227.js new file mode 100644 index 000000000..65cee2294 --- /dev/null +++ b/pr/720/docs/search.index/15497ca32227.js @@ -0,0 +1 @@ +rn_("AYICsCARRwABsDARxQABZXABBQD05g8AAAEA8AABAFOAA7CQEfUAAWFpcgGBArCgFBsAAbCgFB0AAWNyxwAAAIWwUAz2AAGgIAAACW+gIAAADB88AAE6MAAAAQAAAAAACgAQAAAAtQG2AXsE+gYfCSAJfRB+EPEQ8hAIEg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1573b4768191.js b/pr/720/docs/search.index/1573b4768191.js deleted file mode 100644 index 02d471795..000000000 --- a/pr/720/docs/search.index/1573b4768191.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMAOzAAAAEAAI0AAgBzBwAAdQmMAAGEArBwFDgAAaBAAAARGGlzAQcA8/EQAAABABUBI4ACoLAAABLWYXQBAAOwMAkhAAGwMBOZAAGgIAAAB3RhZG8BFwIAADcDAICGoMAAABQwsAAUAwABAJgV") \ No newline at end of file diff --git a/pr/720/docs/search.index/15b4edd8a8f5.js b/pr/720/docs/search.index/15b4edd8a8f5.js new file mode 100644 index 000000000..c316902ba --- /dev/null +++ b/pr/720/docs/search.index/15b4edd8a8f5.js @@ -0,0 +1 @@ +rn_("AQAA9HsTAAABAAEAAQATAgKwgBNPAAFzdvRtCQAAAQCSCgEA8wABYwFlDAAAAQICoLAAABRZoLAAABRaY3Pz0BAAAAEAXwABgQKwUBHzAAGgwAAAFChoafOCAmVp84ACZW8=") \ No newline at end of file diff --git a/pr/720/docs/search.index/15f7949486b1.js b/pr/720/docs/search.index/15f7949486b1.js new file mode 100644 index 000000000..aca00d4c1 --- /dev/null +++ b/pr/720/docs/search.index/15f7949486b1.js @@ -0,0 +1 @@ +rn_("AQIAOzAAAAEAABYACQBZEAUAbBEBAP0RAgDREgEAAxMEAAIUAQAqFAAAWRQAAHgUAAATgAKw8BS9AAFmZyOAArBQE70AAW1uAQUA8wIUAAABAHUA8wQBYwGMEQAAAQEBsHAUXQABcDswAAABAAAJAAIA1QcHANIQAQABAgA7MAAAAQAACwACANUTBQCTFAUA8wEBbTswAAABAAANAAQA0AwAAG4RAADqEgUATxQFABMAAqAwAAAM1GVz8gESAAABAAGCArBwFDkAAaBAAAARGGlz9wEAgIawkBQbAAGQSQg=") \ No newline at end of file diff --git a/pr/720/docs/search.index/16096c00710e.js b/pr/720/docs/search.index/16096c00710e.js deleted file mode 100644 index 0034e5343..000000000 --- a/pr/720/docs/search.index/16096c00710e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9HUQAAABALMAAQABhAKwABF+AAGwABGAAAE0NvMCAWHydQwAAAEAAQEA9sUSAAABAHMAAQBRAQEA84ACZW/zgAJoaw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1631657485c6.js b/pr/720/docs/search.index/1631657485c6.js new file mode 100644 index 000000000..73662a6e6 --- /dev/null +++ b/pr/720/docs/search.index/1631657485c6.js @@ -0,0 +1 @@ +rn_("AQYA9L8TAAABAAEAAQABDwD0qRQAAAEAAQABAAEAAbDwFLMAAWs7MAAAAQAACAADABoUAAAfFAYASRQAAAECAPR1EAAAAQC0AAEA9wAAAIWxABScAAGJMADy2xIAAAEAE4ACsBAMUwABZW8BBQA7MAAAAQAADQABAJ0RDQABAgDzBxAAAAEAAQABAgD0AxAAAAEAAQABAAEDADswAAABAAAIAAEAuRAIAAGAAqAAAAAMJrAwFGcAAXFyAYACoEAAABEQsMAUXQABZXMBAQA7MAAAAQAAEwABACUQEwAjgAKwkBPHAAFpbXc2AACKoFAAABQosHAUCAABoCAAAAzwnFUROzAAAAEAAAsABABWBwAA6hADALsSAQArFAQAAQIBsDAReAABcAGiEgAAs4CEoCAAABHiAigE") \ No newline at end of file diff --git a/pr/720/docs/search.index/163ee1b5b3a8.js b/pr/720/docs/search.index/163ee1b5b3a8.js new file mode 100644 index 000000000..35963fbed --- /dev/null +++ b/pr/720/docs/search.index/163ee1b5b3a8.js @@ -0,0 +1 @@ +rn_("AQIBoKAAABNwZPLyBgAAAQABgQKgMAAAFHSgUAAAE/9jcwEEA7AgEU0AAaBQAAAR+aBAAAAUPGxzdvI3FAAAAQDzAANhZW87MAAAAQAACAADAIsEAQAEDAAAEA0FAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1654af6eb785.js b/pr/720/docs/search.index/1654af6eb785.js new file mode 100644 index 000000000..11322b416 --- /dev/null +++ b/pr/720/docs/search.index/1654af6eb785.js @@ -0,0 +1 @@ +rn_("AQIAOzAAAAEAAAUAAgB/DAMAGxMBAAECAPN8EQAAAQABAAEGAPSpFAAAAQABAAEA8wYBbfStEgAAAQABAAEA84ACbnbzgAJhaQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/169f211e0328.js b/pr/720/docs/search.index/169f211e0328.js deleted file mode 100644 index 7a9623896..000000000 --- a/pr/720/docs/search.index/169f211e0328.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsHAUmQABoAAAAASmZmcBAQA7MAAAAQAABwABAEIMBwABAQGgcAAAEqBhARIHAAAjgAKhAAAAFKNkbnOAhKBgAAASnwBBSA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/16a23e4d7f90.js b/pr/720/docs/search.index/16a23e4d7f90.js deleted file mode 100644 index db5a58d22..000000000 --- a/pr/720/docs/search.index/16a23e4d7f90.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIBoKAAABNvZPLyBgAAAQABgQKgMAAAFHOgUAAAE/5jcwEEA7AgEUwAAaBQAAAR+KBAAAAUO2xzdvI2FAAAAQDzAANhZW87MAAAAQAACAADAIsEAQAEDAAAEA0FAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/16a2da4da53d.js b/pr/720/docs/search.index/16a2da4da53d.js new file mode 100644 index 000000000..8ac00650b --- /dev/null +++ b/pr/720/docs/search.index/16a2da4da53d.js @@ -0,0 +1 @@ +rn_("AQsBoEAAABQ7ZfJpFAAAAQABBQD0BBIAAAEAAQABAAGDArAAEO8AAbBQE38AAWR3E4ACoKAAABPzZXYBAgD0ChEAAAEAkwEBAAEAAPTyDwAAAQD1AAgBI4ICsFATVgABZXMBAgD0JhMAAAEAkgABAAEDAPRcEwAAAQCYAAEA84UCYnUBAgD0dhEAAAEAfAEBAPOAAmls8wADYnR1OjAAAAEAAAAAAA8AEAAAAHIH+wf8B/0H/gcbEOEQsBMyFH8UgBSEFJEUkhS4FLwUAQwA8xUUAAABAAEAAYACsAAJGQABoCAAAA0DZG4BBgD0JBMAAAEAkgABAPMDAWL0CBEAAAEAkwEBAJcGAACHsEAP8AABoHAAABKosJATVAABOAkDOjAAAAEAAAAAACQAEAAAAMEFwgXDBcQFNAc1BzMM+Az5DPoM/gz/DAAN6A/pDzwQPRBBEEIQXxBgEGEQYhBjEGQQZRCoEK0Q2RDaEJATtBPbE3UUgRSkFLUUAQMA9DoTAAABAFEBAQDzgAJjbXcBAIDFsYAUxQABQIEECA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/16a948641b54.js b/pr/720/docs/search.index/16a948641b54.js new file mode 100644 index 000000000..b6cbcdfdb --- /dev/null +++ b/pr/720/docs/search.index/16a948641b54.js @@ -0,0 +1 @@ +rn_("AQACoCAAABHeoDAAABKpYmgByg8AAAETAbAAFIUAAXM7MAAAAQAABQABAJ4UBQABBwDzqhIAAAEAAQDzgANkcnQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/16e70f825de2.js b/pr/720/docs/search.index/16e70f825de2.js new file mode 100644 index 000000000..1c485aa9b --- /dev/null +++ b/pr/720/docs/search.index/16e70f825de2.js @@ -0,0 +1 @@ +rn_("AQEA9DsHAAABAAEAAQABAQGgQAAAEYpz9TUMAAArBUoBAQABABOCAqAgAAANDGVyI4ADoEAAAAw0sDAJJgABZW90AQAA9DcHAAABAAEAAQABAgD0pRMAAAEADwABABOAArBAFF0AAWJ284ACb3gBCgD14RMAAAEAAQB4AAEAAYECoCAAABD6sFASvQABYW8BBAGgAAAAE+ZzAfkQAABjAwOwUBFsAAFjZXP2AgkAAAEAAQAsAAEAcgkBAQA7MAAAAQAABQABANcMBQAjgAKwMBNCAWZydPMAhgHAB/LxAQAA/AU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/16ed99e26abc.js b/pr/720/docs/search.index/16ed99e26abc.js deleted file mode 100644 index 0951c2e62..000000000 --- a/pr/720/docs/search.index/16ed99e26abc.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsCATRQBaoFAAABEybXNDgAOw4BQHAAEwEgALOzNkZ3IBAwDz1xIAAAEAAQAjgAKwMBQMAAFjaTOAA7AADQMDaWFpbw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1703dcd812f8.js b/pr/720/docs/search.index/1703dcd812f8.js new file mode 100644 index 000000000..a09392693 --- /dev/null +++ b/pr/720/docs/search.index/1703dcd812f8.js @@ -0,0 +1 @@ +rn_("AQYA9BMTAAABAJkBAQATAgKwYBMVAAFmbfLiDAAAAQAjggKwQBNEAAFlbAEFAPQGFAAAAQBOAAEA8wMBY/IIEwAAAQABgQKgAAAACSygMAAAD9NzdBOAAqAQAAAHTm5404CEsHAUvQABkEAB") \ No newline at end of file diff --git a/pr/720/docs/search.index/1727786f31fa.js b/pr/720/docs/search.index/1727786f31fa.js deleted file mode 100644 index 8ede5a34d..000000000 --- a/pr/720/docs/search.index/1727786f31fa.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA9fQHAAABAAEAAQABAAEAAqAwAAARHKCQAAATkzBo9QISAACZAQEAAQABABOAAqAwAAAPzGRyIwKEsBAI9wNAsCAMAwEMoDAAAA/0EgAY9ZwFAAAtAAEAAQABADOAhLCgEtAAAbBAD9YAARBJAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/175137e32580.js b/pr/720/docs/search.index/175137e32580.js new file mode 100644 index 000000000..681454eef --- /dev/null +++ b/pr/720/docs/search.index/175137e32580.js @@ -0,0 +1 @@ +rn_("AQQA9goNAAABAD8DAQAvAQEAAQoA89USAAABAK0AAQEA9x8JAAABAF0HAQBzAAEAFgEjgAKwYBPwAAFpbwECAPTIDAAAAQBOBgEAAQUA9AYUAAABAE4AAQD3BAAAh6AgAAAMyrCQEfsAAQScAzowAAABAAAAAAAIABAAAACVBRAJEQljDGQMARECEQgTCRM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/178c38e077ae.js b/pr/720/docs/search.index/178c38e077ae.js deleted file mode 100644 index e84586a50..000000000 --- a/pr/720/docs/search.index/178c38e077ae.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9CkTAAABAFoBAQDzBAFzOzAAAAEAAA0AAgCmEwcAnRQFAEcAAASGoIAAABOGsQAUrAABsEAS4wABsIAUvAABsFATKwABFQAW9JYOAAABAAEAAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/178ca3667736.js b/pr/720/docs/search.index/178ca3667736.js deleted file mode 100644 index f52e61afa..000000000 --- a/pr/720/docs/search.index/178ca3667736.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABsGAUDgABZQFHFAAAAQYA9DkTAAABAFEBAQABBAD0UxMAAAEADwEBAPMAA2VyczowAAABAAAAAAAJABAAAAAjCSQJJQlFEYQRmBKZEqYSBxQIFA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/17a621e31f68.js b/pr/720/docs/search.index/17a621e31f68.js new file mode 100644 index 000000000..6696fc53a --- /dev/null +++ b/pr/720/docs/search.index/17a621e31f68.js @@ -0,0 +1 @@ +rn_("AQMAOzAAAAEAAAkABABcCQEAnxADAOIQAQDwEwEAAQIBsEAUfQABdDswAAABAAANAAYA/xIDAGwTAQDcEwEA8xMBAHIUAQCaFAEAE4ACsDATMwFJaXABiAKwABPnAAGwABPpAAE0NhOBAqAwAAARhmRzAYACoCAAAAx3sGAUGAABbngBBQDzsRMAAAEAAQATgAKgMAAAFAxlefMAhBIAA/JAEAAA5wDzgAJydA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/17aebfe0bb9d.js b/pr/720/docs/search.index/17aebfe0bb9d.js new file mode 100644 index 000000000..764800260 --- /dev/null +++ b/pr/720/docs/search.index/17aebfe0bb9d.js @@ -0,0 +1 @@ +rn_("AQAAOzAAAAEAAAYAAgC3EQMAwRICAAEKAbBAFGcAAWX1KxQAAAEAAQABAAEA8wACaXP0JAwAAAEAUwABACOBAqDgAAAUTmV5") \ No newline at end of file diff --git a/pr/720/docs/search.index/17df49c14c76.js b/pr/720/docs/search.index/17df49c14c76.js new file mode 100644 index 000000000..3472a0121 --- /dev/null +++ b/pr/720/docs/search.index/17df49c14c76.js @@ -0,0 +1 @@ +rn_("AYACsFAUGAABoAAAAAkKY3QBAQD0lRMAAAEAAQABAAEDAPTvDAAA4AaeAAEAAYACoBAAAAx3oFAAABKjY2QBAgDz/ggAAFADAQDzAAFt86cEAADGAAEAAYECoBAAABNIoHAAABOQYWPzAAFy81oHAABRCiAA5wcAgIewMA/QANMpICM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/182999809797.js b/pr/720/docs/search.index/182999809797.js deleted file mode 100644 index d7cde7931..000000000 --- a/pr/720/docs/search.index/182999809797.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBoAAAABNNc/TODwAA+AMBAAQAAQECsGAUPgABsEAUfAABZHQ7MAAAAQAADQAGAP4SAwBrEwEA2xMBAPITAQBxFAEAmRQBAAEBA7BwEgAAAbCAEtoAAYATgAAQ+G1uczswAAABAAALAAIA8QgFAGATBQCjgISwsBPJAAGxcBS8AAEIQIIBgAKwMBSwAAGxABQ+AAFjbgEBADswAAABAAAGAAEAwhQGAPMGAWX0bxQAAAEANAABABMBA7BAFJsAAbBgE4cAiWFydfN7EAAAeQIBAHcBAACFsDATMgFJEYEIOzAAAAEAAAYAAgCOEwAA9hMFAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1834499c14e5.js b/pr/720/docs/search.index/1834499c14e5.js deleted file mode 100644 index 71da409f6..000000000 --- a/pr/720/docs/search.index/1834499c14e5.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEAOjAAAAEAAAAAAAgAEAAAAAkJdxAiESMRJBH8E/0TiBSNFAECAPSyEAAAAQABAAEAE4ACoNAAABRzY3NTgAOgcAAAFG5laW+DgISwIBOgAAGgIAAAD+uwAAdSAAEKCAQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1858dd5f6144.js b/pr/720/docs/search.index/1858dd5f6144.js new file mode 100644 index 000000000..3150ef061 --- /dev/null +++ b/pr/720/docs/search.index/1858dd5f6144.js @@ -0,0 +1 @@ +rn_("AQIBsEAUfQABdDswAAABAAANAAYA/xIDAGwTAQDcEwEA8xMBAHIUAQCaFAEAE4ACsDATMwFJaXABBQDzsRMAAAEAAQATgAKgMAAAFAxleVMCA7BwFBgAAWJlcwFAEAAAEwACoCAAAAWkZm31ggAAAOMGAQDVAQEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/18aeef727410.js b/pr/720/docs/search.index/18aeef727410.js deleted file mode 100644 index e58733d80..000000000 --- a/pr/720/docs/search.index/18aeef727410.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMA9gENAADrAloAAQDRAgEAAQQAOzAAAAEAAAoABACPEAUA0hIBADMTAQBZFAAAAYYCoAAAABNXoAAAABNYZHLzAgF2AYMTAADzgAJlbycCAADIoDAAAA/roHAAABKisRAUgQABoIAAABQosNATyQABoLAAABQoQGUICTswAAABAAAJAAMAvgUCAB8HBABaDAEAI4ACY0TMVIdIZHIBAAA6MAAAAQAAAAAACgAQAAAAUQlSCSIQcRNyE6IToxNNFKYUvhS/FBOAAqAwAAAQpWx084ACYWU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/19b75bdc92f3.js b/pr/720/docs/search.index/19b75bdc92f3.js deleted file mode 100644 index 9320e9851..000000000 --- a/pr/720/docs/search.index/19b75bdc92f3.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQsA9KQTAAABAA8AAQABBAGwQBNZAAFlAaMSAADzAAF0AWEUAAABDQDzeBQAADYAAQABEADzphQAABgAAQDzgQNrbXMBAAA7MAAAAQAABgACAI4TAAD2EwUAI4YCsEAUbAABZXMBBAD0xBAAAAEAAQABAPOAA2NydDOAA7BgEOQAAWFscg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/19c9dbfd629e.js b/pr/720/docs/search.index/19c9dbfd629e.js deleted file mode 100644 index c9a2be50e..000000000 --- a/pr/720/docs/search.index/19c9dbfd629e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQDKoRAAABR6gAj/ABrdoEAAABEVsGAUagABoBAAAAyDsFAUAwABsDARdwABoAAAAAxBsSAUjgABsEAREwIjQE6wCTowAAABAAAAAAAUABAAAAAVCRYJKQkqCQgMCQwKDAsMEQwWDN0MoRLNEs4SzxKKE4sToBOhExIUExQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1a313ca338b0.js b/pr/720/docs/search.index/1a313ca338b0.js new file mode 100644 index 000000000..27530ba0b --- /dev/null +++ b/pr/720/docs/search.index/1a313ca338b0.js @@ -0,0 +1 @@ +rn_("AYMCsCARhQEioJAAABQqbXABggKwoBQbAAGwoBQdAAFjcgECAaBAAAARhGUBOxAAADOAhLAgEQEAAbAgD7YAAVAUAPOAAm9y") \ No newline at end of file diff --git a/pr/720/docs/search.index/1a45b3f127a1.js b/pr/720/docs/search.index/1a45b3f127a1.js deleted file mode 100644 index b5814e508..000000000 --- a/pr/720/docs/search.index/1a45b3f127a1.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYAOzAAAAEAAAUAAQBgEwUAg4YEsFATJwABsHATkAABoNAAABRuYm5vdhOAArAQEvgAAXByAQABoDAAABHvdAGvEwAA8wIBc/KoEAAACwMTgAKgYAAAEJlldQECAPYKDQAAAQA/AwEALgEBAAGAArAAEuMAAYAOmjUAAWVzAQEA81cHAAAtDAEAY4ADsIAUAwABYm5084ADYW9yARQAOzAAAAEAAAUAAQCdFAUAAQAAOzAAAAEAAAYAAgCOEwAA9hMFACOIArBAFGwAAWVzAQQBsDATXgABY/OGEQAAAQABAAEFADswAAABAAAIAAMA/BECAAITBAApFAAA8wIDY2Vw88sMAAABAAEA84ACb3UBAAGwYBQOAAFlAUcUAADzAgFz9iMJAAABAAEAIAg/ACIBAQgA88ASAAABAAEAQ4ADoBAAABOSoOAAABQZZG9zAQIBoFAAABGFcgEmEQAAAYACoEAAABCloHAAABRZYWUBAAA7MAAAAQAACwACAPQGBQDcEgUA84ACdHYjAAKwEAfuAAFucvYYCQAAWAATBwEAtwABAPMAhzCRDDowAAABAAAAAAAIABAAAADJBMoEAxEEEfYS9xKAE4ETeRQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1a4760f711b7.js b/pr/720/docs/search.index/1a4760f711b7.js deleted file mode 100644 index 18520b819..000000000 --- a/pr/720/docs/search.index/1a4760f711b7.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsRAUmwABsBAMUwABZW8BBQA7MAAAAQAADQABAJwRDQABAgDzBxAAAAEAAQABAgD0AxAAAAEAAQABAAEDADswAAABAAAIAAEAuRAIAIcHAACHsKATxgABsNAUXAABoFAAABQnjBQROzAAAAEAAAYAAwBWBwAA6hADALoSAQDzgQJsdPMAAWk7MAAAAQAAjgADAJwEAAD3EAAACBKMAAEFAPN+FAAAAQA8AAEAAaBAAAAQ+2XzBQkAAAEAoQkTgAKgMAAAD95kcvMAAWXz7AYAAAEAAQDzgAJodAEBADswAAABAACNAAIA9xAAAAgSjAAjgAOwABAYAx+gUAAAECJnaXQBCAD0/BMAAAEAiwAFABMAhLDwFIAANLCQFGMAAbBQE0EBZkCJADswAAABAAASAAkAaRACAO0RAQAuEwEAURMBAIgTAQDtEwEAJRQBADQUAQB1FAEA1wEAAIawgBG0AAGgQAAACSgIMCY6MAAAAQAAAAAADQAQAAAAkQCSAGAHagkDDA8NChELEZ0SnhIlEyYTuBO5Ew==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1a65a2901852.js b/pr/720/docs/search.index/1a65a2901852.js deleted file mode 100644 index 62d20d0e6..000000000 --- a/pr/720/docs/search.index/1a65a2901852.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIBoDAAABB3YQFWDAAAAYECoCAAABD6sFASvAABYW8BAwGgAAAAE+VzAfkQAAAjgAKgAAAAB/JydmMAA7BQEWsAAWNlczswAAABAAAIAAQAAgkCADAJAQBvEAIAohIAAAGAArDQFLAAAaCQAAATrmJoJwEAgIWwUBErAAGw8BPGAAGwIA+rAAFEIQTzgAJudA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1a661bac4231.js b/pr/720/docs/search.index/1a661bac4231.js new file mode 100644 index 000000000..12ade19ef --- /dev/null +++ b/pr/720/docs/search.index/1a661bac4231.js @@ -0,0 +1 @@ +rn_("AYICoFAAABLjoQAAABSZY3QjAAKwQA/RAAFldTswAAABAAA3ABYAxAYBANUMAQD2DAEA1g8BAFkQBQCPEAUADREBAGwRAQD9EQIA0RIDAAMTBAA0EwEAPBMBAEsTAQDREwEA5BMBAAIUAQAGFAEAKhQAAFUUAQBZFAEAeBQAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1b5ac0a0d3eb.js b/pr/720/docs/search.index/1b5ac0a0d3eb.js deleted file mode 100644 index 6651ab407..000000000 --- a/pr/720/docs/search.index/1b5ac0a0d3eb.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABsKAS0gABZTswAAABAAAJAAIA4wcHABQTAQABAAGgIAAADOttAYQFAAABgAKwoBLQAAGwQA/WAAFsbwEAAPQOEwAAAQABAAEA8wQBZPSxEgAAAQABAAEAIwKEsKAUVgABsEATDAABsHAT/wABFYAAASgUAAABAAGwgBQ8AAFw8jgUAAABAEMAA6AgAAARYKBAAAAStWRlc/P4DwAAUAMBAPOBAmVp1wIAAIawIBKWAAGw0BRAAAEXAQL0owQAAAEAAQDHAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1b8e9adbdcdb.js b/pr/720/docs/search.index/1b8e9adbdcdb.js new file mode 100644 index 000000000..8e07bdd6d --- /dev/null +++ b/pr/720/docs/search.index/1b8e9adbdcdb.js @@ -0,0 +1 @@ +rn_("AQQA9K4QAAABAAEAAQABAAA6MAAAAQAAAAAACgAQAAAA5g/nD9cQ2BBkEfUR9hETExQTrRSuFPMBAXnyDRQAAAEAAQADoKAAABRaoCAAABOTsDAR6wABZWl08vcSAAABAAEDADswAAABAAAGAAEAZREGAAEIAPT9EwAAAQCLAAUAEwEDsJAUZAABsFATQgFmZ2xwOzAAAAEAABIACQBpEAIA7hEBAC8TAQBSEwEAiRMBAO4TAQAmFAEANRQBAHYUAQABgAKwMBHnAAGwMBHpAAFydgECAbAAErcAAWQ7MAAAAQAABQACAOMRAwDmEgEAI4ECoJAAABRZaW8BBwD0dRQAAAwAIwARAHcWAAGJsFAUDQABsFASuQEXsGATQAABtQkDOjAAAAEAAAAAAA4AEAAAAN8M4AzhDJsOnA7QENEQDBEwEY8RkBGREZIRNhNxE0OAA6AgAAAM0aAQAAAM3m1ubwEDAPRmEAAAAQABABsBAYACoLAAABQosDATdAABbnRDAAOgIAAAERuwUBHzAAFlaGk7MAAAAQAABgADAA4MAAAEEgMA0xMBAPOAAmRyhwsAAAqAAfgAEAGAAfsAEAGgUAAAEYygUAAAFF+gMAAAEJmgMAAAEKQwMWNlaW9zdHV39ZgHAAABAC0I2wJeAQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1bb2d6c36549.js b/pr/720/docs/search.index/1bb2d6c36549.js new file mode 100644 index 000000000..a4b3ed5aa --- /dev/null +++ b/pr/720/docs/search.index/1bb2d6c36549.js @@ -0,0 +1 @@ +rn_("AYACsHAUmgABoAAAAASmZmcBAQA7MAAAAQAABwABAEIMBwABAQGgcAAAEqFhARIHAAAjgAKhAAAAFKRkbnOAhKBgAAASoABBSA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1bb2d6d431c6.js b/pr/720/docs/search.index/1bb2d6d431c6.js deleted file mode 100644 index 7863e0a31..000000000 --- a/pr/720/docs/search.index/1bb2d6d431c6.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9AoRAAABAJIBAQAjgQKgYAAAE0JiaQEAAPTyDwAAAQD1AAcBI4ICsFATVQABZXMBiQKwIBRxAAGgMAAAFHtpcAECAPQlEwAAAQCSAAEAAQMA9FsTAAABAJgAAQDzhQJidQECAPR1EQAAAQB8AQEA84ACaWy3AQAAhaAgAAATLRIBDDowAAABAAAAAAAUABAAAAByB/sH/Af9B/4HEAxKDEsMTAxNDBsQ4RCvEzEUfhR/FIMUkBSRFLcUuxQBBQDzFBQAAAEAAQBDhgOwkBSZAAGgAAAAErliZHcBgAKwAAkZAAGwIA0DA2lkbgEDAPPwDwAAAQAHAQECAPYaDAAAAQCOAwEA5gMBAAEAAPQ3CQAAAQABAAEAAQAAOzAAAAEAAAYAAgCOEwAA9hMFACOBArBAFGwAAWVz84ADZXh5AQAA9DMJAAABAAEAAQAjgAKwIBMhAAFyeAcNAADIoJAAABNwsFAQHAABsMATugABoBAAABFxsEAM5gABAEeACzowAAABAAAAAAAJABAAAABwBXEF7AztDAEN7A9GEEcQGBMZEwEGAPQjEwAAAQCSAAEA8wMBYvQIEQAAAQCSAQEAtwwAAImgcAAAEqewkBNTAAGwYBA+AAGgMAAAE3k4iRM6MAAAAQAAAAAALwAQAAAAwQXCBcMFxAU0BzUH+wj8CP0ILQkuCR8MMwz4DPkM+gz+DP8MAA3oD+kPPBA9EEEQQhBfEGAQYRBiEGMQZBBlEIcQjhCoEK0Q2RDaEEgRSRH9Eo8TsxPaE3QUgBSjFLQU") \ No newline at end of file diff --git a/pr/720/docs/search.index/1bcbe3047453.js b/pr/720/docs/search.index/1bcbe3047453.js deleted file mode 100644 index bc62dab49..000000000 --- a/pr/720/docs/search.index/1bcbe3047453.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQADsCARTAABoFAAABH4oEAAABQ7bHN28jYUAAABAAECAPTXEQAAAQABAAEAE4QCsCAR2wABYXPzgAJhZROAAlLd8URqtnJzAQEAOzAAAAEAAAYAAQDCFAYA8wYBZfRvFAAAAQA0AAEAEwcDsEAUmwABsGAThwCJYXJ183sQAAB5AgEAI4ACoBAAAAwXZXIBAAA7MAAAAQAAIgAOAMQEAQCIBQoAJgkBAC0MAQDmDAEAmg4AALgPBADPDwAA8g8BAOgQAQD6EAAAjREAAOoRAQDvEQAAAQEAOjAAAAEAAAAAAAwAEAAAAAkJUwxUDHcQjBCNECIRIxEkEfwT/ROIFI0UAYECsAARfgABsAARgAABNDYBBQD0BRQAAAEATgABAPMEAWPyBxMAAAEAAQMBoEAAABQ6ZfJoFAAAAQABBQDz1xIAAAEAAQABBADzDBMAAAEAYQEBAAD0DhMAAAEAAQABAPMEAWT0sRIAAAEAAQABAOcSAAGJsKAUVgABoDAAABEosGAUjgABsHAT/wABtcgEOjAAAAEAAAAAAAwAEAAAAAEJLwleDF8M/g//DwAQ4BFOE08TKBSBFIIUEYECErAgEdsAAWFzAQIA880SAAABAAEA9wAAgMWgEAAAEKWAADgIAQUA9MsSAAABAKkAAQABCAD0ihMAAAEAhwABADMBA7BAE1kAAWFiZfX0DAAAAQBFA2kC1QABAAA7MAAAAQAABgACAC0MAQC4DwQA84ICc3UBBgD0hRAAAAEAtwABAPMAAmJ09XoFAAABAOYOWAABAAEPAPQlFAAAAQBPAAEAAQQA9IMQAAABALcAAQAjgAKxABSLAAFvcGOBA7CAE6AAAWNzdAELADswAAABAAAGAAEAHhQGAAEMAPSIEwAAAQCrAAEAI4ACoHAAABRIZ3fzgAJlbwENAPN4FAAANgABAAEQAPOmFAAAGAABAAEBAbBgEsUAAXL3tgUAAAEAOgIwBAEA9wMBAAEDAbAADPMDRnP0KQwAAAEAAQABAAEDAPQnDAAAAQA5BQEAAYACoEAAABPdsDAS+AABYXPzgANucnYBCQD08BEAAAEAPwEBAAEHAPQREQAAAQCwAAEA84ACaGkBAQKwIAzxAAGwAAxpAAFlc/JjBwAAAQABBQDzHhMAAAEAAQDzBQFy9OQPAAABAO8AAQDzgAJiY9eeAQCOoCAAAAdloFAAABGKoOAAABQRsEAUuQABsNAUAwABl/ULOzAAAAEAABwADgAGAgIAZQQBABMJAAAjDAAAZwwBAGsMAADXDAUAlQ4AAHkQAQDNEAEAdxEBAMQRAQBWFAEAahQBAAGAAqCwAAAUc6AwAAARJWxuEwACsIAUPAABZXD0hxMAAIkAKAABAAEDAbBAFGYAAWX1KhQAAAEAAQABAAEAAQYA9L4TAAABAAEAAQABDwD0qBQAAAEAAQABAAECADswAAABAAAFAAEAkhQFAPMNAW07MAAAAQAABQABAE4UBQABBAD1tRIAAA4AAQCRAAEAAQACoBAAABFgsPAUsgABZWs7MAAAAQAACgAEABkUAAAeFAYASBQAAF8UAQABAgD0shAAAAEAAQABAAECAPR1EAAAAQCzAAEA98sAAIygUAAAERSxABSbAAGgoAAAE1C9tAM7MAAAAQAAJgANAPsLAwD4DwAAIxABADMRBwCJEQAA2hIBAOMSAQDnEgEASBMBAGYTBABCFAQASRQDALgUAAABAgA7MAAAAQAACwACANQTBQCSFAUA8wEBbTswAAABAAANAAQA0AwAAG0RAADpEgUAThQFABMBAqAwAAAM1GVz8gASAAABAAGJArAgFHEAAaAwAAAUe2lwEwADoCAAABMtoIAAABNCZWl19RAMAAA6AAEAAQABAAGGArCQFJkAAaAAAAASuWJkAYACsDATIQABoDAAABD4cnbXAAADhaAwAAAQbKAwAAATeRABEzowAAABAAAAAAAJABAAAAD7CPwI/QgtCS4JhxCOEEgRSRH9EgEGADowAAABAAAAAAAHABAAAADYD9kPphCnECMTJBO2E7cTAQcA9JsTAAABAAEAAQB3AAAAhqBwAAATs6BAAAATRqBwAAARJkNABTswAAABAAAQAAcAHAIAAFsHAQBkCQEA/BABAAgRAQCTEQUAmxIBAHd3AICLsLAUhgABoGAAABEmtUEP") \ No newline at end of file diff --git a/pr/720/docs/search.index/1be2131faf3c.js b/pr/720/docs/search.index/1be2131faf3c.js deleted file mode 100644 index 508d4e7b6..000000000 --- a/pr/720/docs/search.index/1be2131faf3c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9LEPAAABAAEAAQDzAgFzATIRAAABAAKwgBSQAAGgYAAAFLdkc/L3CAAAQAOTgISwwBPMAAGgEAAAEd0AwUA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1be4871c7cfc.js b/pr/720/docs/search.index/1be4871c7cfc.js deleted file mode 100644 index 51cb13252..000000000 --- a/pr/720/docs/search.index/1be4871c7cfc.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQAOjAAAAEAAAAAAAcAEAAAANgP2Q+mEKcQIxMkE7YTtxMBBAD02g8AAAEAAQABAAEAiKEQAAAUeoAI/wAa3aBAAAARFbBgFGoAAaAQAAAMg7BQFAMAAbAwEXcAAbEgFI4AATnBAjowAAABAAAAAAARABAAAAAVCRYJKQkqCQgMCQwKDAsMEQwWDN0MoRKKE4sToBOhExIUExTzgANlaW8=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1c67c4cae9f3.js b/pr/720/docs/search.index/1c67c4cae9f3.js new file mode 100644 index 000000000..600ed76a3 --- /dev/null +++ b/pr/720/docs/search.index/1c67c4cae9f3.js @@ -0,0 +1 @@ +rn_("AQEAOzAAAAEAAAcAAQBTCQcAAQIA90wQAADcALkCAQABAHgAAQATgAKwMBDpAKVpdPMAAXPyjxQAAAEAM4ADsRAUAAABZG5w") \ No newline at end of file diff --git a/pr/720/docs/search.index/1ca61b2e06ca.js b/pr/720/docs/search.index/1ca61b2e06ca.js new file mode 100644 index 000000000..08ae99893 --- /dev/null +++ b/pr/720/docs/search.index/1ca61b2e06ca.js @@ -0,0 +1 @@ +rn_("AYACsHASmQABsCAUswABaW8BAAGw8BSzAAFrOzAAAAEAAAgAAwAaFAAAHxQGAEkUAADzBQFk8tsSAAABAAECAPPcEAAAAQABAPMAAWk6MAAAAQAAAAAABwAQAAAAthDwEt8T4BMPFBAUMBQxFCODArCwFI8AAWFzAYECoKAAABNIoEAAABB0b3bzgIQBUAE=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1cb57e2db032.js b/pr/720/docs/search.index/1cb57e2db032.js new file mode 100644 index 000000000..1445729e0 --- /dev/null +++ b/pr/720/docs/search.index/1cb57e2db032.js @@ -0,0 +1 @@ +rn_("AQYAOzAAAAEAAAUAAQBhEwUAg4YEsFATKAABsHATkQABoNAAABRvYm5vdhOAArAQEvkAAXByAQABoDAAABHwdAGwEwAA8wIBc/KoEAAADAMTgAKgYAAAEJlldQECAPYKDQAAAQA/AwEALwEBAAGAArAAEuQAAYAOmjUQAWVzAQEA81cHAAAuDAEAY4ADsIAUBAABYm5084ADYW9yARQAOzAAAAEAAAUAAQCeFAUAAQAAOzAAAAEAAAYAAgCPEwAA9xMFACOIArBAFG0AAWVzAQQBsDATXwABY/OHEQAAAQABAAEFADswAAABAAAIAAMA/RECAAMTBAAqFAAA8wIDY2Vw88sMAAABAAEA84ACb3UBAAGwYBQPAAFlAUgUAADzAgFz9iMJAAABAAEAIQg/ACIBAQgA88ESAAABAAEAQ4ADoBAAABOToOAAABQaZG9zAQIBoFAAABGGcgEnEQAAAYACoEAAABCloHAAABRaYWUBAAA7MAAAAQAACwACAPQGBQDdEgUA84ACdHYjAAKwEAfuAAFucvYYCQAAWAATBwEAuAABAPMAhzCRDDowAAABAAAAAAAIABAAAADJBMoEAxEEEfcS+BKBE4ITehQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1d073aeac2ba.js b/pr/720/docs/search.index/1d073aeac2ba.js new file mode 100644 index 000000000..f99b135ff --- /dev/null +++ b/pr/720/docs/search.index/1d073aeac2ba.js @@ -0,0 +1 @@ +rn_("AYkCsCAUcgABoDAAABR8aXATAAOgIAAAEy6ggAAAE0NlaXX1EAwAADoAAQABAAEAAYYCsJAUmgABoAAAABK6YmQBgAKwMBMiAAGgMAAAEPhydtcAAAKFoDAAABBsoDAAABN6EAETOjAAAAEAAAAAAAkAEAAAAPsI/Aj9CC0JLgmHEI4QSRFKEf4SAQMBsDATPgABc/PKEAAAAQABAAEAADswAAABAAAKAAMAcxECAL8TAwCpFAMAlwEAAIWgIAAABbGwIAf/AAFQGAH1egwAAAEAAQABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/1d276fafa4c6.js b/pr/720/docs/search.index/1d276fafa4c6.js deleted file mode 100644 index 7c73b557f..000000000 --- a/pr/720/docs/search.index/1d276fafa4c6.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQADoKAAABRZoCAAABOSsDAR6gABZWl08vYSAAABAAEDADswAAABAAAGAAEAZBEGAAEIAPT8EwAAAQCLAAUAEwEDsJAUYwABsFATQQFmZ2xwOzAAAAEAABIACQBpEAIA7REBAC4TAQBREwEAiBMBAO0TAQAlFAEANBQBAHUUAQABgAKwMBHmAAGwMBHoAAFydgECAbAAErYAAWQ7MAAAAQAABQACAOIRAwDlEgEAI4ECoJAAABRYaW8BBwD0dBQAAAwAIwARAHcLAAGIsFASuAEXsGATPwABlQkDOjAAAAEAAAAAAA4AEAAAAN8M4AzhDJsOnA7QENEQDBEvEY4RjxGQEZERNRNwEyOAAqAQAAAM3m5v") \ No newline at end of file diff --git a/pr/720/docs/search.index/1da0089589f8.js b/pr/720/docs/search.index/1da0089589f8.js new file mode 100644 index 000000000..cda523ee7 --- /dev/null +++ b/pr/720/docs/search.index/1da0089589f8.js @@ -0,0 +1 @@ +rn_("AQABsPAUswABazswAAABAAAIAAMAGhQAAB8UBgBJFAAAEwACsQAUnAABZG7y2xIAAAEAE4ACsBAMUwABZW8BBQA7MAAAAQAADQABAJ0RDQABAgDzBxAAAAEAAQABAgD0AxAAAAEAAQABAAEDADswAAABAAAIAAEAuRAIAAGAAqBAAAARELDAFF0AAWVzAQEAOzAAAAEAABMAAQAlEBMAI4ACsJATxwABaW03NgAAiqAQAAAMJqBQAAAUKLBwFAgAAaAgAAAM8JxVETswAAABAAAGAAMAVgcAAOoQAwC7EgEA84ACbHQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/1db6f0fddb6f.js b/pr/720/docs/search.index/1db6f0fddb6f.js deleted file mode 100644 index 973e52051..000000000 --- a/pr/720/docs/search.index/1db6f0fddb6f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBsAAM8wNGc/QpDAAAAQABAAEAAQIA9CcMAAABADkFAQAjAAKgQAAADO9lcvK4BAAAAQABgAKgQAAAE92wMBL4AAFhcwECAaBAAAAUZWXyiRQAAAEA84AEbG5ydg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1dbb8572c4de.js b/pr/720/docs/search.index/1dbb8572c4de.js deleted file mode 100644 index 2fe0f305d..000000000 --- a/pr/720/docs/search.index/1dbb8572c4de.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQcA9JQTAAABAAEAAQDzBQF0OzAAAAEAAAgAAgAFDAAAOAwHAAEFAPOwEwAAAQABADcAAICFsDAQTQABoKAAABPOoDAAABQLEEFI") \ No newline at end of file diff --git a/pr/720/docs/search.index/1e619d7f9016.js b/pr/720/docs/search.index/1e619d7f9016.js deleted file mode 100644 index ed1139149..000000000 --- a/pr/720/docs/search.index/1e619d7f9016.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEAOjAAAAEAAAAAAAgAEAAAAAkJdxAiESMRJBH8E/0TiBSNFAEBAqBAAAAUbqAwAAARKGVo9wEJAAAuAC8DAQCBBaECAQABAgD01xEAAAEAAQABABOBArAgEdsAAWFz84ACbm8BAgD0shAAAAEAAQABABMAAqDQAAAUc2Nz8iMQAAABAPOAA2Vpbw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1e76f3f2f3ae.js b/pr/720/docs/search.index/1e76f3f2f3ae.js deleted file mode 100644 index 7f6370cda..000000000 --- a/pr/720/docs/search.index/1e76f3f2f3ae.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQsBoEAAABQ6ZfJoFAAAAQABBQD0AxIAAAEAAQABAAGDArAAEO8AAbBQE34AAWR3E4ACoKAAABPyZXYBAgD0ChEAAAEAkgEBAAEAAPTyDwAAAQD1AAcBI4ICsFATVQABZXMBAgD0JRMAAAEAkgABAAEDAPRbEwAAAQCYAAEA84UCYnUBAgD0dREAAAEAfAEBAPOAAmls8wADYnR1OjAAAAEAAAAAAA8AEAAAAHIH+wf8B/0H/gcbEOEQrxMxFH4UfxSDFJAUkRS3FLsUAQwA8xQUAAABAAEAAYACsAAJGQABoCAAAA0DZG4BBgD0IxMAAAEAkgABAPMDAWL0CBEAAAEAkgEBAJcGAACHsEAP8AABoHAAABKnsJATUwABOAkDOjAAAAEAAAAAACQAEAAAAMEFwgXDBcQFNAc1BzMM+Az5DPoM/gz/DAAN6A/pDzwQPRBBEEIQXxBgEGEQYhBjEGQQZRCoEK0Q2RDaEI8TsxPaE3QUgBSjFLQUAQMA9DkTAAABAFEBAQDzgAJjbXcBAIDFsYAUxAABQIEECA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1edda76fba5c.js b/pr/720/docs/search.index/1edda76fba5c.js deleted file mode 100644 index 87259f6ce..000000000 --- a/pr/720/docs/search.index/1edda76fba5c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQACoCAAABOSsDAR6gABaXTy9hIAAAEAAQMAOzAAAAEAAAYAAQBkEQYAAQgA9PwTAAABAIsABQATAQOwkBRjAAGwUBNBAWZnbHA7MAAAAQAAEgAJAGkQAgDtEQEALhMBAFETAQCIEwEA7RMBACUUAQA0FAEAdRQBAAGAArAwEeYAAbAwEegAAXJ2AQQBsAAStgABZDswAAABAAAFAAIA4hEDAOUSAQC3BQABh7BQErgBF7BgEz8AAZQJAzowAAABAAAAAAALABAAAADfDOAM4QybDpwODBGOEY8RkBGRETUTcBMjgAKgEAAADN5ubwEDAPNmEAAAAQABACOAAqAAAAAMDmRyYwGEoFAAABGLoDAAABCkFAEQ8pgHAAABABOAA7BgEtoAAbAAD6sAAWNnchOAA6CwAAAUGaBAAAAOmmVvcw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/1fee3e0237a8.js b/pr/720/docs/search.index/1fee3e0237a8.js deleted file mode 100644 index 436d39989..000000000 --- a/pr/720/docs/search.index/1fee3e0237a8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9HoTAAABAAEAAQATAgKwgBNOAAFzdvRtCQAAAQCRCgEA8wABYwFlDAAAAQICoLAAABRYoLAAABRZY3Pz0BAAAAEAXgABgQKwUBHyAAGgwAAAFCdoafOCAmVp84ACZW8=") \ No newline at end of file diff --git a/pr/720/docs/search.index/20173a2c01e8.js b/pr/720/docs/search.index/20173a2c01e8.js deleted file mode 100644 index 779c6c959..000000000 --- a/pr/720/docs/search.index/20173a2c01e8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQA884RAAABAAEAAYICsEASxwABsEASyQABNDYBCwDzyBMAAGoAAQABBgD0tRQAAAEACgABAPMCAXIBERQAAPMCAWU7MAAAAQAABQACAH8QAwAwEQEAE4ACoFAAABL9ZHTzAIQRAQH37xAAAAEAbgAdAAEAAQA8AQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/20f76c7fa42e.js b/pr/720/docs/search.index/20f76c7fa42e.js deleted file mode 100644 index 174b2ad11..000000000 --- a/pr/720/docs/search.index/20f76c7fa42e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9DsHAAABAAEAAQABhQKwcBQXAAGwMBNrAAFlcxMAA7BAD9QAAaBgAAARjGJlczswAAABAAASAAQAqwUBAMYGCgBREAEAqRADAAECAPO1BQAARwoBAAEDAPXMDwAAoQABAAQAAQABCgGgQAAAFGVl8okUAAABACMABKAwAAARHKCQAAATk7BgEroAATBjaGn1AhIAAJkBAQABAAEA84ACZHLnBAAAh7AQCPcDQLAgDAMBDKAwAAAP9BJBODswAAABAAASAAYAjAACAJwFAADJBQMAmgcFAN0HAwANDAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/21ba71cbe90a.js b/pr/720/docs/search.index/21ba71cbe90a.js new file mode 100644 index 000000000..c6e29308b --- /dev/null +++ b/pr/720/docs/search.index/21ba71cbe90a.js @@ -0,0 +1 @@ +rn_("AQUBsEASxAABZfLoEgAAAQABAAA7MAAAAQAAEQAEAAECAQC5EAgAtxEDAMESAgABCgGwQBRnAAFl9SsUAAABAAEAAQABAEcGAACHsCARFAI9sMAUswABoCAAAAb6sDAHWAABGIkKOjAAAAEAAAAAAAwAEAAAAFQHVQc/CR0MHgwkDCUMeAx5DMgMyQwXExgT") \ No newline at end of file diff --git a/pr/720/docs/search.index/21d8ee2846b8.js b/pr/720/docs/search.index/21d8ee2846b8.js new file mode 100644 index 000000000..02bcf895a --- /dev/null +++ b/pr/720/docs/search.index/21d8ee2846b8.js @@ -0,0 +1 @@ +rn_("AQUBsEASxAABZTswAAABAAAFAAIA6BIBAEoUAwABggKgkAAAFDegkAAAFDgyMwEAhKAgAAASoKAgAAAI+LCAFLEAAbAwDgYAAQCRATswAAABAAAMAAYAngQAANYEAwBpCQAAsQ8DAAwUAAAdFAEA8wABcwEzEQAAAQUA9JUTAAABAAEAAQABAAD1egwAAAEAAQABAAEA84ACZ2tzgISwsBPwAAERSAABBQGgQAAAEfpl8wUNAAAUBAEAE4ACoDAAAAwzZXIBgAOwUBQwAAGgEAAAC/qgcAAAE4RnbnKjAISgUAAAFGOgoAAAE/8UAQQ7MAAAAQAAEQAEAAECAQC5EAgAtxEDAMESAgABhQKwcBQYAAGwMBNsAAFlcxMAA7BAD9QAAaBgAAARjWJlczswAAABAAASAAQAqwUBAMYGCgBREAEAqRADAAEDAPRtEAAAAQAEAAEAAQoBoEAAABRmZfKKFAAAAQATgAKwYBK7AAFjafOAAmRy8wACZW87MAAAAQAACQACAJoHBQDdBwMAAQIBsDARWQABbjswAAABAAAJAAEA8AsJAAEAAPSuEAAAAQABAAEAAQEAOzAAAAEAAO4AAgDGBQAAAQjtAGMAA7AQEygAAWVpczowAAABAAAAAAAOABAAAAALCUYJRwlICUkJGgwbDKkPqg/TD+oP2xAAEZETkhPjgISwIAdYAAERQAQBgYSwMAwGAAGgQAAADNGggAAAEWCwQAzSAAEAAB0BBQD14RMAAAEAAQB4AAEAE4ACoAAAAAb6YWcBAwD0mRIAAAEAbgEBAPOAAmlvAQEAOzAAAAEAAO4AAgB2BwAAAgvtAAEIAbBAFGcAAWX1KxQAAAEAAQABAAEA84ECZ3QBAQGgcAAAEgBpOzAAAAEAAAABAgB1BwAAAgr/AAEFAPPKEAAAAQABAPOAAmFvE4ACoEAAAAwycnUBgAKgAAAAB1qgEAAACQpkeBMAArAgDPwAAWVy8hwQAAABABOAArCwFLMAAXJ4AQoA9JwTAAABAAEAAQATgAKwEBEUAj1hZQEEAPSpEAAAAQABAAEAAQQAOjAAAAEAAAAAAAcAEAAAADwTPRNLE0wT0RPSE+QT5RMBAwDz1RIAAAEArQCXAQCAhbBAEv0APLBAEQYAAYFIAce/AwCPoIAAABLXsGAM7AABsEAMXAABsTAUhwABP6kfOzAAAAEAAEsAIgB6AAAAfwAAAL8EAQDLBAAAggUBAEAHAQBQBwAAVAcBAD8JAABTCQcAawkBAAUMAAAdDAEAJAwBADgMBwBcDAEAeAwBAMgMAQDmDwEAVhABANcQAQDkEAEA+xAAAB0RAgAuEQEAQBEEAGQRAACxEQMA9REBALESAAATEwEAFxMBAEcTAACtFAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/21fc35579d6a.js b/pr/720/docs/search.index/21fc35579d6a.js deleted file mode 100644 index e748810d3..000000000 --- a/pr/720/docs/search.index/21fc35579d6a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIAOzAAAAEAAAUAAQCSFAUA8w0BbTswAAABAAAFAAEAThQFACMDA7BAEsMAAbAAE4cAiWVmczswAAABAAAYAAYAMxEHAOcSAQBmEwQAQhQEAEkUAwC4FAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/21fc60b1602f.js b/pr/720/docs/search.index/21fc60b1602f.js deleted file mode 100644 index 89b4046d0..000000000 --- a/pr/720/docs/search.index/21fc60b1602f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBoAAAABPlcwH5EAAAAQMA9IgQAAABAAEAAQATgAKwUBCMAAFhaQGAArBwFLAAAbBwFDwAAWVyAYACoLAAABRzoDAAABElbG6XAgAAhqAgAAASn6AgAAAI+LAwDgYAARCRBTowAAABAAAAAAARABAAAACeBNYE1wTYBNkEaQmxD7IPsw+0D00ThxMLFBAUHBQdFDgUORQBAgA6MAAAAQAAAAAACgAQAAAAUQlSCSIQcRNyE6IToxNNFKYUvhS/FAEAADswAAABAAAGAAIAjhMAAPYTBQABAgGwMBNeAAFjOjAAAAEAAAAAABMAEAAAAPsMzA9mEGcQaBBtEG4QchBzEA8RghGGEYcRiBH/EVMTVBM6FGMUZBQBAwDzyBMAAGoAAQATgQKwQBFuAAFhZROAAqCwAAAUemFlAQEBsEAUZgABZfUqFAAAAQABAAEAAQATgAKgEAAADA9hb4cPAADIsDAJCQdusEAUbAABoIAAABKaQEyICfPyBwAAJQQ/AAGAAqCAAAATeKCQAAATUGFrAQMA88ASAAABAAEAI4CEsSAUvAABoAAAAAksoDAAAA/TBAQGAQgA9cQUAAABAAEAAQABABOKArBAFJsAAWFyk4CEoMAAABNMoQAAABQZAUAGAQMBoEAAABH5ZfMFDQAAFAQBAAEFAPS+EwAAAQABAAEAo4CEoIAAABM4sAATcwABEQAGAQYA9KgUAAABAAEAAQDzCAFt9KwSAAABAAEAAQABAgA7MAAAAQAABQABAJIUBQDzDQFtOzAAAAEAAAUAAQBOFAUAAQQA9w0NAAABAKcFDgABAJEAAQABAwGAE4AAEPhzOzAAAAEAAAUAAQBgEwUAI4ICoJAAABRiaXMBBQGgUAAAFCdo8roSAAABABOAArAwE3MAAW50AYACoIAAABOTsEAR8gABYWUBgAKgEAAAERugAAAAEWBucgEJAaBAAAAUZWXyiRQAAAEAI4ACoJAAABPLaWzHIwAACqAwAAARHLBQEycAAbDwFLIAAbBwE5AAAaDQAAAUbjBiY2VoaWtub3Y7MAAAAQAAHgALAA4MAADzEAMAAhIEAIwTAQCbEwMA0hMBABkUAAAeFAYAPBQBAEgUAABfFAEAAQICoLAAABRYoLAAABRZY3Pz0BAAAAEAXgABAQKwUBHyAAGgwAAAFCdoafLSEwAAAQDzgAJlaQEBAbCQE4wAAXP0shAAAAEAAQABAAEDAaAAAAAQ7nMBVRAAAPOAA2hpdAEBAaBQAAATC2MBzwwAAAEFAbCAFF8AAXY7MAAAAQAABwACANERAwDCEwMAAQEA9HUQAAABALMAAQDjgISwcBH2AAEOCAD3tQcA0LCQEpgAAaBQAAARFKCgAAATr6AQAAAHTkA/vSk7MAAAAQAAPQAYAMYEAADIBAAAmQUCABUHAwD7CwMA0gwBAMAPAgDODwAA+A8AAAEQAQAjEAEAMhEIAIkRAADaEgEA4xIBAOcSAQBIEwEAZhMEALwTAQDGEwEAyxMAAEIUBABJFAMAuBQAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2239713765f5.js b/pr/720/docs/search.index/2239713765f5.js deleted file mode 100644 index 1fcbe605e..000000000 --- a/pr/720/docs/search.index/2239713765f5.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEBoEAAABRlZfKJFAAAAQABgAOgMAAAEqGw4BRAAAGwkBSLAAFhY22HAQCAhbAQES0AAbAQEUwAAaCgAAAUczEJAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/226ac74944f5.js b/pr/720/docs/search.index/226ac74944f5.js new file mode 100644 index 000000000..68f7c9bf6 --- /dev/null +++ b/pr/720/docs/search.index/226ac74944f5.js @@ -0,0 +1 @@ +rn_("AQgBoIAAABS5ZgGZEwAAE4ACoOAAABR6YnABAwGwABQyAFJz9ugPAAABAMQALAABAAEDAYACsEASvQABoBAAABEYcHIBgQOgAAAAEYqwAA/PASugEAAAD8dlc3XzgANhb3IBAgD13BAAAAEAAQBgAgEAAQQAOzAAAAEAAAkAAQBPEQkAAQAA9L8RAAABAAEAAQABgAKgkAAAE/SwUBKlAAFid/OAAmR0o4CEsFAUDwABsJATNAABQCADVwMAAIagcAAAE+ugQAAAFF8wQQw7MAAAAQAAQgAhAMQEAQCIBQoAfQcAACYJAQAsCQAALQwBAFAMAgDmDAEA8wwAAJoOAAC4DwQAzw8AAPIPAQA5EAAAthAAAMQQAwDoEAEA+hAAACERAQCOEQAA4hEAAOsRAQDwEQAA8BIAACoTAQDfEwEA5hMAAA8UAQAwFAEASBQAAIUUAQC2FAEAwRQBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/228447d4f222.js b/pr/720/docs/search.index/228447d4f222.js deleted file mode 100644 index 06e0dce17..000000000 --- a/pr/720/docs/search.index/228447d4f222.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9HoTAAABAAEAAQDzBgFz8v8TAAABAAEBAbBQEvgAAWX3EwkAAFQDAQARBAEA3AMBAAEDAPS+EQAAAQABAAEAAQMA9LoRAAABAAEAAQDzgwJsc/OAAmN0U4ADoBAAAAzKYW9y") \ No newline at end of file diff --git a/pr/720/docs/search.index/22d00b1c59e3.js b/pr/720/docs/search.index/22d00b1c59e3.js deleted file mode 100644 index 991c379a4..000000000 --- a/pr/720/docs/search.index/22d00b1c59e3.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIBsEAUfAABdDswAAABAAANAAYA/hIDAGsTAQDbEwEA8hMBAHEUAQCZFAEAE4ACsDATMgFJaXABBQDzsBMAAAEAAQATgAKgMAAAFAtleVMAA7BwFBcAAWJlcwFAEAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/233ca4e57e96.js b/pr/720/docs/search.index/233ca4e57e96.js new file mode 100644 index 000000000..7e7ede29e --- /dev/null +++ b/pr/720/docs/search.index/233ca4e57e96.js @@ -0,0 +1 @@ +rn_("AYACsAAT5wABsAAT6QABNDYBBgD0thQAAAEACgABAPMCAnJ28/UPAAABABwE8wIBZTswAAABAAAFAAIAfxADADERAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/235afbc24e7c.js b/pr/720/docs/search.index/235afbc24e7c.js deleted file mode 100644 index 1854553bd..000000000 --- a/pr/720/docs/search.index/235afbc24e7c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMAOzAAAAEAAAkABABcCQEAnxADAOIQAQDvEwEAAQIBsEAUfAABdDswAAABAAANAAYA/hIDAGsTAQDbEwEA8hMBAHEUAQCZFAEAE4ACsDATMgFJaXABiAKwABPmAAGwABPoAAE0NhOBAqAwAAARhWRzAYACoCAAAAx3sGAUFwABbngBBQDzsBMAAAEAAQATgAKgMAAAFAtlefMAhBIAA/JAEAAA5gDzgAJydA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/23762464f5f4.js b/pr/720/docs/search.index/23762464f5f4.js new file mode 100644 index 000000000..58a5c453c --- /dev/null +++ b/pr/720/docs/search.index/23762464f5f4.js @@ -0,0 +1 @@ +rn_("AQAA9CoTAAABAFoBAQDzBAFzOzAAAAEAAA0AAgCnEwcAnhQFAEcAAASGoIAAABOHsQAUrQABsEAS5AABsIAUvQABsFATLAABFQAW9JYOAAABAAEAAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/23a40eca4762.js b/pr/720/docs/search.index/23a40eca4762.js deleted file mode 100644 index 916463b93..000000000 --- a/pr/720/docs/search.index/23a40eca4762.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYAOzAAAAEAAAkAAQBOEQkAAQIAOzAAAAEAABMAAQAlEBMAE4GEoFAAABEQoBAAAAwmoCAAAAzwHEAAE4ACsFAThAABYW4zgAOwMA/IAAFpc3Q=") \ No newline at end of file diff --git a/pr/720/docs/search.index/23b208bab09b.js b/pr/720/docs/search.index/23b208bab09b.js new file mode 100644 index 000000000..067229ae2 --- /dev/null +++ b/pr/720/docs/search.index/23b208bab09b.js @@ -0,0 +1 @@ +rn_("AQEBoEAAABRmZfKKFAAAAQABgAOgMAAAEqKw4BRBAAGwkBSMAAFhY22HAQCAhbAQES4AAbAQEU0AAaCgAAAUdDEJAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2424bb274ca9.js b/pr/720/docs/search.index/2424bb274ca9.js deleted file mode 100644 index 8d7706aaf..000000000 --- a/pr/720/docs/search.index/2424bb274ca9.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYICsCARRgABsDARxAABZXABBQD05g8AAAEA8AABAFOAA7CQEfQAAWFpcgGBArCgFBoAAbCgFBwAAWNyxwAAAIWwUAz2AAGgIAAACW+gIAAADB88AAE6MAAAAQAAAAAACgAQAAAAtQG2AXsE+gYfCSAJfRB+EPEQ8hAHEg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/243cde139a13.js b/pr/720/docs/search.index/243cde139a13.js deleted file mode 100644 index 65c9b20f6..000000000 --- a/pr/720/docs/search.index/243cde139a13.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYECoCAAABSYsEAP/AABYnABBQD0ShMAAAEAmAABAPMDAWMBsBIAAAEMAbAAFIQAAXM7MAAAAQAABQABAJ0UBQDzgAJudgGAArAwDFcAAaAwAAAMWWlvAQMBoAAAABRicwH4EQAAAQQA9BIMAAABAAEAAQDXAwCAhrAABXQAAZFIAQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/24443483573e.js b/pr/720/docs/search.index/24443483573e.js new file mode 100644 index 000000000..09db5dace --- /dev/null +++ b/pr/720/docs/search.index/24443483573e.js @@ -0,0 +1 @@ +rn_("AQ0A9eETAAABAAEAeAABAAECAPQKEQAAAQCTAQEAAQMA9HYRAAABAHwBAQDzAAJidQEbEAAAAQMA9AgRAAABAJMBAQDzhAJkcwECAPMMCQAAAQBZAPOAAml0ARgA88cUAAABAAEAI4ECsMAT3wABY20BBQGwYBLGAAFy9CEMAAABAPcDAQABCQD28RIAAAEAAAGHADYAAQATgAKwYBDIAAFkbgEDAaBwAAATLmf0WwcAAAEACAIBAAEJAPN/FAAAAQA8AAGBArCAFJEAAaBgAAAUuGRzFwEAiYWw0BS6AAGgQAAAFGKwYBQyAFICkApnugAAjLBwES4AAbCwEz4AAaCgAAAS8LFQFLEAAbDwFA8AAW3BD/SHAAAAAQABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/245720643b05.js b/pr/720/docs/search.index/245720643b05.js deleted file mode 100644 index dd6c3b3e2..000000000 --- a/pr/720/docs/search.index/245720643b05.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQoA9KQTAAABAA8AAQABgwKgIAAAEEygMAAAEOlpdAEAAPQOEwAAAQABAAEA8wQBZPSxEgAAAQABAAEAI4aEsKAUVgABsEATDAABsHAT/wABFYAAAQACsDAQPgABsBATvAABc3TzlwUAAIEGAQABgAKwwBSGAAGgAAAAB1B0efOAhRHBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/24cf76e66d9a.js b/pr/720/docs/search.index/24cf76e66d9a.js new file mode 100644 index 000000000..0b4c4b441 --- /dev/null +++ b/pr/720/docs/search.index/24cf76e66d9a.js @@ -0,0 +1 @@ +rn_("AQUA9IgQAAABAAEAAQABFAD1xRQAAAEAAQABAAEAAQUBsIAUYAABdjswAAABAAAHAAIA0hEDAMMTAwAjgAKwcBH3AAFiZFcCAACGsMATjQABoKAAABOwoJAAABN5BeACOzAAAAEAAAUAAgAVBwMAARABAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2539e79c2dcd.js b/pr/720/docs/search.index/2539e79c2dcd.js new file mode 100644 index 000000000..75c02d5f0 --- /dev/null +++ b/pr/720/docs/search.index/2539e79c2dcd.js @@ -0,0 +1 @@ +rn_("AYADoIAAABLXsFAS/QA8sHAUMAABYWNzAQABoIAAABS5ZvL6CAAAnwoBBwD1ZxMAAAEAAQABAAEAI4ACoFAAABFkYW/zAAJmczswAAABAAAIAAQATQcAAH4HBQAEDQAAnBEAAPOAAmR5") \ No newline at end of file diff --git a/pr/720/docs/search.index/254b3dc1eadd.js b/pr/720/docs/search.index/254b3dc1eadd.js deleted file mode 100644 index e6a846551..000000000 --- a/pr/720/docs/search.index/254b3dc1eadd.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQACoCAAABOSsDAR6gABaXTy9hIAAAEAAQMAOzAAAAEAAAYAAQBkEQYAAQgA9PwTAAABAIsABQATAQOwkBRjAAGwUBNBAWZnbHA7MAAAAQAAEgAJAGkQAgDtEQEALhMBAFETAQCIEwEA7RMBACUUAQA0FAEAdRQBAAGAArAwEeYAAbAwEegAAXJ2AQQBsAAStgABZDswAAABAAAFAAIA4hEDAOUSAQC3BQABh7BQErgBF7BgEz8AAZQJAzowAAABAAAAAAALABAAAADfDOAM4QybDpwODBGOEY8RkBGRETUTcBMjgAKgEAAADN5ubwEDAPNmEAAAAQABACOAAqAAAAAMDmRyYwGEoFAAABGLoDAAABCkFAEQ8pgHAAABABOAArBgEtoAAWNnE4ADoLAAABQZoEAAAA6aZW9z") \ No newline at end of file diff --git a/pr/720/docs/search.index/255778576e99.js b/pr/720/docs/search.index/255778576e99.js new file mode 100644 index 000000000..a8beddcd1 --- /dev/null +++ b/pr/720/docs/search.index/255778576e99.js @@ -0,0 +1 @@ +rn_("AYACsCATRgBaoFAAABEzbXNDgAOw4BQIAAEaZhusQjFkZ3IBAwDz2BIAAAEAAQAjgAKwMBQNAAFjaTOAA7AADQMDaWFpbw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/25672b9a3070.js b/pr/720/docs/search.index/25672b9a3070.js deleted file mode 100644 index b31379f81..000000000 --- a/pr/720/docs/search.index/25672b9a3070.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIAOzAAAAEAABEABQCuBQAAMgwAAOgMAAAKEA0AcBEAAAGEArDQFLAAAaCQAAATrmJoAYQCsAARfgABsAARgAABNDaXBAAAh6AgAAAR3aAwAAARRKAwAAASqLBwD+IAActACDswAAABAAARARQAuAEAAKQFAAD4CAAA/ggAABsJAgAMDAAATgwBAHUMAQDrDAAAGA3tAMoPAADfDwEA1hAAAJIRAADwEgEA1BMFAPETAAB4FAAAkhQFAK4UAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/2602dc5a7bc0.js b/pr/720/docs/search.index/2602dc5a7bc0.js deleted file mode 100644 index a60d9687a..000000000 --- a/pr/720/docs/search.index/2602dc5a7bc0.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYADsAAT5gABsAAT6AABsHAUXwABNDZhAQQA9LUUAAABAAoAAQAjgQKgQAAAEV5tcAECADswAAABAAAOAAQAagcBAAgNAQBOEQkAjBEAAAEBADswAAABAAAIAAMA1hIAAEwTAADCFAYAAQEAOzAAAAEAAAoAAwByEQIAvhMDAKgUAwAjgAKgMAAAEFhkZ9cDAADGoIAAABKwQEaACDswAAABAAAYAAkA9Q8BABYRAQBKEQEAWhEDANERBQDCEwMAERQAAG8UAQCkFAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/269ae53d56fe.js b/pr/720/docs/search.index/269ae53d56fe.js new file mode 100644 index 000000000..8b23e5635 --- /dev/null +++ b/pr/720/docs/search.index/269ae53d56fe.js @@ -0,0 +1 @@ +rn_("AQAA9AoRAAABAJMBAQAjgQKgYAAAE0NiaQEAAPTyDwAAAQD1AAgBI4ECsFATVgABZXMTgAKAB1Ee8AFhcgGJArAgFHIAAaAwAAAUfGlwAQIA9CYTAAABAJIAAQABAwD0XBMAAAEAmAABAPOFAmJ1AQIA9HYRAAABAHwBAQDzgAJpbLcBAACFoCAAABMuEgEMOjAAAAEAAAAAABYAEAAAAHIH+wf8B/0H/gcQDEoMSwxMDE0MGxDhEHQTdROwEzIUfxSAFIQUkRSSFLgUvBQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/26b19c61c64e.js b/pr/720/docs/search.index/26b19c61c64e.js deleted file mode 100644 index 42c510e6e..000000000 --- a/pr/720/docs/search.index/26b19c61c64e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYkCsCAUcQABoDAAABR7aXATAAOgIAAAEy2ggAAAE0JlaXX1EAwAADoAAQABAAEAAYYCsJAUmQABoAAAABK5YmQBAgD0GgwAAAEAjgMBAAEAAPQ3CQAAAQABAAEAAQAAOzAAAAEAAAYAAgCOEwAA9hMFACOBArBAFGwAAWVz84ADZXh5AQAA9DMJAAABAAEAAQAjgAKwIBMhAAFyeEcBAADGsMATugABoBAAABFxsEAM5gABoDAAABD4AESAC/RwBQAAAQB7BwEA1wAAAIWgMAAAEGygMAAAE3kQARM6MAAAAQAAAAAACgAQAAAA+wj8CP0ILQkuCR8MhxCOEEgRSRH9Eg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2713334de97c.js b/pr/720/docs/search.index/2713334de97c.js deleted file mode 100644 index 414ef0230..000000000 --- a/pr/720/docs/search.index/2713334de97c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9CkTAAABAFoBAQDzBAFzOzAAAAEAAA0AAgCmEwcAnRQFAEcAAAGGoIAAABOGsQAUrAABsEAS4wABsIAUvAABsFATKwABFQAW9JYOAAABAAEAAQABBQDz/g8AAAEAAQBjgAOwQBCMAAFtbm8=") \ No newline at end of file diff --git a/pr/720/docs/search.index/271b78f43c84.js b/pr/720/docs/search.index/271b78f43c84.js new file mode 100644 index 000000000..0d35f1665 --- /dev/null +++ b/pr/720/docs/search.index/271b78f43c84.js @@ -0,0 +1 @@ +rn_("AQEBoGAAABSZc/LcEQAAAQABCAD1QxQAAAEAAQABAAEAowCEsCAJcQABoIAAABLwMEAIOzAAAAEAAAUAAgDyAQAAmhAEAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2725d533e78b.js b/pr/720/docs/search.index/2725d533e78b.js deleted file mode 100644 index 164ab15b6..000000000 --- a/pr/720/docs/search.index/2725d533e78b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMA9gENAADrAloAAQDRAgEAAQQAOzAAAAEAAAoABACPEAUA0hIBADMTAQBZFAAAAYYCoAAAABNXoAAAABNYZHLzAgF2AYMTAADzgAJlbycCAADIoDAAAA/roHAAABKisRAUgQABoIAAABQosNATyQABoLAAABQoQGUICTswAAABAAAJAAMAvgUCAB8HBABaDAEAI4ACY0TMVIdIZHIBAAA6MAAAAQAAAAAACgAQAAAAUQlSCSIQcRNyE6IToxNNFKYUvhS/FBOAAqAwAAAQpWx0w4AEoAAAABCVoAAAABCWNDZhZQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/275265ed50a5.js b/pr/720/docs/search.index/275265ed50a5.js deleted file mode 100644 index f9e3849c8..000000000 --- a/pr/720/docs/search.index/275265ed50a5.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYQCsAARfgABsAARgAABNDbzAAFh8nUMAAABACOAArCQEYQBImx0AYACsHATmQABsIAT0gABY3MBAAA6MAAAAQAAAAAACQAQAAAA3hHfEfoS+xLrE+wTQBRBFLwUvRTzgAJkZScBAICFoNAAABQRsBAEwQABoDAAABB4AggL") \ No newline at end of file diff --git a/pr/720/docs/search.index/2797aa38226c.js b/pr/720/docs/search.index/2797aa38226c.js new file mode 100644 index 000000000..4bbde3dc8 --- /dev/null +++ b/pr/720/docs/search.index/2797aa38226c.js @@ -0,0 +1 @@ +rn_("AQABoJAAABN4aPJAEwAAAQDzAgFk8hMHAAABAAECADswAAABAAAFAAEAkxQFAPMLAW07MAAAAQAABQABAE8UBQAjgAKwIAzsAAFhbwECAPP+CAAAUAMBAAGKArAAE+cAAbAAE+kAATQ2I4ECoDAAAAx3ZXIBgAKwQBH1AAEz8aChDy1jdbcGAACHsBAQUwABsFAUawABEVEJ9Z0EAAAKAMYAAQCeBw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/27dc20cd64df.js b/pr/720/docs/search.index/27dc20cd64df.js deleted file mode 100644 index 306184a54..000000000 --- a/pr/720/docs/search.index/27dc20cd64df.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9JQTAAABAAEAAQABAAD1egwAAAEAAQABAAEA84ACZ2sTgAKwsBPvAAFhbwGAAqAgAAAL+qBAAAAMM2V0AYUCsHAUFwABsDATawABZXMTAAOwQA/UAAGgYAAAEYxiZXM7MAAAAQAAEgAEAKsFAQDGBgoAURABAKkQAwABAwD0bRAAAAEABAABAAEKAaBAAAAUZWXyiRQAAAEAE4ACsGASugABY2nzgAJkcvMAAmVvOzAAAAEAAAkAAgCaBwUA3QcDAAECAbAwEVgAAW47MAAAAQAACQABAPALCQDzgAJvdAEDADswAAABAADuAAIAdgcAAAIL7QABAgGgcAAAEf9pOzAAAAEAAAABAgB1BwAAAgr/ABOAAqBAAAAMMnJ1AQQA9EoTAAABAJgAAQABAwDz1BIAAAEArQDzgAJhb9cHAACIsEAM/AABsTAUhgABNIEWOzAAAAEAAB4ADQC/BAEAggUBAAUMAAA4DAcAXAwBAOYPAQDXEAEAYxEAALARAwD0EQEAsBIAABITAQCsFAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/28e08809acf2.js b/pr/720/docs/search.index/28e08809acf2.js new file mode 100644 index 000000000..f0e1cda9f --- /dev/null +++ b/pr/720/docs/search.index/28e08809acf2.js @@ -0,0 +1 @@ +rn_("AQgA9P0TAAABAIsABQATAAOwkBRkAAGwUBNCAWZnbHA7MAAAAQAAEgAJAGkQAgDuEQEALxMBAFITAQCJEwEA7hMBACYUAQA1FAEAdhQBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2909ad8af809.js b/pr/720/docs/search.index/2909ad8af809.js new file mode 100644 index 000000000..cd6a76d80 --- /dev/null +++ b/pr/720/docs/search.index/2909ad8af809.js @@ -0,0 +1 @@ +rn_("AQ8A9CYUAAABAE8AAQABBAD0gxAAAAEAuAABAAECADowAAABAAAAAAAJABAAAADfEeAR+xL8EuwT7RNBFEIUvRS+FPMAAW/ycwkAAAEAU4ADsQAUjAABaG9ww4CEoBAAABNesIAToQABBQAG") \ No newline at end of file diff --git a/pr/720/docs/search.index/29212c997b44.js b/pr/720/docs/search.index/29212c997b44.js deleted file mode 100644 index d9630d35e..000000000 --- a/pr/720/docs/search.index/29212c997b44.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA9GcHAAB6COEAAQABBQD0SRQAAAEAAQABAAEFAPQ7EwAAAQCUAAEA8wICY3X1VhAAAAEAxgABAAEA84ACbnM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/2923606a2790.js b/pr/720/docs/search.index/2923606a2790.js deleted file mode 100644 index 1a702708b..000000000 --- a/pr/720/docs/search.index/2923606a2790.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAEoAAAABCZsCARTAABoFAAABH4oEAAABQ7ZGxzdjswAAABAAATAAYArgUAADIMAADoDAAAChANAHARAAA2FAEAAQIA9NcRAAABAAEAAQAThAKwIBHbAAFhc/OAAmFl") \ No newline at end of file diff --git a/pr/720/docs/search.index/29503497fefb.js b/pr/720/docs/search.index/29503497fefb.js deleted file mode 100644 index 5b9c9310e..000000000 --- a/pr/720/docs/search.index/29503497fefb.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACoAAAABCVoAAAABCWNDYBgAOwABPmAAGwABPoAAGwcBRfAAE0NmEBBAD0tRQAAAEACgABACOBAqBAAAARXm1wAQEAOzAAAAEAAAgAAwDWEgAATBMAAMIUBgDHAQACxaBAAAAQWKCAAAASsEAGgAg7MAAAAQAAFgAIAPUPAQAWEQEAWhEDANERBQDCEwMAERQAAG8UAQCkFAEA8wACZXY6MAAAAQAAAAAAFQAQAAAAEwIUAhUCsAUCDa8PsA/ND+sPfxCAEIEQghAwETERxxLIEskSyhLIEzIUMxQBgQKwcBFaAAGwcBFcAAE0NiOAArAQB2EAAW5wAQMCsEATIQABoDAAABN5ZXf0hxAAAAcAugABABOBAqBwAAATs2dvAQQAOzAAAAEAAAYAAgAEDAAAEA0FAGOAA7BQD/UAAWRzdFcBAACFoBAAABBYsSAUbwABESEBOzAAAAEAAAoAAwB+AAAAlAAFANcRAwA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/29a4091c28ec.js b/pr/720/docs/search.index/29a4091c28ec.js deleted file mode 100644 index 7723da4fa..000000000 --- a/pr/720/docs/search.index/29a4091c28ec.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9HoTAAABAAEAAQABBADzwA8AAAEAAQABgAKgUAAAENagYAAAEUVpcgGAAqAgAAAMdKBgAAARRGVoAQEA83AMAAABAAEAE4ECoBAAAAxzYWMBAwA7MAAAAQAABQACAGwMAwBYEQEAAQYA9BITAAABAJkBAQATAAKwYBMUAAFmbfLiDAAAAQAjgAKgwAAAE+VucqcPAACIoEAAAA+9sEAPvgABNCAXOzAAAAEAABkAAwALAgAAbAQOAPALCQABgAOwcBOZAAGwMBNDAAGwgBPSAAFjcnMBAAGwIBOZAAFvOjAAAAEAAAAAAAkAEAAAAN4R3xH6EvsS6xPsE0AUQRS8FL0UAYACsCAJIQABsDATTgABcnT3BAAAyKAgAAAHdKBgAAAP7bCAE04AAUAGkgn2FwIAAHkC3QQBAJEKAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/2a13341e5a7f.js b/pr/720/docs/search.index/2a13341e5a7f.js new file mode 100644 index 000000000..ecadb23c8 --- /dev/null +++ b/pr/720/docs/search.index/2a13341e5a7f.js @@ -0,0 +1 @@ +rn_("AQABsIAUPQABcPI5FAAAAQBDBQOgIAAAEWGgQAAAErZkZXPz+A8AAFEDAQABAgA7MAAAAQAAEwABACUQEwATgYSgUAAAERCgEAAADCagIAAADPAcQAAzgAOwUBOFAAFhZm4=") \ No newline at end of file diff --git a/pr/720/docs/search.index/2aa572615107.js b/pr/720/docs/search.index/2aa572615107.js deleted file mode 100644 index a9dfa6ae9..000000000 --- a/pr/720/docs/search.index/2aa572615107.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUBsEASwwABZTswAAABAAAFAAIA5xIBAEkUAwABggKgkAAAFDagkAAAFDcyMwEAhKAgAAASn6AgAAAI+LCAFLAAAbAwDgYAAQCRATswAAABAAAMAAYAngQAANYEAwBpCQAAsQ8DAAsUAAAcFAEA8wABcwEyEQAAAQUA9JQTAAABAAEAAQABAAD1egwAAAEAAQABAAEA84ACZ2tzgISwsBPvAAERSAABBQGgQAAAEfll8wUNAAAUBAEAE4ACoDAAAAwzZXIBgAOwUBQvAAGgEAAAC/qgcAAAE4NnbnKjAISgUAAAFGKgoAAAE/4UAQQ7MAAAAQAAEQAEAAECAQC5EAgAthEDAMASAgABhQKwcBQXAAGwMBNrAAFlcxMAA7BAD9QAAaBgAAARjGJlczswAAABAAASAAQAqwUBAMYGCgBREAEAqRADAAEDAPRtEAAAAQAEAAEAAQoBoEAAABRlZfKJFAAAAQATgAKwYBK6AAFjafOAAmRy8wACZW87MAAAAQAACQACAJoHBQDdBwMAAQIBsDARWAABbjswAAABAAAJAAEA8AsJAAEAAPSuEAAAAQABAAEAAQEAOzAAAAEAAO4AAgDGBQAAAQjtAGMAA7AQEycAAWVpczowAAABAAAAAAAOABAAAAALCUYJRwlICUkJGgwbDKkPqg/TD+oP2xAAEZATkRPjgISwIAdYAAERQAQBgYSwMAwGAAGgQAAADNGggAAAEV+wQAzSAAEAAB0BBQD14BMAAAEAAQB4AAEAE4ACoAAAAAb6YWcBAwD0mBIAAAEAbgEBAPOAAmlvAQEAOzAAAAEAAO4AAgB2BwAAAgvtAAEIAbBAFGYAAWX1KhQAAAEAAQABAAEA84ECZ3QBAQGgcAAAEf9pOzAAAAEAAAABAgB1BwAAAgr/AAEFAPPKEAAAAQABAPOAAmFvE4ACoEAAAAwycnUBgAKgAAAAB1qgEAAACQpkeBMAArAgDPwAAWVy8hwQAAABABOAArCwFLIAAXJ4AQoA9JsTAAABAAEAAQATgAKwEBEUAjxhZQEEAPSpEAAAAQABAAEAAQQAOjAAAAEAAAAAAAcAEAAAADsTPBNKE0sT0BPRE+MT5BMBAwDz1BIAAAEArQCXAQCAhbBAEvwAPLBAEQYAAYFIAce/AwCPoIAAABLWsGAM7AABsEAMXAABsTAUhgABP6kfOzAAAAEAAEsAIgB6AAAAfwAAAL8EAQDLBAAAggUBAEAHAQBQBwAAVAcBAD8JAABTCQcAawkBAAUMAAAdDAEAJAwBADgMBwBcDAEAeAwBAMgMAQDmDwEAVhABANcQAQDkEAEA+xAAAB0RAgAtEQEAPxEEAGMRAACwEQMA9BEBALASAAASEwEAFhMBAEYTAACsFAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/2abad999474c.js b/pr/720/docs/search.index/2abad999474c.js new file mode 100644 index 000000000..6678fae73 --- /dev/null +++ b/pr/720/docs/search.index/2abad999474c.js @@ -0,0 +1 @@ +rn_("AYQCoCAAABEooDAAABGOaXQBAQA7MAAAAQAAjQACAHMHAAB1CYwAYwADsAACGgABZGVsOjAAAAEAAAAAAAcAEAAAALcEhQWGBYcFdwdFEZoTmxM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/2b35b1fa753b.js b/pr/720/docs/search.index/2b35b1fa753b.js deleted file mode 100644 index f999ecbe2..000000000 --- a/pr/720/docs/search.index/2b35b1fa753b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAAOjAAAAEAAAAAAAoAEAAAAOYP5w/XENgQYxH0EfUREhMTE6wUrRTzAQF58gwUAAABACMAA6BAAAARgqBQAAAUXmVvc/LGDwAA2gI=") \ No newline at end of file diff --git a/pr/720/docs/search.index/2b3dd3c328d1.js b/pr/720/docs/search.index/2b3dd3c328d1.js new file mode 100644 index 000000000..4c6954791 --- /dev/null +++ b/pr/720/docs/search.index/2b3dd3c328d1.js @@ -0,0 +1 @@ +rn_("AQUAOzAAAAEAAAYBAgDkDAEAnQ4EAQEBAaAAAAATTnP1xgQAAAgL+QMBAAQAAQECoGAAABPPoOAAABQqZXQ7MAAAAQAACAABAM0ECAABgAOwIBKXAAGwsBLRAAGwsBLTAAFiY3PzgARjbHR2") \ No newline at end of file diff --git a/pr/720/docs/search.index/2b9e99969beb.js b/pr/720/docs/search.index/2b9e99969beb.js deleted file mode 100644 index ddf9a4c0d..000000000 --- a/pr/720/docs/search.index/2b9e99969beb.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQA9goNAAABAD8DAQAuAQEAAQoA89QSAAABAK0AAQEA9x8JAAABAF0HAQBzAAEAFQEjgAKwYBPvAAFpbwECAPTIDAAAAQBNBgEAAQUA9AUUAAABAE4AAQD3CAAAiLCQE7wAAaAgAAAMyrCQEfoAAQTcAzowAAABAAAAAAAIABAAAACVBRAJEQljDGQMARECEQcTCBM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/2bb7edc74135.js b/pr/720/docs/search.index/2bb7edc74135.js new file mode 100644 index 000000000..3dd4f26c9 --- /dev/null +++ b/pr/720/docs/search.index/2bb7edc74135.js @@ -0,0 +1 @@ +rn_("AQMBsDATXwABY/OHEQAAAQABAAEDAYATgQAQ+HM7MAAAAQAABQABAGETBQAjggKgkAAAFGNpcwcBAIDFsFATKAABoKAAABPMsHATkQABoNAAABRvgAEYCPOAAmRy") \ No newline at end of file diff --git a/pr/720/docs/search.index/2bc95fa13920.js b/pr/720/docs/search.index/2bc95fa13920.js deleted file mode 100644 index f4a08c59d..000000000 --- a/pr/720/docs/search.index/2bc95fa13920.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUBsEASwwABZfLnEgAAAQABAAA7MAAAAQAAEQAEAAECAQC5EAgAthEDAMASAgABCgGwQBRmAAFl9SoUAAABAAEAAQABAEcGAACHsCARFAI8sMAUsgABoCAAAAb6sDAHWAABGIkKOjAAAAEAAAAAAAwAEAAAAFQHVQc/CR0MHgwkDCUMeAx5DMgMyQwWExcT") \ No newline at end of file diff --git a/pr/720/docs/search.index/2be35184ddea.js b/pr/720/docs/search.index/2be35184ddea.js deleted file mode 100644 index dfcb50a09..000000000 --- a/pr/720/docs/search.index/2be35184ddea.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUAOzAAAAEAAAcAAwDLEQIAfhMBABQUAgABBADzzhEAAAEAAQAjAAKgYAAAEv1hcvPvEAAAAQDJAQGAAqEQAAAUo7CAFJkAAWl1NwQAgYexUBTAAAGgAAAAEM+wcBPeAAGhMAAAFLQKQBsjgAKgMAAAEppudg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2c10172e8da1.js b/pr/720/docs/search.index/2c10172e8da1.js deleted file mode 100644 index f4042a06a..000000000 --- a/pr/720/docs/search.index/2c10172e8da1.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBoEAAABH5ZfMFDQAAFAQBAAEGAPQWEQAAAQC+AAEAE4EDoAAAABFesSAUpAABYWRuAQUA9IgQAAABAAEAAQABFAD1xBQAAAEAAQABAAEAAQUBsIAUXwABdjswAAABAAAHAAIA0REDAMITAwAjgAKwcBH2AAFiZFcCAAGGsMATjAABoKAAABOvoJAAABN4BeACOzAAAAEAAAUAAgAVBwMAARABAAEGAPPUEgAAAQCtAPOAA3J0dgEDADswAAABAAAHAAIAvhMDAKgUAwDzAAFzAWIUAADzAAFzAfgRAABHBQCAiKCAAAATOKAwAAAMQbBwFIEAAbAAE3MAAaAQAAAM6xNBDg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2caa3300cc72.js b/pr/720/docs/search.index/2caa3300cc72.js new file mode 100644 index 000000000..5b6abdea0 --- /dev/null +++ b/pr/720/docs/search.index/2caa3300cc72.js @@ -0,0 +1 @@ +rn_("AYkCsCAUcgABoDAAABR8aXATAAOgIAAAEy6ggAAAE0NlaXX1EAwAADoAAQABAAEAAYYCsJAUmgABoAAAABK6YmQBAgD0GgwAAAEAjgMBAAEAAPQ3CQAAAQABAAEAAQAAOzAAAAEAAAYAAgCPEwAA9xMFACOBArBAFG0AAWVz84ADZXh5AQAA9DMJAAABAAEAAQAjgAKwIBMiAAFyeEcBAADGsMATuwABoBAAABFysEAM5gABoDAAABD4AESAC/RwBQAAAQB7BwEA1wAAAIWgMAAAEGygMAAAE3oQARM6MAAAAQAAAAAACgAQAAAA+wj8CP0ILQkuCR8MhxCOEEkRShH+Eg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2ccce52d6bb9.js b/pr/720/docs/search.index/2ccce52d6bb9.js deleted file mode 100644 index eb0a2232b..000000000 --- a/pr/720/docs/search.index/2ccce52d6bb9.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9MsSAAABAKkAAQABCAD0ihMAAAEAhwABADMBA7BAE1kAAWFiZfX0DAAAAQBFA2kC1QABAAA7MAAAAQAABgACAC0MAQC4DwQA84ACc3UjgQKwgBOEAAFydAEGAPSFEAAAAQC3AAEAUwADsIATCQABYml09XoFAAABAOYOWAABAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2d153fd624bd.js b/pr/720/docs/search.index/2d153fd624bd.js new file mode 100644 index 000000000..cda6e7843 --- /dev/null +++ b/pr/720/docs/search.index/2d153fd624bd.js @@ -0,0 +1 @@ +rn_("AYACsRAUnAABsBAMUwABZW8BBQA7MAAAAQAADQABAJ0RDQABAgDzBxAAAAEAAQABAgD0AxAAAAEAAQABAAEDADswAAABAAAIAAEAuRAIAIcHAACHsKATxwABsNAUXQABoFAAABQojBQROzAAAAEAAAYAAwBWBwAA6hADALsSAQDzgQJsdPMAAWk7MAAAAQAAjgADAJwEAAD3EAAACRKMAAEFAPN/FAAAAQA8AAEAAaBAAAAQ+2XzBQkAAAEAogkTgAKgMAAAD95kcvMAAWXz7AYAAAEAAQDzgAJodAEBADswAAABAACNAAIA9xAAAAkSjAAjgAOwABAYAyCgUAAAECJnaXQBCAD0/RMAAAEAiwAFABMAhLDwFIEANLCQFGQAAbBQE0IBZkCJADswAAABAAASAAkAaRACAO4RAQAvEwEAUhMBAIkTAQDuEwEAJhQBADUUAQB2FAEA1wEAAIawgBG1AAGgQAAACSgIMCY6MAAAAQAAAAAADQAQAAAAkQCSAGAHagkDDA8NChELEZ4SnxImEycTuRO6Ew==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2d6225cca40e.js b/pr/720/docs/search.index/2d6225cca40e.js new file mode 100644 index 000000000..f275d2d8e --- /dev/null +++ b/pr/720/docs/search.index/2d6225cca40e.js @@ -0,0 +1 @@ +rn_("AQEAOzAAAAEAAAYAAQBlEQYAAQAA9x8JAAABAF0HAQBzAAEAFgEBggKgIAAAESigMAAAEY5pdPOAA2FncwEBAaBAAAAUO2XyaRQAAAEAI4ACsFAT8AABZnPzgAJpbw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2d9a6dddfba0.js b/pr/720/docs/search.index/2d9a6dddfba0.js deleted file mode 100644 index 5445c6f66..000000000 --- a/pr/720/docs/search.index/2d9a6dddfba0.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9L4RAAABAAEAAQDzAAFl9MQQAAABAAEAAQABAwD0uhEAAAEAAQABAMcAAACFsKATHAABsCAMJAABsIAS+gABCAwG8wUHAAABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/2dc983a2ccc0.js b/pr/720/docs/search.index/2dc983a2ccc0.js new file mode 100644 index 000000000..4e7c42a09 --- /dev/null +++ b/pr/720/docs/search.index/2dc983a2ccc0.js @@ -0,0 +1 @@ +rn_("AQoA9KUTAAABAA8AAQABgwKgIAAAEEygMAAAEOlpdAEAAPQPEwAAAQABAAEA8wQBZPSyEgAAAQABAAEAI4aEsKAUVwABsEATDQABsHAUAAABFYAAAQACsDAQPgABsBATvQABc3TzlwUAAIEGAQABgAKwwBSHAAGgAAAAB1B0efOAhRHBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2eec7becf814.js b/pr/720/docs/search.index/2eec7becf814.js deleted file mode 100644 index 157d704af..000000000 --- a/pr/720/docs/search.index/2eec7becf814.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQACoCAAABOSsDAR6gABaXTy9hIAAAEAAQMAOzAAAAEAAAYAAQBkEQYAAQgA9PwTAAABAIsABQATAQOwkBRjAAGwUBNBAWZnbHA7MAAAAQAAEgAJAGkQAgDtEQEALhMBAFETAQCIEwEA7RMBACUUAQA0FAEAdRQBAAGAArAwEeYAAbAwEegAAXJ2AQQBsAAStgABZDswAAABAAAFAAIA4hEDAOUSAQC3BQABh7BQErgBF7BgEz8AAZQJAzowAAABAAAAAAALABAAAADfDOAM4QybDpwODBGOEY8RkBGRETUTcBMjgAKgEAAADN5ubwEDAPNmEAAAAQABACOAAqAAAAAMDmRyYwCEoFAAABGLoDAAABCkFAEQ8pgHAAABAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2f9af585d36b.js b/pr/720/docs/search.index/2f9af585d36b.js new file mode 100644 index 000000000..e9b62166b --- /dev/null +++ b/pr/720/docs/search.index/2f9af585d36b.js @@ -0,0 +1 @@ +rn_("AQQA888RAAABAAEAAYICsEASyAABsEASygABNDYBCwDzyRMAAGoAAQABBgD0thQAAAEACgABAPMCAXIBEhQAAPMCAWU7MAAAAQAABQACAH8QAwAxEQEAE4ACoFAAABL+ZHTzAIQRAQH37xAAAAEAbwAdAAEAAQA8AQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/2fe26730b02a.js b/pr/720/docs/search.index/2fe26730b02a.js new file mode 100644 index 000000000..58e35991e --- /dev/null +++ b/pr/720/docs/search.index/2fe26730b02a.js @@ -0,0 +1 @@ +rn_("AQUAOzAAAAEAAAcAAwDMEQIAfxMBABUUAgABBADzzxEAAAEAAQAjAAKgYAAAEv5hcvPvEAAAAQDKAQGAAqEQAAAUpLCAFJoAAWl1NwQAgYexUBTBAAGgAAAAEM+wcBPfAAGhMAAAFLUKQBsjgAKgMAAAEptudg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3012000b3b33.js b/pr/720/docs/search.index/3012000b3b33.js deleted file mode 100644 index 50de0ad39..000000000 --- a/pr/720/docs/search.index/3012000b3b33.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYICoFAAABLioQAAABSYY3QjAAKwQA/RAAFldTswAAABAAA3ABYAxAYBANUMAQD2DAEA1g8BAFkQBQCPEAUADREBAGsRAQD8EQIA0BIDAAITBAAzEwEAOxMBAEoTAQDQEwEA4xMBAAEUAQAFFAEAKRQAAFQUAQBYFAEAdxQAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3041b5b08137.js b/pr/720/docs/search.index/3041b5b08137.js new file mode 100644 index 000000000..2a9822981 --- /dev/null +++ b/pr/720/docs/search.index/3041b5b08137.js @@ -0,0 +1 @@ +rn_("AQIA9LERAAABAAEAAQABCgD0wxMAAAEAAQABAPOBAm10AQYA83MRAAABAAEAAYICsGATSQABsNAUaQABaXITgAKwEAzpAAFlaQEFAPQGFAAAAQBOAAEA8wQBY/IIEwAAAQABBQDz2BIAAAEAAQDzggJmdAEAAbAAFGAAAWT0+wsAAAEAAQABAPOBAmVpNwYAAImxMBSKAAGgYAAAEXKgUAAAEQWwkBMZAAGwQBEBAAG1EAcBPBQAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3067b7ed1d8a.js b/pr/720/docs/search.index/3067b7ed1d8a.js deleted file mode 100644 index e5b0a2e90..000000000 --- a/pr/720/docs/search.index/3067b7ed1d8a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQcA9eATAAABAAEAeAABAAEHAPPKEAAAAQABAAGAAqAAAAAHWqAQAAAJCmR48wEBZfIcEAAAAQDnAAAAhbBgDOwAAbBADFwAATIIAfTLBAAAhQLdCQEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/306b2c075538.js b/pr/720/docs/search.index/306b2c075538.js new file mode 100644 index 000000000..bc6bd4143 --- /dev/null +++ b/pr/720/docs/search.index/306b2c075538.js @@ -0,0 +1 @@ +rn_("AYACsHAR3wABsCAP6gDxaHkBBQD0Bg0AAAEAQQMBAAEAAPRgDAAAAQABAG8AAQIAOjAAAAEAAAAAAAkAEAAAAN8P4A/WEJMR8RLyEvITeRSvFLAUAQMA8xsJAAABAAEA1wMAAIagQAAAEfoYQAc6MAAAAQAAAAAAFwAQAAAAaAdpB/MHKAlcCV0JBQ3ID8kP7Q+YEJ8QoBChEKIQ4hDjEBkRGhGWEvAT8RMbFBwU") \ No newline at end of file diff --git a/pr/720/docs/search.index/30db8ea8ec7f.js b/pr/720/docs/search.index/30db8ea8ec7f.js new file mode 100644 index 000000000..47a83c06e --- /dev/null +++ b/pr/720/docs/search.index/30db8ea8ec7f.js @@ -0,0 +1 @@ +rn_("AQADoKAAABRaoCAAABOTsDAR6wABZWl08vcSAAABAAEDADswAAABAAAGAAEAZREGAAEIAPT9EwAAAQCLAAUAEwEDsJAUZAABsFATQgFmZ2xwOzAAAAEAABIACQBpEAIA7hEBAC8TAQBSEwEAiRMBAO4TAQAmFAEANRQBAHYUAQABgAKwMBHnAAGwMBHpAAFydgECAbAAErcAAWQ7MAAAAQAABQACAOMRAwDmEgEAI4ECoJAAABRZaW8BBwD0dRQAAAwAIwARAHcLAAGIsFASuQEXsGATQAABlQkDOjAAAAEAAAAAAA4AEAAAAN8M4AzhDJsOnA7QENEQDBEwEY8RkBGREZIRNhNxEyOAAqAQAAAM3m5v") \ No newline at end of file diff --git a/pr/720/docs/search.index/313cbeca05af.js b/pr/720/docs/search.index/313cbeca05af.js deleted file mode 100644 index b7f81f8a4..000000000 --- a/pr/720/docs/search.index/313cbeca05af.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYADsAAT5gABsAAT6AABsHAUXwABNDZhAQQA9LUUAAABAAoAAQAjgQKgQAAAEV5tcAEBADswAAABAAAIAAMA1hIAAEwTAADCFAYAxwEAAMWgQAAAEFiggAAAErBABoAIOzAAAAEAABYACAD1DwEAFhEBAFoRAwDREQUAwhMDABEUAABvFAEApBQBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/32222f9e344c.js b/pr/720/docs/search.index/32222f9e344c.js deleted file mode 100644 index a0d067b6f..000000000 --- a/pr/720/docs/search.index/32222f9e344c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9CUTAAABAJIAAQABAgD0/hAAAAEAmgABAAEDAPRbEwAAAQCYAAEAAQIBoEAAABNGcjswAAABAAAHAAIA/BABAJMRBQDzAIQDQAg6MAAAAQAAAAAAFQAQAAAASgdLB0wH2A/ZD4UQhhCmEKcQPRE+EfAR8REjEyQTMBMxE0ITbRNuE7YTtxM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/3247e5fdd14a.js b/pr/720/docs/search.index/3247e5fdd14a.js new file mode 100644 index 000000000..532caabaf --- /dev/null +++ b/pr/720/docs/search.index/3247e5fdd14a.js @@ -0,0 +1 @@ +rn_("AQUA8x8TAAABAAEAAQAAOzAAAAEAAAUAAgD/CwMA9xEBAPMAAWT0/hAAAAEAmwABAFMAA7AwFFcAAWVwcvTkDwAAAQDvAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/325a13350a7a.js b/pr/720/docs/search.index/325a13350a7a.js deleted file mode 100644 index 284acd3c3..000000000 --- a/pr/720/docs/search.index/325a13350a7a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEAOzAAAAEAAAYAAQDCFAYA8wYBZfRvFAAAAQA0AAEAEwCEoCAAAAlbsEAUmwABsGAThwCJAQEJ83sQAAB5AgEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/327aa5bf1162.js b/pr/720/docs/search.index/327aa5bf1162.js new file mode 100644 index 000000000..f0be2debc --- /dev/null +++ b/pr/720/docs/search.index/327aa5bf1162.js @@ -0,0 +1 @@ +rn_("AQQBoFAAABRfcwGhEgAAAYICsEASyAABsEASygABNDYBCwDzyRMAAGoAAQABBgD0thQAAAEACgABAPMCAXIBEhQAAPMDAWU7MAAAAQAABQACAH8QAwAxEQEA84QDYWVpY4ADoFAAABSZY2V0") \ No newline at end of file diff --git a/pr/720/docs/search.index/330ed03d9762.js b/pr/720/docs/search.index/330ed03d9762.js deleted file mode 100644 index 5fc76432e..000000000 --- a/pr/720/docs/search.index/330ed03d9762.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYA9BYRAAABAL4AAQATgQOgAAAAEV6xIBSkAAFhZG4BBQD0iBAAAAEAAQABAAEUAPXEFAAAAQABAAEAAQABBQGwgBRfAAF2OzAAAAEAAAcAAgDREQMAwhMDACOAArBwEfYAAWJkVwIAAYawwBOMAAGgoAAAE6+gkAAAE3gF4AI7MAAAAQAABQACABUHAwABEAEAAQYA89QSAAABAK0AAQABoGAAAA/tcgGQBAAA1wEAgMWgMAAADA0AAIoK") \ No newline at end of file diff --git a/pr/720/docs/search.index/332ba6c0b552.js b/pr/720/docs/search.index/332ba6c0b552.js new file mode 100644 index 000000000..6688bff84 --- /dev/null +++ b/pr/720/docs/search.index/332ba6c0b552.js @@ -0,0 +1 @@ +rn_("AQUA9JUTAAABAAEAAQABAAD1egwAAAEAAQABAAEA84ACZ2sTgAKwsBPwAAFhbwGAAqAgAAAL+qBAAAAMM2V0AYUCsHAUGAABsDATbAABZXMTAAOwQA/UAAGgYAAAEY1iZXM7MAAAAQAAEgAEAKsFAQDGBgoAURABAKkQAwABAwD0bRAAAAEABAABAAEKAaBAAAAUZmXyihQAAAEAE4ACsGASuwABY2nzgAJkcvMAAmVvOzAAAAEAAAkAAgCaBwUA3QcDAAECAbAwEVkAAW47MAAAAQAACQABAPALCQDzgAJvdAEDADswAAABAADuAAIAdgcAAAIL7QABAgGgcAAAEgBpOzAAAAEAAAABAgB1BwAAAgr/ABOAAqBAAAAMMnJ1AQQA9EsTAAABAJgAAQABAwDz1RIAAAEArQDzgAJhb9cHAACIsEAM/AABsTAUhwABNIEWOzAAAAEAAB4ADQC/BAEAggUBAAUMAAA4DAcAXAwBAOYPAQDXEAEAZBEAALERAwD1EQEAsRIAABMTAQCtFAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/337314d00c2a.js b/pr/720/docs/search.index/337314d00c2a.js deleted file mode 100644 index 118f9ae55..000000000 --- a/pr/720/docs/search.index/337314d00c2a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEBoGAAABSYc/LbEQAAAQABCAD1QhQAAAEAAQABAAEAowCEsCAJcQABoIAAABLvMEAIOzAAAAEAAAUAAgDyAQAAmhAEAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/33a323740d96.js b/pr/720/docs/search.index/33a323740d96.js new file mode 100644 index 000000000..fe73b9256 --- /dev/null +++ b/pr/720/docs/search.index/33a323740d96.js @@ -0,0 +1 @@ +rn_("AQcA9JUTAAABAAEAAQDzBQF0OzAAAAEAAAgAAgAFDAAAOAwHAAEFAPOxEwAAAQABADcAAICFsDAQTQABoKAAABPPoDAAABQMEEFI") \ No newline at end of file diff --git a/pr/720/docs/search.index/33aa3ee11527.js b/pr/720/docs/search.index/33aa3ee11527.js new file mode 100644 index 000000000..9bb1e9104 --- /dev/null +++ b/pr/720/docs/search.index/33aa3ee11527.js @@ -0,0 +1 @@ +rn_("AQUA9IgQAAABAAEAAQABEwD1xRQAAAEAAQABAAEAE4ACoMAAABNNYW8BAgKgsAAAFFmgsAAAFFpjc/PQEAAAAQBfAAGBArBQEfMAAaDAAAAUKGhp84ACZWkjgAKwsBONAAFpdAEFAbCAFGAAAXY7MAAAAQAABwACANIRAwDDEwMAI4ACsHAR9wABYmR3AgAAhqCgAAATsKCQAAATeQXgAjswAAABAAAFAAIAFQcDAAEQAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/33ee246893ce.js b/pr/720/docs/search.index/33ee246893ce.js deleted file mode 100644 index 49bac9d04..000000000 --- a/pr/720/docs/search.index/33ee246893ce.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsHASmAABsCAUsgABaW8BAAGw8BSyAAFrOzAAAAEAAAgAAwAZFAAAHhQGAEgUAADzBQFk8toSAAABAAECAPPcEAAAAQABAPMAAWk6MAAAAQAAAAAABwAQAAAAthDvEt4T3xMOFA8ULxQwFCODArCwFI4AAWFzAYECoKAAABNHoEAAABB0b3bzgIQBUAE=") \ No newline at end of file diff --git a/pr/720/docs/search.index/33f1a0a10f2d.js b/pr/720/docs/search.index/33f1a0a10f2d.js new file mode 100644 index 000000000..3a87efda7 --- /dev/null +++ b/pr/720/docs/search.index/33f1a0a10f2d.js @@ -0,0 +1 @@ +rn_("AYMCsQAUvwABsNAUrwABa20BCwDzAhQAAAEAdQAzAoSgYAAAEpahAAAAFHoEgAM7MAAAAQAANAACAE8HAACgBzMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/340fac1d0ace.js b/pr/720/docs/search.index/340fac1d0ace.js new file mode 100644 index 000000000..14d3383cc --- /dev/null +++ b/pr/720/docs/search.index/340fac1d0ace.js @@ -0,0 +1 @@ +rn_("AQIAOzAAAAEAAAUAAQCTFAUA8w0BbTswAAABAAAFAAEATxQFAEMAhLAAFGAAAbBAEsQAAbAAE4gAiTgAAjswAAABAAAcAAcA+wsDADQRBwDoEgEAZxMEAEMUBABKFAMAuRQAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3461ae96092e.js b/pr/720/docs/search.index/3461ae96092e.js new file mode 100644 index 000000000..a80fcfa82 --- /dev/null +++ b/pr/720/docs/search.index/3461ae96092e.js @@ -0,0 +1 @@ +rn_("AQMA88ESAAABAAEAI4ECsSAUvQABY2sBBAGgQAAAEfpl8wUNAAAUBAEAAQAAOzAAAAEAAAUAAgDzEAMAjRMBAHOAhKAwAAAUOwgwAQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/34d17abef16f.js b/pr/720/docs/search.index/34d17abef16f.js deleted file mode 100644 index a9313f8c0..000000000 --- a/pr/720/docs/search.index/34d17abef16f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYECoBAAABNHoHAAABOPYWMBhwKwABPmAAGwABPoAAE0NlMAhKCQAAATb7CwFAwAAYEACfUkBwAANgA/CREBIAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/35454983f2d7.js b/pr/720/docs/search.index/35454983f2d7.js new file mode 100644 index 000000000..a028c0272 --- /dev/null +++ b/pr/720/docs/search.index/35454983f2d7.js @@ -0,0 +1 @@ +rn_("AQcA9qMTAAABAKoAWQAYAAEA8wEBaQFbCQAAAQAAOzAAAAEAAAUAAQBeCQUApwAAgMUwQbWwgTewYBQIAAGgEAAACTIAAiCK") \ No newline at end of file diff --git a/pr/720/docs/search.index/3545cf7f836f.js b/pr/720/docs/search.index/3545cf7f836f.js deleted file mode 100644 index 344bd9683..000000000 --- a/pr/720/docs/search.index/3545cf7f836f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA8x4TAAABAAEAAQAAOzAAAAEAAAUAAgD/CwMA9hEBAPMAAWT0/hAAAAEAmgABAFMAA7AwFFYAAWVwcvTkDwAAAQDvAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/358b5f8021f2.js b/pr/720/docs/search.index/358b5f8021f2.js deleted file mode 100644 index bdc66b3c7..000000000 --- a/pr/720/docs/search.index/358b5f8021f2.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9L4RAAABAAEAAQATAAKgMAAAEYlldPTEEAAAAQABAAEAAQMA9LoRAAABAAEAAQABgAKgAAAAEJWgAAAAEJY0NvMDAXYBAg0AAJcCAACIsKATHAABsCAMJAABsGATFgABsIAS+gABoCAAABEACUxGOjAAAAEAAAAAAAkAEAAAAAUHBgcHBzUM9w9fEakSqhKrEl4U") \ No newline at end of file diff --git a/pr/720/docs/search.index/358dcb9f0de5.js b/pr/720/docs/search.index/358dcb9f0de5.js deleted file mode 100644 index 7afd3ff68..000000000 --- a/pr/720/docs/search.index/358dcb9f0de5.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQAOjAAAAEAAAAAAAcAEAAAANgP2Q+mEKcQIxMkE7YTtxMBBAD02g8AAAEAAQABAAEAAqAQAAAMg7BQFAMAAWlv8ikJAAABAPOAA2Vpbw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/36ce02943eb1.js b/pr/720/docs/search.index/36ce02943eb1.js deleted file mode 100644 index 594b1868a..000000000 --- a/pr/720/docs/search.index/36ce02943eb1.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEBoEAAABGJc/U1DAAAKgVKAQEAAQATggKgIAAADQxlcgECAPTuDwAAAQD3AAEAI4ECoBAAAAw0ZWkTgAKg8AAAFChucjMAA7AwCSYAAWVvdAHdEQAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/36f320f1ba81.js b/pr/720/docs/search.index/36f320f1ba81.js new file mode 100644 index 000000000..8565c98e9 --- /dev/null +++ b/pr/720/docs/search.index/36f320f1ba81.js @@ -0,0 +1 @@ +rn_("AQEBsFAP1gABY/SjBAAAAQABAMcAAQABoIAAABS5ZgGZEwAA8wYBc/IEDQAAmAQzAAOgYAAAFJljaXPy3BEAAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/378b1aab08c9.js b/pr/720/docs/search.index/378b1aab08c9.js deleted file mode 100644 index b18d85209..000000000 --- a/pr/720/docs/search.index/378b1aab08c9.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBoEAAABGCZQHGDwAAAQIA8y8MAAABAAEAIwACsCAMHQABa3L28AYAAAEAFArtAAEANALzAAJyePLvCAAAAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/378be24803ea.js b/pr/720/docs/search.index/378be24803ea.js new file mode 100644 index 000000000..59f096c3d --- /dev/null +++ b/pr/720/docs/search.index/378be24803ea.js @@ -0,0 +1 @@ +rn_("AQAA9iERAAABAJQDAQAKAAEAAQAAOzAAAAEAAAYAAgCPEwAA9xMFACOIArBAFG0AAWVzAQ0BsEAUZwABZfUrFAAAAQABAAEAAQABBQA7MAAAAQAACAADAP0RAgADEwQAKhQAANcBAACFK7ftx0E1FIQC88sMAAABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/38509af683de.js b/pr/720/docs/search.index/38509af683de.js new file mode 100644 index 000000000..eced03c24 --- /dev/null +++ b/pr/720/docs/search.index/38509af683de.js @@ -0,0 +1 @@ +rn_("AQAA9HsTAAABAAEAAQATAAKwgBNPAAFzdvRtCQAAAQCSCgEAE4ACsDARDQABbG4BgAKgAAAAEJWgAAAAEJY0NvMDAXYBAg0AABMAAqBAAAARimFz9zUMAADCA2kBSgEBAAEAswEBAgD0JhMAAAEAkgABAAEDAPRcEwAAAQCYAAEA8wACYnU6MAAAAQAAAAAAEwAQAAAASgdLB0wH2A/ZD4UQhhCmEKcQPhE/EfER8hEkEyUTMRMyE0MTtxO4E/OAAmR0E4ACoCAAAA0MZXIBBwGgQAAAFDtl8mkUAAABAAEBADswAAABAAAFAAEAXgkFAEcAAACFsDAPrwABoFAAABB4sHARBgABsUAUwwABgSkA8nYFAAABAPOAAmx0lwEAgIaxMBQ9AAGxEBRrAAGgsAAAE14RRQg=") \ No newline at end of file diff --git a/pr/720/docs/search.index/388d28ec6ee7.js b/pr/720/docs/search.index/388d28ec6ee7.js deleted file mode 100644 index 9b37bdee1..000000000 --- a/pr/720/docs/search.index/388d28ec6ee7.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQoBoIAAABS4ZgGYEwAAAQgA9UIUAAABAAEAAQABAPMDAWb1mhAAAAEAAQABAAEA84MCYXMBAgKgIAAAEd2gMAAAEqhiaAHKDwAAI4ACoIAAABNMYXDzAAJobQGmBAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/398edce99fb2.js b/pr/720/docs/search.index/398edce99fb2.js new file mode 100644 index 000000000..f14ee888c --- /dev/null +++ b/pr/720/docs/search.index/398edce99fb2.js @@ -0,0 +1 @@ +rn_("AQABsGAUDwABZQFIFAAAAQYA9DoTAAABAFEBAQABBAD0VBMAAAEADwEBAPMAA2VyczowAAABAAAAAAAJABAAAAAjCSQJJQlGEYURmRKaEqcSCBQJFA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/39cd5ed38a87.js b/pr/720/docs/search.index/39cd5ed38a87.js new file mode 100644 index 000000000..63778931b --- /dev/null +++ b/pr/720/docs/search.index/39cd5ed38a87.js @@ -0,0 +1 @@ +rn_("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") \ No newline at end of file diff --git a/pr/720/docs/search.index/3a72e593e0b3.js b/pr/720/docs/search.index/3a72e593e0b3.js new file mode 100644 index 000000000..c1ac73377 --- /dev/null +++ b/pr/720/docs/search.index/3a72e593e0b3.js @@ -0,0 +1 @@ +rn_("AQAA9HsTAAABAAEAAQDzBgFz8gAUAAABAAEBAbBQEvkAAWX3EwkAAFQDAQARBAEA3QMBAAEDAPS/EQAAAQABAAEAAQMA9LsRAAABAAEAAQDzgwJsc/OAAmN0U4ADoBAAAAzKYW9y") \ No newline at end of file diff --git a/pr/720/docs/search.index/3a8f25986add.js b/pr/720/docs/search.index/3a8f25986add.js deleted file mode 100644 index 8aba7e1e3..000000000 --- a/pr/720/docs/search.index/3a8f25986add.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMAOzAAAAEAAEQAAgAeCQAAhAxDAAEFAPTEEAAAAQABAAEAE4ACsLATpAABYWwBBAD0sQ8AAAEAAQABAHMABKAQAAAQeGJwcnY7MAAAAQAACgACAGQRBgC6EQMAAYACsIAREwIjsOAUDAABaXIBAwGwQBFhAAFlAZUOAAABBQA7MAAAAQAABgABAF8QBgABAwA7MAAAAQAABQABANcMBQDzAAJwczowAAABAAAAAAANABAAAACpBaoFwQYSCVkMZgwGEQcRthK3Eg4TDxMQExETVwAAAIWwUBC2AjmwUA/QANOgQAAAEYxIgAM7MAAAAQAADwAGAKIEAABoBQMAvQ8AAOIRAwCxEgMA5RIBANMAhKBgAAAM6xAIBvOvAQAAAQAaCw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3ad93ce64a37.js b/pr/720/docs/search.index/3ad93ce64a37.js deleted file mode 100644 index 14c18044e..000000000 --- a/pr/720/docs/search.index/3ad93ce64a37.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEAOjAAAAEAAAAAAAcAEAAAAFETUhPtE+4TJRQmFHUUdhTzBgFpAXATAABDgAOwABSwAAGwUBNFAFpkZm4BAAGwQBMcAAFlOzAAAAEAAA0AAgDRBgwAEBEAACOAAqAwAAAMEWFlNwAAgMWwUBOZAAGwEBQ+AAGwYBOgAAEAApgI") \ No newline at end of file diff --git a/pr/720/docs/search.index/3aff0f2fea02.js b/pr/720/docs/search.index/3aff0f2fea02.js new file mode 100644 index 000000000..7890a9e01 --- /dev/null +++ b/pr/720/docs/search.index/3aff0f2fea02.js @@ -0,0 +1 @@ +rn_("AQEAOjAAAAEAAAAAAAkAEAAAAN8P4A/WEJMR8RLyEvITeRSvFLAUAYACsOAT7AABsDAUBAABZHDDgISxQBTBAAGgkAAAE7ACgAk=") \ No newline at end of file diff --git a/pr/720/docs/search.index/3b0d86fd7fb4.js b/pr/720/docs/search.index/3b0d86fd7fb4.js deleted file mode 100644 index cdce689dd..000000000 --- a/pr/720/docs/search.index/3b0d86fd7fb4.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYkCsCAUcQABoDAAABR7aXATAAOgIAAAEy2ggAAAE0JlaXX1EAwAADoAAQABAAEAAYYCsJAUmQABoAAAABK5YmQBgAKwMBMhAAGgMAAAEPhydtcAAAKFoDAAABBsoDAAABN5EAETOjAAAAEAAAAAAAkAEAAAAPsI/Aj9CC0JLgmHEI4QSBFJEf0SAQMBsDATPQABc/PKEAAAAQABAAEAADswAAABAAAKAAMAchECAL4TAwCoFAMAlwEAAIWgIAAABbGwIAf/AAFQGAH1egwAAAEAAQABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/3b2c7cca574a.js b/pr/720/docs/search.index/3b2c7cca574a.js deleted file mode 100644 index 4c0258c35..000000000 --- a/pr/720/docs/search.index/3b2c7cca574a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIAOzAAAAEAAO4AAgAMDAAAGA3tAPMAAW07MAAAAQAA7gACAKMFAADNBe0AAQMAOzAAAAEAAAgAAgCiDwYAXhMBAPMAAWM7MAAAAQAAVwAnAKgECwBvBQAADgkBACcMAQAvDAIA7wwAAPsMAgANDQEAzA8AANEPAQDUDwEA3g8AAGYQAgBtEAEAchABAJcQAAAPEQAAFREAAGERAQBuEQEAghEBAIYRAgDmEQEA+RECAP8RAAC1EgAAvhIBAMMSAQAMEwEAHBMBACETAQBDEwEAUxMDAFkTAQC6EwEAzhMAADoUAABjFAQAbBQCAPOAAnJ3AQkA834UAAABADwAAYACoEAAABNdsCAUGgABaGkBAQDz+Q8AAAEAAQATgAKwwBS5AAF0dQGBArCAFJAAAaBgAAAUt2RzNwMAgYagQAAAFGGwYBQxAFICkA4BiAKwABPmAAGwABPoAAE0NjOAA6AwAAARhWRuc2MAA6AQAAAEy2FlbwGGAAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/3b43efdb153b.js b/pr/720/docs/search.index/3b43efdb153b.js new file mode 100644 index 000000000..0fc010ece --- /dev/null +++ b/pr/720/docs/search.index/3b43efdb153b.js @@ -0,0 +1 @@ +rn_("AQMBoEAAABH6ZfMFDQAAFAQBAAEGAPQWEQAAAQC/AAEAE4EDoAAAABFfsSAUpQABYWRuAYABJM925m2aZQEGAPPVEgAAAQCtAPOAA3J0dgEDADswAAABAAAHAAIAvxMDAKkUAwDzAAFzAWMUAADzAAFzAfkRAABHBQCAiKCAAAATOaAwAAAMQbBwFIIAAbAAE3QAAaAQAAAM6xNBDg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3b53b2390177.js b/pr/720/docs/search.index/3b53b2390177.js new file mode 100644 index 000000000..6fa9af9e4 --- /dev/null +++ b/pr/720/docs/search.index/3b53b2390177.js @@ -0,0 +1 @@ +rn_("AQgA9HUQAAABALQAAQABAAGggAAAFLlm8voIAACfCgEHAPVnEwAAAQABAAEAAQAjgAKgUAAAEWRhb/MCAmZzOzAAAAEAAAgABABNBwAAfgcFAAQNAACcEQAAM4ADoEAAAAwNYWVv") \ No newline at end of file diff --git a/pr/720/docs/search.index/3b91ca3f9acb.js b/pr/720/docs/search.index/3b91ca3f9acb.js new file mode 100644 index 000000000..738d9dc05 --- /dev/null +++ b/pr/720/docs/search.index/3b91ca3f9acb.js @@ -0,0 +1 @@ +rn_("AQIA9awRAAABAAEAAQABAAGAArBgExcAAaAgAAARAG95AQABoMAAABQ8afRwEwAACAAcABsAAQUA9KkUAAABAAEAAQATgAKwcBSCAAFlaQECAPT+EAAAAQCbAAEAAQIBoEAAABNHcjswAAABAAAHAAIA/BABAJQRBQDzgAJhb2cDAACGsIATRgBasKATvQABDDAGOzAAAAEAAAgAAwAcDAAAxxEDAK0SAwDzgAJlaQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3bfe87876fca.js b/pr/720/docs/search.index/3bfe87876fca.js deleted file mode 100644 index b060cd394..000000000 --- a/pr/720/docs/search.index/3bfe87876fca.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBgBOAABD4czswAAABAAAFAAEAYBMFACOCAqCQAAAUYmlzAQEA9CUTAAABAJIAAQAjgAKwoBQMAAFjbgGEArCgFBoAAbCgFBwAAWNyAQIAOzAAAAEAAAYAAQBfEAYAE4ICoCAAABP+ZXUBAgDzzhEAAAEAAQABgAKwIBQ+AAGgYAAAE49vdmOBA6AQAAATR2FjcwEDADswAAABAAAFAAEA1wwFAAEBAPMbCQAAAQABAAEBAPT+EAAAAQCaAAEAU4ADoMAAABRubnB1AYACsDAQHAABoWAAABSnYWUBgQKwQBLHAAGwQBLJAAE0NgEFAaBQAAAUJ2jyuhIAAAEAAQUA9HUQAAABALMAAQBzgISwMBNzAAEBoAQBCADzbxMAAAgAHAATgAKwQBHyAAFhZQEKAPPIEwAAagABAAEAAaAgAAAQl3IBYBEAAAEAAPTMEwAAAQBKAAEApwEAgIWgMAAAEPugEAAAERsJICEBCQGgQAAAFGVl8okUAAABAEOAhKAgAAAUc6CQAAATy6EwAAAUiBBJAAECAPRbEwAAAQCYAAEAE4ACsEATJwABaXkBAQKgMAAAEv2gQAAAE0ZncjswAAABAAAHAAIA/BABAJMRBQABgAKwABPmAAGwABPoAAE0NgEGAPS1FAAAAQAKAAEA8wICcnYBERQAAPMCAWU7MAAAAQAABQACAH8QAwAwEQEA84ACZHTn1x8AEaAwAAARHLDwFLIAAbBwE5AAATBhYmNlaGlrbG5vcHJzdHV2OzAAAAEAABgBRADDBAAAqQUBALEFAACzBQEAwQYAACQHAABKBwIAWgcAAGwHBQBzBwAA1AcAAPkHAQD/CAEABQkBABIJAABxCQEAdQmMAP8LAwAODAAAEgwDACAMAABZDAAAZgwAAK0PAQDYDwUAWBAAAIUQAQCZEAAAphABAO8QAQDzEAMABhEBAD0RAQBeEQAAexECAKoRAADKEQAA7BEAAPARAQD2EQEAAhIEAKcSAAC2EgEAuRIAAMUSAQDXEgIADhMDACMTAQAwEwEAORMBAD8TAQBCEwAARRMAAFcTAABtEwEAjBMBAJsTBAC2EwEAyRMBAMwTAQDSEwEA3RMAABcUAgAeFAYAPBQBAEgUAABfFAEAixQBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3c0a881cec02.js b/pr/720/docs/search.index/3c0a881cec02.js new file mode 100644 index 000000000..4ed52a396 --- /dev/null +++ b/pr/720/docs/search.index/3c0a881cec02.js @@ -0,0 +1 @@ +rn_("AQUA9AYUAAABAE4AAQDzBAFj8ggTAAABAAEFAPPYEgAAAQABAPOCAmZ0AQABsAAUYAABZPT7CwAAAQABAAEA84ACZWkTgAKw4BRrAAF0dg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3c4d6a050636.js b/pr/720/docs/search.index/3c4d6a050636.js deleted file mode 100644 index 19633e0e1..000000000 --- a/pr/720/docs/search.index/3c4d6a050636.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMA82YQAAABAAEAAYACoLAAABQnsDATcwABbnRDAAOgIAAAERuwUBHyAAFlaGk7MAAAAQAABgADAA4MAAADEgMA0hMBAPOAAmRy") \ No newline at end of file diff --git a/pr/720/docs/search.index/3d9548e24189.js b/pr/720/docs/search.index/3d9548e24189.js deleted file mode 100644 index 7278d3ef3..000000000 --- a/pr/720/docs/search.index/3d9548e24189.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMA9H8MAAABAAEAAQABAAGwUBQ+AAFyAcMEAABTAYSwQBK+AAGwQBR8AAGYAAQ6MAAAAQAAAAAAKAAQAAAAjQSOBI8EmAUMCQ0JMglmCdQMyw8+ED8QTBB8ENwQ3RDeECcRnxL+Ev8SABMBEy0TPRM+E2sTbBPbE9wT4BPhE+IT8hPzE1oUWxRxFHIUmRSaFA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3d985c0366b5.js b/pr/720/docs/search.index/3d985c0366b5.js deleted file mode 100644 index 33d986a30..000000000 --- a/pr/720/docs/search.index/3d985c0366b5.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsHARdwABsCAUXAABYWQBBQD0ShMAAAEAmAABAPMAAWMBsBIAAEOAA7AwE6AAAbCgFD4AAWFzeQEGAPQWEQAAAQC+AAEAk4CEoAAAABFesSAUpAABCSAB84ACZWk=") \ No newline at end of file diff --git a/pr/720/docs/search.index/3e4ccfb55bfa.js b/pr/720/docs/search.index/3e4ccfb55bfa.js new file mode 100644 index 000000000..73ba64521 --- /dev/null +++ b/pr/720/docs/search.index/3e4ccfb55bfa.js @@ -0,0 +1 @@ +rn_("AQIAOjAAAAEAAAAAAA4AEAAAAA0NDg0VEfoR+xH8EbYSvxLAEsQSxRIdEx4TVhNXEwEJAPN8EQAAAQABAAEKAPPOEgAAAQABAAEGAPVAEQAAAQABAAEAAQDzgAJkbnMAhLEgFD8AAQARA/IoEwAAAQABDQD2oxMAAAEAqgBZABgAAQABgAKwoBO7AAGgEAAADDZjdQEBAPTNEwAAAQBKAAEA8wABZfJxCQAAAQD3AACAxbAwELcAAQACqAg=") \ No newline at end of file diff --git a/pr/720/docs/search.index/3e66de6aea10.js b/pr/720/docs/search.index/3e66de6aea10.js deleted file mode 100644 index 1fac986e4..000000000 --- a/pr/720/docs/search.index/3e66de6aea10.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYQCsAARfgABsAARgAABNDbzAgFh8nUMAAABAAEAAPbFEgAAAQBzAAEAUQEBAPMAAWTz1BIAAAEArQBjgAOgIAAACPlhZW8=") \ No newline at end of file diff --git a/pr/720/docs/search.index/3e70f6735510.js b/pr/720/docs/search.index/3e70f6735510.js new file mode 100644 index 000000000..ec9e36c4a --- /dev/null +++ b/pr/720/docs/search.index/3e70f6735510.js @@ -0,0 +1 @@ +rn_("AQoBoIAAABS5ZgGZEwAAAQgA9UMUAAABAAEAAQABAPMDAWb1mhAAAAEAAQABAAEA84MCYXMBAgKgIAAAEd6gMAAAEqliaAHKDwAAI4ACoIAAABNNYXDzAAJobQGmBAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/3e7e25ece402.js b/pr/720/docs/search.index/3e7e25ece402.js new file mode 100644 index 000000000..618d44276 --- /dev/null +++ b/pr/720/docs/search.index/3e7e25ece402.js @@ -0,0 +1 @@ +rn_("AQMA9H8MAAABAAEAAQABAAGwUBQ/AAFyAcMEAABTAYSwQBK/AAGwQBR9AAGYAAQ6MAAAAQAAAAAAKAAQAAAAjQSOBI8EmAUMCQ0JMglmCdQMyw8+ED8QTBB8ENwQ3RDeECgRoBL/EgATARMCEy4TPhM/E2wTbRPcE90T4RPiE+MT8xP0E1sUXBRyFHMUmhSbFA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3e845aeac648.js b/pr/720/docs/search.index/3e845aeac648.js new file mode 100644 index 000000000..3f22110c9 --- /dev/null +++ b/pr/720/docs/search.index/3e845aeac648.js @@ -0,0 +1 @@ +rn_("AQEAOjAAAAEAAAAAAAgAEAAAAAkJdxAjESQRJRH9E/4TiRSOFAECAPSyEAAAAQABAAEAE4ACoNAAABR0Y3NTgAOgcAAAFG9laW+DgISwIBOhAAGgIAAAD+uwAAdSAAEKCAQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/3ea7fcccf5b3.js b/pr/720/docs/search.index/3ea7fcccf5b3.js deleted file mode 100644 index acf8d196b..000000000 --- a/pr/720/docs/search.index/3ea7fcccf5b3.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABoLAAABPOYvNYEwAALgEBAAGAAqAgAAAPz6AwAAAT2mFy8wABdAF9BwAAAQQBoEAAABRlZfKJFAAAAQABBQA7MAAAAQAACwAFAFkQBQDQEgEAARQBAFgUAAB3FAAA4wGEoDAAAA/NhQACOzAAAAEAAAsABQCmBQIAvAYEAFcMAQCLEQAA4hIAAGOAA6AAAAATV2Rucg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/3ebb6f16d447.js b/pr/720/docs/search.index/3ebb6f16d447.js deleted file mode 100644 index 9e9672863..000000000 --- a/pr/720/docs/search.index/3ebb6f16d447.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQ0A9eATAAABAAEAeAABAAECAPQKEQAAAQCSAQEAAQMA9HURAAABAHwBAQDzAAJidQEbEAAAAQMA9AgRAAABAJIBAQDzhAJkcwECAPMMCQAAAQBZAPOAAml0ARgA88YUAAABAAEAI4ECsMAT3gABY20BBQGwYBLFAAFy9CEMAAABAPcDAQABCQD28BIAAAEAAAGHADYAAQATgAKwYBDIAAFkbgEDAaBwAAATLWf0WwcAAAEACAIBAAEJAPN+FAAAAQA8AAGBArCAFJAAAaBgAAAUt2RzFwEAiYWw0BS5AAGgQAAAFGGwYBQxAFICkApnugAAjLBwES0AAbCwEz0AAaCgAAAS77FQFLAAAbDwFA4AAW3BD/SHAAAAAQABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/3f573bc8125f.js b/pr/720/docs/search.index/3f573bc8125f.js new file mode 100644 index 000000000..a62ba4331 --- /dev/null +++ b/pr/720/docs/search.index/3f573bc8125f.js @@ -0,0 +1 @@ +rn_("AQIA9CYTAAABAJIAAQABAwD0XBMAAAEAmAABAPMCAmJ1OjAAAAEAAAAAABMAEAAAAEoHSwdMB9gP2Q+FEIYQphCnED4RPxHxEfIRJBMlEzETMhNDE7cTuBM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/7ce496ab7c6d.js b/pr/720/docs/search.index/3f5aea27f45d.js similarity index 55% rename from pr/720/docs/search.index/7ce496ab7c6d.js rename to pr/720/docs/search.index/3f5aea27f45d.js index 9a7f53b0b..fc0e7207a 100644 --- a/pr/720/docs/search.index/7ce496ab7c6d.js +++ b/pr/720/docs/search.index/3f5aea27f45d.js @@ -1 +1 @@ -rn_("AYECsDAQPgABsBATvAABc3QBAwDzzRIAAAEAAQAjgAKwABHEAAFoaQEAADswAAABAAATAAEAhAcTACOAAqAwAAAM3WFl84ACcnTzAAJhbDswAAABAAAoAAMAmgATAK4BAAAlEBMA") \ No newline at end of file +rn_("AYECsDAQPgABsBATvQABc3QBAwDzzhIAAAEAAQAjgAKwABHFAAFoaQEAADswAAABAAATAAEAhAcTACOAAqAwAAAM3WFl84ACcnTzAAJhbDswAAABAAAoAAMAmgATAK4BAAAlEBMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/3f5c2e66fd15.js b/pr/720/docs/search.index/3f5c2e66fd15.js new file mode 100644 index 000000000..c515cce18 --- /dev/null +++ b/pr/720/docs/search.index/3f5c2e66fd15.js @@ -0,0 +1 @@ +rn_("AQkA838UAAABADwAAYADoEAAABNesCAUGwABoCAAAA/TaGl5AQkBoIAAABS5ZgGZEwAAAQMBsAAUMgBSc/KtEAAALgMjgAKgIAAAD89hcgECAPXcEAAAAQABAGACAQDzAANpdHU6MAAAAQAAAAAAEAAQAAAAfQcsCfMMORC2EPASKhMrE98T4BPmEw8UEBQwFDEUhRSGFAGAAqAwAAAUYrCwE7UAAWFsAQEA8/kPAAABAAEAE4ACsMAUugABdHUBAwDzwRIAAAEAAQABAQD1QBEAAAEAAQABAAEAQ4ADsJAUCAABoEAAABEgYWN0AQQBoEAAABRmZfKKFAAAAQABAgA7MAAAAQAACwAFAFkQBQDREgEAAhQBAFkUAAB4FAAAE4ICsPAUvQABZmcBgQKwgBSRAAGgYAAAFLhkcwEIAPVDFAAAAQABAAEAAQDzAgFm9ZoQAAABAAEAAQABACOAA6AgAAAPzbCgFI8AAWRydHfvAQCNsBAUPQABsOAUPwABl9UOOzAAAAEAADoBEwCHBAEAtAQCAKYFAgC8BgQA7gcBACkMAwBXDAEA5AwBAJ0OBAHwDwEAtxABAMoQAgD4EAEAjBEAAL8RAwDpEQEA4xIAAKcTBwCeFAUA") \ No newline at end of file diff --git a/pr/720/docs/search.index/3f639926587b.js b/pr/720/docs/search.index/3f639926587b.js deleted file mode 100644 index 98985247f..000000000 --- a/pr/720/docs/search.index/3f639926587b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQA9K4QAAABAAEAAQABAAA6MAAAAQAAAAAACgAQAAAA5g/nD9cQ2BBjEfQR9RESExMTrBStFPMBAXnyDBQAAAEAAQADoKAAABRZoCAAABOSsDAR6gABZWl08vYSAAABAAEDADswAAABAAAGAAEAZBEGAAEIAPT8EwAAAQCLAAUAEwEDsJAUYwABsFATQQFmZ2xwOzAAAAEAABIACQBpEAIA7REBAC4TAQBREwEAiBMBAO0TAQAlFAEANBQBAHUUAQABgAKwMBHmAAGwMBHoAAFydgECAbAAErYAAWQ7MAAAAQAABQACAOIRAwDlEgEAI4ECoJAAABRYaW8BBwD0dBQAAAwAIwARAHcWAAGJsFAUDAABsFASuAEXsGATPwABtQkDOjAAAAEAAAAAAA4AEAAAAN8M4AzhDJsOnA7QENEQDBEvEY4RjxGQEZERNRNwE0OAA6AgAAAM0aAQAAAM3m1ubwEDAPRmEAAAAQABABoBAYACoLAAABQnsDATcwABbnRDAAOgIAAAERuwUBHyAAFlaGk7MAAAAQAABgADAA4MAAADEgMA0hMBAPOAAmRyhwsAAAqAAfgAEAGAAfsAEAGgUAAAEYugUAAAFF6gMAAAEJmgMAAAEKQwMWNlaW9zdHV39ZgHAAABAC0I2gJeAQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4084c65e327d.js b/pr/720/docs/search.index/4084c65e327d.js new file mode 100644 index 000000000..cd3290566 --- /dev/null +++ b/pr/720/docs/search.index/4084c65e327d.js @@ -0,0 +1 @@ +rn_("AQUAOzAAAAEAAAYAAQBfEAYAAQMAOzAAAAEAAAUAAQDXDAUAYwADoJAAABN4aHBzOjAAAAEAAAAAAA8AEAAAAKkFqgXBBhIJWQxmDAYRBxG3ErgSDxMQExETEhNAE0ET") \ No newline at end of file diff --git a/pr/720/docs/search.index/40fbc4e3aee2.js b/pr/720/docs/search.index/40fbc4e3aee2.js deleted file mode 100644 index 878137268..000000000 --- a/pr/720/docs/search.index/40fbc4e3aee2.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIBoQAAABSAZPJgBwAACgIBBgGgMAAAEe90Aa8TAAABAwGwUBL4AAFl9RMJAABUAwEAEQQBAAEBAaEAAAAUdGTysgUAAD4CFwcAAIewoBL2AAGg4AAAFEewEAWzAAEegArzYgQAAAEAAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4167a805d71e.js b/pr/720/docs/search.index/4167a805d71e.js new file mode 100644 index 000000000..7ab0debf5 --- /dev/null +++ b/pr/720/docs/search.index/4167a805d71e.js @@ -0,0 +1 @@ +rn_("AQgA9UMUAAABAAEAAQABAPMAAWY7MAAAAQAABQACAPIBAACaEAQAAQIAOzAAAAEAAAsAAgDVEwUAkxQFAPMGAW07MAAAAQAADQAEANAMAABuEQAA6hIFAE8UBQBjgAOwAAkhAAFlbXM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4167ad16be7b.js b/pr/720/docs/search.index/4167ad16be7b.js new file mode 100644 index 000000000..30ff07928 --- /dev/null +++ b/pr/720/docs/search.index/4167ad16be7b.js @@ -0,0 +1 @@ +rn_("AYQCoCAAABEooDAAABGOaXQBAQA7MAAAAQAAjQACAHMHAAB1CYwA8wACZWz1twQAAMACzglVAgEAAQIAOzAAAAEAAO4AAgAMDAAAGA3tAMcAAACFsLATRAABsBATygABsDANFgABFDACOzAAAAEAABoBCwDgAQYAowUAAM0F7QBCBwcAQxACAJ0RDQDMEQIApRIBACwTAQB/EwEAFRQCAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4177e23c85bd.js b/pr/720/docs/search.index/4177e23c85bd.js deleted file mode 100644 index 228db7e24..000000000 --- a/pr/720/docs/search.index/4177e23c85bd.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsHAS2gABoLAAABQZZW8jAQOwcBIAAAGAE4AAEPhtbnM7MAAAAQAAGgAGAGoHAQDxCAUACA0BAE4RCQCMEQAAYBMFAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/41e0f1bd02bf.js b/pr/720/docs/search.index/41e0f1bd02bf.js new file mode 100644 index 000000000..9bbf01738 --- /dev/null +++ b/pr/720/docs/search.index/41e0f1bd02bf.js @@ -0,0 +1 @@ +rn_("AQABoEAAABCtdPfzDAAARgPxAgEAuwCfAAEA8wABczswAAABAAAcAAgAtAQCACkMAwDwDwEAtxABAPgQAQDpEQEApxMHAJ4UBQAjgAKxEBSlAAFhdA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4273cf82f9c4.js b/pr/720/docs/search.index/4273cf82f9c4.js new file mode 100644 index 000000000..5bb6aa686 --- /dev/null +++ b/pr/720/docs/search.index/4273cf82f9c4.js @@ -0,0 +1 @@ +rn_("AQUA9AYUAAABAE4AAQDzAwFj8ggTAAABACOAArBwFL0AAWhvAYICsAAS5AABsAAR6wABZXNDAAOgoAAAFFqgIAAAE5NlaXTy9xIAAAEAAQIAOzAAAAEAAAYAAQBlEQYAAQIBoEAAABQ7ZfJpFAAAAQDzgAJpbwEIAPT9EwAAAQCLAAUAEwEDsJAUZAABsFATQgFmZ2xwOzAAAAEAABIACQBpEAIA7hEBAC8TAQBSEwEAiRMBAO4TAQAmFAEANRQBAHYUAQABgAKwQBK5ARegIAAAESlhaQEDAPPYEgAAAQABACOBArAwFA0AAWNpAQAA9CoTAAABAFoBAQDzAwFzOzAAAAEAAA8AAwDpEQEApxMHAJ4UBQABAwD15xEAAAEAJQEBAGEB84ACcnYBAAA7MAAAAQAABQACALcSAQAPEwMA8wIBZDswAAABAAAJAAMA4xEDALISAwDmEgEAI4ACoJAAABRZaW8TgAKw8BStAAFsbwEFAPR1FAAADAAjABEAI4ACoGAAABOHZ3MjgAKwkBRXAAFibPfHAACNsGAUjwABsHAUAAABsGATQAABsFATLAABtckXOjAAAAEAAAAAACIAEAAAALUFAQkvCV4MXwzfDOAM4QyWDpcOmA6ZDpsOnA78D/0P/g//DwAQ0BDREAwRMBGPEZARkRGSEeERNhNPE1ATcRMpFIIUgxQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/428750539964.js b/pr/720/docs/search.index/428750539964.js new file mode 100644 index 000000000..7eeb7a043 --- /dev/null +++ b/pr/720/docs/search.index/428750539964.js @@ -0,0 +1 @@ +rn_("AQcAOzAAAAEAAI0AAgD3EAAACRKMAAEDADswAAABAACMAAEACA6MAAECADswAAABAAAHAAEAQgwHAPMAA2JpdDswAAABAACNAAIAoQQAANsEjAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/42d2406e1020.js b/pr/720/docs/search.index/42d2406e1020.js new file mode 100644 index 000000000..eb285eb87 --- /dev/null +++ b/pr/720/docs/search.index/42d2406e1020.js @@ -0,0 +1 @@ +rn_("AQUAOzAAAAEAAAcAAwDMEQIAfxMBABUUAgABBwD2oxMAAAEAqgBZABgAAQABBADzzxEAAAEAAQAjAAKgYAAAEv5hcvPvEAAAAQDKAQGAAqEQAAAUpLCAFJoAAWl1dwgAAIixUBTBAAGgAAAAEM+wcBPfAAGhMAAAFLUKQRvyWwkAAEoHAYECoFAAABEUoKAAABNRa3ABAwA7MAAAAQAABgECAOQMAQCdDgQB84ACbHTzgAJhZQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/42d3b763f13b.js b/pr/720/docs/search.index/42d3b763f13b.js deleted file mode 100644 index d7406b0ec..000000000 --- a/pr/720/docs/search.index/42d3b763f13b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYICsEAUYwABsGATOQABZXIBBQD0nxAAAAEAAQABAPOAAmZtAQYAOjAAAAEAAAAAAAgAEAAAAN8P4A+SEfAS8RLxE3gUrhSvFAEAArCwFAkAAaFAAAAUp2Vn9HkHAAABAAEAAQDDAISgsAAAE9qwQBC3AAEUIAT37wYAAN8FgQMBADoBLgEXAWOAA7AwEBwAAWFlaQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/42daba1cef63.js b/pr/720/docs/search.index/42daba1cef63.js new file mode 100644 index 000000000..963e794ac --- /dev/null +++ b/pr/720/docs/search.index/42daba1cef63.js @@ -0,0 +1 @@ +rn_("AQgA9OwTAAABAFQAAQABAgGgYAAAFJlz8twRAAABAAGAArAgECMAAaCQAAAUSGFlAQcBsEAUZwABZfUrFAAAAQABAAEAAQABAwGwQBR9AAF08twTAAABACOEAqBAAAAUDGJzE4ACsMAUsQABdXkBAQD02BEAAAEAAQABABOAArAwEQMAAWRsN3QAAIuwQBO7AAGgUAAAEXGgkAAAE6+wUBMKAAGgMAAADGuzmAc7MAAAAQAAZQATAAkCAQBoBAMAxQUAAMIGAQBhBwEABwkBABQJAAAeCQAAUAkAAIQMQwDeDAAA7g8BABgQAADIEAEA5hABACwRAQCsEQQAvRIBADgTAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4331b9640b27.js b/pr/720/docs/search.index/4331b9640b27.js new file mode 100644 index 000000000..de1e5c93a --- /dev/null +++ b/pr/720/docs/search.index/4331b9640b27.js @@ -0,0 +1 @@ +rn_("AYICsEAUZAABsGATOgABZXIBBQD0nxAAAAEAAQABAPOAAmZtAQYAOjAAAAEAAAAAAAgAEAAAAN8P4A+TEfES8hLyE3kUrxSwFAEAArCwFAoAAaFAAAAUqGVn9HkHAAABAAEAAQDDAISgsAAAE9uwQBC3AAEUIAT37wYAAN8FgQMBADsBLgEXAWOAA7AwEBwAAWFlaQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/433c3dda6c7f.js b/pr/720/docs/search.index/433c3dda6c7f.js new file mode 100644 index 000000000..a54b90871 --- /dev/null +++ b/pr/720/docs/search.index/433c3dda6c7f.js @@ -0,0 +1 @@ +rn_("AQEA8/kPAAABAAEAAYmEoIAAABS4oEAAABRioGAAABSEoJAAABS8AoAKE4EDoKAAABPysNAUWwABY2l1M4ADsMAUugABYXR1") \ No newline at end of file diff --git a/pr/720/docs/search.index/43819ce322e0.js b/pr/720/docs/search.index/43819ce322e0.js deleted file mode 100644 index 6b63db2e2..000000000 --- a/pr/720/docs/search.index/43819ce322e0.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYQCoCAAABEnoDAAABGNaXQBAQA7MAAAAQAAjQACAHMHAAB1CYwAYwADsAACGgABZGVsOjAAAAEAAAAAAAcAEAAAALcEhQWGBYcFdwdEEZkTmhM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4471911fea22.js b/pr/720/docs/search.index/4471911fea22.js deleted file mode 100644 index 172aa1c1a..000000000 --- a/pr/720/docs/search.index/4471911fea22.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUAOzAAAAEAAAYAAQBfEAYAAQMAOzAAAAEAAAUAAQDXDAUAYwADoJAAABN3aHBzOjAAAAEAAAAAAA8AEAAAAKkFqgXBBhIJWQxmDAYRBxG2ErcSDhMPExATERM/E0AT") \ No newline at end of file diff --git a/pr/720/docs/search.index/448b5003b9dc.js b/pr/720/docs/search.index/448b5003b9dc.js new file mode 100644 index 000000000..49795da42 --- /dev/null +++ b/pr/720/docs/search.index/448b5003b9dc.js @@ -0,0 +1 @@ +rn_("AQUA9OgPAAABAPAAAQCDAISgQAAADPuwcBNyAAGwIAx4AAEQBQI7MAAAAQAACQADALsEAwB/BQIAzxECAAGAAqAgAAARJrAgFD0AAWR0AYQCsLAUjwABsAAT3wABYXPTgISgsAAAFHRAKAQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/44bfb2b21a2e.js b/pr/720/docs/search.index/44bfb2b21a2e.js new file mode 100644 index 000000000..f72f725b1 --- /dev/null +++ b/pr/720/docs/search.index/44bfb2b21a2e.js @@ -0,0 +1 @@ +rn_("AQIA9F4MAAABACMIAQAjgAKwABAjAAFlaQGJArAgFHIAAaAwAAAUfGlwEwADoCAAABMuoIAAABNDZWl19RAMAAA6AAEAAQABAAGGArCQFJoAAaAAAAASumJkAYACsDATIgABoDAAABD4cnbXAAAAhaAwAAAQbKAwAAATehABEzowAAABAAAAAAAKABAAAAD7CPwI/QgtCS4JHwyHEI4QSRFKEf4SY4ADsBAI7wABZG10") \ No newline at end of file diff --git a/pr/720/docs/search.index/454c52ea575e.js b/pr/720/docs/search.index/454c52ea575e.js deleted file mode 100644 index 4608a695f..000000000 --- a/pr/720/docs/search.index/454c52ea575e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9EkUAAABAAEAAQABBQD0OxMAAAEAlAABAPMAAmN19VYQAAABAMYAAQABAAEJAPN+FAAAAQA8AAGBArCAFJAAAaBgAAAUt2RzFwEAhIWw0BS5AAGgQAAAFGGwYBQxAFICkAojgAKgcAAAEV9kcgELAaBAAAAUZWXyiRQAAAEAE4ACsDAQcgABZHLzAgFl9N0HAAABAAEAAQAjgAKwIAwGAAFleQEKAPPAEgAAAQABAAELADswAAABAAAHAAEAphMHAAECAPQFFAAAAQBOAAEAtwAAgIWwcBL2AAGw0BSsAAFgIAYBBgDzzRIAAAEAAQABAwGwQBR8AAF08tsTAAABACOFAqBAAAAUC2JzIwIDsEARAwABoFAAABFwYWJm9wcJAAABAEgAeAcBAGIAAQDzgAJpcAEEAPNvEAAAAQABAPMAAXA7MAAAAQAADAABAN8GDAAjgAOgMAAADBawcBO6AAFhZWnzgANkbW4BAAA6MAAAAQAAAAAABwAQAAAAEglmDLYStxIOEw8TEBMRE/MCAWQ7MAAAAQAACQADAOIRAwCxEgMA5RIBACOAAqCQAAAUWGlvAYADsDATbQABgBOwABABsFARIAABY3N48wABZQHMBAAA5xUAgImgAAAADHegQAAADNGwQAzSAAGQSF0=") \ No newline at end of file diff --git a/pr/720/docs/search.index/458f9d447ca8.js b/pr/720/docs/search.index/458f9d447ca8.js deleted file mode 100644 index fd3fafcfe..000000000 --- a/pr/720/docs/search.index/458f9d447ca8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYMCoFAAABEUoKAAABNQa3ABAAGwQBKYAAFs9GsJAAABAHgHAQABCAD0rBIAAAEAAQABAAEEAaAAAAAQ7nMBVRAAAAECAaBQAAATC2MBzwwAALcAAACGsEANDQABoJAAABM4oDAAAAwPlRABOzAAAAEAAAgABADIBAAAmQUCANIMAQDADwIAo4CEsDAJKQABoBAAABOGkQBAARABsAAUhAABczswAAABAAAFAAEAnRQFAAEDAPRrCQAAAQB4BwEAY4ADoAAAAAwPbnJ1AQACsNATzAABoDAAAA/DYmr2fAUAAAEAAQBJAAEAdwEBAAGwgBPrAAF0OzAAAAEAAEYABADFBQAAFAkAAB4JAACEDEMAAQkA880SAAABAAEA84ADY2d0AYMCoJAAABQ2oJAAABQ3MjMBgAKgUAAAFGKggAAAE4NjZfMAAnN08kAHAAABAAEAAaCwAAATzmLzWBMAAC4BAQAjgAKgAAAAE1dkciOAAqBQAAAUKGNl84ACaXkBBAD1PxEAAAEAAQABAAEA8wEBbgE2BwAAAQEAOzAAAAEAAAkAAgDjBwcAFBMBAAEGAPS+EwAAAQABAAEAAQ8A9KgUAAABAAEAAQDzgQJobQEAAbBAFGYAAWX1KhQAAAEAAQABAAEAU4ADoCAAABHhbG50120AgMugIAAAFJiwYBDSAAGwQA/8AAHAGzgK") \ No newline at end of file diff --git a/pr/720/docs/search.index/45b43961206f.js b/pr/720/docs/search.index/45b43961206f.js deleted file mode 100644 index b334d93f6..000000000 --- a/pr/720/docs/search.index/45b43961206f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIBsEAUfAABdDswAAABAAANAAYA/hIDAGsTAQDbEwEA8hMBAHEUAQCZFAEAE4ACsDATMgFJaXABBQDzsBMAAAEAAQATgAKgMAAAFAtleVMCA7BwFBcAAWJlcwFAEAAAEwACoCAAAAWkZm31ggAAAOMGAQDVAQEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/45ccc7ad5291.js b/pr/720/docs/search.index/45ccc7ad5291.js deleted file mode 100644 index 595cb8328..000000000 --- a/pr/720/docs/search.index/45ccc7ad5291.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABoCAAAAzrbQGEBQAAAQAA9A4TAAABAAEAAQDzBAFk9LESAAABAAEAAQAjhISwoBRWAAGwQBMMAAGwcBP/AAEVgAAzgAOw0BRAAAFhZWk=") \ No newline at end of file diff --git a/pr/720/docs/search.index/45d9dd3f98fe.js b/pr/720/docs/search.index/45d9dd3f98fe.js deleted file mode 100644 index 6df7f5498..000000000 --- a/pr/720/docs/search.index/45d9dd3f98fe.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQcAOzAAAAEAAI0AAgD3EAAACBKMAAEDADswAAABAACMAAEACA6MAAECADswAAABAAAHAAEAQgwHAPMAA2JpdDswAAABAACNAAIAoQQAANsEjAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/46205e713ecc.js b/pr/720/docs/search.index/46205e713ecc.js new file mode 100644 index 000000000..d63e125ca --- /dev/null +++ b/pr/720/docs/search.index/46205e713ecc.js @@ -0,0 +1 @@ +rn_("AQMBoEAAABGDZQHGDwAAAQIA8y8MAAABAAEAIwACsCAMHQABa3L28AYAAAEAFAruAAEANALzAAJyePLvCAAAAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/46221eeede87.js b/pr/720/docs/search.index/46221eeede87.js deleted file mode 100644 index eb4d2c9ae..000000000 --- a/pr/720/docs/search.index/46221eeede87.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAAOjAAAAEAAAAAAAoAEAAAAOYP5w/XENgQYxH0EfUREhMTE6wUrRQBBADz4Q8AAOEAAQDzAAFx9woNAAABAD8DAQDNAGEAAQDzAAJleTowAAABAAAAAAAOABAAAAAJCVMMVAx3EIwQjRAiESMRJBH8E/0TDBQNFIgUjRQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/46349ba99789.js b/pr/720/docs/search.index/46349ba99789.js new file mode 100644 index 000000000..9a2c40010 --- /dev/null +++ b/pr/720/docs/search.index/46349ba99789.js @@ -0,0 +1 @@ +rn_("AQEA9qEFAAABACoNAQCpAAEAAQAAOzAAAAEAAAcAAwARAgEAaQwBAB4QAwABgwKwcBOaAAGwgBPTAAFjcwEFAPRKFAAAAQABAAEAAQUA9DwTAAABAJQAAQDzCAJjdfVWEAAAAQDGAAEAAQABAgD0vxEAAAEAAQABABMAAqAwAAARimV09MQQAAABAAEAAQABAwD0uxEAAAEAAQABAAGAAqAAAAAQlaAAAAAQljQ28wMBdgECDQAAlwEAAIawoBMdAAGwIAwkAAGwgBL7AAEJDAY6MAAAAQAAAAAACQAQAAAABQcGBwcHNQz3D2ARqhKrEqwSXxQBAgD0JhMAAAEAkgABAAEDAPRcEwAAAQCYAAEA8wACYnU6MAAAAQAAAAAAFQAQAAAASgdLB0wH2A/ZD4UQhhCmEKcQPhE/EfER8hEkEyUTMRMyE0MTbhNvE7cTuBMBAQD0nQUAAAEAUwcBALcAAICFsQAUQQABsAAHVAABDAhEAQgAOzAAAAEAAAUAAQDdEgUA1w0AAIiwQBEuAAGgIAAADQy5AAs7MAAAAQAADwAFAHwAAQD9BgcAYwcBAHUQAQAqEQEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/46dda721da8a.js b/pr/720/docs/search.index/46dda721da8a.js deleted file mode 100644 index 7a340409f..000000000 --- a/pr/720/docs/search.index/46dda721da8a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEAOzAAAAEAAAYAAQDCFAYA8wYBZfRvFAAAAQA0AAEAEwMDsEAUmwABsGAThwCJYXJ183sQAAB5AgEAI4ACgBF7ABABZHI=") \ No newline at end of file diff --git a/pr/720/docs/search.index/46fb88136a2a.js b/pr/720/docs/search.index/46fb88136a2a.js new file mode 100644 index 000000000..2e1af3568 --- /dev/null +++ b/pr/720/docs/search.index/46fb88136a2a.js @@ -0,0 +1 @@ +rn_("AQUA9EoUAAABAAEAAQABBQD0PBMAAAEAlAABAPMAAmN19VYQAAABAMYAAQABAAEJAPN/FAAAAQA8AAGBArCAFJEAAaBgAAAUuGRzFwEAhIWw0BS6AAGgQAAAFGKwYBQyAFICkAojgAKgcAAAEWBkcgELAaBAAAAUZmXyihQAAAEAE4ACsDAQcgABZHLzAgFl9N0HAAABAAEAAQAjgAKwIAwGAAFleQEKAPPBEgAAAQABAAELADswAAABAAAHAAEApxMHAAECAPQGFAAAAQBOAAEAtwAAgIWwcBL3AAGw0BStAAFgIAYBBgDzzhIAAAEAAQABAwGwQBR9AAF08twTAAABACOFAqBAAAAUDGJzIwIDsEARAwABoFAAABFxYWJm9wcJAAABAEgAeAcBAGMAAQDzgAJpcAEEAPNvEAAAAQABAPMAAXA7MAAAAQAADAABAN8GDAAjgAOgMAAADBawcBO7AAFhZWnzgANkbW4BAAA6MAAAAQAAAAAABwAQAAAAEglmDLcSuBIPExATERMSE/MCAWQ7MAAAAQAACQADAOMRAwCyEgMA5hIBACOAAqCQAAAUWWlvAYADsDATbgABgBOxABABsFARIQABY3N48wABZQHMBAAA5xUAgImgAAAADHegQAAADNGwQAzSAAGQSF0=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4715969cb3bf.js b/pr/720/docs/search.index/4715969cb3bf.js deleted file mode 100644 index 188aa23e0..000000000 --- a/pr/720/docs/search.index/4715969cb3bf.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQ0A9eATAAABAAEAeAABAAEHAPPIEwAAagABACOAAqEQAAAUGW5yAQcA9LYRAAABAAEAAQAzAASgIAAACSiw4BQOAAExZWlyOjAAAAEAAAAAAAkAEAAAAGAEYQROBwoJbAxtDG4MbwxYEVkRAQIA9AoRAAABAJIBAQABAwD0dREAAAEAfAEBAPMAAmJ1ARsQAAABAwD0CBEAAAEAkgEBAPOEAmRzAQIA8wwJAAABAFkA84ACaXQBGADzxhQAAAEAAQAjgQKwwBPeAAFjbQENAbBAFGYAAWX1KhQAAAEAAQABAAEAE4ICsAARIAABa3MBBAD0rhAAAAEAAQABAAGBAqAgAAARG7BAE3MAAWVp84ICZXQBBAGwYBLFAAFy9CEMAAABAPcDAQDzgANhZW8BCQD28BIAAAEAAAGHADYAAQATgAKwYBDIAAFkbgEGADswAAABAAAFAAIA8xADAIwTAQABAwGgcAAAEy1n9FsHAAABAAgCAQABCQDzfhQAAAEAPAABgQKwgBSQAAGgYAAAFLdkcxcBAIiFsNAUuQABoEAAABRhsGAUMQBSApAKAQQA9MwTAAABAEoAAQBTgAOwkBSyAAFlaG8BAAGgQAAAEYJlAcYPAAAjgQKwUBEtAAFrdHfsAwCOoZAAABSnsLATPQABoKAAABLvsVAUsAAB/cEPOzAAAAEAACEACACBAAAAhwADAHIFAQA3BwcAMwkHAEIMBwBTEAEAmhIAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/47f9564a89e4.js b/pr/720/docs/search.index/47f9564a89e4.js new file mode 100644 index 000000000..b82f1090c --- /dev/null +++ b/pr/720/docs/search.index/47f9564a89e4.js @@ -0,0 +1 @@ +rn_("AYACoAAAABCVoAAAABCWNDYBgAOwABPnAAGwABPpAAGwcBRgAAE0NmEBBAD0thQAAAEACgABACOBAqBAAAARX21wAQEAOzAAAAEAAAgAAwDXEgAATRMAAMMUBgDHAQACxaBAAAAQWKCAAAASsUAGgAg7MAAAAQAAFgAIAPUPAQAWEQEAWxEDANIRBQDDEwMAEhQAAHAUAQClFAEA8wACZXY6MAAAAQAAAAAAFQAQAAAAEwIUAhUCsAUCDa8PsA/ND+sPfxCAEIEQghAxETIRyBLJEsoSyxLJEzMUNBQBgQKwcBFbAAGwcBFdAAE0NiOAArAQB2EAAW5wAQMCsEATIgABoDAAABN6ZXf0hxAAAAcAuwABABOBAqBwAAATtGdvAQQAOzAAAAEAAAYAAgAEDAAAEA0FAGOAA7BQD/UAAWRzdFcBAACFoBAAABBYsSAUcAABESEBOzAAAAEAAAoAAwB+AAAAlAAFANgRAwA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/482faea55872.js b/pr/720/docs/search.index/482faea55872.js deleted file mode 100644 index 93e875f8a..000000000 --- a/pr/720/docs/search.index/482faea55872.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQBoEAAABGDZQE7EAAAAQgA9MYRAAABAAEAAQABAwGgQAAAEYJlAcYPAAABAgDzLwwAAAEAAQAjAAKwIAwdAAFrcvbwBgAAAQAUCu0AAQA0AvOAAnJ4AQMBsIAUXwABdjswAAABAAALAAMAFhEBANERBQDCEwMAI4ACsGAQhwDBYXIBgAKgsAAAE+qwMA/EAAFlaAEDAaBAAAARFWXyFQkAAAEA1xMAAIugIAAAB2awsBM5AAGgkAAAEvyggAAAEcqgAAAAE0afGEw6MAAAAQAAAAAADAAQAAAADAJ8BH0EfgQGDAcMcAxxDHIMBg4HDkcTXRM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/48cb78020f8e.js b/pr/720/docs/search.index/48cb78020f8e.js deleted file mode 100644 index e88abd865..000000000 --- a/pr/720/docs/search.index/48cb78020f8e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYMCsQAUvgABsNAUrgABa20BCwDzARQAAAEAdQAzAoSgYAAAEpWhAAAAFHkEgAM7MAAAAQAANAACAE8HAACgBzMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/491826f98ad3.js b/pr/720/docs/search.index/491826f98ad3.js deleted file mode 100644 index 35e981ed4..000000000 --- a/pr/720/docs/search.index/491826f98ad3.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQkA834UAAABADwAAYACoEAAABNdsCAUGgABaGkBAQDz+Q8AAAEAAQATgAKwwBS5AAF0dQGBArCAFJAAAaBgAAAUt2RzNwMAg4agQAAAFGGwYBQxAFICkA4BEgGwABSEAAFzOzAAAAEAAAUAAQCdFAUAAQDGoFAAABLioAAAABCZsCARTAABoFAAABH4oQAAABSYoEAAABQ7AAMCCzswAAABAAAVAAcArgUAADIMAADoDAAAChANAHARAAD4EgEANhQBAAEBAbCwFIsAAWw7MAAAAQAADAADACUHCAAGDQEASBABAAEBAaAwAAARKGjzAQkAAC4AsQgBAgD01xEAAAEAAQABABOBArAgEdsAAWFz84ICbm/3AQCAh6AgAAAFrbBADBgAARUBBw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/493e1a0b131a.js b/pr/720/docs/search.index/493e1a0b131a.js deleted file mode 100644 index e59658a9a..000000000 --- a/pr/720/docs/search.index/493e1a0b131a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQgA9HUQAAABALMAAQABAAGggAAAFLhm8voIAACeCgEHAPVmEwAAAQABAAEAAQAjgAKgUAAAEWNhb/MCAmZzOzAAAAEAAAgABABNBwAAfgcFAAQNAACbEQAAM4ADoEAAAAwNYWVv") \ No newline at end of file diff --git a/pr/720/docs/search.index/49737cee27c8.js b/pr/720/docs/search.index/49737cee27c8.js deleted file mode 100644 index f4a702dc8..000000000 --- a/pr/720/docs/search.index/49737cee27c8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUAOzAAAAEAAAcAAwDLEQIAfhMBABQUAgABBADzzhEAAAEAAQAjAAKgYAAAEv1hcvPvEAAAAQDJAQGAAqEQAAAUo7CAFJkAAWl1NwQAgYexUBTAAAGgAAAAEM+wcBPeAAGhMAAAFLQKQBsBAAA7MAAAAQAAjAABAAgOjAABAgD2ohMAAAEAqgBZABgAAQAjgQKgIAAAEQ9ydvOAAmVvI4ACoCAAABKaZHQBAAA7MAAAAQAA8AAEAMYFAAABCO0AgwwAAHERAADzgANkbnY=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4a6b146615f8.js b/pr/720/docs/search.index/4a6b146615f8.js new file mode 100644 index 000000000..4db61cc89 --- /dev/null +++ b/pr/720/docs/search.index/4a6b146615f8.js @@ -0,0 +1 @@ +rn_("AQIBsIAT7AABdAEUCQAAAYECoBAAABNIoHAAABOQYWPzAQFy8qsRAAAgAPOAAmVpAQAA9BIMAAABAAEAAQDzgAJkcvMAAWX0jwAAAGEMTwcBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4ae5903ada8f.js b/pr/720/docs/search.index/4ae5903ada8f.js deleted file mode 100644 index 88c25b840..000000000 --- a/pr/720/docs/search.index/4ae5903ada8f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQkBoEAAABRlZfKJFAAAAQABgAKwAAzpAAGggAAAE8tkcAECA7BgE0gAAbDQFGgAAaCAAAAT6mlycwFzFAAA1wAAgIWwMA/EAAGhMAAAFIiQSQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4b0efb148f32.js b/pr/720/docs/search.index/4b0efb148f32.js new file mode 100644 index 000000000..2f200a289 --- /dev/null +++ b/pr/720/docs/search.index/4b0efb148f32.js @@ -0,0 +1 @@ +rn_("AQUA9MwSAAABAKkAAQABCAD0ixMAAAEAhwABADMAA7BAE1oAAWFiZTowAAABAAAAAAAMABAAAAAxBzIHMwf0DPUMxw86EIgQiRCKEIsQpBJ5Ew==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4b3652259c76.js b/pr/720/docs/search.index/4b3652259c76.js new file mode 100644 index 000000000..bfa7b68a4 --- /dev/null +++ b/pr/720/docs/search.index/4b3652259c76.js @@ -0,0 +1 @@ +rn_("AQsA9HUUAAAMACMAEQABCgA6MAAAAQAAAAAABwAQAAAAUhNTE+4T7xMmFCcUdhR3FPOBAm90EwCEsCATRgBasDARSwABoFAAABEzEDACOzAAAAEAAAgABACEAAEArgADAFgHAQBvCQAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/4b5efd7b6a23.js b/pr/720/docs/search.index/4b5efd7b6a23.js deleted file mode 100644 index cacb27d33..000000000 --- a/pr/720/docs/search.index/4b5efd7b6a23.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA9UoJAAABAAEAAQABAPMAAWnyshQAAAEAAQQCoCAAABHdoDAAABKoYmgByg8AAKcAAIDFoBAAAAzusBAUmwABoDAAABB8BBAoAQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4b7dc887fedc.js b/pr/720/docs/search.index/4b7dc887fedc.js new file mode 100644 index 000000000..9711fd678 --- /dev/null +++ b/pr/720/docs/search.index/4b7dc887fedc.js @@ -0,0 +1 @@ +rn_("AQAAOjAAAAEAAAAAAAoAEAAAAOYP5w/XENgQZBH1EfYRExMUE60UrhTzAQF58g0UAAABACMAA6BAAAARg6BQAAAUX2Vvc/LGDwAA2wI=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4bbac020109f.js b/pr/720/docs/search.index/4bbac020109f.js new file mode 100644 index 000000000..58ef2ee7a --- /dev/null +++ b/pr/720/docs/search.index/4bbac020109f.js @@ -0,0 +1 @@ +rn_("AYMCoJAAABQ3oJAAABQ4MjMBgAKgUAAAFGOggAAAE4RjZfMAAnN08kAHAAABAAEAAaCwAAATz2LzWRMAAC4BAQAjgAKgAAAAE1hkcgEAAbCAFD0AAXDyORQAAAEAQwADoCAAABFhoEAAABK2ZGVz8/gPAABRAwEAE4ICoCAAABQpZWnzgAJjZQEEADswAAABAAAJAAQAXAkBAJ8QAwDiEAEA8BMBAPOAA2VpeQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4c6ccd5ef6f9.js b/pr/720/docs/search.index/4c6ccd5ef6f9.js deleted file mode 100644 index 54cc71c63..000000000 --- a/pr/720/docs/search.index/4c6ccd5ef6f9.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMAOzAAAAEAAAUAAQDcEgUAAQQBoFAAABQnaPK6EgAAAQABAAKwQBO6AAGgoAAAFEdlcjowAAABAAAAAAAHABAAAADCBsMGYQdiB+4P7w/mEOcQ84ADZ2lz") \ No newline at end of file diff --git a/pr/720/docs/search.index/4cb2932fc572.js b/pr/720/docs/search.index/4cb2932fc572.js new file mode 100644 index 000000000..5bb77b095 --- /dev/null +++ b/pr/720/docs/search.index/4cb2932fc572.js @@ -0,0 +1 @@ +rn_("AQQBsEAUZwABZfUrFAAAAQABAAEAAQABAgA7MAAAAQAACwACANUTBQCTFAUA8wEBbTswAAABAAANAAQA0AwAAG4RAADqEgUATxQFAPMBAWXyARIAAAEAM4CEsBAQjAABoCAAAAwXFEAE") \ No newline at end of file diff --git a/pr/720/docs/search.index/4cbe7f17ed91.js b/pr/720/docs/search.index/4cbe7f17ed91.js new file mode 100644 index 000000000..75a162fea --- /dev/null +++ b/pr/720/docs/search.index/4cbe7f17ed91.js @@ -0,0 +1 @@ +rn_("AYQCsAARfwABsAARgQABNDbzAgFh8nUMAAABAAEAAPbGEgAAAQBzAAEAUQEBAPMAAWTz1RIAAAEArQBjgAOgIAAACPlhZW8=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4cc81ce44b1f.js b/pr/720/docs/search.index/4cc81ce44b1f.js new file mode 100644 index 000000000..bb75e3b32 --- /dev/null +++ b/pr/720/docs/search.index/4cc81ce44b1f.js @@ -0,0 +1 @@ +rn_("AQIA9QETAAABAPIAfgABABOAArAwEzMBSWlwAQYA87ETAAABAAEA8wICYnMBQBAAAPMBAWYBZgcAAAECAPRcEwAAAQCYAAEAM4ADsEATKAABaXV5") \ No newline at end of file diff --git a/pr/720/docs/search.index/4dd22e56451b.js b/pr/720/docs/search.index/4dd22e56451b.js deleted file mode 100644 index 14c67a960..000000000 --- a/pr/720/docs/search.index/4dd22e56451b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIBsIAT6wABdAEUCQAAAYECoBAAABNHoHAAABOPYWPzAQFy8qoRAAAgAPOAAmVpAQAA9BIMAAABAAEAAQDzgAJkcvMAAWX0jwAAAGEMTgcBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4e14ce064f55.js b/pr/720/docs/search.index/4e14ce064f55.js new file mode 100644 index 000000000..a83827d30 --- /dev/null +++ b/pr/720/docs/search.index/4e14ce064f55.js @@ -0,0 +1 @@ +rn_("AYACsHAReAABsCAUXQABYWQBBQD0SxMAAAEAmAABAPMAAWMBsRIAAEOAA7AwE6EAAbCgFD8AAWFzeQEGAPQWEQAAAQC/AAEAk4CEoAAAABFfsSAUpQABCSAB84ACZWk=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4e73de40c9f5.js b/pr/720/docs/search.index/4e73de40c9f5.js deleted file mode 100644 index 44946cf57..000000000 --- a/pr/720/docs/search.index/4e73de40c9f5.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQkA834UAAABADwAAYADoEAAABNdsCAUGgABoCAAAA/TaGl5AQkBoIAAABS4ZgGYEwAAAQMBsAAUMQBSc/KtEAAALQMjgAKgIAAAD89hcgECAPXcEAAAAQABAF8CAQDzAANpdHU6MAAAAQAAAAAAEAAQAAAAfQcsCfMMORC2EO8SKRMqE94T3xPlEw4UDxQvFDAUhBSFFAGAAqAwAAAUYbCwE7QAAWFsAQEA8/kPAAABAAEAE4ACsMAUuQABdHUBAwDzwBIAAAEAAQABAQD1PxEAAAEAAQABAAEAI4ACsJAUBwABYXQBBAGgQAAAFGVl8okUAAABAAECADswAAABAAALAAUAWRAFANASAQABFAEAWBQAAHcUAAATggKw8BS8AAFmZwGBArCAFJAAAaBgAAAUt2RzAQgA9UIUAAABAAEAAQABAPMCAWb1mhAAAAEAAQABAAEAI4ADoCAAAA/NsKAUjgABZHJ0d+8BAI2wEBQ8AAGw4BQ+AAGX1Q47MAAAAQAAOgETAIcEAQC0BAIApgUCALwGBADuBwEAKQwDAFcMAQDkDAEAnQ4EAfAPAQC3EAEAyhACAPgQAQCLEQAAvhEDAOgRAQDiEgAAphMHAJ0UBQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/4ea9347ec9c1.js b/pr/720/docs/search.index/4ea9347ec9c1.js deleted file mode 100644 index 7c8afc83f..000000000 --- a/pr/720/docs/search.index/4ea9347ec9c1.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQcA9AMSAAABAAEAAQAjAAKgcAAAEgJhcgF4BwAAAQAA9iARAAABAJQDAQAKAAEAAQAAOzAAAAEAAAYAAgCOEwAA9hMFACOIArBAFGwAAWVzAQ0BsEAUZgABZfUqFAAAAQABAAEAAQABBQA7MAAAAQAACAADAPwRAgACEwQAKRQAANcDAACGBbqAxTPrFIQG9cEEAAABAAkIAQABAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4ea99a0432f7.js b/pr/720/docs/search.index/4ea99a0432f7.js deleted file mode 100644 index fcaa04b67..000000000 --- a/pr/720/docs/search.index/4ea99a0432f7.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9asRAAABAAEAAQABAAGAArBgExYAAaAgAAARAG95AQABoMAAABQ7afRvEwAACAAcABsAAQMA9JQTAAABAAEAAQABBQD0qBQAAAEAAQABABOAArBwFIEAAWVpAQIA9P4QAAABAJoAAQABAgGgQAAAE0ZyOzAAAAEAAAcAAgD8EAEAkxEFAPOAAmFvZwcAAIewgBNFAFqwoBO8AAEMMAc7MAAAAQAADgAEAJUEBQAcDAAAxhEDAKwSAwCnAACAhaDwAAATz7BQEE8AAaCQAAARipSBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4f020f79d021.js b/pr/720/docs/search.index/4f020f79d021.js deleted file mode 100644 index 27976a6a5..000000000 --- a/pr/720/docs/search.index/4f020f79d021.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQACoDAAABEcoJAAABOTMGj1AhIAAJkBAQABAAEAE4ACoDAAAA/MZHIjAYSwEAj3A0CwIAwDAQygMAAAD/QSABj1nAUAAC0AAQABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/4f3d19b6424b.js b/pr/720/docs/search.index/4f3d19b6424b.js new file mode 100644 index 000000000..b8fc96d73 --- /dev/null +++ b/pr/720/docs/search.index/4f3d19b6424b.js @@ -0,0 +1 @@ +rn_("AQEA9GcHAAB6COEAAQABBQD0ShQAAAEAAQABAAEFAPQ8EwAAAQCUAAEA8wICY3X1VhAAAAEAxgABAAEAYwAEoDAAAAw2oHAAABHiZW5zdvN0EAAAnwAkAg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/4fbe24f6d57c.js b/pr/720/docs/search.index/4fbe24f6d57c.js deleted file mode 100644 index 88517138d..000000000 --- a/pr/720/docs/search.index/4fbe24f6d57c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9AUUAAABAE4AAQDzAwFj8gcTAAABACOAArBwFLwAAWhvAYICsAAS4wABsAAR6gABZXNDAAOgoAAAFFmgIAAAE5JlaXT19hIAAAEAiQABAPgAAYACsHAS2gABoLAAABQZZW8BAgA7MAAAAQAABgABAGQRBgABAgGgQAAAFDpl8mgUAAABAPOAAmlvAQgA9PwTAAABAIsABQATAQOwkBRjAAGwUBNBAWZnbHA7MAAAAQAAEgAJAGkQAgDtEQEALhMBAFETAQCIEwEA7RMBACUUAQA0FAEAdRQBAAGAArBAErgBF6AgAAARKGFpAQMA89cSAAABAAEAI4ECsDAUDAABY2kBAAD0KRMAAAEAWgEBAPMDAXM7MAAAAQAADwADAOgRAQCmEwcAnRQFAAEDAPXmEQAAAQAlAQEAYQHzgAJydgEAADswAAABAAAFAAIAthIBAA4TAwDzAgFkOzAAAAEAAAkAAwDiEQMAsRIDAOUSAQAjgAKgkAAAFFhpbxOAArDwFKwAAWxvAQUA9HQUAAAMACMAEQAjgAKgYAAAE4ZncyOAArCQFFYAAWJs9xcDAI+wcBIAAAGwYBSOAAGwcBP/AAGwYBM/AAGwUBMrAAG1+Rc7MAAAAQAAPgAZALUFAABqBwEA8QgFAAEJAAAvCQAADwwAAF4MAQDfDAIACA0BAJYOAwCbDgEA/A8EANAQAQAMEQAALxEAAE4RCQCMEQAAjhEDAOARAAA1EwAAThMBAGATBQBwEwAAKBQAAIEUAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5012ed2e4dc3.js b/pr/720/docs/search.index/5012ed2e4dc3.js deleted file mode 100644 index 13e3a114f..000000000 --- a/pr/720/docs/search.index/5012ed2e4dc3.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQsA9HQUAAAMACMAEQABCgA6MAAAAQAAAAAABwAQAAAAURNSE+0T7hMlFCYUdRR2FPOBAm90EwCEsCATRQBasDARSgABoFAAABEyEDACOzAAAAEAAAgABACEAAEArgADAFgHAQBvCQAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/504ca52d3ae9.js b/pr/720/docs/search.index/504ca52d3ae9.js deleted file mode 100644 index d45566c4f..000000000 --- a/pr/720/docs/search.index/504ca52d3ae9.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQcA9AMSAAABAAEAAQAjAQKgcAAAEgJhcgF4BwAAAQMAOzAAAAEAAAgAAgCiDwYAXhMBAPMAAmN0OzAAAAEAAFcAJwCoBAsAbwUAAA4JAQAnDAEALwwCAO8MAAD7DAIADQ0BAMwPAADRDwEA1A8BAN4PAABmEAIAbRABAHIQAQCXEAAADxEAABURAABhEQEAbhEBAIIRAQCGEQIA5hEBAPkRAgD/EQAAtRIAAL4SAQDDEgEADBMBABwTAQAhEwEAQxMBAFMTAwBZEwEAuhMBAM4TAAA6FAAAYxQEAGwUAgA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/508290633409.js b/pr/720/docs/search.index/508290633409.js deleted file mode 100644 index c597cc7e4..000000000 --- a/pr/720/docs/search.index/508290633409.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQBsEAUZgABZfUqFAAAAQABAAEAAQABAgA7MAAAAQAACwACANQTBQCSFAUA8wEBbTswAAABAAANAAQA0AwAAG0RAADpEgUAThQFAPMBAWXyABIAAAEAM4CEsBAQjAABoCAAAAwXFEAE") \ No newline at end of file diff --git a/pr/720/docs/search.index/5106fdea4a6c.js b/pr/720/docs/search.index/5106fdea4a6c.js deleted file mode 100644 index 0c5af044d..000000000 --- a/pr/720/docs/search.index/5106fdea4a6c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9AUUAAABAE4AAQDzBAFj8gcTAAABAAEFAPPXEgAAAQABAPOCAmZ0AQABsAAUXwABZPT7CwAAAQABAAEA84ACZWkTgAKw4BRqAAF0dg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/512b2221e6e7.js b/pr/720/docs/search.index/512b2221e6e7.js new file mode 100644 index 000000000..ad333058e --- /dev/null +++ b/pr/720/docs/search.index/512b2221e6e7.js @@ -0,0 +1 @@ +rn_("AQYA9L8TAAABAAEAAQABDwD0qRQAAAEAAQABAPOHAmhtAQAA9A8TAAABAAEAAQDzBAFk9LISAAABAAEAAQAjh4SwoBRXAAGwQBMNAAGwcBQAAAEVgAABAAGgQAAAEJdlOzAAAAEAAAcAAgBsBwUA+QcBABOAArBQEE0AAWRyAQkA9eETAAABAAEAeAABALcCAICGsCASvQABc6KeS+HXEUkB") \ No newline at end of file diff --git a/pr/720/docs/search.index/51d0879dcf6d.js b/pr/720/docs/search.index/51d0879dcf6d.js deleted file mode 100644 index fded95d74..000000000 --- a/pr/720/docs/search.index/51d0879dcf6d.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsFAUFwABoAAAAAkKY3QBAQD0lBMAAAEAAQABAAEDAPTvDAAA3waeAAEAAYACoBAAAAx3oFAAABKiY2QBAgDz/ggAAFADAQDzAAFt86cEAADGAAEAAYECoBAAABNHoHAAABOPYWPzAAFy81oHAABQCiAA5wcAgIewMA/QANMpICM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5219aed485bd.js b/pr/720/docs/search.index/5219aed485bd.js deleted file mode 100644 index a830de700..000000000 --- a/pr/720/docs/search.index/5219aed485bd.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAAOzAAAAEAAAYAAgC2EQMAwBICAAEKAbBAFGYAAWX1KhQAAAEAAQABAAEA8wACaXP0JAwAAAEAUwABACOBAqDgAAAUTWV5") \ No newline at end of file diff --git a/pr/720/docs/search.index/52703ee3070c.js b/pr/720/docs/search.index/52703ee3070c.js deleted file mode 100644 index 3cc4b4124..000000000 --- a/pr/720/docs/search.index/52703ee3070c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABoJAAABN3aPI/EwAAAQDzAgFk8hMHAAABAAECADswAAABAAAFAAEAkhQFAPMLAW07MAAAAQAABQABAE4UBQAjgAKwIAzsAAFhbwECAPP+CAAAUAMBAAGKArAAE+YAAbAAE+gAATQ2I4ECoDAAAAx3ZXIBgAKwQBH0AAFIy3gCD45jdbcGAACHsBAQUwABsFAUagABEVEJ9Z0EAAAKAMYAAQCeBw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/52ddf1446ab6.js b/pr/720/docs/search.index/52ddf1446ab6.js deleted file mode 100644 index e82176981..000000000 --- a/pr/720/docs/search.index/52ddf1446ab6.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9MsSAAABAKkAAQABCAD0ihMAAAEAhwABADMAA7BAE1kAAWFiZTowAAABAAAAAAAMABAAAAAxBzIHMwf0DPUMxw86EIgQiRCKEIsQoxJ4Ew==") \ No newline at end of file diff --git a/pr/720/docs/search.index/53cea0b9a841.js b/pr/720/docs/search.index/53cea0b9a841.js new file mode 100644 index 000000000..209d75871 --- /dev/null +++ b/pr/720/docs/search.index/53cea0b9a841.js @@ -0,0 +1 @@ +rn_("AQEA9UARAAABAAEAAQABACOBArCQFAgAAWF0Q4ADsRAUigABsIATygABY290EwACsAAUXQABbnL2DQIAAAEAewIBAKwCXQw=") \ No newline at end of file diff --git a/pr/720/docs/search.index/53ffd91bdfe9.js b/pr/720/docs/search.index/53ffd91bdfe9.js deleted file mode 100644 index 4561b5d6d..000000000 --- a/pr/720/docs/search.index/53ffd91bdfe9.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMA9BAJAAABAFIDAQABAwDzYAwAAAEAAQDzgAJpbwEBAbBQEQ0AAWP0XQcAAAEAAQAIAiOBAqBQAAAQz2NuAQQAOzAAAAEAAAcAAwDLEQIAfhMBABQUAgABAQA6MAAAAQAAAAAABwAQAAAA7RHuES4TLxOIE4kTNBQ1FPMJAWkBDBEAANcCAACHsMATcwABoFAAAA+1oRAAABReFAEXOzAAAAEAACMAAQC5ASMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/5450ecaeec3d.js b/pr/720/docs/search.index/5450ecaeec3d.js deleted file mode 100644 index f7807e0d2..000000000 --- a/pr/720/docs/search.index/5450ecaeec3d.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBgBOAABD4czswAAABAAAFAAEAYBMFACOCAqCQAAAUYmlzBwEAhMWwUBMnAAGgoAAAE8uwcBOQAAGg0AAAFG6AARgI") \ No newline at end of file diff --git a/pr/720/docs/search.index/5516462dd4eb.js b/pr/720/docs/search.index/5516462dd4eb.js new file mode 100644 index 000000000..55de23b10 --- /dev/null +++ b/pr/720/docs/search.index/5516462dd4eb.js @@ -0,0 +1 @@ +rn_("AQACoCAAABOTsDAR6wABaXTy9xIAAAEAAQMAOzAAAAEAAAYAAQBlEQYAAQgA9P0TAAABAIsABQATAQOwkBRkAAGwUBNCAWZnbHA7MAAAAQAAEgAJAGkQAgDuEQEALxMBAFITAQCJEwEA7hMBACYUAQA1FAEAdhQBAAGAArAwEecAAbAwEekAAXJ2AQQBsAAStwABZDswAAABAAAFAAIA4xEDAOYSAQC3BQABh7BQErkBF7BgE0AAAZQJAzowAAABAAAAAAALABAAAADfDOAM4QybDpwODBGPEZARkRGSETYTcRMjgAKgEAAADN5ubwEDAPNmEAAAAQABACOAAqAAAAAMDmRyYwGEoFAAABGMoDAAABCkFAEQ8pgHAAABABOAArBgEtsAAWNnE4ADoLAAABQaoEAAAA6aZW9z") \ No newline at end of file diff --git a/pr/720/docs/search.index/5525682f4073.js b/pr/720/docs/search.index/5525682f4073.js deleted file mode 100644 index e064d1550..000000000 --- a/pr/720/docs/search.index/5525682f4073.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA9GcHAAB6COEAAQABBQD0SRQAAAEAAQABAAEFAPQ7EwAAAQCUAAEA8wICY3X1VhAAAAEAxgABAAEAYwAEoDAAAAw2oHAAABHhZW5zdvN0EAAAnwAjAg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/563edf471dd7.js b/pr/720/docs/search.index/563edf471dd7.js new file mode 100644 index 000000000..f5933d256 --- /dev/null +++ b/pr/720/docs/search.index/563edf471dd7.js @@ -0,0 +1 @@ +rn_("AYYCoAAAABNYoAAAABNZZHIBgAKgcAAAE+ugMAAAERhmdAELAaBAAAAUO2XyaRQAAAEAI4ECsFAQ7wABY3YBAAGwgBQ9AAFw8jkUAAABAEMGA6AgAAARYaBAAAAStmRlc/P4DwAAUQMBAPMABGlyc3Y7MAAAAQAADwAFAPQGBQDdEgUAChMBAIQTAAB0FAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/56cab5b365ee.js b/pr/720/docs/search.index/56cab5b365ee.js new file mode 100644 index 000000000..683e906e9 --- /dev/null +++ b/pr/720/docs/search.index/56cab5b365ee.js @@ -0,0 +1 @@ +rn_("AYADsAAT5wABsAAT6QABsHAUYAABNDZhAQQA9LYUAAABAAoAAQAjgQKgQAAAEV9tcAEBADswAAABAAAIAAMA1xIAAE0TAADDFAYAxwEAAMWgQAAAEFiggAAAErFABoAIOzAAAAEAABYACAD1DwEAFhEBAFsRAwDSEQUAwxMDABIUAABwFAEApRQBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/56f51737f884.js b/pr/720/docs/search.index/56f51737f884.js deleted file mode 100644 index 9cb37da96..000000000 --- a/pr/720/docs/search.index/56f51737f884.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9asRAAABAAEAAQABAAGAArBgExYAAaAgAAARAG95AQABoMAAABQ7afRvEwAACAAcABsAAQUA9KgUAAABAAEAAQATgAKwcBSBAAFlaQECAPT+EAAAAQCaAAEAAQIBoEAAABNGcjswAAABAAAHAAIA/BABAJMRBQDzgAJhb2cDAACGsIATRQBasKATvAABDDAGOzAAAAEAAAgAAwAcDAAAxhEDAKwSAwDzgAJlaQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/5718d5014774.js b/pr/720/docs/search.index/5718d5014774.js deleted file mode 100644 index 1faad6f1b..000000000 --- a/pr/720/docs/search.index/5718d5014774.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA9qEFAAABACkNAQCpAAEAAQAAOzAAAAEAAAcAAwARAgEAaQwBAB4QAwABgwKwcBOZAAGwgBPSAAFjcwEFAPRJFAAAAQABAAEAAQUA9DsTAAABAJQAAQDzCAJjdfVWEAAAAQDGAAEAAQABAgD0vhEAAAEAAQABABMAAqAwAAARiWV09MQQAAABAAEAAQABAwD0uhEAAAEAAQABAAGAAqAAAAAQlaAAAAAQljQ28wMBdgECDQAAlwEAAIawoBMcAAGwIAwkAAGwgBL6AAEJDAY6MAAAAQAAAAAACQAQAAAABQcGBwcHNQz3D18RqRKqEqsSXhQBAgD0JRMAAAEAkgABAAEDAPRbEwAAAQCYAAEA8wACYnU6MAAAAQAAAAAAFQAQAAAASgdLB0wH2A/ZD4UQhhCmEKcQPRE+EfAR8REjEyQTMBMxE0ITbRNuE7YTtxMBAQD0nQUAAAEAUwcBALcAAICFsQAUQAABsAAHVAABDAhEAQgAOzAAAAEAAAUAAQDcEgUA1w0AAIiwQBEtAAGgIAAADQy5AAs7MAAAAQAADwAFAHwAAQD9BgcAYwcBAHUQAQApEQEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/579722880242.js b/pr/720/docs/search.index/579722880242.js new file mode 100644 index 000000000..74cd8da1b --- /dev/null +++ b/pr/720/docs/search.index/579722880242.js @@ -0,0 +1 @@ +rn_("AQwA9MMTAAABAAEAAQABBgDzcxEAAAEAAQABggKwYBNJAAGw0BRpAAFpchOAArAQDOkAAWVpFwMAg4ixMBSKAAGgYAAAEXKgUAAAEQWwkBMZAAGwQBEBAAG0EAfzAAFh9D0JAAABAAkIAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/57b5a794dbfd.js b/pr/720/docs/search.index/57b5a794dbfd.js deleted file mode 100644 index be13974a4..000000000 --- a/pr/720/docs/search.index/57b5a794dbfd.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9HoTAAABAAEAAQATAAKwgBNOAAFzdvRtCQAAAQCRCgEAE4ACsDARDQABbG4BgAKgAAAAEJWgAAAAEJY0NvMDAXYBAg0AABMAAqBAAAARiWFz9zUMAADCA2gBSgEBAAEAswEBAgD0JRMAAAEAkgABAAEDAPRbEwAAAQCYAAEA8wACYnU6MAAAAQAAAAAAEwAQAAAASgdLB0wH2A/ZD4UQhhCmEKcQPRE+EfAR8REjEyQTMBMxE0ITthO3E/OAAmR0E4ACoCAAAA0MZXIBBwGgQAAAFDpl8mgUAAABAAEBADswAAABAAAFAAEAXgkFAEcAAACFsDAPrwABoFAAABB4sHARBgABsUAUwgABgSkA8nYFAAABAPOAAmx0lwEAgIaxMBQ8AAGxEBRqAAGgsAAAE10RRQg=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5877afb34948.js b/pr/720/docs/search.index/5877afb34948.js deleted file mode 100644 index 95e16b370..000000000 --- a/pr/720/docs/search.index/5877afb34948.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYkCsCAUcQABoDAAABR7aXATAAOgIAAAEy2ggAAAE0JlaXX1EAwAADoAAQABAAEAAYYCsJAUmQABoAAAABK5YmQBgAKwMBMhAAGgMAAAEPhydtcAAACFoDAAABBsoDAAABN5EAETOjAAAAEAAAAAAAkAEAAAAPsI/Aj9CC0JLgmHEI4QSBFJEf0S") \ No newline at end of file diff --git a/pr/720/docs/search.index/59718cd9c46f.js b/pr/720/docs/search.index/59718cd9c46f.js deleted file mode 100644 index e14b0f428..000000000 --- a/pr/720/docs/search.index/59718cd9c46f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUAOzAAAAEAAAYBAgDkDAEAnQ4EAQEBAaAAAAATTXP1xgQAAAgL+AMBAAQAAQECoGAAABPOoOAAABQpZXQ7MAAAAQAACAABAM0ECAABgAOwIBKWAAGwsBLQAAGwsBLSAAFiY3PzgARjbHR2") \ No newline at end of file diff --git a/pr/720/docs/search.index/598f05b02570.js b/pr/720/docs/search.index/598f05b02570.js deleted file mode 100644 index aabcc114e..000000000 --- a/pr/720/docs/search.index/598f05b02570.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9AoRAAABAJIBAQAjgQKgYAAAE0JiaQEAAPTyDwAAAQD1AAcBI4ECsFATVQABZXMTgAKAB1Ee8AFhcgGJArAgFHEAAaAwAAAUe2lwAQIA9CUTAAABAJIAAQABAwD0WxMAAAEAmAABAPOFAmJ1AQIA9HURAAABAHwBAQDzgAJpbLcBAACFoCAAABMtEgEMOjAAAAEAAAAAABYAEAAAAHIH+wf8B/0H/gcQDEoMSwxMDE0MGxDhEHMTdBOvEzEUfhR/FIMUkBSRFLcUuxQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/59d3892a5c9c.js b/pr/720/docs/search.index/59d3892a5c9c.js deleted file mode 100644 index ada6e4a9c..000000000 --- a/pr/720/docs/search.index/59d3892a5c9c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQA9goNAAABAD8DAQAuAQEAAQoA89QSAAABAK0AAQEA9x8JAAABAF0HAQBzAAEAFQEjgAKwYBPvAAFpbwECAPTIDAAAAQBNBgEAAQUA9AUUAAABAE4AAQD3BAAAh6AgAAAMyrCQEfoAAQScAzowAAABAAAAAAAIABAAAACVBRAJEQljDGQMARECEQcTCBM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5a454e6b8e3d.js b/pr/720/docs/search.index/5a454e6b8e3d.js new file mode 100644 index 000000000..1b8297698 --- /dev/null +++ b/pr/720/docs/search.index/5a454e6b8e3d.js @@ -0,0 +1 @@ +rn_("AYACoCAAAA/PoDAAABPbYXLzAAF0AX0HAAABBAGgQAAAFGZl8ooUAAABAAEFADswAAABAAALAAUAWRAFANESAQACFAEAWRQAAHgUAADjAISgMAAAD82FAAI7MAAAAQAACwAFAKYFAgC8BgQAVwwBAIwRAADjEgAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/5a5e2d8166b8.js b/pr/720/docs/search.index/5a5e2d8166b8.js deleted file mode 100644 index d700ccff7..000000000 --- a/pr/720/docs/search.index/5a5e2d8166b8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYMCsQAUvgABsNAUrgABa20BCwDzARQAAAEAdQAzAYSgYAAAEpWhAAAAFHkEgAM7MAAAAQAANAACAE8HAACgBzMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/5a649cef0a96.js b/pr/720/docs/search.index/5a649cef0a96.js new file mode 100644 index 000000000..cf410a6a8 --- /dev/null +++ b/pr/720/docs/search.index/5a649cef0a96.js @@ -0,0 +1 @@ +rn_("AQIAOzAAAAEAABEABQCuBQAAMgwAAOgMAAAKEA0AcREAAAGAAqCAAAARIKAgAAASqWVpAYQCsNAUsQABoJAAABOvYmgBhAKwABF/AAGwABGBAAE0NpcFAACHoCAAABHeoDAAABFFsHAP4gABy0AIOzAAAAEAABEBFAC4AQAApAUAAPgIAAD+CAAAGwkCAAwMAABODAEAdQwBAOsMAAAYDe0Ayg8AAN8PAQDWEAAAkxEAAPESAQDVEwUA8hMAAHkUAACTFAUArxQBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/5a7dfa305296.js b/pr/720/docs/search.index/5a7dfa305296.js deleted file mode 100644 index 514f87c2a..000000000 --- a/pr/720/docs/search.index/5a7dfa305296.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAA9CkTAAABAFoBAQDzBAFzOzAAAAEAAA0AAgCmEwcAnRQFAEcAAAGGoIAAABOGsQAUrAABsEAS4wABsIAUvAABsFATKwABFQAW9JYOAAABAAEAAQABBQDz/g8AAAEAAQBjgISwQBCMAAGgAAAABt4A8AA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5b1f64117211.js b/pr/720/docs/search.index/5b1f64117211.js deleted file mode 100644 index 93ed73bd8..000000000 --- a/pr/720/docs/search.index/5b1f64117211.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUAOzAAAAEAAAcAAwDLEQIAfhMBABQUAgABBADzzhEAAAEAAQAjAAKgYAAAEv1hcvPvEAAAAQDJAQGAAqEQAAAUo7CAFJkAAWl1NwQAgoexUBTAAAGgAAAAEM+wcBPeAAGhMAAAFLQKQBsTgAKwEBMJAAFpcg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/5b2d763cb01a.js b/pr/720/docs/search.index/5b2d763cb01a.js new file mode 100644 index 000000000..3c0c83277 --- /dev/null +++ b/pr/720/docs/search.index/5b2d763cb01a.js @@ -0,0 +1 @@ +rn_("AQ0A9eETAAABAAEAeAABAAEHAPPJEwAAagABACOAAqEQAAAUGm5yAQcA9LcRAAABAAEAAQAzAASgIAAACSiw4BQPAAExZWlyOjAAAAEAAAAAAAkAEAAAAGAEYQROBwoJbAxtDG4MbwxZEVoRAQIA9AoRAAABAJMBAQABAwD0dhEAAAEAfAEBAPMAAmJ1ARsQAAABAwD0CBEAAAEAkwEBAPOEAmRzAQIA8wwJAAABAFkA84ACaXQBGADzxxQAAAEAAQAjgQKwwBPfAAFjbQENAbBAFGcAAWX1KxQAAAEAAQABAAEAE4ICsAARIQABa3MBBAD0rhAAAAEAAQABAAGBAqAgAAARG7BAE3QAAWVp84ICZXQBBAGwYBLGAAFy9CEMAAABAPcDAQDzgANhZW8BCQD28RIAAAEAAAGHADYAAQATgAKwYBDIAAFkbgEGADswAAABAAAFAAIA8xADAI0TAQABAwGgcAAAEy5n9FsHAAABAAgCAQABCQDzfxQAAAEAPAABgQKwgBSRAAGgYAAAFLhkcxcBAIiFsNAUugABoEAAABRisGAUMgBSApAKAQQA9M0TAAABAEoAAQBTgAOwkBSzAAFlaG8BAAGgQAAAEYNlAcYPAAAjgQKwUBEuAAFrdHfsAwCOoZAAABSosLATPgABoKAAABLwsVAUsQAB/cEPOzAAAAEAACEACACBAAAAhwADAHIFAQA3BwcAMwkHAEIMBwBTEAEAmxIAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/5b3c708e7c7f.js b/pr/720/docs/search.index/5b3c708e7c7f.js new file mode 100644 index 000000000..18a2494a1 --- /dev/null +++ b/pr/720/docs/search.index/5b3c708e7c7f.js @@ -0,0 +1 @@ +rn_("AQUAOzAAAAEAAAcAAwDMEQIAfxMBABUUAgABBADzzxEAAAEAAQAjAAKgYAAAEv5hcvPvEAAAAQDKAQGAAqEQAAAUpLCAFJoAAWl1NwQAgYexUBTBAAGgAAAAEM+wcBPfAAGhMAAAFLUKQBsBAAA7MAAAAQAAjAABAAgOjAABAgD2oxMAAAEAqgBZABgAAQAjgQKgIAAAEQ9ydvOAAmVvI4ACoCAAABKbZHQBAAA7MAAAAQAA8AAEAMYFAAABCO0AgwwAAHIRAADzgANkbnY=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5bff1c7ebbc7.js b/pr/720/docs/search.index/5bff1c7ebbc7.js deleted file mode 100644 index cc904f3b2..000000000 --- a/pr/720/docs/search.index/5bff1c7ebbc7.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQgA9OsTAAABAFQAAQABAgGgYAAAFJhz8tsRAAABAAGAArAgECMAAaCQAAAUR2FlAQcBsEAUZgABZfUqFAAAAQABAAEAAQABAwGwQBR8AAF08tsTAAABACOEAqBAAAAUC2JzE4ACsMAUsAABdXkBAQD01xEAAAEAAQABABOAArAwEQMAAWRsN3QAAIuwQBO6AAGgUAAAEXCgkAAAE66wUBMJAAGgMAAADGuzmAc7MAAAAQAAZQATAAkCAQBoBAMAxQUAAMIGAQBhBwEABwkBABQJAAAeCQAAUAkAAIQMQwDeDAAA7g8BABgQAADIEAEA5hABACsRAQCrEQQAvBIBADcTAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5c06b39c26ac.js b/pr/720/docs/search.index/5c06b39c26ac.js deleted file mode 100644 index 00b6f59b7..000000000 --- a/pr/720/docs/search.index/5c06b39c26ac.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQACoKAAABM3oDAAAAzOYWkBeRMAAAEAAbAwEUoAAW7yWAcAAAEAAQEA89QHAADZBwEAEwADsCAQGAMfoFAAABCoZWlz9VsEAAABAAEAAQABAAGEArCgFBoAAbCgFBwAAWNy8wEBdPTsEQAA6wABAAEAAQMBsGAUagABZjswAAABAAAHAAMACAwDAIoTAQASFAEA84ACYWXzgIQAKAU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5c14c7898b88.js b/pr/720/docs/search.index/5c14c7898b88.js deleted file mode 100644 index 4dc9b63e2..000000000 --- a/pr/720/docs/search.index/5c14c7898b88.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9LARAAABAAEAAQABAQDzzhEAAAEAAQATgAIxPL7KBa9lcwEKAPTCEwAAAQABAAEAAYACsCAUPgABoGAAABOPb3YBgAKwMBLFAAGgAAAAE0djZPOAhQUQBg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/5c4ef8f443b9.js b/pr/720/docs/search.index/5c4ef8f443b9.js new file mode 100644 index 000000000..6efed5db0 --- /dev/null +++ b/pr/720/docs/search.index/5c4ef8f443b9.js @@ -0,0 +1 @@ +rn_("AQkBoIAAABS5ZgGZEwAAAQIA9dwQAAABAAEAYAIBAPMAAml1OjAAAAEAAAAAAAcAEAAAALYQ8BLfE+ATDxQQFDAUMRQBCAD1QxQAAAEAAQABAAEA8wIBZvWaEAAAAQABAAEAAQATgAKwoBSPAAFydPMCAmFz88oQAAABAAEAAQQBsEAUZwABZfUrFAAAAQABAAEAAQABAgA7MAAAAQAACwACANUTBQCTFAUA8wMBbTswAAABAAANAAQA0AwAAG4RAADqEgUATxQFAPOBAmNl84ACYWU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5ce895e7e8e7.js b/pr/720/docs/search.index/5ce895e7e8e7.js new file mode 100644 index 000000000..8c063dbe2 --- /dev/null +++ b/pr/720/docs/search.index/5ce895e7e8e7.js @@ -0,0 +1 @@ +rn_("AQAA9CoTAAABAFoBAQDzBAFzOzAAAAEAAA0AAgCnEwcAnhQFAEcAAAGGoIAAABOHsQAUrQABsEAS5AABsIAUvQABsFATLAABFQAW9JYOAAABAAEAAQABBQDz/g8AAAEAAQBjgISwQBCMAAGgAAAABt4A8AA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5d6612847f3a.js b/pr/720/docs/search.index/5d6612847f3a.js deleted file mode 100644 index d47b6f0a5..000000000 --- a/pr/720/docs/search.index/5d6612847f3a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsFARBgABoLAAABP+Y3MBBADzwA8AAAEAAQABgAKgUAAAENagYAAAEUVpcgGAAqAgAAAMdKBgAAARRGVoAQEA83AMAAABAAEAE4ECoBAAAAxzYWMBgAKwEBPJAAGwMA0WAAFlcyMAAqBAAAAUZWV38okUAAABAAEDADswAAABAAAFAAIAbAwDAFgRAQABBgD0EhMAAAEAmQEBABMAArBgExQAAWZt8uIMAAABAAEBAPQREQAAAQCwAAEAI4ACoLAAABPlZGcBggKgoAAAE0egQAAAEHRvdvOAA2ducgGAAqBAAAATC6AwAAAPvWhsV38AAIugcAAAEzewQA++AAE8YFc7MAAAAQAAGgAEAAsCAABsBA4A8AsJAM8MAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5d7b5c402287.js b/pr/720/docs/search.index/5d7b5c402287.js deleted file mode 100644 index 9445644df..000000000 --- a/pr/720/docs/search.index/5d7b5c402287.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEA9yIRAAABAAEA2AIBAIsABQABAgD0shAAAAEAAQABABOAAqDQAAAUc2Nz84ACZW8jgQKwAAdSAAFsdCOAA7AABbMAAbCgFAkAAWRydA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/5d86574c4361.js b/pr/720/docs/search.index/5d86574c4361.js new file mode 100644 index 000000000..49feb487b --- /dev/null +++ b/pr/720/docs/search.index/5d86574c4361.js @@ -0,0 +1 @@ +rn_("AQIA9L8RAAABAAEAAQATAAKgMAAAEYpldPTEEAAAAQABAAEAAQMA9LsRAAABAAEAAQABgAKgAAAAEJWgAAAAEJY0NvMDAXYBAg0AAJcCAACIsKATHQABsCAMJAABsGATFwABsIAS+wABoCAAABEACUxGOjAAAAEAAAAAAAkAEAAAAAUHBgcHBzUM9w9gEaoSqxKsEl8U") \ No newline at end of file diff --git a/pr/720/docs/search.index/5e453f313503.js b/pr/720/docs/search.index/5e453f313503.js new file mode 100644 index 000000000..7513bcc78 --- /dev/null +++ b/pr/720/docs/search.index/5e453f313503.js @@ -0,0 +1 @@ +rn_("AQMA9gENAADrAloAAQDSAgEAAQQAOzAAAAEAAAoABACPEAUA0xIBADQTAQBaFAAAAYYCoAAAABNYoAAAABNZZHLzAgF2AYQTAADzgAJlbycCAADIoDAAAA/roHAAABKjsRAUggABoIAAABQpsNATygABoLAAABQpQGUICTswAAABAAAJAAMAvgUCAB8HBABaDAEAI4ACaG1pVgJQZHIBAAA6MAAAAQAAAAAACgAQAAAAUQlSCSIQchNzE6MTpBNOFKcUvxTAFBOAAqAwAAAQpWx0w4AEoAAAABCVoAAAABCWNDZhZQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/5e4bf3861ee8.js b/pr/720/docs/search.index/5e4bf3861ee8.js deleted file mode 100644 index 68cb7dfa8..000000000 --- a/pr/720/docs/search.index/5e4bf3861ee8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9IgQAAABAAEAAQABEwD1xBQAAAEAAQABAAEAE4ACoMAAABNMYW8BAgKgsAAAFFigsAAAFFljc/PQEAAAAQBeAAGBArBQEfIAAaDAAAAUJ2hp84ACZWkjgAKwsBOMAAFpdAEFAbCAFF8AAXY7MAAAAQAABwACANERAwDCEwMAI4ACsHAR9gABYmR3AgAAhqCgAAATr6CQAAATeAXgAjswAAABAAAFAAIAFQcDAAEQAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5e4f7698639b.js b/pr/720/docs/search.index/5e4f7698639b.js deleted file mode 100644 index d493f7392..000000000 --- a/pr/720/docs/search.index/5e4f7698639b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABsPAUsgABazswAAABAAAIAAMAGRQAAB4UBgBIFAAAEwACsQAUmwABZG7y2hIAAAEAE4ACsBAMUwABZW8BBQA7MAAAAQAADQABAJwRDQABAgDzBxAAAAEAAQABAgD0AxAAAAEAAQABAAEDADswAAABAAAIAAEAuRAIAAGAAqBAAAARELDAFFwAAWVzAQEAOzAAAAEAABMAAQAlEBMAI4ACsJATxgABaW03NgAAiqAQAAAMJqBQAAAUJ7BwFAcAAaAgAAAM8JxVETswAAABAAAGAAMAVgcAAOoQAwC6EgEA84ACbHQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/5e924f1d2e1a.js b/pr/720/docs/search.index/5e924f1d2e1a.js new file mode 100644 index 000000000..6f77a0281 --- /dev/null +++ b/pr/720/docs/search.index/5e924f1d2e1a.js @@ -0,0 +1 @@ +rn_("AQcA9AQSAAABAAEAAQAjAAKgcAAAEgNhcgF4BwAAAQAA9iERAAABAJQDAQAKAAEAAQAAOzAAAAEAAAYAAgCPEwAA9xMFACOIArBAFG0AAWVzAQ0BsEAUZwABZfUrFAAAAQABAAEAAQABBQA7MAAAAQAACAADAP0RAgADEwQAKhQAANcDAACGK7ftx0E1FIQG9cEEAAABAAkIAQABAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/5e927132f915.js b/pr/720/docs/search.index/5e927132f915.js new file mode 100644 index 000000000..774f4eb6b --- /dev/null +++ b/pr/720/docs/search.index/5e927132f915.js @@ -0,0 +1 @@ +rn_("AQYAOzAAAAEAAAkAAQBPEQkAI4ADsGAThQABsDAPyAABaXN0AQgA9UMUAAABAAEAAQABAPMBAWb1mhAAAAEAAQABAAEAY4ADoDAAABNHZWd0") \ No newline at end of file diff --git a/pr/720/docs/search.index/5f09f98d1a04.js b/pr/720/docs/search.index/5f09f98d1a04.js new file mode 100644 index 000000000..002953b6d --- /dev/null +++ b/pr/720/docs/search.index/5f09f98d1a04.js @@ -0,0 +1 @@ +rn_("AYMCoFAAABEUoKAAABNRa3ABAAGwQBKZAAFs9GsJAAABAHgHAQABCAD0rRIAAAEAAQABAAEEAaAAAAAQ7nMBVRAAAAECAaBQAAATDGMBzwwAALcAAACGsEANDQABoJAAABM5oDAAAAwPlRABOzAAAAEAAAgABADIBAAAmQUCANIMAQDADwIAo4CEsDAJKQABoBAAABOHkQBAARABsAAUhQABczswAAABAAAFAAEAnhQFAAEDAPRrCQAAAQB4BwEAY4ADoAAAAAwPbnJ1AQACsNATzQABoDAAAA/DYmr2fAUAAAEAAQBJAAEAdwEBAAGwgBPsAAF0OzAAAAEAAEYABADFBQAAFAkAAB4JAACEDEMAAQkA884SAAABAAEA84ADY2d0AYMCoJAAABQ3oJAAABQ4MjMBgAKgUAAAFGOggAAAE4RjZfMAAnN08kAHAAABAAEAAaCwAAATz2LzWRMAAC4BAQAjgAKgAAAAE1hkciOAAqBQAAAUKWNl84ACaXkBBAD1QBEAAAEAAQABAAEA8wEBbgE2BwAAAQEAOzAAAAEAAAkAAgDjBwcAFRMBAAEGAPS/EwAAAQABAAEAAQ8A9KkUAAABAAEAAQDzgQJobQEAAbBAFGcAAWX1KxQAAAEAAQABAAEAU4ADoCAAABHibG50120AgMugIAAAFJmwYBDSAAGwQA/8AAHAGzgK") \ No newline at end of file diff --git a/pr/720/docs/search.index/5f2c5d55a404.js b/pr/720/docs/search.index/5f2c5d55a404.js new file mode 100644 index 000000000..ac9847889 --- /dev/null +++ b/pr/720/docs/search.index/5f2c5d55a404.js @@ -0,0 +1 @@ +rn_("AQAAOjAAAAEAAAAAAAoAEAAAAOYP5w/XENgQZBH1EfYRExMUE60UrhQBBADz4Q8AAOEAAQDzAAFx9woNAAABAD8DAQDNAGIAAQDzAAJleTowAAABAAAAAAAOABAAAAAJCVMMVAx3EIwQjRAjESQRJRH9E/4TDRQOFIkUjhQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6024cbf2ac8d.js b/pr/720/docs/search.index/6024cbf2ac8d.js deleted file mode 100644 index d6a1a9ad3..000000000 --- a/pr/720/docs/search.index/6024cbf2ac8d.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEBsIATbQABdfJECQAAAQAjgAKwEAlCAAEzNgECAPNRBwAA7wEBAAECAPQ9CQAAAQAICAEAAQIA81AMAAABAAEAE4ACsBAJOwABaXUBAgA7MAAAAQAACwACANQTBQCSFAUA8wkBbTswAAABAAAMAAMAbREAAOkSBQBOFAUAdzAAAIqgMAAAE+qgcAAAEf+gIAAACT+wMBHEAAGwUBABAAEzhQs7MAAAAQAANAIEAP4BAAAkAjIBdQcAAAIK/wA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/60287e11cc71.js b/pr/720/docs/search.index/60287e11cc71.js deleted file mode 100644 index a94ca7392..000000000 --- a/pr/720/docs/search.index/60287e11cc71.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9CUTAAABAJIAAQABAwD0WxMAAAEAmAABAPMFAmJ1OjAAAAEAAAAAAAcAEAAAAIUQhhA9ET4R8BHxETATMRMBAgD0dREAAAEAfAEBAAEFAPN7EQAAAQABAAEEAPTLEgAAAQCpAAEA84CEEQkA") \ No newline at end of file diff --git a/pr/720/docs/search.index/607b24e31083.js b/pr/720/docs/search.index/607b24e31083.js deleted file mode 100644 index f4253903a..000000000 --- a/pr/720/docs/search.index/607b24e31083.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYMCoJAAABQ2oJAAABQ3MjMBgAKgUAAAFGKggAAAE4NjZfMAAnN08kAHAAABAAEAAaCwAAATzmLzWBMAAC4BAQAjgAKgAAAAE1dkcgEAAbCAFDwAAXDyOBQAAAEAQwADoCAAABFgoEAAABK1ZGVz8/gPAABQAwEAE4ICoCAAABQoZWnzgAJjZQEEADswAAABAAAJAAQAXAkBAJ8QAwDiEAEA7xMBAPOAA2VpeQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/60e98a5178e4.js b/pr/720/docs/search.index/60e98a5178e4.js deleted file mode 100644 index d217b0300..000000000 --- a/pr/720/docs/search.index/60e98a5178e4.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYAOzAAAAEAAAkAAQBOEQkAI4ADsGAThAABsDAPyAABaXN0AQgA9UIUAAABAAEAAQABAPMBAWb1mhAAAAEAAQABAAEAY4ADoDAAABNGZWd0") \ No newline at end of file diff --git a/pr/720/docs/search.index/60eabdb6a059.js b/pr/720/docs/search.index/60eabdb6a059.js deleted file mode 100644 index 90fd8382b..000000000 --- a/pr/720/docs/search.index/60eabdb6a059.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYMCsCARhAEioJAAABQpbXABggKwoBQaAAGwoBQcAAFjcgECAaBAAAARg2UBOxAAADOAhLAgEQEAAbAgD7YAAVAUAPOAAm9y") \ No newline at end of file diff --git a/pr/720/docs/search.index/61108dfc4c35.js b/pr/720/docs/search.index/61108dfc4c35.js new file mode 100644 index 000000000..11c400d8b --- /dev/null +++ b/pr/720/docs/search.index/61108dfc4c35.js @@ -0,0 +1 @@ +rn_("AQACoDAAABEcoJAAABOUMGj1AxIAAJkBAQABAAEAE4ACoDAAAA/MZHIjAYSwEAj3A0CwIAwDAQygMAAAD/QSABj1nAUAAC0AAQABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/617ee73e3969.js b/pr/720/docs/search.index/617ee73e3969.js deleted file mode 100644 index ab9f38a15..000000000 --- a/pr/720/docs/search.index/617ee73e3969.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsAARfgABsAARgAABNDYBCwA7MAAAAQAABgABAB4UBgAjgAKggAAAFEhlbyMCA6BgAAAT3bBAFLkAAWVucAEjDAAA8wACYXYB3gYAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/619b1251040a.js b/pr/720/docs/search.index/619b1251040a.js new file mode 100644 index 000000000..ca53c151f --- /dev/null +++ b/pr/720/docs/search.index/619b1251040a.js @@ -0,0 +1 @@ +rn_("AQYAOzAAAAEAAAkAAQBPEQkAAQIAOzAAAAEAABMAAQAlEBMAE4GEoFAAABEQoBAAAAwmoCAAAAzwHEAAE4ACsFAThQABYW4zgAOwMA/IAAFpc3Q=") \ No newline at end of file diff --git a/pr/720/docs/search.index/61b0c96080da.js b/pr/720/docs/search.index/61b0c96080da.js new file mode 100644 index 000000000..d4a115396 --- /dev/null +++ b/pr/720/docs/search.index/61b0c96080da.js @@ -0,0 +1 @@ +rn_("AQcA9eETAAABAAEAeAABAAEHAPPKEAAAAQABAAGAAqAAAAAHWqAQAAAJCmR48wEBZfIcEAAAAQDnAAAAhbBgDOwAAbBADFwAATIIAfTLBAAAhQLeCQEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/62d9bdfe377f.js b/pr/720/docs/search.index/62d9bdfe377f.js deleted file mode 100644 index 2a9aad45b..000000000 --- a/pr/720/docs/search.index/62d9bdfe377f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYMCsQAUvgABsNAUrgABa20BCwA7MAAAAQAABgABAB4UBgAjgAKggAAAFEhlbyMEA6BgAAAT3bBAFLkAAWVucAEjDAAAAQsA8wEUAAABAHUAdwAAAIWgYAAAEpWhAAAAFHkEgQM7MAAAAQAAOwAEALgFBQBPBwAAoAczAIURAABDgAOwgBGEASKgAAAAAhhka3Q=") \ No newline at end of file diff --git a/pr/720/docs/search.index/630085df3b42.js b/pr/720/docs/search.index/630085df3b42.js new file mode 100644 index 000000000..0bbe7a6b0 --- /dev/null +++ b/pr/720/docs/search.index/630085df3b42.js @@ -0,0 +1 @@ +rn_("AYACsEATcgABoMAAABQwZW8BAgD02BEAAAEAAQABABMAA7AgEdwAAbCAFEEAAWFzdAHeDAAAAQQA8/4PAAABAAEAs4CEsEAThQABQQAG") \ No newline at end of file diff --git a/pr/720/docs/search.index/6327cdc02f4b.js b/pr/720/docs/search.index/6327cdc02f4b.js deleted file mode 100644 index 118b4adf3..000000000 --- a/pr/720/docs/search.index/6327cdc02f4b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQgA834UAAABADwAI4ACsAAQ3wABbW4BgAOgQAAAE12wIBQaAAGgIAAAD9NoaXkBCQGggAAAFLhmAZgTAAABAwGwABQxAFJz8q0QAAAtA0OAA7AgD88BK7BQErwAAWFvcgECAPXcEAAAAQABAF8CAQDzAANpdHU6MAAAAQAAAAAAEQAQAAAAfQcsCfMMORC2EOER7xIpEyoT3hPfE+UTDhQPFC8UMBSEFIUUAQYA9BITAAABAJkBAQATAgKwYBMUAAFmbfLiDAAAAQAjggKwQBNDAAFlbAGAAqAwAAAUYbCwE7QAAWFsAQYA8+EPAADhAAEAAQUA9AUUAAABAE4AAQDzAgFj8gcTAAABAAECAaAwAAAQd2EBVgwAAAGAArBQESsAAbAgD6sAAWNu84ACbnQBBQA7MAAAAQAADgACAOgMAAAKEA0AAQIAOzAAAAEAAAcAAQBTCQcA5wUAAAmgMAAADFWgsAAAFC+ggAAAEaqw0BQ+AAEwYWZpa21ydXY7MAAAAQAAagIFAAACAABtA+0AdgcAAAIL7QAIDowAAQEA8/kPAAABAAEAE4ACsMAUuQABdHUBAwDzwBIAAAEAAQABAQD1PxEAAAEAAQABAAEAAQEBsDAP6gDxdPZoBwAAAQCKAPoHqwD9AWOAA7CQFAcAAWFtdAEDAaBAAAAUZWXyiRQAAAEAE4ACsGAUvAABZXIBAwGgAAAAE+VzAfkQAAABAgA6MAAAAQAAAAAACgAQAAAAUQlSCSIQcRNyE6IToxNNFKYUvhS/FIMABKCAAAASmrBwEW4AAbAgEQ8A8GZucnYB8gcAAAGBAqAAAAAJLKAwAAAP03N0xwEAgMawABQ8AAGwkBKYAAGgEAAAB04AEogoAQIAOzAAAAEAAA0ABgBZEAUAaxEBANASAQABFAEAWBQAAHcUAAATggKw8BS8AAFmZwGAArCAFJAAAaBgAAAUt2RzE4ACsMATzAABaW8BCAD1QhQAAAEAAQABAAEA8wIBZvWaEAAAAQABAAEAAQAjgAOgIAAAD82woBSOAAFkcnT3+wcAj6AwAAAPw5fXDzswAAABAABSAR4AhwQBALQEAgB8BQIApgUCAMcFAQC8BgQAPwcAAFcHAADuBwEAAgkCADAJAQApDAMAVwwBAH8MAwDkDAEAnQ4EAfAPAQBvEAIAtxABAMoQAgD4EAEAixEAAL4RAwDoEQEAohIAAOISAAAaEwEAhBMBAKYTBwCdFAUA") \ No newline at end of file diff --git a/pr/720/docs/search.index/6344cc548748.js b/pr/720/docs/search.index/6344cc548748.js deleted file mode 100644 index ad3a2f768..000000000 --- a/pr/720/docs/search.index/6344cc548748.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYICsEASxwABsEASyQABNDYBCwDzyBMAAGoAAQABBgD0tRQAAAEACgABAPMCAXIBERQAAPMDAWU7MAAAAQAABQACAH8QAwAwEQEA84ADYWVp") \ No newline at end of file diff --git a/pr/720/docs/search.index/642891ddd2e0.js b/pr/720/docs/search.index/642891ddd2e0.js deleted file mode 100644 index 7c2786d53..000000000 --- a/pr/720/docs/search.index/642891ddd2e0.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsIATCQABsKAThAABaXQBgAKw4BSGAAGwQBBTAAFscgEGAPTqEAAAAQABAAEARwUAAIeg0AAAFF6wUBBRAAGgAAAAE4aw8BQ4AAEFkQPy9A8AALAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/643b6936a58b.js b/pr/720/docs/search.index/643b6936a58b.js deleted file mode 100644 index 5e579385b..000000000 --- a/pr/720/docs/search.index/643b6936a58b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEBsIATbQABdfJECQAAAQAjgAKwEAlCAAEzNgEGAPPxEAAAAQAVAROAArAAD7YAAW91AQIA81EHAADvAQEAAQMA880SAAABAAEAI4ACsAARxAABaGkBAAA7MAAAAQAAEwABAIQHEwAjgAKgMAAADN1hZfOAAnJ0E4ACsDATvAABYWwBAAGggAAAFLhm8voIAACeCgEHAPVmEwAAAQABAAEAAQAjgAKgUAAAEWNhb/MCAmZzOzAAAAEAAAgABABNBwAAfgcFAAQNAACbEQAAE4ACoEAAAAwNYW8BAwGwQBR8AAF08tsTAAABACOFAqBAAAAUC2JzIwADsEARAwABoFAAABFwYWJm9wcJAAABAEgAeAcBAGIAAQATgQKgUAAAEf9ndAGAAqBAAAAR7KAgAAAT6mFpAQIA9D0JAAABAAgIAQABAgDzUAwAAAEAAQATgAOwEAk7AAGwMBQcAAFpdXkBAgA7MAAAAQAACwACANQTBQCSFAUA8wgBbTswAAABAAAMAAMAbREAAOkSBQBOFAUAAYECoIAAABLWoHAAABQvYXPzgAJucrfbAQCNoUAAABSNoCAAAAk/sFAQAQABN5UPOzAAAAEAADUCBQD+AQAAJAIyAQgHAAB1BwAAAgr/AA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/644655b6a37b.js b/pr/720/docs/search.index/644655b6a37b.js deleted file mode 100644 index 99228ec90..000000000 --- a/pr/720/docs/search.index/644655b6a37b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIBsEATugABZfLCBgAAAQABBADzbxAAAAEAAQBDAAOwQBMcAAGxABQBAAFlZnA7MAAAAQAAJAAGABkCAADRBgwA3wYMAKIPBgAQEQAAXhMBAGOAA7AwDBEABWFlaQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/6483b5e7deef.js b/pr/720/docs/search.index/6483b5e7deef.js deleted file mode 100644 index d11d89b9c..000000000 --- a/pr/720/docs/search.index/6483b5e7deef.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACoFAAABFFoFAAABKVYXUBgwKxABS+AAGw0BSuAAFrbQELADswAAABAAAGAAEAHhQGACOAAqCAAAAUSGVvIwMDoGAAABPdsEAUuQABZW5wASMMAAAjgAKgQAAAENZtcAELAPMBFAAAAQB1APcAAACFoQAAABR5BIEDOzAAAAEAADsABAC4BQUATwcAAKAHMwCFEQAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/64c2c1e2630c.js b/pr/720/docs/search.index/64c2c1e2630c.js deleted file mode 100644 index fd3851d0f..000000000 --- a/pr/720/docs/search.index/64c2c1e2630c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsAAT5gABsAAT6AABNDYBBgD0tRQAAAEACgABAPMCAnJ28/UPAAABABsE8wIBZTswAAABAAAFAAIAfxADADARAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/64ddaa20de73.js b/pr/720/docs/search.index/64ddaa20de73.js deleted file mode 100644 index 2e6af0109..000000000 --- a/pr/720/docs/search.index/64ddaa20de73.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9LARAAABAAEAAQABCgD0whMAAAEAAQABAPOBAm10AQYA83IRAAABAAEAAYICsGATSAABsNAUaAABaXITgAKwEAzpAAFlaQEFAPQFFAAAAQBOAAEA8wQBY/IHEwAAAQABBQDz1xIAAAEAAQDzggJmdAEAAbAAFF8AAWT0+wsAAAEAAQABAPOBAmVpNwYAAImxMBSJAAGgYAAAEXGgUAAAEQWwkBMYAAGwQBEBAAG1EAcBOxQAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/652e095d3b43.js b/pr/720/docs/search.index/652e095d3b43.js deleted file mode 100644 index d8048c8ae..000000000 --- a/pr/720/docs/search.index/652e095d3b43.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQ8A9CUUAAABAE8AAQABBAD0gxAAAAEAtwABAAECADowAAABAAAAAAAJABAAAADeEd8R+hL7EusT7BNAFEEUvBS9FPMAAW/ycwkAAAEAU4ADsQAUiwABaG9ww4CEoBAAABNdsIAToAABBQAG") \ No newline at end of file diff --git a/pr/720/docs/search.index/65a7280005a0.js b/pr/720/docs/search.index/65a7280005a0.js new file mode 100644 index 000000000..0320d05b7 --- /dev/null +++ b/pr/720/docs/search.index/65a7280005a0.js @@ -0,0 +1 @@ +rn_("AQAA9LEPAAABAAEAAQDzAgFzATMRAAABAAKwgBSRAAGgYAAAFLhkc/L3CAAAQAOTgISwwBPNAAGgEAAAEd4AwUA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/66141220346d.js b/pr/720/docs/search.index/66141220346d.js new file mode 100644 index 000000000..45b6bd461 --- /dev/null +++ b/pr/720/docs/search.index/66141220346d.js @@ -0,0 +1 @@ +rn_("AQMBoAAAABNOc/TODwAA+QMBAAQAAQECsGAUPwABsEAUfQABZHQ7MAAAAQAADQAGAP8SAwBsEwEA3BMBAPMTAQByFAEAmhQBAAEBA7BwEgEAAbCAEtsAAYATgQAQ+G1uczswAAABAAALAAIA8QgFAGETBQCjgISwsBPKAAGxcBS9AAEIQIIBgAKwMBSxAAGxABQ/AAFjbgEBADswAAABAAAGAAEAwxQGAPMGAWX0cBQAAAEANAABABMBA7BAFJwAAbBgE4gAiWFydfN7EAAAegIBAHcBAACFsDATMwFJEYEIOzAAAAEAAAYAAgCPEwAA9xMFAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/6648973ff739.js b/pr/720/docs/search.index/6648973ff739.js new file mode 100644 index 000000000..a399bc1c4 --- /dev/null +++ b/pr/720/docs/search.index/6648973ff739.js @@ -0,0 +1 @@ +rn_("AQMA9BAJAAABAFIDAQABAwDzYAwAAAEAAQDzgAJpbwEBAbBQEQ0AAWP0XQcAAAEAAQAIAiOBAqBQAAAQz2NuAQQAOzAAAAEAAAcAAwDMEQIAfxMBABUUAgABAQA6MAAAAQAAAAAABwAQAAAA7hHvES8TMBOJE4oTNRQ2FPMJAWkBDBEAANcCAACHsMATdAABoFAAAA+1oRAAABRfFAEXOzAAAAEAACMAAQC5ASMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/66753853a13a.js b/pr/720/docs/search.index/66753853a13a.js deleted file mode 100644 index 73b9c9ad1..000000000 --- a/pr/720/docs/search.index/66753853a13a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACoCAAAA/PoDAAABPaYXLzAAF0AX0HAAABBAGgQAAAFGVl8okUAAABAAEFADswAAABAAALAAUAWRAFANASAQABFAEAWBQAAHcUAADjAISgMAAAD82FAAI7MAAAAQAACwAFAKYFAgC8BgQAVwwBAIsRAADiEgAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/66fc142f300b.js b/pr/720/docs/search.index/66fc142f300b.js deleted file mode 100644 index 0cd879c0f..000000000 --- a/pr/720/docs/search.index/66fc142f300b.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQACoCAAABHdoDAAABKoYmgByg8AAAETAbAAFIQAAXM7MAAAAQAABQABAJ0UBQABBwDzqRIAAAEAAQDzgANkcnQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/674efefd99bd.js b/pr/720/docs/search.index/674efefd99bd.js new file mode 100644 index 000000000..de2e0b768 --- /dev/null +++ b/pr/720/docs/search.index/674efefd99bd.js @@ -0,0 +1 @@ +rn_("AQIA9CYTAAABAJIAAQABAgD0/hAAAAEAmwABAAEDAPRcEwAAAQCYAAEAAQIBoEAAABNHcjswAAABAAAHAAIA/BABAJQRBQDzAIQDQAg6MAAAAQAAAAAAFQAQAAAASgdLB0wH2A/ZD4UQhhCmEKcQPhE/EfER8hEkEyUTMRMyE0MTbhNvE7cTuBM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/68343b5d5132.js b/pr/720/docs/search.index/68343b5d5132.js new file mode 100644 index 000000000..79ad6a3fb --- /dev/null +++ b/pr/720/docs/search.index/68343b5d5132.js @@ -0,0 +1 @@ +rn_("AQAAOzAAAAEAAAYAAgCPEwAA9xMFACOIArBAFG0AAWVzAQQBsDATXwABY/OHEQAAAQABAAEFADswAAABAAAIAAMA/RECAAMTBAAqFAAA8wMDY2Vw88sMAAABAAEAAQABsGAUDwABZQFIFAAA8wIBc/YjCQAAAQABACEIPwAiAQECAaBQAAARhnIBJxEAAPOAA2ZtcA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/686d69560250.js b/pr/720/docs/search.index/686d69560250.js new file mode 100644 index 000000000..5bf0725d4 --- /dev/null +++ b/pr/720/docs/search.index/686d69560250.js @@ -0,0 +1 @@ +rn_("AYICsEASyAABsEASygABNDYBCwDzyRMAAGoAAQABBgD0thQAAAEACgABAPMCAXIBEhQAAPMDAWU7MAAAAQAABQACAH8QAwAxEQEA84ADYWVp") \ No newline at end of file diff --git a/pr/720/docs/search.index/68a60c89df9d.js b/pr/720/docs/search.index/68a60c89df9d.js new file mode 100644 index 000000000..652114c09 --- /dev/null +++ b/pr/720/docs/search.index/68a60c89df9d.js @@ -0,0 +1 @@ +rn_("AQIA9L8RAAABAAEAAQDzAAFl9MQQAAABAAEAAQABAwD0uxEAAAEAAQABAMcAAACFsKATHQABsCAMJAABsIAS+wABCAwG8wUHAAABAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/6957822f864f.js b/pr/720/docs/search.index/6957822f864f.js deleted file mode 100644 index 9ae377e51..000000000 --- a/pr/720/docs/search.index/6957822f864f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQkA834UAAABADwAAYACoEAAABNdsCAUGgABaGkBAQDz+Q8AAAEAAQATgAKwwBS5AAF0dQGBArCAFJAAAaBgAAAUt2RzNwMAgIagQAAAFGGwYBQxAFICkA4BAAGwUBENAAFj9F0HAAABAAEACALDgISgEAAADHegUAAAEqIMQAQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6971cfa6cb7c.js b/pr/720/docs/search.index/6971cfa6cb7c.js new file mode 100644 index 000000000..43aee5df9 --- /dev/null +++ b/pr/720/docs/search.index/6971cfa6cb7c.js @@ -0,0 +1 @@ +rn_("AQQA9n8UAAABABEAAQAmAAQAAQMA88ESAAABAAEAI4ECsSAUvQABY2sTgAKgMAAAFDtuclMAA6BAAAAMH2VvcvQpEQAAgAHAAQEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/69b1257472c5.js b/pr/720/docs/search.index/69b1257472c5.js deleted file mode 100644 index 86ddd5429..000000000 --- a/pr/720/docs/search.index/69b1257472c5.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYA9I4RAAABAAEAAQABAgA7MAAAAQAACgAEAI8QBQDSEgEAMxMBAFkUAADzgAJmbgEBADswAAABAAAIAAIAog8GAF4TAQDzgAJkbgEBAPMuBwAAAQABAAGGAqAAAAATV6AAAAATWGRy8wEBdgGDEwAAQwADsIAS5wABsLAUiwABa2xyOzAAAAEAAAwAAwAlBwgABg0BAEgQAQABAgD19AcAAAEAAQABAAEA8wCEFEEAAYAAAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6a398dfc8494.js b/pr/720/docs/search.index/6a398dfc8494.js new file mode 100644 index 000000000..ab2abfc3c --- /dev/null +++ b/pr/720/docs/search.index/6a398dfc8494.js @@ -0,0 +1 @@ +rn_("AYMCsQAUvwABsNAUrwABa20BCwA7MAAAAQAABgABAB8UBgAjgAKggAAAFEllbyMEA6BgAAAT3rBAFLoAAWVucAEjDAAAAQsA8wIUAAABAHUAdwAAAIWgYAAAEpahAAAAFHoEgQM7MAAAAQAAOwAEALgFBQBPBwAAoAczAIYRAABDgAOwgBGFASKgAAAAAhhka3Q=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6af8c712a209.js b/pr/720/docs/search.index/6af8c712a209.js new file mode 100644 index 000000000..dfe3c2e91 --- /dev/null +++ b/pr/720/docs/search.index/6af8c712a209.js @@ -0,0 +1 @@ +rn_("AYMCsQAUvwABsNAUrwABa20BCwDzAhQAAAEAdQAzAYSgYAAAEpahAAAAFHoEgAM7MAAAAQAANAACAE8HAACgBzMA") \ No newline at end of file diff --git a/pr/720/docs/search.index/6b013a6e0b24.js b/pr/720/docs/search.index/6b013a6e0b24.js new file mode 100644 index 000000000..1c474d004 --- /dev/null +++ b/pr/720/docs/search.index/6b013a6e0b24.js @@ -0,0 +1 @@ +rn_("AYECoCAAABSZsEAP/AABYnABBQD0SxMAAAEAmAABAPMDAWMBsRIAAAEMAbAAFIUAAXM7MAAAAQAABQABAJ4UBQDzgAJudgGAArAwDFcAAaAwAAAMWWlvAQMBoAAAABRjcwH5EQAAAQQA9BIMAAABAAEAAQDXAwCAhrAABXQAAZFIAQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/6b063349b342.js b/pr/720/docs/search.index/6b063349b342.js new file mode 100644 index 000000000..882e298f8 --- /dev/null +++ b/pr/720/docs/search.index/6b063349b342.js @@ -0,0 +1 @@ +rn_("AQEA9GcHAAB6COEAAQABBQD0ShQAAAEAAQABAAEFAPQ8EwAAAQCUAAEA8wICY3X1VhAAAAEAxgABAAEA84ACbnM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6b2a45acfbf1.js b/pr/720/docs/search.index/6b2a45acfbf1.js deleted file mode 100644 index 368fbfe11..000000000 --- a/pr/720/docs/search.index/6b2a45acfbf1.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIAOzAAAAEAAAUAAQCSFAUA8w0BbTswAAABAAAFAAEAThQFAEMAhLAAFF8AAbBAEsMAAbAAE4cAiTgAAjswAAABAAAcAAcA+wsDADMRBwDnEgEAZhMEAEIUBABJFAMAuBQAAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/6b7ac8f4866d.js b/pr/720/docs/search.index/6b7ac8f4866d.js deleted file mode 100644 index df5f8cbd8..000000000 --- a/pr/720/docs/search.index/6b7ac8f4866d.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQEBsFAP1gABY/SjBAAAAQABAMcAAQABoIAAABS4ZgGYEwAA8wYBc/IEDQAAlwQzAAOgYAAAFJhjaXPy2xEAAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/6b95550a6642.js b/pr/720/docs/search.index/6b95550a6642.js deleted file mode 100644 index b2c094780..000000000 --- a/pr/720/docs/search.index/6b95550a6642.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9QATAAABAPIAfgABABOAArAwEzIBSWlwAQYA87ATAAABAAEA8wICYnMBQBAAAPMBAWYBZgcAAAECAPRbEwAAAQCYAAEAM4ADsEATJwABaXV5") \ No newline at end of file diff --git a/pr/720/docs/search.index/6be7775146ac.js b/pr/720/docs/search.index/6be7775146ac.js deleted file mode 100644 index e5ca5bc69..000000000 --- a/pr/720/docs/search.index/6be7775146ac.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBsEARYQABZQGVDgAAAQUAOzAAAAEAAAYAAQBfEAYAAQMAOzAAAAEAAAUAAQDXDAUA8wACcHM6MAAAAQAAAAAADQAQAAAAqQWqBcEGEglZDGYMBhEHEbYStxIOEw8TEBMREzMAA7BQD9AA02RwcjswAAABAAAPAAYAogQAAGgFAwC9DwAA4hEDALESAwDlEgEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/6c223b5d689a.js b/pr/720/docs/search.index/6c223b5d689a.js deleted file mode 100644 index 36f449874..000000000 --- a/pr/720/docs/search.index/6c223b5d689a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsEATcQABoMAAABQvZW8BAgD01xEAAAEAAQABABMAA7AgEdsAAbCAFEAAAWFzdAHeDAAAAQQA8/4PAAABAAEAs4CEsEAThAABQQAG") \ No newline at end of file diff --git a/pr/720/docs/search.index/6c2c4dc5a026.js b/pr/720/docs/search.index/6c2c4dc5a026.js deleted file mode 100644 index dd009328f..000000000 --- a/pr/720/docs/search.index/6c2c4dc5a026.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQgA9PwTAAABAIsABQATAAOwkBRjAAGwUBNBAWZnbHA7MAAAAQAAEgAJAGkQAgDtEQEALhMBAFETAQCIEwEA7RMBACUUAQA0FAEAdRQBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/6cc5a584e86e.js b/pr/720/docs/search.index/6cc5a584e86e.js deleted file mode 100644 index 6d27d9819..000000000 --- a/pr/720/docs/search.index/6cc5a584e86e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQgBoIAAABS4ZgGYEwAAE4ACoOAAABR5YnABAwGwABQxAFJz9ugPAAABAMQALAABAAADAYACsEASvAABoBAAABEYcHIBgQOgAAAAEYmwAA/PASugEAAAD8dlc3XzgANhb3IBAgD13BAAAAEAAQBfAgEAAQQAOzAAAAEAAAkAAQBOEQkAAQAA9L4RAAABAAEAAQABgAKgkAAAE/OwUBKkAAFid/OAAmR0o4CEsFAUDgABsJATMwABQCADVwMAAIagcAAAE+qgQAAAFF4wQQw7MAAAAQAAQgAhAMQEAQCIBQoAfQcAACYJAQAsCQAALQwBAFAMAgDmDAEA8wwAAJoOAAC4DwQAzw8AAPIPAQA5EAAAthAAAMQQAwDoEAEA+hAAACARAQCNEQAA4REAAOoRAQDvEQAA7xIAACkTAQDeEwEA5RMAAA4UAQAvFAEARxQAAIQUAQC1FAEAwBQBAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/6d172713b950.js b/pr/720/docs/search.index/6d172713b950.js deleted file mode 100644 index 08cf09140..000000000 --- a/pr/720/docs/search.index/6d172713b950.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9CUTAAABAJIAAQABAwD0WxMAAAEAmAABAPMCAmJ1OjAAAAEAAAAAABMAEAAAAEoHSwdMB9gP2Q+FEIYQphCnED0RPhHwEfERIxMkEzATMRNCE7YTtxM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6d3e4d35925e.js b/pr/720/docs/search.index/6d3e4d35925e.js deleted file mode 100644 index 9e8346fef..000000000 --- a/pr/720/docs/search.index/6d3e4d35925e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYA9OsTAAABAFQAAQAjgAKhEAAAFKdjchOAAqAgAAAJC2h5AQEBoGAAABSYc/LbEQAAAQAjgAKwIAlxAAFldQGAArAgECMAAaCQAAAUR2FlAQcBsEAUZgABZfUqFAAAAQABAAEAAQABAAD0KRMAAAEAWgEBAPMEAXM7MAAAAQAADQACAKYTBwCdFAUARwAABIaggAAAE4axABSsAAGwQBLjAAGwgBS8AAGwUBMrAAEVABb0lg4AAAEAAQABAIMAhLBAFLIAAbAwExoAAbAwE7oAAcAAAzowAAABAAAAAAAJABAAAAC6BBEREhG0EbURwhHDEQkUChR6FAEDAbBAFHwAAXTy2xMAAAEAI4QCoEAAABQLYnMTgAKwwBSwAAF1eQGAAqAAAAAJK7AgEQMAAWdwAQEA9NcRAAABAAEAAQDzgAJkbLfoAACMoNAAABOSoFAAABFwoJAAABOusFATCQABoDAAAAxrt5gHOzAAAAEAAGgAFQADAgEACQIBAGgEAwDFBQAAwgYBAGEHAQB0BwAABwkBABQJAAAeCQAAUAkAAIQMQwDeDAAA7g8BABgQAADIEAEA5hABACsRAQCrEQQAvBIBADcTAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6d5bf0cc001d.js b/pr/720/docs/search.index/6d5bf0cc001d.js deleted file mode 100644 index 2c9607147..000000000 --- a/pr/720/docs/search.index/6d5bf0cc001d.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9MsSAAABAKkAAQABCAD0ihMAAAEAhwABADMBA7BAE1kAAWFiZTowAAABAAAAAAAMABAAAAAxBzIHMwf0DPUMxw86EIgQiRCKEIsQoxJ4EwEAADswAAABAAAiAA4AxAQBAIgFCgAmCQEALQwBAOYMAQCaDgAAuA8EAM8PAADyDwEA6BABAPoQAACNEQAA6hEBAO8RAAABgQKwABF+AAGwABGAAAE0NiOAArCAFI4AAW9wAQABsEATVQABZfOJEQAAWgEBALcBAICFoGAAABEmEAEL") \ No newline at end of file diff --git a/pr/720/docs/search.index/6d8907ef9d8d.js b/pr/720/docs/search.index/6d8907ef9d8d.js new file mode 100644 index 000000000..e8eed362f --- /dev/null +++ b/pr/720/docs/search.index/6d8907ef9d8d.js @@ -0,0 +1 @@ +rn_("AQEAOzAAAAEAAAYAAQDDFAYA8wYBZfRwFAAAAQA0AAEAEwCEoCAAAAlbsEAUnAABsGATiACJAQEJ83sQAAB6AgEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/6dc536e1c4d1.js b/pr/720/docs/search.index/6dc536e1c4d1.js deleted file mode 100644 index 6707d1158..000000000 --- a/pr/720/docs/search.index/6dc536e1c4d1.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQQA9n4UAAABABEAAQAmAAQAAQMA88ASAAABAAEAI4ECsSAUvAABY2sTgAKgMAAAFDpuclMAA6BAAAAMH2VvcvQoEQAAgAHAAQEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/6e058b4cb634.js b/pr/720/docs/search.index/6e058b4cb634.js deleted file mode 100644 index 69fd54940..000000000 --- a/pr/720/docs/search.index/6e058b4cb634.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIAOjAAAAEAAAAAAAgAEAAAABoMGwypD6oP6g/bEAARkBOREwEAAPQ3CQAAAQABAAEAAQUBsDATGgABaPMJFAAAAQBwABODArAwEM0AAWNwAQMA9OgPAAABAPAAAQABgQKgAAAAEYmgEAAAD8dldfOAAmFyAQAA9L4RAAABAAEAAQABgAKgkAAAE/OwUBKkAAFid/OAAmR0E4ACsJATMwABbnLzAAJldPTEEAAAAQABAAEAAQEA9XoMAAABAAEAAQABABOAArCwE+8AAWFvIwACsEAM/AABZXQ7MAAAAQAACQAEAL8EAQCCBQEAXAwBALARAwABAgA7MAAAAQAACQACAOMHBwAUEwEAAYACsJATfgABoKAAABPyZXYTgAKxgBTEAAFjbQGCArBAFBwAAaBQAAAR7GJmE4ACoEAAABRHZHMjgAKg0AAAFJhjbvOAhBEBQAEFAbBAE1kAAWUBoxIAAEOCA6EAAAAUpqDQAAAUeGttcxOAArBgEOQAAWFyAQUAOzAAAAEAAI0AAgD3EAAACBKMAAGCA7AgExYAAbAgEH0AAbBAEXkAAWtsc1OAA7AgFHwAAWt0dQGJhKCAAAAUt6BAAAAUYaBgAAAUg6CQAAAUuwKAChOCA6CgAAAT8bDQFFoAAWNpdQEBAPS6EQAAAQABAAEAQ4ADsXAUwgABoNAAABQwY29zI4ACsGAQ4gABaW8BAAD0JAwAAAEAUwABACOBAqDgAAAUTWV5AQ0AOjAAAAEAAAAAAAcAEAAAAFETUhPtE+4TJRQmFHUUdhQBgQKwQBNxAAGgwAAAFC9lbwECADowAAABAAAAAAAIABAAAADfD+APkhHwEvES8RN4FK4UrxTzAQFvOzAAAAEAAAkABABcCQEAnxADAOIQAQDvEwEA84ADbW5yAQAAOzAAAAEAAAYAAgCOEwAA9hMFAEOAA7BAFGwAAaAgAAAM+2VycyMAArAwE9IAAWNy8rwTAAABAAGBArCAExwAAaEAAAAUd2NmAQsA9HoTAAABAAEAAQABgAKgAAAAEJWgAAAAEJY0NvMCAXYBAg0AAPMAAmRsARcJAADX/jkAkrCgFBoAAbBwEd4AAbCAEvoAAaCwAAATNZ3dfzswAAABAAAXAAsAqwEBALsEAwB/BQIA+wYBAAUHAgA1DAAA9w8AAF8RAADOEQIAqRICAF4UAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6e3afbd9ac87.js b/pr/720/docs/search.index/6e3afbd9ac87.js deleted file mode 100644 index 526dd7165..000000000 --- a/pr/720/docs/search.index/6e3afbd9ac87.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYACsHAR3gABsCAP6gDxaHkBBQD0Bg0AAAEAQQMBAAEAAPRgDAAAAQABAG8AAQIAOjAAAAEAAAAAAAkAEAAAAN8P4A/WEJIR8BLxEvETeBSuFK8UAQMA8xsJAAABAAEA1wMAAIagQAAAEfkYQAc6MAAAAQAAAAAAFwAQAAAAaAdpB/MHKAlcCV0JBQ3ID8kP7Q+YEJ8QoBChEKIQ4hDjEBkRGhGVEu8T8BMaFBsU") \ No newline at end of file diff --git a/pr/720/docs/search.index/6e9d4bfea4fb.js b/pr/720/docs/search.index/6e9d4bfea4fb.js deleted file mode 100644 index 3099aae81..000000000 --- a/pr/720/docs/search.index/6e9d4bfea4fb.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIAOjAAAAEAAAAAAA4AEAAAAA0NDg0VEfkR+hH7EbUSvhK/EsMSxBIcEx0TVRNWEwEJAPN7EQAAAQABAAEKAPPNEgAAAQABAAEGAPU/EQAAAQABAAEAAQDzgAJkbnMAhLEgFD4AAQARA/InEwAAAQABDQD2ohMAAAEAqgBZABgAAQABgAKwoBO6AAGgEAAADDZjdQEBAPTMEwAAAQBKAAEA8wABZfJxCQAAAQD3AACAxbAwELcAAQACqAg=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6f49c791ea73.js b/pr/720/docs/search.index/6f49c791ea73.js new file mode 100644 index 000000000..aa669bb0e --- /dev/null +++ b/pr/720/docs/search.index/6f49c791ea73.js @@ -0,0 +1 @@ +rn_("AQsA9KUTAAABAA8AAQABBAGwQBNaAAFlAaQSAADzAAF0AWIUAAABDQDzeRQAADYAAQABEADzpxQAABgAAQDzgQNrbXMBAAA7MAAAAQAABgACAI8TAAD3EwUAI4YCsEAUbQABZXMBBAD0xBAAAAEAAQABAPOAA2NydDOAA7BgEOQAAWFscg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/6f69eae96848.js b/pr/720/docs/search.index/6f69eae96848.js new file mode 100644 index 000000000..8517dbde5 --- /dev/null +++ b/pr/720/docs/search.index/6f69eae96848.js @@ -0,0 +1 @@ +rn_("AQkBoEAAABRmZfKKFAAAAQABgAKwAAzpAAGggAAAE8xkcAECA7BgE0kAAbDQFGkAAaCAAAAT62lycwF0FAAA1wAAgIWwMA/EAAGhMAAAFImQSQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6f97b59b2ed3.js b/pr/720/docs/search.index/6f97b59b2ed3.js new file mode 100644 index 000000000..ef4958211 --- /dev/null +++ b/pr/720/docs/search.index/6f97b59b2ed3.js @@ -0,0 +1 @@ +rn_("AQEAOzAAAAEAAAYAAQDDFAYA8wYBZfRwFAAAAQA0AAEAEwMDsEAUnAABsGATiACJYXJ183sQAAB6AgEAI4ACgBF8ABABZHI=") \ No newline at end of file diff --git a/pr/720/docs/search.index/6fb57124e92e.js b/pr/720/docs/search.index/6fb57124e92e.js deleted file mode 100644 index 8a5afa4d5..000000000 --- a/pr/720/docs/search.index/6fb57124e92e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQMBoAAAABNNc/TODwAA+AMBAAQAAQECsGAUPgABsEAUfAABZHQ7MAAAAQAADQAGAP4SAwBrEwEA2xMBAPITAQBxFAEAmRQBAAEBA7BwEgAAAbCAEtoAAYATgAAQ+G1uczswAAABAAALAAIA8QgFAGATBQCjgISwsBPJAAGxcBS8AAEIQIIBAIWgcAAAEp+wMBSwAAGgcAAAEQ+xABQ+AAGwABNBAWYGIQHyeAUAAAEAAQEAOzAAAAEAAAYAAQDCFAYA8wYBZfRvFAAAAQA0AAEAEwEDsEAUmwABsGAThwCJYXJ183sQAAB5AgEAdwQAAIegEAAABa2wMBMyAUmgQAAAETIRwQw7MAAAAQAABgACAI4TAAD2EwUA") \ No newline at end of file diff --git a/pr/720/docs/search.index/7062e3671fca.js b/pr/720/docs/search.index/7062e3671fca.js new file mode 100644 index 000000000..3ab026e81 --- /dev/null +++ b/pr/720/docs/search.index/7062e3671fca.js @@ -0,0 +1 @@ +rn_("AQAA9D0JAAABAAkIAQABCQGggAAAFLlmAZkTAAABAgD13BAAAAEAAQBgAgEA8wACaXU6MAAAAQAAAAAABwAQAAAAthDwEt8T4BMPFBAUMBQxFAEIAPVDFAAAAQABAAEAAQDzAgFm9ZoQAAABAAEAAQABABOAArCgFI8AAXJ08wACYXPzyhAAAAEAAQDzgAJ0dg==") \ No newline at end of file diff --git a/pr/720/docs/search.index/716b8677ab3a.js b/pr/720/docs/search.index/716b8677ab3a.js new file mode 100644 index 000000000..15c1bb179 --- /dev/null +++ b/pr/720/docs/search.index/716b8677ab3a.js @@ -0,0 +1 @@ +rn_("AQIA9ecRAAABACUBAQBhAQEBAPcjEQAAAQABANgCAQCLAAUAAQIA9LIQAAABAAEAAQATgAKg0AAAFHRjc/OAAmVvI4ACsAAHUgABbHTzAAJhcvKrDwAAAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/71a0950cf629.js b/pr/720/docs/search.index/71a0950cf629.js new file mode 100644 index 000000000..9c3d21432 --- /dev/null +++ b/pr/720/docs/search.index/71a0950cf629.js @@ -0,0 +1 @@ +rn_("AQQAOjAAAAEAAAAAAAcAEAAAANgP2Q+mEKcQJBMlE7cTuBMBBAD02g8AAAEAAQABAAEAiKEQAAAUe4AI/wAa3qBAAAARFbBgFGsAAaAQAAAMg7BQFAQAAbAwEXgAAbEgFI8AATnBAjowAAABAAAAAAARABAAAAAVCRYJKQkqCQgMCQwKDAsMEQwWDN0MohKLE4wToROiExMUFBTzgANlaW8=") \ No newline at end of file diff --git a/pr/720/docs/search.index/71b075553573.js b/pr/720/docs/search.index/71b075553573.js deleted file mode 100644 index 2e43866dd..000000000 --- a/pr/720/docs/search.index/71b075553573.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIBsEAUfAABdDswAAABAAANAAYA/hIDAGsTAQDbEwEA8hMBAHEUAQCZFAEAE4ACsDATMgFJaXABBQDzsBMAAAEAAQATgAKgMAAAFAtleVMBA7BwFBcAAWJlcwFAEAAAE4ADsDAUjgABsCAG+wABZWxz") \ No newline at end of file diff --git a/pr/720/docs/search.index/7230b78ac5d0.js b/pr/720/docs/search.index/7230b78ac5d0.js new file mode 100644 index 000000000..eec60c2ee --- /dev/null +++ b/pr/720/docs/search.index/7230b78ac5d0.js @@ -0,0 +1 @@ +rn_("AQAA9HsTAAABAAEAAQABBADzwA8AAAEAAQABgAKgUAAAENagYAAAEUZpcgGAAqAgAAAMdKBgAAARRWVoAQEA83AMAAABAAEAE4ECoBAAAAxzYWMBAwA7MAAAAQAABQACAGwMAwBZEQEAAQYA9BMTAAABAJkBAQATAAKwYBMVAAFmbfLiDAAAAQAjgAKgwAAAE+ZucqcPAACIoEAAAA+9sEAPvgABNCAXOzAAAAEAABkAAwALAgAAbAQOAPALCQABgAOwcBOaAAGwMBNEAAGwgBPTAAFjcnMBAAGwIBOaAAFvOjAAAAEAAAAAAAkAEAAAAN8R4BH7EvwS7BPtE0EUQhS9FL4UAYACsCAJIQABsDATTwABcnT3BAAAyKAgAAAHdKBgAAAP7bCAE08AAUAGkgn2FwIAAHkC3QQBAJIKAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/7253c52cbe08.js b/pr/720/docs/search.index/7253c52cbe08.js new file mode 100644 index 000000000..aa86b7d5d --- /dev/null +++ b/pr/720/docs/search.index/7253c52cbe08.js @@ -0,0 +1 @@ +rn_("AQEBsIATbgABdfJECQAAAQAjgAKwEAlCAAEzNgECAPNRBwAA7wEBAAECAPQ9CQAAAQAJCAEAAQIA81AMAAABAAEAE4ACsBAJOwABaXUBAgA7MAAAAQAACwACANUTBQCTFAUA8wkBbTswAAABAAAMAAMAbhEAAOoSBQBPFAUAdzAAAIqgMAAAE+ugcAAAEgCgIAAACT+wMBHFAAGwUBABAAEzhQs7MAAAAQAANAIEAP4BAAAkAjIBdQcAAAIK/wA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/72b333c2cba0.js b/pr/720/docs/search.index/72b333c2cba0.js new file mode 100644 index 000000000..87f7007e4 --- /dev/null +++ b/pr/720/docs/search.index/72b333c2cba0.js @@ -0,0 +1 @@ +rn_("AQQBoEAAABGEZQE7EAAAAQgA9McRAAABAAEAAQABAwGgQAAAEYNlAcYPAAABAgDzLwwAAAEAAQAjAAKwIAwdAAFrcvbwBgAAAQAUCu4AAQA0AvOAAnJ4AQMBsIAUYAABdjswAAABAAALAAMAFhEBANIRBQDDEwMAI4ACsGAQhwDCYXIBgAKgsAAAE+uwMA/EAAFlaAEDAaBAAAARFWXyFQkAAAEA1xMAAIugIAAAB2awsBM6AAGgkAAAEv2ggAAAEcugAAAAE0efGEw6MAAAAQAAAAAADAAQAAAADAJ8BH0EfgQGDAcMcAxxDHIMBg4HDkgTXhM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/73a29e4be1d7.js b/pr/720/docs/search.index/73a29e4be1d7.js new file mode 100644 index 000000000..012fa907f --- /dev/null +++ b/pr/720/docs/search.index/73a29e4be1d7.js @@ -0,0 +1 @@ +rn_("AQMBgBOBABD4czswAAABAAAFAAEAYRMFACOCAqCQAAAUY2lzBwEAhMWwUBMoAAGgoAAAE8ywcBORAAGg0AAAFG+AARgI") \ No newline at end of file diff --git a/pr/720/docs/search.index/74b35500777b.js b/pr/720/docs/search.index/74b35500777b.js new file mode 100644 index 000000000..a30453c35 --- /dev/null +++ b/pr/720/docs/search.index/74b35500777b.js @@ -0,0 +1 @@ +rn_("AQkA838UAAABADwAAYACoEAAABNesCAUGwABaGkBAQDz+Q8AAAEAAQATgAKwwBS6AAF0dQGBArCAFJEAAaBgAAAUuGRzNwMAg4agQAAAFGKwYBQyAFICkA4BEgGwABSFAAFzOzAAAAEAAAUAAQCeFAUAAQDGoFAAABLjoAAAABCZsCARTQABoFAAABH5oQAAABSZoEAAABQ8AAMCCzswAAABAAAVAAcArgUAADIMAADoDAAAChANAHERAAD5EgEANxQBAAEBAbCwFIwAAWw7MAAAAQAADAADACUHCAAGDQEASBABAAEBAaAwAAARKWjzAQkAAC4AsggBAgD02BEAAAEAAQABABOBArAgEdwAAWFz84ICbm/3AQCAh6AgAAAFrbBADBgAARUBBw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/754a85f8c0e5.js b/pr/720/docs/search.index/754a85f8c0e5.js new file mode 100644 index 000000000..0fb5a3fd7 --- /dev/null +++ b/pr/720/docs/search.index/754a85f8c0e5.js @@ -0,0 +1 @@ +rn_("AQAEoAAAABCZsCARTQABoFAAABH5oEAAABQ8ZGxzdjswAAABAAATAAYArgUAADIMAADoDAAAChANAHERAAA3FAEAAQIA9NgRAAABAAEAAQAThAKwIBHcAAFhc/OAAmFl") \ No newline at end of file diff --git a/pr/720/docs/search.index/7557654d6c60.js b/pr/720/docs/search.index/7557654d6c60.js new file mode 100644 index 000000000..f4a3c219d --- /dev/null +++ b/pr/720/docs/search.index/7557654d6c60.js @@ -0,0 +1 @@ +rn_("AQIAOzAAAAEAAO4AAgAMDAAAGA3tAPMAAW07MAAAAQAA7gACAKMFAADNBe0AAQMAOzAAAAEAAAgAAgCiDwYAXxMBAPMAAWM7MAAAAQAAVwAnAKgECwBvBQAADgkBACcMAQAvDAIA7wwAAPsMAgANDQEAzA8AANEPAQDUDwEA3g8AAGYQAgBtEAEAchABAJcQAAAPEQAAFREAAGIRAQBvEQEAgxEBAIcRAgDnEQEA+hECAAASAAC2EgAAvxIBAMQSAQANEwEAHRMBACITAQBEEwEAVBMDAFoTAQC7EwEAzxMAADsUAABkFAQAbRQCAPOAAnJ3AQkA838UAAABADwAAYACoEAAABNesCAUGwABaGkBAQDz+Q8AAAEAAQATgAKwwBS6AAF0dQGBArCAFJEAAaBgAAAUuGRzNwMAgYagQAAAFGKwYBQyAFICkA4BiAKwABPnAAGwABPpAAE0NjOAA6AwAAARhmRuc2MAA6AQAAAEy2FlbwGGAAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/758d161430bc.js b/pr/720/docs/search.index/758d161430bc.js deleted file mode 100644 index 4407f7996..000000000 --- a/pr/720/docs/search.index/758d161430bc.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAAOzAAAAEAAAYAAgCOEwAA9hMFACOIArBAFGwAAWVzAQQBsDATXgABY/OGEQAAAQABAAEFADswAAABAAAIAAMA/BECAAITBAApFAAA8wEDY2Vw88sMAAABAAEAAQIA9hgJAABYABMHAQC3AAEA84ACbnI=") \ No newline at end of file diff --git a/pr/720/docs/search.index/758e54a129f0.js b/pr/720/docs/search.index/758e54a129f0.js new file mode 100644 index 000000000..b84e4d0ee --- /dev/null +++ b/pr/720/docs/search.index/758e54a129f0.js @@ -0,0 +1 @@ +rn_("AQAA9HUQAAABALQAAQABhAKwABF/AAGwABGBAAE0NvMCAWHydQwAAAEAAQEA9sYSAAABAHMAAQBRAQEA84ACZW/zgAJoaw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/758efd32c564.js b/pr/720/docs/search.index/758efd32c564.js new file mode 100644 index 000000000..f48766f60 --- /dev/null +++ b/pr/720/docs/search.index/758efd32c564.js @@ -0,0 +1 @@ +rn_("AYACoFAAABFGoFAAABKWYXUBgwKxABS/AAGw0BSvAAFrbQELADswAAABAAAGAAEAHxQGACOAAqCAAAAUSWVvIwMDoGAAABPesEAUugABZW5wASMMAAAjgAKgQAAAENZtcAELAPMCFAAAAQB1APcAAACFoQAAABR6BIEDOzAAAAEAADsABAC4BQUATwcAAKAHMwCGEQAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/7617c97acd1f.js b/pr/720/docs/search.index/7617c97acd1f.js new file mode 100644 index 000000000..4cc53a2d7 --- /dev/null +++ b/pr/720/docs/search.index/7617c97acd1f.js @@ -0,0 +1 @@ +rn_("AQMAOzAAAAEAAI0AAgD3EAAACRKMAAEAAbBwE80AAWXy4g8AAAEA8wABc/RNEAAAAQBOBAEAM4ADoGAAABGrZGlv") \ No newline at end of file diff --git a/pr/720/docs/search.index/7668997d4899.js b/pr/720/docs/search.index/7668997d4899.js new file mode 100644 index 000000000..d6144d3e4 --- /dev/null +++ b/pr/720/docs/search.index/7668997d4899.js @@ -0,0 +1 @@ +rn_("AQMBsEARYgABZQGVDgAAAQUAOzAAAAEAAAYAAQBfEAYAAQMAOzAAAAEAAAUAAQDXDAUA8wACcHM6MAAAAQAAAAAADQAQAAAAqQWqBcEGEglZDGYMBhEHEbcSuBIPExATERMSEzMAA7BQD9AA02RwcjswAAABAAAPAAYAogQAAGgFAwC9DwAA4xEDALISAwDmEgEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/768ee4759e5c.js b/pr/720/docs/search.index/768ee4759e5c.js deleted file mode 100644 index 87e359742..000000000 --- a/pr/720/docs/search.index/768ee4759e5c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQIA9eYRAAABACUBAQBhAQEBAPciEQAAAQABANgCAQCLAAUAAQIA9LIQAAABAAEAAQATgAKg0AAAFHNjc/OAAmVvI4ACsAAHUgABbHTzAAJhcvKrDwAAAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/776081052934.js b/pr/720/docs/search.index/776081052934.js new file mode 100644 index 000000000..df4e2f10a --- /dev/null +++ b/pr/720/docs/search.index/776081052934.js @@ -0,0 +1 @@ +rn_("AQUA9UMQAAABAAEAYAIBAAEEAaAAAAAQ4XP1/gwAAAEAAQBBAwEAAQIA9awRAAABAAEAAQABAAGAArBgExcAAaAgAAARAG95AQABoMAAABQ8afRwEwAACAAcABsAAQUA9KkUAAABAAEAAQATgAKwcBSCAAFlaQECAPT+EAAAAQCbAAEAAQIBoEAAABNHcjswAAABAAAHAAIA/BABAJQRBQDzgAJhb2cDAACGsIATRgBasKATvQABDDAGOzAAAAEAAAgAAwAcDAAAxxEDAK0SAwDzggJlaUcBAACFsHATzQABoIAAABS5oEAAAA/3sEAE9PoIAADoBgEAtgMBgQKgIAAAEPqwUBK9AAFhbwEEAaAAAAAT5nMB+RAAAGMEA7BQEWwAAWNlc/YCCQAAAQABACwAAQByCQEAADswAAABAAAkAAgAQgcHAEMQAgCdEQ0AzBECAKUSAQAsEwEAfxMBABUUAgABBQDzHxMAAAEAAQABAQA7MAAAAQAABQACAP8LAwD3EQEAUwADsDAUVwABZXBy9OQPAAABAO8AAQABAAOwQBQdAAGhQAAAFI6gUAAAEe1iY2YBCAcAAOOAhLFAFLYAAQIwEAEBhKCwAAAT27BAELcAAbDAFAoAAaBgAAARkxQgBPbvBgAAYAkBADsBLgEXAQEDADswAAABAAAFAAEA3RIFAAEAAaCgAAAUSHL07g8AAAEA9wABAPOBAmdzAQcA9WcTAAABAAEAAQABAAGAAqBAAAARZLBQEUsAAWNp84ACYW8BAAGgIAAAEYRy8zQMAACBA3EBE4ACgAVyAB0ocngBAwKwQBMiAAGgMAAAE3pld/KOEAAAvAATgwKgcAAAE7RnbwECAPUBEwAAAQDyAH4AAQATgAKwMBMzAUlpcAEGAPOxEwAAAQABAPMFAmJzAUAQAAABAgD0HhAAAAEAAQABACOAAqBgAAASoWJj918BAM2wYBDfAAGgkAAAEqLATnIVOjAAAAEAAAAAABgAEAAAABoCGwKEBIUEhgQSB00Hfgd/B4AHgQeCB4MH+gt0DAQNOxBNEE4QGxGcEZwUnRSxFLIU") \ No newline at end of file diff --git a/pr/720/docs/search.index/776540b8ab1a.js b/pr/720/docs/search.index/776540b8ab1a.js deleted file mode 100644 index e6031017c..000000000 --- a/pr/720/docs/search.index/776540b8ab1a.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYQCsCARhAEioJAAABQpbXABgAKgMAAAERCgUAAAE85jchcBAACGsCATmQABoGAAABM3sMAUXAABoGAAABHgEEAPOzAAAAEAABIABgDNBAgA3hEBAPoSAQDrEwEAQBQBALwUAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/779759506437.js b/pr/720/docs/search.index/779759506437.js deleted file mode 100644 index ed3241b32..000000000 --- a/pr/720/docs/search.index/779759506437.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQYA9L4TAAABAAEAAQABDwD0qBQAAAEAAQABAAEAAbDwFLIAAWs7MAAAAQAACAADABkUAAAeFAYASBQAAAECAPR1EAAAAQCzAAEA9wAAAIWxABSbAAGJMADy2hIAAAEAE4ACsBAMUwABZW8BBQA7MAAAAQAADQABAJwRDQABAgDzBxAAAAEAAQABAgD0AxAAAAEAAQABAAEDADswAAABAAAIAAEAuRAIAAGAAqAAAAAMJrAwFGYAAXFyAYACoEAAABEQsMAUXAABZXMBAQA7MAAAAQAAEwABACUQEwAjgAKwkBPGAAFpbXc2AACKoFAAABQnsHAUBwABoCAAAAzwnFUROzAAAAEAAAsABABWBwAA6hADALoSAQAqFAQAAQIBsDARdwABcAGhEgAAs4CEoCAAABHhAigE") \ No newline at end of file diff --git a/pr/720/docs/search.index/77c18862fa4c.js b/pr/720/docs/search.index/77c18862fa4c.js deleted file mode 100644 index 094475f25..000000000 --- a/pr/720/docs/search.index/77c18862fa4c.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQABsIAT6wABdAEUCQAAAQkA880SAAABAAEA84ACY2cBgwKgkAAAFDagkAAAFDcyMwGAAqBQAAAUYqCAAAATg2Nl8wACc3TyQAcAAAEAAQABoLAAABPOYvNYEwAALgEBACOAAqAAAAATV2RyI4ACoFAAABQoY2XzgAJpeQEGAPU/EQAAAQABAAEAAQABAQGwQBRmAAFl9SoUAAABAAEAAQABAPcAAICFoBAAAAwPKWAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/77cafdb357d2.js b/pr/720/docs/search.index/77cafdb357d2.js new file mode 100644 index 000000000..c2687bc85 --- /dev/null +++ b/pr/720/docs/search.index/77cafdb357d2.js @@ -0,0 +1 @@ +rn_("AQUA9MwSAAABAKkAAQABCAD0ixMAAAEAhwABADMBA7BAE1oAAWFiZfX0DAAAAQBFA2oC1QABAAA7MAAAAQAABgACAC0MAQC4DwQA84ACc3UjgQKwgBOFAAFydAEGAPSFEAAAAQC4AAEAUwADsIATCgABYml09XoFAAABAOcOWAABAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/77cff9841c95.js b/pr/720/docs/search.index/77cff9841c95.js deleted file mode 100644 index eede255ab..000000000 --- a/pr/720/docs/search.index/77cff9841c95.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AYEBVvUXN/iEayMAAqCAAAAUuGZo8voIAACeCgEFAPMeEwAAAQABAAEBADswAAABAAAFAAIA/wsDAPYRAQBTAAOwMBRWAAFlcHL05A8AAAEA7wABAAEAA7BAFBwAAaFAAAAUjaBQAAAR7GJjZgEIBwAA84ACbW4BAYSgsAAAE9qwQBC3AAGwwBQJAAGgYAAAEZIUIAT27wYAAGAJAQA6AS4BFwEBBQA7MAAAAQAABQABANwSBQABBwD1ZhMAAAEAAQABAAEAI4ACoFAAABFjYW/zAIUgSQI7MAAAAQAACAAEAE0HAAB+BwUABA0AAJsRAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/7811abcc9a5f.js b/pr/720/docs/search.index/7811abcc9a5f.js deleted file mode 100644 index 5b987d9de..000000000 --- a/pr/720/docs/search.index/7811abcc9a5f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQAAOzAAAAEAAAYAAgCOEwAA9hMFACOIArBAFGwAAWVzAQQBsDATXgABY/OGEQAAAQABAAEFADswAAABAAAIAAMA/BECAAITBAApFAAA8wMDY2Vw88sMAAABAAEAAQABsGAUDgABZQFHFAAA8wIBc/YjCQAAAQABACAIPwAiAQECAaBQAAARhXIBJhEAAPOAA2ZtcA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/781f5efba775.js b/pr/720/docs/search.index/781f5efba775.js new file mode 100644 index 000000000..15ba1ce84 --- /dev/null +++ b/pr/720/docs/search.index/781f5efba775.js @@ -0,0 +1 @@ +rn_("AQkA838UAAABADwAAYACoEAAABNesCAUGwABaGkBAQDz+Q8AAAEAAQATgAKwwBS6AAF0dQGBArCAFJEAAaBgAAAUuGRzNwMAgIagQAAAFGKwYBQyAFICkA4BAAGwUBENAAFj9F0HAAABAAEACALDgISgEAAADHegUAAAEqMMQAQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/78bdd7950dc0.js b/pr/720/docs/search.index/78bdd7950dc0.js new file mode 100644 index 000000000..6273b6aff --- /dev/null +++ b/pr/720/docs/search.index/78bdd7950dc0.js @@ -0,0 +1 @@ +rn_("AQYA9OwTAAABAFQAAQAjgAKhEAAAFKhjchOAAqAgAAAJC2h5AQEBoGAAABSZc/LcEQAAAQAjgAKwIAlxAAFldQGAArAgECMAAaCQAAAUSGFlAQcBsEAUZwABZfUrFAAAAQABAAEAAQABAAD0KhMAAAEAWgEBAPMEAXM7MAAAAQAADQACAKcTBwCeFAUARwAABIaggAAAE4exABStAAGwQBLkAAGwgBS9AAGwUBMsAAEVABb0lg4AAAEAAQABAIMAhLBAFLMAAbAwExsAAbAwE7sAAcAAAzowAAABAAAAAAAJABAAAAC6BBEREhG1EbYRwxHEEQoUCxR7FAEDAbBAFH0AAXTy3BMAAAEAI4QCoEAAABQMYnMTgAKwwBSxAAF1eQGAAqAAAAAJK7AgEQMAAWdwAQEA9NgRAAABAAEAAQDzgAJkbLfoAACMoNAAABOToFAAABFxoJAAABOvsFATCgABoDAAAAxrt5gHOzAAAAEAAGgAFQADAgEACQIBAGgEAwDFBQAAwgYBAGEHAQB0BwAABwkBABQJAAAeCQAAUAkAAIQMQwDeDAAA7g8BABgQAADIEAEA5hABACwRAQCsEQQAvRIBADgTAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/78d93f5ae36e.js b/pr/720/docs/search.index/78d93f5ae36e.js new file mode 100644 index 000000000..bfbcda2d0 --- /dev/null +++ b/pr/720/docs/search.index/78d93f5ae36e.js @@ -0,0 +1 @@ +rn_("AQUA9MwSAAABAKkAAQABCAD0ixMAAAEAhwABADMBA7BAE1oAAWFiZTowAAABAAAAAAAMABAAAAAxBzIHMwf0DPUMxw86EIgQiRCKEIsQpBJ5EwEAADswAAABAAAiAA4AxAQBAIgFCgAmCQEALQwBAOYMAQCaDgAAuA8EAM8PAADyDwEA6BABAPoQAACOEQAA6xEBAPARAAABgQKwABF/AAGwABGBAAE0NiOAArCAFI8AAW9wAQABsEATVgABZfOKEQAAWgEBALcBAICFoGAAABEnEAEL") \ No newline at end of file diff --git a/pr/720/docs/search.index/7906e11d0aff.js b/pr/720/docs/search.index/7906e11d0aff.js deleted file mode 100644 index 305c28d7f..000000000 --- a/pr/720/docs/search.index/7906e11d0aff.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUAOzAAAAEAAAcAAwDLEQIAfhMBABQUAgABBwD2ohMAAAEAqgBZABgAAQABBADzzhEAAAEAAQAjAAKgYAAAEv1hcvPvEAAAAQDJAQGAAqEQAAAUo7CAFJkAAWl1dwgAAIixUBTAAAGgAAAAEM+wcBPeAAGhMAAAFLQKQRvyWwkAAEoHAYECoFAAABEUoKAAABNQa3ABAwA7MAAAAQAABgECAOQMAQCdDgQB84ACbHTzgAJhZQ==") \ No newline at end of file diff --git a/pr/720/docs/search.index/7907354f6eb1.js b/pr/720/docs/search.index/7907354f6eb1.js new file mode 100644 index 000000000..293e99564 --- /dev/null +++ b/pr/720/docs/search.index/7907354f6eb1.js @@ -0,0 +1 @@ +rn_("AQDKoRAAABR7gAj/ABreoEAAABEVsGAUawABoBAAAAyDsFAUBAABsDAReAABoAAAAAxBsSAUjwABsEAREwIkQE6wCTowAAABAAAAAAAUABAAAAAVCRYJKQkqCQgMCQwKDAsMEQwWDN0MohLOEs8S0BKLE4wToROiExMUFBQ=") \ No newline at end of file diff --git a/pr/720/docs/search.index/795c95422e5f.js b/pr/720/docs/search.index/795c95422e5f.js new file mode 100644 index 000000000..e511bab7f --- /dev/null +++ b/pr/720/docs/search.index/795c95422e5f.js @@ -0,0 +1 @@ +rn_("AQECsCAM8QABsAAMaQABZXPyYwcAAAEAAQUA8x8TAAABAAEA8wQBcvTkDwAAAQDvAAEAE4ACoLAAABRfYXPzgAJiYw==") \ No newline at end of file diff --git a/pr/720/docs/search.index/79ad745a1e86.js b/pr/720/docs/search.index/79ad745a1e86.js new file mode 100644 index 000000000..6212aba0b --- /dev/null +++ b/pr/720/docs/search.index/79ad745a1e86.js @@ -0,0 +1 @@ +rn_("AQMA9gENAADrAloAAQDSAgEAAQQAOzAAAAEAAAoABACPEAUA0xIBADQTAQBaFAAAAYYCoAAAABNYoAAAABNZZHLzAgF2AYQTAADzgAJlbycCAADIoDAAAA/roHAAABKjsRAUggABoIAAABQpsNATygABoLAAABQpQGUICTswAAABAAAJAAMAvgUCAB8HBABaDAEAI4ACaG1pVgJQZHIBAAA6MAAAAQAAAAAACgAQAAAAUQlSCSIQchNzE6MTpBNOFKcUvxTAFBOAAqAwAAAQpWx084ACYWU=") \ No newline at end of file diff --git a/pr/720/docs/search.index/79dce85c194a.js b/pr/720/docs/search.index/79dce85c194a.js new file mode 100644 index 000000000..4c8e6ff13 --- /dev/null +++ b/pr/720/docs/search.index/79dce85c194a.js @@ -0,0 +1 @@ +rn_("AQgA838UAAABADwAI4ACsAAQ3wABbW4BgAOgQAAAE16wIBQbAAGgIAAAD9NoaXkBCQGggAAAFLlmAZkTAAABAwGwABQyAFJz8q0QAAAuA0OAA7AgD88BK7BQEr0AAWFvcgECAPXcEAAAAQABAGACAQDzAANpdHU6MAAAAQAAAAAAEQAQAAAAfQcsCfMMORC2EOIR8BIqEysT3xPgE+YTDxQQFDAUMRSFFIYUAQYA9BMTAAABAJkBAQATAgKwYBMVAAFmbfLiDAAAAQAjggKwQBNEAAFlbAGAAqAwAAAUYrCwE7UAAWFsAQYA8+EPAADhAAEAAQUA9AYUAAABAE4AAQDzAgFj8ggTAAABAAECAaAwAAAQd2EBVgwAAAGAArBQESwAAbAgD6sAAWNu84ACbnQBBQA7MAAAAQAADgACAOgMAAAKEA0AAQIAOzAAAAEAAAcAAQBTCQcA5wUAAAmgMAAADFWgsAAAFDCggAAAEauw0BQ/AAEwYWZpa21ydXY7MAAAAQAAagIFAAACAABtA+0AdgcAAAIL7QAIDowAAQEA8/kPAAABAAEAE4ACsMAUugABdHUBAwDzwRIAAAEAAQABAQD1QBEAAAEAAQABAAEAAQEBsDAP6gDxdPZoBwAAAQCKAPoHqwD+AcOAhLCQFAgAAaBAAAARIAUQBAEDAaBAAAAUZmXyihQAAAEAE4ACsGAUvQABZXIBAwGgAAAAE+ZzAfkQAAABAgA6MAAAAQAAAAAACgAQAAAAUQlSCSIQchNzE6MTpBNOFKcUvxTAFIMABKCAAAASm7BwEW8AAbAgEQ8A8WZucnYB8gcAAAGBAqAAAAAJLKAwAAAP03N0xwEAgMawABQ9AAGwkBKZAAGgEAAAB04AEogoAQIAOzAAAAEAAA0ABgBZEAUAbBEBANESAQACFAEAWRQAAHgUAAATggKw8BS9AAFmZwGAArCAFJEAAaBgAAAUuGRzE4ACsMATzQABaW8BCAD1QxQAAAEAAQABAAEA8wIBZvWaEAAAAQABAAEAAQAjgAOgIAAAD82woBSPAAFkcnT3+wcAj6AwAAAPw5fXDzswAAABAABSAR4AhwQBALQEAgB8BQIApgUCAMcFAQC8BgQAPwcAAFcHAADuBwEAAgkCADAJAQApDAMAVwwBAH8MAwDkDAEAnQ4EAfAPAQBvEAIAtxABAMoQAgD4EAEAjBEAAL8RAwDpEQEAoxIAAOMSAAAbEwEAhRMBAKcTBwCeFAUA") \ No newline at end of file diff --git a/pr/720/docs/search.index/7cdfc41c47d8.js b/pr/720/docs/search.index/7cdfc41c47d8.js deleted file mode 100644 index 660ef6675..000000000 --- a/pr/720/docs/search.index/7cdfc41c47d8.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQUA9MsSAAABAKkAAQABCAD0ihMAAAEAhwABADMBA7BAE1kAAWFiZfX0DAAAAQBFA2kC1QABAAA7MAAAAQAABgACAC0MAQC4DwQA84ACc3UjgQKwgBOEAAFydAGAArBwEwkAAaAQAAAM1G56AQYA9IUQAAABALcAAQDzAANiaXT1egUAAAEA5g5YAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/7d274ea31c09.js b/pr/720/docs/search.index/7d274ea31c09.js new file mode 100644 index 000000000..c91d0b411 --- /dev/null +++ b/pr/720/docs/search.index/7d274ea31c09.js @@ -0,0 +1 @@ +rn_("AQUA9AYUAAABAE4AAQDzAwFj8ggTAAABACOAArBwFL0AAWhvAYICsAAS5AABsAAR6wABZXNDAAOgoAAAFFqgIAAAE5NlaXT19xIAAAEAiQABAPgAAYACsHAS2wABoLAAABQaZW8BAgA7MAAAAQAABgABAGURBgABAgGgQAAAFDtl8mkUAAABAPOAAmlvAQgA9P0TAAABAIsABQATAQOwkBRkAAGwUBNCAWZnbHA7MAAAAQAAEgAJAGkQAgDuEQEALxMBAFITAQCJEwEA7hMBACYUAQA1FAEAdhQBAAGAArBAErkBF6AgAAARKWFpAQMA89gSAAABAAEAI4ECsDAUDQABY2kBAAD0KhMAAAEAWgEBAPMDAXM7MAAAAQAADwADAOkRAQCnEwcAnhQFAAEDAPXnEQAAAQAlAQEAYQHzgAJydgEAADswAAABAAAFAAIAtxIBAA8TAwDzAgFkOzAAAAEAAAkAAwDjEQMAshIDAOYSAQAjgAKgkAAAFFlpbxOAArDwFK0AAWxvAQUA9HUUAAAMACMAEQAjgAKgYAAAE4dncyOAArCQFFcAAWJs9xcDAI+wcBIBAAGwYBSPAAGwcBQAAAGwYBNAAAGwUBMsAAG1+Rc7MAAAAQAAPgAZALUFAABqBwEA8QgFAAEJAAAvCQAADwwAAF4MAQDfDAIACA0BAJYOAwCbDgEA/A8EANAQAQAMEQAAMBEAAE8RCQCNEQAAjxEDAOERAAA2EwAATxMBAGETBQBxEwAAKRQAAIIUAQA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/7d5fb1732d0e.js b/pr/720/docs/search.index/7d5fb1732d0e.js deleted file mode 100644 index 86c9196cf..000000000 --- a/pr/720/docs/search.index/7d5fb1732d0e.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQcA9qITAAABAKoAWQAYAAEA8wEBaQFbCQAAAQAAOzAAAAEAAAUAAQBeCQUApwAAgMVk3aog3nOwYBQHAAGgEAAACTIAAiCK") \ No newline at end of file diff --git a/pr/720/docs/search.index/7e26bb2f5dee.js b/pr/720/docs/search.index/7e26bb2f5dee.js new file mode 100644 index 000000000..83a36f6db --- /dev/null +++ b/pr/720/docs/search.index/7e26bb2f5dee.js @@ -0,0 +1 @@ +rn_("AYQCsAARfwABsAARgQABNDbzAAFh8nUMAAABACOAArCQEYUBImx0AYACsHATmgABsIAT0wABY3MBAAA6MAAAAQAAAAAACQAQAAAA3xHgEfsS/BLsE+0TQRRCFL0UvhTzgAJkZScBAICFoNAAABQSsBAEwQABoDAAABB4AggL") \ No newline at end of file diff --git a/pr/720/docs/search.index/7e6d6e61a59f.js b/pr/720/docs/search.index/7e6d6e61a59f.js deleted file mode 100644 index 33e120b45..000000000 --- a/pr/720/docs/search.index/7e6d6e61a59f.js +++ /dev/null @@ -1 +0,0 @@ -rn_("AQgA9UIUAAABAAEAAQABAPMAAWY7MAAAAQAABQACAPIBAACaEAQAAQIAOzAAAAEAAAsAAgDUEwUAkhQFAPMGAW07MAAAAQAADQAEANAMAABtEQAA6RIFAE4UBQBjgAOwAAkhAAFlbXM=") \ No newline at end of file diff --git a/pr/720/docs/search.index/7f0296d1eeab.js b/pr/720/docs/search.index/7f0296d1eeab.js new file mode 100644 index 000000000..036aeef87 --- /dev/null +++ b/pr/720/docs/search.index/7f0296d1eeab.js @@ -0,0 +1 @@ +rn_("AQAA9DsHAAABAAEAAQABhQKwcBQYAAGwMBNsAAFlcxMAA7BAD9QAAaBgAAARjWJlczswAAABAAASAAQAqwUBAMYGCgBREAEAqRADAAECAPO1BQAARwoBAAEDAPXMDwAAoQABAAQAAQABCgGgQAAAFGZl8ooUAAABACMABKAwAAARHKCQAAATlLBgErsAATBjaGn1AxIAAJkBAQABAAEA84ACZHLnBAAAh7AQCPcDQLAgDAMBDKAwAAAP9BJBODswAAABAAASAAYAjAACAJwFAADJBQMAmgcFAN0HAwANDAAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/7f48b0bba760.js b/pr/720/docs/search.index/7f48b0bba760.js new file mode 100644 index 000000000..7fcedcb53 --- /dev/null +++ b/pr/720/docs/search.index/7f48b0bba760.js @@ -0,0 +1 @@ +rn_("AQIBoDAAABB3YQFWDAAAAYECoCAAABD6sFASvQABYW8BAwGgAAAAE+ZzAfkQAAAjgAKgAAAAB/JydmMAA7BQEWwAAWNlczswAAABAAAIAAQAAgkCADAJAQBvEAIAoxIAAAGAArDQFLEAAaCQAAATr2JoJwEAgIWwUBEsAAGw8BPHAAGwIA+rAAFEIQTzgAJudA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/7f80dc322a83.js b/pr/720/docs/search.index/7f80dc322a83.js new file mode 100644 index 000000000..057569959 --- /dev/null +++ b/pr/720/docs/search.index/7f80dc322a83.js @@ -0,0 +1 @@ +rn_("AQUA9MwSAAABAKkAAQABCAD0ixMAAAEAhwABADMBA7BAE1oAAWFiZfX0DAAAAQBFA2oC1QABAAA7MAAAAQAABgACAC0MAQC4DwQA84ACc3UjgQKwgBOFAAFydAGAArBwEwoAAaAQAAAM1G56AQYA9IUQAAABALgAAQDzAANiaXT1egUAAAEA5w5YAAEA") \ No newline at end of file diff --git a/pr/720/docs/search.index/7f8b0b9bd765.js b/pr/720/docs/search.index/7f8b0b9bd765.js new file mode 100644 index 000000000..b6923c1aa --- /dev/null +++ b/pr/720/docs/search.index/7f8b0b9bd765.js @@ -0,0 +1 @@ +rn_("AQAA9CoTAAABAFoBAQDzBAFzOzAAAAEAAA0AAgCnEwcAnhQFAEcAAAGGoIAAABOHsQAUrQABsEAS5AABsIAUvQABsFATLAABFQAW9JYOAAABAAEAAQABBQDz/g8AAAEAAQBjgAOwQBCMAAFtbm8=") \ No newline at end of file diff --git a/pr/720/docs/search.index/7ff31f82574b.js b/pr/720/docs/search.index/7ff31f82574b.js new file mode 100644 index 000000000..ae896089c --- /dev/null +++ b/pr/720/docs/search.index/7ff31f82574b.js @@ -0,0 +1 @@ +rn_("AYACsFARBgABoLAAABP/Y3MBBADzwA8AAAEAAQABgAKgUAAAENagYAAAEUZpcgGAAqAgAAAMdKBgAAARRWVoAQEA83AMAAABAAEAE4ECoBAAAAxzYWMBgAKwEBPKAAGwMA0WAAFlcyMAAqBAAAAUZmV38ooUAAABAAEDADswAAABAAAFAAIAbAwDAFkRAQABBgD0ExMAAAEAmQEBABMAArBgExUAAWZt8uIMAAABAAEBAPQREQAAAQCxAAEAI4ACoLAAABPmZGcBggKgoAAAE0igQAAAEHRvdvOAA2ducgGAAqBAAAATDKAwAAAPvWhsV38AAIugcAAAEziwQA++AAE8YFc7MAAAAQAAGgAEAAsCAABsBA4A8AsJAM8MAAA=") \ No newline at end of file diff --git a/pr/720/docs/search.index/desc/5c696247fc77.js b/pr/720/docs/search.index/desc/5c696247fc77.js deleted file mode 100644 index e34ac4369..000000000 --- a/pr/720/docs/search.index/desc/5c696247fc77.js +++ /dev/null @@ -1 +0,0 @@ -rd_("AmData flows in both directions0CdThe CE codepoint, signalling that congestion was \xe2\x80\xa600AjContains the success valueBeThe PathId of this path.BmReturns the PathId of this path.AoGet the identity of this stream00CdThe path which can now be used for application data.AlThe path that was abandoned.B`Which path had its state droppedAmPath which has changed statusCfPath over which the observed address was reported, \xe2\x80\xa643210AlWhich stream is now readableAlWhich stream is now writableAnWhich stream has been finishedAmWhich stream has been stoppedAnType of the Long header packetClWhether a stream communicates data in both directions or \xe2\x80\xa60AhContains the error valueAoThe largest representable valueAlThe maximum path ID allowed.10ClConnects to a QUIC perf server and maintains a specified \xe2\x80\xa6BmData flows only from the stream\xe2\x80\x99s initiator0AnWhich directions data flows in0CaDirectionality for which streams have been openedCdDirectionality for which streams are newly availableCjExplicit congestion notification bits to set on the packet0CeThe Explicit Congestion Notification bits for the \xe2\x80\xa61CdReturns the most recently observed external address.B`The current best RTT estimation.BfThe number of I/O operations executed.0BcLength of QUIC packet being decodedAlLength of the packet payload0BmThe number of bytes the associated buffer hasBbSet a custom TokenLog0CaMinimum RTT registered so far for this estimator.ClConstruct with an approximate maximum memory usage and a \xe2\x80\xa6CjConstruct an endpoint with arbitrary configuration and \xe2\x80\xa6DiCreates a new QlogConfig that writes a qlog trace to the \xe2\x80\xa6CiCreates a new qlog factory that writes files into the \xe2\x80\xa6D`Create a default config with a particular reset_keyCmCreate a default config with a particular handshake token \xe2\x80\xa6CkCreate a default config with a particular cryptographic \xe2\x80\xa6AmConstruct cid from byte arrayoConstruct emptyAeCreate a new StreamIdBeCreates a new FourTuple.DjConstruct a state using the given config and current time \xe2\x80\xa60;9AeCreate a new endpointDcCreate a new instance of FixedLengthConnectionIdParserBdCreate a generator with a random key;:98DgBegin decoding a QUIC packet from bytes, returning any \xe2\x80\xa68BkConstruct an error with a code and a reasonCgInitialize Random CID generator with a fixed CID length98766BfQUIC transport protocol implementationCkGet SystemTime::now() or the mocked equivalentAhLook up the current time01ChCurrent best estimate of this connection\xe2\x80\x99s latency \xe2\x80\xa6000BcExperimental! Use at your own risk.0ChThe ECT(0) codepoint, indicating that an endpoint is \xe2\x80\xa600ChThe ECT(1) codepoint, indicating that an endpoint is \xe2\x80\xa600CaA complete set of keys for a certain packet space0CbA Long packet header, as used during the handshakeChNot attributed to any particular FrameType.CkAn open network transmission within a multipath-enabled \xe2\x80\xa6Ab(Multi)Path eventsB`An error occurred during readingCeWhether an endpoint was the initiator of a connection0nThe 0 path id.0CaThe address observed by the remote over this path0CjThe source address of the datagram(s) contained in the \xe2\x80\xa6mType of errorBlCurrent congestion window of the connection.0gPayloadAoReturns the argument unchanged.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BaCalls U::from(self).000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dNextCoMethod for opening a sealed message data in-place.B`Open a single stream if possible1CgReturns the Path structure of an open pathBhPing the remote endpoint over this path.AhPing the remote endpointCkCheck whether the timer has expired, and register to be \xe2\x80\xa6BaReturns application-facing eventsBgRead data contiguously from the stream.AoRead from the given recv streamCcDecode TransportParameters from bufferBiReceive an unreliable, unordered datagramBdMethod for sealing a token in-place.0CiQueue an unreliable, unordered datagram for immediate \xe2\x80\xa6CbSends a Transmit on the given socket.CmNumber of address validation tokens sent to a client when \xe2\x80\xa60BmThe side of the connection (client or server)ChLook up whether we\xe2\x80\x99re the client or server of this \xe2\x80\xa6AlMethod for signing a message0CdAmount of data written to the caller-supplied buffer0hSpin bitAcStop accepting data0BoStop accepting data on the given receive streamCiTry to find and take a token that was stored with the \xe2\x80\xa60BgA chunk of data from the receive stream0CiThe RFC8312 congestion controller, as widely used for TCP0Borustls reports protocol errors using this type.0DbErrors encountered while decoding TransportParametersCdErrors that the nat traversal state might encounter.BeEvents of interest to the applicationCiEvent emitted when the client receives ADD_ADDRESS or \xe2\x80\xa6CjAttributed to a specific FrameType, never \xe2\x80\xa6A`Any other error.0CcThe peer abandoned transmitting data on this streamCnThe peer is unable to continue processing this connection, \xe2\x80\xa6CdThe peer abandoned transmitting data on this stream.1AeA Retry packet headerCdA short packet header, as used during the data phaseCmBest-effort extraction of the ALPN protocols from the TLS \xe2\x80\xa60BiConstruct a fresh Controller0AiThe contents of the chunkCiThe total amount of bytes which have been transferred \xe2\x80\xa610BnUnderlying error describing reason for failureBaClose the connection immediately.CnClose all of this endpoint\xe2\x80\x99s connections immediately and \xe2\x80\xa6AaCloses this path.AnClose a connection immediatelyBcFrame type that triggered the errorCcDistinguishes streams of the same initiator and \xe2\x80\xa60CjReturns whether the codepoint is a CE, signalling that \xe2\x80\xa60AgKey for encrypting data0BgParse a connection id from given bufferAhReturns all known paths.BlUpdate the timer to expire at iBbClose the send stream immediately.BeAbandon transmitting data on a streamCnRespond with a retry packet, requiring the client to retry \xe2\x80\xa60CiDrive future to completion in the backgroundCeShow connection stats the at the end of the benchmarkAmReturns connection statisticsBiReturns relevant stats from this EndpointCaReturns the PathStats for this path.CgAggregate connection statistics at the moment of close.3BcTitle to record in the qlog capture0CmWrite a buffer into this stream, returning how many bytes \xe2\x80\xa6AmSend data on the given streamCcEncode TransportParameters into bufferC`Future produced by Endpoint::acceptClPaths marked as backup will only be used if there are no \xe2\x80\xa60CeChunks returned from RecvStream::read().AmThe initiator of a connectionAdRun as a perf client1CoState of a Connection at the moment it was closed.CgAttempted to initiate NAT traversal on a closed, or \xe2\x80\xa6BcThe receiver lagged too far behind.CcFuture produced by Connection::open_biChOne or more new streams has been opened and might be \xe2\x80\xa6ChId representing different paths when using multipath \xe2\x80\xa60AbCoding result typeAlThe acceptor of a connectionAdRun as a perf server1mStream eventsAiAn integer less than 2^620CfGet the next incoming connection attempt from a clientClAttempt to accept this incoming connection (an error may \xe2\x80\xa6CcAccept a remotely initiated stream of a certain \xe2\x80\xa61BlAllows to configure the desired cipher suiteCiHelper to construct an endpoint for use with outgoing \xe2\x80\xa6CcWait for the connection to be closed for any reasonAfCoding related traits.BnAccess the configuration used by this endpointChTraits and implementations for the QUIC cryptography \xe2\x80\xa6BjCreate QUIC error code from TLS alert codeBoTLS configuration used for incoming connections210BkAn underlying crypto (e.g. TLS) layer errorCgDecode a plain header from given buffer, with given \xe2\x80\xa6DiDecode a Self from the provided buffer, if the buffer is \xe2\x80\xa6ChThe destination IP address which was encoded in this \xe2\x80\xa6D`Append the encoding of self to the provided buffer.CmNotify the peer that no more data will ever be written to \xe2\x80\xa6CnFinish a send stream, signalling that no more data will be \xe2\x80\xa6B`Process an incoming UDP datagramAfHeader protection keys0ClIgnore this incoming connection attempt, not sending any \xe2\x80\xa60C`Potentially store a token for later one-time use0CfPerform NSS-compatible TLS key logging to the file \xe2\x80\xa6AhThe offset in the stream0B`Packet deliveries were confirmed0AfPacket protection keys0lRandom valueBeThe reason the connection was closed.BcHuman-readable reason for the close0BcReason why this path was abandoned.11BhHuman-readable explanation of the reasonBeReason that the connection was closed2AjSwitch to a new UDP socketBgReject this incoming connection attempt0BoReturns the remote address of the network path.AgKey for decrypting data10AmTLS interface based on rustls0CnHelper to construct an endpoint for use with both incoming \xe2\x80\xa6BkOptional source IP address for the datagram00CgThe current local PathStatus of this path.B`The new status set by the remote0CfThe size of a single datagram in the associated bufferCkStatistics about datagrams and bytes received on this path.CjStatistics about UDP datagrams received on the connection.10CgStatistics about datagrams and bytes sent on this path.CeStatistics about UDP datagrams transmitted on the \xe2\x80\xa610AnMethod for verifying a message0CcNumber of ack-eliciting bytes that may be in flight0A`Send would blockCcNo more data is currently available on this stream.CjThe peer is not able to accept additional data, or the \xe2\x80\xa6BfA catch-all error for unlikely errors.0BlA key for signing with HMAC-based algorithms0AhAn Initial packet headerBnA pair of keys for bidirectional communication0BhA simple, standard congestion controller0CdFuture produced by Connection::open_uniCkAbstracts I/O and timer operations for runtime independenceBfA cryptographic session (commonly TLS)0CcThe peer is no longer accepting data on this streamCfFuture returned from SendStream::stopped.ClThe peer is no longer accepting data on this stream, and \xe2\x80\xa6CkThe peer is no longer accepting data on this stream. No \xe2\x80\xa6CgThe peer asked us to stop sending on an outgoing streamAaAccess to streamsCaThe stream is larger than the user-supplied limitCnAttributed to some frame type this implementation does not \xe2\x80\xa6l0-RTT packetCjReturns the length of a CID for connections created by \xe2\x80\xa60CdProvide the length of dst_cid in short header packetCcThe total number of clients which should be createdAlConnect to a remote endpointAeInitiate a connectionBbDecrypt the Initial packet payloadCgDecrypt the packet payload with the given packet numberBcDecrypt the given packet\xe2\x80\x99s header210ClConstructs a value with arbitrary fields, intended to be \xe2\x80\xa6DjConstruct an event that indicating that a Connection will \xe2\x80\xa6BkThe destination connection ID of the packetBkThe destination Connection ID of the packetAiDestination Connection ID00000CgEncrypt the packet payload with the given packet numberBcEncrypt the given packet\xe2\x80\x99s header10CbCheck if this stream has been opened during 0-RTT.0CmRetrieve implementation-specific metrics used to populate \xe2\x80\xa60CnThe maximum UDP payload size guaranteed to be supported by \xe2\x80\xa60CjUniform interface to send and receive UDP packets with \xe2\x80\xa6BbOne or more packets were just sent0BmInitiate a new outgoing bidirectional stream.CaReturns the path ID of the new path being opened.AdSource Connection ID0000CiCompletes when the peer stops the stream or reads the \xe2\x80\xa6CjCheck if this stream was stopped, get the reason if it wasCcThe total number of streams which should be createdAlProvide control over streamsCeThe length of the AEAD tag appended to packets on \xe2\x80\xa60CdUpgrade the handle to a full ConnectionB`Upgrades to a Path.AkSet the QUIC version to use0lQUIC versionB`The version that was unsupported11CeFuture produced by Connection::accept_biAfAn unreliable datagramBdDatagram support is disabled locally0A`A QUIC endpoint.BcThe main entry point to the libraryChA finished stream has been fully acknowledged or stoppedCkAn incoming connection for which the server has not yet \xe2\x80\xa60BoLong packet types with uniform header structureB`The largest encoded value length0Cmthe connection is being closed abruptly in the absence of \xe2\x80\xa60CeFuture returned by Connection::on_closedClFuture produced by crate::Connection::open_pathCmA currently open stream likely has data or errors waiting \xe2\x80\xa6CkMetadata for a single buffer filled with bytes received \xe2\x80\xa6BkResponse generated directly by the endpointCfIdentifier for a stream within a particular connection0CnCommunication with the peer has lapsed for longer than the \xe2\x80\xa6CkWe didn\xe2\x80\x99t receive any data from the remote within the \xe2\x80\xa61ChResponsible for limiting clients\xe2\x80\x99 ability to reuse \xe2\x80\xa60ClThe datagram is larger than the connection can currently \xe2\x80\xa60AbAn outgoing packet00CmStatistics about UDP datagrams transmitted or received on \xe2\x80\xa60CnA formerly write-blocked stream might be ready for a write \xe2\x80\xa6AkCongestion algorithm to useAhContents of the datagramBoMark the read data as consumed from the stream.BnStatistics about frames received on this path.CcStatistics about frames received on the connection.10CaStatistics about frames transmitted on this path.CfStatistics about frames transmitted on the connection.10DhConstructs cid by reading len bytes from a Buf0DkCreates a new qlog factory that writes files into QLOGDIR, \xe2\x80\xa60BfCreate a generator with a specific keyBjConstruct a VarInt infallibly0BeSucceeds iff x < 2^620AeWhat type we receivedAoWhat handshake type we received10CbWhether 0-RTT is/was possible during the handshakeCmSpecifies the time to wait after completing MTU discovery \xe2\x80\xa60CcReturns Self for use in down-casting to extract \xe2\x80\xa60EhReturns true if the Connection associated with this handle \xe2\x80\xa6CmDuration after an address validation token was issued for \xe2\x80\xa60CeThe local IP address which was used when the peer \xe2\x80\xa60BjThe local IP used for this path, if known.BnReturns the local address of the network path.20ClCompute the maximum size of datagrams that may be passed \xe2\x80\xa6BnInitiate a new outgoing unidirectional stream.BcGet the priority of the send streamAlGet the priority of a streamCfThe negotiated application protocol, if ALPN is in use0Aeqlog output directoryBbOptional response to transmit backCiOptional seed to be used internally for random number \xe2\x80\xa60AlSlow start threshold (bytes)0BeSucceeds iff x < 2^6200000DaSends a Transmit on the given socket without any \xe2\x80\xa6DkQuickly determine whether cid could have been generated by \xe2\x80\xa600BmA path was abandoned and is no longer usable.0CfFuture produced by Connection::accept_uniCdPaths marked with as available will be used when \xe2\x80\xa60CnAt least one new stream of a certain directionality may be \xe2\x80\xa6BkThe connection was successfully establishedAoAPI to control datagram trafficAlDecoding of QUIC primitives.CkA path was discarded and all remaining state for it has \xe2\x80\xa60BgInfallible encoding of QUIC primitives.CnIdentifies a network path by the combination of remote and \xe2\x80\xa60A`Handshake packetBcKeys used to protect packet headers0CiCatch-all error for problems while decoding transport \xe2\x80\xa6CeNat traversal attempt failed due to a multipath errorBdKeys used to protect packet payloads0BmErrors that might trigger a path being closed0AnApplication events about paths0BjStatistics related to a transmission path.0AeA read error occurredBmErrors that arise from reading from a stream.C`Errors triggered when reading from a recv streamCiAn object for asynchronously writing to an associated \xe2\x80\xa6BmAccept the next incoming bidirectional streamBbDuplicate the controller\xe2\x80\x99s state0BeThe number of UDP datagrams observed.AaControl datagrams1BeCreate new object from the given bits00BoWhich side of a connection initiated the stream0CmConvert into a 0-RTT or 0.5-RTT connection at the cost of \xe2\x80\xa6BoShorthand for self == Side::Client0B`Whether the connection is closedBoShorthand for self == Side::Server0CbWhether it is legal to respond with a retry packet0CdWhether to allow clients to migrate to new addresses0CdConstruct a timer that will expire at iBoLow-level protocol logic for the QUIC protoocolCjWait for the connection to be closed without keeping a \xe2\x80\xa6CjOpens an additional path if the multipath extension is \xe2\x80\xa6AaOpens a new path.BmPing the remote endpoint over a specific pathCiAttempts to read from the stream into the provided bufferCeReceive UDP datagrams, or register to be woken if \xe2\x80\xa6CkSend a UDP datagram, or register to be woken if sending \xe2\x80\xa6ClPrivate key used to send authenticated connection resets \xe2\x80\xa60BmGenerate the integrity tag for a retry packet0BgA stable identifier for this connectionCePrivate key used to authenticate data included in \xe2\x80\xa60BlThe position of a token in the packet bufferCgTransport configuration to use for incoming connections0CkWaits for all connections on the endpoint to be cleanly \xe2\x80\xa6BoWrite a buffer into this stream in its entiretyCiAbstract implementation of an async timer for runtime \xe2\x80\xa6BoNumber of UDP packets to send/receive at a timeCmConfiguration for the Bbr3 congestion controller0CkError indicating that a path has not been opened or has \xe2\x80\xa6BnThe path is already closed or was never opened1101BeIn-progress connection attempt futureAbA QUIC connection.CeProtocol state and logic for a single QUIC connectionCeCommon interface for different congestion controllers0CjNumber of frames transmitted or received of each frame \xe2\x80\xa60BoThe connection ID was not recognized by the \xe2\x80\xa60DdThe type used to refer to FrameTypes in closing and \xe2\x80\xa6DbA stream of PathEvents for all paths in a connection.AnThe QUIC-MULTIPATH path status0BeConfiguration for qlog trace logging.0BnA stream that can only be used to receive dataAaAccess to streamsChErrors that arise while waiting for a stream to be resetDhError for attempting to retry an Incoming which already \xe2\x80\xa60BkA stream that can only be used to send data3BmObject to get current SystemTime0AdA rustls TLS session0CkResponsible for storing validation tokens received from \xe2\x80\xa60AeA borrowed UDP socketBjErrors that arise from writing to a streamBoErrors triggered while writing to a send streamBoAccept the next incoming uni-directional streamCkWhether the implementation is permitted to set the spin \xe2\x80\xa60CbReturns the number of bytes read from this stream.0CiCloses a path and sends a PATH_ABANDON frame with the \xe2\x80\xa6CdLogic for controlling the rate at which data is sent0BfWhether to print connection statisticsBnClass of error as encoded in the specificationB`Application-specific reason code10CaThe error code to be sent with the abandon frame.BoThe error that was sent with the abandon frame.AoError code supplied by the peerBcType of frame that caused the close0AiExtract the integer value0CnWhether there is no longer any need to keep the connection \xe2\x80\xa6DkDetermine whether this is the last event a Connection will \xe2\x80\xa6CiLook up the local IP address and port used by this socketDgGet the local SocketAddr the underlying socket is bound toBfThe number of bytes lost on this path.BkThe number of bytes lost on the connection.10CjPad UDP datagrams carrying application data to current \xe2\x80\xa60AgReturns path statisticsCjPer-path statistics for every path the connection knew \xe2\x80\xa6CjThe final path stats, they are no longer available via \xe2\x80\xa620C`Attempt to write bytes from buf into the stream.CoReads the next segment of data as zero-copy Bytes.AoReads the next segment of data.CkRead an exact number of bytes contiguously from the stream.BnSets the PathStatus of this path.BoEpoch qlog event times are recorded relative to0ClError type for attempting to accept an IncomingBjErrors in the configuration of an endpoint0AeGeneric crypto errors0CnConfiguration for the Cubic congestion controller0CdA new path has established connection with the peer.0CdReasons why attempting to finish a stream might failCnMaximum duration of inactivity to accept before timing out \xe2\x80\xa60AnValue exceeds supported bounds0D`Constructs a QlogConfig for individual connections.0AfA noq runtime for smolB`Application events about streamsCbAccept this incoming connection using a custom \xe2\x80\xa6CeLargest UDP payload size the path currently supports.ClStorage size required for the largest packet that can be \xe2\x80\xa61BiDescription to record in the qlog capture0BjThe socket this datagram should be sent to00DcCreates a new FourTuple without a known local address.0BkStarting guess for maximum UDP payload sizeCkThe initial value to be used as the maximum UDP payload \xe2\x80\xa60ChUDP payload size that the network must be capable of \xe2\x80\xa6BjThe RTT used before an RTT sample is taken0BfThe initial round-trip-time (in msecs)CiWhether this is the event is the event indicating the \xe2\x80\xa6CeThe amount of concurrent streams which should be usedDdPackets are acked in batches, all with the same now \xe2\x80\xa60AePacing rate (bytes/s)0DeA stream of PathEvents for all paths in this connection.DfGets the local PathStatus for a known PathIdCkConvenience method to read all remaining data into a bufferAlProvide control over streamsBoThe sample size used for this key\xe2\x80\x99s algorithm01CiMaximum number of bytes to transmit to a peer without \xe2\x80\xa600BoThe server name specified by the client, if any0BmObject to get current SystemTime0BdSet a custom TokenStore0CaNumber of bytes to transmit from client to serverCnSpecifies the upper bound to the max UDP payload size that \xe2\x80\xa60ChReturns a weak reference to the inner connection struct.CdReturns a WeakPathHandle for this path.DgCreate a server config with the given crypto::ServerConfig0CeSets a prefix to the filename of the generated files.0DdWrites a single Bytes into this stream in its entirety.BbAn ADD_ADDRESS frame was received.BfConfiguration for outgoing connectionsCaClient-side configuration for the crypto protocol10CgThe stream has already been stopped, finished, or resetBmThe stream has already been finished or resetCmError indicating that a stream has not been opened or has \xe2\x80\xa6CjThe stream has not been opened or was already stopped, \xe2\x80\xa6CfThe stream has not been opened or has already been \xe2\x80\xa6CmThe stream has not been opened or was already finished or \xe2\x80\xa63CgErrors in the parameters being used to create a new \xe2\x80\xa60BkProtocol-level identifier for a connection.0CkWe couldn\xe2\x80\x99t decrypt a message. This is invariably fatal.0BjExplicit congestion notification codepoint00CnWe couldn\xe2\x80\x99t encrypt a message because it was larger than \xe2\x80\xa60BhParameters that are semantically invalidCkCannot close the last remaining open path via the local \xe2\x80\xa60Akn0\xe2\x80\x99s nat traversal eventsDhNull implementation of TokenLog, which never accepts tokens0ClReceived an observation of our external address from the \xe2\x80\xa60CiFuture produced by Connection::read_datagramBiThe remote changed the status of the path0BlRTT estimation for a particular network pathCnFuture produced by Connection::send_datagram_waitBiParameters governing incoming connectionsCaServer-side configuration for the crypto protocol10CmErrors that arise while monitoring for a send stream stop \xe2\x80\xa6AgA noq runtime for TokioC`Returns the lifetime of generated Connection IDs0BjWhether the connection is closed, and why.CjConnect to a remote endpoint using a custom configuration.AlConservative estimate of RTTBnGet the 0-RTT keys if available (clients only)0AgWhich types we expectedB`Which handshake type we expected10AcGenerates a new CID0ClThe number of segments to read when GRO is enabled. Used \xe2\x80\xa6DeProcess ConnectionEvents generated by the associated \xe2\x80\xa6EaProcess EndpointEvents emitted from related ConnectionsCgCreate the initial set of keys given the client\xe2\x80\x99s \xe2\x80\xa6000BhThe number of packets lost on this path.BmThe number of packets lost on the connection.10DcMaximum number of Incoming to allow to exist at a time0CjWhether datagrams might get fragmented into multiple parts0CmWhether transmitted datagrams might get fragmented by the \xe2\x80\xa6BdThe network path used for this path.CkReturns the path\xe2\x80\x99s network path represented as a 4-tuple.CkThe original destination CID when initiating the connectionCiThe original destination connection ID sent by the clientDhReturns the next time at which handle_timeout should be \xe2\x80\xa6D`Configures qlog capturing by setting a QlogFactory.0AgThe runtime type to useCkThe segment size if this transmission contains multiple \xe2\x80\xa600CkSend Quantum (bytes) used to control the size of packet \xe2\x80\xa60ChThe number of streams that may have unacknowledged data.CbSet the lifetime of CIDs created by this generator0BcSet the priority of the send streamAlSet the priority of a streamCnInitialize a QUIC-compatible TLS client configuration with \xe2\x80\xa6000AmSend data on the given streamCkWe received a fatal alert. This means the peer is unhappy.0BhBloom filter-based TokenLog0CmThe connection could not be created because not enough of \xe2\x80\xa6000CaEvent resulting from processing a single datagramBlEvents sent from a Connection to an EndpointAoStatistics on Endpoint activityBnThe stream finished before all bytes were readBlAuthentication data for (rustls) TLS session0Ccreceived an invalid Retry Token in a client Initial0ChIterator over ALPN protocol names from a TLS ClientHelloAlThe packet header is invalidBkThe local application closed the connection0DaThe datagram may result in starting a new ConnectionD`Configuration for the NewReno congestion controller0BjDecodes a QUIC packet\xe2\x80\x99s invariant headerCgErrors triggered when opening a recv stream for readingCaDefault implementation of TimeSource0CgError indicating that the provided buffer was too smallChFor clients, if the peer accepted the 0-RTT data packetsAbAck Frequency modeAfExports for benchmarksBoSupply a custom connection ID generator factory0DgCreate a UdpSender that can register a single task for \xe2\x80\xa6CaNumber of bytes to transmit from server to clientAmGet the Incoming0CnThe max_ack_delay we will request the peer to use0CgDisable packet encryption/decryption (for debugging \xe2\x80\xa6CkThe known MTU for the current network path has been updated0BbCryptographic identity of the peerBgGet the peer\xe2\x80\x99s identity, if availableDhFor the rustls TlsSession, the Any type is \xe2\x80\xa610AkReturns packets to transmitDjConfigures qlog capturing through the QLOGDIR environment \xe2\x80\xa60AoReceive an application datagramDfTransmit data as an unreliable, unordered application \xe2\x80\xa6CmWhether to implement fair queuing for send streams having \xe2\x80\xa60BfLength of sign\xe2\x80\x99s output0BnStart a client session with this configurationBnStart a server session with this configuration10BdA REMOVE_ADDRESS frame was received.CgAbstract implementation of a UDP socket for runtime \xe2\x80\xa6BgErrors triggered when abandoning a path0AgThe connection was lost00000ChGlobal configuration for the endpoint, affecting all \xe2\x80\xa60Cithe endpoint encountered an internal error and cannot \xe2\x80\xa60FbBasic adapter to let Incoming be await-ed like a ConnectingBhEncounter a frame ID that was not valid.CeThe peer sent us a TLS message with invalid contents.0Amno viable network path exists0DhNull implementation of TokenStore, which does not store \xe2\x80\xa60CiThe peer deviated from the standard TLS protocol. The \xe2\x80\xa60BmErrors that arise from reading from a stream.C`Errors from RecvStream::read_to_endCaIndicates whether a frame needs to be transmittedCmThe peer violated the QUIC specification as understood by \xe2\x80\xa60CiTransport-level errors occur when a peer violates the \xe2\x80\xa6C`Tokio-compatible UDP socket with some useful \xe2\x80\xa6DiWeak handle for a Path that does not keep the connection \xe2\x80\xa6BnCreate a client endpoint and client connectionAgGet a session referenceDiReturns a QlogConfig for a connection, if logging should \xe2\x80\xa60AiProcess timer expirationsBjParameters negotiated during the handshake0CfGet data negotiated during the handshake, if available0AiInitial congestion windowCiDefault limit on the amount of outstanding data in bytes.001000BnConverts this stream into an unordered stream.DdReturns true until the connection is fully established.CeWhether the connection is in the process of being \xe2\x80\xa61BfVerify the integrity of a retry packet0CnSpecifies the minimum MTU change to stop the MTU discovery \xe2\x80\xa60BdCompute keys for the next key update0AhOne packet was just lost0AhOne packet was just sent0BkConfigures qlog capturing into a directory.0AlRead bytes of handshake data0BeWhether to use the unordered read APIClMaximum number of bytes the peer may transmit across all \xe2\x80\xa600CkCompletes when the stream has been reset by the peer or \xe2\x80\xa60CiCheck whether this stream has been reset by the peer, \xe2\x80\xa6AjThe peer\xe2\x80\x99s UDP addressesAhThe peer\xe2\x80\x99s UDP addressBgThe peer\xe2\x80\x99s UDP address for this path.1CeSaturating integer addition. Computes self + rhs, \xe2\x80\xa6000ChSaturating integer subtraction. Computes self - rhs, \xe2\x80\xa60CkMaximum reordering in time space before time based loss \xe2\x80\xa60ChReason given by the transport for closing the connection0BfReasons why a connection might be lost0CiThe datagram is redirected to its ConnectionBlEvents sent from an Endpoint to a ConnectionAfConnection statistics.0BiStatistics for the currently open streamsAcPlain packet headerBkEnables writing qlog traces to a directory.0AkThe remote closed the path.CfError for when a validation token may have been reused0C`Parameters governing the core QUIC state machine0CbThe peer doesn\xe2\x80\x99t implement any supported version0CdFuture that completes when a connection is fully \xe2\x80\xa6CbThis was a 0-RTT stream and the server rejected it000CjAutomatically select an appropriate runtime from those \xe2\x80\xa6CkWhether to accept QUIC packets containing any value for \xe2\x80\xa60CdMaximum number of incoming packets that may fail \xe2\x80\xa60CnThe interface index of the interface on which the datagram \xe2\x80\xa6AjSwitch to a new UDP socketCiCreates a server endpoint which runs on the given runtimeD`Sets the PathStatus for a known PathIdCfSee proto::TransportConfig::send_window()BoSee TransportConfig::send_window()BmReturns whether a frame should be transmittedD`Convert t into the socket type used by this runtimeCdWrites handshake bytes into the given buffer and \xe2\x80\xa60ClStream produced by Path::observed_external_addrCiReason given by an application for closing the connection0CbThe peer\xe2\x80\x99s QUIC stack aborted the connection \xe2\x80\xa60DjInternal identifier for a Connection currently associated \xe2\x80\xa6CdOne or more application datagrams have been receivedBjDecrypted payload of a QUIC Initial packet0CaThe endpoint can no longer create new connections0Cnreceived a STREAM frame or a RESET_STREAM frame containing \xe2\x80\xa60ClSpecific failure cases from keys_match or a \xe2\x80\xa60A`key update error0CaCurrent limits do not allow us to open more paths0ClThe peer doesn\xe2\x80\x99t support a protocol version/feature we \xe2\x80\xa60BjA QUIC-compatible TLS client configuration0BjA QUIC-compatible TLS server configuration0EfTokenStore implementation that stores up to N tokens per \xe2\x80\xa60CgAn endpoint (local or remote) tried to add too many \xe2\x80\xa6CaPath could not be validated and will be abandonedCmWe didn\xe2\x80\x99t receive a path response in time after opening \xe2\x80\xa61BcA Version Negotiation packet headerCiRecord that the token was used and, ideally, return a \xe2\x80\xa60CjCurrent state of the congestion control algorithm, for \xe2\x80\xa6CcCurrent state of this connection\xe2\x80\x99s congestion \xe2\x80\xa6BaUpdate traffic keys spontaneously0CnThe maximum amount of segments which can be transmitted if \xe2\x80\xa6CnMaximum duration of inactivity to accept before timing out \xe2\x80\xa60Cgn0\xe2\x80\x99s (https://n0.computer) NAT Traversal protocol \xe2\x80\xa6CeGet the number of connections that are currently openBmNumber of connections that are currently openDeOpens a new path if no path exists yet for network_path.CmOpens a new path only if no path on the same network path \xe2\x80\xa6CiMaximum reordering in packet number space before FACK \xe2\x80\xa60B`Reads the next segments of data.CfGet the size of the socket receive bufferAlReceive buffer size in bytesCcGet the size of the socket send bufferAiSend buffer size in bytesBiSet a custom TransportConfig000ChConfiguration for sending and handling validation tokens0CnCreate a server config with the given certificate chain to \xe2\x80\xa60DfWrites a slice of Bytes into this stream in its entirety.Cfthe application or application protocol caused the \xe2\x80\xa60AnThe peer closed the connectionBoThe path was closed locally by the application.1B`Constructs controllers on demand0CnCommon congestion controller metrics used both for logging \xe2\x80\xa60ClThe trait for encrypting tokens that power retry packets \xe2\x80\xa60BcThe given server name was malformed0CbHints when the caller identifies a network change.0AcPacket decode errorBdReason for why a path was abandoned.BmErrors that can arise when sending a datagram0CcThe peer does not support receiving datagram frames0BdCongestion events on the connection.0AiCongestion window (bytes)0ClCompute the maximum size of datagrams that may be passed \xe2\x80\xa6BoBytes available in the outgoing datagram bufferClReplace the server configuration, affecting new incoming \xe2\x80\xa60CmWaits for all connections on the endpoint to be ready for \xe2\x80\xa6DgWrites Bytes from a slice of buffers into this stream, \xe2\x80\xa6Cmthe endpoint has reached the confidentiality or integrity \xe2\x80\xa60CkParameters for controlling the peer\xe2\x80\x99s acknowledgement \xe2\x80\xa60DjThe max_fragment_size value supplied in configuration was \xe2\x80\xa60Bmthe server refused to accept a new connection0BjParse connection id in short header packetCjOne or more application datagrams have been sent after \xe2\x80\xa6Ckreceived more data than permitted in advertised data limits0AoThe TLS handshake was confirmedBjThe connection\xe2\x80\x99s handshake data is readyCeAttempted an ordered read following an unordered readAnWe saw an invalid certificate.0BcParameters governing MTU discovery.0BnNot enough addresses to complete the operationCkdetected an error with protocol compliance that was not \xe2\x80\xa60Cjreceived a frame for a stream identifier that exceeded \xe2\x80\xa60Cnreceived a frame for a stream that was not in a state that \xe2\x80\xa60AnError from setting path status0AjTransport-level error code0ChThe local endpoint does not support the QUIC version \xe2\x80\xa6CkError indicating that the specified QUIC version is not \xe2\x80\xa61C`Packet uses a QUIC version that is not supported1CiMaximum quantity of out-of-order crypto layer data to \xe2\x80\xa60C`Create a VarInt without ensuring it\xe2\x80\x99s in range0ChCumulative number of Quic handshakes ignored on this \xe2\x80\xa6EgReturns true if the two WeakConnectionHandle point at the \xe2\x80\xa6CiMinimum interval between outgoing stateless reset packets0CjConstruct with an approximate maximum memory usage and \xe2\x80\xa60ChCumulative number of Quic handshakes refused on this \xe2\x80\xa6AnReturns the remote path statusDfTransmit data as an unreliable, unordered application \xe2\x80\xa6CnUpdates the set of ALPN protocols configured in the client \xe2\x80\xa6CnUpdates the set of ALPN protocols configured in the server \xe2\x80\xa610CiSee proto::TransportConfig::receive_window()CbSee TransportConfig::receive_window()B`Override supported QUIC versions0CiOverride the instant relative to which all events are \xe2\x80\xa60CcA stream of NAT traversal updates for a connection.BkNo remote CIDs available to open a new path0CkTransport parameters used to negotiate connection-level \xe2\x80\xa6CgA stream that can be used to receive data out-of-order.CmThe certificate verifier doesn\xe2\x80\x99t support the given type \xe2\x80\xa60CfThe operation is not allowed for this endpoint\xe2\x80\x99s \xe2\x80\xa6CiCumulative number of Quic handshakes accepted by this \xe2\x80\xa6CjSpecifies the amount of time that MTU discovery should \xe2\x80\xa60CiIf the 0-RTT-encrypted data has been accepted by the peer0BgWait for the handshake to be confirmed.CgInform the connection if a path may recover after a \xe2\x80\xa60CgPeriod of inactivity before sending a keep-alive packet0CfThe number of PLPMTUD probe packets lost on this path.0BlPackets were deemed lost or marked congested0CgCumulative number of Quic handshakes sent from this \xe2\x80\xa6CnThe number of remotely initiated open streams of a certain \xe2\x80\xa6AhBench fns for SendBufferCfThe number of PLPMTUD probe packets sent on this path.0Bireceived a frame that was badly formatted0CkThis function doesn\xe2\x80\x99t work until the TLS handshake is \xe2\x80\xa60CkWe received a TLS message that isn\xe2\x80\x99t valid right now. \xe2\x80\xa60CkThe remote address for the path is not supported by the \xe2\x80\xa6CiThe remote SocketAddr supplied was malformed10ChThe initial cipher suite (AES-128-GCM-SHA256) is not \xe2\x80\xa60CnWatches the external address reported by the peer for this \xe2\x80\xa6BdPaths can only be opened client-side0DmError returned when constructing a VarInt from a value >= \xe2\x80\xa60CeA handle to some connection internals, use with care.DkSpecifies the ACK frequency config (see AckFrequencyConfig \xe2\x80\xa60CjThe number of times a black hole was detected in the path.0CgMaximum number of received bytes to buffer for each \xe2\x80\xa60AeIs multipath enabled?ClMaximum number of datagrams that might be described by a \xe2\x80\xa60CkMaximum UDP payload size accepted from peers (excluding \xe2\x80\xa60AmMax UDP payload size in bytesDkSpecifies the MTU discovery config (see MtuDiscoveryConfig \xe2\x80\xa60AmReturn endpoint-facing eventsCkThe preferred IPv4 address that will be communicated to \xe2\x80\xa60CkThe preferred IPv6 address that will be communicated to \xe2\x80\xa60ChThe reordering threshold we will request the peer to use0ClDuration after a retry token was issued for which it\xe2\x80\x99s \xe2\x80\xa60BmSets the max idle timeout for a specific pathDfResize the receive buffer of socket to bytesDcResize the send buffer of socket to bytesBfThe peer\xe2\x80\x99s QUIC transport parametersBdQUIC connection transport parameters1CaGenerates connection IDs for incoming connections0CdAn incoming connection did not support any known \xe2\x80\xa60BjNo default client configuration was set up0BiPath abandoned due to unstable interfaces0ClConfiguration for sending and handling validation tokens \xe2\x80\xa60CmMaximum number of packets that may be sent using a single \xe2\x80\xa60CiNotify connections that the local network address has \xe2\x80\xa6ChHandle a change in the local address, i.e. an active \xe2\x80\xa6CiCounter for the number of bytes currently used in the \xe2\x80\xa6CkReduction in congestion window when a new loss event is \xe2\x80\xa60DdMaximum number of datagrams that a Transmit may encode.0CfA stream of NAT traversal updates for this connection.CjGet the address observed by the remote over the given pathCiMaximum number of bytes the peer may transmit without \xe2\x80\xa600Chreceived more data in CRYPTO frames than can be buffered0B`The extension was not negotiatedCbWe failed to figure out what time it currently is.0CbWe failed to acquire random bytes from the system.0CnError indicating that this operation requires multipath to \xe2\x80\xa6BnThe extension was not negotiated with the peerAkMultipath is not negotiated210CnError when the multipath extension was not negotiated, but \xe2\x80\xa6BnHeader of an Initial packet, before decryptionCgDerive keying material from this connection\xe2\x80\x99s TLS \xe2\x80\xa6EdFill output with output.len() bytes of keying material \xe2\x80\xa60BnPathological case: many segments, get from endCfGet segments in the old way, using a loop of get callsClCurrent number of remotely initiated streams that may be \xe2\x80\xa6ClTrack changes on our external address as reported by the \xe2\x80\xa60CmCreate a client configuration that trusts specified trust \xe2\x80\xa60BkThe peer didn\xe2\x80\x99t give us any certificates.0BkThe peer sent an oversized record/fragment.0CkThe ack-eliciting threshold we will request the peer to use0BiWhether there are any pending retransmitsCdWhether the Multipath for QUIC extension is enabled.CbThe peer\xe2\x80\x99s ACK-frequency parameters have changed0C`Sets the keep_alive_interval for a specific pathBoSet a custom ValidationTokenConfig0BmPath abandoned at the application\xe2\x80\x99s request0CjGet the current value of max_udp_payload_size0ChConfigure how to populate the destination CID of the \xe2\x80\xa60CjConstruct an endpoint with arbitrary configuration and \xe2\x80\xa6CfWhether the socket address that is initiating this \xe2\x80\xa60CmModify the number of open paths allowed when multipath is \xe2\x80\xa6Cmthe number of connection IDs provided by the peer exceeds \xe2\x80\xa60CbError returned by Session::export_keying_material.0CiA provided certificate revocation list (CRL) was invalid.0CmPath abandoned due to no available connection IDs for the \xe2\x80\xa60Clreceived transport parameters that were badly formatted, \xe2\x80\xa60CiRegisters one address at which this endpoint might be \xe2\x80\xa6ClAdd addresses the local endpoint considers are reachable \xe2\x80\xa6ClMaximum number of outgoing application datagram bytes to \xe2\x80\xa60CiSet the client configuration used by connectBnSets the max_idle_timeout for a specific path.BfThe QUIC protocol version implemented.CfThe path became unusable after a local network change.BoBytes available in the outgoing datagram bufferDhMaximum number of received bytes to buffer for all Incoming0DaVariant of max_concurrent_bidi_streams affecting \xe2\x80\xa60CmSets whether the server is allowed to migrate once during \xe2\x80\xa60ClModify the number of remotely initiated streams that may \xe2\x80\xa6BmSpurious congestion events on the connection.0CnCreate a client configuration that trusts the platform\xe2\x80\x99s \xe2\x80\xa60CkGenerates 8-byte connection IDs that can be efficiently \xe2\x80\xa6CkAn error occurred while handling Encrypted Client Hello \xe2\x80\xa60CkPath abandoned due to resource limitations in the transport0CiGenerates purely random connection IDs of a specified \xe2\x80\xa6ChWhether to use \xe2\x80\x9cGeneric Segmentation Offload\xe2\x80\x9d to \xe2\x80\xa60CmMaximum number of incoming bidirectional streams that may \xe2\x80\xa60ClMaximum number of incoming application datagram bytes to \xe2\x80\xa60BcInitiates a new nat traversal round0BdPackets were incorrectly deemed lostCaequivalent to BBRHandleSpuriousLossDetection: \xe2\x80\xa610CnRemoves one or more addresses from the set of addresses at \xe2\x80\xa6CgRemoves an address the endpoing no longer considers \xe2\x80\xa6C`Sets the keep_alive_interval for a specific pathDeA ConnectionIdParser implementation that assumes the \xe2\x80\xa6CjWe received a TLS handshake message that isn\xe2\x80\x99t valid \xe2\x80\xa60CiHow to construct new congestion::Controllers0BlSets a default per-path maximum idle timeout0CkConfigures an outbound rate limit (in bytes per second) \xe2\x80\xa60CkThe key exchange group negotiated with the peer. Useful \xe2\x80\xa60CbWhether to send observed address reports to peers.0CiModify the number of remotely initiated bidirectional \xe2\x80\xa6BiEnables the Multipath Extension for QUIC.0CjModify the number of remotely initiated unidirectional \xe2\x80\xa6CeNumber of consecutive PTOs after which network is \xe2\x80\xa60BkSets a default per-path keep alive interval0CjWhether to receive observed address reports from other \xe2\x80\xa60BmGet the current local nat traversal addresses0CkGet the currently advertised nat traversal addresses by \xe2\x80\xa60CkSets the maximum number of nat traversal addresses this \xe2\x80\xa60AcNat traversal draft") \ No newline at end of file diff --git a/pr/720/docs/search.index/desc/8802f729d4c0.js b/pr/720/docs/search.index/desc/8802f729d4c0.js new file mode 100644 index 000000000..75f2db3f6 --- /dev/null +++ b/pr/720/docs/search.index/desc/8802f729d4c0.js @@ -0,0 +1 @@ +rd_("AmData flows in both directions0CdThe CE codepoint, signalling that congestion was \xe2\x80\xa600AjContains the success valueBeThe PathId of this path.BmReturns the PathId of this path.AoGet the identity of this stream00CdThe path which can now be used for application data.AlThe path that was abandoned.B`Which path had its state droppedAmPath which has changed statusCfPath over which the observed address was reported, \xe2\x80\xa643210AlWhich stream is now readableAlWhich stream is now writableAnWhich stream has been finishedAmWhich stream has been stoppedAnType of the Long header packetClWhether a stream communicates data in both directions or \xe2\x80\xa60AhContains the error valueAoThe largest representable valueAlThe maximum path ID allowed.10ClConnects to a QUIC perf server and maintains a specified \xe2\x80\xa6BmData flows only from the stream\xe2\x80\x99s initiator0AnWhich directions data flows in0CaDirectionality for which streams have been openedCdDirectionality for which streams are newly availableCjExplicit congestion notification bits to set on the packet0CeThe Explicit Congestion Notification bits for the \xe2\x80\xa61CdReturns the most recently observed external address.B`The current best RTT estimation.BfThe number of I/O operations executed.0BcLength of QUIC packet being decodedAlLength of the packet payload0BmThe number of bytes the associated buffer hasBbSet a custom TokenLog0CaMinimum RTT registered so far for this estimator.ClConstruct with an approximate maximum memory usage and a \xe2\x80\xa6CjConstruct an endpoint with arbitrary configuration and \xe2\x80\xa6DiCreates a new QlogConfig that writes a qlog trace to the \xe2\x80\xa6CiCreates a new qlog factory that writes files into the \xe2\x80\xa6D`Create a default config with a particular reset_keyCmCreate a default config with a particular handshake token \xe2\x80\xa6CkCreate a default config with a particular cryptographic \xe2\x80\xa6AmConstruct cid from byte arrayoConstruct emptyAeCreate a new StreamIdBeCreates a new FourTuple.DjConstruct a state using the given config and current time \xe2\x80\xa60;9AeCreate a new endpointDcCreate a new instance of FixedLengthConnectionIdParserBdCreate a generator with a random key;:98DgBegin decoding a QUIC packet from bytes, returning any \xe2\x80\xa68BkConstruct an error with a code and a reasonCgInitialize Random CID generator with a fixed CID length98766BfQUIC transport protocol implementationCkGet SystemTime::now() or the mocked equivalentAhLook up the current time01ChCurrent best estimate of this connection\xe2\x80\x99s latency \xe2\x80\xa6000BcExperimental! Use at your own risk.0ChThe ECT(0) codepoint, indicating that an endpoint is \xe2\x80\xa600ChThe ECT(1) codepoint, indicating that an endpoint is \xe2\x80\xa600CaA complete set of keys for a certain packet space0CbA Long packet header, as used during the handshakeChNot attributed to any particular FrameType.CkAn open network transmission within a multipath-enabled \xe2\x80\xa6Ab(Multi)Path eventsB`An error occurred during readingCeWhether an endpoint was the initiator of a connection0nThe 0 path id.0CaThe address observed by the remote over this path0CjThe source address of the datagram(s) contained in the \xe2\x80\xa6mType of errorBlCurrent congestion window of the connection.0gPayloadAoReturns the argument unchanged.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BaCalls U::from(self).000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dNextCoMethod for opening a sealed message data in-place.B`Open a single stream if possible1CgReturns the Path structure of an open pathBhPing the remote endpoint over this path.AhPing the remote endpointCkCheck whether the timer has expired, and register to be \xe2\x80\xa6BaReturns application-facing eventsBgRead data contiguously from the stream.AoRead from the given recv streamCcDecode TransportParameters from bufferBiReceive an unreliable, unordered datagramBdMethod for sealing a token in-place.0CiQueue an unreliable, unordered datagram for immediate \xe2\x80\xa6CbSends a Transmit on the given socket.CmNumber of address validation tokens sent to a client when \xe2\x80\xa60BmThe side of the connection (client or server)ChLook up whether we\xe2\x80\x99re the client or server of this \xe2\x80\xa6AlMethod for signing a message0CdAmount of data written to the caller-supplied buffer0hSpin bitAcStop accepting data0BoStop accepting data on the given receive streamCiTry to find and take a token that was stored with the \xe2\x80\xa60BgA chunk of data from the receive stream0CiThe RFC8312 congestion controller, as widely used for TCP0Borustls reports protocol errors using this type.0DbErrors encountered while decoding TransportParametersCdErrors that the nat traversal state might encounter.BeEvents of interest to the applicationCiEvent emitted when the client receives ADD_ADDRESS or \xe2\x80\xa6CjAttributed to a specific FrameType, never \xe2\x80\xa6A`Any other error.0CcThe peer abandoned transmitting data on this streamCnThe peer is unable to continue processing this connection, \xe2\x80\xa6CdThe peer abandoned transmitting data on this stream.1AeA Retry packet headerCdA short packet header, as used during the data phaseCmBest-effort extraction of the ALPN protocols from the TLS \xe2\x80\xa60BiConstruct a fresh Controller0AiThe contents of the chunkCiThe total amount of bytes which have been transferred \xe2\x80\xa610BnUnderlying error describing reason for failureBaClose the connection immediately.CnClose all of this endpoint\xe2\x80\x99s connections immediately and \xe2\x80\xa6AaCloses this path.AnClose a connection immediatelyBcFrame type that triggered the errorCcDistinguishes streams of the same initiator and \xe2\x80\xa60CjReturns whether the codepoint is a CE, signalling that \xe2\x80\xa60AgKey for encrypting data0BgParse a connection id from given bufferAhReturns all known paths.BlUpdate the timer to expire at iBbClose the send stream immediately.BeAbandon transmitting data on a streamCnRespond with a retry packet, requiring the client to retry \xe2\x80\xa60CiDrive future to completion in the backgroundCeShow connection stats the at the end of the benchmarkAmReturns connection statisticsBiReturns relevant stats from this EndpointCaReturns the PathStats for this path.CgAggregate connection statistics at the moment of close.3BcTitle to record in the qlog capture0CmWrite a buffer into this stream, returning how many bytes \xe2\x80\xa6AmSend data on the given streamCcEncode TransportParameters into bufferC`Future produced by Endpoint::acceptClPaths marked as backup will only be used if there are no \xe2\x80\xa60CeChunks returned from RecvStream::read().AmThe initiator of a connectionAdRun as a perf client1CoState of a Connection at the moment it was closed.CgAttempted to initiate NAT traversal on a closed, or \xe2\x80\xa6BcThe receiver lagged too far behind.CcFuture produced by Connection::open_biChOne or more new streams has been opened and might be \xe2\x80\xa6ChId representing different paths when using multipath \xe2\x80\xa60AbCoding result typeAlThe acceptor of a connectionAdRun as a perf server1mStream eventsAiAn integer less than 2^620CfGet the next incoming connection attempt from a clientClAttempt to accept this incoming connection (an error may \xe2\x80\xa6CcAccept a remotely initiated stream of a certain \xe2\x80\xa61BlAllows to configure the desired cipher suiteCiHelper to construct an endpoint for use with outgoing \xe2\x80\xa6CcWait for the connection to be closed for any reasonAfCoding related traits.BnAccess the configuration used by this endpointChTraits and implementations for the QUIC cryptography \xe2\x80\xa6BjCreate QUIC error code from TLS alert codeBoTLS configuration used for incoming connections210BkAn underlying crypto (e.g. TLS) layer errorCgDecode a plain header from given buffer, with given \xe2\x80\xa6DiDecode a Self from the provided buffer, if the buffer is \xe2\x80\xa6ChThe destination IP address which was encoded in this \xe2\x80\xa6D`Append the encoding of self to the provided buffer.CmNotify the peer that no more data will ever be written to \xe2\x80\xa6CnFinish a send stream, signalling that no more data will be \xe2\x80\xa6B`Process an incoming UDP datagramAfHeader protection keys0ClIgnore this incoming connection attempt, not sending any \xe2\x80\xa60C`Potentially store a token for later one-time use0CfPerform NSS-compatible TLS key logging to the file \xe2\x80\xa6AhThe offset in the stream0B`Packet deliveries were confirmed0AfPacket protection keys0lRandom valueBeThe reason the connection was closed.BcHuman-readable reason for the close0BcReason why this path was abandoned.11BhHuman-readable explanation of the reasonBeReason that the connection was closed2AjSwitch to a new UDP socketBgReject this incoming connection attempt0BoReturns the remote address of the network path.AgKey for decrypting data10AmTLS interface based on rustls0CnHelper to construct an endpoint for use with both incoming \xe2\x80\xa6BkOptional source IP address for the datagram00CgThe current local PathStatus of this path.B`The new status set by the remote0CfThe size of a single datagram in the associated bufferCkStatistics about datagrams and bytes received on this path.CjStatistics about UDP datagrams received on the connection.10CgStatistics about datagrams and bytes sent on this path.CeStatistics about UDP datagrams transmitted on the \xe2\x80\xa610AnMethod for verifying a message0CcNumber of ack-eliciting bytes that may be in flight0A`Send would blockCcNo more data is currently available on this stream.CjThe peer is not able to accept additional data, or the \xe2\x80\xa6BfA catch-all error for unlikely errors.0BlA key for signing with HMAC-based algorithms0AhAn Initial packet headerBnA pair of keys for bidirectional communication0BhA simple, standard congestion controller0CdFuture produced by Connection::open_uniCkAbstracts I/O and timer operations for runtime independenceBfA cryptographic session (commonly TLS)0CcThe peer is no longer accepting data on this streamCfFuture returned from SendStream::stopped.ClThe peer is no longer accepting data on this stream, and \xe2\x80\xa6CkThe peer is no longer accepting data on this stream. No \xe2\x80\xa6CgThe peer asked us to stop sending on an outgoing streamAaAccess to streamsCaThe stream is larger than the user-supplied limitCnAttributed to some frame type this implementation does not \xe2\x80\xa6l0-RTT packetCjReturns the length of a CID for connections created by \xe2\x80\xa60CdProvide the length of dst_cid in short header packetCcThe total number of clients which should be createdAlConnect to a remote endpointAeInitiate a connectionBbDecrypt the Initial packet payloadCgDecrypt the packet payload with the given packet numberBcDecrypt the given packet\xe2\x80\x99s header210ClConstructs a value with arbitrary fields, intended to be \xe2\x80\xa6DjConstruct an event that indicating that a Connection will \xe2\x80\xa6BkThe destination connection ID of the packetBkThe destination Connection ID of the packetAiDestination Connection ID00000CgEncrypt the packet payload with the given packet numberBcEncrypt the given packet\xe2\x80\x99s header10CmCheck if this stream predates completion of the handshake \xe2\x80\xa6CbCheck if this stream has been opened during 0-RTT.CmRetrieve implementation-specific metrics used to populate \xe2\x80\xa60CnThe maximum UDP payload size guaranteed to be supported by \xe2\x80\xa60CjUniform interface to send and receive UDP packets with \xe2\x80\xa6BbOne or more packets were just sent0BmInitiate a new outgoing bidirectional stream.CaReturns the path ID of the new path being opened.AdSource Connection ID0000CiCompletes when the peer stops the stream or reads the \xe2\x80\xa6CjCheck if this stream was stopped, get the reason if it wasCcThe total number of streams which should be createdAlProvide control over streamsCeThe length of the AEAD tag appended to packets on \xe2\x80\xa60CdUpgrade the handle to a full ConnectionB`Upgrades to a Path.AkSet the QUIC version to use0lQUIC versionB`The version that was unsupported11CeFuture produced by Connection::accept_biAfAn unreliable datagramBdDatagram support is disabled locally0A`A QUIC endpoint.BcThe main entry point to the libraryChA finished stream has been fully acknowledged or stoppedCkAn incoming connection for which the server has not yet \xe2\x80\xa60BoLong packet types with uniform header structureB`The largest encoded value length0Cmthe connection is being closed abruptly in the absence of \xe2\x80\xa60CeFuture returned by Connection::on_closedClFuture produced by crate::Connection::open_pathCmA currently open stream likely has data or errors waiting \xe2\x80\xa6CkMetadata for a single buffer filled with bytes received \xe2\x80\xa6BkResponse generated directly by the endpointCfIdentifier for a stream within a particular connection0CnCommunication with the peer has lapsed for longer than the \xe2\x80\xa6CkWe didn\xe2\x80\x99t receive any data from the remote within the \xe2\x80\xa61ChResponsible for limiting clients\xe2\x80\x99 ability to reuse \xe2\x80\xa60ClThe datagram is larger than the connection can currently \xe2\x80\xa60AbAn outgoing packet00CmStatistics about UDP datagrams transmitted or received on \xe2\x80\xa60CnA formerly write-blocked stream might be ready for a write \xe2\x80\xa6AkCongestion algorithm to useAhContents of the datagramBoMark the read data as consumed from the stream.BnStatistics about frames received on this path.CcStatistics about frames received on the connection.10CaStatistics about frames transmitted on this path.CfStatistics about frames transmitted on the connection.10DhConstructs cid by reading len bytes from a Buf0DkCreates a new qlog factory that writes files into QLOGDIR, \xe2\x80\xa60BfCreate a generator with a specific keyBjConstruct a VarInt infallibly0BeSucceeds iff x < 2^620AeWhat type we receivedAoWhat handshake type we received10CbWhether 0-RTT is/was possible during the handshakeCmSpecifies the time to wait after completing MTU discovery \xe2\x80\xa60CcReturns Self for use in down-casting to extract \xe2\x80\xa60EhReturns true if the Connection associated with this handle \xe2\x80\xa6CmDuration after an address validation token was issued for \xe2\x80\xa60CeThe local IP address which was used when the peer \xe2\x80\xa60BjThe local IP used for this path, if known.BnReturns the local address of the network path.20ClCompute the maximum size of datagrams that may be passed \xe2\x80\xa6BnInitiate a new outgoing unidirectional stream.BcGet the priority of the send streamAlGet the priority of a streamCfThe negotiated application protocol, if ALPN is in use0Aeqlog output directoryBbOptional response to transmit backCiOptional seed to be used internally for random number \xe2\x80\xa60AlSlow start threshold (bytes)0BeSucceeds iff x < 2^6200000DaSends a Transmit on the given socket without any \xe2\x80\xa6DkQuickly determine whether cid could have been generated by \xe2\x80\xa600BmA path was abandoned and is no longer usable.0CfFuture produced by Connection::accept_uniCdPaths marked with as available will be used when \xe2\x80\xa60CnAt least one new stream of a certain directionality may be \xe2\x80\xa6BkThe connection was successfully establishedAoAPI to control datagram trafficAlDecoding of QUIC primitives.CkA path was discarded and all remaining state for it has \xe2\x80\xa60BgInfallible encoding of QUIC primitives.CnIdentifies a network path by the combination of remote and \xe2\x80\xa60A`Handshake packetBcKeys used to protect packet headers0CiCatch-all error for problems while decoding transport \xe2\x80\xa6CeNat traversal attempt failed due to a multipath errorBdKeys used to protect packet payloads0BmErrors that might trigger a path being closed0AnApplication events about paths0BjStatistics related to a transmission path.0AeA read error occurredBmErrors that arise from reading from a stream.C`Errors triggered when reading from a recv streamCiAn object for asynchronously writing to an associated \xe2\x80\xa6BmAccept the next incoming bidirectional streamBbDuplicate the controller\xe2\x80\x99s state0BeThe number of UDP datagrams observed.AaControl datagrams1BeCreate new object from the given bits00BoWhich side of a connection initiated the stream0CmConvert into a 0-RTT or 0.5-RTT connection at the cost of \xe2\x80\xa6BoShorthand for self == Side::Client0B`Whether the connection is closedBoShorthand for self == Side::Server0CbWhether it is legal to respond with a retry packet0CdWhether to allow clients to migrate to new addresses0CdConstruct a timer that will expire at iBoLow-level protocol logic for the QUIC protoocolCjWait for the connection to be closed without keeping a \xe2\x80\xa6CjOpens an additional path if the multipath extension is \xe2\x80\xa6AaOpens a new path.BmPing the remote endpoint over a specific pathCiAttempts to read from the stream into the provided bufferCeReceive UDP datagrams, or register to be woken if \xe2\x80\xa6CkSend a UDP datagram, or register to be woken if sending \xe2\x80\xa6ClPrivate key used to send authenticated connection resets \xe2\x80\xa60BmGenerate the integrity tag for a retry packet0BgA stable identifier for this connectionCePrivate key used to authenticate data included in \xe2\x80\xa60BlThe position of a token in the packet bufferCgTransport configuration to use for incoming connections0CkWaits for all connections on the endpoint to be cleanly \xe2\x80\xa6BoWrite a buffer into this stream in its entiretyCiAbstract implementation of an async timer for runtime \xe2\x80\xa6BoNumber of UDP packets to send/receive at a timeCmConfiguration for the Bbr3 congestion controller0CkError indicating that a path has not been opened or has \xe2\x80\xa6BnThe path is already closed or was never opened1101BeIn-progress connection attempt futureAbA QUIC connection.CeProtocol state and logic for a single QUIC connectionCeCommon interface for different congestion controllers0CjNumber of frames transmitted or received of each frame \xe2\x80\xa60BoThe connection ID was not recognized by the \xe2\x80\xa60DdThe type used to refer to FrameTypes in closing and \xe2\x80\xa6DbA stream of PathEvents for all paths in a connection.AnThe QUIC-MULTIPATH path status0BeConfiguration for qlog trace logging.0BnA stream that can only be used to receive dataAaAccess to streamsChErrors that arise while waiting for a stream to be resetDhError for attempting to retry an Incoming which already \xe2\x80\xa60BkA stream that can only be used to send data3BmObject to get current SystemTime0AdA rustls TLS session0CkResponsible for storing validation tokens received from \xe2\x80\xa60AeA borrowed UDP socketBjErrors that arise from writing to a streamBoErrors triggered while writing to a send streamBoAccept the next incoming uni-directional streamCkWhether the implementation is permitted to set the spin \xe2\x80\xa60CbReturns the number of bytes read from this stream.0CiCloses a path and sends a PATH_ABANDON frame with the \xe2\x80\xa6CdLogic for controlling the rate at which data is sent0BfWhether to print connection statisticsBnClass of error as encoded in the specificationB`Application-specific reason code10CaThe error code to be sent with the abandon frame.BoThe error that was sent with the abandon frame.AoError code supplied by the peerBcType of frame that caused the close0AiExtract the integer value0CnWhether there is no longer any need to keep the connection \xe2\x80\xa6DkDetermine whether this is the last event a Connection will \xe2\x80\xa6CiLook up the local IP address and port used by this socketDgGet the local SocketAddr the underlying socket is bound toBfThe number of bytes lost on this path.BkThe number of bytes lost on the connection.10CjPad UDP datagrams carrying application data to current \xe2\x80\xa60AgReturns path statisticsCjPer-path statistics for every path the connection knew \xe2\x80\xa6CjThe final path stats, they are no longer available via \xe2\x80\xa620C`Attempt to write bytes from buf into the stream.CoReads the next segment of data as zero-copy Bytes.AoReads the next segment of data.CkRead an exact number of bytes contiguously from the stream.BnSets the PathStatus of this path.BoEpoch qlog event times are recorded relative to0ClError type for attempting to accept an IncomingBjErrors in the configuration of an endpoint0AeGeneric crypto errors0CnConfiguration for the Cubic congestion controller0CdA new path has established connection with the peer.0CdReasons why attempting to finish a stream might failCnMaximum duration of inactivity to accept before timing out \xe2\x80\xa60AnValue exceeds supported bounds0D`Constructs a QlogConfig for individual connections.0AfA noq runtime for smolB`Application events about streamsCbAccept this incoming connection using a custom \xe2\x80\xa6CeLargest UDP payload size the path currently supports.ClStorage size required for the largest packet that can be \xe2\x80\xa61BiDescription to record in the qlog capture0BjThe socket this datagram should be sent to00DcCreates a new FourTuple without a known local address.0BkStarting guess for maximum UDP payload sizeCkThe initial value to be used as the maximum UDP payload \xe2\x80\xa60ChUDP payload size that the network must be capable of \xe2\x80\xa6BjThe RTT used before an RTT sample is taken0BfThe initial round-trip-time (in msecs)CiWhether this is the event is the event indicating the \xe2\x80\xa6CeThe amount of concurrent streams which should be usedDdPackets are acked in batches, all with the same now \xe2\x80\xa60AePacing rate (bytes/s)0DeA stream of PathEvents for all paths in this connection.DfGets the local PathStatus for a known PathIdCkConvenience method to read all remaining data into a bufferAlProvide control over streamsBoThe sample size used for this key\xe2\x80\x99s algorithm01CiMaximum number of bytes to transmit to a peer without \xe2\x80\xa600BoThe server name specified by the client, if any0BmObject to get current SystemTime0BdSet a custom TokenStore0CaNumber of bytes to transmit from client to serverCnSpecifies the upper bound to the max UDP payload size that \xe2\x80\xa60ChReturns a weak reference to the inner connection struct.CdReturns a WeakPathHandle for this path.DgCreate a server config with the given crypto::ServerConfig0CeSets a prefix to the filename of the generated files.0DdWrites a single Bytes into this stream in its entirety.BbAn ADD_ADDRESS frame was received.BfConfiguration for outgoing connectionsCaClient-side configuration for the crypto protocol10CgThe stream has already been stopped, finished, or resetBmThe stream has already been finished or resetCmError indicating that a stream has not been opened or has \xe2\x80\xa6CjThe stream has not been opened or was already stopped, \xe2\x80\xa6CfThe stream has not been opened or has already been \xe2\x80\xa6CmThe stream has not been opened or was already finished or \xe2\x80\xa63CgErrors in the parameters being used to create a new \xe2\x80\xa60BkProtocol-level identifier for a connection.0CkWe couldn\xe2\x80\x99t decrypt a message. This is invariably fatal.0BjExplicit congestion notification codepoint00CnWe couldn\xe2\x80\x99t encrypt a message because it was larger than \xe2\x80\xa60BhParameters that are semantically invalidCkCannot close the last remaining open path via the local \xe2\x80\xa60Akn0\xe2\x80\x99s nat traversal eventsDhNull implementation of TokenLog, which never accepts tokens0ClReceived an observation of our external address from the \xe2\x80\xa60CiFuture produced by Connection::read_datagramBiThe remote changed the status of the path0BlRTT estimation for a particular network pathCnFuture produced by Connection::send_datagram_waitBiParameters governing incoming connectionsCaServer-side configuration for the crypto protocol10CmErrors that arise while monitoring for a send stream stop \xe2\x80\xa6AgA noq runtime for TokioC`Returns the lifetime of generated Connection IDs0BjWhether the connection is closed, and why.CjConnect to a remote endpoint using a custom configuration.AlConservative estimate of RTTBnGet the 0-RTT keys if available (clients only)0AgWhich types we expectedB`Which handshake type we expected10AcGenerates a new CID0CcThe number of segments to read when GRO is enabled.DeProcess ConnectionEvents generated by the associated \xe2\x80\xa6EaProcess EndpointEvents emitted from related ConnectionsCgCreate the initial set of keys given the client\xe2\x80\x99s \xe2\x80\xa6000BhThe number of packets lost on this path.BmThe number of packets lost on the connection.10DcMaximum number of Incoming to allow to exist at a time0CjWhether datagrams might get fragmented into multiple parts0CmWhether transmitted datagrams might get fragmented by the \xe2\x80\xa6BdThe network path used for this path.CkReturns the path\xe2\x80\x99s network path represented as a 4-tuple.CkThe original destination CID when initiating the connectionCiThe original destination connection ID sent by the clientDhReturns the next time at which handle_timeout should be \xe2\x80\xa6D`Configures qlog capturing by setting a QlogFactory.0AgThe runtime type to useCkThe segment size if this transmission contains multiple \xe2\x80\xa600CkSend Quantum (bytes) used to control the size of packet \xe2\x80\xa60ChThe number of streams that may have unacknowledged data.CbSet the lifetime of CIDs created by this generator0BcSet the priority of the send streamAlSet the priority of a streamCnInitialize a QUIC-compatible TLS client configuration with \xe2\x80\xa6000AmSend data on the given streamCkWe received a fatal alert. This means the peer is unhappy.0BhBloom filter-based TokenLog0CmThe connection could not be created because not enough of \xe2\x80\xa6000CaEvent resulting from processing a single datagramBlEvents sent from a Connection to an EndpointAoStatistics on Endpoint activityBnThe stream finished before all bytes were readBlAuthentication data for (rustls) TLS session0Ccreceived an invalid Retry Token in a client Initial0ChIterator over ALPN protocol names from a TLS ClientHelloAlThe packet header is invalidBkThe local application closed the connection0DaThe datagram may result in starting a new ConnectionD`Configuration for the NewReno congestion controller0BjDecodes a QUIC packet\xe2\x80\x99s invariant headerCgErrors triggered when opening a recv stream for readingCaDefault implementation of TimeSource0CgError indicating that the provided buffer was too smallChFor clients, if the peer accepted the 0-RTT data packetsAbAck Frequency modeCnSucceeds when an incoming connection is proven not to be a \xe2\x80\xa6AfExports for benchmarksBoSupply a custom connection ID generator factory0DgCreate a UdpSender that can register a single task for \xe2\x80\xa6CaNumber of bytes to transmit from server to clientAmGet the Incoming0CnThe max_ack_delay we will request the peer to use0CgDisable packet encryption/decryption (for debugging \xe2\x80\xa6CkThe known MTU for the current network path has been updated0BbCryptographic identity of the peerBgGet the peer\xe2\x80\x99s identity, if availableDhFor the rustls TlsSession, the Any type is \xe2\x80\xa610AkReturns packets to transmitDjConfigures qlog capturing through the QLOGDIR environment \xe2\x80\xa60AoReceive an application datagramDfTransmit data as an unreliable, unordered application \xe2\x80\xa6CmWhether to implement fair queuing for send streams having \xe2\x80\xa60BfLength of sign\xe2\x80\x99s output0BnStart a client session with this configurationBnStart a server session with this configuration10BdA REMOVE_ADDRESS frame was received.CgAbstract implementation of a UDP socket for runtime \xe2\x80\xa6BgErrors triggered when abandoning a path0AgThe connection was lost00000ChGlobal configuration for the endpoint, affecting all \xe2\x80\xa60Cithe endpoint encountered an internal error and cannot \xe2\x80\xa60FbBasic adapter to let Incoming be await-ed like a ConnectingBhEncounter a frame ID that was not valid.CeThe peer sent us a TLS message with invalid contents.0Amno viable network path exists0DhNull implementation of TokenStore, which does not store \xe2\x80\xa60CiThe peer deviated from the standard TLS protocol. The \xe2\x80\xa60BmErrors that arise from reading from a stream.C`Errors from RecvStream::read_to_endCaIndicates whether a frame needs to be transmittedCmThe peer violated the QUIC specification as understood by \xe2\x80\xa60CiTransport-level errors occur when a peer violates the \xe2\x80\xa6C`Tokio-compatible UDP socket with some useful \xe2\x80\xa6DiWeak handle for a Path that does not keep the connection \xe2\x80\xa6BnCreate a client endpoint and client connectionAgGet a session referenceDiReturns a QlogConfig for a connection, if logging should \xe2\x80\xa60AiProcess timer expirationsBjParameters negotiated during the handshake0CfGet data negotiated during the handshake, if available0AiInitial congestion windowCiDefault limit on the amount of outstanding data in bytes.001000BnConverts this stream into an unordered stream.DdReturns true until the connection is fully established.CeWhether the connection is in the process of being \xe2\x80\xa61BfVerify the integrity of a retry packet0CnSpecifies the minimum MTU change to stop the MTU discovery \xe2\x80\xa60BdCompute keys for the next key update0AhOne packet was just lost0AhOne packet was just sent0BkConfigures qlog capturing into a directory.0AlRead bytes of handshake data0BeWhether to use the unordered read APIClMaximum number of bytes the peer may transmit across all \xe2\x80\xa600CkCompletes when the stream has been reset by the peer or \xe2\x80\xa60CiCheck whether this stream has been reset by the peer, \xe2\x80\xa6AjThe peer\xe2\x80\x99s UDP addressesAhThe peer\xe2\x80\x99s UDP addressBgThe peer\xe2\x80\x99s UDP address for this path.1CeSaturating integer addition. Computes self + rhs, \xe2\x80\xa6000ChSaturating integer subtraction. Computes self - rhs, \xe2\x80\xa60CkMaximum reordering in time space before time based loss \xe2\x80\xa60ChReason given by the transport for closing the connection0BfReasons why a connection might be lost0CiThe datagram is redirected to its ConnectionBlEvents sent from an Endpoint to a ConnectionAfConnection statistics.0BiStatistics for the currently open streamsAcPlain packet headerBkEnables writing qlog traces to a directory.0AkThe remote closed the path.CfError for when a validation token may have been reused0C`Parameters governing the core QUIC state machine0CbThe peer doesn\xe2\x80\x99t implement any supported version0CdFuture that completes when a connection is fully \xe2\x80\xa6CbThis was a 0-RTT stream and the server rejected it000CjAutomatically select an appropriate runtime from those \xe2\x80\xa6CkWhether to accept QUIC packets containing any value for \xe2\x80\xa60CdMaximum number of incoming packets that may fail \xe2\x80\xa60CnThe interface index of the interface on which the datagram \xe2\x80\xa6AjSwitch to a new UDP socketCiCreates a server endpoint which runs on the given runtimeD`Sets the PathStatus for a known PathIdCfSee proto::TransportConfig::send_window()BoSee TransportConfig::send_window()BmReturns whether a frame should be transmittedD`Convert t into the socket type used by this runtimeCdWrites handshake bytes into the given buffer and \xe2\x80\xa60ClStream produced by Path::observed_external_addrCiReason given by an application for closing the connection0CbThe peer\xe2\x80\x99s QUIC stack aborted the connection \xe2\x80\xa60DjInternal identifier for a Connection currently associated \xe2\x80\xa6CdOne or more application datagrams have been receivedBjDecrypted payload of a QUIC Initial packet0CaThe endpoint can no longer create new connections0Cnreceived a STREAM frame or a RESET_STREAM frame containing \xe2\x80\xa60ClSpecific failure cases from keys_match or a \xe2\x80\xa60A`key update error0CaCurrent limits do not allow us to open more paths0ClThe peer doesn\xe2\x80\x99t support a protocol version/feature we \xe2\x80\xa60BjA QUIC-compatible TLS client configuration0BjA QUIC-compatible TLS server configuration0EfTokenStore implementation that stores up to N tokens per \xe2\x80\xa60CgAn endpoint (local or remote) tried to add too many \xe2\x80\xa6CaPath could not be validated and will be abandonedCmWe didn\xe2\x80\x99t receive a path response in time after opening \xe2\x80\xa61BcA Version Negotiation packet headerCiRecord that the token was used and, ideally, return a \xe2\x80\xa60CjCurrent state of the congestion control algorithm, for \xe2\x80\xa6CcCurrent state of this connection\xe2\x80\x99s congestion \xe2\x80\xa6BaUpdate traffic keys spontaneously0CjMaximum number of segments to transmit if Generic Send \xe2\x80\xa6CnMaximum duration of inactivity to accept before timing out \xe2\x80\xa60Cgn0\xe2\x80\x99s (https://n0.computer) NAT Traversal protocol \xe2\x80\xa6CeGet the number of connections that are currently openBmNumber of connections that are currently openDeOpens a new path if no path exists yet for network_path.CmOpens a new path only if no path on the same network path \xe2\x80\xa6CiMaximum reordering in packet number space before FACK \xe2\x80\xa60B`Reads the next segments of data.CfGet the size of the socket receive bufferAlReceive buffer size in bytesCcGet the size of the socket send bufferAiSend buffer size in bytesBiSet a custom TransportConfig000ChConfiguration for sending and handling validation tokens0CnCreate a server config with the given certificate chain to \xe2\x80\xa60DfWrites a slice of Bytes into this stream in its entirety.Cfthe application or application protocol caused the \xe2\x80\xa60AnThe peer closed the connectionBoThe path was closed locally by the application.1B`Constructs controllers on demand0CnCommon congestion controller metrics used both for logging \xe2\x80\xa60ClThe trait for encrypting tokens that power retry packets \xe2\x80\xa60BcThe given server name was malformed0CbHints when the caller identifies a network change.0AcPacket decode errorBdReason for why a path was abandoned.BmErrors that can arise when sending a datagram0CcThe peer does not support receiving datagram frames0BdCongestion events on the connection.0AiCongestion window (bytes)0ClCompute the maximum size of datagrams that may be passed \xe2\x80\xa6BoBytes available in the outgoing datagram bufferClReplace the server configuration, affecting new incoming \xe2\x80\xa60CmWaits for all connections on the endpoint to be ready for \xe2\x80\xa6DgWrites Bytes from a slice of buffers into this stream, \xe2\x80\xa6Cmthe endpoint has reached the confidentiality or integrity \xe2\x80\xa60CkParameters for controlling the peer\xe2\x80\x99s acknowledgement \xe2\x80\xa60DjThe max_fragment_size value supplied in configuration was \xe2\x80\xa60Bmthe server refused to accept a new connection0BjParse connection id in short header packetCjOne or more application datagrams have been sent after \xe2\x80\xa6Ckreceived more data than permitted in advertised data limits0AoThe TLS handshake was confirmedBjThe connection\xe2\x80\x99s handshake data is readyCeAttempted an ordered read following an unordered readAnWe saw an invalid certificate.0BcParameters governing MTU discovery.0BnNot enough addresses to complete the operationCkdetected an error with protocol compliance that was not \xe2\x80\xa60Cjreceived a frame for a stream identifier that exceeded \xe2\x80\xa60Cnreceived a frame for a stream that was not in a state that \xe2\x80\xa60AnError from setting path status0AjTransport-level error code0ChThe local endpoint does not support the QUIC version \xe2\x80\xa6CkError indicating that the specified QUIC version is not \xe2\x80\xa61C`Packet uses a QUIC version that is not supported1CiMaximum quantity of out-of-order crypto layer data to \xe2\x80\xa60C`Create a VarInt without ensuring it\xe2\x80\x99s in range0ChCumulative number of Quic handshakes ignored on this \xe2\x80\xa6EgReturns true if the two WeakConnectionHandle point at the \xe2\x80\xa6CiMinimum interval between outgoing stateless reset packets0CjConstruct with an approximate maximum memory usage and \xe2\x80\xa60ChCumulative number of Quic handshakes refused on this \xe2\x80\xa6AnReturns the remote path statusDfTransmit data as an unreliable, unordered application \xe2\x80\xa6CnUpdates the set of ALPN protocols configured in the client \xe2\x80\xa6CnUpdates the set of ALPN protocols configured in the server \xe2\x80\xa610CiSee proto::TransportConfig::receive_window()CbSee TransportConfig::receive_window()B`Override supported QUIC versions0CiOverride the instant relative to which all events are \xe2\x80\xa60CcA stream of NAT traversal updates for a connection.BkNo remote CIDs available to open a new path0CkTransport parameters used to negotiate connection-level \xe2\x80\xa6CgA stream that can be used to receive data out-of-order.CmThe certificate verifier doesn\xe2\x80\x99t support the given type \xe2\x80\xa60CfThe operation is not allowed for this endpoint\xe2\x80\x99s \xe2\x80\xa6CiCumulative number of Quic handshakes accepted by this \xe2\x80\xa6CjSpecifies the amount of time that MTU discovery should \xe2\x80\xa60CiIf the 0-RTT-encrypted data has been accepted by the peer0BgWait for the handshake to be confirmed.CgInform the connection if a path may recover after a \xe2\x80\xa60CgPeriod of inactivity before sending a keep-alive packet0CfThe number of PLPMTUD probe packets lost on this path.0BlPackets were deemed lost or marked congested0CgCumulative number of Quic handshakes sent from this \xe2\x80\xa6CnThe number of remotely initiated open streams of a certain \xe2\x80\xa6AhBench fns for SendBufferCfThe number of PLPMTUD probe packets sent on this path.0Bireceived a frame that was badly formatted0CkThis function doesn\xe2\x80\x99t work until the TLS handshake is \xe2\x80\xa60CkWe received a TLS message that isn\xe2\x80\x99t valid right now. \xe2\x80\xa60CkThe remote address for the path is not supported by the \xe2\x80\xa6CiThe remote SocketAddr supplied was malformed10ChThe initial cipher suite (AES-128-GCM-SHA256) is not \xe2\x80\xa60CnWatches the external address reported by the peer for this \xe2\x80\xa6BdPaths can only be opened client-side0DmError returned when constructing a VarInt from a value >= \xe2\x80\xa60CeA handle to some connection internals, use with care.DkSpecifies the ACK frequency config (see AckFrequencyConfig \xe2\x80\xa60CjThe number of times a black hole was detected in the path.0CgMaximum number of received bytes to buffer for each \xe2\x80\xa60AeIs multipath enabled?ClMaximum number of datagrams that might be described by a \xe2\x80\xa60CkMaximum UDP payload size accepted from peers (excluding \xe2\x80\xa60AmMax UDP payload size in bytesDkSpecifies the MTU discovery config (see MtuDiscoveryConfig \xe2\x80\xa60AmReturn endpoint-facing eventsCkThe preferred IPv4 address that will be communicated to \xe2\x80\xa60CkThe preferred IPv6 address that will be communicated to \xe2\x80\xa60ChThe reordering threshold we will request the peer to use0ClDuration after a retry token was issued for which it\xe2\x80\x99s \xe2\x80\xa60BmSets the max idle timeout for a specific pathDfResize the receive buffer of socket to bytesDcResize the send buffer of socket to bytesBfThe peer\xe2\x80\x99s QUIC transport parametersBdQUIC connection transport parameters1CaGenerates connection IDs for incoming connections0CdAn incoming connection did not support any known \xe2\x80\xa60BjNo default client configuration was set up0BiPath abandoned due to unstable interfaces0ClConfiguration for sending and handling validation tokens \xe2\x80\xa60CmMaximum number of packets that may be sent using a single \xe2\x80\xa60CiNotify connections that the local network address has \xe2\x80\xa6ChHandle a change in the local address, i.e. an active \xe2\x80\xa6CiCounter for the number of bytes currently used in the \xe2\x80\xa6CkReduction in congestion window when a new loss event is \xe2\x80\xa60DdMaximum number of datagrams that a Transmit may encode.0CfA stream of NAT traversal updates for this connection.CjGet the address observed by the remote over the given pathCiMaximum number of bytes the peer may transmit without \xe2\x80\xa600Chreceived more data in CRYPTO frames than can be buffered0B`The extension was not negotiatedCbWe failed to figure out what time it currently is.0CbWe failed to acquire random bytes from the system.0CnError indicating that this operation requires multipath to \xe2\x80\xa6BnThe extension was not negotiated with the peerAkMultipath is not negotiated210CnError when the multipath extension was not negotiated, but \xe2\x80\xa6BnHeader of an Initial packet, before decryptionCgDerive keying material from this connection\xe2\x80\x99s TLS \xe2\x80\xa6EdFill output with output.len() bytes of keying material \xe2\x80\xa60BnPathological case: many segments, get from endCfGet segments in the old way, using a loop of get callsClCurrent number of remotely initiated streams that may be \xe2\x80\xa6ClTrack changes on our external address as reported by the \xe2\x80\xa60CmCreate a client configuration that trusts specified trust \xe2\x80\xa60BkThe peer didn\xe2\x80\x99t give us any certificates.0BkThe peer sent an oversized record/fragment.0CkThe ack-eliciting threshold we will request the peer to use0BiWhether there are any pending retransmitsCdWhether the Multipath for QUIC extension is enabled.CbThe peer\xe2\x80\x99s ACK-frequency parameters have changed0C`Sets the keep_alive_interval for a specific pathBoSet a custom ValidationTokenConfig0BmPath abandoned at the application\xe2\x80\x99s request0CjGet the current value of max_udp_payload_size0ChConfigure how to populate the destination CID of the \xe2\x80\xa60CjConstruct an endpoint with arbitrary configuration and \xe2\x80\xa6CfWhether the socket address that is initiating this \xe2\x80\xa60CmModify the number of open paths allowed when multipath is \xe2\x80\xa6Cmthe number of connection IDs provided by the peer exceeds \xe2\x80\xa60CbError returned by Session::export_keying_material.0CiA provided certificate revocation list (CRL) was invalid.0CmPath abandoned due to no available connection IDs for the \xe2\x80\xa60Clreceived transport parameters that were badly formatted, \xe2\x80\xa60CiRegisters one address at which this endpoint might be \xe2\x80\xa6ClAdd addresses the local endpoint considers are reachable \xe2\x80\xa6ClMaximum number of outgoing application datagram bytes to \xe2\x80\xa60CiSet the client configuration used by connectBnSets the max_idle_timeout for a specific path.BfThe QUIC protocol version implemented.CfThe path became unusable after a local network change.BoBytes available in the outgoing datagram bufferDhMaximum number of received bytes to buffer for all Incoming0DaVariant of max_concurrent_bidi_streams affecting \xe2\x80\xa60CmSets whether the server is allowed to migrate once during \xe2\x80\xa60ClModify the number of remotely initiated streams that may \xe2\x80\xa6BmSpurious congestion events on the connection.0CnCreate a client configuration that trusts the platform\xe2\x80\x99s \xe2\x80\xa60CkGenerates 8-byte connection IDs that can be efficiently \xe2\x80\xa6CkAn error occurred while handling Encrypted Client Hello \xe2\x80\xa60CkPath abandoned due to resource limitations in the transport0CiGenerates purely random connection IDs of a specified \xe2\x80\xa6ChWhether to use \xe2\x80\x9cGeneric Segmentation Offload\xe2\x80\x9d to \xe2\x80\xa60CmMaximum number of incoming bidirectional streams that may \xe2\x80\xa60ClMaximum number of incoming application datagram bytes to \xe2\x80\xa60BcInitiates a new nat traversal round0BdPackets were incorrectly deemed lostCaequivalent to BBRHandleSpuriousLossDetection: \xe2\x80\xa610CnRemoves one or more addresses from the set of addresses at \xe2\x80\xa6CgRemoves an address the endpoing no longer considers \xe2\x80\xa6C`Sets the keep_alive_interval for a specific pathDeA ConnectionIdParser implementation that assumes the \xe2\x80\xa6CjWe received a TLS handshake message that isn\xe2\x80\x99t valid \xe2\x80\xa60CiHow to construct new congestion::Controllers0BlSets a default per-path maximum idle timeout0CkConfigures an outbound rate limit (in bytes per second) \xe2\x80\xa60CkThe key exchange group negotiated with the peer. Useful \xe2\x80\xa60CbWhether to send observed address reports to peers.0CiModify the number of remotely initiated bidirectional \xe2\x80\xa6BiEnables the Multipath Extension for QUIC.0CjModify the number of remotely initiated unidirectional \xe2\x80\xa6CeNumber of consecutive PTOs after which network is \xe2\x80\xa60BkSets a default per-path keep alive interval0CjWhether to receive observed address reports from other \xe2\x80\xa60BmGet the current local nat traversal addresses0CkGet the currently advertised nat traversal addresses by \xe2\x80\xa60CkSets the maximum number of nat traversal addresses this \xe2\x80\xa60AcNat traversal draft") \ No newline at end of file diff --git a/pr/720/docs/search.index/entry/1d4df8beee4b.js b/pr/720/docs/search.index/entry/1d4df8beee4b.js new file mode 100644 index 000000000..cdd376738 --- /dev/null +++ b/pr/720/docs/search.index/entry/1d4df8beee4b.js @@ -0,0 +1 @@ +rd_("Af[477,15,478,0,133,0,0]Ak[3173,15,3174,3174,134,0,0]Ag[477,15,478,0,4208,0,0]Al[3173,15,3174,1829,4209,0,0]Al[2029,15,2030,2030,4210,0,0]Al[3173,15,1731,1731,1470,0,0]Ao[1228,13,1229,1229,4047,3111,0]Am[477,13,478,3740,4899,3111,0]Am[477,13,478,4270,1458,3111,0]Al[477,13,478,1126,520,3111,0]Am[477,13,478,1126,4492,3111,0]Am[477,13,478,4157,4485,3111,0]Am[477,13,478,4157,3121,3111,0]Am[477,13,478,4157,3324,3111,0]Am[477,13,478,4157,4484,3111,0]Am[477,13,478,4162,3342,3111,0]Am[477,13,478,4162,4248,3111,0]Aj[477,13,478,0,1480,3111,0]Aj[477,13,478,0,5070,3111,0]Aj[477,13,478,0,1184,3111,0]Aj[477,13,478,0,1463,3111,0]Aj[477,13,478,0,3317,3111,0]Aj[477,13,478,0,3116,3111,0]Aj[477,13,478,0,4955,3111,0]Aj[477,13,478,0,3290,3111,0]Aj[477,13,478,0,2343,3111,0]Aj[477,13,478,0,3303,3111,0]Aj[477,13,478,0,3118,3111,0]Aj[477,13,478,0,4194,3111,0]Aj[477,13,478,0,4584,3111,0]Aj[477,13,478,0,3112,3111,0]Aj[477,13,478,0,4451,3111,0]Aj[477,13,478,0,4064,3111,0]Aj[477,13,478,0,4050,3111,0]Aj[477,13,478,0,3099,3111,0]Aj[477,13,478,0,4581,3111,0]Aj[477,13,478,0,4788,3111,0]Aj[477,13,478,0,4200,3111,0]Aj[477,13,478,0,4203,3111,0]Aj[477,13,478,0,4208,3111,0]Aj[477,13,478,0,4960,3111,0]Ai[477,13,478,0,526,3111,0]Ai[477,13,478,0,133,3111,0]Aj[477,13,478,0,2330,3111,0]Aj[477,13,478,0,3097,3111,0]Ak[477,13,1735,0,5224,3111,0]Ak[477,13,1818,0,1201,3111,0]Ao[3173,13,3174,1856,1481,3111,0]Ao[3173,13,3174,1856,5071,3111,0]Ao[3173,13,3174,3138,1185,3111,0]Ao[3173,13,3174,3147,4900,3111,0]Ao[3173,13,3174,1403,1464,3111,0]Ao[3173,13,3174,1403,3318,3111,0]Ao[3173,13,3174,1403,3117,3111,0]Ao[3173,13,3174,1403,4898,3111,0]Ao[3173,13,3174,1403,4956,3111,0]Ao[3173,13,3174,1403,3293,3111,0]Ao[3173,13,3174,1418,2344,3111,0]Ao[3173,13,3174,1418,3304,3111,0]Ao[3173,13,3174,1418,3119,3111,0]Ao[3173,13,3174,1152,3122,3111,0]Ao[3173,13,3174,1152,4374,3111,0]Ao[3173,13,3174,1157,3343,3111,0]Ao[3173,13,3174,1157,4063,3111,0]Ao[3173,13,3174,2044,4082,3111,0]Ao[3173,13,3174,2044,4486,3111,0]Ao[3173,13,3174,2044,4198,3111,0]Ao[3173,13,3174,3741,4585,3111,0]Ao[3173,13,3174,3741,3113,3111,0]Ao[3173,13,3174,3741,4452,3111,0]Ao[3173,13,3174,3276,4065,3111,0]Ao[3173,13,3174,1733,4051,3111,0]Ao[3173,13,3174,1393,3100,3111,0]Ao[3173,13,3174,1393,4467,3111,0]Ao[3173,13,3174,1393,3310,3111,0]Ao[3173,13,3174,1393,3332,3111,0]Ao[3173,13,3174,1393,4205,3111,0]Ao[3173,13,3174,1393,4583,3111,0]Ao[3173,13,3174,1393,4790,3111,0]Ao[3173,13,3174,2354,4794,3111,0]Ao[3173,13,3174,2354,4201,3111,0]Ao[3173,13,3174,1798,2316,3111,0]Ao[3173,13,3174,1798,4895,3111,0]Ao[3173,13,3174,1829,4204,3111,0]Ao[3173,13,3174,1829,4209,3111,0]Al[3173,13,3174,0,4490,3111,0]Al[3173,13,3174,0,4961,3111,0]An[3173,13,3174,3174,527,3111,0]An[3173,13,3174,3174,134,3111,0]Ao[3173,13,3174,3174,2331,3111,0]Ao[3173,13,3174,3174,3098,3111,0]Ao[3173,13,1731,1731,4380,3111,0]Ao[3173,13,5112,5112,5008,3111,0]Ao[3173,13,5112,5112,1203,3111,0]Ao[3173,13,1736,1736,5225,3111,0]Al[3173,13,1819,0,1202,3111,0]Ao[2029,13,2030,2030,4210,3111,0]Ai[477,13,478,1126,520,0,0]Aj[477,13,478,1126,4492,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5009,0,0]Aj[477,13,478,4162,3328,0,0]Ah[477,14,3114,0,4059,0,0]Ah[477,14,3114,0,3072,0,0]Ah[477,14,3114,0,3091,0,0]Ah[477,14,3114,0,4233,0,0]Ah[477,14,3114,0,4224,0,0]Ai[3173,14,3115,0,4060,0,0]Ai[3173,14,3115,0,3073,0,0]Ai[3173,14,3115,0,3092,0,0]Ai[3173,14,3115,0,4234,0,0]Ai[3173,14,3115,0,4225,0,0]Ai[3173,14,4081,0,2326,0,0]Ai[3173,14,4081,0,2346,0,0]Ai[3173,14,4081,0,2310,0,0]Ai[3173,14,4081,0,1901,0,0]Ae[1228,7,1229,0,0,0,0]Ah[3173,14,4596,0,516,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ae[2408,5,2409,0,0,0,0]Af[477,6,478,3174,0,0,0]Ae[3173,6,3174,0,0,0,0]Al[3173,15,1731,1731,1470,0,0]Ag[477,19,478,0,1480,0,0]Ag[477,19,478,0,1463,0,0]Al[3173,19,3174,1856,1481,0,0]Al[3173,19,3174,1403,1464,0,0]Ae[1228,5,1229,0,0,0,0]Ae[1127,5,1725,0,0,0,0]Ae[1127,5,1824,0,0,0,0]Af[477,15,478,0,133,0,0]Ak[3173,15,3174,3174,134,0,0]Ai[477,13,478,0,2343,127,0]Ai[477,13,478,0,3303,127,0]Ai[477,13,478,0,4588,127,0]An[3173,13,3174,1418,2344,127,0]An[3173,13,3174,1418,3304,127,0]An[3173,13,3174,1418,4589,127,0]Ai[477,13,478,0,1480,144,0]Ai[477,13,478,0,1463,144,0]Ai[477,13,478,0,4064,144,0]Ai[477,13,478,0,4203,144,0]Ah[477,13,478,0,526,144,0]Ah[477,13,478,0,133,144,0]Ai[477,13,478,0,2330,144,0]An[3173,13,3174,1856,1481,144,0]An[3173,13,3174,3147,4900,144,0]An[3173,13,3174,1403,1464,144,0]An[3173,13,3174,1152,3122,144,0]An[3173,13,3174,1152,4374,144,0]An[3173,13,3174,1157,3343,144,0]An[3173,13,3174,3276,4065,144,0]An[3173,13,3174,2354,4794,144,0]An[3173,13,3174,1798,4895,144,0]An[3173,13,3174,1829,4204,144,0]Am[3173,13,3174,3174,527,144,0]Am[3173,13,3174,3174,134,144,0]An[3173,13,3174,3174,2331,144,0]Ag[477,13,478,0,2330,0,0]Al[3173,13,3174,3174,2331,0,0]Ai[3173,14,4081,0,1460,0,0]Ai[3173,14,4081,0,3081,0,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Al[2029,14,2030,2030,2328,0,0]Al[2029,14,2030,2030,2342,0,0]An[1228,13,1229,1229,141,1191,0]Ao[1228,13,1229,1229,4075,1191,0]Ao[1228,13,1229,1229,4047,1191,0]Ao[1228,13,1417,1417,4487,1191,0]Ao[4088,13,4089,4089,5162,1191,0]Am[477,13,478,4270,5066,1191,0]Am[477,13,478,3740,3295,1191,0]Am[477,13,478,3740,3297,1191,0]Am[477,13,478,3740,1450,1191,0]Am[477,13,478,3740,5073,1191,0]D`[477,13,478,3740,4899,1191,0,\"impl-Debug-for-SendDatagramError\"]Db[477,13,478,3740,4899,1873,0,\"impl-Display-for-SendDatagramError\"]Am[477,13,478,2353,2308,1191,0]Am[477,13,478,2353,4347,1191,0]Cg[477,13,478,4270,1458,1873,0,\"impl-Display-for-Lagged\"]Ce[477,13,478,4270,1458,1191,0,\"impl-Debug-for-Lagged\"]Am[477,13,478,4270,3316,1191,0]Am[477,13,478,4270,5001,1191,0]Am[477,13,478,2385,2312,1191,0]Ci[477,13,478,2385,3325,1191,0,\"impl-Debug-for-RetryError\"]Ck[477,13,478,2385,3325,1873,0,\"impl-Display-for-RetryError\"]Am[477,13,478,2385,4466,1191,0]Al[477,13,478,1126,520,1191,0]Am[477,13,478,1126,4492,1191,0]Am[477,13,478,4157,3322,1191,0]Am[477,13,478,4157,5009,1191,0]Co[477,13,478,4157,4485,1873,0,\"impl-Display-for-ReadToEndError\"]Cm[477,13,478,4157,4485,1191,0,\"impl-Debug-for-ReadToEndError\"]Cj[477,13,478,4157,3121,1873,0,\"impl-Display-for-ReadError\"]Ch[477,13,478,4157,3121,1191,0,\"impl-Debug-for-ReadError\"]Ck[477,13,478,4157,3324,1873,0,\"impl-Display-for-ResetError\"]Ci[477,13,478,4157,3324,1191,0,\"impl-Debug-for-ResetError\"]Co[477,13,478,4157,4484,1873,0,\"impl-Display-for-ReadExactError\"]Cm[477,13,478,4157,4484,1191,0,\"impl-Debug-for-ReadExactError\"]Am[477,13,478,1431,4249,1191,0]Am[477,13,478,1169,4078,1191,0]Am[477,13,478,4162,3328,1191,0]Ci[477,13,478,4162,3342,1191,0,\"impl-Debug-for-WriteError\"]Ck[477,13,478,4162,3342,1873,0,\"impl-Display-for-WriteError\"]Ck[477,13,478,4162,4248,1191,0,\"impl-Debug-for-StoppedError\"]Cm[477,13,478,4162,4248,1873,0,\"impl-Display-for-StoppedError\"]Am[477,13,478,4162,1903,1191,0]Cb[477,13,478,0,1480,1191,0,\"impl-Debug-for-VarInt\"]Cd[477,13,478,0,1480,1873,0,\"impl-Display-for-VarInt\"]D`[477,13,478,0,5070,1191,0,\"impl-Debug-for-VarIntBoundsExceeded\"]Db[477,13,478,0,5070,1873,0,\"impl-Display-for-VarIntBoundsExceeded\"]Aj[477,13,478,0,1184,1191,0]Cb[477,13,478,0,1463,1191,0,\"impl-Debug-for-PathId\"]Cd[477,13,478,0,1463,1873,0,\"impl-Display-for-PathId\"]Aj[477,13,478,0,3317,1191,0]Aj[477,13,478,0,3116,1191,0]Cn[477,13,478,0,4955,1191,0,\"impl-Debug-for-SetPathStatusError\"]D`[477,13,478,0,4955,1873,0,\"impl-Display-for-SetPathStatusError\"]Ch[477,13,478,0,3290,1873,0,\"impl-Display-for-ClosedPath\"]Cf[477,13,478,0,3290,1191,0,\"impl-Debug-for-ClosedPath\"]Aj[477,13,478,0,2343,1191,0]Aj[477,13,478,0,3303,1191,0]Aj[477,13,478,0,3118,1191,0]Aj[477,13,478,0,4588,1191,0]Cj[477,13,478,0,4194,1873,0,\"impl-Display-for-ClosedStream\"]Ch[477,13,478,0,4194,1191,0,\"impl-Debug-for-ClosedStream\"]Ck[477,13,478,0,4584,1191,0,\"impl-Debug-for-ConnectionError\"]Cm[477,13,478,0,4584,1873,0,\"impl-Display-for-ConnectionError\"]Ce[477,13,478,0,3112,1191,0,\"impl-Debug-for-PathError\"]Cg[477,13,478,0,3112,1873,0,\"impl-Display-for-PathError\"]Cl[477,13,478,0,4451,1873,0,\"impl-Display-for-ClosePathError\"]Cj[477,13,478,0,4451,1191,0,\"impl-Debug-for-ClosePathError\"]Aj[477,13,478,0,4598,1191,0]Aj[477,13,478,0,4607,1191,0]Aj[477,13,478,0,4925,1191,0]Aj[477,13,478,0,4940,1191,0]Aj[477,13,478,0,4064,1191,0]Aj[477,13,478,0,4461,1191,0]Aj[477,13,478,0,4242,1191,0]Aj[477,13,478,0,5127,1191,0]Aj[477,13,478,0,4188,1191,0]Ci[477,13,478,0,4050,1873,0,\"impl-Display-for-ConfigError\"]Cg[477,13,478,0,4050,1191,0,\"impl-Debug-for-ConfigError\"]Cg[477,13,478,0,3099,1873,0,\"impl-Display-for-FrameType\"]Ce[477,13,478,0,3099,1191,0,\"impl-Debug-for-FrameType\"]Ck[477,13,478,0,4581,1191,0,\"impl-Debug-for-ConnectionClose\"]Cm[477,13,478,0,4581,1873,0,\"impl-Display-for-ConnectionClose\"]Cn[477,13,478,0,4788,1873,0,\"impl-Display-for-ApplicationClose\"]Cl[477,13,478,0,4788,1191,0,\"impl-Debug-for-ApplicationClose\"]Ch[477,13,478,0,4200,1191,0,\"impl-Debug-for-ConnectError\"]Cj[477,13,478,0,4200,1873,0,\"impl-Display-for-ConnectError\"]Cj[477,13,478,0,4203,1873,0,\"impl-Display-for-ConnectionId\"]Ch[477,13,478,0,4203,1191,0,\"impl-Debug-for-ConnectionId\"]Aj[477,13,478,0,4208,1191,0]Cn[477,13,478,0,4960,1191,0,\"impl-Debug-for-TransportErrorCode\"]D`[477,13,478,0,4960,1873,0,\"impl-Display-for-TransportErrorCode\"]Aj[477,13,478,0,3306,1191,0]Aj[477,13,478,0,4822,1191,0]Ai[477,13,478,0,526,1191,0]C`[477,13,478,0,133,1873,0,\"impl-Display-for-Dir\"]Bn[477,13,478,0,133,1191,0,\"impl-Debug-for-Dir\"]Cf[477,13,478,0,2330,1873,0,\"impl-Display-for-StreamId\"]Cd[477,13,478,0,2330,1191,0,\"impl-Debug-for-StreamId\"]Aj[477,13,478,0,2340,1191,0]Ce[477,13,478,0,3097,1191,0,\"impl-Debug-for-FourTuple\"]Cg[477,13,478,0,3097,1873,0,\"impl-Display-for-FourTuple\"]Aj[477,13,3735,0,501,1191,0]Ak[477,13,3735,0,3286,1191,0]Ak[477,13,3735,0,1188,1191,0]Ak[477,13,3735,0,4055,1191,0]Ak[477,13,3735,0,1886,1191,0]Ak[477,13,3735,0,4366,1191,0]Ak[477,13,1735,0,5224,1191,0]Ak[477,13,1735,0,4053,1191,0]Ak[477,13,1735,0,4964,1191,0]Cb[477,13,1818,0,1201,1191,0,\"impl-Debug-for-Error\"]Cd[477,13,1818,0,1201,1873,0,\"impl-Display-for-Error\"]Dc[477,13,1818,0,5064,1873,0,\"impl-Display-for-NoInitialCipherSuite\"]Da[477,13,1818,0,5064,1191,0,\"impl-Debug-for-NoInitialCipherSuite\"]Ao[3173,13,3174,3741,3298,1191,0]Ao[3173,13,3174,2354,2309,1191,0]Cg[3173,13,3174,1856,1481,1191,0,\"impl-Debug-for-VarInt\"]Ci[3173,13,3174,1856,1481,1873,0,\"impl-Display-for-VarInt\"]Dg[3173,13,3174,1856,5071,1873,0,\"impl-Display-for-VarIntBoundsExceeded\"]De[3173,13,3174,1856,5071,1191,0,\"impl-Debug-for-VarIntBoundsExceeded\"]Ao[3173,13,3174,3138,1185,1191,0]Dd[3173,13,3174,3147,4900,1873,0,\"impl-Display-for-SendDatagramError\"]Db[3173,13,3174,3147,4900,1191,0,\"impl-Debug-for-SendDatagramError\"]Cg[3173,13,3174,1403,1464,1191,0,\"impl-Debug-for-PathId\"]Ci[3173,13,3174,1403,1464,1873,0,\"impl-Display-for-PathId\"]Ao[3173,13,3174,1403,4238,1191,0]Ao[3173,13,3174,1403,3318,1191,0]Ao[3173,13,3174,1403,3117,1191,0]Ao[3173,13,3174,1403,4898,1191,0]Dc[3173,13,3174,1403,4956,1191,0,\"impl-Debug-for-SetPathStatusError\"]De[3173,13,3174,1403,4956,1873,0,\"impl-Display-for-SetPathStatusError\"]Cm[3173,13,3174,1403,3293,1873,0,\"impl-Display-for-ClosedPath\"]Ck[3173,13,3174,1403,3293,1191,0,\"impl-Debug-for-ClosedPath\"]Ao[3173,13,3174,1418,2344,1191,0]Ao[3173,13,3174,1418,3304,1191,0]Ao[3173,13,3174,1418,3119,1191,0]Ao[3173,13,3174,1418,4589,1191,0]Cj[3173,13,3174,1152,3122,1191,0,\"impl-Debug-for-ReadError\"]Cl[3173,13,3174,1152,3122,1873,0,\"impl-Display-for-ReadError\"]Cn[3173,13,3174,1152,4374,1191,0,\"impl-Debug-for-ReadableError\"]D`[3173,13,3174,1152,4374,1873,0,\"impl-Display-for-ReadableError\"]Cm[3173,13,3174,1157,3343,1873,0,\"impl-Display-for-WriteError\"]Ck[3173,13,3174,1157,3343,1191,0,\"impl-Debug-for-WriteError\"]Cn[3173,13,3174,1157,4063,1873,0,\"impl-Display-for-FinishError\"]Cl[3173,13,3174,1157,4063,1191,0,\"impl-Debug-for-FinishError\"]Ao[3173,13,3174,2044,4082,1191,0]Ao[3173,13,3174,2044,4486,1191,0]Cm[3173,13,3174,2044,4198,1191,0,\"impl-Debug-for-ClosedStream\"]Co[3173,13,3174,2044,4198,1873,0,\"impl-Display-for-ClosedStream\"]Db[3173,13,3174,3741,4585,1873,0,\"impl-Display-for-ConnectionError\"]D`[3173,13,3174,3741,4585,1191,0,\"impl-Debug-for-ConnectionError\"]Cl[3173,13,3174,3741,3113,1873,0,\"impl-Display-for-PathError\"]Cj[3173,13,3174,3741,3113,1191,0,\"impl-Debug-for-PathError\"]Da[3173,13,3174,3741,4452,1873,0,\"impl-Display-for-ClosePathError\"]Co[3173,13,3174,3741,4452,1191,0,\"impl-Debug-for-ClosePathError\"]Di[3173,13,3174,3741,5158,1873,0,\"impl-Display-for-MultipathNotNegotiated\"]Dg[3173,13,3174,3741,5158,1191,0,\"impl-Debug-for-MultipathNotNegotiated\"]Ao[3173,13,3174,3741,1206,1191,0]Ao[3173,13,3174,1148,4599,1191,0]Ao[3173,13,3174,3276,4608,1191,0]Ao[3173,13,3174,3276,4926,1191,0]Ao[3173,13,3174,3276,4941,1191,0]Ao[3173,13,3174,3276,4065,1191,0]Ao[3173,13,3174,1733,4462,1191,0]Ao[3173,13,3174,1733,4244,1191,0]Ao[3173,13,3174,1733,5128,1191,0]Ao[3173,13,3174,1733,4190,1191,0]Cl[3173,13,3174,1733,4051,1191,0,\"impl-Debug-for-ConfigError\"]Cn[3173,13,3174,1733,4051,1873,0,\"impl-Display-for-ConfigError\"]Cj[3173,13,3174,1393,3100,1191,0,\"impl-Debug-for-FrameType\"]Cl[3173,13,3174,1393,3100,1873,0,\"impl-Display-for-FrameType\"]Co[3173,13,3174,1393,4467,1191,0,\"impl-Debug-for-InvalidFrameId\"]Da[3173,13,3174,1393,4467,1873,0,\"impl-Display-for-InvalidFrameId\"]Cm[3173,13,3174,1393,3310,1873,0,\"impl-Display-for-MaybeFrame\"]Ck[3173,13,3174,1393,3310,1191,0,\"impl-Debug-for-MaybeFrame\"]Cm[3173,13,3174,1393,3332,1873,0,\"impl-Display-for-StreamInfo\"]Ck[3173,13,3174,1393,3332,1191,0,\"impl-Debug-for-StreamInfo\"]Co[3173,13,3174,1393,4205,1873,0,\"impl-Display-for-DatagramInfo\"]Cm[3173,13,3174,1393,4205,1191,0,\"impl-Debug-for-DatagramInfo\"]D`[3173,13,3174,1393,4583,1191,0,\"impl-Debug-for-ConnectionClose\"]Db[3173,13,3174,1393,4583,1873,0,\"impl-Display-for-ConnectionClose\"]Dc[3173,13,3174,1393,4790,1873,0,\"impl-Display-for-ApplicationClose\"]Da[3173,13,3174,1393,4790,1191,0,\"impl-Debug-for-ApplicationClose\"]Ck[3173,13,3174,1393,2302,1873,0,\"impl-Display-for-Datagram\"]Ci[3173,13,3174,1393,2302,1191,0,\"impl-Debug-for-Datagram\"]Ao[3173,13,3174,2354,4794,1191,0]Ao[3173,13,3174,2354,2313,1191,0]Cm[3173,13,3174,2354,4201,1191,0,\"impl-Debug-for-ConnectError\"]Co[3173,13,3174,2354,4201,1873,0,\"impl-Display-for-ConnectError\"]Ao[3173,13,3174,2354,4045,1191,0]Cm[3173,13,3174,2354,3326,1873,0,\"impl-Display-for-RetryError\"]Ck[3173,13,3174,2354,3326,1191,0,\"impl-Debug-for-RetryError\"]Ao[3173,13,3174,1798,4369,1191,0]Ao[3173,13,3174,1798,4597,1191,0]Ao[3173,13,3174,1798,5161,1191,0]Ao[3173,13,3174,1798,2316,1191,0]Dd[3173,13,3174,1798,4895,1873,0,\"impl-Display-for-PacketDecodeError\"]Db[3173,13,3174,1798,4895,1191,0,\"impl-Debug-for-PacketDecodeError\"]Ao[3173,13,3174,1829,4587,1191,0]Ao[3173,13,3174,1829,4346,1191,0]Cm[3173,13,3174,1829,4204,1191,0,\"impl-Debug-for-ConnectionId\"]Co[3173,13,3174,1829,4204,1873,0,\"impl-Display-for-ConnectionId\"]Ao[3173,13,3174,1829,4209,1191,0]Ce[3173,13,3174,0,4490,1873,0,\"impl-Display-for-Error\"]Cc[3173,13,3174,0,4490,1191,0,\"impl-Debug-for-Error\"]Cd[3173,13,3174,0,4961,1873,0,\"impl-Display-for-Code\"]Cb[3173,13,3174,0,4961,1191,0,\"impl-Debug-for-Code\"]Ao[3173,13,3174,4388,3307,1191,0]Ao[3173,13,3174,4388,5263,1191,0]Ao[3173,13,3174,4996,4823,1191,0]An[3173,13,3174,3174,527,1191,0]Cc[3173,13,3174,3174,134,1191,0,\"impl-Debug-for-Dir\"]Ce[3173,13,3174,3174,134,1873,0,\"impl-Display-for-Dir\"]Ci[3173,13,3174,3174,2331,1191,0,\"impl-Debug-for-StreamId\"]Ck[3173,13,3174,3174,2331,1873,0,\"impl-Display-for-StreamId\"]Ao[3173,13,3174,3174,2341,1191,0]Cl[3173,13,3174,3174,3098,1873,0,\"impl-Display-for-FourTuple\"]Cj[3173,13,3174,3174,3098,1191,0,\"impl-Debug-for-FourTuple\"]D`[3173,13,1731,1731,4380,1873,0,\"impl-Display-for-UnexpectedEnd\"]Cn[3173,13,1731,1731,4380,1191,0,\"impl-Debug-for-UnexpectedEnd\"]Ao[3173,13,5112,5112,5008,1191,0]Cf[3173,13,5112,5112,1203,1191,0,\"impl-Debug-for-Error\"]Ch[3173,13,5112,5112,1203,1873,0,\"impl-Display-for-Error\"]Ao[3173,13,1736,1736,5225,1191,0]Ao[3173,13,1736,1736,4054,1191,0]Ao[3173,13,1736,1736,4967,1191,0]Ce[3173,13,1819,0,1202,1873,0,\"impl-Display-for-Error\"]Cc[3173,13,1819,0,1202,1191,0,\"impl-Debug-for-Error\"]De[3173,13,1819,1819,5065,1191,0,\"impl-Debug-for-NoInitialCipherSuite\"]Dg[3173,13,1819,1819,5065,1873,0,\"impl-Display-for-NoInitialCipherSuite\"]Am[3173,13,3736,535,502,1191,0]An[3173,13,3736,535,3287,1191,0]Ao[3173,13,3736,1389,1189,1191,0]Ao[3173,13,3736,1389,4056,1191,0]Ao[3173,13,3736,2408,1887,1191,0]Ao[3173,13,3736,2408,4367,1191,0]Cf[3173,13,4854,4854,1204,1191,0,\"impl-Debug-for-Error\"]Ch[3173,13,4854,4854,1204,1873,0,\"impl-Display-for-Error\"]Ao[3173,13,4854,4854,1207,1191,0]An[2029,13,2030,431,4491,1191,0]Ao[2029,13,2030,2030,2328,1191,0]Ao[2029,13,2030,2030,2342,1191,0]Ao[2029,13,2030,2030,4210,1191,0]Aj[477,13,478,4270,5066,0,0]Al[3173,13,3174,1403,4238,0,0]Ag[477,14,478,0,2343,0,1]Al[3173,14,3174,1418,2344,0,1]Al[3173,13,3174,1798,4369,0,0]Al[3173,14,3174,1798,5161,0,0]Ah[3173,14,4596,0,516,0,0]Al[2029,14,2030,2030,2328,0,0]Ag[477,13,478,0,5127,0,0]Al[3173,13,3174,1733,5128,0,0]8Al[1228,13,1417,1417,4487,0,0]Al[4088,13,4089,4089,5162,0,0]Ag[477,13,478,0,4338,0,0]Aj[477,13,478,2353,2308,0,0]Ag[477,13,478,0,3319,0,0]Ag[477,13,478,0,4598,0,0]Ag[477,13,478,0,4461,0,0]Ag[477,13,478,0,4242,0,0]Ag[477,13,478,0,4188,0,0]Ag[477,13,478,0,4203,0,0]Ag[477,13,478,0,4822,0,0]Ag[477,13,478,0,2330,0,0]Ag[477,13,478,0,3097,0,0]Ah[477,13,3735,0,1188,0,0]Ah[477,13,3735,0,1886,0,0]Al[3173,13,3174,4617,4339,0,0]Al[3173,13,3174,1148,3320,0,0]Al[3173,13,3174,2354,2309,0,0]Al[3173,13,3174,1798,5289,0,0]Al[3173,13,3174,4388,5258,0,0]Al[3173,13,3174,1148,4599,0,0]Al[3173,13,3174,1733,4462,0,0]Al[3173,13,3174,1733,4244,0,0]Al[3173,13,3174,1733,4190,0,0]Al[3173,13,3174,1798,4369,0,0]Al[3173,13,3174,1829,4204,0,0]Ai[3173,13,3174,0,4490,0,0]Al[3173,13,3174,4388,5263,0,0]Al[3173,13,3174,4996,4823,0,0]Al[3173,13,3174,3174,2331,0,0]Al[3173,13,3174,3174,3098,0,0]Al[3173,13,3736,1389,1189,0,0]Al[3173,13,3736,2408,1887,0,0]Ak[2029,13,2030,431,4491,0,0]Al[1127,13,4305,4305,5210,0,0]Al[1127,13,4305,4305,5211,0,0]Aa[477,3,0,0,0,0,0]Ah[477,13,478,0,526,140,0]Am[3173,13,3174,3174,527,140,0]Ag[477,12,478,0,3335,0,0]Aj[477,13,478,2036,1898,0,0]0Am[477,13,478,1431,4249,1898,0]Aj[477,13,478,0,4378,3335,0]Al[3173,12,3174,1733,3336,0,0]Ao[3173,13,3174,1733,4379,3336,0]Aj[477,13,478,3740,3297,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,14,3174,1418,3119,0,0]Ae[1127,7,1725,0,0,0,0]Ae[1127,7,1824,0,0,0,0]Ac[477,4,478,0,0,0,0]Af[477,5,3735,535,0,0,0]Ag[3173,5,3736,535,0,0,0]Al[1127,15,1128,1128,5000,0,0]Ag[477,15,478,0,4208,0,0]Al[3173,15,3174,1829,4209,0,0]Al[2029,15,2030,2030,4210,0,0]210Ag[477,5,1735,1736,0,0,0]Ae[3173,5,1736,0,0,0,0]Al[3173,15,3174,1798,4597,0,0]Al[3173,15,3174,1393,3310,0,0]Af[477,5,478,1126,0,0,0]Al[3173,15,3174,3741,1206,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Aj[477,15,478,4157,4485,0,0]Af[477,6,478,3174,0,0,0]Ae[3173,6,3174,0,0,0,0]Ag[477,19,478,0,1463,0,0]Al[3173,19,3174,1403,1464,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ah[477,14,3114,0,4224,0,0]Ai[3173,14,3115,0,4225,0,0]Al[2029,14,2030,2030,2328,0,0]Aa[536,3,0,0,0,0,0]Ai[3173,14,3174,0,4490,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Al[3173,14,3174,1393,2302,0,0]Al[477,13,478,3740,2323,504,0]Al[477,13,478,2385,2312,504,0]Ak[477,13,478,1126,520,504,0]Al[477,13,478,1126,4492,504,0]Al[477,13,478,4157,3322,504,0]Al[477,13,478,4162,3328,504,0]An[3173,13,3174,1152,1446,504,0]Am[1228,13,1229,1229,141,511,0]An[1228,13,1229,1229,4075,511,0]An[1228,13,1229,1229,4047,511,0]An[1228,13,1417,1417,4083,511,0]An[1228,13,1417,1417,1221,511,0]An[1228,13,1417,1417,4487,511,0]Ak[536,13,537,537,4048,511,0]An[4088,13,4089,4089,5162,511,0]Al[477,13,478,3740,4612,511,0]Al[477,13,478,3740,2323,511,0]Ai[477,13,478,0,4338,511,0]Al[477,13,478,4270,5066,511,0]Al[477,13,478,1126,2324,511,0]Al[477,13,478,1126,4786,511,0]Al[477,13,478,3740,3295,511,0]Al[477,13,478,3740,3297,511,0]Al[477,13,478,3740,1889,511,0]Al[477,13,478,3740,1459,511,0]Al[477,13,478,3740,3076,511,0]Al[477,13,478,3740,2296,511,0]Al[477,13,478,3740,4232,511,0]Al[477,13,478,3740,4239,511,0]Al[477,13,478,3740,1450,511,0]Al[477,13,478,3740,5073,511,0]Al[477,13,478,3740,4899,511,0]0Al[477,13,478,2353,2308,511,0]Al[477,13,478,2353,4347,511,0]Al[477,13,478,2353,1437,511,0]Al[477,13,478,4270,1458,511,0]Al[477,13,478,4270,3316,511,0]Al[477,13,478,4270,5001,511,0]Al[477,13,478,2385,2312,511,0]Al[477,13,478,2385,3325,511,0]Al[477,13,478,2385,4466,511,0]Ak[477,13,478,1126,520,511,0]Al[477,13,478,1126,4492,511,0]Al[477,13,478,4157,3322,511,0]Al[477,13,478,4157,5009,511,0]Al[477,13,478,4157,4485,511,0]0Al[477,13,478,4157,3121,511,0]Df[477,13,478,4157,3121,511,0,\"impl-From%3CResetError%3E-for-ReadError\"]Dk[477,13,478,4157,3121,511,0,\"impl-From%3CConnectionError%3E-for-ReadError\"]Al[477,13,478,4157,3324,511,0]0Al[477,13,478,4157,4484,511,0]0Al[477,13,478,1431,4249,511,0]Al[477,13,478,1169,4078,511,0]Al[477,13,478,4162,3328,511,0]Dl[477,13,478,4162,3342,511,0,\"impl-From%3CConnectionError%3E-for-WriteError\"]Di[477,13,478,4162,3342,511,0,\"impl-From%3CClosedStream%3E-for-WriteError\"]Al[477,13,478,4162,3342,511,0]Di[477,13,478,4162,3342,511,0,\"impl-From%3CStoppedError%3E-for-WriteError\"]Al[477,13,478,4162,4248,511,0]0Al[477,13,478,4162,1903,511,0]Ai[477,13,478,0,3319,511,0]Ai[477,13,478,0,4378,511,0]Ai[477,13,478,0,4796,511,0]Ai[477,13,478,0,4604,511,0]Ai[477,13,478,0,4222,511,0]Ai[477,13,478,0,4475,511,0]Ci[477,13,478,0,1480,511,0,\"impl-From%3Cu32%3E-for-VarInt\"]Ci[477,13,478,0,1480,511,0,\"impl-From%3Cu16%3E-for-VarInt\"]Ch[477,13,478,0,1480,511,0,\"impl-From%3Cu8%3E-for-VarInt\"]Dh[477,13,478,0,1480,511,0,\"impl-From%3CTransportErrorCode%3E-for-VarInt\"]Cn[477,13,478,0,1480,511,0,\"impl-From%3CStreamId%3E-for-VarInt\"]Ai[477,13,478,0,1480,511,0]Ai[477,13,478,0,5070,511,0]Ai[477,13,478,0,1184,511,0]Ai[477,13,478,0,1463,511,0]0Ai[477,13,478,0,3317,511,0]Ai[477,13,478,0,3116,511,0]Ai[477,13,478,0,4955,511,0]Ai[477,13,478,0,3290,511,0]Ai[477,13,478,0,2343,511,0]Ai[477,13,478,0,3303,511,0]Ai[477,13,478,0,3118,511,0]Ai[477,13,478,0,4588,511,0]Ai[477,13,478,0,4194,511,0]Ai[477,13,478,0,4584,511,0]Dd[477,13,478,0,4584,511,0,\"impl-From%3CClose%3E-for-ConnectionError\"]Dm[477,13,478,0,4584,511,0,\"impl-From%3CTransportError%3E-for-ConnectionError\"]Dj[477,13,478,0,4584,511,0,\"impl-From%3CCloseReason%3E-for-ConnectionError\"]Ai[477,13,478,0,3112,511,0]Ai[477,13,478,0,4451,511,0]Ai[477,13,478,0,4598,511,0]Ai[477,13,478,0,4607,511,0]Ai[477,13,478,0,4925,511,0]Ai[477,13,478,0,4940,511,0]Ai[477,13,478,0,4064,511,0]0Ai[477,13,478,0,4461,511,0]Ai[477,13,478,0,4242,511,0]Ai[477,13,478,0,5127,511,0]Ai[477,13,478,0,4188,511,0]Dj[477,13,478,0,4050,511,0,\"impl-From%3CTryFromIntError%3E-for-ConfigError\"]Do[477,13,478,0,4050,511,0,\"impl-From%3CVarIntBoundsExceeded%3E-for-ConfigError\"]Ai[477,13,478,0,4050,511,0]Ai[477,13,478,0,3099,511,0]Ai[477,13,478,0,4581,511,0]0Ai[477,13,478,0,4788,511,0]Ai[477,13,478,0,4200,511,0]0Ai[477,13,478,0,4203,511,0]Ai[477,13,478,0,4208,511,0]Ai[477,13,478,0,4960,511,0]0Ai[477,13,478,0,3306,511,0]Ai[477,13,478,0,4822,511,0]Ah[477,13,478,0,526,511,0]Ah[477,13,478,0,133,511,0]Ai[477,13,478,0,2330,511,0]0Ai[477,13,478,0,2340,511,0]Ai[477,13,478,0,3097,511,0]0Ai[477,13,3735,0,501,511,0]Aj[477,13,3735,0,3286,511,0]Aj[477,13,3735,0,1188,511,0]Aj[477,13,3735,0,4055,511,0]Aj[477,13,3735,0,1886,511,0]Aj[477,13,3735,0,4366,511,0]Aj[477,13,3735,0,4886,511,0]Aj[477,13,1735,0,1881,511,0]Ai[477,13,1735,0,514,511,0]Aj[477,13,1735,0,5224,511,0]Aj[477,13,1735,0,4053,511,0]Aj[477,13,1735,0,4964,511,0]Aj[477,13,1818,0,3337,511,0]Aj[477,13,1818,0,4349,511,0]Df[477,13,1818,0,1201,511,0,\"impl-From%3CPeerIncompatible%3E-for-Error\"]D`[477,13,1818,0,1201,511,0,\"impl-From%3COtherError%3E-for-Error\"]Df[477,13,1818,0,1201,511,0,\"impl-From%3CCertificateError%3E-for-Error\"]Do[477,13,1818,0,1201,511,0,\"impl-From%3CUnsupportedOperationError%3E-for-Error\"]Df[477,13,1818,0,1201,511,0,\"impl-From%3CInconsistentKeys%3E-for-Error\"]Dm[477,13,1818,0,1201,511,0,\"impl-From%3CCertRevocationListError%3E-for-Error\"]Do[477,13,1818,0,1201,511,0,\"impl-From%3CEncryptedClientHelloError%3E-for-Error\"]De[477,13,1818,0,1201,511,0,\"impl-From%3CSystemTimeError%3E-for-Error\"]De[477,13,1818,0,1201,511,0,\"impl-From%3CGetRandomFailed%3E-for-Error\"]Dd[477,13,1818,0,1201,511,0,\"impl-From%3CPeerMisbehaved%3E-for-Error\"]Aj[477,13,1818,0,1201,511,0]Dd[477,13,1818,0,1201,511,0,\"impl-From%3CInvalidMessage%3E-for-Error\"]Aj[477,13,1818,0,4818,511,0]Aj[477,13,1818,0,5064,511,0]Aj[477,13,1818,0,4820,511,0]Am[2408,13,2409,2409,132,511,0]An[2408,13,2409,2409,2299,511,0]An[3173,13,3174,4617,4339,511,0]An[3173,13,3174,3147,3089,511,0]An[3173,13,3174,1152,1446,511,0]An[3173,13,3174,2044,1907,511,0]An[3173,13,3174,2044,3323,511,0]An[3173,13,3174,2044,3329,511,0]An[3173,13,3174,3741,3298,511,0]An[3173,13,3174,1148,3320,511,0]An[3173,13,3174,1733,4379,511,0]An[3173,13,3174,2354,2309,511,0]An[3173,13,3174,2354,4345,511,0]An[3173,13,3174,2354,4797,511,0]An[3173,13,3174,2354,4357,511,0]An[3173,13,3174,1798,5289,511,0]An[3173,13,3174,4388,5258,511,0]An[3173,13,3174,1430,4605,511,0]An[3173,13,3174,1430,4223,511,0]An[3173,13,3174,1430,4476,511,0]Co[3173,13,3174,1856,1481,511,0,\"impl-From%3CCode%3E-for-VarInt\"]Cm[3173,13,3174,1856,1481,511,0,\"impl-From%3Cu8%3E-for-VarInt\"]Cn[3173,13,3174,1856,1481,511,0,\"impl-From%3Cu16%3E-for-VarInt\"]Cn[3173,13,3174,1856,1481,511,0,\"impl-From%3Cu32%3E-for-VarInt\"]Dc[3173,13,3174,1856,1481,511,0,\"impl-From%3CStreamId%3E-for-VarInt\"]An[3173,13,3174,1856,1481,511,0]An[3173,13,3174,1856,5071,511,0]An[3173,13,3174,3138,1185,511,0]An[3173,13,3174,3147,4900,511,0]An[3173,13,3174,1403,1464,511,0]0An[3173,13,3174,1403,4238,511,0]An[3173,13,3174,1403,3318,511,0]An[3173,13,3174,1403,3117,511,0]An[3173,13,3174,1403,4898,511,0]An[3173,13,3174,1403,4956,511,0]An[3173,13,3174,1403,3293,511,0]An[3173,13,3174,1418,2344,511,0]An[3173,13,3174,1418,3304,511,0]An[3173,13,3174,1418,3119,511,0]An[3173,13,3174,1418,4589,511,0]An[3173,13,3174,1152,3122,511,0]An[3173,13,3174,1152,4374,511,0]An[3173,13,3174,1157,3343,511,0]An[3173,13,3174,1157,4063,511,0]An[3173,13,3174,2044,4082,511,0]An[3173,13,3174,2044,4486,511,0]An[3173,13,3174,2044,4198,511,0]An[3173,13,3174,3741,4585,511,0]0An[3173,13,3174,3741,3113,511,0]An[3173,13,3174,3741,4452,511,0]An[3173,13,3174,3741,5158,511,0]An[3173,13,3174,3741,1206,511,0]0An[3173,13,3174,1148,4599,511,0]An[3173,13,3174,3276,4608,511,0]An[3173,13,3174,3276,4926,511,0]An[3173,13,3174,3276,4941,511,0]An[3173,13,3174,3276,4065,511,0]0An[3173,13,3174,1733,4462,511,0]An[3173,13,3174,1733,4244,511,0]An[3173,13,3174,1733,5128,511,0]An[3173,13,3174,1733,4190,511,0]Do[3173,13,3174,1733,4051,511,0,\"impl-From%3CTryFromIntError%3E-for-ConfigError\"]An[3173,13,3174,1733,4051,511,0]Ed[3173,13,3174,1733,4051,511,0,\"impl-From%3CVarIntBoundsExceeded%3E-for-ConfigError\"]An[3173,13,3174,1393,3100,511,0]An[3173,13,3174,1393,4467,511,0]An[3173,13,3174,1393,3310,511,0]An[3173,13,3174,1393,3332,511,0]An[3173,13,3174,1393,4205,511,0]An[3173,13,3174,1393,4583,511,0]0An[3173,13,3174,1393,4790,511,0]An[3173,13,3174,1393,2302,511,0]An[3173,13,3174,2354,4794,511,0]An[3173,13,3174,2354,2313,511,0]An[3173,13,3174,2354,4201,511,0]0An[3173,13,3174,2354,4045,511,0]An[3173,13,3174,2354,3326,511,0]An[3173,13,3174,1798,4369,511,0]An[3173,13,3174,1798,4597,511,0]An[3173,13,3174,1798,5161,511,0]An[3173,13,3174,1798,2316,511,0]An[3173,13,3174,1798,4895,511,0]0An[3173,13,3174,1829,4587,511,0]An[3173,13,3174,1829,4346,511,0]An[3173,13,3174,1829,4204,511,0]An[3173,13,3174,1829,4209,511,0]Ak[3173,13,3174,0,4490,511,0]0Ak[3173,13,3174,0,4961,511,0]0An[3173,13,3174,4388,3307,511,0]An[3173,13,3174,4388,5263,511,0]An[3173,13,3174,4996,4823,511,0]Am[3173,13,3174,3174,527,511,0]Am[3173,13,3174,3174,134,511,0]An[3173,13,3174,3174,2331,511,0]0An[3173,13,3174,3174,2341,511,0]An[3173,13,3174,3174,3098,511,0]0An[3173,13,1731,1731,4380,511,0]An[3173,13,5112,5112,5008,511,0]An[3173,13,5112,5112,1203,511,0]0An[3173,13,1736,1736,1882,511,0]Am[3173,13,1736,1736,515,511,0]An[3173,13,1736,1736,5225,511,0]An[3173,13,1736,1736,4054,511,0]An[3173,13,1736,1736,4967,511,0]An[3173,13,1819,1819,3338,511,0]An[3173,13,1819,1819,4350,511,0]E`[3173,13,1819,0,1202,511,0,\"impl-From%3CUnsupportedOperationError%3E-for-Error\"]Dg[3173,13,1819,0,1202,511,0,\"impl-From%3CCertificateError%3E-for-Error\"]Ak[3173,13,1819,0,1202,511,0]Dg[3173,13,1819,0,1202,511,0,\"impl-From%3CInconsistentKeys%3E-for-Error\"]De[3173,13,1819,0,1202,511,0,\"impl-From%3CInvalidMessage%3E-for-Error\"]De[3173,13,1819,0,1202,511,0,\"impl-From%3CPeerMisbehaved%3E-for-Error\"]Df[3173,13,1819,0,1202,511,0,\"impl-From%3CGetRandomFailed%3E-for-Error\"]Df[3173,13,1819,0,1202,511,0,\"impl-From%3CSystemTimeError%3E-for-Error\"]E`[3173,13,1819,0,1202,511,0,\"impl-From%3CEncryptedClientHelloError%3E-for-Error\"]Dn[3173,13,1819,0,1202,511,0,\"impl-From%3CCertRevocationListError%3E-for-Error\"]Dg[3173,13,1819,0,1202,511,0,\"impl-From%3CPeerIncompatible%3E-for-Error\"]Da[3173,13,1819,0,1202,511,0,\"impl-From%3COtherError%3E-for-Error\"]An[3173,13,1819,1819,4819,511,0]An[3173,13,1819,1819,5065,511,0]An[3173,13,1819,1819,4821,511,0]Al[3173,13,3736,535,502,511,0]Am[3173,13,3736,535,3287,511,0]An[3173,13,3736,1389,1189,511,0]An[3173,13,3736,1389,4056,511,0]An[3173,13,3736,2408,1887,511,0]An[3173,13,3736,2408,4367,511,0]An[3173,13,3736,3736,4887,511,0]An[3173,13,4854,4854,1204,511,0]An[3173,13,4854,4854,1207,511,0]An[2029,13,2030,2030,3341,511,0]0Am[2029,13,2030,431,4491,511,0]An[2029,13,2030,2030,2328,511,0]An[2029,13,2030,2030,2342,511,0]An[2029,13,2030,2030,4210,511,0]An[1127,13,1128,1128,3086,511,0]An[1127,13,1128,1128,5000,511,0]Am[1127,13,1725,1725,142,511,0]An[1127,13,1419,1419,1222,511,0]An[1127,13,1419,1419,4084,511,0]An[1127,13,1419,1419,4593,511,0]An[1127,13,4305,4305,5210,511,0]An[1127,13,4305,4305,5211,511,0]Am[1127,13,1824,1824,143,511,0]Ai[477,13,478,0,1480,512,0]Ai[477,13,478,0,1463,512,0]Ai[477,13,478,0,4064,512,0]Ai[477,13,478,0,4203,512,0]Ah[477,13,478,0,526,512,0]Ah[477,13,478,0,133,512,0]Ai[477,13,478,0,2330,512,0]Ai[477,13,478,0,3097,512,0]An[3173,13,3174,1856,1481,512,0]An[3173,13,3174,3147,4900,512,0]An[3173,13,3174,1403,1464,512,0]An[3173,13,3174,1152,3122,512,0]An[3173,13,3174,1152,4374,512,0]An[3173,13,3174,1157,3343,512,0]An[3173,13,3174,3276,4065,512,0]An[3173,13,3174,2354,4794,512,0]An[3173,13,3174,1798,4895,512,0]An[3173,13,3174,1829,4204,512,0]Am[3173,13,3174,3174,527,512,0]Am[3173,13,3174,3174,134,512,0]An[3173,13,3174,3174,2331,512,0]An[3173,13,3174,3174,3098,512,0]Am[1228,13,1229,1229,141,513,0]An[1228,13,1229,1229,4075,513,0]An[1228,13,1229,1229,4047,513,0]An[1228,13,1417,1417,4083,513,0]An[1228,13,1417,1417,1221,513,0]An[1228,13,1417,1417,4487,513,0]Ak[536,13,537,537,4048,513,0]An[4088,13,4089,4089,5162,513,0]Al[477,13,478,3740,4612,513,0]Al[477,13,478,3740,2323,513,0]Ai[477,13,478,0,4338,513,0]Al[477,13,478,4270,5066,513,0]Al[477,13,478,1126,2324,513,0]Al[477,13,478,1126,4786,513,0]Al[477,13,478,3740,3295,513,0]Al[477,13,478,3740,3297,513,0]Al[477,13,478,3740,1889,513,0]Al[477,13,478,3740,1459,513,0]Al[477,13,478,3740,3076,513,0]Al[477,13,478,3740,2296,513,0]Al[477,13,478,3740,4232,513,0]Al[477,13,478,3740,4239,513,0]Al[477,13,478,3740,1450,513,0]Al[477,13,478,3740,5073,513,0]Al[477,13,478,3740,4899,513,0]Al[477,13,478,2353,2308,513,0]Al[477,13,478,2353,4347,513,0]Al[477,13,478,2353,1437,513,0]Al[477,13,478,4270,1458,513,0]Al[477,13,478,4270,3316,513,0]Al[477,13,478,4270,5001,513,0]Al[477,13,478,2385,2312,513,0]Al[477,13,478,2385,3325,513,0]Al[477,13,478,2385,4466,513,0]Ak[477,13,478,1126,520,513,0]Al[477,13,478,1126,4492,513,0]Al[477,13,478,4157,3322,513,0]Al[477,13,478,4157,5009,513,0]Al[477,13,478,4157,4485,513,0]Al[477,13,478,4157,3121,513,0]Al[477,13,478,4157,3324,513,0]Al[477,13,478,4157,4484,513,0]Al[477,13,478,1431,4249,513,0]Al[477,13,478,1169,4078,513,0]Al[477,13,478,4162,3328,513,0]Al[477,13,478,4162,3342,513,0]Al[477,13,478,4162,4248,513,0]Al[477,13,478,4162,1903,513,0]Ai[477,13,478,0,3319,513,0]Ai[477,13,478,0,4378,513,0]Ai[477,13,478,0,4796,513,0]Ai[477,13,478,0,4604,513,0]Ai[477,13,478,0,4222,513,0]Ai[477,13,478,0,4475,513,0]Ai[477,13,478,0,1480,513,0]Ai[477,13,478,0,5070,513,0]Ai[477,13,478,0,1184,513,0]Ai[477,13,478,0,1463,513,0]Ai[477,13,478,0,3317,513,0]Ai[477,13,478,0,3116,513,0]Ai[477,13,478,0,4955,513,0]Ai[477,13,478,0,3290,513,0]Ai[477,13,478,0,2343,513,0]Ai[477,13,478,0,3303,513,0]Ai[477,13,478,0,3118,513,0]Ai[477,13,478,0,4588,513,0]Ai[477,13,478,0,4194,513,0]Ai[477,13,478,0,4584,513,0]Ai[477,13,478,0,3112,513,0]Ai[477,13,478,0,4451,513,0]Ai[477,13,478,0,4598,513,0]Ai[477,13,478,0,4607,513,0]Ai[477,13,478,0,4925,513,0]Ai[477,13,478,0,4940,513,0]Ai[477,13,478,0,4064,513,0]Ai[477,13,478,0,4461,513,0]Ai[477,13,478,0,4242,513,0]Ai[477,13,478,0,5127,513,0]Ai[477,13,478,0,4188,513,0]Ai[477,13,478,0,4050,513,0]Ai[477,13,478,0,3099,513,0]Ai[477,13,478,0,4581,513,0]Ai[477,13,478,0,4788,513,0]Ai[477,13,478,0,4200,513,0]Ai[477,13,478,0,4203,513,0]Ai[477,13,478,0,4208,513,0]Ai[477,13,478,0,4960,513,0]Ai[477,13,478,0,3306,513,0]Ai[477,13,478,0,4822,513,0]Ah[477,13,478,0,526,513,0]Ah[477,13,478,0,133,513,0]Ai[477,13,478,0,2330,513,0]Ai[477,13,478,0,2340,513,0]Ai[477,13,478,0,3097,513,0]Ai[477,13,3735,0,501,513,0]Aj[477,13,3735,0,3286,513,0]Aj[477,13,3735,0,1188,513,0]Aj[477,13,3735,0,4055,513,0]Aj[477,13,3735,0,1886,513,0]Aj[477,13,3735,0,4366,513,0]Aj[477,13,3735,0,4886,513,0]Aj[477,13,1735,0,1881,513,0]Ai[477,13,1735,0,514,513,0]Aj[477,13,1735,0,5224,513,0]Aj[477,13,1735,0,4053,513,0]Aj[477,13,1735,0,4964,513,0]Aj[477,13,1818,0,3337,513,0]Aj[477,13,1818,0,4349,513,0]Aj[477,13,1818,0,1201,513,0]Aj[477,13,1818,0,4818,513,0]Aj[477,13,1818,0,5064,513,0]Aj[477,13,1818,0,4820,513,0]Am[2408,13,2409,2409,132,513,0]An[2408,13,2409,2409,2299,513,0]An[3173,13,3174,4617,4339,513,0]An[3173,13,3174,3147,3089,513,0]An[3173,13,3174,1152,1446,513,0]An[3173,13,3174,2044,1907,513,0]An[3173,13,3174,2044,3323,513,0]An[3173,13,3174,2044,3329,513,0]An[3173,13,3174,3741,3298,513,0]An[3173,13,3174,1148,3320,513,0]An[3173,13,3174,1733,4379,513,0]An[3173,13,3174,2354,2309,513,0]An[3173,13,3174,2354,4345,513,0]An[3173,13,3174,2354,4797,513,0]An[3173,13,3174,2354,4357,513,0]An[3173,13,3174,1798,5289,513,0]An[3173,13,3174,4388,5258,513,0]An[3173,13,3174,1430,4605,513,0]An[3173,13,3174,1430,4223,513,0]An[3173,13,3174,1430,4476,513,0]An[3173,13,3174,1856,1481,513,0]An[3173,13,3174,1856,5071,513,0]An[3173,13,3174,3138,1185,513,0]An[3173,13,3174,3147,4900,513,0]An[3173,13,3174,1403,1464,513,0]An[3173,13,3174,1403,4238,513,0]An[3173,13,3174,1403,3318,513,0]An[3173,13,3174,1403,3117,513,0]An[3173,13,3174,1403,4898,513,0]An[3173,13,3174,1403,4956,513,0]An[3173,13,3174,1403,3293,513,0]An[3173,13,3174,1418,2344,513,0]An[3173,13,3174,1418,3304,513,0]An[3173,13,3174,1418,3119,513,0]An[3173,13,3174,1418,4589,513,0]An[3173,13,3174,1152,3122,513,0]An[3173,13,3174,1152,4374,513,0]An[3173,13,3174,1157,3343,513,0]An[3173,13,3174,1157,4063,513,0]An[3173,13,3174,2044,4082,513,0]An[3173,13,3174,2044,4486,513,0]An[3173,13,3174,2044,4198,513,0]An[3173,13,3174,3741,4585,513,0]An[3173,13,3174,3741,3113,513,0]An[3173,13,3174,3741,4452,513,0]An[3173,13,3174,3741,5158,513,0]An[3173,13,3174,3741,1206,513,0]An[3173,13,3174,1148,4599,513,0]An[3173,13,3174,3276,4608,513,0]An[3173,13,3174,3276,4926,513,0]An[3173,13,3174,3276,4941,513,0]An[3173,13,3174,3276,4065,513,0]An[3173,13,3174,1733,4462,513,0]An[3173,13,3174,1733,4244,513,0]An[3173,13,3174,1733,5128,513,0]An[3173,13,3174,1733,4190,513,0]An[3173,13,3174,1733,4051,513,0]An[3173,13,3174,1393,3100,513,0]An[3173,13,3174,1393,4467,513,0]An[3173,13,3174,1393,3310,513,0]An[3173,13,3174,1393,3332,513,0]An[3173,13,3174,1393,4205,513,0]An[3173,13,3174,1393,4583,513,0]An[3173,13,3174,1393,4790,513,0]An[3173,13,3174,1393,2302,513,0]An[3173,13,3174,2354,4794,513,0]An[3173,13,3174,2354,2313,513,0]An[3173,13,3174,2354,4201,513,0]An[3173,13,3174,2354,4045,513,0]An[3173,13,3174,2354,3326,513,0]An[3173,13,3174,1798,4369,513,0]An[3173,13,3174,1798,4597,513,0]An[3173,13,3174,1798,5161,513,0]An[3173,13,3174,1798,2316,513,0]An[3173,13,3174,1798,4895,513,0]An[3173,13,3174,1829,4587,513,0]An[3173,13,3174,1829,4346,513,0]An[3173,13,3174,1829,4204,513,0]An[3173,13,3174,1829,4209,513,0]Ak[3173,13,3174,0,4490,513,0]Ak[3173,13,3174,0,4961,513,0]An[3173,13,3174,4388,3307,513,0]An[3173,13,3174,4388,5263,513,0]An[3173,13,3174,4996,4823,513,0]Am[3173,13,3174,3174,527,513,0]Am[3173,13,3174,3174,134,513,0]An[3173,13,3174,3174,2331,513,0]An[3173,13,3174,3174,2341,513,0]An[3173,13,3174,3174,3098,513,0]An[3173,13,1731,1731,4380,513,0]An[3173,13,5112,5112,5008,513,0]An[3173,13,5112,5112,1203,513,0]An[3173,13,1736,1736,1882,513,0]Am[3173,13,1736,1736,515,513,0]An[3173,13,1736,1736,5225,513,0]An[3173,13,1736,1736,4054,513,0]An[3173,13,1736,1736,4967,513,0]An[3173,13,1819,1819,3338,513,0]An[3173,13,1819,1819,4350,513,0]Ak[3173,13,1819,0,1202,513,0]An[3173,13,1819,1819,4819,513,0]An[3173,13,1819,1819,5065,513,0]An[3173,13,1819,1819,4821,513,0]Al[3173,13,3736,535,502,513,0]Am[3173,13,3736,535,3287,513,0]An[3173,13,3736,1389,1189,513,0]An[3173,13,3736,1389,4056,513,0]An[3173,13,3736,2408,1887,513,0]An[3173,13,3736,2408,4367,513,0]An[3173,13,3736,3736,4887,513,0]An[3173,13,4854,4854,1204,513,0]An[3173,13,4854,4854,1207,513,0]An[2029,13,2030,2030,3341,513,0]Am[2029,13,2030,431,4491,513,0]An[2029,13,2030,2030,2328,513,0]An[2029,13,2030,2030,2342,513,0]An[2029,13,2030,2030,4210,513,0]An[1127,13,1128,1128,3086,513,0]An[1127,13,1128,1128,5000,513,0]Am[1127,13,1725,1725,142,513,0]An[1127,13,1419,1419,1222,513,0]An[1127,13,1419,1419,4084,513,0]An[1127,13,1419,1419,4593,513,0]An[1127,13,4305,4305,5210,513,0]An[1127,13,4305,4305,5211,513,0]Am[1127,13,1824,1824,143,513,0]Ac[536,7,537,0,0,0,0]Ae[4088,7,4089,0,0,0,0]Ae[4391,7,4392,0,0,0,0]Ae[2408,7,2409,0,0,0,0]Ae[4918,7,4919,0,0,0,0]Al[3173,13,3174,1152,1446,0,0]Ao[3173,13,3174,2354,4357,2314,0]Ah[477,12,1735,0,4888,0,0]Al[3173,13,3174,2044,1907,0,0]Al[3173,12,1736,1736,4889,0,0]Aj[477,13,478,3740,3297,0,0]Ab[1127,3,0,0,0,0,0]Ai[477,13,478,1126,520,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,14,3174,1418,3304,0,0]Aj[477,12,478,2036,3282,0,0]Am[477,13,478,3740,4612,1455,0]Am[477,13,478,3740,2323,1455,0]Am[477,13,478,1126,2324,1455,0]Am[477,13,478,3740,3295,1455,0]Am[477,13,478,3740,1889,1455,0]Am[477,13,478,3740,1459,1455,0]Am[477,13,478,3740,3076,1455,0]Am[477,13,478,3740,2296,1455,0]Am[477,13,478,3740,4232,1455,0]Am[477,13,478,3740,4239,1455,0]Am[477,13,478,2353,1437,1455,0]Am[477,13,478,2385,4466,1455,0]Am[477,13,478,4162,1903,1455,0]?Aj[477,13,478,4157,3322,0,0]Al[3173,13,3174,2044,3323,0,0]Al[3173,13,5112,5112,5008,0,0]Al[3173,13,3174,3147,3089,0,0]Ak[2029,13,2030,431,4491,0,0]Ah[477,12,1735,0,4888,0,0]Al[3173,12,1736,1736,4889,0,0]32Ag[477,13,478,0,5127,0,0]Al[3173,13,3174,1733,5128,0,0]Aj[477,13,478,3740,3297,0,0]Al[3173,13,3174,3741,3298,0,0]Ah[477,12,1735,0,1877,0,0]Al[3173,12,1736,1736,1878,0,0]Al[1228,14,1417,1417,4487,0,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Ai[3173,14,4596,0,1218,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5009,0,0]Al[3173,13,3174,2044,3323,0,0]Ag[477,12,478,0,3339,0,0]Aj[477,13,478,0,4475,3339,0]Aj[477,13,478,0,4822,3339,0]Al[3173,12,3174,1430,3340,0,0]Ao[3173,13,3174,1430,4476,3340,0]Ao[3173,13,3174,4996,4823,3340,0]Af[477,5,478,3138,0,0,0]Ah[3173,5,3174,3138,0,0,0]Ag[477,5,3735,1389,0,0,0]Ah[3173,5,3736,1389,0,0,0]Al[1127,15,1128,1128,5000,0,0]Ag[477,6,1818,1392,0,0,0]Ah[3173,6,1819,1392,0,0,0]Ae[3173,6,5112,0,0,0,0]Ae[3173,6,4854,0,0,0,0]Ah[3173,6,3174,3741,0,0,0]1Al[3173,15,3174,1393,3310,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Aj[477,15,478,4157,3121,0,0]Ag[477,15,478,0,4584,0,0]Al[3173,15,3174,1152,3122,0,0]Al[3173,15,3174,3741,4585,0,0]Al[3173,15,3174,1798,4597,0,0]0Ae[1228,5,1417,0,0,0,0]Ae[1127,5,1419,0,0,0,0]Al[1228,15,1229,1229,4075,0,0]Ag[477,13,478,0,4796,0,0]Al[3173,13,3174,2354,4797,0,0]Ab[1228,3,0,0,0,0,0]Ah[477,12,3735,0,4884,0,0]Ak[477,13,3735,0,3286,4884,0]Ak[477,13,3735,0,4055,4884,0]Ak[477,13,3735,0,4366,4884,0]Al[3173,12,3736,3736,4885,0,0]An[3173,13,3736,535,3287,4885,0]Ao[3173,13,3736,1389,4056,4885,0]Ao[3173,13,3736,2408,4367,4885,0]Al[1127,13,1128,1128,5000,0,0]Ag[477,14,478,0,1184,0,0]Ag[477,14,478,0,2343,0,0]Al[3173,14,3174,3138,1185,0,0]Al[3173,14,3174,1418,2344,0,0]Al[3173,14,3174,2354,4045,0,0]An[1228,13,1229,1229,141,1186,0]Ao[1228,13,1229,1229,4075,1186,0]Ao[1228,13,1229,1229,4047,1186,0]Am[477,13,478,3740,3297,1186,0]Am[477,13,478,3740,1450,1186,0]Am[477,13,478,3740,5073,1186,0]Am[477,13,478,3740,4899,1186,0]Am[477,13,478,2353,2308,1186,0]Am[477,13,478,2353,4347,1186,0]Am[477,13,478,4270,1458,1186,0]Al[477,13,478,1126,520,1186,0]Am[477,13,478,1126,4492,1186,0]Am[477,13,478,4157,4485,1186,0]Am[477,13,478,4157,3121,1186,0]Am[477,13,478,4157,3324,1186,0]Am[477,13,478,4157,4484,1186,0]Am[477,13,478,4162,3342,1186,0]Am[477,13,478,4162,4248,1186,0]Aj[477,13,478,0,1480,1186,0]Aj[477,13,478,0,5070,1186,0]Aj[477,13,478,0,1463,1186,0]Aj[477,13,478,0,3317,1186,0]Aj[477,13,478,0,3116,1186,0]Aj[477,13,478,0,4955,1186,0]Aj[477,13,478,0,3290,1186,0]Aj[477,13,478,0,2343,1186,0]Aj[477,13,478,0,3303,1186,0]Aj[477,13,478,0,3118,1186,0]Aj[477,13,478,0,4588,1186,0]Aj[477,13,478,0,4194,1186,0]Aj[477,13,478,0,4584,1186,0]Aj[477,13,478,0,3112,1186,0]Aj[477,13,478,0,4451,1186,0]Aj[477,13,478,0,4607,1186,0]Aj[477,13,478,0,4925,1186,0]Aj[477,13,478,0,4940,1186,0]Aj[477,13,478,0,4064,1186,0]Aj[477,13,478,0,4461,1186,0]Aj[477,13,478,0,4242,1186,0]Aj[477,13,478,0,5127,1186,0]Aj[477,13,478,0,4188,1186,0]Aj[477,13,478,0,4050,1186,0]Aj[477,13,478,0,3099,1186,0]Aj[477,13,478,0,4581,1186,0]Aj[477,13,478,0,4788,1186,0]Aj[477,13,478,0,4200,1186,0]Aj[477,13,478,0,4203,1186,0]Aj[477,13,478,0,4208,1186,0]Aj[477,13,478,0,4960,1186,0]Aj[477,13,478,0,3306,1186,0]Ai[477,13,478,0,526,1186,0]Ai[477,13,478,0,133,1186,0]Aj[477,13,478,0,2330,1186,0]Aj[477,13,478,0,3097,1186,0]Aj[477,13,3735,0,501,1186,0]Ak[477,13,3735,0,3286,1186,0]Ak[477,13,3735,0,1188,1186,0]Ak[477,13,3735,0,4055,1186,0]Ak[477,13,3735,0,1886,1186,0]Ak[477,13,3735,0,4366,1186,0]Ak[477,13,1818,0,1201,1186,0]Ak[477,13,1818,0,4818,1186,0]Ak[477,13,1818,0,5064,1186,0]Ak[477,13,1818,0,4820,1186,0]Ao[3173,13,3174,1856,1481,1186,0]Ao[3173,13,3174,1856,5071,1186,0]Ao[3173,13,3174,3147,4900,1186,0]Ao[3173,13,3174,1403,1464,1186,0]Ao[3173,13,3174,1403,4238,1186,0]Ao[3173,13,3174,1403,3318,1186,0]Ao[3173,13,3174,1403,3117,1186,0]Ao[3173,13,3174,1403,4898,1186,0]Ao[3173,13,3174,1403,4956,1186,0]Ao[3173,13,3174,1403,3293,1186,0]Ao[3173,13,3174,1418,2344,1186,0]Ao[3173,13,3174,1418,3304,1186,0]Ao[3173,13,3174,1418,3119,1186,0]Ao[3173,13,3174,1418,4589,1186,0]Ao[3173,13,3174,1152,3122,1186,0]Ao[3173,13,3174,1152,4374,1186,0]Ao[3173,13,3174,1157,3343,1186,0]Ao[3173,13,3174,1157,4063,1186,0]Ao[3173,13,3174,2044,4486,1186,0]Ao[3173,13,3174,2044,4198,1186,0]Ao[3173,13,3174,3741,4585,1186,0]Ao[3173,13,3174,3741,3113,1186,0]Ao[3173,13,3174,3741,4452,1186,0]Ao[3173,13,3174,3741,5158,1186,0]Ao[3173,13,3174,3276,4608,1186,0]Ao[3173,13,3174,3276,4926,1186,0]Ao[3173,13,3174,3276,4941,1186,0]Ao[3173,13,3174,3276,4065,1186,0]Ao[3173,13,3174,1733,4462,1186,0]Ao[3173,13,3174,1733,4244,1186,0]Ao[3173,13,3174,1733,5128,1186,0]Ao[3173,13,3174,1733,4190,1186,0]Ao[3173,13,3174,1733,4051,1186,0]Ao[3173,13,3174,1393,3100,1186,0]Ao[3173,13,3174,1393,3310,1186,0]Ao[3173,13,3174,1393,3332,1186,0]Ao[3173,13,3174,1393,4205,1186,0]Ao[3173,13,3174,1393,4583,1186,0]Ao[3173,13,3174,1393,4790,1186,0]Ao[3173,13,3174,1393,2302,1186,0]Ao[3173,13,3174,2354,4794,1186,0]Ao[3173,13,3174,2354,4201,1186,0]Ao[3173,13,3174,1798,4597,1186,0]Ao[3173,13,3174,1798,5161,1186,0]Ao[3173,13,3174,1798,2316,1186,0]Ao[3173,13,3174,1798,4895,1186,0]Ao[3173,13,3174,1829,4204,1186,0]Ao[3173,13,3174,1829,4209,1186,0]Al[3173,13,3174,0,4490,1186,0]Al[3173,13,3174,0,4961,1186,0]Ao[3173,13,3174,4388,3307,1186,0]Ao[3173,13,3174,4388,5263,1186,0]An[3173,13,3174,3174,527,1186,0]An[3173,13,3174,3174,134,1186,0]Ao[3173,13,3174,3174,2331,1186,0]Ao[3173,13,3174,3174,3098,1186,0]Ao[3173,13,1731,1731,4380,1186,0]Ao[3173,13,5112,5112,5008,1186,0]Ao[3173,13,5112,5112,1203,1186,0]Al[3173,13,1819,0,1202,1186,0]Ao[3173,13,1819,1819,4819,1186,0]Ao[3173,13,1819,1819,5065,1186,0]Ao[3173,13,1819,1819,4821,1186,0]Am[3173,13,3736,535,502,1186,0]An[3173,13,3736,535,3287,1186,0]Ao[3173,13,3736,1389,1189,1186,0]Ao[3173,13,3736,1389,4056,1186,0]Ao[3173,13,3736,2408,1887,1186,0]Ao[3173,13,3736,2408,4367,1186,0]Ao[3173,13,4854,4854,1207,1186,0]Ao[2029,13,2030,2030,2328,1186,0]Ao[2029,13,2030,2030,2342,1186,0]Ao[2029,13,2030,2030,4210,1186,0]Ao[1127,13,1128,1128,5000,1186,0]Ao[1127,13,1419,1419,4593,1186,0]Ao[1127,13,4305,4305,5210,1186,0]Ao[1127,13,4305,4305,5211,1186,0]Aj[477,13,478,3740,3297,0,0]Aj[477,13,478,2353,2308,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,0,4203,1192,0]Ao[3173,13,3174,1829,4204,1192,0]Ai[3173,14,3174,0,4490,0,0]Ag[477,13,478,0,2330,0,0]Al[3173,13,3174,3174,2331,0,0]Ag[477,13,478,0,4208,0,0]Al[3173,13,3174,1829,4209,0,0]Ah[477,14,1735,0,1881,0,0]Al[3173,14,1736,1736,1882,0,0]Al[3173,12,3174,1798,4931,0,0]Ao[3173,13,3174,1798,5289,4931,0];Al[1228,13,1417,1417,1221,0,0]Ai[536,13,537,537,4048,0,0]Al[1127,13,1419,1419,1222,0,0]Aj[477,12,478,2036,3282,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2309,0,0]Aj[477,12,478,2036,1898,0,0]Am[477,13,478,1431,4249,1898,0]Am[477,13,478,1169,4078,1898,0]Ae[1228,2,1229,0,0,0,0]Ak[1228,14,1229,1229,141,0,0]Aj[477,13,478,3740,3297,0,0]Aj[477,13,478,2353,2308,0,0]Ai[477,13,478,1126,520,0,0]Aj[477,14,478,3740,1450,0,0]Al[3173,13,3174,3741,3298,0,0]Ae[1127,2,1128,0,0,0,0]Ag[477,13,478,0,3319,0,0]Al[3173,13,3174,1148,3320,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]Al[3173,13,5112,5112,5008,0,0]Af[477,5,478,2353,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Al[1228,15,1229,1229,4047,0,0]0Ag[477,15,478,0,3317,0,0]Al[3173,15,3174,1403,3318,0,0]Ah[3173,5,3174,1152,0,0,0]Af[477,15,478,0,526,0,0]Al[2408,15,2409,2409,2299,0,0]Ak[3173,15,3174,3174,527,0,0]Af[477,5,478,3740,0,0,0]Al[3173,15,4854,4854,1204,0,0]:9Af[477,5,478,4270,0,0,0]2Al[3173,15,3174,2044,4082,0,0]Af[477,5,478,1403,0,0,0]Ah[3173,5,3174,1403,0,0,0]Ae[3173,8,1731,0,0,0,0]987?Al[3173,15,3174,3741,1206,0,0]?Af[477,5,478,1856,0,0,0]Ah[3173,5,3174,1856,0,0,0]Aj[477,13,478,2353,2308,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2044,1907,0,0]Al[3173,13,3174,2354,2309,0,0]An[1228,13,1229,1229,141,1444,0]Ao[1228,13,1229,1229,4075,1444,0]Ao[1228,13,1229,1229,4047,1444,0]Ao[1228,13,1417,1417,4083,1444,0]Ao[1228,13,1417,1417,1221,1444,0]Ao[1228,13,1417,1417,4487,1444,0]Al[536,13,537,537,4048,1444,0]Ao[4088,13,4089,4089,5162,1444,0]Am[477,13,478,3740,4612,1444,0]Am[477,13,478,3740,2323,1444,0]Aj[477,13,478,0,4338,1444,0]Am[477,13,478,4270,5066,1444,0]Am[477,13,478,1126,2324,1444,0]Am[477,13,478,1126,4786,1444,0]Am[477,13,478,3740,3295,1444,0]Am[477,13,478,3740,3297,1444,0]Am[477,13,478,3740,1889,1444,0]Am[477,13,478,3740,1459,1444,0]Am[477,13,478,3740,3076,1444,0]Am[477,13,478,3740,2296,1444,0]Am[477,13,478,3740,4232,1444,0]Am[477,13,478,3740,4239,1444,0]Am[477,13,478,3740,1450,1444,0]Am[477,13,478,3740,5073,1444,0]Am[477,13,478,3740,4899,1444,0]Am[477,13,478,2353,2308,1444,0]Am[477,13,478,2353,4347,1444,0]Am[477,13,478,2353,1437,1444,0]Am[477,13,478,4270,1458,1444,0]Am[477,13,478,4270,3316,1444,0]Am[477,13,478,4270,5001,1444,0]Am[477,13,478,2385,2312,1444,0]Am[477,13,478,2385,3325,1444,0]Am[477,13,478,2385,4466,1444,0]Al[477,13,478,1126,520,1444,0]Am[477,13,478,1126,4492,1444,0]Am[477,13,478,4157,3322,1444,0]Am[477,13,478,4157,5009,1444,0]Am[477,13,478,4157,4485,1444,0]Am[477,13,478,4157,3121,1444,0]Am[477,13,478,4157,3324,1444,0]Am[477,13,478,4157,4484,1444,0]Am[477,13,478,1431,4249,1444,0]Am[477,13,478,1169,4078,1444,0]Am[477,13,478,4162,3328,1444,0]Am[477,13,478,4162,3342,1444,0]Am[477,13,478,4162,4248,1444,0]Am[477,13,478,4162,1903,1444,0]Aj[477,13,478,0,3319,1444,0]Aj[477,13,478,0,4378,1444,0]Aj[477,13,478,0,4796,1444,0]Aj[477,13,478,0,4604,1444,0]Aj[477,13,478,0,4222,1444,0]Aj[477,13,478,0,4475,1444,0]Aj[477,13,478,0,1480,1444,0]Aj[477,13,478,0,5070,1444,0]Aj[477,13,478,0,1184,1444,0]Aj[477,13,478,0,1463,1444,0]Aj[477,13,478,0,3317,1444,0]Aj[477,13,478,0,3116,1444,0]Aj[477,13,478,0,4955,1444,0]Aj[477,13,478,0,3290,1444,0]Aj[477,13,478,0,2343,1444,0]Aj[477,13,478,0,3303,1444,0]Aj[477,13,478,0,3118,1444,0]Aj[477,13,478,0,4588,1444,0]Aj[477,13,478,0,4194,1444,0]Aj[477,13,478,0,4584,1444,0]Aj[477,13,478,0,3112,1444,0]Aj[477,13,478,0,4451,1444,0]Aj[477,13,478,0,4598,1444,0]Aj[477,13,478,0,4607,1444,0]Aj[477,13,478,0,4925,1444,0]Aj[477,13,478,0,4940,1444,0]Aj[477,13,478,0,4064,1444,0]Aj[477,13,478,0,4461,1444,0]Aj[477,13,478,0,4242,1444,0]Aj[477,13,478,0,5127,1444,0]Aj[477,13,478,0,4188,1444,0]Aj[477,13,478,0,4050,1444,0]Aj[477,13,478,0,3099,1444,0]Aj[477,13,478,0,4581,1444,0]Aj[477,13,478,0,4788,1444,0]Aj[477,13,478,0,4200,1444,0]Aj[477,13,478,0,4203,1444,0]Aj[477,13,478,0,4208,1444,0]Aj[477,13,478,0,4960,1444,0]Aj[477,13,478,0,3306,1444,0]Aj[477,13,478,0,4822,1444,0]Ai[477,13,478,0,526,1444,0]Ai[477,13,478,0,133,1444,0]Aj[477,13,478,0,2330,1444,0]Aj[477,13,478,0,2340,1444,0]Aj[477,13,478,0,3097,1444,0]Aj[477,13,3735,0,501,1444,0]Ak[477,13,3735,0,3286,1444,0]Ak[477,13,3735,0,1188,1444,0]Ak[477,13,3735,0,4055,1444,0]Ak[477,13,3735,0,1886,1444,0]Ak[477,13,3735,0,4366,1444,0]Ak[477,13,3735,0,4886,1444,0]Ak[477,13,1735,0,1881,1444,0]Aj[477,13,1735,0,514,1444,0]Ak[477,13,1735,0,5224,1444,0]Ak[477,13,1735,0,4053,1444,0]Ak[477,13,1735,0,4964,1444,0]Ak[477,13,1818,0,3337,1444,0]Ak[477,13,1818,0,4349,1444,0]Ak[477,13,1818,0,1201,1444,0]Ak[477,13,1818,0,4818,1444,0]Ak[477,13,1818,0,5064,1444,0]Ak[477,13,1818,0,4820,1444,0]An[2408,13,2409,2409,132,1444,0]Ao[2408,13,2409,2409,2299,1444,0]Ao[3173,13,3174,4617,4339,1444,0]Ao[3173,13,3174,3147,3089,1444,0]Ao[3173,13,3174,1152,1446,1444,0]Ao[3173,13,3174,2044,1907,1444,0]Ao[3173,13,3174,2044,3323,1444,0]Ao[3173,13,3174,2044,3329,1444,0]Ao[3173,13,3174,3741,3298,1444,0]Ao[3173,13,3174,1148,3320,1444,0]Ao[3173,13,3174,1733,4379,1444,0]Ao[3173,13,3174,2354,2309,1444,0]Ao[3173,13,3174,2354,4345,1444,0]Ao[3173,13,3174,2354,4797,1444,0]Ao[3173,13,3174,2354,4357,1444,0]Ao[3173,13,3174,1798,5289,1444,0]Ao[3173,13,3174,4388,5258,1444,0]Ao[3173,13,3174,1430,4605,1444,0]Ao[3173,13,3174,1430,4223,1444,0]Ao[3173,13,3174,1430,4476,1444,0]Ao[3173,13,3174,1856,1481,1444,0]Ao[3173,13,3174,1856,5071,1444,0]Ao[3173,13,3174,3138,1185,1444,0]Ao[3173,13,3174,3147,4900,1444,0]Ao[3173,13,3174,1403,1464,1444,0]Ao[3173,13,3174,1403,4238,1444,0]Ao[3173,13,3174,1403,3318,1444,0]Ao[3173,13,3174,1403,3117,1444,0]Ao[3173,13,3174,1403,4898,1444,0]Ao[3173,13,3174,1403,4956,1444,0]Ao[3173,13,3174,1403,3293,1444,0]Ao[3173,13,3174,1418,2344,1444,0]Ao[3173,13,3174,1418,3304,1444,0]Ao[3173,13,3174,1418,3119,1444,0]Ao[3173,13,3174,1418,4589,1444,0]Ao[3173,13,3174,1152,3122,1444,0]Ao[3173,13,3174,1152,4374,1444,0]Ao[3173,13,3174,1157,3343,1444,0]Ao[3173,13,3174,1157,4063,1444,0]Ao[3173,13,3174,2044,4082,1444,0]Ao[3173,13,3174,2044,4486,1444,0]Ao[3173,13,3174,2044,4198,1444,0]Ao[3173,13,3174,3741,4585,1444,0]Ao[3173,13,3174,3741,3113,1444,0]Ao[3173,13,3174,3741,4452,1444,0]Ao[3173,13,3174,3741,5158,1444,0]Ao[3173,13,3174,3741,1206,1444,0]Ao[3173,13,3174,1148,4599,1444,0]Ao[3173,13,3174,3276,4608,1444,0]Ao[3173,13,3174,3276,4926,1444,0]Ao[3173,13,3174,3276,4941,1444,0]Ao[3173,13,3174,3276,4065,1444,0]Ao[3173,13,3174,1733,4462,1444,0]Ao[3173,13,3174,1733,4244,1444,0]Ao[3173,13,3174,1733,5128,1444,0]Ao[3173,13,3174,1733,4190,1444,0]Ao[3173,13,3174,1733,4051,1444,0]Ao[3173,13,3174,1393,3100,1444,0]Ao[3173,13,3174,1393,4467,1444,0]Ao[3173,13,3174,1393,3310,1444,0]Ao[3173,13,3174,1393,3332,1444,0]Ao[3173,13,3174,1393,4205,1444,0]Ao[3173,13,3174,1393,4583,1444,0]Ao[3173,13,3174,1393,4790,1444,0]Ao[3173,13,3174,1393,2302,1444,0]Ao[3173,13,3174,2354,4794,1444,0]Ao[3173,13,3174,2354,2313,1444,0]Ao[3173,13,3174,2354,4201,1444,0]Ao[3173,13,3174,2354,4045,1444,0]Ao[3173,13,3174,2354,3326,1444,0]Ao[3173,13,3174,1798,4369,1444,0]Ao[3173,13,3174,1798,4597,1444,0]Ao[3173,13,3174,1798,5161,1444,0]Ao[3173,13,3174,1798,2316,1444,0]Ao[3173,13,3174,1798,4895,1444,0]Ao[3173,13,3174,1829,4587,1444,0]Ao[3173,13,3174,1829,4346,1444,0]Ao[3173,13,3174,1829,4204,1444,0]Ao[3173,13,3174,1829,4209,1444,0]Al[3173,13,3174,0,4490,1444,0]Al[3173,13,3174,0,4961,1444,0]Ao[3173,13,3174,4388,3307,1444,0]Ao[3173,13,3174,4388,5263,1444,0]Ao[3173,13,3174,4996,4823,1444,0]An[3173,13,3174,3174,527,1444,0]An[3173,13,3174,3174,134,1444,0]Ao[3173,13,3174,3174,2331,1444,0]Ao[3173,13,3174,3174,2341,1444,0]Ao[3173,13,3174,3174,3098,1444,0]Ao[3173,13,1731,1731,4380,1444,0]Ao[3173,13,5112,5112,5008,1444,0]Ao[3173,13,5112,5112,1203,1444,0]Ao[3173,13,1736,1736,1882,1444,0]An[3173,13,1736,1736,515,1444,0]Ao[3173,13,1736,1736,5225,1444,0]Ao[3173,13,1736,1736,4054,1444,0]Ao[3173,13,1736,1736,4967,1444,0]Ao[3173,13,1819,1819,3338,1444,0]Ao[3173,13,1819,1819,4350,1444,0]Al[3173,13,1819,0,1202,1444,0]Ao[3173,13,1819,1819,4819,1444,0]Ao[3173,13,1819,1819,5065,1444,0]Ao[3173,13,1819,1819,4821,1444,0]Am[3173,13,3736,535,502,1444,0]An[3173,13,3736,535,3287,1444,0]Ao[3173,13,3736,1389,1189,1444,0]Ao[3173,13,3736,1389,4056,1444,0]Ao[3173,13,3736,2408,1887,1444,0]Ao[3173,13,3736,2408,4367,1444,0]Ao[3173,13,3736,3736,4887,1444,0]Ao[3173,13,4854,4854,1204,1444,0]Ao[3173,13,4854,4854,1207,1444,0]Ao[2029,13,2030,2030,3341,1444,0]An[2029,13,2030,431,4491,1444,0]Ao[2029,13,2030,2030,2328,1444,0]Ao[2029,13,2030,2030,2342,1444,0]Ao[2029,13,2030,2030,4210,1444,0]Ao[1127,13,1128,1128,3086,1444,0]Ao[1127,13,1128,1128,5000,1444,0]An[1127,13,1725,1725,142,1444,0]Ao[1127,13,1419,1419,1222,1444,0]Ao[1127,13,1419,1419,4084,1444,0]Ao[1127,13,1419,1419,4593,1444,0]Ao[1127,13,4305,4305,5210,1444,0]Ao[1127,13,4305,4305,5211,1444,0]An[1127,13,1824,1824,143,1444,0]Ak[1228,14,1229,1229,141,0,0]Ac[536,7,537,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Ae[1127,2,1128,0,0,0,0]Ae[4918,7,4919,0,0,0,0]Aj[477,13,478,3740,3297,0,0]Ae[3173,2,3174,0,0,0,0]Al[3173,13,3174,2354,2309,0,0]Af[477,2,478,3174,0,0,0]Ag[477,13,478,0,4960,0,0]Ag[477,14,478,0,3303,0,0]Ag[477,14,478,0,4242,0,0]5Ai[3173,13,3174,0,4961,0,0]Al[3173,14,3174,1418,3304,0,0]Al[3173,14,3174,1733,4244,0,0]Ai[3173,14,3174,0,4490,0,0]Aj[477,13,478,0,1480,3090,0]Aj[477,13,478,0,1463,3090,0]Aj[477,13,478,0,3099,3090,0]Aj[477,13,478,0,4960,3090,0]Aj[477,13,478,0,2330,3090,0]Ao[3173,13,3174,1856,1481,3090,0]Ao[3173,13,3174,1403,1464,3090,0]Ao[3173,13,3174,1393,3100,3090,0]Ao[3173,13,3174,1393,3310,3090,0]Al[3173,13,3174,1798,4597,0,0]Al[3173,13,3174,0,4961,3090,0]Ao[3173,13,3174,3174,2331,3090,0]Al[3173,12,1731,1731,3090,0,0]Al[2029,14,2030,2030,2328,0,0]Aj[477,13,478,0,1480,3095,0]Aj[477,13,478,0,1463,3095,0]Aj[477,13,478,0,3099,3095,0]Aj[477,13,478,0,4960,3095,0]Aj[477,13,478,0,2330,3095,0]Ao[3173,13,3174,1856,1481,3095,0]Ao[3173,13,3174,1403,1464,3095,0]Ao[3173,13,3174,1393,3100,3095,0]Ao[3173,13,3174,1393,3310,3095,0]Ao[3173,13,3174,1393,2302,3095,0]Al[3173,13,3174,0,4961,3095,0]Ao[3173,13,3174,3174,2331,3095,0]Al[3173,12,1731,1731,3095,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]Al[1127,13,1419,1419,4084,0,0]Al[3173,13,3174,2354,2309,0,0]Ag[477,14,1735,0,514,0,0]Ak[3173,14,1736,1736,515,0,0]Aj[477,13,478,2385,2312,0,0]3Ag[477,12,478,0,3339,0,0]Aj[477,13,478,0,4475,3339,0]Aj[477,13,478,0,4822,3339,0]Al[3173,12,3174,1430,3340,0,0]Ao[3173,13,3174,1430,4476,3340,0]Ao[3173,13,3174,4996,4823,3340,0]Al[1127,14,1128,1128,3086,0,0]Ag[477,14,478,0,1184,0,0]Al[3173,14,3174,3138,1185,0,0]Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Ag[477,14,1735,0,514,0,0]Ak[3173,14,1736,1736,515,0,0]Ai[3173,14,4596,0,4828,0,0]Aj[477,14,478,3740,1450,0,0]Ag[477,14,478,0,4581,0,0]Ag[477,14,478,0,4788,0,0]Ah[477,14,3114,0,3072,0,0]Al[3173,14,3174,1393,4583,0,0]Al[3173,14,3174,1393,4790,0,0]Ai[3173,14,3174,0,4490,0,0]Ai[3173,14,1205,0,4454,0,0]Ai[3173,14,3115,0,3073,0,0]Aj[477,13,478,2353,2308,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2309,0,0]Ag[477,13,478,0,3097,0,0]Ah[477,14,1735,0,1881,0,0]Al[3173,13,3174,3174,3098,0,0]Al[3173,14,1736,1736,1882,0,0]Ac[477,4,478,0,0,0,0]Ag[477,2,1735,1736,0,0,0]Ae[3173,4,3174,0,0,0,0]Ae[3173,2,1736,0,0,0,0]Ac[536,7,537,0,0,0,0];Ae[1127,2,1128,0,0,0,0]Ae[4918,7,4919,0,0,0,0]Am[477,13,478,3740,4899,1194,0]Am[477,13,478,4157,4485,1194,0]Am[477,13,478,4157,3121,1194,0]Am[477,13,478,4157,3324,1194,0]Am[477,13,478,4157,4484,1194,0]Am[477,13,478,4162,3342,1194,0]Am[477,13,478,4162,4248,1194,0]Aj[477,13,478,0,4584,1194,0]Ao[3173,13,3174,3741,4585,1194,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Al[2029,14,2030,2030,2342,0,0]Ai[477,13,478,1126,520,0,0]Ah[477,14,3114,0,4233,0,0]Ai[3173,14,3115,0,4234,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Al[2029,14,2030,2030,2328,0,0]Ag[477,14,478,0,3118,0,0]Ag[477,14,478,0,4588,0,0]Al[3173,14,3174,1418,3119,0,0]Al[3173,14,3174,1418,4589,0,0]3210Ah[477,12,1735,0,1877,0,0]Al[3173,12,1736,1736,1878,0,0]Ah[477,12,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,12,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Al[3173,15,3174,3147,4900,0,0]Al[3173,15,3174,1152,3122,0,0]Al[3173,15,3174,1157,3343,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Ah[477,10,1735,1736,0,0,0]Af[3173,10,1736,0,0,0,0]Al[3173,15,3174,1798,4597,0,0]Ag[477,5,1735,1736,0,0,0]Ae[3173,5,1736,0,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ag[477,5,3735,2408,0,0,0]Ah[3173,5,3736,2408,0,0,0]Al[1127,15,1128,1128,5000,0,0]Af[477,5,478,3740,0,0,0]5454Ag[477,10,478,2036,0,0,0];:Aj[477,15,478,4162,3342,0,0]Af[477,5,478,4162,0,0,0]Al[3173,15,3174,1157,3343,0,0]Al[3173,15,3174,1157,4063,0,0]Al[3173,15,3174,2044,4082,0,0]Ah[3173,5,3174,2044,0,0,0]Aj[477,15,478,4157,4485,0,0]Al[3173,15,3174,1393,3310,0,0]Al[3173,15,3174,1798,2316,0,0]Ag[477,12,478,0,5118,0,0]Al[3173,12,3174,4388,5119,0,0]Ao[3173,13,3174,4388,5258,5119,0]Ao[3173,13,3174,4388,5263,5119,0]Ak[1228,14,1229,1229,141,0,0]An[1228,13,1229,1229,141,4453,0]An[2408,13,2409,2409,132,4453,0]Ak[2408,14,2409,2409,132,0,0]Ao[1127,13,1128,1128,3086,4453,0]An[1127,13,1725,1725,142,4453,0]An[1127,13,1824,1824,143,4453,0]Aj[477,13,478,0,1480,3294,0]Aj[477,13,478,0,1463,3294,0]Aj[477,13,478,0,4064,3294,0]Aj[477,13,478,0,4203,3294,0]Ai[477,13,478,0,526,3294,0]Ai[477,13,478,0,133,3294,0]Aj[477,13,478,0,2330,3294,0]Ao[3173,13,3174,1856,1481,3294,0]Ao[3173,13,3174,3147,4900,3294,0]Ao[3173,13,3174,1403,1464,3294,0]Ao[3173,13,3174,1152,3122,3294,0]Ao[3173,13,3174,1152,4374,3294,0]Ao[3173,13,3174,1157,3343,3294,0]Ao[3173,13,3174,3276,4065,3294,0]Ao[3173,13,3174,2354,4794,3294,0]Ao[3173,13,3174,1798,4895,3294,0]Ao[3173,13,3174,1829,4204,3294,0]An[3173,13,3174,3174,527,3294,0]An[3173,13,3174,3174,134,3294,0]Ao[3173,13,3174,3174,2331,3294,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]Aj[477,13,478,2385,2312,0,0]Ah[477,12,1735,0,3109,0,0]Ah[477,12,1735,0,3102,0,0]Al[3173,13,3174,2354,2313,0,0]Al[3173,12,1736,1736,3110,0,0]Al[3173,12,1736,1736,3103,0,0]Ao[1228,13,1417,1417,4083,1872,0]Ao[1228,13,1417,1417,1221,1872,0]Al[536,13,537,537,4048,1872,0]Aj[477,13,478,0,4338,1872,0]Am[477,13,478,2353,4347,1872,0]Aj[477,13,478,0,1480,1872,0]Aj[477,13,478,0,1463,1872,0]Aj[477,13,478,0,3317,1872,0]Aj[477,13,478,0,3290,1872,0]Aj[477,13,478,0,2343,1872,0]Aj[477,13,478,0,3303,1872,0]Aj[477,13,478,0,3118,1872,0]Aj[477,13,478,0,4588,1872,0]Aj[477,13,478,0,4194,1872,0]Aj[477,13,478,0,4607,1872,0]Aj[477,13,478,0,4925,1872,0]Aj[477,13,478,0,4940,1872,0]Aj[477,13,478,0,4064,1872,0]Aj[477,13,478,0,4461,1872,0]Aj[477,13,478,0,5127,1872,0]Aj[477,13,478,0,4822,1872,0]Ak[477,13,3735,0,3286,1872,0]Ak[477,13,3735,0,4055,1872,0]Ak[477,13,3735,0,4366,1872,0]Ak[477,13,3735,0,4886,1872,0]Ao[3173,13,3174,4617,4339,1872,0]Ao[3173,13,3174,4388,5258,1872,0]Ao[3173,13,3174,1856,1481,1872,0]Ao[3173,13,3174,1403,1464,1872,0]Ao[3173,13,3174,1403,3318,1872,0]Ao[3173,13,3174,1403,3293,1872,0]Ao[3173,13,3174,1418,2344,1872,0]Ao[3173,13,3174,1418,3304,1872,0]Ao[3173,13,3174,1418,3119,1872,0]Ao[3173,13,3174,1418,4589,1872,0]Ao[3173,13,3174,2044,4486,1872,0]Ao[3173,13,3174,2044,4198,1872,0]Ao[3173,13,3174,3276,4608,1872,0]Ao[3173,13,3174,3276,4926,1872,0]Ao[3173,13,3174,3276,4941,1872,0]Ao[3173,13,3174,3276,4065,1872,0]Ao[3173,13,3174,1733,4462,1872,0]Ao[3173,13,3174,1733,5128,1872,0]Ao[3173,13,3174,4388,5263,1872,0]Ao[3173,13,3174,4996,4823,1872,0]An[3173,13,3736,535,3287,1872,0]Ao[3173,13,3736,1389,4056,1872,0]Ao[3173,13,3736,2408,4367,1872,0]Ao[3173,13,3736,3736,4887,1872,0]Ao[2029,13,2030,2030,2328,1872,0]Ao[1127,13,1419,1419,1222,1872,0]Ao[1127,13,1419,1419,4593,1872,0]Al[3173,13,3174,1829,4346,0,0]Al[3173,13,3174,1798,4369,0,0]Al[3173,13,3174,1798,4597,0,0]Al[3173,14,3174,1798,5161,0,0]Ai[3173,14,4894,0,4962,0,0]Ah[3173,14,4596,0,516,0,0]Ai[3173,14,4596,0,1216,0,0]Ai[3173,14,4596,0,1218,0,0]Ai[3173,14,4596,0,4828,0,0]Ah[477,12,1735,0,3109,0,0]Ah[477,12,1735,0,3102,0,0]Al[3173,12,1736,1736,3110,0,0]Al[3173,12,1736,1736,3103,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5009,0,0]Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]Ab[2029,3,0,0,0,0,0]:6Aj[477,13,478,3740,3297,0,0]Aj[477,13,478,1126,2324,0,0]Al[3173,14,3174,1798,5161,0,0]Ai[3173,14,4894,0,4962,0,0]Ah[3173,14,4596,0,516,0,0]Ai[3173,14,4596,0,1216,0,0]Ai[3173,14,4596,0,4828,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]Ak[1228,14,1229,1229,141,0,0]Al[1228,14,1417,1417,1221,0,0]Al[3173,13,3174,3741,3298,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Am[1228,13,1229,1229,141,128,0]An[1228,13,1229,1229,4075,128,0]An[1228,13,1229,1229,4047,128,0]An[1228,13,1417,1417,4083,128,0]An[1228,13,1417,1417,1221,128,0]An[1228,13,1417,1417,4487,128,0]Ak[536,13,537,537,4048,128,0]An[4088,13,4089,4089,5162,128,0]Al[477,13,478,3740,4612,128,0]Al[477,13,478,3740,2323,128,0]Ai[477,13,478,0,4338,128,0]Al[477,13,478,4270,5066,128,0]Al[477,13,478,1126,2324,128,0]Al[477,13,478,1126,4786,128,0]Al[477,13,478,3740,3295,128,0]Al[477,13,478,3740,3297,128,0]Al[477,13,478,3740,1889,128,0]Al[477,13,478,3740,1459,128,0]Al[477,13,478,3740,3076,128,0]Al[477,13,478,3740,2296,128,0]Al[477,13,478,3740,4232,128,0]Al[477,13,478,3740,4239,128,0]Al[477,13,478,3740,1450,128,0]Al[477,13,478,3740,5073,128,0]Al[477,13,478,3740,4899,128,0]Al[477,13,478,2353,2308,128,0]Al[477,13,478,2353,4347,128,0]Al[477,13,478,2353,1437,128,0]Al[477,13,478,4270,1458,128,0]Al[477,13,478,4270,3316,128,0]Al[477,13,478,4270,5001,128,0]Al[477,13,478,2385,2312,128,0]Al[477,13,478,2385,3325,128,0]Al[477,13,478,2385,4466,128,0]Ak[477,13,478,1126,520,128,0]Al[477,13,478,1126,4492,128,0]Al[477,13,478,4157,3322,128,0]Al[477,13,478,4157,5009,128,0]Al[477,13,478,4157,4485,128,0]Al[477,13,478,4157,3121,128,0]Al[477,13,478,4157,3324,128,0]Al[477,13,478,4157,4484,128,0]Al[477,13,478,1431,4249,128,0]Al[477,13,478,1169,4078,128,0]Al[477,13,478,4162,3328,128,0]Al[477,13,478,4162,3342,128,0]Al[477,13,478,4162,4248,128,0]Al[477,13,478,4162,1903,128,0]Ai[477,13,478,0,3319,128,0]Ai[477,13,478,0,4378,128,0]Ai[477,13,478,0,4796,128,0]Ai[477,13,478,0,4604,128,0]Ai[477,13,478,0,4222,128,0]Ai[477,13,478,0,4475,128,0]Ai[477,13,478,0,1480,128,0]Ai[477,13,478,0,5070,128,0]Ai[477,13,478,0,1184,128,0]Ai[477,13,478,0,1463,128,0]Ai[477,13,478,0,3317,128,0]Ai[477,13,478,0,3116,128,0]Ai[477,13,478,0,4955,128,0]Ai[477,13,478,0,3290,128,0]Ai[477,13,478,0,2343,128,0]Ai[477,13,478,0,3303,128,0]Ai[477,13,478,0,3118,128,0]Ai[477,13,478,0,4588,128,0]Ai[477,13,478,0,4194,128,0]Ai[477,13,478,0,4584,128,0]Ai[477,13,478,0,3112,128,0]Ai[477,13,478,0,4451,128,0]Ai[477,13,478,0,4598,128,0]Ai[477,13,478,0,4607,128,0]Ai[477,13,478,0,4925,128,0]Ai[477,13,478,0,4940,128,0]Ai[477,13,478,0,4064,128,0]Ai[477,13,478,0,4461,128,0]Ai[477,13,478,0,4242,128,0]Ai[477,13,478,0,5127,128,0]Ai[477,13,478,0,4188,128,0]Ai[477,13,478,0,4050,128,0]Ai[477,13,478,0,3099,128,0]Ai[477,13,478,0,4581,128,0]Ai[477,13,478,0,4788,128,0]Ai[477,13,478,0,4200,128,0]Ai[477,13,478,0,4203,128,0]Ai[477,13,478,0,4208,128,0]Ai[477,13,478,0,4960,128,0]Ai[477,13,478,0,3306,128,0]Ai[477,13,478,0,4822,128,0]Ah[477,13,478,0,526,128,0]Ah[477,13,478,0,133,128,0]Ai[477,13,478,0,2330,128,0]Ai[477,13,478,0,2340,128,0]Ai[477,13,478,0,3097,128,0]Ai[477,13,3735,0,501,128,0]Aj[477,13,3735,0,3286,128,0]Aj[477,13,3735,0,1188,128,0]Aj[477,13,3735,0,4055,128,0]Aj[477,13,3735,0,1886,128,0]Aj[477,13,3735,0,4366,128,0]Aj[477,13,3735,0,4886,128,0]Aj[477,13,1735,0,1881,128,0]Ai[477,13,1735,0,514,128,0]Aj[477,13,1735,0,5224,128,0]Aj[477,13,1735,0,4053,128,0]Aj[477,13,1735,0,4964,128,0]Aj[477,13,1818,0,3337,128,0]Aj[477,13,1818,0,4349,128,0]Aj[477,13,1818,0,1201,128,0]Aj[477,13,1818,0,4818,128,0]Aj[477,13,1818,0,5064,128,0]Aj[477,13,1818,0,4820,128,0]Am[2408,13,2409,2409,132,128,0]An[2408,13,2409,2409,2299,128,0]An[3173,13,3174,4617,4339,128,0]An[3173,13,3174,3147,3089,128,0]An[3173,13,3174,1152,1446,128,0]An[3173,13,3174,2044,1907,128,0]An[3173,13,3174,2044,3323,128,0]An[3173,13,3174,2044,3329,128,0]An[3173,13,3174,3741,3298,128,0]An[3173,13,3174,1148,3320,128,0]An[3173,13,3174,1733,4379,128,0]An[3173,13,3174,2354,2309,128,0]An[3173,13,3174,2354,4345,128,0]An[3173,13,3174,2354,4797,128,0]An[3173,13,3174,2354,4357,128,0]An[3173,13,3174,1798,5289,128,0]An[3173,13,3174,4388,5258,128,0]An[3173,13,3174,1430,4605,128,0]An[3173,13,3174,1430,4223,128,0]An[3173,13,3174,1430,4476,128,0]An[3173,13,3174,1856,1481,128,0]An[3173,13,3174,1856,5071,128,0]An[3173,13,3174,3138,1185,128,0]An[3173,13,3174,3147,4900,128,0]An[3173,13,3174,1403,1464,128,0]An[3173,13,3174,1403,4238,128,0]An[3173,13,3174,1403,3318,128,0]An[3173,13,3174,1403,3117,128,0]An[3173,13,3174,1403,4898,128,0]An[3173,13,3174,1403,4956,128,0]An[3173,13,3174,1403,3293,128,0]An[3173,13,3174,1418,2344,128,0]An[3173,13,3174,1418,3304,128,0]An[3173,13,3174,1418,3119,128,0]An[3173,13,3174,1418,4589,128,0]An[3173,13,3174,1152,3122,128,0]An[3173,13,3174,1152,4374,128,0]An[3173,13,3174,1157,3343,128,0]An[3173,13,3174,1157,4063,128,0]An[3173,13,3174,2044,4082,128,0]An[3173,13,3174,2044,4486,128,0]An[3173,13,3174,2044,4198,128,0]An[3173,13,3174,3741,4585,128,0]An[3173,13,3174,3741,3113,128,0]An[3173,13,3174,3741,4452,128,0]An[3173,13,3174,3741,5158,128,0]An[3173,13,3174,3741,1206,128,0]An[3173,13,3174,1148,4599,128,0]An[3173,13,3174,3276,4608,128,0]An[3173,13,3174,3276,4926,128,0]An[3173,13,3174,3276,4941,128,0]An[3173,13,3174,3276,4065,128,0]An[3173,13,3174,1733,4462,128,0]An[3173,13,3174,1733,4244,128,0]An[3173,13,3174,1733,5128,128,0]An[3173,13,3174,1733,4190,128,0]An[3173,13,3174,1733,4051,128,0]An[3173,13,3174,1393,3100,128,0]An[3173,13,3174,1393,4467,128,0]An[3173,13,3174,1393,3310,128,0]An[3173,13,3174,1393,3332,128,0]An[3173,13,3174,1393,4205,128,0]An[3173,13,3174,1393,4583,128,0]An[3173,13,3174,1393,4790,128,0]An[3173,13,3174,1393,2302,128,0]An[3173,13,3174,2354,4794,128,0]An[3173,13,3174,2354,2313,128,0]An[3173,13,3174,2354,4201,128,0]An[3173,13,3174,2354,4045,128,0]An[3173,13,3174,2354,3326,128,0]An[3173,13,3174,1798,4369,128,0]An[3173,13,3174,1798,4597,128,0]An[3173,13,3174,1798,5161,128,0]An[3173,13,3174,1798,2316,128,0]An[3173,13,3174,1798,4895,128,0]An[3173,13,3174,1829,4587,128,0]An[3173,13,3174,1829,4346,128,0]An[3173,13,3174,1829,4204,128,0]An[3173,13,3174,1829,4209,128,0]Ak[3173,13,3174,0,4490,128,0]Ak[3173,13,3174,0,4961,128,0]An[3173,13,3174,4388,3307,128,0]An[3173,13,3174,4388,5263,128,0]An[3173,13,3174,4996,4823,128,0]Am[3173,13,3174,3174,527,128,0]Am[3173,13,3174,3174,134,128,0]An[3173,13,3174,3174,2331,128,0]An[3173,13,3174,3174,2341,128,0]An[3173,13,3174,3174,3098,128,0]An[3173,13,1731,1731,4380,128,0]An[3173,13,5112,5112,5008,128,0]An[3173,13,5112,5112,1203,128,0]An[3173,13,1736,1736,1882,128,0]Am[3173,13,1736,1736,515,128,0]An[3173,13,1736,1736,5225,128,0]An[3173,13,1736,1736,4054,128,0]An[3173,13,1736,1736,4967,128,0]An[3173,13,1819,1819,3338,128,0]An[3173,13,1819,1819,4350,128,0]Ak[3173,13,1819,0,1202,128,0]An[3173,13,1819,1819,4819,128,0]An[3173,13,1819,1819,5065,128,0]An[3173,13,1819,1819,4821,128,0]Al[3173,13,3736,535,502,128,0]Am[3173,13,3736,535,3287,128,0]An[3173,13,3736,1389,1189,128,0]An[3173,13,3736,1389,4056,128,0]An[3173,13,3736,2408,1887,128,0]An[3173,13,3736,2408,4367,128,0]An[3173,13,3736,3736,4887,128,0]An[3173,13,4854,4854,1204,128,0]An[3173,13,4854,4854,1207,128,0]An[2029,13,2030,2030,3341,128,0]Am[2029,13,2030,431,4491,128,0]An[2029,13,2030,2030,2328,128,0]An[2029,13,2030,2030,2342,128,0]An[2029,13,2030,2030,4210,128,0]An[1127,13,1128,1128,3086,128,0]An[1127,13,1128,1128,5000,128,0]Am[1127,13,1725,1725,142,128,0]An[1127,13,1419,1419,1222,128,0]An[1127,13,1419,1419,4084,128,0]An[1127,13,1419,1419,4593,128,0]An[1127,13,4305,4305,5210,128,0]An[1127,13,4305,4305,5211,128,0]Am[1127,13,1824,1824,143,128,0]Aj[477,13,478,3740,5073,0,0]Aj[477,13,478,1126,4492,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Al[3173,14,3174,1798,5161,0,0]Ai[3173,14,4894,0,4962,0,0]Ah[3173,14,4596,0,516,0,0]Ai[3173,14,4596,0,1216,0,0]Af[477,5,478,3740,0,0,0]Al[1228,15,1229,1229,4047,0,0]Ae[2408,6,2409,0,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Aj[477,15,478,3740,4899,0,0]Al[3173,15,3174,3147,4900,0,0]Af[477,5,478,2353,0,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,2044,4082,0,0]Af[477,5,478,2385,0,0,0]2Ah[3173,6,3174,1798,0,0,0]Ag[477,19,478,0,1480,0,0]Al[3173,19,3174,1856,1481,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]=Ah[477,12,1735,0,4243,0,0]>Ak[477,13,1818,0,4820,4243,0]>Al[3173,12,1736,1736,4245,0,0]>Ao[3173,13,1819,1819,4821,4245,0]Ao[1127,13,4305,4305,5211,4245,0]An[2408,13,2409,2409,132,4066,0]Ao[2408,13,2409,2409,2299,4066,0]Ag[477,14,478,0,3118,0,0]Ag[477,14,478,0,4588,0,0]Al[3173,14,3174,1418,3119,0,0]Al[3173,14,3174,1418,4589,0,0]Ag[477,13,478,0,4242,0,0]Al[3173,13,3174,1733,4244,0,0]Aj[477,13,478,2036,4449,0,0]0Ak[2029,13,2030,431,4491,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,3741,3298,0,0]Al[1127,13,1419,1419,4593,0,0]Ae[1127,2,1128,0,0,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2313,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]6Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]32Ak[1228,14,1229,1229,141,0,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Al[2029,14,2030,2030,2342,0,0]Ah[477,14,3735,0,4886,0,0]Al[3173,14,3736,3736,4887,0,0]Al[3173,13,3174,2044,1907,0,0]Al[3173,13,3174,4388,5258,0,0]Al[3173,13,3174,4388,5263,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]>=Al[1228,14,1417,1417,1221,0,0]Ai[536,14,537,537,4048,0,0]Ah[477,13,1818,0,4818,0,0]Ah[477,13,1818,0,4820,0,0]Al[3173,13,1819,1819,4819,0,0]Al[3173,13,1819,1819,4821,0,0]6Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Af[477,5,478,4617,0,0,0]Ah[3173,5,3174,4617,0,0,0]Ag[477,15,478,0,4584,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,3741,4585,0,0]Al[3173,15,3174,2354,4201,0,0]Ah[3173,6,3174,2354,0,0,0]Ah[3173,5,3174,1829,0,0,0]Af[477,5,478,2353,0,0,0]Aj[477,15,478,4157,4484,0,0]Ag[477,5,1818,1819,0,0,0]Ae[3173,5,1819,0,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,1798,4895,0,0]?=5454Al[3173,15,3174,2354,4345,0,0]Ag[477,5,3735,2408,0,0,0]Ah[3173,5,3736,2408,0,0,0]Ah[3173,5,3174,1798,0,0,0]98Ah[3173,6,3174,1152,0,0,0]:9Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ae[3173,5,1731,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Al[1127,14,1128,1128,3086,0,0]Aj[477,13,478,3740,3297,0,0]Ae[3173,2,3174,0,0,0,0]Ag[477,13,478,0,4461,0,0]Al[3173,13,3174,1733,4462,0,0]Aj[477,12,478,2036,4449,0,0]Ab[4391,3,0,0,0,0,0]Ak[1228,14,1229,1229,141,0,0]Al[1228,14,1417,1417,4083,0,0]:9Aj[477,13,478,2385,3325,0,0]Al[3173,13,3174,2354,3326,0,0]Ag[477,13,478,0,4925,0,0]Al[3173,13,3174,3276,4926,0,0]<>=Al[1127,13,1419,1419,4084,0,0]Ah[477,12,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,12,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Aj[477,13,478,3740,3297,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Am[477,13,478,4162,3328,3283,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]8810Ah[477,12,1735,0,1877,0,0]Al[3173,12,1736,1736,1878,0,0]Ah[477,12,1735,0,4189,0,0]Ah[477,12,1735,0,4243,0,0]Ak[477,13,1818,0,4818,4189,0]Ak[477,13,1818,0,4820,4243,0]Al[3173,12,1736,1736,4191,0,0]Al[3173,12,1736,1736,4245,0,0]Ao[3173,13,1819,1819,4819,4191,0]Ao[3173,13,1819,1819,4821,4245,0]Ao[1127,13,4305,4305,5210,4191,0]Ao[1127,13,4305,4305,5211,4245,0]Am[477,13,478,4270,3316,3124,0]Am[477,13,478,4270,5001,3124,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Al[3173,15,4854,4854,1207,0,0]Ag[477,10,478,2036,0,0,0]Af[477,6,478,3741,0,0,0]Ah[3173,6,3174,3741,0,0,0]Aj[477,15,478,3740,4899,0,0]Aj[477,15,478,4157,3121,0,0]Aj[477,15,478,4157,3324,0,0]Aj[477,15,478,4162,3342,0,0]Aj[477,15,478,4162,4248,0,0]Al[3173,15,3174,3741,1206,0,0]Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]Af[477,5,478,2385,0,0,0]Ah[3173,5,3174,1393,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]76Af[477,5,478,1430,0,0,0]Ah[3173,5,3174,1430,0,0,0]543232Af[477,6,478,4157,0,0,0]0Ah[3173,5,3174,2044,0,0,0]Ae[1228,5,1417,0,0,0,0]Ag[477,15,478,0,4584,0,0]Al[3173,15,3174,3741,4585,0,0]Ae[3173,5,3174,0,0,0,0]Ag[2029,5,2030,431,0,0,0]Af[477,5,478,1126,0,0,0]Ae[1228,7,1229,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Ai[536,14,537,537,4048,0,0]Ag[477,12,478,0,4071,0,0]Aj[477,13,478,0,4598,4071,0]Al[3173,12,3174,1148,4072,0,0]Ao[3173,13,3174,1148,4599,4072,0]5Aj[477,13,478,3740,3295,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ao[2408,13,2409,2409,2299,3333,0]Ah[477,12,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ah[477,13,3735,0,3286,0,0]Ak[477,13,3735,0,1188,3299,0]Ah[477,13,3735,0,4055,0,0]Ak[477,13,3735,0,1886,3299,0]Ah[477,13,3735,0,4366,0,0]Al[3173,12,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ak[3173,13,3736,535,3287,0,0]Ao[3173,13,3736,1389,1189,3300,0]Al[3173,13,3736,1389,4056,0,0]Ao[3173,13,3736,2408,1887,3300,0]Al[3173,13,3736,2408,4367,0,0]Aj[477,13,478,4157,3322,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]4310Ag[477,13,478,0,4940,0,0]Al[3173,13,3174,3276,4941,0,0]6532Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]3210Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]>=;:Ak[1228,14,1229,1229,141,0,0]21Al[1127,14,1128,1128,3086,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5009,0,0]Al[3173,13,3174,2044,3323,0,0]Aj[477,13,478,3740,3295,0,0]Aj[477,13,478,2385,2312,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,2354,2313,0,0]<;Ag[477,13,478,0,1480,0,0]Ag[477,13,478,0,1463,0,0]Al[3173,13,3174,1856,1481,0,0]Al[3173,13,3174,1403,1464,0,0]20Ae[1228,7,1417,0,0,0,0]?>Al[1228,14,1417,1417,1221,0,0]Ao[1127,13,1128,1128,5000,3127,0]Ag[477,15,478,0,3099,0,0]Af[477,5,478,1393,0,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Af[477,6,478,3741,0,0,0]Ah[3173,6,3174,3741,0,0,0]Al[3173,15,3174,2354,4345,0,0]Ah[3173,5,3174,1829,0,0,0]Af[477,5,478,1418,0,0,0]Ah[3173,5,3174,1418,0,0,0]97Ae[1127,5,1419,0,0,0,0]:8Ah[3173,6,3174,1798,0,0,0]Af[477,5,478,1148,0,0,0]Ah[3173,5,3174,1148,0,0,0]Al[3173,15,3174,1403,4898,0,0]Af[477,5,478,1430,0,0,0]Ah[3173,5,3174,1430,0,0,0]Af[477,5,478,3276,0,0,0]Ah[3173,5,3174,3276,0,0,0]Ag[477,15,478,0,4584,0,0]Al[3173,15,3174,3741,4585,0,0]Af[477,5,478,3740,0,0,0]Aj[477,15,478,4157,3121,0,0]Aj[477,15,478,4157,3324,0,0]Aj[477,15,478,4162,3342,0,0]Aj[477,15,478,4162,4248,0,0]An[1228,13,1229,1229,141,4344,0]Ao[1228,13,1229,1229,4075,4344,0]Ao[1228,13,1229,1229,4047,4344,0]Am[477,13,478,3740,3297,4344,0]Am[477,13,478,3740,1450,4344,0]Am[477,13,478,3740,5073,4344,0]Am[477,13,478,3740,4899,4344,0]Am[477,13,478,2353,2308,4344,0]Am[477,13,478,2353,4347,4344,0]Am[477,13,478,4270,1458,4344,0]Al[477,13,478,1126,520,4344,0]Am[477,13,478,1126,4492,4344,0]Am[477,13,478,4157,4485,4344,0]Am[477,13,478,4157,3121,4344,0]Am[477,13,478,4157,3324,4344,0]Am[477,13,478,4157,4484,4344,0]Am[477,13,478,4162,3342,4344,0]Am[477,13,478,4162,4248,4344,0]Aj[477,13,478,0,1480,4344,0]Aj[477,13,478,0,5070,4344,0]Aj[477,13,478,0,1463,4344,0]Aj[477,13,478,0,3317,4344,0]Aj[477,13,478,0,3116,4344,0]Aj[477,13,478,0,4955,4344,0]Aj[477,13,478,0,3290,4344,0]Aj[477,13,478,0,2343,4344,0]Aj[477,13,478,0,3303,4344,0]Aj[477,13,478,0,3118,4344,0]Aj[477,13,478,0,4588,4344,0]Aj[477,13,478,0,4194,4344,0]Aj[477,13,478,0,4584,4344,0]Aj[477,13,478,0,3112,4344,0]Aj[477,13,478,0,4451,4344,0]Aj[477,13,478,0,4607,4344,0]Aj[477,13,478,0,4925,4344,0]Aj[477,13,478,0,4940,4344,0]Aj[477,13,478,0,4064,4344,0]Aj[477,13,478,0,4461,4344,0]Aj[477,13,478,0,4242,4344,0]Aj[477,13,478,0,5127,4344,0]Aj[477,13,478,0,4188,4344,0]Aj[477,13,478,0,4050,4344,0]Aj[477,13,478,0,3099,4344,0]Aj[477,13,478,0,4581,4344,0]Aj[477,13,478,0,4788,4344,0]Aj[477,13,478,0,4200,4344,0]Aj[477,13,478,0,4203,4344,0]Aj[477,13,478,0,4208,4344,0]Aj[477,13,478,0,4960,4344,0]Aj[477,13,478,0,3306,4344,0]Ai[477,13,478,0,526,4344,0]Ai[477,13,478,0,133,4344,0]Aj[477,13,478,0,2330,4344,0]Aj[477,13,478,0,3097,4344,0]Aj[477,13,3735,0,501,4344,0]Ak[477,13,3735,0,3286,4344,0]Ak[477,13,3735,0,1188,4344,0]Ak[477,13,3735,0,4055,4344,0]Ak[477,13,3735,0,1886,4344,0]Ak[477,13,3735,0,4366,4344,0]Ak[477,13,1818,0,1201,4344,0]Ak[477,13,1818,0,4818,4344,0]Ak[477,13,1818,0,5064,4344,0]Ak[477,13,1818,0,4820,4344,0]Ao[3173,13,3174,1856,1481,4344,0]Ao[3173,13,3174,1856,5071,4344,0]Ao[3173,13,3174,3147,4900,4344,0]Ao[3173,13,3174,1403,1464,4344,0]Ao[3173,13,3174,1403,4238,4344,0]Ao[3173,13,3174,1403,3318,4344,0]Ao[3173,13,3174,1403,3117,4344,0]Ao[3173,13,3174,1403,4898,4344,0]Ao[3173,13,3174,1403,4956,4344,0]Ao[3173,13,3174,1403,3293,4344,0]Ao[3173,13,3174,1418,2344,4344,0]Ao[3173,13,3174,1418,3304,4344,0]Ao[3173,13,3174,1418,3119,4344,0]Ao[3173,13,3174,1418,4589,4344,0]Ao[3173,13,3174,1152,3122,4344,0]Ao[3173,13,3174,1152,4374,4344,0]Ao[3173,13,3174,1157,3343,4344,0]Ao[3173,13,3174,1157,4063,4344,0]Ao[3173,13,3174,2044,4486,4344,0]Ao[3173,13,3174,2044,4198,4344,0]Ao[3173,13,3174,3741,4585,4344,0]Ao[3173,13,3174,3741,3113,4344,0]Ao[3173,13,3174,3741,4452,4344,0]Ao[3173,13,3174,3741,5158,4344,0]Ao[3173,13,3174,3276,4608,4344,0]Ao[3173,13,3174,3276,4926,4344,0]Ao[3173,13,3174,3276,4941,4344,0]Ao[3173,13,3174,3276,4065,4344,0]Ao[3173,13,3174,1733,4462,4344,0]Ao[3173,13,3174,1733,4244,4344,0]Ao[3173,13,3174,1733,5128,4344,0]Ao[3173,13,3174,1733,4190,4344,0]Ao[3173,13,3174,1733,4051,4344,0]Ao[3173,13,3174,1393,3100,4344,0]Ao[3173,13,3174,1393,3310,4344,0]Ao[3173,13,3174,1393,3332,4344,0]Ao[3173,13,3174,1393,4205,4344,0]Ao[3173,13,3174,1393,4583,4344,0]Ao[3173,13,3174,1393,4790,4344,0]Ao[3173,13,3174,1393,2302,4344,0]Ao[3173,13,3174,2354,4794,4344,0]Ao[3173,13,3174,2354,4201,4344,0]Ao[3173,13,3174,1798,4597,4344,0]Ao[3173,13,3174,1798,5161,4344,0]Ao[3173,13,3174,1798,2316,4344,0]Ao[3173,13,3174,1798,4895,4344,0]Ao[3173,13,3174,1829,4204,4344,0]Ao[3173,13,3174,1829,4209,4344,0]Al[3173,13,3174,0,4490,4344,0]Al[3173,13,3174,0,4961,4344,0]Ao[3173,13,3174,4388,3307,4344,0]Ao[3173,13,3174,4388,5263,4344,0]An[3173,13,3174,3174,527,4344,0]An[3173,13,3174,3174,134,4344,0]Ao[3173,13,3174,3174,2331,4344,0]Ao[3173,13,3174,3174,3098,4344,0]Ao[3173,13,1731,1731,4380,4344,0]Ao[3173,13,5112,5112,5008,4344,0]Ao[3173,13,5112,5112,1203,4344,0]Al[3173,13,1819,0,1202,4344,0]Ao[3173,13,1819,1819,4819,4344,0]Ao[3173,13,1819,1819,5065,4344,0]Ao[3173,13,1819,1819,4821,4344,0]Am[3173,13,3736,535,502,4344,0]An[3173,13,3736,535,3287,4344,0]Ao[3173,13,3736,1389,1189,4344,0]Ao[3173,13,3736,1389,4056,4344,0]Ao[3173,13,3736,2408,1887,4344,0]Ao[3173,13,3736,2408,4367,4344,0]Ao[3173,13,4854,4854,1207,4344,0]Ao[2029,13,2030,2030,2328,4344,0]Ao[2029,13,2030,2030,2342,4344,0]Ao[2029,13,2030,2030,4210,4344,0]Ao[1127,13,1128,1128,5000,4344,0]Ao[1127,13,1419,1419,4593,4344,0]Ao[1127,13,4305,4305,5210,4344,0]Ao[1127,13,4305,4305,5211,4344,0]Af[477,7,478,2036,0,0,0]Ag[477,13,478,0,4461,0,0]Al[3173,13,3174,1733,4462,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Al[2029,14,2030,2030,2328,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Ae[1127,7,1128,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Ae[4391,7,4392,0,0,0,0]Ae[1228,7,1229,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,3740,3297,0,0]1Al[3173,13,3174,2044,4486,0,0]Al[1228,13,1417,1417,1221,0,0]Al[1228,14,1417,1417,4083,0,0]Aj[477,12,478,2036,1898,0,0]Am[477,13,478,1431,4249,1898,0]Am[477,13,478,1169,4078,1898,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Af[477,5,478,1126,0,0,0]Ag[477,15,478,0,3099,0,0]Af[477,5,478,1393,0,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Ag[477,15,478,0,4584,0,0]Al[3173,15,3174,3741,4585,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,3741,1206,0,0]Af[477,5,478,2354,0,0,0]2Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]32Ag[477,15,478,0,3112,0,0]Al[3173,15,3174,3741,3113,0,0]Ag[477,15,478,0,3099,0,0]?0?0?43Ag[477,5,1818,1819,0,0,0]Ae[3173,5,1819,0,0,0,0]10Af[477,5,478,4996,0,0,0]Ah[3173,5,3174,4996,0,0,0]Al[3173,15,4854,4854,1204,0,0]7Al[3173,15,3174,1403,4898,0,0]7Al[3173,15,3174,1798,4597,0,0]Ag[477,12,478,0,2336,0,0]Aj[477,13,478,0,4338,2336,0]Aj[477,13,478,0,4222,2336,0]Al[3173,12,3174,1430,2337,0,0]Ao[3173,13,3174,4617,4339,2337,0]Ao[3173,13,3174,1430,4223,2337,0]Ae[4088,7,4089,0,0,0,0]Aj[477,13,478,3740,3297,0,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]32An[1228,13,1229,1229,141,4463,0]An[2408,13,2409,2409,132,4463,0]Ao[2408,13,2409,2409,2299,4463,0]Ao[1127,13,1128,1128,3086,4463,0]An[1127,13,1725,1725,142,4463,0]An[1127,13,1824,1824,143,4463,0]Ak[2029,13,2030,431,4491,0,0]Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]:9Ae[3173,2,3174,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]?>43Aj[477,13,478,4157,3322,0,0]Ae[4391,7,4392,0,0,0,0]7Al[1127,14,1128,1128,3086,0,0]80Ae[1228,7,1229,0,0,0,0]Ag[477,13,478,0,4242,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4244,0,0]Al[3173,13,3174,1733,4190,0,0]Ag[477,14,478,0,4242,0,0]Al[3173,14,3174,1733,4244,0,0]53Aj[477,13,478,4162,3328,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]Ag[477,15,478,0,4584,0,0]Al[3173,15,3174,1403,4898,0,0]Al[3173,15,3174,3741,4585,0,0]Ah[477,10,3735,3736,0,0,0]Af[3173,10,3736,0,0,0,0]Ag[477,5,3735,3736,0,0,0]Ae[3173,5,3736,0,0,0,0]Ah[477,10,1735,1736,0,0,0]Af[3173,10,1736,0,0,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,10,478,3741,0,0,0]Ai[3173,10,3174,3741,0,0,0]Ah[3173,6,3174,1798,0,0,0]Ah[3173,6,3174,1403,0,0,0]Af[477,6,478,3740,0,0,0]Ah[3173,6,3174,3147,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Aj[477,15,478,3740,4899,0,0]Al[3173,15,3174,3147,4900,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Ah[477,14,3735,0,4886,0,0]Al[3173,14,3736,3736,4887,0,0]Aj[477,13,478,3740,3297,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Al[3173,13,3174,3147,3089,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]Ab[4918,3,0,0,0,0,0]Ao[1127,13,1128,1128,5000,3127,0]3Aj[477,13,478,4162,3328,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]Af[477,5,478,3276,0,0,0]Ah[3173,5,3174,3276,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]54Ai[3173,10,3174,1798,0,0,0]Al[3173,15,3174,3741,1206,0,0]7600Al[3173,15,3174,1152,4374,0,0]4365Al[3173,15,4854,4854,1204,0,0]Ae[1127,9,1128,0,0,0,0]:9Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]<;<;Af[477,6,478,1403,0,0,0]Ah[3173,6,3174,1403,0,0,0]32Al[1228,15,1229,1229,4075,0,0]Ac[477,5,478,0,0,0,0]Ae[3173,5,3174,0,0,0,0]Ag[477,15,478,0,4200,0,0]Ag[477,5,1735,1736,0,0,0]Al[3173,15,3174,2354,4201,0,0]Al[3173,15,3174,1798,4895,0,0]Ae[3173,5,1736,0,0,0,0]An[1228,13,1229,1229,141,4453,0]An[2408,13,2409,2409,132,4453,0]Ao[1127,13,1128,1128,3086,4453,0]An[1127,13,1725,1725,142,4453,0]An[1127,13,1824,1824,143,4453,0]Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]Ag[477,13,478,0,1480,0,0]Al[3173,13,3174,1856,1481,0,0]Aj[477,14,478,2353,4347,0,0]Aj[477,13,478,3740,5073,0,0]Ag[477,13,478,0,4461,0,0]Al[3173,13,3174,1733,4462,0,0]Ag[477,13,478,0,4338,0,0]Al[3173,13,3174,4617,4339,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]7Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,13,1818,0,4818,0,0]Ah[477,13,1818,0,4820,0,0]Al[3173,13,1819,1819,4819,0,0]Al[3173,13,1819,1819,4821,0,0]45;:Ao[4088,13,4089,4089,5162,4954,0]Ag[477,13,478,0,4598,0,0]Al[3173,13,3174,1148,4599,0,0]Ae[1127,6,1128,0,0,0,0]Af[477,5,478,4270,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Ag[477,15,478,0,3112,0,0]Al[3173,15,3174,3741,3113,0,0]Ae[3173,5,5112,0,0,0,0]Af[477,5,478,4157,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Al[3173,15,4854,4854,1204,0,0]Aj[477,14,478,2353,4347,0,0]Ai[477,13,478,0,526,3078,0]Ai[477,13,478,0,133,3078,0]An[3173,13,3174,3174,527,3078,0]An[3173,13,3174,3174,134,3078,0]Ao[2408,13,2409,2409,2299,3333,0]Ag[477,13,478,0,4940,0,0]Al[3173,13,3174,3276,4941,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Aj[477,13,478,3740,3297,0,0]Ag[477,12,478,0,4892,0,0]Al[3173,12,3174,3741,4893,0,0]Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Ah[477,12,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,12,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Aj[477,14,478,2353,4347,0,0]Al[3173,13,3174,2044,1907,0,0]Ah[3173,2,4386,4161,0,0,0]Ae[1228,7,1229,0,0,0,0]==Ai[477,13,478,1126,520,0,0]Ak[2029,13,2030,431,4491,0,0]032Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Ae[3173,2,3174,0,0,0,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ag[477,10,478,4388,0,0,0]Ai[3173,10,3174,4388,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,13,3174,2354,2309,0,0]Ah[477,13,3735,0,4366,0,0]Al[3173,13,3736,2408,4367,0,0]Aj[477,13,478,2036,3125,0,0]0Aj[477,13,478,3740,3297,0,0]5Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]Al[1127,14,1128,1128,3086,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]Al[3173,15,4854,4854,1204,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]10Ag[477,15,478,0,4955,0,0]Ag[477,15,478,0,3112,0,0]Ag[477,15,478,0,4451,0,0]Al[3173,15,3174,1403,4956,0,0]Al[3173,15,3174,3741,3113,0,0]Al[3173,15,3174,3741,4452,0,0]Ah[3173,5,3174,3741,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1798,0,0,0]Ae[4088,5,4089,0,0,0,0]Al[1127,13,1128,1128,3086,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ah[3173,7,5043,5042,0,0,0]0Al[3173,13,3174,3741,3298,0,0]6Ai[477,13,478,1126,520,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ao[4088,13,4089,4089,5162,4954,0]0Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]10Ag[477,13,478,0,4925,0,0]Al[3173,13,3174,3276,4926,0,0]Am[1228,13,1229,1229,141,499,0]Am[2408,13,2409,2409,132,499,0]An[1127,13,1128,1128,3086,499,0]Am[1127,13,1725,1725,142,499,0]Am[1127,13,1824,1824,143,499,0]??Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ai[477,13,478,1126,520,0,0]An[1228,13,1229,1229,141,4463,0]An[2408,13,2409,2409,132,4463,0]Ao[2408,13,2409,2409,2299,4463,0]Ao[1127,13,1128,1128,3086,4463,0]An[1127,13,1725,1725,142,4463,0]An[1127,13,1824,1824,143,4463,0]Ag[477,13,478,0,4242,0,0]Al[3173,13,3174,1733,4244,0,0]Ag[477,19,478,0,4960,0,0]Ai[3173,19,3174,0,4961,0,0]Ae[1127,5,4305,0,0,0,0]0Ag[477,13,478,0,4461,0,0]Al[3173,13,3174,1733,4462,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Aj[477,13,478,2353,2308,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2313,0,0]Al[3173,13,3174,3741,3298,0,0]Ao[4088,13,4089,4089,5162,4954,0];:Ag[477,5,1735,1736,0,0,0]Ae[3173,5,1736,0,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]?>?>Aj[477,13,478,3740,3297,0,0]6Ag[477,13,478,0,4607,0,0]Al[3173,13,3174,3276,4608,0,0]Ae[4088,7,4089,0,0,0,0]Ae[4391,7,4392,0,0,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]?Ah[477,12,1735,0,4243,0,0]>Ak[477,13,1818,0,4819,4243,0]>Al[3173,12,1736,1736,4245,0,0]>Ao[3173,13,1819,1819,4820,4245,0]Ao[1127,13,4305,4305,5210,4245,0]An[2408,13,2409,2409,132,4066,0]Ao[2408,13,2409,2409,2299,4066,0]Ag[477,14,478,0,3118,0,0]Ag[477,14,478,0,4587,0,0]Al[3173,14,3174,1418,3119,0,0]Al[3173,14,3174,1418,4588,0,0]Ag[477,13,478,0,4242,0,0]Al[3173,13,3174,1733,4244,0,0]Aj[477,13,478,2036,4448,0,0]0Ak[2029,13,2030,431,4490,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,3741,3298,0,0]Al[1127,13,1419,1419,4592,0,0]Ae[1127,2,1128,0,0,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2313,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]6Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]32Ak[1228,14,1229,1229,141,0,0]Ag[477,14,478,0,2340,0,0]Al[3173,14,3174,3174,2341,0,0]Al[2029,14,2030,2030,2342,0,0]Ah[477,14,3735,0,4885,0,0]Al[3173,14,3736,3736,4886,0,0]Al[3173,13,3174,2044,1907,0,0]Al[3173,13,3174,4387,5257,0,0]Al[3173,13,3174,4387,5262,0,0]Aj[477,13,478,4162,3328,0,0]Al[3173,13,3174,2044,3329,0,0]>=Al[1228,14,1417,1417,1221,0,0]Ai[536,14,537,537,4048,0,0]Ah[477,13,1818,0,4817,0,0]Ah[477,13,1818,0,4819,0,0]Al[3173,13,1819,1819,4818,0,0]Al[3173,13,1819,1819,4820,0,0]6Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Af[477,5,478,4616,0,0,0]Ah[3173,5,3174,4616,0,0,0]Ag[477,15,478,0,4583,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,3741,4584,0,0]Al[3173,15,3174,2354,4201,0,0]Ah[3173,6,3174,2354,0,0,0]Ah[3173,5,3174,1829,0,0,0]Af[477,5,478,2353,0,0,0]Aj[477,15,478,4157,4483,0,0]Ag[477,5,1818,1819,0,0,0]Ae[3173,5,1819,0,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,1798,4894,0,0]?=5454Al[3173,15,3174,2354,4345,0,0]Ag[477,5,3735,2408,0,0,0]Ah[3173,5,3736,2408,0,0,0]Ah[3173,5,3174,1798,0,0,0]98Ah[3173,6,3174,1152,0,0,0]:9Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ae[3173,5,1731,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Al[1127,14,1128,1128,3086,0,0]Ae[3173,2,3174,0,0,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Aj[477,12,478,2036,4448,0,0]Ab[4390,3,0,0,0,0,0]Ak[1228,14,1229,1229,141,0,0]Al[1228,14,1417,1417,4083,0,0]98Aj[477,13,478,2385,3325,0,0]Al[3173,13,3174,2354,3326,0,0]Ag[477,13,478,0,4924,0,0]Al[3173,13,3174,3276,4925,0,0];==;:Ak[1228,14,1229,1229,141,0,0]21Al[1127,14,1128,1128,3086,0,0]Aj[477,13,478,4157,3322,0,0]Aj[477,13,478,4157,5008,0,0]Al[3173,13,3174,2044,3323,0,0]Aj[477,13,478,3740,3295,0,0]Aj[477,13,478,2385,2312,0,0]Ai[477,13,478,1126,520,0,0]Al[3173,13,3174,2354,2313,0,0]<;Ag[477,13,478,0,1480,0,0]Ag[477,13,478,0,1463,0,0]Al[3173,13,3174,1856,1481,0,0]Al[3173,13,3174,1403,1464,0,0]20Ae[1228,7,1417,0,0,0,0]?>Al[1228,14,1417,1417,1221,0,0]Ao[1127,13,1128,1128,4999,3127,0]Ag[477,15,478,0,3099,0,0]Af[477,5,478,1393,0,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Af[477,6,478,3741,0,0,0]Ah[3173,6,3174,3741,0,0,0]Al[3173,15,3174,2354,4345,0,0]Ah[3173,5,3174,1829,0,0,0]Af[477,5,478,1418,0,0,0]Ah[3173,5,3174,1418,0,0,0]97Ae[1127,5,1419,0,0,0,0]:8Ah[3173,6,3174,1798,0,0,0]Af[477,5,478,1148,0,0,0]Ah[3173,5,3174,1148,0,0,0]Al[3173,15,3174,1403,4897,0,0]Af[477,5,478,1430,0,0,0]Ah[3173,5,3174,1430,0,0,0]Af[477,5,478,3276,0,0,0]Ah[3173,5,3174,3276,0,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,3741,4584,0,0]Af[477,5,478,3740,0,0,0]Aj[477,15,478,4157,3121,0,0]Aj[477,15,478,4157,3324,0,0]Aj[477,15,478,4162,3342,0,0]Aj[477,15,478,4162,4248,0,0]An[1228,13,1229,1229,141,4344,0]Ao[1228,13,1229,1229,4075,4344,0]Ao[1228,13,1229,1229,4047,4344,0]Am[477,13,478,3740,3297,4344,0]Am[477,13,478,3740,1450,4344,0]Am[477,13,478,3740,5072,4344,0]Am[477,13,478,3740,4898,4344,0]Am[477,13,478,2353,2308,4344,0]Am[477,13,478,2353,4347,4344,0]Am[477,13,478,4270,1458,4344,0]Al[477,13,478,1126,520,4344,0]Am[477,13,478,1126,4491,4344,0]Am[477,13,478,4157,4484,4344,0]Am[477,13,478,4157,3121,4344,0]Am[477,13,478,4157,3324,4344,0]Am[477,13,478,4157,4483,4344,0]Am[477,13,478,4162,3342,4344,0]Am[477,13,478,4162,4248,4344,0]Aj[477,13,478,0,1480,4344,0]Aj[477,13,478,0,5069,4344,0]Aj[477,13,478,0,1463,4344,0]Aj[477,13,478,0,3317,4344,0]Aj[477,13,478,0,3116,4344,0]Aj[477,13,478,0,4954,4344,0]Aj[477,13,478,0,3290,4344,0]Aj[477,13,478,0,2343,4344,0]Aj[477,13,478,0,3303,4344,0]Aj[477,13,478,0,3118,4344,0]Aj[477,13,478,0,4587,4344,0]Aj[477,13,478,0,4194,4344,0]Aj[477,13,478,0,4583,4344,0]Aj[477,13,478,0,3112,4344,0]Aj[477,13,478,0,4450,4344,0]Aj[477,13,478,0,4606,4344,0]Aj[477,13,478,0,4924,4344,0]Aj[477,13,478,0,4939,4344,0]Aj[477,13,478,0,4064,4344,0]Aj[477,13,478,0,4460,4344,0]Aj[477,13,478,0,4242,4344,0]Aj[477,13,478,0,5126,4344,0]Aj[477,13,478,0,4188,4344,0]Aj[477,13,478,0,4050,4344,0]Aj[477,13,478,0,3099,4344,0]Aj[477,13,478,0,4580,4344,0]Aj[477,13,478,0,4787,4344,0]Aj[477,13,478,0,4200,4344,0]Aj[477,13,478,0,4203,4344,0]Aj[477,13,478,0,4208,4344,0]Aj[477,13,478,0,4959,4344,0]Aj[477,13,478,0,3306,4344,0]Ai[477,13,478,0,526,4344,0]Ai[477,13,478,0,133,4344,0]Aj[477,13,478,0,2330,4344,0]Aj[477,13,478,0,3097,4344,0]Aj[477,13,3735,0,501,4344,0]Ak[477,13,3735,0,3286,4344,0]Ak[477,13,3735,0,1188,4344,0]Ak[477,13,3735,0,4055,4344,0]Ak[477,13,3735,0,1886,4344,0]Ak[477,13,3735,0,4366,4344,0]Ak[477,13,1818,0,1201,4344,0]Ak[477,13,1818,0,4817,4344,0]Ak[477,13,1818,0,5063,4344,0]Ak[477,13,1818,0,4819,4344,0]Ao[3173,13,3174,1856,1481,4344,0]Ao[3173,13,3174,1856,5070,4344,0]Ao[3173,13,3174,3147,4899,4344,0]Ao[3173,13,3174,1403,1464,4344,0]Ao[3173,13,3174,1403,4238,4344,0]Ao[3173,13,3174,1403,3318,4344,0]Ao[3173,13,3174,1403,3117,4344,0]Ao[3173,13,3174,1403,4897,4344,0]Ao[3173,13,3174,1403,4955,4344,0]Ao[3173,13,3174,1403,3293,4344,0]Ao[3173,13,3174,1418,2344,4344,0]Ao[3173,13,3174,1418,3304,4344,0]Ao[3173,13,3174,1418,3119,4344,0]Ao[3173,13,3174,1418,4588,4344,0]Ao[3173,13,3174,1152,3122,4344,0]Ao[3173,13,3174,1152,4374,4344,0]Ao[3173,13,3174,1157,3343,4344,0]Ao[3173,13,3174,1157,4063,4344,0]Ao[3173,13,3174,2044,4485,4344,0]Ao[3173,13,3174,2044,4198,4344,0]Ao[3173,13,3174,3741,4584,4344,0]Ao[3173,13,3174,3741,3113,4344,0]Ao[3173,13,3174,3741,4451,4344,0]Ao[3173,13,3174,3741,5157,4344,0]Ao[3173,13,3174,3276,4607,4344,0]Ao[3173,13,3174,3276,4925,4344,0]Ao[3173,13,3174,3276,4940,4344,0]Ao[3173,13,3174,3276,4065,4344,0]Ao[3173,13,3174,1733,4461,4344,0]Ao[3173,13,3174,1733,4244,4344,0]Ao[3173,13,3174,1733,5127,4344,0]Ao[3173,13,3174,1733,4190,4344,0]Ao[3173,13,3174,1733,4051,4344,0]Ao[3173,13,3174,1393,3100,4344,0]Ao[3173,13,3174,1393,3310,4344,0]Ao[3173,13,3174,1393,3332,4344,0]Ao[3173,13,3174,1393,4205,4344,0]Ao[3173,13,3174,1393,4582,4344,0]Ao[3173,13,3174,1393,4789,4344,0]Ao[3173,13,3174,1393,2302,4344,0]Ao[3173,13,3174,2354,4793,4344,0]Ao[3173,13,3174,2354,4201,4344,0]Ao[3173,13,3174,1798,4596,4344,0]Ao[3173,13,3174,1798,5160,4344,0]Ao[3173,13,3174,1798,2316,4344,0]Ao[3173,13,3174,1798,4894,4344,0]Ao[3173,13,3174,1829,4204,4344,0]Ao[3173,13,3174,1829,4209,4344,0]Al[3173,13,3174,0,4489,4344,0]Al[3173,13,3174,0,4960,4344,0]Ao[3173,13,3174,4387,3307,4344,0]Ao[3173,13,3174,4387,5262,4344,0]An[3173,13,3174,3174,527,4344,0]An[3173,13,3174,3174,134,4344,0]Ao[3173,13,3174,3174,2331,4344,0]Ao[3173,13,3174,3174,3098,4344,0]Ao[3173,13,1731,1731,4380,4344,0]Ao[3173,13,5111,5111,5007,4344,0]Ao[3173,13,5111,5111,1203,4344,0]Al[3173,13,1819,0,1202,4344,0]Ao[3173,13,1819,1819,4818,4344,0]Ao[3173,13,1819,1819,5064,4344,0]Ao[3173,13,1819,1819,4820,4344,0]Am[3173,13,3736,535,502,4344,0]An[3173,13,3736,535,3287,4344,0]Ao[3173,13,3736,1389,1189,4344,0]Ao[3173,13,3736,1389,4056,4344,0]Ao[3173,13,3736,2408,1887,4344,0]Ao[3173,13,3736,2408,4367,4344,0]Ao[3173,13,4853,4853,1207,4344,0]Ao[2029,13,2030,2030,2328,4344,0]Ao[2029,13,2030,2030,2342,4344,0]Ao[2029,13,2030,2030,4210,4344,0]Ao[1127,13,1128,1128,4999,4344,0]Ao[1127,13,1419,1419,4592,4344,0]Ao[1127,13,4305,4305,5209,4344,0]Ao[1127,13,4305,4305,5210,4344,0]Af[477,7,478,2036,0,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Al[2029,14,2030,2030,2328,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Ae[1127,7,1128,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Ae[4390,7,4391,0,0,0,0]Ae[1228,7,1229,0,0,0,0]Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,3740,3297,0,0]1Al[3173,13,3174,2044,4485,0,0]Al[1228,13,1417,1417,1221,0,0]Al[1228,14,1417,1417,4083,0,0]Aj[477,12,478,2036,1898,0,0]Am[477,13,478,1431,4249,1898,0]Am[477,13,478,1169,4078,1898,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Af[477,5,478,1126,0,0,0]Ag[477,15,478,0,3099,0,0]Af[477,5,478,1393,0,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1393,0,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,3741,4584,0,0]Ah[3173,5,3174,2354,0,0,0]Al[3173,15,3174,3741,1206,0,0]Af[477,5,478,2354,0,0,0]2Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]32Ag[477,15,478,0,3112,0,0]Al[3173,15,3174,3741,3113,0,0]Ag[477,15,478,0,3099,0,0]?0?0?43Ag[477,5,1818,1819,0,0,0]Ae[3173,5,1819,0,0,0,0]10Af[477,5,478,4995,0,0,0]Ah[3173,5,3174,4995,0,0,0]Al[3173,15,4853,4853,1204,0,0]7Al[3173,15,3174,1403,4897,0,0]7Al[3173,15,3174,1798,4596,0,0]Ag[477,12,478,0,2336,0,0]Aj[477,13,478,0,4338,2336,0]Aj[477,13,478,0,4222,2336,0]Al[3173,12,3174,1430,2337,0,0]Ao[3173,13,3174,4616,4339,2337,0]Ao[3173,13,3174,1430,4223,2337,0]Ae[4088,7,4089,0,0,0,0]Aj[477,13,478,3740,3297,0,0]Al[3173,13,3174,3741,3298,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]32An[1228,13,1229,1229,141,4462,0]An[2408,13,2409,2409,132,4462,0]Ao[2408,13,2409,2409,2299,4462,0]Ao[1127,13,1128,1128,3086,4462,0]An[1127,13,1725,1725,142,4462,0]An[1127,13,1824,1824,143,4462,0]Ak[2029,13,2030,431,4490,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]:9Ae[3173,2,3174,0,0,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]?>43Aj[477,13,478,4157,3322,0,0]Ae[4390,7,4391,0,0,0,0]7Al[1127,14,1128,1128,3086,0,0]80Ae[1228,7,1229,0,0,0,0]Ag[477,13,478,0,4242,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4244,0,0]Al[3173,13,3174,1733,4190,0,0]Ag[477,14,478,0,4242,0,0]Al[3173,14,3174,1733,4244,0,0]53Aj[477,13,478,4162,3328,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ag[477,15,478,0,4583,0,0]Al[3173,15,3174,1403,4897,0,0]Al[3173,15,3174,3741,4584,0,0]Ah[477,10,3735,3736,0,0,0]Af[3173,10,3736,0,0,0,0]Ag[477,5,3735,3736,0,0,0]Ae[3173,5,3736,0,0,0,0]Ah[477,10,1735,1736,0,0,0]Af[3173,10,1736,0,0,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,10,478,3741,0,0,0]Ai[3173,10,3174,3741,0,0,0]Ah[3173,6,3174,1798,0,0,0]Ah[3173,6,3174,1403,0,0,0]Af[477,6,478,3740,0,0,0]Ah[3173,6,3174,3147,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Aj[477,15,478,3740,4898,0,0]Al[3173,15,3174,3147,4899,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Ah[477,14,3735,0,4885,0,0]Al[3173,14,3736,3736,4886,0,0]Aj[477,13,478,3740,3297,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]10Al[3173,13,3174,3147,3089,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,2354,2309,0,0]Ab[4917,3,0,0,0,0,0]Ao[1127,13,1128,1128,4999,3127,0]3Aj[477,13,478,4162,3328,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Af[477,5,478,3276,0,0,0]Ah[3173,5,3174,3276,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]54Ai[3173,10,3174,1798,0,0,0]Al[3173,15,3174,3741,1206,0,0]7600Al[3173,15,3174,1152,4374,0,0]4365Al[3173,15,4853,4853,1204,0,0]Ae[1127,9,1128,0,0,0,0]:9Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]<;<;Af[477,6,478,1403,0,0,0]Ah[3173,6,3174,1403,0,0,0]32Al[1228,15,1229,1229,4075,0,0]Ac[477,5,478,0,0,0,0]Ae[3173,5,3174,0,0,0,0]Ag[477,15,478,0,4200,0,0]Ag[477,5,1735,1736,0,0,0]Al[3173,15,3174,2354,4201,0,0]Al[3173,15,3174,1798,4894,0,0]Ae[3173,5,1736,0,0,0,0]An[1228,13,1229,1229,141,4452,0]An[2408,13,2409,2409,132,4452,0]Ao[1127,13,1128,1128,3086,4452,0]An[1127,13,1725,1725,142,4452,0]An[1127,13,1824,1824,143,4452,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ag[477,13,478,0,1480,0,0]Al[3173,13,3174,1856,1481,0,0]Aj[477,14,478,2353,4347,0,0]Aj[477,13,478,3740,5072,0,0]Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ag[477,13,478,0,4338,0,0]Al[3173,13,3174,4616,4339,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]7Al[3173,13,3174,3741,3298,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,13,1818,0,4817,0,0]Ah[477,13,1818,0,4819,0,0]Al[3173,13,1819,1819,4818,0,0]Al[3173,13,1819,1819,4820,0,0]45;:Ao[4088,13,4089,4089,5161,4953,0]Ag[477,13,478,0,4597,0,0]Al[3173,13,3174,1148,4598,0,0]Ae[1127,6,1128,0,0,0,0]Af[477,5,478,4270,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]10Ag[477,15,478,0,3112,0,0]Al[3173,15,3174,3741,3113,0,0]Ae[3173,5,5111,0,0,0,0]Af[477,5,478,4157,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Al[3173,15,4853,4853,1204,0,0]Aj[477,14,478,2353,4347,0,0]Ai[477,13,478,0,526,3078,0]Ai[477,13,478,0,133,3078,0]An[3173,13,3174,3174,527,3078,0]An[3173,13,3174,3174,134,3078,0]Ao[2408,13,2409,2409,2299,3333,0]Ag[477,13,478,0,4939,0,0]Al[3173,13,3174,3276,4940,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Aj[477,13,478,3740,3297,0,0]Ag[477,12,478,0,4891,0,0]Al[3173,12,3174,3741,4892,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ag[477,14,478,0,3118,0,0]Al[3173,14,3174,1418,3119,0,0]Ah[477,12,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Ak[477,13,3735,0,1188,3299,0]Ak[477,13,3735,0,1886,3299,0]Al[3173,12,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ao[3173,13,3736,1389,1189,3300,0]Ao[3173,13,3736,2408,1887,3300,0]Aj[477,14,478,2353,4347,0,0]Al[3173,13,3174,2044,1907,0,0]Ah[3173,2,4385,4161,0,0,0]Ae[1228,7,1229,0,0,0,0]==Ai[477,13,478,1126,520,0,0]Ak[2029,13,2030,431,4490,0,0]032Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Ae[3173,2,3174,0,0,0,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ag[477,10,478,4387,0,0,0]Ai[3173,10,3174,4387,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]Ag[477,15,478,0,4200,0,0]Al[3173,15,3174,2354,4201,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Af[477,5,478,1733,0,0,0]Ah[3173,5,3174,1733,0,0,0]Ah[477,12,1735,0,3109,0,0]Al[3173,12,1736,1736,3110,0,0]Aj[477,13,478,2353,2308,0,0]Al[3173,13,3174,3741,3298,0,0]Al[3173,13,3174,2354,2309,0,0]Ah[477,13,3735,0,4366,0,0]Al[3173,13,3736,2408,4367,0,0]Aj[477,13,478,2036,3125,0,0]0Aj[477,13,478,3740,3297,0,0]5Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Al[1127,14,1128,1128,3086,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Al[3173,15,4853,4853,1204,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]10Ag[477,15,478,0,4954,0,0]Ag[477,15,478,0,3112,0,0]Ag[477,15,478,0,4450,0,0]Al[3173,15,3174,1403,4955,0,0]Al[3173,15,3174,3741,3113,0,0]Al[3173,15,3174,3741,4451,0,0]Ah[3173,5,3174,3741,0,0,0]Ag[477,15,478,0,3099,0,0]Al[3173,15,3174,1393,3100,0,0]Ah[3173,5,3174,1798,0,0,0]Ae[4088,5,4089,0,0,0,0]Al[1127,13,1128,1128,3086,0,0]Aj[477,13,478,3740,3297,0,0]Ah[477,12,1735,0,1899,0,0]Ak[477,13,1818,0,3337,1899,0]Al[3173,12,1736,1736,1900,0,0]Ao[3173,13,1819,1819,3338,1900,0]Ah[3173,7,5042,5041,0,0,0]0Al[3173,13,3174,3741,3298,0,0]6Ai[477,13,478,1126,520,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]Ao[4088,13,4089,4089,5161,4953,0]0Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]10Ag[477,13,478,0,4924,0,0]Al[3173,13,3174,3276,4925,0,0]Am[1228,13,1229,1229,141,499,0]Am[2408,13,2409,2409,132,499,0]An[1127,13,1128,1128,3086,499,0]Am[1127,13,1725,1725,142,499,0]Am[1127,13,1824,1824,143,499,0]??Ah[477,13,3735,0,3299,0,0]Aj[477,13,3735,0,501,3299,0]Al[3173,13,3736,3736,3300,0,0]Am[3173,13,3736,535,502,3300,0]Ai[477,13,478,1126,520,0,0]An[1228,13,1229,1229,141,4462,0]An[2408,13,2409,2409,132,4462,0]Ao[2408,13,2409,2409,2299,4462,0]Ao[1127,13,1128,1128,3086,4462,0]An[1127,13,1725,1725,142,4462,0]An[1127,13,1824,1824,143,4462,0]Ag[477,13,478,0,4242,0,0]Al[3173,13,3174,1733,4244,0,0]Ag[477,19,478,0,4959,0,0]Ai[3173,19,3174,0,4960,0,0]Ae[1127,5,4305,0,0,0,0]0Ag[477,13,478,0,4460,0,0]Al[3173,13,3174,1733,4461,0,0]Ag[477,13,478,0,4188,0,0]Al[3173,13,3174,1733,4190,0,0]Aj[477,13,478,2353,2308,0,0]Aj[477,13,478,2385,2312,0,0]Al[3173,13,3174,2354,2313,0,0]Al[3173,13,3174,3741,3298,0,0]Ao[4088,13,4089,4089,5161,4953,0];:Ag[477,5,1735,1736,0,0,0]Ae[3173,5,1736,0,0,0,0]Ah[477,15,1818,0,1201,0,0]Ai[3173,15,1819,0,1202,0,0]?>?>Aj[477,13,478,3740,3297,0,0]6Ag[477,13,478,0,4606,0,0]Al[3173,13,3174,3276,4607,0,0]Ae[4088,7,4089,0,0,0,0]Ae[4390,7,4391,0,0,0,0]Ag[477,14,478,0,3303,0,0]Al[3173,14,3174,1418,3304,0,0]?>>>>>>Aa[\"{BBChBFCn}\",[]]?????A`[\"{IFfBCAd}\",[]]A`[\"{cc{}}\",[\"T\"]]A`[\"{KIbBFLb}\",[]]11111A`[\"{KIbABCf}\",[]]222Aa[\"{AJ@fAHCd}\",[]]33A`[\"{BBChIFf}\",[]]44444444A`[\"{BHN`IFd}\",[]]A`[\"{BEFnIFd}\",[]]6A`[\"{BEHdIFd}\",[]]A`[\"{BBNhIFd}\",[]]A`[\"{BBOjIFd}\",[]]A`[\"{BCMlIFd}\",[]]A`[\"{BCOfIFd}\",[]]A`[\"{BHLnIFd}\",[]]A`[\"{BHGhIFd}\",[]]A`[\"{BEInIFd}\",[]]A`[\"{AIN`IFd}\",[]]????????????An[\"{{{AHO`{c}}}AJAjCNh}\",[\"S\"]]A`[\"{cc{}}\",[\"T\"]]0000000000000Bm[\"{{{AHO`{KI`}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bk[\"{{{AHO`{KFn}}{AHO`{CGbc}}}ICjKF`}\",[\"H\"]]Bn[\"{{{AHO`{AOL`}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{B@Mf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{DAl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{A@j}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{ABCd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AHCb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{KIb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BFDh}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bk[\"{{{AHO`{KG`}}{AHO`{CGbc}}}ICjKF`}\",[\"H\"]]Bn[\"{{{AHO`{AHFd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BBBl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AJAn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AOLb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BEGd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BFCn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{B@Mh}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{DAn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{A@l}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{ABCf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AHCd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Aa[\"{{}c{}}\",[\"U\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n[\"{{}ICj}\",[]]0000Cc[\"{{{AHO`{CGbKDl}}KCb}{{KGd{{KFl{IDb}}AHFd}}}}\",[]]Cf[\"{{{AHO`{CGbBB@j}}}{{KFl{c}}}{}}\",[\"Iterator::Item\"]]Dl[\"{{{AHO`{BFC`}}ICh{AHO`{CGb{K@j{Oh}}}}}{{KGd{{AHO`{{K@j{Oh}}}}AOJj}}}}\",[]]Bi[\"{{{AHO`{CGbNNf}}A@l}{{KFl{ABCf}}}}\",[]]Dl[\"{{{AHO`{BFCb}}ICh{AHO`{CGb{K@j{Oh}}}}}{{KGd{{AHO`{{K@j{Oh}}}}AOJl}}}}\",[]]Bf[\"{{{AHO`{AILb}}KFn}{{KFl{DA`}}}}\",[]]Bf[\"{{{AHO`{DA`}}}{{KGd{ICjAIKd}}}}\",[]]A`[\"{AILnCNb}\",[]]Am[\"{{{AHO`{CGbAILd}}}ICj}\",[]]A`[\"{AIM`CNb}\",[]]Ck[\"{{{ABb{{AHO`{CGbAIJd}}}}{AHO`{CGbNIn}}}{{DAh{ICj}}}}\",[]]Dk[\"{{{ABb{{AHO`{CGbBD@h}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbABBf}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbABBh}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAIKn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbNLb}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbKFf}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAH@h}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAAO`}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBAA`}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBAAn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbKCj}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBBNd}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbNMn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Bf[\"{{{AHO`{CGbAILd}}}{{KFl{IFl}}}}\",[]]De[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{Oh}}}}}{{KGd{{KFl{KCb}}AHFb}}}}\",[]]Bm[\"{{{AHO`{CGbAIOf}}DC`}{{KGd{KDlBBBl}}}}\",[]]C`[\"{{DAn{AHO`{CGbc}}}{{KGd{BGB`IFf}}}A@f}\",[\"R\"]]Bf[\"{{{AHO`{CGbAHBb}}}{{KFl{ICn}}}}\",[]]Ec[\"{{{AHO`{BCAf}}AJAj{AHO`{CGb{K@j{AIMh}}}}{AHO`{CGb{K@j{ABC`}}}}}{{KGf{KCb}}}}\",[]]Cn[\"{{{AHO`{BFC`}}ICh{AHO`{CGb{ABh{Oh}}}}}{{KGd{ICjAOJj}}}}\",[]]Cn[\"{{{AHO`{BFCb}}ICh{AHO`{CGb{ABh{Oh}}}}}{{KGd{ICjAOJl}}}}\",[]]C`[\"{{{AHO`{CGbAHBb}}ICnDC`}{{KGd{ICjBFDh}}}}\",[]]Cc[\"{{{AHO`{BCAf}}AJAj{AHO`{ABDl}}}{{KGf{ICj}}}}\",[]]Bn[\"{{{AHO`{CGbBH@n}}CN`}{{AHO`{CGbBH@n}}}}\",[]]Bn[\"{{{AHO`{CGbBHA`}}CN`}{{AHO`{CGbBHA`}}}}\",[]]Aj[\"{{{AHO`{AILb}}}DAl}\",[]]Aj[\"{{{AHO`{AILd}}}DAn}\",[]]Cn[\"{{{AHO`{NJj}}{AHO`{{K@j{Oh}}}}{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Cn[\"{{{AHO`{NJl}}{AHO`{{K@j{Oh}}}}{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]A`[\"{BC@nCNb}\",[]]A`[\"{ABDhKCb}\",[]]A`[\"{ABDjKCb}\",[]]o[\"{IHdDC`}\",[]]Bm[\"{{{AHO`{CGbAIOd}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbBGBb}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAIOf}}KIb}{{KGd{ICjB@Ll}}}}\",[]]Bn[\"{{{AHO`{AJAf}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BBOf}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BEJl}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{AJAh}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BBOh}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BEJn}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bd[\"{{{AHO`{BEGh}}}{{KFl{BB@h}}}}\",[]]Bd[\"{{{AHO`{BEGj}}}{{KFl{BB@j}}}}\",[]]Bi[\"{{{A@b{BFBh}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{AIJl}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{AOJn}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{BBAl}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{BFBj}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{AIJn}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{AOK`}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{BBAn}}NK`CMn}{{A@d{AILh}}}}\",[]]Aj[\"{BGA`{{A@b{BFBj}}}}\",[]]o[\"{ID`ICn}\",[]]A`[\"{ABDnCNb}\",[]]o[\"{IDbICn}\",[]]A`[\"{ABE`CNb}\",[]]Aa[\"{AOIjBCMb}\",[]]Ai[\"{{{AHO`{AAj}}}AAj}\",[]]Ak[\"{{{AHO`{AOMf}}}AOMf}\",[]]Ak[\"{{{AHO`{AOIn}}}AOIn}\",[]]Ak[\"{{{AHO`{AILb}}}AILb}\",[]]Ai[\"{{{AHO`{KEd}}}KEd}\",[]]Ak[\"{{{AHO`{BGJb}}}BGJb}\",[]]Ak[\"{{{AHO`{BFDf}}}BFDf}\",[]]Ak[\"{{{AHO`{AB@h}}}AB@h}\",[]]Ak[\"{{{AHO`{BAOf}}}BAOf}\",[]]Ai[\"{{{AHO`{KFd}}}KFd}\",[]]Ai[\"{{{AHO`{DA`}}}DA`}\",[]]Ak[\"{{{AHO`{BCAh}}}BCAh}\",[]]Ak[\"{{{AHO`{BC@j}}}BC@j}\",[]]Ak[\"{{{AHO`{AHFb}}}AHFb}\",[]]Ak[\"{{{AHO`{AIOh}}}AIOh}\",[]]Ak[\"{{{AHO`{BC@h}}}BC@h}\",[]]Ak[\"{{{AHO`{AJAl}}}AJAl}\",[]]Ak[\"{{{AHO`{BAC`}}}BAC`}\",[]]Ai[\"{{{AHO`{KI`}}}KI`}\",[]]Ak[\"{{{AHO`{BGIl}}}BGIl}\",[]]Ai[\"{{{AHO`{KFn}}}KFn}\",[]]Ak[\"{{{AHO`{AINj}}}AINj}\",[]]Ak[\"{{{AHO`{AHEh}}}AHEh}\",[]]Ak[\"{{{AHO`{BFKf}}}BFKf}\",[]]Ak[\"{{{AHO`{AIKd}}}AIKd}\",[]]Ak[\"{{{AHO`{ABDn}}}ABDn}\",[]]Ak[\"{{{AHO`{AILn}}}AILn}\",[]]Ak[\"{{{AHO`{AHEl}}}AHEl}\",[]]Ak[\"{{{AHO`{BCMh}}}BCMh}\",[]]Ak[\"{{{AHO`{B@Ld}}}B@Ld}\",[]]Ak[\"{{{AHO`{BCM`}}}BCM`}\",[]]Ak[\"{{{AHO`{AHE`}}}AHE`}\",[]]Ak[\"{{{AHO`{BBLf}}}BBLf}\",[]]Ak[\"{{{AHO`{BCOn}}}BCOn}\",[]]Ak[\"{{{AHO`{BFGj}}}BFGj}\",[]]Ak[\"{{{AHO`{BFIh}}}BFIh}\",[]]Ak[\"{{{AHO`{AOL`}}}AOL`}\",[]]Ak[\"{{{AHO`{BBMj}}}BBMj}\",[]]Ak[\"{{{AHO`{BABd}}}BABd}\",[]]Ak[\"{{{AHO`{BH@n}}}BH@n}\",[]]Ak[\"{{{AHO`{B@Kh}}}B@Kh}\",[]]Ak[\"{{{AHO`{AOJd}}}AOJd}\",[]]Ak[\"{{{AHO`{AHCf}}}AHCf}\",[]]Ak[\"{{{AHO`{BCLj}}}BCLj}\",[]]Ak[\"{{{AHO`{BEFh}}}BEFh}\",[]]Ak[\"{{{AHO`{B@M`}}}B@M`}\",[]]Ak[\"{{{AHO`{B@Mf}}}B@Mf}\",[]]Ak[\"{{{AHO`{B@N`}}}B@N`}\",[]]Ak[\"{{{AHO`{BFL`}}}BFL`}\",[]]Ak[\"{{{AHO`{AIMd}}}AIMd}\",[]]Ai[\"{{{AHO`{DAl}}}DAl}\",[]]Ai[\"{{{AHO`{A@j}}}A@j}\",[]]Ak[\"{{{AHO`{ABCd}}}ABCd}\",[]]Ak[\"{{{AHO`{AHCb}}}AHCb}\",[]]Ai[\"{{{AHO`{CNj}}}CNj}\",[]]Ak[\"{{{AHO`{AIJl}}}AIJl}\",[]]Ai[\"{{{AHO`{IDh}}}IDh}\",[]]Ak[\"{{{AHO`{AOJn}}}AOJn}\",[]]Ai[\"{{{AHO`{NKl}}}NKl}\",[]]Ak[\"{{{AHO`{BBAl}}}BBAl}\",[]]Ai[\"{{{AHO`{IFb}}}IFb}\",[]]Ak[\"{{{AHO`{BEJd}}}BEJd}\",[]]Ak[\"{{{AHO`{BGI`}}}BGI`}\",[]]Ak[\"{{{AHO`{BEJh}}}BEJh}\",[]]Ai[\"{{{AHO`{KIb}}}KIb}\",[]]Ak[\"{{{AHO`{BGIn}}}BGIn}\",[]]Ak[\"{{{AHO`{BFDh}}}BFDh}\",[]]Ai[\"{{{AHO`{KG`}}}KG`}\",[]]Ak[\"{{{AHO`{BAAl}}}BAAl}\",[]]Ak[\"{{{AHO`{AINl}}}AINl}\",[]]Ak[\"{{{AHO`{AHEj}}}AHEj}\",[]]Ak[\"{{{AHO`{BFDd}}}BFDd}\",[]]Ak[\"{{{AHO`{BFKh}}}BFKh}\",[]]Ak[\"{{{AHO`{AIKj}}}AIKj}\",[]]Ak[\"{{{AHO`{ABE`}}}ABE`}\",[]]Ak[\"{{{AHO`{AIM`}}}AIM`}\",[]]Ak[\"{{{AHO`{AHEn}}}AHEn}\",[]]Ak[\"{{{AHO`{BCMj}}}BCMj}\",[]]Ak[\"{{{AHO`{AHFd}}}AHFd}\",[]]Ak[\"{{{AHO`{BBBl}}}BBBl}\",[]]Ak[\"{{{AHO`{AJAn}}}AJAn}\",[]]Ak[\"{{{AHO`{AOKn}}}AOKn}\",[]]Ak[\"{{{AHO`{BC@l}}}BC@l}\",[]]Ak[\"{{{AHO`{B@Ll}}}B@Ll}\",[]]Ak[\"{{{AHO`{BCMb}}}BCMb}\",[]]Ak[\"{{{AHO`{AHEb}}}AHEb}\",[]]Ak[\"{{{AHO`{BBLh}}}BBLh}\",[]]Ak[\"{{{AHO`{BHDl}}}BHDl}\",[]]Ak[\"{{{AHO`{BD@`}}}BD@`}\",[]]Ak[\"{{{AHO`{BFGl}}}BFGl}\",[]]Ak[\"{{{AHO`{BFIj}}}BFIj}\",[]]Ak[\"{{{AHO`{AOLb}}}AOLb}\",[]]Ak[\"{{{AHO`{BBMl}}}BBMl}\",[]]Ak[\"{{{AHO`{BABh}}}BABh}\",[]]Ak[\"{{{AHO`{BHA`}}}BHA`}\",[]]Ak[\"{{{AHO`{B@Kl}}}B@Kl}\",[]]Ak[\"{{{AHO`{AOJf}}}AOJf}\",[]]Ak[\"{{{AHO`{AHCh}}}AHCh}\",[]]Ak[\"{{{AHO`{AIMl}}}AIMl}\",[]]Ak[\"{{{AHO`{AJ@h}}}AJ@h}\",[]]Ak[\"{{{AHO`{B@Mj}}}B@Mj}\",[]]Ak[\"{{{AHO`{BCLn}}}BCLn}\",[]]Ak[\"{{{AHO`{BEFl}}}BEFl}\",[]]Ak[\"{{{AHO`{AAOl}}}AAOl}\",[]]Ak[\"{{{AHO`{BEGd}}}BEGd}\",[]]Ak[\"{{{AHO`{B@Mb}}}B@Mb}\",[]]Ak[\"{{{AHO`{BCNj}}}BCNj}\",[]]Ak[\"{{{AHO`{BHEb}}}BHEb}\",[]]Ak[\"{{{AHO`{ABAh}}}ABAh}\",[]]Ak[\"{{{AHO`{BFCn}}}BFCn}\",[]]Ak[\"{{{AHO`{B@Mh}}}B@Mh}\",[]]Ak[\"{{{AHO`{B@Nb}}}B@Nb}\",[]]Ak[\"{{{AHO`{BCAd}}}BCAd}\",[]]Ak[\"{{{AHO`{BFLb}}}BFLb}\",[]]Ak[\"{{{AHO`{AIMf}}}AIMf}\",[]]Ak[\"{{{AHO`{BIAn}}}BIAn}\",[]]Ai[\"{{{AHO`{DAn}}}DAn}\",[]]Ai[\"{{{AHO`{A@l}}}A@l}\",[]]Ak[\"{{{AHO`{ABCf}}}ABCf}\",[]]Ak[\"{{{AHO`{AHCd}}}AHCd}\",[]]Ak[\"{{{AHO`{BBCh}}}BBCh}\",[]]Ak[\"{{{AHO`{BGB`}}}BGB`}\",[]]Ai[\"{{{AHO`{IFf}}}IFf}\",[]]Ai[\"{{{AHO`{IFd}}}IFd}\",[]]Ak[\"{{{AHO`{BEJf}}}BEJf}\",[]]Ak[\"{{{AHO`{BGIb}}}BGIb}\",[]]Ak[\"{{{AHO`{BEJj}}}BEJj}\",[]]Ai[\"{{{AHO`{CNl}}}CNl}\",[]]Ak[\"{{{AHO`{AIJn}}}AIJn}\",[]]Ai[\"{{{AHO`{IDj}}}IDj}\",[]]Ak[\"{{{AHO`{AOK`}}}AOK`}\",[]]Ai[\"{{{AHO`{NKn}}}NKn}\",[]]Ak[\"{{{AHO`{BBAn}}}BBAn}\",[]]Ai[\"{{{AHO`{IFn}}}IFn}\",[]]Ak[\"{{{AHO`{ABC`}}}ABC`}\",[]]Ak[\"{{{AHO`{ABDl}}}ABDl}\",[]]Ak[\"{{{AHO`{B@Nd}}}B@Nd}\",[]]Ak[\"{{{AHO`{BGA`}}}BGA`}\",[]]Ak[\"{{{AHO`{BCNb}}}BCNb}\",[]]Ak[\"{{{AHO`{BHKd}}}BHKd}\",[]]Ak[\"{{{AHO`{BHKf}}}BHKf}\",[]]Bn[\"{{{AHO`{AILb}}KI`{AHO`{{K@j{Oh}}}}}ICj}\",[]]Bn[\"{{{AHO`{AB@h}}KI`{AHO`{{K@j{Oh}}}}}ICj}\",[]]Bf[\"{{{AHO`{DA`}}}{{KGd{ICjBBLf}}}}\",[]]Bf[\"{{{AHO`{CGbAILd}}NK`KIbICn}ICj}\",[]]Bj[\"{{{AHO`{B@Mf}}}{{AHO`{{K@j{Oh}}}}}}\",[]]Bj[\"{{{AHO`{B@Mh}}}{{AHO`{{K@j{Oh}}}}}}\",[]]Aa[\"{BCAdAIMl}\",[]]A`[\"{ABCdCNb}\",[]]A`[\"{ABCfCNb}\",[]]A`[\"{B@N`DC`}\",[]]A`[\"{B@NbDC`}\",[]]l[\"{NKb}\",[]]l[\"{NKd}\",[]]Cf[\"{{{AHO`{BFHf}}{AHO`{CGbA@f}}}{{KGd{B@MhBFCn}}}}\",[]]Cf[\"{{{AHO`{BIEb}}{AHO`{CGbA@f}}}{{KGd{B@MhBFCn}}}}\",[]]Bc[\"{{{AHO`{AILd}}}{{ABh{KG`}}}}\",[]]Bd[\"{{{AHO`{IHj}}{AHO`{CMl}}}ICj}\",[]]Am[\"{{{AHO`{AOJ`}}KCb}ICj}\",[]]Ai[\"{{{AHO`{IHl}}}ICj}\",[]]Bg[\"{{{ABb{{AHO`{CGbAIJd}}}}NK`}ICj}\",[]]Bm[\"{{{AHO`{CGbAJ@`}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAJ@b}}KIb}{{KGd{ICjB@Ll}}}}\",[]]Am[\"{ABA`{{KGd{ICjAIOj}}}}\",[]]Dc[\"{{{AHO`{CGbAB@j}}ABAb{AHO`{CGb{ABh{Oh}}}}}{{KGd{ABDjAIOl}}}}\",[]]Bj[\"{{{AHO`{NMd}}{ABb{{A@d{KEn}}}}}ICj}\",[]]Bk[\"{{{AHO`{BACb}}{ABb{{A@d{KEn}}}}}ICj}\",[]]Bk[\"{{{AHO`{AOMl}}{ABb{{A@d{KEn}}}}}ICj}\",[]]o[\"{AAjDC`}\",[]]Ak[\"{{{AHO`{AILb}}}BCMh}\",[]]Ak[\"{{{AHO`{AB@h}}}BAOf}\",[]]Aj[\"{{{AHO`{DA`}}}AHEl}\",[]]A`[\"{KEdBCMh}\",[]]An[\"{{{AHO`{CGbAILd}}}BCMj}\",[]]Ce[\"{{{AHO`{CGbAINn}}{KFl{KHl}}}{{AHO`{CGbAINn}}}}\",[]]Ce[\"{{{AHO`{CGbAIO`}}{KFl{KHl}}}{{AHO`{CGbAIO`}}}}\",[]]Ck[\"{{{AHO`{CGbAJ@`}}{AHO`{{K@j{Oh}}}}}{{KGd{KCbAJAl}}}}\",[]]Ck[\"{{{AHO`{CGbAJ@b}}{AHO`{{K@j{Oh}}}}}{{KGd{KCbAJAn}}}}\",[]]Bl[\"{{{AHO`{BGB`}}{AHO`{CGbc}}}ICjKDj}\",[\"W\"]]Aj[\"{{{AHO`{AB@h}}}KCj}\",[]]An[\"{ABA`{{KGd{AIKnBCM`}}}}\",[]]Bi[\"{{{AHO`{CGbNNf}}A@l}{{KFl{ABCf}}}}\",[]]Fj[\"{{{AHO`{CGbAB@j}}ABAbNK`{AHO`{CGb{ABh{Oh}}}}{KFl{{A@b{BABh}}}}}{{KGd{{KC`{BEGdAILd}}{A@d{AOIj}}}}}}\",[]]Am[\"{AHO`{{AHO`{c}}}{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A`[\"{AAjAOIn}\",[]]Bc[\"{{AJ@fBBLdAAj}{{KGh{AOJ`}}}}\",[]]Aj[\"{AJ@f{{KGf{AB@h}}}}\",[]]Ba[\"{{}{{KGd{ICj{A@d{IEd}}}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BCM`}\",[]]Be[\"{{{AHO`{AB@j}}}{{AHO`{BBMl}}}}\",[]]o[\"{OhBFL`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{BABdA@b}\",[]]o[\"{OhBFLb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{BABhA@b}\",[]]A`[\"{BCAdKFl}\",[]]Bm[\"{{{AHO`{CGbc}}}{{KGd{KI`BBCh}}}A@f}\",[\"B\"]]Bm[\"{{{AHO`{CGbc}}}{{KGd{KFnBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{AHCfBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{BFL`BBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{ABCdBBCh}}}A@f}\",[\"B\"]]Bi[\"{{{AHO`{CGbc}}}{{KGl{KIb}}}A@f}\",[\"B\"]]Bi[\"{{{AHO`{CGbc}}}{{KGl{KG`}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AHCh}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AIMl}}}A@f}\",[\"B\"]]Fm[\"{{{AHO`{CGb{KEl{c}}}}{AHO`{e}}{AHO`{{K@j{CN`}}}}DC`}{{KGd{BCNjBFCn}}}{{ICl{{K@j{Oh}}}}}{BFHfIHh}}\",[\"\",\"\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{BFLb}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{ABCf}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AHBd}}}A@f}\",[\"B\"]]A`[\"{ABC`KFl}\",[]]Bk[\"{{{AHO`{KI`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KFn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHCf}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{BFL`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{ABCd}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KIb}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KG`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHCh}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AIMl}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AAOl}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{BFLb}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{ABCf}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHBn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bj[\"{{{AHO`{CGbAJ@`}}}{{KGd{ICjB@Ld}}}}\",[]]Bj[\"{{{AHO`{CGbAJ@b}}}{{KGd{ICjAOKn}}}}\",[]]An[\"{{{AHO`{AONh}}AB@d}ICj}\",[]]Ea[\"{{{AHO`{CGbAB@j}}NK`AHCd{KFl{B@Nb}}AAOb{AHO`{CGb{ABh{Oh}}}}}{{KFl{BAOb}}}}\",[]]o[\"{D@dNKb}\",[]]o[\"{D@fNKd}\",[]]A`[\"{ABA`ICj}\",[]]Ba[\"{{{AHO`{CGbAB@j}}ABAb}ICj}\",[]]Bh[\"{{{AHO`{AJAf}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BBOf}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BEJl}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{AJAh}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BBOh}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BEJn}}{AHO`{CMl}}ICn}ICj}\",[]]A`[\"{AHAlDC`}\",[]]o[\"{ID`CNb}\",[]]o[\"{IDbCNb}\",[]]Ch[\"{{{AHO`{CGbAILf}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbCNj}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbIDh}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbNKl}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Ch[\"{{{AHO`{CGbAILh}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbCNl}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbIDj}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbNKn}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]o[\"{D@dNKb}\",[]]o[\"{D@fNKd}\",[]]o[\"{BEKhOh}\",[]]A`[\"{KEdBCM`}\",[]]A`[\"{BCLjICn}\",[]]A`[\"{BEFhICn}\",[]]Aa[\"{AH@`BFDb}\",[]]A`[\"{BCLnICn}\",[]]A`[\"{BEFlICn}\",[]]A`[\"{BCAdKHl}\",[]]Aa[\"{BBLlBCMb}\",[]]Aa[\"{AH@bBFDd}\",[]]Bg[\"{{{AHO`{AB@h}}AHFl}{{KGf{ICj}}}}\",[]]A`[\"{ABA`ICj}\",[]]Cf[\"{{{AHO`{CGbAB@j}}ABAb{AHO`{CGb{ABh{Oh}}}}}ABDj}\",[]]Ak[\"{{{AHO`{AHCb}}}AJ@f}\",[]]l[\"{NKb}\",[]]Ak[\"{{{AHO`{AHCd}}}AJ@f}\",[]]l[\"{NKd}\",[]]An[\"{{AB@fAAj}{{KGh{ICj}}}}\",[]]B`[\"{{BABdAJ@f}{{KGf{AB@h}}}}\",[]]Bc[\"{BABb{{KGd{ICj{A@d{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BFDf}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BC@j}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AHFb}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AIOh}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BC@h}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AJAl}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BAC`}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BCM`}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BCMb}}}{{KFl{{AHO`{IEd}}}}}}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABDlKFl}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AINjAIKd}}}}\",[]]Aa[\"{BAAbAINj}\",[]]Aa[\"{BAAdAINl}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{ABC`KCb}\",[]]Aa[\"{AHElABDn}\",[]]Aa[\"{BCMhABDn}\",[]]Aa[\"{AHEnABE`}\",[]]Aa[\"{BCMjABE`}\",[]]3210Dh[\"{{{AHO`{NJj}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAOJj}}}}\",[]]Dh[\"{{{AHO`{NJl}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAOJl}}}}\",[]]Aj[\"{{{AHO`{AILf}}}CNb}\",[]]Ai[\"{{{AHO`{CNj}}}CNb}\",[]]Ai[\"{{{AHO`{IDh}}}CNb}\",[]]Ai[\"{{{AHO`{NKl}}}CNb}\",[]]Aj[\"{{{AHO`{AILh}}}CNb}\",[]]Ai[\"{{{AHO`{CNl}}}CNb}\",[]]Ai[\"{{{AHO`{IDj}}}CNb}\",[]]Ai[\"{{{AHO`{NKn}}}CNb}\",[]]Aj[\"{{{AHO`{BGOl}}}KCb}\",[]]Aj[\"{{{AHO`{BGOn}}}KCb}\",[]]Aj[\"{{{AHO`{BIAd}}}KCb}\",[]]Aj[\"{{{AHO`{BIAn}}}KCb}\",[]]o[\"{AAjKCb}\",[]]n[\"{{}NIl}\",[]]0A`[\"{A@hAAOf}\",[]]111Ba[\"{{AHO`{AHO`{c}}}ABBj{}}\",[\"K\"]]0000000000000000000Cg[\"{{{AHO`{AB@h}}AJ@f{AHO`{CMl}}}{{KGd{AIKnB@M`}}}}\",[]]Dl[\"{{{AHO`{CGbAB@j}}NK`B@KlAJ@f{AHO`{CMl}}}{{KGd{{KC`{BEGdAILd}}B@Mb}}}}\",[]]Bd[\"{{{AHO`{ABA`}}}{{KFl{BEGh}}}}\",[]]Dm[\"{{{AHO`{AHDj}}KFnCNb{AHO`{{K@j{Oh}}}}{AHO`{CGbAAOb}}}{{KGd{ICjAOJj}}}}\",[]]Ca[\"{{{AHO`{AHCl}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Bd[\"{{{AHO`{ABAb}}}{{KFl{BEGj}}}}\",[]]Dm[\"{{{AHO`{AHDl}}KG`CNb{AHO`{{K@j{Oh}}}}{AHO`{CGbAAOb}}}{{KGd{ICjAOJl}}}}\",[]]Ca[\"{{{AHO`{AHCn}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]o[\"{{}AONf}\",[]]n[\"{{}IHj}\",[]]o[\"{{}AOJ`}\",[]]o[\"{{}BANd}\",[]]o[\"{{}BAOf}\",[]]n[\"{{}KI`}\",[]]n[\"{{}KFn}\",[]]o[\"{{}AINj}\",[]]o[\"{{}AIKd}\",[]]o[\"{{}ABDn}\",[]]o[\"{{}AILn}\",[]]o[\"{{}AHEl}\",[]]o[\"{{}BCMh}\",[]]o[\"{{}B@Ld}\",[]]o[\"{{}BCOn}\",[]]o[\"{{}BFGj}\",[]]o[\"{{}BFIh}\",[]]o[\"{{}AOL`}\",[]]o[\"{{}BBMj}\",[]]o[\"{{}BH@n}\",[]]o[\"{{}BEJl}\",[]]o[\"{{}AIJl}\",[]]o[\"{{}AOJn}\",[]]o[\"{{}BBAl}\",[]]o[\"{{}BFBl}\",[]]o[\"{{}BANf}\",[]]o[\"{{}BIAd}\",[]]n[\"{{}KIb}\",[]]n[\"{{}KG`}\",[]]o[\"{{}AINl}\",[]]o[\"{{}AIKj}\",[]]o[\"{{}ABE`}\",[]]o[\"{{}AIM`}\",[]]o[\"{{}AHEn}\",[]]o[\"{{}BCMj}\",[]]o[\"{{}BC@l}\",[]]o[\"{{}B@Ll}\",[]]o[\"{{}BD@`}\",[]]o[\"{{}BFGl}\",[]]o[\"{{}BFIj}\",[]]o[\"{{}AOLb}\",[]]o[\"{{}BBMl}\",[]]o[\"{{}BHA`}\",[]]o[\"{{}BIAn}\",[]]o[\"{{}BEJn}\",[]]o[\"{{}AIJn}\",[]]o[\"{{}AOK`}\",[]]o[\"{{}BBAn}\",[]]o[\"{{}BFBn}\",[]]o[\"{{}ABC`}\",[]]n[\"{{}IHl}\",[]]o[\"{{}BCNb}\",[]]o[\"{{}BAOd}\",[]]Ak[\"{{{AHO`{BBBb}}}B@Mh}\",[]]Ak[\"{{{AHO`{BCNj}}}B@Mh}\",[]]Aa[\"{BHEbB@Mh}\",[]]Aa[\"{BFLdB@Mh}\",[]]A`[\"{D@hB@Mh}\",[]]A`[\"{IH`B@Mh}\",[]]A`[\"{IHdB@Mh}\",[]]Aa[\"{BEKhB@Mh}\",[]]Cg[\"{{{AHO`{AHDj}}KFnCNb{AHO`{CGb{K@j{Oh}}}}KCb}ICj}\",[]]Ca[\"{{{AHO`{AHCl}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Cg[\"{{{AHO`{AHDl}}KG`CNb{AHO`{CGb{K@j{Oh}}}}KCb}ICj}\",[]]Ca[\"{{{AHO`{AHCn}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Aj[\"{{{AHO`{AIOd}}}DC`}\",[]]Aj[\"{{{AHO`{BGBb}}}DC`}\",[]]Ak[\"{{{AHO`{AILf}}}BFBl}\",[]]Aj[\"{{{AHO`{CNj}}}BFBl}\",[]]Aj[\"{{{AHO`{IDh}}}BFBl}\",[]]Aj[\"{{{AHO`{NKl}}}BFBl}\",[]]Ak[\"{{{AHO`{AILh}}}BFBn}\",[]]Aj[\"{{{AHO`{CNl}}}BFBn}\",[]]Aj[\"{{{AHO`{IDj}}}BFBn}\",[]]Aj[\"{{{AHO`{NKn}}}BFBn}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CMn}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}CMn}{{AHO`{CGbBD@`}}}}\",[]]Bf[\"{{{AHO`{CGbAILf}}NK`CNbCNb}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}NK`CNbCNb}ICj}\",[]]Aj[\"{{{AHO`{AILb}}}KFf}\",[]]Bc[\"{{{AHO`{ABBh}}}{{KFl{KFn}}}}\",[]]Aa[\"{BHEbB@Mh}\",[]]Aa[\"{BFLdB@Mh}\",[]]A`[\"{D@hB@Mh}\",[]]A`[\"{IH`B@Mh}\",[]]Aa[\"{BEKhB@Mh}\",[]]Aj[\"{{{AHO`{AJ@`}}}NMn}\",[]]Bn[\"{{{AHO`{AJ@b}}}{{KGd{{KFl{KIb}}B@Ll}}}}\",[]]o[\"{AAjKCb}\",[]]o[\"{IHjKCb}\",[]]Am[\"{{{AHO`{CGbAILd}}}NNf}\",[]]Aj[\"{{{AHO`{AHDj}}}KCb}\",[]]Aj[\"{{{AHO`{AHDl}}}KCb}\",[]]A`[\"{AHO`KHn}\",[]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bd[\"{{{AHO`{BGJb}}}{{KFl{AILb}}}}\",[]]Bc[\"{{{AHO`{BCAh}}}{{KFl{DA`}}}}\",[]]Bn[\"{{{AHO`{CGbB@Kh}}CN`}{{AHO`{CGbB@Kh}}}}\",[]]Bn[\"{{{AHO`{CGbB@Kl}}CN`}{{AHO`{CGbB@Kl}}}}\",[]]A`[\"{BHEbCN`}\",[]]A`[\"{BFLdCN`}\",[]]o[\"{D@hCN`}\",[]]o[\"{IH`CN`}\",[]]A`[\"{AHAlKFl}\",[]]Aa[\"{ABDlAHO`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aa[\"{BC@nAB@d}\",[]]A`[\"{KDlBC@l}\",[]]Aa[\"{AHElAILn}\",[]]Aa[\"{BCMhAILn}\",[]]Aa[\"{AHEnAIM`}\",[]]Aa[\"{BCMjAIM`}\",[]]3210Bh[\"{{{AHO`{CGbc}}KCb}B@Mf{A@fIHh}}\",[\"\"]]Bh[\"{{{AHO`{CGbc}}KCb}B@Mh{A@fIHh}}\",[\"\"]]o[\"{{}BCNl}\",[]]o[\"{{}BCNn}\",[]]A`[\"{CNbBIAd}\",[]]Cd[\"{{{AHO`{CMl}}}{{KGh{AOMfc}}}{}}\",[\"FromStr::Err\"]]Cd[\"{{{AHO`{CMl}}}{{KGh{AOInc}}}{}}\",[\"FromStr::Err\"]]o[\"{CN`KI`}\",[]]o[\"{CN`KIb}\",[]]Al[\"{CNb{{KGd{KI`BGIl}}}}\",[]]Al[\"{CNb{{KGd{KIbBGIn}}}}\",[]]Aa[\"{BGH`AOJh}\",[]]Aa[\"{BIEdBB@b}\",[]]Aa[\"{BGHbAOJh}\",[]]Aa[\"{BIEfBB@b}\",[]]Af[\"{{}{{KFl{Ab}}}}\",[]]0000Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBFIh}}AB@d}{{AHO`{CGbBFIh}}}}\",[]]Bo[\"{{{AHO`{CGbBFIj}}AB@d}{{AHO`{CGbBFIj}}}}\",[]]Bb[\"{{{A@d{AILf}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{CNj}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{IDh}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{NKl}}}{{A@d{A@`}}}}\",[]]Bb[\"{{{A@d{AILh}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{CNl}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{IDj}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{NKn}}}{{A@d{A@`}}}}\",[]]Aj[\"{{{AHO`{BGJb}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBH@n}}AB@d}{{AHO`{CGbBH@n}}}}\",[]]Bo[\"{{{AHO`{CGbBHA`}}AB@d}{{AHO`{CGbBHA`}}}}\",[]]Bc[\"{{{AHO`{AIKn}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{ABA`}}}{{KFl{KFb}}}}\",[]]Bm[\"{{{AHO`{DA`}}}{{KGd{{KFl{KFb}}AIKd}}}}\",[]]Bc[\"{{{AHO`{AHCb}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{ABAb}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{AHCd}}}{{KFl{KFb}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bc[\"{{{AHO`{AHBb}}}{{KFl{KCb}}}}\",[]]Am[\"{{{AHO`{AONh}}KCb}ICj}\",[]]Aj[\"{{{AHO`{AILb}}}NLb}\",[]]Bg[\"{{{AHO`{AJ@`}}}{{KGd{CElB@Ld}}}}\",[]]Bg[\"{{{AHO`{AJ@b}}}{{KGd{CElB@Ll}}}}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]]A`[\"{AHAlKFl}\",[]]A`[\"{AOIjKFl}\",[]]Ck[\"{{{AHO`{CGbBBMj}}{KFl{{IIh{Oh}}}}}{{AHO`{CGbBBMj}}}}\",[]]Ck[\"{{{AHO`{CGbBBMl}}{KFl{{IIh{Oh}}}}}{{AHO`{CGbBBMl}}}}\",[]]A`[\"{BFBlKFl}\",[]]A`[\"{BFBnKFl}\",[]]Ac[\"{AHO`c{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Ao[\"{c{{KGd{e}}}{}{}}\",[\"U\",\"T\"]]000000000000000000000000000000000000000000000000000000Al[\"{KCb{{KGd{KI`BGIl}}}}\",[]]Al[\"{ICh{{KGd{KI`BGIl}}}}\",[]]Al[\"{CNb{{KGd{KI`BGIl}}}}\",[]]3333333333333333333Aj[\"{AB@d{{KGd{AOL`}}}}\",[]]4444444Ai[\"{CNb{{KGd{AHCf}}}}\",[]]5555555555555555555555555555Aj[\"{B@Kd{{KGd{BEJd}}}}\",[]]6Bc[\"{{{A@b{B@Kd}}}{{KGd{BEJd}}}}\",[]]7Aj[\"{BAB`{{KGd{BEJh}}}}\",[]]8Bc[\"{{{A@b{BAB`}}}{{KGd{BEJh}}}}\",[]]99999999999999999999Al[\"{ICh{{KGd{KIbBGIn}}}}\",[]]Al[\"{KCb{{KGd{KIbBGIn}}}}\",[]];Al[\"{CNb{{KGd{KIbBGIn}}}}\",[]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Bm[\"{B@Kd{{KGd{BEJfc}}}{}}\",[\"TryFrom::Error\"]]Cf[\"{{{A@b{B@Kd}}}{{KGd{BEJfc}}}{}}\",[\"TryFrom::Error\"]]Ao[\"{c{{KGd{e}}}{}{}}\",[\"U\",\"T\"]]00Cf[\"{{{A@b{BAB`}}}{{KGd{BEJjc}}}{}}\",[\"TryFrom::Error\"]]Bm[\"{BAB`{{KGd{BEJjc}}}{}}\",[\"TryFrom::Error\"]]22222222222222222222222Aj[\"{{}{{KGd{c}}}{}}\",[\"U\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cd[\"{{{ABb{{AHO`{CGbc}}}}{AHO`{CGbNIn}}}DAh{}}\",[\"F\"]]000000000Cc[\"{{{AHO`{BCAf}}AJAj{AHO`{ABDl}}}{{KGf{ICj}}}}\",[]]Bk[\"{{{AHO`{BGOl}}B@Mf}{{KGd{ICjAIMd}}}}\",[]]Bk[\"{{{AHO`{BGOn}}B@Mh}{{KGd{ICjAIMf}}}}\",[]]0Bk[\"{{{AHO`{BIAd}}B@Mh}{{KGd{ICjAIMf}}}}\",[]]Ak[\"{{{AHO`{AILb}}}AAO`}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{KI`IF`}}}}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{DAlIF`}}}}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{A@jIF`}}}}\",[]]Bj[\"{{{AHO`{CGbBACd}}}{{KGd{ABCdIF`}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{KIb}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{DAn}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{A@l}}}}\",[]]Bg[\"{{{AHO`{CGbBACd}}}{{KGj{ABCf}}}}\",[]]Aa[\"{AOInBGIj}\",[]]Bd[\"{{{AHO`{AILf}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{CNj}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{IDh}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{NKl}}}{{A@d{AILf}}}}\",[]]Bd[\"{{{AHO`{AILh}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{CNl}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{IDj}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{NKn}}}{{A@d{AILh}}}}\",[]]A`[\"{ABDnCNb}\",[]]An[\"{{{AHO`{CGbAILd}}}AHBb}\",[]]A`[\"{ABE`CNb}\",[]]C`[\"{{{AHO`{CGbB@Mf}}}{{AHO`{CGb{K@j{Oh}}}}}}\",[]]C`[\"{{{AHO`{CGbB@Mh}}}{{AHO`{CGb{K@j{Oh}}}}}}\",[]]Ah[\"{Oh{{KFl{B@N`}}}}\",[]]Ah[\"{Oh{{KFl{B@Nb}}}}\",[]]Ah[\"{Oh{{KFl{B@Nd}}}}\",[]]A`[\"{ABCdDAl}\",[]]A`[\"{ABCfDAn}\",[]]Bi[\"{AIKn{{KGd{{KC`{AILbBD@h}}AIKn}}}}\",[]]Aa[\"{{}c{}}\",[\"I\"]]o[\"{DAlDC`}\",[]]o[\"{DAnDC`}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]21Aj[\"{{{AHO`{ABA`}}}DC`}\",[]]Aj[\"{{{AHO`{ABAb}}}DC`}\",[]]Bn[\"{{{AHO`{CGbBABd}}DC`}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}DC`}{{AHO`{CGbBABh}}}}\",[]]Bm[\"{{{AHO`{NMd}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]Bn[\"{{{AHO`{BACb}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]Bn[\"{{{AHO`{AOMl}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Ak[\"{{{AHO`{AILb}}}ABBf}\",[]]Bo[\"{{{AHO`{AILb}}cAINj}ABBh{{D@b{AHCb}}}}\",[\"\"]]Ce[\"{{{AHO`{CGbAILd}}AHCdAINlNK`}{{KGd{KG`AHEb}}}}\",[]]43Bm[\"{{{AHO`{CGbAILd}}KG`}{{KGd{ICjAIKj}}}}\",[]]E`[\"{{{ABb{{AHO`{CGbBGId}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbBEFd}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbAINh}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbBGAb}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbAIOd}}}}{AHO`{CGbNIn}}{AHO`{CGbNLn}}}{{DAh{{KGf{ICj}}}}}}\",[]]Ef[\"{{{ABb{{AHO`{CGbAIOd}}}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{Oh}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]Ec[\"{{{AHO`{CGbAIOd}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{Oh}}}}}{{DAh{{KGd{KCbAHFb}}}}}}\",[]]Fg[\"{{{AHO`{CGbBBLb}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{AIMh}}}}{AHO`{CGb{K@j{ABC`}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]Dn[\"{{{ABb{{AHO`{CGbAHFj}}}}{AHO`{ABDl}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]>=Ce[\"{{{AHO`{CGbBBMj}}{A@b{NJj}}}{{AHO`{CGbBBMj}}}}\",[]]Ce[\"{{{AHO`{CGbBBMl}}{A@b{NJl}}}{{AHO`{CGbBBMl}}}}\",[]]Cj[\"{{{AHO`{BABf}}CN`B@Mf{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BEJh}}CN`B@Mf{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BABj}}CN`B@Mh{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BEJj}}CN`B@Mh{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BHKf}}CN`B@Md{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Bb[\"{KCb{{KC`{KCb{KFl{KCb}}}}}}\",[]]000Aj[\"{{{AHO`{AILb}}}KCb}\",[]]A`[\"{AHO`KHl}\",[]]0000000000000000000000000000000000000000000000000000000000000000000Cf[\"{{{AHO`{CGbBABd}}{A@b{BFC`}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{BFCb}}}{{AHO`{CGbBABh}}}}\",[]]A`[\"{BHEbIGf}\",[]]A`[\"{BABdA@b}\",[]]A`[\"{BABhA@b}\",[]]Aj[\"{{{AHO`{AB@h}}}ICj}\",[]]Ck[\"{{{AHO`{CGbAJ@`}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAJAl}}}}\",[]]n[\"{{}KCb}\",[]]Ak[\"{{{AHO`{AILb}}}AH@h}\",[]]Ba[\"{{{AHO`{CGbABDn}}ABDn}ICj}\",[]]Ba[\"{{{AHO`{CGbAILn}}AILn}ICj}\",[]]Ba[\"{{{AHO`{CGbBCMh}}AHEl}ICj}\",[]]Ba[\"{{{AHO`{CGbABE`}}ABE`}ICj}\",[]]Ba[\"{{{AHO`{CGbAIM`}}AIM`}ICj}\",[]]Ba[\"{{{AHO`{CGbBCMj}}AHEn}ICj}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}DC`}{{AHO`{CGbBD@`}}}}\",[]]Bi[\"{{{AHO`{CGb}}}{{AHO`{CGbc}}}{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bg[\"{{{AHO`{AIOd}}}{{KGd{CNbB@Ld}}}}\",[]]Bg[\"{{{AHO`{AIOf}}}{{KGd{CNbB@Ll}}}}\",[]]Bc[\"{{AHO`{AHO`{CGbc}}}ICj{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cc[\"{{{AHO`{CGbAILd}}NK`KG`KIb}{{KGd{ICjBBLh}}}}\",[]]A`[\"{AHAlDC`}\",[]]B`[\"{{AHO`{AHO`{c}}}DC`{}}\",[\"K\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Aa[\"{BCLjBFL`}\",[]]A`[\"{BEFhKI`}\",[]]Aa[\"{BCLnBFLb}\",[]]A`[\"{BEFlKIb}\",[]]A`[\"{BFB`KIb}\",[]]A`[\"{BCO`KIb}\",[]]o[\"{NMjKIb}\",[]]Aa[\"{BCLjAIMj}\",[]]Aa[\"{BCLnAIMl}\",[]]o[\"{KI`CNb}\",[]]o[\"{KIbCNb}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Aj[\"{{{AHO`{BAOd}}}DC`}\",[]]Bd[\"{{{AHO`{BBLb}}}{{KGf{AJ@f}}}}\",[]]Bd[\"{{{AHO`{AB@h}}}{{KGf{AJ@f}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{BCMhCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BCMjCNb}\",[]]Cc[\"{{{AHO`{BCNb}}{AHO`{AIOn}}CNb}{{A@b{AONh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}DC`}{{AHO`{CGbBD@`}}}}\",[]]Bg[\"{{{AHO`{AILb}}KFn}{{KFl{AHEl}}}}\",[]]o[\"{KEdABh}\",[]]A`[\"{AHBfA@d}\",[]]Bj[\"{{{AHO`{CGbAILd}}KG`}{{KFl{AHEn}}}}\",[]]A`[\"{AHBhA@d}\",[]]Db[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]00Eg[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}{AHO`{{K@j{Oh}}}}}{{DAh{{KGd{KCbAJAl}}}}}}\",[]]Ec[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}{AHO`{{K@j{Oh}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]0Bm[\"{{{AHO`{IHl}}{AHO`{D@n}}}{{KGf{ICj}}}}\",[]]Cd[\"{{{AHO`{CGbAIOd}}KCb}{{KGd{{KFl{ICn}}AHFb}}}}\",[]]Cd[\"{{{AHO`{CGbBGBb}}KCb}{{KGd{{KFl{ID`}}AHFb}}}}\",[]]Cn[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{Oh}}}}}{{KGd{ICjBC@h}}}}\",[]]Bk[\"{{{AHO`{DA`}}AINj}{{KGd{AINjBFKf}}}}\",[]]Bn[\"{{{AHO`{CGbAINn}}NK`}{{AHO`{CGbAINn}}}}\",[]]Bn[\"{{{AHO`{CGbAIO`}}NK`}{{AHO`{CGbAIO`}}}}\",[]]A`[\"{BC@nAG`}\",[]]o[\"{IHjCNb}\",[]]o[\"{{}AJ@f}\",[]]0o[\"{{}AHO`}\",[]]Bk[\"{{ABA`{A@b{BABd}}}{{KGd{AIKnBCM`}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bh[\"{{{AHO`{AHAl}}AJ@f}{{KGh{AHFl}}}}\",[]]A`[\"{AHElCMn}\",[]]Aj[\"{{{AHO`{AILd}}}CMn}\",[]]A`[\"{AHEnCMn}\",[]]Ce[\"{{{AHO`{CGbAINn}}{KFl{KHl}}}{{AHO`{CGbAINn}}}}\",[]]Ce[\"{{{AHO`{CGbAIO`}}{KFl{KHl}}}{{AHO`{CGbAIO`}}}}\",[]]Aa[\"{ABDhAJ@f}\",[]]Aa[\"{ABDjAJ@f}\",[]]Aa[\"{ABDlAJ@f}\",[]]Aa[\"{AJ@fAHCb}\",[]]Aa[\"{AJ@fAHCd}\",[]]o[\"{AAjCMn}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CMn}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}CMn}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{AHAlCMn}\",[]]Bo[\"{{{AHO`{CGbBCOn}}AB@d}{{AHO`{CGbBCOn}}}}\",[]]Bo[\"{{{AHO`{CGbBD@`}}AB@d}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{AHAlKFl}\",[]]k[\"{{}}\",[]]0000000000Bh[\"{ABA`c{}}\",[\"IntoFuture::IntoFuture\"]]11Aj[\"{{{AHO`{BAOd}}}DC`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]o[\"{AAjKCb}\",[]]Ao[\"{{AHO`c}{{NKf{c}}}{}}\",[\"S\"]]0C`[\"{{{AHO`{CGbAILf}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bo[\"{{{AHO`{CGbCNj}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]C`[\"{{{AHO`{CGbAILh}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bo[\"{{{AHO`{CGbCNl}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bk[\"{{{AHO`{CGbIHl}}NK`{AHO`{BCNb}}}ICj}\",[]]A`[\"{BFBlKFl}\",[]]A`[\"{BFBnKFl}\",[]]Bn[\"{{{AHO`{KI`}}{AHO`{KI`}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KFn}}{AHO`{KFn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AOL`}}{AHO`{AOL`}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{B@Mf}}{AHO`{B@Mf}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{DAl}}{AHO`{DAl}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{A@j}}{AHO`{A@j}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{ABCd}}{AHO`{ABCd}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KIb}}{AHO`{KIb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BFDh}}{AHO`{BFDh}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KG`}}{AHO`{KG`}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AHFd}}{AHO`{AHFd}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BBBl}}{AHO`{BBBl}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AJAn}}{AHO`{AJAn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AOLb}}{AHO`{AOLb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BEGd}}{AHO`{BEGd}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BFCn}}{AHO`{BFCn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{B@Mh}}{AHO`{B@Mh}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{DAn}}{AHO`{DAn}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{A@l}}{AHO`{A@l}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{ABCf}}{AHO`{ABCf}}}{{KFl{ABBj}}}}\",[]]Ak[\"{{{AHO`{AILb}}}AINh}\",[]]Bk[\"{{{AHO`{AILd}}KG`}{{KGd{AINlAIKj}}}}\",[]]Cc[\"{{{AHO`{CGbAIOd}}KCb}{{KGd{{ABh{Oh}}BC@j}}}}\",[]]Bb[\"{{{AHO`{CGbAILd}}ABCf}AIOf}\",[]]Aj[\"{{{AHO`{AHCl}}}KCb}\",[]]Aj[\"{{{AHO`{AHCn}}}KCb}\",[]]Bb[\"{{{AHO`{CGbAILd}}ABCf}AJ@b}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CNb}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}CNb}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{AHAlKFl}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]]Cf[\"{{{AHO`{CGbBABd}}{A@b{AJ@n}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{AJA`}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kh}}{A@b{AJAf}}}{{AHO`{CGbB@Kh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kl}}{A@b{AJAh}}}{{AHO`{CGbB@Kl}}}}\",[]]o[\"{AAjCNb}\",[]]Bn[\"{{{AHO`{CGbBFIh}}CMn}{{AHO`{CGbBFIh}}}}\",[]]Bn[\"{{{AHO`{CGbBFIj}}CMn}{{AHO`{CGbBFIj}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BGJb}\",[]]Aj[\"{{{AHO`{DA`}}}BCAh}\",[]]Aj[\"{{{A@b{BABf}}}BABd}\",[]]Aj[\"{{{A@b{BABj}}}BABh}\",[]]Aj[\"{{BCNlc}BCNlABCn}\",[\"\"]]Aj[\"{{BCNnc}BCNnABCn}\",[\"\"]]Bm[\"{{{AHO`{CGbAJ@`}}ICn}{{KGd{ICjAJAl}}}}\",[]]n[\"{{}KFb}\",[]]o[\"{NIlNIl}\",[]]0000Bd[\"{{{AHO`{BGOl}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BGOn}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BIAd}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BIAn}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{AILb}}}{{KFl{BCM`}}}}\",[]]Ck[\"{{{AHO`{AB@h}}B@KhAJ@f{AHO`{CMl}}}{{KGd{AIKnB@M`}}}}\",[]]Ak[\"{{{AHO`{BAAl}}}AB@d}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]An[\"{{AIObDC`}{{KGh{KCb}}}}\",[]]Cl[\"{{{AHO`{NMf}}}{{KFl{{KC`{{A@d{AHCl}}{A@d{AHDj}}}}}}}}\",[]]Cm[\"{{{AHO`{AJAb}}}{{KFl{{KC`{{A@d{AHCl}}{A@d{AHDj}}}}}}}}\",[]]Cl[\"{{{AHO`{NMh}}}{{KFl{{KC`{{A@d{AHCn}}{A@d{AHDl}}}}}}}}\",[]]Cm[\"{{{AHO`{AJAd}}}{{KFl{{KC`{{A@d{AHCn}}{A@d{AHDl}}}}}}}}\",[]]A`[\"{BGH`ABh}\",[]]A`[\"{BIEdABh}\",[]]A`[\"{BGHbABh}\",[]]A`[\"{BIEfABh}\",[]]An[\"{{{AHO`{CGbBGOl}}}B@Mf}\",[]]An[\"{{{AHO`{CGbBGOn}}}B@Mh}\",[]]An[\"{{{AHO`{CGbBIAd}}}B@Mh}\",[]]An[\"{{{AHO`{CGbBIAn}}}B@Mh}\",[]]Ak[\"{{{AHO`{BCAf}}}B@Oj}\",[]]Ba[\"{{{AHO`{CGbAILd}}BCMf}ICj}\",[]]Bo[\"{{{AHO`{CGbAB@j}}BEGdBAOd}{{KFl{BCMf}}}}\",[]]B`[\"{{{AHO`{NMf}}B@MfDAl}D@d}\",[]]Bn[\"{{{AHO`{BABf}}CN`B@Mf}{{KGd{D@dBFLh}}}}\",[]]Ba[\"{{{AHO`{AJAb}}B@MfDAl}D@d}\",[]]Bn[\"{{{AHO`{BEJh}}CN`B@Mf}{{KGd{D@dBFLh}}}}\",[]]B`[\"{{{AHO`{NMh}}B@MhDAn}D@f}\",[]]Bn[\"{{{AHO`{BABj}}CN`B@Mh}{{KGd{D@fBFLn}}}}\",[]]Ba[\"{{{AHO`{AJAd}}B@MhDAn}D@f}\",[]]Bn[\"{{{AHO`{BEJj}}CN`B@Mh}{{KGd{D@fBFLn}}}}\",[]]Bn[\"{{{AHO`{BHKf}}CN`B@Md}{{KGd{D@fBFLn}}}}\",[]]Aj[\"{{}{{NM`{c}}}{}}\",[\"T\"]]0A`[\"{AHElCNb}\",[]]A`[\"{BCMhCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BCMjCNb}\",[]]Bn[\"{{{AHO`{CGbBABd}}KCb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}KCb}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{BBLb}}}DC`}\",[]]0Aj[\"{{{AHO`{BCAf}}}DC`}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AHCbAIKd}}}}\",[]]Bk[\"{{{AHO`{AILd}}KG`}{{KGd{AHCdAIKj}}}}\",[]]Cc[\"{{{AHO`{BCNb}}{AHO`{AIOb}}CNb}{{A@b{AONh}}}}\",[]]Ak[\"{{{AHO`{ABA`}}}B@Mf}\",[]]Ak[\"{{{AHO`{ABAb}}}B@Mh}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bf[\"{{{AHO`{CGbAILd}}}{{KFl{NK`}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{A@b{AOLn}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBD@`}}{A@b{AOM`}}}{{AHO`{CGbBD@`}}}}\",[]]43A`[\"{AAjAOMf}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABDlKFl}\",[]]A`[\"{BFBlKFl}\",[]]A`[\"{BFBnKFl}\",[]]Ai[\"{{{AHO`{NNf}}}KCb}\",[]]Bo[\"{{{AHO`{CGbBIAd}}AB@d}{{AHO`{CGbBIAd}}}}\",[]]Bo[\"{{{AHO`{CGbBIAn}}AB@d}{{AHO`{CGbBIAn}}}}\",[]]Bj[\"{{{AHO`{AJ@`}}CEl}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAJ@b}}CEl}{{KGd{ICjB@Ll}}}}\",[]]?>A`[\"{IHjAONf}\",[]]A`[\"{AOJ`IHj}\",[]]Bj[\"{{{A@b{B@Kd}}IHn}{{KGd{BEJdBGI`}}}}\",[]]Bj[\"{{{A@b{BAB`}}IHn}{{KGd{BEJhBGI`}}}}\",[]]Bj[\"{{{A@b{B@Kd}}IHn}{{KGd{BEJfBGIb}}}}\",[]]Bj[\"{{{A@b{BAB`}}IHn}{{KGd{BEJjBGIb}}}}\",[]]Dj[\"{{{AHO`{CGbAJ@b}}{AHO`{CGb{AHO`{CGb{K@j{ICn}}}}}}}{{KGd{KCbAJAn}}}}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{AHAlDC`}\",[]]Bg[\"{{{AHO`{AILb}}}{{KGd{ICjBCM`}}}}\",[]]Cd[\"{{{AHO`{CGbBBMj}}{A@b{A`}}}{{AHO`{CGbBBMj}}}}\",[]]Cd[\"{{{AHO`{CGbBBMl}}{A@b{A`}}}{{AHO`{CGbBBMl}}}}\",[]]Bk[\"{{{AHO`{BBLb}}}{{ABb{{A@d{AHFj}}}}}}\",[]]o[\"{AAjCNb}\",[]]Aa[\"{AONfAHD`}\",[]]87Aa[\"{AIOjABA`}\",[]]Aa[\"{AIOlABAb}\",[]]Cf[\"{{{AHO`{CGbBFGj}}{KFl{AB@d}}}{{AHO`{CGbBFGj}}}}\",[]]Cf[\"{{{AHO`{CGbBFGl}}{KFl{AB@d}}}{{AHO`{CGbBFGl}}}}\",[]]:<;An[\"{{{AHO`{AONh}}AB@d}ICj}\",[]]B`[\"{{{AHO`{CGbAILf}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbCNj}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbIDh}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbNKl}}CMn}ICj}\",[]]B`[\"{{{AHO`{CGbAILh}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbCNl}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbIDj}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbNKn}}CMn}ICj}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Bj[\"{{{AHO`{AILb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMf}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMh}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAd}}}{{KFl{{A@d{A@`}}}}}}\",[]]Db[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]Db[\"{{{AHO`{CGbAILd}}NK`B@Oj{AHO`{CGb{ABh{Oh}}}}}{{KFl{ABDj}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{AHO`{CMl}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBD@`}}{AHO`{CMl}}}{{AHO`{CGbBD@`}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BAA`}\",[]]Bj[\"{{{AHO`{AILb}}ICn}{{KGd{ICjBFDf}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}DC`}{{AHO`{CGbBD@`}}}}\",[]]Ai[\"{{{AHO`{NJj}}}KCb}\",[]]Ai[\"{{{AHO`{NJl}}}KCb}\",[]]Dh[\"{{{AHO`{B@Kj}}CN`{AHO`{CMl}}{AHO`{BGB`}}}{{KGd{{A@d{NMf}}B@M`}}}}\",[]]Cb[\"{{{AHO`{BABf}}CN`{AHO`{BGB`}}}{{A@d{NMf}}}}\",[]]Dh[\"{{{AHO`{BEJd}}CN`{AHO`{CMl}}{AHO`{BGB`}}}{{KGd{{A@d{NMf}}B@M`}}}}\",[]]Cb[\"{{{AHO`{BEJh}}CN`{AHO`{BGB`}}}{{A@d{NMf}}}}\",[]]Dh[\"{{{AHO`{B@Kn}}CN`{AHO`{CMl}}{AHO`{BGB`}}}{{KGd{{A@d{NMh}}B@Mb}}}}\",[]]Cb[\"{{{AHO`{BABj}}CN`{AHO`{BGB`}}}{{A@d{NMh}}}}\",[]]Dh[\"{{{AHO`{BEJf}}CN`{AHO`{CMl}}{AHO`{BGB`}}}{{KGd{{A@d{NMh}}B@Mb}}}}\",[]]Cb[\"{{{AHO`{BEJj}}CN`{AHO`{BGB`}}}{{A@d{NMh}}}}\",[]]Dh[\"{{{AHO`{BHKd}}CN`{AHO`{CMl}}{AHO`{BGB`}}}{{KGd{{A@d{NMh}}B@Ln}}}}\",[]]Cb[\"{{{AHO`{BHKf}}CN`{AHO`{BGB`}}}{{A@d{NMh}}}}\",[]]Dd[\"{{{ABb{{AHO`{CGbc}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{KGd}}}}}{}}\",[\"S\"]]0Bn[\"{{AJ@fBBLdAAj}{{KGh{{KC`{AB@fAIL`}}}}}}\",[]]Bd[\"{{{AHO`{AILd}}}{{AHO`{NMh}}}}\",[]]A`[\"{AOJ`IHj}\",[]]Cb[\"{{{AHO`{AOLn}}DAlAJ@fB@MfNK`}{{KFl{AINn}}}}\",[]]Cb[\"{{{AHO`{BCNl}}DAlAJ@fB@MfNK`}{{KFl{AINn}}}}\",[]]Cb[\"{{{AHO`{AOM`}}DAnAJ@fB@MhNK`}{{KFl{AIO`}}}}\",[]]Cb[\"{{{AHO`{BCNn}}DAnAJ@fB@MhNK`}{{KFl{AIO`}}}}\",[]]B`[\"{{{AHO`{CGbAILd}}NK`}ICj}\",[]]Ca[\"{{{AHO`{CGbAIKn}}}{{KGd{{A@d{A@`}}BCM`}}}}\",[]]Bj[\"{{{AHO`{AILb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMf}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMh}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAd}}}{{KFl{{A@d{A@`}}}}}}\",[]]o[\"{AILnOh}\",[]]o[\"{AIM`Oh}\",[]]Ai[\"{{{AHO`{CMl}}}DC`}\",[]]Aj[\"{{{AHO`{AILf}}}CNb}\",[]]Ai[\"{{{AHO`{CNj}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAIJl}}CNb}{{AHO`{CGbAIJl}}}}\",[]]Ai[\"{{{AHO`{IDh}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAOJn}}CNb}{{AHO`{CGbAOJn}}}}\",[]]Ai[\"{{{AHO`{NKl}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAl}}CNb}{{AHO`{CGbBBAl}}}}\",[]]Aj[\"{{{AHO`{AILh}}}CNb}\",[]]Ai[\"{{{AHO`{CNl}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAIJn}}CNb}{{AHO`{CGbAIJn}}}}\",[]]Ai[\"{{{AHO`{IDj}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAOK`}}CNb}{{AHO`{CGbAOK`}}}}\",[]]Ai[\"{{{AHO`{NKn}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAn}}CNb}{{AHO`{CGbBBAn}}}}\",[]]Aa[\"{AIOdBGBb}\",[]]Ai[\"{{{AHO`{NMf}}}DC`}\",[]]Aj[\"{{{AHO`{AJAb}}}DC`}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Ai[\"{{{AHO`{NMh}}}DC`}\",[]]Aj[\"{{{AHO`{AJAd}}}DC`}\",[]]Co[\"{{{AHO`{NMf}}B@Mf{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]D`[\"{{{AHO`{AJAb}}B@Mf{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]Co[\"{{{AHO`{NMh}}B@Mh{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]D`[\"{{{AHO`{AJAd}}B@Mh{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]Bn[\"{{{AHO`{CGbBFIh}}CMn}{{AHO`{CGbBFIh}}}}\",[]]Bn[\"{{{AHO`{CGbBFIj}}CMn}{{AHO`{CGbBFIj}}}}\",[]]Cd[\"{{{AHO`{CGbNMf}}}{{KFl{{NKb{{A@d{AHDj}}}}}}}}\",[]]Ce[\"{{{AHO`{CGbAJAb}}}{{KFl{{NKb{{A@d{AHDj}}}}}}}}\",[]]Cd[\"{{{AHO`{CGbNMh}}}{{KFl{{NKd{{A@d{AHDl}}}}}}}}\",[]]Ce[\"{{{AHO`{CGbAJAd}}}{{KFl{{NKd{{A@d{AHDl}}}}}}}}\",[]]Bf[\"{{{AHO`{CGbAILf}}CMnCNbNK`}ICj}\",[]]Be[\"{{{AHO`{CGbCNj}}CMnCNbNK`}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}CMnCNbNK`}ICj}\",[]]Be[\"{{{AHO`{CGbCNl}}CMnCNbNK`}ICj}\",[]]Bf[\"{{{AHO`{CGbAILf}}NK`CMnCNb}ICj}\",[]]Be[\"{{{AHO`{CGbCNj}}NK`CMnCNb}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}NK`CMnCNb}ICj}\",[]]Be[\"{{{AHO`{CGbCNl}}NK`CMnCNb}ICj}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]De[\"{{{AHO`{CGbBCOn}}c{AHO`{CMl}}}{{AHO`{CGbBCOn}}}{{ICl{D@n}}}}\",[\"\"]]De[\"{{{AHO`{CGbBD@`}}c{AHO`{CMl}}}{{AHO`{CGbBD@`}}}{{ICl{D@n}}}}\",[\"\"]]Ci[\"{{{AHO`{CGbNMf}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`IEl}}}}\",[]]Cj[\"{{{AHO`{CGbAJAb}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`IEl}}}}\",[]]Cj[\"{{{AHO`{CGbNMh}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`BCAd}}}}\",[]]Ck[\"{{{AHO`{CGbAJAd}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`BCAd}}}}\",[]]o[\"{AAjDC`}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KI`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}KIb}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{AHAlKFl}\",[]]Ca[\"{{{AHO`{CGbAIOd}}}{{KGd{{KFl{KI`}}AIOh}}}}\",[]]Ca[\"{{{AHO`{CGbBGBb}}}{{KGd{{KFl{KI`}}AIOh}}}}\",[]]Ca[\"{{{AHO`{CGbAIOf}}}{{KGd{{KFl{KIb}}B@Ll}}}}\",[]]Ak[\"{{{AHO`{AIKn}}}AJ@f}\",[]]Ak[\"{{{AHO`{ABA`}}}AJ@f}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AJ@fAIKd}}}}\",[]]Ak[\"{{{AHO`{ABAb}}}AJ@f}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]B`[\"{{KI`c}KI`{{D@b{KI`}}}}\",[\"\"]]B`[\"{{KFnc}KFn{{D@b{KFn}}}}\",[\"\"]]B`[\"{{KIbc}KIb{{D@b{KIb}}}}\",[\"\"]]B`[\"{{KG`c}KG`{{D@b{KG`}}}}\",[\"\"]]20Ae[\"{{AB@dCNb}AG`}\",[]]Bn[\"{{{AHO`{CGbBCOn}}AFn}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}AFn}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{IHjAB@d}\",[]]B`[\"{{}{{AHO`{{K@j{BGA`}}}}}}\",[]]An[\"{{AHO`{ONf{CGbOh}}}ICj}\",[]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000An[\"{{}{{KFl{{A@b{NMd}}}}}}\",[]]Bn[\"{{{AHO`{CGbBBMj}}DC`}{{AHO`{CGbBBMj}}}}\",[]]Bn[\"{{{AHO`{CGbBBMl}}DC`}{{AHO`{CGbBBMl}}}}\",[]]Aj[\"{{{AHO`{AHDj}}}CNb}\",[]]Aj[\"{{{AHO`{AHDl}}}CNb}\",[]]A`[\"{ABC`KFl}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Bf[\"{{{AHO`{CMl}}}{{KGh{CNbBBB`}}}}\",[]]Bn[\"{{{AHO`{AB@h}}{A@d{BBLb}}}{{KGf{ICj}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Cj[\"{{{AHO`{NMb}}BBLdBBBj{AHO`{AAj}}}{{KC`{AJ@fAB@f}}}}\",[]]Cb[\"{{{AHO`{CGbAILd}}KG`AINl}{{KGd{AINlBFKh}}}}\",[]]Am[\"{{{AHO`{AILb}}CNb}ICj}\",[]]B`[\"{{{AHO`{CGbAILd}}CNb}ICj}\",[]]A`[\"{BC@lDC`}\",[]]B`[\"{{{AHO`{CGbIHj}}BC@n}ICj}\",[]]Aa[\"{AONfAHD`}\",[]]Bn[\"{{{AHO`{NMd}}AHFl}{{KGf{{A@d{BBLb}}}}}}\",[]]Bo[\"{{{AHO`{BACb}}AHFl}{{KGf{{A@d{BBLb}}}}}}\",[]]Bo[\"{{{AHO`{AOMl}}AHFl}{{KGf{{A@d{BBLb}}}}}}\",[]]Ci[\"{{{AHO`{CGbNMf}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@d}}}}\",[]]Cj[\"{{{AHO`{CGbAJAb}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@d}}}}\",[]]Ci[\"{{{AHO`{CGbNMh}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@f}}}}\",[]]Cj[\"{{{AHO`{CGbAJAd}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@f}}}}\",[]]Cb[\"{{{AHO`{ABD`}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{BANd}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{B@Ol}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{ABDb}}IChAJ@lAB@d}{{KGd{ICjBCOj}}}}\",[]]Cb[\"{{{AHO`{BANf}}IChAJ@lAB@d}{{KGd{ICjBCOj}}}}\",[]]Cb[\"{{{AHO`{B@On}}IChAJ@lAB@d}{{KGd{ICjBCOj}}}}\",[]]Al[\"{{}{{KGd{B@KfBGIb}}}}\",[]]Bn[\"{{{AHO`{AILb}}KFn}{{KFl{{A@d{AILf}}}}}}\",[]]Bo[\"{{{AHO`{AILd}}KG`}{{KFl{{AHO`{AILh}}}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aj[\"{{{AHO`{AILb}}}ICj}\",[]]Am[\"{{{AHO`{CGbAILd}}}ICj}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAjIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{A@hIEn}}}}\",[]]Bg[\"{{{AHO`{AIJb}}}{{KGd{AAOfIEn}}}}\",[]]Bg[\"{{{AHO`{AIJb}}}{{KGd{AHAlIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAlIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAnIEn}}}}\",[]]Ak[\"{{{AHO`{BCAf}}}B@Oj}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AOL`}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBD@`}}{KFl{AOLb}}}{{AHO`{CGbBD@`}}}}\",[]]<;Aj[\"{{{AHO`{AB@h}}}KCb}\",[]]Aj[\"{{{AHO`{AB@j}}}KCb}\",[]]Bo[\"{{{AHO`{AILb}}cAINj}ABBh{{D@b{AHCb}}}}\",[\"\"]]Co[\"{{{AHO`{CGbAILd}}AHCdAINlNK`}{{KGd{{KC`{KG`DC`}}AHEb}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CN`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}CN`}{{AHO`{CGbBD@`}}}}\",[]]Df[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{ICn}}}}}{{KGd{{KFl{KCb}}AHFb}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Bg[\"{{{AHO`{BCAf}}AJAj}{{KGf{KCb}}}}\",[]]A`[\"{AHAlCNb}\",[]]10Aj[\"{{{AHO`{AAj}}}BCOl}\",[]]Cf[\"{{{AHO`{CGbBABd}}{A@b{BCOn}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kh}}{A@b{BCOn}}}{{AHO`{CGbB@Kh}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{BD@`}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kl}}{A@b{BD@`}}}{{AHO`{CGbB@Kl}}}}\",[]]Aa[\"{BABdBH@n}\",[]]Aa[\"{BABhBHA`}\",[]]Bj[\"{{{ABh{BBLd}}BBBj}{{KGd{BABdIFb}}}}\",[]]Bj[\"{{{ABh{BBLd}}BBBj}{{KGd{BABhIFd}}}}\",[]]Co[\"{{{AHO`{CGbAJ@`}}{AHO`{CGb{K@j{ICn}}}}}{{KGd{ICjAJAl}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BFBlCNb}\",[]]A`[\"{BFBnCNb}\",[]]Bc[\"{{{AHO`{AILb}}}{{KFl{KCb}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Aj[\"{{{AHO`{AHBb}}}KCb}\",[]]Be[\"{{{AHO`{AB@h}}{KFl{BABd}}}ICj}\",[]]Bo[\"{{{AHO`{CGbAB@j}}{KFl{{A@b{BABh}}}}}ICj}\",[]]Bd[\"{{{AHO`{BGA`}}}{{KFl{BBBh}}}}\",[]]Aj[\"{{{AHO`{AB@h}}}ICj}\",[]]Dj[\"{{{AHO`{CGbAJ@`}}{AHO`{CGb{AHO`{CGb{K@j{ICn}}}}}}}{{KGd{KCbAJAl}}}}\",[]]o[\"{{}AHO`}\",[]]n[\"{{}NIl}\",[]]0000Bn[\"{{{AHO`{CGbBCOn}}KCb}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}KCb}{{AHO`{CGbBD@`}}}}\",[]]o[\"{CNbKI`}\",[]]o[\"{CNbKIb}\",[]]A`[\"{BAOfCNb}\",[]]Bf[\"{{{AHO`{BGJb}}{AHO`{BGJb}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBBMj}}AB@d}{{AHO`{CGbBBMj}}}}\",[]]Bo[\"{{{AHO`{CGbBBMl}}AB@d}{{AHO`{CGbBBMl}}}}\",[]]Ae[\"{{KCbCNb}BANd}\",[]]Ae[\"{{KCbCNb}BANf}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]7Bg[\"{{{AHO`{AILd}}KG`}{{KFl{AINl}}}}\",[]]An[\"{{{AHO`{AILb}}ICn}BAAn}\",[]]Bm[\"{{{AHO`{CGbBEJd}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJh}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJf}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJj}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Am[\"{{{AHO`{AILb}}KI`}ICj}\",[]]B`[\"{{{AHO`{CGbAILd}}KIb}ICj}\",[]]Ce[\"{{{AHO`{CGbBBMj}}{ABh{CN`}}}{{AHO`{CGbBBMj}}}}\",[]]Ce[\"{{{AHO`{CGbBBMl}}{ABh{CN`}}}{{AHO`{CGbBBMl}}}}\",[]]Fg[\"{{{AHO`{BHEd}}{AHO`{BBLd}}{AHO`{{K@j{BBLd}}}}{AHO`{AJ@d}}{AHO`{{K@j{Oh}}}}ABEb}{{KGd{BFKbIEh}}}}\",[]]Af[\"{{BCNlNK`}BCNl}\",[]]Af[\"{{BCNnNK`}BCNn}\",[]]A`[\"{BAOfCNb}\",[]]Al[\"{BACd{{KGd{DAlIF`}}}}\",[]]Al[\"{BACd{{KGd{A@jIF`}}}}\",[]]Ai[\"{BACd{{KGj{DAn}}}}\",[]]Ai[\"{BACd{{KGj{A@l}}}}\",[]]o[\"{NIlNIl}\",[]]Bo[\"{{{AHO`{CGbBFIh}}AB@d}{{AHO`{CGbBFIh}}}}\",[]]Bo[\"{{{AHO`{CGbBFIj}}AB@d}{{AHO`{CGbBFIj}}}}\",[]]Bb[\"{{{AHO`{NMf}}}{{KFl{DC`}}}}\",[]]Bc[\"{{{AHO`{AJAb}}}{{KFl{DC`}}}}\",[]]Bb[\"{{{AHO`{NMh}}}{{KFl{DC`}}}}\",[]]Bc[\"{{{AHO`{AJAd}}}{{KFl{DC`}}}}\",[]]Bg[\"{{{AHO`{AILb}}}{{KGd{ICjBCM`}}}}\",[]]Ba[\"{{{AHO`{BFCh}}KFnAHCb}DC`}\",[]]Ba[\"{{{AHO`{BFCj}}KG`AHCd}DC`}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AB@d}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBD@`}}{KFl{AB@d}}}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Bo[\"{{{AHO`{CGbAILf}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbCNj}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbIDh}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbNKl}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bo[\"{{{AHO`{CGbAILh}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbCNl}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbIDj}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbNKn}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]A`[\"{BAOfCNb}\",[]]Al[\"{{{AHO`{NNf}}A@l}CNb}\",[]]Bi[\"{{{AHO`{CGbAIOn}}CNb}{{KGh{ICj}}}}\",[]]<;A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Cf[\"{{{AHO`{CGbBCOn}}{KFl{BFGj}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBD@`}}{KFl{BFGl}}}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAjIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{A@hIEn}}}}\",[]]Bj[\"{{{AHO`{CGbAIJb}}}{{KGd{AAOfIEn}}}}\",[]]Bj[\"{{{AHO`{CGbAIJb}}}{{KGd{AHAlIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAlIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAnIEn}}}}\",[]]Cd[\"{{{A@b{AIL`}}CNbDC`}{{KGh{{KC`{BC@nBC@n}}}}}}\",[]]Bn[\"{{{AHO`{CGbBABd}}CNb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}CNb}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{AILb}}}DC`}\",[]]Ak[\"{{{AHO`{BBLb}}}B@Oj}\",[]]0Ci[\"{{{AHO`{CGbBBMj}}CMn}{{KGd{{AHO`{CGbBBMj}}AOJd}}}}\",[]]Ci[\"{{{AHO`{CGbBBMl}}CMn}{{KGd{{AHO`{CGbBBMl}}AOJf}}}}\",[]]A`[\"{AHAlCMn}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{BFIh}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBD@`}}{KFl{BFIj}}}{{AHO`{CGbBD@`}}}}\",[]]Bg[\"{{{AHO`{CGbAILd}}}{{KFl{BAOd}}}}\",[]]Cf[\"{{{AHO`{CGbBABd}}{KFl{BABl}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{KFl{BABl}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbBABd}}{KFl{BABn}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{KFl{BABn}}}{{AHO`{CGbBABh}}}}\",[]]Cd[\"{{}{{KGd{{KC`{{ABh{BBLd}}BBBj}}{A@d{IEd}}}}}}\",[]]Bn[\"{{{AHO`{CGbBFGj}}KI`}{{AHO`{CGbBFGj}}}}\",[]]Bn[\"{{{AHO`{CGbBFGl}}KIb}{{AHO`{CGbBFGl}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bo[\"{{{AHO`{CGbBABd}}AB@d}{{AHO`{CGbBABd}}}}\",[]]Bo[\"{{{AHO`{CGbBABh}}AB@d}{{AHO`{CGbBABh}}}}\",[]]Ci[\"{{{AHO`{DA`}}{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKd}}}}\",[]]Bj[\"{{{AHO`{BCAf}}AJAjKCb}{{KGf{ICj}}}}\",[]]054Bm[\"{{{AHO`{NMf}}}{{KGd{{KFl{BGB`}}IEl}}}}\",[]]Bn[\"{{{AHO`{AJAb}}}{{KGd{{KFl{BGB`}}IEl}}}}\",[]]Bn[\"{{{AHO`{NMh}}}{{KGd{{KFl{BGB`}}BCAd}}}}\",[]]Bo[\"{{{AHO`{AJAd}}}{{KGd{{KFl{BGB`}}BCAd}}}}\",[]]Aj[\"{{{AHO`{AHDj}}}CNb}\",[]]Aj[\"{{{AHO`{AHDl}}}CNb}\",[]]Bl[\"{{{AHO`{AB@h}}{KFl{{A@b{BFCh}}}}}ICj}\",[]]Cc[\"{{{AHO`{CGbAILd}}{KFl{{AHO`{BFCj}}}}NK`}ICj}\",[]]Aj[\"{{{AHO`{AB@j}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAl}}AFn}{{AHO`{CGbBBAl}}}}\",[]]Bn[\"{{{AHO`{CGbBBAn}}AFn}{{AHO`{CGbBBAn}}}}\",[]]Ak[\"{{{AHO`{AHFj}}}B@Oj}\",[]]0Ak[\"{{{AHO`{AILb}}}BGAb}\",[]]Cb[\"{{{AHO`{AILd}}KG`}{{KGd{{KFl{AJ@f}}AIKj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KI`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}KIb}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{AHAlKFl}\",[]]Bo[\"{{{AHO`{AHAl}}{AHO`{CMl}}}{{KGf{BCOl}}}}\",[]]Em[\"{{{AHO`{AILb}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]El[\"{{{AHO`{NMf}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]Em[\"{{{AHO`{AJAb}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]El[\"{{{AHO`{NMh}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHMb}}}}\",[]]Em[\"{{{AHO`{AJAd}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHMb}}}}\",[]]Am[\"{{{AHO`{CGbAHB`}}}ICj}\",[]]0Am[\"{{{AHO`{AILd}}A@l}CNb}\",[]]Ak[\"{{{AHO`{AILb}}}BGId}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{BEFdAIKd}}}}\",[]]>=E`[\"{{{AHO`{BHEd}}{AHO`{{K@j{Oh}}}}{AHO`{BBLd}}{AHO`{BH@`}}}{{KGd{BHGjIEh}}}}\",[]]0Bg[\"{{{A@b{BBCb}}}{{KGd{B@KhBGJ`}}}}\",[]]Bg[\"{{{A@b{BBCb}}}{{KGd{B@KlBGJ`}}}}\",[]]Bn[\"{{{AHO`{CGbBFGj}}KI`}{{AHO`{CGbBFGj}}}}\",[]]Bn[\"{{{AHO`{CGbBFGl}}KIb}{{AHO`{CGbBFGl}}}}\",[]]o[\"{NIlNIl}\",[]]0000Aj[\"{{{AHO`{AILd}}}DC`}\",[]]0Bd[\"{{{AHO`{CGbAILf}}CNbAB@d}ICj}\",[]]Bc[\"{{{AHO`{CGbCNj}}CNbAB@d}ICj}\",[]]Bd[\"{{{AHO`{CGbAILh}}CNbAB@d}ICj}\",[]]Bc[\"{{{AHO`{CGbCNl}}CNbAB@d}ICj}\",[]]Ci[\"{{{AHO`{DA`}}{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKd}}}}\",[]]Cd[\"{{{AHO`{CGbAAj}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbA@h}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Ce[\"{{{AHO`{CGbAAOf}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Ce[\"{{{AHO`{CGbAHAl}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbAAl}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbAAn}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Bo[\"{{{AHO`{CGbBABd}}BH@n}{{AHO`{CGbBABd}}}}\",[]]Bo[\"{{{AHO`{CGbBABh}}BHA`}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{BBMj}}}CNb}\",[]]Aj[\"{{{AHO`{BBMl}}}CNb}\",[]]Cd[\"{{{AHO`{CGbB@Kh}}{A@b{A`}}}{{AHO`{CGbB@Kh}}}}\",[]]Cd[\"{{{AHO`{CGbB@Kl}}{A@b{A`}}}{{AHO`{CGbB@Kl}}}}\",[]]Cl[\"{{BBMj{KFl{BABd}}{A@d{BBLb}}{A@b{NMd}}}{{KGf{AB@h}}}}\",[]]Aj[\"{{{AHO`{ABA`}}}DC`}\",[]]Aj[\"{{{AHO`{ABAb}}}DC`}\",[]]Ca[\"{{{AHO`{CGbAILd}}NK`AIMn}{{KGd{ICjBHDl}}}}\",[]]Bd[\"{{{AHO`{BHEd}}}{{ABh{BCOd}}}}\",[]]Bj[\"{{{AHO`{AILb}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bm[\"{{{AHO`{CGbAILd}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KCb}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}KCb}{{AHO`{CGbBD@`}}}}\",[]]Bm[\"{{}{{KGd{{KC`{BBLdBFJd}}{A@d{IEd}}}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]An[\"{{{AHO`{AB@h}}B@Kh}ICj}\",[]]Dc[\"{{{AHO`{CGbAILd}}NK`KG`{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKj}}}}\",[]]o[\"{{}AHO`}\",[]]Aj[\"{{{AHO`{AILb}}}KCb}\",[]]Bn[\"{{{AHO`{CGbBABd}}CNb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}CNb}{{AHO`{CGbBABh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KI`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}KIb}{{AHO`{CGbBD@`}}}}\",[]]:Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}DC`}{{AHO`{CGbBD@`}}}}\",[]]Bc[\"{{{AHO`{CGbAILd}}A@lKIb}ICj}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Ak[\"{{}{{KGd{B@KhIFb}}}}\",[]]Ak[\"{{}{{KGd{B@KlIFd}}}}\",[]]6587Cg[\"{{{AHO`{CGbAAj}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbA@h}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Ch[\"{{{AHO`{CGbAAOf}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Ch[\"{{{AHO`{CGbAHAl}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbAAl}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbAAn}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]n[\"{{}ICj}\",[]]Ce[\"{{{AHO`{CGbBCOn}}{KFl{KCb}}}{{AHO`{CGbBCOn}}}}\",[]]Ce[\"{{{AHO`{CGbBD@`}}{KFl{KCb}}}{{AHO`{CGbBD@`}}}}\",[]]Bn[\"{{{AHO`{AILb}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Cd[\"{{{AHO`{CGbAILd}}NK`}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Am[\"{{{AHO`{CGbAILf}}}ICj}\",[]]Al[\"{{{AHO`{CGbCNj}}}ICj}\",[]]Al[\"{{{AHO`{CGbIDh}}}ICj}\",[]]Am[\"{{{AHO`{CGbAILh}}}ICj}\",[]]Al[\"{{{AHO`{CGbCNl}}}ICj}\",[]]Al[\"{{{AHO`{CGbIDj}}}ICj}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Bj[\"{{{AHO`{AILb}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bm[\"{{{AHO`{CGbAILd}}AJ@f}{{KGd{ICjIFh}}}}\",[]]D`[\"{{{AHO`{CGbAILd}}KG`{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKj}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{A@b{BFBh}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBD@`}}{A@b{BFBj}}}{{AHO`{CGbBD@`}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AB@d}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBD@`}}{KFl{AB@d}}}{{AHO`{CGbBD@`}}}}\",[]]Ce[\"{{{AHO`{CGbBCOn}}{KFl{CNb}}}{{AHO`{CGbBCOn}}}}\",[]]Ce[\"{{{AHO`{CGbBD@`}}{KFl{CNb}}}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]];Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}DC`}{{AHO`{CGbBD@`}}}}\",[]]Am[\"{{{AHO`{AILb}}KI`}ICj}\",[]]o[\"{NIlNIl}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CN`}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{CGbBD@`}}CN`}{{AHO`{CGbBD@`}}}}\",[]]310;:54Bn[\"{{{AHO`{AILb}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Bn[\"{{{AHO`{AILd}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]10Bm[\"{{{AHO`{CGbBCOn}}Oh}{{AHO`{CGbBCOn}}}}\",[]]Bm[\"{{{AHO`{CGbBD@`}}Oh}{{AHO`{CGbBD@`}}}}\",[]]A`[\"{BGB`KFl}\",[]]") \ No newline at end of file diff --git a/pr/720/docs/search.index/function/dc6a9ddb2aa5.js b/pr/720/docs/search.index/function/dc6a9ddb2aa5.js deleted file mode 100644 index ba1babaf0..000000000 --- a/pr/720/docs/search.index/function/dc6a9ddb2aa5.js +++ /dev/null @@ -1 +0,0 @@ -rd_("Bf[\"{{{AHO`{AOIn}}{AHO`{AOIn}}}DC`}\",[]]Bf[\"{{{AHO`{BFDd}}{AHO`{BFDd}}}DC`}\",[]]Bd[\"{{{AHO`{KFd}}{AHO`{KFd}}}DC`}\",[]]Bd[\"{{{AHO`{DA`}}{AHO`{DA`}}}DC`}\",[]]Bf[\"{{{AHO`{BCAf}}{AHO`{BCAf}}}DC`}\",[]]Bf[\"{{{AHO`{BC@h}}{AHO`{BC@h}}}DC`}\",[]]Bf[\"{{{AHO`{AHFb}}{AHO`{AHFb}}}DC`}\",[]]Bf[\"{{{AHO`{AIOh}}{AHO`{AIOh}}}DC`}\",[]]Bf[\"{{{AHO`{BC@f}}{AHO`{BC@f}}}DC`}\",[]]Bf[\"{{{AHO`{AJAl}}{AHO`{AJAl}}}DC`}\",[]]Bf[\"{{{AHO`{BAC`}}{AHO`{BAC`}}}DC`}\",[]]Bd[\"{{{AHO`{KI`}}{AHO`{KI`}}}DC`}\",[]]Bf[\"{{{AHO`{BGIj}}{AHO`{BGIj}}}DC`}\",[]]Bd[\"{{{AHO`{ID`}}{AHO`{ID`}}}DC`}\",[]]Bd[\"{{{AHO`{KFn}}{AHO`{KFn}}}DC`}\",[]]Bf[\"{{{AHO`{AINj}}{AHO`{AINj}}}DC`}\",[]]Bf[\"{{{AHO`{AHEh}}{AHO`{AHEh}}}DC`}\",[]]Bf[\"{{{AHO`{BFKd}}{AHO`{BFKd}}}DC`}\",[]]Bf[\"{{{AHO`{AIKd}}{AHO`{AIKd}}}DC`}\",[]]Bf[\"{{{AHO`{ABDn}}{AHO`{ABDn}}}DC`}\",[]]Bf[\"{{{AHO`{AILn}}{AHO`{AILn}}}DC`}\",[]]Bf[\"{{{AHO`{AHEl}}{AHO`{AHEl}}}DC`}\",[]]Bf[\"{{{AHO`{B@Ld}}{AHO`{B@Ld}}}DC`}\",[]]Bf[\"{{{AHO`{BCLn}}{AHO`{BCLn}}}DC`}\",[]]Bf[\"{{{AHO`{AHE`}}{AHO`{AHE`}}}DC`}\",[]]Bf[\"{{{AHO`{BBLd}}{AHO`{BBLd}}}DC`}\",[]]Bf[\"{{{AHO`{AOL`}}{AHO`{AOL`}}}DC`}\",[]]Bf[\"{{{AHO`{AOJd}}{AHO`{AOJd}}}DC`}\",[]]Bf[\"{{{AHO`{AHCf}}{AHO`{AHCf}}}DC`}\",[]]Bf[\"{{{AHO`{BCLh}}{AHO`{BCLh}}}DC`}\",[]]Bf[\"{{{AHO`{BEFf}}{AHO`{BEFf}}}DC`}\",[]]Bf[\"{{{AHO`{B@M`}}{AHO`{B@M`}}}DC`}\",[]]Bf[\"{{{AHO`{B@Mf}}{AHO`{B@Mf}}}DC`}\",[]]Bf[\"{{{AHO`{B@N`}}{AHO`{B@N`}}}DC`}\",[]]Bf[\"{{{AHO`{BFKn}}{AHO`{BFKn}}}DC`}\",[]]Bd[\"{{{AHO`{DAl}}{AHO`{DAl}}}DC`}\",[]]Bd[\"{{{AHO`{A@j}}{AHO`{A@j}}}DC`}\",[]]Bf[\"{{{AHO`{ABCd}}{AHO`{ABCd}}}DC`}\",[]]Bf[\"{{{AHO`{AHCb}}{AHO`{AHCb}}}DC`}\",[]]Bf[\"{{{AHO`{BHLn}}{AHO`{BHLn}}}DC`}\",[]]Bd[\"{{{AHO`{IFb}}{AHO`{IFb}}}DC`}\",[]]Bd[\"{{{AHO`{KIb}}{AHO`{KIb}}}DC`}\",[]]Bf[\"{{{AHO`{BGIl}}{AHO`{BGIl}}}DC`}\",[]]Bd[\"{{{AHO`{IDb}}{AHO`{IDb}}}DC`}\",[]]Bf[\"{{{AHO`{BFDf}}{AHO`{BFDf}}}DC`}\",[]]Bd[\"{{{AHO`{KG`}}{AHO`{KG`}}}DC`}\",[]]Bf[\"{{{AHO`{AINl}}{AHO`{AINl}}}DC`}\",[]]Bf[\"{{{AHO`{AHEj}}{AHO`{AHEj}}}DC`}\",[]]Bf[\"{{{AHO`{BFDb}}{AHO`{BFDb}}}DC`}\",[]]Bf[\"{{{AHO`{BFKf}}{AHO`{BFKf}}}DC`}\",[]]Bf[\"{{{AHO`{AIKj}}{AHO`{AIKj}}}DC`}\",[]]Bf[\"{{{AHO`{ABE`}}{AHO`{ABE`}}}DC`}\",[]]Bf[\"{{{AHO`{AIM`}}{AHO`{AIM`}}}DC`}\",[]]Bf[\"{{{AHO`{AHEn}}{AHO`{AHEn}}}DC`}\",[]]Bf[\"{{{AHO`{AHFd}}{AHO`{AHFd}}}DC`}\",[]]Bf[\"{{{AHO`{BBBl}}{AHO`{BBBl}}}DC`}\",[]]Bf[\"{{{AHO`{AJAn}}{AHO`{AJAn}}}DC`}\",[]]Bf[\"{{{AHO`{AOKn}}{AHO`{AOKn}}}DC`}\",[]]Bf[\"{{{AHO`{AONd}}{AHO`{AONd}}}DC`}\",[]]Bf[\"{{{AHO`{BC@j}}{AHO`{BC@j}}}DC`}\",[]]Bf[\"{{{AHO`{B@Ll}}{AHO`{B@Ll}}}DC`}\",[]]Bf[\"{{{AHO`{BCM`}}{AHO`{BCM`}}}DC`}\",[]]Bf[\"{{{AHO`{AHEb}}{AHO`{AHEb}}}DC`}\",[]]Bf[\"{{{AHO`{BBLf}}{AHO`{BBLf}}}DC`}\",[]]Bf[\"{{{AHO`{AOLb}}{AHO`{AOLb}}}DC`}\",[]]Bf[\"{{{AHO`{AOJf}}{AHO`{AOJf}}}DC`}\",[]]Bf[\"{{{AHO`{AHCh}}{AHO`{AHCh}}}DC`}\",[]]Bf[\"{{{AHO`{BBNd}}{AHO`{BBNd}}}DC`}\",[]]Bf[\"{{{AHO`{AIMl}}{AHO`{AIMl}}}DC`}\",[]]Bf[\"{{{AHO`{AJ@h}}{AHO`{AJ@h}}}DC`}\",[]]Bf[\"{{{AHO`{B@Mj}}{AHO`{B@Mj}}}DC`}\",[]]Bf[\"{{{AHO`{BCLl}}{AHO`{BCLl}}}DC`}\",[]]Bf[\"{{{AHO`{BEFj}}{AHO`{BEFj}}}DC`}\",[]]Bf[\"{{{AHO`{BEGb}}{AHO`{BEGb}}}DC`}\",[]]Bf[\"{{{AHO`{B@Mb}}{AHO`{B@Mb}}}DC`}\",[]]Bf[\"{{{AHO`{ABAh}}{AHO`{ABAh}}}DC`}\",[]]Bf[\"{{{AHO`{BFCl}}{AHO`{BFCl}}}DC`}\",[]]Bf[\"{{{AHO`{B@Mh}}{AHO`{B@Mh}}}DC`}\",[]]Bf[\"{{{AHO`{B@Nb}}{AHO`{B@Nb}}}DC`}\",[]]Bf[\"{{{AHO`{BCAb}}{AHO`{BCAb}}}DC`}\",[]]Bf[\"{{{AHO`{BFL`}}{AHO`{BFL`}}}DC`}\",[]]Bd[\"{{{AHO`{DAn}}{AHO`{DAn}}}DC`}\",[]]Bd[\"{{{AHO`{A@l}}{AHO`{A@l}}}DC`}\",[]]Bf[\"{{{AHO`{ABCf}}{AHO`{ABCf}}}DC`}\",[]]Bf[\"{{{AHO`{AHCd}}{AHO`{AHCd}}}DC`}\",[]]Bf[\"{{{AHO`{BBCh}}{AHO`{BBCh}}}DC`}\",[]]Bf[\"{{{AHO`{BGAn}}{AHO`{BGAn}}}DC`}\",[]]Bd[\"{{{AHO`{IFf}}{AHO`{IFf}}}DC`}\",[]]Bf[\"{{{AHO`{BHM`}}{AHO`{BHM`}}}DC`}\",[]]Bd[\"{{{AHO`{IFd}}{AHO`{IFd}}}DC`}\",[]]Bf[\"{{{AHO`{B@Nd}}{AHO`{B@Nd}}}DC`}\",[]]Ai[\"{{{AHO`{DA`}}}KFn}\",[]]Aj[\"{{{AHO`{BCAf}}}KFn}\",[]]Ak[\"{{{AHO`{AIOd}}}ABCd}\",[]]Ak[\"{{{AHO`{BGB`}}}ABCd}\",[]]Ak[\"{{{AHO`{AJ@`}}}ABCd}\",[]]A`[\"{AOKfKFn}\",[]]A`[\"{AH@`KFn}\",[]]A`[\"{AHBfKFn}\",[]]A`[\"{BAAbKFn}\",[]]A`[\"{BA@`KFn}\",[]]A`[\"{AOKhKG`}\",[]]A`[\"{AH@bKG`}\",[]]A`[\"{AHBhKG`}\",[]]A`[\"{BAAdKG`}\",[]]A`[\"{BA@bKG`}\",[]]Aa[\"{ABBlABCf}\",[]]Aa[\"{ABEdABCf}\",[]]Aa[\"{AB@lABCf}\",[]]A`[\"{NMjABCf}\",[]]A`[\"{AOMfNMb}\",[]]A`[\"{D@hABAh}\",[]]Ac[\"{{ABDnABDn}}\",[]]Ac[\"{{AILnAILn}}\",[]]Ac[\"{{BCMfAHEl}}\",[]]Bc[\"{{ABE`ABE`}c{}}\",[\"Add::Output\"]]Bc[\"{{AIM`AIM`}c{}}\",[\"Add::Output\"]]Bc[\"{{BCMhAHEn}c{}}\",[\"Add::Output\"]]Be[\"{{{AHO`{KI`}}{AHO`{KI`}}}ABBj}\",[]]Be[\"{{{AHO`{KFn}}{AHO`{KFn}}}ABBj}\",[]]Bg[\"{{{AHO`{AOL`}}{AHO`{AOL`}}}ABBj}\",[]]Bg[\"{{{AHO`{B@Mf}}{AHO`{B@Mf}}}ABBj}\",[]]Be[\"{{{AHO`{DAl}}{AHO`{DAl}}}ABBj}\",[]]Be[\"{{{AHO`{A@j}}{AHO`{A@j}}}ABBj}\",[]]Bg[\"{{{AHO`{ABCd}}{AHO`{ABCd}}}ABBj}\",[]]Be[\"{{{AHO`{KIb}}{AHO`{KIb}}}ABBj}\",[]]Bg[\"{{{AHO`{BFDf}}{AHO`{BFDf}}}ABBj}\",[]]Be[\"{{{AHO`{KG`}}{AHO`{KG`}}}ABBj}\",[]]Bg[\"{{{AHO`{AHFd}}{AHO`{AHFd}}}ABBj}\",[]]Bg[\"{{{AHO`{BBBl}}{AHO`{BBBl}}}ABBj}\",[]]Bg[\"{{{AHO`{AJAn}}{AHO`{AJAn}}}ABBj}\",[]]Bg[\"{{{AHO`{AOLb}}{AHO`{AOLb}}}ABBj}\",[]]Bg[\"{{{AHO`{BEGb}}{AHO`{BEGb}}}ABBj}\",[]]Bg[\"{{{AHO`{BFCl}}{AHO`{BFCl}}}ABBj}\",[]]Bg[\"{{{AHO`{B@Mh}}{AHO`{B@Mh}}}ABBj}\",[]]Be[\"{{{AHO`{DAn}}{AHO`{DAn}}}ABBj}\",[]]Be[\"{{{AHO`{A@l}}{AHO`{A@l}}}ABBj}\",[]]Bg[\"{{{AHO`{ABCf}}{AHO`{ABCf}}}ABBj}\",[]]A`[\"{ABCdA@j}\",[]]A`[\"{ABCfA@l}\",[]]o[\"{KFhA@l}\",[]]A`[\"{AHAbA@l}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABC`KFl}\",[]]A`[\"{ABDlKFl}\",[]]Bh[\"{{{AHO`{AAj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOMf}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOIn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BC@l}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BHEb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BGIb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIKn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AILb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{KEd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BGJ`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFDd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AB@h}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BAOf}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{KFd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AINh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BGA`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABA`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIOj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBNb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{DA`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCAf}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIOd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BGB`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BC@h}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AHFb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AIOh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BC@f}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BACb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOMl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AJ@`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AJAl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BAC`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{NMn}}{AHO`{CGbAHC`}}}KGb}\",[]]Cd[\"{{{AHO`{KI`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BGIj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Cd[\"{{{AHO`{ID`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{KFn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AINj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AHEh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFKd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AIKd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{ABDn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AILn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AHEl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BCMf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{B@Ld}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BCLn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AHE`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BBLd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BCNj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BCOl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFGh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFIf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AOL`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BBMh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BABd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BH@l}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{B@Kh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AOJd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AHCf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BCLh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BEFf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{B@M`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{B@Mf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{B@N`}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFKn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{AIMd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BEJj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{DAl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{A@j}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{ABCd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{ABDh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AHCb}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Cd[\"{{{AHO`{CNj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AIJl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{IDh}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AOJn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{NKl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BBAl}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BHLn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{AOJj}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Ce[\"{{{AHO`{BFLf}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]Cd[\"{{{AHO`{IFb}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Ce[\"{{{AHO`{BGHn}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Bi[\"{{{AHO`{AILd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AB@j}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{KIb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BGIl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{IDb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFDf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{KG`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BAAl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AINl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AHEj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFDb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFKf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AIKj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{ABE`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIM`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AHEn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCMh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AHFd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBBl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AJAn}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AOKn}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AONd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BC@j}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Ll}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BCM`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AHEb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBLf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BHDj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{IFl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCNl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCOn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFGj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFIh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOLb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BBMj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BABh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BH@n}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Kl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOJf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AHCh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBNd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AIMl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AJ@h}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{B@Mj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BCLl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BEFj}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AAOl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BEGb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABAb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Mb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AOIj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIOl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBBb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCNh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BHE`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABAh}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFCl}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BCMd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BAOd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Mh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{B@Nb}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCAb}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BFL`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{AIMf}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BIAl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BEJl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{DAn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{A@l}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{ABCf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{ABDj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AHCd}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BBCh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BGAn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{IFf}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bi[\"{{{AHO`{BHM`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOJl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BFLl}}{AHO`{CGbAHC`}}}KGb}\",[]]Cd[\"{{{AHO`{IFd}}{AHO`{CGbAHC`}}}{{KGd{ICjIEb}}}}\",[]]0Bi[\"{{{AHO`{BGI`}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{CNl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AIJn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{IDj}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{AOK`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{NKn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BBAn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bh[\"{{{AHO`{IFh}}{AHO`{CGbAHC`}}}KGb}\",[]]0Bh[\"{{{AHO`{IFn}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{BCAd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABC`}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{ABDl}}{AHO`{CGbAHC`}}}KGb}\",[]]Bi[\"{{{AHO`{B@Nd}}{AHO`{CGbAHC`}}}KGb}\",[]]Bd[\"{{{AHO`{BGIb}}}{{KFl{AJ@f}}}}\",[]]Ak[\"{{{AHO`{BAAl}}}AB@d}\",[]]A`[\"{ABDnCNb}\",[]]A`[\"{ABE`CNb}\",[]]Aj[\"{{{AHO`{BBBb}}}KCb}\",[]]A`[\"{BHE`CNb}\",[]]o[\"{D@hCNb}\",[]]A`[\"{ABC`KCb}\",[]]Cf[\"{{{AHO`{CGbBH@l}}{A@b{ABD`}}}{{AHO`{CGbBH@l}}}}\",[]]Cf[\"{{{AHO`{CGbBH@n}}{A@b{ABDb}}}{{AHO`{CGbBH@n}}}}\",[]]8Af[\"{{AB@dCNb}BC@l}\",[]]Ah[\"{{}{{A@b{BHEb}}}}\",[]]Ae[\"{{KCbCN`}BANd}\",[]]Ce[\"{{BBMh{KFl{BABd}}AHFl{A@b{NMd}}}{{KGf{AB@h}}}}\",[]]Ai[\"{{{A@d{IIb}}}AINn}\",[]]A`[\"{NLlBCNj}\",[]]Ai[\"{{{A@b{NJj}}}BBMh}\",[]]Be[\"{{{A@b{BABf}}{A@b{BFBn}}}BABd}\",[]]Aj[\"{{{A@b{B@Kj}}}B@Kh}\",[]]B`[\"{{{AHO`{{K@j{Oh}}}}}B@Mf}\",[]]Ae[\"{{CN`KCb}BEJj}\",[]]Ah[\"{{DAlA@jCNb}ABCd}\",[]]Am[\"{{AJ@f{KFl{KFb}}}AHCb}\",[]]Ao[\"{{{A@b{AOJn}}NK`CMn}IDh}\",[]]Ao[\"{{{A@b{BBAl}}NK`CMn}NKl}\",[]]Ae[\"{{KCbCN`}BANf}\",[]]Ai[\"{{{A@d{IIb}}}AIO`}\",[]]Bo[\"{{{A@b{BBMj}}{KFl{{A@b{BABh}}}}DC`}AB@j}\",[]]A`[\"{KCbBIE`}\",[]]o[\"{{}BIAb}\",[]]A`[\"{NLlBCNl}\",[]]Ai[\"{{{A@b{NJl}}}BBMj}\",[]]Be[\"{{{A@b{BABj}}{A@b{BFC`}}}BABh}\",[]]Aj[\"{{{A@b{B@Kn}}}B@Kl}\",[]]Ek[\"{{AAOb{AHO`{c}}{AHO`{{K@j{CN`}}}}DC`}{{KGd{{KC`{BBBb{KFl{AAOb}}}}BFCl}}}{BFHdIHh}}\",[\"\"]]B`[\"{{{AHO`{{K@j{Oh}}}}}B@Mh}\",[]]Af[\"{{BFL`KHl}BCAb}\",[]]A`[\"{KCbBIAl}\",[]]Ae[\"{{CN`KCb}BEJl}\",[]]Ah[\"{{DAnA@lCNb}ABCf}\",[]]Am[\"{{AJ@f{KFl{KFb}}}AHCd}\",[]]Ao[\"{{{A@b{AOK`}}NK`CMn}IDj}\",[]]Ao[\"{{{A@b{BBAn}}NK`CMn}NKn}\",[]]Aj[\"{AJAj{{KGf{BCAd}}}}\",[]]Aa[\"{BEJdBHKb}\",[]]Aa[\"{BEJhBHKd}\",[]]o[\"{DAlDAl}\",[]]o[\"{DAnDAn}\",[]]Ak[\"{{{AHO`{AJ@n}}}AJ@l}\",[]]Ai[\"{{{AHO`{NMd}}}NK`}\",[]]0Aj[\"{{{AHO`{BACb}}}NK`}\",[]]Ak[\"{{{AHO`{BBCd}}}AJ@l}\",[]]Ak[\"{{{AHO`{AJA`}}}AJ@l}\",[]]Ak[\"{{{AHO`{BBCf}}}AJ@l}\",[]]Bg[\"{{{AHO`{AILb}}KFn}{{KFl{AB@d}}}}\",[]]Aa[\"{AHElAB@d}\",[]]Bg[\"{{{AHO`{AILd}}KG`}{{KFl{AB@d}}}}\",[]]Aa[\"{AHEnAB@d}\",[]]Ah[\"{AAl{{KGh{ICj}}}}\",[]]Ah[\"{AAn{{KGh{ICj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aa[\"{BA@`AJ@f}\",[]]Aa[\"{BA@bAJ@f}\",[]]Aa[\"{ABC`AJ@f}\",[]]Aa[\"{BCAbBFL`}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{AAOlICn}\",[]]Am[\"{{{AHO`{CGbABBf}}}ICj}\",[]]Am[\"{{{AHO`{CGbABA`}}}ICj}\",[]]Al[\"{{{AHO`{CGbDA`}}}ICj}\",[]]Am[\"{{{AHO`{CGbBCAf}}}ICj}\",[]]Am[\"{{{AHO`{CGbAIOd}}}ICj}\",[]]Am[\"{{{AHO`{CGbAJ@`}}}ICj}\",[]]Al[\"{{{AHO`{CGbKDl}}}ICj}\",[]]A`[\"{cc{}}\",[\"T\"]]000000000000000000000000Aa[\"{BCLnBFDd}\",[]]1111111111111Aa[\"{AHFbBC@h}\",[]]2Aa[\"{AIOhAHFb}\",[]]3Aa[\"{BCLnAHFb}\",[]]Aa[\"{BCLnAIOh}\",[]]55Aa[\"{AHFbBC@f}\",[]]666Aa[\"{B@LdAJAl}\",[]]Aa[\"{BAC`AJAl}\",[]]Aa[\"{BCLnAJAl}\",[]]9Aa[\"{BCLnBAC`}\",[]]::::::::A`[\"{ABCdKI`}\",[]]A`[\"{BFKnKI`}\",[]]o[\"{CN`KI`}\",[]]o[\"{CMnKI`}\",[]]n[\"{OhKI`}\",[]]????Al[\"{cKFn{{D@b{CN`}}}}\",[\"T\"]]A`[\"{cc{}}\",[\"T\"]]00000000Aa[\"{AOJbBCLn}\",[]]1A`[\"{IDfBCLn}\",[]]A`[\"{IElBCLn}\",[]]3333333A`[\"{KI`AOL`}\",[]]44444Aa[\"{BD@`AOJd}\",[]]Aa[\"{BGIjAOJd}\",[]]66A`[\"{IElBCLh}\",[]]7Aa[\"{BFLfB@M`}\",[]]8888A`[\"{KI`BFKn}\",[]]9999A`[\"{KI`ABCd}\",[]]::Aa[\"{AJ@fAHCb}\",[]];;;;;;;;;;;;;;;;A`[\"{BBOhIFb}\",[]]A`[\"{AIN`IFb}\",[]]A`[\"{BCMjIFb}\",[]]A`[\"{BCOdIFb}\",[]]A`[\"{BHLlIFb}\",[]]A`[\"{BHGfIFb}\",[]]A`[\"{BEFlIFb}\",[]]A`[\"{BHMnIFb}\",[]]A`[\"{BEHbIFb}\",[]]A`[\"{BEIlIFb}\",[]]A`[\"{BBNfIFb}\",[]]A`[\"{cc{}}\",[\"T\"]]0000000000000000000000A`[\"{BFL`KIb}\",[]]n[\"{OhKIb}\",[]]o[\"{CMnKIb}\",[]]o[\"{CN`KIb}\",[]]A`[\"{ABCfKIb}\",[]]5555Al[\"{cKG`{{D@b{CN`}}}}\",[\"T\"]]666666666666666666Aa[\"{BCAbBCM`}\",[]]7777A`[\"{AHEjIFl}\",[]]888888A`[\"{KIbAOLb}\",[]]9999Aa[\"{BD@`AOJf}\",[]]:Aa[\"{BGIlAOJf}\",[]];;;;;Aa[\"{BCAbBCLl}\",[]]<<<<<>>>>A`[\"{IFfBCAb}\",[]]?A`[\"{KIbBFL`}\",[]]A`[\"{cc{}}\",[\"T\"]]0000A`[\"{KIbABCf}\",[]]111Aa[\"{AJ@fAHCd}\",[]]22A`[\"{BBChIFf}\",[]]33333333A`[\"{BHMnIFd}\",[]]A`[\"{BEFlIFd}\",[]]5A`[\"{BEHbIFd}\",[]]A`[\"{BBNfIFd}\",[]]A`[\"{BBOhIFd}\",[]]A`[\"{BCMjIFd}\",[]]A`[\"{BCOdIFd}\",[]]A`[\"{BHLlIFd}\",[]]A`[\"{BHGfIFd}\",[]]A`[\"{BEIlIFd}\",[]]A`[\"{AIN`IFd}\",[]]>>>>>>>>>>>>An[\"{{{AHO`{c}}}AJAjCNh}\",[\"S\"]]??????????????Bm[\"{{{AHO`{KI`}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bk[\"{{{AHO`{KFn}}{AHO`{CGbc}}}ICjKF`}\",[\"H\"]]Bn[\"{{{AHO`{AOL`}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{B@Mf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{DAl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{A@j}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{ABCd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AHCb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{KIb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BFDf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bk[\"{{{AHO`{KG`}}{AHO`{CGbc}}}ICjKF`}\",[\"H\"]]Bn[\"{{{AHO`{AHFd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BBBl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AJAn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AOLb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BEGb}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{BFCl}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{B@Mh}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{DAn}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bm[\"{{{AHO`{A@l}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{ABCf}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Bn[\"{{{AHO`{AHCd}}{AHO`{CGbc}}}ICjKF`}\",[\"__H\"]]Aa[\"{{}c{}}\",[\"U\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n[\"{{}ICj}\",[]]0000Cc[\"{{{AHO`{CGbKDl}}KCb}{{KGd{{KFl{IDb}}AHFd}}}}\",[]]Cf[\"{{{AHO`{CGbBB@j}}}{{KFl{c}}}{}}\",[\"Iterator::Item\"]]Dl[\"{{{AHO`{BFBn}}ICh{AHO`{CGb{K@j{Oh}}}}}{{KGd{{AHO`{{K@j{Oh}}}}AOJj}}}}\",[]]Bi[\"{{{AHO`{CGbNNf}}A@l}{{KFl{ABCf}}}}\",[]]Dl[\"{{{AHO`{BFC`}}ICh{AHO`{CGb{K@j{Oh}}}}}{{KGd{{AHO`{{K@j{Oh}}}}AOJl}}}}\",[]]Bf[\"{{{AHO`{AILb}}KFn}{{KFl{DA`}}}}\",[]]Bf[\"{{{AHO`{DA`}}}{{KGd{ICjAIKd}}}}\",[]]A`[\"{AILnCNb}\",[]]Am[\"{{{AHO`{CGbAILd}}}ICj}\",[]]A`[\"{AIM`CNb}\",[]]Ck[\"{{{ABb{{AHO`{CGbAIJd}}}}{AHO`{CGbNIn}}}{{DAh{ICj}}}}\",[]]Dk[\"{{{ABb{{AHO`{CGbBD@f}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbABBf}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbABBh}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAIKn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbNLb}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbKFf}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAH@h}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbAAO`}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBAA`}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBAAn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbKCj}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dk[\"{{{ABb{{AHO`{CGbBBNb}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Dj[\"{{{ABb{{AHO`{CGbNMn}}}}{AHO`{CGbNIn}}}{{DAh{c}}}{}}\",[\"Future::Output\"]]Bf[\"{{{AHO`{CGbAILd}}}{{KFl{IFl}}}}\",[]]De[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{Oh}}}}}{{KGd{{KFl{KCb}}AHFb}}}}\",[]]Bm[\"{{{AHO`{CGbAIOf}}DC`}{{KGd{KDlBBBl}}}}\",[]]C`[\"{{DAn{AHO`{CGbc}}}{{KGd{BGAnIFf}}}A@f}\",[\"R\"]]Bf[\"{{{AHO`{CGbAHBb}}}{{KFl{ICn}}}}\",[]]Ec[\"{{{AHO`{BCAd}}AJAj{AHO`{CGb{K@j{AIMh}}}}{AHO`{CGb{K@j{ABC`}}}}}{{KGf{KCb}}}}\",[]]Cn[\"{{{AHO`{BFBn}}ICh{AHO`{CGb{ABh{Oh}}}}}{{KGd{ICjAOJj}}}}\",[]]Cn[\"{{{AHO`{BFC`}}ICh{AHO`{CGb{ABh{Oh}}}}}{{KGd{ICjAOJl}}}}\",[]]C`[\"{{{AHO`{CGbAHBb}}ICnDC`}{{KGd{ICjBFDf}}}}\",[]]Cc[\"{{{AHO`{BCAd}}AJAj{AHO`{ABDl}}}{{KGf{ICj}}}}\",[]]Bn[\"{{{AHO`{CGbBH@l}}CN`}{{AHO`{CGbBH@l}}}}\",[]]Bn[\"{{{AHO`{CGbBH@n}}CN`}{{AHO`{CGbBH@n}}}}\",[]]Aj[\"{{{AHO`{AILb}}}DAl}\",[]]Aj[\"{{{AHO`{AILd}}}DAn}\",[]]Cn[\"{{{AHO`{NJj}}{AHO`{{K@j{Oh}}}}{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Cn[\"{{{AHO`{NJl}}{AHO`{{K@j{Oh}}}}{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]A`[\"{BC@lCNb}\",[]]A`[\"{ABDhKCb}\",[]]A`[\"{ABDjKCb}\",[]]o[\"{IHdDC`}\",[]]Bm[\"{{{AHO`{CGbAIOd}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbBGB`}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAIOf}}KIb}{{KGd{ICjB@Ll}}}}\",[]]Bn[\"{{{AHO`{AJAf}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BBOd}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BEJj}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{AJAh}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BBOf}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bn[\"{{{AHO`{BEJl}}{AHO`{CMl}}}{{KFl{ICn}}}}\",[]]Bd[\"{{{AHO`{BEGf}}}{{KFl{BB@h}}}}\",[]]Bd[\"{{{AHO`{BEGh}}}{{KFl{BB@j}}}}\",[]]Bi[\"{{{A@b{BFBf}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{AIJl}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{AOJn}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{BBAl}}NK`CMn}{{A@d{AILf}}}}\",[]]Bi[\"{{{A@b{BFBh}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{AIJn}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{AOK`}}NK`CMn}{{A@d{AILh}}}}\",[]]Bi[\"{{{A@b{BBAn}}NK`CMn}{{A@d{AILh}}}}\",[]]Aj[\"{BG@n{{A@b{BFBh}}}}\",[]]o[\"{ID`ICn}\",[]]A`[\"{ABDnCNb}\",[]]o[\"{IDbICn}\",[]]A`[\"{ABE`CNb}\",[]]Aa[\"{AOIjBCM`}\",[]]Ai[\"{{{AHO`{AAj}}}AAj}\",[]]Ak[\"{{{AHO`{AOMf}}}AOMf}\",[]]Ak[\"{{{AHO`{AOIn}}}AOIn}\",[]]Ak[\"{{{AHO`{AILb}}}AILb}\",[]]Ai[\"{{{AHO`{KEd}}}KEd}\",[]]Ak[\"{{{AHO`{BGJ`}}}BGJ`}\",[]]Ak[\"{{{AHO`{BFDd}}}BFDd}\",[]]Ak[\"{{{AHO`{AB@h}}}AB@h}\",[]]Ak[\"{{{AHO`{BAOf}}}BAOf}\",[]]Ai[\"{{{AHO`{KFd}}}KFd}\",[]]Ai[\"{{{AHO`{DA`}}}DA`}\",[]]Ak[\"{{{AHO`{BCAf}}}BCAf}\",[]]Ak[\"{{{AHO`{BC@h}}}BC@h}\",[]]Ak[\"{{{AHO`{AHFb}}}AHFb}\",[]]Ak[\"{{{AHO`{AIOh}}}AIOh}\",[]]Ak[\"{{{AHO`{BC@f}}}BC@f}\",[]]Ak[\"{{{AHO`{AJAl}}}AJAl}\",[]]Ak[\"{{{AHO`{BAC`}}}BAC`}\",[]]Ai[\"{{{AHO`{KI`}}}KI`}\",[]]Ak[\"{{{AHO`{BGIj}}}BGIj}\",[]]Ai[\"{{{AHO`{KFn}}}KFn}\",[]]Ak[\"{{{AHO`{AINj}}}AINj}\",[]]Ak[\"{{{AHO`{AHEh}}}AHEh}\",[]]Ak[\"{{{AHO`{BFKd}}}BFKd}\",[]]Ak[\"{{{AHO`{AIKd}}}AIKd}\",[]]Ak[\"{{{AHO`{ABDn}}}ABDn}\",[]]Ak[\"{{{AHO`{AILn}}}AILn}\",[]]Ak[\"{{{AHO`{AHEl}}}AHEl}\",[]]Ak[\"{{{AHO`{BCMf}}}BCMf}\",[]]Ak[\"{{{AHO`{B@Ld}}}B@Ld}\",[]]Ak[\"{{{AHO`{BCLn}}}BCLn}\",[]]Ak[\"{{{AHO`{AHE`}}}AHE`}\",[]]Ak[\"{{{AHO`{BBLd}}}BBLd}\",[]]Ak[\"{{{AHO`{BCOl}}}BCOl}\",[]]Ak[\"{{{AHO`{BFGh}}}BFGh}\",[]]Ak[\"{{{AHO`{BFIf}}}BFIf}\",[]]Ak[\"{{{AHO`{AOL`}}}AOL`}\",[]]Ak[\"{{{AHO`{BBMh}}}BBMh}\",[]]Ak[\"{{{AHO`{BABd}}}BABd}\",[]]Ak[\"{{{AHO`{BH@l}}}BH@l}\",[]]Ak[\"{{{AHO`{B@Kh}}}B@Kh}\",[]]Ak[\"{{{AHO`{AOJd}}}AOJd}\",[]]Ak[\"{{{AHO`{AHCf}}}AHCf}\",[]]Ak[\"{{{AHO`{BCLh}}}BCLh}\",[]]Ak[\"{{{AHO`{BEFf}}}BEFf}\",[]]Ak[\"{{{AHO`{B@M`}}}B@M`}\",[]]Ak[\"{{{AHO`{B@Mf}}}B@Mf}\",[]]Ak[\"{{{AHO`{B@N`}}}B@N`}\",[]]Ak[\"{{{AHO`{BFKn}}}BFKn}\",[]]Ak[\"{{{AHO`{AIMd}}}AIMd}\",[]]Ai[\"{{{AHO`{DAl}}}DAl}\",[]]Ai[\"{{{AHO`{A@j}}}A@j}\",[]]Ak[\"{{{AHO`{ABCd}}}ABCd}\",[]]Ak[\"{{{AHO`{AHCb}}}AHCb}\",[]]Ai[\"{{{AHO`{CNj}}}CNj}\",[]]Ak[\"{{{AHO`{AIJl}}}AIJl}\",[]]Ai[\"{{{AHO`{IDh}}}IDh}\",[]]Ak[\"{{{AHO`{AOJn}}}AOJn}\",[]]Ai[\"{{{AHO`{NKl}}}NKl}\",[]]Ak[\"{{{AHO`{BBAl}}}BBAl}\",[]]Ai[\"{{{AHO`{IFb}}}IFb}\",[]]Ak[\"{{{AHO`{BEJb}}}BEJb}\",[]]Ak[\"{{{AHO`{BGHn}}}BGHn}\",[]]Ak[\"{{{AHO`{BEJf}}}BEJf}\",[]]Ai[\"{{{AHO`{KIb}}}KIb}\",[]]Ak[\"{{{AHO`{BGIl}}}BGIl}\",[]]Ak[\"{{{AHO`{BFDf}}}BFDf}\",[]]Ai[\"{{{AHO`{KG`}}}KG`}\",[]]Ak[\"{{{AHO`{BAAl}}}BAAl}\",[]]Ak[\"{{{AHO`{AINl}}}AINl}\",[]]Ak[\"{{{AHO`{AHEj}}}AHEj}\",[]]Ak[\"{{{AHO`{BFDb}}}BFDb}\",[]]Ak[\"{{{AHO`{BFKf}}}BFKf}\",[]]Ak[\"{{{AHO`{AIKj}}}AIKj}\",[]]Ak[\"{{{AHO`{ABE`}}}ABE`}\",[]]Ak[\"{{{AHO`{AIM`}}}AIM`}\",[]]Ak[\"{{{AHO`{AHEn}}}AHEn}\",[]]Ak[\"{{{AHO`{BCMh}}}BCMh}\",[]]Ak[\"{{{AHO`{AHFd}}}AHFd}\",[]]Ak[\"{{{AHO`{BBBl}}}BBBl}\",[]]Ak[\"{{{AHO`{AJAn}}}AJAn}\",[]]Ak[\"{{{AHO`{AOKn}}}AOKn}\",[]]Ak[\"{{{AHO`{BC@j}}}BC@j}\",[]]Ak[\"{{{AHO`{B@Ll}}}B@Ll}\",[]]Ak[\"{{{AHO`{BCM`}}}BCM`}\",[]]Ak[\"{{{AHO`{AHEb}}}AHEb}\",[]]Ak[\"{{{AHO`{BBLf}}}BBLf}\",[]]Ak[\"{{{AHO`{BHDj}}}BHDj}\",[]]Ak[\"{{{AHO`{BCOn}}}BCOn}\",[]]Ak[\"{{{AHO`{BFGj}}}BFGj}\",[]]Ak[\"{{{AHO`{BFIh}}}BFIh}\",[]]Ak[\"{{{AHO`{AOLb}}}AOLb}\",[]]Ak[\"{{{AHO`{BBMj}}}BBMj}\",[]]Ak[\"{{{AHO`{BABh}}}BABh}\",[]]Ak[\"{{{AHO`{BH@n}}}BH@n}\",[]]Ak[\"{{{AHO`{B@Kl}}}B@Kl}\",[]]Ak[\"{{{AHO`{AOJf}}}AOJf}\",[]]Ak[\"{{{AHO`{AHCh}}}AHCh}\",[]]Ak[\"{{{AHO`{AIMl}}}AIMl}\",[]]Ak[\"{{{AHO`{AJ@h}}}AJ@h}\",[]]Ak[\"{{{AHO`{B@Mj}}}B@Mj}\",[]]Ak[\"{{{AHO`{BCLl}}}BCLl}\",[]]Ak[\"{{{AHO`{BEFj}}}BEFj}\",[]]Ak[\"{{{AHO`{AAOl}}}AAOl}\",[]]Ak[\"{{{AHO`{BEGb}}}BEGb}\",[]]Ak[\"{{{AHO`{B@Mb}}}B@Mb}\",[]]Ak[\"{{{AHO`{BCNh}}}BCNh}\",[]]Ak[\"{{{AHO`{BHE`}}}BHE`}\",[]]Ak[\"{{{AHO`{ABAh}}}ABAh}\",[]]Ak[\"{{{AHO`{BFCl}}}BFCl}\",[]]Ak[\"{{{AHO`{B@Mh}}}B@Mh}\",[]]Ak[\"{{{AHO`{B@Nb}}}B@Nb}\",[]]Ak[\"{{{AHO`{BCAb}}}BCAb}\",[]]Ak[\"{{{AHO`{BFL`}}}BFL`}\",[]]Ak[\"{{{AHO`{AIMf}}}AIMf}\",[]]Ak[\"{{{AHO`{BIAl}}}BIAl}\",[]]Ai[\"{{{AHO`{DAn}}}DAn}\",[]]Ai[\"{{{AHO`{A@l}}}A@l}\",[]]Ak[\"{{{AHO`{ABCf}}}ABCf}\",[]]Ak[\"{{{AHO`{AHCd}}}AHCd}\",[]]Ak[\"{{{AHO`{BBCh}}}BBCh}\",[]]Ak[\"{{{AHO`{BGAn}}}BGAn}\",[]]Ai[\"{{{AHO`{IFf}}}IFf}\",[]]Ai[\"{{{AHO`{IFd}}}IFd}\",[]]Ak[\"{{{AHO`{BEJd}}}BEJd}\",[]]Ak[\"{{{AHO`{BGI`}}}BGI`}\",[]]Ak[\"{{{AHO`{BEJh}}}BEJh}\",[]]Ai[\"{{{AHO`{CNl}}}CNl}\",[]]Ak[\"{{{AHO`{AIJn}}}AIJn}\",[]]Ai[\"{{{AHO`{IDj}}}IDj}\",[]]Ak[\"{{{AHO`{AOK`}}}AOK`}\",[]]Ai[\"{{{AHO`{NKn}}}NKn}\",[]]Ak[\"{{{AHO`{BBAn}}}BBAn}\",[]]Ai[\"{{{AHO`{IFn}}}IFn}\",[]]Ak[\"{{{AHO`{ABC`}}}ABC`}\",[]]Ak[\"{{{AHO`{ABDl}}}ABDl}\",[]]Ak[\"{{{AHO`{B@Nd}}}B@Nd}\",[]]Ak[\"{{{AHO`{BG@n}}}BG@n}\",[]]Ak[\"{{{AHO`{BCN`}}}BCN`}\",[]]Ak[\"{{{AHO`{BHKb}}}BHKb}\",[]]Ak[\"{{{AHO`{BHKd}}}BHKd}\",[]]Bn[\"{{{AHO`{AILb}}KI`{AHO`{{K@j{Oh}}}}}ICj}\",[]]Bn[\"{{{AHO`{AB@h}}KI`{AHO`{{K@j{Oh}}}}}ICj}\",[]]Bf[\"{{{AHO`{DA`}}}{{KGd{ICjBBLd}}}}\",[]]Bf[\"{{{AHO`{CGbAILd}}NK`KIbICn}ICj}\",[]]Bj[\"{{{AHO`{B@Mf}}}{{AHO`{{K@j{Oh}}}}}}\",[]]Bj[\"{{{AHO`{B@Mh}}}{{AHO`{{K@j{Oh}}}}}}\",[]]Aa[\"{BCAbAIMl}\",[]]A`[\"{ABCdCNb}\",[]]A`[\"{ABCfCNb}\",[]]A`[\"{B@N`DC`}\",[]]A`[\"{B@NbDC`}\",[]]l[\"{NKb}\",[]]l[\"{NKd}\",[]]Cf[\"{{{AHO`{BFHd}}{AHO`{CGbA@f}}}{{KGd{B@MhBFCl}}}}\",[]]Cf[\"{{{AHO`{BIE`}}{AHO`{CGbA@f}}}{{KGd{B@MhBFCl}}}}\",[]]Bc[\"{{{AHO`{AILd}}}{{ABh{KG`}}}}\",[]]Bd[\"{{{AHO`{IHj}}{AHO`{CMl}}}ICj}\",[]]Am[\"{{{AHO`{AOJ`}}KCb}ICj}\",[]]Ai[\"{{{AHO`{IHl}}}ICj}\",[]]Bg[\"{{{ABb{{AHO`{CGbAIJd}}}}NK`}ICj}\",[]]Bm[\"{{{AHO`{CGbAJ@`}}KI`}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAJ@b}}KIb}{{KGd{ICjB@Ll}}}}\",[]]Am[\"{ABA`{{KGd{ICjAIOj}}}}\",[]]Dc[\"{{{AHO`{CGbAB@j}}ABAb{AHO`{CGb{ABh{Oh}}}}}{{KGd{ABDjAIOl}}}}\",[]]Bj[\"{{{AHO`{NMd}}{ABb{{A@d{KEn}}}}}ICj}\",[]]Bk[\"{{{AHO`{BACb}}{ABb{{A@d{KEn}}}}}ICj}\",[]]Bk[\"{{{AHO`{AOMl}}{ABb{{A@d{KEn}}}}}ICj}\",[]]o[\"{AAjDC`}\",[]]Ak[\"{{{AHO`{AILb}}}BCMf}\",[]]Ak[\"{{{AHO`{AB@h}}}BAOf}\",[]]Aj[\"{{{AHO`{DA`}}}AHEl}\",[]]A`[\"{KEdBCMf}\",[]]An[\"{{{AHO`{CGbAILd}}}BCMh}\",[]]Ce[\"{{{AHO`{CGbAINn}}{KFl{KHl}}}{{AHO`{CGbAINn}}}}\",[]]Ce[\"{{{AHO`{CGbAIO`}}{KFl{KHl}}}{{AHO`{CGbAIO`}}}}\",[]]Ck[\"{{{AHO`{CGbAJ@`}}{AHO`{{K@j{Oh}}}}}{{KGd{KCbAJAl}}}}\",[]]Ck[\"{{{AHO`{CGbAJ@b}}{AHO`{{K@j{Oh}}}}}{{KGd{KCbAJAn}}}}\",[]]Bl[\"{{{AHO`{BGAn}}{AHO`{CGbc}}}ICjKDj}\",[\"W\"]]Aj[\"{{{AHO`{AB@h}}}KCj}\",[]]An[\"{ABA`{{KGd{AIKnBCLn}}}}\",[]]Bi[\"{{{AHO`{CGbNNf}}A@l}{{KFl{ABCf}}}}\",[]]Fj[\"{{{AHO`{CGbAB@j}}ABAbNK`{AHO`{CGb{ABh{Oh}}}}{KFl{{A@b{BABh}}}}}{{KGd{{KC`{BEGbAILd}}{A@d{AOIj}}}}}}\",[]]Am[\"{AHO`{{AHO`{c}}}{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A`[\"{AAjAOIn}\",[]]Bc[\"{{AJ@fBBLbAAj}{{KGh{AOJ`}}}}\",[]]Aj[\"{AJ@f{{KGf{AB@h}}}}\",[]]Ba[\"{{}{{KGd{ICj{A@d{IEd}}}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BCLn}\",[]]Be[\"{{{AHO`{AB@j}}}{{AHO`{BBMj}}}}\",[]]o[\"{OhBFKn}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{BABdA@b}\",[]]o[\"{OhBFL`}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{BABhA@b}\",[]]A`[\"{BCAbKFl}\",[]]Bm[\"{{{AHO`{CGbc}}}{{KGd{KI`BBCh}}}A@f}\",[\"B\"]]Bm[\"{{{AHO`{CGbc}}}{{KGd{KFnBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{AHCfBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{BFKnBBCh}}}A@f}\",[\"B\"]]Bn[\"{{{AHO`{CGbc}}}{{KGd{ABCdBBCh}}}A@f}\",[\"B\"]]Bi[\"{{{AHO`{CGbc}}}{{KGl{KIb}}}A@f}\",[\"B\"]]Bi[\"{{{AHO`{CGbc}}}{{KGl{KG`}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AHCh}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AIMl}}}A@f}\",[\"B\"]]Ek[\"{{{AHO`{CGb{KEl{AAOb}}}}{AHO`{c}}{AHO`{{K@j{CN`}}}}DC`}{{KGd{BCNhBFCl}}}{BFHdIHh}}\",[\"\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{BFL`}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{ABCf}}}A@f}\",[\"B\"]]Bj[\"{{{AHO`{CGbc}}}{{KGl{AHBd}}}A@f}\",[\"B\"]]A`[\"{ABC`KFl}\",[]]Bk[\"{{{AHO`{KI`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KFn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHCf}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{BFKn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{ABCd}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KIb}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bk[\"{{{AHO`{KG`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHCh}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AIMl}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AAOl}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{BFL`}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{ABCf}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bl[\"{{{AHO`{AHBn}}{AHO`{CGbc}}}ICjKDj}\",[\"B\"]]Bj[\"{{{AHO`{CGbAJ@`}}}{{KGd{ICjB@Ld}}}}\",[]]Bj[\"{{{AHO`{CGbAJ@b}}}{{KGd{ICjAOKn}}}}\",[]]An[\"{{{AHO`{AONh}}AB@d}ICj}\",[]]Ea[\"{{{AHO`{CGbAB@j}}NK`AHCd{KFl{B@Nb}}AAOb{AHO`{CGb{ABh{Oh}}}}}{{KFl{BAOb}}}}\",[]]o[\"{D@dNKb}\",[]]o[\"{D@fNKd}\",[]]A`[\"{ABA`ICj}\",[]]Ba[\"{{{AHO`{CGbAB@j}}ABAb}ICj}\",[]]Bh[\"{{{AHO`{AJAf}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BBOd}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BEJj}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{AJAh}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BBOf}}{AHO`{CMl}}ICn}ICj}\",[]]Bh[\"{{{AHO`{BEJl}}{AHO`{CMl}}ICn}ICj}\",[]]A`[\"{AHAlDC`}\",[]]o[\"{ID`CNb}\",[]]o[\"{IDbCNb}\",[]]Ch[\"{{{AHO`{CGbAILf}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbCNj}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbIDh}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Cg[\"{{{AHO`{CGbNKl}}NK`NK`CNbCNbDC`{AHO`{BAAj}}}ICj}\",[]]Ch[\"{{{AHO`{CGbAILh}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbCNl}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbIDj}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]Cg[\"{{{AHO`{CGbNKn}}NK`NK`CNbCNbDC`{AHO`{BAAl}}}ICj}\",[]]o[\"{D@dNKb}\",[]]o[\"{D@fNKd}\",[]]o[\"{BEKfOh}\",[]]A`[\"{KEdBCLn}\",[]]A`[\"{BCLhICn}\",[]]A`[\"{BEFfICn}\",[]]Aa[\"{AH@`BFD`}\",[]]A`[\"{BCLlICn}\",[]]A`[\"{BEFjICn}\",[]]A`[\"{BCAbKHl}\",[]]Aa[\"{BBLjBCM`}\",[]]Aa[\"{AH@bBFDb}\",[]]Bg[\"{{{AHO`{AB@h}}AHFl}{{KGf{ICj}}}}\",[]]A`[\"{ABA`ICj}\",[]]Cf[\"{{{AHO`{CGbAB@j}}ABAb{AHO`{CGb{ABh{Oh}}}}}ABDj}\",[]]Ak[\"{{{AHO`{AHCb}}}AJ@f}\",[]]l[\"{NKb}\",[]]Ak[\"{{{AHO`{AHCd}}}AJ@f}\",[]]l[\"{NKd}\",[]]An[\"{{AB@fAAj}{{KGh{ICj}}}}\",[]]B`[\"{{BABdAJ@f}{{KGf{AB@h}}}}\",[]]Bc[\"{BABb{{KGd{ICj{A@d{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BFDd}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BC@h}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AHFb}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AIOh}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BC@f}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{AJAl}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BAC`}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BCLn}}}{{KFl{{AHO`{IEd}}}}}}\",[]]Bk[\"{{{AHO`{BCM`}}}{{KFl{{AHO`{IEd}}}}}}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABDlKFl}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AINjAIKd}}}}\",[]]Aa[\"{BAAbAINj}\",[]]Aa[\"{BAAdAINl}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{ABC`KCb}\",[]]Aa[\"{AHElABDn}\",[]]Aa[\"{BCMfABDn}\",[]]Aa[\"{AHEnABE`}\",[]]Aa[\"{BCMhABE`}\",[]]3210Dh[\"{{{AHO`{NJj}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAOJj}}}}\",[]]Dh[\"{{{AHO`{NJl}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAOJl}}}}\",[]]Aj[\"{{{AHO`{AILf}}}CNb}\",[]]Ai[\"{{{AHO`{CNj}}}CNb}\",[]]Ai[\"{{{AHO`{IDh}}}CNb}\",[]]Ai[\"{{{AHO`{NKl}}}CNb}\",[]]Aj[\"{{{AHO`{AILh}}}CNb}\",[]]Ai[\"{{{AHO`{CNl}}}CNb}\",[]]Ai[\"{{{AHO`{IDj}}}CNb}\",[]]Ai[\"{{{AHO`{NKn}}}CNb}\",[]]Aj[\"{{{AHO`{BGOj}}}KCb}\",[]]Aj[\"{{{AHO`{BGOl}}}KCb}\",[]]Aj[\"{{{AHO`{BIAb}}}KCb}\",[]]Aj[\"{{{AHO`{BIAl}}}KCb}\",[]]o[\"{AAjKCb}\",[]]n[\"{{}NIl}\",[]]0A`[\"{A@hAAOf}\",[]]111Ba[\"{{AHO`{AHO`{c}}}ABBj{}}\",[\"K\"]]0000000000000000000Cg[\"{{{AHO`{AB@h}}AJ@f{AHO`{CMl}}}{{KGd{AIKnB@M`}}}}\",[]]Dl[\"{{{AHO`{CGbAB@j}}NK`B@KlAJ@f{AHO`{CMl}}}{{KGd{{KC`{BEGbAILd}}B@Mb}}}}\",[]]Bd[\"{{{AHO`{ABA`}}}{{KFl{BEGf}}}}\",[]]Dm[\"{{{AHO`{AHDj}}KFnCNb{AHO`{{K@j{Oh}}}}{AHO`{CGbAAOb}}}{{KGd{ICjAOJj}}}}\",[]]Ca[\"{{{AHO`{AHCl}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Bd[\"{{{AHO`{ABAb}}}{{KFl{BEGh}}}}\",[]]Dm[\"{{{AHO`{AHDl}}KG`CNb{AHO`{{K@j{Oh}}}}{AHO`{CGbAAOb}}}{{KGd{ICjAOJl}}}}\",[]]Ca[\"{{{AHO`{AHCn}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]o[\"{{}AONf}\",[]]n[\"{{}IHj}\",[]]o[\"{{}AOJ`}\",[]]o[\"{{}BANd}\",[]]o[\"{{}BAOf}\",[]]n[\"{{}KI`}\",[]]n[\"{{}KFn}\",[]]o[\"{{}AINj}\",[]]o[\"{{}AIKd}\",[]]o[\"{{}ABDn}\",[]]o[\"{{}AILn}\",[]]o[\"{{}AHEl}\",[]]o[\"{{}BCMf}\",[]]o[\"{{}B@Ld}\",[]]o[\"{{}BCOl}\",[]]o[\"{{}BFGh}\",[]]o[\"{{}BFIf}\",[]]o[\"{{}AOL`}\",[]]o[\"{{}BBMh}\",[]]o[\"{{}BH@l}\",[]]o[\"{{}BEJj}\",[]]o[\"{{}AIJl}\",[]]o[\"{{}AOJn}\",[]]o[\"{{}BBAl}\",[]]o[\"{{}BFBj}\",[]]o[\"{{}BANf}\",[]]o[\"{{}BIAb}\",[]]n[\"{{}KIb}\",[]]n[\"{{}KG`}\",[]]o[\"{{}AINl}\",[]]o[\"{{}AIKj}\",[]]o[\"{{}ABE`}\",[]]o[\"{{}AIM`}\",[]]o[\"{{}AHEn}\",[]]o[\"{{}BCMh}\",[]]o[\"{{}BC@j}\",[]]o[\"{{}B@Ll}\",[]]o[\"{{}BCOn}\",[]]o[\"{{}BFGj}\",[]]o[\"{{}BFIh}\",[]]o[\"{{}AOLb}\",[]]o[\"{{}BBMj}\",[]]o[\"{{}BH@n}\",[]]o[\"{{}BIAl}\",[]]o[\"{{}BEJl}\",[]]o[\"{{}AIJn}\",[]]o[\"{{}AOK`}\",[]]o[\"{{}BBAn}\",[]]o[\"{{}BFBl}\",[]]o[\"{{}ABC`}\",[]]n[\"{{}IHl}\",[]]o[\"{{}BCN`}\",[]]o[\"{{}BAOd}\",[]]Ak[\"{{{AHO`{BBBb}}}B@Mh}\",[]]Ak[\"{{{AHO`{BCNh}}}B@Mh}\",[]]Aa[\"{BHE`B@Mh}\",[]]Aa[\"{BFLbB@Mh}\",[]]A`[\"{D@hB@Mh}\",[]]A`[\"{IH`B@Mh}\",[]]A`[\"{IHdB@Mh}\",[]]Aa[\"{BEKfB@Mh}\",[]]Cg[\"{{{AHO`{AHDj}}KFnCNb{AHO`{CGb{K@j{Oh}}}}KCb}ICj}\",[]]Ca[\"{{{AHO`{AHCl}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Cg[\"{{{AHO`{AHDl}}KG`CNb{AHO`{CGb{K@j{Oh}}}}KCb}ICj}\",[]]Ca[\"{{{AHO`{AHCn}}KCb{AHO`{CGb{K@j{Oh}}}}}ICj}\",[]]Aj[\"{{{AHO`{AIOd}}}DC`}\",[]]Aj[\"{{{AHO`{BGB`}}}DC`}\",[]]Ak[\"{{{AHO`{AILf}}}BFBj}\",[]]Aj[\"{{{AHO`{CNj}}}BFBj}\",[]]Aj[\"{{{AHO`{IDh}}}BFBj}\",[]]Aj[\"{{{AHO`{NKl}}}BFBj}\",[]]Ak[\"{{{AHO`{AILh}}}BFBl}\",[]]Aj[\"{{{AHO`{CNl}}}BFBl}\",[]]Aj[\"{{{AHO`{IDj}}}BFBl}\",[]]Aj[\"{{{AHO`{NKn}}}BFBl}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CMn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CMn}{{AHO`{CGbBCOn}}}}\",[]]Bf[\"{{{AHO`{CGbAILf}}NK`CNbCNb}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}NK`CNbCNb}ICj}\",[]]Aj[\"{{{AHO`{AILb}}}KFf}\",[]]Bc[\"{{{AHO`{ABBh}}}{{KFl{KFn}}}}\",[]]Aa[\"{BHE`B@Mh}\",[]]Aa[\"{BFLbB@Mh}\",[]]A`[\"{D@hB@Mh}\",[]]A`[\"{IH`B@Mh}\",[]]Aa[\"{BEKfB@Mh}\",[]]Aj[\"{{{AHO`{AJ@`}}}NMn}\",[]]Bn[\"{{{AHO`{AJ@b}}}{{KGd{{KFl{KIb}}B@Ll}}}}\",[]]o[\"{AAjKCb}\",[]]o[\"{IHjKCb}\",[]]Am[\"{{{AHO`{CGbAILd}}}NNf}\",[]]Aj[\"{{{AHO`{AHDj}}}KCb}\",[]]Aj[\"{{{AHO`{AHDl}}}KCb}\",[]]A`[\"{AHO`KHn}\",[]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bd[\"{{{AHO`{BGJ`}}}{{KFl{AILb}}}}\",[]]Bc[\"{{{AHO`{BCAf}}}{{KFl{DA`}}}}\",[]]Bn[\"{{{AHO`{CGbB@Kh}}CN`}{{AHO`{CGbB@Kh}}}}\",[]]Bn[\"{{{AHO`{CGbB@Kl}}CN`}{{AHO`{CGbB@Kl}}}}\",[]]A`[\"{BHE`CN`}\",[]]A`[\"{BFLbCN`}\",[]]o[\"{D@hCN`}\",[]]o[\"{IH`CN`}\",[]]A`[\"{AHAlKFl}\",[]]Aa[\"{ABDlAHO`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aa[\"{BC@lAB@d}\",[]]A`[\"{KDlBC@j}\",[]]Aa[\"{AHElAILn}\",[]]Aa[\"{BCMfAILn}\",[]]Aa[\"{AHEnAIM`}\",[]]Aa[\"{BCMhAIM`}\",[]]3210Bh[\"{{{AHO`{CGbc}}KCb}B@Mf{A@fIHh}}\",[\"\"]]Bh[\"{{{AHO`{CGbc}}KCb}B@Mh{A@fIHh}}\",[\"\"]]o[\"{{}BCNj}\",[]]o[\"{{}BCNl}\",[]]A`[\"{CNbBIAb}\",[]]Cd[\"{{{AHO`{CMl}}}{{KGh{AOMfc}}}{}}\",[\"FromStr::Err\"]]Cd[\"{{{AHO`{CMl}}}{{KGh{AOInc}}}{}}\",[\"FromStr::Err\"]]o[\"{CN`KI`}\",[]]o[\"{CN`KIb}\",[]]Al[\"{CNb{{KGd{KI`BGIj}}}}\",[]]Al[\"{CNb{{KGd{KIbBGIl}}}}\",[]]Aa[\"{BGGnAOJh}\",[]]Aa[\"{BIEbBB@b}\",[]]Aa[\"{BGH`AOJh}\",[]]Aa[\"{BIEdBB@b}\",[]]Af[\"{{}{{KFl{Ab}}}}\",[]]0000Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBFIf}}AB@d}{{AHO`{CGbBFIf}}}}\",[]]Bo[\"{{{AHO`{CGbBFIh}}AB@d}{{AHO`{CGbBFIh}}}}\",[]]Bb[\"{{{A@d{AILf}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{CNj}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{IDh}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{NKl}}}{{A@d{A@`}}}}\",[]]Bb[\"{{{A@d{AILh}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{CNl}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{IDj}}}{{A@d{A@`}}}}\",[]]Ba[\"{{{A@d{NKn}}}{{A@d{A@`}}}}\",[]]Aj[\"{{{AHO`{BGJ`}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBH@l}}AB@d}{{AHO`{CGbBH@l}}}}\",[]]Bo[\"{{{AHO`{CGbBH@n}}AB@d}{{AHO`{CGbBH@n}}}}\",[]]Bc[\"{{{AHO`{AIKn}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{ABA`}}}{{KFl{KFb}}}}\",[]]Bm[\"{{{AHO`{DA`}}}{{KGd{{KFl{KFb}}AIKd}}}}\",[]]Bc[\"{{{AHO`{AHCb}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{ABAb}}}{{KFl{KFb}}}}\",[]]Bc[\"{{{AHO`{AHCd}}}{{KFl{KFb}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bc[\"{{{AHO`{AHBb}}}{{KFl{KCb}}}}\",[]]Am[\"{{{AHO`{AONh}}KCb}ICj}\",[]]Aj[\"{{{AHO`{AILb}}}NLb}\",[]]Bg[\"{{{AHO`{AJ@`}}}{{KGd{CElB@Ld}}}}\",[]]Bg[\"{{{AHO`{AJ@b}}}{{KGd{CElB@Ll}}}}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]]A`[\"{AHAlKFl}\",[]]A`[\"{AOIjKFl}\",[]]Ck[\"{{{AHO`{CGbBBMh}}{KFl{{IIh{Oh}}}}}{{AHO`{CGbBBMh}}}}\",[]]Ck[\"{{{AHO`{CGbBBMj}}{KFl{{IIh{Oh}}}}}{{AHO`{CGbBBMj}}}}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Ac[\"{AHO`c{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Ao[\"{c{{KGd{e}}}{}{}}\",[\"U\",\"T\"]]000000000000000000000000000000000000000000000000000000Al[\"{CNb{{KGd{KI`BGIj}}}}\",[]]Al[\"{ICh{{KGd{KI`BGIj}}}}\",[]]Al[\"{KCb{{KGd{KI`BGIj}}}}\",[]]3333333333333333333Aj[\"{AB@d{{KGd{AOL`}}}}\",[]]444444Ai[\"{CNb{{KGd{AHCf}}}}\",[]]55555555555555555555555555555Bc[\"{{{A@b{B@Kd}}}{{KGd{BEJb}}}}\",[]]Aj[\"{B@Kd{{KGd{BEJb}}}}\",[]]77Bc[\"{{{A@b{BAB`}}}{{KGd{BEJf}}}}\",[]]Aj[\"{BAB`{{KGd{BEJf}}}}\",[]]999999999999999999999Al[\"{ICh{{KGd{KIbBGIl}}}}\",[]]Al[\"{KCb{{KGd{KIbBGIl}}}}\",[]];Al[\"{CNb{{KGd{KIbBGIl}}}}\",[]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Bm[\"{B@Kd{{KGd{BEJdc}}}{}}\",[\"TryFrom::Error\"]]Cf[\"{{{A@b{B@Kd}}}{{KGd{BEJdc}}}{}}\",[\"TryFrom::Error\"]]Ao[\"{c{{KGd{e}}}{}{}}\",[\"U\",\"T\"]]00Cf[\"{{{A@b{BAB`}}}{{KGd{BEJhc}}}{}}\",[\"TryFrom::Error\"]]Bm[\"{BAB`{{KGd{BEJhc}}}{}}\",[\"TryFrom::Error\"]]22222222222222222222222Aj[\"{{}{{KGd{c}}}{}}\",[\"U\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cd[\"{{{ABb{{AHO`{CGbc}}}}{AHO`{CGbNIn}}}DAh{}}\",[\"F\"]]000000000Cc[\"{{{AHO`{BCAd}}AJAj{AHO`{ABDl}}}{{KGf{ICj}}}}\",[]]Bk[\"{{{AHO`{BGOj}}B@Mf}{{KGd{ICjAIMd}}}}\",[]]Bk[\"{{{AHO`{BGOl}}B@Mh}{{KGd{ICjAIMf}}}}\",[]]0Bk[\"{{{AHO`{BIAb}}B@Mh}{{KGd{ICjAIMf}}}}\",[]]Ak[\"{{{AHO`{AILb}}}AAO`}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{KI`IF`}}}}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{DAlIF`}}}}\",[]]Bi[\"{{{AHO`{CGbBACd}}}{{KGd{A@jIF`}}}}\",[]]Bj[\"{{{AHO`{CGbBACd}}}{{KGd{ABCdIF`}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{KIb}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{DAn}}}}\",[]]Bf[\"{{{AHO`{CGbBACd}}}{{KGj{A@l}}}}\",[]]Bg[\"{{{AHO`{CGbBACd}}}{{KGj{ABCf}}}}\",[]]Aa[\"{AOInBGIh}\",[]]Bd[\"{{{AHO`{AILf}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{CNj}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{IDh}}}{{A@d{AILf}}}}\",[]]Bc[\"{{{AHO`{NKl}}}{{A@d{AILf}}}}\",[]]Bd[\"{{{AHO`{AILh}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{CNl}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{IDj}}}{{A@d{AILh}}}}\",[]]Bc[\"{{{AHO`{NKn}}}{{A@d{AILh}}}}\",[]]A`[\"{ABDnCNb}\",[]]An[\"{{{AHO`{CGbAILd}}}AHBb}\",[]]A`[\"{ABE`CNb}\",[]]C`[\"{{{AHO`{CGbB@Mf}}}{{AHO`{CGb{K@j{Oh}}}}}}\",[]]C`[\"{{{AHO`{CGbB@Mh}}}{{AHO`{CGb{K@j{Oh}}}}}}\",[]]Ah[\"{Oh{{KFl{B@N`}}}}\",[]]Ah[\"{Oh{{KFl{B@Nb}}}}\",[]]Ah[\"{Oh{{KFl{B@Nd}}}}\",[]]A`[\"{ABCdDAl}\",[]]A`[\"{ABCfDAn}\",[]]Bi[\"{AIKn{{KGd{{KC`{AILbBD@f}}AIKn}}}}\",[]]Aa[\"{{}c{}}\",[\"I\"]]o[\"{DAlDC`}\",[]]o[\"{DAnDC`}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]21Aj[\"{{{AHO`{ABA`}}}DC`}\",[]]Aj[\"{{{AHO`{ABAb}}}DC`}\",[]]Bn[\"{{{AHO`{CGbBABd}}DC`}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}DC`}{{AHO`{CGbBABh}}}}\",[]]Bm[\"{{{AHO`{NMd}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]Bn[\"{{{AHO`{BACb}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]Bn[\"{{{AHO`{AOMl}}NK`}{{ABb{{A@d{AIJd}}}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Ak[\"{{{AHO`{AILb}}}ABBf}\",[]]Bo[\"{{{AHO`{AILb}}cAINj}ABBh{{D@b{AHCb}}}}\",[\"\"]]Ce[\"{{{AHO`{CGbAILd}}AHCdAINlNK`}{{KGd{KG`AHEb}}}}\",[]]43Bm[\"{{{AHO`{CGbAILd}}KG`}{{KGd{ICjAIKj}}}}\",[]]E`[\"{{{ABb{{AHO`{CGbBGIb}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbBEFb}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbAINh}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbBGA`}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{c}}}}}{}}\",[\"Stream::Item\"]]E`[\"{{{ABb{{AHO`{CGbAIOd}}}}{AHO`{CGbNIn}}{AHO`{CGbNLn}}}{{DAh{{KGf{ICj}}}}}}\",[]]Ec[\"{{{AHO`{CGbAIOd}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{Oh}}}}}{{DAh{{KGd{KCbAHFb}}}}}}\",[]]Ef[\"{{{ABb{{AHO`{CGbAIOd}}}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{Oh}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]Fg[\"{{{AHO`{CGbBBL`}}{AHO`{CGbNIn}}{AHO`{CGb{K@j{AIMh}}}}{AHO`{CGb{K@j{ABC`}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]Dn[\"{{{ABb{{AHO`{CGbAHFj}}}}{AHO`{ABDl}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]>=Ce[\"{{{AHO`{CGbBBMh}}{A@b{NJj}}}{{AHO`{CGbBBMh}}}}\",[]]Ce[\"{{{AHO`{CGbBBMj}}{A@b{NJl}}}{{AHO`{CGbBBMj}}}}\",[]]Cj[\"{{{AHO`{BABf}}CN`B@Mf{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BEJf}}CN`B@Mf{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BABj}}CN`B@Mh{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BEJh}}CN`B@Mh{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Cj[\"{{{AHO`{BHKd}}CN`B@Md{AHO`{{K@j{Oh}}}}}{{IIh{Oh}}}}\",[]]Bb[\"{KCb{{KC`{KCb{KFl{KCb}}}}}}\",[]]000Aj[\"{{{AHO`{AILb}}}KCb}\",[]]A`[\"{AHO`KHl}\",[]]0000000000000000000000000000000000000000000000000000000000000000000Cf[\"{{{AHO`{CGbBABd}}{A@b{BFBn}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{BFC`}}}{{AHO`{CGbBABh}}}}\",[]]A`[\"{BHE`IGf}\",[]]A`[\"{BABdA@b}\",[]]A`[\"{BABhA@b}\",[]]Aj[\"{{{AHO`{AB@h}}}ICj}\",[]]Ck[\"{{{AHO`{CGbAJ@`}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjAJAl}}}}\",[]]n[\"{{}KCb}\",[]]Ak[\"{{{AHO`{AILb}}}AH@h}\",[]]Ba[\"{{{AHO`{CGbABDn}}ABDn}ICj}\",[]]Ba[\"{{{AHO`{CGbAILn}}AILn}ICj}\",[]]Ba[\"{{{AHO`{CGbBCMf}}AHEl}ICj}\",[]]Ba[\"{{{AHO`{CGbABE`}}ABE`}ICj}\",[]]Ba[\"{{{AHO`{CGbAIM`}}AIM`}ICj}\",[]]Ba[\"{{{AHO`{CGbBCMh}}AHEn}ICj}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bi[\"{{{AHO`{CGb}}}{{AHO`{CGbc}}}{}}\",[\"T\"]]000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Bg[\"{{{AHO`{AIOd}}}{{KGd{CNbB@Ld}}}}\",[]]Bg[\"{{{AHO`{AIOf}}}{{KGd{CNbB@Ll}}}}\",[]]Bc[\"{{AHO`{AHO`{CGbc}}}ICj{}}\",[\"T\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Cc[\"{{{AHO`{CGbAILd}}NK`KG`KIb}{{KGd{ICjBBLf}}}}\",[]]A`[\"{AHAlDC`}\",[]]B`[\"{{AHO`{AHO`{c}}}DC`{}}\",[\"K\"]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Aa[\"{BCLhBFKn}\",[]]A`[\"{BEFfKI`}\",[]]Aa[\"{BCLlBFL`}\",[]]A`[\"{BEFjKIb}\",[]]A`[\"{BFAnKIb}\",[]]A`[\"{BCNnKIb}\",[]]o[\"{NMjKIb}\",[]]Aa[\"{BCLhAIMj}\",[]]Aa[\"{BCLlAIMl}\",[]]o[\"{KI`CNb}\",[]]o[\"{KIbCNb}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Aj[\"{{{AHO`{BAOd}}}DC`}\",[]]Bd[\"{{{AHO`{BBL`}}}{{KGf{AJ@f}}}}\",[]]Bd[\"{{{AHO`{AB@h}}}{{KGf{AJ@f}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{BCMfCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BCMhCNb}\",[]]Cc[\"{{{AHO`{BCN`}}{AHO`{AIOn}}CNb}{{A@b{AONh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bg[\"{{{AHO`{AILb}}KFn}{{KFl{AHEl}}}}\",[]]o[\"{KEdABh}\",[]]A`[\"{AHBfA@d}\",[]]Bj[\"{{{AHO`{CGbAILd}}KG`}{{KFl{AHEn}}}}\",[]]A`[\"{AHBhA@d}\",[]]Db[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]00Eg[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}{AHO`{{K@j{Oh}}}}}{{DAh{{KGd{KCbAJAl}}}}}}\",[]]Ec[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}{AHO`{{K@j{Oh}}}}}{{DAh{{KGf{KCb}}}}}}\",[]]0Bm[\"{{{AHO`{IHl}}{AHO`{D@n}}}{{KGf{ICj}}}}\",[]]Cd[\"{{{AHO`{CGbAIOd}}KCb}{{KGd{{KFl{ICn}}AHFb}}}}\",[]]Cd[\"{{{AHO`{CGbBGB`}}KCb}{{KGd{{KFl{ID`}}AHFb}}}}\",[]]Cn[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{Oh}}}}}{{KGd{ICjBC@f}}}}\",[]]Bk[\"{{{AHO`{DA`}}AINj}{{KGd{AINjBFKd}}}}\",[]]Bn[\"{{{AHO`{CGbAINn}}NK`}{{AHO`{CGbAINn}}}}\",[]]Bn[\"{{{AHO`{CGbAIO`}}NK`}{{AHO`{CGbAIO`}}}}\",[]]A`[\"{BC@lAG`}\",[]]o[\"{IHjCNb}\",[]]o[\"{{}AJ@f}\",[]]0o[\"{{}AHO`}\",[]]Bk[\"{{ABA`{A@b{BABd}}}{{KGd{AIKnBCLn}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bh[\"{{{AHO`{AHAl}}AJ@f}{{KGh{AHFl}}}}\",[]]A`[\"{AHElCMn}\",[]]Aj[\"{{{AHO`{AILd}}}CMn}\",[]]A`[\"{AHEnCMn}\",[]]Ce[\"{{{AHO`{CGbAINn}}{KFl{KHl}}}{{AHO`{CGbAINn}}}}\",[]]Ce[\"{{{AHO`{CGbAIO`}}{KFl{KHl}}}{{AHO`{CGbAIO`}}}}\",[]]Aa[\"{ABDhAJ@f}\",[]]Aa[\"{ABDjAJ@f}\",[]]Aa[\"{ABDlAJ@f}\",[]]Aa[\"{AJ@fAHCb}\",[]]Aa[\"{AJ@fAHCd}\",[]]o[\"{AAjCMn}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CMn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CMn}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlCMn}\",[]]Bo[\"{{{AHO`{CGbBCOl}}AB@d}{{AHO`{CGbBCOl}}}}\",[]]Bo[\"{{{AHO`{CGbBCOn}}AB@d}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]k[\"{{}}\",[]]0000000000Bh[\"{ABA`c{}}\",[\"IntoFuture::IntoFuture\"]]11Aj[\"{{{AHO`{BAOd}}}DC`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]o[\"{AAjKCb}\",[]]Ao[\"{{AHO`c}{{NKf{c}}}{}}\",[\"S\"]]0C`[\"{{{AHO`{CGbAILf}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bo[\"{{{AHO`{CGbCNj}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]C`[\"{{{AHO`{CGbAILh}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bo[\"{{{AHO`{CGbCNl}}NK`CNbDC`{KFl{CNb}}}ICj}\",[]]Bk[\"{{{AHO`{CGbIHl}}NK`{AHO`{BCN`}}}ICj}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Bn[\"{{{AHO`{KI`}}{AHO`{KI`}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KFn}}{AHO`{KFn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AOL`}}{AHO`{AOL`}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{B@Mf}}{AHO`{B@Mf}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{DAl}}{AHO`{DAl}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{A@j}}{AHO`{A@j}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{ABCd}}{AHO`{ABCd}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KIb}}{AHO`{KIb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BFDf}}{AHO`{BFDf}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{KG`}}{AHO`{KG`}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AHFd}}{AHO`{AHFd}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BBBl}}{AHO`{BBBl}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AJAn}}{AHO`{AJAn}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{AOLb}}{AHO`{AOLb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BEGb}}{AHO`{BEGb}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{BFCl}}{AHO`{BFCl}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{B@Mh}}{AHO`{B@Mh}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{DAn}}{AHO`{DAn}}}{{KFl{ABBj}}}}\",[]]Bn[\"{{{AHO`{A@l}}{AHO`{A@l}}}{{KFl{ABBj}}}}\",[]]C`[\"{{{AHO`{ABCf}}{AHO`{ABCf}}}{{KFl{ABBj}}}}\",[]]Ak[\"{{{AHO`{AILb}}}AINh}\",[]]Bk[\"{{{AHO`{AILd}}KG`}{{KGd{AINlAIKj}}}}\",[]]Cc[\"{{{AHO`{CGbAIOd}}KCb}{{KGd{{ABh{Oh}}BC@h}}}}\",[]]Bb[\"{{{AHO`{CGbAILd}}ABCf}AIOf}\",[]]Aj[\"{{{AHO`{AHCl}}}KCb}\",[]]Aj[\"{{{AHO`{AHCn}}}KCb}\",[]]Bb[\"{{{AHO`{CGbAILd}}ABCf}AJ@b}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CNb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CNb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]]Cf[\"{{{AHO`{CGbBABd}}{A@b{AJ@n}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{AJA`}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kh}}{A@b{AJAf}}}{{AHO`{CGbB@Kh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kl}}{A@b{AJAh}}}{{AHO`{CGbB@Kl}}}}\",[]]o[\"{AAjCNb}\",[]]Bn[\"{{{AHO`{CGbBFIf}}CMn}{{AHO`{CGbBFIf}}}}\",[]]Bn[\"{{{AHO`{CGbBFIh}}CMn}{{AHO`{CGbBFIh}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BGJ`}\",[]]Aj[\"{{{AHO`{DA`}}}BCAf}\",[]]Aj[\"{{{A@b{BABf}}}BABd}\",[]]Aj[\"{{{A@b{BABj}}}BABh}\",[]]Aj[\"{{BCNjc}BCNjABCn}\",[\"\"]]Aj[\"{{BCNlc}BCNlABCn}\",[\"\"]]Bm[\"{{{AHO`{CGbAJ@`}}ICn}{{KGd{ICjAJAl}}}}\",[]]n[\"{{}KFb}\",[]]o[\"{NIlNIl}\",[]]0000Bd[\"{{{AHO`{BGOj}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BGOl}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BIAb}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{BIAl}}}{{KFl{AB@d}}}}\",[]]Bd[\"{{{AHO`{AILb}}}{{KFl{BCLn}}}}\",[]]Ck[\"{{{AHO`{AB@h}}B@KhAJ@f{AHO`{CMl}}}{{KGd{AIKnB@M`}}}}\",[]]Ak[\"{{{AHO`{BAAl}}}AB@d}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]An[\"{{AIObDC`}{{KGh{KCb}}}}\",[]]Cl[\"{{{AHO`{NMf}}}{{KFl{{KC`{{A@d{AHCl}}{A@d{AHDj}}}}}}}}\",[]]Cm[\"{{{AHO`{AJAb}}}{{KFl{{KC`{{A@d{AHCl}}{A@d{AHDj}}}}}}}}\",[]]Cl[\"{{{AHO`{NMh}}}{{KFl{{KC`{{A@d{AHCn}}{A@d{AHDl}}}}}}}}\",[]]Cm[\"{{{AHO`{AJAd}}}{{KFl{{KC`{{A@d{AHCn}}{A@d{AHDl}}}}}}}}\",[]]A`[\"{BGGnABh}\",[]]A`[\"{BIEbABh}\",[]]A`[\"{BGH`ABh}\",[]]A`[\"{BIEdABh}\",[]]An[\"{{{AHO`{CGbBGOj}}}B@Mf}\",[]]An[\"{{{AHO`{CGbBGOl}}}B@Mh}\",[]]An[\"{{{AHO`{CGbBIAb}}}B@Mh}\",[]]An[\"{{{AHO`{CGbBIAl}}}B@Mh}\",[]]Ak[\"{{{AHO`{BCAd}}}B@Oj}\",[]]Ba[\"{{{AHO`{CGbAILd}}BCMd}ICj}\",[]]Bo[\"{{{AHO`{CGbAB@j}}BEGbBAOd}{{KFl{BCMd}}}}\",[]]B`[\"{{{AHO`{NMf}}B@MfDAl}D@d}\",[]]Bn[\"{{{AHO`{BABf}}CN`B@Mf}{{KGd{D@dBFLf}}}}\",[]]Ba[\"{{{AHO`{AJAb}}B@MfDAl}D@d}\",[]]Bn[\"{{{AHO`{BEJf}}CN`B@Mf}{{KGd{D@dBFLf}}}}\",[]]B`[\"{{{AHO`{NMh}}B@MhDAn}D@f}\",[]]Bn[\"{{{AHO`{BABj}}CN`B@Mh}{{KGd{D@fBFLl}}}}\",[]]Ba[\"{{{AHO`{AJAd}}B@MhDAn}D@f}\",[]]Bn[\"{{{AHO`{BEJh}}CN`B@Mh}{{KGd{D@fBFLl}}}}\",[]]Bn[\"{{{AHO`{BHKd}}CN`B@Md}{{KGd{D@fBFLl}}}}\",[]]Aj[\"{{}{{NM`{c}}}{}}\",[\"T\"]]0A`[\"{AHElCNb}\",[]]A`[\"{BCMfCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BCMhCNb}\",[]]Bn[\"{{{AHO`{CGbBABd}}KCb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}KCb}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{BBL`}}}DC`}\",[]]0Aj[\"{{{AHO`{BCAd}}}DC`}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AHCbAIKd}}}}\",[]]Bk[\"{{{AHO`{AILd}}KG`}{{KGd{AHCdAIKj}}}}\",[]]Cc[\"{{{AHO`{BCN`}}{AHO`{AIOb}}CNb}{{A@b{AONh}}}}\",[]]Ak[\"{{{AHO`{ABA`}}}B@Mf}\",[]]Ak[\"{{{AHO`{ABAb}}}B@Mh}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bf[\"{{{AHO`{CGbAILd}}}{{KFl{NK`}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{A@b{AOLn}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{A@b{AOM`}}}{{AHO`{CGbBCOn}}}}\",[]]43A`[\"{AAjAOMf}\",[]]A`[\"{ABDhKFl}\",[]]A`[\"{ABDjKFl}\",[]]A`[\"{ABDlKFl}\",[]]A`[\"{BFBjKFl}\",[]]A`[\"{BFBlKFl}\",[]]Ai[\"{{{AHO`{NNf}}}KCb}\",[]]Bo[\"{{{AHO`{CGbBIAb}}AB@d}{{AHO`{CGbBIAb}}}}\",[]]Bo[\"{{{AHO`{CGbBIAl}}AB@d}{{AHO`{CGbBIAl}}}}\",[]]Bj[\"{{{AHO`{AJ@`}}CEl}{{KGd{ICjB@Ld}}}}\",[]]Bm[\"{{{AHO`{CGbAJ@b}}CEl}{{KGd{ICjB@Ll}}}}\",[]]?>A`[\"{IHjAONf}\",[]]A`[\"{AOJ`IHj}\",[]]Bj[\"{{{A@b{B@Kd}}IHn}{{KGd{BEJbBGHn}}}}\",[]]Bj[\"{{{A@b{BAB`}}IHn}{{KGd{BEJfBGHn}}}}\",[]]Bj[\"{{{A@b{B@Kd}}IHn}{{KGd{BEJdBGI`}}}}\",[]]Bj[\"{{{A@b{BAB`}}IHn}{{KGd{BEJhBGI`}}}}\",[]]Dj[\"{{{AHO`{CGbAJ@b}}{AHO`{CGb{AHO`{CGb{K@j{ICn}}}}}}}{{KGd{KCbAJAn}}}}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]A`[\"{AHAlDC`}\",[]]Cd[\"{{{AHO`{CGbBBMh}}{A@b{A`}}}{{AHO`{CGbBBMh}}}}\",[]]Cd[\"{{{AHO`{CGbBBMj}}{A@b{A`}}}{{AHO`{CGbBBMj}}}}\",[]]Bk[\"{{{AHO`{BBL`}}}{{ABb{{A@d{AHFj}}}}}}\",[]]o[\"{AAjCNb}\",[]]Aa[\"{AONfAHD`}\",[]]76Aa[\"{AIOjABA`}\",[]]Aa[\"{AIOlABAb}\",[]]Cf[\"{{{AHO`{CGbBFGh}}{KFl{AB@d}}}{{AHO`{CGbBFGh}}}}\",[]]Cf[\"{{{AHO`{CGbBFGj}}{KFl{AB@d}}}{{AHO`{CGbBFGj}}}}\",[]]9;:An[\"{{{AHO`{AONh}}AB@d}ICj}\",[]]B`[\"{{{AHO`{CGbAILf}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbCNj}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbIDh}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbNKl}}CMn}ICj}\",[]]B`[\"{{{AHO`{CGbAILh}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbCNl}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbIDj}}CMn}ICj}\",[]]Ao[\"{{{AHO`{CGbNKn}}CMn}ICj}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Bj[\"{{{AHO`{AILb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMf}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMh}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAd}}}{{KFl{{A@d{A@`}}}}}}\",[]]Db[\"{{{ABb{{AHO`{CGbAJ@`}}}}{AHO`{CGbNIn}}}{{DAh{{KGf{ICj}}}}}}\",[]]Db[\"{{{AHO`{CGbAILd}}NK`B@Oj{AHO`{CGb{ABh{Oh}}}}}{{KFl{ABDj}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{AHO`{CMl}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{AHO`{CMl}}}{{AHO`{CGbBCOn}}}}\",[]]Ak[\"{{{AHO`{AILb}}}BAA`}\",[]]Bj[\"{{{AHO`{AILb}}ICn}{{KGd{ICjBFDd}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Ai[\"{{{AHO`{NJj}}}KCb}\",[]]Ai[\"{{{AHO`{NJl}}}KCb}\",[]]Dh[\"{{{AHO`{B@Kj}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMf}}B@M`}}}}\",[]]Cb[\"{{{AHO`{BABf}}CN`{AHO`{BGAn}}}{{A@d{NMf}}}}\",[]]Dh[\"{{{AHO`{BEJb}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMf}}B@M`}}}}\",[]]Cb[\"{{{AHO`{BEJf}}CN`{AHO`{BGAn}}}{{A@d{NMf}}}}\",[]]Dh[\"{{{AHO`{B@Kn}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Mb}}}}\",[]]Cb[\"{{{AHO`{BABj}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dh[\"{{{AHO`{BEJd}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Mb}}}}\",[]]Cb[\"{{{AHO`{BEJh}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dh[\"{{{AHO`{BHKb}}CN`{AHO`{CMl}}{AHO`{BGAn}}}{{KGd{{A@d{NMh}}B@Ln}}}}\",[]]Cb[\"{{{AHO`{BHKd}}CN`{AHO`{BGAn}}}{{A@d{NMh}}}}\",[]]Dd[\"{{{ABb{{AHO`{CGbc}}}}{AHO`{CGbNIn}}}{{DAh{{KFl{KGd}}}}}{}}\",[\"S\"]]0Bn[\"{{AJ@fBBLbAAj}{{KGh{{KC`{AB@fAIL`}}}}}}\",[]]Bd[\"{{{AHO`{AILd}}}{{AHO`{NMh}}}}\",[]]A`[\"{AOJ`IHj}\",[]]Cb[\"{{{AHO`{AOLn}}DAlAJ@fB@MfNK`}{{KFl{AINn}}}}\",[]]Cb[\"{{{AHO`{BCNj}}DAlAJ@fB@MfNK`}{{KFl{AINn}}}}\",[]]Cb[\"{{{AHO`{AOM`}}DAnAJ@fB@MhNK`}{{KFl{AIO`}}}}\",[]]Cb[\"{{{AHO`{BCNl}}DAnAJ@fB@MhNK`}{{KFl{AIO`}}}}\",[]]B`[\"{{{AHO`{CGbAILd}}NK`}ICj}\",[]]Ca[\"{{{AHO`{CGbAIKn}}}{{KGd{{A@d{A@`}}BCLn}}}}\",[]]Bj[\"{{{AHO`{AILb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMf}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAb}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bi[\"{{{AHO`{NMh}}}{{KFl{{A@d{A@`}}}}}}\",[]]Bj[\"{{{AHO`{AJAd}}}{{KFl{{A@d{A@`}}}}}}\",[]]o[\"{AILnOh}\",[]]o[\"{AIM`Oh}\",[]]Ai[\"{{{AHO`{CMl}}}DC`}\",[]]Aj[\"{{{AHO`{AILf}}}CNb}\",[]]Ai[\"{{{AHO`{CNj}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAIJl}}CNb}{{AHO`{CGbAIJl}}}}\",[]]Ai[\"{{{AHO`{IDh}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAOJn}}CNb}{{AHO`{CGbAOJn}}}}\",[]]Ai[\"{{{AHO`{NKl}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAl}}CNb}{{AHO`{CGbBBAl}}}}\",[]]Aj[\"{{{AHO`{AILh}}}CNb}\",[]]Ai[\"{{{AHO`{CNl}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAIJn}}CNb}{{AHO`{CGbAIJn}}}}\",[]]Ai[\"{{{AHO`{IDj}}}CNb}\",[]]Bn[\"{{{AHO`{CGbAOK`}}CNb}{{AHO`{CGbAOK`}}}}\",[]]Ai[\"{{{AHO`{NKn}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAn}}CNb}{{AHO`{CGbBBAn}}}}\",[]]Aa[\"{AIOdBGB`}\",[]]Ai[\"{{{AHO`{NMf}}}DC`}\",[]]Aj[\"{{{AHO`{AJAb}}}DC`}\",[]]Aj[\"{{{AHO`{AILd}}}DC`}\",[]]Ai[\"{{{AHO`{NMh}}}DC`}\",[]]Aj[\"{{{AHO`{AJAd}}}DC`}\",[]]Co[\"{{{AHO`{NMf}}B@Mf{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]D`[\"{{{AHO`{AJAb}}B@Mf{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]Co[\"{{{AHO`{NMh}}B@Mh{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]D`[\"{{{AHO`{AJAd}}B@Mh{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}DC`}\",[]]Bn[\"{{{AHO`{CGbBFIf}}CMn}{{AHO`{CGbBFIf}}}}\",[]]Bn[\"{{{AHO`{CGbBFIh}}CMn}{{AHO`{CGbBFIh}}}}\",[]]Cd[\"{{{AHO`{CGbNMf}}}{{KFl{{NKb{{A@d{AHDj}}}}}}}}\",[]]Ce[\"{{{AHO`{CGbAJAb}}}{{KFl{{NKb{{A@d{AHDj}}}}}}}}\",[]]Cd[\"{{{AHO`{CGbNMh}}}{{KFl{{NKd{{A@d{AHDl}}}}}}}}\",[]]Ce[\"{{{AHO`{CGbAJAd}}}{{KFl{{NKd{{A@d{AHDl}}}}}}}}\",[]]Bf[\"{{{AHO`{CGbAILf}}CMnCNbNK`}ICj}\",[]]Be[\"{{{AHO`{CGbCNj}}CMnCNbNK`}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}CMnCNbNK`}ICj}\",[]]Be[\"{{{AHO`{CGbCNl}}CMnCNbNK`}ICj}\",[]]Bf[\"{{{AHO`{CGbAILf}}NK`CMnCNb}ICj}\",[]]Be[\"{{{AHO`{CGbCNj}}NK`CMnCNb}ICj}\",[]]Bf[\"{{{AHO`{CGbAILh}}NK`CMnCNb}ICj}\",[]]Be[\"{{{AHO`{CGbCNl}}NK`CMnCNb}ICj}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]De[\"{{{AHO`{CGbBCOl}}c{AHO`{CMl}}}{{AHO`{CGbBCOl}}}{{ICl{D@n}}}}\",[\"\"]]De[\"{{{AHO`{CGbBCOn}}c{AHO`{CMl}}}{{AHO`{CGbBCOn}}}{{ICl{D@n}}}}\",[\"\"]]Ci[\"{{{AHO`{CGbNMf}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`IEl}}}}\",[]]Cj[\"{{{AHO`{CGbAJAb}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`IEl}}}}\",[]]Cj[\"{{{AHO`{CGbNMh}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`BCAb}}}}\",[]]Ck[\"{{{AHO`{CGbAJAd}}{AHO`{{K@j{Oh}}}}}{{KGd{DC`BCAb}}}}\",[]]o[\"{AAjDC`}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]Ca[\"{{{AHO`{CGbAIOd}}}{{KGd{{KFl{KI`}}AIOh}}}}\",[]]Ca[\"{{{AHO`{CGbBGB`}}}{{KGd{{KFl{KI`}}AIOh}}}}\",[]]Ca[\"{{{AHO`{CGbAIOf}}}{{KGd{{KFl{KIb}}B@Ll}}}}\",[]]Ak[\"{{{AHO`{AIKn}}}AJ@f}\",[]]Ak[\"{{{AHO`{ABA`}}}AJ@f}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{AJ@fAIKd}}}}\",[]]Ak[\"{{{AHO`{ABAb}}}AJ@f}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]B`[\"{{KI`c}KI`{{D@b{KI`}}}}\",[\"\"]]B`[\"{{KFnc}KFn{{D@b{KFn}}}}\",[\"\"]]B`[\"{{KIbc}KIb{{D@b{KIb}}}}\",[\"\"]]B`[\"{{KG`c}KG`{{D@b{KG`}}}}\",[\"\"]]20Ae[\"{{AB@dCNb}AG`}\",[]]Bn[\"{{{AHO`{CGbBCOl}}AFn}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}AFn}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{IHjAB@d}\",[]]B`[\"{{}{{AHO`{{K@j{BG@n}}}}}}\",[]]An[\"{{AHO`{ONf{CGbOh}}}ICj}\",[]]00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000An[\"{{}{{KFl{{A@b{NMd}}}}}}\",[]]Bn[\"{{{AHO`{CGbBBMh}}DC`}{{AHO`{CGbBBMh}}}}\",[]]Bn[\"{{{AHO`{CGbBBMj}}DC`}{{AHO`{CGbBBMj}}}}\",[]]Aj[\"{{{AHO`{AHDj}}}CNb}\",[]]Aj[\"{{{AHO`{AHDl}}}CNb}\",[]]A`[\"{ABC`KFl}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Bf[\"{{{AHO`{CMl}}}{{KGh{CNbBBB`}}}}\",[]]Bn[\"{{{AHO`{AB@h}}{A@d{BBL`}}}{{KGf{ICj}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Cj[\"{{{AHO`{NMb}}BBLbBBBj{AHO`{AAj}}}{{KC`{AJ@fAB@f}}}}\",[]]Cb[\"{{{AHO`{CGbAILd}}KG`AINl}{{KGd{AINlBFKf}}}}\",[]]Am[\"{{{AHO`{AILb}}CNb}ICj}\",[]]B`[\"{{{AHO`{CGbAILd}}CNb}ICj}\",[]]A`[\"{BC@jDC`}\",[]]B`[\"{{{AHO`{CGbIHj}}BC@l}ICj}\",[]]Aa[\"{AONfAHD`}\",[]]Bn[\"{{{AHO`{NMd}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Bo[\"{{{AHO`{BACb}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Bo[\"{{{AHO`{AOMl}}AHFl}{{KGf{{A@d{BBL`}}}}}}\",[]]Ci[\"{{{AHO`{CGbNMf}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@d}}}}\",[]]Cj[\"{{{AHO`{CGbAJAb}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@d}}}}\",[]]Ci[\"{{{AHO`{CGbNMh}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@f}}}}\",[]]Cj[\"{{{AHO`{CGbAJAd}}{AHO`{CGb{ABh{Oh}}}}}{{KFl{D@f}}}}\",[]]Cb[\"{{{AHO`{ABD`}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{BANd}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{B@Ol}}IChAJ@lAB@d}{{KGd{ICjBCOf}}}}\",[]]Cb[\"{{{AHO`{ABDb}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{BANf}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Cb[\"{{{AHO`{B@On}}IChAJ@lAB@d}{{KGd{ICjBCOh}}}}\",[]]Al[\"{{}{{KGd{B@KfBGI`}}}}\",[]]Bn[\"{{{AHO`{AILb}}KFn}{{KFl{{A@d{AILf}}}}}}\",[]]Bo[\"{{{AHO`{AILd}}KG`}{{KFl{{AHO`{AILh}}}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Aj[\"{{{AHO`{AILb}}}ICj}\",[]]Am[\"{{{AHO`{CGbAILd}}}ICj}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAjIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{A@hIEn}}}}\",[]]Bg[\"{{{AHO`{AIJb}}}{{KGd{AAOfIEn}}}}\",[]]Bg[\"{{{AHO`{AIJb}}}{{KGd{AHAlIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAlIEn}}}}\",[]]Bf[\"{{{AHO`{AIJb}}}{{KGd{AAnIEn}}}}\",[]]Ak[\"{{{AHO`{BCAd}}}B@Oj}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AOL`}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AOLb}}}{{AHO`{CGbBCOn}}}}\",[]]<;Aj[\"{{{AHO`{AB@h}}}KCb}\",[]]Aj[\"{{{AHO`{AB@j}}}KCb}\",[]]Bo[\"{{{AHO`{AILb}}cAINj}ABBh{{D@b{AHCb}}}}\",[\"\"]]Co[\"{{{AHO`{CGbAILd}}AHCdAINlNK`}{{KGd{{KC`{KG`DC`}}AHEb}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CN`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CN`}{{AHO`{CGbBCOn}}}}\",[]]Df[\"{{{AHO`{CGbAIOd}}{AHO`{CGb{K@j{ICn}}}}}{{KGd{{KFl{KCb}}AHFb}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Bg[\"{{{AHO`{BCAd}}AJAj}{{KGf{KCb}}}}\",[]]A`[\"{AHAlCNb}\",[]]10Aj[\"{{{AHO`{AAj}}}BCOj}\",[]]Cf[\"{{{AHO`{CGbBABd}}{A@b{BCOl}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kh}}{A@b{BCOl}}}{{AHO`{CGbB@Kh}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{A@b{BCOn}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbB@Kl}}{A@b{BCOn}}}{{AHO`{CGbB@Kl}}}}\",[]]Aa[\"{BABdBH@l}\",[]]Aa[\"{BABhBH@n}\",[]]Bj[\"{{{ABh{BBLb}}BBBj}{{KGd{BABdIFb}}}}\",[]]Bj[\"{{{ABh{BBLb}}BBBj}{{KGd{BABhIFd}}}}\",[]]Co[\"{{{AHO`{CGbAJ@`}}{AHO`{CGb{K@j{ICn}}}}}{{KGd{ICjAJAl}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]A`[\"{BFBjCNb}\",[]]A`[\"{BFBlCNb}\",[]]Bc[\"{{{AHO`{AILb}}}{{KFl{KCb}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Aj[\"{{{AHO`{AHBb}}}KCb}\",[]]Be[\"{{{AHO`{AB@h}}{KFl{BABd}}}ICj}\",[]]Bo[\"{{{AHO`{CGbAB@j}}{KFl{{A@b{BABh}}}}}ICj}\",[]]Bd[\"{{{AHO`{BG@n}}}{{KFl{BBBh}}}}\",[]]Aj[\"{{{AHO`{AB@h}}}ICj}\",[]]Dj[\"{{{AHO`{CGbAJ@`}}{AHO`{CGb{AHO`{CGb{K@j{ICn}}}}}}}{{KGd{KCbAJAl}}}}\",[]]o[\"{{}AHO`}\",[]]n[\"{{}NIl}\",[]]0000Bn[\"{{{AHO`{CGbBCOl}}KCb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KCb}{{AHO`{CGbBCOn}}}}\",[]]o[\"{CNbKI`}\",[]]o[\"{CNbKIb}\",[]]A`[\"{BAOfCNb}\",[]]Bf[\"{{{AHO`{BGJ`}}{AHO`{BGJ`}}}DC`}\",[]]Bo[\"{{{AHO`{CGbBBMh}}AB@d}{{AHO`{CGbBBMh}}}}\",[]]Bo[\"{{{AHO`{CGbBBMj}}AB@d}{{AHO`{CGbBBMj}}}}\",[]]Ae[\"{{KCbCNb}BANd}\",[]]Ae[\"{{KCbCNb}BANf}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]7Bg[\"{{{AHO`{AILd}}KG`}{{KFl{AINl}}}}\",[]]An[\"{{{AHO`{AILb}}ICn}BAAn}\",[]]Bm[\"{{{AHO`{CGbBEJb}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJf}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJd}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Bm[\"{{{AHO`{CGbBEJh}}{ABh{{ABh{Oh}}}}}ICj}\",[]]Am[\"{{{AHO`{AILb}}KI`}ICj}\",[]]B`[\"{{{AHO`{CGbAILd}}KIb}ICj}\",[]]Ce[\"{{{AHO`{CGbBBMh}}{ABh{CN`}}}{{AHO`{CGbBBMh}}}}\",[]]Ce[\"{{{AHO`{CGbBBMj}}{ABh{CN`}}}{{AHO`{CGbBBMj}}}}\",[]]Fg[\"{{{AHO`{BHEb}}{AHO`{BBLb}}{AHO`{{K@j{BBLb}}}}{AHO`{AJ@d}}{AHO`{{K@j{Oh}}}}ABEb}{{KGd{BFK`IEh}}}}\",[]]Af[\"{{BCNjNK`}BCNj}\",[]]Af[\"{{BCNlNK`}BCNl}\",[]]A`[\"{BAOfCNb}\",[]]Al[\"{BACd{{KGd{DAlIF`}}}}\",[]]Al[\"{BACd{{KGd{A@jIF`}}}}\",[]]Ai[\"{BACd{{KGj{DAn}}}}\",[]]Ai[\"{BACd{{KGj{A@l}}}}\",[]]o[\"{NIlNIl}\",[]]Bo[\"{{{AHO`{CGbBFIf}}AB@d}{{AHO`{CGbBFIf}}}}\",[]]Bo[\"{{{AHO`{CGbBFIh}}AB@d}{{AHO`{CGbBFIh}}}}\",[]]Bb[\"{{{AHO`{NMf}}}{{KFl{DC`}}}}\",[]]Bc[\"{{{AHO`{AJAb}}}{{KFl{DC`}}}}\",[]]Bb[\"{{{AHO`{NMh}}}{{KFl{DC`}}}}\",[]]Bc[\"{{{AHO`{AJAd}}}{{KFl{DC`}}}}\",[]]Bg[\"{{{AHO`{AILb}}}{{KGd{ICjBCLn}}}}\",[]]Ba[\"{{{AHO`{BFCf}}KFnAHCb}DC`}\",[]]Ba[\"{{{AHO`{BFCh}}KG`AHCd}DC`}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AB@d}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AB@d}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Bo[\"{{{AHO`{CGbAILf}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbCNj}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbIDh}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbNKl}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bo[\"{{{AHO`{CGbAILh}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbCNl}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbIDj}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]Bn[\"{{{AHO`{CGbNKn}}NK`NK`DC`DC`CNbCNb}ICj}\",[]]A`[\"{BAOfCNb}\",[]]Al[\"{{{AHO`{NNf}}A@l}CNb}\",[]]Bi[\"{{{AHO`{CGbAIOn}}CNb}{{KGh{ICj}}}}\",[]]<;A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]10Cf[\"{{{AHO`{CGbBCOl}}{KFl{BFGh}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{BFGj}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAjIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{A@hIEn}}}}\",[]]Bj[\"{{{AHO`{CGbAIJb}}}{{KGd{AAOfIEn}}}}\",[]]Bj[\"{{{AHO`{CGbAIJb}}}{{KGd{AHAlIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAlIEn}}}}\",[]]Bi[\"{{{AHO`{CGbAIJb}}}{{KGd{AAnIEn}}}}\",[]]Cd[\"{{{A@b{AIL`}}CNbDC`}{{KGh{{KC`{BC@lBC@l}}}}}}\",[]]Bn[\"{{{AHO`{CGbBABd}}CNb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}CNb}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{AILb}}}DC`}\",[]]Ak[\"{{{AHO`{BBL`}}}B@Oj}\",[]]0Ci[\"{{{AHO`{CGbBBMh}}CMn}{{KGd{{AHO`{CGbBBMh}}AOJd}}}}\",[]]Ci[\"{{{AHO`{CGbBBMj}}CMn}{{KGd{{AHO`{CGbBBMj}}AOJf}}}}\",[]]A`[\"{AHAlCMn}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{BFIf}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{BFIh}}}{{AHO`{CGbBCOn}}}}\",[]]Bg[\"{{{AHO`{CGbAILd}}}{{KFl{BAOd}}}}\",[]]Cf[\"{{{AHO`{CGbBABd}}{KFl{BABl}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{KFl{BABl}}}{{AHO`{CGbBABh}}}}\",[]]Cf[\"{{{AHO`{CGbBABd}}{KFl{BABn}}}{{AHO`{CGbBABd}}}}\",[]]Cf[\"{{{AHO`{CGbBABh}}{KFl{BABn}}}{{AHO`{CGbBABh}}}}\",[]]Cd[\"{{}{{KGd{{KC`{{ABh{BBLb}}BBBj}}{A@d{IEd}}}}}}\",[]]Bn[\"{{{AHO`{CGbBFGh}}KI`}{{AHO`{CGbBFGh}}}}\",[]]Bn[\"{{{AHO`{CGbBFGj}}KIb}{{AHO`{CGbBFGj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bo[\"{{{AHO`{CGbBABd}}AB@d}{{AHO`{CGbBABd}}}}\",[]]Bo[\"{{{AHO`{CGbBABh}}AB@d}{{AHO`{CGbBABh}}}}\",[]]Ci[\"{{{AHO`{DA`}}{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKd}}}}\",[]]Bj[\"{{{AHO`{BCAd}}AJAjKCb}{{KGf{ICj}}}}\",[]]054Bm[\"{{{AHO`{NMf}}}{{KGd{{KFl{BGAn}}IEl}}}}\",[]]Bn[\"{{{AHO`{AJAb}}}{{KGd{{KFl{BGAn}}IEl}}}}\",[]]Bn[\"{{{AHO`{NMh}}}{{KGd{{KFl{BGAn}}BCAb}}}}\",[]]Bo[\"{{{AHO`{AJAd}}}{{KGd{{KFl{BGAn}}BCAb}}}}\",[]]Aj[\"{{{AHO`{AHDj}}}CNb}\",[]]Aj[\"{{{AHO`{AHDl}}}CNb}\",[]]Bl[\"{{{AHO`{AB@h}}{KFl{{A@b{BFCf}}}}}ICj}\",[]]Cc[\"{{{AHO`{CGbAILd}}{KFl{{AHO`{BFCh}}}}NK`}ICj}\",[]]Aj[\"{{{AHO`{AB@j}}}CNb}\",[]]Bn[\"{{{AHO`{CGbBBAl}}AFn}{{AHO`{CGbBBAl}}}}\",[]]Bn[\"{{{AHO`{CGbBBAn}}AFn}{{AHO`{CGbBBAn}}}}\",[]]Ak[\"{{{AHO`{AHFj}}}B@Oj}\",[]]0Ak[\"{{{AHO`{AILb}}}BGA`}\",[]]Cb[\"{{{AHO`{AILd}}KG`}{{KGd{{KFl{AJ@f}}AIKj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{AHAlKFl}\",[]]Bo[\"{{{AHO`{AHAl}}{AHO`{CMl}}}{{KGf{BCOj}}}}\",[]]Em[\"{{{AHO`{AILb}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]El[\"{{{AHO`{NMf}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]Em[\"{{{AHO`{AJAb}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHLn}}}}\",[]]El[\"{{{AHO`{NMh}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]Em[\"{{{AHO`{AJAd}}{AHO`{CGb{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}{AHO`{{K@j{Oh}}}}}{{KGd{ICjBHM`}}}}\",[]]Am[\"{{{AHO`{CGbAHB`}}}ICj}\",[]]0Am[\"{{{AHO`{AILd}}A@l}CNb}\",[]]Ak[\"{{{AHO`{AILb}}}BGIb}\",[]]Bg[\"{{{AHO`{DA`}}}{{KGd{BEFbAIKd}}}}\",[]]>=E`[\"{{{AHO`{BHEb}}{AHO`{{K@j{Oh}}}}{AHO`{BBLb}}{AHO`{BGOn}}}{{KGd{BHGhIEh}}}}\",[]]0Bg[\"{{{A@b{BBCb}}}{{KGd{B@KhBGIn}}}}\",[]]Bg[\"{{{A@b{BBCb}}}{{KGd{B@KlBGIn}}}}\",[]]Bn[\"{{{AHO`{CGbBFGh}}KI`}{{AHO`{CGbBFGh}}}}\",[]]Bn[\"{{{AHO`{CGbBFGj}}KIb}{{AHO`{CGbBFGj}}}}\",[]]o[\"{NIlNIl}\",[]]0000Aj[\"{{{AHO`{AILd}}}DC`}\",[]]0Bd[\"{{{AHO`{CGbAILf}}CNbAB@d}ICj}\",[]]Bc[\"{{{AHO`{CGbCNj}}CNbAB@d}ICj}\",[]]Bd[\"{{{AHO`{CGbAILh}}CNbAB@d}ICj}\",[]]Bc[\"{{{AHO`{CGbCNl}}CNbAB@d}ICj}\",[]]Ci[\"{{{AHO`{DA`}}{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKd}}}}\",[]]Cd[\"{{{AHO`{CGbAAj}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbA@h}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Ce[\"{{{AHO`{CGbAAOf}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Ce[\"{{{AHO`{CGbAHAl}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbAAl}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Cd[\"{{{AHO`{CGbAAn}}{AHO`{AIJb}}}{{KGd{ICjIEn}}}}\",[]]Bo[\"{{{AHO`{CGbBABd}}BH@l}{{AHO`{CGbBABd}}}}\",[]]Bo[\"{{{AHO`{CGbBABh}}BH@n}{{AHO`{CGbBABh}}}}\",[]]Aj[\"{{{AHO`{BBMh}}}CNb}\",[]]Aj[\"{{{AHO`{BBMj}}}CNb}\",[]]Cd[\"{{{AHO`{CGbB@Kh}}{A@b{A`}}}{{AHO`{CGbB@Kh}}}}\",[]]Cd[\"{{{AHO`{CGbB@Kl}}{A@b{A`}}}{{AHO`{CGbB@Kl}}}}\",[]]Cl[\"{{BBMh{KFl{BABd}}{A@d{BBL`}}{A@b{NMd}}}{{KGf{AB@h}}}}\",[]]Aj[\"{{{AHO`{ABA`}}}DC`}\",[]]Aj[\"{{{AHO`{ABAb}}}DC`}\",[]]Ca[\"{{{AHO`{CGbAILd}}NK`AIMn}{{KGd{ICjBHDj}}}}\",[]]Bd[\"{{{AHO`{BHEb}}}{{ABh{BCOb}}}}\",[]]Bj[\"{{{AHO`{AILb}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bm[\"{{{AHO`{CGbAILd}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KCb}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KCb}{{AHO`{CGbBCOn}}}}\",[]]Bm[\"{{}{{KGd{{KC`{BBLbBFJb}}{A@d{IEd}}}}}}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]A`[\"{AILnCNb}\",[]]A`[\"{AIM`CNb}\",[]]An[\"{{{AHO`{AB@h}}B@Kh}ICj}\",[]]Dc[\"{{{AHO`{CGbAILd}}NK`KG`{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKj}}}}\",[]]o[\"{{}AHO`}\",[]]Aj[\"{{{AHO`{AILb}}}KCb}\",[]]Bn[\"{{{AHO`{CGbBABd}}CNb}{{AHO`{CGbBABd}}}}\",[]]Bn[\"{{{AHO`{CGbBABh}}CNb}{{AHO`{CGbBABh}}}}\",[]]Bn[\"{{{AHO`{CGbBCOl}}KI`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}KIb}{{AHO`{CGbBCOn}}}}\",[]]:Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Bc[\"{{{AHO`{CGbAILd}}A@lKIb}ICj}\",[]]A`[\"{AHElCNb}\",[]]A`[\"{AHEnCNb}\",[]]Ak[\"{{}{{KGd{B@KhIFb}}}}\",[]]Ak[\"{{}{{KGd{B@KlIFd}}}}\",[]]6587Cg[\"{{{AHO`{CGbAAj}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbA@h}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Ch[\"{{{AHO`{CGbAAOf}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Ch[\"{{{AHO`{CGbAHAl}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbAAl}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]Cg[\"{{{AHO`{CGbAAn}}{AHO`{CGbAIJb}}}{{KGd{ICjIEn}}}}\",[]]n[\"{{}ICj}\",[]]Ce[\"{{{AHO`{CGbBCOl}}{KFl{KCb}}}{{AHO`{CGbBCOl}}}}\",[]]Ce[\"{{{AHO`{CGbBCOn}}{KFl{KCb}}}{{AHO`{CGbBCOn}}}}\",[]]Bn[\"{{{AHO`{AILb}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Cd[\"{{{AHO`{CGbAILd}}NK`}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Am[\"{{{AHO`{CGbAILf}}}ICj}\",[]]Al[\"{{{AHO`{CGbCNj}}}ICj}\",[]]Al[\"{{{AHO`{CGbIDh}}}ICj}\",[]]Am[\"{{{AHO`{CGbAILh}}}ICj}\",[]]Al[\"{{{AHO`{CGbCNl}}}ICj}\",[]]Al[\"{{{AHO`{CGbIDj}}}ICj}\",[]]Ai[\"{AIL`{{KGh{ICj}}}}\",[]]Bj[\"{{{AHO`{AILb}}AJ@f}{{KGd{ICjIFh}}}}\",[]]Bm[\"{{{AHO`{CGbAILd}}AJ@f}{{KGd{ICjIFh}}}}\",[]]D`[\"{{{AHO`{CGbAILd}}KG`{KFl{AB@d}}}{{KGd{{KFl{AB@d}}AIKj}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{A@b{BFBf}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{A@b{BFBh}}}{{AHO`{CGbBCOn}}}}\",[]]Cf[\"{{{AHO`{CGbBCOl}}{KFl{AB@d}}}{{AHO`{CGbBCOl}}}}\",[]]Cf[\"{{{AHO`{CGbBCOn}}{KFl{AB@d}}}{{AHO`{CGbBCOn}}}}\",[]]Ce[\"{{{AHO`{CGbBCOl}}{KFl{CNb}}}{{AHO`{CGbBCOl}}}}\",[]]Ce[\"{{{AHO`{CGbBCOn}}{KFl{CNb}}}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{BAOjKFl}\",[]]A`[\"{BAOlKFl}\",[]];Bn[\"{{{AHO`{CGbBCOl}}DC`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}DC`}{{AHO`{CGbBCOn}}}}\",[]]Am[\"{{{AHO`{AILb}}KI`}ICj}\",[]]o[\"{NIlNIl}\",[]]Bn[\"{{{AHO`{CGbBCOl}}CN`}{{AHO`{CGbBCOl}}}}\",[]]Bn[\"{{{AHO`{CGbBCOn}}CN`}{{AHO`{CGbBCOn}}}}\",[]]310;:54Bn[\"{{{AHO`{AILb}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]Bn[\"{{{AHO`{AILd}}}{{KGd{{ABh{AJ@f}}IFh}}}}\",[]]10Bm[\"{{{AHO`{CGbBCOl}}Oh}{{AHO`{CGbBCOl}}}}\",[]]Bm[\"{{{AHO`{CGbBCOn}}Oh}{{AHO`{CGbBCOn}}}}\",[]]A`[\"{BGAnKFl}\",[]]") \ No newline at end of file diff --git a/pr/720/docs/search.index/generic_inverted_index/5e274bd1d1e0.js b/pr/720/docs/search.index/generic_inverted_index/5e274bd1d1e0.js deleted file mode 100644 index 735c3af32..000000000 --- a/pr/720/docs/search.index/generic_inverted_index/5e274bd1d1e0.js +++ /dev/null @@ -1 +0,0 @@ -rb_("QU5sADswAAABAADuAAIAbQPtAFYMAAA7MAAAAQAAawIqACQCGAA+AgwATAIAAE4CAABRAgEAVAICAFoCAABcAgcAaQIDAG4CCAB4AgAAewIGAIMCBACKAgEAjQIAAI8CAwCUAgMAmQIBAJwCDwC3AhYA0wIDANgCEQDrAgMA8AIFAPcCAwD8AgAA/gIEAAQDBQALAwYAEwMEABkDAAAbAwQAIQMCACUDAQAoAwcAMgMAADwDCwBJAw0AdQmMAAIL7QAVEAAAwhABADswAAABAADeAQ4AlwACAM0F7QACCjYAPAoSAFAKBQBXChwAdgoBAHoKFACRCgAAkwoeALMKBQC6CikA5goCAOsKFgA7MAAAAQAAIwELAG0CAADXAgAASAMAAIQHEwCyCgAAuQoAAOQKAADqCgAAnQ4EARwQAQBTEAEAOzAAAAEAAIUBBwBhBAAAQAkBAOUKAADpCgAAGA3tAAgOjADXEQUAOzAAAAEAAAYAAgDWBgMA2wYCADswAAABAAAsAAcAVwMVAJsFAADRBgQA3wYMADsJAQBnDAAA+BIAADswAAABAAAKAAIAfgQAAPALCQA7MAAAAQAADAABAG0EDAA7MAAAAQAABQACAGwMAwBYEQEAAsQRAADFEQAAAAAAAtEBAADaBgAAQ24AAAA7MAAAAQAA7QAMAAIKNgA8ChIAUAoFAFcKHAB2CgEAegoUAJEKAACTCh4AswoFALoKKQDmCgIA6woWAA==") \ No newline at end of file diff --git a/pr/720/docs/search.index/generic_inverted_index/af191f824100.js b/pr/720/docs/search.index/generic_inverted_index/af191f824100.js new file mode 100644 index 000000000..f287b2042 --- /dev/null +++ b/pr/720/docs/search.index/generic_inverted_index/af191f824100.js @@ -0,0 +1 @@ +rb_("QU9nADswAAABAADuAAIAbQPtAFYMAAA7MAAAAQAAawIqACQCGAA+AgwATAIBAFACAABSAgAAVAICAFkCAABcAgcAaQIDAG4CCQB7AgUAggIEAIkCAgCNAgEAkAIBAJMCBQCaAgEAnQINALUCAAC3AhYA0wIDANgCEQDrAgMA8AIFAPcCAwD8AgAA/gIEAAQDBQALAwYAEwMEABkDAAAbAwQAIQMCACUDAQAoAwcAMgMAADwDCwBJAw0AdQmMAAIL7QAVEAAAwhABADswAAABAADeARAAlwACAM0F7QACCjYAPAoSAFAKBgBYChsAdQoAAHcKAAB5CgAAewoTAJEKAACTCh4AswoFALoKKQDmCgIA6woWADswAAABAAAjAQsAbQIAANcCAABIAwAAhAcTALIKAAC5CgAA5AoAAOoKAACdDgQBHBABAFMQAQA7MAAAAQAAhQEHAGEEAABACQEA5QoAAOkKAAAYDe0ACA6MANgRBQA7MAAAAQAABgACANYGAwDbBgIAOzAAAAEAACwABwBXAxUAmwUAANEGBADfBgwAOwkBAGcMAAD5EgAAOzAAAAEAAAoAAgB+BAAA8AsJADswAAABAAAMAAEAbQQMADswAAABAAAFAAIAbAwDAFkRAQACxREAAMYRAAAAAAAB0QEAAAAAAdoGAABFaQAAADswAAABAADtAA4AAgo2ADwKEgBQCgYAWAobAHUKAAB3CgAAeQoAAHsKEwCRCgAAkwoeALMKBQC6CikA5goCAOsKFgAAAAAAAAAAAAAAAAAAAAHaBgAA") \ No newline at end of file diff --git a/pr/720/docs/search.index/name/b64d8369dc91.js b/pr/720/docs/search.index/name/a216655cbdda.js similarity index 52% rename from pr/720/docs/search.index/name/b64d8369dc91.js rename to pr/720/docs/search.index/name/a216655cbdda.js index 72651b222..f1458e399 100644 --- a/pr/720/docs/search.index/name/b64d8369dc91.js +++ b/pr/720/docs/search.index/name/a216655cbdda.js @@ -1 +1 @@ -rd_("b()b->bBi0bCe00bFnbIdbOkb[]beq000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bid000000000000000000brtbtybu8cAck0cAddcAnycArccBoxcBufcClicDir0cErrcMAX000cNotcOpt00cOrdcPincUni0cVeccadd00000ccmp0000000000000000000cdir000cecn000cf32cf64cfmt00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cget0ci32cimpcios0clen000clog0cmincmutcnew00000000000000000000000000000000000cnoqcnot0cnow000000crtt000crun0cstrcu16cu32cu64cudpdArgsdAsFddBbr300dDropdEct000dEct100dFromdHashdIntodKeys0dLong0dNonedPath00dPing0dPolldReaddSide0dZERO0dacks0daddr00dbbr3dbooldbulkdcodedcwnd0ddataddrop000000dfrom000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dhash000000000000000000000dinto000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dmain0000dnext0dopen00dpath0dperfdping000dpoll00000000000000dqlogdread00drecv00dseal0dsend00dsent0dside0dsign0dsize00dsmoldspindstop00dtake00000du128duniteAsRefeByteseChunk0eCloneeCloseeCubic00eDebugeDerefeError00000000000eEvent00eKnowneOther0eRangeeReset000eRetry0eShort0eSizedeStats0eSuiteeTokioeWriteealpns0earrayebenchebuild00000000ebytes000ecauseeclone00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eclose000ecubicederef0eerroreframe0eindex0eis_ce0elocal0eparse0epaths0eprint00ereset00eretry0esliceespawn00estats0000000000etitle0etokenetokioetupleeusizeewrite00fAcceptfAckEcn0fAes128fAes256fBackup0fBorrowfBufMutfChunksfClient00fClosed0fCrypto0fCursorfFuturefHasherfIpAddrfLaggedfOpenBifOpened0fOptionfPathId0fResult00000fServer00fStream000fStringfTypeIdfVarInt0faccept000fborrow000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fcipherfclient0000fclosedfcoding0fconfig0fcrypto0000000000fdecode000000000000fdst_ipfencode000000000000ffinish00fhandlefheader0fignore0finsert00000fkeylogfoffset0fon_ack0000000fpacket00frandomfreason00000000frebindfrefuse0fremote000frustls00000fserver0000fsharedfsource00000000fsrc_ip00fstatus00fstream0fstridefudp_rx000fudp_tx000fvarintfverify0fwindow0000000gBlocked00gCommandgContextgDefaultgDisplaygFromStrgGeneral0gHmacKey0gInitialgInstantgKeyPair0gLayeredgMaxData0gNewReno00gOpenUnigPadding0gPathAck0gPathBufgReadBufgRequestgRuntime0gSession0gStopped00000gStreamsgToOwnedgTooLonggTryFromgTryIntogUnknowngZeroRttgcid_len000gclientsgcommand00000gcompare0000000000000000000gconnect0gdecrypt00000gdefault000000000000000000000000000000000000000000000000000gdrainedgdst_cid0000000gencrypt000gis_0rtt0gmetrics0000000gmin_mtu0gnoq_udpgon_sent0gopen_bigpath_idgpointergruntimegsrc_cid0000gstopped0gstreams000gtag_len0gtype_id000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gupgrade0gversion00000hAcceptBihBytesMuthChacha20hCommandshDatagram00hDerefMuthDisabled0hDurationhEndpoint00hFinished0hIncoming0hIteratorhLayerExthLongTypehMAX_SIZE0hNO_ERROR0hNewToken0hOnClosedhOpenPathhOrderinghReadable0hRecvMetahResponsehStreamId0hTimedOut00hToStringhTokenLog0hTooLarge0hTransmit00hUdpStats0hUnixTimehWritable0hcong_alghcontentshdatagram0hdurationhendpoint0hfinalizehframe_rx000hframe_tx000hfrom_buf0hfrom_env0hfrom_keyhfrom_str0hfrom_u320hfrom_u640hgot_type000hgroup_id0000hhas_0rtthincominghinterval0hinto_any0000000his_alivehlifetime0hlocal_ip00000hmax_data0hmax_sizehnew_renohnoq_perfhon_byteshopen_unihpriority0hprotocol0hqlog_dirhresponsehrng_seed0hssthresh0hto_owned00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000htry_from000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000htry_into000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000htry_poll000000000htry_sendhvalidate000iAbandoned000iAcceptUniiAddAssigniArbitraryiAsyncRead0iAvailable000iBorrowMutiCommonOptiConnectediCriterioniDatagramsiDecodableiDiscarded000iEncodableiFormatteriFourTuple0iFrameType0iHandshakeiHeaderKey0iHistogramiMalformediMaxPathId0iMultipathiPacketKey0iPartialEqiPathError0iPathEvent000iPathStats0iReadError00iTryFutureiTryStreamiUdpSenderiUdpSocketiValueEnumiaccept_biiarbitrary0000000ias_rustlsiassemblericlone_box0000000idatagrams000ideref_mut0ifrom_bits00iinitiator0iinto_0rttiinto_iteriis_client0iis_closediis_server0imay_retry0imigration0inew_timer00inew_token0inoq_protoion_closediopen_path0ipath_acks0iping_pathipoll_next000ipoll_read00ipoll_recvipoll_sendireach_out0ireferenceireset_key0iretry_tag0000isize_hint000istable_idito_string0000000000000000000000000000000000000000000000000000000000000000000itoken_key0itoken_positransport00iwait_idleiwrite_alljArgMatchesjAsyncTimerjAsyncWrite0jBATCH_SIZEjBbr3Config0jClosedPath00000jComparablejConnectingjConnection00jController0jEquivalent0jFrameStats0jIntoFuturejInvalidCid0jIoSliceMutjMaybeFrame0jNonZeroU32jOtherErrorjPartialOrdjPathAckEcn0jPathEventsjPathStatus0jQlogConfig0jRecvStream00jResetErrorjRetryError0jSendStream00jServerNamejSocketAddrjStreamInfojSubcommandjSystemTimejTimeSource0jTlsSession0jTokenStore0jUdpSockRefjWriteError0jaccept_unijadd_assign00000jallow_spin0jborrow_mut000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000jbytes_read0jclone_into00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000jclose_pathjcongestion000jconn_statsjconnection0jequivalent00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000jerror_code000000jframe_type0jinto_inner0jis_drained0jlocal_addr0jlost_bytes000jnew_senderjpad_to_mtu0jpath_stats0000jpoll_closejpoll_flush0jpoll_write00jprint_jsonjread_chunk0jread_exactjset_statusjstart_time0jthroughputjtotal_sizekAcceptErrorkCLIENT_ADDRkCipherSuitekClientStatskCloseReasonkConfigError0kContentTypekCryptoError0kCubicConfig0kDataBlocked0kEstablished000kFinishErrorkIdleTimeout0kIntoRequestkOutOfBounds0kPathAbandon0kQlogFactory0kResetStream0kRuntimeTypekSERVER_ADDRkSERVER_NAMEkSmolRuntimekStopSending0kStreamEvent0kStreamStats0kaccept_withkadd_address0kbind_socketkcertificatekcurrent_mtu00kdescription0kdestination00kfrom_remote0kinitial_mtu000kinitial_rtt00kinto_future0000000000000kis_drainingkmax_path_id0kmax_streamsknamed_layer0kon_end_acks000kon_intervalkpacing_rate0kpartial_cmp0000000000000000000kpath_eventskpath_statuskread_to_endkrecv_stream0ksample_size0ksend_bufferksend_stream0ksend_window00kserver_name0ktime_source0ktoken_store0kupload_sizekupper_bound0kweak_handle0kwith_crypto0kwith_prefix0kwrite_chunklAckFrequency0lAddressAddedlClientConfig00000lClosedStream000000lConnectError00lConnectionId00lDatagramInfolDecryptError0lEcnCodepoint00lEncryptError0lIllegalValuelImmediateAck0lIntoIteratorlLOCALHOST_V4lLastOpenPath0lNatTraversallNonZeroUsizelNoneTokenLog0lObservedAddr000lPathResponse0lPathsBlocked0lReadDatagramlRemoteStatus000lRttEstimator0lSendDatagramlServerConfig00000lSocketAddrV4lSocketAddrV6lStoppedErrorlTokioRuntimelUnstructuredlaugment_args0000lcid_lifetime000lclose_reasonlconnect_withlconservativeldata_blocked0ldrain_streamlearly_crypto000levent_streamlexpect_types000lgenerate_cid000lgro_segmentslhandle_event0linitial_keys00000000linto_request0llost_packets000lmax_incoming0lmay_fragment00lnetwork_path0lnew_receiverlnoprotection0lorig_dst_cid0lpath_abandon0lpoll_timeoutlqlog_factory0lreset_stream0lruntime_typelsegment_size00lsend_quantum0lsend_streamslset_lifetime0lset_priority0lstop_sending0lstream_statslupload_statslwith_initial000lwrite_chunksmAlertReceived0mBloomTokenLog0mCidsExhausted000mCloneToUninitmDatagramEventmEndpointEventmEndpointStatsmFinishedEarlymHandshakeData0mHandshakeDone0mHandshakeTypemINVALID_TOKEN0mIncomingAlpns0mInvalidHeadermLocallyClosed0mMaxStreamData0mMaxStreamsUni0mNewConnectionmNewRenoConfig0mParseIntErrormPartialDecodemPathChallenge0mPossibleValuemPrivateKeyDermReadableErrormRemoveAddress0mRootCertStoremStdSystemTime0mUnexpectedEndmaccepted_0rttmack_frequency00mbench_exports0mcid_generator00mcreate_sendermdata_transfermdownload_sizemduration_histmimmediate_ack0minto_incoming0mmax_ack_delay0mno_protectionmobserved_addr0mon_first_bytemon_mtu_update0000000mpath_response0mpaths_blocked0mpeer_identity0000mpoll_shutdownmpoll_transmitmqlog_from_env0mread_datagrammsend_datagrammsend_fairness0msignature_len0mstart_session000000000mtry_poll_next0nAddIpv4Address0nAddIpv6Address0nAddressRemovednAsyncUdpSocketnCertificateDernClosePathError0nCommandFactorynConnectionLost000000nEndpointConfig0nFromArgMatchesnINTERNAL_ERROR0nIncomingFuturenInvalidFrameIdnInvalidMessage00nMaxStreamsBidi0nNO_VIABLE_PATH0nNoneTokenStore0nPeerMisbehaved00nReachOutAtIpv40nReachOutAtIpv60nReadExactErrornReadToEndErrornShouldTransmitnTransferResultnTransportError00nUdpSocketStatenWeakPathHandlenconnect_clientncrypto_sessionndownload_statsnfor_connection000nhandle_timeoutnhandshake_data00000nhandshake_done0nhas_subcommandninitial_window0000000000000ninto_unorderednis_handshaking0000nis_valid_retry000nminimum_change0nnext_1rtt_keys000non_packet_lost000non_packet_sent000npath_challenge0nqlog_from_path0nread_handshake000nread_unorderednreceive_window00nreceived_reset00nremote_address000nremove_address0nsaturating_add000nsaturating_sub0nthroughput_bpsntime_threshold0ntotal_durationnvalue_variantsoConnectionClose000oConnectionError0oConnectionEvent0oConnectionStats0oGetRandomFailedoNewConnectionId0oOpenStreamStatsoPathCidsBlocked0oProtectedHeader0oQlogFileFactory0oRemoteAbandoned0oSignatureSchemeoSystemTimeErroroTokenReuseError0oTransportConfig00oTryFromIntErroroVersionMismatch0oZeroRttAcceptedoZeroRttRejected000obloom_token_logoclone_to_uninit00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000odefault_runtimeogrease_quic_bit0ointegrity_limit0ointerface_indexomax_stream_data0omax_streams_uni0oparse_byte_sizeorebind_abstractosend_unreliableoserver_endpointoset_path_statusoset_send_window0oshould_transmitostream_finishedothroughput_histowrap_udp_socket00owrite_handshake000A`AddressDiscoveryA`ApplicationClose000A`CertificateErrorA`ConnectionClosed0A`ConnectionHandleA`DatagramReceivedA`DecryptedInitial0A`EndpointStopping0A`FINAL_SIZE_ERROR0A`InconsistentKeys00A`KEY_UPDATE_ERROR0A`MaxPathIdReached0A`ObservedIpv4Addr0A`ObservedIpv6Addr0A`PathStatusBackup0A`PeerIncompatible00A`QuicClientConfig0A`QuicServerConfig0A`TokenMemoryCache0A`TooManyAddressesA`ValidationFailed00A`VersionNegotiate0A`check_and_insert00000A`configure_clientA`congestion_state0A`connection_close0A`force_key_update0A`from_arg_matches00000A`max_gso_segmentsA`max_idle_timeout0A`max_streams_bidi0A`n0_nat_traversal0A`open_connections0A`open_path_ensure0A`packet_threshold0A`read_many_chunksA`receive_datagramA`recv_buffer_size0A`send_buffer_size0A`transport_config0000A`validation_token0A`with_single_cert0A`write_all_chunksAaAPPLICATION_ERROR0AaApplicationClosed000AaControllerFactory0AaControllerMetrics0AaHandshakeTokenKey0AaInvalidServerName0AaNetworkChangeHint0AaPacketDecodeError0AaPathAbandonReason00AaSendDatagramError0AaStreamDataBlocked0AaStreamsBlockedUni0AaUnsupportedByPeer0Aacongestion_events0Aacongestion_window0Aamax_datagram_sizeAanew_connection_id0Aapath_cids_blocked0Aasend_buffer_spaceAaset_server_config0Aaset_up_connectionAato_possible_valueAawait_all_drainingAawrite_many_chunksAbAEAD_LIMIT_REACHED0AbAckFrequencyConfig0AbBadMaxFragmentSize0AbCONNECTION_REFUSED0AbConnectionIdParserAbDatagramsUnblockedAbFLOW_CONTROL_ERROR0AbHandshakeConfirmedAbHandshakeDataReadyAbIllegalOrderedReadAbInvalidCertificate0AbMtuDiscoveryConfig0AbNotEnoughAddressesAbPERF_CIPHER_SUITESAbPROTOCOL_VIOLATION0AbPrivatePkcs8KeyDerAbRetireConnectionId0AbSTREAM_LIMIT_ERROR0AbSTREAM_STATE_ERROR0AbServerCertVerifiedAbServerCertVerifierAbSetPathStatusError0AbStreamsBlockedBidi0AbTokioCurrentThreadAbTransportErrorCode0AbUnsupportedVersion00000Abcommand_for_update0000Abcrypto_buffer_size0Abfrom_u64_unchecked0Abignored_handshakesAbis_same_connectionAbmin_reset_interval0Abnew_expected_items0Abpath_status_backup0Abrefused_handshakesAbremote_path_statusAbsend_datagram_waitAbset_alpn_protocols000Abset_receive_window0Absupported_versions0Abtoken_memory_cacheAbverify_server_certAbwith_start_instant0AcCongestionAlgorithmAcNatTraversalUpdatesAcPathNewConnectionId0AcPathStatusAvailable0AcRemoteCidsExhausted0AcTransportParametersAcUnorderedRecvStreamAcUnsupportedNameType0AcWrongConnectionSideAcaccepted_handshakesAcarbitrary_take_rest000Acaugment_subcommandsAcblack_hole_cooldown0Acearly_data_accepted000Achandshake_confirmedAcis_path_recoverable0Ackeep_alive_interval0Aclost_plpmtud_probes0Acon_congestion_event0000000Acoutgoing_handshakesAcremote_open_streamsAcsend_buffer_benches00Acsend_data_on_streamAcsent_plpmtud_probes0Acstream_data_blocked0Acstreams_blocked_uni0AdFRAME_ENCODING_ERROR0AdHandshakeNotComplete0AdInappropriateMessage000AdInvalidRemoteAddress000AdNoInitialCipherSuite0AdObservedExternalAddrAdServerSideNotAllowed0AdSupportedCipherSuiteAdVarIntBoundsExceeded0AdVerifierBuilderErrorAdWeakConnectionHandleAdack_frequency_config0Adblack_holes_detected0Adfrom_arg_matches_mut00000Adhandle_client_streamAdincoming_buffer_size0Adis_multipath_enabledAdmax_receive_segments0Admax_udp_payload_size00Admtu_discovery_config0Adpoll_endpoint_eventsAdpreferred_address_v40Adpreferred_address_v60Adread_certs_from_fileAdreordering_threshold0Adretire_connection_id0Adretry_token_lifetime0Adset_max_idle_timeoutAdset_recv_buffer_sizeAdset_send_buffer_sizeAdstreams_blocked_bidi0Adtransport_parameters00000AeConnectionIdGenerator0AeDigitallySignedStructAeNoApplicationProtocol0AeNoDefaultClientConfig0AePATH_UNSTABLE_OR_POOR0AeValidationTokenConfig0Aeconfidentiality_limit0Aehandle_network_change0Aeincoming_buffer_bytesAeloss_reduction_factor0Aemax_transmit_segments0Aenat_traversal_updatesAepath_observed_addressAepath_status_available0Aestream_receive_window00AfCRYPTO_BUFFER_EXCEEDED0AfExtensionNotNegotiatedAfFailedToGetCurrentTime0AfFailedToGetRandomBytes0AfMultipathNotNegotiated000000AfPathRetireConnectionId0AfProtectedInitialHeaderAfSkipServerVerificationAfbuild_transport_configAfexport_keying_material0000Afget_into_many_segmentsAfget_loop_many_segmentsAfmax_concurrent_streamsAfobserved_external_addr0Afpath_new_connection_id0Afverify_tls12_signatureAfverify_tls13_signatureAfwith_root_certificates0AgCertRevocationListErrorAgHandshakeSignatureValidAgNoCertificatesPresented0AgPeerSentOversizedRecord0Agack_eliciting_threshold0Agaugment_args_for_update0000Aghas_pending_retransmitsAgis_multipath_negotiatedAgon_ack_frequency_update000Agset_keep_alive_intervalAgupdate_from_arg_matches00000Agvalidation_token_config0AhAPPLICATION_ABANDON_PATH0AhNoProtectionClientConfigAhNoProtectionServerConfigAhget_max_udp_payload_size0Ahinitial_dst_cid_provider0Ahnew_with_abstract_socketAhremote_address_validated0Ahset_max_concurrent_pathsAhsupported_verify_schemesAiCONNECTION_ID_LIMIT_ERROR0AiEncryptedClientHelloErrorAiExportKeyingMaterialError0AiInvalidCertRevocationList0AiNO_CID_AVAILABLE_FOR_PATH0AiTRANSPORT_PARAMETER_ERROR0AiUnsupportedOperationErrorAiadd_nat_traversal_address0Aidatagram_send_buffer_size0Aigenerate_self_signed_certAiopen_bidirectional_streamAipath_retire_connection_id0Aiset_default_client_configAiset_path_max_idle_timeoutAjDEFAULT_SUPPORTED_VERSIONSAjUnusableAfterNetworkChangeAjdatagram_send_buffer_spaceAjincoming_buffer_size_total0Ajmax_concurrent_uni_streams0Ajopen_unidirectional_streamAjserver_handshake_migration0Ajset_max_concurrent_streamsAjspurious_congestion_events0Ajtry_with_platform_verifier0AkHashedConnectionIdGeneratorAkInvalidEncryptedClientHello0AkPATH_RESOURCE_LIMIT_REACHED0AkRandomConnectionIdGeneratorAkenable_segmentation_offload0Akmax_concurrent_bidi_streams0Akupdate_from_arg_matches_mut00000Alconfigure_tracing_subscriberAldatagram_receive_buffer_size0Alinitiate_nat_traversal_round0Alon_spurious_congestion_event00000Alreceive_bidirectional_streamAlremove_nat_traversal_address0Alset_path_keep_alive_intervalAmFixedLengthConnectionIdParserAmInappropriateHandshakeMessage000Amcongestion_controller_factory0Amdefault_path_max_idle_timeout0Ammax_outgoing_bytes_per_second0Amnegotiated_key_exchange_group0Amreceive_unidirectional_streamAmsend_observed_address_reports0Amset_max_concurrent_bi_streamsAnaugment_subcommands_for_updateAnmax_concurrent_multipath_paths0Anset_max_concurrent_uni_streamsAopersistent_congestion_threshold0B`default_path_keep_alive_interval0B`receive_observed_address_reports0Baget_local_nat_traversal_addresses0Bbget_remote_nat_traversal_addresses0Bbmax_remote_nat_traversal_addresses00") \ No newline at end of file +rd_("b()b->bBi0bCe00bFnbIdbOkb[]beq000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bid000000000000000000brtbtybu8cAck0cAddcAnycArccBoxcBufcClicDir0cErrcMAX000cNotcOpt00cOrdcPincUni0cVeccadd00000ccmp0000000000000000000cdir000cecn000cf32cf64cfmt00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cget0ci32cimpcios0clen000clog0cmincmutcnew00000000000000000000000000000000000cnoqcnot0cnow000000crtt000crun0cstrcu16cu32cu64cudpdArgsdAsFddBbr300dDropdEct000dEct100dFromdHashdIntodKeys0dLong0dNonedPath00dPing0dPolldReaddSide0dZERO0dacks0daddr00dbbr3dbooldbulkdcodedcwnd0ddataddrop000000dfrom000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dhash000000000000000000000dinto000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dmain0000dnext0dopen00dpath0dperfdping000dpoll00000000000000dqlogdread00drecv00dseal0dsend00dsent0dside0dsign0dsize00dsmoldspindstop00dtake00000du128duniteAsRefeByteseChunk0eCloneeCloseeCubic00eDebugeDerefeError00000000000eEvent00eKnowneOther0eRangeeReset000eRetry0eShort0eSizedeStats0eSuiteeTokioeWriteealpns0earrayebenchebuild00000000ebytes000ecauseeclone00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eclose000ecubicederef0eerroreframe0eindex0eis_ce0elocal0eparse0epaths0eprint00ereset00eretry0esliceespawn00estats0000000000etitle0etokenetokioetupleeusizeewrite00fAcceptfAckEcn0fAes128fAes256fBackup0fBorrowfBufMutfChunksfClient00fClosed0fCrypto0fCursorfFuturefHasherfIpAddrfLaggedfOpenBifOpened0fOptionfPathId0fResult00000fServer00fStream000fStringfTypeIdfVarInt0faccept000fborrow000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fcipherfclient0000fclosedfcoding0fconfig0fcrypto0000000000fdecode000000000000fdst_ipfencode000000000000ffinish00fhandlefheader0fignore0finsert00000fkeylogfoffset0fon_ack0000000fpacket00frandomfreason00000000frebindfrefuse0fremote000frustls00000fserver0000fsharedfsource00000000fsrc_ip00fstatus00fstream0fstridefudp_rx000fudp_tx000fvarintfverify0fwindow0000000gBlocked00gCommandgContextgDefaultgDisplaygFromStrgGeneral0gHmacKey0gInitialgInstantgKeyPair0gLayeredgMaxData0gNewReno00gOpenUnigPadding0gPathAck0gPathBufgReadBufgRequestgRuntime0gSession0gStopped00000gStreamsgToOwnedgTooLonggTryFromgTryIntogUnknowngZeroRttgcid_len000gclientsgcommand00000gcompare0000000000000000000gconnect0gdecrypt00000gdefault000000000000000000000000000000000000000000000000000gdrainedgdst_cid0000000gencrypt000gis_0rtt0gmetrics0000000gmin_mtu0gnoq_udpgon_sent0gopen_bigpath_idgpointergruntimegsrc_cid0000gstopped0gstreams000gtag_len0gtype_id000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gupgrade0gversion00000hAcceptBihBytesMuthChacha20hCommandshDatagram00hDerefMuthDisabled0hDurationhEndpoint00hFinished0hIncoming0hIteratorhLayerExthLongTypehMAX_SIZE0hNO_ERROR0hNewToken0hOnClosedhOpenPathhOrderinghReadable0hRecvMetahResponsehStreamId0hTimedOut00hToStringhTokenLog0hTooLarge0hTransmit00hUdpStats0hUnixTimehWritable0hcong_alghcontentshdatagram0hdurationhendpoint0hfinalizehframe_rx000hframe_tx000hfrom_buf0hfrom_env0hfrom_keyhfrom_str0hfrom_u320hfrom_u640hgot_type000hgroup_id0000hhas_0rtthincominghinterval0hinto_any0000000his_alivehlifetime0hlocal_ip00000hmax_data0hmax_sizehnew_renohnoq_perfhon_byteshopen_unihpriority0hprotocol0hqlog_dirhresponsehrng_seed0hssthresh0hto_owned00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000htry_from000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000htry_into000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000htry_poll000000000htry_sendhvalidate000iAbandoned000iAcceptUniiAddAssigniArbitraryiAsyncRead0iAvailable000iBorrowMutiCommonOptiConnectediCriterioniDatagramsiDecodableiDiscarded000iEncodableiFormatteriFourTuple0iFrameType0iHandshakeiHeaderKey0iHistogramiMalformediMaxPathId0iMultipathiPacketKey0iPartialEqiPathError0iPathEvent000iPathStats0iReadError00iTryFutureiTryStreamiUdpSenderiUdpSocketiValueEnumiaccept_biiarbitrary0000000ias_rustlsiassemblericlone_box0000000idatagrams000ideref_mut0ifrom_bits00iinitiator0iinto_0rttiinto_iteriis_client0iis_closediis_server0imay_retry0imigration0inew_timer00inew_token0inoq_protoion_closediopen_path0ipath_acks0iping_pathipoll_next000ipoll_read00ipoll_recvipoll_sendireach_out0ireferenceireset_key0iretry_tag0000isize_hint000istable_idito_string0000000000000000000000000000000000000000000000000000000000000000000itoken_key0itoken_positransport00iwait_idleiwrite_alljArgMatchesjAsyncTimerjAsyncWrite0jBATCH_SIZEjBbr3Config0jClosedPath00000jComparablejConnectingjConnection00jController0jEquivalent0jFrameStats0jIntoFuturejInvalidCid0jIoSliceMutjMaybeFrame0jNonZeroU32jOtherErrorjPartialOrdjPathAckEcn0jPathEventsjPathStatus0jQlogConfig0jRecvStream00jResetErrorjRetryError0jSendStream00jServerNamejSocketAddrjStreamInfojSubcommandjSystemTimejTimeSource0jTlsSession0jTokenStore0jUdpSockRefjWriteError0jaccept_unijadd_assign00000jallow_spin0jborrow_mut000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000jbytes_read0jclone_into00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000jclose_pathjcongestion000jconn_statsjconnection0jequivalent00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000jerror_code000000jframe_type0jinto_inner0jis_drained0jlocal_addr0jlost_bytes000jnew_senderjpad_to_mtu0jpath_stats0000jpoll_closejpoll_flush0jpoll_write00jprint_jsonjread_chunk0jread_exactjset_statusjstart_time0jthroughputjtotal_sizekAcceptErrorkCLIENT_ADDRkCipherSuitekClientStatskCloseReasonkConfigError0kContentTypekCryptoError0kCubicConfig0kDataBlocked0kEstablished000kFinishErrorkIdleTimeout0kIntoRequestkOutOfBounds0kPathAbandon0kQlogFactory0kResetStream0kRuntimeTypekSERVER_ADDRkSERVER_NAMEkSmolRuntimekStopSending0kStreamEvent0kStreamStats0kaccept_withkadd_address0kbind_socketkcertificatekcurrent_mtu00kdescription0kdestination00kfrom_remote0kinitial_mtu000kinitial_rtt00kinto_future0000000000000kis_drainingkmax_path_id0kmax_streamsknamed_layer0kon_end_acks000kon_intervalkpacing_rate0kpartial_cmp0000000000000000000kpath_eventskpath_statuskread_to_endkrecv_stream0ksample_size0ksend_bufferksend_stream0ksend_window00kserver_name0ktime_source0ktoken_store0kupload_sizekupper_bound0kweak_handle0kwith_crypto0kwith_prefix0kwrite_chunklAckFrequency0lAddressAddedlClientConfig00000lClosedStream000000lConnectError00lConnectionId00lDatagramInfolDecryptError0lEcnCodepoint00lEncryptError0lIllegalValuelImmediateAck0lIntoIteratorlLOCALHOST_V4lLastOpenPath0lNatTraversallNonZeroUsizelNoneTokenLog0lObservedAddr000lPathResponse0lPathsBlocked0lReadDatagramlRemoteStatus000lRttEstimator0lSendDatagramlServerConfig00000lSocketAddrV4lSocketAddrV6lStoppedErrorlTokioRuntimelUnstructuredlaugment_args0000lcid_lifetime000lclose_reasonlconnect_withlconservativeldata_blocked0ldrain_streamlearly_crypto000levent_streamlexpect_types000lgenerate_cid000lgro_segmentslhandle_event0linitial_keys00000000linto_request0llost_packets000lmax_incoming0lmay_fragment00lnetwork_path0lnew_receiverlnoprotection0lorig_dst_cid0lpath_abandon0lpoll_timeoutlqlog_factory0lreset_stream0lruntime_typelsegment_size00lsend_quantum0lsend_streamslset_lifetime0lset_priority0lstop_sending0lstream_statslupload_statslwith_initial000lwrite_chunksmAlertReceived0mBloomTokenLog0mCidsExhausted000mCloneToUninitmDatagramEventmEndpointEventmEndpointStatsmFinishedEarlymHandshakeData0mHandshakeDone0mHandshakeTypemINVALID_TOKEN0mIncomingAlpns0mInvalidHeadermLocallyClosed0mMaxStreamData0mMaxStreamsUni0mNewConnectionmNewRenoConfig0mParseIntErrormPartialDecodemPathChallenge0mPossibleValuemPrivateKeyDermReadableErrormRemoveAddress0mRootCertStoremStdSystemTime0mUnexpectedEndmaccepted_0rttmack_frequency00mauthenticatedmbench_exports0mcid_generator00mcreate_sendermdata_transfermdownload_sizemduration_histmimmediate_ack0minto_incoming0mmax_ack_delay0mno_protectionmobserved_addr0mon_first_bytemon_mtu_update0000000mpath_response0mpaths_blocked0mpeer_identity0000mpoll_shutdownmpoll_transmitmqlog_from_env0mread_datagrammsend_datagrammsend_fairness0msignature_len0mstart_session000000000mtry_poll_next0nAddIpv4Address0nAddIpv6Address0nAddressRemovednAsyncUdpSocketnCertificateDernClosePathError0nCommandFactorynConnectionLost000000nEndpointConfig0nFromArgMatchesnINTERNAL_ERROR0nIncomingFuturenInvalidFrameIdnInvalidMessage00nMaxStreamsBidi0nNO_VIABLE_PATH0nNoneTokenStore0nPeerMisbehaved00nReachOutAtIpv40nReachOutAtIpv60nReadExactErrornReadToEndErrornShouldTransmitnTransferResultnTransportError00nUdpSocketStatenWeakPathHandlenconnect_clientncrypto_sessionndownload_statsnfor_connection000nhandle_timeoutnhandshake_data00000nhandshake_done0nhas_subcommandninitial_window0000000000000ninto_unorderednis_handshaking0000nis_valid_retry000nminimum_change0nnext_1rtt_keys000non_packet_lost000non_packet_sent000npath_challenge0nqlog_from_path0nread_handshake000nread_unorderednreceive_window00nreceived_reset00nremote_address000nremove_address0nsaturating_add000nsaturating_sub0nthroughput_bpsntime_threshold0ntotal_durationnvalue_variantsoConnectionClose000oConnectionError0oConnectionEvent0oConnectionStats0oGetRandomFailedoNewConnectionId0oOpenStreamStatsoPathCidsBlocked0oProtectedHeader0oQlogFileFactory0oRemoteAbandoned0oSignatureSchemeoSystemTimeErroroTokenReuseError0oTransportConfig00oTryFromIntErroroVersionMismatch0oZeroRttAcceptedoZeroRttRejected000obloom_token_logoclone_to_uninit00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000odefault_runtimeogrease_quic_bit0ointegrity_limit0ointerface_indexomax_stream_data0omax_streams_uni0oparse_byte_sizeorebind_abstractosend_unreliableoserver_endpointoset_path_statusoset_send_window0oshould_transmitostream_finishedothroughput_histowrap_udp_socket00owrite_handshake000A`AddressDiscoveryA`ApplicationClose000A`CertificateErrorA`ConnectionClosed0A`ConnectionHandleA`DatagramReceivedA`DecryptedInitial0A`EndpointStopping0A`FINAL_SIZE_ERROR0A`InconsistentKeys00A`KEY_UPDATE_ERROR0A`MaxPathIdReached0A`ObservedIpv4Addr0A`ObservedIpv6Addr0A`PathStatusBackup0A`PeerIncompatible00A`QuicClientConfig0A`QuicServerConfig0A`TokenMemoryCache0A`TooManyAddressesA`ValidationFailed00A`VersionNegotiate0A`check_and_insert00000A`configure_clientA`congestion_state0A`connection_close0A`force_key_update0A`from_arg_matches00000A`max_gso_segmentsA`max_idle_timeout0A`max_streams_bidi0A`n0_nat_traversal0A`open_connections0A`open_path_ensure0A`packet_threshold0A`read_many_chunksA`receive_datagramA`recv_buffer_size0A`send_buffer_size0A`transport_config0000A`validation_token0A`with_single_cert0A`write_all_chunksAaAPPLICATION_ERROR0AaApplicationClosed000AaControllerFactory0AaControllerMetrics0AaHandshakeTokenKey0AaInvalidServerName0AaNetworkChangeHint0AaPacketDecodeError0AaPathAbandonReason00AaSendDatagramError0AaStreamDataBlocked0AaStreamsBlockedUni0AaUnsupportedByPeer0Aacongestion_events0Aacongestion_window0Aamax_datagram_sizeAanew_connection_id0Aapath_cids_blocked0Aasend_buffer_spaceAaset_server_config0Aaset_up_connectionAato_possible_valueAawait_all_drainingAawrite_many_chunksAbAEAD_LIMIT_REACHED0AbAckFrequencyConfig0AbBadMaxFragmentSize0AbCONNECTION_REFUSED0AbConnectionIdParserAbDatagramsUnblockedAbFLOW_CONTROL_ERROR0AbHandshakeConfirmedAbHandshakeDataReadyAbIllegalOrderedReadAbInvalidCertificate0AbMtuDiscoveryConfig0AbNotEnoughAddressesAbPERF_CIPHER_SUITESAbPROTOCOL_VIOLATION0AbPrivatePkcs8KeyDerAbRetireConnectionId0AbSTREAM_LIMIT_ERROR0AbSTREAM_STATE_ERROR0AbServerCertVerifiedAbServerCertVerifierAbSetPathStatusError0AbStreamsBlockedBidi0AbTokioCurrentThreadAbTransportErrorCode0AbUnsupportedVersion00000Abcommand_for_update0000Abcrypto_buffer_size0Abfrom_u64_unchecked0Abignored_handshakesAbis_same_connectionAbmin_reset_interval0Abnew_expected_items0Abpath_status_backup0Abrefused_handshakesAbremote_path_statusAbsend_datagram_waitAbset_alpn_protocols000Abset_receive_window0Absupported_versions0Abtoken_memory_cacheAbverify_server_certAbwith_start_instant0AcCongestionAlgorithmAcNatTraversalUpdatesAcPathNewConnectionId0AcPathStatusAvailable0AcRemoteCidsExhausted0AcTransportParametersAcUnorderedRecvStreamAcUnsupportedNameType0AcWrongConnectionSideAcaccepted_handshakesAcarbitrary_take_rest000Acaugment_subcommandsAcblack_hole_cooldown0Acearly_data_accepted000Achandshake_confirmedAcis_path_recoverable0Ackeep_alive_interval0Aclost_plpmtud_probes0Acon_congestion_event0000000Acoutgoing_handshakesAcremote_open_streamsAcsend_buffer_benches00Acsend_data_on_streamAcsent_plpmtud_probes0Acstream_data_blocked0Acstreams_blocked_uni0AdFRAME_ENCODING_ERROR0AdHandshakeNotComplete0AdInappropriateMessage000AdInvalidRemoteAddress000AdNoInitialCipherSuite0AdObservedExternalAddrAdServerSideNotAllowed0AdSupportedCipherSuiteAdVarIntBoundsExceeded0AdVerifierBuilderErrorAdWeakConnectionHandleAdack_frequency_config0Adblack_holes_detected0Adfrom_arg_matches_mut00000Adhandle_client_streamAdincoming_buffer_size0Adis_multipath_enabledAdmax_receive_segments0Admax_udp_payload_size00Admtu_discovery_config0Adpoll_endpoint_eventsAdpreferred_address_v40Adpreferred_address_v60Adread_certs_from_fileAdreordering_threshold0Adretire_connection_id0Adretry_token_lifetime0Adset_max_idle_timeoutAdset_recv_buffer_sizeAdset_send_buffer_sizeAdstreams_blocked_bidi0Adtransport_parameters00000AeConnectionIdGenerator0AeDigitallySignedStructAeNoApplicationProtocol0AeNoDefaultClientConfig0AePATH_UNSTABLE_OR_POOR0AeValidationTokenConfig0Aeconfidentiality_limit0Aehandle_network_change0Aeincoming_buffer_bytesAeloss_reduction_factor0Aemax_transmit_segments0Aenat_traversal_updatesAepath_observed_addressAepath_status_available0Aestream_receive_window00AfCRYPTO_BUFFER_EXCEEDED0AfExtensionNotNegotiatedAfFailedToGetCurrentTime0AfFailedToGetRandomBytes0AfMultipathNotNegotiated000000AfPathRetireConnectionId0AfProtectedInitialHeaderAfSkipServerVerificationAfbuild_transport_configAfexport_keying_material0000Afget_into_many_segmentsAfget_loop_many_segmentsAfmax_concurrent_streamsAfobserved_external_addr0Afpath_new_connection_id0Afverify_tls12_signatureAfverify_tls13_signatureAfwith_root_certificates0AgCertRevocationListErrorAgHandshakeSignatureValidAgNoCertificatesPresented0AgPeerSentOversizedRecord0Agack_eliciting_threshold0Agaugment_args_for_update0000Aghas_pending_retransmitsAgis_multipath_negotiatedAgon_ack_frequency_update000Agset_keep_alive_intervalAgupdate_from_arg_matches00000Agvalidation_token_config0AhAPPLICATION_ABANDON_PATH0AhNoProtectionClientConfigAhNoProtectionServerConfigAhget_max_udp_payload_size0Ahinitial_dst_cid_provider0Ahnew_with_abstract_socketAhremote_address_validated0Ahset_max_concurrent_pathsAhsupported_verify_schemesAiCONNECTION_ID_LIMIT_ERROR0AiEncryptedClientHelloErrorAiExportKeyingMaterialError0AiInvalidCertRevocationList0AiNO_CID_AVAILABLE_FOR_PATH0AiTRANSPORT_PARAMETER_ERROR0AiUnsupportedOperationErrorAiadd_nat_traversal_address0Aidatagram_send_buffer_size0Aigenerate_self_signed_certAiopen_bidirectional_streamAipath_retire_connection_id0Aiset_default_client_configAiset_path_max_idle_timeoutAjDEFAULT_SUPPORTED_VERSIONSAjUnusableAfterNetworkChangeAjdatagram_send_buffer_spaceAjincoming_buffer_size_total0Ajmax_concurrent_uni_streams0Ajopen_unidirectional_streamAjserver_handshake_migration0Ajset_max_concurrent_streamsAjspurious_congestion_events0Ajtry_with_platform_verifier0AkHashedConnectionIdGeneratorAkInvalidEncryptedClientHello0AkPATH_RESOURCE_LIMIT_REACHED0AkRandomConnectionIdGeneratorAkenable_segmentation_offload0Akmax_concurrent_bidi_streams0Akupdate_from_arg_matches_mut00000Alconfigure_tracing_subscriberAldatagram_receive_buffer_size0Alinitiate_nat_traversal_round0Alon_spurious_congestion_event00000Alreceive_bidirectional_streamAlremove_nat_traversal_address0Alset_path_keep_alive_intervalAmFixedLengthConnectionIdParserAmInappropriateHandshakeMessage000Amcongestion_controller_factory0Amdefault_path_max_idle_timeout0Ammax_outgoing_bytes_per_second0Amnegotiated_key_exchange_group0Amreceive_unidirectional_streamAmsend_observed_address_reports0Amset_max_concurrent_bi_streamsAnaugment_subcommands_for_updateAnmax_concurrent_multipath_paths0Anset_max_concurrent_uni_streamsAopersistent_congestion_threshold0B`default_path_keep_alive_interval0B`receive_observed_address_reports0Baget_local_nat_traversal_addresses0Bbget_remote_nat_traversal_addresses0Bbmax_remote_nat_traversal_addresses00") \ No newline at end of file diff --git a/pr/720/docs/search.index/normalizedName/977a3ccfe9de.js b/pr/720/docs/search.index/normalizedName/0f19d05307c5.js similarity index 53% rename from pr/720/docs/search.index/normalizedName/977a3ccfe9de.js rename to pr/720/docs/search.index/normalizedName/0f19d05307c5.js index dc5d48aef..00e97911a 100644 --- a/pr/720/docs/search.index/normalizedName/977a3ccfe9de.js +++ b/pr/720/docs/search.index/normalizedName/0f19d05307c5.js @@ -1 +1 @@ -rd_("b()b->bbi0bce00bfnbidbokb[]beq0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003333333333333333333brtbtybu8cack0caddcanycarccboxcbufcclicdir0cerrcmax000cnotcopt00cordcpincuni0cvec>>>>>>ccmp00000000000000000009999cecn000cf32cf64cfmt00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cget0ci32cimpcios0clen000clog0cmincmutcnew00000000000000000000000000000000000cnoqcnot0cnow000000crtt000crun0cstrcu16cu32cu64cudpdargsdasfddbbr300ddropdect000dect100dfromdhashdintodkeys0dlong0dnonedpath00dping0dpolldreaddside0dzero0dacks0daddr00dbbr3dbooldbulkdcodedcwnd0ddataddrop000000dfrom000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dhash000000000000000000000dinto000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dmain0000dnext0dopen00dpath0dperfdping000dpoll00000000000000dqlogdread00drecv00dseal0dsend00dsent0dside0dsign0dsize00dsmoldspindstop00dtake00000du128duniteasrefebytesechunk0ecloneecloseecubic00edebugederefeerror00000000000eevent00eknowneother0erangeereset000eretry0eshort0esizedestats0esuiteetokioewriteealpns0earrayebenchebuild00000000ebytes000ecauseeclone00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eclose000ecubicederef0eerroreframe0eindex0disce0elocal0eparse0epaths0eprint00ereset00eretry0esliceespawn00estats0000000000etitle0etokenetokioetupleeusizeewrite00facceptfackecn0faes128faes256fbackup0fborrowfbufmutfchunksfclient00fclosed0fcrypto0fcursorffuturefhasherfipaddrflaggedfopenbifopened0foptionfpathid0fresult00000fserver00fstream000fstringftypeidfvarint0faccept000fborrow000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fcipherfclient0000fclosedfcoding0fconfig0fcrypto0000000000fdecode000000000000edstipfencode000000000000ffinish00fhandlefheader0fignore0finsert00000fkeylogfoffset0eonack0000000fpacket00frandomfreason00000000frebindfrefuse0fremote000frustls00000fserver0000fsharedfsource00000000esrcip00fstatus00fstream0fstrideeudprx000eudptx000fvarintfverify0fwindow0000000gblocked00gcommandgcontextgdefaultgdisplaygfromstrggeneral0ghmackey0ginitialginstantgkeypair0glayeredgmaxdata0gnewreno00gopenunigpadding0gpathack0gpathbufgreadbufgrequestgruntime0gsession0gstopped00000gstreamsgtoownedgtoolonggtryfromgtryintogunknowngzerorttfcidlen000gclientsgcommand00000gcompare0000000000000000000gconnect0gdecrypt00000gdefault000000000000000000000000000000000000000000000000000gdrainedfdstcid0000000gencrypt000fis0rtt0gmetrics0000000fminmtu0fnoqudpfonsent0fopenbifpathidgpointergruntimefsrccid0000gstopped0gstreams000ftaglen0ftypeid000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gupgrade0gversion00000hacceptbihbytesmuthchacha20hcommandshdatagram00hderefmuthdisabled0hdurationhendpoint00hfinished0hincoming0hiteratorhlayerexthlongtypegmaxsize0gnoerror0hnewtoken0honclosedhopenpathhorderinghreadable0hrecvmetahresponsehstreamid0htimedout00htostringhtokenlog0htoolarge0htransmit00hudpstats0hunixtimehwritable0gcongalghcontentshdatagram0hdurationhendpoint0hfinalizegframerx000gframetx000gfrombuf0gfromenv0gfromkeygfromstr0gfromu320gfromu640ggottype000ggroupid0000ghas0rtthincominghinterval0gintoany0000000gisalivehlifetime0glocalip00000gmaxdata0gmaxsizegnewrenognoqperfgonbytesgopenunihpriority0hprotocol0gqlogdirhresponsegrngseed0hssthresh0gtoowned00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gtryfrom000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gtryinto000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gtrypoll000000000gtrysendhvalidate000iabandoned000iacceptuniiaddassigniarbitraryiasyncread0iavailable000iborrowmuticommonopticonnectedicriterionidatagramsidecodableidiscarded000iencodableiformatterifourtuple0iframetype0ihandshakeiheaderkey0ihistogramimalformedimaxpathid0imultipathipacketkey0ipartialeqipatherror0ipathevent000ipathstats0ireaderror00itryfutureitrystreamiudpsenderiudpsocketivalueenumhacceptbiiarbitrary0000000hasrustlsiassemblerhclonebox0000000idatagrams000hderefmut0hfrombits00iinitiator0hinto0rtthintoiterhisclient0hisclosedhisserver0hmayretry0imigration0hnewtimer00hnewtoken0hnoqprotohonclosedhopenpath0hpathacks0hpingpathhpollnext000hpollread00hpollrecvhpollsendhreachout0ireferencehresetkey0hretrytag0000hsizehint000hstableidhtostring0000000000000000000000000000000000000000000000000000000000000000000htokenkey0htokenpositransport00hwaitidlehwritealljargmatchesjasynctimerjasyncwrite0ibatchsizejbbr3config0jclosedpath00000jcomparablejconnectingjconnection00jcontroller0jequivalent0jframestats0jintofuturejinvalidcid0jioslicemutjmaybeframe0jnonzerou32jothererrorjpartialordjpathackecn0jpatheventsjpathstatus0jqlogconfig0jrecvstream00jreseterrorjretryerror0jsendstream00jservernamejsocketaddrjstreaminfojsubcommandjsystemtimejtimesource0jtlssession0jtokenstore0judpsockrefjwriteerror0iacceptuniiaddassign00000iallowspin0iborrowmut000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ibytesread0icloneinto00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000iclosepathjcongestion000iconnstatsjconnection0jequivalent00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ierrorcode000000iframetype0iintoinner0iisdrained0ilocaladdr0ilostbytes000inewsenderhpadtomtu0ipathstats0000ipollcloseipollflush0ipollwrite00iprintjsonireadchunk0ireadexactisetstatusistarttime0jthroughputitotalsizekaccepterrorjclientaddrkciphersuitekclientstatskclosereasonkconfigerror0kcontenttypekcryptoerror0kcubicconfig0kdatablocked0kestablished000kfinisherrorkidletimeout0kintorequestkoutofbounds0kpathabandon0kqlogfactory0kresetstream0kruntimetypejserveraddrjservernameksmolruntimekstopsending0kstreamevent0kstreamstats0jacceptwithjaddaddress0jbindsocketkcertificatejcurrentmtu00kdescription0kdestination00jfromremote0jinitialmtu000jinitialrtt00jintofuture0000000000000jisdrainingimaxpathid0jmaxstreamsjnamedlayer0ionendacks000jonintervaljpacingrate0jpartialcmp0000000000000000000jpatheventsjpathstatusireadtoendjrecvstream0jsamplesize0jsendbufferjsendstream0jsendwindow00jservername0jtimesource0jtokenstore0juploadsizejupperbound0jweakhandle0jwithcrypto0jwithprefix0jwritechunklackfrequency0laddressaddedlclientconfig00000lclosedstream000000lconnecterror00lconnectionid00ldatagraminfoldecrypterror0lecncodepoint00lencrypterror0lillegalvaluelimmediateack0lintoiteratorklocalhostv4llastopenpath0lnattraversallnonzerousizelnonetokenlog0lobservedaddr000lpathresponse0lpathsblocked0lreaddatagramlremotestatus000lrttestimator0lsenddatagramlserverconfig00000lsocketaddrv4lsocketaddrv6lstoppederrorltokioruntimelunstructuredkaugmentargs0000kcidlifetime000kclosereasonkconnectwithlconservativekdatablocked0kdrainstreamkearlycrypto000keventstreamkexpecttypes000kgeneratecid000kgrosegmentskhandleevent0kinitialkeys00000000kintorequest0klostpackets000kmaxincoming0kmayfragment00knetworkpath0knewreceiverlnoprotection0jorigdstcid0kpathabandon0kpolltimeoutkqlogfactory0kresetstream0kruntimetypeksegmentsize00ksendquantum0ksendstreamsksetlifetime0ksetpriority0kstopsending0kstreamstatskuploadstatskwithinitial000kwritechunksmalertreceived0mbloomtokenlog0mcidsexhausted000mclonetouninitmdatagrameventmendpointeventmendpointstatsmfinishedearlymhandshakedata0mhandshakedone0mhandshaketypelinvalidtoken0mincomingalpns0minvalidheadermlocallyclosed0mmaxstreamdata0mmaxstreamsuni0mnewconnectionmnewrenoconfig0mparseinterrormpartialdecodempathchallenge0mpossiblevaluemprivatekeydermreadableerrormremoveaddress0mrootcertstoremstdsystemtime0munexpectedendlaccepted0rttlackfrequency00lbenchexports0lcidgenerator00lcreatesenderldatatransferldownloadsizeldurationhistlimmediateack0lintoincoming0kmaxackdelay0lnoprotectionlobservedaddr0konfirstbytekonmtuupdate0000000lpathresponse0lpathsblocked0lpeeridentity0000lpollshutdownlpolltransmitkqlogfromenv0lreaddatagramlsenddatagramlsendfairness0lsignaturelen0lstartsession000000000ktrypollnext0naddipv4address0naddipv6address0naddressremovednasyncudpsocketncertificatedernclosepatherror0ncommandfactorynconnectionlost000000nendpointconfig0nfromargmatchesminternalerror0nincomingfutureninvalidframeidninvalidmessage00nmaxstreamsbidi0lnoviablepath0nnonetokenstore0npeermisbehaved00nreachoutatipv40nreachoutatipv60nreadexacterrornreadtoenderrornshouldtransmitntransferresultntransporterror00nudpsocketstatenweakpathhandlemconnectclientmcryptosessionmdownloadstatsmforconnection000mhandletimeoutmhandshakedata00000mhandshakedone0mhassubcommandminitialwindow0000000000000mintounorderedmishandshaking0000lisvalidretry000mminimumchange0lnext1rttkeys000lonpacketlost000lonpacketsent000mpathchallenge0lqlogfrompath0mreadhandshake000mreadunorderedmreceivewindow00mreceivedreset00mremoteaddress000mremoveaddress0msaturatingadd000msaturatingsub0mthroughputbpsmtimethreshold0mtotaldurationmvaluevariantsoconnectionclose000oconnectionerror0oconnectionevent0oconnectionstats0ogetrandomfailedonewconnectionid0oopenstreamstatsopathcidsblocked0oprotectedheader0oqlogfilefactory0oremoteabandoned0osignatureschemeosystemtimeerrorotokenreuseerror0otransportconfig00otryfrominterroroversionmismatch0ozerorttacceptedozerorttrejected000mbloomtokenlogmclonetouninit00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ndefaultruntimemgreasequicbit0nintegritylimit0ninterfaceindexmmaxstreamdata0mmaxstreamsuni0mparsebytesizenrebindabstractnsendunreliablenserverendpointmsetpathstatusmsetsendwindow0nshouldtransmitnstreamfinishednthroughputhistmwrapudpsocket00nwritehandshake000A`addressdiscoveryA`applicationclose000A`certificateerrorA`connectionclosed0A`connectionhandleA`datagramreceivedA`decryptedinitial0A`endpointstopping0nfinalsizeerror0A`inconsistentkeys00nkeyupdateerror0A`maxpathidreached0A`observedipv4addr0A`observedipv6addr0A`pathstatusbackup0A`peerincompatible00A`quicclientconfig0A`quicserverconfig0A`tokenmemorycache0A`toomanyaddressesA`validationfailed00A`versionnegotiate0ncheckandinsert00000oconfigureclientocongestionstate0oconnectionclose0nforcekeyupdate0nfromargmatches00000nmaxgsosegmentsnmaxidletimeout0nmaxstreamsbidi0nn0nattraversal0oopenconnections0nopenpathensure0opacketthreshold0nreadmanychunksoreceivedatagramnrecvbuffersize0nsendbuffersize0otransportconfig0000ovalidationtoken0nwithsinglecert0nwriteallchunksA`applicationerror0Aaapplicationclosed000Aacontrollerfactory0Aacontrollermetrics0Aahandshaketokenkey0Aainvalidservername0Aanetworkchangehint0Aapacketdecodeerror0Aapathabandonreason00Aasenddatagramerror0Aastreamdatablocked0Aastreamsblockeduni0Aaunsupportedbypeer0A`congestionevents0A`congestionwindow0omaxdatagramsizeonewconnectionid0opathcidsblocked0osendbufferspaceosetserverconfig0osetupconnectionotopossiblevalueowaitalldrainingowritemanychunksA`aeadlimitreached0Abackfrequencyconfig0Abbadmaxfragmentsize0Aaconnectionrefused0AbconnectionidparserAbdatagramsunblockedA`flowcontrolerror0AbhandshakeconfirmedAbhandshakedatareadyAbillegalorderedreadAbinvalidcertificate0Abmtudiscoveryconfig0AbnotenoughaddressesA`perfciphersuitesAaprotocolviolation0Abprivatepkcs8keyderAbretireconnectionid0A`streamlimiterror0A`streamstateerror0AbservercertverifiedAbservercertverifierAbsetpathstatuserror0Abstreamsblockedbidi0AbtokiocurrentthreadAbtransporterrorcode0Abunsupportedversion00000A`commandforupdate0000A`cryptobuffersize0A`fromu64unchecked0AaignoredhandshakesA`issameconnectionA`minresetinterval0A`newexpecteditems0A`pathstatusbackup0AarefusedhandshakesA`remotepathstatusA`senddatagramwaitA`setalpnprotocols000A`setreceivewindow0Aasupportedversions0A`tokenmemorycacheA`verifyservercertA`withstartinstant0AccongestionalgorithmAcnattraversalupdatesAcpathnewconnectionid0Acpathstatusavailable0Acremotecidsexhausted0ActransportparametersAcunorderedrecvstreamAcunsupportednametype0AcwrongconnectionsideAbacceptedhandshakesAaarbitrarytakerest000AbaugmentsubcommandsAablackholecooldown0Aaearlydataaccepted000AbhandshakeconfirmedAaispathrecoverable0Aakeepaliveinterval0Aalostplpmtudprobes0Aaoncongestionevent0000000AboutgoinghandshakesAaremoteopenstreamsAasendbufferbenches00A`senddataonstreamAasentplpmtudprobes0Aastreamdatablocked0Aastreamsblockeduni0Abframeencodingerror0Adhandshakenotcomplete0Adinappropriatemessage000Adinvalidremoteaddress000Adnoinitialciphersuite0AdobservedexternaladdrAdserversidenotallowed0AdsupportedciphersuiteAdvarintboundsexceeded0AdverifierbuildererrorAdweakconnectionhandleAbackfrequencyconfig0Abblackholesdetected0Aafromargmatchesmut00000AbhandleclientstreamAbincomingbuffersize0AbismultipathenabledAbmaxreceivesegments0Aamaxudppayloadsize00Abmtudiscoveryconfig0AbpollendpointeventsAbpreferredaddressv40Abpreferredaddressv60AareadcertsfromfileAcreorderingthreshold0Abretireconnectionid0Abretrytokenlifetime0AasetmaxidletimeoutAasetrecvbuffersizeAasetsendbuffersizeAbstreamsblockedbidi0Actransportparameters00000Aeconnectionidgenerator0AedigitallysignedstructAenoapplicationprotocol0Aenodefaultclientconfig0Abpathunstableorpoor0Aevalidationtokenconfig0Adconfidentialitylimit0Achandlenetworkchange0AcincomingbufferbytesAclossreductionfactor0Acmaxtransmitsegments0AcnattraversalupdatesAcpathobservedaddressAcpathstatusavailable0Acstreamreceivewindow00Adcryptobufferexceeded0AfextensionnotnegotiatedAffailedtogetcurrenttime0Affailedtogetrandombytes0Afmultipathnotnegotiated000000Afpathretireconnectionid0AfprotectedinitialheaderAfskipserververificationAdbuildtransportconfigAdexportkeyingmaterial0000AcgetintomanysegmentsAcgetloopmanysegmentsAdmaxconcurrentstreamsAdobservedexternaladdr0Acpathnewconnectionid0Adverifytls12signatureAdverifytls13signatureAdwithrootcertificates0AgcertrevocationlisterrorAghandshakesignaturevalidAgnocertificatespresented0Agpeersentoversizedrecord0Aeackelicitingthreshold0Adaugmentargsforupdate0000AehaspendingretransmitsAeismultipathnegotiatedAdonackfrequencyupdate000AdsetkeepaliveintervalAdupdatefromargmatches00000Aevalidationtokenconfig0Afapplicationabandonpath0AhnoprotectionclientconfigAhnoprotectionserverconfigAdgetmaxudppayloadsize0Aeinitialdstcidprovider0AenewwithabstractsocketAfremoteaddressvalidated0AesetmaxconcurrentpathsAfsupportedverifyschemesAfconnectionidlimiterror0AiencryptedclienthelloerrorAiexportkeyingmaterialerror0Aiinvalidcertrevocationlist0Aenocidavailableforpath0Agtransportparametererror0AiunsupportedoperationerrorAfaddnattraversaladdress0Afdatagramsendbuffersize0AfgenerateselfsignedcertAgopenbidirectionalstreamAfpathretireconnectionid0AfsetdefaultclientconfigAesetpathmaxidletimeoutAhdefaultsupportedversionsAjunusableafternetworkchangeAgdatagramsendbufferspaceAgincomingbuffersizetotal0Agmaxconcurrentunistreams0AhopenunidirectionalstreamAhserverhandshakemigration0AgsetmaxconcurrentstreamsAhspuriouscongestionevents0Agtrywithplatformverifier0AkhashedconnectionidgeneratorAkinvalidencryptedclienthello0Ahpathresourcelimitreached0AkrandomconnectionidgeneratorAienablesegmentationoffload0Ahmaxconcurrentbidistreams0Agupdatefromargmatchesmut00000AjconfiguretracingsubscriberAidatagramreceivebuffersize0Aiinitiatenattraversalround0Aionspuriouscongestionevent00000AjreceivebidirectionalstreamAiremovenattraversaladdress0AhsetpathkeepaliveintervalAmfixedlengthconnectionidparserAminappropriatehandshakemessage000Akcongestioncontrollerfactory0Aidefaultpathmaxidletimeout0Aimaxoutgoingbytespersecond0Ajnegotiatedkeyexchangegroup0AkreceiveunidirectionalstreamAjsendobservedaddressreports0AisetmaxconcurrentbistreamsAkaugmentsubcommandsforupdateAkmaxconcurrentmultipathpaths0AjsetmaxconcurrentunistreamsAmpersistentcongestionthreshold0Aldefaultpathkeepaliveinterval0Amreceiveobservedaddressreports0Amgetlocalnattraversaladdresses0Angetremotenattraversaladdresses0Anmaxremotenattraversaladdresses00") \ No newline at end of file +rd_("b()b->bbi0bce00bfnbidbokb[]beq0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003333333333333333333brtbtybu8cack0caddcanycarccboxcbufcclicdir0cerrcmax000cnotcopt00cordcpincuni0cvec>>>>>>ccmp00000000000000000009999cecn000cf32cf64cfmt00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cget0ci32cimpcios0clen000clog0cmincmutcnew00000000000000000000000000000000000cnoqcnot0cnow000000crtt000crun0cstrcu16cu32cu64cudpdargsdasfddbbr300ddropdect000dect100dfromdhashdintodkeys0dlong0dnonedpath00dping0dpolldreaddside0dzero0dacks0daddr00dbbr3dbooldbulkdcodedcwnd0ddataddrop000000dfrom000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dhash000000000000000000000dinto000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dmain0000dnext0dopen00dpath0dperfdping000dpoll00000000000000dqlogdread00drecv00dseal0dsend00dsent0dside0dsign0dsize00dsmoldspindstop00dtake00000du128duniteasrefebytesechunk0ecloneecloseecubic00edebugederefeerror00000000000eevent00eknowneother0erangeereset000eretry0eshort0esizedestats0esuiteetokioewriteealpns0earrayebenchebuild00000000ebytes000ecauseeclone00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eclose000ecubicederef0eerroreframe0eindex0disce0elocal0eparse0epaths0eprint00ereset00eretry0esliceespawn00estats0000000000etitle0etokenetokioetupleeusizeewrite00facceptfackecn0faes128faes256fbackup0fborrowfbufmutfchunksfclient00fclosed0fcrypto0fcursorffuturefhasherfipaddrflaggedfopenbifopened0foptionfpathid0fresult00000fserver00fstream000fstringftypeidfvarint0faccept000fborrow000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fcipherfclient0000fclosedfcoding0fconfig0fcrypto0000000000fdecode000000000000edstipfencode000000000000ffinish00fhandlefheader0fignore0finsert00000fkeylogfoffset0eonack0000000fpacket00frandomfreason00000000frebindfrefuse0fremote000frustls00000fserver0000fsharedfsource00000000esrcip00fstatus00fstream0fstrideeudprx000eudptx000fvarintfverify0fwindow0000000gblocked00gcommandgcontextgdefaultgdisplaygfromstrggeneral0ghmackey0ginitialginstantgkeypair0glayeredgmaxdata0gnewreno00gopenunigpadding0gpathack0gpathbufgreadbufgrequestgruntime0gsession0gstopped00000gstreamsgtoownedgtoolonggtryfromgtryintogunknowngzerorttfcidlen000gclientsgcommand00000gcompare0000000000000000000gconnect0gdecrypt00000gdefault000000000000000000000000000000000000000000000000000gdrainedfdstcid0000000gencrypt000fis0rtt0gmetrics0000000fminmtu0fnoqudpfonsent0fopenbifpathidgpointergruntimefsrccid0000gstopped0gstreams000ftaglen0ftypeid000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gupgrade0gversion00000hacceptbihbytesmuthchacha20hcommandshdatagram00hderefmuthdisabled0hdurationhendpoint00hfinished0hincoming0hiteratorhlayerexthlongtypegmaxsize0gnoerror0hnewtoken0honclosedhopenpathhorderinghreadable0hrecvmetahresponsehstreamid0htimedout00htostringhtokenlog0htoolarge0htransmit00hudpstats0hunixtimehwritable0gcongalghcontentshdatagram0hdurationhendpoint0hfinalizegframerx000gframetx000gfrombuf0gfromenv0gfromkeygfromstr0gfromu320gfromu640ggottype000ggroupid0000ghas0rtthincominghinterval0gintoany0000000gisalivehlifetime0glocalip00000gmaxdata0gmaxsizegnewrenognoqperfgonbytesgopenunihpriority0hprotocol0gqlogdirhresponsegrngseed0hssthresh0gtoowned00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gtryfrom000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gtryinto000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000gtrypoll000000000gtrysendhvalidate000iabandoned000iacceptuniiaddassigniarbitraryiasyncread0iavailable000iborrowmuticommonopticonnectedicriterionidatagramsidecodableidiscarded000iencodableiformatterifourtuple0iframetype0ihandshakeiheaderkey0ihistogramimalformedimaxpathid0imultipathipacketkey0ipartialeqipatherror0ipathevent000ipathstats0ireaderror00itryfutureitrystreamiudpsenderiudpsocketivalueenumhacceptbiiarbitrary0000000hasrustlsiassemblerhclonebox0000000idatagrams000hderefmut0hfrombits00iinitiator0hinto0rtthintoiterhisclient0hisclosedhisserver0hmayretry0imigration0hnewtimer00hnewtoken0hnoqprotohonclosedhopenpath0hpathacks0hpingpathhpollnext000hpollread00hpollrecvhpollsendhreachout0ireferencehresetkey0hretrytag0000hsizehint000hstableidhtostring0000000000000000000000000000000000000000000000000000000000000000000htokenkey0htokenpositransport00hwaitidlehwritealljargmatchesjasynctimerjasyncwrite0ibatchsizejbbr3config0jclosedpath00000jcomparablejconnectingjconnection00jcontroller0jequivalent0jframestats0jintofuturejinvalidcid0jioslicemutjmaybeframe0jnonzerou32jothererrorjpartialordjpathackecn0jpatheventsjpathstatus0jqlogconfig0jrecvstream00jreseterrorjretryerror0jsendstream00jservernamejsocketaddrjstreaminfojsubcommandjsystemtimejtimesource0jtlssession0jtokenstore0judpsockrefjwriteerror0iacceptuniiaddassign00000iallowspin0iborrowmut000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ibytesread0icloneinto00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000iclosepathjcongestion000iconnstatsjconnection0jequivalent00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ierrorcode000000iframetype0iintoinner0iisdrained0ilocaladdr0ilostbytes000inewsenderhpadtomtu0ipathstats0000ipollcloseipollflush0ipollwrite00iprintjsonireadchunk0ireadexactisetstatusistarttime0jthroughputitotalsizekaccepterrorjclientaddrkciphersuitekclientstatskclosereasonkconfigerror0kcontenttypekcryptoerror0kcubicconfig0kdatablocked0kestablished000kfinisherrorkidletimeout0kintorequestkoutofbounds0kpathabandon0kqlogfactory0kresetstream0kruntimetypejserveraddrjservernameksmolruntimekstopsending0kstreamevent0kstreamstats0jacceptwithjaddaddress0jbindsocketkcertificatejcurrentmtu00kdescription0kdestination00jfromremote0jinitialmtu000jinitialrtt00jintofuture0000000000000jisdrainingimaxpathid0jmaxstreamsjnamedlayer0ionendacks000jonintervaljpacingrate0jpartialcmp0000000000000000000jpatheventsjpathstatusireadtoendjrecvstream0jsamplesize0jsendbufferjsendstream0jsendwindow00jservername0jtimesource0jtokenstore0juploadsizejupperbound0jweakhandle0jwithcrypto0jwithprefix0jwritechunklackfrequency0laddressaddedlclientconfig00000lclosedstream000000lconnecterror00lconnectionid00ldatagraminfoldecrypterror0lecncodepoint00lencrypterror0lillegalvaluelimmediateack0lintoiteratorklocalhostv4llastopenpath0lnattraversallnonzerousizelnonetokenlog0lobservedaddr000lpathresponse0lpathsblocked0lreaddatagramlremotestatus000lrttestimator0lsenddatagramlserverconfig00000lsocketaddrv4lsocketaddrv6lstoppederrorltokioruntimelunstructuredkaugmentargs0000kcidlifetime000kclosereasonkconnectwithlconservativekdatablocked0kdrainstreamkearlycrypto000keventstreamkexpecttypes000kgeneratecid000kgrosegmentskhandleevent0kinitialkeys00000000kintorequest0klostpackets000kmaxincoming0kmayfragment00knetworkpath0knewreceiverlnoprotection0jorigdstcid0kpathabandon0kpolltimeoutkqlogfactory0kresetstream0kruntimetypeksegmentsize00ksendquantum0ksendstreamsksetlifetime0ksetpriority0kstopsending0kstreamstatskuploadstatskwithinitial000kwritechunksmalertreceived0mbloomtokenlog0mcidsexhausted000mclonetouninitmdatagrameventmendpointeventmendpointstatsmfinishedearlymhandshakedata0mhandshakedone0mhandshaketypelinvalidtoken0mincomingalpns0minvalidheadermlocallyclosed0mmaxstreamdata0mmaxstreamsuni0mnewconnectionmnewrenoconfig0mparseinterrormpartialdecodempathchallenge0mpossiblevaluemprivatekeydermreadableerrormremoveaddress0mrootcertstoremstdsystemtime0munexpectedendlaccepted0rttlackfrequency00mauthenticatedlbenchexports0lcidgenerator00lcreatesenderldatatransferldownloadsizeldurationhistlimmediateack0lintoincoming0kmaxackdelay0lnoprotectionlobservedaddr0konfirstbytekonmtuupdate0000000lpathresponse0lpathsblocked0lpeeridentity0000lpollshutdownlpolltransmitkqlogfromenv0lreaddatagramlsenddatagramlsendfairness0lsignaturelen0lstartsession000000000ktrypollnext0naddipv4address0naddipv6address0naddressremovednasyncudpsocketncertificatedernclosepatherror0ncommandfactorynconnectionlost000000nendpointconfig0nfromargmatchesminternalerror0nincomingfutureninvalidframeidninvalidmessage00nmaxstreamsbidi0lnoviablepath0nnonetokenstore0npeermisbehaved00nreachoutatipv40nreachoutatipv60nreadexacterrornreadtoenderrornshouldtransmitntransferresultntransporterror00nudpsocketstatenweakpathhandlemconnectclientmcryptosessionmdownloadstatsmforconnection000mhandletimeoutmhandshakedata00000mhandshakedone0mhassubcommandminitialwindow0000000000000mintounorderedmishandshaking0000lisvalidretry000mminimumchange0lnext1rttkeys000lonpacketlost000lonpacketsent000mpathchallenge0lqlogfrompath0mreadhandshake000mreadunorderedmreceivewindow00mreceivedreset00mremoteaddress000mremoveaddress0msaturatingadd000msaturatingsub0mthroughputbpsmtimethreshold0mtotaldurationmvaluevariantsoconnectionclose000oconnectionerror0oconnectionevent0oconnectionstats0ogetrandomfailedonewconnectionid0oopenstreamstatsopathcidsblocked0oprotectedheader0oqlogfilefactory0oremoteabandoned0osignatureschemeosystemtimeerrorotokenreuseerror0otransportconfig00otryfrominterroroversionmismatch0ozerorttacceptedozerorttrejected000mbloomtokenlogmclonetouninit00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ndefaultruntimemgreasequicbit0nintegritylimit0ninterfaceindexmmaxstreamdata0mmaxstreamsuni0mparsebytesizenrebindabstractnsendunreliablenserverendpointmsetpathstatusmsetsendwindow0nshouldtransmitnstreamfinishednthroughputhistmwrapudpsocket00nwritehandshake000A`addressdiscoveryA`applicationclose000A`certificateerrorA`connectionclosed0A`connectionhandleA`datagramreceivedA`decryptedinitial0A`endpointstopping0nfinalsizeerror0A`inconsistentkeys00nkeyupdateerror0A`maxpathidreached0A`observedipv4addr0A`observedipv6addr0A`pathstatusbackup0A`peerincompatible00A`quicclientconfig0A`quicserverconfig0A`tokenmemorycache0A`toomanyaddressesA`validationfailed00A`versionnegotiate0ncheckandinsert00000oconfigureclientocongestionstate0oconnectionclose0nforcekeyupdate0nfromargmatches00000nmaxgsosegmentsnmaxidletimeout0nmaxstreamsbidi0nn0nattraversal0oopenconnections0nopenpathensure0opacketthreshold0nreadmanychunksoreceivedatagramnrecvbuffersize0nsendbuffersize0otransportconfig0000ovalidationtoken0nwithsinglecert0nwriteallchunksA`applicationerror0Aaapplicationclosed000Aacontrollerfactory0Aacontrollermetrics0Aahandshaketokenkey0Aainvalidservername0Aanetworkchangehint0Aapacketdecodeerror0Aapathabandonreason00Aasenddatagramerror0Aastreamdatablocked0Aastreamsblockeduni0Aaunsupportedbypeer0A`congestionevents0A`congestionwindow0omaxdatagramsizeonewconnectionid0opathcidsblocked0osendbufferspaceosetserverconfig0osetupconnectionotopossiblevalueowaitalldrainingowritemanychunksA`aeadlimitreached0Abackfrequencyconfig0Abbadmaxfragmentsize0Aaconnectionrefused0AbconnectionidparserAbdatagramsunblockedA`flowcontrolerror0AbhandshakeconfirmedAbhandshakedatareadyAbillegalorderedreadAbinvalidcertificate0Abmtudiscoveryconfig0AbnotenoughaddressesA`perfciphersuitesAaprotocolviolation0Abprivatepkcs8keyderAbretireconnectionid0A`streamlimiterror0A`streamstateerror0AbservercertverifiedAbservercertverifierAbsetpathstatuserror0Abstreamsblockedbidi0AbtokiocurrentthreadAbtransporterrorcode0Abunsupportedversion00000A`commandforupdate0000A`cryptobuffersize0A`fromu64unchecked0AaignoredhandshakesA`issameconnectionA`minresetinterval0A`newexpecteditems0A`pathstatusbackup0AarefusedhandshakesA`remotepathstatusA`senddatagramwaitA`setalpnprotocols000A`setreceivewindow0Aasupportedversions0A`tokenmemorycacheA`verifyservercertA`withstartinstant0AccongestionalgorithmAcnattraversalupdatesAcpathnewconnectionid0Acpathstatusavailable0Acremotecidsexhausted0ActransportparametersAcunorderedrecvstreamAcunsupportednametype0AcwrongconnectionsideAbacceptedhandshakesAaarbitrarytakerest000AbaugmentsubcommandsAablackholecooldown0Aaearlydataaccepted000AbhandshakeconfirmedAaispathrecoverable0Aakeepaliveinterval0Aalostplpmtudprobes0Aaoncongestionevent0000000AboutgoinghandshakesAaremoteopenstreamsAasendbufferbenches00A`senddataonstreamAasentplpmtudprobes0Aastreamdatablocked0Aastreamsblockeduni0Abframeencodingerror0Adhandshakenotcomplete0Adinappropriatemessage000Adinvalidremoteaddress000Adnoinitialciphersuite0AdobservedexternaladdrAdserversidenotallowed0AdsupportedciphersuiteAdvarintboundsexceeded0AdverifierbuildererrorAdweakconnectionhandleAbackfrequencyconfig0Abblackholesdetected0Aafromargmatchesmut00000AbhandleclientstreamAbincomingbuffersize0AbismultipathenabledAbmaxreceivesegments0Aamaxudppayloadsize00Abmtudiscoveryconfig0AbpollendpointeventsAbpreferredaddressv40Abpreferredaddressv60AareadcertsfromfileAcreorderingthreshold0Abretireconnectionid0Abretrytokenlifetime0AasetmaxidletimeoutAasetrecvbuffersizeAasetsendbuffersizeAbstreamsblockedbidi0Actransportparameters00000Aeconnectionidgenerator0AedigitallysignedstructAenoapplicationprotocol0Aenodefaultclientconfig0Abpathunstableorpoor0Aevalidationtokenconfig0Adconfidentialitylimit0Achandlenetworkchange0AcincomingbufferbytesAclossreductionfactor0Acmaxtransmitsegments0AcnattraversalupdatesAcpathobservedaddressAcpathstatusavailable0Acstreamreceivewindow00Adcryptobufferexceeded0AfextensionnotnegotiatedAffailedtogetcurrenttime0Affailedtogetrandombytes0Afmultipathnotnegotiated000000Afpathretireconnectionid0AfprotectedinitialheaderAfskipserververificationAdbuildtransportconfigAdexportkeyingmaterial0000AcgetintomanysegmentsAcgetloopmanysegmentsAdmaxconcurrentstreamsAdobservedexternaladdr0Acpathnewconnectionid0Adverifytls12signatureAdverifytls13signatureAdwithrootcertificates0AgcertrevocationlisterrorAghandshakesignaturevalidAgnocertificatespresented0Agpeersentoversizedrecord0Aeackelicitingthreshold0Adaugmentargsforupdate0000AehaspendingretransmitsAeismultipathnegotiatedAdonackfrequencyupdate000AdsetkeepaliveintervalAdupdatefromargmatches00000Aevalidationtokenconfig0Afapplicationabandonpath0AhnoprotectionclientconfigAhnoprotectionserverconfigAdgetmaxudppayloadsize0Aeinitialdstcidprovider0AenewwithabstractsocketAfremoteaddressvalidated0AesetmaxconcurrentpathsAfsupportedverifyschemesAfconnectionidlimiterror0AiencryptedclienthelloerrorAiexportkeyingmaterialerror0Aiinvalidcertrevocationlist0Aenocidavailableforpath0Agtransportparametererror0AiunsupportedoperationerrorAfaddnattraversaladdress0Afdatagramsendbuffersize0AfgenerateselfsignedcertAgopenbidirectionalstreamAfpathretireconnectionid0AfsetdefaultclientconfigAesetpathmaxidletimeoutAhdefaultsupportedversionsAjunusableafternetworkchangeAgdatagramsendbufferspaceAgincomingbuffersizetotal0Agmaxconcurrentunistreams0AhopenunidirectionalstreamAhserverhandshakemigration0AgsetmaxconcurrentstreamsAhspuriouscongestionevents0Agtrywithplatformverifier0AkhashedconnectionidgeneratorAkinvalidencryptedclienthello0Ahpathresourcelimitreached0AkrandomconnectionidgeneratorAienablesegmentationoffload0Ahmaxconcurrentbidistreams0Agupdatefromargmatchesmut00000AjconfiguretracingsubscriberAidatagramreceivebuffersize0Aiinitiatenattraversalround0Aionspuriouscongestionevent00000AjreceivebidirectionalstreamAiremovenattraversaladdress0AhsetpathkeepaliveintervalAmfixedlengthconnectionidparserAminappropriatehandshakemessage000Akcongestioncontrollerfactory0Aidefaultpathmaxidletimeout0Aimaxoutgoingbytespersecond0Ajnegotiatedkeyexchangegroup0AkreceiveunidirectionalstreamAjsendobservedaddressreports0AisetmaxconcurrentbistreamsAkaugmentsubcommandsforupdateAkmaxconcurrentmultipathpaths0AjsetmaxconcurrentunistreamsAmpersistentcongestionthreshold0Aldefaultpathkeepaliveinterval0Amreceiveobservedaddressreports0Amgetlocalnattraversaladdresses0Angetremotenattraversaladdresses0Anmaxremotenattraversaladdresses00") \ No newline at end of file diff --git a/pr/720/docs/search.index/root.js b/pr/720/docs/search.index/root.js index 2c89b0e31..b69ba36d8 100644 --- a/pr/720/docs/search.index/root.js +++ b/pr/720/docs/search.index/root.js @@ -1 +1 @@ -rr_('{"normalizedName":{"I":"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","N":"ADLi","E":"OjAAAAAAAAA=","H":"l3o8z+ne"},"crateNames":{"N":"j","E":"OjAAAAAAAAA=","H":"JFDJy0NX"},"name":{"N":"ADLi","E":"OjAAAAAAAAA=","H":"tk2DadyR"},"path":{"N":"BBd","E":"OzAAAAEAAKQSuwACAAQACQAAAAsAbwB8AAEAhgAEAJEAAQCUACEAuAD0AK8BCAC5ASMA3gEOAPEBAAD2AQAA+AEFAAQCAQAIAgIADAIAAA8CBgAZAksCZgQAAGgEEgB8BAIAgAQDAIUECgCRBAkApQQAALcEAgC7BAMAwAQAAMIEAADHBAAAyQQBAM0EngBtBQEAcQUIAHsFCACFBQIAiwUJAJkFAgCdBQUApgUCAKoFAgC0BQAAvgUCAMIFAgDJBfIAvQYEAMMGAADFBgAAyAY8AAYHEgAbBwMAIAcDACUHGQBABwwAUgcBAFYHAABbBwEAXwcAAGEHAwBtBwAAbwcCAHQHAAB3B3UA7gcDAPQHBgD8B/oA+QgAAPsIAQD/CAEABgkAAAwJBQAWCQAAGAkAABsJAgAhCQEAKgkFADIJHQBRCRUAaQmVAgEMAQAJDAIADgwAABQMAQAcDAAAIAwDAC8MAAA3DAkAQgwHAEsMGQBmDBAAeAxSAMwMAwDUDAAA1wwBANoMAQDxDAEADw2GAZgOAgCdDi4BzQ8AANgPAQDcDwEA4g8DAOgPAQDrDwEA7g8BAPQPAwD5D0IAPRACAEIQFgBfEAEAYhACAG0QAQByEAQAeBADAIEQBQCKEAEAmhASAK4QIQDREB8A8xADAPsQAAD+EAEAAREBAAURBwAREQEAFhEBABwRAwAhEQAAIxECACcRNwBlEQUAbhEBAHMRBQB8EQUAhhEBAIsRVwDkEQAA6BEAAO0RAQDwEQEA9xEAAAASAQADEgMACBKnALESAACzEgAAthIBALkSAAC8EgMAwRILAM4SAQDWEgMA2xIYAPUSGAAPEwIAGBMBACMTEQA2EwQAPRMDAEITBwBMEwMAURMFAFsTAgBhEwAAYxMBAGYTGwCDEwIAiBMFAJATHwCyEwsAwBMFAMkTAQDQEyUA9xMEAP8TBQAHFBwAJRQBACkUEAA8FBsAWhQKAGgUBQBvFBgAiRQDAI4UGACqFB4A","H":"qWxZNKjA"},"entry":{"N":"ACLc","E":"OjAAAAEAAAAAAAUBEAAAAAAAAQAHAAgACgB7AH4AfwCAAIEAggCLAI8AkACTALYAtwCtAa4BuAHtAe4B7wHwAfIB8wH3Af4B/wEAAgMCBgILAhYCFwJlBHsEfwSEBJAEmwScBJ0EngShBKIEpgSnBKgEqQSqBKsErAStBK4ErwS0BLoEvwTBBMMExgTIBMsEbAVvBXAFegWEBYgFiQWKBZUFlgWXBZgFowWkBa0FrgWvBbAFswW1BbgFuQW6BbsFvAXBBcUFxgW8BsIGxAbGBscGBQcZBxoHHwckBz8HTQdOB08HUAdRB1cHWgdlB2YHZwdoB2wHcwd1B3YH8gfzB/sH+Aj+CAEJAgkFCQkJCgkUCRUJHgkoCSkJMAkxCVAJZwn/CwAMBAwFDAYMBwwIDAwMDwwSDBMMFwwfDCYMKQwqDDIMMww1DDYMQQxKDHcMywzQDNIM0wzdDN8M5AzlDOgM6wzsDO4M7wzwDPgM/gwBDQINBA0FDZYOlw6bDpwO0A/TD9oP2w/hD/APPBBAEEEQWRBaEGYQaRB3EHwQfxCAEIgQiRCMEI8QkBCVEJYQmRCtENAQ9xAAEQMRDxETERQRGBEgESIRYBFjEWQRbRFyEXsR7BHyEfYR+BH5EfwR/xEHErUSwBLNEtoS9BIOExwTHhMfE1ATVxNYE2ATghOwE7ETvhO/E8sTzhP2E/4TOhQ7FGUUbhSoFKkU","H":"XdUqQ9jQ"},"desc":{"N":"GBn","E":"OzAAAAEAAJoNhwEAAAEABwABAAoAWwB5AAAAewAIAIsAAQCOAAIAkwAaALYA9ACtAQEAuAECANoBAgDeAQEA4wEBAOYBAADrAQgA9gEBAP4BAgADAgAABgIAAAkCAgARAgEAFgICAB0CBgA9AgAASwIAAE0CAABPAgEAUwIAAFcCAgBbAgAAZAIEAG0CAAB3AgAAeQIBAIICAACIAgEAjAIAAI4CAACTAgAAmAIAAJsCAACsAgoAzgIEANcCAADqAgAA7wIAAPYCAAD7AgAA/QIAAAMDAAAKAwAAEgMAABgDAAAaAwAAIAMAACQDAAAnAwAAMAMBADMDCABIAwAAVwMVAFsEBABhBAAAZQQAAGcEAABpBAAAawQAAG0EDAB7BAAAfwQAAIEEAACEBAAAjQQAAJAEAACWBAEAmQQFAKEEAQClBAoAtAQAALoEAAC/BAAAwQQAAMMEBQDLBAEAzgQCANIEAwDbBIwAbAUEAHkFAQB8BQIAhAUAAIYFBQCSBQAAlQUDAJ0FAwCjBQEAqwUFALMFAAC1BQAAuAUEAMEFAQDEBQIAzQXtALwGAQC/BgEAwgYAAMQGAADGBgEAygYAAM4GAADRBggA2wYBAN8GCwDuBgAA9QYBAPgGAQD+BgIAAgcDABkHAgAdBwAAHwcBACIHCwA0BwEAPwcAAEMHAgBHBwIATQcEAFcHAABaBwIAXwcAAGEHBwBsBwAAcwcAAHUHAQB7BwAAfgcZAKAHMADSBwEA5AcCAOgHAgDyBwEA+wcAAP0HAAABCO0A+AgEAP4IAAABCQEABQkAAAkJAQAQCQEAFAkBAB4JAAAoCQEALQkEAEAJAQBKCQQAUAkAAFQJAgBYCQIAZAkBAGcJAgB1CcMAPApSAJEKAACTCmYB/gsCAAQMBAAMDAEADwwAABIMAQAXDAAAGgwBAB8MAAAhDAEAJgwAACkMAQAyDAEANQwBADgMCQBDDAIARwwDAE4MAQBWDAAAYQwDAGkMAQBsDAQAcgwAAHUMAgB7DAAAfQwFAIQMQwDLDAAA0AwAANIMAQDdDAAA3wwAAOQMAQDoDAAA6wwBAO4MBAD4DAAA/gwAAAENBAAQDQUAGA3tAAgOjACWDgEAmw4GAbUPAAC9DwIAwQ8CAMoPAQDNDwMA0w8AANgPAwDhDwAA5A8BAOgPBADuDwIA8g8BAPUPAwAKEA0AGRABABwQAQAfEAAAIRABACUQEwA8EAAAQBABAFYQAQBZEAEAZhAAAGkQAABsEAAAdRADAHwQAAB/EAEAgxADAIgQAQCMEAAAjxABAJUQAQCZEAUAoRABAKYQAgCqEAAArBABALQQAQC7EAEAvxAEAM8QAgDUEAEA2RABAOYQAwD3EAAA/hACAAMRAAAIEQMADxEAABERAwAWEQIAHREBACARAAAiEQAAJhEAACgRAgAwEQIANBECADgRBgBEEQAAUBEBAFQRCQBgEQAAYxEBAG0RAAByEQAAdREBAHsRAAB+EQMAhREAAI0RAACPEQAAkREAAJYRAACYEQMAnREAAJ8RAAChEQAApBEAAKYRAACoEQAArBEAAK8RAACxEQAAsxEAALcRAAC5EQAAuxEAAL0RAAC/EQAAwRECAMcRAADJEQAA1REBAN0RAADgEQIA5BEAAOwRAgDwEQIA9hEAAPgRAQD8EQAA/xEAAAcSjQCbEgQAoRIAAKcSAQCqEgEArRIAAK8SAACxEgAAsxIAALUSAADAEgAAxxIGANoSAADdEgEA4BICAOUSAQDpEgUA8hICAP0SAAACEwAADhMAABwTAAAeEwEAIxMDAC4TAwA1EwEATRMAAFATAgBXEwEAWxMCAGATAABmEwQAdRMBAIITAQCGEwAAiBMDAJQTBACcEwAAnhMAAKcTAgCrEwIAsBMBALMTAAC2EwMAvhMBAMsTAADOEwAA1BMGAOoTAADtEwEA9BMCAPgTAAD7EwAA/hMAABIUAQAlFAEAKBQBACwUAAAuFAAANBQDADoUAQBCFAQAShQAAEwUAABOFAUAWBQBAGIUAABlFAAAbhQAAHMUAwCAFAAAkhQGAJ8UAACiFAEAqBQBALQUAAC4FAAA","H":"XGliR/x3"},"function":{"N":"AABo","E":"OzAAAAEAAJkDVwAAAAoAewAYALYAAQCtAQEAuAEAAN0BAADtASMAFgICAGUEAABnBAAAewQAAH8EAACEBAAAkAQAAJsELQDLBAEAbAUAAG8FAQB6BQAAhAUAAIgFAwCSBQAAlQUDAJwFLAC8BgAAvwYAAMIGAgDGBgIAzAYAAAUHAAAZBwYAIgcAACQHAAA/BwAASgcuAO0HAADyBwEA+wcAAPcIMwAwCQEAUAkAAGcJAQD/CzcAQQwAAEoMAABlDAAAdwwAAMsMAADQDAMA1Qw5AJYOAwCbDgEAzA8AAM4PHADtDwYA+A8AADwQAABAEAEAVhAhAHkQIACtEAAA0BABAO8QLAAgEQIAJhEAAFoRMADiESUAsBIrAPQSAQAMExwANRMAADkTEwBOExcAghMAAIYTDACwEwIAuhMVAPYTAAD5EwAA/BMKABcUEQA6FAUAVhQDAGMUCwB6FAAAiBQFAKcUBAA=","H":"3Gqd2yql"},"type":{"N":"AK`","E":"OzAAAAEAABgTnAACAAQACQAAAAsAbwB8AAIAhgAFAI8AAACRAAEAlAAhALgA9ACuAQkAuQEzAPEBAQD2AQkABAIBAAgCAgAMAgAADwIHABgCggKhBAAApQQCAKoEAACsBAAAtAQAALcEAgC7BAMAwAQAAMIEAADHBAAAyQQBAMwEtwCFBREAmQUCAJ0FBgCmBQIAqgUCALQFAAC+BQYAyQWDAU8HBABWBwAAWwcBAF8HAABhBwMAbQcAAG8HAgBzB34A8wcDAfkIAAD7CAEA/ggCAAYJAAAJCQEADAkFABYJAAAYCQAAGwkCACEJAQAqCdQCAQwBAAQMAwAJDAMADgwAABQMAQAcDAAAIAwDACYMAAApDAEALwwAADIMAQA2DEAAeAxXANIMAgDXDAEA2gwBAN0MAADkDAEA6AwAAPAMAgAEDQAADw28As0PAADYDwEA3A8BAOEPBADoDwEA6w8BAO4PAgD0D2QAXxABAGIQAgBtEAEAchAJAIEQBQCKEAEAmhBWAPMQBAD7EAAA/hABAAERAQAFEQcAEREBABYRAQAcEUIAYxEAAGURBQBtEQIAcxEFAHwRBQCGEQEAixFXAOQRAADoEQAA7REBAPARAgD3EQAAABIBAAMSrACxEgAAsxIAALYSAQC5EgAAvBIDAMESCwDOEgEA1hIDANsSMgAPEwIAGBMBABwTAAAeEwAAIxMXAD0TAwBCEwcATBMDAFETBQBYEwAAWxMCAGETAABjEwEAZhMfAIgTBQCQEy0AwBMFAMkTAQDQEysA/xMFAAcUHAAlFAEAKRQQADwUGwBaFAoAaBQFAG8UGACJFAMAjhQYAKoUHgA=","H":"d8yQm+CH"},"alias":{"N":"`","E":"OzAAAAEAAMgUAQAAAMgU","H":"p2IVDFMs"},"generic_inverted_index":{"N":"b","E":"OjAAAAAAAAA=","H":"XidL0dHg"}}') \ No newline at end of file +rr_('{"normalizedName":{"I":"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","N":"ADLj","E":"OjAAAAAAAAA=","H":"DxnQUwfF"},"crateNames":{"N":"j","E":"OjAAAAAAAAA=","H":"JFDJy0NX"},"name":{"N":"ADLj","E":"OjAAAAAAAAA=","H":"ohZlXL3a"},"path":{"N":"BBd","E":"OzAAAAEAAKUSuwACAAQACQAAAAsAbwB8AAEAhgAEAJEAAQCUACEAuAD0AK8BCAC5ASMA3gEOAPEBAAD2AQAA+AEFAAQCAQAIAgIADAIAAA8CBgAZAksCZgQAAGgEEgB8BAIAgAQDAIUECgCRBAkApQQAALcEAgC7BAMAwAQAAMIEAADHBAAAyQQBAM0EngBtBQEAcQUIAHsFCACFBQIAiwUJAJkFAgCdBQUApgUCAKoFAgC0BQAAvgUCAMIFAgDJBfIAvQYEAMMGAADFBgAAyAY8AAYHEgAbBwMAIAcDACUHGQBABwwAUgcBAFYHAABbBwEAXwcAAGEHAwBtBwAAbwcCAHQHAAB3B3UA7gcDAPQHBgD8B/oA+QgAAPsIAQD/CAEABgkAAAwJBQAWCQAAGAkAABsJAgAhCQEAKgkFADIJHQBRCRUAaQmVAgEMAQAJDAIADgwAABQMAQAcDAAAIAwDAC8MAAA3DAkAQgwHAEsMGQBmDBAAeAxSAMwMAwDUDAAA1wwBANoMAQDxDAEADw2GAZgOAgCdDi4BzQ8AANgPAQDcDwEA4g8DAOgPAQDrDwEA7g8BAPQPAwD5D0IAPRACAEIQFgBfEAEAYhACAG0QAQByEAQAeBADAIEQBQCKEAEAmhASAK4QIQDREB8A8xADAPsQAAD+EAEAAREBAAURBwAREQEAFhEBABwRBAAiEQAAJBECACgRNwBmEQUAbxEBAHQRBQB9EQUAhxEBAIwRVwDlEQAA6REAAO4RAQDxEQEA+BEAAAESAQAEEgMACRKnALISAAC0EgAAtxIBALoSAAC9EgMAwhILAM8SAQDXEgMA3BIYAPYSGAAQEwIAGRMBACQTEQA3EwQAPhMDAEMTBwBNEwMAUhMFAFwTAgBiEwAAZBMBAGcTGwCEEwIAiRMFAJETHwCzEwsAwRMFAMoTAQDREyUA+BMEAAAUBQAIFBwAJhQBACoUEAA9FBsAWxQKAGkUBQBwFBgAihQDAI8UGACrFB4A","H":"qWxZNKjA"},"entry":{"N":"ACLd","E":"OjAAAAEAAAAAAAUBEAAAAAAAAQAHAAgACgB7AH4AfwCAAIEAggCLAI8AkACTALYAtwCtAa4BuAHtAe4B7wHwAfIB8wH3Af4B/wEAAgMCBgILAhYCFwJlBHsEfwSEBJAEmwScBJ0EngShBKIEpgSnBKgEqQSqBKsErAStBK4ErwS0BLoEvwTBBMMExgTIBMsEbAVvBXAFegWEBYgFiQWKBZUFlgWXBZgFowWkBa0FrgWvBbAFswW1BbgFuQW6BbsFvAXBBcUFxgW8BsIGxAbGBscGBQcZBxoHHwckBz8HTQdOB08HUAdRB1cHWgdlB2YHZwdoB2wHcwd1B3YH8gfzB/sH+Aj+CAEJAgkFCQkJCgkUCRUJHgkoCSkJMAkxCVAJZwn/CwAMBAwFDAYMBwwIDAwMDwwSDBMMFwwfDCYMKQwqDDIMMww1DDYMQQxKDHcMywzQDNIM0wzdDN8M5AzlDOgM6wzsDO4M7wzwDPgM/gwBDQINBA0FDZYOlw6bDpwO0A/TD9oP2w/hD/APPBBAEEEQWRBaEGYQaRB3EHwQfxCAEIgQiRCMEI8QkBCVEJYQmRCtENAQ9xAAEQMRDxETERQRGBEhESMRYRFkEWURbhFzEXwR7RHzEfcR+RH6Ef0RABIIErYSwRLOEtsS9RIPEx0THxMgE1ETWBNZE2ETgxOxE7ITvxPAE8wTzxP3E/8TOxQ8FGYUbxSpFKoU","H":"HU34vu5L"},"desc":{"N":"GBo","E":"OzAAAAEAAJoNhgEAAAEABwABAAoAWwB5AAAAewAIAIsAAQCOAAIAkwAaALYA9ACtAQEAuAECANoBAgDeAQEA4wEBAOYBAADrAQgA9gEBAP4BAgADAgAABgIAAAkCAgARAgEAFgICAB0CBgA9AgAASwIAAE4CAQBRAgAAUwIAAFcCAQBaAgEAZAIEAG0CAAB4AgIAgQIAAIcCAQCMAgAAjwIAAJICAACZAgAAnAIAAKsCCQC2AgAAzgIEANcCAADqAgAA7wIAAPYCAAD7AgAA/QIAAAMDAAAKAwAAEgMAABgDAAAaAwAAIAMAACQDAAAnAwAAMAMBADMDCABIAwAAVwMVAFsEBABhBAAAZQQAAGcEAABpBAAAawQAAG0EDAB7BAAAfwQAAIEEAACEBAAAjQQAAJAEAACWBAEAmQQFAKEEAQClBAoAtAQAALoEAAC/BAAAwQQAAMMEBQDLBAEAzgQCANIEAwDbBIwAbAUEAHkFAQB8BQIAhAUAAIYFBQCSBQAAlQUDAJ0FAwCjBQEAqwUFALMFAAC1BQAAuAUEAMEFAQDEBQIAzQXtALwGAQC/BgEAwgYAAMQGAADGBgEAygYAAM4GAADRBggA2wYBAN8GCwDuBgAA9QYBAPgGAQD+BgIAAgcDABkHAgAdBwAAHwcBACIHCwA0BwEAPwcAAEMHAgBHBwIATQcEAFcHAABaBwIAXwcAAGEHBwBsBwAAcwcAAHUHAQB7BwAAfgcZAKAHMADSBwEA5AcCAOgHAgDyBwEA+wcAAP0HAAABCO0A+AgEAP4IAAABCQEABQkAAAkJAQAQCQEAFAkBAB4JAAAoCQEALQkEAEAJAQBKCQQAUAkAAFQJAgBYCQIAZAkBAGcJAgB1CcMAPApSAJEKAACTCmYB/gsCAAQMBAAMDAEADwwAABIMAQAXDAAAGgwBAB8MAAAhDAEAJgwAACkMAQAyDAEANQwBADgMCQBDDAIARwwDAE4MAQBWDAAAYQwDAGkMAQBsDAUAdQwCAHsMAAB9DAUAhAxDAMsMAADQDAAA0gwBAN0MAADfDAAA5AwBAOgMAADrDAEA7gwEAPgMAAD+DAAAAQ0EABANBQAYDe0ACA6MAJYOAQCbDgYBtQ8AAL0PAgDBDwIAyg8BAM0PAwDTDwAA2A8DAOEPAADkDwEA6A8EAO4PAgDyDwEA9Q8DAAoQDQAZEAEAHBABAB8QAAAhEAEAJRATADwQAABAEAEAVhABAFkQAQBmEAAAaRAAAGwQAAB1EAMAfBAAAH8QAQCDEAMAiBABAIwQAACPEAEAlRABAJkQBQChEAEAphACAKoQAACsEAEAtBABALsQAQC/EAQAzxACANQQAQDZEAEA5hADAPcQAAD+EAIAAxEAAAgRAwAPEQAAEREDABYRAgAdEQEAIREAACMRAAAnEQAAKRECADERAgA1EQIAOREGAEURAABREQEAVREJAGERAABkEQEAbhEAAHMRAAB2EQEAfBEAAH8RAwCGEQAAjhEAAJARAACSEQAAlxEAAJkRAwCeEQAAoBEAAKIRAAClEQAApxEAAKkRAACtEQAAsBEAALIRAAC0EQAAuBEAALoRAAC8EQAAvhEAAMARAADCEQIAyBEAAMoRAADWEQEA3hEAAOERAgDlEQAA7RECAPERAgD3EQAA+REBAP0RAAAAEgAACBKNAJwSBACiEgAAqBIBAKsSAQCuEgAAsBIAALISAAC0EgAAthIAAMESAADIEgYA2xIAAN4SAQDhEgIA5hIBAOoSBQDzEgIA/hIAAAMTAAAPEwAAHRMAAB8TAQAkEwMALxMDADYTAQBOEwAAURMCAFgTAQBcEwIAYRMAAGcTBAB2EwEAgxMBAIcTAACJEwMAlRMEAJ0TAACfEwAAqBMCAKwTAgCxEwEAtBMAALcTAwC/EwEAzBMAAM8TAADVEwYA6xMAAO4TAQD1EwIA+RMAAPwTAAD/EwAAExQBACYUAQApFAEALRQAAC8UAAA1FAMAOxQBAEMUBABLFAAATRQAAE8UBQBZFAEAYxQAAGYUAABvFAAAdBQDAIEUAACTFAYAoBQAAKMUAQCpFAEAtRQAALkUAAA=","H":"iAL3KdTA"},"function":{"N":"AAC`","E":"OzAAAAEAAJkDVwAAAAoAewAYALYAAQCtAQEAuAEAAN0BAADtASMAFgICAGUEAABnBAAAewQAAH8EAACEBAAAkAQAAJsELQDLBAEAbAUAAG8FAQB6BQAAhAUAAIgFAwCSBQAAlQUDAJwFLAC8BgAAvwYAAMIGAgDGBgIAzAYAAAUHAAAZBwYAIgcAACQHAAA/BwAASgcuAO0HAADyBwEA+wcAAPcIMwAwCQEAUAkAAGcJAQD/CzcAQQwAAEoMAABlDAAAdwwAAMsMAADQDAMA1Qw5AJYOAwCbDgEAzA8AAM4PHADtDwYA+A8AADwQAABAEAEAVhAhAHkQIACtEAAA0BABAO8QLAAhEQIAJxEAAFsRMADjESUAsRIrAPUSAQANExwANhMAADoTEwBPExcAgxMAAIcTDACxEwIAuxMVAPcTAAD6EwAA/RMKABgUEQA7FAUAVxQDAGQUCwB7FAAAiRQFAKgUBAA=","H":"KbVN8QVt"},"type":{"N":"AK`","E":"OzAAAAEAABkTnAACAAQACQAAAAsAbwB8AAIAhgAFAI8AAACRAAEAlAAhALgA9ACuAQkAuQEzAPEBAQD2AQkABAIBAAgCAgAMAgAADwIHABgCggKhBAAApQQCAKoEAACsBAAAtAQAALcEAgC7BAMAwAQAAMIEAADHBAAAyQQBAMwEtwCFBREAmQUCAJ0FBgCmBQIAqgUCALQFAAC+BQYAyQWDAU8HBABWBwAAWwcBAF8HAABhBwMAbQcAAG8HAgBzB34A8wcDAfkIAAD7CAEA/ggCAAYJAAAJCQEADAkFABYJAAAYCQAAGwkCACEJAQAqCdQCAQwBAAQMAwAJDAMADgwAABQMAQAcDAAAIAwDACYMAAApDAEALwwAADIMAQA2DEAAeAxXANIMAgDXDAEA2gwBAN0MAADkDAEA6AwAAPAMAgAEDQAADw28As0PAADYDwEA3A8BAOEPBADoDwEA6w8BAO4PAgD0D2QAXxABAGIQAgBtEAEAchAJAIEQBQCKEAEAmhBWAPMQBAD7EAAA/hABAAERAQAFEQcAEREBABYRAQAcEUMAZBEAAGYRBQBuEQIAdBEFAH0RBQCHEQEAjBFXAOURAADpEQAA7hEBAPERAgD4EQAAARIBAAQSrACyEgAAtBIAALcSAQC6EgAAvRIDAMISCwDPEgEA1xIDANwSMgAQEwIAGRMBAB0TAAAfEwAAJBMXAD4TAwBDEwcATRMDAFITBQBZEwAAXBMCAGITAABkEwEAZxMfAIkTBQCREy0AwRMFAMoTAQDREysAABQFAAgUHAAmFAEAKhQQAD0UGwBbFAoAaRQFAHAUGACKFAMAjxQYAKsUHgA=","H":"PhYDnvRL"},"alias":{"N":"`","E":"OzAAAAEAAMkUAQAAAMkU","H":"p2IVDFMs"},"generic_inverted_index":{"N":"b","E":"OjAAAAAAAAA=","H":"rxkfgkEA"}}') \ No newline at end of file diff --git a/pr/720/docs/search.index/type/3e16039ef44b.js b/pr/720/docs/search.index/type/3e16039ef44b.js new file mode 100644 index 000000000..63a0fe247 --- /dev/null +++ b/pr/720/docs/search.index/type/3e16039ef44b.js @@ -0,0 +1 @@ +rd_("CDg[\"\",\"ADswAAABAAAFAAIAWwQEAJkUAAAC8gYAABMHAAA6MAAAAQAAAAAACwAQAAAA6wHsAX4FzgyiEugS/hI4E3UUgRSkFLUUOjAAAAEAAAAAABwAEAAAAB0CHgIfAiACIQIiAiMCagR9BYIFwAbuBiAHaQkzEaUS6RJ/EzAUMRR4FJ4UnxSgFKEUohSjFLgUvBQ7MAAAAQAAOQETAGgEAABqBQAAfAUAAPMGAAASBwAAIwcAAH8MAwAQDQUACA6MALcQAAAgEQAANBEHAJMRAAAJEowAphIAAKgSAAA0EwAAgBMAAKATAAA6MAAAAQAAAAAAIAAQAAAAfwWFBYYFhwXsBu0G9Ab1BvYG9wb4BvkG+wv8C/0L/gtVDMMP5BBKEaEStBPzE/QTChRKFEsUTBRNFHAUdBSEFKUUOzAAAAEAAEQAFQBXAxUAhgQAAJIEAgBoBQEAawUAAIAFAQCbBQAA3wYMAO4HAQD6CwAAawwAACIQAABVEAAA5RAAAIwRAAC7EQcANRMAAHsTAwDrEwAAcRQAAKYUAAA7MAAAAQAAYQANAOIARwCaAQEAhQQAAJwHAACfBwAA3gcAAOAHAACpEAMA3RIFANsTAAALFAAATxQFAGIUAAA7MAAAAQAADQAGAGwEAADPDAAAlQ4AAB4QAwCjEgAAkxQFADswAAABAAATAAkAggQBAIsEAQDdBwAA3wcAAL0PAgDGDwAARREAAAwTAACnEwcAOzAAAAEAAAoAAwD9BgcAQAcBAPoSAAABdAwAAASZBwAAmwcAAJ4HAABwDAAAADswAAABAAAFAAIA0QEAACsUBAAAAAHMBQAA\"]Bk[\"AAAAAAAAAAAEJBEAACURAABdFAAAXhQAAA==\",\"\"]0Bg[\"\",\"AAAFSgkAAEsJAABMCQAATQkAAE4JAAA=\"]AGo[\"AAAAAALCAQAA0gEAAAAAAmgFAABpBQAABJwHAACfBwAA3gcAAOAHAAA7MAAAAQAADQAFAJkFAQBxCQEAegwEAM8MAADHEQMAOjAAAAEAAAAAAAkAEAAAAIsEjATdB98Hxg+xEbIRsxG0EQwTBHwEAABABwAAQQcAAP0SAAAGYgQAAGQEAADuEAAAORMAADcUAAA4FAAABYEEAACbBwAAngcAAMEPAADCDwAAA3EMAAByDAAAwA8AADswAAABAAAFAAIA0QEAACsUBAABhBMAAAFzDAAAAdoGAAA=\",\"AAAAAeIRAAAAAm0FAABuBQAAAAJODAAATwwAAAAFegwAAHsMAAB8DAAAfQwAAH4MAAAAAAJiBAAAZAQAAA==\"]ANk[\"AAAEZgIAAM8CAADJBgAAzQYAAANQDAAAUQwAAFIMAAACwgEAANIBAAA7MAAAAQAAjAABAAkSjAAAOzAAAAEAAAcAAwBoBQEAexMDAMcUAQAEnAcAAJ8HAADeBwAA4AcAADswAAABAAASAAcAmQUBABQHAABxCQEAegwEAM8MAADHEQMArRIDADowAAABAAAAAAAKABAAAACCBIMEiwSMBN0H3wfGD7ERshGzEbQRBXwEAACDBQAAQAcAAEEHAABGEQAABGIEAABkBAAANxQAADgUAAAEmwcAAJ4HAADBDwAAwg8AAATvBgAAcQwAAHIMAADADwAABSsUAAAsFAAALRQAAC4UAAAvFAAAAYQTAAAAAswFAADaBgAA\",\"AAAAAAACbQUAAG4FAAAAAk4MAABPDAAAATsQAAAFegwAAHsMAAB8DAAAfQwAAH4MAAAAAAJiBAAAZAQAAAAAAAAAAwgHAACaEQAAmxEAAA==\"]Dc[\"\",\"AAAAADswAAABAAAHAAEAUwkHADswAAABAAAJAAIAQBEEAJURBAAAAZQRAAA=\"]ADi[\"AAAABr8BAADBAQAAzgEAANABAABREAAAUhAAAAJ2CgAAegoAADowAAABAAAAAAAJABAAAADAAcYBxwHPAdgB2QHlCukKORQ6FDswAAABAAANAAQAzQQHAPQPAADqEAMAChQAAALKAQAANRMAADswAAABAAAXAAsAtQEBALwBAAB4DAEAyAwBAEgQAwDXEAEAJBEBAAQTAwDbEwAAXRQBAK0UAQABXxQAAAAAAAAAAAAAAcwFAAA=\",\"AAABugEAAALVBAAAlhIAAAAAAAK1DwAAzxAAAAAAAAAAAAAAAAAEywYAAM8GAADMDAAAzQwAAA==\",1]ADe[\"AAAAAr0BAADJAQAAOzAAAAEAAAcAAQBTCQcAAASFBQAAhgUAAIcFAAChEgAAAAABXxQAAA==\",\"AAAAADswAAABAAAQAAMAwAYAAFMJBwBCDAcAOzAAAAEAAAsABAAjBwAAJhEAAEARBACVEQQAOzAAAAEAAA8ABQDNBAcAYAwCAKoSAgDkEgAAdBQAADowAAABAAAAAAAKABAAAABQEVIRVBFWEVgRlBG3EbgRuRG6EesTBKkQAACqEAAAqxAAAKwQAAAAAAVPEQAAUREAAFMRAABVEQAAVxEAAAAAAAAAAAPMBQAAug8AALwPAAA=\",1]Ec[\"AAAAAAAAOzAAAAEAAAYAAgDWBgMA2wYCADswAAABAAAGAAIA0QYEADsJAQADfgQAAHgFAAB5BQAA\",\"\"]Dg[\"AAAAAAAAAAABUBQAAAGUFAAAAAAAAAAAAAABgAcAAA==\",\"AAAAAAAB6xIAAAHWEwAA\"]Eo[\"AAAAAQ4FAAABxAEAAAIvAAAAnwAAAAEqEAAAAVwDAAACFgEAABcBAAA=\",\"AAABrgAAAAEOBQAAAZYTAAAAAToMAAA=\"]Ic[\"AAAAAVAFAAAD1gEAALATAAAyFAAAAl0AAACsAAAABosBAACMAQAAYwQAAMsFAAA3EAAAhBQAAAFqAwAA\",\"AAABrwAAAAJQBQAAmBMAAAABPgwAAAAAAAAAAAAAAAAAAAKwAAAAsQAAAA==\"]Ik[\"AAAAAtsEAAADEwAAASAHAAABvQYAAAG4AAAAAYwRAAABTxQAAAKjEgAAkxQAAAAAAAAAAAAAOjAAAAEAAAAAAAkAEAAAAIwFuwZ9B/wHAxAbEEwQ2xAoEcsR\",\"AAAAAdsEAAAAAeoSAAAB1RMAAA==\"]Ck[\"AAAAAesBAAAAAAAAAVMUAAABlxQAAA==\",\"AAAAAAAB7hIAAAHZEwAA\"]Ck[\"AAAAAewBAAAAAAAAAVQUAAABmBQAAA==\",\"AAAAAAAB7xIAAAHaEwAA\"]Kk[\"AAAAAAAABH8FAACFBQAAhgUAAIcFAAAAOzAAAAEAAAkAAQDwCwkAOzAAAAEAAA0AAQBsBA0AOzAAAAEAAAkABABsDAMAvQ8CAEURAABZEQEAAAF0DAAAA3AMAADBDwAAwg8AAAJxDAAAwA8AAA==\",\"AAAAAAABJhEAAANgDAAAYQwAAGIMAAA=\"]Oc[\"AAAAAAAAAgoTAAALEwAABHsTAAB8EwAAfRMAAH4TAAACgRMAAIITAAAFFAcAAK0SAACuEgAArxIAALASAAACggQAAIMEAAACgwUAAEYRAAAAAAHvBgAAAAAAAcwFAAA=\",\"AAAAAAJ7BQAAYxQAAAAFnBQAAMMUAADEFAAAxRQAAMYUAAAB6xMAAAI7EAAAnRQAAAAAAAAAAAAAAAW5DwAArhAAAK8QAACwEAAAsRAAAA==\"]Bg[\"AAAAAAAAAATfEQAA4BEAAA0UAAAOFAAA\",\"\"]Bk[\"\",\"AAAAAd4RAAAAAAAAAAAAAAAAAAAAAAHKDwAA\"]Cc[\"AAAAAAAAAeQQAAAB5RAAAA==\",\"AAAAAAACawkAAGwJAAA=\"]FJc[\"AAAAADswAAABAAAXAAkAHQIGAGoEAACRBQAA/gcAAEwMAACyEAMA6RIAADAUAQCeFAUAOzAAAAEAACYCEwBhBAAAegQAAIAEAADzBgAAPAwDABANBQAYDe0ACA6MAD0QAABCEAAAtxAAANYQAAA0EQcAkxEAAAkSjACmEgAAqBIAAIATAADmEwAAOzAAAAEAAMUADwC4ACkAKgFvAJwBDgBjBAAAfwUAAMsFAADWBgMA2wYCAOwGAQA4DAMAuw8AALQTAADVEwUAShQDAIQUAAA7MAAAAQAAqwBDAFcDFQB9BAAAhwQBAJIEAgBrBQAAgAUBAJsFAADRBgQA3wYMAOsHAQDuBwEA8QgBADsJAQBRCQEAXAkBAE4MAQBeDAEAawwAABYNAQC2DwEAyA8BAAQQAQAHEAEAIhAAAEMQAQBNEAEAVRAAALgQAADIEAEA4hABAOUQAABLEQEAlBEAAJ8RAAChEQAAoxEAAKYRAACoEQAAqhEAALURDQDMEQEAzxECAN8RAQCXEgEA+xIBADUTAABsEwEAchMBAHsTAwCaEwEA3BMBAOwTAQDwEwEADRQBABUUAQBBFAEAVRQBAHEUAgB9FAMAghQBAI8UAwCmFAAAthQBALoUAQC9FAEAwRQBAMcUAQA7MAAAAQAAnQAnAOIARwCaAQEAtQEBAGAEAAB+BAAAhQQAAHgFAQCTBQEAnAcAAJ8HAADeBwAA4AcAAPALCQB4DAEAyAwBAMQPAQD8DwEAOxAAAEgQAwDXEAEAJBEBAC4RAQBHEQEApBIAAPESAQAEEwMAgRMBAKMTAQDREwEA5BMBAOcTAwALFAAATxQFAF0UAQBiFAAAmhQBAJ0UAACtFAUAvxQBADswAAABAAApAAwAbAQNAJkFAQAUBwAAcQkBAGgMAADPDAAAlQ4AAB4QAwDHEQMArRIDAOETAQCTFAUAOzAAAAEAABoADACCBAEAiwQBAN0HAADfBwAAbAwDAL0PAgDGDwAARREAAFkRAQAMEwAApxMHAKcUAAA6MAAAAQAAAAAADwAQAAAAfASDBf0G/gb/BgAHAQcCBwMHBAdGEcURxhH6Ev0SeRQFYgQAAGQEAAB0DAAA7hAAADkTAAAHgQQAAJkHAACbBwAAngcAAHAMAADBDwAAwg8AAATvBgAAcQwAAHIMAADADwAABSsUAAAsFAAALRQAAC4UAAAvFAAAAAFzDAAAAswFAADaBgAA\",\"AAAAAAA7MAAAAQAA7QABABgN7QAAOjAAAAEAAAAAAFsAEAAAAIcEiATrB+wH8QjyCFEJUglcCV0JTgxPDF4MXwwWDRcNtg+3D8gPyQ8EEAUQBxAIEEMQRBBNEE4QyBDJEOIQ4xBLEUwRnxGhEaMRphGoEaoRtRG2EcwRzRHfEeARlxKYEvsS/BJsE20TchNzE5oTmxPcE90T7BPtE/AT8RMNFA4UFRQWFEEUQhRVFFYUchRzFH0UfhR/FIAUghSDFI8UkBSRFJIUthS3FLoUuxS9FL4UwRTCFMcUyBQ7MAAAAQAAMwAVALUBAQCTBQEAeAwBAMgMAQD8DwEASBADANcQAQAkEQEALhEBAEcRAQDxEgEABBMDAIETAQCjEwEA0RMBAOQTAQDnEwMAXRQBAJoUAQCtFAUAvxQBAARxCQAAcgkAAOETAADiEwAAAALFEQAAxhEAAA==\"]Ic[\"AAAAAZwRAAAABHwFAABACQAAQQkAAKASAAA7MAAAAQAADAADAJUEBQD0BgUAKhQAAAADmAcAAEcRAABIEQAAAaQQAAAAB08RAABREQAAUxEAAFURAABXEQAAxREAAMYRAAAAAZkHAAA=\",\"\"]Ko[\"AAACZQIAANACAAAAADswAAABAAALAAMAxgEBANgBAQA0EQcAOzAAAAEAAAcAAQDNBAcAOzAAAAEAAA8ABQDrBwEABBABAE0QAQC1EQEAuxEHAAAC4RMAAOITAAA=\",\"AAAAAfoPAAAAAAAAAAAAAAAAAAAAAAX5DwAA+w8AAAMQAAAGEAAA4xMAAA==\"]AAk[\"AAAEZAIAANECAABCCQAAQwkAAAS7AQAAwwEAAMgBAADVAQAAAm0CAADXAgAAAAA6MAAAAQAAAAAAEwAQAAAAhwSIBPEI8gi6ELwQvhDAEMEQUBFSEVQRVhFYEfsS/BK6FLsUvRS+FAKBEwAAghMAAAV6DAAAewwAAHwMAAB9DAAAfgwAAAAFTxEAAFERAABTEQAAVREAAFcRAAAAAAAB0QEAAAAAAdoGAAA=\",\"AAAAAAAAAAAAAAAAAAAAAAAABPMIAAD0CAAA9QgAAPYIAAA=\"]CAk[\"AAADPwkAAG4TAABvEwAABbkBAABXCgAA3hEAAHQTAAB1EwAAOjAAAAEAAAAAAAcAEAAAAMQB1gFECUUJOwqSCrkKpRIBphIAAAW0EwAAShQAAEsUAABMFAAATRQAADowAAABAAAAAAAXABAAAADuB+8HtQ9DEEQQzxCfEaERoxGmEagRqhG7EbwRvRG+Eb8RwBHBEcIR3BPdE30UfhQD2xMAALEUAACyFAAABB4QAAAfEAAAIBAAACEQAAA7MAAAAQAACQADAN0HAADfBwAApxMHADswAAABAAAHAAEA/QYHAAACmwcAAJ4HAAA=\",\"AAAEcgUAAHMFAACrDwAArA8AADswAAABAAAWAAsAQgcHAJ0RAQCgEQAAohEAAKQRAQCnEQAAqREAAJkSAQAIFAEADBQAAFsUAQACsBMAADIUAAADBg4AAAcOAACgEgAAAAAAAAAAAAAAAAAAOjAAAAEAAAAAAHEAEAAAAK8BsAGyAbMBEQISAhoCGwJpBGsEjQTXBNkEygbOBvsG/AY0BzUHLQkuCWQJZQlLDE0MYwxkDGkMagx1DHYMsQ+yD7MPtA/LD/UP9g8ZEBoQTBCmEKcQxBDFEMYQxxDUENUQ2RDaEOYQ5xAdER4RKBEqESsRMREyETwRPRE+ET8RwxHEEdYR1xGcEp0SnhKfEuYS5xLzEvQSABMCEyoTKxMsEy0TLxMwEzETMhNwE3YTdxN4E5QTpROmE68TtRO2E7cTuBO5E7oT0xPUE+4T7xP1E/YTExQUFDUUNhR2FHcUhRSGFA==\"]Ac[\"AAAAAAFIAwAA\",\"\"]Gc[\"AAAABBEFAABDBwAA5AcAAJ4RAAADVAkAAEMMAACfFAAAATURAAABSxQAAAK8EQAAwBEAAAEdAQAAAR8QAAABqBMAAAH+BgAA\",\"AAAAAREFAAA=\"]Gc[\"AAAABFoFAABHBwAA6AcAAKURAAADWAkAAEcMAACiFAAAATkRAAACngEAAE0UAAACvhEAAMIRAAAAASEQAAABrBMAAAECBwAA\",\"AAAAAVoFAAA=\"]Cm[\"AAAAAAJtAgAA1wIAADswAAABAAAFAAEA2BEFAAACZwwAAPkSAAA=\",\"\",1]Ek[\"AAAAAAAAAAAAAAAAAAAAAAAAAvAGAAAGBwAA\",\"AAAAAAACuRAAALsQAAAAAroQAAC8EAAAAAKtEgAArhIAAA==\"]Eo[\"AAAAAAAAAAAAAAAAAAAAAAAAAvEGAAAHBwAA\",\"AAAAAAACvRAAAL8QAAAAA74QAADAEAAAwRAAAAACrxIAALASAAA=\"]Ck[\"AAAAAAAAAAAAAAAAAAAAAAAABXoAAACzAQAA2QcAAPYHAAD1CAAA\",\"\"]Bg[\"AAAAAAAAAcMPAAAAAAAAAsURAADGEQAA\",\"\"]Hg[\"AAAABGYAAADlBAAAjwUAAFAQAAABHwIAAAcOAAAAaAQAAGoFAAAxBwAAzRAAANQRAAA0FAAAA84AAABgCQAAxw8AAAAC8hMAAE4UAAA=\",\"AAAAAeUEAAAB8AgAAAFmBAAA\"]Ic[\"\",\"AAAAAAAAAAA7MAAAAQAACQABAPALCQA7MAAAAQAADQABAGwEDQA7MAAAAQAACQAEAGwMAwC9DwIARREAAFkRAQAAAXQMAAADcAwAAMEPAADCDwAAA3EMAAByDAAAwA8AAAAAAXMMAAA=\"]Hk[\"AAAD3gEAAFcMAABaDAAAAQ0FAAABxAEAAAQuAAAAngAAALkQAAC7EAAAASkQAAABWwMAAAMVAQAAjxEAAJARAAA=\",\"AAAC3gEAAFMMAAACiQQAAA0FAAABlRMAAAABOQwAAA==\"]Hk[\"AAAD3wEAAFgMAABbDAAAAU8FAAAB1gEAAARcAAAAqwAAAL0QAAC/EAAAAooBAAA2EAAAAWkDAAADfgQAAJERAACSEQAA\",\"AAAC3wEAAFQMAAADigQAAE8FAACXEwAAAAE9DAAA\"]AMo[\"AAAAAAGoEAAAAAA6MAAAAQAAAAAAEwAQAAAAygF9BF4MXwwWDRcNtg+3D0sRTBGXEpgSghSDFI8UkBS2FLcUwRTCFAKFBAAA2xMAAAQeEAAAHxAAACAQAAAhEAAAOzAAAAEAAAcAAQCnEwcAOzAAAAEAAAcAAQD9BgcAAAAAAdEBAAAAAAHaBgAA\",\"AAAHdAUAAHUFAABXDAAAWAwAAFoMAABbDAAApxIAADowAAABAAAAAAAYABAAAADhB+IHTwlbCVkMXAxdDK0Prg8YEMoQyxDMEBwRnBGsEa0RrhGvEbAR3hNIFEkUYBRhFDswAAABAAAIAQIAnQ4EAZwTAwA7MAAAAQAAXQADAAsAWgBxEwAAoRMBAAAAAATHEQAAyBEAAMkRAADKEQAABLERAACyEQAAsxEAALQRAAAB+hIAAAAAAAAAAAeRBAAAjAUAAPoGAACaDgAAHxEAADARAADLEQAA\"]Dk[\"AAAAAAI6CgAAjwoAAAAAADswAAABAAAFAAEA3RIFAAACggQAAIMEAAAAAmIEAABkBAAA\",\"\"]CAc[\"\",\"ADswAAABAAAFAAIAWwQEAJkUAAAC8gYAABMHAAA6MAAAAQAAAAAACwAQAAAA6wHsAX4FzgyiEugS/hI4E3UUgRSkFLUUOjAAAAEAAAAAABwAEAAAAB0CHgIfAiACIQIiAiMCagR9BYIFwAbuBiAHaQkzEaUS6RJ/EzAUMRR4FJ4UnxSgFKEUohSjFLgUvBQ7MAAAAQAANQESAGgEAABqBQAAfAUAAPMGAAASBwAAIwcAABANBQAIDowAtxAAACARAAA0EQcAkxEAAAkSjACmEgAAqBIAADQTAACAEwAAoBMAADowAAABAAAAAAAeABAAAAB/BYUFhgWHBewG7Qb0BvUG9gb3BvgG+Qb7C/wL/Qv+C8MP5BBKEaEStBPzE/QTChRKFEsUTBRNFHAUhBSlFDswAAABAABCABMAVwMVAIYEAACSBAIAaAUBAGsFAACABQEAmwUAAN8GDADuBwEA+gsAAGsMAAAiEAAAVRAAAOUQAAC7EQcANRMAAHsTAwBxFAAAphQAADswAAABAABcAAsA4gBHAJoBAQCFBAAAnAcAAJ8HAADeBwAA4AcAAN0SBQALFAAATxQFAGIUAAA7MAAAAQAADAAFAGwEAADPDAAAlQ4AAB4QAwCTFAUAOzAAAAEAABMACQCCBAEAiwQBAN0HAADfBwAAvQ8CAMYPAABFEQAADBMAAKcTBwA7MAAAAQAACQACAP0GBwBABwEAAXQMAAADmwcAAJ4HAABwDAAAAAUrFAAALBQAAC0UAAAuFAAALxQAAA==\"]Cc[\"AAAAAAAAAAAAAAACxREAAMYRAAAAAAAAAAAB2gYAAA==\",\"\"]Kg[\"AAAAAAF6EwAAADswAAABAAAGAAIA9AYFAEoRAAACawUAAFUQAAABhQQAAAABDBMAAAH9EgAAAu4QAAA5EwAA\",\"AAAAAAABgAQAADswAAABAAAFAAEAlQQFAAABxA8AAAAAAAAAAAAAAAccAgAA1gQAANgEAAAKBwAACwcAAA0HAAAOBwAA\"]Dk[\"AAAAAAABGAAAAAAAAeYAAAAAAAAAAAAAAAAC1gQAAPsGAAA=\",\"AAAAAAAAAAABxQ8AAA==\"]Dk[\"AAAAAAABNgAAAAEwAQAAAAAAAAAAAAAAAAAC2AQAAPwGAAA=\",\"AAAAAAAAAAABYAQAAA==\"]Ac[\"AAABeAIAAA==\",\"\"]Fg[\"AAAABBMFAABEBwAA5QcAAKARAAADVQkAAEQMAACgFAAAATYRAAAAAAEfAQAAAAGpEwAAAf8GAAA=\",\"AAAAARMFAAAAAcYBAAA=\"]Fg[\"AAAABFwFAABIBwAA6QcAAKcRAAADWQkAAEgMAACjFAAAAToRAAABoAEAAAAAAAGtEwAAAQMHAAA=\",\"AAAAAVwFAAAAAdgBAAA=\"]Bk[\"\",\"AAAAAAAAAAA7MAAAAQAASQACAOIARwCaAQEA\"]Ck[\"\",\"AAAAAAHABgAAOzAAAAEAAAkAAgAjBwAAJQcIAAF0FAAAAesTAAA=\"]Bo[\"\",\"AAAAAAAAAAAAAAAAAjcUAAA4FAAAAAAAAYQTAAA=\"]Ck[\"AAACeQIAAIwCAAA=\",\"AAAAAAAAAvgTAAD5EwAAAAACxxEAAMgRAAA=\"]Eo[\"\",\"AAAAAAA7MAAAAQAABQABAOoSBQA7MAAAAQAABQABANUTBQAAOzAAAAEAAAUAAQBPFAUAOzAAAAEAAAUAAQCTFAUA\"]Cc[\"\",\"AAAAAAKVEwAAlhMAAAAEOAwAADkMAAA6DAAAOwwAAA==\"]Eo[\"AAAAARcFAAAAATMAAAAAAAImAQAAJwEAAA==\",\"AAA7MAAAAQAACgACAKsCCQC2AgAAAhcFAACHFAAAAAABChMAAA==\"]Eo[\"AAAAAVYFAAAAAWQAAAAAAAKaAQAAmwEAAA==\",\"AAA7MAAAAQAACgACADADAQAzAwgAAlYFAACIFAAAAAABCxMAAA==\"]Dg[\"AAABGAMAAAFVBQAAAAFiAAAAApUBAACWAQAA\",\"AAABJwMAAAFVBQAAAAAAAAF+BAAA\"]Eo[\"AAAAAAAAAqQBAAClAQAA\",\"AAAAAAAAB3AUAACcFAAApRQAAMMUAADEFAAAxRQAAMYUAAACcRQAAKYUAAABnRQAAA==\"]Bk[\"AAAAAAAAAVUBAAA=\",\"AAAB7wIAAAAAAXoEAAA=\"]Bg[\"AAAAAWAFAAAAAAGmAQAA\",\"AAAAAWAFAAA=\"]Bg[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAcoMAAA=\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAA9oHAAD3BwAA9ggAAA==\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAApEEAADbBwAA\",\"\"]Cg[\"AAAAAAAAAAI7CQAAPAkAAAAAAAAAAAAB0QEAAAAAAdoGAAA=\",\"\"]Fo[\"AAAAAAACfAUAAKgSAAAAAAAAAAAAAAAAAAAE/QcAAMsPAADoEAAA4REAAA==\",\"AAGhBwAAAAAAAAAAAAAAAAAAAAAAAALpEAAAjhEAAA==\"]Bk[\"AAAAAX4FAAAAAAHDDwAAASIQAAA=\",\"AAHSBwAA\"]Bg[\"AAAAAAAABOoQAADrEAAA7BAAAO0QAAA=\",\"\"]Ag[\"AAAAAr0BAADJAQAA\",\"\"]Dg[\"AAAAAAAAAAAAAnEJAAByCQAA\",\"AAAAAAAAAAAABXoMAAB7DAAAfAwAAH0MAAB+DAAA\"]AEo[\"AAAAAALCAQAA0gEAAAAAAmgFAABpBQAABJwHAACfBwAA3gcAAOAHAAA7MAAAAQAACwAEAJkFAQB6DAQAzwwAAMcRAwA6MAAAAQAAAAAACQAQAAAAiwSMBN0H3wfGD7ERshGzEbQRDBMEfAQAAEAHAABBBwAA/RIAAAZiBAAAZAQAAO4QAAA5EwAANxQAADgUAAAFgQQAAJsHAACeBwAAwQ8AAMIPAAADcQwAAHIMAADADwAAOzAAAAEAAAUAAgDRAQAAKxQEAAGEEwAAAXMMAAAB2gYAAA==\",\"AAAAAeIRAAAAAm0FAABuBQAAAAJODAAATwwAAAAAAAACYgQAAGQEAAA=\"]He[\"\",\"AAAAAAAEfwwAAIAMAACBDAAAggwAAAJVDAAAdBQAAAKMEQAA6xMAAAWpEAAAqhAAAKsQAACsEAAA2xMAAAGjEgAAAAH6EgAAAAGZBwAAAAHRAQAAAAABzAUAAA==\",1]AMk[\"AAACywEAANQBAAAGuwEAAMMBAADIAQAA1QEAAHQTAAB1EwAABH0FAABpCQAAOQoAAJAKAAAEfwwAAIAMAACBDAAAggwAAALzEwAA9BMAADowAAABAAAAAAAHABAAAAA7CTwJyBDJEGwTbRNyFHMUOjAAAAEAAAAAAAkAEAAAAGAEnAefB94H4AfED8UPOxCaFJsUAALdBwAA3wcAAA==\",\"AAAAOjAAAAEAAAAAABAAEAAAALEBeQd6B3sHfAf/BwAIgww+ED8Q4RBNEU4R9xL4EjMTfBQDZgkAAKgQAAAuEwAABn8MAACADAAAgQwAAIIMAAD/EgAAARMAAAAAAAKZBQAAmgUAAAACfAQAAP0SAAAC7hAAADkTAAADgQQAAMEPAADCDwAAA3EMAAByDAAAwA8AAAAAAnMMAADUDAAAOjAAAAEAAAAAAAcAEAAAALQBjgSPBDYHfQf8B/0HGxA=\"]Bg[\"AAAAAAAAAAAAAXcEAAA=\",\"AAAAAckFAAA=\"]Bk[\"AAAAAAAAADswAAABAAANAAIAmwUAAN8GDAA=\",\"\"]Cc[\"AAABMgkAAAABIwIAAAAAAAFgBAAA\",\"AAAAAAAAAAF9BAAA\"]Dg[\"AAAAAd8EAAAAAAHAAAAAAAAAAAAAAAAAAAADkAUAAAkHAAC5DwAA\",\"AAAAAd8EAAA=\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAdoGAAA=\",\"\"]Be[\"AAAAAAAAA4UFAACGBQAAhwUAAA==\",\"\",1]Bg[\"AAAAAAAAADswAAABAAAVAAEAVwMVAA==\",\"\"]Ek[\"AAAAAALFAQAA1wEAAA==\",\"AAAAAAVeCQAAXwkAAGEJAABiCQAAYwkAAAABYAkAAAAAAAAAAAAAAAABeBAAAA==\"]Cc[\"AAAAAeQEAAAAAQ0AAAACxgAAAMcAAAA=\",\"AAAAAeQEAAA=\"]Bg[\"AAAAAAAAAAAAAXIEAAA=\",\"AAAAAfAHAAA=\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAbAAAAA=\",\"\"]CAi[\"AAAAAALFAQAA1wEAAAE0EwAAAQoUAAACygEAADUTAAA6MAAAAQAAAAAAHQAQAAAAvAGTBZQF/A/9Dy4RLxHxEvISoxOkE9ET0hPkE+UT5xPoE+kT6hPyEwsUThSaFJsUrxSwFLEUshS/FMAUOzAAAAEAAAYAAwBxCQEAHhADAF8UAAABpxQAAAF5FAAAAAAB7wYAAAAAAAHMBQAA\",\"AAAFSgkAAEsJAABMCQAATQkAAE4JAAAEUAwAAFEMAABSDAAAlhIAADowAAABAAAAAAAYABAAAACrAckEygSaB50H8QfvCPAIXglfCWEJYgljCWYJnxCgEKEQohCjEC4TNxOcE50TnhOfEzswAAABAAAgAA4A5wEAAOkBAABhBAAAZgQAAHoEAACABAAAJQcIAH8MAwC4DwAA1hAAAEARBACVEQQAeRMAAOYTAAA7MAAAAQAAJAAKAGMEAACVBAUAywUAAPoHAABgCQAAuw8AACUQEwDkEgEA+BMBAPsTAQA7MAAAAQAACAAEALgQAAC3EQMAzxECABIUAAA7MAAAAQAADAAGAGAEAADEDwEAqRADAI8RAwDyEwAAThQAAAStEgAArhIAAK8SAACwEgAAOzAAAAEAAAYAAwBsDAMAWREBAKcUAAAEfAQAAEYRAAD9EgAAeRQAAAAAAe8GAAAB0QEAAAAAOzAAAAEAACAAEACyAAMA0AYAAN4GAAAuBwIAKwkAAG0JAwBzCQEACRAAACMQAQBFEAIA3BAEAM4RAACbEgAAFxQAALMUAQDJFAAA\",1]Mg[\"AAAAAe8EAAAAOjAAAAEAAAAAAAcAEAAAABkAmwDnAWYEuA/ZEdwRoRMCJhAAAOQSAAACWAMAAOAGAAAC5wAAAOgAAAAAAd0HAAAAAAGbBwAA\",\"AAGmBwAAAANmAAAAZwAAAO8EAAACbQIAAPEHAAAC2REAANwRAAAAAdIGAAAAAAAAAAAAAAAABWsAAABsAAAAbQAAAG4AAABvAAAA\"]A@c[\"AAAAAR4FAAAABzgAAACjAAAA6QEAANsRAADdEQAAeRMAAKITAAAHMwEAADQBAAC7DwAALhAAADoQAADOEAAA5RIAAARhAwAA5QYAAGsMAAASFAAAAaQSAAABlQ4AAALfBwAApxQAAAF5FAAAAAGeBwAA\",\"AAG8BwAAAAEeBQAAAtcCAAB7BQAAAtsRAADdEQAAAdcGAAAAAAFoDAAAAAH6EgAAAAAAAAAABXAAAABxAAAAcgAAAHMAAAB0AAAA\"]Bo[\"\",\"AAAAAAAAOzAAAAEAAKgAAwC4ACkAKgFvAJwBDgA=\"]CEa[\"\",\"AAA7MAAAAQAA7QABAAIL7QA7MAAAAQAA9AAMAAIKNgA8CjkAdwoCAHsKEwCRCgAAkwoeALMKBQC6CikA5goCAOsKFgDjEgAAhxQBADowAAABAAAAAAASABAAAACCBcoFwAZECUUJOQo6CjsKdgp6Co8KkAqSCrIKuQrkCuoKlROWEzowAAABAAAAAAAWABAAAABoBGoFIwcxB2sJbAnlCukKBg4HDs0QIBHUEeoS6xLsEu0S7hLvEqATNBQ5FDoUOjAAAAEAAAAAACoAEAAAAOwG7Qb6B2AJ+wv8C/0L/gs4DDkMOgw7DFUMxw/0DzoQzhDkEOoQ6xDsEO0QShEKEwsT1RPWE9cT2BPZE9oT+BP5E/sT/BNwFHQUnBSlFMMUxBTFFMYUOjAAAAEAAAAAABoAEAAAAH0EkgSTBJQEgAWBBdEG0gbTBtQG1QZrDFUQuhC8EL4QwBDBEOUQlBHPEdAR0RHrExIUcRSmFDswAAABAABjAA8A4gBHAJoBAQBgBAAAfgQAAIUEAAB4BQEAmAcAAMQPAQA7EAAApBIAAN0SBQDyEwAAThQGAGIUAACdFAAAOzAAAAEAABEACACZBQEAaAwAAM8MAACVDgAApBAAAMcRAwDhEwEAkxQFAAeCBAAAgwQAAMYPAABZEQAAWhEAAAwTAACnFAAAOjAAAAEAAAAAAAsAEAAAAHwEgwVAB0EHTxFREVMRVRFXEfoS/RJ5FAZiBAAAZAQAAO4QAAA5EwAANxQAADgUAAADmQcAAJsHAACeBwAAAnIMAADADwAAOzAAAAEAAAUAAgDRAQAAKxQEAAGEEwAAAALMBQAA2gYAAA==\",1]Le[\"\",\"AAAAAtoBAAC+BgAAAyEHAACvDwAAsA8AAAMSBwAA/xIAAAETAAA6MAAAAQAAAAAABwAQAAAAww+hEqoSqxKsEvMT9BMqFAKGBAAA+gsAAAG8AQAAAV8UAAAEvQ8AAL4PAAC/DwAARREAAAABdAwAAASBBAAAcAwAAMEPAADCDwAAAXEMAAAAAAFzDAAA\",1]Gc[\"\",\"AAAAOjAAAAEAAAAAAAcAEAAAAOsB7AGiEv4SdRSBFKQUtRQCIAcAAKgQAAAFvQYAAEAJAABBCQAA9w8AAKASAAABtBMAAAGMEQAAAdsTAAA=\"]Bo[\"\",\"AAAAApcTAACYEwAAAAQ8DAAAPQwAAD4MAAA/DAAA\"]Bk[\"\",\"AAAAAAAAOzAAAAEAAAYAAgDWBgMA2wYCAA==\"]Fc[\"AAAAAdMBAAAAAAAABJMFAACUBQAA/A8AAP0PAAA=\",\"AAA7MAAAAQAAQwABAIQMQwAAAAAAAAAAAAAAAAAAAAABDwcAAA==\"]Ao[\"\",\"AAA7MAAAAQAA7QABAAEI7QA=\"]A@o[\"AAAEgQIAAJICAACZAgAAqw8AAAHtBAAAA38TAAC4FAAAvBQAAAMWAAAAmgAAANgRAAABJRAAADowAAABAAAAAAAMABAAAABXA5IEkwRoBWkFgAXfBswR7BMVFEEUfxSRFALiAAAA4wAAAA==\",\"AAGlBwAAOzAAAAEAAAYAAwBkAgQAQgkAAG4TAAAB7QQAAARECQAAOQoAADoKAAA7CgAAAdgRAAABOAwAAAPRBgAAzxEAANARAAAAAAAAAAAAAAAAAaMPAAA=\"]AAk[\"AAAE9gIAABoDAAAgAwAArA8AAAEbBQAAAAQ0AAAAoQAAANoRAACAEwAABCwBAAAtAQAALBAAAIQUAAA6MAAAAQAAAAAACgAQAAAAXwOUBGsFgQXkBs0R7RMWFEIUgBSSFAABlQ4AAA==\",\"AAG7BwAAOzAAAAEAAAYAAwDOAgQAQwkAAG8TAAABGwUAAARFCQAAjwoAAJAKAACSCgAAAjwMAADaEQAAAtYGAAD6BwAAAdERAAAAAAAAAAAAAAAABKUPAACmDwAApw8AAKgPAAA=\"]Gc[\"AAA7MAAAAQAACwAEAJoQBACZEwAAQxQEALkUAAA=\",\"ADswAAABAAAJAAMAfgcBAIEHAgBnEwQAOzAAAAEAAAsABACaEAQAmRMAAEMUBAC5FAAA\"]Ic[\"AAAAAAAAAAA7MAAAAQAACQABAPALCQA7MAAAAQAADQABAGwEDQA7MAAAAQAACQAEAGwMAwC9DwIARREAAFkRAQAAAXQMAAADcAwAAMEPAADCDwAAA3EMAAByDAAAwA8AAAAAAXMMAAA=\",\"\"]Cc[\"AAAAAr8BAABNEQAAAAAAAAF4DAAAAAGLBAAAAUAHAAA=\",\"\"]Cc[\"AAAAAs4BAABOEQAAAAAAAAF5DAAAAAGMBAAAAUEHAAA=\",\"\"]ACg[\"AAAAAoUTAACGEwAAAAXGAQAAxwEAANgBAADZAQAAkxEAADswAAABAAALAAMAzQQHAH8FAABgDAIAOzAAAAEAAA0ABQBrBQAA7gcBAMgPAQAiEAAAuxEHAAePEQAAkBEAAJERAACSEQAACxQAAGIUAACdFAAABmgMAACVDgAAHhAAAB8QAAAgEAAAIRAAADswAAABAAAHAAEApxMHADswAAABAAAKAAQA/QYHAEYRAAD6EgAAeRQAAAABmQcAAAHvBgAAAAAAAcwFAAA=\",\"AAAAA+EBAADiAQAA4wEAAAAB1hAAAA==\"]Ek[\"AAAAAAAAAAAAAAAAAAAAAAACdgUAABYHAAA=\",\"AAAAAAAAAAK3EQAAuBEAAAAAAAAAAAAAAAAC8AYAAAYHAAA=\"]Ek[\"AAAAAAAAAAAAAAAAAAAAAAACdwUAABgHAAA=\",\"AAAAAAAAAAK5EQAAuhEAAAAAAAAAAAAAAAAC8QYAAAcHAAA=\"]Ak[\"\",\"AAAAAAIcEAAAHRAAAA==\"]Fc[\"AAAABBUFAABFBwAA5gcAAKIRAAACVgkAAEUMAAABNxEAAAAAASEBAAAAAaoTAAABAAcAAA==\",\"AAAAARUFAAAAAccBAAA=\"]Fc[\"AAAABF4FAABJBwAA6gcAAKkRAAACWgkAAEkMAAABOxEAAAGiAQAAAAAAAa4TAAABBAcAAA==\",\"AAAAAV4FAAAAAdkBAAA=\"]Bg[\"AAAAAAAAAAAAAXEEAAA=\",\"AAAAAWoJAAA=\"]Ag[\"AAACvgEAAM0BAAA=\",\"\"]Ao[\"AAAAAAAAAAAAAAAAAAFwDAAA\",\"\"]Ag[\"\",\"AAACwhAAAMMQAAA=\"]Bg[\"AAAAAAAAAAAAAaMSAAA=\",\"AAABeQAAAA==\"]Dg[\"AAAAAuEBAADiAQAAAAADhQUAAGAMAACqEgAAAAG8AQAAAV8UAAA=\",\"AAAAAZYSAAA=\"]Hg[\"AAAAAawRAAABnBMAAAO5EAAAQREAAJYRAAAB+BMAAAG3EQAAAakQAAACxxEAAK0SAAABsREAAAAAAAABLBQAAA==\",\"AAAAAAAAAAJQEQAAUhEAAAAAAAJPEQAAUREAAA==\"]Ig[\"AAAAAa8RAAABnhMAAAO9EAAAQxEAAJgRAAAB+xMAAAG5EQAAAasQAAACyREAAK8SAAABsxEAAAAAAAABLhQAAA==\",\"AAAAAAGNEQAAAAADVBEAAFYRAABYEQAAAAAAA1MRAABVEQAAVxEAAA==\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAngAAACoDwAA\",\"\"]Bk[\"AAAAAAAAAeEAAAAAAAF5BAAA\",\"AAAAAfkHAAA=\"]Cc[\"AAAAAeEQAAABsBMAAAACYwQAAMsFAAA=\",\"AAAAAAH+BwAA\"]Be[\"AAAAAAA7MAAAAQAAjAABAAkSjAA=\",\"\",1]Bg[\"AAAAAAAAAAAAAXQEAAA=\",\"AAAAATcMAAA=\"]Do[\"AAAAAAAAAAAAAAAAAAKbBwAAngcAAAHvBgAAAdEBAAA=\",\"AAAAAAAAAAAAAAAAAAAAAdEBAAA=\"]Dk[\"AAAAAAAAAAABURQAAAGVFAAA\",\"AAAAAAAB7BIAAAHXEwAAAAAAAAAAAAAAAAABgAcAAA==\"]Dg[\"AAAAAUIFAAAAAAJvAQAAcAEAAAHoBgAAAAAAAAAAAAAAAAEcAgAA\",\"AAAAAUIFAAA=\"]ACg[\"AAAAA7kBAABPCgAA3hEAAAPuBgAAsgoAADMRAAAABEoUAABLFAAATBQAAE0UAAA6MAAAAQAAAAAADQAQAAAAUQlSCVwJXQkHEAgQ4hDjEHITcxOaE5sT8BPxEzswAAABAAAPAAcALhEBAN0SBQCjEwEA8hMAAE4UAACvFAEAvxQBAAABpxQAAAF5FAAA\",\"AAAAA6wBAAC3AQAApRAAAASfEAAAoBAAAKEQAACiEAAAAucBAADpAQAAAAAC8hMAAE4UAAAAAacUAAABeRQAAAAAAAAAAAToAQAA6gEAAC8JAADhEQAA\"]Bk[\"AAAAAAEgBwAA\",\"AAAAAAAAAAGMEQAAAAGjEgAA\"]Ic[\"AAAABuIEAACOBQAAyQUAAM4MAAD3EgAAOBMAAAKwDwAAeBQAAAISBwAANBMAAAPEAAAAoRIAAAoUAAABaQUAAAGYBwAAAaQQAAA=\",\"AAAAAuIEAAC+BgAAASEHAAAAAAABvAEAAAFfFAAA\"]Gc[\"AAAAAvgSAAAMFAAAAcUGAAAB8wYAAAErAQAAArgQAAA1EwAAAAEUBwAAAAGDBQAAAAGZBwAAAe8GAAAAAAABzAUAAA==\",\"AAAAAAAAAAHKAQAA\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAXcAAAA=\",\"\"]Fg[\"AAAD8gYAABMHAAAVEAAABFwMAADSEAAA0xEAAGAUAAAFHgIAAIIFAADKBQAAmgcAAF8JAAAAAsoAAAD0DwAA\",\"AAABLBEAAA==\"]Fg[\"AAAABF0MAADTEAAA1REAAGEUAAACnQcAAGIJAAAB8wYAAAFyAQAAAAABFAcAAAABgwUAAAAAAAAAAAHMBQAA\",\"AAABLREAAA==\"]Dg[\"AAAAAUcFAAAAAVYAAAABewEAAA==\",\"AAAAAUcFAAAAAAAAAAAAAAAAAAAAAAF6AAAA\"]Bk[\"AAAAAAEdAgAAAAAAAAFuBAAA\",\"AAAAAWYMAAA=\"]Cg[\"AAAAAAHxBwAAAAAAAAFvBAAA\",\"AAAAAAAAAAJnDAAA+RIAAA==\"]Dk[\"\",\"AAAAADswAAABAAATAAEAhAcTADswAAABAAATAAEAmgATADswAAABAAATAAEAJRATAA==\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAXUAAAA=\",\"\"]Fg[\"AAAAAWEFAAAAAAGoAQAAAAAAAAAAAYEEAAAAAAABcwwAAAa0AAAAtAEAABUCAADeBgAANgcAAJsSAAA=\",\"AAHRBwAAAAFhBQAA\"]Hk[\"AAAErgAAAGgCAAByBQAAUwwAAAEPBQAAAAIwAAAAoAAAAAErEAAAAl0DAADjBgAAAhgBAAAZAQAA\",\"AAABmQIAAARoAAAAaQAAAGoAAAAPBQAAAcQBAAAAATsMAAAB1QYAAA==\"]Kc[\"AAAErwAAANICAABzBQAAVAwAAAFRBQAAAAReAAAArQAAAD0QAABCEAAAA40BAACOAQAAOBAAAAJrAwAA6gYAAA==\",\"AAABIAMAAAFRBQAAAdYBAAABPwwAAANjBAAAywUAANwGAAAAAAAAAAAAAAAAAAR1AAAAdgAAAHcAAAB4AAAA\"]Ak[\"AAAAAAJTEAAAVBAAAA==\",\"\"]Ao[\"AAAAAAAAAAACtQEAAN0SAAA=\",\"\"]Ao[\"AAAAAAAAAAACtgEAAOASAAA=\",\"\"]Dc[\"AAAAAAAAAAABGgEAAAAAAAAAAAAAAAWyAAAAjgQAAC4HAAD+DwAA3BAAAA==\",\"\"]Fc[\"AAAAAAAAAY8BAAAAAAAAAAAAAAAAAAWzAAAAjwQAAC8HAAD/DwAA3RAAAA==\",\"AAAAAAAAAAAAARQHAAAAAoMFAABGEQAA\"]Fc[\"AAAAAWIFAAAAAAGpAQAAAoYEAAD6CwAAAAAAAAF0DAAAAAAAAAAFtQAAADAHAAAsCQAAABAAAN4QAAA=\",\"AAAAAWIFAAA=\"]Hg[\"AAABlAAAAAH0BAAAAAIeAAAAEA0AAAAAAe8AAAAAAAAAAAAAAAADrwEAANcEAABLDAAA\",\"AAGpBwAAAAH0BAAAAAAAAAAAAAAAAAAAAAAENwcAADgHAAA7BwAAPAcAAA==\"]Hg[\"AAAAApcAAAAlBQAAAAI+AAAAEw0AAAE9AQAAAAAAAAAAAAAAAAADsAEAANkEAABNDAAA\",\"AAG/BwAAAAElBQAAAAAAAAAAAAAAAAAAAAAEOQcAADoHAAA9BwAAPgcAAA==\"]Bc[\"AAAAAAAAAAAAAAAAAAAAAAGEEwAA\",\"\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAXYAAAA=\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAmwAAAAMBwAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAnEAAAARBwAA\",\"\"]Bg[\"AAAAAAAAAAAAAXMEAAA=\",\"AAAAAQ8NAAA=\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAbEAAAA=\",\"\"]Hc[\"AAAAAAAB9w8AAAEqFAAAAAFSFAAAAZYUAAAAAAAAAAAAADowAAABAAAAAAANABAAAAD6BisJbwmaDgYQCRBFEB8RMBHOEQATAhPjExcU\",\"AAAAAAAB7RIAAAHYEwAA\"]Ak[\"AAAAAAIwFAAAMRQAAA==\",\"\"]Cg[\"AAAAATMTAAABZgkAAAGABAAAAAABhQQAAA==\",\"AAAAAAFMDAAA\"]Ag[\"\",\"AAAAAAAAAd0GAAA=\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAm0AAAC6DwAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAnIAAAC8DwAA\",\"\"]Ag[\"AAAAAAAAAAHrBgAA\",\"\"]Dk[\"AAAAAAAAOzAAAAEAAKgAAwC4ACkAKgFvAJwBDgAAOzAAAAEAAEkAAgDiAEcAmgEBAA==\",\"\"]Fo[\"AAAAAhAFAAAVBwAAAWEJAAACMQAAAKETAAAAA14DAABnDAAA+RIAAAIbAQAAHAEAAA==\",\"AAACnAIAAAEQAAABEAUAAAHFAQAAAc0QAAA=\"]Gk[\"AAAAAlIFAAAXBwAAAWMJAAACXwAAAKITAAACkAEAAJEBAAABbAMAAAABaAwAAAAB+hIAAAAAAe8GAAA=\",\"AAACJAMAAAIQAAABUgUAAAHXAQAAAAHOEAAA\"]Dk[\"AAAAAQUFAAAAAScAAAAAAeEGAAACBgEAAAcBAAA=\",\"AAAAAgUFAABXCgAAAAAAAdMGAAA=\"]Dk[\"AAAAATwFAAAAAU0AAAACYQEAAGIBAAAB5gYAAA==\",\"AAAAATwFAAABuQoAAAAB2AYAAA==\"]Ck[\"AAAAAT4QAAAAAAAAApwHAADeBwAA\",\"AAAAAAAAAAACqRAAAKoQAAA=\"]Ck[\"AAAAAT8QAAAAAAAAAp8HAADgBwAA\",\"AAAAAAAAAAACqxAAAKwQAAA=\"]Bk[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAikRAACpEgAA\"]Ek[\"AAAAA/8HAACZEgAACBQAAAAAAAAAAAHdBwAAAAABmwcAAA==\",\"AAAAAAAAAAK3EQAAuBEAAAKpEAAAqhAAAA==\"]Ek[\"AAAAAwAIAACaEgAACRQAAAAAAAAAAAHfBwAAAAABngcAAA==\",\"AAAAAAAAAAK5EQAAuhEAAAKrEAAArBAAAA==\"]Cg[\"AAAAAfoEAAAAASMAAAAAAAL3AAAA+AAAAA==\",\"AAAAAfoEAAA=\"]Dg[\"AAAAATAFAAAAAUkAAAACTwEAAFABAAA=\",\"AAAAATAFAAAAAAAAAAFoDAAAAAH6EgAA\"]Bo[\"AAAAAfEEAAAAARsAAAAAAAHqAAAA\",\"AAAAAfEEAAA=\"]Cc[\"AAAB7wIAAAEhBQAAAAE6AAAAATcBAAA=\",\"AAAAASEFAAA=\"]Ig[\"AAABlgAAAAH2BAAAAAIgAAAAEg0AAAAAAfEAAAAAAAAAAAAAAAA6MAAAAQAAAAAADQAQAAAA6AEaAjcHOwczCTcJsQ/5D8QQKhOlE7UT0xOFFA==\",\"AAGrBwAAAAL2BAAAjwUAAAABuA8AAA==\"]Ic[\"AAAAApkAAAAnBQAAAAJAAAAAFQ0AAAE/AQAAAAAAAAAAAAAAAAA6MAAAAQAAAAAADQAQAAAA6gEbAjkHPQc1CTkJsw/7D8YQKxOmE7YT1BOGFA==\",\"AAHBBwAAAAEnBQAAAAABuw8AAA==\"]Gg[\"AAACSwIAAFMCAAAB6AQAAAACEQAAACcHAAAC1AAAANUAAAA=\",\"AAACTgIAAE8CAAAB6AQAAAAAAAACxA8AAMUPAAAAAAJ8BAAA/RIAAAAAAXIMAAA=\"]Do[\"AAAAASkFAAAAAkEAAACkAAAAA0EBAABCAQAALxAAAAFiAwAA\",\"AAAAASkFAAAAAAAAAWAEAAA=\"]Ck[\"AAAAAg8UAAAQFAAAAAAAAAAAAAABdAwAAA==\",\"AAAAAAABJhEAAA==\"]Co[\"AAAAAAABEgcAAAOqEgAAqxIAAKwSAAAAAbwBAAA=\",\"AAAAAAAB9w8AAA==\"]KDa[\"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\",1]Eo[\"AAAAAAA7MAAAAQAABQABAOoSBQA7MAAAAQAABQABANUTBQAAOzAAAAEAAAUAAQBPFAUAOzAAAAEAAAUAAQCTFAUA\",\"\"]Ck[\"AAAAAAAAAX8FAAAAAAFsBAAA\",\"AAAAAAAAA2AMAABhDAAAYgwAAA==\"]Dg[\"AAAAARIFAAAAAAHOBAAAAZ8RAAABHgEAAA==\",\"AAG1BwAAAAESBQAAAAAAAZ8RAAA=\"]Dc[\"AAAAAVsFAAAAAAKfAQAA0gQAAAGmEQAA\",\"AAHNBwAAAAFbBQAAAAAAAaYRAAA=\"]Fo[\"AAAAAfMEAAAAAR0AAAAAAALtAAAA7gAAAA==\",\"AAGoBwAAAAHzBAAAAAVoBAAAMQcAAM0QAADUEQAANBQAAAFgCQAAAALyEwAAThQAAA==\"]Fc[\"AAAAASQFAAAAAT0AAAACOwEAADwBAAA=\",\"AAG+BwAAAAEkBQAAAAACOhAAAM4QAAACawwAABIUAAAAAAGnFAAAAXkUAAA=\"]Eo[\"AAAAAdIRAAABXgkAAAACvgAAAFUMAAABlBEAAAABcAQAAA==\",\"AAAAAAHKBQAAAAJVDAAA9A8AAAABmAcAAAGkEAAA\"]Dk[\"AAAABqISAAD+EgAAdRQAAIEUAACkFAAAtRQAAAAAAAAB2xMAAA==\",\"AAAAAAAAAAGMEQAA\"]A@g[\"AAAAOjAAAAEAAAAAABEAEAAAAIkE3gSNBcEG8AdqCTcMZgyDDA8NORBPEEkR6BLeExEUMxR8FAejEAAApRIAAC4TAAB6EwAAfxMAALgUAAC8FAAAB+cBAABmBAAAuA8AACARAABAEQAAlREAAKATAAA6MAAAAQAAAAAABwAQAAAAvwBKEeQScBScFKUUwxTFFANoBQAAZwwAAPkSAAAAAAAAAAAAASsUAAA=\",\"AAAAAd4EAAAB7wgAAAABVQwAAA==\"]ACk[\"AAAAOjAAAAEAAAAAAAgAEAAAAIoETwlZDK0P+g8cEa4RSBRJFDowAAABAAAAAAAHABAAAABqBHsFkQX+B0wMjRHpEjIUOjAAAAEAAAAAAAoAEAAAAOkBegQ9EEIQtxDWEJMRphJ5E4AT5hM6MAAAAQAAAAAABwAQAAAAKgG7DzoQzhDlEoQUxBTGFAVrBQAAawwAABIUAABxFAAAphQAAASkEgAACxQAAGIUAACdFAAAAmgMAACVDgAAAacUAAADRhEAAPoSAAB5FAAA\",\"AAAAAAAAAAAAAAAAAAGZBwAAAAAAAAHMBQAA\"]Io[\"AAAAA0IHAADjBwAAnREAAANTCQAAQgwAAJ4UAAABNBEAAAFKFAAAA+4HAAC7EQAAvxEAAAABHhAAAAGnEwAAAf0GAAA=\",\"AAAAAARCDAAAQwwAAEQMAABFDAAAAAXNBAAAzgQAAM8EAADQBAAA5BIAAA==\"]Io[\"AAAAA0YHAADnBwAApBEAAANXCQAARgwAAKEUAAABOBEAAAFMFAAAA+8HAAC9EQAAwREAAAABIBAAAAGrEwAAAQEHAAA=\",\"AAAAAARGDAAARwwAAEgMAABJDAAAAAXRBAAA0gQAANMEAADUBAAA5RIAAA==\"]No[\"AAABlQAAAAH1BAAAAAIfAAAAEQ0AAAAAAfAAAAAAAAAAAAAAAAA6MAAAAQAAAAAAJAAQAAAAEQJpBMoGNActCWQJYwxpDHUM9Q8ZEKYQ1BDZEOYQHREqETERPBE+EZoRwxHWEZwSnhLmEvMSLxMxE3YTtxO5E+4T9RMTFDUUdhQ=\",\"AAGqBwAAAAH1BAAAAAAAAAAAAAAAAAAAAAAEMwkAADQJAAA3CQAAOAkAAA==\"]No[\"AAAAApgAAAAmBQAAAAI/AAAAFA0AAAE+AQAAAAAAAAAAAAAAAAA6MAAAAQAAAAAAJAAQAAAAEgJrBM4GNQcuCWUJZAxqDHYM9g8aEKcQ1RDaEOcQHhErETIRPRE/EZsRxBHXEZ0SnxLnEvQSMBMyE3cTuBO6E+8T9hMUFDYUdxQ=\",\"AAHABwAAAAEmBQAAAAAAAAAAAAAAAAAAAAAENQkAADYJAAA5CQAAOgkAAA==\"]Cc[\"AAAAAQwFAAAAAAAAARMBAAA=\",\"AAAAAQwFAAAAAAH7CwAA\"]Ck[\"AAAAAU0FAAAAAAGHAQAA\",\"AAAAAU0FAAAAAAP8CwAA/QsAAP4LAAA=\"]Bk[\"AAAAAAAAAAAAAAAAAAGBBAAAAAAAAXMMAAA=\",\"\"]Bg[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAakPAAA=\"]Eo[\"AAAAAT0FAAAAAU8AAAACZQEAAGYBAAAB5wYAAA==\",\"AAAAAT0FAAAAAAHZBgAAAAAAAAAAAAAAAAACcQUAAKoPAAA=\"]Ak[\"AAAAAAAAAAABYhQAAA==\",\"\"]Ag[\"AAACrAIAADsDAAA=\",\"\"]Bo[\"AAAAAAAAAcgAAAAAAAABbgwAAA==\",\"AAAAATkQAAA=\"]Fg[\"AAAAAfAEAAAAARoAAAABxw8AAAJnDAAA+RIAAAHpAAAA\",\"AAGnBwAAAAHwBAAAAAExBwAAAccPAAAAAAAAAAAAAAAAAAEyBwAA\"]Gc[\"AAAAASAFAAAAATkAAAABNgEAAAABpBIAAAFoDAAAAAH6EgAA\",\"AAG9BwAAAAEgBQAAAAF5EwAAAToQAAAAAaQSAAAAAAAAAAAAAAABMwcAAA==\"]Do[\"AAAAAAAAAAHIDwAAApMFAAD8DwAA\",\"AAAAAb0BAAAAAAAByA8AAASTBQAA/A8AAI8RAACQEQAA\"]Do[\"AAAAAAAAAAHJDwAAApQFAAD9DwAA\",\"AAAAAckBAAAAAAAByQ8AAASUBQAA/Q8AAJERAACSEQAA\"]Ao[\"AAAAAAGoEAAAAAABzxAAAA==\",\"\"]Gc[\"AAABqxEAAAJoAAAA4QcAAAEhAgAAAQYOAAAB0AAAAAKSBAAAzxEAAALEDwAAOxAAAAABxg8AAAJ8BAAA/RIAAAABcAwAAAJxDAAAcgwAAA==\",\"\"]Cg[\"AAAAAAABBw4AAAADfQQAAJQEAADREQAA\",\"AAAAAAABPRAAAA==\"]Ec[\"AAABTgIAAAHpBAAAAAISAAAAKAcAAALWAAAA1wAAAA==\",\"AAABUQIAAAHpBAAAAAAAAs8RAADQEQAA\"]Bo[\"AAABLBEAAAAAAALLAAAAzAAAAA==\",\"AAAAAAGCBQAA\"]Ck[\"AAABLREAAAAAAAJ2AQAAdwEAAA==\",\"AAAAAAAAAAAAAAABgwUAAA==\"]Ao[\"AAAAAAAAAbQTAAABtQ8AAA==\",\"\"]Hg[\"AAAAAmoAAAD5BwAAASICAAABawkAAAPcAAAA7AYAAOQQAAACgAUAAFUQAAAAApkFAADPDAAABb0PAAC+DwAAvw8AAEURAAAMEwAAAAE5EwAAAsEPAADCDwAAAcAPAAA=\",\"\"]Do[\"AAAAAAABbAkAAALtBgAA+gcAAAKBBQAA5RAAAAABmgUAAAAAAe4QAAA=\",\"AAAAAAABQhAAAA==\"]Bc[\"AAAAAAAAAAAAAAAAAAAAAAGEEwAA\",\"\"]ABg[\"AAAEnAIAACQDAAABEAAAAhAAAAG+BgAAA8UBAADXAQAAIQcAAAK9BgAA9w8AAAJwFAAApRQAAAOMEQAAcRQAAKYUAAAFmAcAAI8RAACQEQAAkREAAJIRAAABpBAAAAAAAAGZBwAA\",\"AAAABRUHAAAXBwAA0hEAANMRAADVEQAAA6sBAACvDwAAsA8AAAHUEQAABZwUAADDFAAAxBQAAMUUAADGFAAAARIUAAABnRQAAAGjEgAAAAAAAAAAAALNDwAA6w8AADswAAABAAAFAAIAEwICAP4PAgA=\"]Cc[\"AAAAAT4FAAAAAVAAAAACZwEAAGgBAAA=\",\"AAAAAT4FAAA=\"]Dc[\"AAAAAAAAAAA7MAAAAQAABQABAN0SBQA=\",\"AAAABOABAADkAQAA5QEAAOYBAAA=\"]Ao[\"AAAAAeABAAAAAAAAAUgQAAA=\",\"\"]Ao[\"AAAAAeUBAAAAAAAAAUkQAAA=\",\"\"]Eo[\"AAAAAa0RAAABnRMAAAO7EAAAQhEAAJcRAAAB+RMAAAG4EQAAAaoQAAACyBEAAK4SAAABshEAAAAAAAABLRQAAA==\",\"\"]Eo[\"AAAAAbARAAABnxMAAAO/EAAARBEAAJkRAAAB/BMAAAG6EQAAAawQAAACyhEAALASAAABtBEAAAAAAAABLxQAAA==\",\"\"]Bc[\"AAAAAAAAApUEAAD0BgAAAAFKEAAA\",\"\"]Bc[\"AAAAAAAAApgEAAD3BgAAAAFLEAAA\",\"\"]Ec[\"AAAAAdoBAAAAAv8SAAABEwAAAvMTAAD0EwAAAoYEAAD6CwAAAAAAAAABgQQAAA==\",\"AAAAAAFIAwAA\"]Gg[\"AAAAAesEAAAAAhQAAAAqBwAAAt0AAADeAAAA\",\"AAADVwIAAFgCAABaAgAAAesEAAAAAAABVRAAAAACmQUAAM8MAAABDBMAAAABORMAAAABwA8AAA==\"]Ek[\"AAAAASsFAAAAAkMAAACmAAAAA0UBAABGAQAAMRAAAAFkAwAA\",\"AAAAASsFAAAAAAAAAAGaBQAAAAAB7hAAAA==\"]Ec[\"AAAAAAAAAXUBAAAAAAAAAAAAAAAAAALaBAAAcAkAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAcwFAAA=\"]Ec[\"AAABQAwAAAHdBAAAAAELAAAAAboAAAA=\",\"AAAAAd0EAAAAAUEJAAAAAAAAAAAAAAAAAAABuwYAAA==\"]Dg[\"AAAAAAF9BQAAAAAAAAAAAAAAAAAAAALpEAAAjhEAAA==\",\"AAGiBwAAAAAAAb0GAAA=\"]Ac[\"AAABegIAAA==\",\"\"]Do[\"AAAAAQQFAAAAASYAAAAAAAIEAQAABQEAAA==\",\"AAAChwIAAIgCAAABBAUAAAAAAAAAAeETAAA=\"]Dk[\"AAAAATsFAAAAAUwAAAACXwEAAGABAAA=\",\"AAAC+wIAAP0CAAABOwUAAAAAAAAAAeITAAA=\"]Bk[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAkYJAABICQAA\"]Dc[\"AAAAAAAAAAABJAEAAA==\",\"AAAAAAAAAAAAAAGCBAAAAUAHAAABYgQAAAGbBwAA\"]Co[\"AAAAAAAAAZgBAAA=\",\"AAAAAAAAAAAAAAGDBAAAAUEHAAABZAQAAAGeBwAA\"]Dk[\"AAAAARQFAAAAAcYBAAABzwQAAAGhEQAAASABAAA=\",\"AAG2BwAAAAEUBQAAAAAAAaERAAA=\"]Dk[\"AAAAAV0FAAAAAdgBAAACoQEAANMEAAABqBEAAA==\",\"AAHOBwAAAAFdBQAAAAAAAagRAAA=\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAWsAAAA=\",\"\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAXAAAAA=\",\"\"]Ck[\"AAAAASwFAAAAAUQAAAACRwEAAEgBAAA=\",\"AAAAASwFAAAAAAHtBgAA\"]Eg[\"AAAAAf8EAAAAAiUAAACcAAAAAScQAAABWQMAAAL/AAAA8RIAAA==\",\"AAGxBwAAAYECAAAC/wQAAE8KAAA=\"]Eg[\"AAAAATYFAAAAAksAAACnAAAAAloBAAAyEAAAAWUDAAAB8hIAAA==\",\"AAHIBwAAAfYCAAABNgUAAAGyCgAA\"]Ao[\"AAAAAAAAAAAC1xAAAI8RAAA=\",\"\"]Ao[\"AAAAAAAAAAAC2BAAAJERAAA=\",\"\"]Do[\"AAABeQAAAAHcBAAAAAABuQAAAA==\",\"AAAAAdwEAAAAAUAJAAAAAAAAAAAAAAAAAAAB2xAAAA==\"]Bg[\"AAAAAAAABNsAAACHBQAAYgwAAKwSAAA=\",\"\"]Ak[\"AAAAAAABRQAAAAFJAQAA\",\"\"]Do[\"AAAAAAAAAAAAAAAAAAAAAAAAAikRAACpEgAA\",\"AAGgBwAAAAAAAAAAAAAAAAAAAAAAAAHoEAAA\"]Cg[\"AAAAAAPuBgAAaQkAADMRAAA=\",\"AAAAAAAAAAK1DwAAzxAAAA==\"]Cc[\"AAAAAXQKAAACdgoAAOQKAAAB5QoAAALqEAAA7BAAAA==\",\"\"]Ac[\"\",\"AAAAAeMSAAA=\"]Gg[\"AAAAAQMFAAABeBQAAAAAAfEIAAAEAwEAAEoQAAAFEwAAXRQAAAGkEAAA\",\"AAAAA8EBAAADBQAAhxQAAAABORQAAAAB8QgAAANKEAAABRMAAF0UAAA=\"]Bc[\"AAAAAcEBAAAAAAAAAAAAAU8RAAA=\",\"\"]Gg[\"AAAAAToFAAAAAAFeAQAAAfIIAAADSxAAAAcTAABeFAAAAAAAAAGZBwAA\",\"AAAAA9ABAAA6BQAAiBQAAAABOhQAAAAB8ggAAANLEAAABxMAAF4UAAA=\"]Bc[\"AAAAAdABAAAAAAAAAAAAAVMRAAA=\",\"\"]Fk[\"AAABWAIAAAH4BAAAAAEhAAAAAAAC8wAAAPQAAAA=\",\"AAGtBwAAAAH4BAAAAAJrCQAABg4AAALsBgAA5BAAAAOSBAAAkwQAAIAFAAA=\"]Fc[\"AAAAAS4FAAAAAUcAAAACSwEAAEwBAAA=\",\"AAHEBwAAAAEuBQAAAAJsCQAABw4AAAH6BwAABJQEAACBBQAA5RAAANERAAA=\"]Ao[\"\",\"AAAAAAAAAAAAAAABVxEAAA==\"]Ek[\"AAAAAQgFAAAAASoAAAAAAAIMAQAADQEAAA==\",\"AAABjwIAAAEIBQAAAAAAAAGYBwAAAaQQAAAAAk8RAABREQAA\"]Eg[\"AAAAAUQFAAAAAVUAAAACcwEAAHQBAAA=\",\"AAABCgMAAAFEBQAAAAAAAAAAAAJTEQAAVREAAAABmQcAAA==\"]Ao[\"AAAAAAAAAAHBEAAAAAF+DAAA\",\"\"]Jk[\"AAAAAQkFAAAABSsAAACdAAAAbQUAALkQAAC7EAAAAvsLAAAoEAAABFoDAABODAAAuhAAALwQAAAEDgEAAA8BAACPEQAAkBEAAAJ6DAAAewwAAAKxEQAAshEAAA==\",\"AAAAAgkFAADSEAAAAsIBAACyEAAAAAABOwkAAA==\"]Og[\"AAAAAUkFAAAABVgAAACqAAAAbgUAAL0QAAC/EAAABoABAACBAQAA/AsAAP0LAAD+CwAANRAAAARoAwAATwwAAL4QAADAEAAAApERAACSEQAAAnwMAAB9DAAAArMRAAC0EQAA\",\"AAAABEkFAADVBwAA1gcAANMQAAAE0gEAALMQAAC0EAAAtRAAAAAAATwJAAACeAUAAHkFAAAAAAAAAAAAAAA7MAAAAQAACgACANcHBQD0BwQA\"]Cc[\"AAAAAT8FAAAAAVEAAAACaQEAAGoBAAA=\",\"AAAAAT8FAAA=\"]Ck[\"AAABdAUAAAEKBQAAAAEsAAAAAAABEAEAAA==\",\"AAAAAgoFAABQDAAA\"]Dg[\"AAABdQUAAAFKBQAAAAFZAAAAAYIBAAAAAAAAAAAAAe8GAAA=\",\"AAAAAkoFAABRDAAA\"]Cc[\"AAAAAWMFAAAAAWUAAAABqgEAAA==\",\"AAAAAmMFAABSDAAA\"]Dg[\"AAAAAAAAAAAAAAABRhEAAA==\",\"AAAABrYQAADwEgAA3xMAAOATAAAPFAAAEBQAAA==\"]Ak[\"AAAAAAAAAAAB3xIAAA==\",\"\"]Ak[\"AAAAAAAAAAAB4hIAAA==\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAm8AAAATAgAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAnQAAAAUAgAA\",\"\"]Bg[\"AAAAAAAAAAAAAXUEAAA=\",\"AAAAAUkRAAA=\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAm4AAAAyBwAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAnMAAAAzBwAA\",\"\"]Bo[\"AAAAAAAAAAAAAAAE/QYAAP4GAAD/BgAAAAcAAA==\",\"\"]Ec[\"AAAABKwBAAC3AQAAHwUAAKUQAAAAAAE1AQAAAAAAAAQBBwAAAgcAAAMHAAAEBwAA\",\"AAAAAR8FAAA=\"]Bg[\"AAAAAAAAAAAAAXYEAAA=\",\"AAAAAAF6EwAA\"]Cc[\"AAAAAXgKAAACegoAAOoKAAAB6QoAAALrEAAA7RAAAA==\",\"\"]Ag[\"AAAAAAABIwcAAA==\",\"\"]No[\"AAAAAQEFAAABIQcAAAE0EwAAAfQPAAAGXgwAAMgQAADcEwAA8BMAAFUUAAB9FAAABwEBAAC8AQAAyAwAAEgQAAAEEwAA5xMAAOkTAAABXxQAAAAAAAAAAAAAA8sGAADMDAAACBMAAA==\",\"AAAAAgEFAABREAAAAAHAAQAAAQoTAAAGXgwAAMgQAADcEwAA8BMAAFUUAAB9FAAABcgMAABIEAAABBMAAOcTAADpEwAA\"]Bo[\"AAAAAVEQAAAAAcABAAAAAroQAABQEQAAAAF6DAAA\",\"\"]Nc[\"AAAAATgFAAAAAAFcAQAAOjAAAAEAAAAAAAcAEAAAAMoBXwzJEDUT3RPxE1YUfhQFyQwAAEkQAAAGEwAA6BMAAOoTAAAAAAAAAAAAAAAEzAUAAM8GAADNDAAACRMAAA==\",\"AAAAAjgFAABSEAAAAAHPAQAAAQsTAAAGXwwAAMkQAADdEwAA8RMAAFYUAAB+FAAABckMAABJEAAABhMAAOgTAADqEwAA\"]Bo[\"AAAAAVIQAAAAAc8BAAAAAr4QAABUEQAAAAF8DAAA\",\"\"]Ao[\"AAAAAAAAAAAC5xMAAOgTAAA=\",\"\"]Ao[\"AAAAAAAAAAAC6RMAAOoTAAA=\",\"\"]Dc[\"AAABWgIAAAHsBAAAAAIVAAAAKwcAAALfAAAA4AAAAA==\",\"AAABWwIAAAHsBAAA\"]Bk[\"AAAAAeMBAAAAAATaAAAAhgUAAGEMAACrEgAA\",\"\"]Ec[\"AAAAApcTAACYEwAAApUTAACWEwAABDwMAAA9DAAAPgwAAD8MAAAEOAwAADkMAAA6DAAAOwwAAA==\",\"\"]Cc[\"AAAAAAAAAAAB3hIAAA==\",\"AAGjBwAAAAK7AQAAdBMAAA==\"]Cc[\"AAAAAAAAAAAB4RIAAA==\",\"AAG5BwAAAALIAQAAdRMAAA==\"]Bc[\"\",\"AAAAAAAAAAAAAAAAAAAB7wYAAA==\"]Ck[\"AAAAAq4PAAAYEAAAAAABfwEAAAG4EAAA\",\"AAHUBwAAAAAAAeYTAAA=\"]Ek[\"AAAAAeMEAAAAAAHFAAAAAAAAAAAAAAAAAAAEcBMAAHgTAACUEwAArxMAAA==\",\"AAGkBwAAAALjBAAAjgUAAA==\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAA20JAABGEAAAsxQAAA==\",\"\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAA24JAABHEAAAtBQAAA==\",\"\"]Bk[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAkcJAABJCQAA\"]Ac[\"\",\"AAAAAAHJBAAA\"]Bc[\"AAAAAAABYQQAAA==\",\"AAAAAAHKBAAA\"]Ec[\"AAAAARYFAAAAAccBAAAB0AQAAAKjEQAADRQAAAEiAQAA\",\"AAG3BwAAAAEWBQAAAAAAAqMRAAANFAAA\"]Ec[\"AAAAAV8FAAAAAdkBAAACowEAANQEAAACqhEAAA4UAAA=\",\"AAHPBwAAAAFfBQAAAAAAAqoRAAAOFAAA\"]Ag[\"\",\"AAAAAAABoBIAAA==\"]Co[\"AAAAArEBAADVBwAAAAABeAEAAA==\",\"AAAAAAAAAAAAAAAAAAAAAdEBAAA=\"]Ac[\"\",\"AAAAAAE3EwAA\"]Cg[\"AAAAAAAAAgoTAAALEwAAAAABoxIAAA==\",\"AAAAAAAAAAHrEwAA\"]Do[\"AAAAASoFAAAAAkIAAAClAAAAA0MBAABEAQAAMBAAAAFjAwAA\",\"AAAAASoFAAAAAAABfQQAAA==\"]Ak[\"AAAAAAACORQAADoUAAA=\",\"\"]Ac[\"AAAAAeQBAAA=\",\"\"]Ac[\"AAAAAeYBAAA=\",\"\"]Eo[\"AAACEgMAACcDAAABUwUAAAABYAAAAAKSAQAAkwEAAA==\",\"AAAAAVMFAAAAAAAF0QYAANIGAADTBgAA1AYAANUGAAA=\"]Fk[\"AAAABMoQAADLEAAA3xMAAOATAAABrw8AAAEmEQAAAaESAAAAAAFfFAAAAAAAAAAAAAFzDAAA\",\"AAAAAAAAA6oSAACrEgAArBIAAA==\"]Fc[\"AAAAAAABvQYAAAIKEwAACxMAAAGMEQAAAAGjEgAAAAACNxQAADgUAAAAAAABhBMAAA==\",\"AAAAAAAAAXQUAAAB6xMAAA==\"]Co[\"AAAAAfsEAAAAASQAAAAAAAL5AAAA+gAAAA==\",\"AAAAAfsEAAAAAWoFAAA=\"]Co[\"AAAAATEFAAAAAUoAAAACUQEAAFIBAAA=\",\"AAAAATEFAAAAAAAAAAGVDgAA\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAARAHAAA=\",\"\"]Ik[\"AAAAAgAFAABbFAAAAAAAApcSAAByEwAABQABAAC8AQAAeAwAACQRAACBEwAAA3EJAADhEwAAXxQAAA==\",\"AAGyBwAAAAK/AQAAAAUAAAAAAAKXEgAAchMAAAN4DAAAJBEAAIETAAACcQkAAOETAAA=\"]Ig[\"AAAAAjcFAABcFAAAAAABWwEAAAPKAQAAmBIAAHMTAAADeQwAACURAACCEwAAAnIJAADiEwAA\",\"AAHJBwAAAALOAQAANwUAAAHFBgAAAAACmBIAAHMTAAADeQwAACURAACCEwAAAnIJAADiEwAA\"]Ao[\"AAAAAAAAAc0AAAAAAAF4BAAA\",\"\"]Bc[\"AAAAAAABTgAAAAJjAQAAZAEAAA==\",\"\"]Ag[\"AAACtgIAADQDAAA=\",\"\"]Ak[\"AAAAAAAAApYEAAD1BgAA\",\"\"]Ak[\"AAAAAAAAApkEAAD4BgAA\",\"\"]Ag[\"AAACtAIAADUDAAA=\",\"\"]Dk[\"AAAAAeoEAAAAAhMAAAApBwAAAtgAAADZAAAA\",\"AAABUwIAAAHqBAAAAAAAAAAAAcYPAAA=\"]Dg[\"AAAAAecEAAAAAhAAAAAmBwAAAtIAAADTAAAA\",\"AAABSwIAAAHnBAAAAAAAAAE7EAAA\"]Co[\"AAABpxIAAAEtBQAAAAFGAAAAAUoBAAA=\",\"AAHDBwAAATIJAAABLQUAAA==\"]Ec[\"AAAAAAABqBIAAAG7AAAAAAAAAAAAAAAAAAADjQQAAC8JAADKDwAA\",\"AAAAAbkBAAAAAAAAAdsTAAA=\"]Hk[\"AAAC6gIAAAMDAAABSwUAAAABWgAAAAKDAQAAhAEAAAAAAAAAAAAAAAAABBkCAABxBQAA0AYAAA8HAAA=\",\"AAABGAMAAALTAQAASwUAAAAAAvsTAAD8EwAAAAACyREAAMoRAAA=\"]Fc[\"AAAAA7YQAADMEAAA8BIAAAAC/xIAAAETAAADpwEAAPMTAAD0EwAAAoYEAAD6CwAAAAAAAAABgQQAAA==\",\"AAAAAdoBAAA=\"]Dc[\"AAAAAmcAAADmBAAAAiACAADwCAAAAQ8AAAABzwAAAA==\",\"AAAAAuYEAABQEAAA\"]Eg[\"AAAAAQYFAAAAASgAAAAAAAIIAQAACQEAAAAAAAAAAAAAAAMKBwAAog8AAKkPAAA=\",\"AAABjAIAAAEGBQAA\"]Eg[\"AAAAAUAFAAAAAVIAAAACawEAAGwBAAAAAAAAAAAAAAAAAAMNBwAApA8AAKoPAAA=\",\"AAABAwMAAAFABQAA\"]Jg[\"AAAFPQIAAE8CAABRAgAAVwIAAFsCAAAB+QQAAAACIgAAACwHAAAAAAL1AAAA9gAAAA==\",\"AAADeAIAAHkCAAB6AgAAAvkEAADBBgAAAsoFAACjEAAAAiARAACgEwAAAfQPAAABlBEAAAAAAAAAAAAAAAABCQcAAA==\"]Ek[\"AAAAAS8FAAAAAkgAAAAtBwAAAk0BAABOAQAA\",\"AAAB6gIAAAEvBQAAAAAAAAAAAAAAAAAAAAAC2gQAABAHAAA=\"]Bk[\"AAAAAAABtxAAAAF+AQAA\",\"AAAAAAAAAAG4EAAA\"]Hg[\"AAABlgAAAAH3BAAAAAESDQAAAAAB8gAAAAAAAAAAAAAAAAY4BwAAPAcAADQJAAA4CQAAsg8AAMUQAAA=\",\"AAGsBwAAAAL3BAAAjQUAAAAAAAAAAAAAAAAAAAAAAZAFAAA=\"]Fo[\"AAAAApkAAAAoBQAAAAEVDQAAAUABAAAAAAAAAAAAAAAAAAY6BwAAPgcAADYJAAA6CQAAtA8AAMcQAAA=\",\"AAHCBwAAAAEoBQAAAZEFAAA=\"]Ag[\"AAACswIAADYDAAA=\",\"\"]Cg[\"AAAAAWUFAAAAAAADtQ8AACIQAADPEAAA\",\"AAHTBwAAAAFlBQAA\"]Dg[\"AAAAAkUFAADWBwAAAAABeQEAAA==\",\"AAAAAUUFAAAAAAAAAAAAAAAAAAAAAAHaBgAA\"]Dg[\"AAAAAYUTAAABUxAAAAAAAAL7AAAAkBEAAA==\",\"AAE9CQAAAb4BAAABhRMAAAFTEAAA\"]Dg[\"AAAAAYYTAAABVBAAAAABVgEAAAABkhEAAA==\",\"AAE+CQAAAc0BAAABhhMAAAFUEAAA\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAacPAAA=\",\"\"]Ac[\"\",\"AAAAAAFjFAAA\"]Ag[\"AAACsgIAADcDAAA=\",\"\"]Bc[\"\",\"AAAAAAAAAAAD3RIAAN4SAADfEgAA\"]Bc[\"\",\"AAAAAAAAAAAD4BIAAOESAADiEgAA\"]Ak[\"\",\"AAAAAQMTAAAAAAEqFAAA\"]ADk[\"AAAAAfwEAAAAAAA6MAAAAQAAAAAAFQAQAAAA6wcWDbYPBBAHEEMQSxHMEd8R+xJsExUUchR/FIIUjxSRFLYUuhS9FMEUxxQ6MAAAAQAAAAAADQAQAAAA/ADXEEcR8RIEEwUToxPRE+QTmhStFK8UsRS/FAAAAcURAAA=\",\"AAGuBwAAAAH8BAAAAAAAOjAAAAEAAAAAABUAEAAAAOsHFg22DwQQBxBDEEsRzBHfEfsSbBMVFHIUfxSCFI8UkRS2FLoUvRTBFMcUOjAAAAEAAAAAAAoAEAAAANcQRxHxEqMT0RPkE5oUrRSvFLEUvxQAAAHFEQAA\"]ADo[\"AAAAATMFAAAAAAFXAQAAOjAAAAEAAAAAABUAEAAAAOwHFw23DwUQCBBEEEwRzRHgEfwSbRMWFHMUgBSDFJAUkhS3FLsUvhTCFMgUOjAAAAEAAAAAAAwAEAAAANgQSBHyEgYTBxOkE9IT5RObFK4UsBSyFMAUAAABxhEAAA==\",\"AAHFBwAAAAEzBQAAAAAAOjAAAAEAAAAAABUAEAAAAOwHFw23DwUQCBBEEEwRzRHgEfwSbRMWFHMUgBSDFJAUkhS3FLsUvhTCFMgUOjAAAAEAAAAAAAoAEAAAANgQSBHyEqQT0hPlE5sUrhSwFLIUwBQAAAHGEQAA\"]Ag[\"AAAChwIAAPsCAAA=\",\"\"]Bk[\"AAAAAAAAAAAAAW0EAAA=\",\"AAAAAAAAAVUMAAA=\"]Bk[\"AAAAAAAAAAAAAAFtDAAA\",\"AAAAAAABNBQAAA==\"]Do[\"AAAAAQcFAAAAASkAAAAAAAIKAQAACwEAAAAAAAAAAAAAAAILBwAAow8AAA==\",\"AAAAAQcFAAA=\"]Do[\"AAAAAUEFAAAAAVMAAAACbQEAAG4BAAAAAAAAAAAAAAAAAAIOBwAApQ8AAA==\",\"AAAAAUEFAAA=\"]Ag[\"AAACrQIAADEDAAA=\",\"\"]Fc[\"AAAAAUMFAAAAAlQAAACoAAAAAnEBAAAzEAAAAmYDAAC4EAAA\",\"AAAAAUMFAAAAAAAAAAAAAAABmQcAAAAAAAABzAUAAA==\"]Ao[\"AAAAAAHJBAAA\",\"AAAAAAGaBwAA\"]Ao[\"AAAAAAHKBAAA\",\"AAAAAAGdBwAA\"]Ag[\"AAACrwIAADMDAAA=\",\"\"]Ag[\"AAACqwIAADoDAAA=\",\"\"]Dg[\"AAAAARgFAAAAAAABexMAAAAAAAFREQAA\",\"AAAAAhgFAAB0CgAAAXYKAAAAAeoQAAA=\"]Do[\"AAAB2wEAAAFXBQAAAAAAAX0TAAAAAAABVREAAA==\",\"AAAAAVcFAAAB5AoAAAHlCgAAAewQAAA=\"]Do[\"AAAAARoFAAAAAAADvBAAAFIRAAB8EwAAAAF7DAAA\",\"AAAAAhoFAAB4CgAAAXoKAAAAAesQAAA=\"]Eg[\"AAAB3AEAAAFZBQAAAAAAA8AQAABWEQAAfhMAAAABfQwAAA==\",\"AAAAAVkFAAAB6goAAAHpCgAAAe0QAAA=\"]Cc[\"AAAAAAAAApcEAAD2BgAAAAEUAQAA\",\"AAG0BwAAAAHDAQAA\"]Cc[\"AAAAAAAAA4kBAACaBAAA+QYAAA==\",\"AAHMBwAAAAHVAQAA\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAAwgHAADcBwAA+AcAAA==\",\"\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAaYPAAA=\",\"\"]Ao[\"AAAAAAAAAc0EAAAAAa0UAAA=\",\"\"]Bk[\"AAAAAAAAAdEEAAAAAa4UAAA=\",\"AAAAAdUEAAA=\"]Eg[\"AAAAAAAAAAAAAAAAAAAAAAAABHMJAAAjEAAA3xAAACwTAAA=\",\"AAG4BwAAAATjBwAA5AcAAOUHAADmBwAA\"]Eg[\"AAAAAAAAAAAAAAAAAAAAAAAABHQJAAAkEAAA4BAAAC0TAAA=\",\"AAHQBwAAAATnBwAA6AcAAOkHAADqBwAA\"]Bo[\"AAAAAAABwAEAAAAAAcgMAAAAAYIEAAAAAWIEAAA=\",\"\"]Bo[\"AAAAAAABzwEAAAAAAckMAAAAAYMEAAAAAWQEAAA=\",\"\"]Ak[\"AAAAAAABoRMAAAEKFAAA\",\"\"]Ao[\"AAAAAAABohMAAAAAAQsUAAA=\",\"\"]Gc[\"AAAAAUgFAAAAAlcAAACpAAAAA3wBAAB9AQAANBAAAAFnAwAA\",\"AAABEgMAAAFIBQAAAAAAAAJ4BQAAeQUAAAAAAAAAAAHRAQAAAAAB2gYAAA==\"]Bg[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAQwHAAA=\"]Dg[\"AAAAASIFAAAAATsAAAABOAEAAA==\",\"AAAAASIFAAAAAAAAAAAAAAAAAAAAAAERBwAA\"]Dg[\"AAAAAeEEAAAAAgwAAAAlBwAAAsIAAADDAAAA\",\"AAABPQIAAAHhBAAAAAABShEAAA==\"]Do[\"AAAAAR0FAAAAAjcAAACiAAAAAzEBAAAyAQAALRAAAAFgAwAA\",\"AAAAAR0FAAAAAAAAAYUEAAA=\"]Ek[\"AAAAAf0EAAAAAAAC7BMAAEEUAAAD/QAAAC4RAADREwAA\",\"AAGvBwAAAAH9BAAAAAAAAuwTAABBFAAAAS4RAAA=\"]Ek[\"AAAAATQFAAAAAAFYAQAAAu0TAABCFAAAAi8RAADSEwAA\",\"AAHGBwAAAAE0BQAAAAAAAu0TAABCFAAAAS8RAAA=\"]Cc[\"AAAAAAAAAAABeAUAAAAAAAAAAAHRAQAAAAAB2gYAAA==\",\"\"]Fg[\"AAAAAf4EAAAAAAAEUQkAAE0QAAC1EQAAmhMAAAL+AAAA5BMAAA==\",\"AAGwBwAAAAH+BAAAAAAABFEJAABNEAAAtREAAJoTAAA=\"]Fg[\"AAAAATUFAAAAAAFZAQAABFIJAABOEAAAthEAAJsTAAAB5RMAAA==\",\"AAHHBwAAAAE1BQAAAAAABFIJAABOEAAAthEAAJsTAAA=\"]Ag[\"\",\"AAAAAAAAAXQUAAA=\"]Bc[\"\",\"AAAAAAAAAAAAAAAAAAAAAAGEEwAA\"]Co[\"AAAAAfIEAAAAARwAAAAAAALrAAAA7AAAAA==\",\"AAAAAfIEAAAAAAHHDwAA\"]Co[\"AAAAASMFAAAAATwAAAACOQEAADoBAAA=\",\"AAAAASMFAAAAAAAAAaQSAAA=\"]Fg[\"AAABZwIAAAELBQAAAAEtAAAAAAHiBgAAAhEBAAASAQAA\",\"AAACkgIAAMkGAAABCwUAAAAAAAHUBgAAAAAAAAAAAAAAAAGiDwAA\"]Gc[\"AAABzgIAAALTAQAATAUAAAABWwAAAAKFAQAAhgEAAAHpBgAA\",\"AAACGgMAAM0GAAABTAUAAAAAAdsGAAAAAAAAAAAAAAAAAAIZAgAApA8AAA==\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAA9gHAAD1BwAA9AgAAA==\",\"\"]Cg[\"AAABjwIAAAAAAAAAASUBAAA=\",\"AAAAAAAAAAK6EAAAvBAAAA==\"]Cg[\"AAABCgMAAAAAAAGZAQAA\",\"AAAAAAAAAAO+EAAAwBAAAMEQAAA=\"]Bo[\"AAAAAtUEAABkBQAAATcTAAA=\",\"AAAAAmQFAADiEQAA\"]Bo[\"AAAAAAAAAckAAAAAAAABbwwAAA==\",\"AAAAAREUAAA=\"]Io[\"AAAAAVQFAAAAAWEAAAABlAEAAAabBQAAUBEAAFIRAABUEQAAVhEAAFgRAAAAAAAFTxEAAFERAABTEQAAVREAAFcRAAAAAAAAAAAByRQAAA==\",\"AAAAAVQFAAAAAAT4EwAA+RMAAPsTAAD8EwAAAAF+BAAA\"]Co[\"AAAAAmkAAADiBwAAAAAB0QAAAAKTBAAA0BEAAAHFDwAA\",\"AAABqxEAAA==\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAkYJAACuEAAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAkgJAACwEAAA\",\"\"]Co[\"AAAAARkFAAAAAAAAAigBAAApAQAA\",\"AAAAARkFAAAAAALqEAAA6xAAAA==\"]Dc[\"AAAAAVgFAAAAAAKcAQAAnQEAAA==\",\"AAAAAlgFAADjEgAAAAAC7BAAAO0QAAA=\"]Cc[\"AAAAAAGrAQAAAAG9AAAAAAAAAWwMAAA=\",\"AAAAATMUAAA=\"]Ac[\"\",\"AAABQAwAAA==\"]Ec[\"AAABiAIAAAHuBAAAAAEXAAAAAAAC5AAAAOUAAAA=\",\"AAAAAe4EAAAERAkAADkKAAA6CgAAOwoAAA==\"]Do[\"AAAB/QIAAAEcBQAAAAE1AAAAAi4BAAAvAQAA\",\"AAAAARwFAAAERQkAAI8KAACQCgAAkgoAAA==\"]Ak[\"\",\"AAAAAAACORQAADoUAAA=\"]Ck[\"AAAAAuAEAABbCQAAAe8IAAABcRMAAAHBAAAA\",\"AAAAAuAEAABPEAAA\"]Bg[\"AAAAAXkHAAACnxAAALIQAAAAAfsLAAA=\",\"\"]Bk[\"AAAAAXoHAAACoBAAALMQAAAAAvwLAAD9CwAA\",\"\"]Bc[\"AAAAAAAAAAAAAAAAAjcUAAA4FAAA\",\"\"]Fo[\"AAAAAQIFAAAAAAADhwQAAFwJAABVFAAAAgIBAAC1AQAA\",\"AAGzBwAAAAECBQAAAAAAAocEAABcCQAAAbUBAAAAAAAAAAAAAAABCBMAAA==\"]Fo[\"AAAAATkFAAAAAAFdAQAAA4gEAABdCQAAVhQAAAG2AQAA\",\"AAHKBwAAAAE5BQAAAAAAAogEAABdCQAAAbYBAAAAAAAAAAAAAAABCRMAAA==\"]Ck[\"AAAAATIFAAAAAAJTAQAAVAEAAA==\",\"AAAAATIFAAAAAAAAAWIUAAA=\"]Ec[\"AAAAAUYFAAAAAAF6AQAAAAAAAAAAAAAAAAAFsgEAANcHAAD0BwAA8wgAAMoMAAA=\",\"AAAAAUYFAAA=\"]Dg[\"AAAAAAFjFAAAAAG8AAAAAAAAAAACNxQAADgUAAAAAAABhBMAAA==\",\"AAABugEAAA==\"]Ag[\"AAACsAIAADkDAAA=\",\"\"]Bc[\"\",\"AAAAAAAAAAAAAAAAAjcUAAA4FAAA\"]Cc[\"AAAAAWYFAAAAAAAAAAAAAVcRAAA=\",\"AAAB2wEAAAFmBQAA\"]Ck[\"AAAAAWcFAAAAAAACwRAAAFgRAAAAAX4MAAA=\",\"AAAB3AEAAAFnBQAA\"]Ag[\"AAACsQIAADgDAAA=\",\"\"]Dg[\"AAAAAAABMgAAAAAAASMBAAA=\",\"AAAAAAAAAAAAAAAAAAAAAysUAAAsFAAALRQAAA==\"]Ck[\"AAAAAAABYwAAAAGXAQAA\",\"AAAAAAAAAAAAAAAAAAAAAi4UAAAvFAAA\"]Ag[\"AAACrgIAADADAAA=\",\"\"]Do[\"AAAAAXsHAAACoRAAALQQAAAAAf4LAAAB4hAAAA==\",\"AALMAQAAugcAAAE/CQAAAAAAAAHiEAAA\"]Ec[\"AAAAAk4FAAB8BwAAAqIQAAC1EAAAAAGIAQAAAeMQAAA=\",\"AAHLBwAAAdQBAAABTgUAAAAAAAHjEAAA\"]Bg[\"AAAAAAAAAAABeQUAAA==\",\"AAABywEAAA==\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAkcJAACvEAAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAkkJAACxEAAA\",\"\"]") \ No newline at end of file diff --git a/pr/720/docs/search.index/type/77cc909be087.js b/pr/720/docs/search.index/type/77cc909be087.js deleted file mode 100644 index 67b245317..000000000 --- a/pr/720/docs/search.index/type/77cc909be087.js +++ /dev/null @@ -1 +0,0 @@ -rd_("CDc[\"\",\"ADswAAABAAAFAAIAWwQEAJgUAAAC8gYAABMHAAA6MAAAAQAAAAAACwAQAAAA6wHsAX4FzgyhEucS/RI3E3QUgBSjFLQUOjAAAAEAAAAAABwAEAAAAB0CHgIfAiACIQIiAiMCagR9BYIFwAbuBiAHaQkyEaQS6BJ+Ey8UMBR3FJ0UnhSfFKAUoRSiFLcUuxQ7MAAAAQAAOAESAGgEAABqBQAAfAUAAPMGAAASBwAAIwcAAH8MAwAQDQUACA6MALcQAAAzEQcAkhEAAAgSjAClEgAApxIAADMTAAB/EwAAnxMAADowAAABAAAAAAAgABAAAAB/BYUFhgWHBewG7Qb0BvUG9gb3BvgG+Qb7C/wL/Qv+C1UMww/kEEkRoBKzE/IT8xMJFEkUShRLFEwUbxRzFIMUpBQ7MAAAAQAARAAVAFcDFQCGBAAAkgQCAGgFAQBrBQAAgAUBAJsFAADfBgwA7gcBAPoLAABrDAAAIhAAAFUQAADlEAAAixEAALoRBwA0EwAAehMDAOoTAABwFAAApRQAADswAAABAABhAA0A4gBHAJoBAQCFBAAAnAcAAJ8HAADeBwAA4AcAAKkQAwDcEgUA2hMAAAoUAABOFAUAYRQAADswAAABAAANAAYAbAQAAM8MAACVDgAAHhADAKISAACSFAUAOzAAAAEAABMACQCCBAEAiwQBAN0HAADfBwAAvQ8CAMYPAABEEQAACxMAAKYTBwA7MAAAAQAACgADAP0GBwBABwEA+RIAAAF0DAAABJkHAACbBwAAngcAAHAMAAAAOzAAAAEAAAUAAgDRAQAAKhQEAAAAAcwFAAA=\"]Bk[\"AAAAAAAAAAAEIxEAACQRAABcFAAAXRQAAA==\",\"\"]0Bg[\"\",\"AAAFSgkAAEsJAABMCQAATQkAAE4JAAA=\"]AGo[\"AAAAAALCAQAA0gEAAAAAAmgFAABpBQAABJwHAACfBwAA3gcAAOAHAAA7MAAAAQAADQAFAJkFAQBxCQEAegwEAM8MAADGEQMAOjAAAAEAAAAAAAkAEAAAAIsEjATdB98Hxg+wEbERshGzEQsTBHwEAABABwAAQQcAAPwSAAAGYgQAAGQEAADuEAAAOBMAADYUAAA3FAAABYEEAACbBwAAngcAAMEPAADCDwAAA3EMAAByDAAAwA8AADswAAABAAAGAAMA0QEAANoGAAAqFAQAAYMTAAABcwwAAA==\",\"AAAAAeERAAAAAm0FAABuBQAAAAJODAAATwwAAAAFegwAAHsMAAB8DAAAfQwAAH4MAAAAAAJiBAAAZAQAAA==\"]ANg[\"AAAEaAIAAM8CAADJBgAAzQYAAANQDAAAUQwAAFIMAAACwgEAANIBAAA7MAAAAQAAjAABAAgSjAAAOzAAAAEAAAcAAwBoBQEAehMDAMYUAQAEnAcAAJ8HAADeBwAA4AcAADswAAABAAASAAcAmQUBABQHAABxCQEAegwEAM8MAADGEQMArBIDADowAAABAAAAAAAKABAAAACCBIMEiwSMBN0H3wfGD7ARsRGyEbMRBXwEAACDBQAAQAcAAEEHAABFEQAABGIEAABkBAAANhQAADcUAAAEmwcAAJ4HAADBDwAAwg8AAATvBgAAcQwAAHIMAADADwAABSoUAAArFAAALBQAAC0UAAAuFAAAAYMTAAAAAcwFAAA=\",\"AAAAAAACbQUAAG4FAAAAAk4MAABPDAAAATsQAAAFegwAAHsMAAB8DAAAfQwAAH4MAAAAAAJiBAAAZAQAAAAAAAAAAwgHAACZEQAAmhEAAA==\"]Dc[\"\",\"AAAAADswAAABAAAHAAEAUwkHADswAAABAAAJAAIAPxEEAJQRBAAAAZMRAAA=\"]ADi[\"AAAABr8BAADBAQAAzgEAANABAABREAAAUhAAAAJ0CgAAeAoAADowAAABAAAAAAAJABAAAADAAcYBxwHPAdgB2QHlCukKOBQ5FDswAAABAAANAAQAzQQHAPQPAADqEAMACRQAAALKAQAANBMAADswAAABAAAXAAsAtQEBALwBAAB4DAEAyAwBAEgQAwDXEAEAIxEBAAMTAwDaEwAAXBQBAKwUAQABXhQAAAAAAAAAAAAAAcwFAAA=\",\"AAABugEAAALVBAAAlRIAAAAAAAK1DwAAzxAAAAAAAAAAAAAAAAAEywYAAM8GAADMDAAAzQwAAA==\",1]ADe[\"AAAAAr0BAADJAQAAOzAAAAEAAAcAAQBTCQcAAASFBQAAhgUAAIcFAACgEgAAAAABXhQAAA==\",\"AAAAADswAAABAAAQAAMAwAYAAFMJBwBCDAcAOzAAAAEAAAsABAAjBwAAJREAAD8RBACUEQQAOzAAAAEAAA8ABQDNBAcAYAwCAKkSAgDjEgAAcxQAADowAAABAAAAAAAKABAAAABPEVERUxFVEVcRkxG2EbcRuBG5EeoTBKkQAACqEAAAqxAAAKwQAAAAAAVOEQAAUBEAAFIRAABUEQAAVhEAAAAAAAAAAAPMBQAAug8AALwPAAA=\",1]Ec[\"AAAAAAAAOzAAAAEAAAYAAgDWBgMA2wYCADswAAABAAAGAAIA0QYEADsJAQADfgQAAHgFAAB5BQAA\",\"\"]Dg[\"AAAAAAAAAAABTxQAAAGTFAAAAAAAAAAAAAABgAcAAA==\",\"AAAAAAAB6hIAAAHVEwAA\"]Eo[\"AAAAAQ4FAAABxAEAAAIvAAAAnwAAAAEqEAAAAVwDAAACFgEAABcBAAA=\",\"AAABrgAAAAEOBQAAAZUTAAAAAToMAAA=\"]Ic[\"AAAAAVAFAAAD1gEAAK8TAAAxFAAAAl0AAACsAAAABosBAACMAQAAYwQAAMsFAAA3EAAAgxQAAAFqAwAA\",\"AAABrwAAAAJQBQAAlxMAAAABPgwAAAAAAAAAAAAAAAAAAAKwAAAAsQAAAA==\"]Ik[\"AAAAAtsEAAACEwAAASAHAAABvQYAAAG4AAAAAYsRAAABThQAAAKiEgAAkhQAAAAAAAAAAAAAOjAAAAEAAAAAAAkAEAAAAIwFuwZ9B/wHAxAbEEwQ2xAnEcoR\",\"AAAAAdsEAAAAAekSAAAB1BMAAA==\"]Ck[\"AAAAAesBAAAAAAAAAVIUAAABlhQAAA==\",\"AAAAAAAB7RIAAAHYEwAA\"]Ck[\"AAAAAewBAAAAAAAAAVMUAAABlxQAAA==\",\"AAAAAAAB7hIAAAHZEwAA\"]Kk[\"AAAAAAAABH8FAACFBQAAhgUAAIcFAAAAOzAAAAEAAAkAAQDwCwkAOzAAAAEAAA0AAQBsBA0AOzAAAAEAAAkABABsDAMAvQ8CAEQRAABYEQEAAAF0DAAAA3AMAADBDwAAwg8AAAJyDAAAwA8AAA==\",\"AAAAAAABJREAAANgDAAAYQwAAGIMAAA=\"]Oc[\"AAAAAAAAAgkTAAAKEwAABHoTAAB7EwAAfBMAAH0TAAACgBMAAIETAAAFFAcAAKwSAACtEgAArhIAAK8SAAACggQAAIMEAAACgwUAAEURAAAAAAHvBgAAAAAAAcwFAAA=\",\"AAAAAAJ7BQAAYhQAAAAFmxQAAMIUAADDFAAAxBQAAMUUAAAB6hMAAAI7EAAAnBQAAAAAAAAAAAAAAAW5DwAArhAAAK8QAACwEAAAsRAAAA==\"]Bg[\"AAAAAAAAAATeEQAA3xEAAAwUAAANFAAA\",\"\"]Bk[\"\",\"AAAAAd0RAAAAAAAAAAAAAAAAAAAAAAHKDwAA\"]Cc[\"AAAAAAAAAeQQAAAB5RAAAA==\",\"AAAAAAACawkAAGwJAAA=\"]FIk[\"AAAAADswAAABAAAXAAkAHQIGAGoEAACRBQAA/gcAAEwMAACyEAMA6BIAAC8UAQCdFAUAOzAAAAEAACYCEwBhBAAAegQAAIAEAADzBgAAPAwDABANBQAYDe0ACA6MAD0QAABCEAAAtxAAANYQAAAzEQcAkhEAAAgSjAClEgAApxIAAH8TAADlEwAAOzAAAAEAAMUADwC4ACkAKgFvAJwBDgBjBAAAfwUAAMsFAADWBgMA2wYCAOwGAQA4DAMAuw8AALMTAADUEwUASRQDAIMUAAA7MAAAAQAAqwBDAFcDFQB9BAAAhwQBAJIEAgBrBQAAgAUBAJsFAADRBgQA3wYMAOsHAQDuBwEA8QgBADsJAQBRCQEAXAkBAE4MAQBeDAEAawwAABYNAQC2DwEAyA8BAAQQAQAHEAEAIhAAAEMQAQBNEAEAVRAAALgQAADIEAEA4hABAOUQAABKEQEAkxEAAJ4RAACgEQAAohEAAKURAACnEQAAqREAALQRDQDLEQEAzhECAN4RAQCWEgEA+hIBADQTAABrEwEAcRMBAHoTAwCZEwEA2xMBAOsTAQDvEwEADBQBABQUAQBAFAEAVBQBAHAUAgB8FAMAgRQBAI4UAwClFAAAtRQBALkUAQC8FAEAwBQBAMYUAQA7MAAAAQAAnQAnAOIARwCaAQEAtQEBAGAEAAB+BAAAhQQAAHgFAQCTBQEAnAcAAJ8HAADeBwAA4AcAAPALCQB4DAEAyAwBAMQPAQD8DwEAOxAAAEgQAwDXEAEAIxEBAC0RAQBGEQEAoxIAAPASAQADEwMAgBMBAKITAQDQEwEA4xMBAOYTAwAKFAAAThQFAFwUAQBhFAAAmRQBAJwUAACsFAUAvhQBADswAAABAAApAAwAbAQNAJkFAQAUBwAAcQkBAGgMAADPDAAAlQ4AAB4QAwDGEQMArBIDAOATAQCSFAUAOzAAAAEAABoADACCBAEAiwQBAN0HAADfBwAAbAwDAL0PAgDGDwAARBEAAFgRAQALEwAAphMHAKYUAAA6MAAAAQAAAAAADwAQAAAAfASDBf0G/gb/BgAHAQcCBwMHBAdFEcQRxRH5EvwSeBQFYgQAAGQEAAB0DAAA7hAAADgTAAAHgQQAAJkHAACbBwAAngcAAHAMAADBDwAAwg8AAATvBgAAcQwAAHIMAADADwAAOzAAAAEAAAUAAgDaBgAAKhQEAAABcwwAAAHMBQAA\",\"AAAAAAA7MAAAAQAA7QABABgN7QAAOjAAAAEAAAAAAFsAEAAAAIcEiATrB+wH8QjyCFEJUglcCV0JTgxPDF4MXwwWDRcNtg+3D8gPyQ8EEAUQBxAIEEMQRBBNEE4QyBDJEOIQ4xBKEUsRnhGgEaIRpRGnEakRtBG1EcsRzBHeEd8RlhKXEvoS+xJrE2wTcRNyE5kTmhPbE9wT6xPsE+8T8BMMFA0UFBQVFEAUQRRUFFUUcRRyFHwUfRR+FH8UgRSCFI4UjxSQFJEUtRS2FLkUuhS8FL0UwBTBFMYUxxQ7MAAAAQAAMwAVALUBAQCTBQEAeAwBAMgMAQD8DwEASBADANcQAQAjEQEALREBAEYRAQDwEgEAAxMDAIATAQCiEwEA0BMBAOMTAQDmEwMAXBQBAJkUAQCsFAUAvhQBAARxCQAAcgkAAOATAADhEwAAAALEEQAAxREAAA==\"]Ic[\"AAAAAZsRAAAABHwFAABACQAAQQkAAJ8SAAA7MAAAAQAADAADAJUEBQD0BgUAKRQAAAADmAcAAEYRAABHEQAAAaQQAAAAB04RAABQEQAAUhEAAFQRAABWEQAAxBEAAMURAAAAAZkHAAA=\",\"\"]Ko[\"AAACZwIAANACAAAAADswAAABAAALAAMAxgEBANgBAQAzEQcAOzAAAAEAAAcAAQDNBAcAOzAAAAEAAA8ABQDrBwEABBABAE0QAQC0EQEAuhEHAAAC4BMAAOETAAA=\",\"AAAAAfoPAAAAAAAAAAAAAAAAAAAAAAX5DwAA+w8AAAMQAAAGEAAA4hMAAA==\"]AAg[\"AAAEZgIAANECAABCCQAAQwkAAAS7AQAAwwEAAMgBAADVAQAAAm0CAADXAgAAAAA6MAAAAQAAAAAAEwAQAAAAhwSIBPEI8gi6ELwQvhDAEMEQTxFREVMRVRFXEfoS+xK5FLoUvBS9FAKAEwAAgRMAAAV6DAAAewwAAHwMAAB9DAAAfgwAAAAFThEAAFARAABSEQAAVBEAAFYRAAAAAAAC0QEAANoGAAA=\",\"AAAAAAAAAAAAAAAAAAAAAAAABPMIAAD0CAAA9QgAAPYIAAA=\"]CAk[\"AAADPwkAAG0TAABuEwAABbkBAABWCgAA3REAAHMTAAB0EwAAOjAAAAEAAAAAAAcAEAAAAMQB1gFECUUJOQqSCrkKpBIBpRIAAAWzEwAASRQAAEoUAABLFAAATBQAADowAAABAAAAAAAXABAAAADuB+8HtQ9DEEQQzxCeEaARohGlEacRqRG6EbsRvBG9Eb4RvxHAEcER2xPcE3wUfRQD2hMAALAUAACxFAAABB4QAAAfEAAAIBAAACEQAAA7MAAAAQAACQADAN0HAADfBwAAphMHADswAAABAAAHAAEA/QYHAAACmwcAAJ4HAAA=\",\"AAAEcgUAAHMFAACrDwAArA8AADswAAABAAAWAAsAQgcHAJwRAQCfEQAAoREAAKMRAQCmEQAAqBEAAJgSAQAHFAEACxQAAFoUAQACrxMAADEUAAADBg4AAAcOAACfEgAAAAAAAAAAAAAAAAAAOjAAAAEAAAAAAHEAEAAAAK8BsAGyAbMBEQISAhoCGwJpBGsEjQTXBNkEygbOBvsG/AY0BzUHLQkuCWQJZQlLDE0MYwxkDGkMagx1DHYMsQ+yD7MPtA/LD/UP9g8ZEBoQTBCmEKcQxBDFEMYQxxDUENUQ2RDaEOYQ5xAdER4RJxEpESoRMBExETsRPBE9ET4RwhHDEdUR1hGbEpwSnRKeEuUS5hLyEvMS/xIBEykTKhMrEywTLhMvEzATMRNvE3UTdhN3E5MTpBOlE64TtBO1E7YTtxO4E7kT0hPTE+0T7hP0E/UTEhQTFDQUNRR1FHYUhBSFFA==\"]Ac[\"AAAAAAFIAwAA\",\"\"]Gc[\"AAAABBEFAABDBwAA5AcAAJ0RAAADVAkAAEMMAACeFAAAATQRAAABShQAAAK7EQAAvxEAAAEdAQAAAR8QAAABpxMAAAH+BgAA\",\"AAAAAREFAAA=\"]Gc[\"AAAABFoFAABHBwAA6AcAAKQRAAADWAkAAEcMAAChFAAAATgRAAACngEAAEwUAAACvREAAMERAAAAASEQAAABqxMAAAECBwAA\",\"AAAAAVoFAAA=\"]Cm[\"AAAAAAJtAgAA1wIAADswAAABAAAFAAEA1xEFAAACZwwAAPgSAAA=\",\"\",1]Ek[\"AAAAAAAAAAAAAAAAAAAAAAAAAvAGAAAGBwAA\",\"AAAAAAACuRAAALsQAAAAAroQAAC8EAAAAAKsEgAArRIAAA==\"]Eo[\"AAAAAAAAAAAAAAAAAAAAAAAAAvEGAAAHBwAA\",\"AAAAAAACvRAAAL8QAAAAA74QAADAEAAAwRAAAAACrhIAAK8SAAA=\"]Ck[\"AAAAAAAAAAAAAAAAAAAAAAAABXoAAACzAQAA2QcAAPYHAAD1CAAA\",\"\"]Bg[\"AAAAAAAAAcMPAAAAAAAAAsQRAADFEQAA\",\"\"]Hg[\"AAAABGYAAADlBAAAjwUAAFAQAAABHwIAAAcOAAAAaAQAAGoFAAAxBwAAzRAAANMRAAAzFAAAA84AAABgCQAAxw8AAAAC8RMAAE0UAAA=\",\"AAAAAeUEAAAB8AgAAAFmBAAA\"]Ic[\"\",\"AAAAAAAAAAA7MAAAAQAACQABAPALCQA7MAAAAQAADQABAGwEDQA7MAAAAQAACQAEAGwMAwC9DwIARBEAAFgRAQAAAXQMAAADcAwAAMEPAADCDwAAA3EMAAByDAAAwA8AAAAAAXMMAAA=\"]Hk[\"AAAD3gEAAFcMAABaDAAAAQ0FAAABxAEAAAQuAAAAngAAALkQAAC7EAAAASkQAAABWwMAAAMVAQAAjhEAAI8RAAA=\",\"AAAC3gEAAFMMAAACiQQAAA0FAAABlBMAAAABOQwAAA==\"]Hk[\"AAAD3wEAAFgMAABbDAAAAU8FAAAB1gEAAARcAAAAqwAAAL0QAAC/EAAAAooBAAA2EAAAAWkDAAADfgQAAJARAACREQAA\",\"AAAC3wEAAFQMAAADigQAAE8FAACWEwAAAAE9DAAA\"]AMk[\"AAAAAAGoEAAAAAA6MAAAAQAAAAAAEwAQAAAAygF9BF4MXwwWDRcNtg+3D0oRSxGWEpcSgRSCFI4UjxS1FLYUwBTBFAKFBAAA2hMAAAQeEAAAHxAAACAQAAAhEAAAOzAAAAEAAAcAAQCmEwcAOzAAAAEAAAcAAQD9BgcAAAAAAtEBAADaBgAA\",\"AAAHdAUAAHUFAABXDAAAWAwAAFoMAABbDAAAphIAADowAAABAAAAAAAYABAAAADhB+IHTwlbCVkMXAxdDK0Prg8YEMoQyxDMEBwRmxGrEawRrRGuEa8R3RNHFEgUXxRgFDswAAABAAAIAQIAnQ4EAZsTAwA7MAAAAQAAXQADAAsAWgBwEwAAoBMBAAAAAATGEQAAxxEAAMgRAADJEQAABLARAACxEQAAshEAALMRAAAB+RIAAAAAAAAAAAeRBAAAjAUAAPoGAACaDgAAHxEAAC8RAADKEQAA\"]Dk[\"AAAAAAI6CgAAjwoAAAAAADswAAABAAAFAAEA3BIFAAACggQAAIMEAAAAAmIEAABkBAAA\",\"\"]C@k[\"\",\"ADswAAABAAAFAAIAWwQEAJgUAAAC8gYAABMHAAA6MAAAAQAAAAAACwAQAAAA6wHsAX4FzgyhEucS/RI3E3QUgBSjFLQUOjAAAAEAAAAAABwAEAAAAB0CHgIfAiACIQIiAiMCagR9BYIFwAbuBiAHaQkyEaQS6BJ+Ey8UMBR3FJ0UnhSfFKAUoRSiFLcUuxQ7MAAAAQAANAERAGgEAABqBQAAfAUAAPMGAAASBwAAIwcAABANBQAIDowAtxAAADMRBwCSEQAACBKMAKUSAACnEgAAMxMAAH8TAACfEwAAOjAAAAEAAAAAAB4AEAAAAH8FhQWGBYcF7AbtBvQG9Qb2BvcG+Ab5BvsL/Av9C/4Lww/kEEkRoBKzE/IT8xMJFEkUShRLFEwUbxSDFKQUOzAAAAEAAEIAEwBXAxUAhgQAAJIEAgBoBQEAawUAAIAFAQCbBQAA3wYMAO4HAQD6CwAAawwAACIQAABVEAAA5RAAALoRBwA0EwAAehMDAHAUAAClFAAAOzAAAAEAAFwACwDiAEcAmgEBAIUEAACcBwAAnwcAAN4HAADgBwAA3BIFAAoUAABOFAUAYRQAADswAAABAAAMAAUAbAQAAM8MAACVDgAAHhADAJIUBQA7MAAAAQAAEwAJAIIEAQCLBAEA3QcAAN8HAAC9DwIAxg8AAEQRAAALEwAAphMHADswAAABAAAJAAIA/QYHAEAHAQABdAwAAAObBwAAngcAAHAMAAAABSoUAAArFAAALBQAAC0UAAAuFAAA\"]Bc[\"AAAAAAAAAAAAAAACxBEAAMURAAA=\",\"\"]Kg[\"AAAAAAF5EwAAADswAAABAAAGAAIA9AYFAEkRAAACawUAAFUQAAABhQQAAAABCxMAAAH8EgAAAu4QAAA4EwAA\",\"AAAAAAABgAQAADswAAABAAAFAAEAlQQFAAABxA8AAAAAAAAAAAAAAAccAgAA1gQAANgEAAAKBwAACwcAAA0HAAAOBwAA\"]Dk[\"AAAAAAABGAAAAAAAAeYAAAAAAAAAAAAAAAAC1gQAAPsGAAA=\",\"AAAAAAAAAAABxQ8AAA==\"]Dk[\"AAAAAAABNgAAAAEwAQAAAAAAAAAAAAAAAAAC2AQAAPwGAAA=\",\"AAAAAAAAAAABYAQAAA==\"]Ac[\"AAABeQIAAA==\",\"\"]Fg[\"AAAABBMFAABEBwAA5QcAAJ8RAAADVQkAAEQMAACfFAAAATURAAAAAAEfAQAAAAGoEwAAAf8GAAA=\",\"AAAAARMFAAAAAcYBAAA=\"]Fg[\"AAAABFwFAABIBwAA6QcAAKYRAAADWQkAAEgMAACiFAAAATkRAAABoAEAAAAAAAGsEwAAAQMHAAA=\",\"AAAAAVwFAAAAAdgBAAA=\"]Bk[\"\",\"AAAAAAAAAAA7MAAAAQAASQACAOIARwCaAQEA\"]Ck[\"\",\"AAAAAAHABgAAOzAAAAEAAAkAAgAjBwAAJQcIAAFzFAAAAeoTAAA=\"]Bo[\"\",\"AAAAAAAAAAAAAAAAAjYUAAA3FAAAAAAAAYMTAAA=\"]Ck[\"AAACegIAAIwCAAA=\",\"AAAAAAAAAvcTAAD4EwAAAAACxhEAAMcRAAA=\"]Eo[\"\",\"AAAAAAA7MAAAAQAABQABAOkSBQA7MAAAAQAABQABANQTBQAAOzAAAAEAAAUAAQBOFAUAOzAAAAEAAAUAAQCSFAUA\"]Cc[\"\",\"AAAAAAKUEwAAlRMAAAAEOAwAADkMAAA6DAAAOwwAAA==\"]Eg[\"AAAAARcFAAAAATMAAAAAAAImAQAAJwEAAA==\",\"AAA7MAAAAQAACgABAKwCCgACFwUAAIYUAAAAAAEJEwAA\"]Eo[\"AAAAAVYFAAAAAWQAAAAAAAKaAQAAmwEAAA==\",\"AAA7MAAAAQAACgACADADAQAzAwgAAlYFAACHFAAAAAABChMAAA==\"]Dg[\"AAABGAMAAAFVBQAAAAFiAAAAApUBAACWAQAA\",\"AAABJwMAAAFVBQAAAAAAAAF+BAAA\"]Eo[\"AAAAAAAAAqQBAAClAQAA\",\"AAAAAAAAB28UAACbFAAApBQAAMIUAADDFAAAxBQAAMUUAAACcBQAAKUUAAABnBQAAA==\"]Bk[\"AAAAAAAAAVUBAAA=\",\"AAAB7wIAAAAAAXoEAAA=\"]Bg[\"AAAAAWAFAAAAAAGmAQAA\",\"AAAAAWAFAAA=\"]Bg[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAcoMAAA=\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAA9oHAAD3BwAA9ggAAA==\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAApEEAADbBwAA\",\"\"]Cc[\"AAAAAAAAAAI7CQAAPAkAAAAAAAAAAAAC0QEAANoGAAA=\",\"\"]Fo[\"AAAAAAACfAUAAKcSAAAAAAAAAAAAAAAAAAAE/QcAAMsPAADoEAAA4BEAAA==\",\"AAGhBwAAAAAAAAAAAAAAAAAAAAAAAALpEAAAjREAAA==\"]Bk[\"AAAAAX4FAAAAAAHDDwAAASIQAAA=\",\"AAHSBwAA\"]Bg[\"AAAAAAAABOoQAADrEAAA7BAAAO0QAAA=\",\"\"]Ag[\"AAAAAr0BAADJAQAA\",\"\"]Dg[\"AAAAAAAAAAAAAnEJAAByCQAA\",\"AAAAAAAAAAAABXoMAAB7DAAAfAwAAH0MAAB+DAAA\"]AEk[\"AAAAAALCAQAA0gEAAAAAAmgFAABpBQAABJwHAACfBwAA3gcAAOAHAAA7MAAAAQAACwAEAJkFAQB6DAQAzwwAAMYRAwA6MAAAAQAAAAAACQAQAAAAiwSMBN0H3wfGD7ARsRGyEbMRCxMEfAQAAEAHAABBBwAA/BIAAAZiBAAAZAQAAO4QAAA4EwAANhQAADcUAAAFgQQAAJsHAACeBwAAwQ8AAMIPAAADcQwAAHIMAADADwAAOzAAAAEAAAYAAwDRAQAA2gYAACoUBAABgxMAAAFzDAAA\",\"AAAAAeERAAAAAm0FAABuBQAAAAJODAAATwwAAAAAAAACYgQAAGQEAAA=\"]He[\"\",\"AAAAAAAEfwwAAIAMAACBDAAAggwAAAJVDAAAcxQAAAKLEQAA6hMAAAWpEAAAqhAAAKsQAACsEAAA2hMAAAGiEgAAAAH5EgAAAAGZBwAAAAHRAQAAAAABzAUAAA==\",1]AMk[\"AAACywEAANQBAAAGuwEAAMMBAADIAQAA1QEAAHMTAAB0EwAABH0FAABpCQAAOwoAAJAKAAAEfwwAAIAMAACBDAAAggwAAALyEwAA8xMAADowAAABAAAAAAAHABAAAAA7CTwJyBDJEGsTbBNxFHIUOjAAAAEAAAAAAAkAEAAAAGAEnAefB94H4AfED8UPOxCZFJoUAALdBwAA3wcAAA==\",\"AAAAOjAAAAEAAAAAABAAEAAAALEBeQd6B3sHfAf/BwAIgww+ED8Q4RBMEU0R9hL3EjITexQDZgkAAKgQAAAtEwAABn8MAACADAAAgQwAAIIMAAD+EgAAABMAAAAAAAKZBQAAmgUAAAACfAQAAPwSAAAC7hAAADgTAAADgQQAAMEPAADCDwAAA3EMAAByDAAAwA8AAAAAAnMMAADUDAAAOjAAAAEAAAAAAAcAEAAAALQBjgSPBDYHfQf8B/0HGxA=\"]Bg[\"AAAAAAAAAAAAAXcEAAA=\",\"AAAAAckFAAA=\"]Bk[\"AAAAAAAAADswAAABAAANAAIAmwUAAN8GDAA=\",\"\"]Cc[\"AAABMgkAAAABIwIAAAAAAAFgBAAA\",\"AAAAAAAAAAF9BAAA\"]Dg[\"AAAAAd8EAAAAAAHAAAAAAAAAAAAAAAAAAAADkAUAAAkHAAC5DwAA\",\"AAAAAd8EAAA=\"]Bc[\"AAAAAAAAAAAAAAAAAAAAAdoGAAA=\",\"\"]Be[\"AAAAAAAAA4UFAACGBQAAhwUAAA==\",\"\",1]Bg[\"AAAAAAAAADswAAABAAAVAAEAVwMVAA==\",\"\"]Ek[\"AAAAAALFAQAA1wEAAA==\",\"AAAAAAVeCQAAXwkAAGEJAABiCQAAYwkAAAABYAkAAAAAAAAAAAAAAAABeBAAAA==\"]Cc[\"AAAAAeQEAAAAAQ0AAAACxgAAAMcAAAA=\",\"AAAAAeQEAAA=\"]Bg[\"AAAAAAAAAAAAAXIEAAA=\",\"AAAAAfAHAAA=\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAbAAAAA=\",\"\"]CAi[\"AAAAAALFAQAA1wEAAAEzEwAAAQkUAAACygEAADQTAAA6MAAAAQAAAAAAHQAQAAAAvAGTBZQF/A/9Dy0RLhHwEvESohOjE9AT0RPjE+QT5hPnE+gT6RPxEwoUTRSZFJoUrhSvFLAUsRS+FL8UOzAAAAEAAAYAAwBxCQEAHhADAF4UAAABphQAAAF4FAAAAAAB7wYAAAAAAAHMBQAA\",\"AAAFSgkAAEsJAABMCQAATQkAAE4JAAAEUAwAAFEMAABSDAAAlRIAADowAAABAAAAAAAYABAAAACrAckEygSaB50H8QfvCPAIXglfCWEJYgljCWYJnxCgEKEQohCjEC0TNhObE5wTnROeEzswAAABAAAgAA4A5wEAAOkBAABhBAAAZgQAAHoEAACABAAAJQcIAH8MAwC4DwAA1hAAAD8RBACUEQQAeBMAAOUTAAA7MAAAAQAAJAAKAGMEAACVBAUAywUAAPoHAABgCQAAuw8AACUQEwDjEgEA9xMBAPoTAQA7MAAAAQAACAAEALgQAAC2EQMAzhECABEUAAA7MAAAAQAADAAGAGAEAADEDwEAqRADAI4RAwDxEwAATRQAAASsEgAArRIAAK4SAACvEgAAOzAAAAEAAAYAAwBsDAMAWBEBAKYUAAAEfAQAAEURAAD8EgAAeBQAAAAAAe8GAAAB0QEAAAAAOzAAAAEAACAAEACyAAMA0AYAAN4GAAAuBwIAKwkAAG0JAwBzCQEACRAAACMQAQBFEAIA3BAEAM0RAACaEgAAFhQAALIUAQDIFAAA\",1]Mg[\"AAAAAe8EAAAAOjAAAAEAAAAAAAcAEAAAABkAmwDnAWYEuA/YEdsRoBMCJhAAAOMSAAACWAMAAOAGAAAC5wAAAOgAAAAAAd0HAAAAAAGbBwAA\",\"AAGmBwAAAANmAAAAZwAAAO8EAAACbQIAAPEHAAAC2BEAANsRAAAAAdIGAAAAAAAAAAAAAAAABWsAAABsAAAAbQAAAG4AAABvAAAA\"]A@c[\"AAAAAR4FAAAABzgAAACjAAAA6QEAANoRAADcEQAAeBMAAKETAAAHMwEAADQBAAC7DwAALhAAADoQAADOEAAA5BIAAARhAwAA5QYAAGsMAAARFAAAAaMSAAABlQ4AAALfBwAAphQAAAF4FAAAAAGeBwAA\",\"AAG8BwAAAAEeBQAAAtcCAAB7BQAAAtoRAADcEQAAAdcGAAAAAAFoDAAAAAH5EgAAAAAAAAAABXAAAABxAAAAcgAAAHMAAAB0AAAA\"]Bo[\"\",\"AAAAAAAAOzAAAAEAAKgAAwC4ACkAKgFvAJwBDgA=\"]CDm[\"\",\"AAA7MAAAAQAA7QABAAIL7QA7MAAAAQAA9AAMAAIKNgA8CjcAdQoCAHkKFQCRCgAAkwoeALMKBQC6CikA5goCAOsKFgDiEgAAhhQBADowAAABAAAAAAASABAAAACCBcoFwAZECUUJOQo6CjsKdAp4Co8KkAqSCrIKuQrkCuoKlBOVEzowAAABAAAAAAAVABAAAABoBGoFIwcxB2sJbAnlCukKBg4HDs0Q0xHpEuoS6xLsEu0S7hKfEzMUOBQ5FDowAAABAAAAAAAqABAAAADsBu0G+gdgCfsL/Av9C/4LOAw5DDoMOwxVDMcP9A86EM4Q5BDqEOsQ7BDtEEkRCRMKE9QT1RPWE9cT2BPZE/cT+BP6E/sTbxRzFJsUpBTCFMMUxBTFFDowAAABAAAAAAAaABAAAAB9BJIEkwSUBIAFgQXRBtIG0wbUBtUGawxVELoQvBC+EMAQwRDlEJMRzhHPEdAR6hMRFHAUpRQ7MAAAAQAAYwAPAOIARwCaAQEAYAQAAH4EAACFBAAAeAUBAJgHAADEDwEAOxAAAKMSAADcEgUA8RMAAE0UBgBhFAAAnBQAADswAAABAAARAAgAmQUBAGgMAADPDAAAlQ4AAKQQAADGEQMA4BMBAJIUBQAHggQAAIMEAADGDwAAWBEAAFkRAAALEwAAphQAADowAAABAAAAAAALABAAAAB8BIMFQAdBB04RUBFSEVQRVhH5EvwSeBQGYgQAAGQEAADuEAAAOBMAADYUAAA3FAAAA5kHAACbBwAAngcAAAJxDAAAwA8AADswAAABAAAGAAMA0QEAANoGAAAqFAQAAYMTAAAAAcwFAAA=\",1]Le[\"\",\"AAAAAtoBAAC+BgAAAyEHAACvDwAAsA8AAAMSBwAA/hIAAAATAAA6MAAAAQAAAAAABwAQAAAAww+gEqkSqhKrEvIT8xMpFAKGBAAA+gsAAAG8AQAAAV4UAAAEvQ8AAL4PAAC/DwAARBEAAAABdAwAAASBBAAAcAwAAMEPAADCDwAAAXIMAAAAAAFzDAAA\",1]Gc[\"\",\"AAAAOjAAAAEAAAAAAAcAEAAAAOsB7AGhEv0SdBSAFKMUtBQCIAcAAKgQAAAFvQYAAEAJAABBCQAA9w8AAJ8SAAABsxMAAAGLEQAAAdoTAAA=\"]Bo[\"\",\"AAAAApYTAACXEwAAAAQ8DAAAPQwAAD4MAAA/DAAA\"]Bk[\"\",\"AAAAAAAAOzAAAAEAAAYAAgDWBgMA2wYCAA==\"]Fc[\"AAAAAdMBAAAAAAAABJMFAACUBQAA/A8AAP0PAAA=\",\"AAA7MAAAAQAAQwABAIQMQwAAAAAAAAAAAAAAAAAAAAABDwcAAA==\"]Ao[\"\",\"AAA7MAAAAQAA7QABAAEI7QA=\"]A@o[\"AAAEggIAAJMCAACYAgAAqw8AAAHtBAAAA34TAAC3FAAAuxQAAAMWAAAAmgAAANcRAAABJRAAADowAAABAAAAAAAMABAAAABXA5IEkwRoBWkFgAXfBssR6xMUFEAUfhSQFALiAAAA4wAAAA==\",\"AAGlBwAAOzAAAAEAAAYAAwBkAgQAQgkAAG0TAAAB7QQAAARECQAAOQoAADoKAAA7CgAAAdcRAAABOAwAAAPRBgAAzhEAAM8RAAAAAAAAAAAAAAAAAaMPAAA=\"]AAk[\"AAAE9gIAABoDAAAgAwAArA8AAAEbBQAAAAQ0AAAAoQAAANkRAAB/EwAABCwBAAAtAQAALBAAAIMUAAA6MAAAAQAAAAAACgAQAAAAXwOUBGsFgQXkBswR7BMVFEEUfxSRFAABlQ4AAA==\",\"AAG7BwAAOzAAAAEAAAYAAwDOAgQAQwkAAG4TAAABGwUAAARFCQAAjwoAAJAKAACSCgAAAjwMAADZEQAAAtYGAAD6BwAAAdARAAAAAAAAAAAAAAAABKUPAACmDwAApw8AAKgPAAA=\"]Gc[\"AAA7MAAAAQAACwAEAJoQBACYEwAAQhQEALgUAAA=\",\"ADswAAABAAAJAAMAfgcBAIEHAgBmEwQAOzAAAAEAAAsABACaEAQAmBMAAEIUBAC4FAAA\"]Ic[\"AAAAAAAAAAA7MAAAAQAACQABAPALCQA7MAAAAQAADQABAGwEDQA7MAAAAQAACQAEAGwMAwC9DwIARBEAAFgRAQAAAXQMAAADcAwAAMEPAADCDwAAA3EMAAByDAAAwA8AAAAAAXMMAAA=\",\"\"]Cc[\"AAAAAr8BAABMEQAAAAAAAAF4DAAAAAGLBAAAAUAHAAA=\",\"\"]Cc[\"AAAAAs4BAABNEQAAAAAAAAF5DAAAAAGMBAAAAUEHAAA=\",\"\"]ACg[\"AAAAAoQTAACFEwAAAAXGAQAAxwEAANgBAADZAQAAkhEAADswAAABAAALAAMAzQQHAH8FAABgDAIAOzAAAAEAAA0ABQBrBQAA7gcBAMgPAQAiEAAAuhEHAAeOEQAAjxEAAJARAACREQAAChQAAGEUAACcFAAABmgMAACVDgAAHhAAAB8QAAAgEAAAIRAAADswAAABAAAHAAEAphMHADswAAABAAAKAAQA/QYHAEURAAD5EgAAeBQAAAABmQcAAAHvBgAAAAAAAcwFAAA=\",\"AAAAA+EBAADiAQAA4wEAAAAB1hAAAA==\"]Ek[\"AAAAAAAAAAAAAAAAAAAAAAACdgUAABYHAAA=\",\"AAAAAAAAAAK2EQAAtxEAAAAAAAAAAAAAAAAC8AYAAAYHAAA=\"]Ek[\"AAAAAAAAAAAAAAAAAAAAAAACdwUAABgHAAA=\",\"AAAAAAAAAAK4EQAAuREAAAAAAAAAAAAAAAAC8QYAAAcHAAA=\"]Ak[\"\",\"AAAAAAIcEAAAHRAAAA==\"]Fc[\"AAAABBUFAABFBwAA5gcAAKERAAACVgkAAEUMAAABNhEAAAAAASEBAAAAAakTAAABAAcAAA==\",\"AAAAARUFAAAAAccBAAA=\"]Fc[\"AAAABF4FAABJBwAA6gcAAKgRAAACWgkAAEkMAAABOhEAAAGiAQAAAAAAAa0TAAABBAcAAA==\",\"AAAAAV4FAAAAAdkBAAA=\"]Bg[\"AAAAAAAAAAAAAXEEAAA=\",\"AAAAAWoJAAA=\"]Ag[\"AAACvgEAAM0BAAA=\",\"\"]Ao[\"AAAAAAAAAAAAAAAAAAFwDAAA\",\"\"]Ag[\"\",\"AAACwhAAAMMQAAA=\"]Bg[\"AAAAAAAAAAAAAaISAAA=\",\"AAABeQAAAA==\"]Dg[\"AAAAAuEBAADiAQAAAAADhQUAAGAMAACpEgAAAAG8AQAAAV4UAAA=\",\"AAAAAZUSAAA=\"]Hg[\"AAAAAasRAAABmxMAAAO5EAAAQBEAAJURAAAB9xMAAAG2EQAAAakQAAACxhEAAKwSAAABsBEAAAAAAAABKxQAAA==\",\"AAAAAAAAAAJPEQAAUREAAAAAAAJOEQAAUBEAAA==\"]Ig[\"AAAAAa4RAAABnRMAAAO9EAAAQhEAAJcRAAAB+hMAAAG4EQAAAasQAAACyBEAAK4SAAABshEAAAAAAAABLRQAAA==\",\"AAAAAAGMEQAAAAADUxEAAFURAABXEQAAAAAAA1IRAABUEQAAVhEAAA==\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAngAAACoDwAA\",\"\"]Bk[\"AAAAAAAAAeEAAAAAAAF5BAAA\",\"AAAAAfkHAAA=\"]Cc[\"AAAAAeEQAAABrxMAAAACYwQAAMsFAAA=\",\"AAAAAAH+BwAA\"]Be[\"AAAAAAA7MAAAAQAAjAABAAgSjAA=\",\"\",1]Bg[\"AAAAAAAAAAAAAXQEAAA=\",\"AAAAATcMAAA=\"]Ec[\"AAAAAAAAAAAAAAAAAAKbBwAAngcAAAHvBgAAAtEBAADaBgAA\",\"AAAAAAAAAAAAAAAAAAAAAdEBAAA=\"]Dk[\"AAAAAAAAAAABUBQAAAGUFAAA\",\"AAAAAAAB6xIAAAHWEwAAAAAAAAAAAAAAAAABgAcAAA==\"]Dg[\"AAAAAUIFAAAAAAJvAQAAcAEAAAHoBgAAAAAAAAAAAAAAAAEcAgAA\",\"AAAAAUIFAAA=\"]ACg[\"AAAAA7kBAABPCgAA3REAAAPuBgAAsgoAADIRAAAABEkUAABKFAAASxQAAEwUAAA6MAAAAQAAAAAADQAQAAAAUQlSCVwJXQkHEAgQ4hDjEHETchOZE5oT7xPwEzswAAABAAAPAAcALREBANwSBQCiEwEA8RMAAE0UAACuFAEAvhQBAAABphQAAAF4FAAA\",\"AAAAA6wBAAC3AQAApRAAAASfEAAAoBAAAKEQAACiEAAAAucBAADpAQAAAAAC8RMAAE0UAAAAAaYUAAABeBQAAAAAAAAAAAToAQAA6gEAAC8JAADgEQAA\"]Bk[\"AAAAAAEgBwAA\",\"AAAAAAAAAAGLEQAAAAGiEgAA\"]Ic[\"AAAABuIEAACOBQAAyQUAAM4MAAD2EgAANxMAAAKwDwAAdxQAAAISBwAAMxMAAAPEAAAAoBIAAAkUAAABaQUAAAGYBwAAAaQQAAA=\",\"AAAAAuIEAAC+BgAAASEHAAAAAAABvAEAAAFeFAAA\"]Gc[\"AAAAAvcSAAALFAAAAcUGAAAB8wYAAAErAQAAArgQAAA0EwAAAAEUBwAAAAGDBQAAAAGZBwAAAe8GAAAAAAABzAUAAA==\",\"AAAAAAAAAAHKAQAA\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAXcAAAA=\",\"\"]Fg[\"AAAD8gYAABMHAAAVEAAABFwMAADSEAAA0hEAAF8UAAAFHgIAAIIFAADKBQAAmgcAAF8JAAAAAsoAAAD0DwAA\",\"AAABKxEAAA==\"]Fg[\"AAAABF0MAADTEAAA1BEAAGAUAAACnQcAAGIJAAAB8wYAAAFyAQAAAAABFAcAAAABgwUAAAAAAAAAAAHMBQAA\",\"AAABLBEAAA==\"]Dg[\"AAAAAUcFAAAAAVYAAAABewEAAA==\",\"AAAAAUcFAAAAAAAAAAAAAAAAAAAAAAF6AAAA\"]Bk[\"AAAAAAEdAgAAAAAAAAFuBAAA\",\"AAAAAWYMAAA=\"]Cg[\"AAAAAAHxBwAAAAAAAAFvBAAA\",\"AAAAAAAAAAJnDAAA+BIAAA==\"]Dk[\"\",\"AAAAADswAAABAAATAAEAhAcTADswAAABAAATAAEAmgATADswAAABAAATAAEAJRATAA==\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAXUAAAA=\",\"\"]Fg[\"AAAAAWEFAAAAAAGoAQAAAAAAAAAAAYEEAAAAAAABcwwAAAa0AAAAtAEAABUCAADeBgAANgcAAJoSAAA=\",\"AAHRBwAAAAFhBQAA\"]Hk[\"AAAErgAAAGQCAAByBQAAUwwAAAEPBQAAAAIwAAAAoAAAAAErEAAAAl0DAADjBgAAAhgBAAAZAQAA\",\"AAABmAIAAARoAAAAaQAAAGoAAAAPBQAAAcQBAAAAATsMAAAB1QYAAA==\"]Kc[\"AAAErwAAANICAABzBQAAVAwAAAFRBQAAAAReAAAArQAAAD0QAABCEAAAA40BAACOAQAAOBAAAAJrAwAA6gYAAA==\",\"AAABIAMAAAFRBQAAAdYBAAABPwwAAANjBAAAywUAANwGAAAAAAAAAAAAAAAAAAR1AAAAdgAAAHcAAAB4AAAA\"]Ak[\"AAAAAAJTEAAAVBAAAA==\",\"\"]Ao[\"AAAAAAAAAAACtQEAANwSAAA=\",\"\"]Ao[\"AAAAAAAAAAACtgEAAN8SAAA=\",\"\"]Dc[\"AAAAAAAAAAABGgEAAAAAAAAAAAAAAAWyAAAAjgQAAC4HAAD+DwAA3BAAAA==\",\"\"]Fc[\"AAAAAAAAAY8BAAAAAAAAAAAAAAAAAAWzAAAAjwQAAC8HAAD/DwAA3RAAAA==\",\"AAAAAAAAAAAAARQHAAAAAoMFAABFEQAA\"]Fc[\"AAAAAWIFAAAAAAGpAQAAAoYEAAD6CwAAAAAAAAF0DAAAAAAAAAAFtQAAADAHAAAsCQAAABAAAN4QAAA=\",\"AAAAAWIFAAA=\"]Hg[\"AAABlAAAAAH0BAAAAAIeAAAAEA0AAAAAAe8AAAAAAAAAAAAAAAADrwEAANcEAABLDAAA\",\"AAGpBwAAAAH0BAAAAAAAAAAAAAAAAAAAAAAENwcAADgHAAA7BwAAPAcAAA==\"]Hg[\"AAAAApcAAAAlBQAAAAI+AAAAEw0AAAE9AQAAAAAAAAAAAAAAAAADsAEAANkEAABNDAAA\",\"AAG/BwAAAAElBQAAAAAAAAAAAAAAAAAAAAAEOQcAADoHAAA9BwAAPgcAAA==\"]Bc[\"AAAAAAAAAAAAAAAAAAAAAAGDEwAA\",\"\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAXYAAAA=\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAmwAAAAMBwAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAnEAAAARBwAA\",\"\"]Bg[\"AAAAAAAAAAAAAXMEAAA=\",\"AAAAAQ8NAAA=\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAbEAAAA=\",\"\"]Hc[\"AAAAAAAB9w8AAAEpFAAAAAFRFAAAAZUUAAAAAAAAAAAAADowAAABAAAAAAANABAAAAD6BisJbwmaDgYQCRBFEB8RLxHNEf8SARPiExYU\",\"AAAAAAAB7BIAAAHXEwAA\"]Ak[\"AAAAAAIvFAAAMBQAAA==\",\"\"]Cg[\"AAAAATITAAABZgkAAAGABAAAAAABhQQAAA==\",\"AAAAAAFMDAAA\"]Ag[\"\",\"AAAAAAAAAd0GAAA=\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAm0AAAC6DwAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAnIAAAC8DwAA\",\"\"]Ag[\"AAAAAAAAAAHrBgAA\",\"\"]Dk[\"AAAAAAAAOzAAAAEAAKgAAwC4ACkAKgFvAJwBDgAAOzAAAAEAAEkAAgDiAEcAmgEBAA==\",\"\"]Fo[\"AAAAAhAFAAAVBwAAAWEJAAACMQAAAKATAAAAA14DAABnDAAA+BIAAAIbAQAAHAEAAA==\",\"AAACmwIAAAEQAAABEAUAAAHFAQAAAc0QAAA=\"]Gk[\"AAAAAlIFAAAXBwAAAWMJAAACXwAAAKETAAACkAEAAJEBAAABbAMAAAABaAwAAAAB+RIAAAAAAe8GAAA=\",\"AAACJAMAAAIQAAABUgUAAAHXAQAAAAHOEAAA\"]Dk[\"AAAAAQUFAAAAAScAAAAAAeEGAAACBgEAAAcBAAA=\",\"AAAAAgUFAABWCgAAAAAAAdMGAAA=\"]Dk[\"AAAAATwFAAAAAU0AAAACYQEAAGIBAAAB5gYAAA==\",\"AAAAATwFAAABuQoAAAAB2AYAAA==\"]Ck[\"AAAAAT4QAAAAAAAAApwHAADeBwAA\",\"AAAAAAAAAAACqRAAAKoQAAA=\"]Ck[\"AAAAAT8QAAAAAAAAAp8HAADgBwAA\",\"AAAAAAAAAAACqxAAAKwQAAA=\"]Bk[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAigRAACoEgAA\"]Ek[\"AAAAA/8HAACYEgAABxQAAAAAAAAAAAHdBwAAAAABmwcAAA==\",\"AAAAAAAAAAK2EQAAtxEAAAKpEAAAqhAAAA==\"]Ek[\"AAAAAwAIAACZEgAACBQAAAAAAAAAAAHfBwAAAAABngcAAA==\",\"AAAAAAAAAAK4EQAAuREAAAKrEAAArBAAAA==\"]Cg[\"AAAAAfoEAAAAASMAAAAAAAL3AAAA+AAAAA==\",\"AAAAAfoEAAA=\"]Dg[\"AAAAATAFAAAAAUkAAAACTwEAAFABAAA=\",\"AAAAATAFAAAAAAAAAAFoDAAAAAH5EgAA\"]Bo[\"AAAAAfEEAAAAARsAAAAAAAHqAAAA\",\"AAAAAfEEAAA=\"]Cc[\"AAAB7wIAAAEhBQAAAAE6AAAAATcBAAA=\",\"AAAAASEFAAA=\"]Ig[\"AAABlgAAAAH2BAAAAAIgAAAAEg0AAAAAAfEAAAAAAAAAAAAAAAA6MAAAAQAAAAAADQAQAAAA6AEaAjcHOwczCTcJsQ/5D8QQKROkE7QT0hOEFA==\",\"AAGrBwAAAAL2BAAAjwUAAAABuA8AAA==\"]Ic[\"AAAAApkAAAAnBQAAAAJAAAAAFQ0AAAE/AQAAAAAAAAAAAAAAAAA6MAAAAQAAAAAADQAQAAAA6gEbAjkHPQc1CTkJsw/7D8YQKhOlE7UT0xOFFA==\",\"AAHBBwAAAAEnBQAAAAABuw8AAA==\"]Gg[\"AAACSwIAAFMCAAAB6AQAAAACEQAAACcHAAAC1AAAANUAAAA=\",\"AAACTQIAAE8CAAAB6AQAAAAAAAACxA8AAMUPAAAAAAJ8BAAA/BIAAAAAAXEMAAA=\"]Do[\"AAAAASkFAAAAAkEAAACkAAAAA0EBAABCAQAALxAAAAFiAwAA\",\"AAAAASkFAAAAAAAAAWAEAAA=\"]Ck[\"AAAAAg4UAAAPFAAAAAAAAAAAAAABdAwAAA==\",\"AAAAAAABJREAAA==\"]Co[\"AAAAAAABEgcAAAOpEgAAqhIAAKsSAAAAAbwBAAA=\",\"AAAAAAAB9w8AAA==\"]KCm[\"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\",1]Eo[\"AAAAAAA7MAAAAQAABQABAOkSBQA7MAAAAQAABQABANQTBQAAOzAAAAEAAAUAAQBOFAUAOzAAAAEAAAUAAQCSFAUA\",\"\"]Ck[\"AAAAAAAAAX8FAAAAAAFsBAAA\",\"AAAAAAAAA2AMAABhDAAAYgwAAA==\"]Dg[\"AAAAARIFAAAAAAHOBAAAAZ4RAAABHgEAAA==\",\"AAG1BwAAAAESBQAAAAAAAZ4RAAA=\"]Dc[\"AAAAAVsFAAAAAAKfAQAA0gQAAAGlEQAA\",\"AAHNBwAAAAFbBQAAAAAAAaURAAA=\"]Fo[\"AAAAAfMEAAAAAR0AAAAAAALtAAAA7gAAAA==\",\"AAGoBwAAAAHzBAAAAAVoBAAAMQcAAM0QAADTEQAAMxQAAAFgCQAAAALxEwAATRQAAA==\"]Fc[\"AAAAASQFAAAAAT0AAAACOwEAADwBAAA=\",\"AAG+BwAAAAEkBQAAAAACOhAAAM4QAAACawwAABEUAAAAAAGmFAAAAXgUAAA=\"]Eo[\"AAAAAdERAAABXgkAAAACvgAAAFUMAAABkxEAAAABcAQAAA==\",\"AAAAAAHKBQAAAAJVDAAA9A8AAAABmAcAAAGkEAAA\"]Dk[\"AAAABqESAAD9EgAAdBQAAIAUAACjFAAAtBQAAAAAAAAB2hMAAA==\",\"AAAAAAAAAAGLEQAA\"]A@c[\"AAAAOjAAAAEAAAAAABEAEAAAAIkE3gSNBcEG8AdqCTcMZgyDDA8NORBPEEgR5xLdExAUMhR7FAejEAAApBIAAC0TAAB5EwAAfhMAALcUAAC7FAAABucBAABmBAAAuA8AAD8RAACUEQAAnxMAADowAAABAAAAAAAHABAAAAC/AEkR4xJvFJsUpBTCFMQUA2gFAABnDAAA+BIAAAAAAAAAAAABKhQAAA==\",\"AAAAAd4EAAAB7wgAAAABVQwAAA==\"]ACk[\"AAAAOjAAAAEAAAAAAAgAEAAAAIoETwlZDK0P+g8cEa0RRxRIFDowAAABAAAAAAAHABAAAABqBHsFkQX+B0wMjBHoEjEUOjAAAAEAAAAAAAoAEAAAAOkBegQ9EEIQtxDWEJIRpRJ4E38T5RM6MAAAAQAAAAAABwAQAAAAKgG7DzoQzhDkEoMUwxTFFAVrBQAAawwAABEUAABwFAAApRQAAASjEgAAChQAAGEUAACcFAAAAmgMAACVDgAAAaYUAAADRREAAPkSAAB4FAAA\",\"AAAAAAAAAAAAAAAAAAGZBwAAAAAAAAHMBQAA\"]Io[\"AAAAA0IHAADjBwAAnBEAAANTCQAAQgwAAJ0UAAABMxEAAAFJFAAAA+4HAAC6EQAAvhEAAAABHhAAAAGmEwAAAf0GAAA=\",\"AAAAAARCDAAAQwwAAEQMAABFDAAAAAXNBAAAzgQAAM8EAADQBAAA4xIAAA==\"]Io[\"AAAAA0YHAADnBwAAoxEAAANXCQAARgwAAKAUAAABNxEAAAFLFAAAA+8HAAC8EQAAwBEAAAABIBAAAAGqEwAAAQEHAAA=\",\"AAAAAARGDAAARwwAAEgMAABJDAAAAAXRBAAA0gQAANMEAADUBAAA5BIAAA==\"]No[\"AAABlQAAAAH1BAAAAAIfAAAAEQ0AAAAAAfAAAAAAAAAAAAAAAAA6MAAAAQAAAAAAJAAQAAAAEQJpBMoGNActCWQJYwxpDHUM9Q8ZEKYQ1BDZEOYQHREpETAROxE9EZkRwhHVEZsSnRLlEvISLhMwE3UTthO4E+0T9BMSFDQUdRQ=\",\"AAGqBwAAAAH1BAAAAAAAAAAAAAAAAAAAAAAEMwkAADQJAAA3CQAAOAkAAA==\"]No[\"AAAAApgAAAAmBQAAAAI/AAAAFA0AAAE+AQAAAAAAAAAAAAAAAAA6MAAAAQAAAAAAJAAQAAAAEgJrBM4GNQcuCWUJZAxqDHYM9g8aEKcQ1RDaEOcQHhEqETERPBE+EZoRwxHWEZwSnhLmEvMSLxMxE3YTtxO5E+4T9RMTFDUUdhQ=\",\"AAHABwAAAAEmBQAAAAAAAAAAAAAAAAAAAAAENQkAADYJAAA5CQAAOgkAAA==\"]Cc[\"AAAAAQwFAAAAAAAAARMBAAA=\",\"AAAAAQwFAAAAAAH7CwAA\"]Ck[\"AAAAAU0FAAAAAAGHAQAA\",\"AAAAAU0FAAAAAAP8CwAA/QsAAP4LAAA=\"]Bk[\"AAAAAAAAAAAAAAAAAAGBBAAAAAAAAXMMAAA=\",\"\"]Bg[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAakPAAA=\"]Eo[\"AAAAAT0FAAAAAU8AAAACZQEAAGYBAAAB5wYAAA==\",\"AAAAAT0FAAAAAAHZBgAAAAAAAAAAAAAAAAACcQUAAKoPAAA=\"]Ak[\"AAAAAAAAAAABYRQAAA==\",\"\"]Ag[\"AAACrQIAADsDAAA=\",\"\"]Bo[\"AAAAAAAAAcgAAAAAAAABbgwAAA==\",\"AAAAATkQAAA=\"]Fg[\"AAAAAfAEAAAAARoAAAABxw8AAAJnDAAA+BIAAAHpAAAA\",\"AAGnBwAAAAHwBAAAAAExBwAAAccPAAAAAAAAAAAAAAAAAAEyBwAA\"]Gc[\"AAAAASAFAAAAATkAAAABNgEAAAABoxIAAAFoDAAAAAH5EgAA\",\"AAG9BwAAAAEgBQAAAAF4EwAAAToQAAAAAaMSAAAAAAAAAAAAAAABMwcAAA==\"]Do[\"AAAAAAAAAAHIDwAAApMFAAD8DwAA\",\"AAAAAb0BAAAAAAAByA8AAASTBQAA/A8AAI4RAACPEQAA\"]Do[\"AAAAAAAAAAHJDwAAApQFAAD9DwAA\",\"AAAAAckBAAAAAAAByQ8AAASUBQAA/Q8AAJARAACREQAA\"]Ao[\"AAAAAAGoEAAAAAABzxAAAA==\",\"\"]Gc[\"AAABqhEAAAJoAAAA4QcAAAEhAgAAAQYOAAAB0AAAAAKSBAAAzhEAAALEDwAAOxAAAAABxg8AAAJ8BAAA/BIAAAABcAwAAAJxDAAAcgwAAA==\",\"\"]Cg[\"AAAAAAABBw4AAAADfQQAAJQEAADQEQAA\",\"AAAAAAABPRAAAA==\"]Ec[\"AAABTQIAAAHpBAAAAAISAAAAKAcAAALWAAAA1wAAAA==\",\"AAABUAIAAAHpBAAAAAAAAs4RAADPEQAA\"]Bo[\"AAABKxEAAAAAAALLAAAAzAAAAA==\",\"AAAAAAGCBQAA\"]Ck[\"AAABLBEAAAAAAAJ2AQAAdwEAAA==\",\"AAAAAAAAAAAAAAABgwUAAA==\"]Ao[\"AAAAAAAAAbMTAAABtQ8AAA==\",\"\"]Hg[\"AAAAAmoAAAD5BwAAASICAAABawkAAAPcAAAA7AYAAOQQAAACgAUAAFUQAAAAApkFAADPDAAABb0PAAC+DwAAvw8AAEQRAAALEwAAAAE4EwAAAsEPAADCDwAAAcAPAAA=\",\"\"]Do[\"AAAAAAABbAkAAALtBgAA+gcAAAKBBQAA5RAAAAABmgUAAAAAAe4QAAA=\",\"AAAAAAABQhAAAA==\"]Bc[\"AAAAAAAAAAAAAAAAAAAAAAGDEwAA\",\"\"]ABg[\"AAAEmwIAACQDAAABEAAAAhAAAAG+BgAAA8UBAADXAQAAIQcAAAK9BgAA9w8AAAJvFAAApBQAAAOLEQAAcBQAAKUUAAAFmAcAAI4RAACPEQAAkBEAAJERAAABpBAAAAAAAAGZBwAA\",\"AAAABRUHAAAXBwAA0REAANIRAADUEQAAA6sBAACvDwAAsA8AAAHTEQAABZsUAADCFAAAwxQAAMQUAADFFAAAAREUAAABnBQAAAGiEgAAAAAAAAAAAALNDwAA6w8AADswAAABAAAFAAIAEwICAP4PAgA=\"]Cc[\"AAAAAT4FAAAAAVAAAAACZwEAAGgBAAA=\",\"AAAAAT4FAAA=\"]Dc[\"AAAAAAAAAAA7MAAAAQAABQABANwSBQA=\",\"AAAABOABAADkAQAA5QEAAOYBAAA=\"]Ao[\"AAAAAeABAAAAAAAAAUgQAAA=\",\"\"]Ao[\"AAAAAeUBAAAAAAAAAUkQAAA=\",\"\"]Eo[\"AAAAAawRAAABnBMAAAO7EAAAQREAAJYRAAAB+BMAAAG3EQAAAaoQAAACxxEAAK0SAAABsREAAAAAAAABLBQAAA==\",\"\"]Eo[\"AAAAAa8RAAABnhMAAAO/EAAAQxEAAJgRAAAB+xMAAAG5EQAAAawQAAACyREAAK8SAAABsxEAAAAAAAABLhQAAA==\",\"\"]Bc[\"AAAAAAAAApUEAAD0BgAAAAFKEAAA\",\"\"]Bc[\"AAAAAAAAApgEAAD3BgAAAAFLEAAA\",\"\"]Ec[\"AAAAAdoBAAAAAv4SAAAAEwAAAvITAADzEwAAAoYEAAD6CwAAAAAAAAABgQQAAA==\",\"AAAAAAFIAwAA\"]Gg[\"AAAAAesEAAAAAhQAAAAqBwAAAt0AAADeAAAA\",\"AAADVwIAAFgCAABZAgAAAesEAAAAAAABVRAAAAACmQUAAM8MAAABCxMAAAABOBMAAAABwA8AAA==\"]Ek[\"AAAAASsFAAAAAkMAAACmAAAAA0UBAABGAQAAMRAAAAFkAwAA\",\"AAAAASsFAAAAAAAAAAGaBQAAAAAB7hAAAA==\"]Ec[\"AAAAAAAAAXUBAAAAAAAAAAAAAAAAAALaBAAAcAkAAA==\",\"AAAAAAAAAAAAAAAAAAAAAAAAAcwFAAA=\"]Ec[\"AAABQAwAAAHdBAAAAAELAAAAAboAAAA=\",\"AAAAAd0EAAAAAUEJAAAAAAAAAAAAAAAAAAABuwYAAA==\"]Dg[\"AAAAAAF9BQAAAAAAAAAAAAAAAAAAAALpEAAAjREAAA==\",\"AAGiBwAAAAAAAb0GAAA=\"]Ac[\"AAABdwIAAA==\",\"\"]Do[\"AAAAAQQFAAAAASYAAAAAAAIEAQAABQEAAA==\",\"AAACiAIAAIkCAAABBAUAAAAAAAAAAeATAAA=\"]Dk[\"AAAAATsFAAAAAUwAAAACXwEAAGABAAA=\",\"AAAC+wIAAP0CAAABOwUAAAAAAAAAAeETAAA=\"]Bk[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAkYJAABICQAA\"]Dc[\"AAAAAAAAAAABJAEAAA==\",\"AAAAAAAAAAAAAAGCBAAAAUAHAAABYgQAAAGbBwAA\"]Co[\"AAAAAAAAAZgBAAA=\",\"AAAAAAAAAAAAAAGDBAAAAUEHAAABZAQAAAGeBwAA\"]Dk[\"AAAAARQFAAAAAcYBAAABzwQAAAGgEQAAASABAAA=\",\"AAG2BwAAAAEUBQAAAAAAAaARAAA=\"]Dk[\"AAAAAV0FAAAAAdgBAAACoQEAANMEAAABpxEAAA==\",\"AAHOBwAAAAFdBQAAAAAAAacRAAA=\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAWsAAAA=\",\"\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAXAAAAA=\",\"\"]Ck[\"AAAAASwFAAAAAUQAAAACRwEAAEgBAAA=\",\"AAAAASwFAAAAAAHtBgAA\"]Eg[\"AAAAAf8EAAAAAiUAAACcAAAAAScQAAABWQMAAAL/AAAA8BIAAA==\",\"AAGxBwAAAYICAAAC/wQAAE8KAAA=\"]Eg[\"AAAAATYFAAAAAksAAACnAAAAAloBAAAyEAAAAWUDAAAB8RIAAA==\",\"AAHIBwAAAfYCAAABNgUAAAGyCgAA\"]Ao[\"AAAAAAAAAAAC1xAAAI4RAAA=\",\"\"]Ao[\"AAAAAAAAAAAC2BAAAJARAAA=\",\"\"]Do[\"AAABeQAAAAHcBAAAAAABuQAAAA==\",\"AAAAAdwEAAAAAUAJAAAAAAAAAAAAAAAAAAAB2xAAAA==\"]Bg[\"AAAAAAAABNsAAACHBQAAYgwAAKsSAAA=\",\"\"]Ak[\"AAAAAAABRQAAAAFJAQAA\",\"\"]Do[\"AAAAAAAAAAAAAAAAAAAAAAAAAigRAACoEgAA\",\"AAGgBwAAAAAAAAAAAAAAAAAAAAAAAAHoEAAA\"]Cg[\"AAAAAAPuBgAAaQkAADIRAAA=\",\"AAAAAAAAAAK1DwAAzxAAAA==\"]Cc[\"AAAAAXUKAAACdAoAAOQKAAAB5QoAAALqEAAA7BAAAA==\",\"\"]Ac[\"\",\"AAAAAeISAAA=\"]Gg[\"AAAAAQMFAAABdxQAAAAAAfEIAAAEAwEAAEoQAAAEEwAAXBQAAAGkEAAA\",\"AAAAA8EBAAADBQAAhhQAAAABOBQAAAAB8QgAAANKEAAABBMAAFwUAAA=\"]Bc[\"AAAAAcEBAAAAAAAAAAAAAU4RAAA=\",\"\"]Gg[\"AAAAAToFAAAAAAFeAQAAAfIIAAADSxAAAAYTAABdFAAAAAAAAAGZBwAA\",\"AAAAA9ABAAA6BQAAhxQAAAABORQAAAAB8ggAAANLEAAABhMAAF0UAAA=\"]Bc[\"AAAAAdABAAAAAAAAAAAAAVIRAAA=\",\"\"]Fk[\"AAABVwIAAAH4BAAAAAEhAAAAAAAC8wAAAPQAAAA=\",\"AAGtBwAAAAH4BAAAAAJrCQAABg4AAALsBgAA5BAAAAOSBAAAkwQAAIAFAAA=\"]Fc[\"AAAAAS4FAAAAAUcAAAACSwEAAEwBAAA=\",\"AAHEBwAAAAEuBQAAAAJsCQAABw4AAAH6BwAABJQEAACBBQAA5RAAANARAAA=\"]Ao[\"\",\"AAAAAAAAAAAAAAABVhEAAA==\"]Ek[\"AAAAAQgFAAAAASoAAAAAAAIMAQAADQEAAA==\",\"AAABjgIAAAEIBQAAAAAAAAGYBwAAAaQQAAAAAk4RAABQEQAA\"]Eg[\"AAAAAUQFAAAAAVUAAAACcwEAAHQBAAA=\",\"AAABCgMAAAFEBQAAAAAAAAAAAAJSEQAAVBEAAAABmQcAAA==\"]Ao[\"AAAAAAAAAAHBEAAAAAF+DAAA\",\"\"]Jk[\"AAAAAQkFAAAABSsAAACdAAAAbQUAALkQAAC7EAAAAvsLAAAoEAAABFoDAABODAAAuhAAALwQAAAEDgEAAA8BAACOEQAAjxEAAAJ6DAAAewwAAAKwEQAAsREAAA==\",\"AAAAAgkFAADSEAAAAsIBAACyEAAAAAABOwkAAA==\"]Og[\"AAAAAUkFAAAABVgAAACqAAAAbgUAAL0QAAC/EAAABoABAACBAQAA/AsAAP0LAAD+CwAANRAAAARoAwAATwwAAL4QAADAEAAAApARAACREQAAAnwMAAB9DAAAArIRAACzEQAA\",\"AAAABEkFAADVBwAA1gcAANMQAAAE0gEAALMQAAC0EAAAtRAAAAAAATwJAAACeAUAAHkFAAAAAAAAAAAAAAA7MAAAAQAACgACANcHBQD0BwQA\"]Cc[\"AAAAAT8FAAAAAVEAAAACaQEAAGoBAAA=\",\"AAAAAT8FAAA=\"]Ck[\"AAABdAUAAAEKBQAAAAEsAAAAAAABEAEAAA==\",\"AAAAAgoFAABQDAAA\"]Dg[\"AAABdQUAAAFKBQAAAAFZAAAAAYIBAAAAAAAAAAAAAe8GAAA=\",\"AAAAAkoFAABRDAAA\"]Cc[\"AAAAAWMFAAAAAWUAAAABqgEAAA==\",\"AAAAAmMFAABSDAAA\"]Dg[\"AAAAAAAAAAAAAAABRREAAA==\",\"AAAABrYQAADvEgAA3hMAAN8TAAAOFAAADxQAAA==\"]Ak[\"AAAAAAAAAAAB3hIAAA==\",\"\"]Ak[\"AAAAAAAAAAAB4RIAAA==\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAm8AAAATAgAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAnQAAAAUAgAA\",\"\"]Bg[\"AAAAAAAAAAAAAXUEAAA=\",\"AAAAAUgRAAA=\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAm4AAAAyBwAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAnMAAAAzBwAA\",\"\"]Bo[\"AAAAAAAAAAAAAAAE/QYAAP4GAAD/BgAAAAcAAA==\",\"\"]Ec[\"AAAABKwBAAC3AQAAHwUAAKUQAAAAAAE1AQAAAAAAAAQBBwAAAgcAAAMHAAAEBwAA\",\"AAAAAR8FAAA=\"]Bg[\"AAAAAAAAAAAAAXYEAAA=\",\"AAAAAAF5EwAA\"]Cc[\"AAAAAXkKAAACeAoAAOoKAAAB6QoAAALrEAAA7RAAAA==\",\"\"]Ag[\"AAAAAAABIwcAAA==\",\"\"]No[\"AAAAAQEFAAABIQcAAAEzEwAAAfQPAAAGXgwAAMgQAADbEwAA7xMAAFQUAAB8FAAABwEBAAC8AQAAyAwAAEgQAAADEwAA5hMAAOgTAAABXhQAAAAAAAAAAAAAA8sGAADMDAAABxMAAA==\",\"AAAAAgEFAABREAAAAAHAAQAAAQkTAAAGXgwAAMgQAADbEwAA7xMAAFQUAAB8FAAABcgMAABIEAAAAxMAAOYTAADoEwAA\"]Bo[\"AAAAAVEQAAAAAcABAAAAAroQAABPEQAAAAF6DAAA\",\"\"]Nc[\"AAAAATgFAAAAAAFcAQAAOjAAAAEAAAAAAAcAEAAAAMoBXwzJEDQT3BPwE1UUfRQFyQwAAEkQAAAFEwAA5xMAAOkTAAAAAAAAAAAAAAAEzAUAAM8GAADNDAAACBMAAA==\",\"AAAAAjgFAABSEAAAAAHPAQAAAQoTAAAGXwwAAMkQAADcEwAA8BMAAFUUAAB9FAAABckMAABJEAAABRMAAOcTAADpEwAA\"]Bo[\"AAAAAVIQAAAAAc8BAAAAAr4QAABTEQAAAAF8DAAA\",\"\"]Ao[\"AAAAAAAAAAAC5hMAAOcTAAA=\",\"\"]Ao[\"AAAAAAAAAAAC6BMAAOkTAAA=\",\"\"]Dc[\"AAABWAIAAAHsBAAAAAIVAAAAKwcAAALfAAAA4AAAAA==\",\"AAABWwIAAAHsBAAA\"]Bk[\"AAAAAeMBAAAAAATaAAAAhgUAAGEMAACqEgAA\",\"\"]Ec[\"AAAAApYTAACXEwAAApQTAACVEwAABDwMAAA9DAAAPgwAAD8MAAAEOAwAADkMAAA6DAAAOwwAAA==\",\"\"]Cc[\"AAAAAAAAAAAB3RIAAA==\",\"AAGjBwAAAAK7AQAAcxMAAA==\"]Cc[\"AAAAAAAAAAAB4BIAAA==\",\"AAG5BwAAAALIAQAAdBMAAA==\"]Bc[\"\",\"AAAAAAAAAAAAAAAAAAAB7wYAAA==\"]Ck[\"AAAAAq4PAAAYEAAAAAABfwEAAAG4EAAA\",\"AAHUBwAAAAAAAeUTAAA=\"]Ek[\"AAAAAeMEAAAAAAHFAAAAAAAAAAAAAAAAAAAEbxMAAHcTAACTEwAArhMAAA==\",\"AAGkBwAAAALjBAAAjgUAAA==\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAA20JAABGEAAAshQAAA==\",\"\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAA24JAABHEAAAsxQAAA==\",\"\"]Bk[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAkcJAABJCQAA\"]Ac[\"\",\"AAAAAAHJBAAA\"]Bc[\"AAAAAAABYQQAAA==\",\"AAAAAAHKBAAA\"]Ec[\"AAAAARYFAAAAAccBAAAB0AQAAAKiEQAADBQAAAEiAQAA\",\"AAG3BwAAAAEWBQAAAAAAAqIRAAAMFAAA\"]Ec[\"AAAAAV8FAAAAAdkBAAACowEAANQEAAACqREAAA0UAAA=\",\"AAHPBwAAAAFfBQAAAAAAAqkRAAANFAAA\"]Ag[\"\",\"AAAAAAABnxIAAA==\"]Co[\"AAAAArEBAADVBwAAAAABeAEAAA==\",\"AAAAAAAAAAAAAAAAAAAAAdEBAAA=\"]Ac[\"\",\"AAAAAAE2EwAA\"]Cg[\"AAAAAAAAAgkTAAAKEwAAAAABohIAAA==\",\"AAAAAAAAAAHqEwAA\"]Do[\"AAAAASoFAAAAAkIAAAClAAAAA0MBAABEAQAAMBAAAAFjAwAA\",\"AAAAASoFAAAAAAABfQQAAA==\"]Ak[\"AAAAAAACOBQAADkUAAA=\",\"\"]Ac[\"AAAAAeQBAAA=\",\"\"]Ac[\"AAAAAeYBAAA=\",\"\"]Eo[\"AAACEgMAACcDAAABUwUAAAABYAAAAAKSAQAAkwEAAA==\",\"AAAAAVMFAAAAAAAF0QYAANIGAADTBgAA1AYAANUGAAA=\"]Fk[\"AAAABMoQAADLEAAA3hMAAN8TAAABrw8AAAElEQAAAaASAAAAAAFeFAAAAAAAAAAAAAFzDAAA\",\"AAAAAAAAA6kSAACqEgAAqxIAAA==\"]Fc[\"AAAAAAABvQYAAAIJEwAAChMAAAGLEQAAAAGiEgAAAAACNhQAADcUAAAAAAABgxMAAA==\",\"AAAAAAAAAXMUAAAB6hMAAA==\"]Co[\"AAAAAfsEAAAAASQAAAAAAAL5AAAA+gAAAA==\",\"AAAAAfsEAAAAAWoFAAA=\"]Co[\"AAAAATEFAAAAAUoAAAACUQEAAFIBAAA=\",\"AAAAATEFAAAAAAAAAAGVDgAA\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAARAHAAA=\",\"\"]Ik[\"AAAAAgAFAABaFAAAAAAAApYSAABxEwAABQABAAC8AQAAeAwAACMRAACAEwAAA3EJAADgEwAAXhQAAA==\",\"AAGyBwAAAAK/AQAAAAUAAAAAAAKWEgAAcRMAAAN4DAAAIxEAAIATAAACcQkAAOATAAA=\"]Ig[\"AAAAAjcFAABbFAAAAAABWwEAAAPKAQAAlxIAAHITAAADeQwAACQRAACBEwAAAnIJAADhEwAA\",\"AAHJBwAAAALOAQAANwUAAAHFBgAAAAAClxIAAHITAAADeQwAACQRAACBEwAAAnIJAADhEwAA\"]Ao[\"AAAAAAAAAc0AAAAAAAF4BAAA\",\"\"]Bc[\"AAAAAAABTgAAAAJjAQAAZAEAAA==\",\"\"]Ag[\"AAACtgIAADQDAAA=\",\"\"]Ak[\"AAAAAAAAApYEAAD1BgAA\",\"\"]Ak[\"AAAAAAAAApkEAAD4BgAA\",\"\"]Ag[\"AAACrAIAADUDAAA=\",\"\"]Dk[\"AAAAAeoEAAAAAhMAAAApBwAAAtgAAADZAAAA\",\"AAABUwIAAAHqBAAAAAAAAAAAAcYPAAA=\"]Dg[\"AAAAAecEAAAAAhAAAAAmBwAAAtIAAADTAAAA\",\"AAABSwIAAAHnBAAAAAAAAAE7EAAA\"]Co[\"AAABphIAAAEtBQAAAAFGAAAAAUoBAAA=\",\"AAHDBwAAATIJAAABLQUAAA==\"]Ec[\"AAAAAAABpxIAAAG7AAAAAAAAAAAAAAAAAAADjQQAAC8JAADKDwAA\",\"AAAAAbkBAAAAAAAAAdoTAAA=\"]Hk[\"AAAC6gIAAAMDAAABSwUAAAABWgAAAAKDAQAAhAEAAAAAAAAAAAAAAAAABBkCAABxBQAA0AYAAA8HAAA=\",\"AAABGAMAAALTAQAASwUAAAAAAvoTAAD7EwAAAAACyBEAAMkRAAA=\"]Fc[\"AAAAA7YQAADMEAAA7xIAAAAC/hIAAAATAAADpwEAAPITAADzEwAAAoYEAAD6CwAAAAAAAAABgQQAAA==\",\"AAAAAdoBAAA=\"]Dc[\"AAAAAmcAAADmBAAAAiACAADwCAAAAQ8AAAABzwAAAA==\",\"AAAAAuYEAABQEAAA\"]Eg[\"AAAAAQYFAAAAASgAAAAAAAIIAQAACQEAAAAAAAAAAAAAAAMKBwAAog8AAKkPAAA=\",\"AAABjAIAAAEGBQAA\"]Eg[\"AAAAAUAFAAAAAVIAAAACawEAAGwBAAAAAAAAAAAAAAAAAAMNBwAApA8AAKoPAAA=\",\"AAABAwMAAAFABQAA\"]Io[\"AAAFPQIAAE8CAABQAgAAWQIAAFsCAAAB+QQAAAACIgAAACwHAAAAAAL1AAAA9gAAAA==\",\"AAADdwIAAHkCAAB6AgAAAvkEAADBBgAAAsoFAACjEAAAAZ8TAAAB9A8AAAGTEQAAAAAAAAAAAAAAAAEJBwAA\"]Ek[\"AAAAAS8FAAAAAkgAAAAtBwAAAk0BAABOAQAA\",\"AAAB6gIAAAEvBQAAAAAAAAAAAAAAAAAAAAAC2gQAABAHAAA=\"]Bk[\"AAAAAAABtxAAAAF+AQAA\",\"AAAAAAAAAAG4EAAA\"]Hg[\"AAABlgAAAAH3BAAAAAESDQAAAAAB8gAAAAAAAAAAAAAAAAY4BwAAPAcAADQJAAA4CQAAsg8AAMUQAAA=\",\"AAGsBwAAAAL3BAAAjQUAAAAAAAAAAAAAAAAAAAAAAZAFAAA=\"]Fo[\"AAAAApkAAAAoBQAAAAEVDQAAAUABAAAAAAAAAAAAAAAAAAY6BwAAPgcAADYJAAA6CQAAtA8AAMcQAAA=\",\"AAHCBwAAAAEoBQAAAZEFAAA=\"]Ag[\"AAACrgIAADYDAAA=\",\"\"]Cg[\"AAAAAWUFAAAAAAADtQ8AACIQAADPEAAA\",\"AAHTBwAAAAFlBQAA\"]Dc[\"AAAAAkUFAADWBwAAAAABeQEAAA==\",\"AAAAAUUFAAAAAAAAAAAAAAAAAAHaBgAA\"]Dg[\"AAAAAYQTAAABUxAAAAAAAAL7AAAAjxEAAA==\",\"AAE9CQAAAb4BAAABhBMAAAFTEAAA\"]Dg[\"AAAAAYUTAAABVBAAAAABVgEAAAABkREAAA==\",\"AAE+CQAAAc0BAAABhRMAAAFUEAAA\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAacPAAA=\",\"\"]Ac[\"\",\"AAAAAAFiFAAA\"]Ag[\"AAACrwIAADcDAAA=\",\"\"]Bc[\"\",\"AAAAAAAAAAAD3BIAAN0SAADeEgAA\"]Bc[\"\",\"AAAAAAAAAAAD3xIAAOASAADhEgAA\"]Ak[\"\",\"AAAAAQITAAAAAAEpFAAA\"]ADk[\"AAAAAfwEAAAAAAA6MAAAAQAAAAAAFQAQAAAA6wcWDbYPBBAHEEMQShHLEd4R+hJrExQUcRR+FIEUjhSQFLUUuRS8FMAUxhQ6MAAAAQAAAAAADQAQAAAA/ADXEEYR8BIDEwQTohPQE+MTmRSsFK4UsBS+FAAAAcQRAAA=\",\"AAGuBwAAAAH8BAAAAAAAOjAAAAEAAAAAABUAEAAAAOsHFg22DwQQBxBDEEoRyxHeEfoSaxMUFHEUfhSBFI4UkBS1FLkUvBTAFMYUOjAAAAEAAAAAAAoAEAAAANcQRhHwEqIT0BPjE5kUrBSuFLAUvhQAAAHEEQAA\"]ADo[\"AAAAATMFAAAAAAFXAQAAOjAAAAEAAAAAABUAEAAAAOwHFw23DwUQCBBEEEsRzBHfEfsSbBMVFHIUfxSCFI8UkRS2FLoUvRTBFMcUOjAAAAEAAAAAAAwAEAAAANgQRxHxEgUTBhOjE9ET5BOaFK0UrxSxFL8UAAABxREAAA==\",\"AAHFBwAAAAEzBQAAAAAAOjAAAAEAAAAAABUAEAAAAOwHFw23DwUQCBBEEEsRzBHfEfsSbBMVFHIUfxSCFI8UkRS2FLoUvRTBFMcUOjAAAAEAAAAAAAoAEAAAANgQRxHxEqMT0RPkE5oUrRSvFLEUvxQAAAHFEQAA\"]Ag[\"AAACiAIAAPsCAAA=\",\"\"]Bk[\"AAAAAAAAAAAAAW0EAAA=\",\"AAAAAAAAAVUMAAA=\"]Bk[\"AAAAAAAAAAAAAAFtDAAA\",\"AAAAAAABMxQAAA==\"]Do[\"AAAAAQcFAAAAASkAAAAAAAIKAQAACwEAAAAAAAAAAAAAAAILBwAAow8AAA==\",\"AAAAAQcFAAA=\"]Do[\"AAAAAUEFAAAAAVMAAAACbQEAAG4BAAAAAAAAAAAAAAAAAAIOBwAApQ8AAA==\",\"AAAAAUEFAAA=\"]Ag[\"AAACsgIAADEDAAA=\",\"\"]Fc[\"AAAAAUMFAAAAAlQAAACoAAAAAnEBAAAzEAAAAmYDAAC4EAAA\",\"AAAAAUMFAAAAAAAAAAAAAAABmQcAAAAAAAABzAUAAA==\"]Ao[\"AAAAAAHJBAAA\",\"AAAAAAGaBwAA\"]Ao[\"AAAAAAHKBAAA\",\"AAAAAAGdBwAA\"]Ag[\"AAACtAIAADMDAAA=\",\"\"]Ag[\"AAACtQIAADoDAAA=\",\"\"]Dg[\"AAAAARgFAAAAAAABehMAAAAAAAFQEQAA\",\"AAAAAhgFAAB1CgAAAXQKAAAAAeoQAAA=\"]Do[\"AAAB2wEAAAFXBQAAAAAAAXwTAAAAAAABVBEAAA==\",\"AAAAAVcFAAAB5AoAAAHlCgAAAewQAAA=\"]Do[\"AAAAARoFAAAAAAADvBAAAFERAAB7EwAAAAF7DAAA\",\"AAAAAhoFAAB5CgAAAXgKAAAAAesQAAA=\"]Eg[\"AAAB3AEAAAFZBQAAAAAAA8AQAABVEQAAfRMAAAABfQwAAA==\",\"AAAAAVkFAAAB6goAAAHpCgAAAe0QAAA=\"]Cc[\"AAAAAAAAApcEAAD2BgAAAAEUAQAA\",\"AAG0BwAAAAHDAQAA\"]Cc[\"AAAAAAAAA4kBAACaBAAA+QYAAA==\",\"AAHMBwAAAAHVAQAA\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAAwgHAADcBwAA+AcAAA==\",\"\"]Bg[\"AAAAAAAAAAAAAAAAAAAAAAAAAaYPAAA=\",\"\"]Ao[\"AAAAAAAAAc0EAAAAAawUAAA=\",\"\"]Bk[\"AAAAAAAAAdEEAAAAAa0UAAA=\",\"AAAAAdUEAAA=\"]Eg[\"AAAAAAAAAAAAAAAAAAAAAAAABHMJAAAjEAAA3xAAACsTAAA=\",\"AAG4BwAAAATjBwAA5AcAAOUHAADmBwAA\"]Eg[\"AAAAAAAAAAAAAAAAAAAAAAAABHQJAAAkEAAA4BAAACwTAAA=\",\"AAHQBwAAAATnBwAA6AcAAOkHAADqBwAA\"]Bo[\"AAAAAAABwAEAAAAAAcgMAAAAAYIEAAAAAWIEAAA=\",\"\"]Bo[\"AAAAAAABzwEAAAAAAckMAAAAAYMEAAAAAWQEAAA=\",\"\"]Ak[\"AAAAAAABoBMAAAEJFAAA\",\"\"]Ao[\"AAAAAAABoRMAAAAAAQoUAAA=\",\"\"]Fo[\"AAAAAUgFAAAAAlcAAACpAAAAA3wBAAB9AQAANBAAAAFnAwAA\",\"AAABEgMAAAFIBQAAAAAAAAJ4BQAAeQUAAAAAAAAAAALRAQAA2gYAAA==\"]Bg[\"\",\"AAAAAAAAAAAAAAAAAAAAAAAAAQwHAAA=\"]Dg[\"AAAAASIFAAAAATsAAAABOAEAAA==\",\"AAAAASIFAAAAAAAAAAAAAAAAAAAAAAERBwAA\"]Dg[\"AAAAAeEEAAAAAgwAAAAlBwAAAsIAAADDAAAA\",\"AAABPQIAAAHhBAAAAAABSREAAA==\"]Do[\"AAAAAR0FAAAAAjcAAACiAAAAAzEBAAAyAQAALRAAAAFgAwAA\",\"AAAAAR0FAAAAAAAAAYUEAAA=\"]Ek[\"AAAAAf0EAAAAAAAC6xMAAEAUAAAD/QAAAC0RAADQEwAA\",\"AAGvBwAAAAH9BAAAAAAAAusTAABAFAAAAS0RAAA=\"]Ek[\"AAAAATQFAAAAAAFYAQAAAuwTAABBFAAAAi4RAADREwAA\",\"AAHGBwAAAAE0BQAAAAAAAuwTAABBFAAAAS4RAAA=\"]Bo[\"AAAAAAAAAAABeAUAAAAAAAAAAALRAQAA2gYAAA==\",\"\"]Fg[\"AAAAAf4EAAAAAAAEUQkAAE0QAAC0EQAAmRMAAAL+AAAA4xMAAA==\",\"AAGwBwAAAAH+BAAAAAAABFEJAABNEAAAtBEAAJkTAAA=\"]Fg[\"AAAAATUFAAAAAAFZAQAABFIJAABOEAAAtREAAJoTAAAB5BMAAA==\",\"AAHHBwAAAAE1BQAAAAAABFIJAABOEAAAtREAAJoTAAA=\"]Ag[\"\",\"AAAAAAAAAXMUAAA=\"]Bc[\"\",\"AAAAAAAAAAAAAAAAAAAAAAGDEwAA\"]Co[\"AAAAAfIEAAAAARwAAAAAAALrAAAA7AAAAA==\",\"AAAAAfIEAAAAAAHHDwAA\"]Co[\"AAAAASMFAAAAATwAAAACOQEAADoBAAA=\",\"AAAAASMFAAAAAAAAAaMSAAA=\"]Fg[\"AAABZQIAAAELBQAAAAEtAAAAAAHiBgAAAhEBAAASAQAA\",\"AAACkwIAAMkGAAABCwUAAAAAAAHUBgAAAAAAAAAAAAAAAAGiDwAA\"]Gc[\"AAABzgIAAALTAQAATAUAAAABWwAAAAKFAQAAhgEAAAHpBgAA\",\"AAACGgMAAM0GAAABTAUAAAAAAdsGAAAAAAAAAAAAAAAAAAIZAgAApA8AAA==\"]Cc[\"AAAAAAAAAAAAAAAAAAAAAAAAA9gHAAD1BwAA9AgAAA==\",\"\"]Cg[\"AAABjgIAAAAAAAAAASUBAAA=\",\"AAAAAAAAAAK6EAAAvBAAAA==\"]Cg[\"AAABCgMAAAAAAAGZAQAA\",\"AAAAAAAAAAO+EAAAwBAAAMEQAAA=\"]Bo[\"AAAAAtUEAABkBQAAATYTAAA=\",\"AAAAAmQFAADhEQAA\"]Bo[\"AAAAAAAAAckAAAAAAAABbwwAAA==\",\"AAAAARAUAAA=\"]Io[\"AAAAAVQFAAAAAWEAAAABlAEAAAabBQAATxEAAFERAABTEQAAVREAAFcRAAAAAAAFThEAAFARAABSEQAAVBEAAFYRAAAAAAAAAAAByBQAAA==\",\"AAAAAVQFAAAAAAT3EwAA+BMAAPoTAAD7EwAAAAF+BAAA\"]Co[\"AAAAAmkAAADiBwAAAAAB0QAAAAKTBAAAzxEAAAHFDwAA\",\"AAABqhEAAA==\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAkYJAACuEAAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAkgJAACwEAAA\",\"\"]Co[\"AAAAARkFAAAAAAAAAigBAAApAQAA\",\"AAAAARkFAAAAAALqEAAA6xAAAA==\"]Dc[\"AAAAAVgFAAAAAAKcAQAAnQEAAA==\",\"AAAAAlgFAADiEgAAAAAC7BAAAO0QAAA=\"]Cc[\"AAAAAAGrAQAAAAG9AAAAAAAAAWwMAAA=\",\"AAAAATIUAAA=\"]Ac[\"\",\"AAABQAwAAA==\"]Ec[\"AAABiQIAAAHuBAAAAAEXAAAAAAAC5AAAAOUAAAA=\",\"AAAAAe4EAAAERAkAADkKAAA6CgAAOwoAAA==\"]Do[\"AAAB/QIAAAEcBQAAAAE1AAAAAi4BAAAvAQAA\",\"AAAAARwFAAAERQkAAI8KAACQCgAAkgoAAA==\"]Ak[\"\",\"AAAAAAACOBQAADkUAAA=\"]Ck[\"AAAAAuAEAABbCQAAAe8IAAABcBMAAAHBAAAA\",\"AAAAAuAEAABPEAAA\"]Bg[\"AAAAAXkHAAACnxAAALIQAAAAAfsLAAA=\",\"\"]Bk[\"AAAAAXoHAAACoBAAALMQAAAAAvwLAAD9CwAA\",\"\"]Bc[\"AAAAAAAAAAAAAAAAAjYUAAA3FAAA\",\"\"]Fo[\"AAAAAQIFAAAAAAADhwQAAFwJAABUFAAAAgIBAAC1AQAA\",\"AAGzBwAAAAECBQAAAAAAAocEAABcCQAAAbUBAAAAAAAAAAAAAAABBxMAAA==\"]Fo[\"AAAAATkFAAAAAAFdAQAAA4gEAABdCQAAVRQAAAG2AQAA\",\"AAHKBwAAAAE5BQAAAAAAAogEAABdCQAAAbYBAAAAAAAAAAAAAAABCBMAAA==\"]Ck[\"AAAAATIFAAAAAAJTAQAAVAEAAA==\",\"AAAAATIFAAAAAAAAAWEUAAA=\"]Ec[\"AAAAAUYFAAAAAAF6AQAAAAAAAAAAAAAAAAAFsgEAANcHAAD0BwAA8wgAAMoMAAA=\",\"AAAAAUYFAAA=\"]Dg[\"AAAAAAFiFAAAAAG8AAAAAAAAAAACNhQAADcUAAAAAAABgxMAAA==\",\"AAABugEAAA==\"]Ag[\"AAACsQIAADkDAAA=\",\"\"]Bc[\"\",\"AAAAAAAAAAAAAAAAAjYUAAA3FAAA\"]Cc[\"AAAAAWYFAAAAAAAAAAAAAVYRAAA=\",\"AAAB2wEAAAFmBQAA\"]Ck[\"AAAAAWcFAAAAAAACwRAAAFcRAAAAAX4MAAA=\",\"AAAB3AEAAAFnBQAA\"]Ag[\"AAACsAIAADgDAAA=\",\"\"]Dg[\"AAAAAAABMgAAAAAAASMBAAA=\",\"AAAAAAAAAAAAAAAAAAAAAyoUAAArFAAALBQAAA==\"]Ck[\"AAAAAAABYwAAAAGXAQAA\",\"AAAAAAAAAAAAAAAAAAAAAi0UAAAuFAAA\"]Ag[\"AAACswIAADADAAA=\",\"\"]Do[\"AAAAAXsHAAACoRAAALQQAAAAAf4LAAAB4hAAAA==\",\"AALMAQAAugcAAAE/CQAAAAAAAAHiEAAA\"]Ec[\"AAAAAk4FAAB8BwAAAqIQAAC1EAAAAAGIAQAAAeMQAAA=\",\"AAHLBwAAAdQBAAABTgUAAAAAAAHjEAAA\"]Bg[\"AAAAAAAAAAABeQUAAA==\",\"AAABywEAAA==\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAkcJAACvEAAA\",\"\"]Bk[\"AAAAAAAAAAAAAAAAAAAAAAAAAkkJAACxEAAA\",\"\"]") \ No newline at end of file diff --git a/pr/720/docs/src/noq/connection.rs.html b/pr/720/docs/src/noq/connection.rs.html index ba06d5aa5..813f96e42 100644 --- a/pr/720/docs/src/noq/connection.rs.html +++ b/pr/720/docs/src/noq/connection.rs.html @@ -741,1171 +741,1200 @@ 741 .map(|c| c.clone_box()) 742 } 743 -744 /// Parameters negotiated during the handshake +744 /// Succeeds when an incoming connection is proven not to be a replay attack. 745 /// -746 /// Guaranteed to return `Some` on fully established connections or after -747 /// [`Connecting::handshake_data()`] succeeds. See that method's documentations for details on -748 /// the returned value. -749 /// -750 /// [`Connection::handshake_data()`]: crate::Connecting::handshake_data -751 pub fn handshake_data(&self) -> Option<Box<dyn Any>> { -752 self.0 -753 .lock_without_waking("handshake_data") -754 .inner -755 .crypto_session() -756 .handshake_data() -757 } -758 -759 /// Cryptographic identity of the peer -760 /// -761 /// The dynamic type returned is determined by the configured -762 /// [`Session`](proto::crypto::Session). For the default `rustls` session, the return value can -763 /// be [`downcast`](Box::downcast) to a <code>Vec<[rustls::pki_types::CertificateDer]></code> -764 pub fn peer_identity(&self) -> Option<Box<dyn Any>> { -765 self.0 -766 .lock_without_waking("peer_identity") -767 .inner -768 .crypto_session() -769 .peer_identity() -770 } -771 -772 /// A stable identifier for this connection -773 /// -774 /// Peer addresses and connection IDs can change, but this value will remain -775 /// fixed for the lifetime of the connection. -776 pub fn stable_id(&self) -> usize { -777 self.0.stable_id() -778 } -779 -780 /// Update traffic keys spontaneously -781 /// -782 /// This primarily exists for testing purposes. -783 pub fn force_key_update(&self) { -784 self.0 -785 .lock_and_wake("force_key_update") -786 .inner -787 .force_key_update() -788 } -789 -790 /// Derive keying material from this connection's TLS session secrets. -791 /// -792 /// When both peers call this method with the same `label` and `context` -793 /// arguments and `output` buffers of equal length, they will get the -794 /// same sequence of bytes in `output`. These bytes are cryptographically -795 /// strong and pseudorandom, and are suitable for use as keying material. -796 /// -797 /// See [RFC5705](https://tools.ietf.org/html/rfc5705) for more information. -798 pub fn export_keying_material( -799 &self, -800 output: &mut [u8], -801 label: &[u8], -802 context: &[u8], -803 ) -> Result<(), proto::crypto::ExportKeyingMaterialError> { -804 self.0 -805 .lock_without_waking("export_keying_material") -806 .inner -807 .crypto_session() -808 .export_keying_material(output, label, context) -809 } -810 -811 /// Modify the number of remotely initiated unidirectional streams that may be concurrently open -812 /// -813 /// No streams may be opened by the peer unless fewer than `count` are already open. Large -814 /// `count`s increase both minimum and worst-case memory consumption. -815 pub fn set_max_concurrent_uni_streams(&self, count: VarInt) { -816 let mut conn = self.0.lock_and_wake("set_max_concurrent_uni_streams"); -817 conn.inner.set_max_concurrent_streams(Dir::Uni, count); -818 } -819 -820 /// See [`proto::TransportConfig::send_window()`] -821 pub fn set_send_window(&self, send_window: u64) { -822 let mut conn = self.0.lock_and_wake("set_send_window"); -823 conn.inner.set_send_window(send_window); -824 } -825 -826 /// See [`proto::TransportConfig::receive_window()`] -827 pub fn set_receive_window(&self, receive_window: VarInt) { -828 let mut conn = self.0.lock_and_wake("set_receive_window"); -829 conn.inner.set_receive_window(receive_window); -830 } -831 -832 /// Modify the number of remotely initiated bidirectional streams that may be concurrently open -833 /// -834 /// No streams may be opened by the peer unless fewer than `count` are already open. Large -835 /// `count`s increase both minimum and worst-case memory consumption. -836 pub fn set_max_concurrent_bi_streams(&self, count: VarInt) { -837 let mut conn = self.0.lock_and_wake("set_max_concurrent_bi_streams"); -838 conn.inner.set_max_concurrent_streams(Dir::Bi, count); -839 } -840 -841 /// Track changes on our external address as reported by the peer. -842 pub fn observed_external_addr(&self) -> crate::ObservedExternalAddr { -843 let conn = self.0.lock_without_waking("external_addr"); -844 crate::ObservedExternalAddr::new(conn.observed_external_addr.subscribe()) +746 /// Only interesting for `Connection`s obtained from [`Connecting::into_0rtt`]. On 1-RTT +747 /// connections, always completes immediately. Contrast +748 /// [`handshake_confirmed`](Self::handshake_confirmed), which waits longer on clients e.g. to +749 /// confirm client authentication. +750 /// +751 /// For incoming connections, reads from [`RecvStream`]s are guaranteed not to arise from replay +752 /// attacks after this succeeds, even for streams accepted or read during 0-RTT. For outgoing +753 /// connections, streams opened after this succeeds will never be discarded by the server due to +754 /// 0-RTT rejection. +755 pub async fn authenticated(&self) -> Result<(), ConnectionError> { +756 let notified = { +757 let conn = self.0.state.lock("connected"); +758 if let Some(e) = &conn.error { +759 return Err(e.clone()); +760 } +761 if conn.connected { +762 return Ok(()); +763 } +764 self.0.shared.connected.notified() +765 }; +766 notified.await; +767 let conn = self.0.state.lock("connected"); +768 conn.error.clone().map_or(Ok(()), Err) +769 } +770 +771 /// Parameters negotiated during the handshake +772 /// +773 /// Guaranteed to return `Some` on fully established connections or after +774 /// [`Connecting::handshake_data()`] succeeds. See that method's documentations for details on +775 /// the returned value. +776 /// +777 /// [`Connection::handshake_data()`]: crate::Connecting::handshake_data +778 pub fn handshake_data(&self) -> Option<Box<dyn Any>> { +779 self.0 +780 .lock_without_waking("handshake_data") +781 .inner +782 .crypto_session() +783 .handshake_data() +784 } +785 +786 /// Cryptographic identity of the peer +787 /// +788 /// The dynamic type returned is determined by the configured +789 /// [`Session`](proto::crypto::Session). For the default `rustls` session, the return value can +790 /// be [`downcast`](Box::downcast) to a <code>Vec<[rustls::pki_types::CertificateDer]></code> +791 pub fn peer_identity(&self) -> Option<Box<dyn Any>> { +792 self.0 +793 .lock_without_waking("peer_identity") +794 .inner +795 .crypto_session() +796 .peer_identity() +797 } +798 +799 /// A stable identifier for this connection +800 /// +801 /// Peer addresses and connection IDs can change, but this value will remain +802 /// fixed for the lifetime of the connection. +803 pub fn stable_id(&self) -> usize { +804 self.0.stable_id() +805 } +806 +807 /// Update traffic keys spontaneously +808 /// +809 /// This primarily exists for testing purposes. +810 pub fn force_key_update(&self) { +811 self.0 +812 .lock_and_wake("force_key_update") +813 .inner +814 .force_key_update() +815 } +816 +817 /// Derive keying material from this connection's TLS session secrets. +818 /// +819 /// When both peers call this method with the same `label` and `context` +820 /// arguments and `output` buffers of equal length, they will get the +821 /// same sequence of bytes in `output`. These bytes are cryptographically +822 /// strong and pseudorandom, and are suitable for use as keying material. +823 /// +824 /// See [RFC5705](https://tools.ietf.org/html/rfc5705) for more information. +825 pub fn export_keying_material( +826 &self, +827 output: &mut [u8], +828 label: &[u8], +829 context: &[u8], +830 ) -> Result<(), proto::crypto::ExportKeyingMaterialError> { +831 self.0 +832 .lock_without_waking("export_keying_material") +833 .inner +834 .crypto_session() +835 .export_keying_material(output, label, context) +836 } +837 +838 /// Modify the number of remotely initiated unidirectional streams that may be concurrently open +839 /// +840 /// No streams may be opened by the peer unless fewer than `count` are already open. Large +841 /// `count`s increase both minimum and worst-case memory consumption. +842 pub fn set_max_concurrent_uni_streams(&self, count: VarInt) { +843 let mut conn = self.0.lock_and_wake("set_max_concurrent_uni_streams"); +844 conn.inner.set_max_concurrent_streams(Dir::Uni, count); 845 } 846 -847 /// Is multipath enabled? -848 // TODO(flub): not a useful API, once we do real things with multipath we can remove -849 // this again. -850 pub fn is_multipath_enabled(&self) -> bool { -851 let conn = self.0.lock_without_waking("is_multipath_enabled"); -852 conn.inner.is_multipath_negotiated() -853 } -854 -855 /// Registers one address at which this endpoint might be reachable -856 /// -857 /// When the NAT traversal extension is negotiated, servers send these addresses to clients in -858 /// `ADD_ADDRESS` frames. This allows clients to obtain server address candidates to initiate -859 /// NAT traversal attempts. Clients provide their own reachable addresses in `REACH_OUT` frames -860 /// when [`Self::initiate_nat_traversal_round`] is called. -861 pub fn add_nat_traversal_address( -862 &self, -863 address: SocketAddr, -864 ) -> Result<(), n0_nat_traversal::Error> { -865 let mut conn = self.0.lock_and_wake("add_nat_traversal_addresses"); -866 conn.inner.add_nat_traversal_address(address) -867 } -868 -869 /// Removes one or more addresses from the set of addresses at which this endpoint is reachable -870 /// -871 /// When the NAT traversal extension is negotiated, servers send address removals to -872 /// clients in `REMOVE_ADDRESS` frames. This allows clients to stop using outdated -873 /// server address candidates that are no longer valid for NAT traversal. -874 /// -875 /// For clients, removed addresses will no longer be advertised in `REACH_OUT` frames. -876 /// -877 /// Addresses not present in the set will be silently ignored. -878 pub fn remove_nat_traversal_address( -879 &self, -880 address: SocketAddr, -881 ) -> Result<(), n0_nat_traversal::Error> { -882 let mut conn = self.0.lock_and_wake("remove_nat_traversal_addresses"); -883 conn.inner.remove_nat_traversal_address(address) -884 } -885 -886 /// Get the current local nat traversal addresses -887 pub fn get_local_nat_traversal_addresses( -888 &self, -889 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { -890 let conn = self -891 .0 -892 .lock_without_waking("get_local_nat_traversal_addresses"); -893 conn.inner.get_local_nat_traversal_addresses() +847 /// See [`proto::TransportConfig::send_window()`] +848 pub fn set_send_window(&self, send_window: u64) { +849 let mut conn = self.0.lock_and_wake("set_send_window"); +850 conn.inner.set_send_window(send_window); +851 } +852 +853 /// See [`proto::TransportConfig::receive_window()`] +854 pub fn set_receive_window(&self, receive_window: VarInt) { +855 let mut conn = self.0.lock_and_wake("set_receive_window"); +856 conn.inner.set_receive_window(receive_window); +857 } +858 +859 /// Modify the number of remotely initiated bidirectional streams that may be concurrently open +860 /// +861 /// No streams may be opened by the peer unless fewer than `count` are already open. Large +862 /// `count`s increase both minimum and worst-case memory consumption. +863 pub fn set_max_concurrent_bi_streams(&self, count: VarInt) { +864 let mut conn = self.0.lock_and_wake("set_max_concurrent_bi_streams"); +865 conn.inner.set_max_concurrent_streams(Dir::Bi, count); +866 } +867 +868 /// Track changes on our external address as reported by the peer. +869 pub fn observed_external_addr(&self) -> crate::ObservedExternalAddr { +870 let conn = self.0.lock_without_waking("external_addr"); +871 crate::ObservedExternalAddr::new(conn.observed_external_addr.subscribe()) +872 } +873 +874 /// Is multipath enabled? +875 // TODO(flub): not a useful API, once we do real things with multipath we can remove +876 // this again. +877 pub fn is_multipath_enabled(&self) -> bool { +878 let conn = self.0.lock_without_waking("is_multipath_enabled"); +879 conn.inner.is_multipath_negotiated() +880 } +881 +882 /// Registers one address at which this endpoint might be reachable +883 /// +884 /// When the NAT traversal extension is negotiated, servers send these addresses to clients in +885 /// `ADD_ADDRESS` frames. This allows clients to obtain server address candidates to initiate +886 /// NAT traversal attempts. Clients provide their own reachable addresses in `REACH_OUT` frames +887 /// when [`Self::initiate_nat_traversal_round`] is called. +888 pub fn add_nat_traversal_address( +889 &self, +890 address: SocketAddr, +891 ) -> Result<(), n0_nat_traversal::Error> { +892 let mut conn = self.0.lock_and_wake("add_nat_traversal_addresses"); +893 conn.inner.add_nat_traversal_address(address) 894 } 895 -896 /// Get the currently advertised nat traversal addresses by the server -897 pub fn get_remote_nat_traversal_addresses( -898 &self, -899 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { -900 let conn = self -901 .0 -902 .lock_without_waking("get_remote_nat_traversal_addresses"); -903 conn.inner.get_remote_nat_traversal_addresses() -904 } -905 -906 /// Initiates a new nat traversal round -907 /// -908 /// A nat traversal round involves advertising the client's local addresses in `REACH_OUT` -909 /// frames, and initiating probing of the known remote addresses. When a new round is -910 /// initiated, the previous one is cancelled, and paths that have not been opened are closed. -911 /// -912 /// Returns the server addresses that are now being probed. -913 pub fn initiate_nat_traversal_round(&self) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { -914 let mut conn = self.0.lock_and_wake("initiate_nat_traversal_round"); -915 let now = conn.runtime.now(); -916 conn.inner.initiate_nat_traversal_round(now) -917 } -918} -919 -920/// Normalizes a [`FourTuple`] against the connection's address family. -921/// -922/// If the connection already uses IPv6 paths, the remote is canonicalised via -923/// [`ensure_ipv6`]. If it uses IPv4 and the requested remote is IPv6, this returns -924/// [`PathError::InvalidRemoteAddress`]. -925fn normalize_network_path( -926 network_path: FourTuple, -927 conn: &proto::Connection, -928) -> Result<FourTuple, PathError> { -929 // If endpoint::State::ipv6 is true we want to keep all our IP addresses as IPv6. -930 // If not, we do not support IPv6. We can not access endpoint::State from here -931 // however, but either all our paths use an IPv6 address, or all our paths use an -932 // IPv4 address. So we can use that information. -933 let ipv6 = conn -934 .paths() -935 .iter() -936 .filter_map(|id| { -937 conn.network_path(*id) -938 .map(|addrs| addrs.remote().is_ipv6()) -939 .ok() -940 }) -941 .next() -942 .unwrap_or_default(); -943 let remote = network_path.remote(); -944 if remote.is_ipv6() && !ipv6 { -945 Err(PathError::InvalidRemoteAddress(remote)) -946 } else if ipv6 { -947 let remote = SocketAddr::V6(ensure_ipv6(remote)); -948 Ok(FourTuple::new(remote, network_path.local_ip())) -949 } else { -950 Ok(network_path) -951 } -952} -953 -954pin_project! { -955 /// Future produced by [`Connection::open_uni`] -956 pub struct OpenUni<'a> { -957 conn: &'a ConnectionRef, -958 #[pin] -959 notify: Notified<'a>, -960 } -961} -962 -963impl Future for OpenUni<'_> { -964 type Output = Result<SendStream, ConnectionError>; -965 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { -966 let this = self.project(); -967 let (conn, id, is_0rtt) = ready!(poll_open(ctx, this.conn, this.notify, Dir::Uni))?; -968 Poll::Ready(Ok(SendStream::new(conn, id, is_0rtt))) -969 } -970} -971 -972pin_project! { -973 /// Future produced by [`Connection::open_bi`] -974 pub struct OpenBi<'a> { -975 conn: &'a ConnectionRef, -976 #[pin] -977 notify: Notified<'a>, +896 /// Removes one or more addresses from the set of addresses at which this endpoint is reachable +897 /// +898 /// When the NAT traversal extension is negotiated, servers send address removals to +899 /// clients in `REMOVE_ADDRESS` frames. This allows clients to stop using outdated +900 /// server address candidates that are no longer valid for NAT traversal. +901 /// +902 /// For clients, removed addresses will no longer be advertised in `REACH_OUT` frames. +903 /// +904 /// Addresses not present in the set will be silently ignored. +905 pub fn remove_nat_traversal_address( +906 &self, +907 address: SocketAddr, +908 ) -> Result<(), n0_nat_traversal::Error> { +909 let mut conn = self.0.lock_and_wake("remove_nat_traversal_addresses"); +910 conn.inner.remove_nat_traversal_address(address) +911 } +912 +913 /// Get the current local nat traversal addresses +914 pub fn get_local_nat_traversal_addresses( +915 &self, +916 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { +917 let conn = self +918 .0 +919 .lock_without_waking("get_local_nat_traversal_addresses"); +920 conn.inner.get_local_nat_traversal_addresses() +921 } +922 +923 /// Get the currently advertised nat traversal addresses by the server +924 pub fn get_remote_nat_traversal_addresses( +925 &self, +926 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { +927 let conn = self +928 .0 +929 .lock_without_waking("get_remote_nat_traversal_addresses"); +930 conn.inner.get_remote_nat_traversal_addresses() +931 } +932 +933 /// Initiates a new nat traversal round +934 /// +935 /// A nat traversal round involves advertising the client's local addresses in `REACH_OUT` +936 /// frames, and initiating probing of the known remote addresses. When a new round is +937 /// initiated, the previous one is cancelled, and paths that have not been opened are closed. +938 /// +939 /// Returns the server addresses that are now being probed. +940 pub fn initiate_nat_traversal_round(&self) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { +941 let mut conn = self.0.lock_and_wake("initiate_nat_traversal_round"); +942 let now = conn.runtime.now(); +943 conn.inner.initiate_nat_traversal_round(now) +944 } +945} +946 +947/// Normalizes a [`FourTuple`] against the connection's address family. +948/// +949/// If the connection already uses IPv6 paths, the remote is canonicalised via +950/// [`ensure_ipv6`]. If it uses IPv4 and the requested remote is IPv6, this returns +951/// [`PathError::InvalidRemoteAddress`]. +952fn normalize_network_path( +953 network_path: FourTuple, +954 conn: &proto::Connection, +955) -> Result<FourTuple, PathError> { +956 // If endpoint::State::ipv6 is true we want to keep all our IP addresses as IPv6. +957 // If not, we do not support IPv6. We can not access endpoint::State from here +958 // however, but either all our paths use an IPv6 address, or all our paths use an +959 // IPv4 address. So we can use that information. +960 let ipv6 = conn +961 .paths() +962 .iter() +963 .filter_map(|id| { +964 conn.network_path(*id) +965 .map(|addrs| addrs.remote().is_ipv6()) +966 .ok() +967 }) +968 .next() +969 .unwrap_or_default(); +970 let remote = network_path.remote(); +971 if remote.is_ipv6() && !ipv6 { +972 Err(PathError::InvalidRemoteAddress(remote)) +973 } else if ipv6 { +974 let remote = SocketAddr::V6(ensure_ipv6(remote)); +975 Ok(FourTuple::new(remote, network_path.local_ip())) +976 } else { +977 Ok(network_path) 978 } 979} 980 -981impl Future for OpenBi<'_> { -982 type Output = Result<(SendStream, RecvStream), ConnectionError>; -983 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { -984 let this = self.project(); -985 let (conn, id, is_0rtt) = ready!(poll_open(ctx, this.conn, this.notify, Dir::Bi))?; -986 -987 Poll::Ready(Ok(( -988 SendStream::new(conn.clone(), id, is_0rtt), -989 RecvStream::new(conn, id, is_0rtt), -990 ))) -991 } -992} -993 -994fn poll_open<'a>( -995 ctx: &mut Context<'_>, -996 conn: &'a ConnectionRef, -997 mut notify: Pin<&mut Notified<'a>>, -998 dir: Dir, -999) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> { -1000 let mut state = conn.lock_without_waking("poll_open"); -1001 if let Some(ref e) = state.error { -1002 return Poll::Ready(Err(e.clone())); -1003 } else if let Some(id) = state.inner.streams().open(dir) { -1004 let is_0rtt = state.inner.side().is_client() && state.inner.is_handshaking(); -1005 drop(state); // Release the lock so clone can take it -1006 return Poll::Ready(Ok((conn.clone(), id, is_0rtt))); -1007 } -1008 loop { -1009 match notify.as_mut().poll(ctx) { -1010 // `state` lock ensures we didn't race with readiness -1011 Poll::Pending => return Poll::Pending, -1012 // Spurious wakeup, get a new future -1013 Poll::Ready(()) => { -1014 notify.set(conn.shared.stream_budget_available[dir as usize].notified()) -1015 } -1016 } -1017 } -1018} -1019 -1020pin_project! { -1021 /// Future produced by [`Connection::accept_uni`] -1022 pub struct AcceptUni<'a> { -1023 conn: &'a ConnectionRef, -1024 #[pin] -1025 notify: Notified<'a>, -1026 } -1027} -1028 -1029impl Future for AcceptUni<'_> { -1030 type Output = Result<RecvStream, ConnectionError>; -1031 -1032 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { -1033 let this = self.project(); -1034 let (conn, id, is_0rtt) = ready!(poll_accept(ctx, this.conn, this.notify, Dir::Uni))?; -1035 Poll::Ready(Ok(RecvStream::new(conn, id, is_0rtt))) -1036 } -1037} -1038 -1039pin_project! { -1040 /// Future produced by [`Connection::accept_bi`] -1041 pub struct AcceptBi<'a> { -1042 conn: &'a ConnectionRef, -1043 #[pin] -1044 notify: Notified<'a>, -1045 } -1046} -1047 -1048impl Future for AcceptBi<'_> { -1049 type Output = Result<(SendStream, RecvStream), ConnectionError>; -1050 -1051 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { -1052 let this = self.project(); -1053 let (conn, id, is_0rtt) = ready!(poll_accept(ctx, this.conn, this.notify, Dir::Bi))?; -1054 Poll::Ready(Ok(( -1055 SendStream::new(conn.clone(), id, is_0rtt), -1056 RecvStream::new(conn, id, is_0rtt), -1057 ))) -1058 } -1059} -1060 -1061fn poll_accept<'a>( -1062 ctx: &mut Context<'_>, -1063 conn: &'a ConnectionRef, -1064 mut notify: Pin<&mut Notified<'a>>, -1065 dir: Dir, -1066) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> { -1067 let mut state = conn.lock_and_wake("poll_accept"); -1068 // Check for incoming streams before checking `state.error` so that already-received streams, -1069 // which are necessarily finite, can be drained from a closed connection. -1070 if let Some(id) = state.inner.streams().accept(dir) { -1071 let is_0rtt = state.inner.is_handshaking(); -1072 drop(state); // Release the lock (wake on drop) so clone can take it -1073 return Poll::Ready(Ok((conn.clone(), id, is_0rtt))); -1074 } else if let Some(ref e) = state.error { -1075 return Poll::Ready(Err(e.clone())); -1076 } -1077 loop { -1078 match notify.as_mut().poll(ctx) { -1079 // `state` lock ensures we didn't race with readiness -1080 Poll::Pending => return Poll::Pending, -1081 // Spurious wakeup, get a new future -1082 Poll::Ready(()) => notify.set(conn.shared.stream_incoming[dir as usize].notified()), -1083 } -1084 } -1085} -1086 -1087pin_project! { -1088 /// Future produced by [`Connection::read_datagram`] -1089 pub struct ReadDatagram<'a> { -1090 conn: &'a ConnectionRef, -1091 #[pin] -1092 notify: Notified<'a>, -1093 } -1094} -1095 -1096impl Future for ReadDatagram<'_> { -1097 type Output = Result<Bytes, ConnectionError>; -1098 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { -1099 let mut this = self.project(); -1100 let mut state = this.conn.lock_without_waking("ReadDatagram::poll"); -1101 // Check for buffered datagrams before checking `state.error` so that already-received -1102 // datagrams, which are necessarily finite, can be drained from a closed connection. -1103 if let Some(x) = state.inner.datagrams().recv() { -1104 return Poll::Ready(Ok(x)); -1105 } else if let Some(ref e) = state.error { -1106 return Poll::Ready(Err(e.clone())); -1107 } -1108 loop { -1109 match this.notify.as_mut().poll(ctx) { -1110 // `state` lock ensures we didn't race with readiness -1111 Poll::Pending => return Poll::Pending, -1112 // Spurious wakeup, get a new future -1113 Poll::Ready(()) => this -1114 .notify -1115 .set(this.conn.shared.datagram_received.notified()), -1116 } -1117 } -1118 } -1119} -1120 -1121pin_project! { -1122 /// Future produced by [`Connection::send_datagram_wait`] -1123 pub struct SendDatagram<'a> { -1124 conn: &'a ConnectionRef, -1125 data: Option<Bytes>, -1126 #[pin] -1127 notify: Notified<'a>, -1128 } -1129} -1130 -1131impl Future for SendDatagram<'_> { -1132 type Output = Result<(), SendDatagramError>; -1133 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { -1134 let mut this = self.project(); -1135 let mut state = this.conn.lock_and_wake("SendDatagram::poll"); -1136 if let Some(ref e) = state.error { -1137 return Poll::Ready(Err(SendDatagramError::ConnectionLost(e.clone()))); -1138 } -1139 use proto::SendDatagramError::*; -1140 match state -1141 .inner -1142 .datagrams() -1143 .send(this.data.take().unwrap(), false) -1144 { -1145 Ok(()) => Poll::Ready(Ok(())), -1146 Err(e) => Poll::Ready(Err(match e { -1147 Blocked(data) => { -1148 this.data.replace(data); -1149 loop { -1150 match this.notify.as_mut().poll(ctx) { -1151 Poll::Pending => return Poll::Pending, -1152 // Spurious wakeup, get a new future -1153 Poll::Ready(()) => this -1154 .notify -1155 .set(this.conn.shared.datagrams_unblocked.notified()), -1156 } -1157 } -1158 } -1159 UnsupportedByPeer => SendDatagramError::UnsupportedByPeer, -1160 Disabled => SendDatagramError::Disabled, -1161 TooLarge => SendDatagramError::TooLarge, -1162 })), -1163 } -1164 } -1165} -1166 -1167/// State of a [`Connection`] at the moment it was closed. -1168/// -1169/// Returned by the [`OnClosed`] future from [`Connection::on_closed`]. -1170#[derive(Debug, Clone)] -1171#[non_exhaustive] -1172pub struct Closed { -1173 /// The reason the connection was closed. -1174 pub reason: ConnectionError, -1175 /// Aggregate connection statistics at the moment of close. -1176 pub stats: ConnectionStats, -1177 /// Per-path statistics for every path the connection knew about at close time. -1178 /// -1179 /// This includes paths that haven't been discarded at close time, plus any -1180 /// already-discarded paths whose final stats had been retained because a [`Path`] -1181 /// or [`WeakPathHandle`] handle was kept alive. -1182 /// -1183 /// [`WeakPathHandle`]: crate::WeakPathHandle -1184 pub path_stats: Vec<(PathId, PathStats)>, -1185} -1186 -1187impl Closed { -1188 /// Snapshot the current connection state into a [`Closed`] value. -1189 /// -1190 /// Must only be called once `state.error` has been set. -1191 pub(crate) fn new(state: &mut State, reason: ConnectionError) -> Self { -1192 let stats = state.inner.stats(); +981pin_project! { +982 /// Future produced by [`Connection::open_uni`] +983 pub struct OpenUni<'a> { +984 conn: &'a ConnectionRef, +985 #[pin] +986 notify: Notified<'a>, +987 } +988} +989 +990impl Future for OpenUni<'_> { +991 type Output = Result<SendStream, ConnectionError>; +992 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { +993 let this = self.project(); +994 let (conn, id, is_0rtt) = ready!(poll_open(ctx, this.conn, this.notify, Dir::Uni))?; +995 Poll::Ready(Ok(SendStream::new(conn, id, is_0rtt))) +996 } +997} +998 +999pin_project! { +1000 /// Future produced by [`Connection::open_bi`] +1001 pub struct OpenBi<'a> { +1002 conn: &'a ConnectionRef, +1003 #[pin] +1004 notify: Notified<'a>, +1005 } +1006} +1007 +1008impl Future for OpenBi<'_> { +1009 type Output = Result<(SendStream, RecvStream), ConnectionError>; +1010 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { +1011 let this = self.project(); +1012 let (conn, id, is_0rtt) = ready!(poll_open(ctx, this.conn, this.notify, Dir::Bi))?; +1013 +1014 Poll::Ready(Ok(( +1015 SendStream::new(conn.clone(), id, is_0rtt), +1016 RecvStream::new(conn, id, is_0rtt), +1017 ))) +1018 } +1019} +1020 +1021fn poll_open<'a>( +1022 ctx: &mut Context<'_>, +1023 conn: &'a ConnectionRef, +1024 mut notify: Pin<&mut Notified<'a>>, +1025 dir: Dir, +1026) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> { +1027 let mut state = conn.lock_without_waking("poll_open"); +1028 if let Some(ref e) = state.error { +1029 return Poll::Ready(Err(e.clone())); +1030 } else if let Some(id) = state.inner.streams().open(dir) { +1031 let is_0rtt = state.inner.side().is_client() && state.inner.is_handshaking(); +1032 drop(state); // Release the lock so clone can take it +1033 return Poll::Ready(Ok((conn.clone(), id, is_0rtt))); +1034 } +1035 loop { +1036 match notify.as_mut().poll(ctx) { +1037 // `state` lock ensures we didn't race with readiness +1038 Poll::Pending => return Poll::Pending, +1039 // Spurious wakeup, get a new future +1040 Poll::Ready(()) => { +1041 notify.set(conn.shared.stream_budget_available[dir as usize].notified()) +1042 } +1043 } +1044 } +1045} +1046 +1047pin_project! { +1048 /// Future produced by [`Connection::accept_uni`] +1049 pub struct AcceptUni<'a> { +1050 conn: &'a ConnectionRef, +1051 #[pin] +1052 notify: Notified<'a>, +1053 } +1054} +1055 +1056impl Future for AcceptUni<'_> { +1057 type Output = Result<RecvStream, ConnectionError>; +1058 +1059 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { +1060 let this = self.project(); +1061 let (conn, id, is_0rtt) = ready!(poll_accept(ctx, this.conn, this.notify, Dir::Uni))?; +1062 Poll::Ready(Ok(RecvStream::new(conn, id, is_0rtt))) +1063 } +1064} +1065 +1066pin_project! { +1067 /// Future produced by [`Connection::accept_bi`] +1068 pub struct AcceptBi<'a> { +1069 conn: &'a ConnectionRef, +1070 #[pin] +1071 notify: Notified<'a>, +1072 } +1073} +1074 +1075impl Future for AcceptBi<'_> { +1076 type Output = Result<(SendStream, RecvStream), ConnectionError>; +1077 +1078 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { +1079 let this = self.project(); +1080 let (conn, id, is_0rtt) = ready!(poll_accept(ctx, this.conn, this.notify, Dir::Bi))?; +1081 Poll::Ready(Ok(( +1082 SendStream::new(conn.clone(), id, is_0rtt), +1083 RecvStream::new(conn, id, is_0rtt), +1084 ))) +1085 } +1086} +1087 +1088fn poll_accept<'a>( +1089 ctx: &mut Context<'_>, +1090 conn: &'a ConnectionRef, +1091 mut notify: Pin<&mut Notified<'a>>, +1092 dir: Dir, +1093) -> Poll<Result<(ConnectionRef, StreamId, bool), ConnectionError>> { +1094 let mut state = conn.lock_and_wake("poll_accept"); +1095 // Check for incoming streams before checking `state.error` so that already-received streams, +1096 // which are necessarily finite, can be drained from a closed connection. +1097 if let Some(id) = state.inner.streams().accept(dir) { +1098 let is_0rtt = state.inner.is_handshaking(); +1099 drop(state); // Release the lock (wake on drop) so clone can take it +1100 return Poll::Ready(Ok((conn.clone(), id, is_0rtt))); +1101 } else if let Some(ref e) = state.error { +1102 return Poll::Ready(Err(e.clone())); +1103 } +1104 loop { +1105 match notify.as_mut().poll(ctx) { +1106 // `state` lock ensures we didn't race with readiness +1107 Poll::Pending => return Poll::Pending, +1108 // Spurious wakeup, get a new future +1109 Poll::Ready(()) => notify.set(conn.shared.stream_incoming[dir as usize].notified()), +1110 } +1111 } +1112} +1113 +1114pin_project! { +1115 /// Future produced by [`Connection::read_datagram`] +1116 pub struct ReadDatagram<'a> { +1117 conn: &'a ConnectionRef, +1118 #[pin] +1119 notify: Notified<'a>, +1120 } +1121} +1122 +1123impl Future for ReadDatagram<'_> { +1124 type Output = Result<Bytes, ConnectionError>; +1125 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { +1126 let mut this = self.project(); +1127 let mut state = this.conn.lock_without_waking("ReadDatagram::poll"); +1128 // Check for buffered datagrams before checking `state.error` so that already-received +1129 // datagrams, which are necessarily finite, can be drained from a closed connection. +1130 if let Some(x) = state.inner.datagrams().recv() { +1131 return Poll::Ready(Ok(x)); +1132 } else if let Some(ref e) = state.error { +1133 return Poll::Ready(Err(e.clone())); +1134 } +1135 loop { +1136 match this.notify.as_mut().poll(ctx) { +1137 // `state` lock ensures we didn't race with readiness +1138 Poll::Pending => return Poll::Pending, +1139 // Spurious wakeup, get a new future +1140 Poll::Ready(()) => this +1141 .notify +1142 .set(this.conn.shared.datagram_received.notified()), +1143 } +1144 } +1145 } +1146} +1147 +1148pin_project! { +1149 /// Future produced by [`Connection::send_datagram_wait`] +1150 pub struct SendDatagram<'a> { +1151 conn: &'a ConnectionRef, +1152 data: Option<Bytes>, +1153 #[pin] +1154 notify: Notified<'a>, +1155 } +1156} +1157 +1158impl Future for SendDatagram<'_> { +1159 type Output = Result<(), SendDatagramError>; +1160 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { +1161 let mut this = self.project(); +1162 let mut state = this.conn.lock_and_wake("SendDatagram::poll"); +1163 if let Some(ref e) = state.error { +1164 return Poll::Ready(Err(SendDatagramError::ConnectionLost(e.clone()))); +1165 } +1166 use proto::SendDatagramError::*; +1167 match state +1168 .inner +1169 .datagrams() +1170 .send(this.data.take().unwrap(), false) +1171 { +1172 Ok(()) => Poll::Ready(Ok(())), +1173 Err(e) => Poll::Ready(Err(match e { +1174 Blocked(data) => { +1175 this.data.replace(data); +1176 loop { +1177 match this.notify.as_mut().poll(ctx) { +1178 Poll::Pending => return Poll::Pending, +1179 // Spurious wakeup, get a new future +1180 Poll::Ready(()) => this +1181 .notify +1182 .set(this.conn.shared.datagrams_unblocked.notified()), +1183 } +1184 } +1185 } +1186 UnsupportedByPeer => SendDatagramError::UnsupportedByPeer, +1187 Disabled => SendDatagramError::Disabled, +1188 TooLarge => SendDatagramError::TooLarge, +1189 })), +1190 } +1191 } +1192} 1193 -1194 let non_discarded_paths = state.inner.paths(); -1195 let mut path_stats = -1196 Vec::with_capacity(non_discarded_paths.len() + state.final_path_stats.len()); -1197 -1198 // Non-discarded paths are tracked by proto::Connection. -1199 path_stats.extend( -1200 non_discarded_paths -1201 .into_iter() -1202 .filter_map(|id| state.inner.path_stats(id).map(|stats| (id, stats))), -1203 ); -1204 // Already-discarded paths whose final stats we kept around. -1205 path_stats.extend( -1206 state -1207 .final_path_stats -1208 .iter() -1209 .map(|(id, stats)| (*id, *stats)), -1210 ); -1211 Self { -1212 reason, -1213 stats, -1214 path_stats, -1215 } -1216 } -1217} -1218 -1219/// Future returned by [`Connection::on_closed`] -1220/// -1221/// Resolves to [`Closed`]. -1222pub struct OnClosed { -1223 rx: oneshot::Receiver<Closed>, -1224 conn: WeakConnectionHandle, -1225} -1226 -1227impl Drop for OnClosed { -1228 fn drop(&mut self) { -1229 if self.rx.is_terminated() { -1230 return; -1231 }; -1232 if let Some(conn) = self.conn.upgrade() { -1233 self.rx.close(); -1234 conn.0 -1235 .lock_without_waking("OnClosed::drop") -1236 .on_closed -1237 .retain(|tx| !tx.is_closed()); -1238 } -1239 } -1240} -1241 -1242impl Future for OnClosed { -1243 type Output = Closed; -1244 -1245 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { -1246 let this = self.get_mut(); -1247 // The `expect` is safe because `State::drop` ensures that all senders are triggered -1248 // before being dropped. -1249 Pin::new(&mut this.rx) -1250 .poll(cx) -1251 .map(|x| x.expect("on_close sender is never dropped before sending")) -1252 } -1253} -1254 -1255#[derive(Debug)] -1256#[allow(clippy::redundant_allocation)] -1257pub(crate) struct ConnectionRef(Arc<Arc<ConnectionInner>>); -1258 -1259impl ConnectionRef { -1260 #[allow(clippy::redundant_allocation)] -1261 fn from_arc(inner: Arc<Arc<ConnectionInner>>) -> Self { -1262 inner.shared.ref_count.fetch_add(1, Ordering::Relaxed); -1263 Self(inner) -1264 } -1265 -1266 pub(crate) fn stable_id(&self) -> usize { -1267 &*self.0 as *const _ as usize -1268 } -1269 -1270 pub(crate) fn weak_handle(&self) -> WeakConnectionHandle { -1271 WeakConnectionHandle(Arc::downgrade(&self.0)) -1272 } -1273} -1274 -1275impl Clone for ConnectionRef { -1276 fn clone(&self) -> Self { -1277 Self::from_arc(Arc::clone(&self.0)) -1278 } -1279} -1280 -1281impl Drop for ConnectionRef { -1282 fn drop(&mut self) { -1283 if self.shared.ref_count.fetch_sub(1, Ordering::Relaxed) > 1 { -1284 return; -1285 } -1286 -1287 let conn = &mut *self.lock_without_waking("drop"); -1288 -1289 if !conn.inner.is_closed() { -1290 // If the driver is alive, it's just it and us, so we'd better shut it down. If it's -1291 // not, we can't do any harm. If there were any streams being opened, then either -1292 // the connection will be closed for an unrelated reason or a fresh reference will -1293 // be constructed for the newly opened stream. -1294 conn.implicit_close(&self.shared); -1295 } -1296 } -1297} -1298 -1299impl std::ops::Deref for ConnectionRef { -1300 type Target = ConnectionInner; -1301 fn deref(&self) -> &Self::Target { -1302 &self.0 -1303 } -1304} -1305 -1306#[derive(Debug)] -1307pub(crate) struct ConnectionInner { -1308 /// Kept private intentionally, use [`Self::lock_and_wake`]. -1309 state: Mutex<State>, -1310 pub(crate) shared: Shared, -1311} -1312 -1313impl ConnectionInner { -1314 /// Lock the state and return a guard that wakes the connection driver on drop. -1315 /// -1316 /// Use this for operations that may queue frames. The wake ensures the driver sends queued frames. -1317 /// If that's not needed, use [`Self::lock_without_waking`]. -1318 pub(crate) fn lock_and_wake(&self, purpose: &'static str) -> WakeGuard<'_> { -1319 WakeGuard { -1320 guard: self.state.lock(purpose), -1321 wake: true, +1194/// State of a [`Connection`] at the moment it was closed. +1195/// +1196/// Returned by the [`OnClosed`] future from [`Connection::on_closed`]. +1197#[derive(Debug, Clone)] +1198#[non_exhaustive] +1199pub struct Closed { +1200 /// The reason the connection was closed. +1201 pub reason: ConnectionError, +1202 /// Aggregate connection statistics at the moment of close. +1203 pub stats: ConnectionStats, +1204 /// Per-path statistics for every path the connection knew about at close time. +1205 /// +1206 /// This includes paths that haven't been discarded at close time, plus any +1207 /// already-discarded paths whose final stats had been retained because a [`Path`] +1208 /// or [`WeakPathHandle`] handle was kept alive. +1209 /// +1210 /// [`WeakPathHandle`]: crate::WeakPathHandle +1211 pub path_stats: Vec<(PathId, PathStats)>, +1212} +1213 +1214impl Closed { +1215 /// Snapshot the current connection state into a [`Closed`] value. +1216 /// +1217 /// Must only be called once `state.error` has been set. +1218 pub(crate) fn new(state: &mut State, reason: ConnectionError) -> Self { +1219 let stats = state.inner.stats(); +1220 +1221 let non_discarded_paths = state.inner.paths(); +1222 let mut path_stats = +1223 Vec::with_capacity(non_discarded_paths.len() + state.final_path_stats.len()); +1224 +1225 // Non-discarded paths are tracked by proto::Connection. +1226 path_stats.extend( +1227 non_discarded_paths +1228 .into_iter() +1229 .filter_map(|id| state.inner.path_stats(id).map(|stats| (id, stats))), +1230 ); +1231 // Already-discarded paths whose final stats we kept around. +1232 path_stats.extend( +1233 state +1234 .final_path_stats +1235 .iter() +1236 .map(|(id, stats)| (*id, *stats)), +1237 ); +1238 Self { +1239 reason, +1240 stats, +1241 path_stats, +1242 } +1243 } +1244} +1245 +1246/// Future returned by [`Connection::on_closed`] +1247/// +1248/// Resolves to [`Closed`]. +1249pub struct OnClosed { +1250 rx: oneshot::Receiver<Closed>, +1251 conn: WeakConnectionHandle, +1252} +1253 +1254impl Drop for OnClosed { +1255 fn drop(&mut self) { +1256 if self.rx.is_terminated() { +1257 return; +1258 }; +1259 if let Some(conn) = self.conn.upgrade() { +1260 self.rx.close(); +1261 conn.0 +1262 .lock_without_waking("OnClosed::drop") +1263 .on_closed +1264 .retain(|tx| !tx.is_closed()); +1265 } +1266 } +1267} +1268 +1269impl Future for OnClosed { +1270 type Output = Closed; +1271 +1272 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { +1273 let this = self.get_mut(); +1274 // The `expect` is safe because `State::drop` ensures that all senders are triggered +1275 // before being dropped. +1276 Pin::new(&mut this.rx) +1277 .poll(cx) +1278 .map(|x| x.expect("on_close sender is never dropped before sending")) +1279 } +1280} +1281 +1282#[derive(Debug)] +1283#[allow(clippy::redundant_allocation)] +1284pub(crate) struct ConnectionRef(Arc<Arc<ConnectionInner>>); +1285 +1286impl ConnectionRef { +1287 #[allow(clippy::redundant_allocation)] +1288 fn from_arc(inner: Arc<Arc<ConnectionInner>>) -> Self { +1289 inner.shared.ref_count.fetch_add(1, Ordering::Relaxed); +1290 Self(inner) +1291 } +1292 +1293 pub(crate) fn stable_id(&self) -> usize { +1294 &*self.0 as *const _ as usize +1295 } +1296 +1297 pub(crate) fn weak_handle(&self) -> WeakConnectionHandle { +1298 WeakConnectionHandle(Arc::downgrade(&self.0)) +1299 } +1300} +1301 +1302impl Clone for ConnectionRef { +1303 fn clone(&self) -> Self { +1304 Self::from_arc(Arc::clone(&self.0)) +1305 } +1306} +1307 +1308impl Drop for ConnectionRef { +1309 fn drop(&mut self) { +1310 if self.shared.ref_count.fetch_sub(1, Ordering::Relaxed) > 1 { +1311 return; +1312 } +1313 +1314 let conn = &mut *self.lock_without_waking("drop"); +1315 +1316 if !conn.inner.is_closed() { +1317 // If the driver is alive, it's just it and us, so we'd better shut it down. If it's +1318 // not, we can't do any harm. If there were any streams being opened, then either +1319 // the connection will be closed for an unrelated reason or a fresh reference will +1320 // be constructed for the newly opened stream. +1321 conn.implicit_close(&self.shared); 1322 } 1323 } -1324 -1325 /// Lock the state and return a guard that unlocks once dropped. -1326 /// -1327 /// Use this for operations that don't require any action from the connection driver. -1328 /// Otherwise, use [`Self::lock_and_wake`] instead. -1329 pub(crate) fn lock_without_waking(&self, purpose: &'static str) -> WakeGuard<'_> { -1330 WakeGuard { -1331 guard: self.state.lock(purpose), -1332 wake: false, -1333 } -1334 } -1335} -1336 -1337/// [`MutexGuard`] wrapper that calls [`State::wake`] on drop. -1338#[derive(derive_more::Deref, derive_more::DerefMut)] -1339pub(crate) struct WakeGuard<'a> { -1340 #[deref] -1341 #[deref_mut] -1342 guard: MutexGuard<'a, State>, -1343 wake: bool, -1344} -1345 -1346impl WakeGuard<'_> { -1347 pub(crate) fn skip_waking(&mut self) { -1348 self.wake = false; -1349 } -1350} +1324} +1325 +1326impl std::ops::Deref for ConnectionRef { +1327 type Target = ConnectionInner; +1328 fn deref(&self) -> &Self::Target { +1329 &self.0 +1330 } +1331} +1332 +1333#[derive(Debug)] +1334pub(crate) struct ConnectionInner { +1335 /// Kept private intentionally, use [`Self::lock_and_wake`]. +1336 state: Mutex<State>, +1337 pub(crate) shared: Shared, +1338} +1339 +1340impl ConnectionInner { +1341 /// Lock the state and return a guard that wakes the connection driver on drop. +1342 /// +1343 /// Use this for operations that may queue frames. The wake ensures the driver sends queued frames. +1344 /// If that's not needed, use [`Self::lock_without_waking`]. +1345 pub(crate) fn lock_and_wake(&self, purpose: &'static str) -> WakeGuard<'_> { +1346 WakeGuard { +1347 guard: self.state.lock(purpose), +1348 wake: true, +1349 } +1350 } 1351 -1352impl Drop for WakeGuard<'_> { -1353 fn drop(&mut self) { -1354 if self.wake { -1355 self.guard.wake(); -1356 } -1357 } -1358} -1359 -1360/// A handle to some connection internals, use with care. -1361/// -1362/// This contains a weak reference to the connection so will not itself keep the connection -1363/// alive. -1364#[derive(Debug, Clone)] -1365pub struct WeakConnectionHandle(Weak<Arc<ConnectionInner>>); -1366 -1367impl WeakConnectionHandle { -1368 /// Returns `true` if the [`Connection`] associated with this handle is still alive. -1369 pub fn is_alive(&self) -> bool { -1370 self.0.upgrade().is_some() -1371 } +1352 /// Lock the state and return a guard that unlocks once dropped. +1353 /// +1354 /// Use this for operations that don't require any action from the connection driver. +1355 /// Otherwise, use [`Self::lock_and_wake`] instead. +1356 pub(crate) fn lock_without_waking(&self, purpose: &'static str) -> WakeGuard<'_> { +1357 WakeGuard { +1358 guard: self.state.lock(purpose), +1359 wake: false, +1360 } +1361 } +1362} +1363 +1364/// [`MutexGuard`] wrapper that calls [`State::wake`] on drop. +1365#[derive(derive_more::Deref, derive_more::DerefMut)] +1366pub(crate) struct WakeGuard<'a> { +1367 #[deref] +1368 #[deref_mut] +1369 guard: MutexGuard<'a, State>, +1370 wake: bool, +1371} 1372 -1373 /// Upgrade the handle to a full `Connection` -1374 pub fn upgrade(&self) -> Option<Connection> { -1375 self.upgrade_to_ref().map(Connection) +1373impl WakeGuard<'_> { +1374 pub(crate) fn skip_waking(&mut self) { +1375 self.wake = false; 1376 } -1377 -1378 pub(crate) fn upgrade_to_ref(&self) -> Option<ConnectionRef> { -1379 self.0.upgrade().map(ConnectionRef::from_arc) -1380 } -1381 -1382 /// Returns `true` if the two [`WeakConnectionHandle`] point at the same connection. -1383 pub fn is_same_connection(&self, other: &Self) -> bool { -1384 self.0.ptr_eq(&other.0) -1385 } -1386} -1387 -1388#[derive(Debug, Default)] -1389pub(crate) struct Shared { -1390 handshake_confirmed: Notify, -1391 /// Notified when new streams may be locally initiated due to an increase in stream ID flow -1392 /// control budget -1393 stream_budget_available: [Notify; 2], -1394 /// Notified when the peer has initiated a new stream -1395 stream_incoming: [Notify; 2], -1396 datagram_received: Notify, -1397 datagrams_unblocked: Notify, -1398 closed: Notify, -1399 /// Number of live handles that can be used to initiate or handle I/O; excludes the driver -1400 ref_count: AtomicUsize, -1401} -1402 -1403pub(crate) struct State { -1404 pub(crate) inner: proto::Connection, -1405 driver: Option<Waker>, -1406 handle: ConnectionHandle, -1407 on_handshake_data: Option<oneshot::Sender<()>>, -1408 on_connected: Option<oneshot::Sender<bool>>, -1409 connected: bool, -1410 handshake_confirmed: bool, -1411 timer: Option<Pin<Box<dyn AsyncTimer>>>, -1412 timer_deadline: Option<Instant>, -1413 conn_events: mpsc::UnboundedReceiver<ConnectionEvent>, -1414 endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>, -1415 pub(crate) blocked_writers: FxHashMap<StreamId, Waker>, -1416 pub(crate) blocked_readers: FxHashMap<StreamId, Waker>, -1417 pub(crate) stopped: FxHashMap<StreamId, Arc<Notify>>, -1418 /// Always set to Some before the connection becomes drained -1419 pub(crate) error: Option<ConnectionError>, -1420 /// Tracks paths being opened -1421 open_path: FxHashMap<PathId, watch::Sender<Result<(), PathError>>>, -1422 /// Tracks reference counts for paths. -1423 /// -1424 /// I.e. how many [`Path`] and [`WeakPathHandle`] structs are alive for a path. -1425 /// Each entry's [`PathRefOwner`] holds an [`AtomicUsize`] so that cloning or -1426 /// dropping a [`PathRef`] (held by [`Path`] or [`WeakPathHandle`]) does not need -1427 /// to lock this state. -1428 /// -1429 /// [`WeakPathHandle`]: crate::path::WeakPathHandle -1430 pub(crate) path_refs: FxHashMap<PathId, PathRefOwner>, -1431 /// Final path stats for discarded paths. -1432 /// -1433 /// We only insert entries if the discarded path has a non-zero reference count in [`Self::path_refs`]. -1434 /// When the last reference to a path is dropped its entry is removed from both maps. -1435 pub(crate) final_path_stats: FxHashMap<PathId, PathStats>, -1436 pub(crate) path_events: tokio::sync::broadcast::Sender<PathEvent>, -1437 sender: Pin<Box<dyn UdpSender>>, -1438 pub(crate) runtime: Arc<dyn Runtime>, -1439 send_buffer: Vec<u8>, -1440 /// We buffer a transmit when the underlying I/O would block -1441 buffered_transmit: Option<proto::Transmit>, -1442 /// Our last external address reported by the peer. When multipath is enabled, this will be the -1443 /// last report across all paths. -1444 pub(crate) observed_external_addr: watch::Sender<Option<SocketAddr>>, -1445 pub(crate) nat_traversal_updates: tokio::sync::broadcast::Sender<n0_nat_traversal::Event>, -1446 on_closed: Vec<oneshot::Sender<Closed>>, -1447} -1448 -1449impl State { -1450 #[allow(clippy::too_many_arguments)] -1451 fn new( -1452 inner: proto::Connection, -1453 handle: ConnectionHandle, -1454 endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>, -1455 conn_events: mpsc::UnboundedReceiver<ConnectionEvent>, -1456 on_handshake_data: oneshot::Sender<()>, -1457 on_connected: oneshot::Sender<bool>, -1458 sender: Pin<Box<dyn UdpSender>>, -1459 runtime: Arc<dyn Runtime>, -1460 ) -> Self { -1461 Self { -1462 inner, -1463 driver: None, -1464 handle, -1465 on_handshake_data: Some(on_handshake_data), -1466 on_connected: Some(on_connected), -1467 connected: false, -1468 handshake_confirmed: false, -1469 timer: None, -1470 timer_deadline: None, -1471 conn_events, -1472 endpoint_events, -1473 blocked_writers: FxHashMap::default(), -1474 blocked_readers: FxHashMap::default(), -1475 stopped: FxHashMap::default(), -1476 open_path: FxHashMap::default(), -1477 error: None, -1478 sender, -1479 runtime, -1480 send_buffer: Vec::new(), -1481 buffered_transmit: None, -1482 path_events: tokio::sync::broadcast::channel(32).0, -1483 observed_external_addr: watch::Sender::new(None), -1484 nat_traversal_updates: tokio::sync::broadcast::channel(32).0, -1485 on_closed: Vec::new(), -1486 final_path_stats: Default::default(), -1487 path_refs: Default::default(), -1488 } -1489 } -1490 -1491 fn drive_transmit(&mut self, cx: &mut Context<'_>) -> io::Result<bool> { -1492 let now = self.runtime.now(); -1493 let mut transmits = 0; -1494 -1495 let max_datagrams = self -1496 .sender -1497 .max_transmit_segments() -1498 .min(MAX_TRANSMIT_SEGMENTS); -1499 -1500 loop { -1501 // Retry the last transmit, or get a new one. -1502 let t = match self.buffered_transmit.take() { -1503 Some(t) => t, -1504 None => { -1505 self.send_buffer.clear(); -1506 match self -1507 .inner -1508 .poll_transmit(now, max_datagrams, &mut self.send_buffer) -1509 { -1510 Some(t) => { -1511 transmits += match t.segment_size { -1512 None => 1, -1513 Some(s) => t.size.div_ceil(s), // round up -1514 }; -1515 t -1516 } -1517 None => break, -1518 } -1519 } -1520 }; -1521 -1522 let len = t.size; -1523 match self -1524 .sender -1525 .as_mut() -1526 .poll_send(&udp_transmit(&t, &self.send_buffer[..len]), cx) -1527 { -1528 Poll::Pending => { -1529 self.buffered_transmit = Some(t); -1530 return Ok(false); -1531 } -1532 Poll::Ready(Err(e)) => return Err(e), -1533 Poll::Ready(Ok(())) => {} -1534 } -1535 -1536 if transmits >= MAX_TRANSMIT_DATAGRAMS { -1537 // TODO: What isn't ideal here yet is that if we don't poll all -1538 // datagrams that could be sent we don't go into the `app_limited` -1539 // state and CWND continues to grow until we get here the next time. -1540 // See https://github.com/quinn-rs/quinn/issues/1126 -1541 return Ok(true); -1542 } -1543 } -1544 -1545 Ok(false) -1546 } -1547 -1548 fn forward_endpoint_events(&mut self) { -1549 while let Some(event) = self.inner.poll_endpoint_events() { -1550 // If the endpoint driver is gone, noop. -1551 let _ = self.endpoint_events.send((self.handle, event)); -1552 } -1553 } -1554 -1555 /// If this returns `Err`, the endpoint is dead, so the driver should exit immediately. -1556 fn process_conn_events( -1557 &mut self, -1558 shared: &Shared, -1559 cx: &mut Context<'_>, -1560 ) -> Result<(), ConnectionError> { -1561 loop { -1562 match self.conn_events.poll_recv(cx) { -1563 Poll::Ready(Some(ConnectionEvent::Rebind(sender))) => { -1564 self.sender = sender; -1565 self.inner.handle_network_change(None, self.runtime.now()); -1566 } -1567 Poll::Ready(Some(ConnectionEvent::LocalAddressChanged(hint))) => { -1568 self.inner -1569 .handle_network_change(hint.as_deref().map(|x| x as _), self.runtime.now()); -1570 } -1571 Poll::Ready(Some(ConnectionEvent::Proto(event))) => { -1572 self.inner.handle_event(event); -1573 } -1574 Poll::Ready(Some(ConnectionEvent::Close { reason, error_code })) => { -1575 self.close(error_code, reason, shared); -1576 } -1577 Poll::Ready(None) => { -1578 return Err(ConnectionError::TransportError(TransportError::new( -1579 TransportErrorCode::INTERNAL_ERROR, -1580 "endpoint driver future was dropped".to_string(), -1581 ))); -1582 } -1583 Poll::Pending => { -1584 return Ok(()); -1585 } -1586 } -1587 } -1588 } -1589 -1590 fn forward_app_events(&mut self, shared: &Shared) { -1591 while let Some(event) = self.inner.poll() { -1592 use proto::Event::*; -1593 match event { -1594 HandshakeDataReady => { -1595 if let Some(x) = self.on_handshake_data.take() { -1596 let _ = x.send(()); -1597 } +1377} +1378 +1379impl Drop for WakeGuard<'_> { +1380 fn drop(&mut self) { +1381 if self.wake { +1382 self.guard.wake(); +1383 } +1384 } +1385} +1386 +1387/// A handle to some connection internals, use with care. +1388/// +1389/// This contains a weak reference to the connection so will not itself keep the connection +1390/// alive. +1391#[derive(Debug, Clone)] +1392pub struct WeakConnectionHandle(Weak<Arc<ConnectionInner>>); +1393 +1394impl WeakConnectionHandle { +1395 /// Returns `true` if the [`Connection`] associated with this handle is still alive. +1396 pub fn is_alive(&self) -> bool { +1397 self.0.upgrade().is_some() +1398 } +1399 +1400 /// Upgrade the handle to a full `Connection` +1401 pub fn upgrade(&self) -> Option<Connection> { +1402 self.upgrade_to_ref().map(Connection) +1403 } +1404 +1405 pub(crate) fn upgrade_to_ref(&self) -> Option<ConnectionRef> { +1406 self.0.upgrade().map(ConnectionRef::from_arc) +1407 } +1408 +1409 /// Returns `true` if the two [`WeakConnectionHandle`] point at the same connection. +1410 pub fn is_same_connection(&self, other: &Self) -> bool { +1411 self.0.ptr_eq(&other.0) +1412 } +1413} +1414 +1415#[derive(Debug, Default)] +1416pub(crate) struct Shared { +1417 handshake_confirmed: Notify, +1418 /// Notified when new streams may be locally initiated due to an increase in stream ID flow +1419 /// control budget +1420 stream_budget_available: [Notify; 2], +1421 /// Notified when the peer has initiated a new stream +1422 stream_incoming: [Notify; 2], +1423 datagram_received: Notify, +1424 datagrams_unblocked: Notify, +1425 closed: Notify, +1426 connected: Notify, +1427 /// Number of live handles that can be used to initiate or handle I/O; excludes the driver +1428 ref_count: AtomicUsize, +1429} +1430 +1431pub(crate) struct State { +1432 pub(crate) inner: proto::Connection, +1433 driver: Option<Waker>, +1434 handle: ConnectionHandle, +1435 on_handshake_data: Option<oneshot::Sender<()>>, +1436 on_connected: Option<oneshot::Sender<bool>>, +1437 connected: bool, +1438 handshake_confirmed: bool, +1439 timer: Option<Pin<Box<dyn AsyncTimer>>>, +1440 timer_deadline: Option<Instant>, +1441 conn_events: mpsc::UnboundedReceiver<ConnectionEvent>, +1442 endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>, +1443 pub(crate) blocked_writers: FxHashMap<StreamId, Waker>, +1444 pub(crate) blocked_readers: FxHashMap<StreamId, Waker>, +1445 pub(crate) stopped: FxHashMap<StreamId, Arc<Notify>>, +1446 /// Always set to Some before the connection becomes drained +1447 pub(crate) error: Option<ConnectionError>, +1448 /// Tracks paths being opened +1449 open_path: FxHashMap<PathId, watch::Sender<Result<(), PathError>>>, +1450 /// Tracks reference counts for paths. +1451 /// +1452 /// I.e. how many [`Path`] and [`WeakPathHandle`] structs are alive for a path. +1453 /// Each entry's [`PathRefOwner`] holds an [`AtomicUsize`] so that cloning or +1454 /// dropping a [`PathRef`] (held by [`Path`] or [`WeakPathHandle`]) does not need +1455 /// to lock this state. +1456 /// +1457 /// [`WeakPathHandle`]: crate::path::WeakPathHandle +1458 pub(crate) path_refs: FxHashMap<PathId, PathRefOwner>, +1459 /// Final path stats for discarded paths. +1460 /// +1461 /// We only insert entries if the discarded path has a non-zero reference count in [`Self::path_refs`]. +1462 /// When the last reference to a path is dropped its entry is removed from both maps. +1463 pub(crate) final_path_stats: FxHashMap<PathId, PathStats>, +1464 pub(crate) path_events: tokio::sync::broadcast::Sender<PathEvent>, +1465 sender: Pin<Box<dyn UdpSender>>, +1466 pub(crate) runtime: Arc<dyn Runtime>, +1467 send_buffer: Vec<u8>, +1468 /// We buffer a transmit when the underlying I/O would block +1469 buffered_transmit: Option<proto::Transmit>, +1470 /// Our last external address reported by the peer. When multipath is enabled, this will be the +1471 /// last report across all paths. +1472 pub(crate) observed_external_addr: watch::Sender<Option<SocketAddr>>, +1473 pub(crate) nat_traversal_updates: tokio::sync::broadcast::Sender<n0_nat_traversal::Event>, +1474 on_closed: Vec<oneshot::Sender<Closed>>, +1475} +1476 +1477impl State { +1478 #[allow(clippy::too_many_arguments)] +1479 fn new( +1480 inner: proto::Connection, +1481 handle: ConnectionHandle, +1482 endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>, +1483 conn_events: mpsc::UnboundedReceiver<ConnectionEvent>, +1484 on_handshake_data: oneshot::Sender<()>, +1485 on_connected: oneshot::Sender<bool>, +1486 sender: Pin<Box<dyn UdpSender>>, +1487 runtime: Arc<dyn Runtime>, +1488 ) -> Self { +1489 Self { +1490 inner, +1491 driver: None, +1492 handle, +1493 on_handshake_data: Some(on_handshake_data), +1494 on_connected: Some(on_connected), +1495 connected: false, +1496 handshake_confirmed: false, +1497 timer: None, +1498 timer_deadline: None, +1499 conn_events, +1500 endpoint_events, +1501 blocked_writers: FxHashMap::default(), +1502 blocked_readers: FxHashMap::default(), +1503 stopped: FxHashMap::default(), +1504 open_path: FxHashMap::default(), +1505 error: None, +1506 sender, +1507 runtime, +1508 send_buffer: Vec::new(), +1509 buffered_transmit: None, +1510 path_events: tokio::sync::broadcast::channel(32).0, +1511 observed_external_addr: watch::Sender::new(None), +1512 nat_traversal_updates: tokio::sync::broadcast::channel(32).0, +1513 on_closed: Vec::new(), +1514 final_path_stats: Default::default(), +1515 path_refs: Default::default(), +1516 } +1517 } +1518 +1519 fn drive_transmit(&mut self, cx: &mut Context<'_>) -> io::Result<bool> { +1520 let now = self.runtime.now(); +1521 let mut transmits = 0; +1522 +1523 let max_datagrams = self +1524 .sender +1525 .max_transmit_segments() +1526 .min(MAX_TRANSMIT_SEGMENTS); +1527 +1528 loop { +1529 // Retry the last transmit, or get a new one. +1530 let t = match self.buffered_transmit.take() { +1531 Some(t) => t, +1532 None => { +1533 self.send_buffer.clear(); +1534 match self +1535 .inner +1536 .poll_transmit(now, max_datagrams, &mut self.send_buffer) +1537 { +1538 Some(t) => { +1539 transmits += match t.segment_size { +1540 None => 1, +1541 Some(s) => t.size.div_ceil(s), // round up +1542 }; +1543 t +1544 } +1545 None => break, +1546 } +1547 } +1548 }; +1549 +1550 let len = t.size; +1551 match self +1552 .sender +1553 .as_mut() +1554 .poll_send(&udp_transmit(&t, &self.send_buffer[..len]), cx) +1555 { +1556 Poll::Pending => { +1557 self.buffered_transmit = Some(t); +1558 return Ok(false); +1559 } +1560 Poll::Ready(Err(e)) => return Err(e), +1561 Poll::Ready(Ok(())) => {} +1562 } +1563 +1564 if transmits >= MAX_TRANSMIT_DATAGRAMS { +1565 // TODO: What isn't ideal here yet is that if we don't poll all +1566 // datagrams that could be sent we don't go into the `app_limited` +1567 // state and CWND continues to grow until we get here the next time. +1568 // See https://github.com/quinn-rs/quinn/issues/1126 +1569 return Ok(true); +1570 } +1571 } +1572 +1573 Ok(false) +1574 } +1575 +1576 fn forward_endpoint_events(&mut self) { +1577 while let Some(event) = self.inner.poll_endpoint_events() { +1578 // If the endpoint driver is gone, noop. +1579 let _ = self.endpoint_events.send((self.handle, event)); +1580 } +1581 } +1582 +1583 /// If this returns `Err`, the endpoint is dead, so the driver should exit immediately. +1584 fn process_conn_events( +1585 &mut self, +1586 shared: &Shared, +1587 cx: &mut Context<'_>, +1588 ) -> Result<(), ConnectionError> { +1589 loop { +1590 match self.conn_events.poll_recv(cx) { +1591 Poll::Ready(Some(ConnectionEvent::Rebind(sender))) => { +1592 self.sender = sender; +1593 self.inner.handle_network_change(None, self.runtime.now()); +1594 } +1595 Poll::Ready(Some(ConnectionEvent::LocalAddressChanged(hint))) => { +1596 self.inner +1597 .handle_network_change(hint.as_deref().map(|x| x as _), self.runtime.now()); 1598 } -1599 Connected => { -1600 self.connected = true; -1601 if let Some(x) = self.on_connected.take() { -1602 // We don't care if the on-connected future was dropped -1603 let _ = x.send(self.inner.accepted_0rtt()); -1604 } -1605 if self.inner.side().is_client() && !self.inner.accepted_0rtt() { -1606 // Wake up rejected 0-RTT streams so they can fail immediately with -1607 // `ZeroRttRejected` errors. -1608 wake_all(&mut self.blocked_writers); -1609 wake_all(&mut self.blocked_readers); -1610 wake_all_notify(&mut self.stopped); -1611 } -1612 } -1613 HandshakeConfirmed => { -1614 self.handshake_confirmed = true; -1615 shared.handshake_confirmed.notify_waiters(); -1616 } -1617 ConnectionLost { reason } => { -1618 self.terminate(reason, shared); -1619 } -1620 Stream(StreamEvent::Writable { id }) => wake_stream(id, &mut self.blocked_writers), -1621 Stream(StreamEvent::Opened { dir: Dir::Uni }) => { -1622 shared.stream_incoming[Dir::Uni as usize].notify_waiters(); -1623 } -1624 Stream(StreamEvent::Opened { dir: Dir::Bi }) => { -1625 shared.stream_incoming[Dir::Bi as usize].notify_waiters(); +1599 Poll::Ready(Some(ConnectionEvent::Proto(event))) => { +1600 self.inner.handle_event(event); +1601 } +1602 Poll::Ready(Some(ConnectionEvent::Close { reason, error_code })) => { +1603 self.close(error_code, reason, shared); +1604 } +1605 Poll::Ready(None) => { +1606 return Err(ConnectionError::TransportError(TransportError::new( +1607 TransportErrorCode::INTERNAL_ERROR, +1608 "endpoint driver future was dropped".to_string(), +1609 ))); +1610 } +1611 Poll::Pending => { +1612 return Ok(()); +1613 } +1614 } +1615 } +1616 } +1617 +1618 fn forward_app_events(&mut self, shared: &Shared) { +1619 while let Some(event) = self.inner.poll() { +1620 use proto::Event::*; +1621 match event { +1622 HandshakeDataReady => { +1623 if let Some(x) = self.on_handshake_data.take() { +1624 let _ = x.send(()); +1625 } 1626 } -1627 DatagramReceived => { -1628 shared.datagram_received.notify_waiters(); -1629 } -1630 DatagramsUnblocked => { -1631 shared.datagrams_unblocked.notify_waiters(); -1632 } -1633 Stream(StreamEvent::Readable { id }) => wake_stream(id, &mut self.blocked_readers), -1634 Stream(StreamEvent::Available { dir }) => { -1635 // Might mean any number of streams are ready, so we wake up everyone -1636 shared.stream_budget_available[dir as usize].notify_waiters(); -1637 } -1638 Stream(StreamEvent::Finished { id }) => wake_stream_notify(id, &mut self.stopped), -1639 Stream(StreamEvent::Stopped { id, .. }) => { -1640 wake_stream_notify(id, &mut self.stopped); -1641 wake_stream(id, &mut self.blocked_writers); -1642 } -1643 Path(ref evt @ PathEvent::ObservedAddr { addr: observed, .. }) => { -1644 self.path_events.send(evt.clone()).ok(); -1645 self.observed_external_addr.send_if_modified(|addr| { -1646 let old = addr.replace(observed); -1647 old != *addr -1648 }); -1649 } -1650 Path(ref evt @ PathEvent::Established { id, .. }) => { -1651 self.path_events.send(evt.clone()).ok(); -1652 if let Some(sender) = self.open_path.remove(&id) { -1653 sender.send_modify(|value| *value = Ok(())); -1654 } +1627 Connected => { +1628 self.connected = true; +1629 shared.connected.notify_waiters(); +1630 if let Some(x) = self.on_connected.take() { +1631 // We don't care if the on-connected future was dropped +1632 let _ = x.send(self.inner.accepted_0rtt()); +1633 } +1634 if self.inner.side().is_client() && !self.inner.accepted_0rtt() { +1635 // Wake up rejected 0-RTT streams so they can fail immediately with +1636 // `ZeroRttRejected` errors. +1637 wake_all(&mut self.blocked_writers); +1638 wake_all(&mut self.blocked_readers); +1639 wake_all_notify(&mut self.stopped); +1640 } +1641 } +1642 HandshakeConfirmed => { +1643 self.handshake_confirmed = true; +1644 shared.handshake_confirmed.notify_waiters(); +1645 } +1646 ConnectionLost { reason } => { +1647 self.terminate(reason, shared); +1648 } +1649 Stream(StreamEvent::Writable { id }) => wake_stream(id, &mut self.blocked_writers), +1650 Stream(StreamEvent::Opened { dir: Dir::Uni }) => { +1651 shared.stream_incoming[Dir::Uni as usize].notify_waiters(); +1652 } +1653 Stream(StreamEvent::Opened { dir: Dir::Bi }) => { +1654 shared.stream_incoming[Dir::Bi as usize].notify_waiters(); 1655 } -1656 Path( -1657 ref evt @ PathEvent::Discarded { -1658 id, ref path_stats, .. -1659 }, -1660 ) => { -1661 if self.path_refs.contains_key(&id) { -1662 self.final_path_stats.insert(id, *path_stats.clone()); -1663 } -1664 self.path_events.send(evt.clone()).ok(); -1665 } -1666 Path(ref evt @ PathEvent::Abandoned { id, .. }) => { -1667 if let Some(sender) = self.open_path.remove(&id) { -1668 // We don't care for the reason why this path was closed here, because semantically -1669 // all close reasons for a path that has not yet been opened equals to `ValidationFailed`. -1670 // With the noq API, there is no way to application-close a not-yet-opened path, so -1671 // `ApplicationClosed` cannot occur. And all other variants will only occur for paths -1672 // that have already been opened. -1673 // The previous iteration of this code had another event `PathEvent::LocallyClosed` which -1674 // contained a `PathError`, but that was only ever set to `ValidationFailed`. -1675 let error = PathError::ValidationFailed; -1676 sender.send_modify(|value| *value = Err(error)); -1677 } -1678 // this will happen also for already opened paths -1679 self.path_events.send(evt.clone()).ok(); -1680 } -1681 Path(evt @ PathEvent::RemoteStatus { .. }) => { -1682 self.path_events.send(evt).ok(); -1683 } -1684 NatTraversal(update) => { -1685 self.nat_traversal_updates.send(update).ok(); -1686 } -1687 _ => { -1688 // PathEvent is #[non_exhaustive]. -1689 // It's possible that noq is built against a newer noq-proto version. -1690 // In that case, we need to ignore path events we can't handle yet. -1691 // But for tests, we expect noq and noq-proto to be in sync, so we -1692 // should panic in case we don't actually handle new cases. -1693 #[cfg(test)] -1694 panic!("Unhandled PathEvent variant: {event:?}"); -1695 } -1696 } -1697 } -1698 } -1699 -1700 fn drive_timer(&mut self, cx: &mut Context<'_>) -> bool { -1701 // Check whether we need to (re)set the timer. If so, we must poll again to ensure the -1702 // timer is registered with the runtime (and check whether it's already -1703 // expired). -1704 match self.inner.poll_timeout() { -1705 Some(deadline) => { -1706 if let Some(delay) = &mut self.timer { -1707 // There is no need to reset the tokio timer if the deadline -1708 // did not change -1709 if self -1710 .timer_deadline -1711 .map(|current_deadline| current_deadline != deadline) -1712 .unwrap_or(true) -1713 { -1714 delay.as_mut().reset(deadline); -1715 } -1716 } else { -1717 self.timer = Some(self.runtime.new_timer(deadline)); -1718 } -1719 // Store the actual expiration time of the timer -1720 self.timer_deadline = Some(deadline); -1721 } -1722 None => { -1723 self.timer_deadline = None; -1724 return false; +1656 DatagramReceived => { +1657 shared.datagram_received.notify_waiters(); +1658 } +1659 DatagramsUnblocked => { +1660 shared.datagrams_unblocked.notify_waiters(); +1661 } +1662 Stream(StreamEvent::Readable { id }) => wake_stream(id, &mut self.blocked_readers), +1663 Stream(StreamEvent::Available { dir }) => { +1664 // Might mean any number of streams are ready, so we wake up everyone +1665 shared.stream_budget_available[dir as usize].notify_waiters(); +1666 } +1667 Stream(StreamEvent::Finished { id }) => wake_stream_notify(id, &mut self.stopped), +1668 Stream(StreamEvent::Stopped { id, .. }) => { +1669 wake_stream_notify(id, &mut self.stopped); +1670 wake_stream(id, &mut self.blocked_writers); +1671 } +1672 Path(ref evt @ PathEvent::ObservedAddr { addr: observed, .. }) => { +1673 self.path_events.send(evt.clone()).ok(); +1674 self.observed_external_addr.send_if_modified(|addr| { +1675 let old = addr.replace(observed); +1676 old != *addr +1677 }); +1678 } +1679 Path(ref evt @ PathEvent::Established { id, .. }) => { +1680 self.path_events.send(evt.clone()).ok(); +1681 if let Some(sender) = self.open_path.remove(&id) { +1682 sender.send_modify(|value| *value = Ok(())); +1683 } +1684 } +1685 Path( +1686 ref evt @ PathEvent::Discarded { +1687 id, ref path_stats, .. +1688 }, +1689 ) => { +1690 if self.path_refs.contains_key(&id) { +1691 self.final_path_stats.insert(id, *path_stats.clone()); +1692 } +1693 self.path_events.send(evt.clone()).ok(); +1694 } +1695 Path(ref evt @ PathEvent::Abandoned { id, .. }) => { +1696 if let Some(sender) = self.open_path.remove(&id) { +1697 // We don't care for the reason why this path was closed here, because semantically +1698 // all close reasons for a path that has not yet been opened equals to `ValidationFailed`. +1699 // With the noq API, there is no way to application-close a not-yet-opened path, so +1700 // `ApplicationClosed` cannot occur. And all other variants will only occur for paths +1701 // that have already been opened. +1702 // The previous iteration of this code had another event `PathEvent::LocallyClosed` which +1703 // contained a `PathError`, but that was only ever set to `ValidationFailed`. +1704 let error = PathError::ValidationFailed; +1705 sender.send_modify(|value| *value = Err(error)); +1706 } +1707 // this will happen also for already opened paths +1708 self.path_events.send(evt.clone()).ok(); +1709 } +1710 Path(evt @ PathEvent::RemoteStatus { .. }) => { +1711 self.path_events.send(evt).ok(); +1712 } +1713 NatTraversal(update) => { +1714 self.nat_traversal_updates.send(update).ok(); +1715 } +1716 _ => { +1717 // PathEvent is #[non_exhaustive]. +1718 // It's possible that noq is built against a newer noq-proto version. +1719 // In that case, we need to ignore path events we can't handle yet. +1720 // But for tests, we expect noq and noq-proto to be in sync, so we +1721 // should panic in case we don't actually handle new cases. +1722 #[cfg(test)] +1723 panic!("Unhandled PathEvent variant: {event:?}"); +1724 } 1725 } 1726 } -1727 -1728 if self.timer_deadline.is_none() { -1729 return false; -1730 } -1731 -1732 let delay = self -1733 .timer -1734 .as_mut() -1735 .expect("timer must exist in this state") -1736 .as_mut(); -1737 if delay.poll(cx).is_pending() { -1738 // Since there wasn't a timeout event, there is nothing new -1739 // for the connection to do -1740 return false; -1741 } -1742 -1743 // A timer expired, so the caller needs to check for -1744 // new transmits, which might cause new timers to be set. -1745 self.inner.handle_timeout(self.runtime.now()); -1746 self.timer_deadline = None; -1747 true -1748 } -1749 -1750 /// Wake up a blocked `Driver` task to process I/O -1751 pub(crate) fn wake(&mut self) { -1752 if let Some(x) = self.driver.take() { -1753 x.wake(); -1754 } -1755 } +1727 } +1728 +1729 fn drive_timer(&mut self, cx: &mut Context<'_>) -> bool { +1730 // Check whether we need to (re)set the timer. If so, we must poll again to ensure the +1731 // timer is registered with the runtime (and check whether it's already +1732 // expired). +1733 match self.inner.poll_timeout() { +1734 Some(deadline) => { +1735 if let Some(delay) = &mut self.timer { +1736 // There is no need to reset the tokio timer if the deadline +1737 // did not change +1738 if self +1739 .timer_deadline +1740 .map(|current_deadline| current_deadline != deadline) +1741 .unwrap_or(true) +1742 { +1743 delay.as_mut().reset(deadline); +1744 } +1745 } else { +1746 self.timer = Some(self.runtime.new_timer(deadline)); +1747 } +1748 // Store the actual expiration time of the timer +1749 self.timer_deadline = Some(deadline); +1750 } +1751 None => { +1752 self.timer_deadline = None; +1753 return false; +1754 } +1755 } 1756 -1757 /// Used to wake up all blocked futures when the connection becomes closed for any reason -1758 fn terminate(&mut self, reason: ConnectionError, shared: &Shared) { -1759 self.error = Some(reason.clone()); -1760 if let Some(x) = self.on_handshake_data.take() { -1761 let _ = x.send(()); -1762 } -1763 wake_all(&mut self.blocked_writers); -1764 wake_all(&mut self.blocked_readers); -1765 shared.stream_budget_available[Dir::Uni as usize].notify_waiters(); -1766 shared.stream_budget_available[Dir::Bi as usize].notify_waiters(); -1767 shared.stream_incoming[Dir::Uni as usize].notify_waiters(); -1768 shared.stream_incoming[Dir::Bi as usize].notify_waiters(); -1769 shared.datagram_received.notify_waiters(); -1770 shared.datagrams_unblocked.notify_waiters(); -1771 if let Some(x) = self.on_connected.take() { -1772 let _ = x.send(false); -1773 } -1774 shared.handshake_confirmed.notify_waiters(); -1775 wake_all_notify(&mut self.stopped); -1776 shared.closed.notify_waiters(); -1777 -1778 // Send to the registered on_closed futures. -1779 if !self.on_closed.is_empty() { -1780 let closed = Closed::new(self, reason); -1781 for tx in self.on_closed.drain(..) { -1782 tx.send(closed.clone()).ok(); -1783 } -1784 } -1785 } -1786 -1787 fn close(&mut self, error_code: VarInt, reason: Bytes, shared: &Shared) { -1788 self.inner.close(self.runtime.now(), error_code, reason); -1789 self.terminate(ConnectionError::LocallyClosed, shared); -1790 self.wake(); -1791 } -1792 -1793 /// Close for a reason other than the application's explicit request -1794 pub(crate) fn implicit_close(&mut self, shared: &Shared) { -1795 self.close(0u32.into(), Bytes::new(), shared); -1796 } -1797 -1798 pub(crate) fn check_0rtt(&self) -> Result<(), ()> { -1799 if self.inner.is_handshaking() -1800 || self.inner.accepted_0rtt() -1801 || self.inner.side().is_server() -1802 { -1803 Ok(()) -1804 } else { -1805 Err(()) -1806 } -1807 } -1808 -1809 /// Returns [`PathStats`] for a path, if available. -1810 /// -1811 /// This gets the stats from [`proto::Connection`]. If that returns `None` -1812 /// it gets them from `Self::final_path_stats` instead. -1813 pub(crate) fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> { -1814 self.inner -1815 .path_stats(path_id) -1816 .or_else(|| self.final_path_stats.get(&path_id).copied()) -1817 } -1818 -1819 /// Acquire a new [`PathRef`] for a path id, bumping its reference counter by 1. -1820 /// -1821 /// The returned [`PathRef`] is intended to be stored on a [`Path`] or [`WeakPathHandle`]. -1822 /// Its reference count is automatically increased when cloned. When its owner is dropped, -1823 /// [`PathRef::on_drop`] must be called to decrement the refcount. -1824 /// -1825 /// [`WeakPathHandle`]: crate::path::WeakPathHandle -1826 pub(crate) fn acquire_path_ref(&mut self, path_id: PathId) -> PathRef { -1827 self.path_refs.entry(path_id).or_default().acquire(path_id) -1828 } -1829} -1830 -1831impl Drop for State { -1832 fn drop(&mut self) { -1833 if !self.inner.is_drained() { -1834 // Ensure the endpoint can tidy up -1835 let _ = self -1836 .endpoint_events -1837 .send((self.handle, proto::EndpointEvent::drained())); -1838 } -1839 -1840 if !self.on_closed.is_empty() -1841 && let Some(reason) = self.error.clone() -1842 { -1843 // Ensure that all on_closed oneshot senders are triggered before dropping. -1844 let closed = Closed::new(self, reason); -1845 for tx in self.on_closed.drain(..) { -1846 tx.send(closed.clone()).ok(); -1847 } -1848 } -1849 } -1850} -1851 -1852impl fmt::Debug for State { -1853 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -1854 f.debug_struct("State").field("inner", &self.inner).finish() -1855 } -1856} -1857 -1858fn wake_stream(stream_id: StreamId, wakers: &mut FxHashMap<StreamId, Waker>) { -1859 if let Some(waker) = wakers.remove(&stream_id) { -1860 waker.wake(); -1861 } -1862} -1863 -1864fn wake_all(wakers: &mut FxHashMap<StreamId, Waker>) { -1865 wakers.drain().for_each(|(_, waker)| waker.wake()) -1866} -1867 -1868fn wake_stream_notify(stream_id: StreamId, wakers: &mut FxHashMap<StreamId, Arc<Notify>>) { -1869 if let Some(notify) = wakers.remove(&stream_id) { -1870 notify.notify_waiters() -1871 } -1872} -1873 -1874fn wake_all_notify(wakers: &mut FxHashMap<StreamId, Arc<Notify>>) { -1875 wakers -1876 .drain() -1877 .for_each(|(_, notify)| notify.notify_waiters()) -1878} -1879 -1880/// Errors that can arise when sending a datagram -1881#[derive(Debug, Error, Clone, Eq, PartialEq)] -1882pub enum SendDatagramError { -1883 /// The peer does not support receiving datagram frames -1884 #[error("datagrams not supported by peer")] -1885 UnsupportedByPeer, -1886 /// Datagram support is disabled locally -1887 #[error("datagram support disabled")] -1888 Disabled, -1889 /// The datagram is larger than the connection can currently accommodate -1890 /// -1891 /// Indicates that the path MTU minus overhead or the limit advertised by the peer has been -1892 /// exceeded. -1893 #[error("datagram too large")] -1894 TooLarge, -1895 /// The connection was lost -1896 #[error("connection lost")] -1897 ConnectionLost(#[from] ConnectionError), -1898} -1899 -1900/// The maximum amount of datagrams which will be produced in a single `drive_transmit` call -1901/// -1902/// This limits the amount of CPU resources consumed by datagram generation, -1903/// and allows other tasks (like receiving ACKs) to run in between. -1904const MAX_TRANSMIT_DATAGRAMS: usize = 20; -1905 -1906/// The maximum amount of datagrams that are sent in a single transmit -1907/// -1908/// This can be lower than the maximum platform capabilities, to avoid excessive -1909/// memory allocations when calling `poll_transmit()`. Benchmarks have shown -1910/// that numbers around 10 are a good compromise. -1911const MAX_TRANSMIT_SEGMENTS: NonZeroUsize = NonZeroUsize::new(10).expect("known");
\ No newline at end of file +1757 if self.timer_deadline.is_none() { +1758 return false; +1759 } +1760 +1761 let delay = self +1762 .timer +1763 .as_mut() +1764 .expect("timer must exist in this state") +1765 .as_mut(); +1766 if delay.poll(cx).is_pending() { +1767 // Since there wasn't a timeout event, there is nothing new +1768 // for the connection to do +1769 return false; +1770 } +1771 +1772 // A timer expired, so the caller needs to check for +1773 // new transmits, which might cause new timers to be set. +1774 self.inner.handle_timeout(self.runtime.now()); +1775 self.timer_deadline = None; +1776 true +1777 } +1778 +1779 /// Wake up a blocked `Driver` task to process I/O +1780 pub(crate) fn wake(&mut self) { +1781 if let Some(x) = self.driver.take() { +1782 x.wake(); +1783 } +1784 } +1785 +1786 /// Used to wake up all blocked futures when the connection becomes closed for any reason +1787 fn terminate(&mut self, reason: ConnectionError, shared: &Shared) { +1788 self.error = Some(reason.clone()); +1789 if let Some(x) = self.on_handshake_data.take() { +1790 let _ = x.send(()); +1791 } +1792 wake_all(&mut self.blocked_writers); +1793 wake_all(&mut self.blocked_readers); +1794 shared.stream_budget_available[Dir::Uni as usize].notify_waiters(); +1795 shared.stream_budget_available[Dir::Bi as usize].notify_waiters(); +1796 shared.stream_incoming[Dir::Uni as usize].notify_waiters(); +1797 shared.stream_incoming[Dir::Bi as usize].notify_waiters(); +1798 shared.datagram_received.notify_waiters(); +1799 shared.datagrams_unblocked.notify_waiters(); +1800 if let Some(x) = self.on_connected.take() { +1801 let _ = x.send(false); +1802 } +1803 shared.handshake_confirmed.notify_waiters(); +1804 wake_all_notify(&mut self.stopped); +1805 shared.closed.notify_waiters(); +1806 // Send to the registered on_closed futures. +1807 if !self.on_closed.is_empty() { +1808 let closed = Closed::new(self, reason); +1809 for tx in self.on_closed.drain(..) { +1810 tx.send(closed.clone()).ok(); +1811 } +1812 } +1813 shared.connected.notify_waiters(); +1814 } +1815 +1816 fn close(&mut self, error_code: VarInt, reason: Bytes, shared: &Shared) { +1817 self.inner.close(self.runtime.now(), error_code, reason); +1818 self.terminate(ConnectionError::LocallyClosed, shared); +1819 self.wake(); +1820 } +1821 +1822 /// Close for a reason other than the application's explicit request +1823 pub(crate) fn implicit_close(&mut self, shared: &Shared) { +1824 self.close(0u32.into(), Bytes::new(), shared); +1825 } +1826 +1827 pub(crate) fn check_0rtt(&self) -> Result<(), ()> { +1828 if self.inner.is_handshaking() +1829 || self.inner.accepted_0rtt() +1830 || self.inner.side().is_server() +1831 { +1832 Ok(()) +1833 } else { +1834 Err(()) +1835 } +1836 } +1837 +1838 /// Returns [`PathStats`] for a path, if available. +1839 /// +1840 /// This gets the stats from [`proto::Connection`]. If that returns `None` +1841 /// it gets them from `Self::final_path_stats` instead. +1842 pub(crate) fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> { +1843 self.inner +1844 .path_stats(path_id) +1845 .or_else(|| self.final_path_stats.get(&path_id).copied()) +1846 } +1847 +1848 /// Acquire a new [`PathRef`] for a path id, bumping its reference counter by 1. +1849 /// +1850 /// The returned [`PathRef`] is intended to be stored on a [`Path`] or [`WeakPathHandle`]. +1851 /// Its reference count is automatically increased when cloned. When its owner is dropped, +1852 /// [`PathRef::on_drop`] must be called to decrement the refcount. +1853 /// +1854 /// [`WeakPathHandle`]: crate::path::WeakPathHandle +1855 pub(crate) fn acquire_path_ref(&mut self, path_id: PathId) -> PathRef { +1856 self.path_refs.entry(path_id).or_default().acquire(path_id) +1857 } +1858} +1859 +1860impl Drop for State { +1861 fn drop(&mut self) { +1862 if !self.inner.is_drained() { +1863 // Ensure the endpoint can tidy up +1864 let _ = self +1865 .endpoint_events +1866 .send((self.handle, proto::EndpointEvent::drained())); +1867 } +1868 +1869 if !self.on_closed.is_empty() +1870 && let Some(reason) = self.error.clone() +1871 { +1872 // Ensure that all on_closed oneshot senders are triggered before dropping. +1873 let closed = Closed::new(self, reason); +1874 for tx in self.on_closed.drain(..) { +1875 tx.send(closed.clone()).ok(); +1876 } +1877 } +1878 } +1879} +1880 +1881impl fmt::Debug for State { +1882 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +1883 f.debug_struct("State").field("inner", &self.inner).finish() +1884 } +1885} +1886 +1887fn wake_stream(stream_id: StreamId, wakers: &mut FxHashMap<StreamId, Waker>) { +1888 if let Some(waker) = wakers.remove(&stream_id) { +1889 waker.wake(); +1890 } +1891} +1892 +1893fn wake_all(wakers: &mut FxHashMap<StreamId, Waker>) { +1894 wakers.drain().for_each(|(_, waker)| waker.wake()) +1895} +1896 +1897fn wake_stream_notify(stream_id: StreamId, wakers: &mut FxHashMap<StreamId, Arc<Notify>>) { +1898 if let Some(notify) = wakers.remove(&stream_id) { +1899 notify.notify_waiters() +1900 } +1901} +1902 +1903fn wake_all_notify(wakers: &mut FxHashMap<StreamId, Arc<Notify>>) { +1904 wakers +1905 .drain() +1906 .for_each(|(_, notify)| notify.notify_waiters()) +1907} +1908 +1909/// Errors that can arise when sending a datagram +1910#[derive(Debug, Error, Clone, Eq, PartialEq)] +1911pub enum SendDatagramError { +1912 /// The peer does not support receiving datagram frames +1913 #[error("datagrams not supported by peer")] +1914 UnsupportedByPeer, +1915 /// Datagram support is disabled locally +1916 #[error("datagram support disabled")] +1917 Disabled, +1918 /// The datagram is larger than the connection can currently accommodate +1919 /// +1920 /// Indicates that the path MTU minus overhead or the limit advertised by the peer has been +1921 /// exceeded. +1922 #[error("datagram too large")] +1923 TooLarge, +1924 /// The connection was lost +1925 #[error("connection lost")] +1926 ConnectionLost(#[from] ConnectionError), +1927} +1928 +1929/// The maximum amount of datagrams which will be produced in a single `drive_transmit` call +1930/// +1931/// This limits the amount of CPU resources consumed by datagram generation, +1932/// and allows other tasks (like receiving ACKs) to run in between. +1933const MAX_TRANSMIT_DATAGRAMS: usize = 20; +1934 +1935/// The maximum amount of datagrams that are sent in a single transmit +1936/// +1937/// This can be lower than the maximum platform capabilities, to avoid excessive +1938/// memory allocations when calling `poll_transmit()`. Benchmarks have shown +1939/// that numbers around 10 are a good compromise. +1940const MAX_TRANSMIT_SEGMENTS: NonZeroUsize = NonZeroUsize::new(10).expect("known");
\ No newline at end of file diff --git a/pr/720/docs/src/noq/recv_stream.rs.html b/pr/720/docs/src/noq/recv_stream.rs.html index ade0ce745..bac86778c 100644 --- a/pr/720/docs/src/noq/recv_stream.rs.html +++ b/pr/720/docs/src/noq/recv_stream.rs.html @@ -286,503 +286,509 @@ 286 Ok(()) 287 } 288 -289 /// Check if this stream has been opened during 0-RTT. +289 /// Check if this stream predates completion of the handshake on an incoming connection. 290 /// -291 /// In which case any non-idempotent request should be considered dangerous at the application -292 /// level. Because read data is subject to replay attacks. -293 pub fn is_0rtt(&self) -> bool { -294 self.is_0rtt -295 } -296 -297 /// Get the identity of this stream -298 pub fn id(&self) -> StreamId { -299 self.stream -300 } -301 -302 /// Returns the number of bytes read from this stream. -303 /// -304 /// This is the offset of the next byte to be read, i.e. the length of the contiguous -305 /// prefix of the stream consumed by the application. -306 pub fn bytes_read(&self) -> Result<u64, ClosedStream> { -307 let mut conn = self.conn.lock_without_waking("RecvStream::bytes_read"); -308 conn.inner.recv_stream(self.stream).bytes_read() -309 } -310 -311 /// Completes when the stream has been reset by the peer or otherwise closed -312 /// -313 /// Yields `Some` with the reset error code when the stream is reset by the peer. Yields `None` -314 /// when the stream was previously [`stop()`](Self::stop)ed, or when the stream was -315 /// [`finish()`](crate::SendStream::finish)ed by the peer and all data has been received, after -316 /// which it is no longer meaningful for the stream to be reset. -317 /// -318 /// This operation is cancel-safe. -319 pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError> { -320 poll_fn(|cx| { -321 let mut conn = self.conn.lock_without_waking("RecvStream::reset"); -322 if self.is_0rtt && conn.check_0rtt().is_err() { -323 return Poll::Ready(Err(ResetError::ZeroRttRejected)); -324 } -325 -326 if let Some(code) = self.reset { -327 return Poll::Ready(Ok(Some(code))); -328 } -329 -330 match conn.inner.recv_stream(self.stream).received_reset() { -331 Err(_) => Poll::Ready(Ok(None)), -332 Ok(Some(error_code)) => { -333 // Stream state has just now been freed, so the connection may need to issue new -334 // stream ID flow control credit -335 conn.wake(); -336 Poll::Ready(Ok(Some(error_code))) -337 } -338 Ok(None) => { -339 if let Some(e) = &conn.error { -340 return Poll::Ready(Err(e.clone().into())); -341 } -342 // Resets always notify readers, since a reset is an immediate read error. We -343 // could introduce a dedicated channel to reduce the risk of spurious wakeups, -344 // but that increased complexity is probably not justified, as an application -345 // that is expecting a reset is not likely to receive large amounts of data. -346 conn.blocked_readers.insert(self.stream, cx.waker().clone()); -347 Poll::Pending -348 } -349 } -350 }) -351 .await -352 } -353 -354 /// Handle common logic related to reading out of a receive stream -355 /// -356 /// This takes an `FnMut` closure that takes care of the actual reading process, matching -357 /// the detailed read semantics for the calling function with a particular return type. -358 /// The closure can read from the passed `&mut Chunks` and has to return the status after -359 /// reading: the amount of data read, and the status after the final read call. -360 fn poll_read_generic<T, U>( -361 &mut self, -362 cx: &mut Context<'_>, -363 ordered: bool, -364 mut read_fn: T, -365 ) -> Poll<Result<Option<U>, ReadError>> -366 where -367 T: FnMut(&mut Chunks<'_>) -> ReadStatus<U>, -368 { -369 use proto::ReadError::*; -370 if self.all_data_read { -371 return Poll::Ready(Ok(None)); -372 } -373 -374 let mut conn = self.conn.lock_without_waking("RecvStream::poll_read"); -375 if self.is_0rtt { -376 conn.check_0rtt().map_err(|()| ReadError::ZeroRttRejected)?; -377 } -378 -379 // If we stored an error during a previous call, return it now. This can happen if a -380 // `read_fn` both wants to return data and also returns an error in its final stream status. -381 let status = match self.reset { -382 Some(code) => ReadStatus::Failed(None, Reset(code)), -383 None => { -384 let mut recv = conn.inner.recv_stream(self.stream); -385 let mut chunks = recv.read(ordered).map_err(|e| match e { -386 ReadableError::ClosedStream => ReadError::ClosedStream, -387 ReadableError::IllegalOrderedRead => { -388 // We should never get here because the only way to do unordered reads is -389 // via UnorderedRecvStream, which allows only unordered reads. It is not -390 // possible to get a RecvStream from an UnorderedRecvStream. -391 unreachable!("ordered read after unordered read") -392 } -393 })?; -394 let status = read_fn(&mut chunks); -395 if chunks.finalize().should_transmit() { -396 conn.wake(); -397 } -398 status -399 } -400 }; -401 -402 match status { -403 ReadStatus::Readable(read) => Poll::Ready(Ok(Some(read))), -404 ReadStatus::Finished(read) => { -405 self.all_data_read = true; -406 Poll::Ready(Ok(read)) -407 } -408 ReadStatus::Failed(read, Blocked) => match read { -409 Some(val) => Poll::Ready(Ok(Some(val))), -410 None => { -411 if let Some(ref x) = conn.error { -412 return Poll::Ready(Err(ReadError::ConnectionLost(x.clone()))); -413 } -414 conn.blocked_readers.insert(self.stream, cx.waker().clone()); -415 Poll::Pending -416 } -417 }, -418 ReadStatus::Failed(read, Reset(error_code)) => match read { -419 None => { -420 self.all_data_read = true; -421 self.reset = Some(error_code); -422 Poll::Ready(Err(ReadError::Reset(error_code))) -423 } -424 done => { -425 self.reset = Some(error_code); -426 Poll::Ready(Ok(done)) -427 } -428 }, -429 } -430 } -431 -432 /// Converts this stream into an unordered stream. -433 pub fn into_unordered(self) -> UnorderedRecvStream { -434 UnorderedRecvStream { inner: self } -435 } -436} +291 /// True only if the stream was accepted before the handshake completed, which is only possible +292 /// if you successfully called [`Connecting::into_0rtt`](crate::Connecting::into_0rtt) and the +293 /// client chose to send 0-RTT data. +294 /// +295 /// Under those conditions, depending on cryptographic layer configuration, 0-RTT application +296 /// data may be a replay attack. To guard against this, applications should not execute +297 /// non-idempotent operations until +298 /// [`Connection::authenticated`](crate::Connection::authenticated) succeeds. +299 pub fn is_0rtt(&self) -> bool { +300 self.is_0rtt +301 } +302 +303 /// Get the identity of this stream +304 pub fn id(&self) -> StreamId { +305 self.stream +306 } +307 +308 /// Returns the number of bytes read from this stream. +309 /// +310 /// This is the offset of the next byte to be read, i.e. the length of the contiguous +311 /// prefix of the stream consumed by the application. +312 pub fn bytes_read(&self) -> Result<u64, ClosedStream> { +313 let mut conn = self.conn.lock_without_waking("RecvStream::bytes_read"); +314 conn.inner.recv_stream(self.stream).bytes_read() +315 } +316 +317 /// Completes when the stream has been reset by the peer or otherwise closed +318 /// +319 /// Yields `Some` with the reset error code when the stream is reset by the peer. Yields `None` +320 /// when the stream was previously [`stop()`](Self::stop)ed, or when the stream was +321 /// [`finish()`](crate::SendStream::finish)ed by the peer and all data has been received, after +322 /// which it is no longer meaningful for the stream to be reset. +323 /// +324 /// This operation is cancel-safe. +325 pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError> { +326 poll_fn(|cx| { +327 let mut conn = self.conn.lock_without_waking("RecvStream::reset"); +328 if self.is_0rtt && conn.check_0rtt().is_err() { +329 return Poll::Ready(Err(ResetError::ZeroRttRejected)); +330 } +331 +332 if let Some(code) = self.reset { +333 return Poll::Ready(Ok(Some(code))); +334 } +335 +336 match conn.inner.recv_stream(self.stream).received_reset() { +337 Err(_) => Poll::Ready(Ok(None)), +338 Ok(Some(error_code)) => { +339 // Stream state has just now been freed, so the connection may need to issue new +340 // stream ID flow control credit +341 conn.wake(); +342 Poll::Ready(Ok(Some(error_code))) +343 } +344 Ok(None) => { +345 if let Some(e) = &conn.error { +346 return Poll::Ready(Err(e.clone().into())); +347 } +348 // Resets always notify readers, since a reset is an immediate read error. We +349 // could introduce a dedicated channel to reduce the risk of spurious wakeups, +350 // but that increased complexity is probably not justified, as an application +351 // that is expecting a reset is not likely to receive large amounts of data. +352 conn.blocked_readers.insert(self.stream, cx.waker().clone()); +353 Poll::Pending +354 } +355 } +356 }) +357 .await +358 } +359 +360 /// Handle common logic related to reading out of a receive stream +361 /// +362 /// This takes an `FnMut` closure that takes care of the actual reading process, matching +363 /// the detailed read semantics for the calling function with a particular return type. +364 /// The closure can read from the passed `&mut Chunks` and has to return the status after +365 /// reading: the amount of data read, and the status after the final read call. +366 fn poll_read_generic<T, U>( +367 &mut self, +368 cx: &mut Context<'_>, +369 ordered: bool, +370 mut read_fn: T, +371 ) -> Poll<Result<Option<U>, ReadError>> +372 where +373 T: FnMut(&mut Chunks<'_>) -> ReadStatus<U>, +374 { +375 use proto::ReadError::*; +376 if self.all_data_read { +377 return Poll::Ready(Ok(None)); +378 } +379 +380 let mut conn = self.conn.lock_without_waking("RecvStream::poll_read"); +381 if self.is_0rtt { +382 conn.check_0rtt().map_err(|()| ReadError::ZeroRttRejected)?; +383 } +384 +385 // If we stored an error during a previous call, return it now. This can happen if a +386 // `read_fn` both wants to return data and also returns an error in its final stream status. +387 let status = match self.reset { +388 Some(code) => ReadStatus::Failed(None, Reset(code)), +389 None => { +390 let mut recv = conn.inner.recv_stream(self.stream); +391 let mut chunks = recv.read(ordered).map_err(|e| match e { +392 ReadableError::ClosedStream => ReadError::ClosedStream, +393 ReadableError::IllegalOrderedRead => { +394 // We should never get here because the only way to do unordered reads is +395 // via UnorderedRecvStream, which allows only unordered reads. It is not +396 // possible to get a RecvStream from an UnorderedRecvStream. +397 unreachable!("ordered read after unordered read") +398 } +399 })?; +400 let status = read_fn(&mut chunks); +401 if chunks.finalize().should_transmit() { +402 conn.wake(); +403 } +404 status +405 } +406 }; +407 +408 match status { +409 ReadStatus::Readable(read) => Poll::Ready(Ok(Some(read))), +410 ReadStatus::Finished(read) => { +411 self.all_data_read = true; +412 Poll::Ready(Ok(read)) +413 } +414 ReadStatus::Failed(read, Blocked) => match read { +415 Some(val) => Poll::Ready(Ok(Some(val))), +416 None => { +417 if let Some(ref x) = conn.error { +418 return Poll::Ready(Err(ReadError::ConnectionLost(x.clone()))); +419 } +420 conn.blocked_readers.insert(self.stream, cx.waker().clone()); +421 Poll::Pending +422 } +423 }, +424 ReadStatus::Failed(read, Reset(error_code)) => match read { +425 None => { +426 self.all_data_read = true; +427 self.reset = Some(error_code); +428 Poll::Ready(Err(ReadError::Reset(error_code))) +429 } +430 done => { +431 self.reset = Some(error_code); +432 Poll::Ready(Ok(done)) +433 } +434 }, +435 } +436 } 437 -438/// A stream that can be used to receive data out-of-order. -439/// -440/// Obtained by converting a [`RecvStream`] via [`RecvStream::into_unordered`]. -441/// -442/// This variant of `RecvStream` allows reading chunks of data *exclusively* -443/// out of order. Once you have done an unordered read, ordered reads are no -444/// longer possible since data may have been consumed out of order. +438 /// Converts this stream into an unordered stream. +439 pub fn into_unordered(self) -> UnorderedRecvStream { +440 UnorderedRecvStream { inner: self } +441 } +442} +443 +444/// A stream that can be used to receive data out-of-order. 445/// -446/// The stream state related fns like [`Self::id`], [`Self::is_0rtt`], [`Self::stop`], and -447/// [`Self::received_reset`] behave exactly as on [`RecvStream`]. -448#[derive(Debug)] -449pub struct UnorderedRecvStream { -450 inner: RecvStream, -451} -452 -453impl UnorderedRecvStream { -454 /// Reads the next segment of data. -455 /// -456 /// Yields `None` if the stream was finished. Otherwise, yields a segment of data and its -457 /// offset in the stream. Segments may be received in any order, and the `Chunk`'s `offset` -458 /// field can be used to determine ordering in the caller. Unordered reads are less prone -459 /// to head-of-line blocking within a stream, but require the application to manage -460 /// reassembling the original data. +446/// Obtained by converting a [`RecvStream`] via [`RecvStream::into_unordered`]. +447/// +448/// This variant of `RecvStream` allows reading chunks of data *exclusively* +449/// out of order. Once you have done an unordered read, ordered reads are no +450/// longer possible since data may have been consumed out of order. +451/// +452/// The stream state related fns like [`Self::id`], [`Self::is_0rtt`], [`Self::stop`], and +453/// [`Self::received_reset`] behave exactly as on [`RecvStream`]. +454#[derive(Debug)] +455pub struct UnorderedRecvStream { +456 inner: RecvStream, +457} +458 +459impl UnorderedRecvStream { +460 /// Reads the next segment of data. 461 /// -462 /// This operation is cancel-safe. -463 pub async fn read_chunk(&mut self, max_length: usize) -> Result<Option<Chunk>, ReadError> { -464 ReadChunk { -465 stream: &mut self.inner, -466 max_length, -467 ordered: false, -468 } -469 .await -470 } -471 -472 /// Get the identity of this stream -473 pub fn id(&self) -> StreamId { -474 self.inner.id() -475 } -476 -477 /// Check if this stream has been opened during 0-RTT. -478 /// -479 /// In which case any non-idempotent request should be considered dangerous at the application -480 /// level. Because read data is subject to replay attacks. -481 pub fn is_0rtt(&self) -> bool { -482 self.inner.is_0rtt() -483 } -484 -485 /// Stop accepting data -486 /// -487 /// Discards unread data and notifies the peer to stop transmitting. Once stopped, further -488 /// attempts to operate on a stream will yield `ClosedStream` errors. -489 pub fn stop(&mut self, error_code: VarInt) -> Result<(), ClosedStream> { -490 self.inner.stop(error_code) -491 } -492 -493 /// Completes when the stream has been reset by the peer or otherwise closed -494 /// -495 /// Yields `Some` with the reset error code when the stream is reset by the peer. Yields `None` -496 /// when the stream was previously [`stop()`](Self::stop)ed, or when the stream was -497 /// [`finish()`](crate::SendStream::finish)ed by the peer and all data has been received, after -498 /// which it is no longer meaningful for the stream to be reset. -499 /// -500 /// This operation is cancel-safe. -501 pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError> { -502 self.inner.received_reset().await -503 } -504} -505 -506enum ReadStatus<T> { -507 Readable(T), -508 Finished(Option<T>), -509 Failed(Option<T>, proto::ReadError), +462 /// Yields `None` if the stream was finished. Otherwise, yields a segment of data and its +463 /// offset in the stream. Segments may be received in any order, and the `Chunk`'s `offset` +464 /// field can be used to determine ordering in the caller. Unordered reads are less prone +465 /// to head-of-line blocking within a stream, but require the application to manage +466 /// reassembling the original data. +467 /// +468 /// This operation is cancel-safe. +469 pub async fn read_chunk(&mut self, max_length: usize) -> Result<Option<Chunk>, ReadError> { +470 ReadChunk { +471 stream: &mut self.inner, +472 max_length, +473 ordered: false, +474 } +475 .await +476 } +477 +478 /// Get the identity of this stream +479 pub fn id(&self) -> StreamId { +480 self.inner.id() +481 } +482 +483 /// Check if this stream has been opened during 0-RTT. +484 /// +485 /// In which case any non-idempotent request should be considered dangerous at the application +486 /// level. Because read data is subject to replay attacks. +487 pub fn is_0rtt(&self) -> bool { +488 self.inner.is_0rtt() +489 } +490 +491 /// Stop accepting data +492 /// +493 /// Discards unread data and notifies the peer to stop transmitting. Once stopped, further +494 /// attempts to operate on a stream will yield `ClosedStream` errors. +495 pub fn stop(&mut self, error_code: VarInt) -> Result<(), ClosedStream> { +496 self.inner.stop(error_code) +497 } +498 +499 /// Completes when the stream has been reset by the peer or otherwise closed +500 /// +501 /// Yields `Some` with the reset error code when the stream is reset by the peer. Yields `None` +502 /// when the stream was previously [`stop()`](Self::stop)ed, or when the stream was +503 /// [`finish()`](crate::SendStream::finish)ed by the peer and all data has been received, after +504 /// which it is no longer meaningful for the stream to be reset. +505 /// +506 /// This operation is cancel-safe. +507 pub async fn received_reset(&mut self) -> Result<Option<VarInt>, ResetError> { +508 self.inner.received_reset().await +509 } 510} 511 -512impl<T> From<(Option<T>, Option<proto::ReadError>)> for ReadStatus<T> { -513 fn from(status: (Option<T>, Option<proto::ReadError>)) -> Self { -514 match status { -515 (read, None) => Self::Finished(read), -516 (read, Some(e)) => Self::Failed(read, e), -517 } -518 } -519} -520 -521/// Future produced by [`RecvStream::read_to_end()`]. -522/// -523/// [`RecvStream::read_to_end()`]: crate::RecvStream::read_to_end -524struct ReadToEnd<'a> { -525 stream: &'a mut RecvStream, -526 read: Vec<(Bytes, u64)>, -527 start: u64, -528 end: u64, -529 size_limit: usize, -530} -531 -532impl Future for ReadToEnd<'_> { -533 type Output = Result<Vec<u8>, ReadToEndError>; -534 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { -535 loop { -536 match ready!(self.stream.poll_read_chunk(cx, usize::MAX, false))? { -537 Some(chunk) => { -538 self.start = self.start.min(chunk.offset); -539 let end = chunk.bytes.len() as u64 + chunk.offset; -540 if (end - self.start) > self.size_limit as u64 { -541 return Poll::Ready(Err(ReadToEndError::TooLong)); -542 } -543 self.end = self.end.max(end); -544 self.read.push((chunk.bytes, chunk.offset)); -545 } -546 None => { -547 if self.end == 0 { -548 // Never received anything -549 return Poll::Ready(Ok(Vec::new())); -550 } -551 let start = self.start; -552 let mut buffer = vec![0; (self.end - start) as usize]; -553 for (data, offset) in self.read.drain(..) { -554 let offset = (offset - start) as usize; -555 buffer[offset..offset + data.len()].copy_from_slice(&data); +512enum ReadStatus<T> { +513 Readable(T), +514 Finished(Option<T>), +515 Failed(Option<T>, proto::ReadError), +516} +517 +518impl<T> From<(Option<T>, Option<proto::ReadError>)> for ReadStatus<T> { +519 fn from(status: (Option<T>, Option<proto::ReadError>)) -> Self { +520 match status { +521 (read, None) => Self::Finished(read), +522 (read, Some(e)) => Self::Failed(read, e), +523 } +524 } +525} +526 +527/// Future produced by [`RecvStream::read_to_end()`]. +528/// +529/// [`RecvStream::read_to_end()`]: crate::RecvStream::read_to_end +530struct ReadToEnd<'a> { +531 stream: &'a mut RecvStream, +532 read: Vec<(Bytes, u64)>, +533 start: u64, +534 end: u64, +535 size_limit: usize, +536} +537 +538impl Future for ReadToEnd<'_> { +539 type Output = Result<Vec<u8>, ReadToEndError>; +540 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { +541 loop { +542 match ready!(self.stream.poll_read_chunk(cx, usize::MAX, false))? { +543 Some(chunk) => { +544 self.start = self.start.min(chunk.offset); +545 let end = chunk.bytes.len() as u64 + chunk.offset; +546 if (end - self.start) > self.size_limit as u64 { +547 return Poll::Ready(Err(ReadToEndError::TooLong)); +548 } +549 self.end = self.end.max(end); +550 self.read.push((chunk.bytes, chunk.offset)); +551 } +552 None => { +553 if self.end == 0 { +554 // Never received anything +555 return Poll::Ready(Ok(Vec::new())); 556 } -557 return Poll::Ready(Ok(buffer)); -558 } -559 } -560 } -561 } -562} -563 -564/// Errors from [`RecvStream::read_to_end`] -565#[derive(Debug, Error, Clone, PartialEq, Eq)] -566pub enum ReadToEndError { -567 /// An error occurred during reading -568 #[error("read error: {0}")] -569 Read(#[from] ReadError), -570 /// The stream is larger than the user-supplied limit -571 #[error("stream too long")] -572 TooLong, -573} -574 -575#[cfg(feature = "futures-io")] -576impl futures_io::AsyncRead for RecvStream { -577 fn poll_read( -578 self: Pin<&mut Self>, -579 cx: &mut Context<'_>, -580 buf: &mut [u8], -581 ) -> Poll<io::Result<usize>> { -582 let mut buf = ReadBuf::new(buf); -583 ready!(Self::poll_read_buf(self.get_mut(), cx, &mut buf))?; -584 Poll::Ready(Ok(buf.filled().len())) -585 } -586} -587 -588impl tokio::io::AsyncRead for RecvStream { -589 fn poll_read( -590 self: Pin<&mut Self>, -591 cx: &mut Context<'_>, -592 buf: &mut ReadBuf<'_>, -593 ) -> Poll<io::Result<()>> { -594 ready!(Self::poll_read_buf(self.get_mut(), cx, buf))?; -595 Poll::Ready(Ok(())) -596 } -597} -598 -599impl Drop for RecvStream { -600 fn drop(&mut self) { -601 if self.all_data_read { -602 debug_assert!( -603 !self -604 .conn -605 .lock_without_waking("RecvStream:drop") -606 .blocked_readers -607 .contains_key(&self.stream), -608 "Stream {} should not have a blocked reader when all data read is true", -609 &self.stream -610 ); -611 return; -612 } -613 let mut conn = self.conn.lock_and_wake("RecvStream::drop"); -614 -615 // clean up any previously registered wakers -616 conn.blocked_readers.remove(&self.stream); -617 -618 if conn.error.is_some() || (self.is_0rtt && conn.check_0rtt().is_err()) { -619 conn.skip_waking(); -620 return; -621 } -622 -623 // Ignore ClosedStream errors -624 let _ = conn.inner.recv_stream(self.stream).stop(0u32.into()); -625 } -626} -627 -628/// Errors that arise from reading from a stream. -629#[derive(Debug, Error, Clone, PartialEq, Eq)] -630pub enum ReadError { -631 /// The peer abandoned transmitting data on this stream -632 /// -633 /// Carries an application-defined error code. -634 #[error("stream reset by peer: error {0}")] -635 Reset(VarInt), -636 /// The connection was lost -637 #[error("connection lost")] -638 ConnectionLost(#[from] ConnectionError), -639 /// The stream has already been stopped, finished, or reset -640 #[error("closed stream")] -641 ClosedStream, -642 /// This was a 0-RTT stream and the server rejected it -643 /// -644 /// Can only occur on clients for 0-RTT streams, which can be opened using -645 /// [`Connecting::into_0rtt()`]. -646 /// -647 /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt() -648 #[error("0-RTT rejected")] -649 ZeroRttRejected, -650} -651 -652impl From<ResetError> for ReadError { -653 fn from(e: ResetError) -> Self { -654 match e { -655 ResetError::ConnectionLost(e) => Self::ConnectionLost(e), -656 ResetError::ZeroRttRejected => Self::ZeroRttRejected, -657 } -658 } -659} -660 -661impl From<ReadError> for io::Error { -662 fn from(x: ReadError) -> Self { -663 use ReadError::*; -664 let kind = match x { -665 Reset { .. } | ZeroRttRejected => io::ErrorKind::ConnectionReset, -666 ConnectionLost(_) | ClosedStream => io::ErrorKind::NotConnected, -667 }; -668 Self::new(kind, x) -669 } -670} -671 -672/// Errors that arise while waiting for a stream to be reset -673#[derive(Debug, Error, Clone, PartialEq, Eq)] -674pub enum ResetError { -675 /// The connection was lost -676 #[error("connection lost")] -677 ConnectionLost(#[from] ConnectionError), -678 /// This was a 0-RTT stream and the server rejected it -679 /// -680 /// Can only occur on clients for 0-RTT streams, which can be opened using -681 /// [`Connecting::into_0rtt()`]. -682 /// -683 /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt() -684 #[error("0-RTT rejected")] -685 ZeroRttRejected, -686} -687 -688impl From<ResetError> for io::Error { -689 fn from(x: ResetError) -> Self { -690 use ResetError::*; -691 let kind = match x { -692 ZeroRttRejected => io::ErrorKind::ConnectionReset, -693 ConnectionLost(_) => io::ErrorKind::NotConnected, -694 }; -695 Self::new(kind, x) -696 } -697} -698 -699/// Future produced by [`RecvStream::read()`]. -700/// -701/// [`RecvStream::read()`]: crate::RecvStream::read -702struct Read<'a> { -703 stream: &'a mut RecvStream, -704 buf: ReadBuf<'a>, -705} -706 -707impl Future for Read<'_> { -708 type Output = Result<Option<usize>, ReadError>; -709 -710 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { -711 let this = self.get_mut(); -712 ready!(this.stream.poll_read_buf(cx, &mut this.buf))?; -713 match this.buf.filled().len() { -714 0 if this.buf.capacity() != 0 => Poll::Ready(Ok(None)), -715 n => Poll::Ready(Ok(Some(n))), -716 } -717 } -718} -719 -720/// Future produced by [`RecvStream::read_exact()`]. -721/// -722/// [`RecvStream::read_exact()`]: crate::RecvStream::read_exact -723struct ReadExact<'a> { -724 stream: &'a mut RecvStream, -725 buf: ReadBuf<'a>, -726} -727 -728impl Future for ReadExact<'_> { -729 type Output = Result<(), ReadExactError>; -730 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { -731 let this = self.get_mut(); -732 let mut remaining = this.buf.remaining(); -733 while remaining > 0 { -734 ready!(this.stream.poll_read_buf(cx, &mut this.buf))?; -735 let new = this.buf.remaining(); -736 if new == remaining { -737 return Poll::Ready(Err(ReadExactError::FinishedEarly(this.buf.filled().len()))); -738 } -739 remaining = new; -740 } -741 Poll::Ready(Ok(())) -742 } -743} -744 -745/// Errors that arise from reading from a stream. -746#[derive(Debug, Error, Clone, PartialEq, Eq)] -747pub enum ReadExactError { -748 /// The stream finished before all bytes were read -749 #[error("stream finished early ({0} bytes read)")] -750 FinishedEarly(usize), -751 /// A read error occurred -752 #[error(transparent)] -753 ReadError(#[from] ReadError), -754} -755 -756/// Future produced by [`RecvStream::read_chunk()`] or [`UnorderedRecvStream::read_chunk()`]. -757/// -758/// [`RecvStream::read_chunk()`]: crate::RecvStream::read_chunk -759/// [`UnorderedRecvStream::read_chunk()`]: crate::UnorderedRecvStream::read_chunk -760struct ReadChunk<'a> { -761 stream: &'a mut RecvStream, -762 max_length: usize, -763 ordered: bool, -764} -765 -766impl Future for ReadChunk<'_> { -767 type Output = Result<Option<Chunk>, ReadError>; -768 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { -769 let (max_length, ordered) = (self.max_length, self.ordered); -770 self.stream.poll_read_chunk(cx, max_length, ordered) -771 } -772} -773 -774/// Future produced by [`RecvStream::read_many_chunks()`]. -775/// -776/// [`RecvStream::read_many_chunks()`]: crate::RecvStream::read_many_chunks -777struct ReadChunks<'a> { -778 stream: &'a mut RecvStream, -779 bufs: &'a mut [Bytes], -780} -781 -782impl Future for ReadChunks<'_> { -783 type Output = Result<Option<usize>, ReadError>; -784 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { -785 let this = self.get_mut(); -786 this.stream.poll_read_chunks(cx, this.bufs) -787 } -788}
\ No newline at end of file +557 let start = self.start; +558 let mut buffer = vec![0; (self.end - start) as usize]; +559 for (data, offset) in self.read.drain(..) { +560 let offset = (offset - start) as usize; +561 buffer[offset..offset + data.len()].copy_from_slice(&data); +562 } +563 return Poll::Ready(Ok(buffer)); +564 } +565 } +566 } +567 } +568} +569 +570/// Errors from [`RecvStream::read_to_end`] +571#[derive(Debug, Error, Clone, PartialEq, Eq)] +572pub enum ReadToEndError { +573 /// An error occurred during reading +574 #[error("read error: {0}")] +575 Read(#[from] ReadError), +576 /// The stream is larger than the user-supplied limit +577 #[error("stream too long")] +578 TooLong, +579} +580 +581#[cfg(feature = "futures-io")] +582impl futures_io::AsyncRead for RecvStream { +583 fn poll_read( +584 self: Pin<&mut Self>, +585 cx: &mut Context<'_>, +586 buf: &mut [u8], +587 ) -> Poll<io::Result<usize>> { +588 let mut buf = ReadBuf::new(buf); +589 ready!(Self::poll_read_buf(self.get_mut(), cx, &mut buf))?; +590 Poll::Ready(Ok(buf.filled().len())) +591 } +592} +593 +594impl tokio::io::AsyncRead for RecvStream { +595 fn poll_read( +596 self: Pin<&mut Self>, +597 cx: &mut Context<'_>, +598 buf: &mut ReadBuf<'_>, +599 ) -> Poll<io::Result<()>> { +600 ready!(Self::poll_read_buf(self.get_mut(), cx, buf))?; +601 Poll::Ready(Ok(())) +602 } +603} +604 +605impl Drop for RecvStream { +606 fn drop(&mut self) { +607 if self.all_data_read { +608 debug_assert!( +609 !self +610 .conn +611 .lock_without_waking("RecvStream:drop") +612 .blocked_readers +613 .contains_key(&self.stream), +614 "Stream {} should not have a blocked reader when all data read is true", +615 &self.stream +616 ); +617 return; +618 } +619 let mut conn = self.conn.lock_and_wake("RecvStream::drop"); +620 +621 // clean up any previously registered wakers +622 conn.blocked_readers.remove(&self.stream); +623 +624 if conn.error.is_some() || (self.is_0rtt && conn.check_0rtt().is_err()) { +625 conn.skip_waking(); +626 return; +627 } +628 +629 // Ignore ClosedStream errors +630 let _ = conn.inner.recv_stream(self.stream).stop(0u32.into()); +631 } +632} +633 +634/// Errors that arise from reading from a stream. +635#[derive(Debug, Error, Clone, PartialEq, Eq)] +636pub enum ReadError { +637 /// The peer abandoned transmitting data on this stream +638 /// +639 /// Carries an application-defined error code. +640 #[error("stream reset by peer: error {0}")] +641 Reset(VarInt), +642 /// The connection was lost +643 #[error("connection lost")] +644 ConnectionLost(#[from] ConnectionError), +645 /// The stream has already been stopped, finished, or reset +646 #[error("closed stream")] +647 ClosedStream, +648 /// This was a 0-RTT stream and the server rejected it +649 /// +650 /// Can only occur on clients for 0-RTT streams, which can be opened using +651 /// [`Connecting::into_0rtt()`]. +652 /// +653 /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt() +654 #[error("0-RTT rejected")] +655 ZeroRttRejected, +656} +657 +658impl From<ResetError> for ReadError { +659 fn from(e: ResetError) -> Self { +660 match e { +661 ResetError::ConnectionLost(e) => Self::ConnectionLost(e), +662 ResetError::ZeroRttRejected => Self::ZeroRttRejected, +663 } +664 } +665} +666 +667impl From<ReadError> for io::Error { +668 fn from(x: ReadError) -> Self { +669 use ReadError::*; +670 let kind = match x { +671 Reset { .. } | ZeroRttRejected => io::ErrorKind::ConnectionReset, +672 ConnectionLost(_) | ClosedStream => io::ErrorKind::NotConnected, +673 }; +674 Self::new(kind, x) +675 } +676} +677 +678/// Errors that arise while waiting for a stream to be reset +679#[derive(Debug, Error, Clone, PartialEq, Eq)] +680pub enum ResetError { +681 /// The connection was lost +682 #[error("connection lost")] +683 ConnectionLost(#[from] ConnectionError), +684 /// This was a 0-RTT stream and the server rejected it +685 /// +686 /// Can only occur on clients for 0-RTT streams, which can be opened using +687 /// [`Connecting::into_0rtt()`]. +688 /// +689 /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt() +690 #[error("0-RTT rejected")] +691 ZeroRttRejected, +692} +693 +694impl From<ResetError> for io::Error { +695 fn from(x: ResetError) -> Self { +696 use ResetError::*; +697 let kind = match x { +698 ZeroRttRejected => io::ErrorKind::ConnectionReset, +699 ConnectionLost(_) => io::ErrorKind::NotConnected, +700 }; +701 Self::new(kind, x) +702 } +703} +704 +705/// Future produced by [`RecvStream::read()`]. +706/// +707/// [`RecvStream::read()`]: crate::RecvStream::read +708struct Read<'a> { +709 stream: &'a mut RecvStream, +710 buf: ReadBuf<'a>, +711} +712 +713impl Future for Read<'_> { +714 type Output = Result<Option<usize>, ReadError>; +715 +716 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { +717 let this = self.get_mut(); +718 ready!(this.stream.poll_read_buf(cx, &mut this.buf))?; +719 match this.buf.filled().len() { +720 0 if this.buf.capacity() != 0 => Poll::Ready(Ok(None)), +721 n => Poll::Ready(Ok(Some(n))), +722 } +723 } +724} +725 +726/// Future produced by [`RecvStream::read_exact()`]. +727/// +728/// [`RecvStream::read_exact()`]: crate::RecvStream::read_exact +729struct ReadExact<'a> { +730 stream: &'a mut RecvStream, +731 buf: ReadBuf<'a>, +732} +733 +734impl Future for ReadExact<'_> { +735 type Output = Result<(), ReadExactError>; +736 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { +737 let this = self.get_mut(); +738 let mut remaining = this.buf.remaining(); +739 while remaining > 0 { +740 ready!(this.stream.poll_read_buf(cx, &mut this.buf))?; +741 let new = this.buf.remaining(); +742 if new == remaining { +743 return Poll::Ready(Err(ReadExactError::FinishedEarly(this.buf.filled().len()))); +744 } +745 remaining = new; +746 } +747 Poll::Ready(Ok(())) +748 } +749} +750 +751/// Errors that arise from reading from a stream. +752#[derive(Debug, Error, Clone, PartialEq, Eq)] +753pub enum ReadExactError { +754 /// The stream finished before all bytes were read +755 #[error("stream finished early ({0} bytes read)")] +756 FinishedEarly(usize), +757 /// A read error occurred +758 #[error(transparent)] +759 ReadError(#[from] ReadError), +760} +761 +762/// Future produced by [`RecvStream::read_chunk()`] or [`UnorderedRecvStream::read_chunk()`]. +763/// +764/// [`RecvStream::read_chunk()`]: crate::RecvStream::read_chunk +765/// [`UnorderedRecvStream::read_chunk()`]: crate::UnorderedRecvStream::read_chunk +766struct ReadChunk<'a> { +767 stream: &'a mut RecvStream, +768 max_length: usize, +769 ordered: bool, +770} +771 +772impl Future for ReadChunk<'_> { +773 type Output = Result<Option<Chunk>, ReadError>; +774 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { +775 let (max_length, ordered) = (self.max_length, self.ordered); +776 self.stream.poll_read_chunk(cx, max_length, ordered) +777 } +778} +779 +780/// Future produced by [`RecvStream::read_many_chunks()`]. +781/// +782/// [`RecvStream::read_many_chunks()`]: crate::RecvStream::read_many_chunks +783struct ReadChunks<'a> { +784 stream: &'a mut RecvStream, +785 bufs: &'a mut [Bytes], +786} +787 +788impl Future for ReadChunks<'_> { +789 type Output = Result<Option<usize>, ReadError>; +790 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { +791 let this = self.get_mut(); +792 this.stream.poll_read_chunks(cx, this.bufs) +793 } +794} \ No newline at end of file diff --git a/pr/720/docs/src/noq/send_stream.rs.html b/pr/720/docs/src/noq/send_stream.rs.html index 801f7d568..06851a010 100644 --- a/pr/720/docs/src/noq/send_stream.rs.html +++ b/pr/720/docs/src/noq/send_stream.rs.html @@ -248,241 +248,244 @@ 248 /// For a variety of reasons, the peer may not send acknowledgements immediately upon receiving 249 /// data. As such, relying on `stopped` to know when the peer has read a stream to completion 250 /// may introduce more latency than using an application-level response of some sort. -251 pub fn stopped(&self) -> Stopped { -252 let notified = { -253 // Create an `OwnedNotified` to move into the future. By creating it before the first poll, -254 // we make sure that we don't miss any notifications. -255 let mut conn = self.conn.lock_without_waking("SendStream::stopped"); -256 conn.stopped -257 .entry(self.stream) -258 .or_default() -259 .clone() -260 .notified_owned() -261 }; -262 Stopped { -263 conn: self.conn.clone(), -264 stream: self.stream, -265 is_0rtt: self.is_0rtt, -266 notified, -267 } -268 } -269 -270 /// Get the identity of this stream -271 pub fn id(&self) -> StreamId { -272 self.stream -273 } -274 -275 /// Attempt to write bytes from buf into the stream. -276 /// -277 /// On success, returns Poll::Ready(Ok(num_bytes_written)). -278 /// -279 /// If the stream is not ready for writing, the method returns Poll::Pending and arranges -280 /// for the current task (via cx.waker().wake_by_ref()) to receive a notification when the -281 /// stream becomes writable or is closed. -282 pub fn poll_write( -283 self: Pin<&mut Self>, -284 cx: &mut Context<'_>, -285 buf: &[u8], -286 ) -> Poll<Result<usize, WriteError>> { -287 pin!(self.get_mut().write(buf)).as_mut().poll(cx) -288 } -289} -290 -291/// Check if a send stream is stopped. -292/// -293/// Returns `Some` if the stream is stopped or the connection is closed. -294/// Returns `None` if the stream is not stopped. -295fn send_stream_stopped( -296 conn: &mut State, -297 stream: StreamId, -298 is_0rtt: bool, -299) -> Option<Result<Option<VarInt>, StoppedError>> { -300 if is_0rtt && conn.check_0rtt().is_err() { -301 return Some(Err(StoppedError::ZeroRttRejected)); -302 } -303 match conn.inner.send_stream(stream).stopped() { -304 Err(ClosedStream { .. }) => Some(Ok(None)), -305 Ok(Some(error_code)) => Some(Ok(Some(error_code))), -306 Ok(None) => conn.error.clone().map(|error| Err(error.into())), -307 } -308} -309 -310#[cfg(feature = "futures-io")] -311impl futures_io::AsyncWrite for SendStream { -312 fn poll_write( -313 self: Pin<&mut Self>, -314 cx: &mut Context<'_>, -315 buf: &[u8], -316 ) -> Poll<io::Result<usize>> { -317 self.poll_write(cx, buf).map_err(Into::into) -318 } -319 -320 fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { -321 Poll::Ready(Ok(())) -322 } -323 -324 fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { -325 Poll::Ready(self.get_mut().finish().map_err(Into::into)) -326 } -327} -328 -329impl tokio::io::AsyncWrite for SendStream { -330 fn poll_write( -331 self: Pin<&mut Self>, -332 cx: &mut Context<'_>, -333 buf: &[u8], -334 ) -> Poll<io::Result<usize>> { -335 self.poll_write(cx, buf).map_err(Into::into) -336 } -337 -338 fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { -339 Poll::Ready(Ok(())) -340 } -341 -342 fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { -343 Poll::Ready(self.get_mut().finish().map_err(Into::into)) -344 } -345} -346 -347impl Drop for SendStream { -348 fn drop(&mut self) { -349 let mut conn = self.conn.lock_and_wake("SendStream::drop"); -350 -351 // clean up any previously registered wakers -352 conn.blocked_writers.remove(&self.stream); +251 /// +252 /// Clients may wish to await this after finishing a unidirectional 0-RTT stream to reliably +253 /// determine whether the stream was rejected. +254 pub fn stopped(&self) -> Stopped { +255 let notified = { +256 // Create an `OwnedNotified` to move into the future. By creating it before the first poll, +257 // we make sure that we don't miss any notifications. +258 let mut conn = self.conn.lock_without_waking("SendStream::stopped"); +259 conn.stopped +260 .entry(self.stream) +261 .or_default() +262 .clone() +263 .notified_owned() +264 }; +265 Stopped { +266 conn: self.conn.clone(), +267 stream: self.stream, +268 is_0rtt: self.is_0rtt, +269 notified, +270 } +271 } +272 +273 /// Get the identity of this stream +274 pub fn id(&self) -> StreamId { +275 self.stream +276 } +277 +278 /// Attempt to write bytes from buf into the stream. +279 /// +280 /// On success, returns Poll::Ready(Ok(num_bytes_written)). +281 /// +282 /// If the stream is not ready for writing, the method returns Poll::Pending and arranges +283 /// for the current task (via cx.waker().wake_by_ref()) to receive a notification when the +284 /// stream becomes writable or is closed. +285 pub fn poll_write( +286 self: Pin<&mut Self>, +287 cx: &mut Context<'_>, +288 buf: &[u8], +289 ) -> Poll<Result<usize, WriteError>> { +290 pin!(self.get_mut().write(buf)).as_mut().poll(cx) +291 } +292} +293 +294/// Check if a send stream is stopped. +295/// +296/// Returns `Some` if the stream is stopped or the connection is closed. +297/// Returns `None` if the stream is not stopped. +298fn send_stream_stopped( +299 conn: &mut State, +300 stream: StreamId, +301 is_0rtt: bool, +302) -> Option<Result<Option<VarInt>, StoppedError>> { +303 if is_0rtt && conn.check_0rtt().is_err() { +304 return Some(Err(StoppedError::ZeroRttRejected)); +305 } +306 match conn.inner.send_stream(stream).stopped() { +307 Err(ClosedStream { .. }) => Some(Ok(None)), +308 Ok(Some(error_code)) => Some(Ok(Some(error_code))), +309 Ok(None) => conn.error.clone().map(|error| Err(error.into())), +310 } +311} +312 +313#[cfg(feature = "futures-io")] +314impl futures_io::AsyncWrite for SendStream { +315 fn poll_write( +316 self: Pin<&mut Self>, +317 cx: &mut Context<'_>, +318 buf: &[u8], +319 ) -> Poll<io::Result<usize>> { +320 self.poll_write(cx, buf).map_err(Into::into) +321 } +322 +323 fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { +324 Poll::Ready(Ok(())) +325 } +326 +327 fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { +328 Poll::Ready(self.get_mut().finish().map_err(Into::into)) +329 } +330} +331 +332impl tokio::io::AsyncWrite for SendStream { +333 fn poll_write( +334 self: Pin<&mut Self>, +335 cx: &mut Context<'_>, +336 buf: &[u8], +337 ) -> Poll<io::Result<usize>> { +338 self.poll_write(cx, buf).map_err(Into::into) +339 } +340 +341 fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { +342 Poll::Ready(Ok(())) +343 } +344 +345 fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { +346 Poll::Ready(self.get_mut().finish().map_err(Into::into)) +347 } +348} +349 +350impl Drop for SendStream { +351 fn drop(&mut self) { +352 let mut conn = self.conn.lock_and_wake("SendStream::drop"); 353 -354 if conn.error.is_some() || (self.is_0rtt && conn.check_0rtt().is_err()) { -355 conn.skip_waking(); -356 return; -357 } -358 match conn.inner.send_stream(self.stream).finish() { -359 Ok(()) => {} -360 Err(FinishError::Stopped(reason)) => { -361 if conn.inner.send_stream(self.stream).reset(reason).is_err() { -362 conn.skip_waking() -363 } -364 } -365 // Already finished or reset, which is fine. -366 Err(FinishError::ClosedStream) => { -367 conn.skip_waking(); -368 } -369 } -370 } -371} -372 -373/// Errors that arise from writing to a stream -374#[derive(Debug, Error, Clone, PartialEq, Eq)] -375pub enum WriteError { -376 /// The peer is no longer accepting data on this stream -377 /// -378 /// Carries an application-defined error code. -379 #[error("sending stopped by peer: error {0}")] -380 Stopped(VarInt), -381 /// The connection was lost -382 #[error("connection lost")] -383 ConnectionLost(#[from] ConnectionError), -384 /// The stream has already been finished or reset -385 #[error("closed stream")] -386 ClosedStream, -387 /// This was a 0-RTT stream and the server rejected it -388 /// -389 /// Can only occur on clients for 0-RTT streams, which can be opened using -390 /// [`Connecting::into_0rtt()`]. +354 // clean up any previously registered wakers +355 conn.blocked_writers.remove(&self.stream); +356 +357 if conn.error.is_some() || (self.is_0rtt && conn.check_0rtt().is_err()) { +358 conn.skip_waking(); +359 return; +360 } +361 match conn.inner.send_stream(self.stream).finish() { +362 Ok(()) => {} +363 Err(FinishError::Stopped(reason)) => { +364 if conn.inner.send_stream(self.stream).reset(reason).is_err() { +365 conn.skip_waking() +366 } +367 } +368 // Already finished or reset, which is fine. +369 Err(FinishError::ClosedStream) => { +370 conn.skip_waking(); +371 } +372 } +373 } +374} +375 +376/// Errors that arise from writing to a stream +377#[derive(Debug, Error, Clone, PartialEq, Eq)] +378pub enum WriteError { +379 /// The peer is no longer accepting data on this stream +380 /// +381 /// Carries an application-defined error code. +382 #[error("sending stopped by peer: error {0}")] +383 Stopped(VarInt), +384 /// The connection was lost +385 #[error("connection lost")] +386 ConnectionLost(#[from] ConnectionError), +387 /// The stream has already been finished or reset +388 #[error("closed stream")] +389 ClosedStream, +390 /// This was a 0-RTT stream and the server rejected it 391 /// -392 /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt() -393 #[error("0-RTT rejected")] -394 ZeroRttRejected, -395} -396 -397impl From<ClosedStream> for WriteError { -398 #[inline] -399 fn from(_: ClosedStream) -> Self { -400 Self::ClosedStream -401 } -402} -403 -404impl From<StoppedError> for WriteError { -405 fn from(x: StoppedError) -> Self { -406 match x { -407 StoppedError::ConnectionLost(e) => Self::ConnectionLost(e), -408 StoppedError::ZeroRttRejected => Self::ZeroRttRejected, -409 } -410 } -411} -412 -413impl From<WriteError> for io::Error { -414 fn from(x: WriteError) -> Self { -415 use WriteError::*; -416 let kind = match x { -417 Stopped(_) | ZeroRttRejected => io::ErrorKind::ConnectionReset, -418 ConnectionLost(_) | ClosedStream => io::ErrorKind::NotConnected, -419 }; -420 Self::new(kind, x) -421 } -422} -423 -424/// Errors that arise while monitoring for a send stream stop from the peer -425#[derive(Debug, Error, Clone, PartialEq, Eq)] -426pub enum StoppedError { -427 /// The connection was lost -428 #[error("connection lost")] -429 ConnectionLost(#[from] ConnectionError), -430 /// This was a 0-RTT stream and the server rejected it -431 /// -432 /// Can only occur on clients for 0-RTT streams, which can be opened using -433 /// [`Connecting::into_0rtt()`]. +392 /// Can only occur on clients for 0-RTT streams, which can be opened using +393 /// [`Connecting::into_0rtt()`]. +394 /// +395 /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt() +396 #[error("0-RTT rejected")] +397 ZeroRttRejected, +398} +399 +400impl From<ClosedStream> for WriteError { +401 #[inline] +402 fn from(_: ClosedStream) -> Self { +403 Self::ClosedStream +404 } +405} +406 +407impl From<StoppedError> for WriteError { +408 fn from(x: StoppedError) -> Self { +409 match x { +410 StoppedError::ConnectionLost(e) => Self::ConnectionLost(e), +411 StoppedError::ZeroRttRejected => Self::ZeroRttRejected, +412 } +413 } +414} +415 +416impl From<WriteError> for io::Error { +417 fn from(x: WriteError) -> Self { +418 use WriteError::*; +419 let kind = match x { +420 Stopped(_) | ZeroRttRejected => io::ErrorKind::ConnectionReset, +421 ConnectionLost(_) | ClosedStream => io::ErrorKind::NotConnected, +422 }; +423 Self::new(kind, x) +424 } +425} +426 +427/// Errors that arise while monitoring for a send stream stop from the peer +428#[derive(Debug, Error, Clone, PartialEq, Eq)] +429pub enum StoppedError { +430 /// The connection was lost +431 #[error("connection lost")] +432 ConnectionLost(#[from] ConnectionError), +433 /// This was a 0-RTT stream and the server rejected it 434 /// -435 /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt() -436 #[error("0-RTT rejected")] -437 ZeroRttRejected, -438} -439 -440impl From<StoppedError> for io::Error { -441 fn from(x: StoppedError) -> Self { -442 use StoppedError::*; -443 let kind = match x { -444 ZeroRttRejected => io::ErrorKind::ConnectionReset, -445 ConnectionLost(_) => io::ErrorKind::NotConnected, -446 }; -447 Self::new(kind, x) -448 } -449} -450 -451pin_project! { -452 /// Future returned from [`SendStream::stopped`]. -453 #[derive(Debug)] -454 pub struct Stopped { -455 conn: ConnectionRef, -456 stream: StreamId, -457 is_0rtt: bool, -458 #[pin] -459 notified: OwnedNotified, -460 } -461} -462 -463impl Future for Stopped { -464 type Output = Result<Option<VarInt>, StoppedError>; +435 /// Can only occur on clients for 0-RTT streams, which can be opened using +436 /// [`Connecting::into_0rtt()`]. +437 /// +438 /// [`Connecting::into_0rtt()`]: crate::Connecting::into_0rtt() +439 #[error("0-RTT rejected")] +440 ZeroRttRejected, +441} +442 +443impl From<StoppedError> for io::Error { +444 fn from(x: StoppedError) -> Self { +445 use StoppedError::*; +446 let kind = match x { +447 ZeroRttRejected => io::ErrorKind::ConnectionReset, +448 ConnectionLost(_) => io::ErrorKind::NotConnected, +449 }; +450 Self::new(kind, x) +451 } +452} +453 +454pin_project! { +455 /// Future returned from [`SendStream::stopped`]. +456 #[derive(Debug)] +457 pub struct Stopped { +458 conn: ConnectionRef, +459 stream: StreamId, +460 is_0rtt: bool, +461 #[pin] +462 notified: OwnedNotified, +463 } +464} 465 -466 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { -467 let mut this = self.project(); -468 loop { -469 let mut conn = this.conn.lock_without_waking("SendStream::stopped"); -470 // Check if the stream is stopped before polling the notify. This makes sure that -471 // no wakeups are missed. -472 if let Some(output) = send_stream_stopped(&mut conn, *this.stream, *this.is_0rtt) { -473 return Poll::Ready(output); -474 } -475 std::task::ready!(this.notified.as_mut().poll(cx)); -476 } -477 } -478} -479 -480#[cfg(test)] -481mod tests { -482 fn check_is_send_sync<A: Send + Sync>() {} -483 -484 #[allow(dead_code)] -485 fn test_bounds() { -486 check_is_send_sync::<super::Stopped>(); -487 } -488} \ No newline at end of file +466impl Future for Stopped { +467 type Output = Result<Option<VarInt>, StoppedError>; +468 +469 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { +470 let mut this = self.project(); +471 loop { +472 let mut conn = this.conn.lock_without_waking("SendStream::stopped"); +473 // Check if the stream is stopped before polling the notify. This makes sure that +474 // no wakeups are missed. +475 if let Some(output) = send_stream_stopped(&mut conn, *this.stream, *this.is_0rtt) { +476 return Poll::Ready(output); +477 } +478 std::task::ready!(this.notified.as_mut().poll(cx)); +479 } +480 } +481} +482 +483#[cfg(test)] +484mod tests { +485 fn check_is_send_sync<A: Send + Sync>() {} +486 +487 #[allow(dead_code)] +488 fn test_bounds() { +489 check_is_send_sync::<super::Stopped>(); +490 } +491} \ No newline at end of file diff --git a/pr/720/docs/src/noq_proto/congestion/cubic.rs.html b/pr/720/docs/src/noq_proto/congestion/cubic.rs.html index 5a1e6f3b5..28ff57483 100644 --- a/pr/720/docs/src/noq_proto/congestion/cubic.rs.html +++ b/pr/720/docs/src/noq_proto/congestion/cubic.rs.html @@ -163,140 +163,201 @@ 163 } 164 165 // Update the increment and increase cwnd by MSS. -166 self.state.cwnd_inc += cubic_cwnd - self.state.window; -167 -168 // cwnd_inc can be more than 1 MSS in the late stage of max probing. -169 // however RFC9002 §7.3.3 (Congestion Avoidance) limits -170 // the increase of cwnd to 1 max_datagram_size per cwnd acknowledged. -171 if self.state.cwnd_inc >= self.current_mtu { -172 self.state.window += self.current_mtu; -173 self.state.cwnd_inc = 0; -174 } -175 } -176 } -177 -178 fn on_congestion_event( -179 &mut self, -180 now: Instant, -181 sent: Instant, -182 is_persistent_congestion: bool, -183 is_ecn: bool, -184 _lost_bytes: u64, -185 _largest_lost_pn: u64, -186 ) { -187 if self -188 .state -189 .recovery_start_time -190 .map(|recovery_start_time| sent <= recovery_start_time) -191 .unwrap_or(false) -192 { -193 return; -194 } -195 -196 // Save state in case this event ends up being spurious -197 if !is_ecn { -198 self.pre_congestion_state = Some(self.state.clone()); -199 } -200 -201 self.state.recovery_start_time = Some(now); -202 -203 // Fast convergence -204 if (self.state.window as f64) < self.state.w_max { -205 self.state.w_max = self.state.window as f64 * (1.0 + BETA_CUBIC) / 2.0; -206 } else { -207 self.state.w_max = self.state.window as f64; -208 } +166 // Keep release builds from wrapping the retained credit. +167 self.state.cwnd_inc = self +168 .state +169 .cwnd_inc +170 .saturating_add(cubic_cwnd - self.state.window); +171 +172 // cwnd_inc can be more than 1 MSS in the late stage of max probing. +173 // however RFC9002 §7.3.3 (Congestion Avoidance) limits +174 // the increase of cwnd to 1 max_datagram_size per cwnd acknowledged. +175 // Keep the excess credit for later ACKs instead of discarding it. +176 // https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.3 +177 if self.state.cwnd_inc >= self.current_mtu { +178 self.state.window += self.current_mtu; +179 self.state.cwnd_inc -= self.current_mtu; +180 } +181 } +182 } +183 +184 fn on_congestion_event( +185 &mut self, +186 now: Instant, +187 sent: Instant, +188 is_persistent_congestion: bool, +189 is_ecn: bool, +190 _lost_bytes: u64, +191 _largest_lost_pn: u64, +192 ) { +193 if self +194 .state +195 .recovery_start_time +196 .map(|recovery_start_time| sent <= recovery_start_time) +197 .unwrap_or(false) +198 { +199 return; +200 } +201 +202 // Save state in case this event ends up being spurious +203 if !is_ecn { +204 self.pre_congestion_state = Some(self.state.clone()); +205 } +206 +207 self.state.recovery_start_time = Some(now); +208 let window = self.state.window as f64; 209 -210 self.state.ssthresh = cmp::max( -211 (self.state.w_max * BETA_CUBIC) as u64, -212 self.minimum_window(), -213 ); -214 self.state.window = self.state.ssthresh; -215 self.state.k = self.state.cubic_k(self.current_mtu); -216 -217 self.state.cwnd_inc = (self.state.cwnd_inc as f64 * BETA_CUBIC) as u64; -218 -219 if is_persistent_congestion { -220 self.state.recovery_start_time = None; -221 self.state.w_max = self.state.window as f64; -222 -223 // 4.7 Timeout - reduce ssthresh based on BETA_CUBIC -224 self.state.ssthresh = cmp::max( -225 (self.state.window as f64 * BETA_CUBIC) as u64, -226 self.minimum_window(), -227 ); -228 -229 self.state.cwnd_inc = 0; -230 -231 self.state.window = self.minimum_window(); -232 } -233 } -234 -235 fn on_spurious_congestion_event(&mut self) { -236 if let Some(prior_state) = self.pre_congestion_state.take() -237 && self.state.window < prior_state.window -238 { -239 self.state = prior_state; -240 } -241 } -242 -243 fn on_mtu_update(&mut self, new_mtu: u16) { -244 self.current_mtu = new_mtu as u64; -245 self.state.window = self.state.window.max(self.minimum_window()); -246 } -247 -248 fn window(&self) -> u64 { -249 self.state.window -250 } -251 -252 fn metrics(&self) -> super::ControllerMetrics { -253 super::ControllerMetrics { -254 congestion_window: self.window(), -255 ssthresh: Some(self.state.ssthresh), -256 pacing_rate: None, -257 send_quantum: None, -258 } -259 } -260 -261 fn clone_box(&self) -> Box<dyn Controller> { -262 Box::new(self.clone()) -263 } -264 -265 fn initial_window(&self) -> u64 { -266 self.config.initial_window -267 } -268 -269 fn into_any(self: Box<Self>) -> Box<dyn Any> { -270 self -271 } -272} -273 -274/// Configuration for the `Cubic` congestion controller -275#[derive(Debug, Clone)] -276pub struct CubicConfig { -277 initial_window: u64, -278} -279 -280impl CubicConfig { -281 /// Default limit on the amount of outstanding data in bytes. -282 /// -283 /// Recommended value: `min(10 * max_datagram_size, max(2 * max_datagram_size, 14720))` -284 pub fn initial_window(&mut self, value: u64) -> &mut Self { -285 self.initial_window = value; -286 self -287 } -288} -289 -290impl Default for CubicConfig { -291 fn default() -> Self { -292 Self { -293 initial_window: 14720.clamp(2 * BASE_DATAGRAM_SIZE, 10 * BASE_DATAGRAM_SIZE), -294 } -295 } -296} -297 -298impl ControllerFactory for CubicConfig { -299 fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller> { -300 Box::new(Cubic::new(self, now, current_mtu)) -301 } -302} \ No newline at end of file +210 // Fast convergence lowers W_max first; the 0.7 loss reduction still +211 // applies to the old window, not to that already-reduced W_max. +212 // https://www.rfc-editor.org/rfc/rfc9438.html#section-4.7 +213 // https://www.rfc-editor.org/rfc/rfc9438.html#section-4.6 +214 if window < self.state.w_max { +215 self.state.w_max = window * (1.0 + BETA_CUBIC) / 2.0; +216 } else { +217 self.state.w_max = window; +218 } +219 +220 self.state.ssthresh = cmp::max((window * BETA_CUBIC) as u64, self.minimum_window()); +221 self.state.window = self.state.ssthresh; +222 self.state.k = self.state.cubic_k(self.current_mtu); +223 +224 self.state.cwnd_inc = (self.state.cwnd_inc as f64 * BETA_CUBIC) as u64; +225 +226 if is_persistent_congestion { +227 self.state.recovery_start_time = None; +228 self.state.w_max = self.state.window as f64; +229 +230 // 4.7 Timeout - reduce ssthresh based on BETA_CUBIC +231 self.state.ssthresh = cmp::max( +232 (self.state.window as f64 * BETA_CUBIC) as u64, +233 self.minimum_window(), +234 ); +235 +236 self.state.cwnd_inc = 0; +237 +238 self.state.window = self.minimum_window(); +239 } +240 } +241 +242 fn on_spurious_congestion_event(&mut self) { +243 if let Some(prior_state) = self.pre_congestion_state.take() +244 && self.state.window < prior_state.window +245 { +246 self.state = prior_state; +247 } +248 } +249 +250 fn on_mtu_update(&mut self, new_mtu: u16) { +251 self.current_mtu = new_mtu as u64; +252 self.state.window = self.state.window.max(self.minimum_window()); +253 } +254 +255 fn window(&self) -> u64 { +256 self.state.window +257 } +258 +259 fn metrics(&self) -> super::ControllerMetrics { +260 super::ControllerMetrics { +261 congestion_window: self.window(), +262 ssthresh: Some(self.state.ssthresh), +263 pacing_rate: None, +264 send_quantum: None, +265 } +266 } +267 +268 fn clone_box(&self) -> Box<dyn Controller> { +269 Box::new(self.clone()) +270 } +271 +272 fn initial_window(&self) -> u64 { +273 self.config.initial_window +274 } +275 +276 fn into_any(self: Box<Self>) -> Box<dyn Any> { +277 self +278 } +279} +280 +281/// Configuration for the `Cubic` congestion controller +282#[derive(Debug, Clone)] +283pub struct CubicConfig { +284 initial_window: u64, +285} +286 +287impl CubicConfig { +288 /// Default limit on the amount of outstanding data in bytes. +289 /// +290 /// Recommended value: `min(10 * max_datagram_size, max(2 * max_datagram_size, 14720))` +291 pub fn initial_window(&mut self, value: u64) -> &mut Self { +292 self.initial_window = value; +293 self +294 } +295} +296 +297impl Default for CubicConfig { +298 fn default() -> Self { +299 Self { +300 initial_window: 14720.clamp(2 * BASE_DATAGRAM_SIZE, 10 * BASE_DATAGRAM_SIZE), +301 } +302 } +303} +304 +305impl ControllerFactory for CubicConfig { +306 fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller> { +307 Box::new(Cubic::new(self, now, current_mtu)) +308 } +309} +310#[cfg(test)] +311mod tests { +312 use super::*; +313 +314 #[test] +315 fn fast_convergence_reduces_w_max_without_double_reducing_window() { +316 let now = Instant::now(); +317 let config = Arc::new(CubicConfig::default()); +318 let mut cubic = Cubic::new(config, now, BASE_DATAGRAM_SIZE as u16); +319 let window = 8 * BASE_DATAGRAM_SIZE; +320 +321 cubic.state.window = window; +322 cubic.state.ssthresh = window; +323 cubic.state.w_max = 12.0 * BASE_DATAGRAM_SIZE as f64; +324 +325 cubic.on_congestion_event(now, now + Duration::from_millis(1), false, false, 0, 100); +326 +327 assert_eq!(cubic.state.w_max, window as f64 * (1.0 + BETA_CUBIC) / 2.0); +328 assert_eq!(cubic.state.ssthresh, (window as f64 * BETA_CUBIC) as u64); +329 assert_eq!(cubic.state.window, cubic.state.ssthresh); +330 } +331 +332 #[test] +333 fn congestion_avoidance_preserves_excess_cwnd_increment() { +334 let now = Instant::now(); +335 let rtt = RttEstimator::new(Duration::from_millis(100)); +336 let config = Arc::new(CubicConfig::default()); +337 let mut cubic = Cubic::new(config, now, BASE_DATAGRAM_SIZE as u16); +338 +339 // Put CUBIC directly into congestion avoidance. +340 cubic.state.ssthresh = cubic.state.window; +341 cubic.state.recovery_start_time = Some(now); +342 cubic.state.w_max = cubic.state.window as f64; +343 +344 // Simulate accumulated credit from earlier ACKs. One ACK may only grow +345 // the window by one MTU, but the extra credit must remain for later ACKs. +346 cubic.state.cwnd_inc = 2 * BASE_DATAGRAM_SIZE + 1; +347 let window = cubic.state.window; +348 +349 cubic.on_ack( +350 now, +351 now + Duration::from_millis(1), +352 BASE_DATAGRAM_SIZE, +353 0, +354 false, +355 &rtt, +356 ); +357 +358 // Before this fix, the window grew by one MTU and the remainder was +359 // reset to zero. +360 assert_eq!(cubic.state.window, window + BASE_DATAGRAM_SIZE); +361 assert_eq!(cubic.state.cwnd_inc, BASE_DATAGRAM_SIZE + 1); +362 } +363} \ No newline at end of file diff --git a/pr/720/docs/src/noq_proto/connection/mod.rs.html b/pr/720/docs/src/noq_proto/connection/mod.rs.html index 15fecbea2..ce67f472b 100644 --- a/pr/720/docs/src/noq_proto/connection/mod.rs.html +++ b/pr/720/docs/src/noq_proto/connection/mod.rs.html @@ -1245,7 +1245,7 @@ 1245 .inc_total_sent(transmit.len() as u64); 1246 1247 self.path_stats -1248 .for_path(path_id) +1248 .get_mut(path_id) 1249 .udp_tx 1250 .on_sent(transmit.num_datagrams() as u64, transmit.len()); 1251 @@ -1634,7 +1634,7 @@ 1634 &mut self.spaces[space_id], 1635 is_multipath_negotiated, 1636 &mut builder, -1637 &mut self.path_stats.for_path(path_id).frame_tx, +1637 &mut self.path_stats.get_mut(path_id).frame_tx, 1638 self.crypto_state.has_keys(space_id.encryption_level()), 1639 ); 1640 } @@ -1650,7 +1650,7 @@ 1650 builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND, 1651 "ACKs should leave space for ConnectionClose" 1652 ); -1653 let stats = &mut self.path_stats.for_path(path_id).frame_tx; +1653 let stats = &mut self.path_stats.get_mut(path_id).frame_tx; 1654 if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() { 1655 let max_frame_size = builder.frame_space_remaining(); 1656 let close: Close = match self.state.as_type() { @@ -1808,19 +1808,19 @@ 1808 1809 // We implement MTU probes as ping packets padded up to the probe size 1810 trace!(?probe_size, "writing MTUD probe"); -1811 builder.write_frame(frame::Ping, &mut self.path_stats.for_path(path_id).frame_tx); +1811 builder.write_frame(frame::Ping, &mut self.path_stats.get_mut(path_id).frame_tx); 1812 1813 // If supported by the peer, we want no delays to the probe's ACK 1814 if self.peer_supports_ack_frequency() { 1815 builder.write_frame( 1816 frame::ImmediateAck, -1817 &mut self.path_stats.for_path(path_id).frame_tx, +1817 &mut self.path_stats.get_mut(path_id).frame_tx, 1818 ); 1819 } 1820 1821 builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size)); 1822 -1823 self.path_stats.for_path(path_id).sent_plpmtud_probes += 1; +1823 self.path_stats.get_mut(path_id).sent_plpmtud_probes += 1; 1824 1825 Some(self.build_transmit(path_id, transmit)) 1826 } @@ -1986,7 +1986,7 @@ 1986 // this is sent first. 1987 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, self)?; 1988 let challenge = frame::PathChallenge(token); -1989 let stats = &mut self.path_stats.for_path(path_id).frame_tx; +1989 let stats = &mut self.path_stats.get_mut(path_id).frame_tx; 1990 builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path")); 1991 1992 // An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame @@ -1997,7 +1997,7 @@ 1997 1998 builder.finish(self, now); 1999 self.path_stats -2000 .for_path(path_id) +2000 .get_mut(path_id) 2001 .udp_tx 2002 .on_sent(1, buf.len()); 2003 @@ -2040,7 +2040,7 @@ 2040 buf.start_new_datagram(); 2041 2042 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, buf, self)?; -2043 let stats = &mut self.path_stats.for_path(path_id).frame_tx; +2043 let stats = &mut self.path_stats.get_mut(path_id).frame_tx; 2044 builder.write_frame_with_log_msg(frame, stats, Some("(off-path)")); 2045 2046 // PATH_CHALLENGE (off-path) @@ -2055,7 +2055,7 @@ 2055 && self.n0_nat_traversal.client_side().is_ok() 2056 { 2057 let token = self.rng.random(); -2058 let stats = &mut self.path_stats.for_path(path_id).frame_tx; +2058 let stats = &mut self.path_stats.get_mut(path_id).frame_tx; 2059 builder.write_frame(frame::PathChallenge(token), stats); 2060 let ip_port = (network_path.remote.ip(), network_path.remote.port()); 2061 self.n0_nat_traversal.mark_probe_sent(ip_port, token); @@ -2067,7 +2067,7 @@ 2067 builder.finish(self, now); 2068 2069 let size = buf.len(); -2070 self.path_stats.for_path(path_id).udp_tx.on_sent(1, size); +2070 self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size); 2071 2072 trace!( 2073 dst = ?network_path.remote, @@ -2119,7 +2119,7 @@ 2119 buf.start_new_datagram(); 2120 2121 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, &mut buf, self)?; -2122 let stats = &mut self.path_stats.for_path(path_id).frame_tx; +2122 let stats = &mut self.path_stats.get_mut(path_id).frame_tx; 2123 builder.write_frame_with_log_msg(frame, stats, Some("(nat-traversal)")); 2124 // Off-path: not tracked in congestion control. The packet is sent to a 2125 // different destination than path_id's network path. @@ -2129,7 +2129,7 @@ 2129 self.n0_nat_traversal.mark_probe_sent(remote, token); 2130 2131 let size = buf.len(); -2132 self.path_stats.for_path(path_id).udp_tx.on_sent(1, size); +2132 self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size); 2133 2134 trace!(dst = ?remote, len = buf.len(), "sending off-path NAT probe"); 2135 Some(Transmit { @@ -2218,7 +2218,7 @@ 2218 // anti-amplification blocked for it previously. 2219 .unwrap_or(false); 2220 -2221 let rx = &mut self.path_stats.for_path(path_id).udp_rx; +2221 let rx = &mut self.path_stats.get_mut(path_id).udp_rx; 2222 rx.datagrams += 1; 2223 rx.bytes += first_decode.len() as u64; 2224 let data_len = first_decode.len(); @@ -2233,7 +2233,7 @@ 2233 } 2234 2235 if let Some(data) = remaining { -2236 self.path_stats.for_path(path_id).udp_rx.bytes += data.len() as u64; +2236 self.path_stats.get_mut(path_id).udp_rx.bytes += data.len() as u64; 2237 self.handle_coalesced(now, network_path, path_id, ecn, data); 2238 } 2239 @@ -2298,2547 +2298,2547 @@ 2298 return true; 2299 } 2300 -2301 let peer_may_probe = self.peer_may_probe(); -2302 let local_ip_may_migrate = self.local_ip_may_migrate(); -2303 -2304 // If this packet could initiate a migration and we're a client or a server that -2305 // forbids migration, drop the datagram. This could be relaxed to heuristically -2306 // permit NAT-rebinding-like migration. -2307 if let Some(known_path) = self.path_mut(path_id) { -2308 if network_path.remote != known_path.network_path.remote && !peer_may_probe { -2309 trace!( -2310 %path_id, -2311 %network_path, -2312 %known_path.network_path, -2313 "discarding packet from unrecognized peer" -2314 ); -2315 return true; -2316 } -2317 -2318 if known_path.network_path.local_ip.is_some() -2319 && network_path.local_ip.is_some() -2320 && known_path.network_path.local_ip != network_path.local_ip -2321 && !local_ip_may_migrate -2322 { -2323 trace!( -2324 %path_id, -2325 %network_path, -2326 %known_path.network_path, -2327 "discarding packet sent to incorrect interface" -2328 ); -2329 return true; -2330 } -2331 } -2332 false -2333 } -2334 -2335 /// Whether the peer may probe new paths. -2336 /// -2337 /// RFC9000 §9 and QNT both have probing packets which may arrive from new paths. This -2338 /// indicates whether these are allowed or not. This is a strict superset from -2339 /// [`Self::peer_may_migrate`]: every network path that may be migrated to, may also -2340 /// be probed. But e.g. servers may not migrate, but can be allowed to probe. -2341 // TODO(flub): In RFC9000 the server is allowed to send off-path probing packets -2342 // once the client has been probing such a 4-tuple. These probes are currently -2343 // not yet recognised and will end up being discarded because of this. -2344 // See https://github.com/n0-computer/noq/issues/607. -2345 fn peer_may_probe(&self) -> bool { -2346 match &self.side { -2347 ConnectionSide::Client { .. } => { -2348 if let Some(hs) = self.state.as_handshake() { -2349 hs.allow_server_migration -2350 } else { -2351 self.n0_nat_traversal.is_negotiated() && self.is_handshake_confirmed() -2352 } -2353 } -2354 ConnectionSide::Server { server_config } => { -2355 self.is_handshake_confirmed() -2356 && (server_config.migration || self.n0_nat_traversal.is_negotiated()) -2357 } -2358 } -2359 } -2360 -2361 /// Whether the peer's remote address may migrate. -2362 /// -2363 /// In RFC9000 only the client may migrate. -2364 /// -2365 /// QUIC relies on stable endpoints during the handshake. So other than the server's -2366 /// preferred_address transport parameter no side may migrate before the handshake is -2367 /// completed. -2368 /// -2369 /// It is noteworthy that for iroh we allow server migrations during the handshake when -2370 /// [`state::Handshake::allow_server_migration`] is enabled, but that is handled earlier -2371 /// in [`Self::handle_packet`] and without probing the current and previous paths. -2372 fn peer_may_migrate(&self) -> bool { -2373 match &self.side { -2374 ConnectionSide::Server { server_config } => { -2375 server_config.migration && self.is_handshake_confirmed() -2376 } -2377 ConnectionSide::Client { .. } => false, -2378 } -2379 } -2380 -2381 /// Whether our local IP address is allowed to change with new incoming packets. -2382 /// -2383 /// Incoming packets show us the local IP address we received a packet on, which could -2384 /// be different from what we thought due to e.g. NAT rebinding or moving from mobile -2385 /// data to WiFi without being notified of the network change. -2386 /// -2387 /// This is only allowed to happen after the handshake is confirmed and when we are the -2388 /// client. Unless QNT is negotiated in which case the server is also allowed to -2389 /// migrate. -2390 /// -2391 /// Be aware that probing packets, which do not exist in Multipath without QNT, are -2392 /// exempt from this. -2393 fn local_ip_may_migrate(&self) -> bool { -2394 (self.side.is_client() || self.n0_nat_traversal.is_negotiated()) -2395 && self.is_handshake_confirmed() -2396 } -2397 /// Process timer expirations -2398 /// -2399 /// Executes protocol logic, potentially preparing signals (including application `Event`s, -2400 /// `EndpointEvent`s and outgoing datagrams) that should be extracted through the relevant -2401 /// methods. -2402 /// -2403 /// It is most efficient to call this immediately after the system clock reaches the latest -2404 /// `Instant` that was output by `poll_timeout`; however spurious extra calls will simply -2405 /// no-op and therefore are safe. -2406 pub fn handle_timeout(&mut self, now: Instant) { -2407 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) { -2408 let span = match timer { -2409 Timer::Conn(timer) => trace_span!("timeout", scope = "conn", ?timer), -2410 Timer::PerPath(path_id, timer) => { -2411 trace_span!("timer_fired", scope="path", %path_id, ?timer) -2412 } -2413 }; -2414 let _guard = span.enter(); -2415 trace!("timeout"); -2416 match timer { -2417 Timer::Conn(timer) => match timer { -2418 ConnTimer::Close => { -2419 let was_draining = self.state.move_to_drained(None); -2420 if !was_draining { -2421 self.endpoint_events.push_back(EndpointEventInner::Draining); -2422 } -2423 // move_to_drained checks that we weren't in drained before. -2424 // Adding events to endpoint_events is only legal if `Drained` was never queued before. -2425 self.endpoint_events.push_back(EndpointEventInner::Drained); -2426 } -2427 ConnTimer::Idle => { -2428 self.kill(ConnectionError::TimedOut); -2429 } -2430 ConnTimer::KeepAlive => { -2431 self.ping(); -2432 } -2433 ConnTimer::KeyDiscard => { -2434 self.crypto_state.discard_temporary_keys(); -2435 } -2436 ConnTimer::PushNewCid => { -2437 while let Some((path_id, when)) = self.next_cid_retirement() { -2438 if when > now { -2439 break; -2440 } -2441 match self.local_cid_state.get_mut(&path_id) { -2442 None => error!(%path_id, "No local CID state for path"), -2443 Some(cid_state) => { -2444 // Update `retire_prior_to` field in NEW_CONNECTION_ID frame -2445 let num_new_cid = cid_state.on_cid_timeout().into(); -2446 if !self.state.is_closed() { -2447 trace!( -2448 "push a new CID to peer RETIRE_PRIOR_TO field {}", -2449 cid_state.retire_prior_to() -2450 ); -2451 self.endpoint_events.push_back( -2452 EndpointEventInner::NeedIdentifiers( -2453 path_id, -2454 now, -2455 num_new_cid, -2456 ), -2457 ); -2458 } -2459 } -2460 } -2461 } -2462 } -2463 ConnTimer::NoAvailablePath => { -2464 // Grace period expired: all paths were abandoned and no new path -2465 // was opened. Close the connection. There are no paths left to -2466 // send CONNECTION_CLOSE on, so this is a silent close. -2467 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4-8 -2468 if self.state.is_closed() || self.state.is_drained() { -2469 // Connection already closing/drained (e.g. application called -2470 // close() before the grace timer fired). Nothing to do. -2471 error!("no viable path timer fired, but connection already closing"); -2472 } else { -2473 trace!("no viable path grace period expired, closing connection"); -2474 let err = TransportError::NO_VIABLE_PATH( -2475 "last path abandoned, no new path opened", -2476 ); -2477 self.close_common(); -2478 self.set_close_timer(now); -2479 self.connection_close_pending = true; -2480 self.state.move_to_closed(err); -2481 } -2482 } -2483 ConnTimer::NatTraversalProbeRetry => { -2484 self.n0_nat_traversal.queue_retries(self.is_ipv6()); -2485 if let Some(delay) = -2486 self.n0_nat_traversal.retry_delay(self.config.initial_rtt) -2487 { -2488 self.timers.set( -2489 Timer::Conn(ConnTimer::NatTraversalProbeRetry), -2490 now + delay, -2491 self.qlog.with_time(now), -2492 ); -2493 trace!("re-queued NAT probes"); -2494 } else { -2495 trace!("no more NAT probes remaining"); -2496 } -2497 } -2498 }, -2499 Timer::PerPath(path_id, timer) => { -2500 match timer { -2501 PathTimer::PathIdle => { -2502 if let Err(err) = -2503 self.close_path_inner(now, path_id, PathAbandonReason::TimedOut) -2504 { -2505 warn!(?err, "failed closing path"); -2506 } -2507 } -2508 -2509 PathTimer::PathKeepAlive => { -2510 self.ping_path(path_id).ok(); -2511 } -2512 PathTimer::LossDetection => { -2513 self.on_loss_detection_timeout(now, path_id); -2514 if let Some(path) = self.paths.get_mut(&path_id) { -2515 self.qlog -2516 .emit_recovery_metrics(path_id, &mut path.data, now); -2517 } else { -2518 error!("LossDetection fired for unknown path"); -2519 } -2520 } -2521 PathTimer::PathValidationFailed => { -2522 let Some(path) = self.paths.get_mut(&path_id) else { -2523 continue; -2524 }; -2525 self.timers.stop( -2526 Timer::PerPath(path_id, PathTimer::PathChallengeLost), -2527 self.qlog.with_time(now), -2528 ); -2529 debug!("path migration validation failed"); -2530 if let Some((_, prev)) = path.prev.take() { -2531 path.data = prev; -2532 } -2533 path.data.reset_on_path_challenges(); -2534 } -2535 PathTimer::PathChallengeLost => { -2536 let Some(path) = self.paths.get_mut(&path_id) else { -2537 continue; -2538 }; -2539 trace!(?path.data.lost_challenge_count, "path challenge deemed lost"); -2540 path.data.pending_challenge = true; -2541 path.data.lost_challenge_count += 1; -2542 } -2543 PathTimer::AbandonFromValidation => { -2544 let Some(path) = self.paths.get_mut(&path_id) else { -2545 continue; -2546 }; -2547 path.data.reset_on_path_challenges(); -2548 self.timers.stop( -2549 Timer::PerPath(path_id, PathTimer::PathChallengeLost), -2550 self.qlog.with_time(now), -2551 ); -2552 debug!("new path validation failed"); -2553 if let Err(err) = self.close_path_inner( -2554 now, -2555 path_id, -2556 PathAbandonReason::ValidationFailed, -2557 ) { -2558 warn!(?err, "failed closing path"); -2559 } -2560 } -2561 PathTimer::Pacing => {} -2562 PathTimer::MaxAckDelay => { -2563 // This timer is only armed in the Data space -2564 self.spaces[SpaceId::Data] -2565 .for_path(path_id) -2566 .pending_acks -2567 .on_max_ack_delay_timeout() -2568 } -2569 PathTimer::PathDrained => { -2570 // The path was abandoned and 3*PTO has expired since. Clean up all -2571 // remaining state and install stateless reset token. -2572 self.timers.stop_per_path(path_id, self.qlog.with_time(now)); -2573 if let Some(local_cid_state) = self.local_cid_state.remove(&path_id) { -2574 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events. All timers should be cleared in drained connections. -2575 let (min_seq, max_seq) = local_cid_state.active_seq(); -2576 for seq in min_seq..=max_seq { -2577 self.endpoint_events.push_back( -2578 EndpointEventInner::RetireConnectionId( -2579 now, path_id, seq, false, -2580 ), -2581 ); -2582 } -2583 } -2584 self.discard_path(path_id, now); -2585 } -2586 } -2587 } -2588 } -2589 } -2590 } -2591 -2592 /// Close a connection immediately -2593 /// -2594 /// This does not ensure delivery of outstanding data. It is the application's responsibility to -2595 /// call this only when all important communications have been completed, e.g. by calling -2596 /// [`SendStream::finish`] on outstanding streams and waiting for the corresponding -2597 /// [`StreamEvent::Finished`] event. -2598 /// -2599 /// If [`Streams::send_streams`] returns 0, all outstanding stream data has been -2600 /// delivered. There may still be data from the peer that has not been received. -2601 /// -2602 /// [`StreamEvent::Finished`]: crate::StreamEvent::Finished -2603 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) { -2604 self.close_inner( -2605 now, -2606 Close::Application(frame::ApplicationClose { error_code, reason }), -2607 ) -2608 } -2609 -2610 /// Close the connection immediately, initiated by an API call. -2611 /// -2612 /// This will not produce a [`ConnectionLost`] event propagated by the -2613 /// [`Connection::poll`] call, because the API call already propagated the error to the -2614 /// user. -2615 /// -2616 /// Not to be used when entering immediate close due to an internal state change based -2617 /// on an event. See [`State::move_to_closed_local`] for details. -2618 /// -2619 /// This initiates immediate close from -2620 /// <https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2>, moving to the closed -2621 /// state. -2622 /// -2623 /// [`ConnectionLost`]: crate::Event::ConnectionLost -2624 /// [`Connection::poll`]: super::Connection::poll -2625 fn close_inner(&mut self, now: Instant, reason: Close) { -2626 let was_closed = self.state.is_closed(); -2627 if !was_closed { -2628 self.close_common(); -2629 self.set_close_timer(now); -2630 self.connection_close_pending = true; -2631 self.state.move_to_closed_local(reason); -2632 } -2633 } -2634 -2635 /// Control datagrams -2636 pub fn datagrams(&mut self) -> Datagrams<'_> { -2637 Datagrams { conn: self } -2638 } -2639 -2640 /// Returns connection statistics -2641 pub fn stats(&mut self) -> ConnectionStats { -2642 let mut stats = self.partial_stats.clone(); -2643 -2644 for path_stats in self.path_stats.iter_stats() { -2645 // Self::path_stats() computes the path rtt, cwnd and current_mtu on access -2646 // because they are not simple counters. When computing the connection stats we -2647 // can skip that effort since those fields are not used in the `impl -2648 // Add<PathStats> for ConnectionStats`. -2649 stats += *path_stats; -2650 } -2651 -2652 stats -2653 } -2654 -2655 /// Returns path statistics -2656 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> { -2657 let path = self.paths.get(&path_id)?; -2658 let stats = self.path_stats.for_path(path_id); -2659 stats.rtt = path.data.rtt.get(); -2660 stats.cwnd = path.data.congestion.window(); -2661 stats.current_mtu = path.data.mtud.current_mtu(); -2662 Some(*stats) -2663 } -2664 -2665 /// Ping the remote endpoint -2666 /// -2667 /// Causes an ACK-eliciting packet to be transmitted on the connection. -2668 pub fn ping(&mut self) { -2669 // TODO(flub): This is very brute-force: it pings *all* the paths. Instead it would -2670 // be nice if we could only send a single packet for this. -2671 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() { -2672 path_data.pending_ping = true; -2673 } -2674 } -2675 -2676 /// Ping the remote endpoint over a specific path -2677 /// -2678 /// Causes an ACK-eliciting packet to be transmitted on the path. -2679 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> { -2680 let path_data = self.spaces[self.highest_space] -2681 .number_spaces -2682 .get_mut(&path) -2683 .ok_or(ClosedPath { _private: () })?; -2684 path_data.pending_ping = true; -2685 Ok(()) -2686 } -2687 -2688 /// Update traffic keys spontaneously -2689 /// -2690 /// This can be useful for testing key updates, as they otherwise only happen infrequently. -2691 pub fn force_key_update(&mut self) { -2692 if !self.state.is_established() { -2693 debug!("ignoring forced key update in illegal state"); -2694 return; -2695 } -2696 if self.crypto_state.prev_crypto.is_some() { -2697 // We already just updated, or are currently updating, the keys. Concurrent key updates -2698 // are illegal. -2699 debug!("ignoring redundant forced key update"); +2301 if !self.paths.contains_key(&path_id) && self.abandoned_paths.contains(&path_id) { +2302 trace!(%path_id, "discarding packet for discarded path"); +2303 return true; +2304 } +2305 +2306 let peer_may_probe = self.peer_may_probe(); +2307 let local_ip_may_migrate = self.local_ip_may_migrate(); +2308 +2309 // If this packet could initiate a migration and we're a client or a server that +2310 // forbids migration, drop the datagram. This could be relaxed to heuristically +2311 // permit NAT-rebinding-like migration. +2312 if let Some(known_path) = self.path_mut(path_id) { +2313 if network_path.remote != known_path.network_path.remote && !peer_may_probe { +2314 trace!( +2315 %path_id, +2316 %network_path, +2317 %known_path.network_path, +2318 "discarding packet from unrecognized peer" +2319 ); +2320 return true; +2321 } +2322 +2323 if known_path.network_path.local_ip.is_some() +2324 && network_path.local_ip.is_some() +2325 && known_path.network_path.local_ip != network_path.local_ip +2326 && !local_ip_may_migrate +2327 { +2328 trace!( +2329 %path_id, +2330 %network_path, +2331 %known_path.network_path, +2332 "discarding packet sent to incorrect interface" +2333 ); +2334 return true; +2335 } +2336 } +2337 false +2338 } +2339 +2340 /// Whether the peer may probe new paths. +2341 /// +2342 /// RFC9000 §9 and QNT both have probing packets which may arrive from new paths. This +2343 /// indicates whether these are allowed or not. This is a strict superset from +2344 /// [`Self::peer_may_migrate`]: every network path that may be migrated to, may also +2345 /// be probed. But e.g. servers may not migrate, but can be allowed to probe. +2346 // TODO(flub): In RFC9000 the server is allowed to send off-path probing packets +2347 // once the client has been probing such a 4-tuple. These probes are currently +2348 // not yet recognised and will end up being discarded because of this. +2349 // See https://github.com/n0-computer/noq/issues/607. +2350 fn peer_may_probe(&self) -> bool { +2351 match &self.side { +2352 ConnectionSide::Client { .. } => { +2353 if let Some(hs) = self.state.as_handshake() { +2354 hs.allow_server_migration +2355 } else { +2356 self.n0_nat_traversal.is_negotiated() && self.is_handshake_confirmed() +2357 } +2358 } +2359 ConnectionSide::Server { server_config } => { +2360 self.is_handshake_confirmed() +2361 && (server_config.migration || self.n0_nat_traversal.is_negotiated()) +2362 } +2363 } +2364 } +2365 +2366 /// Whether the peer's remote address may migrate. +2367 /// +2368 /// In RFC9000 only the client may migrate. +2369 /// +2370 /// QUIC relies on stable endpoints during the handshake. So other than the server's +2371 /// preferred_address transport parameter no side may migrate before the handshake is +2372 /// completed. +2373 /// +2374 /// It is noteworthy that for iroh we allow server migrations during the handshake when +2375 /// [`state::Handshake::allow_server_migration`] is enabled, but that is handled earlier +2376 /// in [`Self::handle_packet`] and without probing the current and previous paths. +2377 fn peer_may_migrate(&self) -> bool { +2378 match &self.side { +2379 ConnectionSide::Server { server_config } => { +2380 server_config.migration && self.is_handshake_confirmed() +2381 } +2382 ConnectionSide::Client { .. } => false, +2383 } +2384 } +2385 +2386 /// Whether our local IP address is allowed to change with new incoming packets. +2387 /// +2388 /// Incoming packets show us the local IP address we received a packet on, which could +2389 /// be different from what we thought due to e.g. NAT rebinding or moving from mobile +2390 /// data to WiFi without being notified of the network change. +2391 /// +2392 /// This is only allowed to happen after the handshake is confirmed and when we are the +2393 /// client. Unless QNT is negotiated in which case the server is also allowed to +2394 /// migrate. +2395 /// +2396 /// Be aware that probing packets, which do not exist in Multipath without QNT, are +2397 /// exempt from this. +2398 fn local_ip_may_migrate(&self) -> bool { +2399 (self.side.is_client() || self.n0_nat_traversal.is_negotiated()) +2400 && self.is_handshake_confirmed() +2401 } +2402 /// Process timer expirations +2403 /// +2404 /// Executes protocol logic, potentially preparing signals (including application `Event`s, +2405 /// `EndpointEvent`s and outgoing datagrams) that should be extracted through the relevant +2406 /// methods. +2407 /// +2408 /// It is most efficient to call this immediately after the system clock reaches the latest +2409 /// `Instant` that was output by `poll_timeout`; however spurious extra calls will simply +2410 /// no-op and therefore are safe. +2411 pub fn handle_timeout(&mut self, now: Instant) { +2412 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) { +2413 let span = match timer { +2414 Timer::Conn(timer) => trace_span!("timeout", scope = "conn", ?timer), +2415 Timer::PerPath(path_id, timer) => { +2416 trace_span!("timer_fired", scope="path", %path_id, ?timer) +2417 } +2418 }; +2419 let _guard = span.enter(); +2420 trace!("timeout"); +2421 match timer { +2422 Timer::Conn(timer) => match timer { +2423 ConnTimer::Close => { +2424 let was_draining = self.state.move_to_drained(None); +2425 if !was_draining { +2426 self.endpoint_events.push_back(EndpointEventInner::Draining); +2427 } +2428 // move_to_drained checks that we weren't in drained before. +2429 // Adding events to endpoint_events is only legal if `Drained` was never queued before. +2430 self.endpoint_events.push_back(EndpointEventInner::Drained); +2431 } +2432 ConnTimer::Idle => { +2433 self.kill(ConnectionError::TimedOut); +2434 } +2435 ConnTimer::KeepAlive => { +2436 self.ping(); +2437 } +2438 ConnTimer::KeyDiscard => { +2439 self.crypto_state.discard_temporary_keys(); +2440 } +2441 ConnTimer::PushNewCid => { +2442 while let Some((path_id, when)) = self.next_cid_retirement() { +2443 if when > now { +2444 break; +2445 } +2446 match self.local_cid_state.get_mut(&path_id) { +2447 None => error!(%path_id, "No local CID state for path"), +2448 Some(cid_state) => { +2449 // Update `retire_prior_to` field in NEW_CONNECTION_ID frame +2450 let num_new_cid = cid_state.on_cid_timeout().into(); +2451 if !self.state.is_closed() { +2452 trace!( +2453 "push a new CID to peer RETIRE_PRIOR_TO field {}", +2454 cid_state.retire_prior_to() +2455 ); +2456 self.endpoint_events.push_back( +2457 EndpointEventInner::NeedIdentifiers( +2458 path_id, +2459 now, +2460 num_new_cid, +2461 ), +2462 ); +2463 } +2464 } +2465 } +2466 } +2467 } +2468 ConnTimer::NoAvailablePath => { +2469 // Grace period expired: all paths were abandoned and no new path +2470 // was opened. Close the connection. There are no paths left to +2471 // send CONNECTION_CLOSE on, so this is a silent close. +2472 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4-8 +2473 if self.state.is_closed() || self.state.is_drained() { +2474 // Connection already closing/drained (e.g. application called +2475 // close() before the grace timer fired). Nothing to do. +2476 error!("no viable path timer fired, but connection already closing"); +2477 } else { +2478 trace!("no viable path grace period expired, closing connection"); +2479 let err = TransportError::NO_VIABLE_PATH( +2480 "last path abandoned, no new path opened", +2481 ); +2482 self.close_common(); +2483 self.set_close_timer(now); +2484 self.connection_close_pending = true; +2485 self.state.move_to_closed(err); +2486 } +2487 } +2488 ConnTimer::NatTraversalProbeRetry => { +2489 self.n0_nat_traversal.queue_retries(self.is_ipv6()); +2490 if let Some(delay) = +2491 self.n0_nat_traversal.retry_delay(self.config.initial_rtt) +2492 { +2493 self.timers.set( +2494 Timer::Conn(ConnTimer::NatTraversalProbeRetry), +2495 now + delay, +2496 self.qlog.with_time(now), +2497 ); +2498 trace!("re-queued NAT probes"); +2499 } else { +2500 trace!("no more NAT probes remaining"); +2501 } +2502 } +2503 }, +2504 Timer::PerPath(path_id, timer) => { +2505 match timer { +2506 PathTimer::PathIdle => { +2507 if let Err(err) = +2508 self.close_path_inner(now, path_id, PathAbandonReason::TimedOut) +2509 { +2510 warn!(?err, "failed closing path"); +2511 } +2512 } +2513 +2514 PathTimer::PathKeepAlive => { +2515 self.ping_path(path_id).ok(); +2516 } +2517 PathTimer::LossDetection => { +2518 self.on_loss_detection_timeout(now, path_id); +2519 if let Some(path) = self.paths.get_mut(&path_id) { +2520 self.qlog +2521 .emit_recovery_metrics(path_id, &mut path.data, now); +2522 } else { +2523 error!("LossDetection fired for unknown path"); +2524 } +2525 } +2526 PathTimer::PathValidationFailed => { +2527 let Some(path) = self.paths.get_mut(&path_id) else { +2528 continue; +2529 }; +2530 self.timers.stop( +2531 Timer::PerPath(path_id, PathTimer::PathChallengeLost), +2532 self.qlog.with_time(now), +2533 ); +2534 debug!("path migration validation failed"); +2535 path.data.reset_on_path_challenges(); +2536 if let Some((_, prev)) = path.prev.take() { +2537 path.data = prev; +2538 self.set_loss_detection_timer(now, path_id); +2539 } +2540 } +2541 PathTimer::PathChallengeLost => { +2542 let Some(path) = self.paths.get_mut(&path_id) else { +2543 continue; +2544 }; +2545 trace!(?path.data.lost_challenge_count, "path challenge deemed lost"); +2546 path.data.pending_challenge = true; +2547 path.data.lost_challenge_count += 1; +2548 } +2549 PathTimer::AbandonFromValidation => { +2550 let Some(path) = self.paths.get_mut(&path_id) else { +2551 continue; +2552 }; +2553 path.data.reset_on_path_challenges(); +2554 self.timers.stop( +2555 Timer::PerPath(path_id, PathTimer::PathChallengeLost), +2556 self.qlog.with_time(now), +2557 ); +2558 debug!("new path validation failed"); +2559 if let Err(err) = self.close_path_inner( +2560 now, +2561 path_id, +2562 PathAbandonReason::ValidationFailed, +2563 ) { +2564 warn!(?err, "failed closing path"); +2565 } +2566 } +2567 PathTimer::Pacing => {} +2568 PathTimer::MaxAckDelay => { +2569 // This timer is only armed in the Data space +2570 self.spaces[SpaceId::Data] +2571 .for_path(path_id) +2572 .pending_acks +2573 .on_max_ack_delay_timeout() +2574 } +2575 PathTimer::PathDrained => { +2576 // The path was abandoned and 3*PTO has expired since. Clean up all +2577 // remaining state and install stateless reset token. +2578 self.timers.stop_per_path(path_id, self.qlog.with_time(now)); +2579 if let Some(local_cid_state) = self.local_cid_state.remove(&path_id) { +2580 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events. All timers should be cleared in drained connections. +2581 let (min_seq, max_seq) = local_cid_state.active_seq(); +2582 for seq in min_seq..=max_seq { +2583 self.endpoint_events.push_back( +2584 EndpointEventInner::RetireConnectionId( +2585 now, path_id, seq, false, +2586 ), +2587 ); +2588 } +2589 } +2590 self.discard_path(path_id, now); +2591 } +2592 } +2593 } +2594 } +2595 } +2596 } +2597 +2598 /// Close a connection immediately +2599 /// +2600 /// This does not ensure delivery of outstanding data. It is the application's responsibility to +2601 /// call this only when all important communications have been completed, e.g. by calling +2602 /// [`SendStream::finish`] on outstanding streams and waiting for the corresponding +2603 /// [`StreamEvent::Finished`] event. +2604 /// +2605 /// If [`Streams::send_streams`] returns 0, all outstanding stream data has been +2606 /// delivered. There may still be data from the peer that has not been received. +2607 /// +2608 /// [`StreamEvent::Finished`]: crate::StreamEvent::Finished +2609 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) { +2610 self.close_inner( +2611 now, +2612 Close::Application(frame::ApplicationClose { error_code, reason }), +2613 ) +2614 } +2615 +2616 /// Close the connection immediately, initiated by an API call. +2617 /// +2618 /// This will not produce a [`ConnectionLost`] event propagated by the +2619 /// [`Connection::poll`] call, because the API call already propagated the error to the +2620 /// user. +2621 /// +2622 /// Not to be used when entering immediate close due to an internal state change based +2623 /// on an event. See [`State::move_to_closed_local`] for details. +2624 /// +2625 /// This initiates immediate close from +2626 /// <https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2>, moving to the closed +2627 /// state. +2628 /// +2629 /// [`ConnectionLost`]: crate::Event::ConnectionLost +2630 /// [`Connection::poll`]: super::Connection::poll +2631 fn close_inner(&mut self, now: Instant, reason: Close) { +2632 let was_closed = self.state.is_closed(); +2633 if !was_closed { +2634 self.close_common(); +2635 self.set_close_timer(now); +2636 self.connection_close_pending = true; +2637 self.state.move_to_closed_local(reason); +2638 } +2639 } +2640 +2641 /// Control datagrams +2642 pub fn datagrams(&mut self) -> Datagrams<'_> { +2643 Datagrams { conn: self } +2644 } +2645 +2646 /// Returns connection statistics +2647 pub fn stats(&mut self) -> ConnectionStats { +2648 let mut stats = self.partial_stats.clone(); +2649 +2650 for path_stats in self.path_stats.iter_stats() { +2651 // Self::path_stats() computes the path rtt, cwnd and current_mtu on access +2652 // because they are not simple counters. When computing the connection stats we +2653 // can skip that effort since those fields are not used in the `impl +2654 // Add<PathStats> for ConnectionStats`. +2655 stats += *path_stats; +2656 } +2657 +2658 stats +2659 } +2660 +2661 /// Returns path statistics +2662 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> { +2663 let path = self.paths.get(&path_id)?; +2664 let mut stats = self.path_stats.get(path_id).unwrap_or_default(); +2665 stats.rtt = path.data.rtt.get(); +2666 stats.cwnd = path.data.congestion.window(); +2667 stats.current_mtu = path.data.mtud.current_mtu(); +2668 Some(stats) +2669 } +2670 +2671 /// Ping the remote endpoint +2672 /// +2673 /// Causes an ACK-eliciting packet to be transmitted on the connection. +2674 pub fn ping(&mut self) { +2675 // TODO(flub): This is very brute-force: it pings *all* the paths. Instead it would +2676 // be nice if we could only send a single packet for this. +2677 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() { +2678 path_data.pending_ping = true; +2679 } +2680 } +2681 +2682 /// Ping the remote endpoint over a specific path +2683 /// +2684 /// Causes an ACK-eliciting packet to be transmitted on the path. +2685 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> { +2686 let path_data = self.spaces[self.highest_space] +2687 .number_spaces +2688 .get_mut(&path) +2689 .ok_or(ClosedPath { _private: () })?; +2690 path_data.pending_ping = true; +2691 Ok(()) +2692 } +2693 +2694 /// Update traffic keys spontaneously +2695 /// +2696 /// This can be useful for testing key updates, as they otherwise only happen infrequently. +2697 pub fn force_key_update(&mut self) { +2698 if !self.state.is_established() { +2699 debug!("ignoring forced key update in illegal state"); 2700 return; 2701 } -2702 self.crypto_state.update_keys(None, false); -2703 } -2704 -2705 /// Get a session reference -2706 pub fn crypto_session(&self) -> &dyn crypto::Session { -2707 self.crypto_state.session.as_ref() -2708 } -2709 -2710 /// Whether the connection is in the process of being established -2711 /// -2712 /// If this returns `false`, the connection may be either established or closed, signaled by the -2713 /// emission of a [`Connected`](Event::Connected) or [`ConnectionLost`](Event::ConnectionLost) -2714 /// event respectively. Note that locally-initiated closes via [`close()`](Self::close) do not -2715 /// emit a `ConnectionLost` event. -2716 /// -2717 /// For an established connection this essentially means the handshake is **completed**, -2718 /// but not necessarily yet confirmed. -2719 pub fn is_handshaking(&self) -> bool { -2720 self.state.is_handshake() -2721 } -2722 -2723 /// Whether the connection is closed -2724 /// -2725 /// Closed connections cannot transport any further data. A connection becomes closed when -2726 /// either peer application intentionally closes it, or when either transport layer detects an -2727 /// error such as a time-out or certificate validation failure. -2728 /// -2729 /// A [`ConnectionLost`](Event::ConnectionLost) event is emitted with details when the -2730 /// connection is closed by the peer or due to an error. When the local application closes -2731 /// the connection via [`close()`](Self::close), no `ConnectionLost` event is emitted; -2732 /// instead, pending operations fail with [`ConnectionError::LocallyClosed`]. -2733 pub fn is_closed(&self) -> bool { -2734 self.state.is_closed() -2735 } -2736 -2737 /// Whether there is no longer any need to keep the connection around -2738 /// -2739 /// Closed connections become drained after a brief timeout to absorb any remaining in-flight -2740 /// packets from the peer. All drained connections have been closed. -2741 pub fn is_drained(&self) -> bool { -2742 self.state.is_drained() -2743 } -2744 -2745 /// For clients, if the peer accepted the 0-RTT data packets -2746 /// -2747 /// The value is meaningless until after the handshake completes. -2748 pub fn accepted_0rtt(&self) -> bool { -2749 self.crypto_state.accepted_0rtt -2750 } -2751 -2752 /// Whether 0-RTT is/was possible during the handshake -2753 pub fn has_0rtt(&self) -> bool { -2754 self.crypto_state.zero_rtt_enabled -2755 } -2756 -2757 /// Whether there are any pending retransmits -2758 pub fn has_pending_retransmits(&self) -> bool { -2759 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams) -2760 } -2761 -2762 /// Look up whether we're the client or server of this Connection -2763 pub fn side(&self) -> Side { -2764 self.side.side() -2765 } -2766 -2767 /// Get the address observed by the remote over the given path -2768 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> { -2769 self.path(path_id) -2770 .map(|path_data| { -2771 path_data -2772 .last_observed_addr_report -2773 .as_ref() -2774 .map(|observed| observed.socket_addr()) -2775 }) -2776 .ok_or(ClosedPath { _private: () }) -2777 } -2778 -2779 /// Current best estimate of this connection's latency (round-trip-time) -2780 pub fn rtt(&self, path_id: PathId) -> Option<Duration> { -2781 self.path(path_id).map(|d| d.rtt.get()) -2782 } -2783 -2784 /// Current state of this connection's congestion controller, for debugging purposes -2785 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> { -2786 self.path(path_id).map(|d| d.congestion.as_ref()) -2787 } -2788 -2789 /// Modify the number of remotely initiated streams that may be concurrently open -2790 /// -2791 /// No streams may be opened by the peer unless fewer than `count` are already open. Large -2792 /// `count`s increase both minimum and worst-case memory consumption. -2793 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) { -2794 self.streams.set_max_concurrent(dir, count); -2795 // If the limit was reduced, then a flow control update previously deemed insignificant may -2796 // now be significant. -2797 let pending = &mut self.spaces[SpaceId::Data].pending; -2798 self.streams.queue_max_stream_id(pending); -2799 } -2800 -2801 /// Modify the number of open paths allowed when multipath is enabled -2802 /// -2803 /// When reducing the number of concurrent paths this will only affect delaying sending -2804 /// new MAX_PATH_ID frames until fewer than this number of paths are possible. To -2805 /// actively reduce paths they must be closed using [`Connection::close_path`], which -2806 /// can also be used to close not-yet-opened paths. -2807 /// -2808 /// If multipath is not negotiated (see the [`TransportConfig`]) this can not enable -2809 /// multipath and will fail. -2810 pub fn set_max_concurrent_paths( -2811 &mut self, -2812 now: Instant, -2813 count: NonZeroU32, -2814 ) -> Result<(), MultipathNotNegotiated> { -2815 if !self.is_multipath_negotiated() { -2816 return Err(MultipathNotNegotiated { _private: () }); -2817 } -2818 self.max_concurrent_paths = count; -2819 -2820 let in_use_count = self -2821 .local_max_path_id -2822 .next() -2823 .saturating_sub(self.abandoned_paths.len()) -2824 .as_u32(); -2825 let extra_needed = count.get().saturating_sub(in_use_count); -2826 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed); -2827 -2828 self.set_max_path_id(now, new_max_path_id); -2829 -2830 Ok(()) -2831 } -2832 -2833 /// If needed, issues a new MAX_PATH_ID frame and new CIDs for any newly allowed paths -2834 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) { -2835 if max_path_id <= self.local_max_path_id { -2836 return; -2837 } +2702 if self.crypto_state.prev_crypto.is_some() { +2703 // We already just updated, or are currently updating, the keys. Concurrent key updates +2704 // are illegal. +2705 debug!("ignoring redundant forced key update"); +2706 return; +2707 } +2708 self.crypto_state.update_keys(None, false); +2709 } +2710 +2711 /// Get a session reference +2712 pub fn crypto_session(&self) -> &dyn crypto::Session { +2713 self.crypto_state.session.as_ref() +2714 } +2715 +2716 /// Whether the connection is in the process of being established +2717 /// +2718 /// If this returns `false`, the connection may be either established or closed, signaled by the +2719 /// emission of a [`Connected`](Event::Connected) or [`ConnectionLost`](Event::ConnectionLost) +2720 /// event respectively. Note that locally-initiated closes via [`close()`](Self::close) do not +2721 /// emit a `ConnectionLost` event. +2722 /// +2723 /// For an established connection this essentially means the handshake is **completed**, +2724 /// but not necessarily yet confirmed. +2725 pub fn is_handshaking(&self) -> bool { +2726 self.state.is_handshake() +2727 } +2728 +2729 /// Whether the connection is closed +2730 /// +2731 /// Closed connections cannot transport any further data. A connection becomes closed when +2732 /// either peer application intentionally closes it, or when either transport layer detects an +2733 /// error such as a time-out or certificate validation failure. +2734 /// +2735 /// A [`ConnectionLost`](Event::ConnectionLost) event is emitted with details when the +2736 /// connection is closed by the peer or due to an error. When the local application closes +2737 /// the connection via [`close()`](Self::close), no `ConnectionLost` event is emitted; +2738 /// instead, pending operations fail with [`ConnectionError::LocallyClosed`]. +2739 pub fn is_closed(&self) -> bool { +2740 self.state.is_closed() +2741 } +2742 +2743 /// Whether there is no longer any need to keep the connection around +2744 /// +2745 /// Closed connections become drained after a brief timeout to absorb any remaining in-flight +2746 /// packets from the peer. All drained connections have been closed. +2747 pub fn is_drained(&self) -> bool { +2748 self.state.is_drained() +2749 } +2750 +2751 /// For clients, if the peer accepted the 0-RTT data packets +2752 /// +2753 /// The value is meaningless until after the handshake completes. +2754 pub fn accepted_0rtt(&self) -> bool { +2755 self.crypto_state.accepted_0rtt +2756 } +2757 +2758 /// Whether 0-RTT is/was possible during the handshake +2759 pub fn has_0rtt(&self) -> bool { +2760 self.crypto_state.zero_rtt_enabled +2761 } +2762 +2763 /// Whether there are any pending retransmits +2764 pub fn has_pending_retransmits(&self) -> bool { +2765 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams) +2766 } +2767 +2768 /// Look up whether we're the client or server of this Connection +2769 pub fn side(&self) -> Side { +2770 self.side.side() +2771 } +2772 +2773 /// Get the address observed by the remote over the given path +2774 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> { +2775 self.path(path_id) +2776 .map(|path_data| { +2777 path_data +2778 .last_observed_addr_report +2779 .as_ref() +2780 .map(|observed| observed.socket_addr()) +2781 }) +2782 .ok_or(ClosedPath { _private: () }) +2783 } +2784 +2785 /// Current best estimate of this connection's latency (round-trip-time) +2786 pub fn rtt(&self, path_id: PathId) -> Option<Duration> { +2787 self.path(path_id).map(|d| d.rtt.get()) +2788 } +2789 +2790 /// Current state of this connection's congestion controller, for debugging purposes +2791 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> { +2792 self.path(path_id).map(|d| d.congestion.as_ref()) +2793 } +2794 +2795 /// Modify the number of remotely initiated streams that may be concurrently open +2796 /// +2797 /// No streams may be opened by the peer unless fewer than `count` are already open. Large +2798 /// `count`s increase both minimum and worst-case memory consumption. +2799 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) { +2800 self.streams.set_max_concurrent(dir, count); +2801 // If the limit was reduced, then a flow control update previously deemed insignificant may +2802 // now be significant. +2803 let pending = &mut self.spaces[SpaceId::Data].pending; +2804 self.streams.queue_max_stream_id(pending); +2805 } +2806 +2807 /// Modify the number of open paths allowed when multipath is enabled +2808 /// +2809 /// When reducing the number of concurrent paths this will only affect delaying sending +2810 /// new MAX_PATH_ID frames until fewer than this number of paths are possible. To +2811 /// actively reduce paths they must be closed using [`Connection::close_path`], which +2812 /// can also be used to close not-yet-opened paths. +2813 /// +2814 /// If multipath is not negotiated (see the [`TransportConfig`]) this can not enable +2815 /// multipath and will fail. +2816 pub fn set_max_concurrent_paths( +2817 &mut self, +2818 now: Instant, +2819 count: NonZeroU32, +2820 ) -> Result<(), MultipathNotNegotiated> { +2821 if !self.is_multipath_negotiated() { +2822 return Err(MultipathNotNegotiated { _private: () }); +2823 } +2824 self.max_concurrent_paths = count; +2825 +2826 let in_use_count = self +2827 .local_max_path_id +2828 .next() +2829 .saturating_sub(self.abandoned_paths.len()) +2830 .as_u32(); +2831 let extra_needed = count.get().saturating_sub(in_use_count); +2832 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed); +2833 +2834 self.set_max_path_id(now, new_max_path_id); +2835 +2836 Ok(()) +2837 } 2838 -2839 self.local_max_path_id = max_path_id; -2840 self.spaces[SpaceId::Data].pending.max_path_id = true; -2841 -2842 self.issue_first_path_cids(now); -2843 } +2839 /// If needed, issues a new MAX_PATH_ID frame and new CIDs for any newly allowed paths +2840 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) { +2841 if max_path_id <= self.local_max_path_id { +2842 return; +2843 } 2844 -2845 /// Current number of remotely initiated streams that may be concurrently open -2846 /// -2847 /// If the target for this limit is reduced using [`set_max_concurrent_streams`](Self::set_max_concurrent_streams), -2848 /// it will not change immediately, even if fewer streams are open. Instead, it will -2849 /// decrement by one for each time a remotely initiated stream of matching directionality is closed. -2850 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 { -2851 self.streams.max_concurrent(dir) -2852 } -2853 -2854 /// See [`TransportConfig::send_window()`] -2855 pub fn set_send_window(&mut self, send_window: u64) { -2856 self.streams.set_send_window(send_window); -2857 } -2858 -2859 /// See [`TransportConfig::receive_window()`] -2860 pub fn set_receive_window(&mut self, receive_window: VarInt) { -2861 if self.streams.set_receive_window(receive_window) { -2862 self.spaces[SpaceId::Data].pending.max_data = true; -2863 } -2864 } -2865 -2866 /// Whether the Multipath for QUIC extension is enabled. -2867 /// -2868 /// Multipath is only enabled after the handshake is completed and if it was enabled by both -2869 /// peers. -2870 pub fn is_multipath_negotiated(&self) -> bool { -2871 !self.is_handshaking() -2872 && self.config.max_concurrent_multipath_paths.is_some() -2873 && self.peer_params.initial_max_path_id.is_some() -2874 } -2875 -2876 fn on_ack_received( -2877 &mut self, -2878 now: Instant, -2879 space: SpaceId, -2880 ack: frame::Ack, -2881 ) -> Result<(), TransportError> { -2882 // All ACKs are referencing path 0 -2883 let path = PathId::ZERO; -2884 self.inner_on_ack_received(now, space, path, ack) -2885 } -2886 -2887 fn on_path_ack_received( -2888 &mut self, -2889 now: Instant, -2890 space: SpaceId, -2891 path_ack: frame::PathAck, -2892 ) -> Result<(), TransportError> { -2893 let (ack, path) = path_ack.into_ack(); -2894 self.inner_on_ack_received(now, space, path, ack) -2895 } -2896 -2897 /// Handles an ACK frame acknowledging packets sent on *path*. -2898 fn inner_on_ack_received( -2899 &mut self, -2900 now: Instant, -2901 space: SpaceId, -2902 path: PathId, -2903 ack: frame::Ack, -2904 ) -> Result<(), TransportError> { -2905 if !self.spaces[space].number_spaces.contains_key(&path) { -2906 if self.abandoned_paths.contains(&path) { -2907 // See also -2908 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4.3-3 -2909 // > When an endpoint finally deletes all state associated with the path [...] -2910 // > PATH_ACK frames received with an abandoned path ID are silently ignored, -2911 // > as specified in Section 4. -2912 trace!("silently ignoring PATH_ACK on discarded path"); -2913 return Ok(()); -2914 } else { -2915 return Err(TransportError::PROTOCOL_VIOLATION( -2916 "received PATH_ACK with path ID never used", -2917 )); -2918 } -2919 } -2920 if ack.largest >= self.spaces[space].for_path(path).next_packet_number { -2921 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked")); -2922 } -2923 // `Some(pn)` if this ACK raised `largest_acked_packet_pn`. -2924 let new_largest_pn = { -2925 let space = &mut self.spaces[space].for_path(path); -2926 if space -2927 .largest_acked_packet_pn -2928 .is_none_or(|pn| ack.largest > pn) -2929 { -2930 space.largest_acked_packet_pn = Some(ack.largest); -2931 if let Some(info) = space.sent_packets.get(ack.largest) { -2932 // This should always succeed, but a misbehaving peer might ACK a packet we -2933 // haven't sent. At worst, that will result in us spuriously reducing the -2934 // congestion window. -2935 space.largest_acked_packet_send_time = info.time_sent; -2936 } -2937 Some(ack.largest) -2938 } else { -2939 None -2940 } -2941 }; -2942 -2943 if self.detect_spurious_loss(&ack, space, path) { -2944 self.path_stats.for_path(path).spurious_congestion_events += 1; -2945 self.path_data_mut(path) -2946 .congestion -2947 .on_spurious_congestion_event(); -2948 } -2949 -2950 // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks. -2951 let mut newly_acked: ArrayRangeSet = ArrayRangeSet::new(); -2952 for range in ack.iter() { -2953 self.spaces[space].for_path(path).check_ack(range.clone())?; -2954 for (pn, _) in self.spaces[space] -2955 .for_path(path) -2956 .sent_packets -2957 .iter_range(range) -2958 { -2959 newly_acked.insert_one(pn); -2960 } -2961 } -2962 -2963 if newly_acked.is_empty() { -2964 return Ok(()); -2965 } -2966 -2967 let mut ack_eliciting_acked = false; -2968 for packet in newly_acked.elts() { -2969 if let Some(info) = self.spaces[space].for_path(path).take(packet) { -2970 for (acked_path_id, acked_pn) in info.largest_acked.iter() { -2971 // Assume ACKs for all packets below the largest acknowledged in -2972 // `packet` have been received. This can cause the peer to spuriously -2973 // retransmit if some of our earlier ACKs were lost, but allows for -2974 // simpler state tracking. See discussion at -2975 // https://www.rfc-editor.org/rfc/rfc9000.html#name-limiting-ranges-by-tracking -2976 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) { -2977 pns.pending_acks.subtract_below(*acked_pn); -2978 } -2979 } -2980 ack_eliciting_acked |= info.ack_eliciting; -2981 -2982 // Notify MTU discovery that a packet was acked, because it might be an MTU probe -2983 let path_data = self.path_data_mut(path); -2984 let mtu_updated = path_data.mtud.on_acked(space.kind(), packet, info.size); -2985 if mtu_updated { -2986 path_data -2987 .congestion -2988 .on_mtu_update(path_data.mtud.current_mtu()); -2989 } -2990 -2991 // Notify ack frequency that a packet was acked, because it might contain an ACK_FREQUENCY frame -2992 self.ack_frequency.on_acked(path, packet); -2993 -2994 self.on_packet_acked(now, path, packet, info); -2995 } -2996 } -2997 -2998 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet_pn; -2999 let path_data = self.path_data_mut(path); -3000 let app_limited = path_data.app_limited; -3001 let in_flight = path_data.in_flight.bytes; -3002 -3003 path_data -3004 .congestion -3005 .on_end_acks(now, in_flight, app_limited, largest_ackd); -3006 -3007 if new_largest_pn.is_some() && ack_eliciting_acked { -3008 let ack_delay = if space != SpaceId::Data { -3009 Duration::from_micros(0) -3010 } else { -3011 cmp::min( -3012 self.ack_frequency.peer_max_ack_delay, -3013 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0), -3014 ) -3015 }; -3016 let rtt = now.saturating_duration_since( -3017 self.spaces[space] -3018 .for_path(path) -3019 .largest_acked_packet_send_time, -3020 ); -3021 -3022 let next_pn = self.spaces[space].for_path(path).next_packet_number; -3023 let path_data = self.path_data_mut(path); -3024 // TODO(@divma): should be a method of path, should be contained in a single place -3025 path_data.rtt.update(ack_delay, rtt); -3026 if path_data.first_packet_after_rtt_sample.is_none() { -3027 path_data.first_packet_after_rtt_sample = Some((space.kind(), next_pn)); -3028 } -3029 } -3030 -3031 // Must be called before crypto/pto_count are clobbered -3032 self.detect_lost_packets(now, space, path, true); -3033 -3034 // If the peer did not complete the handshake address validation the ACK could be -3035 // spoofed, e.g. in the Initial space. Setting the pto_count back to 0 removes the -3036 // exponential backoff from the PTO timer and would result in too many tail-loss -3037 // probes being sent. -3038 if self.peer_completed_handshake_address_validation() { -3039 self.path_data_mut(path).pto_count = 0; -3040 } -3041 -3042 // Explicit congestion notification -3043 // TODO(@divma): this code is a good example of logic that should be contained in a single -3044 // place but it's split between the path data and the packet number space data, we should -3045 // find a way to make this work without two lookups -3046 if self.path_data(path).sending_ecn { -3047 if let Some(ecn) = ack.ecn { -3048 // We only examine ECN counters from ACKs that we are certain we received in transmit -3049 // order, allowing us to compute an increase in ECN counts to compare against the number -3050 // of newly acked packets that remains well-defined in the presence of arbitrary packet -3051 // reordering. -3052 if let Some(largest_sent_pn) = new_largest_pn { -3053 let sent = self.spaces[space] -3054 .for_path(path) -3055 .largest_acked_packet_send_time; -3056 self.process_ecn( -3057 now, -3058 space, -3059 path, -3060 newly_acked.range_count() as u64, -3061 ecn, -3062 sent, -3063 largest_sent_pn, -3064 ); -3065 } -3066 } else { -3067 // We always start out sending ECN, so any ack that doesn't acknowledge it disables it. -3068 debug!("ECN not acknowledged by peer"); -3069 self.path_data_mut(path).sending_ecn = false; -3070 } -3071 } -3072 -3073 self.set_loss_detection_timer(now, path); -3074 Ok(()) -3075 } -3076 -3077 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool { -3078 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets; -3079 -3080 if lost_packets.is_empty() { -3081 return false; -3082 } -3083 -3084 for range in ack.iter() { -3085 let spurious_losses: Vec<u64> = lost_packets -3086 .iter_range(range.clone()) -3087 .map(|(pn, _info)| pn) -3088 .collect(); +2845 self.local_max_path_id = max_path_id; +2846 self.spaces[SpaceId::Data].pending.max_path_id = true; +2847 +2848 self.issue_first_path_cids(now); +2849 } +2850 +2851 /// Current number of remotely initiated streams that may be concurrently open +2852 /// +2853 /// If the target for this limit is reduced using [`set_max_concurrent_streams`](Self::set_max_concurrent_streams), +2854 /// it will not change immediately, even if fewer streams are open. Instead, it will +2855 /// decrement by one for each time a remotely initiated stream of matching directionality is closed. +2856 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 { +2857 self.streams.max_concurrent(dir) +2858 } +2859 +2860 /// See [`TransportConfig::send_window()`] +2861 pub fn set_send_window(&mut self, send_window: u64) { +2862 self.streams.set_send_window(send_window); +2863 } +2864 +2865 /// See [`TransportConfig::receive_window()`] +2866 pub fn set_receive_window(&mut self, receive_window: VarInt) { +2867 if self.streams.set_receive_window(receive_window) { +2868 self.spaces[SpaceId::Data].pending.max_data = true; +2869 } +2870 } +2871 +2872 /// Whether the Multipath for QUIC extension is enabled. +2873 /// +2874 /// Multipath is only enabled after the handshake is completed and if it was enabled by both +2875 /// peers. +2876 pub fn is_multipath_negotiated(&self) -> bool { +2877 !self.is_handshaking() +2878 && self.config.max_concurrent_multipath_paths.is_some() +2879 && self.peer_params.initial_max_path_id.is_some() +2880 } +2881 +2882 fn on_ack_received( +2883 &mut self, +2884 now: Instant, +2885 space: SpaceId, +2886 ack: frame::Ack, +2887 ) -> Result<(), TransportError> { +2888 // All ACKs are referencing path 0 +2889 let path = PathId::ZERO; +2890 self.inner_on_ack_received(now, space, path, ack) +2891 } +2892 +2893 fn on_path_ack_received( +2894 &mut self, +2895 now: Instant, +2896 space: SpaceId, +2897 path_ack: frame::PathAck, +2898 ) -> Result<(), TransportError> { +2899 let (ack, path) = path_ack.into_ack(); +2900 self.inner_on_ack_received(now, space, path, ack) +2901 } +2902 +2903 /// Handles an ACK frame acknowledging packets sent on *path*. +2904 fn inner_on_ack_received( +2905 &mut self, +2906 now: Instant, +2907 space: SpaceId, +2908 path: PathId, +2909 ack: frame::Ack, +2910 ) -> Result<(), TransportError> { +2911 if !self.spaces[space].number_spaces.contains_key(&path) { +2912 if self.abandoned_paths.contains(&path) { +2913 // See also +2914 // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4.3-3 +2915 // > When an endpoint finally deletes all state associated with the path [...] +2916 // > PATH_ACK frames received with an abandoned path ID are silently ignored, +2917 // > as specified in Section 4. +2918 trace!("silently ignoring PATH_ACK on discarded path"); +2919 return Ok(()); +2920 } else { +2921 return Err(TransportError::PROTOCOL_VIOLATION( +2922 "received PATH_ACK with path ID never used", +2923 )); +2924 } +2925 } +2926 if ack.largest >= self.spaces[space].for_path(path).next_packet_number { +2927 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked")); +2928 } +2929 // `Some(pn)` if this ACK raised `largest_acked_packet_pn`. +2930 let new_largest_pn = { +2931 let space = &mut self.spaces[space].for_path(path); +2932 if space +2933 .largest_acked_packet_pn +2934 .is_none_or(|pn| ack.largest > pn) +2935 { +2936 space.largest_acked_packet_pn = Some(ack.largest); +2937 if let Some(info) = space.sent_packets.get(ack.largest) { +2938 // This should always succeed, but a misbehaving peer might ACK a packet we +2939 // haven't sent. At worst, that will result in us spuriously reducing the +2940 // congestion window. +2941 space.largest_acked_packet_send_time = info.time_sent; +2942 } +2943 Some(ack.largest) +2944 } else { +2945 None +2946 } +2947 }; +2948 +2949 if self.detect_spurious_loss(&ack, space, path) { +2950 self.path_stats.get_mut(path).spurious_congestion_events += 1; +2951 self.path_data_mut(path) +2952 .congestion +2953 .on_spurious_congestion_event(); +2954 } +2955 +2956 // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks. +2957 let mut newly_acked: ArrayRangeSet = ArrayRangeSet::new(); +2958 for range in ack.iter() { +2959 self.spaces[space].for_path(path).check_ack(range.clone())?; +2960 for (pn, _) in self.spaces[space] +2961 .for_path(path) +2962 .sent_packets +2963 .iter_range(range) +2964 { +2965 newly_acked.insert_one(pn); +2966 } +2967 } +2968 +2969 if newly_acked.is_empty() { +2970 return Ok(()); +2971 } +2972 +2973 let mut ack_eliciting_acked = false; +2974 for packet in newly_acked.elts() { +2975 if let Some(info) = self.spaces[space].for_path(path).take(packet) { +2976 for (acked_path_id, acked_pn) in info.largest_acked.iter() { +2977 // Assume ACKs for all packets below the largest acknowledged in +2978 // `packet` have been received. This can cause the peer to spuriously +2979 // retransmit if some of our earlier ACKs were lost, but allows for +2980 // simpler state tracking. See discussion at +2981 // https://www.rfc-editor.org/rfc/rfc9000.html#name-limiting-ranges-by-tracking +2982 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) { +2983 pns.pending_acks.subtract_below(*acked_pn); +2984 } +2985 } +2986 ack_eliciting_acked |= info.ack_eliciting; +2987 +2988 // Notify MTU discovery that a packet was acked, because it might be an MTU probe +2989 let path_data = self.path_data_mut(path); +2990 let mtu_updated = path_data.mtud.on_acked(space.kind(), packet, info.size); +2991 if mtu_updated { +2992 path_data +2993 .congestion +2994 .on_mtu_update(path_data.mtud.current_mtu()); +2995 } +2996 +2997 // Notify ack frequency that a packet was acked, because it might contain an ACK_FREQUENCY frame +2998 self.ack_frequency.on_acked(path, packet); +2999 +3000 self.on_packet_acked(now, path, packet, info); +3001 } +3002 } +3003 +3004 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet_pn; +3005 let path_data = self.path_data_mut(path); +3006 let app_limited = path_data.app_limited; +3007 let in_flight = path_data.in_flight.bytes; +3008 +3009 path_data +3010 .congestion +3011 .on_end_acks(now, in_flight, app_limited, largest_ackd); +3012 +3013 if new_largest_pn.is_some() && ack_eliciting_acked { +3014 let ack_delay = if space != SpaceId::Data { +3015 Duration::from_micros(0) +3016 } else { +3017 cmp::min( +3018 self.ack_frequency.peer_max_ack_delay, +3019 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0), +3020 ) +3021 }; +3022 let rtt = now.saturating_duration_since( +3023 self.spaces[space] +3024 .for_path(path) +3025 .largest_acked_packet_send_time, +3026 ); +3027 +3028 let next_pn = self.spaces[space].for_path(path).next_packet_number; +3029 let path_data = self.path_data_mut(path); +3030 // TODO(@divma): should be a method of path, should be contained in a single place +3031 path_data.rtt.update(ack_delay, rtt); +3032 if path_data.first_packet_after_rtt_sample.is_none() { +3033 path_data.first_packet_after_rtt_sample = Some((space.kind(), next_pn)); +3034 } +3035 } +3036 +3037 // Must be called before crypto/pto_count are clobbered +3038 self.detect_lost_packets(now, space, path, true); +3039 +3040 // If the peer did not complete the handshake address validation the ACK could be +3041 // spoofed, e.g. in the Initial space. Setting the pto_count back to 0 removes the +3042 // exponential backoff from the PTO timer and would result in too many tail-loss +3043 // probes being sent. +3044 if self.peer_completed_handshake_address_validation() { +3045 self.path_data_mut(path).pto_count = 0; +3046 } +3047 +3048 // Explicit congestion notification +3049 // TODO(@divma): this code is a good example of logic that should be contained in a single +3050 // place but it's split between the path data and the packet number space data, we should +3051 // find a way to make this work without two lookups +3052 if self.path_data(path).sending_ecn { +3053 if let Some(ecn) = ack.ecn { +3054 // We only examine ECN counters from ACKs that we are certain we received in transmit +3055 // order, allowing us to compute an increase in ECN counts to compare against the number +3056 // of newly acked packets that remains well-defined in the presence of arbitrary packet +3057 // reordering. +3058 if let Some(largest_sent_pn) = new_largest_pn { +3059 let sent = self.spaces[space] +3060 .for_path(path) +3061 .largest_acked_packet_send_time; +3062 self.process_ecn( +3063 now, +3064 space, +3065 path, +3066 newly_acked.range_count() as u64, +3067 ecn, +3068 sent, +3069 largest_sent_pn, +3070 ); +3071 } +3072 } else { +3073 // We always start out sending ECN, so any ack that doesn't acknowledge it disables it. +3074 debug!("ECN not acknowledged by peer"); +3075 self.path_data_mut(path).sending_ecn = false; +3076 } +3077 } +3078 +3079 self.set_loss_detection_timer(now, path); +3080 Ok(()) +3081 } +3082 +3083 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool { +3084 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets; +3085 +3086 if lost_packets.is_empty() { +3087 return false; +3088 } 3089 -3090 for pn in spurious_losses { -3091 lost_packets.remove(pn); -3092 } -3093 } -3094 -3095 // If this ACK frame acknowledged all deemed lost packets, -3096 // then we have raised a spurious congestion event in the past. -3097 // We cannot conclude when there are remaining packets, -3098 // but future ACK frames might indicate a spurious loss detection. -3099 lost_packets.is_empty() -3100 } -3101 -3102 /// Drain lost packets that we reasonably think will never arrive -3103 /// -3104 /// The current criterion is copied from `msquic`: -3105 /// discard packets that were sent earlier than 2 probe timeouts ago. -3106 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) { -3107 let two_pto = 2 * self.path_data(path).rtt.pto_base(); -3108 -3109 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets; -3110 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto); -3111 } -3112 -3113 /// Process a new ECN block from an in-order ACK -3114 fn process_ecn( -3115 &mut self, -3116 now: Instant, -3117 space: SpaceId, -3118 path: PathId, -3119 newly_acked_pn: u64, -3120 ecn: frame::EcnCounts, -3121 largest_sent_time: Instant, -3122 largest_sent_pn: u64, -3123 ) { -3124 match self.spaces[space] -3125 .for_path(path) -3126 .detect_ecn(newly_acked_pn, ecn) -3127 { -3128 Err(e) => { -3129 debug!("halting ECN due to verification failure: {}", e); -3130 -3131 self.path_data_mut(path).sending_ecn = false; -3132 // Wipe out the existing value because it might be garbage and could interfere with -3133 // future attempts to use ECN on new paths. -3134 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO; -3135 } -3136 Ok(false) => {} -3137 Ok(true) => { -3138 self.path_stats.for_path(path).congestion_events += 1; -3139 self.path_data_mut(path).congestion.on_congestion_event( -3140 now, -3141 largest_sent_time, -3142 false, -3143 true, -3144 0, -3145 largest_sent_pn, -3146 ); -3147 } -3148 } -3149 } -3150 -3151 // Not timing-aware, so it's safe to call this for inferred acks, such as arise from -3152 // high-latency handshakes -3153 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, pn: u64, info: SentPacket) { -3154 let path = self.path_data_mut(path_id); -3155 let app_limited = path.app_limited; -3156 path.remove_in_flight(&info); -3157 if info.ack_eliciting && info.path_generation == path.generation() { -3158 // Only pass ACKs to the congestion controller if it belongs to this exact -3159 // generation of the path. Otherwise we might be feeding ACKs from the previous -3160 // 4-tuple into our congestion controller. -3161 let rtt = path.rtt; -3162 path.congestion -3163 .on_ack(now, info.time_sent, info.size.into(), pn, app_limited, &rtt); -3164 } -3165 -3166 // Update state for confirmed delivery of frames -3167 if let Some(retransmits) = info.retransmits.get() { -3168 for (id, _) in retransmits.reset_stream.iter() { -3169 self.streams.reset_acked(*id); -3170 } -3171 } -3172 -3173 for frame in info.stream_frames { -3174 self.streams.received_ack_of(frame); -3175 } -3176 } -3177 -3178 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceKind) { -3179 let start = if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) { -3180 now -3181 } else { -3182 self.crypto_state -3183 .prev_crypto -3184 .as_ref() -3185 .expect("no previous keys") -3186 .end_packet -3187 .as_ref() -3188 .expect("update not acknowledged yet") -3189 .1 -3190 }; -3191 -3192 // QUIC-MULTIPATH § 2.5 Key Phase Update Process: use largest PTO of all paths. -3193 self.timers.set( -3194 Timer::Conn(ConnTimer::KeyDiscard), -3195 start + self.max_pto_for_space(space) * 3, -3196 self.qlog.with_time(now), -3197 ); -3198 } -3199 -3200 /// Handle a [`PathTimer::LossDetection`] timeout. -3201 /// -3202 /// This timer expires for two reasons: -3203 /// - An ACK-eliciting packet we sent should be considered lost. -3204 /// - The PTO may have expired and a tail-loss probe needs to be scheduled. -3205 /// -3206 /// The former needs us to schedule re-transmission of the lost data. +3090 for range in ack.iter() { +3091 let spurious_losses: Vec<u64> = lost_packets +3092 .iter_range(range.clone()) +3093 .map(|(pn, _info)| pn) +3094 .collect(); +3095 +3096 for pn in spurious_losses { +3097 lost_packets.remove(pn); +3098 } +3099 } +3100 +3101 // If this ACK frame acknowledged all deemed lost packets, +3102 // then we have raised a spurious congestion event in the past. +3103 // We cannot conclude when there are remaining packets, +3104 // but future ACK frames might indicate a spurious loss detection. +3105 lost_packets.is_empty() +3106 } +3107 +3108 /// Drain lost packets that we reasonably think will never arrive +3109 /// +3110 /// The current criterion is copied from `msquic`: +3111 /// discard packets that were sent earlier than 2 probe timeouts ago. +3112 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) { +3113 let two_pto = 2 * self.path_data(path).rtt.pto_base(); +3114 +3115 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets; +3116 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto); +3117 } +3118 +3119 /// Process a new ECN block from an in-order ACK +3120 fn process_ecn( +3121 &mut self, +3122 now: Instant, +3123 space: SpaceId, +3124 path: PathId, +3125 newly_acked_pn: u64, +3126 ecn: frame::EcnCounts, +3127 largest_sent_time: Instant, +3128 largest_sent_pn: u64, +3129 ) { +3130 match self.spaces[space] +3131 .for_path(path) +3132 .detect_ecn(newly_acked_pn, ecn) +3133 { +3134 Err(e) => { +3135 debug!("halting ECN due to verification failure: {}", e); +3136 +3137 self.path_data_mut(path).sending_ecn = false; +3138 // Wipe out the existing value because it might be garbage and could interfere with +3139 // future attempts to use ECN on new paths. +3140 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO; +3141 } +3142 Ok(false) => {} +3143 Ok(true) => { +3144 self.path_stats.get_mut(path).congestion_events += 1; +3145 self.path_data_mut(path).congestion.on_congestion_event( +3146 now, +3147 largest_sent_time, +3148 false, +3149 true, +3150 0, +3151 largest_sent_pn, +3152 ); +3153 } +3154 } +3155 } +3156 +3157 // Not timing-aware, so it's safe to call this for inferred acks, such as arise from +3158 // high-latency handshakes +3159 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, pn: u64, info: SentPacket) { +3160 let path = self.path_data_mut(path_id); +3161 let app_limited = path.app_limited; +3162 path.remove_in_flight(&info); +3163 if info.ack_eliciting && info.path_generation == path.generation() { +3164 // Only pass ACKs to the congestion controller if it belongs to this exact +3165 // generation of the path. Otherwise we might be feeding ACKs from the previous +3166 // 4-tuple into our congestion controller. +3167 let rtt = path.rtt; +3168 path.congestion +3169 .on_ack(now, info.time_sent, info.size.into(), pn, app_limited, &rtt); +3170 } +3171 +3172 // Update state for confirmed delivery of frames +3173 if let Some(retransmits) = info.retransmits.get() { +3174 for (id, _) in retransmits.reset_stream.iter() { +3175 self.streams.reset_acked(*id); +3176 } +3177 } +3178 +3179 for frame in info.stream_frames { +3180 self.streams.received_ack_of(frame); +3181 } +3182 } +3183 +3184 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceKind) { +3185 let start = if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) { +3186 now +3187 } else { +3188 self.crypto_state +3189 .prev_crypto +3190 .as_ref() +3191 .expect("no previous keys") +3192 .end_packet +3193 .as_ref() +3194 .expect("update not acknowledged yet") +3195 .1 +3196 }; +3197 +3198 // QUIC-MULTIPATH § 2.5 Key Phase Update Process: use largest PTO of all paths. +3199 self.timers.set( +3200 Timer::Conn(ConnTimer::KeyDiscard), +3201 start + self.max_pto_for_space(space) * 3, +3202 self.qlog.with_time(now), +3203 ); +3204 } +3205 +3206 /// Handle a [`PathTimer::LossDetection`] timeout. 3207 /// -3208 /// The latter means we have not received an ACK for an ack-eliciting packet we sent -3209 /// within the PTO time-window. We need to schedule a tail-loss probe, an ack-eliciting -3210 /// packet, to try and elicit new acknowledgements. These new acknowledgements will -3211 /// indicate whether the previously sent packets were lost or not. -3212 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) { -3213 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) { -3214 // Time threshold loss Detection -3215 self.detect_lost_packets(now, pn_space, path_id, false); -3216 self.set_loss_detection_timer(now, path_id); -3217 return; -3218 } -3219 -3220 let Some((_, space)) = self.pto_time_and_space(now, path_id) else { -3221 error!(%path_id, "PTO expired while unset"); -3222 return; -3223 }; -3224 trace!( -3225 in_flight = self.path_data(path_id).in_flight.bytes, -3226 count = self.path_data(path_id).pto_count, -3227 ?space, -3228 %path_id, -3229 "PTO fired" -3230 ); -3231 -3232 let count = match self.path_data(path_id).in_flight.ack_eliciting { -3233 // A PTO when we're not expecting any ACKs must be due to handshake -3234 // anti-amplification deadlock prevention. -3235 0 => { -3236 debug_assert!(!self.peer_completed_handshake_address_validation()); -3237 1 -3238 } -3239 // Conventional loss probe -3240 _ => 2, -3241 }; -3242 let pns = self.spaces[space].for_path(path_id); -3243 pns.loss_probes = pns.loss_probes.saturating_add(count); -3244 let path_data = self.path_data_mut(path_id); -3245 path_data.pto_count = path_data.pto_count.saturating_add(1); -3246 self.set_loss_detection_timer(now, path_id); -3247 } -3248 -3249 /// Detect any lost packets -3250 /// -3251 /// There are two cases in which we detects lost packets: -3252 /// -3253 /// - We received an ACK packet. -3254 /// - The [`PathTimer::LossDetection`] timer expired. So there is an un-acknowledged packet -3255 /// that was followed by an acknowledged packet. The loss timer for this -3256 /// un-acknowledged packet expired and we need to detect that packet as lost. -3257 /// -3258 /// Packets are lost if they are both (See RFC9002 §6.1): -3259 /// -3260 /// - Unacknowledged, in flight and sent prior to an acknowledged packet. -3261 /// - Old enough by either: -3262 /// - Having a packet number [`TransportConfig::packet_threshold`] lower then the last -3263 /// acknowledged packet. -3264 /// - Being sent [`TransportConfig::time_threshold`] * RTT in the past. -3265 fn detect_lost_packets( -3266 &mut self, -3267 now: Instant, -3268 pn_space: SpaceId, -3269 path_id: PathId, -3270 due_to_ack: bool, -3271 ) { -3272 let mut lost_packets = Vec::<u64>::new(); -3273 let mut lost_mtu_probe = None; -3274 let mut in_persistent_congestion = false; -3275 let mut size_of_lost_packets = 0u64; -3276 self.spaces[pn_space].for_path(path_id).loss_time = None; -3277 -3278 // Find all the lost packets, populating all variables initialised above. -3279 -3280 let path = self.path_data(path_id); -3281 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe(); -3282 let loss_delay = path -3283 .rtt -3284 .conservative() -3285 .mul_f32(self.config.time_threshold) -3286 .max(TIMER_GRANULARITY); -3287 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample; -3288 -3289 let largest_acked_packet_pn = self.spaces[pn_space] -3290 .for_path(path_id) -3291 .largest_acked_packet_pn -3292 .expect("detect_lost_packets only to be called if path received at least one ACK"); -3293 let packet_threshold = self.config.packet_threshold as u64; +3208 /// This timer expires for two reasons: +3209 /// - An ACK-eliciting packet we sent should be considered lost. +3210 /// - The PTO may have expired and a tail-loss probe needs to be scheduled. +3211 /// +3212 /// The former needs us to schedule re-transmission of the lost data. +3213 /// +3214 /// The latter means we have not received an ACK for an ack-eliciting packet we sent +3215 /// within the PTO time-window. We need to schedule a tail-loss probe, an ack-eliciting +3216 /// packet, to try and elicit new acknowledgements. These new acknowledgements will +3217 /// indicate whether the previously sent packets were lost or not. +3218 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) { +3219 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) { +3220 // Time threshold loss Detection +3221 self.detect_lost_packets(now, pn_space, path_id, false); +3222 self.set_loss_detection_timer(now, path_id); +3223 return; +3224 } +3225 +3226 let Some((_, space)) = self.pto_time_and_space(now, path_id) else { +3227 debug!(%path_id, "PTO expired while unset"); +3228 return; +3229 }; +3230 trace!( +3231 in_flight = self.path_data(path_id).in_flight.bytes, +3232 count = self.path_data(path_id).pto_count, +3233 ?space, +3234 %path_id, +3235 "PTO fired" +3236 ); +3237 +3238 let count = match self.path_data(path_id).in_flight.ack_eliciting { +3239 // A PTO when we're not expecting any ACKs must be due to handshake +3240 // anti-amplification deadlock prevention. +3241 0 => { +3242 debug_assert!(!self.peer_completed_handshake_address_validation()); +3243 1 +3244 } +3245 // Conventional loss probe +3246 _ => 2, +3247 }; +3248 let pns = self.spaces[space].for_path(path_id); +3249 pns.loss_probes = pns.loss_probes.saturating_add(count); +3250 let path_data = self.path_data_mut(path_id); +3251 path_data.pto_count = path_data.pto_count.saturating_add(1); +3252 self.set_loss_detection_timer(now, path_id); +3253 } +3254 +3255 /// Detect any lost packets +3256 /// +3257 /// There are two cases in which we detects lost packets: +3258 /// +3259 /// - We received an ACK packet. +3260 /// - The [`PathTimer::LossDetection`] timer expired. So there is an un-acknowledged packet +3261 /// that was followed by an acknowledged packet. The loss timer for this +3262 /// un-acknowledged packet expired and we need to detect that packet as lost. +3263 /// +3264 /// Packets are lost if they are both (See RFC9002 §6.1): +3265 /// +3266 /// - Unacknowledged, in flight and sent prior to an acknowledged packet. +3267 /// - Old enough by either: +3268 /// - Having a packet number [`TransportConfig::packet_threshold`] lower then the last +3269 /// acknowledged packet. +3270 /// - Being sent [`TransportConfig::time_threshold`] * RTT in the past. +3271 fn detect_lost_packets( +3272 &mut self, +3273 now: Instant, +3274 pn_space: SpaceId, +3275 path_id: PathId, +3276 due_to_ack: bool, +3277 ) { +3278 let mut lost_packets = Vec::<u64>::new(); +3279 let mut lost_mtu_probe = None; +3280 let mut in_persistent_congestion = false; +3281 let mut size_of_lost_packets = 0u64; +3282 self.spaces[pn_space].for_path(path_id).loss_time = None; +3283 +3284 // Find all the lost packets, populating all variables initialised above. +3285 +3286 let path = self.path_data(path_id); +3287 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe(); +3288 let loss_delay = path +3289 .rtt +3290 .conservative() +3291 .mul_f32(self.config.time_threshold) +3292 .max(TIMER_GRANULARITY); +3293 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample; 3294 -3295 // InPersistentCongestion: Determine if all packets in the time period before the newest -3296 // lost packet, including the edges, are marked lost. PTO computation must always -3297 // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1). -3298 let congestion_period = self -3299 .pto(SpaceKind::Data, path_id) -3300 .saturating_mul(self.config.persistent_congestion_threshold); -3301 let mut persistent_congestion_start: Option<Instant> = None; -3302 let mut prev_packet = None; -3303 let space = self.spaces[pn_space].for_path(path_id); -3304 -3305 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet_pn) { -3306 if prev_packet != Some(packet.wrapping_sub(1)) { -3307 // An intervening packet was acknowledged -3308 persistent_congestion_start = None; -3309 } +3295 let largest_acked_packet_pn = self.spaces[pn_space] +3296 .for_path(path_id) +3297 .largest_acked_packet_pn +3298 .expect("detect_lost_packets only to be called if path received at least one ACK"); +3299 let packet_threshold = self.config.packet_threshold as u64; +3300 +3301 // InPersistentCongestion: Determine if all packets in the time period before the newest +3302 // lost packet, including the edges, are marked lost. PTO computation must always +3303 // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1). +3304 let congestion_period = self +3305 .pto(SpaceKind::Data, path_id) +3306 .saturating_mul(self.config.persistent_congestion_threshold); +3307 let mut persistent_congestion_start: Option<Instant> = None; +3308 let mut prev_packet = None; +3309 let space = self.spaces[pn_space].for_path(path_id); 3310 -3311 // Packets sent before now - loss_delay are deemed lost. -3312 // However, we avoid subtraction as it can panic and there's no -3313 // saturating equivalent of this subtraction operation with a Duration. -3314 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay; -3315 if packet_too_old || largest_acked_packet_pn >= packet + packet_threshold { -3316 // The packet should be declared lost. -3317 if Some(packet) == in_flight_mtu_probe { -3318 // Lost MTU probes are not included in `lost_packets`, because they -3319 // should not trigger a congestion control response -3320 lost_mtu_probe = in_flight_mtu_probe; -3321 } else { -3322 lost_packets.push(packet); -3323 size_of_lost_packets += info.size as u64; -3324 if info.ack_eliciting && due_to_ack { -3325 match persistent_congestion_start { -3326 // Two ACK-eliciting packets lost more than -3327 // congestion_period apart, with no ACKed packets in between -3328 Some(start) if info.time_sent - start > congestion_period => { -3329 in_persistent_congestion = true; -3330 } -3331 // Persistent congestion must start after the first RTT sample -3332 None if first_packet_after_rtt_sample -3333 .is_some_and(|x| x < (pn_space.kind(), packet)) => -3334 { -3335 persistent_congestion_start = Some(info.time_sent); +3311 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet_pn) { +3312 if prev_packet != Some(packet.wrapping_sub(1)) { +3313 // An intervening packet was acknowledged +3314 persistent_congestion_start = None; +3315 } +3316 +3317 // Packets sent before now - loss_delay are deemed lost. +3318 // However, we avoid subtraction as it can panic and there's no +3319 // saturating equivalent of this subtraction operation with a Duration. +3320 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay; +3321 if packet_too_old || largest_acked_packet_pn >= packet + packet_threshold { +3322 // The packet should be declared lost. +3323 if Some(packet) == in_flight_mtu_probe { +3324 // Lost MTU probes are not included in `lost_packets`, because they +3325 // should not trigger a congestion control response +3326 lost_mtu_probe = in_flight_mtu_probe; +3327 } else { +3328 lost_packets.push(packet); +3329 size_of_lost_packets += info.size as u64; +3330 if info.ack_eliciting && due_to_ack { +3331 match persistent_congestion_start { +3332 // Two ACK-eliciting packets lost more than +3333 // congestion_period apart, with no ACKed packets in between +3334 Some(start) if info.time_sent - start > congestion_period => { +3335 in_persistent_congestion = true; 3336 } -3337 _ => {} -3338 } -3339 } -3340 } -3341 } else { -3342 // The packet should not yet be declared lost. -3343 if space.loss_time.is_none() { -3344 // Since we iterate in order the lowest packet number's loss time will -3345 // always be the earliest. -3346 space.loss_time = Some(info.time_sent + loss_delay); -3347 } -3348 persistent_congestion_start = None; -3349 } -3350 -3351 prev_packet = Some(packet); -3352 } -3353 -3354 self.handle_lost_packets( -3355 pn_space, -3356 path_id, -3357 now, -3358 lost_packets, -3359 lost_mtu_probe, -3360 loss_delay, -3361 in_persistent_congestion, -3362 size_of_lost_packets, -3363 ); -3364 } -3365 -3366 /// Drops the path state, declaring any remaining in-flight packets as lost -3367 fn discard_path(&mut self, path_id: PathId, now: Instant) { -3368 trace!(%path_id, "dropping path state"); -3369 let path = self.path_data(path_id); -3370 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe(); +3337 // Persistent congestion must start after the first RTT sample +3338 None if first_packet_after_rtt_sample +3339 .is_some_and(|x| x < (pn_space.kind(), packet)) => +3340 { +3341 persistent_congestion_start = Some(info.time_sent); +3342 } +3343 _ => {} +3344 } +3345 } +3346 } +3347 } else { +3348 // The packet should not yet be declared lost. +3349 if space.loss_time.is_none() { +3350 // Since we iterate in order the lowest packet number's loss time will +3351 // always be the earliest. +3352 space.loss_time = Some(info.time_sent + loss_delay); +3353 } +3354 persistent_congestion_start = None; +3355 } +3356 +3357 prev_packet = Some(packet); +3358 } +3359 +3360 self.handle_lost_packets( +3361 pn_space, +3362 path_id, +3363 now, +3364 lost_packets, +3365 lost_mtu_probe, +3366 loss_delay, +3367 in_persistent_congestion, +3368 size_of_lost_packets, +3369 ); +3370 } 3371 -3372 let mut size_of_lost_packets = 0u64; // add to path_stats.lost_bytes; -3373 let lost_pns: Vec<_> = self.spaces[SpaceId::Data] -3374 .for_path(path_id) -3375 .sent_packets -3376 .iter() -3377 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe) -3378 .map(|(pn, info)| { -3379 size_of_lost_packets += info.size as u64; -3380 pn -3381 }) -3382 .collect(); -3383 -3384 if !lost_pns.is_empty() { -3385 trace!( -3386 %path_id, -3387 count = lost_pns.len(), -3388 lost_bytes = size_of_lost_packets, -3389 "packets lost on path abandon" -3390 ); -3391 self.handle_lost_packets( -3392 SpaceId::Data, -3393 path_id, -3394 now, -3395 lost_pns, -3396 in_flight_mtu_probe, -3397 Duration::ZERO, -3398 false, -3399 size_of_lost_packets, -3400 ); -3401 } -3402 // Before removing the path, we fetch the final path stats via `Self::path_stats`. -3403 // This ensures snapshot values (like rtt) are properly updated. -3404 let path_stats = self.path_stats(path_id).unwrap_or_default(); -3405 self.path_stats.discard(&path_id); -3406 self.partial_stats += path_stats; -3407 self.paths.remove(&path_id); -3408 self.spaces[SpaceId::Data].number_spaces.remove(&path_id); -3409 -3410 self.events.push_back( -3411 PathEvent::Discarded { -3412 id: path_id, -3413 path_stats: Box::new(path_stats), -3414 } -3415 .into(), -3416 ); -3417 } -3418 -3419 fn handle_lost_packets( -3420 &mut self, -3421 pn_space: SpaceId, -3422 path_id: PathId, -3423 now: Instant, -3424 lost_packets: Vec<u64>, -3425 lost_mtu_probe: Option<u64>, -3426 loss_delay: Duration, -3427 in_persistent_congestion: bool, -3428 size_of_lost_packets: u64, -3429 ) { -3430 debug_assert!(lost_packets.is_sorted(), "lost_packets must be sorted"); -3431 -3432 self.drain_lost_packets(now, pn_space, path_id); -3433 -3434 // OnPacketsLost -3435 if let Some(largest_lost) = lost_packets.last().cloned() { -3436 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes; -3437 let largest_lost_sent = self.spaces[pn_space] -3438 .for_path(path_id) -3439 .sent_packets -3440 .get(largest_lost) -3441 .unwrap() -3442 .time_sent; -3443 let path_stats = self.path_stats.for_path(path_id); -3444 path_stats.lost_packets += lost_packets.len() as u64; -3445 path_stats.lost_bytes += size_of_lost_packets; -3446 trace!( -3447 %path_id, -3448 count = lost_packets.len(), -3449 lost_bytes = size_of_lost_packets, -3450 "packets lost", -3451 ); -3452 -3453 for &packet in &lost_packets { -3454 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else { -3455 continue; -3456 }; -3457 self.qlog -3458 .emit_packet_lost(packet, &info, loss_delay, pn_space.kind(), now); -3459 self.paths -3460 .get_mut(&path_id) -3461 .unwrap() -3462 .remove_in_flight(&info); -3463 -3464 for frame in info.stream_frames { -3465 self.streams.retransmit(frame); -3466 } -3467 self.spaces[pn_space].pending |= info.retransmits; -3468 let path = self.path_data_mut(path_id); -3469 path.pending |= info.path_retransmits; -3470 path.mtud.on_non_probe_lost(packet, info.size); -3471 path.congestion.on_packet_lost(info.size, packet, now); -3472 -3473 self.spaces[pn_space].for_path(path_id).lost_packets.insert( -3474 packet, -3475 LostPacket { -3476 time_sent: info.time_sent, -3477 }, -3478 ); -3479 } -3480 -3481 let path = self.path_data_mut(path_id); -3482 if path.mtud.black_hole_detected(now) { -3483 path.congestion.on_mtu_update(path.mtud.current_mtu()); -3484 if let Some(max_datagram_size) = self.datagrams().max_size() -3485 && self.datagrams.drop_oversized(max_datagram_size) -3486 && self.datagrams.send_blocked -3487 { -3488 self.datagrams.send_blocked = false; -3489 self.events.push_back(Event::DatagramsUnblocked); -3490 } -3491 self.path_stats.for_path(path_id).black_holes_detected += 1; -3492 } -3493 -3494 // Don't apply congestion penalty for lost ack-only packets -3495 let lost_ack_eliciting = -3496 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes; -3497 -3498 if lost_ack_eliciting { -3499 self.path_stats.for_path(path_id).congestion_events += 1; -3500 self.path_data_mut(path_id).congestion.on_congestion_event( -3501 now, -3502 largest_lost_sent, -3503 in_persistent_congestion, -3504 false, -3505 size_of_lost_packets, -3506 largest_lost, -3507 ); -3508 } -3509 } -3510 -3511 // Handle a lost MTU probe -3512 if let Some(packet) = lost_mtu_probe { -3513 let info = self.spaces[SpaceId::Data] -3514 .for_path(path_id) -3515 .take(packet) -3516 .unwrap(); // safe: lost_mtu_probe is omitted from lost_packets, and -3517 // therefore must not have been removed yet -3518 self.paths -3519 .get_mut(&path_id) -3520 .unwrap() -3521 .remove_in_flight(&info); -3522 self.path_data_mut(path_id).mtud.on_probe_lost(); -3523 self.path_stats.for_path(path_id).lost_plpmtud_probes += 1; -3524 } -3525 } -3526 -3527 /// Returns the earliest time packets should be declared lost for all spaces on a path. -3528 /// -3529 /// If a path has an acknowledged packet with any prior un-acknowledged packets, the -3530 /// earliest un-acknowledged packet can be declared lost after a timeout has elapsed. -3531 /// The time returned is when this packet should be declared lost. -3532 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> { -3533 SpaceId::iter() -3534 .filter_map(|id| { -3535 self.spaces[id] -3536 .number_spaces -3537 .get(&path_id) -3538 .and_then(|pns| pns.loss_time) -3539 .map(|time| (time, id)) -3540 }) -3541 .min_by_key(|&(time, _)| time) -3542 } -3543 -3544 /// Returns the earliest next PTO should fire for all spaces on a path. -3545 /// -3546 /// This needs to be fully deterministic because it is also used to determine the PTO -3547 /// that fired, not just to set the next timer. So if it fired in the past it needs to -3548 /// return the time from the past at which it fired. -3549 /// -3550 /// This is the next time a tail-loss probe should be sent. -3551 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> { -3552 let path = self.path(path_id)?; -3553 let pto_count = path.pto_count; -3554 -3555 // Cap the maximum interval between two tail-loss probes. -3556 let max_interval = if path.rtt.get() > SLOW_RTT_THRESHOLD { -3557 // For slow links we want to increase the interval beyond 2s. -3558 (path.rtt.get() * 3) / 2 -3559 } else if let Some(idle) = path.idle_timeout.or(self.idle_timeout) -3560 && idle <= MIN_IDLE_FOR_FAST_PTO -3561 { -3562 // If the idle timeout is relatively low, cap at 1s so we get plenty of retries -3563 // before the idle timeout fires. -3564 MAX_PTO_FAST_INTERVAL -3565 } else { -3566 // Otherwise cap to 2s. -3567 MAX_PTO_INTERVAL -3568 }; -3569 -3570 if path_id == PathId::ZERO -3571 && path.in_flight.ack_eliciting == 0 -3572 && !self.peer_completed_handshake_address_validation() -3573 { -3574 // Address Validation during Connection Establishment: -3575 // https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1. To prevent a -3576 // deadlock if an Initial or Handshake packet from the server is lost and the -3577 // server can not send more due to its anti-amplification limit the client must -3578 // send another packet on PTO. -3579 let space = match self.highest_space { -3580 SpaceKind::Handshake => SpaceId::Handshake, -3581 _ => SpaceId::Initial, -3582 }; -3583 -3584 let backoff = 2u32.pow(path.pto_count.min(MAX_BACKOFF_EXPONENT)); -3585 let duration = path.rtt.pto_base() * backoff; -3586 let duration = duration.min(max_interval); -3587 return Some((now + duration, space)); -3588 } +3372 /// Drops the path state, declaring any remaining in-flight packets as lost +3373 fn discard_path(&mut self, path_id: PathId, now: Instant) { +3374 trace!(%path_id, "dropping path state"); +3375 let path = self.path_data(path_id); +3376 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe(); +3377 +3378 let mut size_of_lost_packets = 0u64; // add to path_stats.lost_bytes; +3379 let lost_pns: Vec<_> = self.spaces[SpaceId::Data] +3380 .for_path(path_id) +3381 .sent_packets +3382 .iter() +3383 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe) +3384 .map(|(pn, info)| { +3385 size_of_lost_packets += info.size as u64; +3386 pn +3387 }) +3388 .collect(); +3389 +3390 if !lost_pns.is_empty() { +3391 trace!( +3392 %path_id, +3393 count = lost_pns.len(), +3394 lost_bytes = size_of_lost_packets, +3395 "packets lost on path abandon" +3396 ); +3397 self.handle_lost_packets( +3398 SpaceId::Data, +3399 path_id, +3400 now, +3401 lost_pns, +3402 in_flight_mtu_probe, +3403 Duration::ZERO, +3404 false, +3405 size_of_lost_packets, +3406 ); +3407 } +3408 // Before removing the path, we fetch the final path stats via `Self::path_stats`. +3409 // This ensures snapshot values (like rtt) are properly updated. +3410 let path_stats = self.path_stats(path_id).unwrap_or_default(); +3411 self.path_stats.discard(&path_id); +3412 self.partial_stats += path_stats; +3413 self.paths.remove(&path_id); +3414 self.spaces[SpaceId::Data].number_spaces.remove(&path_id); +3415 +3416 self.events.push_back( +3417 PathEvent::Discarded { +3418 id: path_id, +3419 path_stats: Box::new(path_stats), +3420 } +3421 .into(), +3422 ); +3423 } +3424 +3425 fn handle_lost_packets( +3426 &mut self, +3427 pn_space: SpaceId, +3428 path_id: PathId, +3429 now: Instant, +3430 lost_packets: Vec<u64>, +3431 lost_mtu_probe: Option<u64>, +3432 loss_delay: Duration, +3433 in_persistent_congestion: bool, +3434 size_of_lost_packets: u64, +3435 ) { +3436 debug_assert!(lost_packets.is_sorted(), "lost_packets must be sorted"); +3437 +3438 self.drain_lost_packets(now, pn_space, path_id); +3439 +3440 // OnPacketsLost +3441 if let Some(largest_lost) = lost_packets.last().cloned() { +3442 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes; +3443 let largest_lost_sent = self.spaces[pn_space] +3444 .for_path(path_id) +3445 .sent_packets +3446 .get(largest_lost) +3447 .unwrap() +3448 .time_sent; +3449 let path_stats = self.path_stats.get_mut(path_id); +3450 path_stats.lost_packets += lost_packets.len() as u64; +3451 path_stats.lost_bytes += size_of_lost_packets; +3452 trace!( +3453 %path_id, +3454 count = lost_packets.len(), +3455 lost_bytes = size_of_lost_packets, +3456 "packets lost", +3457 ); +3458 +3459 for &packet in &lost_packets { +3460 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else { +3461 continue; +3462 }; +3463 self.qlog +3464 .emit_packet_lost(packet, &info, loss_delay, pn_space.kind(), now); +3465 self.paths +3466 .get_mut(&path_id) +3467 .unwrap() +3468 .remove_in_flight(&info); +3469 +3470 for frame in info.stream_frames { +3471 self.streams.retransmit(frame); +3472 } +3473 self.spaces[pn_space].pending |= info.retransmits; +3474 let path = self.path_data_mut(path_id); +3475 path.pending |= info.path_retransmits; +3476 path.mtud.on_non_probe_lost(packet, info.size); +3477 path.congestion.on_packet_lost(info.size, packet, now); +3478 +3479 self.spaces[pn_space].for_path(path_id).lost_packets.insert( +3480 packet, +3481 LostPacket { +3482 time_sent: info.time_sent, +3483 }, +3484 ); +3485 } +3486 +3487 let path = self.path_data_mut(path_id); +3488 if path.mtud.black_hole_detected(now) { +3489 path.congestion.on_mtu_update(path.mtud.current_mtu()); +3490 if let Some(max_datagram_size) = self.datagrams().max_size() +3491 && self.datagrams.drop_oversized(max_datagram_size) +3492 && self.datagrams.send_blocked +3493 { +3494 self.datagrams.send_blocked = false; +3495 self.events.push_back(Event::DatagramsUnblocked); +3496 } +3497 self.path_stats.get_mut(path_id).black_holes_detected += 1; +3498 } +3499 +3500 // Don't apply congestion penalty for lost ack-only packets +3501 let lost_ack_eliciting = +3502 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes; +3503 +3504 if lost_ack_eliciting { +3505 self.path_stats.get_mut(path_id).congestion_events += 1; +3506 self.path_data_mut(path_id).congestion.on_congestion_event( +3507 now, +3508 largest_lost_sent, +3509 in_persistent_congestion, +3510 false, +3511 size_of_lost_packets, +3512 largest_lost, +3513 ); +3514 } +3515 } +3516 +3517 // Handle a lost MTU probe +3518 if let Some(packet) = lost_mtu_probe { +3519 let info = self.spaces[SpaceId::Data] +3520 .for_path(path_id) +3521 .take(packet) +3522 .unwrap(); // safe: lost_mtu_probe is omitted from lost_packets, and +3523 // therefore must not have been removed yet +3524 self.paths +3525 .get_mut(&path_id) +3526 .unwrap() +3527 .remove_in_flight(&info); +3528 self.path_data_mut(path_id).mtud.on_probe_lost(); +3529 self.path_stats.get_mut(path_id).lost_plpmtud_probes += 1; +3530 } +3531 } +3532 +3533 /// Returns the earliest time packets should be declared lost for all spaces on a path. +3534 /// +3535 /// If a path has an acknowledged packet with any prior un-acknowledged packets, the +3536 /// earliest un-acknowledged packet can be declared lost after a timeout has elapsed. +3537 /// The time returned is when this packet should be declared lost. +3538 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> { +3539 SpaceId::iter() +3540 .filter_map(|id| { +3541 self.spaces[id] +3542 .number_spaces +3543 .get(&path_id) +3544 .and_then(|pns| pns.loss_time) +3545 .map(|time| (time, id)) +3546 }) +3547 .min_by_key(|&(time, _)| time) +3548 } +3549 +3550 /// Returns the earliest next PTO should fire for all spaces on a path. +3551 /// +3552 /// This needs to be fully deterministic because it is also used to determine the PTO +3553 /// that fired, not just to set the next timer. So if it fired in the past it needs to +3554 /// return the time from the past at which it fired. +3555 /// +3556 /// This is the next time a tail-loss probe should be sent. +3557 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> { +3558 let path = self.path(path_id)?; +3559 let pto_count = path.pto_count; +3560 +3561 // Cap the maximum interval between two tail-loss probes. +3562 let max_interval = if path.rtt.get() > SLOW_RTT_THRESHOLD { +3563 // For slow links we want to increase the interval beyond 2s. +3564 (path.rtt.get() * 3) / 2 +3565 } else if let Some(idle) = path.idle_timeout.or(self.idle_timeout) +3566 && idle <= MIN_IDLE_FOR_FAST_PTO +3567 { +3568 // If the idle timeout is relatively low, cap at 1s so we get plenty of retries +3569 // before the idle timeout fires. +3570 MAX_PTO_FAST_INTERVAL +3571 } else { +3572 // Otherwise cap to 2s. +3573 MAX_PTO_INTERVAL +3574 }; +3575 +3576 if path_id == PathId::ZERO +3577 && path.in_flight.ack_eliciting == 0 +3578 && !self.peer_completed_handshake_address_validation() +3579 { +3580 // Address Validation during Connection Establishment: +3581 // https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1. To prevent a +3582 // deadlock if an Initial or Handshake packet from the server is lost and the +3583 // server can not send more due to its anti-amplification limit the client must +3584 // send another packet on PTO. +3585 let space = match self.highest_space { +3586 SpaceKind::Handshake => SpaceId::Handshake, +3587 _ => SpaceId::Initial, +3588 }; 3589 -3590 let mut result = None; -3591 for space in SpaceId::iter() { -3592 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else { -3593 continue; -3594 }; +3590 let backoff = 2u32.pow(path.pto_count.min(MAX_BACKOFF_EXPONENT)); +3591 let duration = path.rtt.pto_base() * backoff; +3592 let duration = duration.min(max_interval); +3593 return Some((now + duration, space)); +3594 } 3595 -3596 if space == SpaceId::Data && !self.is_handshake_confirmed() { -3597 // https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-7: -3598 // An endpoint MUST NOT set its PTO timer for the Application Data packet -3599 // number space until the handshake is confirmed. -3600 continue; -3601 } -3602 -3603 if !pns.has_in_flight() { -3604 continue; -3605 } -3606 -3607 // Compute the PTO duration for this space, we want to cap the maximum interval -3608 // between two tail-loss probes so to not do a simple exponential backoff but -3609 // rather iterate through the probes to compute the capped increment for an -3610 // exponential backoff at each step. -3611 let duration = { -3612 let max_ack_delay = if space == SpaceId::Data { -3613 self.ack_frequency.max_ack_delay_for_pto() -3614 } else { -3615 Duration::ZERO -3616 }; -3617 let pto_base = path.rtt.pto_base() + max_ack_delay; -3618 let mut duration = pto_base; -3619 for i in 1..=pto_count { -3620 let exponential_duration = pto_base * 2u32.pow(i.min(MAX_BACKOFF_EXPONENT)); -3621 let max_duration = duration + max_interval; -3622 duration = exponential_duration.min(max_duration); -3623 } -3624 duration -3625 }; -3626 -3627 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else { -3628 continue; -3629 }; -3630 // Base the deadline on when the last probe was sent, so the PTO -3631 // doesn't fire before the response has had time to arrive. -3632 let pto = last_ack_eliciting + duration; -3633 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) { -3634 if path.anti_amplification_blocked(1) { -3635 // Nothing would be able to be sent. -3636 continue; -3637 } -3638 if path.in_flight.ack_eliciting == 0 { -3639 // Nothing ack-eliciting, no PTO to arm/fire. -3640 continue; -3641 } -3642 result = Some((pto, space)); -3643 } -3644 } -3645 result -3646 } -3647 -3648 /// Whether the peer validated our address in the connection handshake. -3649 fn peer_completed_handshake_address_validation(&self) -> bool { -3650 if self.side.is_server() || self.state.is_closed() { -3651 return true; -3652 } -3653 // The server is guaranteed to have validated our address if any of our handshake or -3654 // 1-RTT packets are acknowledged or we've seen HANDSHAKE_DONE and discarded -3655 // handshake keys. -3656 self.spaces[SpaceId::Handshake] -3657 .path_space(PathId::ZERO) -3658 .and_then(|pns| pns.largest_acked_packet_pn) -3659 .is_some() -3660 || self.spaces[SpaceId::Data] -3661 .path_space(PathId::ZERO) -3662 .and_then(|pns| pns.largest_acked_packet_pn) -3663 .is_some() -3664 || (self.crypto_state.has_keys(EncryptionLevel::OneRtt) -3665 && !self.crypto_state.has_keys(EncryptionLevel::Handshake)) -3666 } -3667 -3668 /// Resets the the [`PathTimer::LossDetection`] timer to the next instant it may be needed -3669 /// -3670 /// The timer must fire if either: -3671 /// - An ack-eliciting packet we sent needs to be declared lost. -3672 /// - A tail-loss probe needs to be sent. -3673 /// -3674 /// See [`Connection::on_loss_detection_timeout`] for details. -3675 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) { -3676 if self.state.is_closed() { -3677 // No loss detection takes place on closed connections, and `close_common` already -3678 // stopped time timer. Ensure we don't restart it inadvertently, e.g. in response to a -3679 // reordered packet being handled by state-insensitive code. -3680 return; -3681 } -3682 -3683 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) { -3684 // Time threshold loss detection. -3685 self.timers.set( -3686 Timer::PerPath(path_id, PathTimer::LossDetection), -3687 loss_time, -3688 self.qlog.with_time(now), -3689 ); -3690 return; -3691 } -3692 -3693 // Determine which PN space to arm PTO for. -3694 // We can only send tail-loss probes on paths that aren't abandoned yet. -3695 if !self.abandoned_paths.contains(&path_id) -3696 && let Some((timeout, _)) = self.pto_time_and_space(now, path_id) -3697 { -3698 self.timers.set( -3699 Timer::PerPath(path_id, PathTimer::LossDetection), -3700 timeout, -3701 self.qlog.with_time(now), -3702 ); -3703 } else { -3704 self.timers.stop( +3596 let mut result = None; +3597 for space in SpaceId::iter() { +3598 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else { +3599 continue; +3600 }; +3601 +3602 if space == SpaceId::Data && !self.is_handshake_confirmed() { +3603 // https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-7: +3604 // An endpoint MUST NOT set its PTO timer for the Application Data packet +3605 // number space until the handshake is confirmed. +3606 continue; +3607 } +3608 +3609 if !pns.has_in_flight() { +3610 continue; +3611 } +3612 +3613 // Compute the PTO duration for this space, we want to cap the maximum interval +3614 // between two tail-loss probes so to not do a simple exponential backoff but +3615 // rather iterate through the probes to compute the capped increment for an +3616 // exponential backoff at each step. +3617 let duration = { +3618 let max_ack_delay = if space == SpaceId::Data { +3619 self.ack_frequency.max_ack_delay_for_pto() +3620 } else { +3621 Duration::ZERO +3622 }; +3623 let pto_base = path.rtt.pto_base() + max_ack_delay; +3624 let mut duration = pto_base; +3625 for i in 1..=pto_count { +3626 let exponential_duration = pto_base * 2u32.pow(i.min(MAX_BACKOFF_EXPONENT)); +3627 let max_duration = duration + max_interval; +3628 duration = exponential_duration.min(max_duration); +3629 } +3630 duration +3631 }; +3632 +3633 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else { +3634 continue; +3635 }; +3636 // Base the deadline on when the last probe was sent, so the PTO +3637 // doesn't fire before the response has had time to arrive. +3638 let pto = last_ack_eliciting + duration; +3639 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) { +3640 if path.anti_amplification_blocked(1) { +3641 // Nothing would be able to be sent. +3642 continue; +3643 } +3644 if path.in_flight.ack_eliciting == 0 { +3645 // Nothing ack-eliciting, no PTO to arm/fire. +3646 continue; +3647 } +3648 result = Some((pto, space)); +3649 } +3650 } +3651 result +3652 } +3653 +3654 /// Whether the peer validated our address in the connection handshake. +3655 fn peer_completed_handshake_address_validation(&self) -> bool { +3656 if self.side.is_server() || self.state.is_closed() { +3657 return true; +3658 } +3659 // The server is guaranteed to have validated our address if any of our handshake or +3660 // 1-RTT packets are acknowledged or we've seen HANDSHAKE_DONE and discarded +3661 // handshake keys. +3662 self.spaces[SpaceId::Handshake] +3663 .path_space(PathId::ZERO) +3664 .and_then(|pns| pns.largest_acked_packet_pn) +3665 .is_some() +3666 || self.spaces[SpaceId::Data] +3667 .path_space(PathId::ZERO) +3668 .and_then(|pns| pns.largest_acked_packet_pn) +3669 .is_some() +3670 || (self.crypto_state.has_keys(EncryptionLevel::OneRtt) +3671 && !self.crypto_state.has_keys(EncryptionLevel::Handshake)) +3672 } +3673 +3674 /// Resets the the [`PathTimer::LossDetection`] timer to the next instant it may be needed +3675 /// +3676 /// The timer must fire if either: +3677 /// - An ack-eliciting packet we sent needs to be declared lost. +3678 /// - A tail-loss probe needs to be sent. +3679 /// +3680 /// See [`Connection::on_loss_detection_timeout`] for details. +3681 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) { +3682 if self.state.is_closed() { +3683 // No loss detection takes place on closed connections, and `close_common` already +3684 // stopped time timer. Ensure we don't restart it inadvertently, e.g. in response to a +3685 // reordered packet being handled by state-insensitive code. +3686 return; +3687 } +3688 +3689 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) { +3690 // Time threshold loss detection. +3691 self.timers.set( +3692 Timer::PerPath(path_id, PathTimer::LossDetection), +3693 loss_time, +3694 self.qlog.with_time(now), +3695 ); +3696 return; +3697 } +3698 +3699 // Determine which PN space to arm PTO for. +3700 // We can only send tail-loss probes on paths that aren't abandoned yet. +3701 if !self.abandoned_paths.contains(&path_id) +3702 && let Some((timeout, _)) = self.pto_time_and_space(now, path_id) +3703 { +3704 self.timers.set( 3705 Timer::PerPath(path_id, PathTimer::LossDetection), -3706 self.qlog.with_time(now), -3707 ); -3708 } -3709 } -3710 -3711 /// The maximum probe timeout across all paths -3712 /// -3713 /// See [`Connection::pto`] -3714 fn max_pto_for_space(&self, space: SpaceKind) -> Duration { -3715 self.paths -3716 .keys() -3717 .map(|path_id| self.pto(space, *path_id)) -3718 .max() -3719 .unwrap_or_else(|| { -3720 // No paths remain (e.g. last path was abandoned and the NoAvailablePath grace timer -3721 // fired before any new path was opened). Fall back to a PTO derived from the -3722 // configured initial RTT, matching RFC 9002 §6.2.2 initial values. -3723 let rtt = self.config.initial_rtt; -3724 let max_ack_delay = match space { -3725 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO, -3726 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(), -3727 }; -3728 rtt + cmp::max(4 * (rtt / 2), TIMER_GRANULARITY) + max_ack_delay -3729 }) -3730 } -3731 -3732 /// Probe Timeout -3733 /// -3734 /// The PTO is logically the time in which you'd expect to receive an acknowledgement -3735 /// for a packet. So approximately RTT + max_ack_delay. -3736 fn pto(&self, space: SpaceKind, path_id: PathId) -> Duration { -3737 let max_ack_delay = match space { -3738 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO, -3739 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(), -3740 }; -3741 self.path_data(path_id).rtt.pto_base() + max_ack_delay -3742 } -3743 -3744 fn on_packet_authenticated( -3745 &mut self, -3746 now: Instant, -3747 space_id: SpaceKind, -3748 path_id: PathId, -3749 ecn: Option<EcnCodepoint>, -3750 packet_number: Option<u64>, -3751 spin: bool, -3752 is_1rtt: bool, -3753 remote: &FourTuple, -3754 ) { -3755 // During the handshake we already have discarded packets that do not match the path -3756 // remote. So any off-path packet here is either a probing packet or a -3757 // migration. Handling probing packets here means that the path's idle timeout will -3758 // be reset and will delay detecting the path as idle. However tail-loss probes -3759 // would still not get acknowledged if the path was broken so eventually the path -3760 // would still become idle. -3761 let is_on_path = self -3762 .path_data(path_id) -3763 .network_path -3764 .is_probably_same_path(remote); -3765 -3766 self.total_authed_packets += 1; -3767 self.reset_keep_alive(path_id, now); -3768 self.reset_idle_timeout(now, space_id, path_id); -3769 self.path_data_mut(path_id).permit_idle_reset = true; -3770 -3771 // Do not process ECN for off-path packets. If this is a migration we'll get ECN -3772 // back once we've migrated. -3773 if is_on_path { -3774 self.receiving_ecn |= ecn.is_some(); -3775 if let Some(x) = ecn { -3776 let space = &mut self.spaces[space_id]; -3777 space.for_path(path_id).ecn_counters += x; -3778 -3779 if x.is_ce() { -3780 space -3781 .for_path(path_id) -3782 .pending_acks -3783 .set_immediate_ack_required(); -3784 } -3785 } -3786 } -3787 -3788 let Some(packet_number) = packet_number else { -3789 return; -3790 }; -3791 match &self.side { -3792 ConnectionSide::Client { .. } => { -3793 // If we received a handshake packet that authenticated, then we're talking to -3794 // the real server. From now on we should no longer allow the server to migrate -3795 // its address. -3796 if space_id == SpaceKind::Handshake -3797 && let Some(hs) = self.state.as_handshake_mut() -3798 { -3799 hs.allow_server_migration = false; -3800 } -3801 } -3802 ConnectionSide::Server { .. } => { -3803 if self.crypto_state.has_keys(EncryptionLevel::Initial) -3804 && space_id == SpaceKind::Handshake -3805 { -3806 // A server stops sending and processing Initial packets when it receives its first Handshake packet. -3807 self.discard_space(now, SpaceKind::Initial); -3808 } -3809 if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) && is_1rtt { -3810 // Discard 0-RTT keys soon after receiving a 1-RTT packet -3811 self.set_key_discard_timer(now, space_id) -3812 } -3813 } -3814 } -3815 let space = self.spaces[space_id].for_path(path_id); -3816 -3817 space.pending_acks.insert_one(packet_number, now); -3818 if packet_number >= space.largest_received_packet_number.unwrap_or_default() { -3819 space.largest_received_packet_number = Some(packet_number); -3820 -3821 // Update outgoing spin bit for on-path packets, inverting iff we're the client -3822 if is_on_path { -3823 self.spin = self.side.is_client() ^ spin; -3824 } -3825 } -3826 } -3827 -3828 /// Resets the idle timeout timers -3829 /// -3830 /// Without multipath there is only the connection-wide idle timeout. When multipath is -3831 /// enabled there is an additional per-path idle timeout. -3832 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceKind, path_id: PathId) { -3833 // First reset the global idle timeout. -3834 if let Some(timeout) = self.idle_timeout { -3835 if self.state.is_closed() { -3836 self.timers -3837 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now)); -3838 } else { -3839 let dt = cmp::max(timeout, 3 * self.max_pto_for_space(space)); -3840 self.timers.set( -3841 Timer::Conn(ConnTimer::Idle), -3842 now + dt, -3843 self.qlog.with_time(now), -3844 ); -3845 } -3846 } -3847 -3848 // Now handle the per-path state -3849 if let Some(timeout) = self.path_data(path_id).idle_timeout { -3850 if self.state.is_closed() { -3851 self.timers.stop( -3852 Timer::PerPath(path_id, PathTimer::PathIdle), -3853 self.qlog.with_time(now), -3854 ); -3855 } else { -3856 let dt = cmp::max(timeout, 3 * self.pto(space, path_id)); -3857 self.timers.set( +3706 timeout, +3707 self.qlog.with_time(now), +3708 ); +3709 } else { +3710 self.timers.stop( +3711 Timer::PerPath(path_id, PathTimer::LossDetection), +3712 self.qlog.with_time(now), +3713 ); +3714 } +3715 } +3716 +3717 /// The maximum probe timeout across all paths +3718 /// +3719 /// See [`Connection::pto`] +3720 fn max_pto_for_space(&self, space: SpaceKind) -> Duration { +3721 self.paths +3722 .keys() +3723 .map(|path_id| self.pto(space, *path_id)) +3724 .max() +3725 .unwrap_or_else(|| { +3726 // No paths remain (e.g. last path was abandoned and the NoAvailablePath grace timer +3727 // fired before any new path was opened). Fall back to a PTO derived from the +3728 // configured initial RTT, matching RFC 9002 §6.2.2 initial values. +3729 let rtt = self.config.initial_rtt; +3730 let max_ack_delay = match space { +3731 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO, +3732 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(), +3733 }; +3734 rtt + cmp::max(4 * (rtt / 2), TIMER_GRANULARITY) + max_ack_delay +3735 }) +3736 } +3737 +3738 /// Probe Timeout +3739 /// +3740 /// The PTO is logically the time in which you'd expect to receive an acknowledgement +3741 /// for a packet. So approximately RTT + max_ack_delay. +3742 fn pto(&self, space: SpaceKind, path_id: PathId) -> Duration { +3743 let max_ack_delay = match space { +3744 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO, +3745 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(), +3746 }; +3747 self.path_data(path_id).rtt.pto_base() + max_ack_delay +3748 } +3749 +3750 fn on_packet_authenticated( +3751 &mut self, +3752 now: Instant, +3753 space_id: SpaceKind, +3754 path_id: PathId, +3755 ecn: Option<EcnCodepoint>, +3756 packet_number: Option<u64>, +3757 spin: bool, +3758 is_1rtt: bool, +3759 remote: &FourTuple, +3760 ) { +3761 // During the handshake we already have discarded packets that do not match the path +3762 // remote. So any off-path packet here is either a probing packet or a +3763 // migration. Handling probing packets here means that the path's idle timeout will +3764 // be reset and will delay detecting the path as idle. However tail-loss probes +3765 // would still not get acknowledged if the path was broken so eventually the path +3766 // would still become idle. +3767 let is_on_path = self +3768 .path_data(path_id) +3769 .network_path +3770 .is_probably_same_path(remote); +3771 +3772 self.total_authed_packets += 1; +3773 self.reset_keep_alive(path_id, now); +3774 self.reset_idle_timeout(now, space_id, path_id); +3775 self.path_data_mut(path_id).permit_idle_reset = true; +3776 +3777 // Do not process ECN for off-path packets. If this is a migration we'll get ECN +3778 // back once we've migrated. +3779 if is_on_path { +3780 self.receiving_ecn |= ecn.is_some(); +3781 if let Some(x) = ecn { +3782 let space = &mut self.spaces[space_id]; +3783 space.for_path(path_id).ecn_counters += x; +3784 +3785 if x.is_ce() { +3786 space +3787 .for_path(path_id) +3788 .pending_acks +3789 .set_immediate_ack_required(); +3790 } +3791 } +3792 } +3793 +3794 let Some(packet_number) = packet_number else { +3795 return; +3796 }; +3797 match &self.side { +3798 ConnectionSide::Client { .. } => { +3799 // If we received a handshake packet that authenticated, then we're talking to +3800 // the real server. From now on we should no longer allow the server to migrate +3801 // its address. +3802 if space_id == SpaceKind::Handshake +3803 && let Some(hs) = self.state.as_handshake_mut() +3804 { +3805 hs.allow_server_migration = false; +3806 } +3807 } +3808 ConnectionSide::Server { .. } => { +3809 if self.crypto_state.has_keys(EncryptionLevel::Initial) +3810 && space_id == SpaceKind::Handshake +3811 { +3812 // A server stops sending and processing Initial packets when it receives its first Handshake packet. +3813 self.discard_space(now, SpaceKind::Initial); +3814 } +3815 if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) && is_1rtt { +3816 // Discard 0-RTT keys soon after receiving a 1-RTT packet +3817 self.set_key_discard_timer(now, space_id) +3818 } +3819 } +3820 } +3821 let space = self.spaces[space_id].for_path(path_id); +3822 +3823 space.pending_acks.insert_one(packet_number, now); +3824 if packet_number >= space.largest_received_packet_number.unwrap_or_default() { +3825 space.largest_received_packet_number = Some(packet_number); +3826 +3827 // Update outgoing spin bit for on-path packets, inverting iff we're the client +3828 if is_on_path { +3829 self.spin = self.side.is_client() ^ spin; +3830 } +3831 } +3832 } +3833 +3834 /// Resets the idle timeout timers +3835 /// +3836 /// Without multipath there is only the connection-wide idle timeout. When multipath is +3837 /// enabled there is an additional per-path idle timeout. +3838 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceKind, path_id: PathId) { +3839 // First reset the global idle timeout. +3840 if let Some(timeout) = self.idle_timeout { +3841 if self.state.is_closed() { +3842 self.timers +3843 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now)); +3844 } else { +3845 let dt = cmp::max(timeout, 3 * self.max_pto_for_space(space)); +3846 self.timers.set( +3847 Timer::Conn(ConnTimer::Idle), +3848 now + dt, +3849 self.qlog.with_time(now), +3850 ); +3851 } +3852 } +3853 +3854 // Now handle the per-path state +3855 if let Some(timeout) = self.path_data(path_id).idle_timeout { +3856 if self.state.is_closed() { +3857 self.timers.stop( 3858 Timer::PerPath(path_id, PathTimer::PathIdle), -3859 now + dt, -3860 self.qlog.with_time(now), -3861 ); -3862 } -3863 } -3864 } -3865 -3866 /// Resets both the [`ConnTimer::KeepAlive`] and [`PathTimer::PathKeepAlive`] timers -3867 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) { -3868 if !self.state.is_established() { -3869 return; -3870 } +3859 self.qlog.with_time(now), +3860 ); +3861 } else { +3862 let dt = cmp::max(timeout, 3 * self.pto(space, path_id)); +3863 self.timers.set( +3864 Timer::PerPath(path_id, PathTimer::PathIdle), +3865 now + dt, +3866 self.qlog.with_time(now), +3867 ); +3868 } +3869 } +3870 } 3871 -3872 if let Some(interval) = self.config.keep_alive_interval { -3873 self.timers.set( -3874 Timer::Conn(ConnTimer::KeepAlive), -3875 now + interval, -3876 self.qlog.with_time(now), -3877 ); -3878 } -3879 -3880 if let Some(interval) = self.path_data(path_id).keep_alive { -3881 self.timers.set( -3882 Timer::PerPath(path_id, PathTimer::PathKeepAlive), -3883 now + interval, -3884 self.qlog.with_time(now), -3885 ); -3886 } -3887 } -3888 -3889 /// Sets the timer for when a previously issued CID should be retired next -3890 fn reset_cid_retirement(&mut self, now: Instant) { -3891 if let Some((_path, t)) = self.next_cid_retirement() { -3892 self.timers.set( -3893 Timer::Conn(ConnTimer::PushNewCid), -3894 t, -3895 self.qlog.with_time(now), -3896 ); -3897 } -3898 } -3899 -3900 /// The next time when a previously issued CID should be retired -3901 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> { -3902 self.local_cid_state -3903 .iter() -3904 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t))) -3905 .min_by_key(|(_path_id, timeout)| *timeout) -3906 } -3907 -3908 /// Handle the already-decrypted first packet from the client -3909 /// -3910 /// Decrypting the first packet in the `Endpoint` allows stateless packet handling to be more -3911 /// efficient. -3912 pub(crate) fn handle_first_packet( -3913 &mut self, -3914 now: Instant, -3915 network_path: FourTuple, -3916 ecn: Option<EcnCodepoint>, -3917 packet_number: u64, -3918 packet: InitialPacket, -3919 remaining: Option<BytesMut>, -3920 ) -> Result<(), ConnectionError> { -3921 let span = trace_span!("first recv"); -3922 let _guard = span.enter(); -3923 debug_assert!(self.side.is_server()); -3924 let len = packet.header_data.len() + packet.payload.len(); -3925 let path_id = PathId::ZERO; -3926 self.path_data_mut(path_id).total_recvd = len as u64; -3927 -3928 if let Some(hs) = self.state.as_handshake_mut() { -3929 hs.expected_token = packet.header.token.clone(); -3930 } else { -3931 unreachable!("first packet must be delivered in Handshake state"); -3932 } +3872 /// Resets both the [`ConnTimer::KeepAlive`] and [`PathTimer::PathKeepAlive`] timers +3873 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) { +3874 if !self.state.is_established() { +3875 return; +3876 } +3877 +3878 if let Some(interval) = self.config.keep_alive_interval { +3879 self.timers.set( +3880 Timer::Conn(ConnTimer::KeepAlive), +3881 now + interval, +3882 self.qlog.with_time(now), +3883 ); +3884 } +3885 +3886 if let Some(interval) = self.path_data(path_id).keep_alive { +3887 self.timers.set( +3888 Timer::PerPath(path_id, PathTimer::PathKeepAlive), +3889 now + interval, +3890 self.qlog.with_time(now), +3891 ); +3892 } +3893 } +3894 +3895 /// Sets the timer for when a previously issued CID should be retired next +3896 fn reset_cid_retirement(&mut self, now: Instant) { +3897 if let Some((_path, t)) = self.next_cid_retirement() { +3898 self.timers.set( +3899 Timer::Conn(ConnTimer::PushNewCid), +3900 t, +3901 self.qlog.with_time(now), +3902 ); +3903 } +3904 } +3905 +3906 /// The next time when a previously issued CID should be retired +3907 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> { +3908 self.local_cid_state +3909 .iter() +3910 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t))) +3911 .min_by_key(|(_path_id, timeout)| *timeout) +3912 } +3913 +3914 /// Handle the already-decrypted first packet from the client +3915 /// +3916 /// Decrypting the first packet in the `Endpoint` allows stateless packet handling to be more +3917 /// efficient. +3918 pub(crate) fn handle_first_packet( +3919 &mut self, +3920 now: Instant, +3921 network_path: FourTuple, +3922 ecn: Option<EcnCodepoint>, +3923 packet_number: u64, +3924 packet: InitialPacket, +3925 remaining: Option<BytesMut>, +3926 ) -> Result<(), ConnectionError> { +3927 let span = trace_span!("first recv"); +3928 let _guard = span.enter(); +3929 debug_assert!(self.side.is_server()); +3930 let len = packet.header_data.len() + packet.payload.len(); +3931 let path_id = PathId::ZERO; +3932 self.path_data_mut(path_id).total_recvd = len as u64; 3933 -3934 // The first packet is always on PathId::ZERO -3935 self.on_packet_authenticated( -3936 now, -3937 SpaceKind::Initial, -3938 path_id, -3939 ecn, -3940 Some(packet_number), -3941 false, -3942 false, -3943 &network_path, -3944 ); -3945 -3946 let packet: Packet = packet.into(); -3947 -3948 let mut qlog = QlogRecvPacket::new(len); -3949 qlog.header(&packet.header, Some(packet_number), path_id); -3950 -3951 self.process_decrypted_packet( -3952 now, -3953 network_path, -3954 path_id, -3955 Some(packet_number), -3956 packet, -3957 &mut qlog, -3958 )?; -3959 self.qlog.emit_packet_received(qlog, now); -3960 if let Some(data) = remaining { -3961 self.handle_coalesced(now, network_path, path_id, ecn, data); -3962 } -3963 -3964 self.qlog.emit_recovery_metrics( -3965 path_id, -3966 &mut self -3967 .paths -3968 .get_mut(&path_id) -3969 .expect("path_id was supplied by the caller for an active path") -3970 .data, -3971 now, -3972 ); -3973 -3974 Ok(()) -3975 } -3976 -3977 fn init_0rtt(&mut self, now: Instant) { -3978 let Some((header, packet)) = self.crypto_state.session.early_crypto() else { -3979 return; -3980 }; -3981 if self.side.is_client() { -3982 match self.crypto_state.session.transport_parameters() { -3983 Ok(params) => { -3984 let params = params -3985 .expect("crypto layer didn't supply transport parameters with ticket"); -3986 // Certain values must not be cached -3987 let params = TransportParameters { -3988 initial_src_cid: None, -3989 original_dst_cid: None, -3990 preferred_address: None, -3991 retry_src_cid: None, -3992 stateless_reset_token: None, -3993 min_ack_delay: None, -3994 ack_delay_exponent: TransportParameters::default().ack_delay_exponent, -3995 max_ack_delay: TransportParameters::default().max_ack_delay, -3996 initial_max_path_id: None, -3997 ..params -3998 }; -3999 self.set_peer_params(params); -4000 self.qlog.emit_peer_transport_params_restored(self, now); -4001 } -4002 Err(e) => { -4003 error!("session ticket has malformed transport parameters: {}", e); -4004 return; -4005 } -4006 } -4007 } -4008 trace!("0-RTT enabled"); -4009 self.crypto_state.enable_zero_rtt(header, packet); -4010 } -4011 -4012 fn read_crypto( -4013 &mut self, -4014 space: SpaceId, -4015 crypto: &frame::Crypto, -4016 payload_len: usize, -4017 ) -> Result<(), TransportError> { -4018 let expected = if !self.state.is_handshake() { -4019 SpaceId::Data -4020 } else if self.highest_space == SpaceKind::Initial { -4021 SpaceId::Initial -4022 } else { -4023 // On the server, self.highest_space can be Data after receiving the client's first -4024 // flight, but we expect Handshake CRYPTO until the handshake is complete. -4025 SpaceId::Handshake -4026 }; -4027 // We can't decrypt Handshake packets when highest_space is Initial, CRYPTO frames in 0-RTT -4028 // packets are illegal, and we don't process 1-RTT packets until the handshake is -4029 // complete. Therefore, we will never see CRYPTO data from a later-than-expected space. -4030 debug_assert!(space <= expected, "received out-of-order CRYPTO data"); -4031 -4032 let end = crypto.offset + crypto.data.len() as u64; -4033 if space < expected -4034 && end -4035 > self.crypto_state.spaces[space.kind()] -4036 .crypto_stream -4037 .bytes_read() -4038 { -4039 warn!( -4040 "received new {:?} CRYPTO data when expecting {:?}", -4041 space, expected -4042 ); -4043 return Err(TransportError::PROTOCOL_VIOLATION( -4044 "new data at unexpected encryption level", -4045 )); -4046 } -4047 -4048 let crypto_space = &mut self.crypto_state.spaces[space.kind()]; -4049 let max = end.saturating_sub(crypto_space.crypto_stream.bytes_read()); -4050 if max > self.config.crypto_buffer_size as u64 { -4051 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED("")); +3934 if let Some(hs) = self.state.as_handshake_mut() { +3935 hs.expected_token = packet.header.token.clone(); +3936 } else { +3937 unreachable!("first packet must be delivered in Handshake state"); +3938 } +3939 +3940 // The first packet is always on PathId::ZERO +3941 self.on_packet_authenticated( +3942 now, +3943 SpaceKind::Initial, +3944 path_id, +3945 ecn, +3946 Some(packet_number), +3947 false, +3948 false, +3949 &network_path, +3950 ); +3951 +3952 let packet: Packet = packet.into(); +3953 +3954 let mut qlog = QlogRecvPacket::new(len); +3955 qlog.header(&packet.header, Some(packet_number), path_id); +3956 +3957 self.process_decrypted_packet( +3958 now, +3959 network_path, +3960 path_id, +3961 Some(packet_number), +3962 packet, +3963 &mut qlog, +3964 )?; +3965 self.qlog.emit_packet_received(qlog, now); +3966 if let Some(data) = remaining { +3967 self.handle_coalesced(now, network_path, path_id, ecn, data); +3968 } +3969 +3970 self.qlog.emit_recovery_metrics( +3971 path_id, +3972 &mut self +3973 .paths +3974 .get_mut(&path_id) +3975 .expect("path_id was supplied by the caller for an active path") +3976 .data, +3977 now, +3978 ); +3979 +3980 Ok(()) +3981 } +3982 +3983 fn init_0rtt(&mut self, now: Instant) { +3984 let Some((header, packet)) = self.crypto_state.session.early_crypto() else { +3985 return; +3986 }; +3987 if self.side.is_client() { +3988 match self.crypto_state.session.transport_parameters() { +3989 Ok(params) => { +3990 let params = params +3991 .expect("crypto layer didn't supply transport parameters with ticket"); +3992 // Certain values must not be cached +3993 let params = TransportParameters { +3994 initial_src_cid: None, +3995 original_dst_cid: None, +3996 preferred_address: None, +3997 retry_src_cid: None, +3998 stateless_reset_token: None, +3999 min_ack_delay: None, +4000 ack_delay_exponent: TransportParameters::default().ack_delay_exponent, +4001 max_ack_delay: TransportParameters::default().max_ack_delay, +4002 initial_max_path_id: None, +4003 ..params +4004 }; +4005 self.set_peer_params(params); +4006 self.qlog.emit_peer_transport_params_restored(self, now); +4007 } +4008 Err(e) => { +4009 error!("session ticket has malformed transport parameters: {}", e); +4010 return; +4011 } +4012 } +4013 } +4014 trace!("0-RTT enabled"); +4015 self.crypto_state.enable_zero_rtt(header, packet); +4016 } +4017 +4018 fn read_crypto( +4019 &mut self, +4020 space: SpaceId, +4021 crypto: &frame::Crypto, +4022 payload_len: usize, +4023 ) -> Result<(), TransportError> { +4024 let expected = if !self.state.is_handshake() { +4025 SpaceId::Data +4026 } else if self.highest_space == SpaceKind::Initial { +4027 SpaceId::Initial +4028 } else { +4029 // On the server, self.highest_space can be Data after receiving the client's first +4030 // flight, but we expect Handshake CRYPTO until the handshake is complete. +4031 SpaceId::Handshake +4032 }; +4033 // We can't decrypt Handshake packets when highest_space is Initial, CRYPTO frames in 0-RTT +4034 // packets are illegal, and we don't process 1-RTT packets until the handshake is +4035 // complete. Therefore, we will never see CRYPTO data from a later-than-expected space. +4036 debug_assert!(space <= expected, "received out-of-order CRYPTO data"); +4037 +4038 let end = crypto.offset + crypto.data.len() as u64; +4039 if space < expected +4040 && end +4041 > self.crypto_state.spaces[space.kind()] +4042 .crypto_stream +4043 .bytes_read() +4044 { +4045 warn!( +4046 "received new {:?} CRYPTO data when expecting {:?}", +4047 space, expected +4048 ); +4049 return Err(TransportError::PROTOCOL_VIOLATION( +4050 "new data at unexpected encryption level", +4051 )); 4052 } 4053 -4054 crypto_space -4055 .crypto_stream -4056 .insert(crypto.offset, crypto.data.clone(), payload_len); -4057 while let Some(chunk) = crypto_space.crypto_stream.read(usize::MAX, true) { -4058 trace!("consumed {} CRYPTO bytes", chunk.bytes.len()); -4059 if self.crypto_state.session.read_handshake(&chunk.bytes)? { -4060 self.events.push_back(Event::HandshakeDataReady); -4061 } -4062 } -4063 -4064 Ok(()) -4065 } -4066 -4067 fn write_crypto(&mut self) { -4068 loop { -4069 let space = self.highest_space; -4070 let mut outgoing = Vec::new(); -4071 if let Some(crypto) = self.crypto_state.session.write_handshake(&mut outgoing) { -4072 match space { -4073 SpaceKind::Initial => { -4074 self.upgrade_crypto(SpaceKind::Handshake, crypto); -4075 } -4076 SpaceKind::Handshake => { -4077 self.upgrade_crypto(SpaceKind::Data, crypto); -4078 } -4079 SpaceKind::Data => unreachable!("got updated secrets during 1-RTT"), -4080 } -4081 } -4082 if outgoing.is_empty() { -4083 if space == self.highest_space { -4084 break; -4085 } else { -4086 // Keys updated, check for more data to send -4087 continue; -4088 } -4089 } -4090 let offset = self.crypto_state.spaces[space].crypto_offset; -4091 let outgoing = Bytes::from(outgoing); -4092 if let Some(hs) = self.state.as_handshake_mut() -4093 && space == SpaceKind::Initial -4094 && offset == 0 -4095 && self.side.is_client() -4096 { -4097 hs.client_hello = Some(outgoing.clone()); -4098 } -4099 self.crypto_state.spaces[space].crypto_offset += outgoing.len() as u64; -4100 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space); -4101 self.spaces[space].pending.crypto.push_back(frame::Crypto { -4102 offset, -4103 data: outgoing, -4104 }); -4105 } -4106 } -4107 -4108 /// Switch to stronger cryptography during handshake -4109 fn upgrade_crypto(&mut self, space: SpaceKind, crypto: Keys) { -4110 debug_assert!( -4111 !self.crypto_state.has_keys(space.encryption_level()), -4112 "already reached packet space {space:?}" -4113 ); -4114 trace!("{:?} keys ready", space); -4115 if space == SpaceKind::Data { -4116 // Precompute the first key update -4117 self.crypto_state.next_crypto = Some( -4118 self.crypto_state -4119 .session -4120 .next_1rtt_keys() -4121 .expect("handshake should be complete"), -4122 ); -4123 } -4124 -4125 self.crypto_state.spaces[space].keys = Some(crypto); -4126 debug_assert!(space > self.highest_space); -4127 self.highest_space = space; -4128 if space == SpaceKind::Data && self.side.is_client() { -4129 // Discard 0-RTT keys because 1-RTT keys are available. -4130 self.crypto_state.discard_zero_rtt(); -4131 } -4132 } -4133 -4134 fn discard_space(&mut self, now: Instant, space: SpaceKind) { -4135 debug_assert!(space != SpaceKind::Data); -4136 trace!("discarding {:?} keys", space); -4137 if space == SpaceKind::Initial { -4138 // No longer needed -4139 if let ConnectionSide::Client { token, .. } = &mut self.side { -4140 *token = Bytes::new(); -4141 } -4142 } -4143 self.crypto_state.spaces[space].keys = None; -4144 let space = &mut self.spaces[space]; -4145 let pns = space.for_path(PathId::ZERO); -4146 pns.time_of_last_ack_eliciting_packet = None; -4147 pns.loss_time = None; -4148 pns.loss_probes = 0; -4149 let sent_packets = mem::take(&mut pns.sent_packets); -4150 let path = self -4151 .paths -4152 .get_mut(&PathId::ZERO) -4153 .expect("PathId::ZERO is alive while Initial/Handshake spaces exist"); -4154 for (_, packet) in sent_packets.into_iter() { -4155 path.data.remove_in_flight(&packet); -4156 } -4157 -4158 self.set_loss_detection_timer(now, PathId::ZERO) -4159 } -4160 -4161 fn handle_coalesced( -4162 &mut self, -4163 now: Instant, -4164 network_path: FourTuple, -4165 path_id: PathId, -4166 ecn: Option<EcnCodepoint>, -4167 data: BytesMut, -4168 ) { -4169 self.path_data_mut(path_id) -4170 .inc_total_recvd(data.len() as u64); -4171 let mut remaining = Some(data); -4172 let cid_len = self -4173 .local_cid_state -4174 .values() -4175 .map(|cid_state| cid_state.cid_len()) -4176 .next() -4177 .expect("one cid_state must exist"); -4178 while let Some(data) = remaining { -4179 match PartialDecode::new( -4180 data, -4181 &FixedLengthConnectionIdParser::new(cid_len), -4182 &[self.version], -4183 self.endpoint_config.grease_quic_bit, -4184 ) { -4185 Ok((partial_decode, rest)) => { -4186 remaining = rest; -4187 self.handle_decode(now, network_path, path_id, ecn, partial_decode); -4188 } -4189 Err(e) => { -4190 trace!("malformed header: {}", e); -4191 return; -4192 } -4193 } -4194 } -4195 } -4196 -4197 /// Decrypts the packet and processes the payload. -4198 /// -4199 /// Processes the entire packet, starting with removing header protection, then handling -4200 /// a stateless reset if needed, and decrypting and processing the frames in the payload -4201 /// if not a stateless reset. -4202 fn handle_decode( -4203 &mut self, -4204 now: Instant, -4205 network_path: FourTuple, -4206 path_id: PathId, -4207 ecn: Option<EcnCodepoint>, -4208 partial_decode: PartialDecode, -4209 ) { -4210 let qlog = QlogRecvPacket::new(partial_decode.len()); -4211 if let Some(decoded) = self -4212 .crypto_state -4213 .unprotect_header(partial_decode, self.peer_params.stateless_reset_token) -4214 { -4215 self.handle_packet( -4216 now, -4217 network_path, -4218 path_id, -4219 ecn, -4220 decoded.packet, -4221 decoded.stateless_reset, -4222 qlog, -4223 ); -4224 } -4225 } -4226 -4227 /// Handles a packet with header protection removed. -4228 /// -4229 /// The packet body is still encrypted at this point. -4230 /// -4231 /// If the datagram was a stateless reset we may have failed to remove header protection -4232 /// and thus `packet` may be `None`. -4233 fn handle_packet( -4234 &mut self, -4235 now: Instant, -4236 network_path: FourTuple, -4237 path_id: PathId, -4238 ecn: Option<EcnCodepoint>, -4239 packet: Option<Packet>, -4240 stateless_reset: bool, -4241 mut qlog: QlogRecvPacket, -4242 ) { -4243 if let Some(ref packet) = packet { -4244 trace!( -4245 "got {:?} packet ({} bytes) from {} using id {}", -4246 packet.header.space(), -4247 packet.payload.len() + packet.header_data.len(), -4248 network_path, -4249 packet.header.dst_cid(), -4250 ); -4251 } -4252 -4253 let was_closed = self.state.is_closed(); -4254 let was_drained = self.state.is_drained(); -4255 -4256 // Now decrypt the packet payload in-place. -4257 let decrypted = match packet { -4258 None => Err(None), -4259 Some(mut packet) => self -4260 .decrypt_packet(now, path_id, &mut packet) -4261 .map(move |number| (packet, number)), -4262 }; -4263 let result = match decrypted { -4264 _ if stateless_reset => { -4265 debug!("got stateless reset"); -4266 Err(ConnectionError::Reset) -4267 } -4268 Err(Some(e)) => { -4269 warn!("illegal packet: {}", e); -4270 Err(e.into()) -4271 } -4272 Err(None) => { -4273 debug!("failed to authenticate packet"); -4274 self.authentication_failures += 1; -4275 let integrity_limit = self -4276 .crypto_state -4277 .integrity_limit(self.highest_space) -4278 .unwrap(); -4279 if self.authentication_failures > integrity_limit { -4280 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into()) -4281 } else { -4282 return; -4283 } -4284 } -4285 Ok((packet, pn)) => { -4286 // We received an authenticated packet and decrypted it. -4287 qlog.header(&packet.header, pn, path_id); -4288 let span = match pn { -4289 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn), -4290 None => trace_span!("recv", space = ?packet.header.space()), -4291 }; -4292 let _guard = span.enter(); -4293 -4294 // Now the packet is authenticated we do the migration during the handshake, -4295 // see Handshake::allow_server_migration for details. Be careful here to -4296 // not yet rely on the path existing however, new paths are accepted and -4297 // created later. -4298 // Note that we can't do any other migrations yet, for those we need to know -4299 // whether this was a probing packet or not. See the end of -4300 // Self::process_packet for that. -4301 if self.is_handshaking() -4302 && self -4303 .path(path_id) -4304 .map(|path_data| { -4305 !path_data.network_path.is_probably_same_path(&network_path) -4306 }) -4307 .unwrap_or(false) -4308 { -4309 if let Some(hs) = self.state.as_handshake() -4310 && hs.allow_server_migration -4311 { -4312 trace!( -4313 %network_path, -4314 prev = %self.path_data(path_id).network_path, -4315 "server migrated to new remote", -4316 ); -4317 self.path_data_mut(path_id).network_path = network_path; -4318 self.qlog.emit_tuple_assigned(path_id, network_path, now); -4319 } else { -4320 debug!( -4321 recv_path = %network_path, -4322 expected_path = %self.path_data_mut(path_id).network_path, -4323 "discarding packet with unexpected remote during handshake", -4324 ); -4325 return; -4326 } -4327 } -4328 -4329 let dedup = self.spaces[packet.header.space()] -4330 .path_space_mut(path_id) -4331 .map(|pns| &mut pns.dedup); -4332 if pn.zip(dedup).is_some_and(|(n, d)| d.insert(n)) { -4333 debug!("discarding possible duplicate packet"); -4334 self.qlog.emit_packet_received(qlog, now); -4335 return; -4336 } else if self.state.is_handshake() && packet.header.is_short() { -4337 // TODO: SHOULD buffer these to improve reordering tolerance. -4338 trace!("dropping short packet during handshake"); -4339 self.qlog.emit_packet_received(qlog, now); -4340 return; -4341 } else { -4342 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header -4343 && let Some(hs) = self.state.as_handshake() -4344 && self.side.is_server() -4345 && token != &hs.expected_token -4346 { -4347 // Clients must send the same retry token in every Initial. Initial -4348 // packets can be spoofed, so we discard rather than killing the -4349 // connection. -4350 warn!("discarding Initial with invalid retry token"); -4351 self.qlog.emit_packet_received(qlog, now); -4352 return; -4353 } -4354 -4355 if !self.state.is_closed() { -4356 let spin = match packet.header { -4357 Header::Short { spin, .. } => spin, -4358 _ => false, -4359 }; +4054 let crypto_space = &mut self.crypto_state.spaces[space.kind()]; +4055 let max = end.saturating_sub(crypto_space.crypto_stream.bytes_read()); +4056 if max > self.config.crypto_buffer_size as u64 { +4057 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED("")); +4058 } +4059 +4060 crypto_space +4061 .crypto_stream +4062 .insert(crypto.offset, crypto.data.clone(), payload_len); +4063 while let Some(chunk) = crypto_space.crypto_stream.read(usize::MAX, true) { +4064 trace!("consumed {} CRYPTO bytes", chunk.bytes.len()); +4065 if self.crypto_state.session.read_handshake(&chunk.bytes)? { +4066 self.events.push_back(Event::HandshakeDataReady); +4067 } +4068 } +4069 +4070 Ok(()) +4071 } +4072 +4073 fn write_crypto(&mut self) { +4074 loop { +4075 let space = self.highest_space; +4076 let mut outgoing = Vec::new(); +4077 if let Some(crypto) = self.crypto_state.session.write_handshake(&mut outgoing) { +4078 match space { +4079 SpaceKind::Initial => { +4080 self.upgrade_crypto(SpaceKind::Handshake, crypto); +4081 } +4082 SpaceKind::Handshake => { +4083 self.upgrade_crypto(SpaceKind::Data, crypto); +4084 } +4085 SpaceKind::Data => unreachable!("got updated secrets during 1-RTT"), +4086 } +4087 } +4088 if outgoing.is_empty() { +4089 if space == self.highest_space { +4090 break; +4091 } else { +4092 // Keys updated, check for more data to send +4093 continue; +4094 } +4095 } +4096 let offset = self.crypto_state.spaces[space].crypto_offset; +4097 let outgoing = Bytes::from(outgoing); +4098 if let Some(hs) = self.state.as_handshake_mut() +4099 && space == SpaceKind::Initial +4100 && offset == 0 +4101 && self.side.is_client() +4102 { +4103 hs.client_hello = Some(outgoing.clone()); +4104 } +4105 self.crypto_state.spaces[space].crypto_offset += outgoing.len() as u64; +4106 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space); +4107 self.spaces[space].pending.crypto.push_back(frame::Crypto { +4108 offset, +4109 data: outgoing, +4110 }); +4111 } +4112 } +4113 +4114 /// Switch to stronger cryptography during handshake +4115 fn upgrade_crypto(&mut self, space: SpaceKind, crypto: Keys) { +4116 debug_assert!( +4117 !self.crypto_state.has_keys(space.encryption_level()), +4118 "already reached packet space {space:?}" +4119 ); +4120 trace!("{:?} keys ready", space); +4121 if space == SpaceKind::Data { +4122 // Precompute the first key update +4123 self.crypto_state.next_crypto = Some( +4124 self.crypto_state +4125 .session +4126 .next_1rtt_keys() +4127 .expect("handshake should be complete"), +4128 ); +4129 } +4130 +4131 self.crypto_state.spaces[space].keys = Some(crypto); +4132 debug_assert!(space > self.highest_space); +4133 self.highest_space = space; +4134 if space == SpaceKind::Data && self.side.is_client() { +4135 // Discard 0-RTT keys because 1-RTT keys are available. +4136 self.crypto_state.discard_zero_rtt(); +4137 } +4138 } +4139 +4140 fn discard_space(&mut self, now: Instant, space: SpaceKind) { +4141 debug_assert!(space != SpaceKind::Data); +4142 trace!("discarding {:?} keys", space); +4143 if space == SpaceKind::Initial { +4144 // No longer needed +4145 if let ConnectionSide::Client { token, .. } = &mut self.side { +4146 *token = Bytes::new(); +4147 } +4148 } +4149 self.crypto_state.spaces[space].keys = None; +4150 let space = &mut self.spaces[space]; +4151 let pns = space.for_path(PathId::ZERO); +4152 pns.time_of_last_ack_eliciting_packet = None; +4153 pns.loss_time = None; +4154 pns.loss_probes = 0; +4155 let sent_packets = mem::take(&mut pns.sent_packets); +4156 let path = self +4157 .paths +4158 .get_mut(&PathId::ZERO) +4159 .expect("PathId::ZERO is alive while Initial/Handshake spaces exist"); +4160 for (_, packet) in sent_packets.into_iter() { +4161 path.data.remove_in_flight(&packet); +4162 } +4163 +4164 self.set_loss_detection_timer(now, PathId::ZERO) +4165 } +4166 +4167 fn handle_coalesced( +4168 &mut self, +4169 now: Instant, +4170 network_path: FourTuple, +4171 path_id: PathId, +4172 ecn: Option<EcnCodepoint>, +4173 data: BytesMut, +4174 ) { +4175 self.path_data_mut(path_id) +4176 .inc_total_recvd(data.len() as u64); +4177 let mut remaining = Some(data); +4178 let cid_len = self +4179 .local_cid_state +4180 .values() +4181 .map(|cid_state| cid_state.cid_len()) +4182 .next() +4183 .expect("one cid_state must exist"); +4184 while let Some(data) = remaining { +4185 match PartialDecode::new( +4186 data, +4187 &FixedLengthConnectionIdParser::new(cid_len), +4188 &[self.version], +4189 self.endpoint_config.grease_quic_bit, +4190 ) { +4191 Ok((partial_decode, rest)) => { +4192 remaining = rest; +4193 self.handle_decode(now, network_path, path_id, ecn, partial_decode); +4194 } +4195 Err(e) => { +4196 trace!("malformed header: {}", e); +4197 return; +4198 } +4199 } +4200 } +4201 } +4202 +4203 /// Decrypts the packet and processes the payload. +4204 /// +4205 /// Processes the entire packet, starting with removing header protection, then handling +4206 /// a stateless reset if needed, and decrypting and processing the frames in the payload +4207 /// if not a stateless reset. +4208 fn handle_decode( +4209 &mut self, +4210 now: Instant, +4211 network_path: FourTuple, +4212 path_id: PathId, +4213 ecn: Option<EcnCodepoint>, +4214 partial_decode: PartialDecode, +4215 ) { +4216 let qlog = QlogRecvPacket::new(partial_decode.len()); +4217 if let Some(decoded) = self +4218 .crypto_state +4219 .unprotect_header(partial_decode, self.peer_params.stateless_reset_token) +4220 { +4221 self.handle_packet( +4222 now, +4223 network_path, +4224 path_id, +4225 ecn, +4226 decoded.packet, +4227 decoded.stateless_reset, +4228 qlog, +4229 ); +4230 } +4231 } +4232 +4233 /// Handles a packet with header protection removed. +4234 /// +4235 /// The packet body is still encrypted at this point. +4236 /// +4237 /// If the datagram was a stateless reset we may have failed to remove header protection +4238 /// and thus `packet` may be `None`. +4239 fn handle_packet( +4240 &mut self, +4241 now: Instant, +4242 network_path: FourTuple, +4243 path_id: PathId, +4244 ecn: Option<EcnCodepoint>, +4245 packet: Option<Packet>, +4246 stateless_reset: bool, +4247 mut qlog: QlogRecvPacket, +4248 ) { +4249 if let Some(ref packet) = packet { +4250 trace!( +4251 "got {:?} packet ({} bytes) from {} using id {}", +4252 packet.header.space(), +4253 packet.payload.len() + packet.header_data.len(), +4254 network_path, +4255 packet.header.dst_cid(), +4256 ); +4257 } +4258 +4259 let was_closed = self.state.is_closed(); +4260 let was_drained = self.state.is_drained(); +4261 +4262 // Now decrypt the packet payload in-place. +4263 let decrypted = match packet { +4264 None => Err(None), +4265 Some(mut packet) => self +4266 .decrypt_packet(now, path_id, &mut packet) +4267 .map(move |number| (packet, number)), +4268 }; +4269 let result = match decrypted { +4270 _ if stateless_reset => { +4271 debug!("got stateless reset"); +4272 Err(ConnectionError::Reset) +4273 } +4274 Err(Some(e)) => { +4275 warn!("illegal packet: {}", e); +4276 Err(e.into()) +4277 } +4278 Err(None) => { +4279 debug!("failed to authenticate packet"); +4280 self.authentication_failures += 1; +4281 let integrity_limit = self +4282 .crypto_state +4283 .integrity_limit(self.highest_space) +4284 .unwrap(); +4285 if self.authentication_failures > integrity_limit { +4286 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into()) +4287 } else { +4288 return; +4289 } +4290 } +4291 Ok((packet, pn)) => { +4292 // We received an authenticated packet and decrypted it. +4293 qlog.header(&packet.header, pn, path_id); +4294 let span = match pn { +4295 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn), +4296 None => trace_span!("recv", space = ?packet.header.space()), +4297 }; +4298 let _guard = span.enter(); +4299 +4300 // Now the packet is authenticated we do the migration during the handshake, +4301 // see Handshake::allow_server_migration for details. Be careful here to +4302 // not yet rely on the path existing however, new paths are accepted and +4303 // created later. +4304 // Note that we can't do any other migrations yet, for those we need to know +4305 // whether this was a probing packet or not. See the end of +4306 // Self::process_packet for that. +4307 if self.is_handshaking() +4308 && self +4309 .path(path_id) +4310 .map(|path_data| { +4311 !path_data.network_path.is_probably_same_path(&network_path) +4312 }) +4313 .unwrap_or(false) +4314 { +4315 if let Some(hs) = self.state.as_handshake() +4316 && hs.allow_server_migration +4317 { +4318 trace!( +4319 %network_path, +4320 prev = %self.path_data(path_id).network_path, +4321 "server migrated to new remote", +4322 ); +4323 self.path_data_mut(path_id).network_path = network_path; +4324 self.qlog.emit_tuple_assigned(path_id, network_path, now); +4325 } else { +4326 debug!( +4327 recv_path = %network_path, +4328 expected_path = %self.path_data_mut(path_id).network_path, +4329 "discarding packet with unexpected remote during handshake", +4330 ); +4331 return; +4332 } +4333 } +4334 +4335 let dedup = self.spaces[packet.header.space()] +4336 .path_space_mut(path_id) +4337 .map(|pns| &mut pns.dedup); +4338 if pn.zip(dedup).is_some_and(|(n, d)| d.insert(n)) { +4339 debug!("discarding possible duplicate packet"); +4340 self.qlog.emit_packet_received(qlog, now); +4341 return; +4342 } else if self.state.is_handshake() && packet.header.is_short() { +4343 // TODO: SHOULD buffer these to improve reordering tolerance. +4344 trace!("dropping short packet during handshake"); +4345 self.qlog.emit_packet_received(qlog, now); +4346 return; +4347 } else { +4348 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header +4349 && let Some(hs) = self.state.as_handshake() +4350 && self.side.is_server() +4351 && token != &hs.expected_token +4352 { +4353 // Clients must send the same retry token in every Initial. Initial +4354 // packets can be spoofed, so we discard rather than killing the +4355 // connection. +4356 warn!("discarding Initial with invalid retry token"); +4357 self.qlog.emit_packet_received(qlog, now); +4358 return; +4359 } 4360 -4361 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) { -4362 // Only the client is allowed to open paths -4363 self.ensure_path(path_id, network_path, now, pn); -4364 } -4365 if self.paths.contains_key(&path_id) { -4366 self.on_packet_authenticated( -4367 now, -4368 packet.header.space(), -4369 path_id, -4370 ecn, -4371 pn, -4372 spin, -4373 packet.header.is_1rtt(), -4374 &network_path, -4375 ); -4376 } -4377 } -4378 -4379 let res = self.process_decrypted_packet( -4380 now, -4381 network_path, -4382 path_id, -4383 pn, -4384 packet, -4385 &mut qlog, -4386 ); -4387 -4388 self.qlog.emit_packet_received(qlog, now); -4389 res -4390 } -4391 } -4392 }; +4361 if !self.state.is_closed() { +4362 let spin = match packet.header { +4363 Header::Short { spin, .. } => spin, +4364 _ => false, +4365 }; +4366 +4367 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) { +4368 // Only the client is allowed to open paths +4369 self.ensure_path(path_id, network_path, now, pn); +4370 } +4371 if self.paths.contains_key(&path_id) { +4372 self.on_packet_authenticated( +4373 now, +4374 packet.header.space(), +4375 path_id, +4376 ecn, +4377 pn, +4378 spin, +4379 packet.header.is_1rtt(), +4380 &network_path, +4381 ); +4382 } +4383 } +4384 +4385 let res = self.process_decrypted_packet( +4386 now, +4387 network_path, +4388 path_id, +4389 pn, +4390 packet, +4391 &mut qlog, +4392 ); 4393 -4394 // State transitions for error cases -4395 if let Err(conn_err) = result { -4396 match conn_err { -4397 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason), -4398 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason), -4399 ConnectionError::Reset -4400 | ConnectionError::TransportError(TransportError { -4401 code: TransportErrorCode::AEAD_LIMIT_REACHED, -4402 .. -4403 }) => { -4404 let was_draining = self.state.move_to_drained(Some(conn_err)); -4405 if !was_draining { -4406 self.endpoint_events.push_back(EndpointEventInner::Draining); -4407 } -4408 } -4409 ConnectionError::TimedOut => { -4410 unreachable!("timeouts aren't generated by packet processing"); -4411 } -4412 ConnectionError::TransportError(err) => { -4413 debug!("closing connection due to transport error: {}", err); -4414 self.state.move_to_closed(err); -4415 } -4416 ConnectionError::VersionMismatch => { -4417 self.state.move_to_draining(Some(conn_err)); -4418 self.endpoint_events.push_back(EndpointEventInner::Draining); -4419 } -4420 ConnectionError::LocallyClosed => { -4421 unreachable!("LocallyClosed isn't generated by packet processing"); -4422 } -4423 ConnectionError::CidsExhausted => { -4424 unreachable!("CidsExhausted isn't generated by packet processing"); +4394 self.qlog.emit_packet_received(qlog, now); +4395 res +4396 } +4397 } +4398 }; +4399 +4400 // State transitions for error cases +4401 if let Err(conn_err) = result { +4402 match conn_err { +4403 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason), +4404 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason), +4405 ConnectionError::Reset +4406 | ConnectionError::TransportError(TransportError { +4407 code: TransportErrorCode::AEAD_LIMIT_REACHED, +4408 .. +4409 }) => { +4410 let was_draining = self.state.move_to_drained(Some(conn_err)); +4411 if !was_draining { +4412 self.endpoint_events.push_back(EndpointEventInner::Draining); +4413 } +4414 } +4415 ConnectionError::TimedOut => { +4416 unreachable!("timeouts aren't generated by packet processing"); +4417 } +4418 ConnectionError::TransportError(err) => { +4419 debug!("closing connection due to transport error: {}", err); +4420 self.state.move_to_closed(err); +4421 } +4422 ConnectionError::VersionMismatch => { +4423 self.state.move_to_draining(Some(conn_err)); +4424 self.endpoint_events.push_back(EndpointEventInner::Draining); 4425 } -4426 }; -4427 } -4428 -4429 if !was_closed && self.state.is_closed() { -4430 self.close_common(); -4431 if !self.state.is_drained() { -4432 self.set_close_timer(now); -4433 } -4434 } -4435 if !was_drained && self.state.is_drained() { -4436 self.endpoint_events.push_back(EndpointEventInner::Drained); -4437 // Close timer may have been started previously, e.g. if we sent a close and got a -4438 // stateless reset in response -4439 self.timers -4440 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now)); -4441 } -4442 -4443 // Transmit CONNECTION_CLOSE if necessary. -4444 // -4445 // If we received a valid packet and we are in the closed state we should respond -4446 // with a CONNECTION_CLOSE frame. -4447 // TODO: This SHOULD be rate-limited according to §10.2.1 of QUIC-TRANSPORT, but -4448 // that does not yet happen. This is triggered by each received packet. -4449 if matches!(self.state.as_type(), StateType::Closed) { -4450 // From https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2.1-7 -4451 // -4452 // While in the closing state we must either: -4453 // - discard packets coming from an un-validated remote OR -4454 // - ensure we do not send more than 3 times the received data -4455 // -4456 // Doing the 2nd would mean we would be able to send CONNECTION_CLOSE to a peer -4457 // who was (involuntary) migrated just at the time we initiated immediate -4458 // close. It is a lot more work though. So while we would like to do this for -4459 // now we only do 1. -4460 // -4461 // Another shortcoming of the current implementation is that when we have a -4462 // previous PathData which is validated and the remote matches that path, we -4463 // should schedule CONNECTION_CLOSE on that path. However currently we can not -4464 // schedule such a packet. We should also fix this some day. This makes us -4465 // vulnerable to an attacker faking a migration at the right time and then we'd -4466 // be unable to send the CONNECTION_CLOSE to the real remote. -4467 if self -4468 .paths -4469 .get(&path_id) -4470 .map(|p| p.data.validated && p.data.network_path == network_path) -4471 .unwrap_or(false) -4472 { -4473 self.connection_close_pending = true; -4474 } -4475 } -4476 } -4477 -4478 fn process_decrypted_packet( -4479 &mut self, -4480 now: Instant, -4481 network_path: FourTuple, -4482 path_id: PathId, -4483 number: Option<u64>, -4484 packet: Packet, -4485 qlog: &mut QlogRecvPacket, -4486 ) -> Result<(), ConnectionError> { -4487 if !self.paths.contains_key(&path_id) { -4488 // There is a chance this is a server side, first (for this path) packet, which would -4489 // be a protocol violation. It's more likely, however, that this is a packet of a -4490 // pruned path -4491 trace!(%path_id, ?number, "discarding packet for unknown path"); -4492 return Ok(()); -4493 } -4494 let state = match self.state.as_type() { -4495 StateType::Established => { -4496 match packet.header.space() { -4497 SpaceKind::Data => self.process_payload( -4498 now, -4499 network_path, -4500 path_id, -4501 number.unwrap(), -4502 packet, -4503 qlog, -4504 )?, -4505 _ if packet.header.has_frames() => { -4506 self.process_early_payload(now, path_id, packet, qlog)? -4507 } -4508 _ => { -4509 trace!("discarding unexpected pre-handshake packet"); -4510 } -4511 } -4512 return Ok(()); -4513 } -4514 StateType::Closed => { -4515 for result in frame::Iter::new(packet.payload.freeze())? { -4516 let frame = match result { -4517 Ok(frame) => frame, -4518 Err(err) => { -4519 debug!("frame decoding error: {err:?}"); -4520 continue; -4521 } -4522 }; -4523 qlog.frame(&frame); -4524 -4525 if let Frame::Padding = frame { -4526 continue; -4527 }; -4528 -4529 trace!(?frame, "processing frame in closed state"); +4426 ConnectionError::LocallyClosed => { +4427 unreachable!("LocallyClosed isn't generated by packet processing"); +4428 } +4429 ConnectionError::CidsExhausted => { +4430 unreachable!("CidsExhausted isn't generated by packet processing"); +4431 } +4432 }; +4433 } +4434 +4435 if !was_closed && self.state.is_closed() { +4436 self.close_common(); +4437 if !self.state.is_drained() { +4438 self.set_close_timer(now); +4439 } +4440 } +4441 if !was_drained && self.state.is_drained() { +4442 self.endpoint_events.push_back(EndpointEventInner::Drained); +4443 // Close timer may have been started previously, e.g. if we sent a close and got a +4444 // stateless reset in response +4445 self.timers +4446 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now)); +4447 } +4448 +4449 // Transmit CONNECTION_CLOSE if necessary. +4450 // +4451 // If we received a valid packet and we are in the closed state we should respond +4452 // with a CONNECTION_CLOSE frame. +4453 // TODO: This SHOULD be rate-limited according to §10.2.1 of QUIC-TRANSPORT, but +4454 // that does not yet happen. This is triggered by each received packet. +4455 if matches!(self.state.as_type(), StateType::Closed) { +4456 // From https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2.1-7 +4457 // +4458 // While in the closing state we must either: +4459 // - discard packets coming from an un-validated remote OR +4460 // - ensure we do not send more than 3 times the received data +4461 // +4462 // Doing the 2nd would mean we would be able to send CONNECTION_CLOSE to a peer +4463 // who was (involuntary) migrated just at the time we initiated immediate +4464 // close. It is a lot more work though. So while we would like to do this for +4465 // now we only do 1. +4466 // +4467 // Another shortcoming of the current implementation is that when we have a +4468 // previous PathData which is validated and the remote matches that path, we +4469 // should schedule CONNECTION_CLOSE on that path. However currently we can not +4470 // schedule such a packet. We should also fix this some day. This makes us +4471 // vulnerable to an attacker faking a migration at the right time and then we'd +4472 // be unable to send the CONNECTION_CLOSE to the real remote. +4473 if self +4474 .paths +4475 .get(&path_id) +4476 .map(|p| p.data.validated && p.data.network_path == network_path) +4477 .unwrap_or(false) +4478 { +4479 self.connection_close_pending = true; +4480 } +4481 } +4482 } +4483 +4484 fn process_decrypted_packet( +4485 &mut self, +4486 now: Instant, +4487 network_path: FourTuple, +4488 path_id: PathId, +4489 number: Option<u64>, +4490 packet: Packet, +4491 qlog: &mut QlogRecvPacket, +4492 ) -> Result<(), ConnectionError> { +4493 if !self.paths.contains_key(&path_id) { +4494 // There is a chance this is a server side, first (for this path) packet, which would +4495 // be a protocol violation. It's more likely, however, that this is a packet of a +4496 // pruned path +4497 trace!(%path_id, ?number, "discarding packet for unknown path"); +4498 return Ok(()); +4499 } +4500 let state = match self.state.as_type() { +4501 StateType::Established => { +4502 match packet.header.space() { +4503 SpaceKind::Data => self.process_payload( +4504 now, +4505 network_path, +4506 path_id, +4507 number.unwrap(), +4508 packet, +4509 qlog, +4510 )?, +4511 _ if packet.header.has_frames() => { +4512 self.process_early_payload(now, path_id, packet, qlog)? +4513 } +4514 _ => { +4515 trace!("discarding unexpected pre-handshake packet"); +4516 } +4517 } +4518 return Ok(()); +4519 } +4520 StateType::Closed => { +4521 for result in frame::Iter::new(packet.payload.freeze())? { +4522 let frame = match result { +4523 Ok(frame) => frame, +4524 Err(err) => { +4525 debug!("frame decoding error: {err:?}"); +4526 continue; +4527 } +4528 }; +4529 qlog.frame(&frame); 4530 -4531 self.path_stats -4532 .for_path(path_id) -4533 .frame_rx -4534 .record(frame.ty()); -4535 -4536 if let Frame::Close(_error) = frame { -4537 self.state.move_to_draining(None); -4538 self.endpoint_events.push_back(EndpointEventInner::Draining); -4539 break; -4540 } -4541 } -4542 return Ok(()); -4543 } -4544 StateType::Draining | StateType::Drained => return Ok(()), -4545 StateType::Handshake => self.state.as_handshake_mut().expect("checked"), -4546 }; -4547 -4548 match packet.header { -4549 Header::Retry { -4550 src_cid: remote_cid, -4551 .. -4552 } => { -4553 debug_assert_eq!(path_id, PathId::ZERO); -4554 if self.side.is_server() { -4555 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into()); -4556 } -4557 -4558 let is_valid_retry = self -4559 .remote_cids -4560 .get(&path_id) -4561 .map(|cids| cids.active()) -4562 .map(|orig_dst_cid| { -4563 self.crypto_state.session.is_valid_retry( -4564 orig_dst_cid, -4565 &packet.header_data, -4566 &packet.payload, -4567 ) -4568 }) -4569 .unwrap_or_default(); -4570 if self.total_authed_packets > 1 -4571 || packet.payload.len() <= 16 // token + 16 byte tag -4572 || !is_valid_retry -4573 { -4574 trace!("discarding invalid Retry"); -4575 // - After the client has received and processed an Initial or Retry -4576 // packet from the server, it MUST discard any subsequent Retry -4577 // packets that it receives. -4578 // - A client MUST discard a Retry packet with a zero-length Retry Token -4579 // field. -4580 // - Clients MUST discard Retry packets that have a Retry Integrity Tag -4581 // that cannot be validated -4582 return Ok(()); -4583 } -4584 -4585 trace!("retrying with CID {}", remote_cid); -4586 let client_hello = state.client_hello.take().unwrap(); -4587 self.retry_src_cid = Some(remote_cid); -4588 self.remote_cids -4589 .get_mut(&path_id) -4590 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false") -4591 .update_initial_cid(remote_cid); -4592 self.remote_handshake_cid = remote_cid; -4593 -4594 let space = &mut self.spaces[SpaceId::Initial]; -4595 if let Some(info) = space.for_path(PathId::ZERO).take(0) { -4596 self.on_packet_acked(now, PathId::ZERO, 0, info); -4597 }; -4598 -4599 self.discard_space(now, SpaceKind::Initial); // Make sure we clean up after -4600 // any retransmitted Initials -4601 let crypto_space = &mut self.crypto_state.spaces[SpaceKind::Initial]; -4602 crypto_space.keys = Some( -4603 self.crypto_state -4604 .session -4605 .initial_keys(remote_cid, self.side.side()), -4606 ); -4607 crypto_space.crypto_offset = client_hello.len() as u64; -4608 -4609 let next_pn = self.spaces[SpaceId::Initial] -4610 .for_path(path_id) -4611 .next_packet_number; -4612 self.spaces[SpaceId::Initial] = { -4613 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng); -4614 space.for_path(path_id).next_packet_number = next_pn; -4615 space.pending.crypto.push_back(frame::Crypto { -4616 offset: 0, -4617 data: client_hello, -4618 }); -4619 space -4620 }; -4621 -4622 // Retransmit all 0-RTT data -4623 let zero_rtt = mem::take( -4624 &mut self.spaces[SpaceId::Data] -4625 .for_path(PathId::ZERO) -4626 .sent_packets, -4627 ); -4628 for (_, info) in zero_rtt.into_iter() { -4629 self.paths -4630 .get_mut(&PathId::ZERO) -4631 .unwrap() -4632 .remove_in_flight(&info); -4633 self.spaces[SpaceId::Data].pending |= info.retransmits; -4634 } -4635 self.streams.retransmit_all_for_0rtt(); -4636 -4637 let token_len = packet.payload.len() - 16; -4638 let ConnectionSide::Client { ref mut token, .. } = self.side else { -4639 unreachable!("we already short-circuited if we're server"); -4640 }; -4641 *token = packet.payload.freeze().split_to(token_len); -4642 -4643 self.state = State::handshake(state::Handshake { -4644 expected_token: Bytes::new(), -4645 remote_cid_set: false, -4646 client_hello: None, -4647 allow_server_migration: self.config.server_handshake_migration, -4648 }); -4649 Ok(()) -4650 } -4651 Header::Long { -4652 ty: LongType::Handshake, -4653 src_cid: remote_cid, -4654 dst_cid: local_cid, -4655 .. -4656 } => { -4657 debug_assert_eq!(path_id, PathId::ZERO); -4658 if remote_cid != self.remote_handshake_cid { -4659 debug!( -4660 "discarding packet with mismatched remote CID: {} != {}", -4661 self.remote_handshake_cid, remote_cid -4662 ); -4663 return Ok(()); -4664 } -4665 self.on_path_validated(path_id); -4666 -4667 self.process_early_payload(now, path_id, packet, qlog)?; -4668 if self.state.is_closed() { -4669 return Ok(()); -4670 } -4671 -4672 if self.crypto_state.session.is_handshaking() { -4673 trace!("handshake ongoing"); -4674 return Ok(()); -4675 } -4676 -4677 if self.side.is_client() { -4678 // Client-only because server params were set from the client's Initial -4679 let params = self -4680 .crypto_state -4681 .session -4682 .transport_parameters()? -4683 .ok_or_else(|| { -4684 TransportError::new( -4685 TransportErrorCode::crypto(0x6d), -4686 "transport parameters missing".to_owned(), -4687 ) -4688 })?; -4689 -4690 if self.has_0rtt() { -4691 if !self.crypto_state.session.early_data_accepted().unwrap() { -4692 debug_assert!(self.side.is_client()); -4693 debug!("0-RTT rejected"); -4694 self.crypto_state.accepted_0rtt = false; -4695 self.streams.zero_rtt_rejected(); -4696 -4697 // Discard already-queued frames -4698 self.spaces[SpaceId::Data].pending = Retransmits::default(); +4531 if let Frame::Padding = frame { +4532 continue; +4533 }; +4534 +4535 trace!(?frame, "processing frame in closed state"); +4536 +4537 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty()); +4538 +4539 if let Frame::Close(_error) = frame { +4540 self.state.move_to_draining(None); +4541 self.endpoint_events.push_back(EndpointEventInner::Draining); +4542 break; +4543 } +4544 } +4545 return Ok(()); +4546 } +4547 StateType::Draining | StateType::Drained => return Ok(()), +4548 StateType::Handshake => self.state.as_handshake_mut().expect("checked"), +4549 }; +4550 +4551 match packet.header { +4552 Header::Retry { +4553 src_cid: remote_cid, +4554 .. +4555 } => { +4556 debug_assert_eq!(path_id, PathId::ZERO); +4557 if self.side.is_server() { +4558 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into()); +4559 } +4560 +4561 let is_valid_retry = self +4562 .remote_cids +4563 .get(&path_id) +4564 .map(|cids| cids.active()) +4565 .map(|orig_dst_cid| { +4566 self.crypto_state.session.is_valid_retry( +4567 orig_dst_cid, +4568 &packet.header_data, +4569 &packet.payload, +4570 ) +4571 }) +4572 .unwrap_or_default(); +4573 if self.total_authed_packets > 1 +4574 || packet.payload.len() <= 16 // token + 16 byte tag +4575 || !is_valid_retry +4576 { +4577 trace!("discarding invalid Retry"); +4578 // - After the client has received and processed an Initial or Retry +4579 // packet from the server, it MUST discard any subsequent Retry +4580 // packets that it receives. +4581 // - A client MUST discard a Retry packet with a zero-length Retry Token +4582 // field. +4583 // - Clients MUST discard Retry packets that have a Retry Integrity Tag +4584 // that cannot be validated +4585 return Ok(()); +4586 } +4587 +4588 trace!("retrying with CID {}", remote_cid); +4589 let client_hello = state.client_hello.take().unwrap(); +4590 self.retry_src_cid = Some(remote_cid); +4591 self.remote_cids +4592 .get_mut(&path_id) +4593 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false") +4594 .update_initial_cid(remote_cid); +4595 self.remote_handshake_cid = remote_cid; +4596 +4597 let space = &mut self.spaces[SpaceId::Initial]; +4598 if let Some(info) = space.for_path(PathId::ZERO).take(0) { +4599 self.on_packet_acked(now, PathId::ZERO, 0, info); +4600 }; +4601 +4602 self.discard_space(now, SpaceKind::Initial); // Make sure we clean up after +4603 // any retransmitted Initials +4604 let crypto_space = &mut self.crypto_state.spaces[SpaceKind::Initial]; +4605 crypto_space.keys = Some( +4606 self.crypto_state +4607 .session +4608 .initial_keys(remote_cid, self.side.side()), +4609 ); +4610 crypto_space.crypto_offset = client_hello.len() as u64; +4611 +4612 let next_pn = self.spaces[SpaceId::Initial] +4613 .for_path(path_id) +4614 .next_packet_number; +4615 self.spaces[SpaceId::Initial] = { +4616 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng); +4617 space.for_path(path_id).next_packet_number = next_pn; +4618 space.pending.crypto.push_back(frame::Crypto { +4619 offset: 0, +4620 data: client_hello, +4621 }); +4622 space +4623 }; +4624 +4625 // Retransmit all 0-RTT data +4626 let zero_rtt = mem::take( +4627 &mut self.spaces[SpaceId::Data] +4628 .for_path(PathId::ZERO) +4629 .sent_packets, +4630 ); +4631 for (_, info) in zero_rtt.into_iter() { +4632 self.paths +4633 .get_mut(&PathId::ZERO) +4634 .unwrap() +4635 .remove_in_flight(&info); +4636 self.spaces[SpaceId::Data].pending |= info.retransmits; +4637 } +4638 self.streams.retransmit_all_for_0rtt(); +4639 +4640 let token_len = packet.payload.len() - 16; +4641 let ConnectionSide::Client { ref mut token, .. } = self.side else { +4642 unreachable!("we already short-circuited if we're server"); +4643 }; +4644 *token = packet.payload.freeze().split_to(token_len); +4645 +4646 self.state = State::handshake(state::Handshake { +4647 expected_token: Bytes::new(), +4648 remote_cid_set: false, +4649 client_hello: None, +4650 allow_server_migration: self.config.server_handshake_migration, +4651 }); +4652 Ok(()) +4653 } +4654 Header::Long { +4655 ty: LongType::Handshake, +4656 src_cid: remote_cid, +4657 dst_cid: local_cid, +4658 .. +4659 } => { +4660 debug_assert_eq!(path_id, PathId::ZERO); +4661 if remote_cid != self.remote_handshake_cid { +4662 debug!( +4663 "discarding packet with mismatched remote CID: {} != {}", +4664 self.remote_handshake_cid, remote_cid +4665 ); +4666 return Ok(()); +4667 } +4668 self.on_path_validated(path_id); +4669 +4670 self.process_early_payload(now, path_id, packet, qlog)?; +4671 if self.state.is_closed() { +4672 return Ok(()); +4673 } +4674 +4675 if self.crypto_state.session.is_handshaking() { +4676 trace!("handshake ongoing"); +4677 return Ok(()); +4678 } +4679 +4680 if self.side.is_client() { +4681 // Client-only because server params were set from the client's Initial +4682 let params = self +4683 .crypto_state +4684 .session +4685 .transport_parameters()? +4686 .ok_or_else(|| { +4687 TransportError::new( +4688 TransportErrorCode::crypto(0x6d), +4689 "transport parameters missing".to_owned(), +4690 ) +4691 })?; +4692 +4693 if self.has_0rtt() { +4694 if !self.crypto_state.session.early_data_accepted().unwrap() { +4695 debug_assert!(self.side.is_client()); +4696 debug!("0-RTT rejected"); +4697 self.crypto_state.accepted_0rtt = false; +4698 self.streams.zero_rtt_rejected(); 4699 -4700 // Discard 0-RTT packets -4701 let sent_packets = mem::take( -4702 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets, -4703 ); -4704 for (_, packet) in sent_packets.into_iter() { -4705 self.paths -4706 .get_mut(&path_id) -4707 .unwrap() -4708 .remove_in_flight(&packet); -4709 } -4710 } else { -4711 self.crypto_state.accepted_0rtt = true; -4712 params.validate_resumption_from(&self.peer_params)?; -4713 } -4714 } -4715 if let Some(token) = params.stateless_reset_token { -4716 let remote = self.path_data(path_id).network_path.remote; -4717 debug_assert!(!self.state.is_drained()); // requirement for endpoint events, checked above -4718 self.endpoint_events -4719 .push_back(EndpointEventInner::ResetToken(path_id, remote, token)); -4720 } -4721 self.handle_peer_params(params, local_cid, remote_cid, now)?; -4722 self.issue_first_cids(now); -4723 } else { -4724 // Server-only -4725 self.spaces[SpaceId::Data].pending.handshake_done = true; -4726 self.discard_space(now, SpaceKind::Handshake); -4727 self.events.push_back(Event::HandshakeConfirmed); -4728 trace!("handshake confirmed"); -4729 } -4730 -4731 self.events.push_back(Event::Connected); -4732 self.state.move_to_established(); -4733 trace!("established"); -4734 -4735 // Multipath can only be enabled after the state has reached Established. -4736 // So this can not happen any earlier. -4737 self.issue_first_path_cids(now); -4738 Ok(()) -4739 } -4740 Header::Initial(InitialHeader { -4741 src_cid: remote_cid, -4742 dst_cid: local_cid, -4743 .. -4744 }) => { -4745 debug_assert_eq!(path_id, PathId::ZERO); -4746 if !state.remote_cid_set { -4747 trace!("switching remote CID to {}", remote_cid); -4748 let mut state = state.clone(); -4749 self.remote_cids -4750 .get_mut(&path_id) -4751 .expect("PathId::ZERO not yet abandoned") -4752 .update_initial_cid(remote_cid); -4753 self.remote_handshake_cid = remote_cid; -4754 self.original_remote_cid = remote_cid; -4755 state.remote_cid_set = true; -4756 self.state.move_to_handshake(state); -4757 } else if remote_cid != self.remote_handshake_cid { -4758 debug!( -4759 "discarding packet with mismatched remote CID: {} != {}", -4760 self.remote_handshake_cid, remote_cid -4761 ); -4762 return Ok(()); -4763 } -4764 -4765 let starting_space = self.highest_space; -4766 self.process_early_payload(now, path_id, packet, qlog)?; +4700 // Discard already-queued frames +4701 self.spaces[SpaceId::Data].pending = Retransmits::default(); +4702 +4703 // Discard 0-RTT packets +4704 let sent_packets = mem::take( +4705 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets, +4706 ); +4707 for (_, packet) in sent_packets.into_iter() { +4708 self.paths +4709 .get_mut(&path_id) +4710 .unwrap() +4711 .remove_in_flight(&packet); +4712 } +4713 } else { +4714 self.crypto_state.accepted_0rtt = true; +4715 params.validate_resumption_from(&self.peer_params)?; +4716 } +4717 } +4718 if let Some(token) = params.stateless_reset_token { +4719 let remote = self.path_data(path_id).network_path.remote; +4720 debug_assert!(!self.state.is_drained()); // requirement for endpoint events, checked above +4721 self.endpoint_events +4722 .push_back(EndpointEventInner::ResetToken(path_id, remote, token)); +4723 } +4724 self.handle_peer_params(params, local_cid, remote_cid, now)?; +4725 self.issue_first_cids(now); +4726 } else { +4727 // Server-only +4728 self.spaces[SpaceId::Data].pending.handshake_done = true; +4729 self.discard_space(now, SpaceKind::Handshake); +4730 self.events.push_back(Event::HandshakeConfirmed); +4731 trace!("handshake confirmed"); +4732 } +4733 +4734 self.events.push_back(Event::Connected); +4735 self.state.move_to_established(); +4736 trace!("established"); +4737 +4738 // Multipath can only be enabled after the state has reached Established. +4739 // So this can not happen any earlier. +4740 self.issue_first_path_cids(now); +4741 Ok(()) +4742 } +4743 Header::Initial(InitialHeader { +4744 src_cid: remote_cid, +4745 dst_cid: local_cid, +4746 .. +4747 }) => { +4748 debug_assert_eq!(path_id, PathId::ZERO); +4749 if !state.remote_cid_set { +4750 trace!("switching remote CID to {}", remote_cid); +4751 let mut state = state.clone(); +4752 self.remote_cids +4753 .get_mut(&path_id) +4754 .expect("PathId::ZERO not yet abandoned") +4755 .update_initial_cid(remote_cid); +4756 self.remote_handshake_cid = remote_cid; +4757 self.original_remote_cid = remote_cid; +4758 state.remote_cid_set = true; +4759 self.state.move_to_handshake(state); +4760 } else if remote_cid != self.remote_handshake_cid { +4761 debug!( +4762 "discarding packet with mismatched remote CID: {} != {}", +4763 self.remote_handshake_cid, remote_cid +4764 ); +4765 return Ok(()); +4766 } 4767 -4768 if self.side.is_server() -4769 && starting_space == SpaceKind::Initial -4770 && self.highest_space != SpaceKind::Initial -4771 { -4772 let params = self -4773 .crypto_state -4774 .session -4775 .transport_parameters()? -4776 .ok_or_else(|| { -4777 TransportError::new( -4778 TransportErrorCode::crypto(0x6d), -4779 "transport parameters missing".to_owned(), -4780 ) -4781 })?; -4782 self.handle_peer_params(params, local_cid, remote_cid, now)?; -4783 self.issue_first_cids(now); -4784 self.init_0rtt(now); -4785 } -4786 Ok(()) -4787 } -4788 Header::Long { -4789 ty: LongType::ZeroRtt, -4790 .. -4791 } => { -4792 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?; -4793 Ok(()) -4794 } -4795 Header::VersionNegotiate { .. } => { -4796 if self.total_authed_packets > 1 { -4797 return Ok(()); -4798 } -4799 let supported = packet -4800 .payload -4801 .chunks(4) -4802 .any(|x| match <[u8; 4]>::try_from(x) { -4803 Ok(version) => self.version == u32::from_be_bytes(version), -4804 Err(_) => false, -4805 }); -4806 if supported { -4807 return Ok(()); -4808 } -4809 debug!("remote doesn't support our version"); -4810 Err(ConnectionError::VersionMismatch) -4811 } -4812 Header::Short { .. } => unreachable!( -4813 "short packets received during handshake are discarded in handle_packet" -4814 ), -4815 } -4816 } -4817 -4818 /// Process an Initial or Handshake packet payload -4819 fn process_early_payload( -4820 &mut self, -4821 now: Instant, -4822 path_id: PathId, -4823 packet: Packet, -4824 #[allow(unused)] qlog: &mut QlogRecvPacket, -4825 ) -> Result<(), TransportError> { -4826 debug_assert_ne!(packet.header.space(), SpaceKind::Data); -4827 debug_assert_eq!(path_id, PathId::ZERO); -4828 let payload_len = packet.payload.len(); -4829 let mut ack_eliciting = false; -4830 for result in frame::Iter::new(packet.payload.freeze())? { -4831 let frame = result?; -4832 qlog.frame(&frame); -4833 let span = match frame { -4834 Frame::Padding => continue, -4835 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)), -4836 }; -4837 -4838 self.path_stats -4839 .for_path(path_id) -4840 .frame_rx -4841 .record(frame.ty()); +4768 let starting_space = self.highest_space; +4769 self.process_early_payload(now, path_id, packet, qlog)?; +4770 +4771 if self.side.is_server() +4772 && starting_space == SpaceKind::Initial +4773 && self.highest_space != SpaceKind::Initial +4774 { +4775 let params = self +4776 .crypto_state +4777 .session +4778 .transport_parameters()? +4779 .ok_or_else(|| { +4780 TransportError::new( +4781 TransportErrorCode::crypto(0x6d), +4782 "transport parameters missing".to_owned(), +4783 ) +4784 })?; +4785 self.handle_peer_params(params, local_cid, remote_cid, now)?; +4786 self.issue_first_cids(now); +4787 self.init_0rtt(now); +4788 } +4789 Ok(()) +4790 } +4791 Header::Long { +4792 ty: LongType::ZeroRtt, +4793 .. +4794 } => { +4795 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?; +4796 Ok(()) +4797 } +4798 Header::VersionNegotiate { .. } => { +4799 if self.total_authed_packets > 1 { +4800 return Ok(()); +4801 } +4802 let supported = packet +4803 .payload +4804 .chunks(4) +4805 .any(|x| match <[u8; 4]>::try_from(x) { +4806 Ok(version) => self.version == u32::from_be_bytes(version), +4807 Err(_) => false, +4808 }); +4809 if supported { +4810 return Ok(()); +4811 } +4812 debug!("remote doesn't support our version"); +4813 Err(ConnectionError::VersionMismatch) +4814 } +4815 Header::Short { .. } => unreachable!( +4816 "short packets received during handshake are discarded in handle_packet" +4817 ), +4818 } +4819 } +4820 +4821 /// Process an Initial or Handshake packet payload +4822 fn process_early_payload( +4823 &mut self, +4824 now: Instant, +4825 path_id: PathId, +4826 packet: Packet, +4827 #[allow(unused)] qlog: &mut QlogRecvPacket, +4828 ) -> Result<(), TransportError> { +4829 debug_assert_ne!(packet.header.space(), SpaceKind::Data); +4830 debug_assert_eq!(path_id, PathId::ZERO); +4831 let payload_len = packet.payload.len(); +4832 let mut ack_eliciting = false; +4833 for result in frame::Iter::new(packet.payload.freeze())? { +4834 let frame = result?; +4835 qlog.frame(&frame); +4836 let span = match frame { +4837 Frame::Padding => continue, +4838 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)), +4839 }; +4840 +4841 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty()); 4842 4843 let _guard = span.as_ref().map(|x| x.enter()); 4844 ack_eliciting |= frame.is_ack_eliciting(); @@ -4915,2894 +4915,2891 @@ 4915 _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty), 4916 }; 4917 -4918 self.path_stats -4919 .for_path(path_id) -4920 .frame_rx -4921 .record(frame.ty()); -4922 // Crypto, Stream and Datagram frames are special cased in order no pollute -4923 // the log with payload data -4924 match &frame { -4925 Frame::Crypto(f) => { -4926 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO"); +4918 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty()); +4919 // Crypto, Stream and Datagram frames are special cased in order no pollute +4920 // the log with payload data +4921 match &frame { +4922 Frame::Crypto(f) => { +4923 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO"); +4924 } +4925 Frame::Stream(f) => { +4926 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM"); 4927 } -4928 Frame::Stream(f) => { -4929 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM"); +4928 Frame::Datagram(f) => { +4929 trace!(len = f.data.len(), "got frame DATAGRAM"); 4930 } -4931 Frame::Datagram(f) => { -4932 trace!(len = f.data.len(), "got frame DATAGRAM"); +4931 f => { +4932 trace!("got frame {f}"); 4933 } -4934 f => { -4935 trace!("got frame {f}"); -4936 } -4937 } -4938 -4939 let _guard = span.enter(); -4940 if packet.header.is_0rtt() { -4941 match frame { -4942 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => { -4943 return Err(TransportError::PROTOCOL_VIOLATION( -4944 "illegal frame type in 0-RTT", -4945 )); -4946 } -4947 _ => { -4948 if frame.is_1rtt() { -4949 return Err(TransportError::PROTOCOL_VIOLATION( -4950 "illegal frame type in 0-RTT", -4951 )); -4952 } -4953 } -4954 } -4955 } -4956 ack_eliciting |= frame.is_ack_eliciting(); -4957 -4958 // Check whether this could be a probing packet -4959 match frame { -4960 Frame::Padding -4961 | Frame::PathChallenge(_) -4962 | Frame::PathResponse(_) -4963 | Frame::NewConnectionId(_) -4964 | Frame::ObservedAddr(_) => {} -4965 _ => { -4966 is_probing_packet = false; -4967 } -4968 } -4969 -4970 match frame { -4971 Frame::Crypto(frame) => { -4972 self.read_crypto(SpaceId::Data, &frame, payload_len)?; -4973 } -4974 Frame::Stream(frame) => { -4975 if self.streams.received(frame, payload_len)?.should_transmit() { -4976 self.spaces[SpaceId::Data].pending.max_data = true; -4977 } +4934 } +4935 +4936 let _guard = span.enter(); +4937 if packet.header.is_0rtt() { +4938 match frame { +4939 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => { +4940 return Err(TransportError::PROTOCOL_VIOLATION( +4941 "illegal frame type in 0-RTT", +4942 )); +4943 } +4944 _ => { +4945 if frame.is_1rtt() { +4946 return Err(TransportError::PROTOCOL_VIOLATION( +4947 "illegal frame type in 0-RTT", +4948 )); +4949 } +4950 } +4951 } +4952 } +4953 ack_eliciting |= frame.is_ack_eliciting(); +4954 +4955 // Check whether this could be a probing packet +4956 match frame { +4957 Frame::Padding +4958 | Frame::PathChallenge(_) +4959 | Frame::PathResponse(_) +4960 | Frame::NewConnectionId(_) +4961 | Frame::ObservedAddr(_) => {} +4962 _ => { +4963 is_probing_packet = false; +4964 } +4965 } +4966 +4967 match frame { +4968 Frame::Crypto(frame) => { +4969 self.read_crypto(SpaceId::Data, &frame, payload_len)?; +4970 } +4971 Frame::Stream(frame) => { +4972 if self.streams.received(frame, payload_len)?.should_transmit() { +4973 self.spaces[SpaceId::Data].pending.max_data = true; +4974 } +4975 } +4976 Frame::Ack(ack) => { +4977 self.on_ack_received(now, SpaceId::Data, ack)?; 4978 } -4979 Frame::Ack(ack) => { -4980 self.on_ack_received(now, SpaceId::Data, ack)?; -4981 } -4982 Frame::PathAck(ack) => { -4983 if !self.is_multipath_negotiated() { -4984 return Err(TransportError::PROTOCOL_VIOLATION( -4985 "received PATH_ACK frame when multipath was not negotiated", -4986 )); -4987 } -4988 span.record("path", tracing::field::display(&ack.path_id)); -4989 self.on_path_ack_received(now, SpaceId::Data, ack)?; -4990 } -4991 Frame::Padding | Frame::Ping => {} -4992 Frame::Close(reason) => { -4993 close = Some(reason); -4994 } -4995 Frame::PathChallenge(challenge) => { -4996 self.spaces[SpaceKind::Data] -4997 .for_path(path_id) -4998 .pending_path_responses -4999 .push(number, challenge.0, network_path); -5000 // If we were passively migrated (e.g. NAT rebinding), our local_ip will -5001 // not match. Once we processed a non-probing packet the local_ip will -5002 // finally be updated. -5003 let path = &mut self -5004 .path_mut(path_id) -5005 .expect("payload is processed only after the path becomes known"); -5006 if network_path.remote == path.network_path.remote { -5007 // PATH_CHALLENGE on active path, possible off-path packet -5008 // forwarding attack. Send a non-probing packet to recover the -5009 // active path. See -5010 // https://www.rfc-editor.org/rfc/rfc9000.html#section-9.3.3-3. In -5011 // rare cases NAT probes might also appear on-path and would also -5012 // get a non-probing packet as response. There is little harm in -5013 // this. -5014 match self.peer_supports_ack_frequency() { -5015 true => self.immediate_ack(path_id), -5016 false => { -5017 self.ping_path(path_id).ok(); -5018 } -5019 } -5020 } -5021 } -5022 Frame::PathResponse(response) => { -5023 // First try to see if this is a NAT probe response. -5024 if self -5025 .n0_nat_traversal -5026 .handle_path_response(network_path, response.0) -5027 { -5028 self.open_nat_traversed_paths(now); -5029 } else { -5030 // Try to see if this is a response to an on-path PATH_CHALLENGE. -5031 self.handle_path_response_on_path(now, response, path_id); -5032 } +4979 Frame::PathAck(ack) => { +4980 if !self.is_multipath_negotiated() { +4981 return Err(TransportError::PROTOCOL_VIOLATION( +4982 "received PATH_ACK frame when multipath was not negotiated", +4983 )); +4984 } +4985 span.record("path", tracing::field::display(&ack.path_id)); +4986 self.on_path_ack_received(now, SpaceId::Data, ack)?; +4987 } +4988 Frame::Padding | Frame::Ping => {} +4989 Frame::Close(reason) => { +4990 close = Some(reason); +4991 } +4992 Frame::PathChallenge(challenge) => { +4993 self.spaces[SpaceKind::Data] +4994 .for_path(path_id) +4995 .pending_path_responses +4996 .push(number, challenge.0, network_path); +4997 // If we were passively migrated (e.g. NAT rebinding), our local_ip will +4998 // not match. Once we processed a non-probing packet the local_ip will +4999 // finally be updated. +5000 let path = &mut self +5001 .path_mut(path_id) +5002 .expect("payload is processed only after the path becomes known"); +5003 if network_path.remote == path.network_path.remote { +5004 // PATH_CHALLENGE on active path, possible off-path packet +5005 // forwarding attack. Send a non-probing packet to recover the +5006 // active path. See +5007 // https://www.rfc-editor.org/rfc/rfc9000.html#section-9.3.3-3. In +5008 // rare cases NAT probes might also appear on-path and would also +5009 // get a non-probing packet as response. There is little harm in +5010 // this. +5011 match self.peer_supports_ack_frequency() { +5012 true => self.immediate_ack(path_id), +5013 false => { +5014 self.ping_path(path_id).ok(); +5015 } +5016 } +5017 } +5018 } +5019 Frame::PathResponse(response) => { +5020 // First try to see if this is a NAT probe response. +5021 if self +5022 .n0_nat_traversal +5023 .handle_path_response(network_path, response.0) +5024 { +5025 self.open_nat_traversed_paths(now); +5026 } else { +5027 // Try to see if this is a response to an on-path PATH_CHALLENGE. +5028 self.handle_path_response_on_path(now, response, path_id); +5029 } +5030 } +5031 Frame::MaxData(frame::MaxData(bytes)) => { +5032 self.streams.received_max_data(bytes); 5033 } -5034 Frame::MaxData(frame::MaxData(bytes)) => { -5035 self.streams.received_max_data(bytes); +5034 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => { +5035 self.streams.received_max_stream_data(id, offset)?; 5036 } -5037 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => { -5038 self.streams.received_max_stream_data(id, offset)?; +5037 Frame::MaxStreams(frame::MaxStreams { dir, count }) => { +5038 self.streams.received_max_streams(dir, count)?; 5039 } -5040 Frame::MaxStreams(frame::MaxStreams { dir, count }) => { -5041 self.streams.received_max_streams(dir, count)?; -5042 } -5043 Frame::ResetStream(frame) => { -5044 if self.streams.received_reset(frame)?.should_transmit() { -5045 self.spaces[SpaceId::Data].pending.max_data = true; -5046 } +5040 Frame::ResetStream(frame) => { +5041 if self.streams.received_reset(frame)?.should_transmit() { +5042 self.spaces[SpaceId::Data].pending.max_data = true; +5043 } +5044 } +5045 Frame::DataBlocked(DataBlocked(offset)) => { +5046 debug!(offset, "peer claims to be blocked at connection level"); 5047 } -5048 Frame::DataBlocked(DataBlocked(offset)) => { -5049 debug!(offset, "peer claims to be blocked at connection level"); -5050 } -5051 Frame::StreamDataBlocked(StreamDataBlocked { id, offset }) => { -5052 if id.initiator() == self.side.side() && id.dir() == Dir::Uni { -5053 debug!("got STREAM_DATA_BLOCKED on send-only {}", id); -5054 return Err(TransportError::STREAM_STATE_ERROR( -5055 "STREAM_DATA_BLOCKED on send-only stream", -5056 )); -5057 } -5058 debug!( -5059 stream = %id, -5060 offset, "peer claims to be blocked at stream level" -5061 ); -5062 } -5063 Frame::StreamsBlocked(StreamsBlocked { dir, limit }) => { -5064 if limit > MAX_STREAM_COUNT { -5065 return Err(TransportError::FRAME_ENCODING_ERROR( -5066 "unrepresentable stream limit", -5067 )); -5068 } -5069 debug!( -5070 "peer claims to be blocked opening more than {} {} streams", -5071 limit, dir -5072 ); -5073 } -5074 Frame::StopSending(frame::StopSending { id, error_code }) => { -5075 if id.initiator() != self.side.side() { -5076 if id.dir() == Dir::Uni { -5077 debug!("got STOP_SENDING on recv-only {}", id); -5078 return Err(TransportError::STREAM_STATE_ERROR( -5079 "STOP_SENDING on recv-only stream", -5080 )); -5081 } -5082 } else if self.streams.is_local_unopened(id) { -5083 return Err(TransportError::STREAM_STATE_ERROR( -5084 "STOP_SENDING on unopened stream", -5085 )); -5086 } -5087 self.streams.received_stop_sending(id, error_code); -5088 } -5089 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => { -5090 if let Some(ref path_id) = path_id { -5091 span.record("path", tracing::field::display(&path_id)); -5092 } -5093 let path_id = path_id.unwrap_or_default(); -5094 match self.local_cid_state.get_mut(&path_id) { -5095 None => debug!(?path_id, "RETIRE_CONNECTION_ID for unknown path"), -5096 Some(cid_state) => { -5097 let allow_more_cids = cid_state -5098 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?; -5099 -5100 // If the path has closed, we do not issue more CIDs for this path -5101 // For details see https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.2.2 -5102 // > an endpoint SHOULD provide new connection IDs for that path, if still open, using PATH_NEW_CONNECTION_ID frames. -5103 let has_path = !self.abandoned_paths.contains(&path_id); -5104 let allow_more_cids = allow_more_cids && has_path; -5105 -5106 debug_assert!(!self.state.is_drained()); // required for adding endpoint events, process_payload is never called for drained connections -5107 self.endpoint_events -5108 .push_back(EndpointEventInner::RetireConnectionId( -5109 now, -5110 path_id, -5111 sequence, -5112 allow_more_cids, -5113 )); -5114 } -5115 } -5116 } -5117 Frame::NewConnectionId(frame) => { -5118 let path_id = if let Some(path_id) = frame.path_id { -5119 if !self.is_multipath_negotiated() { -5120 return Err(TransportError::PROTOCOL_VIOLATION( -5121 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated", -5122 )); -5123 } -5124 if path_id > self.local_max_path_id { -5125 return Err(TransportError::PROTOCOL_VIOLATION( -5126 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max", -5127 )); -5128 } -5129 path_id -5130 } else { -5131 PathId::ZERO -5132 }; -5133 -5134 if let Some(ref path_id) = frame.path_id { -5135 span.record("path", tracing::field::display(&path_id)); -5136 } -5137 -5138 if self.abandoned_paths.contains(&path_id) { -5139 trace!("ignoring issued CID for abandoned path"); -5140 continue; -5141 } -5142 let remote_cids = self -5143 .remote_cids -5144 .entry(path_id) -5145 .or_insert_with(|| CidQueue::new(frame.id)); -5146 if remote_cids.active().is_empty() { -5147 return Err(TransportError::PROTOCOL_VIOLATION( -5148 "NEW_CONNECTION_ID when CIDs aren't in use", -5149 )); -5150 } -5151 if frame.retire_prior_to > frame.sequence { -5152 return Err(TransportError::PROTOCOL_VIOLATION( -5153 "NEW_CONNECTION_ID retiring unissued CIDs", -5154 )); -5155 } -5156 -5157 use crate::cid_queue::InsertError; -5158 match remote_cids.insert(frame) { -5159 Ok(None) => { -5160 self.open_nat_traversed_paths(now); -5161 } -5162 Ok(Some((retired, reset_token))) => { -5163 let pending_retired = -5164 &mut self.spaces[SpaceId::Data].pending.retire_cids; -5165 /// Ensure `pending_retired` cannot grow without bound. Limit is -5166 /// somewhat arbitrary but very permissive. -5167 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10; -5168 // We don't bother counting in-flight frames because those are bounded -5169 // by congestion control. -5170 if (pending_retired.len() as u64) -5171 .saturating_add(retired.end.saturating_sub(retired.start)) -5172 > MAX_PENDING_RETIRED_CIDS -5173 { -5174 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR( -5175 "queued too many retired CIDs", -5176 )); -5177 } -5178 pending_retired.extend(retired.map(|seq| (path_id, seq))); -5179 self.set_reset_token(path_id, network_path.remote, reset_token); -5180 self.open_nat_traversed_paths(now); +5048 Frame::StreamDataBlocked(StreamDataBlocked { id, offset }) => { +5049 if id.initiator() == self.side.side() && id.dir() == Dir::Uni { +5050 debug!("got STREAM_DATA_BLOCKED on send-only {}", id); +5051 return Err(TransportError::STREAM_STATE_ERROR( +5052 "STREAM_DATA_BLOCKED on send-only stream", +5053 )); +5054 } +5055 debug!( +5056 stream = %id, +5057 offset, "peer claims to be blocked at stream level" +5058 ); +5059 } +5060 Frame::StreamsBlocked(StreamsBlocked { dir, limit }) => { +5061 if limit > MAX_STREAM_COUNT { +5062 return Err(TransportError::FRAME_ENCODING_ERROR( +5063 "unrepresentable stream limit", +5064 )); +5065 } +5066 debug!( +5067 "peer claims to be blocked opening more than {} {} streams", +5068 limit, dir +5069 ); +5070 } +5071 Frame::StopSending(frame::StopSending { id, error_code }) => { +5072 if id.initiator() != self.side.side() { +5073 if id.dir() == Dir::Uni { +5074 debug!("got STOP_SENDING on recv-only {}", id); +5075 return Err(TransportError::STREAM_STATE_ERROR( +5076 "STOP_SENDING on recv-only stream", +5077 )); +5078 } +5079 } else if self.streams.is_local_unopened(id) { +5080 return Err(TransportError::STREAM_STATE_ERROR( +5081 "STOP_SENDING on unopened stream", +5082 )); +5083 } +5084 self.streams.received_stop_sending(id, error_code); +5085 } +5086 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => { +5087 if let Some(ref path_id) = path_id { +5088 span.record("path", tracing::field::display(&path_id)); +5089 } +5090 let path_id = path_id.unwrap_or_default(); +5091 match self.local_cid_state.get_mut(&path_id) { +5092 None => debug!(?path_id, "RETIRE_CONNECTION_ID for unknown path"), +5093 Some(cid_state) => { +5094 let allow_more_cids = cid_state +5095 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?; +5096 +5097 // If the path has closed, we do not issue more CIDs for this path +5098 // For details see https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.2.2 +5099 // > an endpoint SHOULD provide new connection IDs for that path, if still open, using PATH_NEW_CONNECTION_ID frames. +5100 let has_path = !self.abandoned_paths.contains(&path_id); +5101 let allow_more_cids = allow_more_cids && has_path; +5102 +5103 debug_assert!(!self.state.is_drained()); // required for adding endpoint events, process_payload is never called for drained connections +5104 self.endpoint_events +5105 .push_back(EndpointEventInner::RetireConnectionId( +5106 now, +5107 path_id, +5108 sequence, +5109 allow_more_cids, +5110 )); +5111 } +5112 } +5113 } +5114 Frame::NewConnectionId(frame) => { +5115 let path_id = if let Some(path_id) = frame.path_id { +5116 if !self.is_multipath_negotiated() { +5117 return Err(TransportError::PROTOCOL_VIOLATION( +5118 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated", +5119 )); +5120 } +5121 if path_id > self.local_max_path_id { +5122 return Err(TransportError::PROTOCOL_VIOLATION( +5123 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max", +5124 )); +5125 } +5126 path_id +5127 } else { +5128 PathId::ZERO +5129 }; +5130 +5131 if let Some(ref path_id) = frame.path_id { +5132 span.record("path", tracing::field::display(&path_id)); +5133 } +5134 +5135 if self.abandoned_paths.contains(&path_id) { +5136 trace!("ignoring issued CID for abandoned path"); +5137 continue; +5138 } +5139 let remote_cids = self +5140 .remote_cids +5141 .entry(path_id) +5142 .or_insert_with(|| CidQueue::new(frame.id)); +5143 if remote_cids.active().is_empty() { +5144 return Err(TransportError::PROTOCOL_VIOLATION( +5145 "NEW_CONNECTION_ID when CIDs aren't in use", +5146 )); +5147 } +5148 if frame.retire_prior_to > frame.sequence { +5149 return Err(TransportError::PROTOCOL_VIOLATION( +5150 "NEW_CONNECTION_ID retiring unissued CIDs", +5151 )); +5152 } +5153 +5154 use crate::cid_queue::InsertError; +5155 match remote_cids.insert(frame) { +5156 Ok(None) => { +5157 self.open_nat_traversed_paths(now); +5158 } +5159 Ok(Some((retired, reset_token))) => { +5160 let pending_retired = +5161 &mut self.spaces[SpaceId::Data].pending.retire_cids; +5162 /// Ensure `pending_retired` cannot grow without bound. Limit is +5163 /// somewhat arbitrary but very permissive. +5164 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10; +5165 // We don't bother counting in-flight frames because those are bounded +5166 // by congestion control. +5167 if (pending_retired.len() as u64) +5168 .saturating_add(retired.end.saturating_sub(retired.start)) +5169 > MAX_PENDING_RETIRED_CIDS +5170 { +5171 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR( +5172 "queued too many retired CIDs", +5173 )); +5174 } +5175 pending_retired.extend(retired.map(|seq| (path_id, seq))); +5176 self.set_reset_token(path_id, network_path.remote, reset_token); +5177 self.open_nat_traversed_paths(now); +5178 } +5179 Err(InsertError::ExceedsLimit) => { +5180 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR("")); 5181 } -5182 Err(InsertError::ExceedsLimit) => { -5183 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR("")); -5184 } -5185 Err(InsertError::Retired) => { -5186 trace!("discarding already-retired"); -5187 // RETIRE_CONNECTION_ID might not have been previously sent if e.g. a -5188 // range of connection IDs larger than the active connection ID limit -5189 // was retired all at once via retire_prior_to. -5190 self.spaces[SpaceId::Data] -5191 .pending -5192 .retire_cids -5193 .push((path_id, frame.sequence)); -5194 continue; -5195 } -5196 }; -5197 -5198 if self.side.is_server() -5199 && path_id == PathId::ZERO -5200 && self -5201 .remote_cids -5202 .get(&PathId::ZERO) -5203 .map(|cids| cids.active_seq() == 0) -5204 .unwrap_or_default() -5205 { -5206 // We're a server still using the initial remote CID for the client, so -5207 // let's switch immediately to enable clientside stateless resets. -5208 self.update_remote_cid(PathId::ZERO); -5209 } -5210 } -5211 Frame::NewToken(NewToken { token }) => { -5212 let ConnectionSide::Client { -5213 token_store, -5214 server_name, -5215 .. -5216 } = &self.side -5217 else { -5218 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN")); -5219 }; -5220 if token.is_empty() { -5221 return Err(TransportError::FRAME_ENCODING_ERROR("empty token")); -5222 } -5223 trace!("got new token"); -5224 token_store.insert(server_name, token); -5225 } -5226 Frame::Datagram(datagram) => { -5227 if self -5228 .datagrams -5229 .received(datagram, &self.config.datagram_receive_buffer_size)? -5230 { -5231 self.events.push_back(Event::DatagramReceived); -5232 } -5233 } -5234 Frame::AckFrequency(ack_frequency) => { -5235 // This frame can only be sent in the Data space -5236 -5237 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? { -5238 // The AckFrequency frame is stale (we have already received a more -5239 // recent one) -5240 continue; -5241 } -5242 -5243 // Update the params for all of our paths -5244 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() { -5245 space.pending_acks.set_ack_frequency_params(&ack_frequency); -5246 -5247 // Our `max_ack_delay` has been updated, so we may need to adjust -5248 // its associated timeout. -5249 // Packets received on abandoned paths are always acknowledged immediately. -5250 if !self.abandoned_paths.contains(path_id) -5251 && let Some(timeout) = space -5252 .pending_acks -5253 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay) -5254 { -5255 self.timers.set( -5256 Timer::PerPath(*path_id, PathTimer::MaxAckDelay), -5257 timeout, -5258 self.qlog.with_time(now), -5259 ); -5260 } -5261 } -5262 } -5263 Frame::ImmediateAck => { -5264 // This frame can only be sent in the Data space -5265 for pns in self.spaces[SpaceId::Data].iter_paths_mut() { -5266 pns.pending_acks.set_immediate_ack_required(); -5267 } -5268 } -5269 Frame::HandshakeDone => { -5270 if self.side.is_server() { -5271 return Err(TransportError::PROTOCOL_VIOLATION( -5272 "client sent HANDSHAKE_DONE", -5273 )); -5274 } -5275 if self.crypto_state.has_keys(EncryptionLevel::Handshake) { -5276 self.discard_space(now, SpaceKind::Handshake); -5277 self.events.push_back(Event::HandshakeConfirmed); -5278 trace!("handshake confirmed"); -5279 } -5280 } -5281 Frame::ObservedAddr(observed) => { -5282 // check if params allows the peer to send report and this node to receive it -5283 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port); -5284 if !self -5285 .peer_params -5286 .address_discovery_role -5287 .should_report(&self.config.address_discovery_role) -5288 { -5289 return Err(TransportError::PROTOCOL_VIOLATION( -5290 "received OBSERVED_ADDRESS frame when not negotiated", -5291 )); -5292 } -5293 // must only be sent in data space -5294 if packet.header.space() != SpaceKind::Data { -5295 return Err(TransportError::PROTOCOL_VIOLATION( -5296 "OBSERVED_ADDRESS frame outside data space", -5297 )); -5298 } -5299 -5300 let space_open_status = -5301 self.spaces[SpaceKind::Data].for_path(path_id).open_status; -5302 let path = self.path_data_mut(path_id); -5303 if path.network_path.remote == network_path.remote { -5304 if let Some(updated) = path.update_observed_addr_report(observed) -5305 && space_open_status == OpenStatus::Informed -5306 { -5307 self.events.push_back(Event::Path(PathEvent::ObservedAddr { -5308 id: path_id, -5309 addr: updated, -5310 })); -5311 // otherwise the event is reported when the path is deemed open -5312 } -5313 } else { -5314 // include in migration -5315 migration_observed_addr = Some(observed) -5316 } -5317 } -5318 Frame::PathAbandon(frame::PathAbandon { -5319 path_id, -5320 error_code, -5321 }) => { -5322 span.record("path", tracing::field::display(&path_id)); -5323 match self.close_path_inner( -5324 now, -5325 path_id, -5326 PathAbandonReason::RemoteAbandoned { -5327 error_code: error_code.into(), -5328 }, -5329 ) { -5330 Ok(()) => { -5331 trace!("peer abandoned path"); +5182 Err(InsertError::Retired) => { +5183 trace!("discarding already-retired"); +5184 // RETIRE_CONNECTION_ID might not have been previously sent if e.g. a +5185 // range of connection IDs larger than the active connection ID limit +5186 // was retired all at once via retire_prior_to. +5187 self.spaces[SpaceId::Data] +5188 .pending +5189 .retire_cids +5190 .push((path_id, frame.sequence)); +5191 continue; +5192 } +5193 }; +5194 +5195 if self.side.is_server() +5196 && path_id == PathId::ZERO +5197 && self +5198 .remote_cids +5199 .get(&PathId::ZERO) +5200 .map(|cids| cids.active_seq() == 0) +5201 .unwrap_or_default() +5202 { +5203 // We're a server still using the initial remote CID for the client, so +5204 // let's switch immediately to enable clientside stateless resets. +5205 self.update_remote_cid(PathId::ZERO); +5206 } +5207 } +5208 Frame::NewToken(NewToken { token }) => { +5209 let ConnectionSide::Client { +5210 token_store, +5211 server_name, +5212 .. +5213 } = &self.side +5214 else { +5215 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN")); +5216 }; +5217 if token.is_empty() { +5218 return Err(TransportError::FRAME_ENCODING_ERROR("empty token")); +5219 } +5220 trace!("got new token"); +5221 token_store.insert(server_name, token); +5222 } +5223 Frame::Datagram(datagram) => { +5224 if self +5225 .datagrams +5226 .received(datagram, &self.config.datagram_receive_buffer_size)? +5227 { +5228 self.events.push_back(Event::DatagramReceived); +5229 } +5230 } +5231 Frame::AckFrequency(ack_frequency) => { +5232 // This frame can only be sent in the Data space +5233 +5234 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? { +5235 // The AckFrequency frame is stale (we have already received a more +5236 // recent one) +5237 continue; +5238 } +5239 +5240 // Update the params for all of our paths +5241 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() { +5242 space.pending_acks.set_ack_frequency_params(&ack_frequency); +5243 +5244 // Our `max_ack_delay` has been updated, so we may need to adjust +5245 // its associated timeout. +5246 // Packets received on abandoned paths are always acknowledged immediately. +5247 if !self.abandoned_paths.contains(path_id) +5248 && let Some(timeout) = space +5249 .pending_acks +5250 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay) +5251 { +5252 self.timers.set( +5253 Timer::PerPath(*path_id, PathTimer::MaxAckDelay), +5254 timeout, +5255 self.qlog.with_time(now), +5256 ); +5257 } +5258 } +5259 } +5260 Frame::ImmediateAck => { +5261 // This frame can only be sent in the Data space +5262 for pns in self.spaces[SpaceId::Data].iter_paths_mut() { +5263 pns.pending_acks.set_immediate_ack_required(); +5264 } +5265 } +5266 Frame::HandshakeDone => { +5267 if self.side.is_server() { +5268 return Err(TransportError::PROTOCOL_VIOLATION( +5269 "client sent HANDSHAKE_DONE", +5270 )); +5271 } +5272 if self.crypto_state.has_keys(EncryptionLevel::Handshake) { +5273 self.discard_space(now, SpaceKind::Handshake); +5274 self.events.push_back(Event::HandshakeConfirmed); +5275 trace!("handshake confirmed"); +5276 } +5277 } +5278 Frame::ObservedAddr(observed) => { +5279 // check if params allows the peer to send report and this node to receive it +5280 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port); +5281 if !self +5282 .peer_params +5283 .address_discovery_role +5284 .should_report(&self.config.address_discovery_role) +5285 { +5286 return Err(TransportError::PROTOCOL_VIOLATION( +5287 "received OBSERVED_ADDRESS frame when not negotiated", +5288 )); +5289 } +5290 // must only be sent in data space +5291 if packet.header.space() != SpaceKind::Data { +5292 return Err(TransportError::PROTOCOL_VIOLATION( +5293 "OBSERVED_ADDRESS frame outside data space", +5294 )); +5295 } +5296 +5297 let space_open_status = +5298 self.spaces[SpaceKind::Data].for_path(path_id).open_status; +5299 let path = self.path_data_mut(path_id); +5300 if path.network_path.remote == network_path.remote { +5301 if let Some(updated) = path.update_observed_addr_report(observed) +5302 && space_open_status == OpenStatus::Informed +5303 { +5304 self.events.push_back(Event::Path(PathEvent::ObservedAddr { +5305 id: path_id, +5306 addr: updated, +5307 })); +5308 // otherwise the event is reported when the path is deemed open +5309 } +5310 } else { +5311 // include in migration +5312 migration_observed_addr = Some(observed) +5313 } +5314 } +5315 Frame::PathAbandon(frame::PathAbandon { +5316 path_id, +5317 error_code, +5318 }) => { +5319 span.record("path", tracing::field::display(&path_id)); +5320 match self.close_path_inner( +5321 now, +5322 path_id, +5323 PathAbandonReason::RemoteAbandoned { +5324 error_code: error_code.into(), +5325 }, +5326 ) { +5327 Ok(()) => { +5328 trace!("peer abandoned path"); +5329 } +5330 Err(ClosePathError::ClosedPath) => { +5331 trace!("peer abandoned already closed path"); 5332 } -5333 Err(ClosePathError::ClosedPath) => { -5334 trace!("peer abandoned already closed path"); -5335 } -5336 Err(ClosePathError::MultipathNotNegotiated) => { -5337 return Err(TransportError::PROTOCOL_VIOLATION( -5338 "received PATH_ABANDON frame when multipath was not negotiated", -5339 )); -5340 } -5341 Err(ClosePathError::LastOpenPath) => { -5342 // Not reachable: close_path_inner allows remote abandons -5343 // for the last path. But handle gracefully just in case. -5344 error!( -5345 "peer abandoned last path but close_path_inner returned LastOpenPath" -5346 ); -5347 } -5348 }; -5349 -5350 // Start draining the path if it still exists and hasn't started draining yet. -5351 if let Some(path) = self.paths.get_mut(&path_id) -5352 && !mem::replace(&mut path.data.draining, true) -5353 { -5354 let ack_delay = self.ack_frequency.max_ack_delay_for_pto(); -5355 let pto = path.data.rtt.pto_base() + ack_delay; -5356 self.timers.set( -5357 Timer::PerPath(path_id, PathTimer::PathDrained), -5358 now + 3 * pto, -5359 self.qlog.with_time(now), -5360 ); -5361 -5362 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8)); -5363 } -5364 } -5365 Frame::PathStatusAvailable(info) => { -5366 span.record("path", tracing::field::display(&info.path_id)); -5367 if self.is_multipath_negotiated() { -5368 self.on_path_status( -5369 info.path_id, -5370 PathStatus::Available, -5371 info.status_seq_no, -5372 ); -5373 } else { -5374 return Err(TransportError::PROTOCOL_VIOLATION( -5375 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated", -5376 )); -5377 } -5378 } -5379 Frame::PathStatusBackup(info) => { -5380 span.record("path", tracing::field::display(&info.path_id)); -5381 if self.is_multipath_negotiated() { -5382 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no); -5383 } else { -5384 return Err(TransportError::PROTOCOL_VIOLATION( -5385 "received PATH_STATUS_BACKUP frame when multipath was not negotiated", -5386 )); -5387 } -5388 } -5389 Frame::MaxPathId(frame::MaxPathId(path_id)) => { -5390 span.record("path", tracing::field::display(&path_id)); -5391 if !self.is_multipath_negotiated() { -5392 return Err(TransportError::PROTOCOL_VIOLATION( -5393 "received MAX_PATH_ID frame when multipath was not negotiated", -5394 )); -5395 } -5396 // frames that do not increase the path id are ignored -5397 if path_id > self.remote_max_path_id { -5398 self.remote_max_path_id = path_id; -5399 self.issue_first_path_cids(now); -5400 self.open_nat_traversed_paths(now); -5401 } -5402 } -5403 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => { -5404 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST -5405 // be treated as a connection error of type PROTOCOL_VIOLATION. -5406 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids> -5407 if self.is_multipath_negotiated() { -5408 if max_path_id > self.local_max_path_id { -5409 return Err(TransportError::PROTOCOL_VIOLATION( -5410 "PATHS_BLOCKED maximum path identifier was larger than local maximum", -5411 )); -5412 } -5413 } else { -5414 return Err(TransportError::PROTOCOL_VIOLATION( -5415 "received PATHS_BLOCKED frame when not multipath was not negotiated", -5416 )); -5417 } -5418 } -5419 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => { -5420 // Nothing to do. This is recorded in the frame stats, but otherwise we -5421 // always issue all CIDs we're allowed to issue, so either this is an -5422 // impatient peer or a bug on our side. -5423 -5424 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST -5425 // be treated as a connection error of type PROTOCOL_VIOLATION. -5426 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids> -5427 if self.is_multipath_negotiated() { -5428 if path_id > self.local_max_path_id { -5429 return Err(TransportError::PROTOCOL_VIOLATION( -5430 "PATH_CIDS_BLOCKED path identifier was larger than local maximum", -5431 )); -5432 } -5433 if self -5434 .local_cid_state -5435 .get(&path_id) -5436 // The PATH_CIDS_BLOCKED frame may arrive after we've discarded the path state. -5437 // In that case, we can't check for the protocol violation. -5438 .is_some_and(|cid_state| next_seq.0 > cid_state.active_seq().1 + 1) -5439 { -5440 return Err(TransportError::PROTOCOL_VIOLATION( -5441 "PATH_CIDS_BLOCKED next sequence number larger than in local state", -5442 )); -5443 } -5444 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED"); -5445 } else { -5446 return Err(TransportError::PROTOCOL_VIOLATION( -5447 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated", -5448 )); -5449 } -5450 } -5451 Frame::AddAddress(addr) => { -5452 let client_state = match self.n0_nat_traversal.client_side_mut() { -5453 Ok(state) => state, -5454 Err(err) => { -5455 return Err(TransportError::PROTOCOL_VIOLATION(format!( -5456 "Nat traversal(ADD_ADDRESS): {err}" -5457 ))); -5458 } -5459 }; -5460 -5461 if !client_state.check_remote_address(&addr) { -5462 // if the address is not valid we flag it, but update anyway -5463 warn!(?addr, "server sent illegal ADD_ADDRESS frame"); -5464 } -5465 -5466 match client_state.add_remote_address(addr) { -5467 Ok(maybe_added) => { -5468 if let Some(added) = maybe_added { -5469 self.events.push_back(Event::NatTraversal( -5470 n0_nat_traversal::Event::AddressAdded(added), -5471 )); -5472 } +5333 Err(ClosePathError::MultipathNotNegotiated) => { +5334 return Err(TransportError::PROTOCOL_VIOLATION( +5335 "received PATH_ABANDON frame when multipath was not negotiated", +5336 )); +5337 } +5338 Err(ClosePathError::LastOpenPath) => { +5339 // Not reachable: close_path_inner allows remote abandons +5340 // for the last path. But handle gracefully just in case. +5341 error!( +5342 "peer abandoned last path but close_path_inner returned LastOpenPath" +5343 ); +5344 } +5345 }; +5346 +5347 // Start draining the path if it still exists and hasn't started draining yet. +5348 if let Some(path) = self.paths.get_mut(&path_id) +5349 && !mem::replace(&mut path.data.draining, true) +5350 { +5351 let ack_delay = self.ack_frequency.max_ack_delay_for_pto(); +5352 let pto = path.data.rtt.pto_base() + ack_delay; +5353 self.timers.set( +5354 Timer::PerPath(path_id, PathTimer::PathDrained), +5355 now + 3 * pto, +5356 self.qlog.with_time(now), +5357 ); +5358 +5359 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8)); +5360 } +5361 } +5362 Frame::PathStatusAvailable(info) => { +5363 span.record("path", tracing::field::display(&info.path_id)); +5364 if self.is_multipath_negotiated() { +5365 self.on_path_status( +5366 info.path_id, +5367 PathStatus::Available, +5368 info.status_seq_no, +5369 ); +5370 } else { +5371 return Err(TransportError::PROTOCOL_VIOLATION( +5372 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated", +5373 )); +5374 } +5375 } +5376 Frame::PathStatusBackup(info) => { +5377 span.record("path", tracing::field::display(&info.path_id)); +5378 if self.is_multipath_negotiated() { +5379 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no); +5380 } else { +5381 return Err(TransportError::PROTOCOL_VIOLATION( +5382 "received PATH_STATUS_BACKUP frame when multipath was not negotiated", +5383 )); +5384 } +5385 } +5386 Frame::MaxPathId(frame::MaxPathId(path_id)) => { +5387 span.record("path", tracing::field::display(&path_id)); +5388 if !self.is_multipath_negotiated() { +5389 return Err(TransportError::PROTOCOL_VIOLATION( +5390 "received MAX_PATH_ID frame when multipath was not negotiated", +5391 )); +5392 } +5393 // frames that do not increase the path id are ignored +5394 if path_id > self.remote_max_path_id { +5395 self.remote_max_path_id = path_id; +5396 self.issue_first_path_cids(now); +5397 self.open_nat_traversed_paths(now); +5398 } +5399 } +5400 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => { +5401 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST +5402 // be treated as a connection error of type PROTOCOL_VIOLATION. +5403 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids> +5404 if self.is_multipath_negotiated() { +5405 if max_path_id > self.local_max_path_id { +5406 return Err(TransportError::PROTOCOL_VIOLATION( +5407 "PATHS_BLOCKED maximum path identifier was larger than local maximum", +5408 )); +5409 } +5410 } else { +5411 return Err(TransportError::PROTOCOL_VIOLATION( +5412 "received PATHS_BLOCKED frame when not multipath was not negotiated", +5413 )); +5414 } +5415 } +5416 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => { +5417 // Nothing to do. This is recorded in the frame stats, but otherwise we +5418 // always issue all CIDs we're allowed to issue, so either this is an +5419 // impatient peer or a bug on our side. +5420 +5421 // Receipt of a value of Maximum Path Identifier or Path Identifier that is higher than the local maximum value MUST +5422 // be treated as a connection error of type PROTOCOL_VIOLATION. +5423 // Ref <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids> +5424 if self.is_multipath_negotiated() { +5425 if path_id > self.local_max_path_id { +5426 return Err(TransportError::PROTOCOL_VIOLATION( +5427 "PATH_CIDS_BLOCKED path identifier was larger than local maximum", +5428 )); +5429 } +5430 if self +5431 .local_cid_state +5432 .get(&path_id) +5433 // The PATH_CIDS_BLOCKED frame may arrive after we've discarded the path state. +5434 // In that case, we can't check for the protocol violation. +5435 .is_some_and(|cid_state| next_seq.0 > cid_state.active_seq().1 + 1) +5436 { +5437 return Err(TransportError::PROTOCOL_VIOLATION( +5438 "PATH_CIDS_BLOCKED next sequence number larger than in local state", +5439 )); +5440 } +5441 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED"); +5442 } else { +5443 return Err(TransportError::PROTOCOL_VIOLATION( +5444 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated", +5445 )); +5446 } +5447 } +5448 Frame::AddAddress(addr) => { +5449 let client_state = match self.n0_nat_traversal.client_side_mut() { +5450 Ok(state) => state, +5451 Err(err) => { +5452 return Err(TransportError::PROTOCOL_VIOLATION(format!( +5453 "Nat traversal(ADD_ADDRESS): {err}" +5454 ))); +5455 } +5456 }; +5457 +5458 if !client_state.check_remote_address(&addr) { +5459 // if the address is not valid we flag it, but update anyway +5460 warn!(?addr, "server sent illegal ADD_ADDRESS frame"); +5461 } +5462 +5463 match client_state.add_remote_address(addr) { +5464 Ok(maybe_added) => { +5465 if let Some(added) = maybe_added { +5466 self.events.push_back(Event::NatTraversal( +5467 n0_nat_traversal::Event::AddressAdded(added), +5468 )); +5469 } +5470 } +5471 Err(e) => { +5472 warn!(%e, "failed to add remote address") 5473 } -5474 Err(e) => { -5475 warn!(%e, "failed to add remote address") -5476 } -5477 } -5478 } -5479 Frame::RemoveAddress(addr) => { -5480 let client_state = match self.n0_nat_traversal.client_side_mut() { -5481 Ok(state) => state, -5482 Err(err) => { -5483 return Err(TransportError::PROTOCOL_VIOLATION(format!( -5484 "Nat traversal(REMOVE_ADDRESS): {err}" -5485 ))); -5486 } -5487 }; -5488 if let Some(removed_addr) = client_state.remove_remote_address(addr) { -5489 self.events.push_back(Event::NatTraversal( -5490 n0_nat_traversal::Event::AddressRemoved(removed_addr), -5491 )); -5492 } -5493 } -5494 Frame::ReachOut(reach_out) => { -5495 let ipv6 = self.is_ipv6(); -5496 let server_state = match self.n0_nat_traversal.server_side_mut() { -5497 Ok(state) => state, -5498 Err(err) => { -5499 return Err(TransportError::PROTOCOL_VIOLATION(format!( -5500 "Nat traversal(REACH_OUT): {err}" -5501 ))); -5502 } -5503 }; -5504 -5505 let round_before = server_state.current_round(); -5506 -5507 if let Err(err) = server_state.handle_reach_out(reach_out, ipv6) { -5508 return Err(TransportError::PROTOCOL_VIOLATION(format!( -5509 "Nat traversal(REACH_OUT): {err}" -5510 ))); -5511 } -5512 -5513 if server_state.current_round() > round_before { -5514 // A new round was started, reset the NAT probe retry timer. -5515 if let Some(delay) = -5516 self.n0_nat_traversal.retry_delay(self.config.initial_rtt) -5517 { -5518 self.timers.set( -5519 Timer::Conn(ConnTimer::NatTraversalProbeRetry), -5520 now + delay, -5521 self.qlog.with_time(now), -5522 ); -5523 } -5524 } -5525 } -5526 } -5527 } -5528 -5529 let space = self.spaces[SpaceId::Data].for_path(path_id); -5530 if space -5531 .pending_acks -5532 .packet_received(now, number, ack_eliciting, &space.dedup) -5533 { -5534 if self.abandoned_paths.contains(&path_id) { -5535 // § 3.4.3 QUIC-MULTIPATH: promptly send ACKs for packets received from -5536 // abandoned paths. -5537 space.pending_acks.set_immediate_ack_required(); -5538 } else { -5539 self.timers.set( -5540 Timer::PerPath(path_id, PathTimer::MaxAckDelay), -5541 now + self.ack_frequency.max_ack_delay, -5542 self.qlog.with_time(now), -5543 ); -5544 } -5545 } -5546 -5547 // Issue stream ID credit due to ACKs of outgoing finish/resets and incoming finish/resets -5548 // on stopped streams. Incoming finishes/resets on open streams are not handled here as they -5549 // are only freed, and hence only issue credit, once the application has been notified -5550 // during a read on the stream. -5551 let pending = &mut self.spaces[SpaceId::Data].pending; -5552 self.streams.queue_max_stream_id(pending); -5553 -5554 if let Some(reason) = close { -5555 self.state.move_to_draining(Some(reason.into())); -5556 self.endpoint_events.push_back(EndpointEventInner::Draining); -5557 self.connection_close_pending = true; -5558 } -5559 -5560 // For Multipath any packet triggers migration. For RFC9000 or QNT (+ Multipath) -5561 // only non-probing packets trigger migration. -5562 let migrate_on_any_packet = -5563 self.is_multipath_negotiated() && !self.n0_nat_traversal.is_negotiated(); -5564 -5565 // Only migrate if this is the largest packet number seen. -5566 let is_largest_received_pn = Some(number) -5567 == self.spaces[SpaceId::Data] -5568 .for_path(path_id) -5569 .largest_received_packet_number; -5570 -5571 // If we receive a non-probing packet on a new local IP that means we had a NAT -5572 // rebinding-like migration. We update our local address but do not otherwise -5573 // validate the new path, we only need to validate the path if the peer migrates per -5574 // RFC9000 §9: https://www.rfc-editor.org/rfc/rfc9000.html#section-9-4 -5575 if (migrate_on_any_packet || !is_probing_packet) -5576 && is_largest_received_pn -5577 && self.local_ip_may_migrate() -5578 && let Some(new_local_ip) = network_path.local_ip -5579 { -5580 let path_data = self.path_data_mut(path_id); -5581 if path_data -5582 .network_path -5583 .local_ip -5584 .is_some_and(|ip| ip != new_local_ip) -5585 { -5586 debug!( -5587 %path_id, -5588 new_4tuple = %network_path, -5589 prev_4tuple = %path_data.network_path, -5590 "local address passive migration" -5591 ); -5592 } -5593 path_data.network_path.local_ip = Some(new_local_ip) -5594 } -5595 -5596 // If the peer migrated to a new address, trigger migration. -5597 if self.peer_may_migrate() -5598 && (migrate_on_any_packet || !is_probing_packet) -5599 && is_largest_received_pn -5600 && network_path.remote != self.path_data(path_id).network_path.remote -5601 { -5602 self.migrate(path_id, now, network_path, migration_observed_addr); -5603 // Break linkability, if possible -5604 self.update_remote_cid(path_id); -5605 self.spin = false; -5606 } +5474 } +5475 } +5476 Frame::RemoveAddress(addr) => { +5477 let client_state = match self.n0_nat_traversal.client_side_mut() { +5478 Ok(state) => state, +5479 Err(err) => { +5480 return Err(TransportError::PROTOCOL_VIOLATION(format!( +5481 "Nat traversal(REMOVE_ADDRESS): {err}" +5482 ))); +5483 } +5484 }; +5485 if let Some(removed_addr) = client_state.remove_remote_address(addr) { +5486 self.events.push_back(Event::NatTraversal( +5487 n0_nat_traversal::Event::AddressRemoved(removed_addr), +5488 )); +5489 } +5490 } +5491 Frame::ReachOut(reach_out) => { +5492 let ipv6 = self.is_ipv6(); +5493 let server_state = match self.n0_nat_traversal.server_side_mut() { +5494 Ok(state) => state, +5495 Err(err) => { +5496 return Err(TransportError::PROTOCOL_VIOLATION(format!( +5497 "Nat traversal(REACH_OUT): {err}" +5498 ))); +5499 } +5500 }; +5501 +5502 let round_before = server_state.current_round(); +5503 +5504 if let Err(err) = server_state.handle_reach_out(reach_out, ipv6) { +5505 return Err(TransportError::PROTOCOL_VIOLATION(format!( +5506 "Nat traversal(REACH_OUT): {err}" +5507 ))); +5508 } +5509 +5510 if server_state.current_round() > round_before { +5511 // A new round was started, reset the NAT probe retry timer. +5512 if let Some(delay) = +5513 self.n0_nat_traversal.retry_delay(self.config.initial_rtt) +5514 { +5515 self.timers.set( +5516 Timer::Conn(ConnTimer::NatTraversalProbeRetry), +5517 now + delay, +5518 self.qlog.with_time(now), +5519 ); +5520 } +5521 } +5522 } +5523 } +5524 } +5525 +5526 let space = self.spaces[SpaceId::Data].for_path(path_id); +5527 if space +5528 .pending_acks +5529 .packet_received(now, number, ack_eliciting, &space.dedup) +5530 { +5531 if self.abandoned_paths.contains(&path_id) { +5532 // § 3.4.3 QUIC-MULTIPATH: promptly send ACKs for packets received from +5533 // abandoned paths. +5534 space.pending_acks.set_immediate_ack_required(); +5535 } else { +5536 self.timers.set( +5537 Timer::PerPath(path_id, PathTimer::MaxAckDelay), +5538 now + self.ack_frequency.max_ack_delay, +5539 self.qlog.with_time(now), +5540 ); +5541 } +5542 } +5543 +5544 // Issue stream ID credit due to ACKs of outgoing finish/resets and incoming finish/resets +5545 // on stopped streams. Incoming finishes/resets on open streams are not handled here as they +5546 // are only freed, and hence only issue credit, once the application has been notified +5547 // during a read on the stream. +5548 let pending = &mut self.spaces[SpaceId::Data].pending; +5549 self.streams.queue_max_stream_id(pending); +5550 +5551 if let Some(reason) = close { +5552 self.state.move_to_draining(Some(reason.into())); +5553 self.endpoint_events.push_back(EndpointEventInner::Draining); +5554 self.connection_close_pending = true; +5555 } +5556 +5557 // For Multipath any packet triggers migration. For RFC9000 or QNT (+ Multipath) +5558 // only non-probing packets trigger migration. +5559 let migrate_on_any_packet = +5560 self.is_multipath_negotiated() && !self.n0_nat_traversal.is_negotiated(); +5561 +5562 // Only migrate if this is the largest packet number seen. +5563 let is_largest_received_pn = Some(number) +5564 == self.spaces[SpaceId::Data] +5565 .for_path(path_id) +5566 .largest_received_packet_number; +5567 +5568 // If we receive a non-probing packet on a new local IP that means we had a NAT +5569 // rebinding-like migration. We update our local address but do not otherwise +5570 // validate the new path, we only need to validate the path if the peer migrates per +5571 // RFC9000 §9: https://www.rfc-editor.org/rfc/rfc9000.html#section-9-4 +5572 if (migrate_on_any_packet || !is_probing_packet) +5573 && is_largest_received_pn +5574 && self.local_ip_may_migrate() +5575 && let Some(new_local_ip) = network_path.local_ip +5576 { +5577 let path_data = self.path_data_mut(path_id); +5578 if path_data +5579 .network_path +5580 .local_ip +5581 .is_some_and(|ip| ip != new_local_ip) +5582 { +5583 debug!( +5584 %path_id, +5585 new_4tuple = %network_path, +5586 prev_4tuple = %path_data.network_path, +5587 "local address passive migration" +5588 ); +5589 } +5590 path_data.network_path.local_ip = Some(new_local_ip) +5591 } +5592 +5593 // If the peer migrated to a new address, trigger migration. +5594 if self.peer_may_migrate() +5595 && (migrate_on_any_packet || !is_probing_packet) +5596 && is_largest_received_pn +5597 && network_path.remote != self.path_data(path_id).network_path.remote +5598 { +5599 self.migrate(path_id, now, network_path, migration_observed_addr); +5600 // Break linkability, if possible +5601 self.update_remote_cid(path_id); +5602 self.spin = false; +5603 } +5604 +5605 Ok(()) +5606 } 5607 -5608 Ok(()) -5609 } -5610 -5611 /// Handles any on-path PATH_RESPONSE frames. -5612 /// -5613 /// *path_id* and *network_path* are those on which the PATH_RESPONSE was received. -5614 fn handle_path_response_on_path( -5615 &mut self, -5616 now: Instant, -5617 response: frame::PathResponse, -5618 path_id: PathId, -5619 ) { -5620 let is_multipath_negotiated = self.is_multipath_negotiated(); -5621 let path = self -5622 .paths -5623 .get_mut(&path_id) -5624 .expect("payload is processed only after the path becomes known"); -5625 match path.data.on_path_response_received(now, response.0) { -5626 paths::OnPathResponseReceived::OnPath if !self.abandoned_paths.contains(&path_id) => { -5627 let qlog = self.qlog.with_time(now); -5628 self.timers.stop( -5629 Timer::PerPath(path_id, PathTimer::PathValidationFailed), -5630 qlog.clone(), -5631 ); -5632 self.timers.stop( -5633 Timer::PerPath(path_id, PathTimer::AbandonFromValidation), -5634 qlog.clone(), -5635 ); -5636 let next_challenge = path -5637 .data -5638 .earliest_on_path_expiring_challenge() -5639 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto()); -5640 self.timers.set_or_stop( -5641 Timer::PerPath(path_id, PathTimer::PathChallengeLost), -5642 next_challenge, -5643 qlog, -5644 ); -5645 let pns = self.spaces[SpaceKind::Data].for_path(path_id); -5646 if !matches!(pns.open_status, OpenStatus::Informed) { -5647 if is_multipath_negotiated { -5648 self.events -5649 .push_back(Event::Path(PathEvent::Established { id: path_id })); -5650 } -5651 pns.open_status = OpenStatus::Informed; -5652 if let Some(observed) = path.data.last_observed_addr_report.as_ref() { -5653 self.events.push_back(Event::Path(PathEvent::ObservedAddr { -5654 id: path_id, -5655 addr: observed.socket_addr(), -5656 })); -5657 } -5658 } -5659 if let Some((_, ref mut prev)) = path.prev { -5660 // If an on-path response was received while there is a -5661 // previous path from a migration, then the new path is -5662 // validated and we can stop sending challenges that try to -5663 // re-validate the previous path. -5664 prev.reset_on_path_challenges(); -5665 } -5666 } -5667 paths::OnPathResponseReceived::OnPath => { -5668 trace!( -5669 %response, -5670 "ignoring PATH_RESPONSE received after path is abandoned" -5671 ); +5608 /// Handles any on-path PATH_RESPONSE frames. +5609 /// +5610 /// *path_id* and *network_path* are those on which the PATH_RESPONSE was received. +5611 fn handle_path_response_on_path( +5612 &mut self, +5613 now: Instant, +5614 response: frame::PathResponse, +5615 path_id: PathId, +5616 ) { +5617 let is_multipath_negotiated = self.is_multipath_negotiated(); +5618 let path = self +5619 .paths +5620 .get_mut(&path_id) +5621 .expect("payload is processed only after the path becomes known"); +5622 match path.data.on_path_response_received(now, response.0) { +5623 paths::OnPathResponseReceived::OnPath if !self.abandoned_paths.contains(&path_id) => { +5624 let qlog = self.qlog.with_time(now); +5625 self.timers.stop( +5626 Timer::PerPath(path_id, PathTimer::PathValidationFailed), +5627 qlog.clone(), +5628 ); +5629 self.timers.stop( +5630 Timer::PerPath(path_id, PathTimer::AbandonFromValidation), +5631 qlog.clone(), +5632 ); +5633 let next_challenge = path +5634 .data +5635 .earliest_on_path_expiring_challenge() +5636 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto()); +5637 self.timers.set_or_stop( +5638 Timer::PerPath(path_id, PathTimer::PathChallengeLost), +5639 next_challenge, +5640 qlog, +5641 ); +5642 let pns = self.spaces[SpaceKind::Data].for_path(path_id); +5643 if !matches!(pns.open_status, OpenStatus::Informed) { +5644 if is_multipath_negotiated { +5645 self.events +5646 .push_back(Event::Path(PathEvent::Established { id: path_id })); +5647 } +5648 pns.open_status = OpenStatus::Informed; +5649 if let Some(observed) = path.data.last_observed_addr_report.as_ref() { +5650 self.events.push_back(Event::Path(PathEvent::ObservedAddr { +5651 id: path_id, +5652 addr: observed.socket_addr(), +5653 })); +5654 } +5655 } +5656 if let Some((_, ref mut prev)) = path.prev { +5657 // If an on-path response was received while there is a +5658 // previous path from a migration, then the new path is +5659 // validated and we can stop sending challenges that try to +5660 // re-validate the previous path. +5661 prev.reset_on_path_challenges(); +5662 } +5663 } +5664 paths::OnPathResponseReceived::OnPath => { +5665 trace!( +5666 %response, +5667 "ignoring PATH_RESPONSE received after path is abandoned" +5668 ); +5669 } +5670 paths::OnPathResponseReceived::Unknown => { +5671 debug!(%response, "ignoring invalid PATH_RESPONSE"); 5672 } -5673 paths::OnPathResponseReceived::Unknown => { -5674 debug!(%response, "ignoring invalid PATH_RESPONSE"); -5675 } -5676 paths::OnPathResponseReceived::Ignored { -5677 sent_on, -5678 current_path, -5679 } => { -5680 debug!(%sent_on, %current_path, %response, "ignoring valid PATH_RESPONSE"); -5681 } -5682 } -5683 } -5684 -5685 /// Opens any paths that have been successfully NAT traversed. -5686 fn open_nat_traversed_paths(&mut self, now: Instant) { -5687 while let Some(network_path) = self -5688 .n0_nat_traversal -5689 .client_side_mut() -5690 .ok() -5691 .and_then(|s| s.pop_pending_path_open()) -5692 { -5693 match self.open_path_ensure(network_path, PathStatus::Backup, now) { -5694 Ok((path_id, already_existed)) => { -5695 debug!( -5696 %path_id, -5697 ?network_path, -5698 new_path = !already_existed, -5699 "Opened NAT traversal path", -5700 ); -5701 } -5702 Err(err) => match err { -5703 PathError::MultipathNotNegotiated -5704 | PathError::ServerSideNotAllowed -5705 | PathError::ValidationFailed -5706 | PathError::InvalidRemoteAddress(_) => { -5707 error!( -5708 ?err, -5709 ?network_path, -5710 "Failed to open path for successful NAT traversal" -5711 ); -5712 } -5713 PathError::MaxPathIdReached | PathError::RemoteCidsExhausted => { -5714 // Temporary error, put back. -5715 self.n0_nat_traversal -5716 .client_side_mut() -5717 .map(|s| s.push_pending_path_open(network_path)) -5718 .ok(); -5719 debug!( -5720 ?err, -5721 ?network_path, -5722 "Blocked opening NAT traversal path, enqueued" -5723 ); -5724 return; -5725 } -5726 }, -5727 } -5728 } -5729 } -5730 -5731 /// Migrates the 4-tuple of the path. -5732 /// -5733 /// This creates a new [`PathData`] for the migrated path and stores the previous -5734 /// [`PathData`] in [`PathState::prev`]. -5735 fn migrate( -5736 &mut self, -5737 path_id: PathId, -5738 now: Instant, -5739 network_path: FourTuple, -5740 observed_addr: Option<ObservedAddr>, -5741 ) { -5742 trace!( -5743 new_4tuple = %network_path, -5744 prev_4tuple = %self.path_data(path_id).network_path, -5745 %path_id, -5746 "migration initiated", -5747 ); -5748 self.path_generation_counter = self.path_generation_counter.wrapping_add(1); -5749 // TODO(@divma): conditions for path migration in multipath are very specific, check them -5750 // again to prevent path migrations that should actually create a new path -5751 -5752 // Reset rtt/congestion state for new path unless it looks like a NAT rebinding. -5753 // Note that the congestion window will not grow until validation terminates. Helps mitigate -5754 // amplification attacks performed by spoofing source addresses. -5755 let prev_pto = self.pto(SpaceKind::Data, path_id); -5756 let path = self.paths.get_mut(&path_id).expect("known path"); -5757 let mut new_path_data = if network_path.remote.is_ipv4() -5758 && network_path.remote.ip() == path.data.network_path.remote.ip() -5759 { -5760 PathData::from_previous(network_path, &path.data, self.path_generation_counter, now) -5761 } else { -5762 let peer_max_udp_payload_size = -5763 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()) -5764 .unwrap_or(u16::MAX); -5765 PathData::new( -5766 network_path, -5767 self.allow_mtud, -5768 Some(peer_max_udp_payload_size), -5769 self.path_generation_counter, -5770 now, -5771 &self.config, -5772 ) -5773 }; -5774 new_path_data.last_observed_addr_report = path.data.last_observed_addr_report.clone(); -5775 if let Some(report) = observed_addr -5776 && let Some(updated) = new_path_data.update_observed_addr_report(report) -5777 { -5778 tracing::info!("adding observed addr event from migration"); -5779 self.events.push_back(Event::Path(PathEvent::ObservedAddr { -5780 id: path_id, -5781 addr: updated, -5782 })); -5783 } -5784 new_path_data.pending_challenge = true; -5785 new_path_data.pending.observed_address = self -5786 .config -5787 .address_discovery_role -5788 .should_report(&self.peer_params.address_discovery_role); -5789 -5790 let mut prev_path_data = mem::replace(&mut path.data, new_path_data); -5791 -5792 // Only store this as previous path if it was validated. For all we know there could -5793 // already be a previous path stored which might have been validated in the past, -5794 // which is more valuable than one that's not yet validated. -5795 // -5796 // With multipath it is possible that there are no remote CIDs for the path ID -5797 // yet. In this case we would never have sent on this path yet and would not be able -5798 // to send a PATH_CHALLENGE either, which is currently a fire-and-forget affair -5799 // anyway. So don't store such a path either. -5800 if !prev_path_data.validated -5801 && let Some(cid) = self.remote_cids.get(&path_id).map(CidQueue::active) -5802 { -5803 prev_path_data.pending_challenge = true; -5804 // We haven't updated the remote CID yet, this captures the remote CID we were using on -5805 // the previous path. -5806 path.prev = Some((cid, prev_path_data)); -5807 } +5673 paths::OnPathResponseReceived::Ignored { +5674 sent_on, +5675 current_path, +5676 } => { +5677 debug!(%sent_on, %current_path, %response, "ignoring valid PATH_RESPONSE"); +5678 } +5679 } +5680 } +5681 +5682 /// Opens any paths that have been successfully NAT traversed. +5683 fn open_nat_traversed_paths(&mut self, now: Instant) { +5684 while let Some(network_path) = self +5685 .n0_nat_traversal +5686 .client_side_mut() +5687 .ok() +5688 .and_then(|s| s.pop_pending_path_open()) +5689 { +5690 match self.open_path_ensure(network_path, PathStatus::Backup, now) { +5691 Ok((path_id, already_existed)) => { +5692 debug!( +5693 %path_id, +5694 ?network_path, +5695 new_path = !already_existed, +5696 "Opened NAT traversal path", +5697 ); +5698 } +5699 Err(err) => match err { +5700 PathError::MultipathNotNegotiated +5701 | PathError::ServerSideNotAllowed +5702 | PathError::ValidationFailed +5703 | PathError::InvalidRemoteAddress(_) => { +5704 error!( +5705 ?err, +5706 ?network_path, +5707 "Failed to open path for successful NAT traversal" +5708 ); +5709 } +5710 PathError::MaxPathIdReached | PathError::RemoteCidsExhausted => { +5711 // Temporary error, put back. +5712 self.n0_nat_traversal +5713 .client_side_mut() +5714 .map(|s| s.push_pending_path_open(network_path)) +5715 .ok(); +5716 debug!( +5717 ?err, +5718 ?network_path, +5719 "Blocked opening NAT traversal path, enqueued" +5720 ); +5721 return; +5722 } +5723 }, +5724 } +5725 } +5726 } +5727 +5728 /// Migrates the 4-tuple of the path. +5729 /// +5730 /// This creates a new [`PathData`] for the migrated path and stores the previous +5731 /// [`PathData`] in [`PathState::prev`]. +5732 fn migrate( +5733 &mut self, +5734 path_id: PathId, +5735 now: Instant, +5736 network_path: FourTuple, +5737 observed_addr: Option<ObservedAddr>, +5738 ) { +5739 trace!( +5740 new_4tuple = %network_path, +5741 prev_4tuple = %self.path_data(path_id).network_path, +5742 %path_id, +5743 "migration initiated", +5744 ); +5745 self.path_generation_counter = self.path_generation_counter.wrapping_add(1); +5746 // TODO(@divma): conditions for path migration in multipath are very specific, check them +5747 // again to prevent path migrations that should actually create a new path +5748 +5749 // Reset rtt/congestion state for new path unless it looks like a NAT rebinding. +5750 // Note that the congestion window will not grow until validation terminates. Helps mitigate +5751 // amplification attacks performed by spoofing source addresses. +5752 let prev_pto = self.pto(SpaceKind::Data, path_id); +5753 let path = self.paths.get_mut(&path_id).expect("known path"); +5754 let mut new_path_data = if network_path.remote.is_ipv4() +5755 && network_path.remote.ip() == path.data.network_path.remote.ip() +5756 { +5757 PathData::from_previous(network_path, &path.data, self.path_generation_counter, now) +5758 } else { +5759 let peer_max_udp_payload_size = +5760 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()) +5761 .unwrap_or(u16::MAX); +5762 PathData::new( +5763 network_path, +5764 self.allow_mtud, +5765 Some(peer_max_udp_payload_size), +5766 self.path_generation_counter, +5767 now, +5768 &self.config, +5769 ) +5770 }; +5771 new_path_data.last_observed_addr_report = path.data.last_observed_addr_report.clone(); +5772 if let Some(report) = observed_addr +5773 && let Some(updated) = new_path_data.update_observed_addr_report(report) +5774 { +5775 tracing::info!("adding observed addr event from migration"); +5776 self.events.push_back(Event::Path(PathEvent::ObservedAddr { +5777 id: path_id, +5778 addr: updated, +5779 })); +5780 } +5781 new_path_data.pending_challenge = true; +5782 new_path_data.pending.observed_address = self +5783 .config +5784 .address_discovery_role +5785 .should_report(&self.peer_params.address_discovery_role); +5786 +5787 let mut prev_path_data = mem::replace(&mut path.data, new_path_data); +5788 +5789 // Only store this as previous path if it was validated. For all we know there could +5790 // already be a previous path stored which might have been validated in the past, +5791 // which is more valuable than one that's not yet validated. +5792 // +5793 // With multipath it is possible that there are no remote CIDs for the path ID +5794 // yet. In this case we would never have sent on this path yet and would not be able +5795 // to send a PATH_CHALLENGE either, which is currently a fire-and-forget affair +5796 // anyway. So don't store such a path either. +5797 if !prev_path_data.validated +5798 && let Some(cid) = self.remote_cids.get(&path_id).map(CidQueue::active) +5799 { +5800 prev_path_data.pending_challenge = true; +5801 // We haven't updated the remote CID yet, this captures the remote CID we were using on +5802 // the previous path. +5803 path.prev = Some((cid, prev_path_data)); +5804 } +5805 +5806 // We need to re-assign the correct remote to this path in qlog +5807 self.qlog.emit_tuple_assigned(path_id, network_path, now); 5808 -5809 // We need to re-assign the correct remote to this path in qlog -5810 self.qlog.emit_tuple_assigned(path_id, network_path, now); -5811 -5812 self.timers.set( -5813 Timer::PerPath(path_id, PathTimer::PathValidationFailed), -5814 now + 3 * cmp::max(self.pto(SpaceKind::Data, path_id), prev_pto), -5815 self.qlog.with_time(now), -5816 ); -5817 } -5818 -5819 /// Handle a change in the local address, i.e. an active migration -5820 /// -5821 /// In the general (non-multipath) case, paths will perform a RFC9000 migration and be pinged -5822 /// for a liveness check. This is the behaviour of a path assumed to be recoverable, even if -5823 /// this is not the case. -5824 /// -5825 /// Clients in a connection in which multipath has been negotiated should migrate paths to new -5826 /// [`PathId`]s. For paths that are known to be non-recoverable can be migrated to a new -5827 /// [`PathId`] by closing the current path, and opening a new one to the same remote. Treating -5828 /// paths as non recoverable when necessary accelerates connectivity re-establishment, or might -5829 /// allow it altogether. -5830 /// -5831 /// The optional `hint` allows callers to indicate when paths are non-recoverable and should be -5832 /// migrated to new a [`PathId`]. -5833 // NOTE: only clients are allowed to migrate, but generally dealing with RFC9000 migrations is -5834 // lacking <https://github.com/n0-computer/noq/issues/364> -5835 pub fn handle_network_change(&mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant) { -5836 debug!("network changed"); -5837 if self.state.is_drained() { -5838 return; -5839 } -5840 if self.highest_space < SpaceKind::Data { -5841 for path in self.paths.values_mut() { -5842 // Clear the local address for it to be obtained from the socket again. -5843 path.data.network_path.local_ip = None; -5844 } +5809 self.timers.set( +5810 Timer::PerPath(path_id, PathTimer::PathValidationFailed), +5811 now + 3 * cmp::max(self.pto(SpaceKind::Data, path_id), prev_pto), +5812 self.qlog.with_time(now), +5813 ); +5814 } +5815 +5816 /// Handle a change in the local address, i.e. an active migration +5817 /// +5818 /// In the general (non-multipath) case, paths will perform a RFC9000 migration and be pinged +5819 /// for a liveness check. This is the behaviour of a path assumed to be recoverable, even if +5820 /// this is not the case. +5821 /// +5822 /// Clients in a connection in which multipath has been negotiated should migrate paths to new +5823 /// [`PathId`]s. For paths that are known to be non-recoverable can be migrated to a new +5824 /// [`PathId`] by closing the current path, and opening a new one to the same remote. Treating +5825 /// paths as non recoverable when necessary accelerates connectivity re-establishment, or might +5826 /// allow it altogether. +5827 /// +5828 /// The optional `hint` allows callers to indicate when paths are non-recoverable and should be +5829 /// migrated to new a [`PathId`]. +5830 // NOTE: only clients are allowed to migrate, but generally dealing with RFC9000 migrations is +5831 // lacking <https://github.com/n0-computer/noq/issues/364> +5832 pub fn handle_network_change(&mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant) { +5833 debug!("network changed"); +5834 if self.state.is_drained() { +5835 return; +5836 } +5837 if self.highest_space < SpaceKind::Data { +5838 for path in self.paths.values_mut() { +5839 // Clear the local address for it to be obtained from the socket again. +5840 path.data.network_path.local_ip = None; +5841 } +5842 +5843 self.update_remote_cid(PathId::ZERO); +5844 self.ping(); 5845 -5846 self.update_remote_cid(PathId::ZERO); -5847 self.ping(); +5846 return; +5847 } 5848 -5849 return; -5850 } -5851 -5852 // Paths that can't recover so a new path should be open instead. If multipath is not -5853 // negotiated, this will be empty. -5854 let mut non_recoverable_paths = Vec::default(); -5855 let mut recoverable_paths = Vec::default(); -5856 let mut open_paths = 0; -5857 -5858 let is_multipath_negotiated = self.is_multipath_negotiated(); -5859 let is_client = self.side().is_client(); -5860 let immediate_ack_allowed = self.peer_supports_ack_frequency(); -5861 -5862 for (path_id, path) in self.paths.iter_mut() { -5863 if self.abandoned_paths.contains(path_id) { -5864 continue; -5865 } -5866 open_paths += 1; -5867 -5868 // Read the network path BEFORE clearing local_ip, so the hint can -5869 // check which interface the path was using. -5870 let network_path = path.data.network_path; -5871 -5872 // Clear the local address for it to be obtained from the socket again. This applies to -5873 // all paths, regardless of being considered recoverable or not -5874 path.data.network_path.local_ip = None; -5875 let remote = network_path.remote; -5876 -5877 // Without multipath, the connection tries to recover the single path, whereas with -5878 // multipath, even in a single-path scenario, we attempt to migrate the path to a new -5879 // PathId. -5880 let attempt_to_recover = if is_multipath_negotiated { -5881 // Use the hint to determine if the path can recover. When no hint is -5882 // provided, clients default to non-recoverable (abandon and re-open) -5883 // while servers default to recoverable (attempt in-place recovery). -5884 hint.map(|h| h.is_path_recoverable(*path_id, network_path)) -5885 .unwrap_or(!is_client) -5886 } else { -5887 // In the non multipath case, we try to recover the single active path -5888 true -5889 }; -5890 -5891 if attempt_to_recover { -5892 recoverable_paths.push((*path_id, remote)); -5893 } else { -5894 non_recoverable_paths.push((*path_id, remote, path.data.local_status())) -5895 } -5896 } -5897 -5898 /* NON RECOVERABLE PATHS */ -5899 // This are handled first, so that in case the treatment intended for these fails, we can -5900 // go the recoverable route instead. -5901 -5902 // Decide if we need to close first or open first in the multipath case. -5903 // - Opening first has a higher risk of getting limited by the negotiated MAX_PATH_ID. -5904 // - Closing first risks this being the only open path. -5905 // We prefer closing paths first unless we identify this is the last open path. -5906 let open_first = open_paths == non_recoverable_paths.len(); -5907 -5908 for (path_id, remote, status) in non_recoverable_paths.into_iter() { -5909 let network_path = FourTuple { -5910 remote, -5911 local_ip: None, /* allow the local ip to be discovered */ -5912 }; -5913 -5914 if open_first && let Err(e) = self.open_path(network_path, status, now) { -5915 if self.side().is_client() { -5916 debug!(%e, "Failed to open new path for network change"); -5917 } -5918 // if this fails, let the path try to recover itself -5919 recoverable_paths.push((path_id, remote)); -5920 continue; -5921 } -5922 -5923 if let Err(e) = -5924 self.close_path_inner(now, path_id, PathAbandonReason::UnusableAfterNetworkChange) -5925 { -5926 debug!(%e,"Failed to close unrecoverable path after network change"); -5927 recoverable_paths.push((path_id, remote)); -5928 continue; -5929 } -5930 -5931 if !open_first && let Err(e) = self.open_path(network_path, status, now) { -5932 // Path has already been closed if we got here. Since the path was not recoverable, -5933 // this might be desirable in any case, because other paths exist (!open_first) and -5934 // this was is considered non recoverable -5935 debug!(%e,"Failed to open new path for network change"); -5936 } -5937 } -5938 -5939 /* RECOVERABLE PATHS */ -5940 -5941 for (path_id, remote) in recoverable_paths.into_iter() { -5942 // Schedule a Ping for a liveness check. -5943 if let Some(path_space) = self.spaces[SpaceId::Data].number_spaces.get_mut(&path_id) { -5944 path_space.pending_ping = true; -5945 -5946 if immediate_ack_allowed { -5947 path_space.pending_immediate_ack = true; -5948 } -5949 } -5950 -5951 // Reset PTO backoff so retransmits resume promptly. Congestion controller and -5952 // RTT are intentionally preserved for recoverable paths. We explicitly allow -5953 // this reset also during the handshake, so do not check -5954 // Self::peer_competed_handshake_address_validation. -5955 if let Some(path) = self.paths.get_mut(&path_id) { -5956 path.data.pto_count = 0; -5957 } -5958 self.set_loss_detection_timer(now, path_id); -5959 -5960 let Some((reset_token, retired)) = -5961 self.remote_cids.get_mut(&path_id).and_then(CidQueue::next) -5962 else { -5963 continue; -5964 }; -5965 -5966 // Retire the current remote CID and any CIDs we had to skip. -5967 self.spaces[SpaceId::Data] -5968 .pending -5969 .retire_cids -5970 .extend(retired.map(|seq| (path_id, seq))); -5971 -5972 debug_assert!(!self.state.is_drained()); // required for endpoint_events, checked above -5973 self.endpoint_events -5974 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token)); -5975 } -5976 } -5977 -5978 /// Switch to a previously unused remote connection ID, if possible -5979 fn update_remote_cid(&mut self, path_id: PathId) { -5980 let Some((reset_token, retired)) = self -5981 .remote_cids -5982 .get_mut(&path_id) -5983 .and_then(|cids| cids.next()) -5984 else { -5985 return; -5986 }; -5987 -5988 // Retire the current remote CID and any CIDs we had to skip. -5989 self.spaces[SpaceId::Data] -5990 .pending -5991 .retire_cids -5992 .extend(retired.map(|seq| (path_id, seq))); -5993 let remote = self.path_data(path_id).network_path.remote; -5994 self.set_reset_token(path_id, remote, reset_token); -5995 } -5996 -5997 /// Sends this reset token to the endpoint -5998 /// -5999 /// The endpoint needs to know the reset tokens issued by the peer, so that if the peer -6000 /// sends a reset token it knows to route it to this connection. See RFC 9000 section -6001 /// 10.3. Stateless Reset. -6002 /// -6003 /// Reset tokens are different for each path, the endpoint identifies paths by peer -6004 /// socket address however, not by path ID. -6005 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) { -6006 debug_assert!(!self.state.is_drained()); // required for endpoint events, set_reset_token is never called for drained connections -6007 self.endpoint_events -6008 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token)); -6009 -6010 // During the handshake the server sends a reset token in the transport -6011 // parameters. When we are the client and we receive the reset token during the -6012 // handshake we want this to affect our peer transport parameters. -6013 // TODO(flub): Pretty sure this is pointless, the entire params is overwritten -6014 // shortly after this was called. And then the params don't have this anymore. -6015 if path_id == PathId::ZERO { -6016 self.peer_params.stateless_reset_token = Some(reset_token); -6017 } -6018 } -6019 -6020 /// Issue an initial set of connection IDs to the peer upon connection -6021 fn issue_first_cids(&mut self, now: Instant) { -6022 if self -6023 .local_cid_state -6024 .get(&PathId::ZERO) -6025 .expect("PathId::ZERO exists when the connection is created") -6026 .cid_len() -6027 == 0 -6028 { -6029 return; -6030 } -6031 -6032 // Subtract 1 to account for the CID we supplied while handshaking -6033 let mut n = self.peer_params.issue_cids_limit() - 1; -6034 if let ConnectionSide::Server { server_config } = &self.side -6035 && server_config.has_preferred_address() -6036 { -6037 // We also sent a CID in the transport parameters -6038 n -= 1; -6039 } -6040 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events -6041 self.endpoint_events -6042 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n)); -6043 } -6044 -6045 /// Issues an initial set of CIDs for paths that have not yet had any CIDs issued -6046 /// -6047 /// Later CIDs are issued when CIDs expire or are retired by the peer. -6048 fn issue_first_path_cids(&mut self, now: Instant) { -6049 if let Some(max_path_id) = self.max_path_id() { -6050 let mut path_id = self.max_path_id_with_cids.next(); -6051 while path_id <= max_path_id { -6052 self.endpoint_events -6053 .push_back(EndpointEventInner::NeedIdentifiers( -6054 path_id, -6055 now, -6056 self.peer_params.issue_cids_limit(), -6057 )); -6058 path_id = path_id.next(); -6059 } -6060 self.max_path_id_with_cids = max_path_id; -6061 } -6062 } -6063 -6064 /// Populates a packet with frames -6065 /// -6066 /// This tries to fit as many frames as possible into the packet. -6067 /// -6068 /// *path_exclusive_only* means to only build frames which can only be sent on this -6069 /// *path. This is used in multipath for backup paths while there is still an active -6070 /// *path. -6071 fn populate_packet<'a, 'b>( -6072 &mut self, -6073 now: Instant, -6074 space_id: SpaceId, -6075 path_id: PathId, -6076 scheduling_info: &PathSchedulingInfo, -6077 builder: &mut PacketBuilder<'a, 'b>, -6078 ) { -6079 let is_multipath_negotiated = self.is_multipath_negotiated(); -6080 let space_has_keys = self.crypto_state.has_keys(space_id.encryption_level()); -6081 let is_0rtt = space_id == SpaceId::Data && !space_has_keys; -6082 let stats = &mut self.path_stats.for_path(path_id).frame_tx; -6083 let space = &mut self.spaces[space_id]; -6084 let path = &mut self.paths.get_mut(&path_id).expect("known path").data; -6085 space -6086 .for_path(path_id) -6087 .pending_acks -6088 .maybe_ack_non_eliciting(); -6089 -6090 // HANDSHAKE_DONE -6091 if !is_0rtt -6092 && !scheduling_info.is_abandoned -6093 && scheduling_info.may_send_data -6094 && mem::replace(&mut space.pending.handshake_done, false) -6095 { -6096 builder.write_frame(frame::HandshakeDone, stats); -6097 } -6098 -6099 // PING -6100 if !scheduling_info.is_abandoned -6101 && mem::replace(&mut space.for_path(path_id).pending_ping, false) -6102 { -6103 builder.write_frame(frame::Ping, stats); -6104 } -6105 -6106 // IMMEDIATE_ACK -6107 if !scheduling_info.is_abandoned -6108 && mem::replace(&mut space.for_path(path_id).pending_immediate_ack, false) -6109 { -6110 debug_assert_eq!( -6111 space_id, -6112 SpaceId::Data, -6113 "immediate acks must be sent in the data space" -6114 ); -6115 builder.write_frame(frame::ImmediateAck, stats); -6116 } -6117 -6118 // ACK -6119 if !scheduling_info.is_abandoned && scheduling_info.may_send_data { -6120 for path_id in space -6121 .number_spaces -6122 .iter_mut() -6123 .filter(|(_, pns)| pns.pending_acks.can_send()) -6124 .map(|(&path_id, _)| path_id) -6125 .collect::<Vec<_>>() -6126 { -6127 Self::populate_acks( -6128 now, -6129 self.receiving_ecn, -6130 path_id, -6131 space_id, -6132 space, -6133 is_multipath_negotiated, -6134 builder, -6135 stats, -6136 space_has_keys, -6137 ); -6138 } -6139 } -6140 -6141 // ACK_FREQUENCY -6142 if !scheduling_info.is_abandoned -6143 && scheduling_info.may_send_data -6144 && mem::replace(&mut space.pending.ack_frequency, false) -6145 { -6146 let sequence_number = self.ack_frequency.next_sequence_number(); +5849 // Paths that can't recover so a new path should be open instead. If multipath is not +5850 // negotiated, this will be empty. +5851 let mut non_recoverable_paths = Vec::default(); +5852 let mut recoverable_paths = Vec::default(); +5853 let mut open_paths = 0; +5854 +5855 let is_multipath_negotiated = self.is_multipath_negotiated(); +5856 let is_client = self.side().is_client(); +5857 let immediate_ack_allowed = self.peer_supports_ack_frequency(); +5858 +5859 for (path_id, path) in self.paths.iter_mut() { +5860 if self.abandoned_paths.contains(path_id) { +5861 continue; +5862 } +5863 open_paths += 1; +5864 +5865 // Read the network path BEFORE clearing local_ip, so the hint can +5866 // check which interface the path was using. +5867 let network_path = path.data.network_path; +5868 +5869 // Clear the local address for it to be obtained from the socket again. This applies to +5870 // all paths, regardless of being considered recoverable or not +5871 path.data.network_path.local_ip = None; +5872 let remote = network_path.remote; +5873 +5874 // Without multipath, the connection tries to recover the single path, whereas with +5875 // multipath, even in a single-path scenario, we attempt to migrate the path to a new +5876 // PathId. +5877 let attempt_to_recover = if is_multipath_negotiated { +5878 // Use the hint to determine if the path can recover. When no hint is +5879 // provided, clients default to non-recoverable (abandon and re-open) +5880 // while servers default to recoverable (attempt in-place recovery). +5881 hint.map(|h| h.is_path_recoverable(*path_id, network_path)) +5882 .unwrap_or(!is_client) +5883 } else { +5884 // In the non multipath case, we try to recover the single active path +5885 true +5886 }; +5887 +5888 if attempt_to_recover { +5889 recoverable_paths.push((*path_id, remote)); +5890 } else { +5891 non_recoverable_paths.push((*path_id, remote, path.data.local_status())) +5892 } +5893 } +5894 +5895 /* NON RECOVERABLE PATHS */ +5896 // This are handled first, so that in case the treatment intended for these fails, we can +5897 // go the recoverable route instead. +5898 +5899 // Decide if we need to close first or open first in the multipath case. +5900 // - Opening first has a higher risk of getting limited by the negotiated MAX_PATH_ID. +5901 // - Closing first risks this being the only open path. +5902 // We prefer closing paths first unless we identify this is the last open path. +5903 let open_first = open_paths == non_recoverable_paths.len(); +5904 +5905 for (path_id, remote, status) in non_recoverable_paths.into_iter() { +5906 let network_path = FourTuple { +5907 remote, +5908 local_ip: None, /* allow the local ip to be discovered */ +5909 }; +5910 +5911 if open_first && let Err(e) = self.open_path(network_path, status, now) { +5912 if self.side().is_client() { +5913 debug!(%e, "Failed to open new path for network change"); +5914 } +5915 // if this fails, let the path try to recover itself +5916 recoverable_paths.push((path_id, remote)); +5917 continue; +5918 } +5919 +5920 if let Err(e) = +5921 self.close_path_inner(now, path_id, PathAbandonReason::UnusableAfterNetworkChange) +5922 { +5923 debug!(%e,"Failed to close unrecoverable path after network change"); +5924 recoverable_paths.push((path_id, remote)); +5925 continue; +5926 } +5927 +5928 if !open_first && let Err(e) = self.open_path(network_path, status, now) { +5929 // Path has already been closed if we got here. Since the path was not recoverable, +5930 // this might be desirable in any case, because other paths exist (!open_first) and +5931 // this was is considered non recoverable +5932 debug!(%e,"Failed to open new path for network change"); +5933 } +5934 } +5935 +5936 /* RECOVERABLE PATHS */ +5937 +5938 for (path_id, remote) in recoverable_paths.into_iter() { +5939 // Schedule a Ping for a liveness check. +5940 if let Some(path_space) = self.spaces[SpaceId::Data].number_spaces.get_mut(&path_id) { +5941 path_space.pending_ping = true; +5942 +5943 if immediate_ack_allowed { +5944 path_space.pending_immediate_ack = true; +5945 } +5946 } +5947 +5948 // Reset PTO backoff so retransmits resume promptly. Congestion controller and +5949 // RTT are intentionally preserved for recoverable paths. We explicitly allow +5950 // this reset also during the handshake, so do not check +5951 // Self::peer_competed_handshake_address_validation. +5952 if let Some(path) = self.paths.get_mut(&path_id) { +5953 path.data.pto_count = 0; +5954 } +5955 self.set_loss_detection_timer(now, path_id); +5956 +5957 let Some((reset_token, retired)) = +5958 self.remote_cids.get_mut(&path_id).and_then(CidQueue::next) +5959 else { +5960 continue; +5961 }; +5962 +5963 // Retire the current remote CID and any CIDs we had to skip. +5964 self.spaces[SpaceId::Data] +5965 .pending +5966 .retire_cids +5967 .extend(retired.map(|seq| (path_id, seq))); +5968 +5969 debug_assert!(!self.state.is_drained()); // required for endpoint_events, checked above +5970 self.endpoint_events +5971 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token)); +5972 } +5973 } +5974 +5975 /// Switch to a previously unused remote connection ID, if possible +5976 fn update_remote_cid(&mut self, path_id: PathId) { +5977 let Some((reset_token, retired)) = self +5978 .remote_cids +5979 .get_mut(&path_id) +5980 .and_then(|cids| cids.next()) +5981 else { +5982 return; +5983 }; +5984 +5985 // Retire the current remote CID and any CIDs we had to skip. +5986 self.spaces[SpaceId::Data] +5987 .pending +5988 .retire_cids +5989 .extend(retired.map(|seq| (path_id, seq))); +5990 let remote = self.path_data(path_id).network_path.remote; +5991 self.set_reset_token(path_id, remote, reset_token); +5992 } +5993 +5994 /// Sends this reset token to the endpoint +5995 /// +5996 /// The endpoint needs to know the reset tokens issued by the peer, so that if the peer +5997 /// sends a reset token it knows to route it to this connection. See RFC 9000 section +5998 /// 10.3. Stateless Reset. +5999 /// +6000 /// Reset tokens are different for each path, the endpoint identifies paths by peer +6001 /// socket address however, not by path ID. +6002 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) { +6003 debug_assert!(!self.state.is_drained()); // required for endpoint events, set_reset_token is never called for drained connections +6004 self.endpoint_events +6005 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token)); +6006 +6007 // During the handshake the server sends a reset token in the transport +6008 // parameters. When we are the client and we receive the reset token during the +6009 // handshake we want this to affect our peer transport parameters. +6010 // TODO(flub): Pretty sure this is pointless, the entire params is overwritten +6011 // shortly after this was called. And then the params don't have this anymore. +6012 if path_id == PathId::ZERO { +6013 self.peer_params.stateless_reset_token = Some(reset_token); +6014 } +6015 } +6016 +6017 /// Issue an initial set of connection IDs to the peer upon connection +6018 fn issue_first_cids(&mut self, now: Instant) { +6019 if self +6020 .local_cid_state +6021 .get(&PathId::ZERO) +6022 .expect("PathId::ZERO exists when the connection is created") +6023 .cid_len() +6024 == 0 +6025 { +6026 return; +6027 } +6028 +6029 // Subtract 1 to account for the CID we supplied while handshaking +6030 let mut n = self.peer_params.issue_cids_limit() - 1; +6031 if let ConnectionSide::Server { server_config } = &self.side +6032 && server_config.has_preferred_address() +6033 { +6034 // We also sent a CID in the transport parameters +6035 n -= 1; +6036 } +6037 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events +6038 self.endpoint_events +6039 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n)); +6040 } +6041 +6042 /// Issues an initial set of CIDs for paths that have not yet had any CIDs issued +6043 /// +6044 /// Later CIDs are issued when CIDs expire or are retired by the peer. +6045 fn issue_first_path_cids(&mut self, now: Instant) { +6046 if let Some(max_path_id) = self.max_path_id() { +6047 let mut path_id = self.max_path_id_with_cids.next(); +6048 while path_id <= max_path_id { +6049 self.endpoint_events +6050 .push_back(EndpointEventInner::NeedIdentifiers( +6051 path_id, +6052 now, +6053 self.peer_params.issue_cids_limit(), +6054 )); +6055 path_id = path_id.next(); +6056 } +6057 self.max_path_id_with_cids = max_path_id; +6058 } +6059 } +6060 +6061 /// Populates a packet with frames +6062 /// +6063 /// This tries to fit as many frames as possible into the packet. +6064 /// +6065 /// *path_exclusive_only* means to only build frames which can only be sent on this +6066 /// *path. This is used in multipath for backup paths while there is still an active +6067 /// *path. +6068 fn populate_packet<'a, 'b>( +6069 &mut self, +6070 now: Instant, +6071 space_id: SpaceId, +6072 path_id: PathId, +6073 scheduling_info: &PathSchedulingInfo, +6074 builder: &mut PacketBuilder<'a, 'b>, +6075 ) { +6076 let is_multipath_negotiated = self.is_multipath_negotiated(); +6077 let space_has_keys = self.crypto_state.has_keys(space_id.encryption_level()); +6078 let is_0rtt = space_id == SpaceId::Data && !space_has_keys; +6079 let stats = &mut self.path_stats.get_mut(path_id).frame_tx; +6080 let space = &mut self.spaces[space_id]; +6081 let path = &mut self.paths.get_mut(&path_id).expect("known path").data; +6082 space +6083 .for_path(path_id) +6084 .pending_acks +6085 .maybe_ack_non_eliciting(); +6086 +6087 // HANDSHAKE_DONE +6088 if !is_0rtt +6089 && !scheduling_info.is_abandoned +6090 && scheduling_info.may_send_data +6091 && mem::replace(&mut space.pending.handshake_done, false) +6092 { +6093 builder.write_frame(frame::HandshakeDone, stats); +6094 } +6095 +6096 // PING +6097 if !scheduling_info.is_abandoned +6098 && mem::replace(&mut space.for_path(path_id).pending_ping, false) +6099 { +6100 builder.write_frame(frame::Ping, stats); +6101 } +6102 +6103 // IMMEDIATE_ACK +6104 if !scheduling_info.is_abandoned +6105 && mem::replace(&mut space.for_path(path_id).pending_immediate_ack, false) +6106 { +6107 debug_assert_eq!( +6108 space_id, +6109 SpaceId::Data, +6110 "immediate acks must be sent in the data space" +6111 ); +6112 builder.write_frame(frame::ImmediateAck, stats); +6113 } +6114 +6115 // ACK +6116 if !scheduling_info.is_abandoned && scheduling_info.may_send_data { +6117 for path_id in space +6118 .number_spaces +6119 .iter_mut() +6120 .filter(|(_, pns)| pns.pending_acks.can_send()) +6121 .map(|(&path_id, _)| path_id) +6122 .collect::<Vec<_>>() +6123 { +6124 Self::populate_acks( +6125 now, +6126 self.receiving_ecn, +6127 path_id, +6128 space_id, +6129 space, +6130 is_multipath_negotiated, +6131 builder, +6132 stats, +6133 space_has_keys, +6134 ); +6135 } +6136 } +6137 +6138 // ACK_FREQUENCY +6139 if !scheduling_info.is_abandoned +6140 && scheduling_info.may_send_data +6141 && mem::replace(&mut space.pending.ack_frequency, false) +6142 { +6143 let sequence_number = self.ack_frequency.next_sequence_number(); +6144 +6145 // Safe to unwrap because this is always provided when ACK frequency is enabled +6146 let config = self.config.ack_frequency_config.as_ref().unwrap(); 6147 -6148 // Safe to unwrap because this is always provided when ACK frequency is enabled -6149 let config = self.config.ack_frequency_config.as_ref().unwrap(); -6150 -6151 // Ensure the delay is within bounds to avoid a PROTOCOL_VIOLATION error -6152 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay( -6153 path.rtt.get(), -6154 config, -6155 &self.peer_params, -6156 ); -6157 -6158 let frame = frame::AckFrequency { -6159 sequence: sequence_number, -6160 ack_eliciting_threshold: config.ack_eliciting_threshold, -6161 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX), -6162 reordering_threshold: config.reordering_threshold, -6163 }; -6164 builder.write_frame(frame, stats); -6165 -6166 self.ack_frequency -6167 .ack_frequency_sent(path_id, builder.packet_number, max_ack_delay); -6168 } -6169 -6170 // PATH_CHALLENGE (on-path) -6171 if !scheduling_info.is_abandoned -6172 && space_id == SpaceId::Data -6173 && path.pending_challenge -6174 // we don't want to send new challenges if we are already closing -6175 && !self.state.is_closed() -6176 && builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND -6177 // An on-path PATH_CHALLENGE must be part of datagrams expanded to the -6178 // MIN_INITIAL_SIZE (1200 bytes). -6179 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE) -6180 { -6181 path.pending_challenge = false; -6182 -6183 let token = self.rng.random(); -6184 path.record_path_challenge_sent(now, token, path.network_path); -6185 // Generate a new challenge every time we send a new PATH_CHALLENGE -6186 let challenge = frame::PathChallenge(token); -6187 builder.write_frame(challenge, stats); -6188 builder.require_padding(); -6189 let pto = self.ack_frequency.max_ack_delay_for_pto() + path.rtt.pto_base(); -6190 let pns = space.for_path(path_id); -6191 match pns.open_status { -6192 OpenStatus::Sent | OpenStatus::Informed => {} -6193 OpenStatus::Pending => { -6194 pns.open_status = OpenStatus::Sent; -6195 self.timers.set( -6196 Timer::PerPath(path_id, PathTimer::AbandonFromValidation), -6197 now + 3 * pto, -6198 self.qlog.with_time(now), -6199 ); -6200 } -6201 } -6202 -6203 self.timers.set( -6204 Timer::PerPath(path_id, PathTimer::PathChallengeLost), -6205 now + path.on_path_challenge_expiry(), -6206 self.qlog.with_time(now), -6207 ); -6208 -6209 if is_multipath_negotiated && !path.validated && path.pending_challenge { -6210 // queue informing the path status along with the challenge -6211 space.pending.path_status.insert(path_id); -6212 } -6213 -6214 // Always include an OBSERVED_ADDR frame with a PATH_CHALLENGE, regardless -6215 // of whether one has already been sent on this path. -6216 path.pending.observed_address = self -6217 .config -6218 .address_discovery_role -6219 .should_report(&self.peer_params.address_discovery_role); -6220 } -6221 -6222 // PATH_RESPONSE (on-path) -6223 if !scheduling_info.is_abandoned -6224 && space_id == SpaceId::Data -6225 && builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND -6226 // An on-path PATH_RESPONSE must be part of datagrams expanded to the -6227 // MIN_INITIAL_SIZE (1200 bytes). -6228 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE) -6229 && let Some(token) = space.for_path(path_id).pending_path_responses.pop_on_path(path.network_path) -6230 { -6231 let response = frame::PathResponse(token); -6232 builder.write_frame(response, stats); -6233 builder.require_padding(); -6234 -6235 // NOTE: this is technically not required but might be useful to ride the -6236 // request/response nature of path challenges to refresh an observation -6237 // Since PATH_RESPONSE is a probing frame, this is allowed by the spec. -6238 path.pending.observed_address = self -6239 .config -6240 .address_discovery_role -6241 .should_report(&self.peer_params.address_discovery_role); -6242 } -6243 -6244 // ADD_ADDRESS -6245 while space_id == SpaceId::Data -6246 && !scheduling_info.is_abandoned -6247 && scheduling_info.may_send_data -6248 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining() -6249 { -6250 if let Some(added_address) = space.pending.add_address.pop_last() { -6251 builder.write_frame(added_address, stats); -6252 } else { -6253 break; -6254 } -6255 } -6256 -6257 // REMOVE_ADDRESS -6258 while space_id == SpaceId::Data -6259 && !scheduling_info.is_abandoned -6260 && scheduling_info.may_send_data -6261 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining() -6262 { -6263 if let Some(removed_address) = space.pending.remove_address.pop_last() { -6264 builder.write_frame(removed_address, stats); -6265 } else { -6266 break; -6267 } -6268 } -6269 -6270 // REACH_OUT -6271 while !scheduling_info.is_abandoned -6272 && scheduling_info.may_send_data -6273 && let Some(reach_out) = space -6274 .pending -6275 .reach_out -6276 .pop_if(|frame| builder.frame_space_remaining() >= frame.size()) -6277 { -6278 builder.write_frame(reach_out, stats); -6279 } -6280 -6281 // PATH_ABANDON -6282 if space_id == SpaceId::Data -6283 && scheduling_info.is_abandoned -6284 && scheduling_info.may_self_abandon -6285 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining() -6286 && let Some(error_code) = space.pending.path_abandon.remove(&path_id) -6287 { -6288 let frame = frame::PathAbandon { -6289 path_id, -6290 error_code, -6291 }; -6292 builder.write_frame(frame, stats); -6293 -6294 // Consider remotely issued CIDs as retired now that we have sent this frame at -6295 // least once. -6296 self.remote_cids.remove(&path_id); -6297 } -6298 while space_id == SpaceId::Data -6299 && scheduling_info.may_send_data -6300 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining() -6301 && let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first() -6302 { -6303 let frame = frame::PathAbandon { -6304 path_id: abandoned_path_id, -6305 error_code, -6306 }; -6307 builder.write_frame(frame, stats); -6308 -6309 // Consider remotely issued CIDs as retired now that we have sent this frame at -6310 // least once. -6311 self.remote_cids.remove(&abandoned_path_id); -6312 } -6313 -6314 // OBSERVED_ADDR -6315 if !scheduling_info.is_abandoned -6316 && space_id == SpaceId::Data -6317 && path.pending.observed_address -6318 { -6319 let frame = -6320 frame::ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no); -6321 if builder.frame_space_remaining() > frame.size() { -6322 builder.write_frame(frame, stats); -6323 -6324 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8); -6325 path.pending.observed_address = false; -6326 } -6327 } -6328 -6329 // CRYPTO -6330 while !is_0rtt -6331 && !scheduling_info.is_abandoned -6332 && scheduling_info.may_send_data -6333 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND -6334 { -6335 let Some(mut frame) = space.pending.crypto.pop_front() else { -6336 break; -6337 }; -6338 -6339 // Calculate the maximum amount of crypto data we can store in the buffer. -6340 // Since the offset is known, we can reserve the exact size required to encode it. -6341 // For length we reserve 2bytes which allows to encode up to 2^14, -6342 // which is more than what fits into normally sized QUIC frames. -6343 let max_crypto_data_size = builder.frame_space_remaining() -6344 - 1 // Frame Type -6345 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) }) -6346 - 2; // Maximum encoded length for frame size, given we send less than 2^14 bytes -6347 -6348 let len = frame -6349 .data -6350 .len() -6351 .min(2usize.pow(14) - 1) -6352 .min(max_crypto_data_size); -6353 -6354 let data = frame.data.split_to(len); -6355 let offset = frame.offset; -6356 let truncated = frame::Crypto { offset, data }; -6357 builder.write_frame(truncated, stats); -6358 -6359 if !frame.data.is_empty() { -6360 frame.offset += len as u64; -6361 space.pending.crypto.push_front(frame); -6362 } -6363 } -6364 -6365 // PATH_STATUS_AVAILABLE & PATH_STATUS_BACKUP -6366 while space_id == SpaceId::Data -6367 && !scheduling_info.is_abandoned -6368 && scheduling_info.may_send_data -6369 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining() -6370 { -6371 let Some(path_id) = space.pending.path_status.pop_first() else { -6372 break; -6373 }; -6374 let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else { -6375 trace!(%path_id, "discarding queued path status for unknown path"); -6376 continue; -6377 }; -6378 -6379 let seq = path.status.seq(); -6380 match path.local_status() { -6381 PathStatus::Available => { -6382 let frame = frame::PathStatusAvailable { -6383 path_id, -6384 status_seq_no: seq, -6385 }; -6386 builder.write_frame(frame, stats); -6387 } -6388 PathStatus::Backup => { -6389 let frame = frame::PathStatusBackup { -6390 path_id, -6391 status_seq_no: seq, -6392 }; -6393 builder.write_frame(frame, stats); -6394 } -6395 } -6396 } -6397 -6398 // MAX_PATH_ID -6399 if space_id == SpaceId::Data -6400 && !scheduling_info.is_abandoned -6401 && scheduling_info.may_send_data -6402 && space.pending.max_path_id -6403 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining() -6404 { -6405 let frame = frame::MaxPathId(self.local_max_path_id); -6406 builder.write_frame(frame, stats); -6407 space.pending.max_path_id = false; -6408 } -6409 -6410 // PATHS_BLOCKED -6411 if space_id == SpaceId::Data -6412 && !scheduling_info.is_abandoned -6413 && scheduling_info.may_send_data -6414 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining() -6415 && let Some(remote_max_path_id) = space.pending.paths_blocked.take() -6416 { -6417 let frame = frame::PathsBlocked(remote_max_path_id); -6418 builder.write_frame(frame, stats); -6419 } -6420 -6421 // PATH_CIDS_BLOCKED -6422 while space_id == SpaceId::Data -6423 && !scheduling_info.is_abandoned -6424 && scheduling_info.may_send_data -6425 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining() -6426 { -6427 let Some((path_id, next_seq)) = space.pending.path_cids_blocked.pop_first() else { -6428 break; -6429 }; -6430 let frame = frame::PathCidsBlocked { path_id, next_seq }; -6431 builder.write_frame(frame, stats); -6432 } -6433 -6434 // RESET_STREAM, STOP_SENDING, MAX_DATA, MAX_STREAM_DATA, MAX_STREAMS -6435 if space_id == SpaceId::Data -6436 && !scheduling_info.is_abandoned -6437 && scheduling_info.may_send_data -6438 { -6439 self.streams -6440 .write_control_frames(builder, &mut space.pending, stats); -6441 } -6442 -6443 // NEW_CONNECTION_ID -6444 let cid_len = self -6445 .local_cid_state -6446 .values() -6447 .map(|cid_state| cid_state.cid_len()) -6448 .max() -6449 .expect("some local CID state must exist"); -6450 let new_cid_size_bound = -6451 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len); -6452 while !scheduling_info.is_abandoned -6453 && scheduling_info.may_send_data -6454 && builder.frame_space_remaining() > new_cid_size_bound -6455 { -6456 let Some(issued) = space.pending.new_cids.pop() else { -6457 break; -6458 }; -6459 // Path was discarded after this CID was queued, drop. -6460 let Some(cid_state) = self.local_cid_state.get(&issued.path_id) else { -6461 debug!( -6462 path = %issued.path_id, seq = issued.sequence, -6463 "dropping queued NEW_CONNECTION_ID for discarded path", -6464 ); -6465 continue; -6466 }; -6467 let retire_prior_to = cid_state.retire_prior_to(); -6468 -6469 let cid_path_id = match is_multipath_negotiated { -6470 true => Some(issued.path_id), -6471 false => { -6472 debug_assert_eq!(issued.path_id, PathId::ZERO); -6473 None -6474 } -6475 }; -6476 let frame = frame::NewConnectionId { -6477 path_id: cid_path_id, -6478 sequence: issued.sequence, -6479 retire_prior_to, -6480 id: issued.id, -6481 reset_token: issued.reset_token, -6482 }; -6483 builder.write_frame(frame, stats); -6484 } -6485 -6486 // RETIRE_CONNECTION_ID -6487 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated); -6488 while !scheduling_info.is_abandoned -6489 && scheduling_info.may_send_data -6490 && builder.frame_space_remaining() > retire_cid_bound -6491 { -6492 let (path_id, sequence) = match space.pending.retire_cids.pop() { -6493 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq), -6494 Some((path_id, seq)) => (Some(path_id), seq), -6495 None => break, -6496 }; -6497 let frame = frame::RetireConnectionId { path_id, sequence }; -6498 builder.write_frame(frame, stats); -6499 } -6500 -6501 // DATAGRAM -6502 let mut sent_datagrams = false; -6503 while !scheduling_info.is_abandoned -6504 && scheduling_info.may_send_data -6505 && builder.frame_space_remaining() > Datagram::SIZE_BOUND -6506 && space_id == SpaceId::Data -6507 { -6508 match self.datagrams.write(builder, stats) { -6509 true => { -6510 sent_datagrams = true; -6511 } -6512 false => break, -6513 } -6514 } -6515 if self.datagrams.send_blocked && sent_datagrams { -6516 self.events.push_back(Event::DatagramsUnblocked); -6517 self.datagrams.send_blocked = false; -6518 } -6519 -6520 let path = &mut self.paths.get_mut(&path_id).expect("known path").data; -6521 -6522 // NEW_TOKEN -6523 if !scheduling_info.is_abandoned && scheduling_info.may_send_data { -6524 while let Some(network_path) = space.pending.new_tokens.pop() { -6525 debug_assert_eq!(space_id, SpaceId::Data); -6526 let ConnectionSide::Server { server_config } = &self.side else { -6527 panic!("NEW_TOKEN frames should not be enqueued by clients"); -6528 }; -6529 -6530 if !network_path.is_probably_same_path(&path.network_path) { -6531 // NEW_TOKEN frames contain tokens bound to a client's IP address, and are only -6532 // useful if used from the same IP address. Thus, we abandon enqueued NEW_TOKEN -6533 // frames upon an path change. Instead, when the new path becomes validated, -6534 // NEW_TOKEN frames may be enqueued for the new path instead. -6535 continue; -6536 } -6537 -6538 let token = Token::new( -6539 TokenPayload::Validation { -6540 ip: network_path.remote.ip(), -6541 issued: server_config.time_source.now(), -6542 }, -6543 &mut self.rng, -6544 ); -6545 let new_token = NewToken { -6546 token: token.encode(&*server_config.token_key).into(), -6547 }; -6548 -6549 if builder.frame_space_remaining() < new_token.size() { -6550 space.pending.new_tokens.push(network_path); -6551 break; -6552 } -6553 -6554 builder.write_frame(new_token, stats); -6555 builder.retransmits_mut().new_tokens.push(network_path); -6556 } -6557 } -6558 -6559 // STREAM -6560 if !scheduling_info.is_abandoned -6561 && scheduling_info.may_send_data -6562 && space_id == SpaceId::Data -6563 { -6564 self.streams -6565 .write_stream_frames(builder, self.config.send_fairness, stats); -6566 } -6567 } -6568 -6569 /// Write pending ACKs into a buffer -6570 fn populate_acks<'a, 'b>( -6571 now: Instant, -6572 receiving_ecn: bool, -6573 path_id: PathId, -6574 space_id: SpaceId, -6575 space: &mut PacketSpace, -6576 is_multipath_negotiated: bool, -6577 builder: &mut PacketBuilder<'a, 'b>, -6578 stats: &mut FrameStats, -6579 space_has_keys: bool, -6580 ) { -6581 // 0-RTT packets must never carry acks (which would have to be of handshake packets) -6582 debug_assert!(space_has_keys, "tried to send ACK in 0-RTT"); -6583 -6584 debug_assert!( -6585 is_multipath_negotiated || path_id == PathId::ZERO, -6586 "Only PathId::ZERO allowed without multipath (have {path_id:?})" -6587 ); -6588 if is_multipath_negotiated { -6589 debug_assert!( -6590 space_id == SpaceId::Data || path_id == PathId::ZERO, -6591 "path acks must be sent in 1RTT space (have {space_id:?})" -6592 ); -6593 } -6594 -6595 let pns = space.for_path(path_id); -6596 let ranges = pns.pending_acks.ranges(); -6597 debug_assert!(!ranges.is_empty(), "can not send empty ACK range"); -6598 let ecn = if receiving_ecn { -6599 Some(&pns.ecn_counters) -6600 } else { -6601 None -6602 }; -6603 -6604 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64; -6605 // TODO: This should come from `TransportConfig` if that gets configurable. -6606 let ack_delay_exp = TransportParameters::default().ack_delay_exponent; -6607 let delay = delay_micros >> ack_delay_exp.into_inner(); -6608 -6609 if is_multipath_negotiated && space_id == SpaceId::Data { -6610 if !ranges.is_empty() { -6611 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn); -6612 builder.write_frame(frame, stats); -6613 } -6614 } else { -6615 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats); -6616 } -6617 } -6618 -6619 fn close_common(&mut self) { -6620 trace!("connection closed"); -6621 self.timers.reset(); -6622 } -6623 -6624 fn set_close_timer(&mut self, now: Instant) { -6625 // QUIC-MULTIPATH § 2.6 Connection Closure: draining for 3*PTO using the max PTO of -6626 // all paths. -6627 let pto_max = self.max_pto_for_space(self.highest_space); -6628 self.timers.set( -6629 Timer::Conn(ConnTimer::Close), -6630 now + 3 * pto_max, -6631 self.qlog.with_time(now), -6632 ); -6633 } -6634 -6635 /// Handle transport parameters received from the peer -6636 /// -6637 /// *remote_cid* and *local_cid* are the source and destination CIDs respectively of the -6638 /// *packet into which the transport parameters arrived. -6639 fn handle_peer_params( -6640 &mut self, -6641 params: TransportParameters, -6642 local_cid: ConnectionId, -6643 remote_cid: ConnectionId, -6644 now: Instant, -6645 ) -> Result<(), TransportError> { -6646 if Some(self.original_remote_cid) != params.initial_src_cid -6647 || (self.side.is_client() -6648 && (Some(self.initial_dst_cid) != params.original_dst_cid -6649 || self.retry_src_cid != params.retry_src_cid)) -6650 { -6651 return Err(TransportError::TRANSPORT_PARAMETER_ERROR( -6652 "CID authentication failure", -6653 )); -6654 } -6655 if params.initial_max_path_id.is_some() && (local_cid.is_empty() || remote_cid.is_empty()) { -6656 return Err(TransportError::PROTOCOL_VIOLATION( -6657 "multipath must not use zero-length CIDs", -6658 )); -6659 } +6148 // Ensure the delay is within bounds to avoid a PROTOCOL_VIOLATION error +6149 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay( +6150 path.rtt.get(), +6151 config, +6152 &self.peer_params, +6153 ); +6154 +6155 let frame = frame::AckFrequency { +6156 sequence: sequence_number, +6157 ack_eliciting_threshold: config.ack_eliciting_threshold, +6158 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX), +6159 reordering_threshold: config.reordering_threshold, +6160 }; +6161 builder.write_frame(frame, stats); +6162 +6163 self.ack_frequency +6164 .ack_frequency_sent(path_id, builder.packet_number, max_ack_delay); +6165 } +6166 +6167 // PATH_CHALLENGE (on-path) +6168 if !scheduling_info.is_abandoned +6169 && space_id == SpaceId::Data +6170 && path.pending_challenge +6171 // we don't want to send new challenges if we are already closing +6172 && !self.state.is_closed() +6173 && builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND +6174 // An on-path PATH_CHALLENGE must be part of datagrams expanded to the +6175 // MIN_INITIAL_SIZE (1200 bytes). +6176 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE) +6177 { +6178 path.pending_challenge = false; +6179 +6180 let token = self.rng.random(); +6181 path.record_path_challenge_sent(now, token, path.network_path); +6182 // Generate a new challenge every time we send a new PATH_CHALLENGE +6183 let challenge = frame::PathChallenge(token); +6184 builder.write_frame(challenge, stats); +6185 builder.require_padding(); +6186 let pto = self.ack_frequency.max_ack_delay_for_pto() + path.rtt.pto_base(); +6187 let pns = space.for_path(path_id); +6188 match pns.open_status { +6189 OpenStatus::Sent | OpenStatus::Informed => {} +6190 OpenStatus::Pending => { +6191 pns.open_status = OpenStatus::Sent; +6192 self.timers.set( +6193 Timer::PerPath(path_id, PathTimer::AbandonFromValidation), +6194 now + 3 * pto, +6195 self.qlog.with_time(now), +6196 ); +6197 } +6198 } +6199 +6200 self.timers.set( +6201 Timer::PerPath(path_id, PathTimer::PathChallengeLost), +6202 now + path.on_path_challenge_expiry(), +6203 self.qlog.with_time(now), +6204 ); +6205 +6206 if is_multipath_negotiated && !path.validated && path.pending_challenge { +6207 // queue informing the path status along with the challenge +6208 space.pending.path_status.insert(path_id); +6209 } +6210 +6211 // Always include an OBSERVED_ADDR frame with a PATH_CHALLENGE, regardless +6212 // of whether one has already been sent on this path. +6213 path.pending.observed_address = self +6214 .config +6215 .address_discovery_role +6216 .should_report(&self.peer_params.address_discovery_role); +6217 } +6218 +6219 // PATH_RESPONSE (on-path) +6220 if !scheduling_info.is_abandoned +6221 && space_id == SpaceId::Data +6222 && builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND +6223 // An on-path PATH_RESPONSE must be part of datagrams expanded to the +6224 // MIN_INITIAL_SIZE (1200 bytes). +6225 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE) +6226 && let Some(token) = space.for_path(path_id).pending_path_responses.pop_on_path(path.network_path) +6227 { +6228 let response = frame::PathResponse(token); +6229 builder.write_frame(response, stats); +6230 builder.require_padding(); +6231 +6232 // NOTE: this is technically not required but might be useful to ride the +6233 // request/response nature of path challenges to refresh an observation +6234 // Since PATH_RESPONSE is a probing frame, this is allowed by the spec. +6235 path.pending.observed_address = self +6236 .config +6237 .address_discovery_role +6238 .should_report(&self.peer_params.address_discovery_role); +6239 } +6240 +6241 // ADD_ADDRESS +6242 while space_id == SpaceId::Data +6243 && !scheduling_info.is_abandoned +6244 && scheduling_info.may_send_data +6245 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining() +6246 { +6247 if let Some(added_address) = space.pending.add_address.pop_last() { +6248 builder.write_frame(added_address, stats); +6249 } else { +6250 break; +6251 } +6252 } +6253 +6254 // REMOVE_ADDRESS +6255 while space_id == SpaceId::Data +6256 && !scheduling_info.is_abandoned +6257 && scheduling_info.may_send_data +6258 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining() +6259 { +6260 if let Some(removed_address) = space.pending.remove_address.pop_last() { +6261 builder.write_frame(removed_address, stats); +6262 } else { +6263 break; +6264 } +6265 } +6266 +6267 // REACH_OUT +6268 while !scheduling_info.is_abandoned +6269 && scheduling_info.may_send_data +6270 && let Some(reach_out) = space +6271 .pending +6272 .reach_out +6273 .pop_if(|frame| builder.frame_space_remaining() >= frame.size()) +6274 { +6275 builder.write_frame(reach_out, stats); +6276 } +6277 +6278 // PATH_ABANDON +6279 if space_id == SpaceId::Data +6280 && scheduling_info.is_abandoned +6281 && scheduling_info.may_self_abandon +6282 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining() +6283 && let Some(error_code) = space.pending.path_abandon.remove(&path_id) +6284 { +6285 let frame = frame::PathAbandon { +6286 path_id, +6287 error_code, +6288 }; +6289 builder.write_frame(frame, stats); +6290 +6291 // Consider remotely issued CIDs as retired now that we have sent this frame at +6292 // least once. +6293 self.remote_cids.remove(&path_id); +6294 } +6295 while space_id == SpaceId::Data +6296 && scheduling_info.may_send_data +6297 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining() +6298 && let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first() +6299 { +6300 let frame = frame::PathAbandon { +6301 path_id: abandoned_path_id, +6302 error_code, +6303 }; +6304 builder.write_frame(frame, stats); +6305 +6306 // Consider remotely issued CIDs as retired now that we have sent this frame at +6307 // least once. +6308 self.remote_cids.remove(&abandoned_path_id); +6309 } +6310 +6311 // OBSERVED_ADDR +6312 if !scheduling_info.is_abandoned +6313 && space_id == SpaceId::Data +6314 && path.pending.observed_address +6315 { +6316 let frame = +6317 frame::ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no); +6318 if builder.frame_space_remaining() > frame.size() { +6319 builder.write_frame(frame, stats); +6320 +6321 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8); +6322 path.pending.observed_address = false; +6323 } +6324 } +6325 +6326 // CRYPTO +6327 while !is_0rtt +6328 && !scheduling_info.is_abandoned +6329 && scheduling_info.may_send_data +6330 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND +6331 { +6332 let Some(mut frame) = space.pending.crypto.pop_front() else { +6333 break; +6334 }; +6335 +6336 // Calculate the maximum amount of crypto data we can store in the buffer. +6337 // Since the offset is known, we can reserve the exact size required to encode it. +6338 // For length we reserve 2bytes which allows to encode up to 2^14, +6339 // which is more than what fits into normally sized QUIC frames. +6340 let max_crypto_data_size = builder.frame_space_remaining() +6341 - 1 // Frame Type +6342 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) }) +6343 - 2; // Maximum encoded length for frame size, given we send less than 2^14 bytes +6344 +6345 let len = frame +6346 .data +6347 .len() +6348 .min(2usize.pow(14) - 1) +6349 .min(max_crypto_data_size); +6350 +6351 let data = frame.data.split_to(len); +6352 let offset = frame.offset; +6353 let truncated = frame::Crypto { offset, data }; +6354 builder.write_frame(truncated, stats); +6355 +6356 if !frame.data.is_empty() { +6357 frame.offset += len as u64; +6358 space.pending.crypto.push_front(frame); +6359 } +6360 } +6361 +6362 // PATH_STATUS_AVAILABLE & PATH_STATUS_BACKUP +6363 while space_id == SpaceId::Data +6364 && !scheduling_info.is_abandoned +6365 && scheduling_info.may_send_data +6366 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining() +6367 { +6368 let Some(path_id) = space.pending.path_status.pop_first() else { +6369 break; +6370 }; +6371 let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else { +6372 trace!(%path_id, "discarding queued path status for unknown path"); +6373 continue; +6374 }; +6375 +6376 let seq = path.status.seq(); +6377 match path.local_status() { +6378 PathStatus::Available => { +6379 let frame = frame::PathStatusAvailable { +6380 path_id, +6381 status_seq_no: seq, +6382 }; +6383 builder.write_frame(frame, stats); +6384 } +6385 PathStatus::Backup => { +6386 let frame = frame::PathStatusBackup { +6387 path_id, +6388 status_seq_no: seq, +6389 }; +6390 builder.write_frame(frame, stats); +6391 } +6392 } +6393 } +6394 +6395 // MAX_PATH_ID +6396 if space_id == SpaceId::Data +6397 && !scheduling_info.is_abandoned +6398 && scheduling_info.may_send_data +6399 && space.pending.max_path_id +6400 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining() +6401 { +6402 let frame = frame::MaxPathId(self.local_max_path_id); +6403 builder.write_frame(frame, stats); +6404 space.pending.max_path_id = false; +6405 } +6406 +6407 // PATHS_BLOCKED +6408 if space_id == SpaceId::Data +6409 && !scheduling_info.is_abandoned +6410 && scheduling_info.may_send_data +6411 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining() +6412 && let Some(remote_max_path_id) = space.pending.paths_blocked.take() +6413 { +6414 let frame = frame::PathsBlocked(remote_max_path_id); +6415 builder.write_frame(frame, stats); +6416 } +6417 +6418 // PATH_CIDS_BLOCKED +6419 while space_id == SpaceId::Data +6420 && !scheduling_info.is_abandoned +6421 && scheduling_info.may_send_data +6422 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining() +6423 { +6424 let Some((path_id, next_seq)) = space.pending.path_cids_blocked.pop_first() else { +6425 break; +6426 }; +6427 let frame = frame::PathCidsBlocked { path_id, next_seq }; +6428 builder.write_frame(frame, stats); +6429 } +6430 +6431 // RESET_STREAM, STOP_SENDING, MAX_DATA, MAX_STREAM_DATA, MAX_STREAMS +6432 if space_id == SpaceId::Data +6433 && !scheduling_info.is_abandoned +6434 && scheduling_info.may_send_data +6435 { +6436 self.streams +6437 .write_control_frames(builder, &mut space.pending, stats); +6438 } +6439 +6440 // NEW_CONNECTION_ID +6441 let cid_len = self +6442 .local_cid_state +6443 .values() +6444 .map(|cid_state| cid_state.cid_len()) +6445 .max() +6446 .expect("some local CID state must exist"); +6447 let new_cid_size_bound = +6448 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len); +6449 while !scheduling_info.is_abandoned +6450 && scheduling_info.may_send_data +6451 && builder.frame_space_remaining() > new_cid_size_bound +6452 { +6453 let Some(issued) = space.pending.new_cids.pop() else { +6454 break; +6455 }; +6456 // Path was discarded after this CID was queued, drop. +6457 let Some(cid_state) = self.local_cid_state.get(&issued.path_id) else { +6458 debug!( +6459 path = %issued.path_id, seq = issued.sequence, +6460 "dropping queued NEW_CONNECTION_ID for discarded path", +6461 ); +6462 continue; +6463 }; +6464 let retire_prior_to = cid_state.retire_prior_to(); +6465 +6466 let cid_path_id = match is_multipath_negotiated { +6467 true => Some(issued.path_id), +6468 false => { +6469 debug_assert_eq!(issued.path_id, PathId::ZERO); +6470 None +6471 } +6472 }; +6473 let frame = frame::NewConnectionId { +6474 path_id: cid_path_id, +6475 sequence: issued.sequence, +6476 retire_prior_to, +6477 id: issued.id, +6478 reset_token: issued.reset_token, +6479 }; +6480 builder.write_frame(frame, stats); +6481 } +6482 +6483 // RETIRE_CONNECTION_ID +6484 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated); +6485 while !scheduling_info.is_abandoned +6486 && scheduling_info.may_send_data +6487 && builder.frame_space_remaining() > retire_cid_bound +6488 { +6489 let (path_id, sequence) = match space.pending.retire_cids.pop() { +6490 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq), +6491 Some((path_id, seq)) => (Some(path_id), seq), +6492 None => break, +6493 }; +6494 let frame = frame::RetireConnectionId { path_id, sequence }; +6495 builder.write_frame(frame, stats); +6496 } +6497 +6498 // DATAGRAM +6499 let mut sent_datagrams = false; +6500 while !scheduling_info.is_abandoned +6501 && scheduling_info.may_send_data +6502 && builder.frame_space_remaining() > Datagram::SIZE_BOUND +6503 && space_id == SpaceId::Data +6504 { +6505 match self.datagrams.write(builder, stats) { +6506 true => { +6507 sent_datagrams = true; +6508 } +6509 false => break, +6510 } +6511 } +6512 if self.datagrams.send_blocked && sent_datagrams { +6513 self.events.push_back(Event::DatagramsUnblocked); +6514 self.datagrams.send_blocked = false; +6515 } +6516 +6517 let path = &mut self.paths.get_mut(&path_id).expect("known path").data; +6518 +6519 // NEW_TOKEN +6520 if !scheduling_info.is_abandoned && scheduling_info.may_send_data { +6521 while let Some(network_path) = space.pending.new_tokens.pop() { +6522 debug_assert_eq!(space_id, SpaceId::Data); +6523 let ConnectionSide::Server { server_config } = &self.side else { +6524 panic!("NEW_TOKEN frames should not be enqueued by clients"); +6525 }; +6526 +6527 if !network_path.is_probably_same_path(&path.network_path) { +6528 // NEW_TOKEN frames contain tokens bound to a client's IP address, and are only +6529 // useful if used from the same IP address. Thus, we abandon enqueued NEW_TOKEN +6530 // frames upon an path change. Instead, when the new path becomes validated, +6531 // NEW_TOKEN frames may be enqueued for the new path instead. +6532 continue; +6533 } +6534 +6535 let token = Token::new( +6536 TokenPayload::Validation { +6537 ip: network_path.remote.ip(), +6538 issued: server_config.time_source.now(), +6539 }, +6540 &mut self.rng, +6541 ); +6542 let new_token = NewToken { +6543 token: token.encode(&*server_config.token_key).into(), +6544 }; +6545 +6546 if builder.frame_space_remaining() < new_token.size() { +6547 space.pending.new_tokens.push(network_path); +6548 break; +6549 } +6550 +6551 builder.write_frame(new_token, stats); +6552 builder.retransmits_mut().new_tokens.push(network_path); +6553 } +6554 } +6555 +6556 // STREAM +6557 if !scheduling_info.is_abandoned +6558 && scheduling_info.may_send_data +6559 && space_id == SpaceId::Data +6560 { +6561 self.streams +6562 .write_stream_frames(builder, self.config.send_fairness, stats); +6563 } +6564 } +6565 +6566 /// Write pending ACKs into a buffer +6567 fn populate_acks<'a, 'b>( +6568 now: Instant, +6569 receiving_ecn: bool, +6570 path_id: PathId, +6571 space_id: SpaceId, +6572 space: &mut PacketSpace, +6573 is_multipath_negotiated: bool, +6574 builder: &mut PacketBuilder<'a, 'b>, +6575 stats: &mut FrameStats, +6576 space_has_keys: bool, +6577 ) { +6578 // 0-RTT packets must never carry acks (which would have to be of handshake packets) +6579 debug_assert!(space_has_keys, "tried to send ACK in 0-RTT"); +6580 +6581 debug_assert!( +6582 is_multipath_negotiated || path_id == PathId::ZERO, +6583 "Only PathId::ZERO allowed without multipath (have {path_id:?})" +6584 ); +6585 if is_multipath_negotiated { +6586 debug_assert!( +6587 space_id == SpaceId::Data || path_id == PathId::ZERO, +6588 "path acks must be sent in 1RTT space (have {space_id:?})" +6589 ); +6590 } +6591 +6592 let pns = space.for_path(path_id); +6593 let ranges = pns.pending_acks.ranges(); +6594 debug_assert!(!ranges.is_empty(), "can not send empty ACK range"); +6595 let ecn = if receiving_ecn { +6596 Some(&pns.ecn_counters) +6597 } else { +6598 None +6599 }; +6600 +6601 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64; +6602 // TODO: This should come from `TransportConfig` if that gets configurable. +6603 let ack_delay_exp = TransportParameters::default().ack_delay_exponent; +6604 let delay = delay_micros >> ack_delay_exp.into_inner(); +6605 +6606 if is_multipath_negotiated && space_id == SpaceId::Data { +6607 if !ranges.is_empty() { +6608 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn); +6609 builder.write_frame(frame, stats); +6610 } +6611 } else { +6612 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats); +6613 } +6614 } +6615 +6616 fn close_common(&mut self) { +6617 trace!("connection closed"); +6618 self.timers.reset(); +6619 } +6620 +6621 fn set_close_timer(&mut self, now: Instant) { +6622 // QUIC-MULTIPATH § 2.6 Connection Closure: draining for 3*PTO using the max PTO of +6623 // all paths. +6624 let pto_max = self.max_pto_for_space(self.highest_space); +6625 self.timers.set( +6626 Timer::Conn(ConnTimer::Close), +6627 now + 3 * pto_max, +6628 self.qlog.with_time(now), +6629 ); +6630 } +6631 +6632 /// Handle transport parameters received from the peer +6633 /// +6634 /// *remote_cid* and *local_cid* are the source and destination CIDs respectively of the +6635 /// *packet into which the transport parameters arrived. +6636 fn handle_peer_params( +6637 &mut self, +6638 params: TransportParameters, +6639 local_cid: ConnectionId, +6640 remote_cid: ConnectionId, +6641 now: Instant, +6642 ) -> Result<(), TransportError> { +6643 if Some(self.original_remote_cid) != params.initial_src_cid +6644 || (self.side.is_client() +6645 && (Some(self.initial_dst_cid) != params.original_dst_cid +6646 || self.retry_src_cid != params.retry_src_cid)) +6647 { +6648 return Err(TransportError::TRANSPORT_PARAMETER_ERROR( +6649 "CID authentication failure", +6650 )); +6651 } +6652 if params.initial_max_path_id.is_some() && (local_cid.is_empty() || remote_cid.is_empty()) { +6653 return Err(TransportError::PROTOCOL_VIOLATION( +6654 "multipath must not use zero-length CIDs", +6655 )); +6656 } +6657 +6658 self.set_peer_params(params); +6659 self.qlog.emit_peer_transport_params_received(self, now); 6660 -6661 self.set_peer_params(params); -6662 self.qlog.emit_peer_transport_params_received(self, now); +6661 Ok(()) +6662 } 6663 -6664 Ok(()) -6665 } -6666 -6667 fn set_peer_params(&mut self, params: TransportParameters) { -6668 self.streams.set_params(&params); -6669 self.idle_timeout = -6670 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout)); -6671 trace!("negotiated max idle timeout {:?}", self.idle_timeout); -6672 -6673 if let Some(ref info) = params.preferred_address { -6674 // During the handshake PathId::ZERO exists. -6675 self.remote_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId { -6676 path_id: None, -6677 sequence: 1, -6678 id: info.connection_id, -6679 reset_token: info.stateless_reset_token, -6680 retire_prior_to: 0, -6681 }) -6682 .expect( -6683 "preferred address CID is the first received, and hence is guaranteed to be legal", -6684 ); -6685 let remote = self.path_data(PathId::ZERO).network_path.remote; -6686 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token); -6687 } -6688 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(&params); -6689 -6690 let mut multipath_enabled = false; -6691 if let (Some(local_max_path_id), Some(remote_max_path_id)) = ( -6692 self.config.get_initial_max_path_id(), -6693 params.initial_max_path_id, -6694 ) { -6695 // multipath is enabled, register the local and remote maximums -6696 self.local_max_path_id = local_max_path_id; -6697 self.remote_max_path_id = remote_max_path_id; -6698 let initial_max_path_id = local_max_path_id.min(remote_max_path_id); -6699 debug!(%initial_max_path_id, "multipath negotiated"); -6700 multipath_enabled = true; -6701 } -6702 -6703 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) = -6704 self.config -6705 .max_remote_nat_traversal_addresses -6706 .zip(params.max_remote_nat_traversal_addresses) -6707 { -6708 if multipath_enabled { -6709 let max_local_addresses = max_remotely_allowed_remote_addresses.get(); -6710 let max_remote_addresses = max_locally_allowed_remote_addresses.get(); -6711 self.n0_nat_traversal = n0_nat_traversal::State::new( -6712 max_remote_addresses, -6713 max_local_addresses, -6714 self.side(), -6715 ); -6716 debug!( -6717 %max_remote_addresses, %max_local_addresses, -6718 "n0's nat traversal negotiated" -6719 ); -6720 } else { -6721 debug!("n0 nat traversal enabled for both endpoints, but multipath is missing") -6722 } -6723 } -6724 -6725 self.peer_params = params; -6726 let peer_max_udp_payload_size = -6727 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX); -6728 let address_discovery_negotiated = self -6729 .config -6730 .address_discovery_role -6731 .should_report(&self.peer_params.address_discovery_role); -6732 -6733 let path = self.path_data_mut(PathId::ZERO); -6734 path.pending.observed_address = address_discovery_negotiated; -6735 path.mtud -6736 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size); -6737 } -6738 -6739 /// Decrypts a packet, returning the packet number on success -6740 fn decrypt_packet( -6741 &mut self, -6742 now: Instant, -6743 path_id: PathId, -6744 packet: &mut Packet, -6745 ) -> Result<Option<u64>, Option<TransportError>> { -6746 let result = self -6747 .crypto_state -6748 .decrypt_packet_body(packet, path_id, &self.spaces)?; -6749 -6750 let Some(result) = result else { -6751 return Ok(None); -6752 }; -6753 -6754 if result.outgoing_key_update_acked -6755 && let Some(prev) = self.crypto_state.prev_crypto.as_mut() -6756 { -6757 prev.end_packet = Some((result.packet_number, now)); -6758 self.set_key_discard_timer(now, packet.header.space()); -6759 } -6760 -6761 if result.incoming_key_update { -6762 trace!("key update authenticated"); -6763 self.crypto_state -6764 .update_keys(Some((result.packet_number, now)), true); -6765 self.set_key_discard_timer(now, packet.header.space()); -6766 } +6664 fn set_peer_params(&mut self, params: TransportParameters) { +6665 self.streams.set_params(&params); +6666 self.idle_timeout = +6667 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout)); +6668 trace!("negotiated max idle timeout {:?}", self.idle_timeout); +6669 +6670 if let Some(ref info) = params.preferred_address { +6671 // During the handshake PathId::ZERO exists. +6672 self.remote_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId { +6673 path_id: None, +6674 sequence: 1, +6675 id: info.connection_id, +6676 reset_token: info.stateless_reset_token, +6677 retire_prior_to: 0, +6678 }) +6679 .expect( +6680 "preferred address CID is the first received, and hence is guaranteed to be legal", +6681 ); +6682 let remote = self.path_data(PathId::ZERO).network_path.remote; +6683 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token); +6684 } +6685 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(&params); +6686 +6687 let mut multipath_enabled = false; +6688 if let (Some(local_max_path_id), Some(remote_max_path_id)) = ( +6689 self.config.get_initial_max_path_id(), +6690 params.initial_max_path_id, +6691 ) { +6692 // multipath is enabled, register the local and remote maximums +6693 self.local_max_path_id = local_max_path_id; +6694 self.remote_max_path_id = remote_max_path_id; +6695 let initial_max_path_id = local_max_path_id.min(remote_max_path_id); +6696 debug!(%initial_max_path_id, "multipath negotiated"); +6697 multipath_enabled = true; +6698 } +6699 +6700 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) = +6701 self.config +6702 .max_remote_nat_traversal_addresses +6703 .zip(params.max_remote_nat_traversal_addresses) +6704 { +6705 if multipath_enabled { +6706 let max_local_addresses = max_remotely_allowed_remote_addresses.get(); +6707 let max_remote_addresses = max_locally_allowed_remote_addresses.get(); +6708 self.n0_nat_traversal = n0_nat_traversal::State::new( +6709 max_remote_addresses, +6710 max_local_addresses, +6711 self.side(), +6712 ); +6713 debug!( +6714 %max_remote_addresses, %max_local_addresses, +6715 "n0's nat traversal negotiated" +6716 ); +6717 } else { +6718 debug!("n0 nat traversal enabled for both endpoints, but multipath is missing") +6719 } +6720 } +6721 +6722 self.peer_params = params; +6723 let peer_max_udp_payload_size = +6724 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX); +6725 let address_discovery_negotiated = self +6726 .config +6727 .address_discovery_role +6728 .should_report(&self.peer_params.address_discovery_role); +6729 +6730 let path = self.path_data_mut(PathId::ZERO); +6731 path.pending.observed_address = address_discovery_negotiated; +6732 path.mtud +6733 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size); +6734 } +6735 +6736 /// Decrypts a packet, returning the packet number on success +6737 fn decrypt_packet( +6738 &mut self, +6739 now: Instant, +6740 path_id: PathId, +6741 packet: &mut Packet, +6742 ) -> Result<Option<u64>, Option<TransportError>> { +6743 let result = self +6744 .crypto_state +6745 .decrypt_packet_body(packet, path_id, &self.spaces)?; +6746 +6747 let Some(result) = result else { +6748 return Ok(None); +6749 }; +6750 +6751 if result.outgoing_key_update_acked +6752 && let Some(prev) = self.crypto_state.prev_crypto.as_mut() +6753 { +6754 prev.end_packet = Some((result.packet_number, now)); +6755 self.set_key_discard_timer(now, packet.header.space()); +6756 } +6757 +6758 if result.incoming_key_update { +6759 trace!("key update authenticated"); +6760 self.crypto_state +6761 .update_keys(Some((result.packet_number, now)), true); +6762 self.set_key_discard_timer(now, packet.header.space()); +6763 } +6764 +6765 Ok(Some(result.packet_number)) +6766 } 6767 -6768 Ok(Some(result.packet_number)) -6769 } -6770 -6771 fn peer_supports_ack_frequency(&self) -> bool { -6772 self.peer_params.min_ack_delay.is_some() -6773 } -6774 -6775 /// Send an IMMEDIATE_ACK frame to the remote endpoint -6776 /// -6777 /// According to the spec, this will result in an error if the remote endpoint does not support -6778 /// the Acknowledgement Frequency extension -6779 pub(crate) fn immediate_ack(&mut self, path_id: PathId) { -6780 debug_assert_eq!( -6781 self.highest_space, -6782 SpaceKind::Data, -6783 "immediate ack must be written in the data space" -6784 ); -6785 self.spaces[SpaceId::Data] -6786 .for_path(path_id) -6787 .pending_immediate_ack = true; -6788 } -6789 -6790 /// Decodes a packet, returning its decrypted payload, so it can be inspected in tests -6791 #[cfg(test)] -6792 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> { -6793 let ConnectionEventInner::Datagram(DatagramConnectionEvent { -6794 path_id, -6795 first_decode, -6796 remaining, -6797 .. -6798 }) = &event.0 -6799 else { -6800 return None; -6801 }; -6802 -6803 if remaining.is_some() { -6804 panic!("Packets should never be coalesced in tests"); -6805 } -6806 -6807 let decrypted_header = self -6808 .crypto_state -6809 .unprotect_header(first_decode.clone(), self.peer_params.stateless_reset_token)?; -6810 -6811 let mut packet = decrypted_header.packet?; -6812 self.crypto_state -6813 .decrypt_packet_body(&mut packet, *path_id, &self.spaces) -6814 .ok()?; +6768 fn peer_supports_ack_frequency(&self) -> bool { +6769 self.peer_params.min_ack_delay.is_some() +6770 } +6771 +6772 /// Send an IMMEDIATE_ACK frame to the remote endpoint +6773 /// +6774 /// According to the spec, this will result in an error if the remote endpoint does not support +6775 /// the Acknowledgement Frequency extension +6776 pub(crate) fn immediate_ack(&mut self, path_id: PathId) { +6777 debug_assert_eq!( +6778 self.highest_space, +6779 SpaceKind::Data, +6780 "immediate ack must be written in the data space" +6781 ); +6782 self.spaces[SpaceId::Data] +6783 .for_path(path_id) +6784 .pending_immediate_ack = true; +6785 } +6786 +6787 /// Decodes a packet, returning its decrypted payload, so it can be inspected in tests +6788 #[cfg(test)] +6789 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> { +6790 let ConnectionEventInner::Datagram(DatagramConnectionEvent { +6791 path_id, +6792 first_decode, +6793 remaining, +6794 .. +6795 }) = &event.0 +6796 else { +6797 return None; +6798 }; +6799 +6800 if remaining.is_some() { +6801 panic!("Packets should never be coalesced in tests"); +6802 } +6803 +6804 let decrypted_header = self +6805 .crypto_state +6806 .unprotect_header(first_decode.clone(), self.peer_params.stateless_reset_token)?; +6807 +6808 let mut packet = decrypted_header.packet?; +6809 self.crypto_state +6810 .decrypt_packet_body(&mut packet, *path_id, &self.spaces) +6811 .ok()?; +6812 +6813 Some(packet.payload.to_vec()) +6814 } 6815 -6816 Some(packet.payload.to_vec()) -6817 } -6818 -6819 /// The number of bytes of packets containing retransmittable frames that have not been -6820 /// acknowledged or declared lost. -6821 #[cfg(test)] -6822 pub(crate) fn bytes_in_flight(&self) -> u64 { -6823 // TODO(@divma): consider including for multipath? -6824 self.path_data(PathId::ZERO).in_flight.bytes -6825 } -6826 -6827 /// Number of bytes worth of non-ack-only packets that may be sent -6828 #[cfg(test)] -6829 pub(crate) fn congestion_window(&self) -> u64 { -6830 let path = self.path_data(PathId::ZERO); -6831 path.congestion -6832 .window() -6833 .saturating_sub(path.in_flight.bytes) -6834 } -6835 -6836 /// Whether no timers but keepalive, idle, rtt, pushnewcid, and key discard are running -6837 #[cfg(test)] -6838 pub(crate) fn is_idle(&self) -> bool { -6839 let current_timers = self.timers.values(); -6840 current_timers -6841 .into_iter() -6842 .filter(|(timer, _)| { -6843 !matches!( -6844 timer, -6845 Timer::Conn(ConnTimer::KeepAlive) -6846 | Timer::PerPath(_, PathTimer::PathKeepAlive) -6847 | Timer::Conn(ConnTimer::PushNewCid) -6848 | Timer::Conn(ConnTimer::KeyDiscard) -6849 ) -6850 }) -6851 .min_by_key(|(_, time)| *time) -6852 .is_none_or(|(timer, _)| { -6853 matches!( -6854 timer, -6855 Timer::Conn(ConnTimer::Idle) | Timer::PerPath(_, PathTimer::PathIdle) -6856 ) -6857 }) -6858 } -6859 -6860 /// Whether explicit congestion notification is in use on outgoing packets. -6861 #[cfg(test)] -6862 pub(crate) fn using_ecn(&self) -> bool { -6863 self.path_data(PathId::ZERO).sending_ecn -6864 } -6865 -6866 /// The number of received bytes in the current path -6867 #[cfg(test)] -6868 pub(crate) fn total_recvd(&self) -> u64 { -6869 self.path_data(PathId::ZERO).total_recvd -6870 } -6871 -6872 #[cfg(test)] -6873 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) { -6874 self.local_cid_state -6875 .get(&PathId::ZERO) -6876 .unwrap() -6877 .active_seq() -6878 } -6879 -6880 #[cfg(test)] -6881 #[track_caller] -6882 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) { -6883 self.local_cid_state -6884 .get(&PathId(path_id)) -6885 .unwrap() -6886 .active_seq() -6887 } -6888 -6889 /// Instruct the peer to replace previously issued CIDs by sending a NEW_CONNECTION_ID frame -6890 /// with updated `retire_prior_to` field set to `v` -6891 #[cfg(test)] -6892 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) { -6893 let n = self -6894 .local_cid_state -6895 .get_mut(&PathId::ZERO) -6896 .unwrap() -6897 .assign_retire_seq(v); -6898 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events -6899 self.endpoint_events -6900 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n)); -6901 } -6902 -6903 /// Check the current active remote CID sequence for `PathId::ZERO` -6904 #[cfg(test)] -6905 pub(crate) fn active_remote_cid_seq(&self) -> u64 { -6906 self.remote_cids.get(&PathId::ZERO).unwrap().active_seq() -6907 } -6908 -6909 /// Returns the detected maximum udp payload size for the current path -6910 #[cfg(test)] -6911 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 { -6912 self.path_data(path_id).current_mtu() -6913 } -6914 -6915 /// Triggers path validation on all paths -6916 #[cfg(test)] -6917 pub(crate) fn trigger_path_validation(&mut self) { -6918 for path in self.paths.values_mut() { -6919 path.data.pending_challenge = true; -6920 } -6921 } -6922 -6923 /// Simulates a protocol violation error for test purposes. -6924 #[cfg(test)] -6925 pub fn simulate_protocol_violation(&mut self, now: Instant) { -6926 if !self.state.is_closed() { -6927 self.state -6928 .move_to_closed(TransportError::PROTOCOL_VIOLATION("simulated violation")); -6929 self.close_common(); -6930 if !self.state.is_drained() { -6931 self.set_close_timer(now); -6932 } -6933 self.connection_close_pending = true; -6934 } -6935 } -6936 -6937 /// Whether we have **on-path** 1-RTT data to send. -6938 /// -6939 /// This checks for frames that can only be sent in the data space (1-RTT): -6940 /// - Pending PATH_CHALLENGE frames on the active and previous path if just migrated. -6941 /// - Pending PATH_RESPONSE frames. -6942 /// - Pending data to send in STREAM frames. -6943 /// - Pending DATAGRAM frames to send. -6944 /// -6945 /// See also [`PacketSpace::can_send`] which keeps track of all other frame types that -6946 /// may need to be sent. -6947 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames { -6948 let network_path = self.path_data(path_id).network_path; -6949 let space_specific = self -6950 .paths -6951 .get(&path_id) -6952 .is_some_and(|path| path.data.pending_challenge || !path.data.pending.is_empty()) -6953 || self.spaces[SpaceKind::Data] -6954 .number_spaces -6955 .get(&path_id) -6956 .is_some_and(|pns| pns.pending_path_responses.has_pending_on_path(network_path)); -6957 -6958 // Stream control frames are checked in PacketSpace::can_send, only check data here. -6959 let other = self.streams.can_send_stream_data() -6960 || self -6961 .datagrams -6962 .outgoing -6963 .front() -6964 .is_some_and(|x| x.size(true) <= max_size); -6965 -6966 // All `false` fields are set in PacketSpace::can_send. -6967 SendableFrames { -6968 acks: false, -6969 close: false, -6970 space_specific, -6971 other, -6972 } -6973 } -6974 -6975 /// Terminate the connection instantly, without sending a close packet -6976 fn kill(&mut self, reason: ConnectionError) { -6977 self.close_common(); -6978 let was_draining = self.state.move_to_drained(Some(reason)); -6979 if !was_draining { -6980 self.endpoint_events.push_back(EndpointEventInner::Draining); -6981 } -6982 // move_to_drained checks that we were never in drained before, so we -6983 // never sent a `Drained` event before (it's illegal to send more events after drained). -6984 self.endpoint_events.push_back(EndpointEventInner::Drained); -6985 } -6986 -6987 /// Storage size required for the largest packet that can be transmitted on all currently -6988 /// available paths -6989 /// -6990 /// Buffers passed to [`Connection::poll_transmit`] should be at least this large. -6991 /// -6992 /// When multipath is enabled, this value is the minimum MTU across all available paths. -6993 pub fn current_mtu(&self) -> u16 { -6994 self.paths -6995 .iter() -6996 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id)) -6997 .map(|(_path_id, path_state)| path_state.data.current_mtu()) -6998 .min() -6999 .unwrap_or(INITIAL_MTU) -7000 } -7001 -7002 /// Size of non-frame data for a 1-RTT packet -7003 /// -7004 /// Quantifies space consumed by the QUIC header and AEAD tag. All other bytes in a packet are -7005 /// frames. Changes if the length of the remote connection ID changes, which is expected to be -7006 /// rare. If `pn` is specified, may additionally change unpredictably due to variations in -7007 /// latency and packet loss. -7008 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize { -7009 let pn_len = PacketNumber::new( -7010 pn, -7011 self.spaces[SpaceId::Data] -7012 .for_path(path) -7013 .largest_acked_packet_pn -7014 .unwrap_or(0), -7015 ) -7016 .len(); -7017 -7018 // 1 byte for flags -7019 1 + self -7020 .remote_cids -7021 .get(&path) -7022 .map(|cids| cids.active().len()) -7023 .unwrap_or(20) // Max CID len in QUIC v1 -7024 + pn_len -7025 + self.tag_len_1rtt() -7026 } +6816 /// The number of bytes of packets containing retransmittable frames that have not been +6817 /// acknowledged or declared lost. +6818 #[cfg(test)] +6819 pub(crate) fn bytes_in_flight(&self) -> u64 { +6820 // TODO(@divma): consider including for multipath? +6821 self.path_data(PathId::ZERO).in_flight.bytes +6822 } +6823 +6824 /// Number of bytes worth of non-ack-only packets that may be sent +6825 #[cfg(test)] +6826 pub(crate) fn congestion_window(&self) -> u64 { +6827 let path = self.path_data(PathId::ZERO); +6828 path.congestion +6829 .window() +6830 .saturating_sub(path.in_flight.bytes) +6831 } +6832 +6833 /// Whether no timers but keepalive, idle, rtt, pushnewcid, and key discard are running +6834 #[cfg(test)] +6835 pub(crate) fn is_idle(&self) -> bool { +6836 let current_timers = self.timers.values(); +6837 current_timers +6838 .into_iter() +6839 .filter(|(timer, _)| { +6840 !matches!( +6841 timer, +6842 Timer::Conn(ConnTimer::KeepAlive) +6843 | Timer::PerPath(_, PathTimer::PathKeepAlive) +6844 | Timer::Conn(ConnTimer::PushNewCid) +6845 | Timer::Conn(ConnTimer::KeyDiscard) +6846 ) +6847 }) +6848 .min_by_key(|(_, time)| *time) +6849 .is_none_or(|(timer, _)| { +6850 matches!( +6851 timer, +6852 Timer::Conn(ConnTimer::Idle) | Timer::PerPath(_, PathTimer::PathIdle) +6853 ) +6854 }) +6855 } +6856 +6857 /// Whether explicit congestion notification is in use on outgoing packets. +6858 #[cfg(test)] +6859 pub(crate) fn using_ecn(&self) -> bool { +6860 self.path_data(PathId::ZERO).sending_ecn +6861 } +6862 +6863 /// The number of received bytes in the current path +6864 #[cfg(test)] +6865 pub(crate) fn total_recvd(&self) -> u64 { +6866 self.path_data(PathId::ZERO).total_recvd +6867 } +6868 +6869 #[cfg(test)] +6870 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) { +6871 self.local_cid_state +6872 .get(&PathId::ZERO) +6873 .unwrap() +6874 .active_seq() +6875 } +6876 +6877 #[cfg(test)] +6878 #[track_caller] +6879 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) { +6880 self.local_cid_state +6881 .get(&PathId(path_id)) +6882 .unwrap() +6883 .active_seq() +6884 } +6885 +6886 /// Instruct the peer to replace previously issued CIDs by sending a NEW_CONNECTION_ID frame +6887 /// with updated `retire_prior_to` field set to `v` +6888 #[cfg(test)] +6889 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) { +6890 let n = self +6891 .local_cid_state +6892 .get_mut(&PathId::ZERO) +6893 .unwrap() +6894 .assign_retire_seq(v); +6895 debug_assert!(!self.state.is_drained()); // requirement for endpoint_events +6896 self.endpoint_events +6897 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n)); +6898 } +6899 +6900 /// Check the current active remote CID sequence for `PathId::ZERO` +6901 #[cfg(test)] +6902 pub(crate) fn active_remote_cid_seq(&self) -> u64 { +6903 self.remote_cids.get(&PathId::ZERO).unwrap().active_seq() +6904 } +6905 +6906 /// Returns the detected maximum udp payload size for the current path +6907 #[cfg(test)] +6908 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 { +6909 self.path_data(path_id).current_mtu() +6910 } +6911 +6912 /// Triggers path validation on all paths +6913 #[cfg(test)] +6914 pub(crate) fn trigger_path_validation(&mut self) { +6915 for path in self.paths.values_mut() { +6916 path.data.pending_challenge = true; +6917 } +6918 } +6919 +6920 /// Simulates a protocol violation error for test purposes. +6921 #[cfg(test)] +6922 pub fn simulate_protocol_violation(&mut self, now: Instant) { +6923 if !self.state.is_closed() { +6924 self.state +6925 .move_to_closed(TransportError::PROTOCOL_VIOLATION("simulated violation")); +6926 self.close_common(); +6927 if !self.state.is_drained() { +6928 self.set_close_timer(now); +6929 } +6930 self.connection_close_pending = true; +6931 } +6932 } +6933 +6934 /// Whether we have **on-path** 1-RTT data to send. +6935 /// +6936 /// This checks for frames that can only be sent in the data space (1-RTT): +6937 /// - Pending PATH_CHALLENGE frames on the active and previous path if just migrated. +6938 /// - Pending PATH_RESPONSE frames. +6939 /// - Pending data to send in STREAM frames. +6940 /// - Pending DATAGRAM frames to send. +6941 /// +6942 /// See also [`PacketSpace::can_send`] which keeps track of all other frame types that +6943 /// may need to be sent. +6944 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames { +6945 let network_path = self.path_data(path_id).network_path; +6946 let space_specific = self +6947 .paths +6948 .get(&path_id) +6949 .is_some_and(|path| path.data.pending_challenge || !path.data.pending.is_empty()) +6950 || self.spaces[SpaceKind::Data] +6951 .number_spaces +6952 .get(&path_id) +6953 .is_some_and(|pns| pns.pending_path_responses.has_pending_on_path(network_path)); +6954 +6955 // Stream control frames are checked in PacketSpace::can_send, only check data here. +6956 let other = self.streams.can_send_stream_data() +6957 || self +6958 .datagrams +6959 .outgoing +6960 .front() +6961 .is_some_and(|x| x.size(true) <= max_size); +6962 +6963 // All `false` fields are set in PacketSpace::can_send. +6964 SendableFrames { +6965 acks: false, +6966 close: false, +6967 space_specific, +6968 other, +6969 } +6970 } +6971 +6972 /// Terminate the connection instantly, without sending a close packet +6973 fn kill(&mut self, reason: ConnectionError) { +6974 self.close_common(); +6975 let was_draining = self.state.move_to_drained(Some(reason)); +6976 if !was_draining { +6977 self.endpoint_events.push_back(EndpointEventInner::Draining); +6978 } +6979 // move_to_drained checks that we were never in drained before, so we +6980 // never sent a `Drained` event before (it's illegal to send more events after drained). +6981 self.endpoint_events.push_back(EndpointEventInner::Drained); +6982 } +6983 +6984 /// Storage size required for the largest packet that can be transmitted on all currently +6985 /// available paths +6986 /// +6987 /// Buffers passed to [`Connection::poll_transmit`] should be at least this large. +6988 /// +6989 /// When multipath is enabled, this value is the minimum MTU across all available paths. +6990 pub fn current_mtu(&self) -> u16 { +6991 self.paths +6992 .iter() +6993 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id)) +6994 .map(|(_path_id, path_state)| path_state.data.current_mtu()) +6995 .min() +6996 .unwrap_or(INITIAL_MTU) +6997 } +6998 +6999 /// Size of non-frame data for a 1-RTT packet +7000 /// +7001 /// Quantifies space consumed by the QUIC header and AEAD tag. All other bytes in a packet are +7002 /// frames. Changes if the length of the remote connection ID changes, which is expected to be +7003 /// rare. If `pn` is specified, may additionally change unpredictably due to variations in +7004 /// latency and packet loss. +7005 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize { +7006 let pn_len = PacketNumber::new( +7007 pn, +7008 self.spaces[SpaceId::Data] +7009 .for_path(path) +7010 .largest_acked_packet_pn +7011 .unwrap_or(0), +7012 ) +7013 .len(); +7014 +7015 // 1 byte for flags +7016 1 + self +7017 .remote_cids +7018 .get(&path) +7019 .map(|cids| cids.active().len()) +7020 .unwrap_or(20) // Max CID len in QUIC v1 +7021 + pn_len +7022 + self.tag_len_1rtt() +7023 } +7024 +7025 fn predict_1rtt_overhead_no_pn(&self) -> usize { +7026 let pn_len = 4; 7027 -7028 fn predict_1rtt_overhead_no_pn(&self) -> usize { -7029 let pn_len = 4; -7030 -7031 let cid_len = self -7032 .remote_cids -7033 .values() -7034 .map(|cids| cids.active().len()) -7035 .max() -7036 .unwrap_or(20); // Max CID len in QUIC v1 -7037 -7038 // 1 byte for flags -7039 1 + cid_len + pn_len + self.tag_len_1rtt() -7040 } -7041 -7042 fn tag_len_1rtt(&self) -> usize { -7043 // encryption_keys for Data space returns 1-RTT keys if available, otherwise 0-RTT keys -7044 let packet_crypto = self -7045 .crypto_state -7046 .encryption_keys(SpaceKind::Data, self.side.side()) -7047 .map(|(_header, packet, _level)| packet); -7048 // If neither Data nor 0-RTT keys are available, make a reasonable tag length guess. As of -7049 // this writing, all QUIC cipher suites use 16-byte tags. We could return `None` instead, -7050 // but that would needlessly prevent sending datagrams during 0-RTT. -7051 packet_crypto.map_or(16, |x| x.tag_len()) -7052 } -7053 -7054 /// Mark the path as validated, and enqueue NEW_TOKEN frames to be sent as appropriate -7055 fn on_path_validated(&mut self, path_id: PathId) { -7056 self.path_data_mut(path_id).validated = true; -7057 let ConnectionSide::Server { server_config } = &self.side else { -7058 return; -7059 }; -7060 let network_path = self.path_data(path_id).network_path; -7061 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens; -7062 new_tokens.clear(); -7063 for _ in 0..server_config.validation_token.sent { -7064 new_tokens.push(network_path); -7065 } -7066 } -7067 -7068 /// Handle new path status information: PATH_STATUS_AVAILABLE, PATH_STATUS_BACKUP -7069 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) { -7070 if let Some(path) = self.paths.get_mut(&path_id) { -7071 path.data.status.remote_update(status, status_seq_no); -7072 } else { -7073 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id); -7074 } -7075 self.events.push_back( -7076 PathEvent::RemoteStatus { -7077 id: path_id, -7078 status, -7079 } -7080 .into(), -7081 ); -7082 } -7083 -7084 /// Returns the maximum [`PathId`] to be used for sending in this connection. +7028 let cid_len = self +7029 .remote_cids +7030 .values() +7031 .map(|cids| cids.active().len()) +7032 .max() +7033 .unwrap_or(20); // Max CID len in QUIC v1 +7034 +7035 // 1 byte for flags +7036 1 + cid_len + pn_len + self.tag_len_1rtt() +7037 } +7038 +7039 fn tag_len_1rtt(&self) -> usize { +7040 // encryption_keys for Data space returns 1-RTT keys if available, otherwise 0-RTT keys +7041 let packet_crypto = self +7042 .crypto_state +7043 .encryption_keys(SpaceKind::Data, self.side.side()) +7044 .map(|(_header, packet, _level)| packet); +7045 // If neither Data nor 0-RTT keys are available, make a reasonable tag length guess. As of +7046 // this writing, all QUIC cipher suites use 16-byte tags. We could return `None` instead, +7047 // but that would needlessly prevent sending datagrams during 0-RTT. +7048 packet_crypto.map_or(16, |x| x.tag_len()) +7049 } +7050 +7051 /// Mark the path as validated, and enqueue NEW_TOKEN frames to be sent as appropriate +7052 fn on_path_validated(&mut self, path_id: PathId) { +7053 self.path_data_mut(path_id).validated = true; +7054 let ConnectionSide::Server { server_config } = &self.side else { +7055 return; +7056 }; +7057 let network_path = self.path_data(path_id).network_path; +7058 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens; +7059 new_tokens.clear(); +7060 for _ in 0..server_config.validation_token.sent { +7061 new_tokens.push(network_path); +7062 } +7063 } +7064 +7065 /// Handle new path status information: PATH_STATUS_AVAILABLE, PATH_STATUS_BACKUP +7066 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) { +7067 if let Some(path) = self.paths.get_mut(&path_id) { +7068 path.data.status.remote_update(status, status_seq_no); +7069 } else { +7070 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id); +7071 } +7072 self.events.push_back( +7073 PathEvent::RemoteStatus { +7074 id: path_id, +7075 status, +7076 } +7077 .into(), +7078 ); +7079 } +7080 +7081 /// Returns the maximum [`PathId`] to be used for sending in this connection. +7082 /// +7083 /// This is calculated as minimum between the local and remote's maximums when multipath is +7084 /// enabled, or `None` when disabled. 7085 /// -7086 /// This is calculated as minimum between the local and remote's maximums when multipath is -7087 /// enabled, or `None` when disabled. -7088 /// -7089 /// For data that's received, we should use [`Self::local_max_path_id`] instead. -7090 /// The reasoning is that the remote might already have updated to its own newer -7091 /// [`Self::max_path_id`] after sending out a `MAX_PATH_ID` frame, but it got re-ordered. -7092 fn max_path_id(&self) -> Option<PathId> { -7093 if self.is_multipath_negotiated() { -7094 Some(self.remote_max_path_id.min(self.local_max_path_id)) -7095 } else { -7096 None -7097 } -7098 } -7099 -7100 /// Returns whether this connection has a socket that supports IPv6. -7101 /// -7102 /// TODO(matheus23): This is related to noq endpoint state's `ipv6` bool. We should move that info -7103 /// here instead of trying to hack around not knowing it exactly. -7104 pub(crate) fn is_ipv6(&self) -> bool { -7105 self.paths -7106 .values() -7107 .any(|p| p.data.network_path.remote.is_ipv6()) -7108 } -7109 -7110 /// Add addresses the local endpoint considers are reachable for nat traversal. -7111 pub fn add_nat_traversal_address( -7112 &mut self, -7113 address: SocketAddr, -7114 ) -> Result<(), n0_nat_traversal::Error> { -7115 if let Some(added) = self.n0_nat_traversal.add_local_address(address)? { -7116 self.spaces[SpaceId::Data].pending.add_address.insert(added); -7117 }; -7118 Ok(()) -7119 } -7120 -7121 /// Removes an address the endpoing no longer considers reachable for nat traversal -7122 /// -7123 /// Addresses not present in the set will be silently ignored. -7124 pub fn remove_nat_traversal_address( -7125 &mut self, -7126 address: SocketAddr, -7127 ) -> Result<(), n0_nat_traversal::Error> { -7128 if let Some(removed) = self.n0_nat_traversal.remove_local_address(address)? { -7129 self.spaces[SpaceId::Data] -7130 .pending -7131 .remove_address -7132 .insert(removed); -7133 } -7134 Ok(()) -7135 } -7136 -7137 /// Get the current local nat traversal addresses -7138 pub fn get_local_nat_traversal_addresses( -7139 &self, -7140 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { -7141 self.n0_nat_traversal.get_local_nat_traversal_addresses() -7142 } -7143 -7144 /// Get the currently advertised nat traversal addresses by the server -7145 pub fn get_remote_nat_traversal_addresses( -7146 &self, -7147 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { -7148 Ok(self -7149 .n0_nat_traversal -7150 .client_side()? -7151 .get_remote_nat_traversal_addresses()) -7152 } -7153 -7154 /// Initiates a new nat traversal round -7155 /// -7156 /// A nat traversal round involves advertising the client's local addresses in -7157 /// `REACH_OUT` frames, and initiating probing of the known remote addresses. When a new -7158 /// round is initiated, the previous one is cancelled. +7086 /// For data that's received, we should use [`Self::local_max_path_id`] instead. +7087 /// The reasoning is that the remote might already have updated to its own newer +7088 /// [`Self::max_path_id`] after sending out a `MAX_PATH_ID` frame, but it got re-ordered. +7089 fn max_path_id(&self) -> Option<PathId> { +7090 if self.is_multipath_negotiated() { +7091 Some(self.remote_max_path_id.min(self.local_max_path_id)) +7092 } else { +7093 None +7094 } +7095 } +7096 +7097 /// Returns whether this connection has a socket that supports IPv6. +7098 /// +7099 /// TODO(matheus23): This is related to noq endpoint state's `ipv6` bool. We should move that info +7100 /// here instead of trying to hack around not knowing it exactly. +7101 pub(crate) fn is_ipv6(&self) -> bool { +7102 self.paths +7103 .values() +7104 .any(|p| p.data.network_path.remote.is_ipv6()) +7105 } +7106 +7107 /// Add addresses the local endpoint considers are reachable for nat traversal. +7108 pub fn add_nat_traversal_address( +7109 &mut self, +7110 address: SocketAddr, +7111 ) -> Result<(), n0_nat_traversal::Error> { +7112 if let Some(added) = self.n0_nat_traversal.add_local_address(address)? { +7113 self.spaces[SpaceId::Data].pending.add_address.insert(added); +7114 }; +7115 Ok(()) +7116 } +7117 +7118 /// Removes an address the endpoing no longer considers reachable for nat traversal +7119 /// +7120 /// Addresses not present in the set will be silently ignored. +7121 pub fn remove_nat_traversal_address( +7122 &mut self, +7123 address: SocketAddr, +7124 ) -> Result<(), n0_nat_traversal::Error> { +7125 if let Some(removed) = self.n0_nat_traversal.remove_local_address(address)? { +7126 self.spaces[SpaceId::Data] +7127 .pending +7128 .remove_address +7129 .insert(removed); +7130 } +7131 Ok(()) +7132 } +7133 +7134 /// Get the current local nat traversal addresses +7135 pub fn get_local_nat_traversal_addresses( +7136 &self, +7137 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { +7138 self.n0_nat_traversal.get_local_nat_traversal_addresses() +7139 } +7140 +7141 /// Get the currently advertised nat traversal addresses by the server +7142 pub fn get_remote_nat_traversal_addresses( +7143 &self, +7144 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { +7145 Ok(self +7146 .n0_nat_traversal +7147 .client_side()? +7148 .get_remote_nat_traversal_addresses()) +7149 } +7150 +7151 /// Initiates a new nat traversal round +7152 /// +7153 /// A nat traversal round involves advertising the client's local addresses in +7154 /// `REACH_OUT` frames, and initiating probing of the known remote addresses. When a new +7155 /// round is initiated, the previous one is cancelled. +7156 /// +7157 /// For all probes that succeed, if any, a new path will be opened on the successful +7158 /// 4-tuple. 7159 /// -7160 /// For all probes that succeed, if any, a new path will be opened on the successful -7161 /// 4-tuple. -7162 /// -7163 /// Returns the server addresses that are now being probed. If addresses fail due to -7164 /// spurious errors, these might succeed later and not be returned in this set. -7165 pub fn initiate_nat_traversal_round( -7166 &mut self, -7167 now: Instant, -7168 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { -7169 if self.state.is_closed() { -7170 return Err(n0_nat_traversal::Error::Closed); -7171 } -7172 -7173 let ipv6 = self.is_ipv6(); -7174 let client_state = self.n0_nat_traversal.client_side_mut()?; -7175 let (mut reach_out_frames, probed_addrs) = -7176 client_state.initiate_nat_traversal_round(ipv6)?; -7177 if let Some(delay) = self.n0_nat_traversal.retry_delay(self.config.initial_rtt) { -7178 self.timers.set( -7179 Timer::Conn(ConnTimer::NatTraversalProbeRetry), -7180 now + delay, -7181 self.qlog.with_time(now), -7182 ); -7183 } -7184 -7185 self.spaces[SpaceId::Data] -7186 .pending -7187 .reach_out -7188 .append(&mut reach_out_frames); +7160 /// Returns the server addresses that are now being probed. If addresses fail due to +7161 /// spurious errors, these might succeed later and not be returned in this set. +7162 pub fn initiate_nat_traversal_round( +7163 &mut self, +7164 now: Instant, +7165 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> { +7166 if self.state.is_closed() { +7167 return Err(n0_nat_traversal::Error::Closed); +7168 } +7169 +7170 let ipv6 = self.is_ipv6(); +7171 let client_state = self.n0_nat_traversal.client_side_mut()?; +7172 let (mut reach_out_frames, probed_addrs) = +7173 client_state.initiate_nat_traversal_round(ipv6)?; +7174 if let Some(delay) = self.n0_nat_traversal.retry_delay(self.config.initial_rtt) { +7175 self.timers.set( +7176 Timer::Conn(ConnTimer::NatTraversalProbeRetry), +7177 now + delay, +7178 self.qlog.with_time(now), +7179 ); +7180 } +7181 +7182 self.spaces[SpaceId::Data] +7183 .pending +7184 .reach_out +7185 .append(&mut reach_out_frames); +7186 +7187 Ok(probed_addrs) +7188 } 7189 -7190 Ok(probed_addrs) -7191 } -7192 -7193 /// Whether the handshake is considered **confirmed**. -7194 /// -7195 /// <https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2> defines a handshake to be -7196 /// confirmed when you know the peer successfully received and successfully processed -7197 /// your TLS Finished message. -7198 /// -7199 /// Implementation-wise this is the point at which the handshake crypto keys are -7200 /// discarded. So we can use this to know if the handshake is confirmed. -7201 fn is_handshake_confirmed(&self) -> bool { -7202 !self.is_handshaking() && !self.crypto_state.has_keys(EncryptionLevel::Handshake) -7203 } -7204} -7205 -7206impl fmt::Debug for Connection { -7207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -7208 f.debug_struct("Connection") -7209 .field("handshake_cid", &self.handshake_cid) -7210 .finish() -7211 } -7212} -7213 -7214/// The set of abandoned paths. -7215/// -7216/// Implementation based on ArrayRangeSet to share more code. The memory space is -7217/// proportional to the number of concurrently open paths allowed. So does not grow -7218/// unbounded. -7219#[derive(Debug, Default)] -7220struct AbandonedPaths(ArrayRangeSet<ABANDONED_PATH_INLINE_RANGES, u32>); -7221 -7222/// Size of the stack-allocated array in the [`ArrayRangeSet`]. -7223/// -7224/// A range is 2 u32's, so this is 16 * (4 + 4) = 128 bytes. A good size for inline data, -7225/// with plenty of ranges for common multipath use. -7226const ABANDONED_PATH_INLINE_RANGES: usize = 16; -7227 -7228impl AbandonedPaths { -7229 /// The number of abandoned paths. -7230 fn len(&self) -> u32 { -7231 self.0.elts_count() -7232 } -7233 -7234 /// The largest abandoned path. -7235 fn max(&self) -> Option<PathId> { -7236 self.0.max().map(PathId::from) -7237 } -7238 -7239 /// Whether the path is already abandoned. -7240 fn contains(&self, val: &PathId) -> bool { -7241 self.0.contains(val.as_u32()) -7242 } -7243 -7244 /// Adds another abandoned path. -7245 fn insert(&mut self, val: PathId) { -7246 self.0.insert_one(val.as_u32()); -7247 } -7248} -7249 -7250/// Hints when the caller identifies a network change. -7251pub trait NetworkChangeHint: std::fmt::Debug + 'static { -7252 /// Inform the connection if a path may recover after a network change. -7253 /// -7254 /// After network changes, paths may not be recoverable. In this case, waiting for the path to -7255 /// become idle may take longer than what is desirable. If [`Self::is_path_recoverable`] -7256 /// returns `false`, a multipath-enabled, client-side connection will establish a new path to -7257 /// the same remote, closing the current one, instead of migrating the path. -7258 /// -7259 /// Paths that are deemed recoverable will simply be sent a PING for a liveness check. -7260 fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool; -7261} -7262 -7263/// Return value for [`Connection::poll_transmit_path_space`]. -7264#[derive(Debug)] -7265enum PollPathSpaceStatus { -7266 /// Nothing to send in the space, nothing was written into the [`TransmitBuf`]. -7267 NothingToSend { -7268 /// If true there was data to send but congestion control did not allow so. -7269 congestion_blocked: bool, -7270 }, -7271 /// One or more packets have been written into the [`TransmitBuf`]. -7272 WrotePacket { -7273 /// The highest packet number. -7274 last_packet_number: u64, -7275 /// Whether to pad an already started datagram in the next packet. -7276 /// -7277 /// When packets in Initial, 0-RTT or Handshake packet do not fill the entire -7278 /// datagram they may decide to coalesce with the next packet from a higher -7279 /// encryption level on the same path. But the earlier packet may require specific -7280 /// size requirements for the datagram they are sent in. -7281 /// -7282 /// If a space did not complete the datagram, they use this to request the correct -7283 /// padding in the final packet of the datagram so that the final datagram will have -7284 /// the correct size. -7285 /// -7286 /// If a space did fill an entire datagram, it leaves this to the default of -7287 /// [`PadDatagram::No`]. -7288 pad_datagram: PadDatagram, -7289 }, -7290 /// Send the contents of the transmit immediately. -7291 /// -7292 /// Packets were written and the GSO batch must end now, regardless from whether higher -7293 /// spaces still have frames to write. This is used when the last datagram written would -7294 /// require too much padding to continue a GSO batch, which would waste space on the -7295 /// wire. -7296 Send { -7297 /// The highest packet number written into the transmit. -7298 last_packet_number: u64, -7299 }, -7300} -7301 -7302/// Information used to decide what frames to schedule into which packets. -7303/// -7304/// Primarily used by [`Connection::poll_transmit_on_path`] and the functions that help -7305/// building packets for it: [`Connection::poll_transmit_path_space`] and -7306/// [`Connection::populate_packet`]. -7307#[derive(Debug, Copy, Clone)] -7308struct PathSchedulingInfo { -7309 /// Whether the path is abandoned. -7310 /// -7311 /// Note that a path that is abandoned but still has CIDs can still send a packet. After -7312 /// sending that packet the CIDs issued by the remote have to be considered retired as -7313 /// well. -7314 is_abandoned: bool, -7315 /// Whether the path may send [`SpaceKind::Data`] frames. -7316 /// -7317 /// Some paths should only send frames from [`SendableFrames::space_specific`]. All other -7318 /// frames are essentially frames that can be sent on any [`SpaceKind::Data`] space. For -7319 /// those we want to respect packet scheduling rules however. -7320 /// -7321 /// Roughly speaking data frames are only sent on spaces that have CIDs, are not -7322 /// abandoned and have no *better* spaces. However see to comments where this is -7323 /// populated for the exact packet scheduling implementation. -7324 /// -7325 /// This essentially marks this paths as the best validated space ID. Except during -7326 /// the handshake in which case it does not need to be validated. Several paths could be -7327 /// equally good and all have this set to `true`, in that case packet scheduling can -7328 /// choose which path to use. Currently it chooses the lowest path that is not -7329 /// congestion blocked. -7330 /// -7331 /// Note that once in the closed or draining states this will never be true. -7332 may_send_data: bool, -7333 /// Whether the path may send a CONNECTION_CLOSE frame. -7334 /// -7335 /// This essentially marks this path as the best validated space ID with a fallback -7336 /// to unvalidated spaces if there are no validated spaces. Like for -7337 /// [`Self::may_send_data`] other paths could be equally good. -7338 may_send_close: bool, -7339 may_self_abandon: bool, -7340} -7341 -7342#[derive(Debug, Copy, Clone, PartialEq, Eq)] -7343enum PathBlocked { -7344 No, -7345 AntiAmplification, -7346 Congestion, -7347 Pacing, -7348} -7349 -7350/// Fields of `Connection` specific to it being client-side or server-side -7351enum ConnectionSide { -7352 Client { -7353 /// Sent in every outgoing Initial packet. Always empty after Initial keys are discarded -7354 token: Bytes, -7355 token_store: Arc<dyn TokenStore>, -7356 server_name: String, +7190 /// Whether the handshake is considered **confirmed**. +7191 /// +7192 /// <https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2> defines a handshake to be +7193 /// confirmed when you know the peer successfully received and successfully processed +7194 /// your TLS Finished message. +7195 /// +7196 /// Implementation-wise this is the point at which the handshake crypto keys are +7197 /// discarded. So we can use this to know if the handshake is confirmed. +7198 fn is_handshake_confirmed(&self) -> bool { +7199 !self.is_handshaking() && !self.crypto_state.has_keys(EncryptionLevel::Handshake) +7200 } +7201} +7202 +7203impl fmt::Debug for Connection { +7204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +7205 f.debug_struct("Connection") +7206 .field("handshake_cid", &self.handshake_cid) +7207 .finish() +7208 } +7209} +7210 +7211/// The set of abandoned paths. +7212/// +7213/// Implementation based on ArrayRangeSet to share more code. The memory space is +7214/// proportional to the number of concurrently open paths allowed. So does not grow +7215/// unbounded. +7216#[derive(Debug, Default)] +7217struct AbandonedPaths(ArrayRangeSet<ABANDONED_PATH_INLINE_RANGES, u32>); +7218 +7219/// Size of the stack-allocated array in the [`ArrayRangeSet`]. +7220/// +7221/// A range is 2 u32's, so this is 16 * (4 + 4) = 128 bytes. A good size for inline data, +7222/// with plenty of ranges for common multipath use. +7223const ABANDONED_PATH_INLINE_RANGES: usize = 16; +7224 +7225impl AbandonedPaths { +7226 /// The number of abandoned paths. +7227 fn len(&self) -> u32 { +7228 self.0.elts_count() +7229 } +7230 +7231 /// The largest abandoned path. +7232 fn max(&self) -> Option<PathId> { +7233 self.0.max().map(PathId::from) +7234 } +7235 +7236 /// Whether the path is already abandoned. +7237 fn contains(&self, val: &PathId) -> bool { +7238 self.0.contains(val.as_u32()) +7239 } +7240 +7241 /// Adds another abandoned path. +7242 fn insert(&mut self, val: PathId) { +7243 self.0.insert_one(val.as_u32()); +7244 } +7245} +7246 +7247/// Hints when the caller identifies a network change. +7248pub trait NetworkChangeHint: std::fmt::Debug + 'static { +7249 /// Inform the connection if a path may recover after a network change. +7250 /// +7251 /// After network changes, paths may not be recoverable. In this case, waiting for the path to +7252 /// become idle may take longer than what is desirable. If [`Self::is_path_recoverable`] +7253 /// returns `false`, a multipath-enabled, client-side connection will establish a new path to +7254 /// the same remote, closing the current one, instead of migrating the path. +7255 /// +7256 /// Paths that are deemed recoverable will simply be sent a PING for a liveness check. +7257 fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool; +7258} +7259 +7260/// Return value for [`Connection::poll_transmit_path_space`]. +7261#[derive(Debug)] +7262enum PollPathSpaceStatus { +7263 /// Nothing to send in the space, nothing was written into the [`TransmitBuf`]. +7264 NothingToSend { +7265 /// If true there was data to send but congestion control did not allow so. +7266 congestion_blocked: bool, +7267 }, +7268 /// One or more packets have been written into the [`TransmitBuf`]. +7269 WrotePacket { +7270 /// The highest packet number. +7271 last_packet_number: u64, +7272 /// Whether to pad an already started datagram in the next packet. +7273 /// +7274 /// When packets in Initial, 0-RTT or Handshake packet do not fill the entire +7275 /// datagram they may decide to coalesce with the next packet from a higher +7276 /// encryption level on the same path. But the earlier packet may require specific +7277 /// size requirements for the datagram they are sent in. +7278 /// +7279 /// If a space did not complete the datagram, they use this to request the correct +7280 /// padding in the final packet of the datagram so that the final datagram will have +7281 /// the correct size. +7282 /// +7283 /// If a space did fill an entire datagram, it leaves this to the default of +7284 /// [`PadDatagram::No`]. +7285 pad_datagram: PadDatagram, +7286 }, +7287 /// Send the contents of the transmit immediately. +7288 /// +7289 /// Packets were written and the GSO batch must end now, regardless from whether higher +7290 /// spaces still have frames to write. This is used when the last datagram written would +7291 /// require too much padding to continue a GSO batch, which would waste space on the +7292 /// wire. +7293 Send { +7294 /// The highest packet number written into the transmit. +7295 last_packet_number: u64, +7296 }, +7297} +7298 +7299/// Information used to decide what frames to schedule into which packets. +7300/// +7301/// Primarily used by [`Connection::poll_transmit_on_path`] and the functions that help +7302/// building packets for it: [`Connection::poll_transmit_path_space`] and +7303/// [`Connection::populate_packet`]. +7304#[derive(Debug, Copy, Clone)] +7305struct PathSchedulingInfo { +7306 /// Whether the path is abandoned. +7307 /// +7308 /// Note that a path that is abandoned but still has CIDs can still send a packet. After +7309 /// sending that packet the CIDs issued by the remote have to be considered retired as +7310 /// well. +7311 is_abandoned: bool, +7312 /// Whether the path may send [`SpaceKind::Data`] frames. +7313 /// +7314 /// Some paths should only send frames from [`SendableFrames::space_specific`]. All other +7315 /// frames are essentially frames that can be sent on any [`SpaceKind::Data`] space. For +7316 /// those we want to respect packet scheduling rules however. +7317 /// +7318 /// Roughly speaking data frames are only sent on spaces that have CIDs, are not +7319 /// abandoned and have no *better* spaces. However see to comments where this is +7320 /// populated for the exact packet scheduling implementation. +7321 /// +7322 /// This essentially marks this paths as the best validated space ID. Except during +7323 /// the handshake in which case it does not need to be validated. Several paths could be +7324 /// equally good and all have this set to `true`, in that case packet scheduling can +7325 /// choose which path to use. Currently it chooses the lowest path that is not +7326 /// congestion blocked. +7327 /// +7328 /// Note that once in the closed or draining states this will never be true. +7329 may_send_data: bool, +7330 /// Whether the path may send a CONNECTION_CLOSE frame. +7331 /// +7332 /// This essentially marks this path as the best validated space ID with a fallback +7333 /// to unvalidated spaces if there are no validated spaces. Like for +7334 /// [`Self::may_send_data`] other paths could be equally good. +7335 may_send_close: bool, +7336 may_self_abandon: bool, +7337} +7338 +7339#[derive(Debug, Copy, Clone, PartialEq, Eq)] +7340enum PathBlocked { +7341 No, +7342 AntiAmplification, +7343 Congestion, +7344 Pacing, +7345} +7346 +7347/// Fields of `Connection` specific to it being client-side or server-side +7348enum ConnectionSide { +7349 Client { +7350 /// Sent in every outgoing Initial packet. Always empty after Initial keys are discarded +7351 token: Bytes, +7352 token_store: Arc<dyn TokenStore>, +7353 server_name: String, +7354 }, +7355 Server { +7356 server_config: Arc<ServerConfig>, 7357 }, -7358 Server { -7359 server_config: Arc<ServerConfig>, -7360 }, -7361} -7362 -7363impl ConnectionSide { -7364 fn is_client(&self) -> bool { -7365 self.side().is_client() -7366 } -7367 -7368 fn is_server(&self) -> bool { -7369 self.side().is_server() -7370 } -7371 -7372 fn side(&self) -> Side { -7373 match *self { -7374 Self::Client { .. } => Side::Client, -7375 Self::Server { .. } => Side::Server, -7376 } -7377 } -7378} -7379 -7380impl From<SideArgs> for ConnectionSide { -7381 fn from(side: SideArgs) -> Self { -7382 match side { -7383 SideArgs::Client { -7384 token_store, -7385 server_name, -7386 } => Self::Client { -7387 token: token_store.take(&server_name).unwrap_or_default(), -7388 token_store, -7389 server_name, -7390 }, -7391 SideArgs::Server { -7392 server_config, -7393 pref_addr_cid: _, -7394 path_validated: _, -7395 } => Self::Server { server_config }, -7396 } -7397 } -7398} -7399 -7400/// Parameters to `Connection::new` specific to it being client-side or server-side -7401pub(crate) enum SideArgs { -7402 Client { -7403 token_store: Arc<dyn TokenStore>, -7404 server_name: String, -7405 }, -7406 Server { -7407 server_config: Arc<ServerConfig>, -7408 pref_addr_cid: Option<ConnectionId>, -7409 path_validated: bool, -7410 }, -7411} -7412 -7413impl SideArgs { -7414 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> { -7415 match *self { -7416 Self::Client { .. } => None, -7417 Self::Server { pref_addr_cid, .. } => pref_addr_cid, -7418 } -7419 } -7420 -7421 pub(crate) fn path_validated(&self) -> bool { -7422 match *self { -7423 Self::Client { .. } => true, -7424 Self::Server { path_validated, .. } => path_validated, -7425 } -7426 } -7427 -7428 pub(crate) fn side(&self) -> Side { -7429 match *self { -7430 Self::Client { .. } => Side::Client, -7431 Self::Server { .. } => Side::Server, -7432 } -7433 } -7434} -7435 -7436/// Reasons why a connection might be lost -7437#[derive(Debug, Error, Clone, PartialEq, Eq)] -7438pub enum ConnectionError { -7439 /// The peer doesn't implement any supported version -7440 #[error("peer doesn't implement any supported version")] -7441 VersionMismatch, -7442 /// The peer violated the QUIC specification as understood by this implementation -7443 #[error(transparent)] -7444 TransportError(#[from] TransportError), -7445 /// The peer's QUIC stack aborted the connection automatically -7446 #[error("aborted by peer: {0}")] -7447 ConnectionClosed(frame::ConnectionClose), -7448 /// The peer closed the connection -7449 #[error("closed by peer: {0}")] -7450 ApplicationClosed(frame::ApplicationClose), -7451 /// The peer is unable to continue processing this connection, usually due to having restarted -7452 #[error("reset by peer")] -7453 Reset, -7454 /// Communication with the peer has lapsed for longer than the negotiated idle timeout -7455 /// -7456 /// If neither side is sending keep-alives, a connection will time out after a long enough idle -7457 /// period even if the peer is still reachable. See also [`TransportConfig::max_idle_timeout()`] -7458 /// and [`TransportConfig::keep_alive_interval()`]. -7459 #[error("timed out")] -7460 TimedOut, -7461 /// The local application closed the connection -7462 #[error("closed")] -7463 LocallyClosed, -7464 /// The connection could not be created because not enough of the CID space is available -7465 /// -7466 /// Try using longer connection IDs. -7467 #[error("CIDs exhausted")] -7468 CidsExhausted, -7469} -7470 -7471impl From<Close> for ConnectionError { -7472 fn from(x: Close) -> Self { -7473 match x { -7474 Close::Connection(reason) => Self::ConnectionClosed(reason), -7475 Close::Application(reason) => Self::ApplicationClosed(reason), -7476 } -7477 } -7478} -7479 -7480// For compatibility with API consumers -7481impl From<ConnectionError> for io::Error { -7482 fn from(x: ConnectionError) -> Self { -7483 use ConnectionError::*; -7484 let kind = match x { -7485 TimedOut => io::ErrorKind::TimedOut, -7486 Reset => io::ErrorKind::ConnectionReset, -7487 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted, -7488 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => { -7489 io::ErrorKind::Other -7490 } -7491 }; -7492 Self::new(kind, x) -7493 } -7494} -7495 -7496/// Errors that might trigger a path being closed -7497// TODO(@divma): maybe needs to be reworked based on what we want to do with the public API -7498#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)] -7499pub enum PathError { -7500 /// The extension was not negotiated with the peer -7501 #[error("multipath extension not negotiated")] -7502 MultipathNotNegotiated, -7503 /// Paths can only be opened client-side -7504 #[error("the server side may not open a path")] -7505 ServerSideNotAllowed, -7506 /// Current limits do not allow us to open more paths -7507 #[error("maximum number of concurrent paths reached")] -7508 MaxPathIdReached, -7509 /// No remote CIDs available to open a new path -7510 #[error("remoted CIDs exhausted")] -7511 RemoteCidsExhausted, -7512 /// Path could not be validated and will be abandoned -7513 #[error("path validation failed")] -7514 ValidationFailed, -7515 /// The remote address for the path is not supported by the endpoint -7516 #[error("invalid remote address")] -7517 InvalidRemoteAddress(SocketAddr), -7518} -7519 -7520/// Errors triggered when abandoning a path -7521#[derive(Debug, Error, Clone, Eq, PartialEq)] -7522pub enum ClosePathError { -7523 /// Multipath is not negotiated -7524 #[error("Multipath extension not negotiated")] -7525 MultipathNotNegotiated, -7526 /// The path is already closed or was never opened -7527 #[error("closed path")] -7528 ClosedPath, -7529 /// Cannot close the last remaining open path via the local API. -7530 /// -7531 /// Use [`Connection::close`] to end the connection instead. -7532 #[error("last open path")] -7533 LastOpenPath, -7534} -7535 -7536/// Error when the multipath extension was not negotiated, but attempted to be used. -7537#[derive(Debug, Error, Clone, Copy)] -7538#[error("Multipath extension not negotiated")] -7539pub struct MultipathNotNegotiated { -7540 _private: (), -7541} -7542 -7543/// Events of interest to the application -7544#[derive(Debug)] -7545pub enum Event { -7546 /// The connection's handshake data is ready -7547 HandshakeDataReady, -7548 /// The connection was successfully established -7549 Connected, -7550 /// The TLS handshake was confirmed -7551 HandshakeConfirmed, -7552 /// The connection was lost -7553 /// -7554 /// Emitted when the connection is closed due to an error, a timeout, or the peer closing it. -7555 /// This is **not** emitted when the local application closes the connection via -7556 /// [`Connection::close()`](crate::Connection::close). In that case, pending operations will -7557 /// fail with [`ConnectionError::LocallyClosed`]. -7558 ConnectionLost { -7559 /// Reason that the connection was closed -7560 reason: ConnectionError, -7561 }, -7562 /// Stream events -7563 Stream(StreamEvent), -7564 /// One or more application datagrams have been received -7565 DatagramReceived, -7566 /// One or more application datagrams have been sent after blocking -7567 DatagramsUnblocked, -7568 /// (Multi)Path events -7569 Path(PathEvent), -7570 /// n0's nat traversal events -7571 NatTraversal(n0_nat_traversal::Event), -7572} -7573 -7574impl From<PathEvent> for Event { -7575 fn from(source: PathEvent) -> Self { -7576 Self::Path(source) -7577 } -7578} -7579 -7580fn get_max_ack_delay(params: &TransportParameters) -> Duration { -7581 Duration::from_micros(params.max_ack_delay.0 * 1000) -7582} +7358} +7359 +7360impl ConnectionSide { +7361 fn is_client(&self) -> bool { +7362 self.side().is_client() +7363 } +7364 +7365 fn is_server(&self) -> bool { +7366 self.side().is_server() +7367 } +7368 +7369 fn side(&self) -> Side { +7370 match *self { +7371 Self::Client { .. } => Side::Client, +7372 Self::Server { .. } => Side::Server, +7373 } +7374 } +7375} +7376 +7377impl From<SideArgs> for ConnectionSide { +7378 fn from(side: SideArgs) -> Self { +7379 match side { +7380 SideArgs::Client { +7381 token_store, +7382 server_name, +7383 } => Self::Client { +7384 token: token_store.take(&server_name).unwrap_or_default(), +7385 token_store, +7386 server_name, +7387 }, +7388 SideArgs::Server { +7389 server_config, +7390 pref_addr_cid: _, +7391 path_validated: _, +7392 } => Self::Server { server_config }, +7393 } +7394 } +7395} +7396 +7397/// Parameters to `Connection::new` specific to it being client-side or server-side +7398pub(crate) enum SideArgs { +7399 Client { +7400 token_store: Arc<dyn TokenStore>, +7401 server_name: String, +7402 }, +7403 Server { +7404 server_config: Arc<ServerConfig>, +7405 pref_addr_cid: Option<ConnectionId>, +7406 path_validated: bool, +7407 }, +7408} +7409 +7410impl SideArgs { +7411 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> { +7412 match *self { +7413 Self::Client { .. } => None, +7414 Self::Server { pref_addr_cid, .. } => pref_addr_cid, +7415 } +7416 } +7417 +7418 pub(crate) fn path_validated(&self) -> bool { +7419 match *self { +7420 Self::Client { .. } => true, +7421 Self::Server { path_validated, .. } => path_validated, +7422 } +7423 } +7424 +7425 pub(crate) fn side(&self) -> Side { +7426 match *self { +7427 Self::Client { .. } => Side::Client, +7428 Self::Server { .. } => Side::Server, +7429 } +7430 } +7431} +7432 +7433/// Reasons why a connection might be lost +7434#[derive(Debug, Error, Clone, PartialEq, Eq)] +7435pub enum ConnectionError { +7436 /// The peer doesn't implement any supported version +7437 #[error("peer doesn't implement any supported version")] +7438 VersionMismatch, +7439 /// The peer violated the QUIC specification as understood by this implementation +7440 #[error(transparent)] +7441 TransportError(#[from] TransportError), +7442 /// The peer's QUIC stack aborted the connection automatically +7443 #[error("aborted by peer: {0}")] +7444 ConnectionClosed(frame::ConnectionClose), +7445 /// The peer closed the connection +7446 #[error("closed by peer: {0}")] +7447 ApplicationClosed(frame::ApplicationClose), +7448 /// The peer is unable to continue processing this connection, usually due to having restarted +7449 #[error("reset by peer")] +7450 Reset, +7451 /// Communication with the peer has lapsed for longer than the negotiated idle timeout +7452 /// +7453 /// If neither side is sending keep-alives, a connection will time out after a long enough idle +7454 /// period even if the peer is still reachable. See also [`TransportConfig::max_idle_timeout()`] +7455 /// and [`TransportConfig::keep_alive_interval()`]. +7456 #[error("timed out")] +7457 TimedOut, +7458 /// The local application closed the connection +7459 #[error("closed")] +7460 LocallyClosed, +7461 /// The connection could not be created because not enough of the CID space is available +7462 /// +7463 /// Try using longer connection IDs. +7464 #[error("CIDs exhausted")] +7465 CidsExhausted, +7466} +7467 +7468impl From<Close> for ConnectionError { +7469 fn from(x: Close) -> Self { +7470 match x { +7471 Close::Connection(reason) => Self::ConnectionClosed(reason), +7472 Close::Application(reason) => Self::ApplicationClosed(reason), +7473 } +7474 } +7475} +7476 +7477// For compatibility with API consumers +7478impl From<ConnectionError> for io::Error { +7479 fn from(x: ConnectionError) -> Self { +7480 use ConnectionError::*; +7481 let kind = match x { +7482 TimedOut => io::ErrorKind::TimedOut, +7483 Reset => io::ErrorKind::ConnectionReset, +7484 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted, +7485 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => { +7486 io::ErrorKind::Other +7487 } +7488 }; +7489 Self::new(kind, x) +7490 } +7491} +7492 +7493/// Errors that might trigger a path being closed +7494// TODO(@divma): maybe needs to be reworked based on what we want to do with the public API +7495#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)] +7496pub enum PathError { +7497 /// The extension was not negotiated with the peer +7498 #[error("multipath extension not negotiated")] +7499 MultipathNotNegotiated, +7500 /// Paths can only be opened client-side +7501 #[error("the server side may not open a path")] +7502 ServerSideNotAllowed, +7503 /// Current limits do not allow us to open more paths +7504 #[error("maximum number of concurrent paths reached")] +7505 MaxPathIdReached, +7506 /// No remote CIDs available to open a new path +7507 #[error("remoted CIDs exhausted")] +7508 RemoteCidsExhausted, +7509 /// Path could not be validated and will be abandoned +7510 #[error("path validation failed")] +7511 ValidationFailed, +7512 /// The remote address for the path is not supported by the endpoint +7513 #[error("invalid remote address")] +7514 InvalidRemoteAddress(SocketAddr), +7515} +7516 +7517/// Errors triggered when abandoning a path +7518#[derive(Debug, Error, Clone, Eq, PartialEq)] +7519pub enum ClosePathError { +7520 /// Multipath is not negotiated +7521 #[error("Multipath extension not negotiated")] +7522 MultipathNotNegotiated, +7523 /// The path is already closed or was never opened +7524 #[error("closed path")] +7525 ClosedPath, +7526 /// Cannot close the last remaining open path via the local API. +7527 /// +7528 /// Use [`Connection::close`] to end the connection instead. +7529 #[error("last open path")] +7530 LastOpenPath, +7531} +7532 +7533/// Error when the multipath extension was not negotiated, but attempted to be used. +7534#[derive(Debug, Error, Clone, Copy)] +7535#[error("Multipath extension not negotiated")] +7536pub struct MultipathNotNegotiated { +7537 _private: (), +7538} +7539 +7540/// Events of interest to the application +7541#[derive(Debug)] +7542pub enum Event { +7543 /// The connection's handshake data is ready +7544 HandshakeDataReady, +7545 /// The connection was successfully established +7546 Connected, +7547 /// The TLS handshake was confirmed +7548 HandshakeConfirmed, +7549 /// The connection was lost +7550 /// +7551 /// Emitted when the connection is closed due to an error, a timeout, or the peer closing it. +7552 /// This is **not** emitted when the local application closes the connection via +7553 /// [`Connection::close()`](crate::Connection::close). In that case, pending operations will +7554 /// fail with [`ConnectionError::LocallyClosed`]. +7555 ConnectionLost { +7556 /// Reason that the connection was closed +7557 reason: ConnectionError, +7558 }, +7559 /// Stream events +7560 Stream(StreamEvent), +7561 /// One or more application datagrams have been received +7562 DatagramReceived, +7563 /// One or more application datagrams have been sent after blocking +7564 DatagramsUnblocked, +7565 /// (Multi)Path events +7566 Path(PathEvent), +7567 /// n0's nat traversal events +7568 NatTraversal(n0_nat_traversal::Event), +7569} +7570 +7571impl From<PathEvent> for Event { +7572 fn from(source: PathEvent) -> Self { +7573 Self::Path(source) +7574 } +7575} +7576 +7577fn get_max_ack_delay(params: &TransportParameters) -> Duration { +7578 Duration::from_micros(params.max_ack_delay.0 * 1000) +7579} +7580 +7581/// Prevents overflow and improves behavior in extreme circumstances. +7582const MAX_BACKOFF_EXPONENT: u32 = 16; 7583 -7584/// Prevents overflow and improves behavior in extreme circumstances. -7585const MAX_BACKOFF_EXPONENT: u32 = 16; -7586 -7587/// The max interval between successive tail-loss probes. -7588/// -7589/// This is the "normal" value we use. -7590const MAX_PTO_INTERVAL: Duration = Duration::from_secs(2); +7584/// The max interval between successive tail-loss probes. +7585/// +7586/// This is the "normal" value we use. +7587const MAX_PTO_INTERVAL: Duration = Duration::from_secs(2); +7588 +7589/// The idle time, below which we use the shorter [`MAX_PTO_FAST_INTERVAL`]. +7590const MIN_IDLE_FOR_FAST_PTO: Duration = Duration::from_secs(25); 7591 -7592/// The idle time, below which we use the shorter [`MAX_PTO_FAST_INTERVAL`]. -7593const MIN_IDLE_FOR_FAST_PTO: Duration = Duration::from_secs(25); -7594 -7595/// The max interval between successive tail-loss probes with short idle times. -7596/// -7597/// If the path or connection idle time is less than [`MIN_IDLE_FOR_FAST_PTO`] then we use -7598/// this value to ensure we have plenty of retransmits before we reach the idle time. -7599const MAX_PTO_FAST_INTERVAL: Duration = Duration::from_secs(1); -7600 -7601/// The RTT threshold above which we cap the PTO interval to 1.5 * smoothed_rtt -7602/// -7603/// This is RTT time above which 1.5 * RTT > [`MAX_PTO_INTERVAL`], for these links we want -7604/// to extend the interval between tail-loss probes to not fill the entire pipe with them. -7605const SLOW_RTT_THRESHOLD: Duration = -7606 Duration::from_millis((MAX_PTO_INTERVAL.as_millis() as u64 * 2) / 3); -7607 -7608/// Minimal remaining size to allow packet coalescing, excluding cryptographic tag -7609/// -7610/// This must be at least as large as the header for a well-formed empty packet to be coalesced, -7611/// plus some space for frames. We only care about handshake headers because short header packets -7612/// necessarily have smaller headers, and initial packets are only ever the first packet in a -7613/// datagram (because we coalesce in ascending packet space order and the only reason to split a -7614/// packet is when packet space changes). -7615const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32; -7616 -7617/// Largest amount of space that could be occupied by a Handshake or 0-RTT packet's header -7618/// -7619/// Excludes packet-type-specific fields such as packet number or Initial token -7620// https://www.rfc-editor.org/rfc/rfc9000.html#name-0-rtt: flags + version + dcid len + dcid + -7621// scid len + scid + length + pn -7622const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize = -7623 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4; -7624 -7625#[derive(Default)] -7626struct SentFrames { -7627 retransmits: ThinRetransmits, -7628 path_retransmits: PathRetransmits, -7629 /// The packet number of the largest acknowledged packet for each path -7630 largest_acked: FxHashMap<PathId, u64>, -7631 stream_frames: StreamMetaVec, -7632 /// Whether the packet contains non-retransmittable frames (like datagrams) -7633 non_retransmits: bool, -7634 /// If the datagram containing these frames should be padded to the min MTU -7635 requires_padding: bool, -7636} -7637 -7638impl SentFrames { -7639 /// Returns whether the packet contains only ACKs -7640 fn is_ack_only(&self, streams: &StreamsState) -> bool { -7641 !self.largest_acked.is_empty() -7642 && !self.non_retransmits -7643 && self.stream_frames.is_empty() -7644 && self.retransmits.is_empty(streams) -7645 } -7646 -7647 fn retransmits_mut(&mut self) -> &mut Retransmits { -7648 self.retransmits.get_or_create() -7649 } -7650 -7651 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) { -7652 use frame::EncodableFrame::*; -7653 match frame { -7654 PathAck(path_ack_encoder) => { -7655 if let Some(max) = path_ack_encoder.ranges.max() { -7656 self.largest_acked.insert(path_ack_encoder.path_id, max); -7657 } -7658 } -7659 Ack(ack_encoder) => { -7660 if let Some(max) = ack_encoder.ranges.max() { -7661 self.largest_acked.insert(PathId::ZERO, max); -7662 } -7663 } -7664 Close(_) => { /* non retransmittable, but after this we don't really care */ } -7665 PathResponse(_) => self.non_retransmits = true, -7666 HandshakeDone(_) => self.retransmits_mut().handshake_done = true, -7667 ReachOut(frame) => self.retransmits_mut().reach_out.push(frame), -7668 ObservedAddr(_) => self.path_retransmits.observed_address = true, -7669 Ping(_) => self.non_retransmits = true, -7670 ImmediateAck(_) => self.non_retransmits = true, -7671 AckFrequency(_) => self.retransmits_mut().ack_frequency = true, -7672 PathChallenge(_) => self.non_retransmits = true, -7673 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto), -7674 PathAbandon(path_abandon) => { -7675 self.retransmits_mut() -7676 .path_abandon -7677 .entry(path_abandon.path_id) -7678 .or_insert(path_abandon.error_code); -7679 } -7680 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. }) -7681 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => { -7682 self.retransmits_mut().path_status.insert(path_id); -7683 } -7684 MaxPathId(_) => self.retransmits_mut().max_path_id = true, -7685 PathsBlocked(frame::PathsBlocked(path_id)) => { -7686 let paths_blocked = &mut self.retransmits_mut().paths_blocked; -7687 *paths_blocked = cmp::max(*paths_blocked, Some(path_id)); -7688 } -7689 PathCidsBlocked(path_cids_blocked) => { -7690 self.retransmits_mut() -7691 .path_cids_blocked -7692 .entry(path_cids_blocked.path_id) -7693 .and_modify(|next_seq| { -7694 *next_seq = cmp::max(*next_seq, path_cids_blocked.next_seq); -7695 }) -7696 .or_insert(path_cids_blocked.next_seq); -7697 } -7698 ResetStream(reset) => self -7699 .retransmits_mut() -7700 .reset_stream -7701 .push((reset.id, reset.error_code)), -7702 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending), -7703 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()), -7704 RetireConnectionId(retire_cid) => self -7705 .retransmits_mut() -7706 .retire_cids -7707 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)), -7708 Datagram(_) => self.non_retransmits = true, -7709 NewToken(_) => {} -7710 AddAddress(add_address) => { -7711 self.retransmits_mut().add_address.insert(add_address); +7592/// The max interval between successive tail-loss probes with short idle times. +7593/// +7594/// If the path or connection idle time is less than [`MIN_IDLE_FOR_FAST_PTO`] then we use +7595/// this value to ensure we have plenty of retransmits before we reach the idle time. +7596const MAX_PTO_FAST_INTERVAL: Duration = Duration::from_secs(1); +7597 +7598/// The RTT threshold above which we cap the PTO interval to 1.5 * smoothed_rtt +7599/// +7600/// This is RTT time above which 1.5 * RTT > [`MAX_PTO_INTERVAL`], for these links we want +7601/// to extend the interval between tail-loss probes to not fill the entire pipe with them. +7602const SLOW_RTT_THRESHOLD: Duration = +7603 Duration::from_millis((MAX_PTO_INTERVAL.as_millis() as u64 * 2) / 3); +7604 +7605/// Minimal remaining size to allow packet coalescing, excluding cryptographic tag +7606/// +7607/// This must be at least as large as the header for a well-formed empty packet to be coalesced, +7608/// plus some space for frames. We only care about handshake headers because short header packets +7609/// necessarily have smaller headers, and initial packets are only ever the first packet in a +7610/// datagram (because we coalesce in ascending packet space order and the only reason to split a +7611/// packet is when packet space changes). +7612const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32; +7613 +7614/// Largest amount of space that could be occupied by a Handshake or 0-RTT packet's header +7615/// +7616/// Excludes packet-type-specific fields such as packet number or Initial token +7617// https://www.rfc-editor.org/rfc/rfc9000.html#name-0-rtt: flags + version + dcid len + dcid + +7618// scid len + scid + length + pn +7619const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize = +7620 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4; +7621 +7622#[derive(Default)] +7623struct SentFrames { +7624 retransmits: ThinRetransmits, +7625 path_retransmits: PathRetransmits, +7626 /// The packet number of the largest acknowledged packet for each path +7627 largest_acked: FxHashMap<PathId, u64>, +7628 stream_frames: StreamMetaVec, +7629 /// Whether the packet contains non-retransmittable frames (like datagrams) +7630 non_retransmits: bool, +7631 /// If the datagram containing these frames should be padded to the min MTU +7632 requires_padding: bool, +7633} +7634 +7635impl SentFrames { +7636 /// Returns whether the packet contains only ACKs +7637 fn is_ack_only(&self, streams: &StreamsState) -> bool { +7638 !self.largest_acked.is_empty() +7639 && !self.non_retransmits +7640 && self.stream_frames.is_empty() +7641 && self.retransmits.is_empty(streams) +7642 } +7643 +7644 fn retransmits_mut(&mut self) -> &mut Retransmits { +7645 self.retransmits.get_or_create() +7646 } +7647 +7648 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) { +7649 use frame::EncodableFrame::*; +7650 match frame { +7651 PathAck(path_ack_encoder) => { +7652 if let Some(max) = path_ack_encoder.ranges.max() { +7653 self.largest_acked.insert(path_ack_encoder.path_id, max); +7654 } +7655 } +7656 Ack(ack_encoder) => { +7657 if let Some(max) = ack_encoder.ranges.max() { +7658 self.largest_acked.insert(PathId::ZERO, max); +7659 } +7660 } +7661 Close(_) => { /* non retransmittable, but after this we don't really care */ } +7662 PathResponse(_) => self.non_retransmits = true, +7663 HandshakeDone(_) => self.retransmits_mut().handshake_done = true, +7664 ReachOut(frame) => self.retransmits_mut().reach_out.push(frame), +7665 ObservedAddr(_) => self.path_retransmits.observed_address = true, +7666 Ping(_) => self.non_retransmits = true, +7667 ImmediateAck(_) => self.non_retransmits = true, +7668 AckFrequency(_) => self.retransmits_mut().ack_frequency = true, +7669 PathChallenge(_) => self.non_retransmits = true, +7670 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto), +7671 PathAbandon(path_abandon) => { +7672 self.retransmits_mut() +7673 .path_abandon +7674 .entry(path_abandon.path_id) +7675 .or_insert(path_abandon.error_code); +7676 } +7677 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. }) +7678 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => { +7679 self.retransmits_mut().path_status.insert(path_id); +7680 } +7681 MaxPathId(_) => self.retransmits_mut().max_path_id = true, +7682 PathsBlocked(frame::PathsBlocked(path_id)) => { +7683 let paths_blocked = &mut self.retransmits_mut().paths_blocked; +7684 *paths_blocked = cmp::max(*paths_blocked, Some(path_id)); +7685 } +7686 PathCidsBlocked(path_cids_blocked) => { +7687 self.retransmits_mut() +7688 .path_cids_blocked +7689 .entry(path_cids_blocked.path_id) +7690 .and_modify(|next_seq| { +7691 *next_seq = cmp::max(*next_seq, path_cids_blocked.next_seq); +7692 }) +7693 .or_insert(path_cids_blocked.next_seq); +7694 } +7695 ResetStream(reset) => self +7696 .retransmits_mut() +7697 .reset_stream +7698 .push((reset.id, reset.error_code)), +7699 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending), +7700 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()), +7701 RetireConnectionId(retire_cid) => self +7702 .retransmits_mut() +7703 .retire_cids +7704 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)), +7705 Datagram(_) => self.non_retransmits = true, +7706 NewToken(_) => {} +7707 AddAddress(add_address) => { +7708 self.retransmits_mut().add_address.insert(add_address); +7709 } +7710 RemoveAddress(remove_address) => { +7711 self.retransmits_mut().remove_address.insert(remove_address); 7712 } -7713 RemoveAddress(remove_address) => { -7714 self.retransmits_mut().remove_address.insert(remove_address); -7715 } -7716 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta), -7717 MaxData(_) => self.retransmits_mut().max_data = true, -7718 MaxStreamData(max) => { -7719 self.retransmits_mut().max_stream_data.insert(max.id); -7720 } -7721 MaxStreams(max_streams) => { -7722 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true +7713 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta), +7714 MaxData(_) => self.retransmits_mut().max_data = true, +7715 MaxStreamData(max) => { +7716 self.retransmits_mut().max_stream_data.insert(max.id); +7717 } +7718 MaxStreams(max_streams) => { +7719 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true +7720 } +7721 StreamsBlocked(streams_blocked) => { +7722 self.retransmits_mut().streams_blocked[streams_blocked.dir as usize] = true 7723 } -7724 StreamsBlocked(streams_blocked) => { -7725 self.retransmits_mut().streams_blocked[streams_blocked.dir as usize] = true -7726 } -7727 } -7728 } -7729} -7730 -7731/// Compute the negotiated idle timeout based on local and remote max_idle_timeout transport parameters. -7732/// -7733/// According to the definition of max_idle_timeout, a value of `0` means the timeout is disabled; see <https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.4.1.> -7734/// -7735/// According to the negotiation procedure, either the minimum of the timeouts or one specified is used as the negotiated value; see <https://www.rfc-editor.org/rfc/rfc9000#section-10.1-2.> -7736/// -7737/// Returns the negotiated idle timeout as a `Duration`, or `None` when both endpoints have opted out of idle timeout. -7738fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> { -7739 match (x, y) { -7740 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None, -7741 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)), -7742 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)), -7743 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)), -7744 } -7745} -7746 -7747#[cfg(test)] -7748mod tests { -7749 use super::*; -7750 -7751 #[test] -7752 fn negotiate_max_idle_timeout_commutative() { -7753 let test_params = [ -7754 (None, None, None), -7755 (None, Some(VarInt(0)), None), -7756 (None, Some(VarInt(2)), Some(Duration::from_millis(2))), -7757 (Some(VarInt(0)), Some(VarInt(0)), None), -7758 ( -7759 Some(VarInt(2)), -7760 Some(VarInt(0)), -7761 Some(Duration::from_millis(2)), -7762 ), -7763 ( -7764 Some(VarInt(1)), -7765 Some(VarInt(4)), -7766 Some(Duration::from_millis(1)), -7767 ), -7768 ]; -7769 -7770 for (left, right, result) in test_params { -7771 assert_eq!(negotiate_max_idle_timeout(left, right), result); -7772 assert_eq!(negotiate_max_idle_timeout(right, left), result); -7773 } -7774 } -7775 -7776 #[test] -7777 fn abandoned_paths() { -7778 let mut t = AbandonedPaths::default(); -7779 -7780 t.insert(PathId(0)); -7781 t.insert(PathId(1)); -7782 assert_eq!(t.len(), 2); -7783 assert_eq!(t.0.range_count(), 1); // 2 elements compacted into one range -7784 assert!(t.contains(&PathId(0))); -7785 assert!(t.contains(&PathId(1))); -7786 assert!(!t.contains(&PathId(2))); -7787 assert!(!t.contains(&PathId(3))); -7788 assert_eq!(t.max(), Some(PathId(1))); -7789 -7790 t.insert(PathId(3)); -7791 assert_eq!(t.len(), 3); -7792 assert_eq!(t.0.range_count(), 2); // 3 elements compacted into 2 ranges -7793 assert!(t.contains(&PathId(0))); -7794 assert!(t.contains(&PathId(1))); -7795 assert!(!t.contains(&PathId(2))); -7796 assert!(t.contains(&PathId(3))); -7797 assert_eq!(t.max(), Some(PathId(3))); -7798 -7799 t.insert(PathId(2)); -7800 assert_eq!(t.len(), 4); -7801 assert_eq!(t.0.range_count(), 1); // 4 elements compacted into 1 range -7802 assert!(t.contains(&PathId(0))); -7803 assert!(t.contains(&PathId(1))); -7804 assert!(t.contains(&PathId(2))); -7805 assert!(t.contains(&PathId(3))); -7806 assert_eq!(t.max(), Some(PathId(3))); -7807 } -7808} \ No newline at end of file +7724 } +7725 } +7726} +7727 +7728/// Compute the negotiated idle timeout based on local and remote max_idle_timeout transport parameters. +7729/// +7730/// According to the definition of max_idle_timeout, a value of `0` means the timeout is disabled; see <https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.4.1.> +7731/// +7732/// According to the negotiation procedure, either the minimum of the timeouts or one specified is used as the negotiated value; see <https://www.rfc-editor.org/rfc/rfc9000#section-10.1-2.> +7733/// +7734/// Returns the negotiated idle timeout as a `Duration`, or `None` when both endpoints have opted out of idle timeout. +7735fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> { +7736 match (x, y) { +7737 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None, +7738 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)), +7739 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)), +7740 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)), +7741 } +7742} +7743 +7744#[cfg(test)] +7745mod tests { +7746 use super::*; +7747 +7748 #[test] +7749 fn negotiate_max_idle_timeout_commutative() { +7750 let test_params = [ +7751 (None, None, None), +7752 (None, Some(VarInt(0)), None), +7753 (None, Some(VarInt(2)), Some(Duration::from_millis(2))), +7754 (Some(VarInt(0)), Some(VarInt(0)), None), +7755 ( +7756 Some(VarInt(2)), +7757 Some(VarInt(0)), +7758 Some(Duration::from_millis(2)), +7759 ), +7760 ( +7761 Some(VarInt(1)), +7762 Some(VarInt(4)), +7763 Some(Duration::from_millis(1)), +7764 ), +7765 ]; +7766 +7767 for (left, right, result) in test_params { +7768 assert_eq!(negotiate_max_idle_timeout(left, right), result); +7769 assert_eq!(negotiate_max_idle_timeout(right, left), result); +7770 } +7771 } +7772 +7773 #[test] +7774 fn abandoned_paths() { +7775 let mut t = AbandonedPaths::default(); +7776 +7777 t.insert(PathId(0)); +7778 t.insert(PathId(1)); +7779 assert_eq!(t.len(), 2); +7780 assert_eq!(t.0.range_count(), 1); // 2 elements compacted into one range +7781 assert!(t.contains(&PathId(0))); +7782 assert!(t.contains(&PathId(1))); +7783 assert!(!t.contains(&PathId(2))); +7784 assert!(!t.contains(&PathId(3))); +7785 assert_eq!(t.max(), Some(PathId(1))); +7786 +7787 t.insert(PathId(3)); +7788 assert_eq!(t.len(), 3); +7789 assert_eq!(t.0.range_count(), 2); // 3 elements compacted into 2 ranges +7790 assert!(t.contains(&PathId(0))); +7791 assert!(t.contains(&PathId(1))); +7792 assert!(!t.contains(&PathId(2))); +7793 assert!(t.contains(&PathId(3))); +7794 assert_eq!(t.max(), Some(PathId(3))); +7795 +7796 t.insert(PathId(2)); +7797 assert_eq!(t.len(), 4); +7798 assert_eq!(t.0.range_count(), 1); // 4 elements compacted into 1 range +7799 assert!(t.contains(&PathId(0))); +7800 assert!(t.contains(&PathId(1))); +7801 assert!(t.contains(&PathId(2))); +7802 assert!(t.contains(&PathId(3))); +7803 assert_eq!(t.max(), Some(PathId(3))); +7804 } +7805} \ No newline at end of file diff --git a/pr/720/docs/src/noq_proto/connection/paths.rs.html b/pr/720/docs/src/noq_proto/connection/paths.rs.html index 111e2c7af..8ff0f27b4 100644 --- a/pr/720/docs/src/noq_proto/connection/paths.rs.html +++ b/pr/720/docs/src/noq_proto/connection/paths.rs.html @@ -761,7 +761,7 @@ 761} 762 763impl RttEstimator { -764 pub(super) fn new(initial_rtt: Duration) -> Self { +764 pub(crate) fn new(initial_rtt: Duration) -> Self { 765 Self { 766 latest: initial_rtt, 767 smoothed: None, diff --git a/pr/720/docs/src/noq_proto/connection/spaces.rs.html b/pr/720/docs/src/noq_proto/connection/spaces.rs.html index f0b4c6064..0367de338 100644 --- a/pr/720/docs/src/noq_proto/connection/spaces.rs.html +++ b/pr/720/docs/src/noq_proto/connection/spaces.rs.html @@ -897,739 +897,738 @@ 897 next: u64, 898} 899 -900/// Inner bitfield type. -901/// -902/// Because QUIC never reuses packet numbers, this only needs to be large enough to deal with -903/// packets that are reordered but still delivered in a timely manner. -904type Window = u128; -905 -906/// Number of packets tracked by `Dedup`. -907const WINDOW_SIZE: u64 = 1 + mem::size_of::<Window>() as u64 * 8; -908 -909impl Dedup { -910 /// Construct an empty window positioned at the start. -911 #[cfg(test)] -912 pub(super) fn new() -> Self { -913 Self { window: 0, next: 0 } -914 } -915 -916 /// Highest packet number authenticated. -917 fn highest(&self) -> u64 { -918 self.next - 1 -919 } -920 -921 /// Record a newly authenticated packet number. -922 /// -923 /// Returns whether the packet might be a duplicate. -924 pub(super) fn insert(&mut self, packet: u64) -> bool { -925 if let Some(diff) = packet.checked_sub(self.next) { -926 // Right of window -927 self.window = ((self.window << 1) | 1) -928 .checked_shl(cmp::min(diff, u64::from(u32::MAX)) as u32) -929 .unwrap_or(0); -930 self.next = packet + 1; -931 false -932 } else if self.highest() - packet < WINDOW_SIZE { -933 // Within window -934 if let Some(bit) = (self.highest() - packet).checked_sub(1) { -935 // < highest -936 let mask = 1 << bit; -937 let duplicate = self.window & mask != 0; -938 self.window |= mask; -939 duplicate -940 } else { -941 // == highest -942 true -943 } -944 } else { -945 // Left of window -946 true -947 } -948 } -949 -950 /// Returns the packet number of the smallest packet missing between the provided interval -951 /// -952 /// If there are no missing packets, returns `None` -953 fn smallest_missing_in_interval(&self, lower_bound: u64, upper_bound: u64) -> Option<u64> { -954 debug_assert!(lower_bound <= upper_bound); -955 debug_assert!(upper_bound <= self.highest()); -956 const BITFIELD_SIZE: u64 = (mem::size_of::<Window>() * 8) as u64; -957 -958 // Since we already know the packets at the boundaries have been received, we only need to -959 // check those in between them (this removes the necessity of extra logic to deal with the -960 // highest packet, which is stored outside the bitfield) -961 let lower_bound = lower_bound + 1; -962 let upper_bound = upper_bound.saturating_sub(1); +900impl Dedup { +901 /// Construct an empty window positioned at the start. +902 #[cfg(test)] +903 pub(super) fn new() -> Self { +904 Self { window: 0, next: 0 } +905 } +906 +907 /// Highest packet number authenticated. +908 fn highest(&self) -> u64 { +909 self.next - 1 +910 } +911 +912 /// Record a newly authenticated packet number. +913 /// +914 /// Returns whether the packet might be a duplicate. +915 pub(super) fn insert(&mut self, packet: u64) -> bool { +916 if let Some(diff) = packet.checked_sub(self.next) { +917 // Right of window +918 self.window = ((self.window << 1) | 1) +919 .checked_shl(cmp::min(diff, u64::from(u32::MAX)) as u32) +920 .unwrap_or(0); +921 self.next = packet + 1; +922 false +923 } else if self.highest() - packet < WINDOW_SIZE { +924 // Within window +925 if let Some(bit) = (self.highest() - packet).checked_sub(1) { +926 // < highest +927 let mask = 1 << bit; +928 let duplicate = self.window & mask != 0; +929 self.window |= mask; +930 duplicate +931 } else { +932 // == highest +933 true +934 } +935 } else { +936 // Left of window +937 true +938 } +939 } +940 +941 /// Returns the packet number of the smallest packet missing between the provided interval +942 /// +943 /// If there are no missing packets, returns `None` +944 fn smallest_missing_in_interval(&self, lower_bound: u64, upper_bound: u64) -> Option<u64> { +945 debug_assert!(lower_bound <= upper_bound); +946 debug_assert!(upper_bound <= self.highest()); +947 const BITFIELD_SIZE: u64 = Window::BITS as u64; +948 +949 // Since we already know the packets at the boundaries have been received, we only need to +950 // check those in between them (this removes the necessity of extra logic to deal with the +951 // highest packet, which is stored outside the bitfield) +952 let lower_bound = lower_bound + 1; +953 let upper_bound = upper_bound.saturating_sub(1); +954 +955 // Note: the offsets are counted from the right +956 // The highest packet is not included in the bitfield, so we subtract 1 to account for that +957 let start_offset = (self.highest() - upper_bound).max(1) - 1; +958 if start_offset >= BITFIELD_SIZE { +959 // The start offset is outside of the window. All packets outside of the window are +960 // considered to be received. +961 return None; +962 } 963 -964 // Note: the offsets are counted from the right -965 // The highest packet is not included in the bitfield, so we subtract 1 to account for that -966 let start_offset = (self.highest() - upper_bound).max(1) - 1; -967 if start_offset >= BITFIELD_SIZE { -968 // The start offset is outside of the window. All packets outside of the window are -969 // considered to be received. -970 return None; -971 } -972 -973 let end_offset_exclusive = self.highest().saturating_sub(lower_bound); +964 let end_offset_exclusive = self.highest().saturating_sub(lower_bound); +965 +966 // The range is clamped at the edge of the window, because any earlier packets are +967 // considered to be received +968 let range_len = end_offset_exclusive +969 .saturating_sub(start_offset) +970 .min(BITFIELD_SIZE); +971 if range_len == 0 { +972 return None; +973 } 974 -975 // The range is clamped at the edge of the window, because any earlier packets are -976 // considered to be received -977 let range_len = end_offset_exclusive -978 .saturating_sub(start_offset) -979 .min(BITFIELD_SIZE); -980 if range_len == 0 { -981 return None; -982 } +975 // Ensure the shift is within bounds (we already know start_offset < BITFIELD_SIZE, +976 // because of the early return) +977 let mask = if range_len == BITFIELD_SIZE { +978 u128::MAX +979 } else { +980 ((1u128 << range_len) - 1) << start_offset +981 }; +982 let gaps = !self.window & mask; 983 -984 // Ensure the shift is within bounds (we already know start_offset < BITFIELD_SIZE, -985 // because of the early return) -986 let mask = if range_len == BITFIELD_SIZE { -987 u128::MAX -988 } else { -989 ((1u128 << range_len) - 1) << start_offset -990 }; -991 let gaps = !self.window & mask; -992 -993 let smallest_missing_offset = 128 - gaps.leading_zeros() as u64; -994 let smallest_missing_packet = self.highest() - smallest_missing_offset; -995 -996 if smallest_missing_packet <= upper_bound { -997 Some(smallest_missing_packet) -998 } else { -999 None -1000 } -1001 } +984 let smallest_missing_offset = 128 - gaps.leading_zeros() as u64; +985 let smallest_missing_packet = self.highest() - smallest_missing_offset; +986 +987 if smallest_missing_packet <= upper_bound { +988 Some(smallest_missing_packet) +989 } else { +990 None +991 } +992 } +993 +994 /// Returns true if there are any missing packets between the provided interval +995 /// +996 /// The provided packet numbers must have been received before calling this function +997 fn missing_in_interval(&self, lower_bound: u64, upper_bound: u64) -> bool { +998 self.smallest_missing_in_interval(lower_bound, upper_bound) +999 .is_some() +1000 } +1001} 1002 -1003 /// Returns true if there are any missing packets between the provided interval -1004 /// -1005 /// The provided packet numbers must have been received before calling this function -1006 fn missing_in_interval(&self, lower_bound: u64, upper_bound: u64) -> bool { -1007 self.smallest_missing_in_interval(lower_bound, upper_bound) -1008 .is_some() -1009 } -1010} -1011 -1012/// Indicates which data is available for sending. -1013/// -1014/// This applies to a particular space ID that was queried and all refers to on-path data. -1015#[derive(Clone, Copy, PartialEq, Eq, Debug)] -1016pub(super) struct SendableFrames { -1017 /// Whether there are ACK frames to send, these are not ack-eliciting. -1018 pub(super) acks: bool, -1019 /// Whether there is a CONNECTION_CLOSE to send, this is not ack-eliciting. -1020 pub(super) close: bool, -1021 /// Whether there are any frames that must be sent on this specific space. -1022 /// -1023 /// A space here in the sense of a QUIC Multipath packet number space: `Initial`, -1024 /// `Handshake` and all `Data(PathId)` spaces. -1025 /// -1026 /// These are ack-eliciting. Some frames are scheduled per path, e.g. PING, -1027 /// IMMEDIATE_ACK, PATH_CHALLENGE or PATH_RESPONSE. -1028 pub(super) space_specific: bool, -1029 /// Whether there are any other frames to send, these are ack-eliciting. -1030 pub(super) other: bool, -1031} -1032 -1033impl SendableFrames { -1034 /// Returns that no data is available for sending -1035 pub(super) fn empty() -> Self { -1036 Self { -1037 acks: false, -1038 close: false, -1039 space_specific: false, -1040 other: false, -1041 } -1042 } -1043 -1044 /// Whether an ack-eliciting packet will be sent. -1045 pub(super) fn is_ack_eliciting(&self) -> bool { -1046 let Self { -1047 acks: _, -1048 close, -1049 space_specific, -1050 other, -1051 } = *self; -1052 if close { -1053 // No ack-eliciting frames are included with a CONNECTION_CLOSE, only acks. -1054 return false; -1055 } -1056 space_specific || other -1057 } -1058 -1059 /// Whether no data is sendable. -1060 pub(super) fn is_empty(&self) -> bool { -1061 let Self { -1062 acks, -1063 close, -1064 space_specific, -1065 other, -1066 } = *self; -1067 !acks && !close && !space_specific && !other -1068 } -1069} -1070 -1071impl ::std::ops::BitOrAssign for SendableFrames { -1072 fn bitor_assign(&mut self, rhs: Self) { -1073 let Self { -1074 acks, -1075 close, -1076 space_specific, -1077 other, -1078 } = rhs; -1079 -1080 self.acks |= acks; -1081 self.close |= close; -1082 self.space_specific |= space_specific; -1083 self.other |= other; -1084 } -1085} -1086 -1087#[derive(Debug)] -1088pub(super) struct PendingAcks { -1089 /// Whether we should send an ACK immediately, even if that means sending an ACK-only packet -1090 /// -1091 /// When `immediate_ack_required` is false, the normal behavior is to send ACK frames only when -1092 /// there is other data to send, or when the `MaxAckDelay` timer expires. -1093 immediate_ack_required: bool, -1094 /// The number of ack-eliciting packets received since the last ACK frame was sent -1095 /// -1096 /// Once the count _exceeds_ `ack_eliciting_threshold`, an immediate ACK is required -1097 ack_eliciting_since_last_ack_sent: u64, -1098 non_ack_eliciting_since_last_ack_sent: u64, -1099 ack_eliciting_threshold: u64, -1100 /// The reordering threshold, controlling how we respond to out-of-order ack-eliciting packets -1101 /// -1102 /// Different values enable different behavior: -1103 /// -1104 /// * `0`: no special action is taken -1105 /// * `1`: an ACK is immediately sent if it is out-of-order according to RFC 9000 -1106 /// * `>1`: an ACK is immediately sent if it is out-of-order according to the ACK frequency draft -1107 reordering_threshold: u64, -1108 /// The earliest ack-eliciting packet since the last ACK was sent, used to calculate the moment -1109 /// upon which `max_ack_delay` elapses -1110 earliest_ack_eliciting_since_last_ack_sent: Option<Instant>, -1111 /// Packet number ranges for which to still send acknowledgements. -1112 /// -1113 /// These are packet number ranges of ack-eliciting packets the peer has sent and which -1114 /// need to be acknowledged. Packet numbers are only removed from here once the peer has -1115 /// acknowledged the ACKs for them. -1116 ranges: ArrayRangeSet, -1117 /// The largest packet number received and the time it was received -1118 /// -1119 /// Used to calculate ACK delay in [`PendingAcks::ack_delay`]. -1120 largest_packet: Option<(u64, Instant)>, -1121 /// The ack-eliciting packet we have received with the largest packet number -1122 largest_ack_eliciting_packet: Option<u64>, -1123 /// The largest acknowledged packet number sent in an ACK frame -1124 largest_acked: Option<u64>, -1125} -1126 -1127impl PendingAcks { -1128 fn new() -> Self { -1129 Self { -1130 immediate_ack_required: false, -1131 ack_eliciting_since_last_ack_sent: 0, -1132 non_ack_eliciting_since_last_ack_sent: 0, -1133 ack_eliciting_threshold: 1, -1134 reordering_threshold: 1, -1135 earliest_ack_eliciting_since_last_ack_sent: None, -1136 ranges: Default::default(), -1137 largest_packet: Default::default(), -1138 largest_ack_eliciting_packet: Default::default(), -1139 largest_acked: Default::default(), -1140 } -1141 } -1142 -1143 pub(super) fn set_ack_frequency_params(&mut self, frame: &frame::AckFrequency) { -1144 self.ack_eliciting_threshold = frame.ack_eliciting_threshold.into_inner(); -1145 self.reordering_threshold = frame.reordering_threshold.into_inner(); -1146 } -1147 -1148 pub(super) fn set_immediate_ack_required(&mut self) { -1149 self.immediate_ack_required = true; -1150 } -1151 -1152 pub(super) fn on_max_ack_delay_timeout(&mut self) { -1153 self.immediate_ack_required = self.ack_eliciting_since_last_ack_sent > 0; -1154 } -1155 -1156 pub(super) fn max_ack_delay_timeout(&self, max_ack_delay: Duration) -> Option<Instant> { -1157 self.earliest_ack_eliciting_since_last_ack_sent -1158 .map(|earliest_unacked| earliest_unacked + max_ack_delay) -1159 } -1160 -1161 /// Whether any ACK frames SHOULD be sent -1162 /// -1163 /// This is used in the top-level [`Connection::space_can_send`], so determines if a -1164 /// packet will be built. It is often possible to construct new ACK ranges to send -1165 /// before this returns `true`. This results in more ACK frames being sent, and -1166 /// processing those at the receiver costs CPU for very little improvements. -1167 /// -1168 /// [`Connection::space_can_send`]: super::Connection::space_can_send -1169 pub(super) fn can_send(&self) -> bool { -1170 self.immediate_ack_required && !self.ranges.is_empty() -1171 } -1172 -1173 /// Returns the delay since the packet with the largest packet number was received -1174 pub(super) fn ack_delay(&self, now: Instant) -> Duration { -1175 self.largest_packet -1176 .map_or_else(Duration::default, |(_, received)| now - received) -1177 } -1178 -1179 /// Handle receipt of a new packet -1180 /// -1181 /// Returns true if the max ack delay timer should be armed -1182 pub(super) fn packet_received( -1183 &mut self, -1184 now: Instant, -1185 packet_number: u64, -1186 ack_eliciting: bool, -1187 dedup: &Dedup, -1188 ) -> bool { -1189 if !ack_eliciting { -1190 self.non_ack_eliciting_since_last_ack_sent += 1; -1191 return false; -1192 } -1193 -1194 let prev_largest_ack_eliciting = self.largest_ack_eliciting_packet.unwrap_or(0); -1195 -1196 // Track largest ack-eliciting packet -1197 self.largest_ack_eliciting_packet = self -1198 .largest_ack_eliciting_packet -1199 .map(|pn| pn.max(packet_number)) -1200 .or(Some(packet_number)); -1201 -1202 // Handle ack_eliciting_threshold -1203 self.ack_eliciting_since_last_ack_sent += 1; -1204 self.immediate_ack_required |= -1205 self.ack_eliciting_since_last_ack_sent > self.ack_eliciting_threshold; -1206 -1207 // Handle out-of-order packets -1208 self.immediate_ack_required |= -1209 self.is_out_of_order(packet_number, prev_largest_ack_eliciting, dedup); -1210 -1211 // Arm max_ack_delay timer if necessary -1212 if self.earliest_ack_eliciting_since_last_ack_sent.is_none() && !self.can_send() { -1213 self.earliest_ack_eliciting_since_last_ack_sent = Some(now); -1214 return true; -1215 } -1216 -1217 false -1218 } -1219 -1220 fn is_out_of_order( -1221 &self, -1222 packet_number: u64, -1223 prev_largest_ack_eliciting: u64, -1224 dedup: &Dedup, -1225 ) -> bool { -1226 match self.reordering_threshold { -1227 0 => false, -1228 1 => { -1229 // From https://www.rfc-editor.org/rfc/rfc9000#section-13.2.1-7 -1230 packet_number < prev_largest_ack_eliciting -1231 || dedup.missing_in_interval(prev_largest_ack_eliciting, packet_number) -1232 } -1233 _ => { -1234 // From acknowledgement frequency draft, section 6.1: send an ACK immediately if -1235 // doing so would cause the sender to detect a new packet loss -1236 let Some((largest_acked, largest_unacked)) = -1237 self.largest_acked.zip(self.largest_ack_eliciting_packet) -1238 else { -1239 return false; -1240 }; -1241 if self.reordering_threshold > largest_acked { -1242 return false; -1243 } -1244 // The largest packet number that could be declared lost without a new ACK being -1245 // sent -1246 let largest_reported = largest_acked - self.reordering_threshold + 1; -1247 let Some(smallest_missing_unreported) = -1248 dedup.smallest_missing_in_interval(largest_reported, largest_unacked) -1249 else { -1250 return false; -1251 }; -1252 largest_unacked - smallest_missing_unreported >= self.reordering_threshold -1253 } -1254 } -1255 } -1256 -1257 /// Should be called whenever ACKs have been sent -1258 /// -1259 /// This will suppress sending further ACKs until additional ACK eliciting frames arrive -1260 pub(super) fn acks_sent(&mut self) { -1261 // It is possible (though unlikely) that the ACKs we just sent do not cover all the -1262 // ACK-eliciting packets we have received (e.g. if there is not enough room in the packet to -1263 // fit all the ranges). To keep things simple, however, we assume they do. If there are -1264 // indeed some ACKs that weren't covered, the packets might be ACKed later anyway, because -1265 // they are still contained in `self.ranges`. If we somehow fail to send the ACKs at a later -1266 // moment, the peer will assume the packets got lost and will retransmit their frames in a -1267 // new packet, which is suboptimal, because we already received them. Our assumption here is -1268 // that simplicity results in code that is more performant, even in the presence of -1269 // occasional redundant retransmits. -1270 self.immediate_ack_required = false; -1271 self.ack_eliciting_since_last_ack_sent = 0; -1272 self.non_ack_eliciting_since_last_ack_sent = 0; -1273 self.earliest_ack_eliciting_since_last_ack_sent = None; -1274 self.largest_acked = self.largest_ack_eliciting_packet; -1275 } -1276 -1277 /// Insert one packet that needs to be acknowledged -1278 pub(super) fn insert_one(&mut self, packet: u64, now: Instant) { -1279 self.ranges.insert_one(packet); -1280 -1281 if self.largest_packet.is_none_or(|(pn, _)| packet > pn) { -1282 self.largest_packet = Some((packet, now)); -1283 } -1284 -1285 if self.ranges.range_count() > MAX_ACK_BLOCKS { -1286 self.ranges.pop_min(); -1287 } -1288 } -1289 -1290 /// Remove ACKs of packets numbered at or below `max` from the set of pending ACKs -1291 pub(super) fn subtract_below(&mut self, max: u64) { -1292 self.ranges.remove(0..(max + 1)); -1293 } -1294 -1295 /// Returns the set of currently pending ACK ranges -1296 pub(super) fn ranges(&self) -> &ArrayRangeSet { -1297 &self.ranges -1298 } -1299 -1300 /// Queue an ACK if a significant number of non-ACK-eliciting packets have not yet been -1301 /// acknowledged -1302 /// -1303 /// Should be called immediately before a non-probing packet is composed, when we've already -1304 /// committed to sending a packet regardless. -1305 pub(super) fn maybe_ack_non_eliciting(&mut self) { -1306 // If we're going to send a packet anyway, and we've received a significant number of -1307 // non-ACK-eliciting packets, then include an ACK to help the peer perform timely loss -1308 // detection even if they're not sending any ACK-eliciting packets themselves. Exact -1309 // threshold chosen somewhat arbitrarily. -1310 const LAZY_ACK_THRESHOLD: u64 = 10; -1311 if self.non_ack_eliciting_since_last_ack_sent > LAZY_ACK_THRESHOLD { -1312 self.immediate_ack_required = true; -1313 } -1314 } -1315} -1316 -1317/// Helper for mitigating [optimistic ACK attacks] -1318/// -1319/// A malicious peer could prompt the local application to begin a large data transfer, and then -1320/// send ACKs without first waiting for data to be received. This could defeat congestion control, -1321/// allowing the connection to consume disproportionate resources. We therefore occasionally skip -1322/// packet numbers, and classify any ACK referencing a skipped packet number as a transport error. -1323/// -1324/// Skipped packet numbers occur only in the application data space (where costly transfers might -1325/// take place) and are distributed exponentially to reflect the reduced likelihood and impact of -1326/// bad behavior from a peer that has been well-behaved for an extended period. -1327/// -1328/// ACKs for packet numbers that have not yet been allocated are also a transport error, but an -1329/// attacker with knowledge of the congestion control algorithm in use could time falsified ACKs to -1330/// arrive after the packets they reference are sent. -1331/// -1332/// [optimistic ACK attacks]: https://www.rfc-editor.org/rfc/rfc9000.html#name-optimistic-ack-attack -1333pub(super) struct PacketNumberFilter { -1334 /// Next outgoing packet number to skip -1335 next_skipped_packet_number: u64, -1336 /// Most recently skipped packet number -1337 prev_skipped_packet_number: Option<u64>, -1338 /// Next packet number to skip is randomly selected from 2^n..2^n+1 -1339 exponent: u32, -1340} -1341 -1342impl PacketNumberFilter { -1343 pub(super) fn new(rng: &mut (impl CryptoRng + ?Sized)) -> Self { -1344 // First skipped PN is in 0..64 -1345 let exponent = 6; -1346 Self { -1347 next_skipped_packet_number: rng.random_range(0..2u64.saturating_pow(exponent)), -1348 prev_skipped_packet_number: None, -1349 exponent, -1350 } -1351 } -1352 -1353 #[cfg(test)] -1354 pub(super) fn disabled() -> Self { -1355 Self { -1356 next_skipped_packet_number: u64::MAX, -1357 prev_skipped_packet_number: None, -1358 exponent: u32::MAX, -1359 } -1360 } -1361 -1362 /// Whether to use the provided packet number (false) or to skip it (true) -1363 pub(super) fn skip_pn(&mut self, n: u64, rng: &mut (impl CryptoRng + ?Sized)) -> bool { -1364 if n != self.next_skipped_packet_number { -1365 return false; -1366 } -1367 -1368 trace!("skipping pn {n}"); -1369 // Skip this packet number, and choose the next one to skip -1370 self.prev_skipped_packet_number = Some(self.next_skipped_packet_number); -1371 let next_exponent = self.exponent.saturating_add(1); -1372 self.next_skipped_packet_number = rng -1373 .random_range(2u64.saturating_pow(self.exponent)..2u64.saturating_pow(next_exponent)); -1374 self.exponent = next_exponent; -1375 true -1376 } -1377} -1378 -1379/// Ensures we can always fit all our ACKs in a single minimum-MTU packet with room to spare -1380const MAX_ACK_BLOCKS: usize = 64; -1381 -1382#[cfg(test)] -1383mod test { -1384 use rand::Rng; -1385 use rand::seq::SliceRandom; -1386 -1387 use crate::token::ResetToken; -1388 use crate::{ConnectionIdGenerator, RandomConnectionIdGenerator}; -1389 -1390 use super::*; -1391 -1392 #[test] -1393 fn sanity() { -1394 let mut dedup = Dedup::new(); -1395 assert!(!dedup.insert(0)); -1396 assert_eq!(dedup.next, 1); -1397 assert_eq!(dedup.window, 0b1); -1398 assert!(dedup.insert(0)); -1399 assert_eq!(dedup.next, 1); -1400 assert_eq!(dedup.window, 0b1); -1401 assert!(!dedup.insert(1)); -1402 assert_eq!(dedup.next, 2); -1403 assert_eq!(dedup.window, 0b11); -1404 assert!(!dedup.insert(2)); -1405 assert_eq!(dedup.next, 3); -1406 assert_eq!(dedup.window, 0b111); -1407 assert!(!dedup.insert(4)); -1408 assert_eq!(dedup.next, 5); -1409 assert_eq!(dedup.window, 0b11110); -1410 assert!(!dedup.insert(7)); -1411 assert_eq!(dedup.next, 8); -1412 assert_eq!(dedup.window, 0b1111_0100); -1413 assert!(dedup.insert(4)); -1414 assert!(!dedup.insert(3)); -1415 assert_eq!(dedup.next, 8); -1416 assert_eq!(dedup.window, 0b1111_1100); -1417 assert!(!dedup.insert(6)); -1418 assert_eq!(dedup.next, 8); -1419 assert_eq!(dedup.window, 0b1111_1101); -1420 assert!(!dedup.insert(5)); -1421 assert_eq!(dedup.next, 8); -1422 assert_eq!(dedup.window, 0b1111_1111); -1423 } -1424 -1425 #[test] -1426 fn happypath() { -1427 let mut dedup = Dedup::new(); -1428 for i in 0..(2 * WINDOW_SIZE) { -1429 assert!(!dedup.insert(i)); -1430 for j in 0..=i { -1431 assert!(dedup.insert(j)); -1432 } -1433 } -1434 } -1435 -1436 #[test] -1437 fn jump() { -1438 let mut dedup = Dedup::new(); -1439 dedup.insert(2 * WINDOW_SIZE); -1440 assert!(dedup.insert(WINDOW_SIZE)); -1441 assert_eq!(dedup.next, 2 * WINDOW_SIZE + 1); -1442 assert_eq!(dedup.window, 0); -1443 assert!(!dedup.insert(WINDOW_SIZE + 1)); -1444 assert_eq!(dedup.next, 2 * WINDOW_SIZE + 1); -1445 assert_eq!(dedup.window, 1 << (WINDOW_SIZE - 2)); -1446 } -1447 -1448 #[test] -1449 fn dedup_has_missing() { -1450 let mut dedup = Dedup::new(); -1451 -1452 dedup.insert(0); -1453 assert!(!dedup.missing_in_interval(0, 0)); -1454 -1455 dedup.insert(1); -1456 assert!(!dedup.missing_in_interval(0, 1)); -1457 -1458 dedup.insert(3); -1459 assert!(dedup.missing_in_interval(1, 3)); -1460 -1461 dedup.insert(4); -1462 assert!(!dedup.missing_in_interval(3, 4)); -1463 assert!(dedup.missing_in_interval(0, 4)); -1464 -1465 dedup.insert(2); -1466 assert!(!dedup.missing_in_interval(0, 4)); -1467 } -1468 -1469 #[test] -1470 fn dedup_outside_of_window_has_missing() { -1471 let mut dedup = Dedup::new(); -1472 -1473 for i in 0..140 { -1474 dedup.insert(i); -1475 } -1476 -1477 // 0 and 4 are outside of the window -1478 assert!(!dedup.missing_in_interval(0, 4)); -1479 dedup.insert(160); -1480 assert!(!dedup.missing_in_interval(0, 4)); -1481 assert!(!dedup.missing_in_interval(0, 140)); -1482 assert!(dedup.missing_in_interval(0, 160)); -1483 } -1484 -1485 #[test] -1486 fn dedup_smallest_missing() { -1487 let mut dedup = Dedup::new(); -1488 -1489 dedup.insert(0); -1490 assert_eq!(dedup.smallest_missing_in_interval(0, 0), None); -1491 -1492 dedup.insert(1); -1493 assert_eq!(dedup.smallest_missing_in_interval(0, 1), None); -1494 -1495 dedup.insert(5); -1496 dedup.insert(7); -1497 assert_eq!(dedup.smallest_missing_in_interval(0, 7), Some(2)); -1498 assert_eq!(dedup.smallest_missing_in_interval(5, 7), Some(6)); -1499 -1500 dedup.insert(2); -1501 assert_eq!(dedup.smallest_missing_in_interval(1, 7), Some(3)); -1502 -1503 dedup.insert(170); -1504 dedup.insert(172); -1505 dedup.insert(300); -1506 assert_eq!(dedup.smallest_missing_in_interval(170, 172), None); -1507 -1508 dedup.insert(500); -1509 assert_eq!(dedup.smallest_missing_in_interval(0, 500), Some(372)); -1510 assert_eq!(dedup.smallest_missing_in_interval(0, 373), Some(372)); -1511 assert_eq!(dedup.smallest_missing_in_interval(0, 372), None); -1512 } -1513 -1514 #[test] -1515 fn pending_acks_first_packet_is_not_considered_reordered() { -1516 let mut acks = PendingAcks::new(); -1517 let mut dedup = Dedup::new(); -1518 dedup.insert(0); -1519 acks.packet_received(Instant::now(), 0, true, &dedup); -1520 assert!(!acks.immediate_ack_required); -1521 } -1522 -1523 #[test] -1524 fn pending_acks_after_immediate_ack_set() { -1525 let mut acks = PendingAcks::new(); -1526 let mut dedup = Dedup::new(); -1527 -1528 // Receive ack-eliciting packet -1529 dedup.insert(0); -1530 let now = Instant::now(); -1531 acks.insert_one(0, now); -1532 acks.packet_received(now, 0, true, &dedup); -1533 -1534 // Sanity check -1535 assert!(!acks.ranges.is_empty()); -1536 assert!(!acks.can_send()); -1537 -1538 // Can send ACK after max_ack_delay exceeded -1539 acks.set_immediate_ack_required(); -1540 assert!(acks.can_send()); -1541 } -1542 -1543 #[test] -1544 fn pending_acks_ack_delay() { -1545 let mut acks = PendingAcks::new(); -1546 let mut dedup = Dedup::new(); -1547 -1548 let t1 = Instant::now(); -1549 let t2 = t1 + Duration::from_millis(2); -1550 let t3 = t2 + Duration::from_millis(5); -1551 assert_eq!(acks.ack_delay(t1), Duration::from_millis(0)); -1552 assert_eq!(acks.ack_delay(t2), Duration::from_millis(0)); -1553 assert_eq!(acks.ack_delay(t3), Duration::from_millis(0)); -1554 -1555 // In-order packet -1556 dedup.insert(0); -1557 acks.insert_one(0, t1); -1558 acks.packet_received(t1, 0, true, &dedup); -1559 assert_eq!(acks.ack_delay(t1), Duration::from_millis(0)); -1560 assert_eq!(acks.ack_delay(t2), Duration::from_millis(2)); -1561 assert_eq!(acks.ack_delay(t3), Duration::from_millis(7)); -1562 -1563 // Out of order (higher than expected) -1564 dedup.insert(3); -1565 acks.insert_one(3, t2); -1566 acks.packet_received(t2, 3, true, &dedup); -1567 assert_eq!(acks.ack_delay(t2), Duration::from_millis(0)); -1568 assert_eq!(acks.ack_delay(t3), Duration::from_millis(5)); -1569 -1570 // Out of order (lower than expected, so previous instant is kept) -1571 dedup.insert(2); -1572 acks.insert_one(2, t3); -1573 acks.packet_received(t3, 2, true, &dedup); -1574 assert_eq!(acks.ack_delay(t3), Duration::from_millis(5)); -1575 } -1576 -1577 #[test] -1578 fn sent_packet_size() { -1579 // The tracking state of sent packets should be minimal, and not grow -1580 // over time. -1581 assert!(std::mem::size_of::<SentPacket>() <= 128); -1582 } -1583 -1584 #[test] -1585 fn pending_new_cids() { -1586 #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] -1587 use aws_lc_rs::hmac; -1588 #[cfg(feature = "ring")] -1589 use ring::hmac; -1590 -1591 let mut cid_generator = RandomConnectionIdGenerator::new(8); -1592 let mut reset_key = [0; 64]; -1593 rand::rng().fill_bytes(&mut reset_key); -1594 let hmac = hmac::Key::new(hmac::HMAC_SHA256, &reset_key); -1595 -1596 let cid_a = cid_generator.generate_cid(); -1597 let a = IssuedCid { -1598 path_id: PathId::ZERO, -1599 sequence: 1, -1600 id: cid_a, -1601 reset_token: ResetToken::new(&hmac, cid_a), -1602 }; -1603 let cid_b = cid_generator.generate_cid(); -1604 let b = IssuedCid { -1605 path_id: PathId::ZERO, -1606 sequence: 2, -1607 id: cid_b, -1608 reset_token: ResetToken::new(&hmac, cid_b), -1609 }; -1610 let cid_c = cid_generator.generate_cid(); -1611 let c = IssuedCid { -1612 path_id: PathId(1), -1613 sequence: 1, -1614 id: cid_c, -1615 reset_token: ResetToken::new(&hmac, cid_c), -1616 }; -1617 -1618 let mut pending_cids = PendingNewCids::default(); -1619 -1620 for _ in 0..9 { -1621 // Push CIDs in a random order -1622 let mut input = vec![a, b, c]; -1623 input.shuffle(&mut rand::rng()); -1624 for cid in input { -1625 pending_cids.push(cid); -1626 } -1627 -1628 // Pop order is always the same -1629 assert_eq!(pending_cids.pop().map(|i| i.id), Some(a.id)); -1630 assert_eq!(pending_cids.pop().map(|i| i.id), Some(b.id)); -1631 assert_eq!(pending_cids.pop().map(|i| i.id), Some(c.id)); -1632 assert!(pending_cids.pop().is_none()); -1633 } -1634 } -1635} \ No newline at end of file +1003/// Inner bitfield type. +1004/// +1005/// Because QUIC never reuses packet numbers, this only needs to be large enough to deal with +1006/// packets that are reordered but still delivered in a timely manner. +1007type Window = u128; +1008 +1009/// Number of packets tracked by `Dedup`. +1010const WINDOW_SIZE: u64 = 1 + mem::size_of::<Window>() as u64 * 8; +1011/// Indicates which data is available for sending +1012/// +1013/// This applies to a particular space ID that was queried and all refers to on-path data. +1014#[derive(Clone, Copy, PartialEq, Eq, Debug)] +1015pub(super) struct SendableFrames { +1016 /// Whether there are ACK frames to send, these are not ack-eliciting. +1017 pub(super) acks: bool, +1018 /// Whether there is a CONNECTION_CLOSE to send, this is not ack-eliciting. +1019 pub(super) close: bool, +1020 /// Whether there are any frames that must be sent on this specific space. +1021 /// +1022 /// A space here in the sense of a QUIC Multipath packet number space: `Initial`, +1023 /// `Handshake` and all `Data(PathId)` spaces. +1024 /// +1025 /// These are ack-eliciting. Some frames are scheduled per path, e.g. PING, +1026 /// IMMEDIATE_ACK, PATH_CHALLENGE or PATH_RESPONSE. +1027 pub(super) space_specific: bool, +1028 /// Whether there are any other frames to send, these are ack-eliciting. +1029 pub(super) other: bool, +1030} +1031 +1032impl SendableFrames { +1033 /// Returns that no data is available for sending +1034 pub(super) fn empty() -> Self { +1035 Self { +1036 acks: false, +1037 close: false, +1038 space_specific: false, +1039 other: false, +1040 } +1041 } +1042 +1043 /// Whether an ack-eliciting packet will be sent. +1044 pub(super) fn is_ack_eliciting(&self) -> bool { +1045 let Self { +1046 acks: _, +1047 close, +1048 space_specific, +1049 other, +1050 } = *self; +1051 if close { +1052 // No ack-eliciting frames are included with a CONNECTION_CLOSE, only acks. +1053 return false; +1054 } +1055 space_specific || other +1056 } +1057 +1058 /// Whether no data is sendable. +1059 pub(super) fn is_empty(&self) -> bool { +1060 let Self { +1061 acks, +1062 close, +1063 space_specific, +1064 other, +1065 } = *self; +1066 !acks && !close && !space_specific && !other +1067 } +1068} +1069 +1070impl ::std::ops::BitOrAssign for SendableFrames { +1071 fn bitor_assign(&mut self, rhs: Self) { +1072 let Self { +1073 acks, +1074 close, +1075 space_specific, +1076 other, +1077 } = rhs; +1078 +1079 self.acks |= acks; +1080 self.close |= close; +1081 self.space_specific |= space_specific; +1082 self.other |= other; +1083 } +1084} +1085 +1086#[derive(Debug)] +1087pub(super) struct PendingAcks { +1088 /// Whether we should send an ACK immediately, even if that means sending an ACK-only packet +1089 /// +1090 /// When `immediate_ack_required` is false, the normal behavior is to send ACK frames only when +1091 /// there is other data to send, or when the `MaxAckDelay` timer expires. +1092 immediate_ack_required: bool, +1093 /// The number of ack-eliciting packets received since the last ACK frame was sent +1094 /// +1095 /// Once the count _exceeds_ `ack_eliciting_threshold`, an immediate ACK is required +1096 ack_eliciting_since_last_ack_sent: u64, +1097 non_ack_eliciting_since_last_ack_sent: u64, +1098 ack_eliciting_threshold: u64, +1099 /// The reordering threshold, controlling how we respond to out-of-order ack-eliciting packets +1100 /// +1101 /// Different values enable different behavior: +1102 /// +1103 /// * `0`: no special action is taken +1104 /// * `1`: an ACK is immediately sent if it is out-of-order according to RFC 9000 +1105 /// * `>1`: an ACK is immediately sent if it is out-of-order according to the ACK frequency draft +1106 reordering_threshold: u64, +1107 /// The earliest ack-eliciting packet since the last ACK was sent, used to calculate the moment +1108 /// upon which `max_ack_delay` elapses +1109 earliest_ack_eliciting_since_last_ack_sent: Option<Instant>, +1110 /// Packet number ranges for which to still send acknowledgements. +1111 /// +1112 /// These are packet number ranges of ack-eliciting packets the peer has sent and which +1113 /// need to be acknowledged. Packet numbers are only removed from here once the peer has +1114 /// acknowledged the ACKs for them. +1115 ranges: ArrayRangeSet, +1116 /// The largest packet number received and the time it was received +1117 /// +1118 /// Used to calculate ACK delay in [`PendingAcks::ack_delay`]. +1119 largest_packet: Option<(u64, Instant)>, +1120 /// The ack-eliciting packet we have received with the largest packet number +1121 largest_ack_eliciting_packet: Option<u64>, +1122 /// The largest acknowledged packet number sent in an ACK frame +1123 largest_acked: Option<u64>, +1124} +1125 +1126impl PendingAcks { +1127 fn new() -> Self { +1128 Self { +1129 immediate_ack_required: false, +1130 ack_eliciting_since_last_ack_sent: 0, +1131 non_ack_eliciting_since_last_ack_sent: 0, +1132 ack_eliciting_threshold: 1, +1133 reordering_threshold: 1, +1134 earliest_ack_eliciting_since_last_ack_sent: None, +1135 ranges: Default::default(), +1136 largest_packet: Default::default(), +1137 largest_ack_eliciting_packet: Default::default(), +1138 largest_acked: Default::default(), +1139 } +1140 } +1141 +1142 pub(super) fn set_ack_frequency_params(&mut self, frame: &frame::AckFrequency) { +1143 self.ack_eliciting_threshold = frame.ack_eliciting_threshold.into_inner(); +1144 self.reordering_threshold = frame.reordering_threshold.into_inner(); +1145 } +1146 +1147 pub(super) fn set_immediate_ack_required(&mut self) { +1148 self.immediate_ack_required = true; +1149 } +1150 +1151 pub(super) fn on_max_ack_delay_timeout(&mut self) { +1152 self.immediate_ack_required = self.ack_eliciting_since_last_ack_sent > 0; +1153 } +1154 +1155 pub(super) fn max_ack_delay_timeout(&self, max_ack_delay: Duration) -> Option<Instant> { +1156 self.earliest_ack_eliciting_since_last_ack_sent +1157 .map(|earliest_unacked| earliest_unacked + max_ack_delay) +1158 } +1159 +1160 /// Whether any ACK frames SHOULD be sent +1161 /// +1162 /// This is used in the top-level [`Connection::space_can_send`], so determines if a +1163 /// packet will be built. It is often possible to construct new ACK ranges to send +1164 /// before this returns `true`. This results in more ACK frames being sent, and +1165 /// processing those at the receiver costs CPU for very little improvements. +1166 /// +1167 /// [`Connection::space_can_send`]: super::Connection::space_can_send +1168 pub(super) fn can_send(&self) -> bool { +1169 self.immediate_ack_required && !self.ranges.is_empty() +1170 } +1171 +1172 /// Returns the delay since the packet with the largest packet number was received +1173 pub(super) fn ack_delay(&self, now: Instant) -> Duration { +1174 self.largest_packet +1175 .map_or_else(Duration::default, |(_, received)| now - received) +1176 } +1177 +1178 /// Handle receipt of a new packet +1179 /// +1180 /// Returns true if the max ack delay timer should be armed +1181 pub(super) fn packet_received( +1182 &mut self, +1183 now: Instant, +1184 packet_number: u64, +1185 ack_eliciting: bool, +1186 dedup: &Dedup, +1187 ) -> bool { +1188 if !ack_eliciting { +1189 self.non_ack_eliciting_since_last_ack_sent += 1; +1190 return false; +1191 } +1192 +1193 let prev_largest_ack_eliciting = self.largest_ack_eliciting_packet.unwrap_or(0); +1194 +1195 // Track largest ack-eliciting packet +1196 self.largest_ack_eliciting_packet = self +1197 .largest_ack_eliciting_packet +1198 .map(|pn| pn.max(packet_number)) +1199 .or(Some(packet_number)); +1200 +1201 // Handle ack_eliciting_threshold +1202 self.ack_eliciting_since_last_ack_sent += 1; +1203 self.immediate_ack_required |= +1204 self.ack_eliciting_since_last_ack_sent > self.ack_eliciting_threshold; +1205 +1206 // Handle out-of-order packets +1207 self.immediate_ack_required |= +1208 self.is_out_of_order(packet_number, prev_largest_ack_eliciting, dedup); +1209 +1210 // Arm max_ack_delay timer if necessary +1211 if self.earliest_ack_eliciting_since_last_ack_sent.is_none() && !self.can_send() { +1212 self.earliest_ack_eliciting_since_last_ack_sent = Some(now); +1213 return true; +1214 } +1215 +1216 false +1217 } +1218 +1219 fn is_out_of_order( +1220 &self, +1221 packet_number: u64, +1222 prev_largest_ack_eliciting: u64, +1223 dedup: &Dedup, +1224 ) -> bool { +1225 match self.reordering_threshold { +1226 0 => false, +1227 1 => { +1228 // From https://www.rfc-editor.org/rfc/rfc9000#section-13.2.1-7 +1229 packet_number < prev_largest_ack_eliciting +1230 || dedup.missing_in_interval(prev_largest_ack_eliciting, packet_number) +1231 } +1232 _ => { +1233 // From acknowledgement frequency draft, section 6.1: send an ACK immediately if +1234 // doing so would cause the sender to detect a new packet loss +1235 let Some((largest_acked, largest_unacked)) = +1236 self.largest_acked.zip(self.largest_ack_eliciting_packet) +1237 else { +1238 return false; +1239 }; +1240 if self.reordering_threshold > largest_acked { +1241 return false; +1242 } +1243 // The largest packet number that could be declared lost without a new ACK being +1244 // sent +1245 let largest_reported = largest_acked - self.reordering_threshold + 1; +1246 let Some(smallest_missing_unreported) = +1247 dedup.smallest_missing_in_interval(largest_reported, largest_unacked) +1248 else { +1249 return false; +1250 }; +1251 largest_unacked - smallest_missing_unreported >= self.reordering_threshold +1252 } +1253 } +1254 } +1255 +1256 /// Should be called whenever ACKs have been sent +1257 /// +1258 /// This will suppress sending further ACKs until additional ACK eliciting frames arrive +1259 pub(super) fn acks_sent(&mut self) { +1260 // It is possible (though unlikely) that the ACKs we just sent do not cover all the +1261 // ACK-eliciting packets we have received (e.g. if there is not enough room in the packet to +1262 // fit all the ranges). To keep things simple, however, we assume they do. If there are +1263 // indeed some ACKs that weren't covered, the packets might be ACKed later anyway, because +1264 // they are still contained in `self.ranges`. If we somehow fail to send the ACKs at a later +1265 // moment, the peer will assume the packets got lost and will retransmit their frames in a +1266 // new packet, which is suboptimal, because we already received them. Our assumption here is +1267 // that simplicity results in code that is more performant, even in the presence of +1268 // occasional redundant retransmits. +1269 self.immediate_ack_required = false; +1270 self.ack_eliciting_since_last_ack_sent = 0; +1271 self.non_ack_eliciting_since_last_ack_sent = 0; +1272 self.earliest_ack_eliciting_since_last_ack_sent = None; +1273 self.largest_acked = self.largest_ack_eliciting_packet; +1274 } +1275 +1276 /// Insert one packet that needs to be acknowledged +1277 pub(super) fn insert_one(&mut self, packet: u64, now: Instant) { +1278 self.ranges.insert_one(packet); +1279 +1280 if self.largest_packet.is_none_or(|(pn, _)| packet > pn) { +1281 self.largest_packet = Some((packet, now)); +1282 } +1283 +1284 if self.ranges.range_count() > MAX_ACK_BLOCKS { +1285 self.ranges.pop_min(); +1286 } +1287 } +1288 +1289 /// Remove ACKs of packets numbered at or below `max` from the set of pending ACKs +1290 pub(super) fn subtract_below(&mut self, max: u64) { +1291 self.ranges.remove(0..(max + 1)); +1292 } +1293 +1294 /// Returns the set of currently pending ACK ranges +1295 pub(super) fn ranges(&self) -> &ArrayRangeSet { +1296 &self.ranges +1297 } +1298 +1299 /// Queue an ACK if a significant number of non-ACK-eliciting packets have not yet been +1300 /// acknowledged +1301 /// +1302 /// Should be called immediately before a non-probing packet is composed, when we've already +1303 /// committed to sending a packet regardless. +1304 pub(super) fn maybe_ack_non_eliciting(&mut self) { +1305 // If we're going to send a packet anyway, and we've received a significant number of +1306 // non-ACK-eliciting packets, then include an ACK to help the peer perform timely loss +1307 // detection even if they're not sending any ACK-eliciting packets themselves. Exact +1308 // threshold chosen somewhat arbitrarily. +1309 const LAZY_ACK_THRESHOLD: u64 = 10; +1310 if self.non_ack_eliciting_since_last_ack_sent > LAZY_ACK_THRESHOLD { +1311 self.immediate_ack_required = true; +1312 } +1313 } +1314} +1315 +1316/// Helper for mitigating [optimistic ACK attacks] +1317/// +1318/// A malicious peer could prompt the local application to begin a large data transfer, and then +1319/// send ACKs without first waiting for data to be received. This could defeat congestion control, +1320/// allowing the connection to consume disproportionate resources. We therefore occasionally skip +1321/// packet numbers, and classify any ACK referencing a skipped packet number as a transport error. +1322/// +1323/// Skipped packet numbers occur only in the application data space (where costly transfers might +1324/// take place) and are distributed exponentially to reflect the reduced likelihood and impact of +1325/// bad behavior from a peer that has been well-behaved for an extended period. +1326/// +1327/// ACKs for packet numbers that have not yet been allocated are also a transport error, but an +1328/// attacker with knowledge of the congestion control algorithm in use could time falsified ACKs to +1329/// arrive after the packets they reference are sent. +1330/// +1331/// [optimistic ACK attacks]: https://www.rfc-editor.org/rfc/rfc9000.html#name-optimistic-ack-attack +1332pub(super) struct PacketNumberFilter { +1333 /// Next outgoing packet number to skip +1334 next_skipped_packet_number: u64, +1335 /// Most recently skipped packet number +1336 prev_skipped_packet_number: Option<u64>, +1337 /// Next packet number to skip is randomly selected from 2^n..2^n+1 +1338 exponent: u32, +1339} +1340 +1341impl PacketNumberFilter { +1342 pub(super) fn new(rng: &mut (impl CryptoRng + ?Sized)) -> Self { +1343 // First skipped PN is in 0..64 +1344 let exponent = 6; +1345 Self { +1346 next_skipped_packet_number: rng.random_range(0..2u64.saturating_pow(exponent)), +1347 prev_skipped_packet_number: None, +1348 exponent, +1349 } +1350 } +1351 +1352 #[cfg(test)] +1353 pub(super) fn disabled() -> Self { +1354 Self { +1355 next_skipped_packet_number: u64::MAX, +1356 prev_skipped_packet_number: None, +1357 exponent: u32::MAX, +1358 } +1359 } +1360 +1361 /// Whether to use the provided packet number (false) or to skip it (true) +1362 pub(super) fn skip_pn(&mut self, n: u64, rng: &mut (impl CryptoRng + ?Sized)) -> bool { +1363 if n != self.next_skipped_packet_number { +1364 return false; +1365 } +1366 +1367 trace!("skipping pn {n}"); +1368 // Skip this packet number, and choose the next one to skip +1369 self.prev_skipped_packet_number = Some(self.next_skipped_packet_number); +1370 let next_exponent = self.exponent.saturating_add(1); +1371 self.next_skipped_packet_number = rng +1372 .random_range(2u64.saturating_pow(self.exponent)..2u64.saturating_pow(next_exponent)); +1373 self.exponent = next_exponent; +1374 true +1375 } +1376} +1377 +1378/// Ensures we can always fit all our ACKs in a single minimum-MTU packet with room to spare +1379const MAX_ACK_BLOCKS: usize = 64; +1380 +1381#[cfg(test)] +1382mod test { +1383 use rand::Rng; +1384 use rand::seq::SliceRandom; +1385 +1386 use crate::token::ResetToken; +1387 use crate::{ConnectionIdGenerator, RandomConnectionIdGenerator}; +1388 +1389 use super::*; +1390 +1391 #[test] +1392 fn sanity() { +1393 let mut dedup = Dedup::new(); +1394 assert!(!dedup.insert(0)); +1395 assert_eq!(dedup.next, 1); +1396 assert_eq!(dedup.window, 0b1); +1397 assert!(dedup.insert(0)); +1398 assert_eq!(dedup.next, 1); +1399 assert_eq!(dedup.window, 0b1); +1400 assert!(!dedup.insert(1)); +1401 assert_eq!(dedup.next, 2); +1402 assert_eq!(dedup.window, 0b11); +1403 assert!(!dedup.insert(2)); +1404 assert_eq!(dedup.next, 3); +1405 assert_eq!(dedup.window, 0b111); +1406 assert!(!dedup.insert(4)); +1407 assert_eq!(dedup.next, 5); +1408 assert_eq!(dedup.window, 0b11110); +1409 assert!(!dedup.insert(7)); +1410 assert_eq!(dedup.next, 8); +1411 assert_eq!(dedup.window, 0b1111_0100); +1412 assert!(dedup.insert(4)); +1413 assert!(!dedup.insert(3)); +1414 assert_eq!(dedup.next, 8); +1415 assert_eq!(dedup.window, 0b1111_1100); +1416 assert!(!dedup.insert(6)); +1417 assert_eq!(dedup.next, 8); +1418 assert_eq!(dedup.window, 0b1111_1101); +1419 assert!(!dedup.insert(5)); +1420 assert_eq!(dedup.next, 8); +1421 assert_eq!(dedup.window, 0b1111_1111); +1422 } +1423 +1424 #[test] +1425 fn happypath() { +1426 let mut dedup = Dedup::new(); +1427 for i in 0..(2 * WINDOW_SIZE) { +1428 assert!(!dedup.insert(i)); +1429 for j in 0..=i { +1430 assert!(dedup.insert(j)); +1431 } +1432 } +1433 } +1434 +1435 #[test] +1436 fn jump() { +1437 let mut dedup = Dedup::new(); +1438 dedup.insert(2 * WINDOW_SIZE); +1439 assert!(dedup.insert(WINDOW_SIZE)); +1440 assert_eq!(dedup.next, 2 * WINDOW_SIZE + 1); +1441 assert_eq!(dedup.window, 0); +1442 assert!(!dedup.insert(WINDOW_SIZE + 1)); +1443 assert_eq!(dedup.next, 2 * WINDOW_SIZE + 1); +1444 assert_eq!(dedup.window, 1 << (WINDOW_SIZE - 2)); +1445 } +1446 +1447 #[test] +1448 fn dedup_has_missing() { +1449 let mut dedup = Dedup::new(); +1450 +1451 dedup.insert(0); +1452 assert!(!dedup.missing_in_interval(0, 0)); +1453 +1454 dedup.insert(1); +1455 assert!(!dedup.missing_in_interval(0, 1)); +1456 +1457 dedup.insert(3); +1458 assert!(dedup.missing_in_interval(1, 3)); +1459 +1460 dedup.insert(4); +1461 assert!(!dedup.missing_in_interval(3, 4)); +1462 assert!(dedup.missing_in_interval(0, 4)); +1463 +1464 dedup.insert(2); +1465 assert!(!dedup.missing_in_interval(0, 4)); +1466 } +1467 +1468 #[test] +1469 fn dedup_outside_of_window_has_missing() { +1470 let mut dedup = Dedup::new(); +1471 +1472 for i in 0..140 { +1473 dedup.insert(i); +1474 } +1475 +1476 // 0 and 4 are outside of the window +1477 assert!(!dedup.missing_in_interval(0, 4)); +1478 dedup.insert(160); +1479 assert!(!dedup.missing_in_interval(0, 4)); +1480 assert!(!dedup.missing_in_interval(0, 140)); +1481 assert!(dedup.missing_in_interval(0, 160)); +1482 } +1483 +1484 #[test] +1485 fn dedup_smallest_missing() { +1486 let mut dedup = Dedup::new(); +1487 +1488 dedup.insert(0); +1489 assert_eq!(dedup.smallest_missing_in_interval(0, 0), None); +1490 +1491 dedup.insert(1); +1492 assert_eq!(dedup.smallest_missing_in_interval(0, 1), None); +1493 +1494 dedup.insert(5); +1495 dedup.insert(7); +1496 assert_eq!(dedup.smallest_missing_in_interval(0, 7), Some(2)); +1497 assert_eq!(dedup.smallest_missing_in_interval(5, 7), Some(6)); +1498 +1499 dedup.insert(2); +1500 assert_eq!(dedup.smallest_missing_in_interval(1, 7), Some(3)); +1501 +1502 dedup.insert(170); +1503 dedup.insert(172); +1504 dedup.insert(300); +1505 assert_eq!(dedup.smallest_missing_in_interval(170, 172), None); +1506 +1507 dedup.insert(500); +1508 assert_eq!(dedup.smallest_missing_in_interval(0, 500), Some(372)); +1509 assert_eq!(dedup.smallest_missing_in_interval(0, 373), Some(372)); +1510 assert_eq!(dedup.smallest_missing_in_interval(0, 372), None); +1511 } +1512 +1513 #[test] +1514 fn pending_acks_first_packet_is_not_considered_reordered() { +1515 let mut acks = PendingAcks::new(); +1516 let mut dedup = Dedup::new(); +1517 dedup.insert(0); +1518 acks.packet_received(Instant::now(), 0, true, &dedup); +1519 assert!(!acks.immediate_ack_required); +1520 } +1521 +1522 #[test] +1523 fn pending_acks_after_immediate_ack_set() { +1524 let mut acks = PendingAcks::new(); +1525 let mut dedup = Dedup::new(); +1526 +1527 // Receive ack-eliciting packet +1528 dedup.insert(0); +1529 let now = Instant::now(); +1530 acks.insert_one(0, now); +1531 acks.packet_received(now, 0, true, &dedup); +1532 +1533 // Sanity check +1534 assert!(!acks.ranges.is_empty()); +1535 assert!(!acks.can_send()); +1536 +1537 // Can send ACK after max_ack_delay exceeded +1538 acks.set_immediate_ack_required(); +1539 assert!(acks.can_send()); +1540 } +1541 +1542 #[test] +1543 fn pending_acks_ack_delay() { +1544 let mut acks = PendingAcks::new(); +1545 let mut dedup = Dedup::new(); +1546 +1547 let t1 = Instant::now(); +1548 let t2 = t1 + Duration::from_millis(2); +1549 let t3 = t2 + Duration::from_millis(5); +1550 assert_eq!(acks.ack_delay(t1), Duration::from_millis(0)); +1551 assert_eq!(acks.ack_delay(t2), Duration::from_millis(0)); +1552 assert_eq!(acks.ack_delay(t3), Duration::from_millis(0)); +1553 +1554 // In-order packet +1555 dedup.insert(0); +1556 acks.insert_one(0, t1); +1557 acks.packet_received(t1, 0, true, &dedup); +1558 assert_eq!(acks.ack_delay(t1), Duration::from_millis(0)); +1559 assert_eq!(acks.ack_delay(t2), Duration::from_millis(2)); +1560 assert_eq!(acks.ack_delay(t3), Duration::from_millis(7)); +1561 +1562 // Out of order (higher than expected) +1563 dedup.insert(3); +1564 acks.insert_one(3, t2); +1565 acks.packet_received(t2, 3, true, &dedup); +1566 assert_eq!(acks.ack_delay(t2), Duration::from_millis(0)); +1567 assert_eq!(acks.ack_delay(t3), Duration::from_millis(5)); +1568 +1569 // Out of order (lower than expected, so previous instant is kept) +1570 dedup.insert(2); +1571 acks.insert_one(2, t3); +1572 acks.packet_received(t3, 2, true, &dedup); +1573 assert_eq!(acks.ack_delay(t3), Duration::from_millis(5)); +1574 } +1575 +1576 #[test] +1577 fn sent_packet_size() { +1578 // The tracking state of sent packets should be minimal, and not grow +1579 // over time. +1580 assert!(std::mem::size_of::<SentPacket>() <= 128); +1581 } +1582 +1583 #[test] +1584 fn pending_new_cids() { +1585 #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] +1586 use aws_lc_rs::hmac; +1587 #[cfg(feature = "ring")] +1588 use ring::hmac; +1589 +1590 let mut cid_generator = RandomConnectionIdGenerator::new(8); +1591 let mut reset_key = [0; 64]; +1592 rand::rng().fill_bytes(&mut reset_key); +1593 let hmac = hmac::Key::new(hmac::HMAC_SHA256, &reset_key); +1594 +1595 let cid_a = cid_generator.generate_cid(); +1596 let a = IssuedCid { +1597 path_id: PathId::ZERO, +1598 sequence: 1, +1599 id: cid_a, +1600 reset_token: ResetToken::new(&hmac, cid_a), +1601 }; +1602 let cid_b = cid_generator.generate_cid(); +1603 let b = IssuedCid { +1604 path_id: PathId::ZERO, +1605 sequence: 2, +1606 id: cid_b, +1607 reset_token: ResetToken::new(&hmac, cid_b), +1608 }; +1609 let cid_c = cid_generator.generate_cid(); +1610 let c = IssuedCid { +1611 path_id: PathId(1), +1612 sequence: 1, +1613 id: cid_c, +1614 reset_token: ResetToken::new(&hmac, cid_c), +1615 }; +1616 +1617 let mut pending_cids = PendingNewCids::default(); +1618 +1619 for _ in 0..9 { +1620 // Push CIDs in a random order +1621 let mut input = vec![a, b, c]; +1622 input.shuffle(&mut rand::rng()); +1623 for cid in input { +1624 pending_cids.push(cid); +1625 } +1626 +1627 // Pop order is always the same +1628 assert_eq!(pending_cids.pop().map(|i| i.id), Some(a.id)); +1629 assert_eq!(pending_cids.pop().map(|i| i.id), Some(b.id)); +1630 assert_eq!(pending_cids.pop().map(|i| i.id), Some(c.id)); +1631 assert!(pending_cids.pop().is_none()); +1632 } +1633 } +1634} \ No newline at end of file diff --git a/pr/720/docs/src/noq_proto/connection/stats.rs.html b/pr/720/docs/src/noq_proto/connection/stats.rs.html index 6b4b9c044..f229556a5 100644 --- a/pr/720/docs/src/noq_proto/connection/stats.rs.html +++ b/pr/720/docs/src/noq_proto/connection/stats.rs.html @@ -351,7 +351,7 @@ 351 352/// Helper to make [`PathStats`] infallibly available. 353/// -354/// This helper also helps with borrowing issues compared to having the [`Self::for_path`] +354/// This helper also helps with borrowing issues compared to having the [`Self::get_mut`] 355/// function as a helper directly on [`Connection`]. 356/// 357/// [`Connection`]: super::Connection @@ -360,19 +360,23 @@ 360 361impl PathStatsMap { 362 /// Returns the [`PathStats`] for the path. -363 pub(super) fn for_path(&mut self, path_id: PathId) -> &mut PathStats { +363 pub(super) fn get_mut(&mut self, path_id: PathId) -> &mut PathStats { 364 self.0.entry(path_id).or_default() 365 } 366 -367 /// An iterator over all contained [`PathStats`]. -368 pub(super) fn iter_stats(&self) -> impl Iterator<Item = &PathStats> { -369 self.0.values() -370 } -371 -372 /// Removes the stats for a given path. -373 /// -374 /// Only do this once you are discarding the path. -375 pub(super) fn discard(&mut self, path_id: &PathId) { -376 self.0.remove(path_id); -377 } -378} \ No newline at end of file +367 pub(super) fn get(&self, path_id: PathId) -> Option<PathStats> { +368 self.0.get(&path_id).copied() +369 } +370 +371 /// An iterator over all contained [`PathStats`]. +372 pub(super) fn iter_stats(&self) -> impl Iterator<Item = &PathStats> { +373 self.0.values() +374 } +375 +376 /// Removes the stats for a given path. +377 /// +378 /// Only do this once you are discarding the path. +379 pub(super) fn discard(&mut self, path_id: &PathId) { +380 self.0.remove(path_id); +381 } +382} \ No newline at end of file diff --git a/pr/720/docs/src/noq_proto/packet.rs.html b/pr/720/docs/src/noq_proto/packet.rs.html index 541cd3277..7959426cc 100644 --- a/pr/720/docs/src/noq_proto/packet.rs.html +++ b/pr/720/docs/src/noq_proto/packet.rs.html @@ -632,7 +632,7 @@ 632 633 /// Decode a plain header from given buffer, with given [`ConnectionIdParser`]. 634 pub fn decode( -635 buf: &mut io::Cursor<BytesMut>, +635 buf: &mut io::Cursor<impl AsRef<[u8]>>, 636 cid_parser: &(impl ConnectionIdParser + ?Sized), 637 supported_versions: &[u32], 638 grease_quic_bit: bool, diff --git a/pr/720/docs/src/noq_udp/cmsg/mod.rs.html b/pr/720/docs/src/noq_udp/cmsg/mod.rs.html index 937486b08..db505aab7 100644 --- a/pr/720/docs/src/noq_udp/cmsg/mod.rs.html +++ b/pr/720/docs/src/noq_udp/cmsg/mod.rs.html @@ -154,4 +154,7 @@ 154 fn set(&mut self, level: c_int, ty: c_int, len: usize); 155 156 fn len(&self) -> usize; -157} \ No newline at end of file +157} +158 +159#[cfg(unix)] +160pub(crate) const LEN: usize = 88; \ No newline at end of file diff --git a/pr/720/docs/src/noq_udp/unix.rs.html b/pr/720/docs/src/noq_udp/unix.rs.html index 3772fc41b..12a5b5318 100644 --- a/pr/720/docs/src/noq_udp/unix.rs.html +++ b/pr/720/docs/src/noq_udp/unix.rs.html @@ -19,1240 +19,1256 @@ 19 EcnCodepoint, IO_ERROR_LOG_INTERVAL, RecvMeta, Transmit, UdpSockRef, cmsg, log_sendmsg_error, 20}; 21 -22// Adapted from https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/bsd/sys/socket_private.h -23#[cfg(apple_fast)] -24#[repr(C)] -25#[allow(non_camel_case_types)] -26pub(crate) struct msghdr_x { -27 pub msg_name: *mut libc::c_void, -28 pub msg_namelen: libc::socklen_t, -29 pub msg_iov: *mut libc::iovec, -30 pub msg_iovlen: libc::c_int, -31 pub msg_control: *mut libc::c_void, -32 pub msg_controllen: libc::socklen_t, -33 pub msg_flags: libc::c_int, -34 pub msg_datalen: usize, -35} -36 -37#[cfg(target_os = "freebsd")] -38type IpTosTy = libc::c_uchar; -39#[cfg(not(any(target_os = "freebsd", target_os = "netbsd")))] -40type IpTosTy = libc::c_int; -41 -42/// Tokio-compatible UDP socket with some useful specializations. -43/// -44/// Unlike a standard tokio UDP socket, this allows ECN bits to be read and written on some -45/// platforms. -46#[derive(Debug)] -47pub struct UdpSocketState { -48 last_send_error: Mutex<Instant>, -49 max_gso_segments: AtomicUsize, -50 gro_segments: NonZeroUsize, -51 may_fragment: bool, -52 -53 /// True if we have received EINVAL error from `sendmsg` system call at least once. -54 /// -55 /// If enabled, we assume that old kernel is used and switch to fallback mode. -56 /// In particular, we do not use IP_TOS cmsg_type in this case, -57 /// which is not supported on Linux <3.13 and results in not sending the UDP packet at all. -58 sendmsg_einval: AtomicBool, -59 -60 /// Whether to use Apple's fast `sendmsg_x`/`recvmsg_x` APIs. -61 /// -62 /// These private APIs provide better performance but may not be available on all -63 /// Apple OS versions. Callers must verify availability before enabling. -64 #[cfg(apple_fast)] -65 apple_fast_path: AtomicBool, -66} -67 -68impl UdpSocketState { -69 pub fn new(sock: UdpSockRef<'_>) -> io::Result<Self> { -70 let io = sock.0; -71 let mut cmsg_platform_space = 0; -72 if cfg!(target_os = "linux") -73 || cfg!(bsd) -74 || cfg!(apple) -75 || cfg!(target_os = "android") -76 || cfg!(solarish) -77 { -78 cmsg_platform_space += -79 unsafe { libc::CMSG_SPACE(mem::size_of::<libc::in6_pktinfo>() as _) as usize }; -80 } -81 -82 assert!( -83 CMSG_LEN -84 >= unsafe { libc::CMSG_SPACE(mem::size_of::<libc::c_int>() as _) as usize } -85 + cmsg_platform_space -86 ); -87 assert!( -88 mem::align_of::<libc::cmsghdr>() <= mem::align_of::<cmsg::Aligned<[u8; 0]>>(), -89 "control message buffers will be misaligned" -90 ); -91 -92 io.set_nonblocking(true)?; -93 -94 let addr = io.local_addr()?; -95 let is_ipv4 = addr.family() == libc::AF_INET as libc::sa_family_t; -96 -97 // mac and ios do not support IP_RECVTOS on dual-stack sockets :( -98 // older macos versions also don't have the flag and will error out if we don't ignore it -99 #[cfg(not(any( -100 target_os = "openbsd", -101 target_os = "netbsd", -102 target_os = "dragonfly", -103 solarish -104 )))] -105 if (is_ipv4 || !io.only_v6()?) -106 && let Err(_err) = -107 set_socket_option(&*io, libc::IPPROTO_IP, libc::IP_RECVTOS, OPTION_ON) -108 { -109 crate::log::debug!("Ignoring error setting IP_RECVTOS on socket: {_err:?}"); -110 } -111 -112 let mut may_fragment = false; -113 #[cfg_attr( -114 not(any(target_os = "linux", target_os = "android")), -115 expect(unused_mut) -116 )] -117 let mut gro_segments = NonZeroUsize::MIN; -118 -119 #[cfg(any(target_os = "linux", target_os = "android"))] -120 { -121 // Forbid IPv4 fragmentation. Set even for IPv6 to account for IPv6 mapped IPv4 addresses. -122 // Set `may_fragment` to `true` if this option is not supported on the platform. -123 may_fragment |= !set_socket_option_supported( -124 &*io, -125 libc::IPPROTO_IP, -126 libc::IP_MTU_DISCOVER, -127 libc::IP_PMTUDISC_PROBE, -128 )?; -129 -130 if is_ipv4 { -131 set_socket_option(&*io, libc::IPPROTO_IP, libc::IP_PKTINFO, OPTION_ON)?; -132 } else { -133 // Set `may_fragment` to `true` if this option is not supported on the platform. -134 may_fragment |= !set_socket_option_supported( -135 &*io, -136 libc::IPPROTO_IPV6, -137 libc::IPV6_MTU_DISCOVER, -138 libc::IPV6_PMTUDISC_PROBE, -139 )?; -140 } -141 -142 if set_socket_option(&*io, libc::SOL_UDP, libc::UDP_GRO, OPTION_ON).is_ok() { -143 // As defined in net/ipv4/udp_offload.c -144 // #define UDP_GRO_CNT_MAX 64 -145 // -146 // NOTE: this MUST be set to UDP_GRO_CNT_MAX to ensure that the receive buffer size -147 // (get_max_udp_payload_size() * gro_segments()) is large enough to hold the largest GRO -148 // list the kernel might potentially produce. See -149 // https://github.com/quinn-rs/quinn/pull/1354. -150 gro_segments = NonZeroUsize::new(64).expect("known"); -151 } -152 } -153 #[cfg(any(target_os = "freebsd", apple))] -154 { -155 if is_ipv4 { -156 // Set `may_fragment` to `true` if this option is not supported on the platform. -157 may_fragment |= !set_socket_option_supported( -158 &*io, -159 libc::IPPROTO_IP, -160 libc::IP_DONTFRAG, -161 OPTION_ON, -162 )?; -163 } -164 } -165 #[cfg(any(bsd, apple, solarish))] -166 // IP_RECVDSTADDR == IP_SENDSRCADDR on FreeBSD -167 // macOS uses only IP_RECVDSTADDR, no IP_SENDSRCADDR on macOS (the same on Solaris) -168 // macOS also supports IP_PKTINFO -169 { -170 if is_ipv4 { -171 set_socket_option(&*io, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, OPTION_ON)?; -172 } -173 } -174 -175 // Options standardized in RFC 3542 -176 if !is_ipv4 { -177 set_socket_option(&*io, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, OPTION_ON)?; -178 set_socket_option(&*io, libc::IPPROTO_IPV6, libc::IPV6_RECVTCLASS, OPTION_ON)?; -179 // Linux's IP_PMTUDISC_PROBE allows us to operate under interface MTU rather than the -180 // kernel's path MTU guess, but actually disabling fragmentation requires this too. See -181 // __ip6_append_data in ip6_output.c. -182 // Set `may_fragment` to `true` if this option is not supported on the platform. -183 may_fragment |= !set_socket_option_supported( -184 &*io, -185 libc::IPPROTO_IPV6, -186 libc::IPV6_DONTFRAG, -187 OPTION_ON, -188 )?; -189 } -190 -191 let now = Instant::now(); -192 Ok(Self { -193 last_send_error: Mutex::new(now.checked_sub(2 * IO_ERROR_LOG_INTERVAL).unwrap_or(now)), -194 max_gso_segments: AtomicUsize::new(gso::max_gso_segments(&*io)), -195 gro_segments, -196 may_fragment, -197 sendmsg_einval: AtomicBool::new(false), -198 #[cfg(apple_fast)] -199 apple_fast_path: AtomicBool::new(false), -200 }) -201 } -202 -203 /// Sends a [`Transmit`] on the given socket. -204 /// -205 /// This function will only ever return errors of kind [`io::ErrorKind::WouldBlock`]. -206 /// All other errors will be logged and converted to `Ok`. -207 /// -208 /// UDP transmission errors are considered non-fatal because higher-level protocols must -209 /// employ retransmits and timeouts anyway in order to deal with UDP's unreliable nature. -210 /// Thus, logging is most likely the only thing you can do with these errors. -211 /// -212 /// If you would like to handle these errors yourself, use [`UdpSocketState::try_send`] -213 /// instead. -214 pub fn send(&self, socket: UdpSockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { -215 match send(self, socket.0, transmit) { -216 Ok(()) => Ok(()), -217 Err(e) if e.kind() == io::ErrorKind::WouldBlock => Err(e), -218 // - EMSGSIZE is expected for MTU probes. Future work might be able to avoid -219 // these by automatically clamping the MTUD upper bound to the interface MTU. -220 Err(e) if e.raw_os_error() == Some(libc::EMSGSIZE) => Ok(()), -221 Err(e) => { -222 log_sendmsg_error(&self.last_send_error, e, transmit); -223 -224 Ok(()) -225 } -226 } -227 } -228 -229 /// Sends a [`Transmit`] on the given socket without any additional error handling. -230 pub fn try_send(&self, socket: UdpSockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { -231 send(self, socket.0, transmit) -232 } -233 -234 #[cfg(not(any( -235 apple, -236 target_os = "openbsd", -237 target_os = "netbsd", -238 target_os = "dragonfly", -239 solarish -240 )))] -241 pub fn recv( -242 &self, -243 socket: UdpSockRef<'_>, -244 bufs: &mut [IoSliceMut<'_>], -245 meta: &mut [RecvMeta], -246 ) -> io::Result<usize> { -247 recv_via_recvmmsg(socket.0, bufs, meta) -248 } -249 -250 #[cfg(apple_fast)] -251 pub fn recv( -252 &self, -253 socket: UdpSockRef<'_>, -254 bufs: &mut [IoSliceMut<'_>], -255 meta: &mut [RecvMeta], -256 ) -> io::Result<usize> { -257 if self.is_apple_fast_path_enabled() { -258 recv_via_recvmsg_x(self, socket.0, bufs, meta) -259 } else { -260 recv_single(socket.0, bufs, meta) -261 } +22/// Tokio-compatible UDP socket with some useful specializations. +23/// +24/// Unlike a standard tokio UDP socket, this allows ECN bits to be read and written on some +25/// platforms. +26#[derive(Debug)] +27pub struct UdpSocketState { +28 last_send_error: Mutex<Instant>, +29 max_gso_segments: AtomicUsize, +30 gro_segments: NonZeroUsize, +31 may_fragment: bool, +32 +33 /// True if we have received EINVAL error from `sendmsg` system call at least once. +34 /// +35 /// If enabled, we assume that old kernel is used and switch to fallback mode. +36 /// In particular, we do not use IP_TOS cmsg_type in this case, +37 /// which is not supported on Linux <3.13 and results in not sending the UDP packet at all. +38 sendmsg_einval: AtomicBool, +39 +40 /// Whether to use Apple's fast `sendmsg_x`/`recvmsg_x` APIs. +41 /// +42 /// These private APIs provide better performance but may not be available on all +43 /// Apple OS versions. Callers must verify availability before enabling. +44 #[cfg(apple_fast)] +45 apple_fast_path: AtomicBool, +46} +47 +48impl UdpSocketState { +49 pub fn new(sock: UdpSockRef<'_>) -> io::Result<Self> { +50 let io = sock.0; +51 let mut cmsg_platform_space = 0; +52 #[cfg(not(target_os = "redox"))] +53 if cfg!(target_os = "linux") +54 || cfg!(bsd) +55 || cfg!(apple) +56 || cfg!(target_os = "android") +57 || cfg!(solarish) +58 { +59 cmsg_platform_space += +60 unsafe { libc::CMSG_SPACE(mem::size_of::<libc::in6_pktinfo>() as _) as usize }; +61 } +62 +63 assert!( +64 cmsg::LEN +65 >= unsafe { libc::CMSG_SPACE(mem::size_of::<libc::c_int>() as _) as usize } +66 + cmsg_platform_space +67 ); +68 assert!( +69 mem::align_of::<libc::cmsghdr>() <= mem::align_of::<cmsg::Aligned<[u8; 0]>>(), +70 "control message buffers will be misaligned" +71 ); +72 +73 io.set_nonblocking(true)?; +74 +75 let addr = io.local_addr()?; +76 let is_ipv4 = addr.family() == libc::AF_INET as libc::sa_family_t; +77 +78 // mac and ios do not support IP_RECVTOS on dual-stack sockets :( +79 // older macos versions also don't have the flag and will error out if we don't ignore it +80 #[cfg(not(any( +81 target_os = "openbsd", +82 target_os = "netbsd", +83 target_os = "dragonfly", +84 solarish +85 )))] +86 if (is_ipv4 || !io.only_v6()?) +87 && let Err(_err) = +88 set_socket_option(&*io, libc::IPPROTO_IP, libc::IP_RECVTOS, OPTION_ON) +89 { +90 crate::log::debug!("Ignoring error setting IP_RECVTOS on socket: {_err:?}"); +91 } +92 +93 let mut may_fragment = false; +94 #[cfg_attr( +95 not(any(target_os = "linux", target_os = "android")), +96 expect(unused_mut) +97 )] +98 let mut gro_segments = NonZeroUsize::MIN; +99 +100 #[cfg(any(target_os = "linux", target_os = "android"))] +101 { +102 // Forbid IPv4 fragmentation. Set even for IPv6 to account for IPv6 mapped IPv4 addresses. +103 // Set `may_fragment` to `true` if this option is not supported on the platform. +104 may_fragment |= !set_socket_option_supported( +105 &*io, +106 libc::IPPROTO_IP, +107 libc::IP_MTU_DISCOVER, +108 libc::IP_PMTUDISC_PROBE, +109 )?; +110 +111 if is_ipv4 { +112 set_socket_option(&*io, libc::IPPROTO_IP, libc::IP_PKTINFO, OPTION_ON)?; +113 } else { +114 // Set `may_fragment` to `true` if this option is not supported on the platform. +115 may_fragment |= !set_socket_option_supported( +116 &*io, +117 libc::IPPROTO_IPV6, +118 libc::IPV6_MTU_DISCOVER, +119 libc::IPV6_PMTUDISC_PROBE, +120 )?; +121 } +122 +123 if set_socket_option(&*io, libc::SOL_UDP, libc::UDP_GRO, OPTION_ON).is_ok() { +124 // As defined in net/ipv4/udp_offload.c +125 // #define UDP_GRO_CNT_MAX 64 +126 // +127 // NOTE: this MUST be set to UDP_GRO_CNT_MAX to ensure that the receive buffer size +128 // (get_max_udp_payload_size() * gro_segments()) is large enough to hold the largest GRO +129 // list the kernel might potentially produce. See +130 // https://github.com/quinn-rs/quinn/pull/1354. +131 gro_segments = NonZeroUsize::new(64).expect("known"); +132 } +133 } +134 #[cfg(any(target_os = "freebsd", apple))] +135 { +136 if is_ipv4 { +137 // Set `may_fragment` to `true` if this option is not supported on the platform. +138 may_fragment |= !set_socket_option_supported( +139 &*io, +140 libc::IPPROTO_IP, +141 libc::IP_DONTFRAG, +142 OPTION_ON, +143 )?; +144 } +145 } +146 #[cfg(any(bsd, apple, solarish))] +147 // IP_RECVDSTADDR == IP_SENDSRCADDR on FreeBSD +148 // macOS uses only IP_RECVDSTADDR, no IP_SENDSRCADDR on macOS (the same on Solaris) +149 // macOS also supports IP_PKTINFO +150 { +151 if is_ipv4 { +152 set_socket_option(&*io, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, OPTION_ON)?; +153 } +154 } +155 +156 // Options standardized in RFC 3542 +157 #[cfg(not(target_os = "redox"))] +158 if !is_ipv4 { +159 set_socket_option(&*io, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, OPTION_ON)?; +160 set_socket_option(&*io, libc::IPPROTO_IPV6, libc::IPV6_RECVTCLASS, OPTION_ON)?; +161 // Linux's IP_PMTUDISC_PROBE allows us to operate under interface MTU rather than the +162 // kernel's path MTU guess, but actually disabling fragmentation requires this too. See +163 // __ip6_append_data in ip6_output.c. +164 // Set `may_fragment` to `true` if this option is not supported on the platform. +165 may_fragment |= !set_socket_option_supported( +166 &*io, +167 libc::IPPROTO_IPV6, +168 libc::IPV6_DONTFRAG, +169 OPTION_ON, +170 )?; +171 } +172 +173 let now = Instant::now(); +174 Ok(Self { +175 last_send_error: Mutex::new(now.checked_sub(2 * IO_ERROR_LOG_INTERVAL).unwrap_or(now)), +176 max_gso_segments: AtomicUsize::new(gso::max_gso_segments(&*io)), +177 gro_segments, +178 may_fragment, +179 sendmsg_einval: AtomicBool::new(false), +180 #[cfg(apple_fast)] +181 apple_fast_path: AtomicBool::new(false), +182 }) +183 } +184 +185 /// Sends a [`Transmit`] on the given socket. +186 /// +187 /// This function will only ever return errors of kind [`io::ErrorKind::WouldBlock`]. +188 /// All other errors will be logged and converted to `Ok`. +189 /// +190 /// UDP transmission errors are considered non-fatal because higher-level protocols must +191 /// employ retransmits and timeouts anyway in order to deal with UDP's unreliable nature. +192 /// Thus, logging is most likely the only thing you can do with these errors. +193 /// +194 /// If you would like to handle these errors yourself, use [`UdpSocketState::try_send`] +195 /// instead. +196 pub fn send(&self, socket: UdpSockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { +197 match send(self, socket.0, transmit) { +198 Ok(()) => Ok(()), +199 Err(e) if e.kind() == io::ErrorKind::WouldBlock => Err(e), +200 // - EMSGSIZE is expected for MTU probes. Future work might be able to avoid +201 // these by automatically clamping the MTUD upper bound to the interface MTU. +202 Err(e) if e.raw_os_error() == Some(libc::EMSGSIZE) => Ok(()), +203 Err(e) => { +204 log_sendmsg_error(&self.last_send_error, e, transmit); +205 +206 Ok(()) +207 } +208 } +209 } +210 +211 /// Sends a [`Transmit`] on the given socket without any additional error handling. +212 pub fn try_send(&self, socket: UdpSockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { +213 send(self, socket.0, transmit) +214 } +215 +216 #[cfg(not(any( +217 apple, +218 target_os = "openbsd", +219 target_os = "netbsd", +220 target_os = "dragonfly", +221 target_os = "redox", +222 solarish +223 )))] +224 pub fn recv( +225 &self, +226 socket: UdpSockRef<'_>, +227 bufs: &mut [IoSliceMut<'_>], +228 meta: &mut [RecvMeta], +229 ) -> io::Result<usize> { +230 recv_via_recvmmsg(socket.0, bufs, meta) +231 } +232 +233 #[cfg(apple_fast)] +234 pub fn recv( +235 &self, +236 socket: UdpSockRef<'_>, +237 bufs: &mut [IoSliceMut<'_>], +238 meta: &mut [RecvMeta], +239 ) -> io::Result<usize> { +240 if self.is_apple_fast_path_enabled() { +241 recv_via_recvmsg_x(self, socket.0, bufs, meta) +242 } else { +243 recv_single(socket.0, bufs, meta) +244 } +245 } +246 +247 #[cfg(any( +248 target_os = "openbsd", +249 target_os = "netbsd", +250 target_os = "dragonfly", +251 target_os = "redox", +252 solarish, +253 apple_slow +254 ))] +255 pub fn recv( +256 &self, +257 socket: UdpSockRef<'_>, +258 bufs: &mut [IoSliceMut<'_>], +259 meta: &mut [RecvMeta], +260 ) -> io::Result<usize> { +261 recv_single(socket.0, bufs, meta) 262 } 263 -264 #[cfg(any( -265 target_os = "openbsd", -266 target_os = "netbsd", -267 target_os = "dragonfly", -268 solarish, -269 apple_slow -270 ))] -271 pub fn recv( -272 &self, -273 socket: UdpSockRef<'_>, -274 bufs: &mut [IoSliceMut<'_>], -275 meta: &mut [RecvMeta], -276 ) -> io::Result<usize> { -277 recv_single(socket.0, bufs, meta) -278 } -279 -280 /// The maximum amount of segments which can be transmitted if a platform -281 /// supports Generic Send Offload (GSO). -282 /// -283 /// This is 1 if the platform doesn't support GSO. Subject to change if errors are detected -284 /// while using GSO. -285 #[inline] -286 pub fn max_gso_segments(&self) -> NonZeroUsize { -287 self.max_gso_segments -288 .load(Ordering::Relaxed) -289 .try_into() -290 .expect("must have non zero GSO segments") +264 /// Maximum number of segments to transmit if Generic Send Offload (GSO) is enabled. +265 /// +266 /// This is 1 if the platform doesn't support GSO. +267 /// +268 /// Subject to change if errors are detected while using GSO. +269 #[inline] +270 pub fn max_gso_segments(&self) -> NonZeroUsize { +271 self.max_gso_segments +272 .load(Ordering::Relaxed) +273 .try_into() +274 .expect("must have non zero GSO segments") +275 } +276 +277 /// The number of segments to read when GRO is enabled. +278 /// +279 /// Used as a factor to compute the receive buffer size. +280 /// +281 /// Returns 1 if the platform doesn't support GRO. +282 #[inline] +283 pub fn gro_segments(&self) -> NonZeroUsize { +284 self.gro_segments +285 } +286 +287 /// Resize the send buffer of `socket` to `bytes` +288 #[inline] +289 pub fn set_send_buffer_size(&self, socket: UdpSockRef<'_>, bytes: usize) -> io::Result<()> { +290 socket.0.set_send_buffer_size(bytes) 291 } 292 -293 /// The number of segments to read when GRO is enabled. Used as a factor to -294 /// compute the receive buffer size. -295 /// -296 /// Returns 1 if the platform doesn't support GRO. -297 #[inline] -298 pub fn gro_segments(&self) -> NonZeroUsize { -299 self.gro_segments -300 } -301 -302 /// Resize the send buffer of `socket` to `bytes` -303 #[inline] -304 pub fn set_send_buffer_size(&self, socket: UdpSockRef<'_>, bytes: usize) -> io::Result<()> { -305 socket.0.set_send_buffer_size(bytes) -306 } -307 -308 /// Resize the receive buffer of `socket` to `bytes` -309 #[inline] -310 pub fn set_recv_buffer_size(&self, socket: UdpSockRef<'_>, bytes: usize) -> io::Result<()> { -311 socket.0.set_recv_buffer_size(bytes) -312 } -313 -314 /// Get the size of the `socket` send buffer -315 #[inline] -316 pub fn send_buffer_size(&self, socket: UdpSockRef<'_>) -> io::Result<usize> { -317 socket.0.send_buffer_size() -318 } -319 -320 /// Get the size of the `socket` receive buffer -321 #[inline] -322 pub fn recv_buffer_size(&self, socket: UdpSockRef<'_>) -> io::Result<usize> { -323 socket.0.recv_buffer_size() -324 } -325 -326 /// Whether transmitted datagrams might get fragmented by the IP layer -327 /// -328 /// Returns `false` on targets which employ e.g. the `IPV6_DONTFRAG` socket option. -329 #[inline] -330 pub fn may_fragment(&self) -> bool { -331 self.may_fragment -332 } -333 -334 /// Returns true if we previously got an EINVAL error from `sendmsg` syscall. -335 fn sendmsg_einval(&self) -> bool { -336 self.sendmsg_einval.load(Ordering::Relaxed) -337 } -338 -339 /// Sets the flag indicating we got EINVAL error from `sendmsg` syscall. -340 #[cfg(not(any(apple, target_os = "openbsd", target_os = "netbsd")))] -341 fn set_sendmsg_einval(&self) { -342 self.sendmsg_einval.store(true, Ordering::Relaxed) -343 } -344 -345 /// Enables Apple's fast UDP datapath using private `sendmsg_x`/`recvmsg_x` APIs. -346 /// Once enabled, this also updates [`max_gso_segments`] to allow batched sends. -347 /// -348 /// # Safety -349 /// -350 /// These APIs may crash on unsupported OS versions, so callers must verify -351 /// availability before enabling. -352 /// -353 /// [`max_gso_segments`]: Self::max_gso_segments -354 #[cfg(apple_fast)] -355 pub unsafe fn set_apple_fast_path(&self) { -356 self.apple_fast_path.store(true, Ordering::Relaxed); -357 self.max_gso_segments.store(BATCH_SIZE, Ordering::Relaxed); -358 } -359 -360 /// Returns whether Apple's fast UDP datapath is enabled for this socket. -361 #[cfg(apple_fast)] -362 pub fn is_apple_fast_path_enabled(&self) -> bool { -363 self.apple_fast_path.load(Ordering::Relaxed) -364 } -365 -366 /// Disables Apple's fast UDP datapath, reverting to `sendmsg`/`recvmsg`. -367 #[cfg(apple_fast)] -368 fn disable_apple_fast_path(&self) { -369 self.apple_fast_path.store(false, Ordering::Relaxed); -370 self.max_gso_segments.store(1, Ordering::Relaxed); -371 } +293 /// Resize the receive buffer of `socket` to `bytes` +294 #[inline] +295 pub fn set_recv_buffer_size(&self, socket: UdpSockRef<'_>, bytes: usize) -> io::Result<()> { +296 socket.0.set_recv_buffer_size(bytes) +297 } +298 +299 /// Get the size of the `socket` send buffer +300 #[inline] +301 pub fn send_buffer_size(&self, socket: UdpSockRef<'_>) -> io::Result<usize> { +302 socket.0.send_buffer_size() +303 } +304 +305 /// Get the size of the `socket` receive buffer +306 #[inline] +307 pub fn recv_buffer_size(&self, socket: UdpSockRef<'_>) -> io::Result<usize> { +308 socket.0.recv_buffer_size() +309 } +310 +311 /// Whether transmitted datagrams might get fragmented by the IP layer +312 /// +313 /// Returns `false` on targets which employ e.g. the `IPV6_DONTFRAG` socket option. +314 #[inline] +315 pub fn may_fragment(&self) -> bool { +316 self.may_fragment +317 } +318 +319 /// Returns true if we previously got an EINVAL error from `sendmsg` syscall. +320 fn sendmsg_einval(&self) -> bool { +321 self.sendmsg_einval.load(Ordering::Relaxed) +322 } +323 +324 /// Sets the flag indicating we got EINVAL error from `sendmsg` syscall. +325 #[cfg(not(any(apple, target_os = "openbsd", target_os = "netbsd")))] +326 fn set_sendmsg_einval(&self) { +327 self.sendmsg_einval.store(true, Ordering::Relaxed) +328 } +329 +330 /// Enables Apple's fast UDP datapath using private `sendmsg_x`/`recvmsg_x` APIs. +331 /// +332 /// Once enabled, this also updates [`max_gso_segments`] to allow batched sends. +333 /// +334 /// # Safety +335 /// +336 /// These APIs may crash on unsupported OS versions, so callers must verify +337 /// availability before enabling. +338 /// +339 /// [`max_gso_segments`]: Self::max_gso_segments +340 #[cfg(apple_fast)] +341 pub unsafe fn set_apple_fast_path(&self) { +342 self.apple_fast_path.store(true, Ordering::Relaxed); +343 self.max_gso_segments.store(BATCH_SIZE, Ordering::Relaxed); +344 } +345 +346 /// Returns whether Apple's fast UDP datapath is enabled for this socket. +347 #[cfg(apple_fast)] +348 pub fn is_apple_fast_path_enabled(&self) -> bool { +349 self.apple_fast_path.load(Ordering::Relaxed) +350 } +351 +352 /// Disables Apple's fast UDP datapath, reverting to `sendmsg`/`recvmsg`. +353 #[cfg(apple_fast)] +354 fn disable_apple_fast_path(&self) { +355 self.apple_fast_path.store(false, Ordering::Relaxed); +356 self.max_gso_segments.store(1, Ordering::Relaxed); +357 } +358 +359 /// Resolves an Apple fast-path function pointer via `resolver`. +360 /// +361 /// Disables the fast path if the symbol is absent so that future calls use the slow path +362 /// directly. +363 #[cfg(apple_fast)] +364 fn resolve_apple_fast_fn<T>(&self, resolver: fn() -> Option<T>) -> Option<T> { +365 let f = resolver(); +366 if f.is_none() { +367 self.disable_apple_fast_path(); +368 } +369 f +370 } +371} 372 -373 /// Resolves an Apple fast-path function pointer via `resolver`, disabling the fast path if -374 /// the symbol is absent so that future calls use the slow path directly. -375 #[cfg(apple_fast)] -376 fn resolve_apple_fast_fn<T>(&self, resolver: fn() -> Option<T>) -> Option<T> { -377 let f = resolver(); -378 if f.is_none() { -379 self.disable_apple_fast_path(); -380 } -381 f -382 } -383} -384 -385#[cfg(not(any(apple, target_os = "openbsd", target_os = "netbsd")))] -386fn send( -387 #[allow(unused_variables)] // only used on Linux -388 state: &UdpSocketState, -389 io: SockRef<'_>, -390 transmit: &Transmit<'_>, -391) -> io::Result<()> { -392 #[allow(unused_mut)] // only mutable on FreeBSD -393 let mut encode_src_ip = true; -394 #[cfg(target_os = "freebsd")] -395 { -396 let addr = io.local_addr()?; -397 let is_ipv4 = addr.family() == libc::AF_INET as libc::sa_family_t; -398 if is_ipv4 { -399 if let Some(socket) = addr.as_socket_ipv4() { -400 encode_src_ip = socket.ip() == &Ipv4Addr::UNSPECIFIED; -401 } -402 } -403 } -404 let mut msg_hdr: libc::msghdr = unsafe { mem::zeroed() }; -405 let mut iovec: libc::iovec = unsafe { mem::zeroed() }; -406 let mut cmsgs = cmsg::Aligned([0u8; CMSG_LEN]); -407 let dst_addr = socket2::SockAddr::from(transmit.destination); -408 prepare_msg( -409 transmit, -410 &dst_addr, -411 &mut msg_hdr, -412 &mut iovec, -413 &mut cmsgs, -414 encode_src_ip, -415 state.sendmsg_einval(), -416 ); -417 -418 loop { -419 let n = unsafe { libc::sendmsg(io.as_raw_fd(), &msg_hdr, 0) }; -420 -421 if n >= 0 { -422 return Ok(()); -423 } -424 -425 let e = io::Error::last_os_error(); -426 match e.kind() { -427 // Retry the transmission -428 io::ErrorKind::Interrupted => continue, -429 io::ErrorKind::WouldBlock => return Err(e), -430 _ => { -431 // Some network adapters and drivers do not support GSO. Unfortunately, Linux -432 // offers no easy way for us to detect this short of an EIO or sometimes EINVAL -433 // when we try to actually send datagrams using it. -434 #[cfg(any(target_os = "linux", target_os = "android"))] -435 if let Some(libc::EIO) | Some(libc::EINVAL) = e.raw_os_error() { -436 // Prevent new transmits from being scheduled using GSO. Existing GSO transmits -437 // may already be in the pipeline, so we need to tolerate additional failures. -438 if state.max_gso_segments().get() > 1 { -439 crate::log::info!( -440 "`libc::sendmsg` failed with {e}; halting segmentation offload" -441 ); -442 state -443 .max_gso_segments -444 .store(1, std::sync::atomic::Ordering::Relaxed); -445 } -446 } -447 -448 // Some arguments to `sendmsg` are not supported. Switch to -449 // fallback mode and retry if we haven't already. -450 if e.raw_os_error() == Some(libc::EINVAL) && !state.sendmsg_einval() { -451 state.set_sendmsg_einval(); -452 prepare_msg( -453 transmit, -454 &dst_addr, -455 &mut msg_hdr, -456 &mut iovec, -457 &mut cmsgs, -458 encode_src_ip, -459 state.sendmsg_einval(), -460 ); -461 continue; -462 } -463 -464 return Err(e); -465 } -466 } -467 } -468} -469 -470#[cfg(apple_fast)] -471fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { -472 if state.is_apple_fast_path_enabled() { -473 send_via_sendmsg_x(state, io, transmit) -474 } else { -475 send_single(state, io, transmit) -476 } -477} -478 -479/// Send using the fast `sendmsg_x` API. -480#[cfg(apple_fast)] -481fn send_via_sendmsg_x( -482 state: &UdpSocketState, -483 io: SockRef<'_>, -484 transmit: &Transmit<'_>, -485) -> io::Result<()> { -486 let mut hdrs = unsafe { mem::zeroed::<[msghdr_x; BATCH_SIZE]>() }; -487 let mut iovs = unsafe { mem::zeroed::<[libc::iovec; BATCH_SIZE]>() }; -488 let mut ctrls = [cmsg::Aligned([0u8; CMSG_LEN]); BATCH_SIZE]; -489 let addr = socket2::SockAddr::from(transmit.destination); -490 let segment_size = transmit.segment_size.unwrap_or(transmit.contents.len()); -491 let mut cnt = 0; -492 debug_assert!(transmit.contents.len().div_ceil(segment_size) <= BATCH_SIZE); -493 for (i, chunk) in transmit -494 .contents -495 .chunks(segment_size) -496 .enumerate() -497 .take(BATCH_SIZE) -498 { -499 prepare_msg_x( -500 &Transmit { -501 destination: transmit.destination, -502 ecn: transmit.ecn, -503 contents: chunk, -504 segment_size: Some(chunk.len()), -505 src_ip: transmit.src_ip, -506 }, -507 &addr, -508 &mut hdrs[i], -509 &mut iovs[i], -510 &mut ctrls[i], -511 true, -512 state.sendmsg_einval(), -513 ); -514 hdrs[i].msg_datalen = chunk.len(); -515 cnt += 1; -516 } -517 let Some(sendmsg_x) = state.resolve_apple_fast_fn(sendmsg_x_fn) else { -518 return send_single(state, io, transmit); -519 }; -520 retry_if_interrupted(|| unsafe { sendmsg_x(io.as_raw_fd(), hdrs.as_ptr(), cnt as u32, 0) })?; -521 Ok(()) -522} -523 -524#[cfg(any(target_os = "openbsd", target_os = "netbsd", apple_slow))] -525fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { -526 send_single(state, io, transmit) -527} -528 -529#[cfg(any(target_os = "openbsd", target_os = "netbsd", apple))] -530#[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled -531fn send_single(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { -532 let mut hdr: libc::msghdr = unsafe { mem::zeroed() }; -533 let mut iov: libc::iovec = unsafe { mem::zeroed() }; -534 let mut ctrl = cmsg::Aligned([0u8; CMSG_LEN]); -535 let addr = socket2::SockAddr::from(transmit.destination); -536 prepare_msg( -537 transmit, -538 &addr, -539 &mut hdr, -540 &mut iov, -541 &mut ctrl, -542 cfg!(apple) || cfg!(target_os = "openbsd") || cfg!(target_os = "netbsd"), -543 state.sendmsg_einval(), -544 ); -545 retry_if_interrupted(|| unsafe { libc::sendmsg(io.as_raw_fd(), &hdr, 0) })?; -546 Ok(()) -547} -548 -549/// Receive using the batched `recvmmsg` syscall. -550#[cfg(not(any( -551 apple, -552 target_os = "openbsd", -553 target_os = "netbsd", -554 target_os = "dragonfly", -555 solarish -556)))] -557fn recv_via_recvmmsg( -558 io: SockRef<'_>, -559 bufs: &mut [IoSliceMut<'_>], -560 meta: &mut [RecvMeta], -561) -> io::Result<usize> { -562 let mut names = [MaybeUninit::<libc::sockaddr_storage>::uninit(); BATCH_SIZE]; -563 let mut ctrls = [cmsg::Aligned(MaybeUninit::<[u8; CMSG_LEN]>::uninit()); BATCH_SIZE]; -564 let mut hdrs = unsafe { mem::zeroed::<[libc::mmsghdr; BATCH_SIZE]>() }; -565 let max_msg_count = bufs.len().min(BATCH_SIZE); -566 for i in 0..max_msg_count { -567 prepare_recv( -568 &mut bufs[i], -569 &mut names[i], -570 &mut ctrls[i], -571 &mut hdrs[i].msg_hdr, -572 ); -573 } -574 let msg_count = retry_if_interrupted(|| unsafe { -575 libc::recvmmsg( -576 io.as_raw_fd(), -577 hdrs.as_mut_ptr(), -578 bufs.len().min(BATCH_SIZE) as _, -579 0, -580 ptr::null_mut::<libc::timespec>(), -581 ) as isize -582 })?; -583 for i in 0..(msg_count as usize) { -584 meta[i] = decode_recv(&names[i], &hdrs[i].msg_hdr, hdrs[i].msg_len as usize)?; -585 } -586 Ok(msg_count as usize) -587} -588 -589/// Receive using the fast `recvmsg_x` API. -590#[cfg(apple_fast)] -591fn recv_via_recvmsg_x( -592 state: &UdpSocketState, -593 io: SockRef<'_>, -594 bufs: &mut [IoSliceMut<'_>], -595 meta: &mut [RecvMeta], -596) -> io::Result<usize> { -597 let mut names = [MaybeUninit::<libc::sockaddr_storage>::uninit(); BATCH_SIZE]; -598 // MacOS 10.15 `recvmsg_x` does not override the `msghdr_x` -599 // `msg_controllen`. Thus, after the call to `recvmsg_x`, one does not know -600 // which control messages have been written to. To prevent reading -601 // uninitialized memory, do not use `MaybeUninit` for `ctrls`, instead -602 // initialize `ctrls` with `0`s. A control message of all `0`s is -603 // automatically skipped by `libc::CMSG_NXTHDR`. -604 let mut ctrls = [cmsg::Aligned([0u8; CMSG_LEN]); BATCH_SIZE]; -605 let mut hdrs = unsafe { mem::zeroed::<[msghdr_x; BATCH_SIZE]>() }; -606 let max_msg_count = bufs.len().min(BATCH_SIZE); -607 for i in 0..max_msg_count { -608 prepare_recv_x(&mut bufs[i], &mut names[i], &mut ctrls[i], &mut hdrs[i]); -609 } -610 let Some(recvmsg_x) = state.resolve_apple_fast_fn(recvmsg_x_fn) else { -611 return recv_single(io, bufs, meta); -612 }; -613 let msg_count = retry_if_interrupted(|| unsafe { -614 recvmsg_x(io.as_raw_fd(), hdrs.as_mut_ptr(), max_msg_count as _, 0) -615 })?; -616 for i in 0..(msg_count as usize) { -617 meta[i] = decode_recv(&names[i], &hdrs[i], hdrs[i].msg_datalen as usize)?; -618 } -619 Ok(msg_count as usize) -620} -621 -622/// Returns the `sendmsg_x` function pointer, resolving it via `dlsym` on first call. -623/// -624/// Returns `None` if the symbol is not available on the current OS version. -625#[cfg(apple_fast)] -626fn sendmsg_x_fn() -> Option<SendmsgXFn> { -627 static ADDR: std::sync::OnceLock<usize> = std::sync::OnceLock::new(); -628 // SAFETY: `resolve_symbol` only returns non-zero addresses obtained from `dlsym`, which -629 // guarantees a callable symbol whose type matches the declaration above. -630 resolve_symbol(&ADDR, c"sendmsg_x") -631 .map(|addr| unsafe { std::mem::transmute::<usize, SendmsgXFn>(addr) }) -632} -633 -634/// Returns the `recvmsg_x` function pointer, resolving it via `dlsym` on first call. -635/// -636/// Returns `None` if the symbol is not available on the current OS version. -637#[cfg(apple_fast)] -638fn recvmsg_x_fn() -> Option<RecvmsgXFn> { -639 static ADDR: std::sync::OnceLock<usize> = std::sync::OnceLock::new(); -640 // SAFETY: `resolve_symbol` only returns non-zero addresses obtained from `dlsym`, which -641 // guarantees a callable symbol whose type matches the declaration above. -642 resolve_symbol(&ADDR, c"recvmsg_x") -643 .map(|addr| unsafe { std::mem::transmute::<usize, RecvmsgXFn>(addr) }) -644} -645 -646#[cfg(apple_fast)] -647type SendmsgXFn = -648 unsafe extern "C" fn(libc::c_int, *const msghdr_x, libc::c_uint, libc::c_int) -> isize; -649#[cfg(apple_fast)] -650type RecvmsgXFn = -651 unsafe extern "C" fn(libc::c_int, *mut msghdr_x, libc::c_uint, libc::c_int) -> isize; -652 -653/// Resolves a symbol via `dlsym` on first call, caching the result. -654/// -655/// Returns `None` if the symbol is not available on the current OS version. -656#[cfg(apple_fast)] -657fn resolve_symbol(lock: &std::sync::OnceLock<usize>, name: &std::ffi::CStr) -> Option<usize> { -658 let addr = -659 *lock.get_or_init(|| unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize }); -660 (addr != 0).then_some(addr) -661} -662 -663#[cfg(any( -664 target_os = "openbsd", -665 target_os = "netbsd", -666 target_os = "dragonfly", -667 solarish, -668 apple -669))] -670#[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled -671fn recv_single( -672 io: SockRef<'_>, -673 bufs: &mut [IoSliceMut<'_>], -674 meta: &mut [RecvMeta], -675) -> io::Result<usize> { -676 let mut name = MaybeUninit::<libc::sockaddr_storage>::uninit(); -677 let mut ctrl = cmsg::Aligned(MaybeUninit::<[u8; CMSG_LEN]>::uninit()); -678 let mut hdr = unsafe { mem::zeroed::<libc::msghdr>() }; -679 prepare_recv(&mut bufs[0], &mut name, &mut ctrl, &mut hdr); -680 let n = loop { -681 let n = unsafe { libc::recvmsg(io.as_raw_fd(), &mut hdr, 0) }; -682 -683 if hdr.msg_flags & libc::MSG_TRUNC != 0 { -684 continue; -685 } -686 -687 if n >= 0 { -688 break n; -689 } -690 -691 let e = io::Error::last_os_error(); -692 match e.kind() { -693 // Retry receiving -694 io::ErrorKind::Interrupted => continue, -695 _ => return Err(e), -696 } -697 }; -698 meta[0] = decode_recv(&name, &hdr, n as usize)?; -699 Ok(1) -700} -701 -702const CMSG_LEN: usize = 88; -703 -704#[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled -705fn prepare_msg( -706 transmit: &Transmit<'_>, -707 dst_addr: &socket2::SockAddr, -708 hdr: &mut libc::msghdr, -709 iov: &mut libc::iovec, -710 ctrl: &mut cmsg::Aligned<[u8; CMSG_LEN]>, -711 #[allow(unused_variables)] // only used on FreeBSD & macOS -712 encode_src_ip: bool, -713 sendmsg_einval: bool, -714) { -715 iov.iov_base = transmit.contents.as_ptr() as *const _ as *mut _; -716 iov.iov_len = transmit.contents.len(); +373#[cfg(not(any(apple, target_os = "openbsd", target_os = "netbsd")))] +374fn send( +375 #[allow(unused_variables)] // only used on Linux +376 state: &UdpSocketState, +377 io: SockRef<'_>, +378 transmit: &Transmit<'_>, +379) -> io::Result<()> { +380 #[allow(unused_mut)] // only mutable on FreeBSD +381 let mut encode_src_ip = true; +382 #[cfg(target_os = "freebsd")] +383 { +384 let addr = io.local_addr()?; +385 let is_ipv4 = addr.family() == libc::AF_INET as libc::sa_family_t; +386 if is_ipv4 { +387 if let Some(socket) = addr.as_socket_ipv4() { +388 encode_src_ip = socket.ip() == &Ipv4Addr::UNSPECIFIED; +389 } +390 } +391 } +392 let mut msg_hdr: libc::msghdr = unsafe { mem::zeroed() }; +393 let mut iovec: libc::iovec = unsafe { mem::zeroed() }; +394 let mut cmsgs = cmsg::Aligned([0u8; cmsg::LEN]); +395 let dst_addr = socket2::SockAddr::from(transmit.destination); +396 prepare_msg( +397 transmit, +398 &dst_addr, +399 &mut msg_hdr, +400 &mut iovec, +401 &mut cmsgs, +402 encode_src_ip, +403 state.sendmsg_einval(), +404 ); +405 +406 loop { +407 let n = unsafe { libc::sendmsg(io.as_raw_fd(), &msg_hdr, 0) }; +408 +409 if n >= 0 { +410 return Ok(()); +411 } +412 +413 let e = io::Error::last_os_error(); +414 match e.kind() { +415 // Retry the transmission +416 io::ErrorKind::Interrupted => continue, +417 io::ErrorKind::WouldBlock => return Err(e), +418 _ => { +419 // Some network adapters and drivers do not support GSO. Unfortunately, Linux +420 // offers no easy way for us to detect this short of an EIO or sometimes EINVAL +421 // when we try to actually send datagrams using it. +422 #[cfg(any(target_os = "linux", target_os = "android"))] +423 if let Some(libc::EIO) | Some(libc::EINVAL) = e.raw_os_error() { +424 // Prevent new transmits from being scheduled using GSO. Existing GSO transmits +425 // may already be in the pipeline, so we need to tolerate additional failures. +426 if state.max_gso_segments().get() > 1 { +427 crate::log::info!( +428 "`libc::sendmsg` failed with {e}; halting segmentation offload" +429 ); +430 state +431 .max_gso_segments +432 .store(1, std::sync::atomic::Ordering::Relaxed); +433 } +434 } +435 +436 // Some arguments to `sendmsg` are not supported. Switch to +437 // fallback mode and retry if we haven't already. +438 if e.raw_os_error() == Some(libc::EINVAL) && !state.sendmsg_einval() { +439 state.set_sendmsg_einval(); +440 prepare_msg( +441 transmit, +442 &dst_addr, +443 &mut msg_hdr, +444 &mut iovec, +445 &mut cmsgs, +446 encode_src_ip, +447 state.sendmsg_einval(), +448 ); +449 continue; +450 } +451 +452 return Err(e); +453 } +454 } +455 } +456} +457 +458#[cfg(apple_fast)] +459fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { +460 if state.is_apple_fast_path_enabled() { +461 send_via_sendmsg_x(state, io, transmit) +462 } else { +463 send_single(state, io, transmit) +464 } +465} +466 +467/// Send using the fast `sendmsg_x` API. +468#[cfg(apple_fast)] +469fn send_via_sendmsg_x( +470 state: &UdpSocketState, +471 io: SockRef<'_>, +472 transmit: &Transmit<'_>, +473) -> io::Result<()> { +474 let mut hdrs = unsafe { mem::zeroed::<[msghdr_x; BATCH_SIZE]>() }; +475 let mut iovs = unsafe { mem::zeroed::<[libc::iovec; BATCH_SIZE]>() }; +476 let mut ctrls = [cmsg::Aligned([0u8; cmsg::LEN]); BATCH_SIZE]; +477 let addr = socket2::SockAddr::from(transmit.destination); +478 let segment_size = transmit.segment_size.unwrap_or(transmit.contents.len()); +479 let mut cnt = 0; +480 debug_assert!(transmit.contents.len().div_ceil(segment_size) <= BATCH_SIZE); +481 for (i, chunk) in transmit +482 .contents +483 .chunks(segment_size) +484 .enumerate() +485 .take(BATCH_SIZE) +486 { +487 prepare_msg_x( +488 &Transmit { +489 destination: transmit.destination, +490 ecn: transmit.ecn, +491 contents: chunk, +492 segment_size: Some(chunk.len()), +493 src_ip: transmit.src_ip, +494 }, +495 &addr, +496 &mut hdrs[i], +497 &mut iovs[i], +498 &mut ctrls[i], +499 true, +500 state.sendmsg_einval(), +501 ); +502 hdrs[i].msg_datalen = chunk.len(); +503 cnt += 1; +504 } +505 let Some(sendmsg_x) = state.resolve_apple_fast_fn(sendmsg_x_fn) else { +506 return send_single(state, io, transmit); +507 }; +508 retry_if_interrupted(|| unsafe { sendmsg_x(io.as_raw_fd(), hdrs.as_ptr(), cnt as u32, 0) })?; +509 Ok(()) +510} +511 +512#[cfg(any(target_os = "openbsd", target_os = "netbsd", apple_slow))] +513fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { +514 send_single(state, io, transmit) +515} +516 +517#[cfg(any(target_os = "openbsd", target_os = "netbsd", apple))] +518#[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled +519fn send_single(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { +520 let mut hdr: libc::msghdr = unsafe { mem::zeroed() }; +521 let mut iov: libc::iovec = unsafe { mem::zeroed() }; +522 let mut ctrl = cmsg::Aligned([0u8; cmsg::LEN]); +523 let addr = socket2::SockAddr::from(transmit.destination); +524 prepare_msg( +525 transmit, +526 &addr, +527 &mut hdr, +528 &mut iov, +529 &mut ctrl, +530 cfg!(apple) || cfg!(target_os = "openbsd") || cfg!(target_os = "netbsd"), +531 state.sendmsg_einval(), +532 ); +533 retry_if_interrupted(|| unsafe { libc::sendmsg(io.as_raw_fd(), &hdr, 0) })?; +534 Ok(()) +535} +536 +537/// Receive using the batched `recvmmsg` syscall. +538#[cfg(not(any( +539 apple, +540 target_os = "openbsd", +541 target_os = "netbsd", +542 target_os = "dragonfly", +543 target_os = "redox", +544 solarish +545)))] +546fn recv_via_recvmmsg( +547 io: SockRef<'_>, +548 bufs: &mut [IoSliceMut<'_>], +549 meta: &mut [RecvMeta], +550) -> io::Result<usize> { +551 let mut names = [MaybeUninit::<libc::sockaddr_storage>::uninit(); BATCH_SIZE]; +552 let mut ctrls = [cmsg::Aligned(MaybeUninit::<[u8; cmsg::LEN]>::uninit()); BATCH_SIZE]; +553 let mut hdrs = unsafe { mem::zeroed::<[libc::mmsghdr; BATCH_SIZE]>() }; +554 let max_msg_count = bufs.len().min(BATCH_SIZE); +555 for i in 0..max_msg_count { +556 prepare_recv( +557 &mut bufs[i], +558 &mut names[i], +559 &mut ctrls[i], +560 &mut hdrs[i].msg_hdr, +561 ); +562 } +563 let msg_count = retry_if_interrupted(|| unsafe { +564 libc::recvmmsg( +565 io.as_raw_fd(), +566 hdrs.as_mut_ptr(), +567 bufs.len().min(BATCH_SIZE) as _, +568 0, +569 ptr::null_mut::<libc::timespec>(), +570 ) as isize +571 })?; +572 for i in 0..(msg_count as usize) { +573 meta[i] = decode_recv(&names[i], &hdrs[i].msg_hdr, hdrs[i].msg_len as usize)?; +574 } +575 Ok(msg_count as usize) +576} +577 +578/// Receive using the fast `recvmsg_x` API. +579#[cfg(apple_fast)] +580fn recv_via_recvmsg_x( +581 state: &UdpSocketState, +582 io: SockRef<'_>, +583 bufs: &mut [IoSliceMut<'_>], +584 meta: &mut [RecvMeta], +585) -> io::Result<usize> { +586 let mut names = [MaybeUninit::<libc::sockaddr_storage>::uninit(); BATCH_SIZE]; +587 // MacOS 10.15 `recvmsg_x` does not override the `msghdr_x` +588 // `msg_controllen`. Thus, after the call to `recvmsg_x`, one does not know +589 // which control messages have been written to. To prevent reading +590 // uninitialized memory, do not use `MaybeUninit` for `ctrls`, instead +591 // initialize `ctrls` with `0`s. A control message of all `0`s is +592 // automatically skipped by `libc::CMSG_NXTHDR`. +593 let mut ctrls = [cmsg::Aligned([0u8; cmsg::LEN]); BATCH_SIZE]; +594 let mut hdrs = unsafe { mem::zeroed::<[msghdr_x; BATCH_SIZE]>() }; +595 let max_msg_count = bufs.len().min(BATCH_SIZE); +596 for i in 0..max_msg_count { +597 prepare_recv_x(&mut bufs[i], &mut names[i], &mut ctrls[i], &mut hdrs[i]); +598 } +599 let Some(recvmsg_x) = state.resolve_apple_fast_fn(recvmsg_x_fn) else { +600 return recv_single(io, bufs, meta); +601 }; +602 let msg_count = retry_if_interrupted(|| unsafe { +603 recvmsg_x(io.as_raw_fd(), hdrs.as_mut_ptr(), max_msg_count as _, 0) +604 })?; +605 for i in 0..(msg_count as usize) { +606 meta[i] = decode_recv(&names[i], &hdrs[i], hdrs[i].msg_datalen as usize)?; +607 } +608 Ok(msg_count as usize) +609} +610 +611/// Returns the `sendmsg_x` function pointer, resolving it via `dlsym` on first call. +612/// +613/// Returns `None` if the symbol is not available on the current OS version. +614#[cfg(apple_fast)] +615fn sendmsg_x_fn() -> Option<SendmsgXFn> { +616 static ADDR: std::sync::OnceLock<usize> = std::sync::OnceLock::new(); +617 // SAFETY: `resolve_symbol` only returns non-zero addresses obtained from `dlsym`, which +618 // guarantees a callable symbol whose type matches the declaration above. +619 resolve_symbol(&ADDR, c"sendmsg_x") +620 .map(|addr| unsafe { std::mem::transmute::<usize, SendmsgXFn>(addr) }) +621} +622 +623/// Returns the `recvmsg_x` function pointer, resolving it via `dlsym` on first call. +624/// +625/// Returns `None` if the symbol is not available on the current OS version. +626#[cfg(apple_fast)] +627fn recvmsg_x_fn() -> Option<RecvmsgXFn> { +628 static ADDR: std::sync::OnceLock<usize> = std::sync::OnceLock::new(); +629 // SAFETY: `resolve_symbol` only returns non-zero addresses obtained from `dlsym`, which +630 // guarantees a callable symbol whose type matches the declaration above. +631 resolve_symbol(&ADDR, c"recvmsg_x") +632 .map(|addr| unsafe { std::mem::transmute::<usize, RecvmsgXFn>(addr) }) +633} +634 +635#[cfg(apple_fast)] +636type SendmsgXFn = +637 unsafe extern "C" fn(libc::c_int, *const msghdr_x, libc::c_uint, libc::c_int) -> isize; +638#[cfg(apple_fast)] +639type RecvmsgXFn = +640 unsafe extern "C" fn(libc::c_int, *mut msghdr_x, libc::c_uint, libc::c_int) -> isize; +641 +642/// Resolves a symbol via `dlsym` on first call, caching the result. +643/// +644/// Returns `None` if the symbol is not available on the current OS version. +645#[cfg(apple_fast)] +646fn resolve_symbol(lock: &std::sync::OnceLock<usize>, name: &std::ffi::CStr) -> Option<usize> { +647 let addr = +648 *lock.get_or_init(|| unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize }); +649 (addr != 0).then_some(addr) +650} +651 +652#[cfg(any( +653 target_os = "openbsd", +654 target_os = "netbsd", +655 target_os = "dragonfly", +656 target_os = "redox", +657 solarish, +658 apple +659))] +660#[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled +661fn recv_single( +662 io: SockRef<'_>, +663 bufs: &mut [IoSliceMut<'_>], +664 meta: &mut [RecvMeta], +665) -> io::Result<usize> { +666 let mut name = MaybeUninit::<libc::sockaddr_storage>::uninit(); +667 let mut ctrl = cmsg::Aligned(MaybeUninit::<[u8; cmsg::LEN]>::uninit()); +668 let mut hdr = unsafe { mem::zeroed::<libc::msghdr>() }; +669 prepare_recv(&mut bufs[0], &mut name, &mut ctrl, &mut hdr); +670 let n = loop { +671 let n = unsafe { libc::recvmsg(io.as_raw_fd(), &mut hdr, 0) }; +672 +673 if hdr.msg_flags & libc::MSG_TRUNC != 0 { +674 continue; +675 } +676 +677 if n >= 0 { +678 break n; +679 } +680 +681 let e = io::Error::last_os_error(); +682 match e.kind() { +683 // Retry receiving +684 io::ErrorKind::Interrupted => continue, +685 _ => return Err(e), +686 } +687 }; +688 meta[0] = decode_recv(&name, &hdr, n as usize)?; +689 Ok(1) +690} +691 +692#[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled +693fn prepare_msg( +694 transmit: &Transmit<'_>, +695 dst_addr: &socket2::SockAddr, +696 hdr: &mut libc::msghdr, +697 iov: &mut libc::iovec, +698 ctrl: &mut cmsg::Aligned<[u8; cmsg::LEN]>, +699 #[allow(unused_variables)] // only used on FreeBSD & macOS +700 encode_src_ip: bool, +701 sendmsg_einval: bool, +702) { +703 iov.iov_base = transmit.contents.as_ptr() as *const _ as *mut _; +704 iov.iov_len = transmit.contents.len(); +705 +706 // SAFETY: Casting the pointer to a mutable one is legal, +707 // as sendmsg is guaranteed to not alter the mutable pointer +708 // as per the POSIX spec. See the section on the sys/socket.h +709 // header for details. The type is only mutable in the first +710 // place because it is reused by recvmsg as well. +711 let name = dst_addr.as_ptr() as *mut libc::c_void; +712 let namelen = dst_addr.len(); +713 hdr.msg_name = name as *mut _; +714 hdr.msg_namelen = namelen; +715 hdr.msg_iov = iov; +716 hdr.msg_iovlen = 1; 717 -718 // SAFETY: Casting the pointer to a mutable one is legal, -719 // as sendmsg is guaranteed to not alter the mutable pointer -720 // as per the POSIX spec. See the section on the sys/socket.h -721 // header for details. The type is only mutable in the first -722 // place because it is reused by recvmsg as well. -723 let name = dst_addr.as_ptr() as *mut libc::c_void; -724 let namelen = dst_addr.len(); -725 hdr.msg_name = name as *mut _; -726 hdr.msg_namelen = namelen; -727 hdr.msg_iov = iov; -728 hdr.msg_iovlen = 1; -729 -730 hdr.msg_control = ctrl.0.as_mut_ptr() as _; -731 hdr.msg_controllen = CMSG_LEN as _; -732 let mut encoder = unsafe { cmsg::Encoder::new(hdr) }; -733 let ecn = transmit.ecn.map_or(0, |x| x as libc::c_int); -734 // True for IPv4 or IPv4-Mapped IPv6 -735 let is_ipv4 = transmit.destination.is_ipv4() -736 || matches!(transmit.destination.ip(), IpAddr::V6(addr) if addr.to_ipv4_mapped().is_some()); -737 if is_ipv4 { -738 if !sendmsg_einval { -739 #[cfg(not(target_os = "netbsd"))] -740 { -741 encoder.push(libc::IPPROTO_IP, libc::IP_TOS, ecn as IpTosTy); -742 } -743 } -744 } else { -745 encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn); -746 } -747 -748 // On apple_fast, prepare_msg is only compiled for send_single (fallback path), while the main -749 // send path uses prepare_msg_x with msghdr_x. gso::set_segment_size has a different signature -750 // when apple_fast is enabled, and it's a no-op on non-Linux platforms anyway. -751 #[cfg(not(apple_fast))] -752 if let Some(segment_size) = transmit.effective_segment_size() { -753 gso::set_segment_size(&mut encoder, segment_size as u16); -754 } -755 -756 if let Some(ip) = &transmit.src_ip { -757 match ip { -758 IpAddr::V4(v4) => { -759 #[cfg(any(target_os = "linux", target_os = "android"))] +718 hdr.msg_control = ctrl.0.as_mut_ptr() as _; +719 hdr.msg_controllen = cmsg::LEN as _; +720 let mut encoder = unsafe { cmsg::Encoder::new(hdr) }; +721 let ecn = transmit.ecn.map_or(0, |x| x as libc::c_int); +722 // True for IPv4 or IPv4-Mapped IPv6 +723 let is_ipv4 = transmit.destination.is_ipv4() +724 || matches!(transmit.destination.ip(), IpAddr::V6(addr) if addr.to_ipv4_mapped().is_some()); +725 if is_ipv4 { +726 if !sendmsg_einval { +727 #[cfg(not(target_os = "netbsd"))] +728 { +729 encoder.push(libc::IPPROTO_IP, libc::IP_TOS, ecn as IpTosTy); +730 } +731 } +732 } else { +733 #[cfg(not(target_os = "redox"))] +734 encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn); +735 } +736 +737 // On apple_fast, prepare_msg is only compiled for send_single (fallback path), while the main +738 // send path uses prepare_msg_x with msghdr_x. gso::set_segment_size has a different signature +739 // when apple_fast is enabled, and it's a no-op on non-Linux platforms anyway. +740 #[cfg(not(apple_fast))] +741 if let Some(segment_size) = transmit.effective_segment_size() { +742 gso::set_segment_size(&mut encoder, segment_size as u16); +743 } +744 +745 if let Some(ip) = &transmit.src_ip { +746 match ip { +747 IpAddr::V4(v4) => { +748 #[cfg(any(target_os = "linux", target_os = "android"))] +749 { +750 let pktinfo = libc::in_pktinfo { +751 ipi_ifindex: 0, +752 ipi_spec_dst: libc::in_addr { +753 s_addr: u32::from_ne_bytes(v4.octets()), +754 }, +755 ipi_addr: libc::in_addr { s_addr: 0 }, +756 }; +757 encoder.push(libc::IPPROTO_IP, libc::IP_PKTINFO, pktinfo); +758 } +759 #[cfg(any(bsd, apple, solarish))] 760 { -761 let pktinfo = libc::in_pktinfo { -762 ipi_ifindex: 0, -763 ipi_spec_dst: libc::in_addr { -764 s_addr: u32::from_ne_bytes(v4.octets()), -765 }, -766 ipi_addr: libc::in_addr { s_addr: 0 }, -767 }; -768 encoder.push(libc::IPPROTO_IP, libc::IP_PKTINFO, pktinfo); -769 } -770 #[cfg(any(bsd, apple, solarish))] -771 { -772 if encode_src_ip { -773 let addr = libc::in_addr { -774 s_addr: u32::from_ne_bytes(v4.octets()), -775 }; -776 encoder.push(libc::IPPROTO_IP, libc::IP_RECVDSTADDR, addr); -777 } -778 } -779 } -780 IpAddr::V6(v6) => { -781 let pktinfo = libc::in6_pktinfo { -782 ipi6_ifindex: 0, -783 ipi6_addr: libc::in6_addr { -784 s6_addr: v6.octets(), -785 }, -786 }; -787 encoder.push(libc::IPPROTO_IPV6, libc::IPV6_PKTINFO, pktinfo); -788 } -789 } -790 } -791 -792 encoder.finish(); -793} -794 -795/// Prepares an `msghdr_x` for use with `sendmsg_x`. -796#[cfg(apple_fast)] -797fn prepare_msg_x( -798 transmit: &Transmit<'_>, -799 dst_addr: &socket2::SockAddr, -800 hdr: &mut msghdr_x, -801 iov: &mut libc::iovec, -802 ctrl: &mut cmsg::Aligned<[u8; CMSG_LEN]>, -803 #[allow(unused_variables)] encode_src_ip: bool, -804 sendmsg_einval: bool, -805) { -806 iov.iov_base = transmit.contents.as_ptr() as *const _ as *mut _; -807 iov.iov_len = transmit.contents.len(); -808 -809 let name = dst_addr.as_ptr() as *mut libc::c_void; -810 let namelen = dst_addr.len(); -811 hdr.msg_name = name as *mut _; -812 hdr.msg_namelen = namelen; -813 hdr.msg_iov = iov; -814 hdr.msg_iovlen = 1; -815 -816 hdr.msg_control = ctrl.0.as_mut_ptr() as _; -817 hdr.msg_controllen = CMSG_LEN as _; -818 let mut encoder = unsafe { cmsg::Encoder::new(hdr) }; -819 let ecn = transmit.ecn.map_or(0, |x| x as libc::c_int); -820 let is_ipv4 = transmit.destination.is_ipv4() -821 || matches!(transmit.destination.ip(), IpAddr::V6(addr) if addr.to_ipv4_mapped().is_some()); -822 if is_ipv4 { -823 if !sendmsg_einval { -824 encoder.push(libc::IPPROTO_IP, libc::IP_TOS, ecn as IpTosTy); -825 } -826 } else { -827 encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn); -828 } -829 -830 if let Some(ip) = &transmit.src_ip { -831 match ip { -832 IpAddr::V4(v4) => { -833 if encode_src_ip { -834 let addr = libc::in_addr { -835 s_addr: u32::from_ne_bytes(v4.octets()), -836 }; -837 encoder.push(libc::IPPROTO_IP, libc::IP_RECVDSTADDR, addr); -838 } -839 } -840 IpAddr::V6(v6) => { -841 let pktinfo = libc::in6_pktinfo { -842 ipi6_ifindex: 0, -843 ipi6_addr: libc::in6_addr { -844 s6_addr: v6.octets(), -845 }, -846 }; -847 encoder.push(libc::IPPROTO_IPV6, libc::IPV6_PKTINFO, pktinfo); -848 } -849 } -850 } -851 -852 encoder.finish(); -853} -854 -855#[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled -856fn prepare_recv( -857 buf: &mut IoSliceMut<'_>, -858 name: &mut MaybeUninit<libc::sockaddr_storage>, -859 ctrl: &mut cmsg::Aligned<MaybeUninit<[u8; CMSG_LEN]>>, -860 hdr: &mut libc::msghdr, -861) { -862 hdr.msg_name = name.as_mut_ptr() as _; -863 hdr.msg_namelen = mem::size_of::<libc::sockaddr_storage>() as _; -864 hdr.msg_iov = buf as *mut IoSliceMut<'_> as *mut libc::iovec; -865 hdr.msg_iovlen = 1; -866 hdr.msg_control = ctrl.0.as_mut_ptr() as _; -867 hdr.msg_controllen = CMSG_LEN as _; -868 hdr.msg_flags = 0; -869} -870 -871/// Prepares an `msghdr_x` for receiving with `recvmsg_x`. -872#[cfg(apple_fast)] -873fn prepare_recv_x( -874 buf: &mut IoSliceMut<'_>, -875 name: &mut MaybeUninit<libc::sockaddr_storage>, -876 ctrl: &mut cmsg::Aligned<[u8; CMSG_LEN]>, -877 hdr: &mut msghdr_x, -878) { -879 hdr.msg_name = name.as_mut_ptr() as _; -880 hdr.msg_namelen = mem::size_of::<libc::sockaddr_storage>() as _; -881 hdr.msg_iov = buf as *mut IoSliceMut<'_> as *mut libc::iovec; -882 hdr.msg_iovlen = 1; -883 hdr.msg_control = ctrl.0.as_mut_ptr() as _; -884 hdr.msg_controllen = CMSG_LEN as _; -885 hdr.msg_flags = 0; -886 hdr.msg_datalen = buf.len(); -887} -888 -889fn decode_recv<M: cmsg::MsgHdr<ControlMessage = libc::cmsghdr>>( -890 name: &MaybeUninit<libc::sockaddr_storage>, -891 hdr: &M, -892 len: usize, -893) -> io::Result<RecvMeta> { -894 let name = unsafe { name.assume_init() }; -895 let mut ctrl = ControlMetadata { -896 ecn_bits: 0, -897 dst_ip: None, -898 interface_index: None, -899 stride: len, -900 }; -901 -902 let cmsg_iter = unsafe { cmsg::Iter::new(hdr) }; -903 for cmsg in cmsg_iter { -904 ctrl.decode(cmsg); -905 } -906 -907 Ok(RecvMeta { -908 len, -909 stride: ctrl.stride, -910 addr: decode_socket_addr(&name)?, -911 ecn: EcnCodepoint::from_bits(ctrl.ecn_bits), -912 dst_ip: ctrl.dst_ip, -913 interface_index: ctrl.interface_index, -914 }) +761 if encode_src_ip { +762 let addr = libc::in_addr { +763 s_addr: u32::from_ne_bytes(v4.octets()), +764 }; +765 encoder.push(libc::IPPROTO_IP, libc::IP_RECVDSTADDR, addr); +766 } +767 } +768 } +769 #[cfg(target_os = "redox")] +770 IpAddr::V6(_) => {} +771 #[cfg(not(target_os = "redox"))] +772 IpAddr::V6(v6) => { +773 let pktinfo = libc::in6_pktinfo { +774 ipi6_ifindex: 0, +775 ipi6_addr: libc::in6_addr { +776 s6_addr: v6.octets(), +777 }, +778 }; +779 encoder.push(libc::IPPROTO_IPV6, libc::IPV6_PKTINFO, pktinfo); +780 } +781 } +782 } +783 +784 encoder.finish(); +785} +786 +787/// Prepares an `msghdr_x` for use with `sendmsg_x`. +788#[cfg(apple_fast)] +789fn prepare_msg_x( +790 transmit: &Transmit<'_>, +791 dst_addr: &socket2::SockAddr, +792 hdr: &mut msghdr_x, +793 iov: &mut libc::iovec, +794 ctrl: &mut cmsg::Aligned<[u8; cmsg::LEN]>, +795 #[allow(unused_variables)] encode_src_ip: bool, +796 sendmsg_einval: bool, +797) { +798 iov.iov_base = transmit.contents.as_ptr() as *const _ as *mut _; +799 iov.iov_len = transmit.contents.len(); +800 +801 let name = dst_addr.as_ptr() as *mut libc::c_void; +802 let namelen = dst_addr.len(); +803 hdr.msg_name = name as *mut _; +804 hdr.msg_namelen = namelen; +805 hdr.msg_iov = iov; +806 hdr.msg_iovlen = 1; +807 +808 hdr.msg_control = ctrl.0.as_mut_ptr() as _; +809 hdr.msg_controllen = cmsg::LEN as _; +810 let mut encoder = unsafe { cmsg::Encoder::new(hdr) }; +811 let ecn = transmit.ecn.map_or(0, |x| x as libc::c_int); +812 let is_ipv4 = transmit.destination.is_ipv4() +813 || matches!(transmit.destination.ip(), IpAddr::V6(addr) if addr.to_ipv4_mapped().is_some()); +814 if is_ipv4 { +815 if !sendmsg_einval { +816 encoder.push(libc::IPPROTO_IP, libc::IP_TOS, ecn as IpTosTy); +817 } +818 } else { +819 encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn); +820 } +821 +822 if let Some(ip) = &transmit.src_ip { +823 match ip { +824 IpAddr::V4(v4) => { +825 if encode_src_ip { +826 let addr = libc::in_addr { +827 s_addr: u32::from_ne_bytes(v4.octets()), +828 }; +829 encoder.push(libc::IPPROTO_IP, libc::IP_RECVDSTADDR, addr); +830 } +831 } +832 IpAddr::V6(v6) => { +833 let pktinfo = libc::in6_pktinfo { +834 ipi6_ifindex: 0, +835 ipi6_addr: libc::in6_addr { +836 s6_addr: v6.octets(), +837 }, +838 }; +839 encoder.push(libc::IPPROTO_IPV6, libc::IPV6_PKTINFO, pktinfo); +840 } +841 } +842 } +843 +844 encoder.finish(); +845} +846 +847#[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled +848fn prepare_recv( +849 buf: &mut IoSliceMut<'_>, +850 name: &mut MaybeUninit<libc::sockaddr_storage>, +851 ctrl: &mut cmsg::Aligned<MaybeUninit<[u8; cmsg::LEN]>>, +852 hdr: &mut libc::msghdr, +853) { +854 hdr.msg_name = name.as_mut_ptr() as _; +855 hdr.msg_namelen = mem::size_of::<libc::sockaddr_storage>() as _; +856 hdr.msg_iov = buf as *mut IoSliceMut<'_> as *mut libc::iovec; +857 hdr.msg_iovlen = 1; +858 hdr.msg_control = ctrl.0.as_mut_ptr() as _; +859 hdr.msg_controllen = cmsg::LEN as _; +860 hdr.msg_flags = 0; +861} +862 +863/// Prepares an `msghdr_x` for receiving with `recvmsg_x`. +864#[cfg(apple_fast)] +865fn prepare_recv_x( +866 buf: &mut IoSliceMut<'_>, +867 name: &mut MaybeUninit<libc::sockaddr_storage>, +868 ctrl: &mut cmsg::Aligned<[u8; cmsg::LEN]>, +869 hdr: &mut msghdr_x, +870) { +871 hdr.msg_name = name.as_mut_ptr() as _; +872 hdr.msg_namelen = mem::size_of::<libc::sockaddr_storage>() as _; +873 hdr.msg_iov = buf as *mut IoSliceMut<'_> as *mut libc::iovec; +874 hdr.msg_iovlen = 1; +875 hdr.msg_control = ctrl.0.as_mut_ptr() as _; +876 hdr.msg_controllen = cmsg::LEN as _; +877 hdr.msg_flags = 0; +878 hdr.msg_datalen = buf.len(); +879} +880 +881fn decode_recv<M: cmsg::MsgHdr<ControlMessage = libc::cmsghdr>>( +882 name: &MaybeUninit<libc::sockaddr_storage>, +883 hdr: &M, +884 len: usize, +885) -> io::Result<RecvMeta> { +886 let name = unsafe { name.assume_init() }; +887 let mut ctrl = ControlMetadata { +888 ecn_bits: 0, +889 dst_ip: None, +890 interface_index: None, +891 stride: len, +892 }; +893 +894 let cmsg_iter = unsafe { cmsg::Iter::new(hdr) }; +895 for cmsg in cmsg_iter { +896 ctrl.decode(cmsg); +897 } +898 +899 Ok(RecvMeta { +900 len, +901 stride: ctrl.stride, +902 addr: decode_socket_addr(&name)?, +903 ecn: EcnCodepoint::from_bits(ctrl.ecn_bits), +904 dst_ip: ctrl.dst_ip, +905 interface_index: ctrl.interface_index, +906 }) +907} +908 +909/// Metadata decoded from control messages +910struct ControlMetadata { +911 ecn_bits: u8, +912 dst_ip: Option<IpAddr>, +913 interface_index: Option<u32>, +914 stride: usize, 915} 916 -917/// Metadata decoded from control messages -918struct ControlMetadata { -919 ecn_bits: u8, -920 dst_ip: Option<IpAddr>, -921 interface_index: Option<u32>, -922 stride: usize, -923} -924 -925impl ControlMetadata { -926 /// Decodes a control message and updates the metadata state -927 fn decode(&mut self, cmsg: &libc::cmsghdr) { -928 match (cmsg.cmsg_level, cmsg.cmsg_type) { -929 (libc::IPPROTO_IP, libc::IP_TOS) => unsafe { -930 self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg); -931 }, -932 // FreeBSD uses IP_RECVTOS here, and we can be liberal because cmsgs are opt-in. -933 #[cfg(not(any( -934 target_os = "openbsd", -935 target_os = "netbsd", -936 target_os = "dragonfly", -937 solarish -938 )))] -939 (libc::IPPROTO_IP, libc::IP_RECVTOS) => unsafe { -940 self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg); -941 }, -942 (libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => unsafe { -943 // Temporary hack around broken macos ABI. Remove once upstream fixes it. -944 // https://bugreport.apple.com/web/?problemID=48761855 -945 #[allow(clippy::unnecessary_cast)] // cmsg.cmsg_len defined as size_t -946 if cfg!(apple) -947 && cmsg.cmsg_len as usize == libc::CMSG_LEN(mem::size_of::<u8>() as _) as usize -948 { -949 self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg); -950 } else { -951 self.ecn_bits = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as u8; -952 } -953 }, -954 #[cfg(any(target_os = "linux", target_os = "android"))] -955 (libc::IPPROTO_IP, libc::IP_PKTINFO) => { -956 let pktinfo = unsafe { cmsg::decode::<libc::in_pktinfo, libc::cmsghdr>(cmsg) }; -957 self.dst_ip = Some(IpAddr::V4(Ipv4Addr::from( -958 pktinfo.ipi_addr.s_addr.to_ne_bytes(), -959 ))); -960 self.interface_index = Some(pktinfo.ipi_ifindex as u32); -961 } -962 #[cfg(any(bsd, apple))] -963 (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { -964 let in_addr = unsafe { cmsg::decode::<libc::in_addr, libc::cmsghdr>(cmsg) }; -965 self.dst_ip = Some(IpAddr::V4(Ipv4Addr::from(in_addr.s_addr.to_ne_bytes()))); -966 } -967 (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { -968 let pktinfo = unsafe { cmsg::decode::<libc::in6_pktinfo, libc::cmsghdr>(cmsg) }; -969 self.dst_ip = Some(IpAddr::V6(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr))); -970 #[cfg_attr(not(target_os = "android"), expect(clippy::unnecessary_cast))] -971 { -972 self.interface_index = Some(pktinfo.ipi6_ifindex as u32); -973 } -974 } -975 #[cfg(any(target_os = "linux", target_os = "android"))] -976 (libc::SOL_UDP, libc::UDP_GRO) => unsafe { -977 self.stride = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as usize; -978 }, -979 _ => {} -980 } -981 } -982} -983 -984/// Decodes a `sockaddr_storage` into a `SocketAddr` -985fn decode_socket_addr(name: &libc::sockaddr_storage) -> io::Result<SocketAddr> { -986 match libc::c_int::from(name.ss_family) { -987 libc::AF_INET => { -988 // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in. -989 let addr: &libc::sockaddr_in = -990 unsafe { &*(name as *const _ as *const libc::sockaddr_in) }; -991 Ok(SocketAddr::V4(SocketAddrV4::new( -992 Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()), -993 u16::from_be(addr.sin_port), -994 ))) -995 } -996 libc::AF_INET6 => { -997 // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6. -998 let addr: &libc::sockaddr_in6 = -999 unsafe { &*(name as *const _ as *const libc::sockaddr_in6) }; -1000 Ok(SocketAddr::V6(SocketAddrV6::new( -1001 Ipv6Addr::from(addr.sin6_addr.s6_addr), -1002 u16::from_be(addr.sin6_port), -1003 addr.sin6_flowinfo, -1004 addr.sin6_scope_id, -1005 ))) -1006 } -1007 f => Err(io::Error::other(format!( -1008 "expected AF_INET or AF_INET6, got {f}" -1009 ))), -1010 } -1011} -1012 -1013#[cfg(not(apple_slow))] -1014// Chosen somewhat arbitrarily; might benefit from additional tuning. -1015pub(crate) const BATCH_SIZE: usize = 32; -1016 -1017#[cfg(apple_slow)] -1018pub(crate) const BATCH_SIZE: usize = 1; -1019 -1020#[cfg(any(target_os = "linux", target_os = "android"))] -1021mod gso { -1022 use super::*; -1023 use std::{ffi::CStr, mem, str::FromStr, sync::OnceLock}; -1024 -1025 // Support for UDP GSO has been added to linux kernel in version 4.18 -1026 // https://github.com/torvalds/linux/commit/cb586c63e3fc5b227c51fd8c4cb40b34d3750645 -1027 const SUPPORTED_SINCE: KernelVersion = KernelVersion { -1028 version: 4, -1029 major_revision: 18, -1030 }; +917impl ControlMetadata { +918 /// Decodes a control message and updates the metadata state +919 fn decode(&mut self, cmsg: &libc::cmsghdr) { +920 match (cmsg.cmsg_level, cmsg.cmsg_type) { +921 (libc::IPPROTO_IP, libc::IP_TOS) => unsafe { +922 self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg); +923 }, +924 // FreeBSD uses IP_RECVTOS here, and we can be liberal because cmsgs are opt-in. +925 #[cfg(not(any( +926 target_os = "openbsd", +927 target_os = "netbsd", +928 target_os = "dragonfly", +929 solarish +930 )))] +931 (libc::IPPROTO_IP, libc::IP_RECVTOS) => unsafe { +932 self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg); +933 }, +934 #[cfg(not(target_os = "redox",))] +935 (libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => unsafe { +936 // Temporary hack around broken macos ABI. Remove once upstream fixes it. +937 // https://bugreport.apple.com/web/?problemID=48761855 +938 #[allow(clippy::unnecessary_cast)] // cmsg.cmsg_len defined as size_t +939 if cfg!(apple) +940 && cmsg.cmsg_len as usize == libc::CMSG_LEN(mem::size_of::<u8>() as _) as usize +941 { +942 self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg); +943 } else { +944 self.ecn_bits = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as u8; +945 } +946 }, +947 #[cfg(any(target_os = "linux", target_os = "android"))] +948 (libc::IPPROTO_IP, libc::IP_PKTINFO) => { +949 let pktinfo = unsafe { cmsg::decode::<libc::in_pktinfo, libc::cmsghdr>(cmsg) }; +950 self.dst_ip = Some(IpAddr::V4(Ipv4Addr::from( +951 pktinfo.ipi_addr.s_addr.to_ne_bytes(), +952 ))); +953 self.interface_index = Some(pktinfo.ipi_ifindex as u32); +954 } +955 #[cfg(any(bsd, apple))] +956 (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { +957 let in_addr = unsafe { cmsg::decode::<libc::in_addr, libc::cmsghdr>(cmsg) }; +958 self.dst_ip = Some(IpAddr::V4(Ipv4Addr::from(in_addr.s_addr.to_ne_bytes()))); +959 } +960 #[cfg(not(target_os = "redox",))] +961 (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { +962 let pktinfo = unsafe { cmsg::decode::<libc::in6_pktinfo, libc::cmsghdr>(cmsg) }; +963 self.dst_ip = Some(IpAddr::V6(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr))); +964 #[cfg_attr(not(target_os = "android"), expect(clippy::unnecessary_cast))] +965 { +966 self.interface_index = Some(pktinfo.ipi6_ifindex as u32); +967 } +968 } +969 #[cfg(any(target_os = "linux", target_os = "android"))] +970 (libc::SOL_UDP, libc::UDP_GRO) => unsafe { +971 self.stride = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as usize; +972 }, +973 _ => {} +974 } +975 } +976} +977 +978/// Decodes a `sockaddr_storage` into a `SocketAddr` +979fn decode_socket_addr(name: &libc::sockaddr_storage) -> io::Result<SocketAddr> { +980 match libc::c_int::from(name.ss_family) { +981 libc::AF_INET => { +982 // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in. +983 let addr: &libc::sockaddr_in = +984 unsafe { &*(name as *const _ as *const libc::sockaddr_in) }; +985 Ok(SocketAddr::V4(SocketAddrV4::new( +986 Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()), +987 u16::from_be(addr.sin_port), +988 ))) +989 } +990 libc::AF_INET6 => { +991 // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6. +992 let addr: &libc::sockaddr_in6 = +993 unsafe { &*(name as *const _ as *const libc::sockaddr_in6) }; +994 Ok(SocketAddr::V6(SocketAddrV6::new( +995 Ipv6Addr::from(addr.sin6_addr.s6_addr), +996 u16::from_be(addr.sin6_port), +997 addr.sin6_flowinfo, +998 addr.sin6_scope_id, +999 ))) +1000 } +1001 f => Err(io::Error::other(format!( +1002 "expected AF_INET or AF_INET6, got {f}" +1003 ))), +1004 } +1005} +1006 +1007#[cfg(not(apple_slow))] +1008// Chosen somewhat arbitrarily; might benefit from additional tuning. +1009pub(crate) const BATCH_SIZE: usize = 32; +1010 +1011#[cfg(apple_slow)] +1012pub(crate) const BATCH_SIZE: usize = 1; +1013 +1014#[cfg(any(target_os = "linux", target_os = "android"))] +1015mod gso { +1016 use super::*; +1017 use std::{ffi::CStr, mem, str::FromStr, sync::OnceLock}; +1018 +1019 // Support for UDP GSO has been added to linux kernel in version 4.18 +1020 // https://github.com/torvalds/linux/commit/cb586c63e3fc5b227c51fd8c4cb40b34d3750645 +1021 const SUPPORTED_SINCE: KernelVersion = KernelVersion { +1022 version: 4, +1023 major_revision: 18, +1024 }; +1025 +1026 /// Checks whether GSO support is available. +1027 /// +1028 /// Checks the kernel version followed by setting the UDP_SEGMENT option on a socket. +1029 pub(crate) fn max_gso_segments(socket: &impl AsRawFd) -> usize { +1030 const GSO_SIZE: libc::c_int = 1500; 1031 -1032 /// Checks whether GSO support is available by checking the kernel version followed by setting -1033 /// the UDP_SEGMENT option on a socket -1034 pub(crate) fn max_gso_segments(socket: &impl AsRawFd) -> usize { -1035 const GSO_SIZE: libc::c_int = 1500; -1036 -1037 if !SUPPORTED_BY_CURRENT_KERNEL.get_or_init(supported_by_current_kernel) { -1038 return 1; -1039 } -1040 -1041 // As defined in linux/udp.h -1042 // #define UDP_MAX_SEGMENTS (1 << 6UL) -1043 match set_socket_option(socket, libc::SOL_UDP, libc::UDP_SEGMENT, GSO_SIZE) { -1044 Ok(()) => { -1045 // Disable GSO again globally to ensure we can selectively enable it via cmsg. -1046 // See: -1047 // - https://github.com/quinn-rs/quinn/issues/2575 -1048 // - https://man7.org/linux/man-pages/man7/udp.7.html -1049 let _ = set_socket_option(socket, libc::SOL_UDP, libc::UDP_SEGMENT, 0); -1050 -1051 64 -1052 } -1053 Err(_e) => { -1054 crate::log::debug!( -1055 "failed to set `UDP_SEGMENT` socket option ({_e}); setting `max_gso_segments = 1`" -1056 ); +1032 if !SUPPORTED_BY_CURRENT_KERNEL.get_or_init(supported_by_current_kernel) { +1033 return 1; +1034 } +1035 +1036 // As defined in linux/udp.h +1037 // #define UDP_MAX_SEGMENTS (1 << 6UL) +1038 match set_socket_option(socket, libc::SOL_UDP, libc::UDP_SEGMENT, GSO_SIZE) { +1039 Ok(()) => { +1040 // Disable GSO again globally to ensure we can selectively enable it via cmsg. +1041 // See: +1042 // - https://github.com/quinn-rs/quinn/issues/2575 +1043 // - https://man7.org/linux/man-pages/man7/udp.7.html +1044 let _ = set_socket_option(socket, libc::SOL_UDP, libc::UDP_SEGMENT, 0); +1045 +1046 64 +1047 } +1048 Err(_e) => { +1049 crate::log::debug!( +1050 "failed to set `UDP_SEGMENT` socket option ({_e}); setting `max_gso_segments = 1`" +1051 ); +1052 +1053 1 +1054 } +1055 } +1056 } 1057 -1058 1 -1059 } -1060 } -1061 } -1062 -1063 pub(crate) fn set_segment_size( -1064 encoder: &mut cmsg::Encoder<'_, libc::msghdr>, -1065 segment_size: u16, -1066 ) { -1067 encoder.push(libc::SOL_UDP, libc::UDP_SEGMENT, segment_size); -1068 } -1069 -1070 // Avoid calling `supported_by_current_kernel` for each socket by using `OnceLock`. -1071 static SUPPORTED_BY_CURRENT_KERNEL: OnceLock<bool> = OnceLock::new(); -1072 -1073 fn supported_by_current_kernel() -> bool { -1074 let kernel_version_string = match kernel_version_string() { -1075 Ok(kernel_version_string) => kernel_version_string, -1076 Err(_e) => { -1077 crate::log::warn!("GSO disabled: uname returned {_e}"); -1078 return false; -1079 } -1080 }; -1081 -1082 let Some(kernel_version) = KernelVersion::from_str(&kernel_version_string) else { -1083 crate::log::warn!( -1084 "GSO disabled: failed to parse kernel version ({kernel_version_string})" -1085 ); +1058 pub(crate) fn set_segment_size( +1059 encoder: &mut cmsg::Encoder<'_, libc::msghdr>, +1060 segment_size: u16, +1061 ) { +1062 encoder.push(libc::SOL_UDP, libc::UDP_SEGMENT, segment_size); +1063 } +1064 +1065 // Avoid calling `supported_by_current_kernel` for each socket by using `OnceLock`. +1066 static SUPPORTED_BY_CURRENT_KERNEL: OnceLock<bool> = OnceLock::new(); +1067 +1068 fn supported_by_current_kernel() -> bool { +1069 let kernel_version_string = match kernel_version_string() { +1070 Ok(kernel_version_string) => kernel_version_string, +1071 Err(_e) => { +1072 crate::log::warn!("GSO disabled: uname returned {_e}"); +1073 return false; +1074 } +1075 }; +1076 +1077 let Some(kernel_version) = KernelVersion::from_str(&kernel_version_string) else { +1078 crate::log::warn!( +1079 "GSO disabled: failed to parse kernel version ({kernel_version_string})" +1080 ); +1081 return false; +1082 }; +1083 +1084 if kernel_version < SUPPORTED_SINCE { +1085 crate::log::info!("GSO disabled: kernel too old ({kernel_version_string}); need 4.18+",); 1086 return false; -1087 }; +1087 } 1088 -1089 if kernel_version < SUPPORTED_SINCE { -1090 crate::log::info!("GSO disabled: kernel too old ({kernel_version_string}); need 4.18+",); -1091 return false; -1092 } -1093 -1094 true -1095 } -1096 -1097 fn kernel_version_string() -> io::Result<String> { -1098 let mut n = unsafe { mem::zeroed() }; -1099 let r = unsafe { libc::uname(&mut n) }; -1100 if r != 0 { -1101 return Err(io::Error::last_os_error()); -1102 } -1103 Ok(unsafe { -1104 CStr::from_ptr(n.release[..].as_ptr()) -1105 .to_string_lossy() -1106 .into_owned() -1107 }) -1108 } -1109 -1110 // https://www.linfo.org/kernel_version_numbering.html -1111 #[derive(Eq, PartialEq, Ord, PartialOrd, Debug)] -1112 struct KernelVersion { -1113 version: u8, -1114 major_revision: u8, -1115 } -1116 -1117 impl KernelVersion { -1118 fn from_str(release: &str) -> Option<Self> { -1119 let mut split = release -1120 .split_once('-') -1121 .map(|pair| pair.0) -1122 .unwrap_or(release) -1123 .split('.'); -1124 -1125 let version = u8::from_str(split.next()?).ok()?; -1126 let major_revision = u8::from_str(split.next()?).ok()?; -1127 -1128 Some(Self { -1129 version, -1130 major_revision, -1131 }) -1132 } -1133 } -1134 -1135 #[cfg(test)] -1136 mod test { -1137 use super::*; -1138 -1139 #[test] -1140 fn parse_current_kernel_version_release_string() { -1141 let release = kernel_version_string().unwrap(); -1142 KernelVersion::from_str(&release).unwrap(); -1143 } -1144 -1145 #[test] -1146 fn parse_kernel_version_release_string() { -1147 // These are made up for the test -1148 assert_eq!( -1149 KernelVersion::from_str("4.14"), -1150 Some(KernelVersion { -1151 version: 4, -1152 major_revision: 14 -1153 }) -1154 ); -1155 assert_eq!( -1156 KernelVersion::from_str("4.18"), -1157 Some(KernelVersion { -1158 version: 4, -1159 major_revision: 18 -1160 }) -1161 ); -1162 // These were seen in the wild -1163 assert_eq!( -1164 KernelVersion::from_str("4.14.186-27095505"), -1165 Some(KernelVersion { -1166 version: 4, -1167 major_revision: 14 -1168 }) -1169 ); -1170 assert_eq!( -1171 KernelVersion::from_str("6.8.0-59-generic"), -1172 Some(KernelVersion { -1173 version: 6, -1174 major_revision: 8 -1175 }) -1176 ); -1177 } -1178 } -1179} -1180 -1181// On Apple platforms using the `sendmsg_x` call, UDP datagram segmentation is not -1182// offloaded to the NIC or even the kernel, but instead done here in user space in -1183// [`send`]) and then passed to the OS as individual `iovec`s (up to `BATCH_SIZE`). -1184// The initial value is 1 (no batching); callers can enable batching via -1185// `UdpSocketState::set_apple_fast_path()` which updates `max_gso_segments`. -1186#[cfg(not(any(target_os = "linux", target_os = "android")))] -1187mod gso { -1188 use super::*; -1189 -1190 pub(super) fn max_gso_segments(_socket: &impl AsRawFd) -> usize { -1191 1 -1192 } -1193 -1194 #[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled -1195 pub(super) fn set_segment_size( -1196 #[cfg(not(apple_fast))] _encoder: &mut cmsg::Encoder<'_, libc::msghdr>, -1197 #[cfg(apple_fast)] _encoder: &mut cmsg::Encoder<'_, msghdr_x>, -1198 _segment_size: u16, -1199 ) { -1200 } -1201} -1202 -1203/// Returns whether the given socket option is supported on the current platform -1204/// -1205/// Yields `Ok(true)` if the option was set successfully, `Ok(false)` if setting -1206/// the option raised an `ENOPROTOOPT` or `EOPNOTSUPP` error, and `Err` for any other error. -1207fn set_socket_option_supported( -1208 socket: &impl AsRawFd, -1209 level: libc::c_int, -1210 name: libc::c_int, -1211 value: libc::c_int, -1212) -> io::Result<bool> { -1213 match set_socket_option(socket, level, name, value) { -1214 Ok(()) => Ok(true), -1215 Err(err) if err.raw_os_error() == Some(libc::ENOPROTOOPT) => Ok(false), -1216 Err(err) if err.raw_os_error() == Some(libc::EOPNOTSUPP) => Ok(false), -1217 Err(err) => Err(err), -1218 } -1219} -1220 -1221fn set_socket_option( -1222 socket: &impl AsRawFd, -1223 level: libc::c_int, -1224 name: libc::c_int, -1225 value: libc::c_int, -1226) -> io::Result<()> { -1227 let rc = unsafe { -1228 libc::setsockopt( -1229 socket.as_raw_fd(), -1230 level, -1231 name, -1232 &value as *const _ as _, -1233 mem::size_of_val(&value) as _, -1234 ) -1235 }; -1236 -1237 match rc == 0 { -1238 true => Ok(()), -1239 false => Err(io::Error::last_os_error()), -1240 } -1241} -1242 -1243const OPTION_ON: libc::c_int = 1; -1244 -1245/// Calls `f` in a loop, retrying on `EINTR`, and returns the non-negative result or the first -1246/// non-`EINTR` error. -1247fn retry_if_interrupted(mut f: impl FnMut() -> isize) -> io::Result<isize> { -1248 loop { -1249 let n = f(); -1250 if n >= 0 { -1251 return Ok(n); -1252 } -1253 let e = io::Error::last_os_error(); -1254 if e.kind() != io::ErrorKind::Interrupted { -1255 return Err(e); -1256 } -1257 } -1258} \ No newline at end of file +1089 true +1090 } +1091 +1092 fn kernel_version_string() -> io::Result<String> { +1093 let mut n = unsafe { mem::zeroed() }; +1094 let r = unsafe { libc::uname(&mut n) }; +1095 if r != 0 { +1096 return Err(io::Error::last_os_error()); +1097 } +1098 Ok(unsafe { +1099 CStr::from_ptr(n.release[..].as_ptr()) +1100 .to_string_lossy() +1101 .into_owned() +1102 }) +1103 } +1104 +1105 // https://www.linfo.org/kernel_version_numbering.html +1106 #[derive(Eq, PartialEq, Ord, PartialOrd, Debug)] +1107 struct KernelVersion { +1108 version: u8, +1109 major_revision: u8, +1110 } +1111 +1112 impl KernelVersion { +1113 fn from_str(release: &str) -> Option<Self> { +1114 let mut split = release +1115 .split_once('-') +1116 .map(|pair| pair.0) +1117 .unwrap_or(release) +1118 .split('.'); +1119 +1120 let version = u8::from_str(split.next()?).ok()?; +1121 let major_revision = u8::from_str(split.next()?).ok()?; +1122 +1123 Some(Self { +1124 version, +1125 major_revision, +1126 }) +1127 } +1128 } +1129 +1130 #[cfg(test)] +1131 mod test { +1132 use super::*; +1133 +1134 #[test] +1135 fn parse_current_kernel_version_release_string() { +1136 let release = kernel_version_string().unwrap(); +1137 KernelVersion::from_str(&release).unwrap(); +1138 } +1139 +1140 #[test] +1141 fn parse_kernel_version_release_string() { +1142 // These are made up for the test +1143 assert_eq!( +1144 KernelVersion::from_str("4.14"), +1145 Some(KernelVersion { +1146 version: 4, +1147 major_revision: 14 +1148 }) +1149 ); +1150 assert_eq!( +1151 KernelVersion::from_str("4.18"), +1152 Some(KernelVersion { +1153 version: 4, +1154 major_revision: 18 +1155 }) +1156 ); +1157 // These were seen in the wild +1158 assert_eq!( +1159 KernelVersion::from_str("4.14.186-27095505"), +1160 Some(KernelVersion { +1161 version: 4, +1162 major_revision: 14 +1163 }) +1164 ); +1165 assert_eq!( +1166 KernelVersion::from_str("6.8.0-59-generic"), +1167 Some(KernelVersion { +1168 version: 6, +1169 major_revision: 8 +1170 }) +1171 ); +1172 } +1173 } +1174} +1175 +1176// On Apple platforms using the `sendmsg_x` call, UDP datagram segmentation is not +1177// offloaded to the NIC or even the kernel, but instead done here in user space in +1178// [`send`]) and then passed to the OS as individual `iovec`s (up to `BATCH_SIZE`). +1179// The initial value is 1 (no batching); callers can enable batching via +1180// `UdpSocketState::set_apple_fast_path()` which updates `max_gso_segments`. +1181#[cfg(not(any(target_os = "linux", target_os = "android")))] +1182mod gso { +1183 use super::*; +1184 +1185 pub(super) fn max_gso_segments(_socket: &impl AsRawFd) -> usize { +1186 1 +1187 } +1188 +1189 #[cfg_attr(apple_fast, allow(dead_code))] // Unused when apple_fast is enabled +1190 pub(super) fn set_segment_size( +1191 #[cfg(not(apple_fast))] _encoder: &mut cmsg::Encoder<'_, libc::msghdr>, +1192 #[cfg(apple_fast)] _encoder: &mut cmsg::Encoder<'_, msghdr_x>, +1193 _segment_size: u16, +1194 ) { +1195 } +1196} +1197 +1198// Adapted from https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/bsd/sys/socket_private.h +1199#[cfg(apple_fast)] +1200#[repr(C)] +1201#[allow(non_camel_case_types)] +1202pub(crate) struct msghdr_x { +1203 pub msg_name: *mut libc::c_void, +1204 pub msg_namelen: libc::socklen_t, +1205 pub msg_iov: *mut libc::iovec, +1206 pub msg_iovlen: libc::c_int, +1207 pub msg_control: *mut libc::c_void, +1208 pub msg_controllen: libc::socklen_t, +1209 pub msg_flags: libc::c_int, +1210 pub msg_datalen: usize, +1211} +1212 +1213#[cfg(target_os = "freebsd")] +1214type IpTosTy = libc::c_uchar; +1215#[cfg(not(any(target_os = "freebsd", target_os = "netbsd")))] +1216type IpTosTy = libc::c_int; +1217 +1218/// Returns whether the given socket option is supported on the current platform +1219/// +1220/// Yields `Ok(true)` if the option was set successfully, `Ok(false)` if setting +1221/// the option raised an `ENOPROTOOPT` or `EOPNOTSUPP` error, and `Err` for any other error. +1222fn set_socket_option_supported( +1223 socket: &impl AsRawFd, +1224 level: libc::c_int, +1225 name: libc::c_int, +1226 value: libc::c_int, +1227) -> io::Result<bool> { +1228 match set_socket_option(socket, level, name, value) { +1229 Ok(()) => Ok(true), +1230 Err(err) if err.raw_os_error() == Some(libc::ENOPROTOOPT) => Ok(false), +1231 Err(err) if err.raw_os_error() == Some(libc::EOPNOTSUPP) => Ok(false), +1232 Err(err) => Err(err), +1233 } +1234} +1235 +1236fn set_socket_option( +1237 socket: &impl AsRawFd, +1238 level: libc::c_int, +1239 name: libc::c_int, +1240 value: libc::c_int, +1241) -> io::Result<()> { +1242 let rc = unsafe { +1243 libc::setsockopt( +1244 socket.as_raw_fd(), +1245 level, +1246 name, +1247 &value as *const _ as _, +1248 mem::size_of_val(&value) as _, +1249 ) +1250 }; +1251 +1252 match rc == 0 { +1253 true => Ok(()), +1254 false => Err(io::Error::last_os_error()), +1255 } +1256} +1257 +1258const OPTION_ON: libc::c_int = 1; +1259 +1260/// Calls `f` in a loop, retrying on `EINTR`. +1261/// +1262/// Returns the non-negative result or the first non-`EINTR` error. +1263fn retry_if_interrupted(mut f: impl FnMut() -> isize) -> io::Result<isize> { +1264 loop { +1265 let n = f(); +1266 if n >= 0 { +1267 return Ok(n); +1268 } +1269 let e = io::Error::last_os_error(); +1270 if e.kind() != io::ErrorKind::Interrupted { +1271 return Err(e); +1272 } +1273 } +1274} \ No newline at end of file