diff --git a/data/example-sicd-1.0.1.xml b/data/example-sicd-1.0.1.xml new file mode 100644 index 0000000..1688711 --- /dev/null +++ b/data/example-sicd-1.0.1.xml @@ -0,0 +1,1156 @@ + + + Synthetic + SyntheticCore + MONOSTATIC + + SPOTLIGHT + + UNCLASSIFIED + + + Valkyrie Systems Sage | sar_common_kit 1.9.0.0 + 2022-12-05T18:43:30.208726Z + + + RE32F_IM32F + 1494 + 1723 + 0 + 0 + + 1494 + 1723 + + + 747 + 861 + + + + 256 + 343 + + + 256 + 484 + + + 256 + 624 + + + 256 + 765 + + + 256 + 905 + + + 256 + 1046 + + + 256 + 1186 + + + 256 + 1327 + + + 256 + 1468 + + + 379 + 1456 + + + 502 + 1445 + + + 624 + 1434 + + + 747 + 1423 + + + 870 + 1412 + + + 992 + 1401 + + + 1115 + 1390 + + + 1238 + 1378 + + + 1238 + 1238 + + + 1238 + 1097 + + + 1238 + 957 + + + 1238 + 817 + + + 1238 + 676 + + + 1238 + 536 + + + 1238 + 395 + + + 1238 + 255 + + + 1115 + 266 + + + 992 + 277 + + + 870 + 288 + + + 747 + 299 + + + 624 + 310 + + + 502 + 321 + + + 379 + 332 + + + + + WGS_84 + + + 6378137 + 0 + 0 + + + 0 + 0 + 0 + + + + + 0.0080807974971151136 + -0.0061258326901634519 + + + 0.0056733384282420182 + 0.0074368679872295704 + + + -0.008071597406306948 + 0.0061267096368526897 + + + -0.0056641383373949505 + -0.0074359910405444127 + + + + + 0.005238360895824838 + -0.0036433852169764111 + + + 0.0050420582635510016 + -0.0025375503997010318 + + + 0.004845755628902701 + -0.0014317155805202205 + + + 0.0046494529921086835 + -0.00032588076026081428 + + + 0.0044531503533953975 + 0.00077995406025051814 + + + 0.0042568477129873231 + 0.0018857888801836113 + + + 0.004060545071107439 + 0.0029916236987124986 + + + 0.0038642424279800454 + 0.0040974585150061532 + + + 0.003667939783831225 + 0.0052032933282371652 + + + 0.0025546522020080289 + 0.0050083048147242385 + + + 0.0014413646175311253 + 0.0048133163010931164 + + + 0.00032807703126864579 + 0.0046183277873471356 + + + -0.00078521055587245359 + 0.0044233392734964747 + + + -0.0018984981430081194 + 0.0042283507595426628 + + + -0.003011785729254395 + 0.0040333622454942607 + + + -0.0041250733137164937 + 0.0038383737313532821 + + + -0.0052383608955085424 + 0.003643385217128532 + + + -0.0050420582632763646 + 0.0025375503997804791 + + + -0.0048457556287156058 + 0.0014317155805582487 + + + -0.0046494529920602899 + 0.00032588076028108935 + + + -0.0044531503535271385 + -0.00077995406023062997 + + + -0.0042568477133461038 + -0.0018857888801565275 + + + -0.0040605450717476526 + -0.0029916236986777789 + + + -0.0038642424289528294 + -0.004097458514977414 + + + -0.0036679397851883686 + -0.0052032933282338163 + + + -0.0025546522030494749 + -0.0050083048147000261 + + + -0.0014413646182779216 + -0.0048133163010521838 + + + -0.00032807703177041223 + -0.0046183277872955016 + + + 0.00078521055559128701 + -0.0044233392734311441 + + + 0.0018984981429170419 + -0.0042283507594636036 + + + 0.003011785729324451 + -0.0040333622453953642 + + + 0.0041250733139214331 + -0.0038383737312319729 + + + + + [6378137.0, -405.5797876726389, 579.2279653395692] + + + [6378137.0, 86.82408883346518, 492.403876506104] + + + [6378137.0, 579.2279653395692, 405.5797876726388] + + + [6378137.0, -492.40387650610404, 86.8240888334652] + + + [6378137.0, 0.0, 0.0] + + + [6378137.0, 492.40387650610404, -86.8240888334652] + + + [6378137.0, -579.2279653395692, -405.5797876726388] + + + [6378137.0, -86.82408883346518, -492.403876506104] + + + [6378137.0, 405.5797876726389, -579.2279653395692] + + + + + SLANT + RGAZIM + + 1.6800674762530383 + + + + -0.50000122375786304 + -0.15037583977714006 + -0.8528692064148875 + + 0.88229809656554448 + 0.99747529707162585 + -1 + 0.88798408351600244 + 66.712157247222834 + -0.44399204175799412 + 0.44399204175800833 + + -0 + + + + + -0.13518643844872713 + 0.98628938466763816 + -0.094646059985916131 + + 0.8788669876603048 + 0.99666461341322399 + -1 + 0.88870636679539183 + 1.3449549529642717e-08 + -0.44435318339769592 + 0.44435318339769592 + + -0 + + + + + 2022-12-05T18:41:24.051402Z + 3.4668291025146964 + + + 0.0056816659534297907 + 1.734252544716481 + 0 + 1040 + + -3.4200358124461596 + 601.94243049797956 + -2.5957560931224679e-05 + -2.0559365748016132e-08 + 8.5465035653447778e-11 + 1.5613913034987107e-13 + + + + 1.734252544716481 + 3.4628234234795321 + 1041 + 2080 + + -3.4200358124461596 + 601.94243049797956 + -2.5957560931224679e-05 + -2.0559365748016132e-08 + 8.5465035653447778e-11 + 1.5613913034987107e-13 + + + + + + + + 7228127.9124448663 + 352.53242998756502 + -3.5891719134975157 + -5.7694198643316104e-05 + 2.7699968593303768e-07 + 2.1592636134572539e-09 + + + 268129.91744542622 + -7332.3823879634392 + -0.13313219332893028 + 0.0012135963117010783 + 1.0196690368353028e-08 + 1.3607911396273635e-11 + + + 1451527.4824241539 + -401.08990372640221 + -0.72076439428225647 + 6.6511087447480695e-05 + 5.6690990559856781e-08 + 3.2123861103114586e-10 + + + + + 6378136.9999999972 + -2.7603991862673482e-10 + -8.8046691538817019e-10 + 3.6552842678534889e-10 + -4.5501609492503518e-13 + + + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + + + + + 7228127.9122881154 + 352.53243031729494 + -3.5891718145261389 + -5.7760778794926364e-05 + 2.961407356089768e-07 + 1.5152746784999351e-10 + + + 268129.91754994984 + -7332.3823894408897 + -0.13313219336015877 + 0.0012135939299440443 + 1.0894413139775905e-08 + -6.1574812416329165e-11 + + + 1451527.4820069293 + -401.0899032701904 + -0.72076438617145899 + 6.6502336106517436e-05 + 5.9235211780521735e-08 + 4.8536679801755301e-11 + + + + + + 7228127.9122881237 + 352.53243031084878 + -3.5891718013492584 + -5.7769234785477141e-05 + 2.985788077956373e-07 + -1.4884336849092922e-10 + + + 268129.91754994984 + -7332.3823894398674 + -0.13313219479068839 + 0.0012135948482529309 + 1.0630300780216877e-08 + -3.4535962553841784e-11 + + + 1451527.4820069303 + -401.08990326673984 + -0.72076439093449318 + 6.6505493849440306e-05 + 5.8315612455559405e-08 + 1.3835573401835279e-10 + + + + + + + 9933296178.0950012 + 10066703821.904999 + + + + + V + + + V:V + 1 + + + + + + 0.0052383608956667301 + -0.0036433852170520572 + 0.039373653940856457 + + + 0.0036679397845088379 + 0.0052032933282355155 + 0.039283305406570435 + + + -0.0052383608956667301 + 0.0036433852170520572 + 0.039373653940856457 + + + -0.0036679397845088379 + -0.0052032933282355155 + 0.039283305406570435 + + + + + + 6378137 + 0 + 0 + + 650 + 750 + + + + 0 + -0.17364817766693033 + -0.98480775301220813 + + 0.76980043496519579 + 1301 + 0 + + + + 0 + 0.98480775301220813 + -0.17364817766693033 + + 0.66641108974957253 + 1501 + 0 + + + + + + + 1 + 1 + + V:V + 0.0056816659534327432 + 3.4611621345438324 + + 9933296178.0950298 + 10066703821.905016 + + PFA + NO + NO + NO + NO + + inscription + true + fixed + fixed + + + polar_deterministic_phase + true + true + none + none + one_dimensional + + + + 1.6800674762530383 + + 7228710.0595508879 + 255810.65024467336 + 1450851.5901888732 + + + 340.47184478328006 + -7332.8194533174392 + -403.5112050640754 + + + -7.1789158206813477 + -0.25403049783428427 + -1.4408563791978921 + + L + 1701141.9562064605 + 1282320.3392587577 + 80.000333057346595 + 30.000080950049 + 59.999919049951004 + 8.9805970546123763 + 31.195125856239255 + 9.9994779614198173 + 352.45909403041333 + + + + ABSOLUTE + + -47.698407849729996 + + + + 234.567891 + 0.0123456789 + 3.45678912e-05 + 1.23456789e-09 + 2.34567891e-12 + 1.23456789e-16 + 1.23456789e-19 + -0.023456789 + -5.67891234e-06 + -4.56789123e-09 + -8.91234567e-13 + -4.56789123e-16 + -9.12345678e-20 + -3.45678912e-23 + 5.67891234e-05 + 3.45678912e-09 + 7.89123456e-12 + 4.56789123e-16 + 5.67891234e-19 + 6.78912345e-23 + 5.67891234e-26 + -6.78912345e-09 + -1.23456789e-12 + -1.23456789e-15 + -7.89123456e-20 + -6.78912345e-23 + -5.67891234e-26 + -1.23456789e-29 + 7.89123456e-12 + 5.67891234e-16 + 1.23456789e-18 + 1.23456789e-22 + 1.23456789e-25 + 1.23456789e-29 + 6.78912345e-33 + -1.23456789e-15 + -1.23456789e-19 + -1.23456789e-22 + -8.91234567e-26 + -4.56789123e-29 + 9.12345678e-33 + 2.34567891e-36 + + + + + + + 0.13982986262005959 + -0.0027594341203054122 + -2.642141233211328e-06 + 1.4412928975132546e-08 + 4.9106827976192821e-11 + -1.1406011989724555e-13 + + + -0.985103968766331 + -0.00072022999981332595 + 8.6929909937280073e-06 + 1.7419413461433799e-08 + -7.0195266020811239e-11 + -3.1383419971071391e-13 + + + 0.10008886172036295 + -0.0032336279155612555 + -3.6150726160461875e-06 + 2.4227194540266762e-08 + 6.8535490141060762e-11 + -1.9455706113121084e-13 + + + + + -0.85523535607199153 + -0.00010473716447760117 + 1.0612386361416289e-06 + 1.2191988789775561e-10 + -6.5342561715559025e-13 + 3.2519400278010645e-16 + + + -0.06921308838843146 + 0.00073787526119144643 + 7.399077245060788e-08 + -1.0525875572605681e-09 + -3.3788216228145983e-14 + 7.6241787500235205e-16 + + + 0.51359715158881925 + -7.4969848184029868e-05 + 1.2309351838082699e-06 + 3.5096979204331667e-10 + -2.0820927565561895e-12 + -5.4913780628865013e-16 + + + 10000000000 + + + 0 + + + 0 + + + + + 0 + -4.1430777012935061e-12 + -25810177.686242383 + -0.00014382609695309318 + -13687592749336.885 + 292.19947867443852 + -4.2115648774405212e+18 + -1442527537.8580344 + -4.4559066869820204e+25 + -4.1430777012935061e-12 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -25810177.686242383 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -0.00014382609695309318 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -13687592749336.885 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 292.19947867443852 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -4.2115648774405212e+18 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1442527537.8580344 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -4.4559066869820204e+25 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + + + + + 0 + + + 0 + + + + 0 + + false + + + + + 0.13982986262005959 + -0.0027594341203054122 + -2.642141233211328e-06 + 1.4412928975132546e-08 + 4.9106827976192821e-11 + -1.1406011989724555e-13 + + + -0.985103968766331 + -0.00072022999981332595 + 8.6929909937280073e-06 + 1.7419413461433799e-08 + -7.0195266020811239e-11 + -3.1383419971071391e-13 + + + 0.10008886172036295 + -0.0032336279155612555 + -3.6150726160461875e-06 + 2.4227194540266762e-08 + 6.8535490141060762e-11 + -1.9455706113121084e-13 + + + + + -0.85523535607199153 + -0.00010473716447760117 + 1.0612386361416289e-06 + 1.2191988789775561e-10 + -6.5342561715559025e-13 + 3.2519400278010645e-16 + + + -0.06921308838843146 + 0.00073787526119144643 + 7.399077245060788e-08 + -1.0525875572605681e-09 + -3.3788216228145983e-14 + 7.6241787500235205e-16 + + + 0.51359715158881925 + -7.4969848184029868e-05 + 1.2309351838082699e-06 + 3.5096979204331667e-10 + -2.0820927565561895e-12 + -5.4913780628865013e-16 + + + 10000000000 + + + 0 + + + 0 + + + + + 0 + -4.1430777012935061e-12 + -25810177.686242383 + -0.00014382609695309318 + -13687592749336.885 + 292.19947867443852 + -4.2115648774405212e+18 + -1442527537.8580344 + -4.4559066869820204e+25 + -4.1430777012935061e-12 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -25810177.686242383 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -0.00014382609695309318 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -13687592749336.885 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 292.19947867443852 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -4.2115648774405212e+18 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1442527537.8580344 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -4.4559066869820204e+25 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + + + + + 0 + + + 0 + + + + 0 + + false + + + + + 0.13982986262005959 + -0.0027594341203054122 + -2.642141233211328e-06 + + + -0.985103968766331 + -0.00072022999981332595 + 8.6929909937280073e-06 + + + 0.10008886172036295 + -0.0032336279155612555 + -3.6150726160461875e-06 + + + + + -0.85523535607199153 + -0.00010473716447760117 + 1.0612386361416289e-06 + + + -0.06921308838843146 + 0.00073787526119144643 + 7.399077245060788e-08 + + + 0.51359715158881925 + -7.4969848184029868e-05 + 1.2309351838082699e-06 + + + 10000000000 + + + 0 + + + 0 + + + + + 0 + -4.1430777012935061e-12 + -25810177.686242383 + -4.1430777012935061e-12 + 0 + 0 + -25810177.686242383 + 0 + 0 + + + 0 + + + + + 0 + + + 0 + + + + 0 + + false + + + + + 1 + 0 + 0 + + + 0.85540832579135895 + 0.067973204303252321 + -0.51347467325894713 + + 1.6800674762530463 + + -0.0071413060968959627 + 0.004245118151048095 + 3.303261280436797e-06 + -2.152475729568344e-08 + -5.5340201006749593e-11 + 1.6174039129702326e-13 + 1.2038148814517427e-15 + -1.0008410326624715e-16 + 1.6819824323114349e-17 + -1.1931290667377136e-18 + + + 0.99999143699142279 + 2.1389170906735031e-05 + 0.051388964320644458 + 0.0048322065140747042 + -0.020014437732713723 + 0.0023716850734943114 + 0.14153200650672734 + 4.5834686287659396 + -1395.0901983623608 + + 66.268165205464854 + 67.156149288980856 + -0.44524655663963569 + 0.44524655663963569 + + diff --git a/data/syntax_only/sicd/make_syntax_only_sicd_xmls.py b/data/syntax_only/sicd/make_syntax_only_sicd_xmls.py index 65afb56..b80ceee 100644 --- a/data/syntax_only/sicd/make_syntax_only_sicd_xmls.py +++ b/data/syntax_only/sicd/make_syntax_only_sicd_xmls.py @@ -234,6 +234,7 @@ def main(args=None): diff.diff_files or { pathlib.Path(__file__).name, + "manual-syntax-only-sicd-1.0.1.xml", "manual-syntax-only-sicd-1.1.0.xml", "stubs", }.symmetric_difference(diff.left_only) diff --git a/data/syntax_only/sicd/manual-syntax-only-sicd-1.0.1.xml b/data/syntax_only/sicd/manual-syntax-only-sicd-1.0.1.xml new file mode 100644 index 0000000..9fa4cec --- /dev/null +++ b/data/syntax_only/sicd/manual-syntax-only-sicd-1.0.1.xml @@ -0,0 +1,871 @@ + + + Synthetic + Synthetic + SyntheticCore + MONOSTATIC + + SPOTLIGHT + Syntax-only Mode + + UNCLASSIFIED + SYNTAX-ONLY0 + SYNTAX-ONLY1 + 1.23 + 4.56 + + + Valkyrie Systems Sage + 2022-12-05T18:43:30.208726Z + SyntaxOnlySite + SyntaxOnlyProfile + + + RE32F_IM32F + 1494 + 1723 + 0 + 0 + + 1494 + 1723 + + + 747 + 861 + + + + 256 + 343 + + + 256 + 484 + + + 256 + 624 + + + 256 + 765 + + + 256 + 905 + + + + + WGS_84 + + + 6378137 + 0 + 0 + + + 0 + 0 + 0 + + + + + 0.0080807974971151136 + -0.0061258326901634519 + + + 0.0056733384282420182 + 0.0074368679872295704 + + + -0.008071597406306948 + 0.0061267096368526897 + + + -0.0056641383373949505 + -0.0074359910405444127 + + + + + 0.005238360895824838 + -0.0036433852169764111 + + + 0.0050420582635510016 + -0.0025375503997010318 + + + 0.004845755628902701 + -0.0014317155805202205 + + + 0.0046494529921086835 + -0.00032588076026081428 + + + 0.0044531503533953975 + 0.00077995406025051814 + + + + Description 0 + + + 0.0046494529921086835 + -0.00032588076026081428 + + + 0.0044531503533953975 + 0.00077995406025051814 + + + + Nested Description + + 0.0044531503533953975 + 0.00077995406025051814 + + + Double nested Description + + + 0.005238360895824838 + -0.0036433852169764111 + + + 0.0050420582635510016 + -0.0025375503997010318 + + + 0.004845755628902701 + -0.0014317155805202205 + + + + + + + + SLANT + RGAZIM + + 1.6800674762530383 + + + + -0.50000122375786304 + -0.15037583977714006 + -0.8528692064148875 + + 0.88229809656554448 + 0.99747529707162585 + -1 + 0.88798408351600244 + 66.712157247222834 + -0.44399204175799412 + 0.44399204175800833 + + -0 + + + SyntaxWindowRow + SyntaxWindowParameterValue0 + SyntaxWindowParameterValue1 + + + 0.111 + 0.222 + + + + + -0.13518643844872713 + 0.98628938466763816 + -0.094646059985916131 + + 0.8788669876603048 + 0.99666461341322399 + -1 + 0.88870636679539183 + 1.3449549529642717e-08 + -0.44435318339769592 + 0.44435318339769592 + + -0 + + + SyntaxWindowCol + SyntaxWindowParameterValue0 + + + 0.333 + 0.444 + 0.555 + 0.666 + 0.777 + 0.888 + 0.999 + 0.101010 + 0.11111 + 0.121212 + + + + + 2022-12-05T18:41:24.051402Z + 3.4668291025146964 + + + 0.0056816659534297907 + 1.734252544716481 + 0 + 1040 + + -3.4200358124461596 + 601.94243049797956 + + + + 1.734252544716481 + 3.4628234234795321 + 1041 + 2080 + + -3.4200358124461596 + 1.5613913034987107e-13 + + + + + + + + 7228127.9124448663 + 2.1592636134572539e-09 + + + 268129.91744542622 + 1.3607911396273635e-11 + + + 1451527.4824241539 + 3.2123861103114586e-10 + + + + + 6378136.9999999972 + -2.7603991862673482e-10 + -4.5501609492503518e-13 + + + 0 + + + 0 + + + + + 7228127.9122881154 + 1.5152746784999351e-10 + + + 268129.91754994984 + -7332.3823894408897 + -0.13313219336015877 + + + 1451527.4820069293 + -401.0899032701904 + + + + + + 7228127.9122881237 + -3.5891718013492584 + -1.4884336849092922e-10 + + + 268129.91754994984 + 1.0630300780216877e-08 + -3.4535962553841784e-11 + + + 1451527.4820069303 + 6.6505493849440306e-05 + 5.8315612455559405e-08 + 1.3835573401835279e-10 + + + + + 7228127.9122881237 + 352.53243031084878 + + + 268129.91754994984 + -7332.3823894398674 + + + 1451527.4820069303 + -401.08990326673984 + + + + + + + 9933296178.0950012 + 10066703821.904999 + + 1 + + + 1.1 + 2.2 + 3.3 + 4.4 + STRETCH + 5.5 + 6.6 + 7.7 + 8.8 + 9.9 + + + 10.10 + + + V + + + 1 + V + + + 2 + H + + + + + V:V + 1 + + + + + + 0.0052383608956667301 + -0.0036433852170520572 + 0.039373653940856457 + + + 0.0036679397845088379 + 0.0052032933282355155 + 0.039283305406570435 + + + -0.0052383608956667301 + 0.0036433852170520572 + 0.039373653940856457 + + + -0.0036679397845088379 + -0.0052032933282355155 + 0.039283305406570435 + + + + + + 6378137 + 0 + 0 + + 650 + 750 + + + + 0 + -0.17364817766693033 + -0.98480775301220813 + + 0.76980043496519579 + 1301 + 0 + + + + 0 + 0.98480775301220813 + -0.17364817766693033 + + 0.66641108974957253 + 1501 + 0 + + + + 0 + 0 + 10 + 10 + Seg1 + + + 20 + 20 + 200 + 200 + Seg2 + + + ARBITRARY + + + rcvalue0 + rcvalue1 + + + + 1 + 1.23456 + 1 + + V:V + 0.0056816659534327432 + 3.4611621345438324 + + 9933296178.0950298 + 10066703821.905016 + + Seg1 + PFA + NO + NO + NO + NO + + inscription + true + fixed + fixed + + + polar_deterministic_phase + true + true + none + none + one_dimensional + + + false + + 2022-01-01T18:43:30.208726Z + 1.1 + + 2.2 + 3.3 + + + 4.4 + 5.5 + + + 6.6 + 7.7 + + + 8.8 + 9.9 + + + 0.0 + -1.1 + + + -2.2 + -3.3 + + 1.111 + 2.222 + 3.333 + 4.444 + 5.555 + + + + + 1.6800674762530383 + + 7228710.0595508879 + 255810.65024467336 + 1450851.5901888732 + + + 340.47184478328006 + -7332.8194533174392 + -403.5112050640754 + + + -7.1789158206813477 + -0.25403049783428427 + -1.4408563791978921 + + L + 1701141.9562064605 + 1282320.3392587577 + 80.000333057346595 + 30.000080950049 + 59.999919049951004 + 8.9805970546123763 + 31.195125856239255 + 9.9994779614198173 + 352.45909403041333 + + + + ABSOLUTE + + -47.698407849729996 + + + + 234.567891 + 0.0123456789 + 2.34567891e-36 + + + 234.567891 + 0.0123456789 + + + 234.567891 + + + 234.567891 + 0.0123456789 + + + + + + + -1.1406011989724555e-13 + + + -3.1383419971071391e-13 + + + -1.9455706113121084e-13 + + + + + 3.2519400278010645e-16 + + + 7.6241787500235205e-16 + + + -5.4913780628865013e-16 + + + 10000000000 + + + 0 + + + 0 + + + + + 0 + -4.1430777012935061e-12 + -25810177.686242383 + -0.00014382609695309318 + + + 0 + + + + + 0 + + + 0 + + + + 0 + + true + false + + + + + 0.13982986262005959 + + + -0.985103968766331 + + + 0.10008886172036295 + + + + + -0.00010473716447760117 + + + 0.00073787526119144643 + + + -7.4969848184029868e-05 + + + 10000000000 + + + 0 + + + 0 + + + + + 0 + -4.1430777012935061e-12 + + + 0 + + + + + 0 + + + 0 + + + + 0 + + true + false + + + + + 0.13982986262005959 + -0.0027594341203054122 + -2.642141233211328e-06 + + + -0.985103968766331 + -0.00072022999981332595 + 8.6929909937280073e-06 + + + 0.10008886172036295 + -0.0032336279155612555 + -3.6150726160461875e-06 + + + + + -0.85523535607199153 + -0.00010473716447760117 + 1.0612386361416289e-06 + + + -0.06921308838843146 + 0.00073787526119144643 + 7.399077245060788e-08 + + + 0.51359715158881925 + -7.4969848184029868e-05 + 1.2309351838082699e-06 + + + 10000000000 + + + 0 + + + 0 + + + + + -4.1430777012935061e-12 + -25810177.686242383 + + + 0 + + + + + 0 + + + 0 + + + + 0 + + true + false + + + + + 1.1 + 2.2 + 0.3 + + + + ECF + 1.1 + 1.2 + 1.3 + 2.1 + 2.2 + 2.3 + + 0.12 + 0.13 + 0.111 + 0.112 + 0.113 + 0.23 + 0.211 + 0.212 + 0.213 + 0.311 + 0.312 + 0.313 + 0.1112 + 0.1113 + 0.1213 + + + 0.123 + 0.456 + + + + 111.111 + 222.222 + 333.333 + + 0.1234 + 0.4567 + + + + 1111.11 + 2222.22 + + 0.12345 + 0.45678 + + + + 11111.1 + 22222.2 + 0.333333 + + 0.123456 + 0.456789 + + + + + added to error stats + 24 + + + + 2 + + COHERENT + 1 + 1 + + SyntaxCore0 + 00 + + + + STEREO + 2 + 3 + + SyntaxCore1 + 11 + match parameter 0 + match parameter 1 + + + SyntaxCore2 + 22 + + + SyntaxCore3 + 33 + + + + + + 1 + 0 + 0 + + + 0.85540832579135895 + 0.067973204303252321 + -0.51347467325894713 + + 1.6800674762530463 + + 0.004245118151048095 + -1.1931290667377136e-18 + + + 0.99999143699142279 + -1395.0901983623608 + + 66.268165205464854 + 67.156149288980856 + -0.44524655663963569 + 0.44524655663963569 + + false + + 0.1234 + + + + diff --git a/example-sicd-1.4.0.xml b/example-sicd-1.4.0.xml new file mode 100644 index 0000000..8031dff --- /dev/null +++ b/example-sicd-1.4.0.xml @@ -0,0 +1,1155 @@ + + + SyntheticCollector + SyntheticIlluminator + SyntheticCore + BISTATIC + + SPOTLIGHT + + UNCLASSIFIED + + + + Valkyrie Systems Sage | sar_common_kit 1.12.7.0 + 2024-05-29T14:14:28.527158Z + + + RE16I_IM16I + 5727 + 2362 + 0 + 0 + + 5727 + 2362 + + + 2862 + 1181 + + + + 257 + 458 + + + 257 + 664 + + + 257 + 871 + + + 257 + 1077 + + + 257 + 1283 + + + 257 + 1489 + + + 257 + 1695 + + + 258 + 1901 + + + 909 + 1927 + + + 1560 + 1953 + + + 2212 + 1979 + + + 2863 + 2005 + + + 3515 + 2032 + + + 4167 + 2058 + + + 4819 + 2084 + + + 5471 + 2110 + + + 5470 + 1904 + + + 5470 + 1697 + + + 5470 + 1491 + + + 5470 + 1285 + + + 5470 + 1079 + + + 5470 + 873 + + + 5470 + 667 + + + 5471 + 461 + + + 4819 + 435 + + + 4167 + 409 + + + 3515 + 382 + + + 2863 + 356 + + + 2212 + 330 + + + 1560 + 304 + + + 909 + 278 + + + 258 + 252 + + + + + WGS_84 + + + 6378137.0 + 0.0 + 0.0 + + + 0.0 + 0.0 + 0.0 + + + + + 0.014897862606592356 + -0.017437308528912253 + + + 0.014897768031627434 + 0.021163623843799044 + + + -0.014908271521658396 + 0.017419658573337677 + + + -0.014908176943349049 + -0.021181273798596613 + + + + + 0.013565541682007258 + -0.010106046843261916 + + + 0.013565541801622458 + -0.0067373646010435535 + + + 0.01356554187325984 + -0.003368682312502394 + + + 0.013565541897120899 + -8.516417242015484e-13 + + + 0.013565541873261311 + 0.0033686823106291604 + + + 0.013565541801625912 + 0.006737364598634134 + + + 0.013565541682010298 + 0.010106046839808005 + + + 0.013565541514099444 + 0.013474729010749732 + + + 0.010174156220276785 + 0.01347472901163532 + + + 0.006782770853358983 + 0.013474729012158562 + + + 0.0033913854376698156 + 0.013474729012430834 + + + -2.6022512747123617e-12 + 0.013474729012516382 + + + -0.003391385443368514 + 0.013474729012433899 + + + -0.006782770860703309 + 0.013474729012166842 + + + -0.01017415623079379 + 0.013474729011650225 + + + -0.01356554152995587 + 0.013474729010784626 + + + -0.013565541692520524 + 0.010106046839828532 + + + -0.013565541808964347 + 0.006737364598650603 + + + -0.013565541878958582 + 0.003368682310640344 + + + -0.013565541902314552 + -8.418411092555245e-13 + + + -0.013565541878965639 + -0.0033686823124879583 + + + -0.013565541808972332 + -0.00673736460103327 + + + -0.013565541692531232 + -0.010106046843241515 + + + -0.013565541529955526 + -0.013474729015924553 + + + -0.010174156230794866 + -0.013474729015065781 + + + -0.0067827708607095276 + -0.013474729014560594 + + + -0.0033913854433709027 + -0.013474729014291217 + + + -2.5992199764179006e-12 + -0.01347472901420946 + + + 0.003391385437666461 + -0.013474729014291921 + + + 0.006782770853353226 + -0.013474729014563733 + + + 0.010174156220270113 + -0.013474729015082692 + + + 0.013565541514092755 + -0.01347472901595803 + + + + + [6378137.0, -1500.0000000000002, 1499.9999999999998] + + + [6378137.0, -1.3597399555105185e-13, 1500.0] + + + [6378137.0, 1499.9999999999998, 1500.0000000000002] + + + [6378137.0, -1500.0, -1.3597399555105185e-13] + + + [6378137.0, 0.0, 0.0] + + + [6378137.0, 1500.0, 1.3597399555105185e-13] + + + [6378137.0, -1499.9999999999998, -1500.0000000000002] + + + [6378137.0, 1.3597399555105185e-13, -1500.0] + + + [6378137.0, 1500.0000000000002, -1499.9999999999998] + + + + + SLANT + RGAZIM + + 1.220622599302364 + + + + -0.6324666831642389 + -1.8785395735164345e-06 + -0.7745875646155944 + + 0.4457608086829121 + 0.5052016895768469 + -1 + 1.753244705578659 + 52.73973463842882 + -0.8766223527893331 + 0.876622352789326 + + -7.1054273576009995e-15 + + + 0.24 + 1 + 0.24 + + + + + 0.15186491422355175 + 0.9805917870219334 + -0.12400320535344456 + + 1.7839287889393634 + 1.992421560873471 + -1 + 0.4445556125741249 + 1.4140792425898493e-08 + -0.22227780628706245 + 0.22227780628706245 + + -0.0 + + + 0.08 + 1 + 0.08 + + + + + 2024-05-29T14:12:54.201358Z + 2.5506314363333673 + + + 0.0056816788146032745 + 2.5457378091913605 + 0 + 3267 + + -7.309967755320728 + 1286.5858834408305 + -5.5515038096979516e-05 + -4.3570087476994035e-08 + 1.8377033854619403e-10 + 1.5271499300195306e-13 + + + + + + + + 7454209.806422097 + 188.91655848763938 + -2.362373172007106 + 0.008127437652222326 + -2.92667702058293e-05 + -1.368075007928718e-07 + + + -7806.301805510545 + 6399.79719992698 + -1.5176922483654318 + 0.012467192043075523 + 3.726013254183058e-05 + -1.397447612729364e-07 + + + 1320352.0463603565 + -1803.7760411526824 + 2.4966351791850445 + 0.004834761184214687 + -3.7703330808027104e-05 + -9.370498209584064e-08 + + + + + 6378136.999999999 + 1.0117353019721192e-09 + -1.300545089959474e-09 + 9.753603318545005e-10 + -1.8293251800574153e-12 + + + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + + + 7228591.873064234 + 349.35203072665144 + -3.5888150542803015 + -5.723841062565759e-05 + 3.0087728187636757e-07 + -4.625526166678253e-10 + + + -1049712.7187069822 + 6236.733905546889 + 0.5211481133917936 + -0.001032145860271645 + -4.4279215119308946e-08 + 2.3725686228796543e-10 + + + 1037377.8795793299 + 3876.4857837673303 + -0.5150370396531049 + -0.0006413991418346274 + 4.1109885533649076e-08 + 2.732374834891698e-10 + + + + + + 7228591.873064231 + 349.35203073848567 + -3.5888150782417543 + -5.721932194916093e-05 + 2.9420750505303616e-07 + 3.7643643999940754e-10 + + + 1037377.879579329 + 3876.485783772678 + -0.5150370506416224 + -0.0006413897271125511 + 3.7579090483879526e-08 + 7.661408873950234e-10 + + + 1049712.7187069813 + -6236.733905544733 + -0.5211481187626775 + 0.001032150750149735 + 4.233522616045636e-08 + 5.136923640479921e-11 + + + + + + + 9831251195.313576 + 10168748804.686424 + + + + 1.3499904374914016e-05 + 337497609.3728504 + 9831251195.313576 + 25000000000000.0 + STRETCH + 2.5878502230492327e-05 + 371357935.6673492 + 340411441.0284035 + 9831251195.313576 + 25000000000000.0 + + + V + + + V:V + 1 + + + + + + 0.013565541522053958 + -0.01347472901336879 + 0.3539563147351146 + + + 0.013565541522053961 + 0.013474729013368785 + 0.3539563147351146 + + + -0.013565541522053958 + 0.01347472901336879 + 0.3539563147351146 + + + -0.013565541522053961 + -0.013474729013368785 + 0.3539563147351146 + + + + + + 6378137.0 + 0.0 + 0.0 + + 3486.0 + 1125.0 + + + + 0.0 + 7.850462293418876e-17 + -1.0 + + 0.43033155140602114 + 6973 + 0 + + + + 0.0 + 1.0 + 7.850462293418876e-17 + + 1.3334613092121825 + 2251 + 0 + + + + 0 + 0 + 6972 + 1125 + seg_a + + + 0 + 1127 + 6972 + 2250 + seg_b + + + + + + + + 1 + 1 + + V:V + 0.005681678814600955 + 2.544960558148007 + + 9831251195.31346 + 10168748804.68658 + + seg_a + PFA + NO + NO + NO + NO + + inscription + true + fixed + fixed + + + Valkyrie Systems Sage | sar_common_kit 1.12.7.0 @ 2024-05-29T14:12:54.542381Z + true + + + polar_deterministic_phase + true + true + none + none + one_dimensional + + + + 1.220622599302364 + + 7454436.897212301 + 3.196803887290116 + 1318154.045054647 + + + 183.18553958831498 + 6396.148135849851 + -1797.6598076071073 + + + -4.665751377210959 + -2.943416986273964 + 5.028001363512413 + + R + 1701749.5571450454 + 1116294.5815923752 + 78.92654152200815 + 39.232345287680424 + 50.767654712319576 + -11.30659792863627 + 40.57506621800416 + 0.00013895445024772232 + 17.54326436775956 + + 75.52489181855174 + -0.0340344908580102 + + + + 7229011.019446171 + -1042134.655298896 + 1042086.8397567043 + + + 340.63134517481444 + 6237.995668410955 + 3875.2314592071652 + + + -7.178042045200563 + 1.0347714409874964 + -1.034748933920567 + + R + 1701756.803523214 + 1282722.60115929 + 79.99897665632014 + 29.999829628178375 + 60.000170371821625 + 314.9986855385722 + + + + + 7229014.886120505 + 1042130.8346154559 + 1042063.8361967074 + + + 340.54985391074274 + 3875.2197116091465 + -6238.007415617825 + + + -7.17804584140809 + -1.034792608466006 + -1.0347011189112367 + + R + 1701742.3107668809 + 1282705.8664475959 + 79.99897665619744 + 30.000261674499125 + 59.99973832550087 + 45.001841827292225 + + + + + + ABSOLUTE + + -70.61028002864373 + + + + 1.0009107550886 + -1.2656962480467898e-08 + 1.841160823979366e-07 + 7.37605984703672e-14 + 2.3376306367702188e-14 + 1.8645443146453884e-06 + -5.974449624682831e-08 + 1.477222002059004e-13 + -1.567005982925404e-14 + 5.62973990351021e-21 + 2.9915266098531715e-07 + -2.5952777137288582e-14 + 6.391795060352621e-14 + 5.490727612893473e-20 + 1.0910470909479996e-20 + -3.652591414143523e-14 + -1.457647634489385e-14 + -4.566165397967709e-20 + -1.0062412563341771e-20 + -4.039707185538362e-26 + 6.245092836531276e-14 + 9.22097450583639e-20 + 1.9018060090238893e-20 + 2.676161031873004e-26 + 2.0473637507616747e-27 + -1.4156917307094574e-19 + -7.008482656417528e-21 + -7.161305555692102e-26 + 5.030180584628427e-28 + 5.986398355224382e-33 + + + + + + + 0.1385797228721903 + -0.002760945178520682 + -2.6203366249547734e-06 + 1.4485678722368534e-08 + 4.876927786251232e-11 + -1.1376979196412772e-13 + + + 0.7506670547090979 + 0.002439091450415394 + -5.082427564355023e-06 + -2.8097256219038232e-08 + 1.9002256433101935e-11 + 3.6828276318198224e-13 + + + 0.6459834621590832 + -0.0022420613876123915 + -7.927564976264752e-06 + 1.0018936627184642e-08 + 9.62944465867411e-11 + 2.0815204363838186e-14 + + + + + 0.8552805091032545 + 0.00010376114141890252 + -1.0609071111614952e-06 + -1.207112657984025e-10 + 6.538241092703245e-13 + -5.76536979126892e-16 + + + 0.23813408977855877 + 0.0005620596491955484 + 7.653455689187554e-07 + -6.62799773310883e-10 + -1.2207571830256701e-12 + 4.229217799962556e-16 + + + -0.4602036571273811 + 0.000483678131134207 + -9.665445237464232e-07 + -8.87617267201027e-10 + 1.688275707351889e-12 + 5.84714577712134e-16 + + + 10000000000.0 + + + 0.0 + + + 0.0 + + + + + 0.0 + 1.830851508157883e-12 + -1814485.8372625443 + -2.208286609514295e-06 + -67647577942.01662 + 1.1886185612774636 + -1463292882577055.0 + -140393.14526142203 + -1.0883947565151394e+21 + 1.830851508157883e-12 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -1814485.8372625443 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -2.208286609514295e-06 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -67647577942.01662 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 1.1886185612774636 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -1463292882577055.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -140393.14526142203 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -1.0883947565151394e+21 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + + + + + 0.0 + + + 0.0 + + + + 0.0 + + false + + + + + 0.13857972287219025 + -0.00276094517852056 + -2.620336625243285e-06 + 1.4485678988875624e-08 + 4.8769161197407225e-11 + -1.1375096936147393e-13 + + + 0.6459834621590832 + -0.002242061387614175 + -7.927564972177376e-06 + 1.0018932954832954e-08 + 9.629586368326803e-11 + 2.0618376108071688e-14 + + + -0.7506670547090983 + -0.0024390914504133017 + 5.082427558756091e-06 + 2.8097261855089025e-08 + -1.9004683908030164e-11 + -3.679090656234575e-13 + + + + + 0.8552805091032539 + 0.00010376114142167065 + -1.0609071180596748e-06 + -1.207043400114697e-10 + 6.507868530371908e-13 + -9.743797322315395e-17 + + + -0.4602036571273811 + 0.00048367813113425924 + -9.665445239876957e-07 + -8.876169832814811e-10 + 1.6881432972254367e-12 + 6.050807582195414e-16 + + + -0.23813408977855874 + -0.0005620596491953135 + -7.653455692406227e-07 + 6.627999246022303e-10 + 1.2207431985624998e-12 + -4.2550048742723904e-16 + + + 10000000000.0 + + + 0.0 + + + 0.0 + + + + + 0.0 + 1.830851508157883e-12 + -1814485.8372625443 + -2.208286609514295e-06 + -67647577942.01662 + 1.1886185612774636 + -1463292882577055.0 + -140393.14526142203 + -1.0883947565151394e+21 + 1.830851508157883e-12 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -1814485.8372625443 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -2.208286609514295e-06 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -67647577942.01662 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 1.1886185612774636 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -1463292882577055.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -140393.14526142203 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + -1.0883947565151394e+21 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + + + + + 0.0 + + + 0.0 + + + + 0.0 + + false + + + + + 1.0 + 0.0 + 0.0 + + + 0.7595544373616576 + -0.19606057028786392 + -0.6201913493470818 + + 1.2206225993023674 + + 0.004675603312478452 + -0.003828024629854423 + -2.0534202450677696e-06 + 1.6330042734228727e-08 + 2.8141525578340645e-11 + -1.0877634693549419e-13 + -7.010768197194295e-15 + 3.096179373981025e-15 + -7.25744581845732e-16 + 6.835061157382706e-17 + + + 0.7905497991684931 + -0.04747343763300925 + -0.03877390170180205 + 0.03373684498686244 + 0.004080681063554339 + -0.007265643668194507 + 0.6062197250310172 + -199.23671702338058 + -25028.825068538503 + + 51.86311228563949 + 53.61635699121815 + -0.2224562254252088 + 0.2224562254252088 + + diff --git a/example-sidd-1.4.0.xml b/example-sidd-1.4.0.xml new file mode 100644 index 0000000..9db3de5 --- /dev/null +++ b/example-sidd-1.4.0.xml @@ -0,0 +1,499 @@ + + + + Valkyrie Systems Sage | sar_common_kit 1.16.0.0 + 2026-07-06T19:41:48.276070Z + None + + + unknown + unknown + + + MONO8I + 1 + + + + UNKNOWN + + UNKNOWN + + + + + AVERAGE + + PLACEHOLDER + + + BILINEAR + + + CONVOLUTION + + + PLACEHOLDER + + + BILINEAR + + + CORRELATION + + + + + + + + PLACEHOLDER + + + BILINEAR + + + CONVOLUTION + + + PLACEHOLDER + + + BILINEAR + + + CORRELATION + + + + DOWN + + + + + PLACEHOLDER + + + BILINEAR + + + CONVOLUTION + + + + NONE + 1 + + + + + WGS_84 + + + 0.013572607228224258 + -0.013493990372664301 + + + 0.013572607607177684 + 5.989343374235574e-06 + + + -0.013568715820197173 + 5.9893433742376906e-06 + + + -0.01356871544135241 + -0.013493990372664298 + + + + + 0.013566764930813392 + -0.010109065350397206 + + + 0.013564841682008598 + -0.006743229534362815 + + + 0.013563676606113632 + -0.003360803989664334 + + + 0.013563281129551538 + 5.530814172134693e-06 + + + 0.013563647943415323 + 0.0033721144636969787 + + + 0.01356477721677736 + 0.006738946929590938 + + + 0.013566669118748848 + 0.010106028182547293 + + + 0.013564114246783917 + 0.013472702674748786 + + + 0.01017344904233069 + 0.01347110427161968 + + + 0.0067835476783148965 + 0.01346975657388732 + + + 0.003389203303064201 + 0.013468004924255903 + + + 8.283901117087555e-07 + 0.013467158137722713 + + + -0.003391974065284905 + 0.013482254425192153 + + + -0.006784028268153691 + 0.01348125416351242 + + + -0.010175320287793332 + 0.013480503905766232 + + + -0.013565850922307002 + 0.013480003358603963 + + + -0.013563303200052597 + 0.01011332745337482 + + + -0.013565201319569571 + 0.0067299027867724626 + + + -0.013566326905741987 + 0.0033630719269244127 + + + -0.013566691145281072 + -3.5107456751303633e-06 + + + -0.01356629420658204 + -0.0033698452015257954 + + + -0.013565136257987357 + -0.006735931411108482 + + + -0.013563217467789747 + -0.010101769344891062 + + + -0.013565737028685838 + -0.013468011050542274 + + + -0.010175207282825284 + -0.013467501070036228 + + + -0.006783916601625538 + -0.013466744297839688 + + + -0.0033918493193197674 + -0.013482077636211242 + + + 9.656270839475448e-07 + -0.01348082641057728 + + + 0.0033893390380206846 + -0.013479981497289087 + + + 0.0067836802742381455 + -0.01347823504283712 + + + 0.01017357923240379 + -0.013476895079848231 + + + 0.013564241578389667 + -0.01347530734617673 + + + + + + + + 6378137.0 + 0.0 + 0.0 + + + 3487.0 + 1126.0 + + + + 0.43033155140602114 + 1.3334613092121825 + + + 1.2206225993023663 + + + + 0.0 + 7.850462293418876e-17 + -1.0 + + + 0.0 + 1.0 + 7.850462293418876e-17 + + + + + 6974 + 1127 + + + + 7454209.806422097 + 188.91655848763938 + -2.362373172007106 + 0.008127437652222326 + -2.92667702058293e-05 + -1.368075007928718e-07 + + + -7806.301805510545 + 6399.79719992698 + -1.5176922483654318 + 0.012467192043075523 + 3.726013254183058e-05 + -1.397447612729364e-07 + + + 1320352.0463603565 + -1803.7760411526824 + 2.4966351791850445 + 0.004834761184214687 + -3.7703330808027104e-05 + -9.370498209584064e-08 + + + + + 1 + 282 + + + 1 + 563 + + + 2 + 845 + + + 2 + 1126 + + + 2 + 1408 + + + 2 + 1689 + + + 1 + 1970 + + + 2 + 2251 + + + 873 + 2251 + + + 1744 + 2250 + + + 2616 + 2250 + + + 3487 + 2250 + + + 4359 + 2252 + + + 5230 + 2251 + + + 6102 + 2251 + + + 6973 + 2251 + + + 6972 + 1970 + + + 6973 + 1688 + + + 6973 + 1407 + + + 6973 + 1126 + + + 6973 + 845 + + + 6973 + 564 + + + 6972 + 283 + + + 6973 + 2 + + + 6102 + 2 + + + 5230 + 2 + + + 4359 + 0 + + + 3487 + 1 + + + 2616 + 1 + + + 1744 + 1 + + + 873 + 1 + + + 2 + 1 + + + + + + + SyntheticCollector + + SPOTLIGHT + + 2024-05-29T14:12:54.201358Z + 2.5506314363333673 + + 0.5057460137485116 + 1.9945650273380746 + + + + 0.00013895445024772235 + 40.57506621800417 + -74.26511926770692 + 39.232345287680424 + -11.306597928636268 + 78.92654152200815 + + + + -0.00013895445025222033 + 1.2247088831585344 + + + 162.45673563224045 + 0.8563490735545047 + + 172.79277348524383 + 74.30179613706103 + + + + + 0.6529155256147169 + 2.0352095020740757 + + 3.1210381484294056 + + V + V + + 180.0 + + + + + + fixed + fixed + + + + + + + true + none + none + one_dimensional + + + diff --git a/pdm.lock b/pdm.lock new file mode 100644 index 0000000..526c1e5 --- /dev/null +++ b/pdm.lock @@ -0,0 +1,1751 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "all", "dev", "dev-lint", "dev-test", "doc", "test", "verification", "xsdtypes-generation"] +strategy = ["inherit_metadata"] +lock_version = "4.5.0" +content_hash = "sha256:ba3f381bb96bab0b75942f2bb6d49581ea4638dde48570a977c9c1aa196934b9" + +[[metadata.targets]] +requires_python = ">=3.12" + +[[package]] +name = "aiohappyeyeballs" +version = "2.7.1" +requires_python = ">=3.10" +summary = "Happy Eyeballs for asyncio" +groups = ["dev", "dev-test"] +files = [ + {file = "aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472"}, + {file = "aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d"}, +] + +[[package]] +name = "aiohttp" +version = "3.14.1" +requires_python = ">=3.10" +summary = "Async http client/server framework (asyncio)" +groups = ["dev", "dev-test"] +dependencies = [ + "aiohappyeyeballs>=2.5.0", + "aiosignal>=1.4.0", + "async-timeout<6.0,>=4.0; python_version < \"3.11\"", + "attrs>=17.3.0", + "frozenlist>=1.1.1", + "multidict<7.0,>=4.5", + "propcache>=0.2.0", + "typing-extensions>=4.4; python_version < \"3.13\"", + "yarl<2.0,>=1.17.0", +] +files = [ + {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d35143e27778b4bb0fb189562d7f275bff79c62ab8e98459717c0ea617ff2480"}, + {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bcfb80a2cc36fba2534e5e5b5264dc7ae6fcd9bf15256da3e53d2f499e6fa29d"}, + {file = "aiohttp-3.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27fd7c91e51729b4f7e1577865fa6d34c9adccbc39aabe9000285b48af9f0ec2"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64c567bf9eaf664280116a8688f63016e6b32db2505908e2bdaca1b6438142f2"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f5e6ff2bdbb8f4cd3fbe41f99e25bbcd58e3bf9f13d3dd31a11e7917251cc77a"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f73e01dc37122325caf079982621262f96d74823c179038a82fddfc50359264"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb2c0c80d431c0d03f2c7dbf125150fedd4f0de17366a7ca33f7ccb822391842"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e6fc1a85fa7194a1a7d19f44e8609180f4a8eb5fa4c7ed8b4355f080fad235c"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:686b6c0d3911ec387b444ddf5dc62fb7f7c0a7d5186a7861626496a5ab4aff95"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c6fa4dc7ad6f8109c70bb1499e589f76b0b792baf39f9b017eb92c8a81d0a199"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:87a5eea1b2a5e21e1ebdbb33ad4165359189327e63fc4e4894693e7f821ac817"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c1421eb01d4fd608d88cc8290211d177a58532b55ad94076fb349c5bf467f0a"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:34b257ec41345c1e8f2df68fa908a7952f5de932723871eb633ecbbff396c9a4"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:de538791a80e5d862addbc183f70f0158ac9b9bb872bb147f1fd2a683691e087"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f71173be42d3241d428f760122febb748de0623f44308a6f120d0dd9ec572e3"}, + {file = "aiohttp-3.14.1-cp312-cp312-win32.whl", hash = "sha256:ec8dc383ee57ea3e883477dcca3f11b65d58199f1080acaf4cd6ad9a99698be4"}, + {file = "aiohttp-3.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2aa92c87868cd13674989f9ee83e5f9f7ea4237589b728048e1f0c8f6caa3271"}, + {file = "aiohttp-3.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:2c840c90759922cb5e6dda94596e079a30fb5a5ba548e7e0dc00574703940847"}, + {file = "aiohttp-3.14.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:b3a03285a7f9c7b016324574a6d92a1c895da6b978cb8f1deee3ac72bc6da178"}, + {file = "aiohttp-3.14.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:2a73f487ab8ef5abbb24b7aa9b73e98eaba9e9e031804ff2416f02eca315ccaf"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:915fbb7b41b115192259f8c9ae58f3ddc444d2b5579917270211858e606a4afd"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:7fb4bdf95b0561a79f259f9d28fbc109728c5ee7f27aff6391f0ca703a329abe"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1b9748363260121d2927704f5d4fc498150669ca3ae93625986ee89c8f80dcd4"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:86a6dab78b0e43e2897a3bbe15745aa60dc5423ca437b7b0b164c069bf91b876"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dfd6e47d3c44c2279907607f73a4240b88c69eb8b90da7e2441a8045dfd21da"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:317acd9f8602858dc7d59679812c376c7f0b97bcbbf16e0d6237f54141d8a8a6"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd869c427324e5cb15195793de951295710db28be7d818247f3097b4ab5d4b96"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93b032b5ec3255473c143627d21a69ac74ae12f7f33974cb587c564d11b1066f"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f234b4deb12f3ad59127e037bc57c40c21e45b45282df7d3a55a0f409f595296"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9af6779bfb46abf124068327abcdf9ce95c9ef8287a3e8da76ccf2d0f16c28fa"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:faccab372e66bc76d5731525e7f1143c922271725b9d38c9f97edcc66266b451"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f380468b09d2a81633ee863b0ec5648d364bd17bb8ecfb8c2f387f7ac1faf42c"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:97e704dcd26271f5bda3fa07c3ce0fb76d6d3f8659f4baa1a24442cc9ba177ca"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:269b76ac5394092b95bc4a098f4fc6c191c083c3bd12775d1e30e663132f6a09"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0b3e614340c889d575451696374c9d17affd54cd607ca0babed8f8c37b9397"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5663ee9257cfa1add7253a7da3035a02f31b6600ec48261585e1800a81533080"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:603a2c834142172ffddc054067f5ec0ca65d57a0aa98a71bc81952573208e345"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb21957bb8aca671c1765e32f58164cf0c50e6bf41c0bbbd16da20732ecaf588"}, + {file = "aiohttp-3.14.1-cp313-cp313-win32.whl", hash = "sha256:e509a55f681e6158c20f70f102f9cf61fb20fbc382272bc6d94b7343f2582780"}, + {file = "aiohttp-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:1ac8531b638959718e18c2207fbfe297819875da46a740b29dfa29beba64355a"}, + {file = "aiohttp-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:250d14af67f6b6a1a4a811049b1afa69d61d617fca6bf33149b3ab1a6dbcf7b8"}, + {file = "aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15"}, + {file = "aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444"}, + {file = "aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0"}, + {file = "aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719"}, + {file = "aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6"}, + {file = "aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035"}, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +requires_python = ">=3.9" +summary = "aiosignal: a list of registered asynchronous callbacks" +groups = ["dev", "dev-test"] +dependencies = [ + "frozenlist>=1.1.0", + "typing-extensions>=4.2; python_version < \"3.13\"", +] +files = [ + {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, + {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, +] + +[[package]] +name = "alabaster" +version = "1.0.0" +requires_python = ">=3.10" +summary = "A light, configurable Sphinx theme" +groups = ["doc"] +files = [ + {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, + {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, +] + +[[package]] +name = "argcomplete" +version = "3.7.0" +requires_python = ">=3.8" +summary = "Bash tab completion for argparse" +groups = ["test"] +files = [ + {file = "argcomplete-3.7.0-py3-none-any.whl", hash = "sha256:d8f0f22d2a8a7caa383be1e22b6caf1ecaf0ebd10d8f83cc125e36540c95830c"}, + {file = "argcomplete-3.7.0.tar.gz", hash = "sha256:afde224f753f874807b1dc1414e883ab8fe0cda9c04807b6047dcb8e1ac23913"}, +] + +[[package]] +name = "ast-serialize" +version = "0.6.0" +requires_python = ">=3.7" +summary = "Python bindings for mypy AST serialization" +groups = ["dev", "dev-lint"] +files = [ + {file = "ast_serialize-0.6.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:a7520b672827885bafeae7501f684d14d47d17e5f45256f9df547686cca52264"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a14191beec7e0c078d2fc1f6edc0aee88bcd4db9f18e1bc9f8052b559c22dddc"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32ef62ec34cf6be20ad77d4799556638fbdf187f3ae10698dfb20ef9f2c89516"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13b7769970a39983b0adf2f38917b1cd3b8946f76df045756c3d741bc689f089"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f7a408601bb3edaefb3bc67a4c01f5235e3253653b6a5729a2ee2382b35341c"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8670bfa51208a2c0c8d138928e40e998fab158f9200d53bb80c088b5b8eda7b8"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4826809eb8597a8cd59fd924b6d7c285b8969a1e0007e2cb652cab62376270f"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:577a6c189068686869f5f1ddc38363f3ae1808a4753b577266f9202071a7bb66"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:085de7f62dc9cc247eb01e965a362707d1d90b1d89a82c5bf78301a60a3c417b"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9f8a8b78b13173de6a9ec22111d9be674874cd5bdccda04f14ae5ebc2bef403a"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f2ff3baffc3a29c1f15bc9098aa0c09763410262d5e6cef42116f7356c184554"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0067b25fce104eaae5b88383de9ab803faeb671831e14ca698b771b356e2600f"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c617417f9cbb0cb144f6283c3cbe0d2e0f01beaf9f608f662b21191058a626ec"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-win32.whl", hash = "sha256:5337cb256dcea3df9288205213d1601581536526b8f4da44b6974f1180f3252a"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2d947e45cafc4b09bd7528917fa84c517654a43de173c79785574b7b3068ac24"}, + {file = "ast_serialize-0.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6e15ec740436e1a0d62de848641abe5f3a2f89a7f94907d534795ac91bbacf14"}, + {file = "ast_serialize-0.6.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:093cb8bb91b720d8523580498d031791bb1bbaa048599c3d21085d380e11a596"}, + {file = "ast_serialize-0.6.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e61580a69faf47e3689795367ed211f2a10fd741478cc0f36a0f128793360aad"}, + {file = "ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305802f2ce2a7c4e87835078ea85c58b586ddda8095b92fe2ead9364ae19c80a"}, + {file = "ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c7b8b8f0c42f752ea00b2b7d7c090b3f80d9c1c5c75cadf16423790a0cc74081"}, + {file = "ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd5b91b9e6f2356ace3a556963b0cd783b395fbbb0bb17b4defc283415466e77"}, + {file = "ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d6ef91590258ada18909b9caea344dac4de2013906b035473cd674a43f4b790"}, + {file = "ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcbed41e9386059fc0261d602445ede0976c2ecec2939688bcbcb9ed0b6f28b7"}, + {file = "ast_serialize-0.6.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:cdc4e6f930b9090c2f92c9036ad12ffb8e6e44d4a5ba06f1458a05d60f203f7b"}, + {file = "ast_serialize-0.6.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:897ac47b5637be41c0c07061c8a912fafa967ef1dc73fa115e4bfa70882a093b"}, + {file = "ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c4af9a1386166e40ed01464991806f89038a2d89782576c7774876fa77034e32"}, + {file = "ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:c901adbd750029b9ac4ad3d6aa56853e0ad4875119fbf52b7b8298afc223828b"}, + {file = "ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae22a366b752ab4496191525b78b097b5b72d531752e3c1dd7e383a8f2c8a1a"}, + {file = "ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4ed29121da8b3fdc291002801a1de0f76248fa07dce89157a5f277842cf6126e"}, + {file = "ast_serialize-0.6.0-cp39-abi3-pyemscripten_2026_0_wasm32.whl", hash = "sha256:b1dac4e09d341c1300ba69cdcbe62867b32a8c75d90db9bf4d083bec3b039f0b"}, + {file = "ast_serialize-0.6.0-cp39-abi3-win32.whl", hash = "sha256:82c312a7844d2fdeb4d5c48bd3d215bf940dafd4704e1a9bcf252a99010a99b1"}, + {file = "ast_serialize-0.6.0-cp39-abi3-win_amd64.whl", hash = "sha256:113b58346f9ceb664352032770caca817d4a3c86f611c6088e6ef65ddaa70f0e"}, + {file = "ast_serialize-0.6.0-cp39-abi3-win_arm64.whl", hash = "sha256:ccd132fe8db56f61fe743b1f644d01b8d65b83248a8da506f3132bda86d6ed5e"}, + {file = "ast_serialize-0.6.0.tar.gz", hash = "sha256:aadd3ffcf4858c9726bf3515f7b199c7eadbe504f96028e4a87172c0da65a8fe"}, +] + +[[package]] +name = "attrs" +version = "26.1.0" +requires_python = ">=3.9" +summary = "Classes Without Boilerplate" +groups = ["dev", "dev-test", "test"] +files = [ + {file = "attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"}, + {file = "attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32"}, +] + +[[package]] +name = "babel" +version = "2.18.0" +requires_python = ">=3.8" +summary = "Internationalization utilities" +groups = ["doc"] +dependencies = [ + "pytz>=2015.7; python_version < \"3.9\"", +] +files = [ + {file = "babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35"}, + {file = "babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d"}, +] + +[[package]] +name = "certifi" +version = "2026.6.17" +requires_python = ">=3.7" +summary = "Python package for providing Mozilla's CA Bundle." +groups = ["dev", "dev-test", "doc"] +files = [ + {file = "certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db"}, + {file = "certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.8" +requires_python = ">=3.7" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["dev", "dev-test", "doc"] +files = [ + {file = "charset_normalizer-3.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:faac37c4904598daa00cb4c9b32f3b4cc814fb5f145d7a531ceb4a70f2114132"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f191c19a32dc6cec0fb8079789d786254653a9ce906fcab04ccd2eed07bba233"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05811b76943d477bb90822dedb5c4565cef70148847a59d574e2b35043aeb563"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3868a3e4ec1e40b419e060d063f93eac6f046fa21426c4816421223ae7dc8ab8"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25f93d194eb6264c64416cabff46a91f6d99b97e7525a1b4f35c77a99e75cc68"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:ee6a62492f18d432cca031fabd158f400a8c25bf7b9458f50953393a2a23d97a"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1c16cb4fc35e4b064f5ee78d849f15a550ada1729c3372916672e38f1f01d1d4"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2fbd0edb0426ab28e70fac9d1d4ef549eb5a64a2521f0428c441d75e4387e6c2"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccb9052771216170015f810b88065fd9e13b1e0b391f92abb9b47e0919a42aad"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3809ba5d3cd02aca0894597f2669a825bdfe2229061515c128b0f4e5533b4ab5"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-win32.whl", hash = "sha256:de63c31666a049f653ada24e800192e3c019e96bc7d70fb449a000bccf26a36f"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:14a4bbe066f3fb05c6ba70e9cf9d34614b57a2fd70ea8c27cc30f34155e16a58"}, + {file = "charset_normalizer-3.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:2b5b0c0dca0a02c3f816f89abf18af3d20416dedbc3d3aa5f3981045f88ae7b0"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:057f8609f7341618c98e5aa9a6109fa116acff2a658497d47ab3325b5e8f2b08"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c591f9a82adc5b89a039b90df74e43de2b9177fb46771172bed7b80722a70db0"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b56f449132d9adefe55b87635d05177a914ed5d070438a74725e1d77a280002"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1004c3b5831a301dadfb9e916f38e78e2ff3e08db24a1ad7c354db8ee3dea9c3"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:60883e22821d17c9e5b4f3ca1ef8074f766e3db28791f851b665929c515635c0"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:21e4dbb942c8a6342e2685f232dd2a7bc73465697bd26ead4f118271d28be383"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84bcae14c65e645ca66b661339183d32b8c846a17c96e3e81ab3d346e1c498d4"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b4e4d44b8287aa13a25e16e29393d494b0643b24894f7c8266c6f6788dd36337"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f68545d1b267dbfafd5d253b6d1cb161562c4e61ab25b5c4cdb7d9e5923e441e"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1936e48214adea74922a20c8ab41b1393ae27cc9e329eb1f0b937d3416824f36"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-win32.whl", hash = "sha256:1f8e3521860187d597f3867d8466da225b9179ea2833bb26de1bb026144d07c3"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:8b654b6f52a0a9a6be38e88f3e1dc68f1093ebeb2abbadafc7c82da0786a34be"}, + {file = "charset_normalizer-3.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:d2d5a250ee26e29468b7607d97479221b069fa8aaf6f929ac84ec0e962e15154"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:77e993ecf65f21ab1f82266ff5e84a7de2c879e7d9b8bc006009df83f22a1d5e"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:524939917f17f6de502dfda30b472550965740d7f126659d4c4f8dd1569cce22"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a4508989ba8e2ce43ef989453d18188b261546e8188cbdd4ef451fb9e4c3b467"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9e44127f7d11eee4548ad2cdf1f4e1b6eaaddd5cb92d15ad65f6ecc9bcf403ab"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bb90317359f7e67bb6df615999a95e0980877468e617ddce8b6c2f8e7fe60d95"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:35d9e7a9c960520ae89d1f4e305d1c047a74dea2e0f73a0e84f879356c2e8776"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:92e322b054c7ff886f78feab7360736bb45de2e18cf4a0ee84e8fc5a08d53a19"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c0086d97094363556206dc3bcf43f7edcfc043ea7a568a46f45efea74858bd1"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:0752c849b51198267df2aba013c4de3a2955bd014a4fd70828809946c1acbc0c"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2a4707e09eca11e81ece4fced600c5a0a801f568b962244f6f517bc274745fc9"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-win32.whl", hash = "sha256:8ea67f427c073ae3da0923aa55f3715131fa613a61a7f2f8d762bde75eaf00ae"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-win_amd64.whl", hash = "sha256:ff71018850863362e5c7533769d0a9f77715c31af1502d523630ce822922f5c9"}, + {file = "charset_normalizer-3.4.8-cp314-cp314-win_arm64.whl", hash = "sha256:44464e66f4da2f21dea7145c7693f9f60717ca4794a954dea5bf8c2c932678bd"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:50a0c2e58ad2c203adb616fef28941b7e13716adbc25e0dfaeec29f5afe6382f"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1e589fdb95c76f08288bbb346230cdd8994db74903db6637b380f7b5fc9336"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b3d7c887444c5a7ef0d68d358d81e758a850bc626f8e639e2ca5667153272b20"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:65c389b96c0cfff3a3f0458fa1c7ce554a30e23101a88a49f03997afce6a929f"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:593403fc47dcdf55e2987b2e3cc2e064127e2b908929f1f18b2e4a4652cbd780"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:606088e9fa2b7469ab9c42d4da8e05a415622a07714edd2fcd8fed48dda4c853"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0317406326fed512f42a1632ad91a96228a7616c06547666a6dd79967f1bd6ca"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b67d50ee47e5c57a0064a9cb575b963a7125819dfd1fd094d44d378fff94659b"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:79e402b869f270140afa5e2b0e2ac100585358d812fe3dd093d424f7a72964e0"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2970b9f7ab69ec3a0423ec6b6ac718e79fbf4a282c0bc103ef88c1ef50dfa15a"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-win32.whl", hash = "sha256:458c2972a78043b7261c9726670029f15f722e70669bcbe961153a01968f589f"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-win_amd64.whl", hash = "sha256:0c926329a1df7cd56d7d8349fe354460d20aefd2e394c9e159e479d018b2b359"}, + {file = "charset_normalizer-3.4.8-cp314-cp314t-win_arm64.whl", hash = "sha256:2232baea80a2b01783679fed4e625ccdb19a974f44c9cf0fba21a777a4c8179c"}, + {file = "charset_normalizer-3.4.8-py3-none-any.whl", hash = "sha256:b7c1fb310df524e01fbe84d43b7f95aa4f808f8eaa0dafc185f64ba395e37d54"}, + {file = "charset_normalizer-3.4.8.tar.gz", hash = "sha256:d9bf144d6faf12c70d58e47f7512992ae2882b820031d6cef68152deb645bf2d"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["dev", "dev-test", "doc", "test"] +marker = "sys_platform == \"win32\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "colorlog" +version = "6.10.1" +requires_python = ">=3.6" +summary = "Add colours to the output of Python's logging module." +groups = ["test"] +dependencies = [ + "colorama; sys_platform == \"win32\"", +] +files = [ + {file = "colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c"}, + {file = "colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321"}, +] + +[[package]] +name = "dependency-groups" +version = "1.3.1" +requires_python = ">=3.8" +summary = "A tool for resolving PEP 735 Dependency Group data" +groups = ["test"] +dependencies = [ + "packaging", + "tomli; python_version < \"3.11\"", +] +files = [ + {file = "dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030"}, + {file = "dependency_groups-1.3.1.tar.gz", hash = "sha256:78078301090517fd938c19f64a53ce98c32834dfe0dee6b88004a569a6adfefd"}, +] + +[[package]] +name = "distlib" +version = "0.4.3" +summary = "Distribution utilities" +groups = ["test"] +marker = "python_version >= \"3.10\"" +files = [ + {file = "distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b"}, + {file = "distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed"}, +] + +[[package]] +name = "docutils" +version = "0.22.4" +requires_python = ">=3.9" +summary = "Docutils -- Python Documentation Utilities" +groups = ["doc"] +files = [ + {file = "docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de"}, + {file = "docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968"}, +] + +[[package]] +name = "elementpath" +version = "5.1.3" +requires_python = ">=3.10" +summary = "XPath 1.0/2.0/3.0/3.1 parsers and selectors for ElementTree and lxml" +groups = ["xsdtypes-generation"] +files = [ + {file = "elementpath-5.1.3-py3-none-any.whl", hash = "sha256:c46f5e0e36c149b892308843e1e394bdee17ceafbc18cfa39250403dd8475a4e"}, + {file = "elementpath-5.1.3.tar.gz", hash = "sha256:35e98cc2e26332305a49b32eaaebfb7289d1963c88d3989ff5ccb02c46809820"}, +] + +[[package]] +name = "filelock" +version = "3.29.5" +requires_python = ">=3.10" +summary = "A platform independent file lock." +groups = ["test"] +marker = "python_version >= \"3.10\"" +files = [ + {file = "filelock-3.29.5-py3-none-any.whl", hash = "sha256:8af830889ba3a0ffcefbd6c7d2af8a54012058103771f2e10848222f476a1693"}, + {file = "filelock-3.29.5.tar.gz", hash = "sha256:6e6034c57a00a020e767f2614a5539863f056de7e7991d6d1473aef7ff73f156"}, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +requires_python = ">=3.9" +summary = "A list-like structure which implements collections.abc.MutableSequence" +groups = ["dev", "dev-test"] +files = [ + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"}, + {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"}, + {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"}, + {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"}, + {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"}, + {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"}, +] + +[[package]] +name = "humanize" +version = "4.16.0" +requires_python = ">=3.10" +summary = "Python humanize utilities" +groups = ["test"] +files = [ + {file = "humanize-4.16.0-py3-none-any.whl", hash = "sha256:353eb2f34c09d098b2880eee8bef21832eae6d174f48c5762fff7e5fcb74d01d"}, + {file = "humanize-4.16.0.tar.gz", hash = "sha256:7dc2244a2f84a4bfb1d36c37bac80cd78e35cdc5c119206d87b018e1445f3a3f"}, +] + +[[package]] +name = "idna" +version = "3.18" +requires_python = ">=3.9" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["dev", "dev-test", "doc"] +files = [ + {file = "idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2"}, + {file = "idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848"}, +] + +[[package]] +name = "imagesize" +version = "1.5.0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +summary = "Getting image size from png/jpeg/jpeg2000/gif file" +groups = ["doc"] +files = [ + {file = "imagesize-1.5.0-py2.py3-none-any.whl", hash = "sha256:32677681b3f434c2cb496f00e89c5a291247b35b1f527589909e008057da5899"}, + {file = "imagesize-1.5.0.tar.gz", hash = "sha256:8bfc5363a7f2133a89f0098451e0bcb1cd71aba4dc02bbcecb39d99d40e1b94f"}, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +requires_python = ">=3.10" +summary = "brain-dead simple config-ini parsing" +groups = ["dev", "dev-test"] +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + +[[package]] +name = "jbpy" +version = "0.6.1" +requires_python = ">=3.11" +summary = "Library for reading and writing Joint BIIF Profile (JBP) files (NITF and NSIF)" +groups = ["default"] +files = [ + {file = "jbpy-0.6.1-py3-none-any.whl", hash = "sha256:8c046d48db9ddab218bf9a9ff4797c64ae567746eaf3fa9a27ebe4f8bc319885"}, + {file = "jbpy-0.6.1.tar.gz", hash = "sha256:23efac30cbbae33e4318eb71f073825b0b7a6578335479e34bb61451406dc523"}, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +groups = ["doc"] +dependencies = [ + "MarkupSafe>=2.0", +] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[[package]] +name = "librt" +version = "0.12.0" +requires_python = ">=3.9" +summary = "Mypyc runtime library" +groups = ["dev", "dev-lint"] +marker = "platform_python_implementation != \"PyPy\"" +files = [ + {file = "librt-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9bce19aa7c05f91c989f9da7b567f81d21d57a2e6501e2b811aa0f3f79614c1a"}, + {file = "librt-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0ace09f5bf4d982fe726015f102fb856658b41580597104e301e630ed1d8d86"}, + {file = "librt-0.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d007efe9243ede81ce75990ad7aa172da1e2024144b3eff17ba46a5fff1fff3c"}, + {file = "librt-0.12.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:ad324a5e4858388a4864915b90a42efc8b374376393f14b9940f2454e791912b"}, + {file = "librt-0.12.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10a40cf74cdd97b6f8f905056db73f5d459783de2ca04c6ebd1bf47652818e7e"}, + {file = "librt-0.12.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:92e61c09de95217ae02a9d17f4f66cf073253cdc51bcfdc0f15c62c9a70baa85"}, + {file = "librt-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0461344061d6fc3718940f5855d95647831cef6d03a6c7506897f98222784ad4"}, + {file = "librt-0.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e6dfe89074732c9287b3c0f5a6af575c9ede380a788013876cc7b14fe0da0361"}, + {file = "librt-0.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9efed79d51ad1383bba0855f613cca7aa91c943e709af2413ac7f4bb9936ce08"}, + {file = "librt-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1eac6cc0e23e448fb3c1446ed85ff796afb616eed5897c978d35dbec030b7c7c"}, + {file = "librt-0.12.0-cp312-cp312-win32.whl", hash = "sha256:0ab8ee0210047ae86ca023ccfbfe3df82077fd1c9bc021aebbf37d993ef64af0"}, + {file = "librt-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:51c8bfa12632c81b94401c101bcedd0c56c3a1f8fa3273ca3472b28cd2f54003"}, + {file = "librt-0.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:5eebd451f5def089369ba6d8ff0291303d035e8154f9f26f7633835c5b029ade"}, + {file = "librt-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8d9a55760a34ae5ce70434aabb6a6c61c6c44a0ec58ca1cfd9cd86e4745d417d"}, + {file = "librt-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ff0b197e338b4cf432873e0d6ef025213fdea85311ec4d87d2ea88c28adf2409"}, + {file = "librt-0.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e69f120a20b69e2539d603bbd4d62db38399b10f8bf73a1cf445038a621e8af"}, + {file = "librt-0.12.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:fde3cde595e947fc8e755b0a21f919a1622483d07c662d00496e040773d22591"}, + {file = "librt-0.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d977447315fa09ea4e8c7ae9b4e22f7659b5128161c1fd55ff786b5349f73503"}, + {file = "librt-0.12.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7ffac8a67e4143cea9a549d4822b93bc0bbaad73fc25aa0ab0ba5ec27d178677"}, + {file = "librt-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:94af1ed773ff104ef08ef3d669a0ba9d3a5916c609eb698cffe5d5476d66ff9b"}, + {file = "librt-0.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:548199d21d22fb26398dfbbe0ba953a52465c66f3a49f38e6fddce1b127faf53"}, + {file = "librt-0.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c8f1f413b966a9dd3ecf80cd337b0ad7bb3de2474a4ff448ed3ebabfc3f803fc"}, + {file = "librt-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55f13f95b629be5b6ab38918e439bf14169d6f9a8deaae55e0c14e12fb0c74b9"}, + {file = "librt-0.12.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:8b2dc079dfe29e77a47a19073d2040fa4879aa3656501f1650f8402ddce0313c"}, + {file = "librt-0.12.0-cp313-cp313-win32.whl", hash = "sha256:da58944be8270f2bfee628a9a2a60c1cf6a12c8bea8e2c9b6edf3e5414ca7793"}, + {file = "librt-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:1db4be3037e4ce065a071fa7deee93e78ebc25f448340a02a6c1c0b82c37e383"}, + {file = "librt-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:05fd2542892ad770b5dd45003fd080477cf220b611d3ee59b0792097eb0873a9"}, + {file = "librt-0.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:b37ee42e09722284a6d9288fe44a191f7276060a3195939bb77c6502058dbb34"}, + {file = "librt-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ade11988728b3e4768dadc5696e82c60e9b35fc95335a9b4d1f5d69e753ccec7"}, + {file = "librt-0.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f351ed425380e39bd86df382578aa5b8c5b98e2e265112de7379e7d030258150"}, + {file = "librt-0.12.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:857d2163e088c868967717ace8e980017fd868a735f3de010412af02bdc30319"}, + {file = "librt-0.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2befc80aa5f2f5b93f28abaaf11feff6677931dd548320e44c52deaa9399744"}, + {file = "librt-0.12.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:be3694dcfa97c6715dd19ac73d3e1b21a805514a5785663e57fecacd3ff64e5a"}, + {file = "librt-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2d5f67e86f45638843d025b0828f2e9e55fc45ff9180d2618ccdeaf72a796050"}, + {file = "librt-0.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:64572c85e4ab7d572c9b72cd76b5f90b21181b1459fa6b1aac6f8958c4fcff31"}, + {file = "librt-0.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:8b961912b0e688c1eb4658a46bdb0606b31918d65597fbe7356ca83aa653ffcc"}, + {file = "librt-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:722375903e3f079436a7a33da51ce73931536dd041f9feb01536f05d8e010c96"}, + {file = "librt-0.12.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:a5a96a8f536b65ef1bf910c09e7e71647edde5111f6e1b51f413c6fba5bfe71b"}, + {file = "librt-0.12.0-cp314-cp314-win32.whl", hash = "sha256:8ffc99c356f1777c506e1b69dc303879153ae2640ba15b8f3d4448bc87139149"}, + {file = "librt-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:1e68fb20798f455cda41d20a306a23c901218883f17a4bab1ed6e1331b265fb7"}, + {file = "librt-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:2df534f97916cf38ec9b1ddafeb68ae1a4cd4a54775ff26a797026774c0517cf"}, + {file = "librt-0.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c09e581b1c2b8a62b809d4f4bd101ca3de93791e5b0ed1a14085d911be3dee3f"}, + {file = "librt-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:976888d0d831402086e641018bcc3208e0a38f0835789da91f72894b2cb4161f"}, + {file = "librt-0.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:563c37cdb41d08fe1e3f08b201abac0e317ca18e88b91285466ee0a585797520"}, + {file = "librt-0.12.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:b97eb1a3140e279cc76f85b0fb92b7eb3dfbe0471260ee878bc9dc4bf9a0d649"}, + {file = "librt-0.12.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:06e0623351ab9904cf628245f99c714586f4dd23dc740b88c8bc670d8401a847"}, + {file = "librt-0.12.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:da12f017b2e404554be14d466cd992459feaa44f252b0f18d909a85266ce1237"}, + {file = "librt-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d97f31003a5c86b9e78155a829572c3a26484064fb7ac1d9695fe628bd93d029"}, + {file = "librt-0.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:bd43a6c69876aef4f04eaae3d3b99b0be64755fda274002fa445b92480bf664e"}, + {file = "librt-0.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c01755c72fca1dc6b8d5c2ed228b8e7b2ffe184675c22f0f05ebd8fe188b9250"}, + {file = "librt-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:625ae561d5fa36400856dcc27464400d047bc2d5e3446be88f437b03fefd72e4"}, + {file = "librt-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8d73191883553ee0739741544bf3b00aba2a1224e45d9580b30cbc29e21dc03b"}, + {file = "librt-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e1cbb037324e759f0afa270229731ff0047772667f3cb38ef5df2cabf0175ede"}, + {file = "librt-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bca1472acbd473eff61059b4409f802c5a1bcb4cd0344d06f939df9c4c125d40"}, + {file = "librt-0.12.0.tar.gz", hash = "sha256:cb26faedbd09c6130e9c1b64d8000efec5076ffd18d606c6cd1cf02730e6d8b0"}, +] + +[[package]] +name = "lxml" +version = "6.1.1" +requires_python = ">=3.8" +summary = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +groups = ["default"] +files = [ + {file = "lxml-6.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7"}, + {file = "lxml-6.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a"}, + {file = "lxml-6.1.1-cp312-cp312-win32.whl", hash = "sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a"}, + {file = "lxml-6.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77"}, + {file = "lxml-6.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f"}, + {file = "lxml-6.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:68a9198d0fc122d14bb76837de9aa80cf84caed990b5b237f532ed87d3706736"}, + {file = "lxml-6.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7d47866cb32fb503450b6edc9df355d10dc49836af2e89901bd6ac6b0896d9d9"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb7c9811bfaa8b1ed5ed319f5d370dfbcaa59d52ea64be2a5a85e18195930354"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:762ff394d5bd56da0cf034a23dcce4e13923f15321a2adfa2ac00201dc6d3fca"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a088f287f7d8275a33c07f2cac6c50b9319309a0200a39e7e75d80c707723099"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e902da4b04e6b52e5893900d4b8ab46068f75f3561f01bf1080957f9fd932ed6"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d4962d4c66bf830a7e59ed6cfc17d148149898a3aefa8ec6e59763e6e3ed085"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:581d4c8ae690a6609e64862dd6b7c2489635c2d13907fc2b20f2bc200ff1d21e"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:876e1ff5930ed8bf295ec5ef9a8155e9b6b1876bbf1deed8b3a8069311875a8f"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9eb9b5a968f6e0f6d640092a567e14529ff8cea2e29d00da6f78a79fa49f013c"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:aa49e06d94aba782c6a02eecb7e507969e7e7a41b267f1b359bb35585f295d5b"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:70cdfd80589d59e43e18005dd7244e8895e93db8ab6a620b7e23df5445a4e3d2"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:aad9aa39483ed8ec44d6d2e59e5b98a0d80676ef0d92f44bfc374836111f62f5"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d49514be2f28d895c38cf9d2b72d7b9a07d00314519f456c0b50b53cfcf4c785"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:47402e62c52ff5988c1e8c6c63177f5708bccf48e366dea4e3dcf1e645e04947"}, + {file = "lxml-6.1.1-cp313-cp313-win32.whl", hash = "sha256:3483644525531e1d5762b0c44a8e18b6efba321b6dcf8a8952de10b037618bca"}, + {file = "lxml-6.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:a10bd2fd62e8ce916ececb342f348f190724a098c1faa056fdfb2a22ad5e8660"}, + {file = "lxml-6.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:424aa57aca0897eb922aef34395bd1289b3b6f04e6bae20ea123c0c7e333cffc"}, + {file = "lxml-6.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:19b7ab10b210b0b3ad7985d9ac4eb66ab09a90b20fe6e2f7ba55d01a234345d0"}, + {file = "lxml-6.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c08e5c694306507275f2290073350c4f32e383db15213b2c69e7ff39c1193840"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:74a9717fd0d82effef5c2854f0d917231d5324b5a3eb7275c43ac9fa32f97a14"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efe0374196335f93b53269acd811b944f2e6bdc88e8894f214bd636455484909"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac931cdc9442c1763b8a8f6cd62c0c938737eafc5be75eff88df55fc73bc0d00"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:aee395f5d0927f947758b4ec119fd5fc8ec71f07a1c5c52077b30b04c0fa6955"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9395002973c827b3ed67db77e6ec09f092919a587022174554096a269378fb13"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:73bc2086f141224ebddb7fc5c6a36ca58b31b94b561e1dfe8e073e3270fad1e7"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:3779def59032b81e44a5f70096ef6bf2082f8d901937dca354474ba09782e245"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:86c89b9d55ebf820ad7c90bc533410f0d098054f293351f10603c0c46ff598f5"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19607c6bbff2a44cf3fe8250abccd20942d3462473e0a721d01d379ed017e462"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c6ed5141a5c7507cf3ee76bd363b0d6f801e3321adc35b5d825a23115faa5465"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:62aeb7e85b5d60320b9d77eef2e773994e2c0ce10121b277e0a19804e1654a5a"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b1b963fd8f5caa68e99dfae060d54de1fe9cba899b8718b44a00cdca53c3e590"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63876be28efefa04a1df615b46770e82042cce445cfdce55160522f57b231ccb"}, + {file = "lxml-6.1.1-cp314-cp314-win32.whl", hash = "sha256:7f7a92e8583f06b1fd49d01158143b8461cfcd135dcb10ec807270a3051bd603"}, + {file = "lxml-6.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:b2d444f2e66624d68e9c6b211e28a76e22fff5fcabcfff4deac18b529b7d4137"}, + {file = "lxml-6.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:3fd9728a2735fda14f4e8235830c86b539e9661e849665bf926d3f867943b4bf"}, + {file = "lxml-6.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:787b2496d0dbe8cd180984e8d29e3a6f76e7ea34db781cb3bd55e4ba1ef8b4ee"}, + {file = "lxml-6.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2c8daa471358dc2d6fcf02165e80ec68f77871a286df95bc5cc3816153b0fd2c"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:acd7d70b64c0aae0c7922cca83d288a16f5f6da523637697872253415269baef"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4f0dd2f01f9f8a89f565d000e03abcf0a13d692a346c8d22f628d49af098777a"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b7e8a14c8634bf6f7a568634cb395305a6d964aeb5b7ee32248094bed3a7e2c"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:86281fbdd6a8162756f8d603f37e3435bfa38043adb79c6dc6a2dfee065e7525"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5d7152ec39ca7c402d8fb9bad86140a15b9503bd0c54484e3f1bbe3dd37ceca"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:88d8cb75b9d82858497a5393e3c63cfbf03035225e4b35a49ed7ccb151e4dc0e"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f64ec5397ea6a41fc1b4af0380d79b44a755b5531dcaccd9940fb260dca93038"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d34bbf07dbc7ca5970671b1512e928991fb5e9d95365636c9b2d8b4f53af405e"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:17e0e18d4ad8adbd0399291bc44845b69d9dd68439a3cdebdf35ff902ec05072"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:3ab541146f1f6968c462d6c2ac495148e8cdba2f8347700b2141b6ec5a75bf52"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2a0217714657e023ef4293500f65aa20fce6164c8fd6b08fa5bd4a859fb14b9b"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:05a82eb6e1530a64f26225b55cbd178113bd0b5af1c2b625f25e5296742c26d2"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9e36f163528fc50cbef305f02a5fd66d404edf7049cdaff211dbc2cba5a7013e"}, + {file = "lxml-6.1.1-cp314-cp314t-win32.whl", hash = "sha256:649dda677cf3bd6ac9ae14007ba0c824ded8ce5808b53fc7431d9140399118c1"}, + {file = "lxml-6.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:793033d6c5cdf33a573f910d9bea14ef8f5771820411d118da8e1182edb53d5e"}, + {file = "lxml-6.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c"}, + {file = "lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40"}, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +requires_python = ">=3.9" +summary = "Safely add untrusted strings to HTML/XML markup." +groups = ["doc"] +files = [ + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, +] + +[[package]] +name = "multidict" +version = "6.7.1" +requires_python = ">=3.9" +summary = "multidict implementation" +groups = ["dev", "dev-test"] +dependencies = [ + "typing-extensions>=4.1.0; python_version < \"3.11\"", +] +files = [ + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"}, + {file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"}, + {file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"}, + {file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"}, + {file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"}, + {file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"}, + {file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"}, + {file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"}, + {file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"}, + {file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"}, + {file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"}, + {file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"}, + {file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"}, + {file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"}, + {file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"}, + {file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"}, + {file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"}, + {file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"}, +] + +[[package]] +name = "mypy" +version = "2.1.0" +requires_python = ">=3.10" +summary = "Optional static typing for Python" +groups = ["dev", "dev-lint"] +dependencies = [ + "ast-serialize<1.0.0,>=0.3.0", + "librt>=0.11.0; platform_python_implementation != \"PyPy\"", + "mypy-extensions>=1.0.0", + "pathspec>=1.0.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=4.14.0; python_version >= \"3.15\"", + "typing-extensions>=4.6.0; python_version < \"3.15\"", +] +files = [ + {file = "mypy-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:244358bf1c0da7722230bce60683d52e8e9fd030554926f15b747a84efb5b3af"}, + {file = "mypy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ec7c57657493c7a75534df2751c8ae2cda383c16ecc55d2106c54476b1b16f6"}, + {file = "mypy-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8161b6ff4392410023224f0969d17db93e1e154bc3e4ba62598e720723ae211"}, + {file = "mypy-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf03e12003084a67395184d3eb8cbd6a489dc3655b5664b28c210a9e2403ab0b"}, + {file = "mypy-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:20509760fd791c51579d573153407d226385ec1f8bcce55d730b354f3336bc22"}, + {file = "mypy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:6753d0c1fdd6b1a23b9e4f283ce80b2153b724adcb2653b20b85a8a28ac6436b"}, + {file = "mypy-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:98ebb6589bb3b6d0c6f0c459d53ca55b8091fbc13d277c4041c885392e8195e8"}, + {file = "mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5"}, + {file = "mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e"}, + {file = "mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e"}, + {file = "mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285"}, + {file = "mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5"}, + {file = "mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65"}, + {file = "mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d"}, + {file = "mypy-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7354c5a7f69d9345c3d6e69921d57088eea3ddeeb6b20d34c1b3855b02c36ec2"}, + {file = "mypy-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:49890d4f76ac9e06ec117f9e09f3174da70a620a0c300953d8595c926e80947f"}, + {file = "mypy-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:761be68e023ef5d94678772396a8af1220030f80837a3afd8d0aef3b419666f4"}, + {file = "mypy-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c90345fc182dc363b891350457ec69c35140858538f38b4540845afcc32b1aef"}, + {file = "mypy-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b84802e7b5a6daf1f5e15bc9fcd7ddae77be13981ffab037f1c67bb84d67d135"}, + {file = "mypy-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:022c771234936ceac541ebaf836fe9e2abeb3f5e09aff21588fe543ff006fe21"}, + {file = "mypy-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:498207db725cec88829a6a5c2fc771205fd043719ef98bc49aba8fb9fc4e6d57"}, + {file = "mypy-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d5e5cad0efeba72b93cd17490cc0d69c5ac9ca132994fe3fb0314808aeeb83e"}, + {file = "mypy-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ff715050c127d724fd260a2e666e7747fdd83511c0c47d449d98238970aef780"}, + {file = "mypy-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82208da9e09414d520e912d3e462d454854bed0810b71540bb016dcbca7308fd"}, + {file = "mypy-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e79ebc1b904b84f0310dff7469655a9c36c7a68bddb37bdd42b67a332df61d08"}, + {file = "mypy-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e583edc957cfb0deb142079162ae826f58449b116c1d442f2d91c69d9fced081"}, + {file = "mypy-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b33b6cd332695bba180d55e717a79d3038e479a2c49cc5eb3d53603409b9a5d7"}, + {file = "mypy-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4f910fe825376a7b66ef7ca8c98e5a149e8cd64c19ae71d84047a74ee060d4e6"}, + {file = "mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289"}, + {file = "mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +requires_python = ">=3.8" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["dev", "dev-lint"] +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "nox" +version = "2026.4.10" +requires_python = ">=3.9" +summary = "Flexible test automation." +groups = ["test"] +dependencies = [ + "argcomplete<4,>=1.9.4", + "attrs>=24.1", + "colorlog<7,>=2.6.1", + "dependency-groups>=1.1", + "humanize>=4", + "packaging>=22", + "tomli>=1.1; python_version < \"3.11\"", + "virtualenv>=20.14.1; python_version < \"3.10\"", + "virtualenv>=20.15; python_version >= \"3.10\"", +] +files = [ + {file = "nox-2026.4.10-py3-none-any.whl", hash = "sha256:082c117627590d9b90aa21f86df89b310b07c5842539524203bcb3c719f116c1"}, + {file = "nox-2026.4.10.tar.gz", hash = "sha256:2d0af5374f3f37a295428c927d1b04a8182aa01762897d172446dda2f1ce9692"}, +] + +[[package]] +name = "numpy" +version = "2.5.1" +requires_python = ">=3.12" +summary = "Fundamental package for array computing in Python" +groups = ["default", "dev", "dev-test"] +files = [ + {file = "numpy-2.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c889b56fe48b1018f764b0eec8df59ab654e9148aa91faa12596043500de277"}, + {file = "numpy-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab451b59c5643c570974c43aef780703ef1d3b4965d2be07afd530615a9358d1"}, + {file = "numpy-2.5.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:78798bd5b9ad744056af8efa90e3b9ddaa53272a0848a483084a1cc0a13b2dc0"}, + {file = "numpy-2.5.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2ae0ca40bcb22d6ba59c1dfd5446f49940b0f2d821fde133f10dda11f816b84e"}, + {file = "numpy-2.5.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61ac47e772e6b8ea489e1d2f441a34c5c3ac17327e7ce294cbdf535795ad4e75"}, + {file = "numpy-2.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59fda5e192b570217ec2580c96f00e9a7e12ef6866a900eb089b62c1a32545ca"}, + {file = "numpy-2.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f7119ebff1a9829e9f431a4f9d28e703023bb6b9fe7c8f724467dbfc27c94ab3"}, + {file = "numpy-2.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e824c2acf8862052246be5a44c15da1777940c60d010dd2aab897824d9c430f9"}, + {file = "numpy-2.5.1-cp312-cp312-win32.whl", hash = "sha256:08d60c810432eb83360958dea0999ac4cfb94531ea8efcbf0b7f277c2068aeb2"}, + {file = "numpy-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7d60026c0bdb1380e83bfa7a0419c4577ee4b9a08880afcb6dadeb74c649fa2"}, + {file = "numpy-2.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:17a25e09640602e10bc8de0e6fa2b3fd68eedd84ba6d7842dc8f32f9ab87bd0b"}, + {file = "numpy-2.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0bfebd8695f9863592fe744be833a258120b14a9f39da255e8aa8fade2c0ddd1"}, + {file = "numpy-2.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:30b44a6b53a7ae63c54c089a8726e5563ed302716c5b7ccc85afade40b0e7ff6"}, + {file = "numpy-2.5.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:6165343f81b56ef8f514f396989e529b61d9dc709b99421b07e9f3e698e2287d"}, + {file = "numpy-2.5.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4939237038ada79308dda3204ac6462df056b5672b2e25db1149cf873668b3e1"}, + {file = "numpy-2.5.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c6759f538fb912fc46de0a6b1758ccf7b57bc7c7ebebc23974fdac3de8db0cd"}, + {file = "numpy-2.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9726558e8db4a5bf7929a70ae50f63abda4daf0efe810e3bfbab95976f75fc1a"}, + {file = "numpy-2.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3935f3b419b244a02732676fa5317a9193cc596a4c0646db07e5b421229ac9f7"}, + {file = "numpy-2.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc932a65ded7ce9013d120845a2514dcccb1a67bfc8deb8d37633762951904a6"}, + {file = "numpy-2.5.1-cp313-cp313-win32.whl", hash = "sha256:4b4ff1608417eb7a59da7b967bbb798cacfe071d2caf526a24281cd562072ed9"}, + {file = "numpy-2.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:6c3fe51bc6a16453d452997053454f309e8e0ed7b42d6b361ce4ac8c32913d74"}, + {file = "numpy-2.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:f7feb014281029e628ba2d5a007407443b06e418b6fe451d1e2adcbc8eba0107"}, + {file = "numpy-2.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7c786fe9a5bbe360022e584c5a34cf6b54265c71bd7ec8ac3d8fec38968071f8"}, + {file = "numpy-2.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32985c896d897419ef8da6917872d80b78ad0ea26d85b23245c7366ffde76d75"}, + {file = "numpy-2.5.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:efd736408cc97c79b9e6917338dfc8f06013b2274f992e96b1d9a81a71e2a2c2"}, + {file = "numpy-2.5.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:ab84dc6b074fa881cae55bea94cc4f68e285181ba7f32497bf7dee6b1496165b"}, + {file = "numpy-2.5.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caf3e317d33d60c37986b452613f4ab51246d0691350c03d0cb4a898627f4a95"}, + {file = "numpy-2.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:54ad769f17bc2d833b620851989f62054fb9ab93c969d9e1dc3c8e3d56beea21"}, + {file = "numpy-2.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c12afb53450fa976d4c681c50a7423729a4c51c0465ed9f32b8a9cabbc472373"}, + {file = "numpy-2.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e8c11c405efc5ff6816d5983c96cdfa215bab3428961243af3ff59b228490438"}, + {file = "numpy-2.5.1-cp314-cp314-win32.whl", hash = "sha256:f2479a47f8d5932d1718168a681ad6e536a9df484c83cfcf9de365e164537ace"}, + {file = "numpy-2.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:24d0eb82c0541d3415a33425db64ae439dffccd7b4dbcb30e7c35120205c506a"}, + {file = "numpy-2.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:5a4c988b38d261deeeaad9954e3deb091ad905c94e8bb6708654ef1d97f286b0"}, + {file = "numpy-2.5.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a33276be12fa045805f477f22482088b66bb758ffbe89a9d21457de863a32e22"}, + {file = "numpy-2.5.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:f089d7b00756190aacf1f5d34bdf38c3c430ac82b4f868f8cede73380460fce7"}, + {file = "numpy-2.5.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:09e9bfd8d2cf479c7d174804fb3811c53a8e9f20a37444008606b57d6b7a826d"}, + {file = "numpy-2.5.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e68d8dd1e7eba712948f2053a29ec86917bc70ba1358df869d9f06649ef9cf09"}, + {file = "numpy-2.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99d5095fa265a0c4152e7bb12759e14381ef5496152f1ce58f44bdf55c44beb4"}, + {file = "numpy-2.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ab87a91b3cc3382b8956095bd8f95e00cf679bb81554339be1a2ba404a1473c1"}, + {file = "numpy-2.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:224ca51130ef7da85bea2191625181cb4f337f9cb64b471f10c1a12aa8b60077"}, + {file = "numpy-2.5.1-cp314-cp314t-win32.whl", hash = "sha256:6eab239876581b2b3c5a242281b6007bbdbcd1c7085d7709bb57c5929b11e6bf"}, + {file = "numpy-2.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:83ce9c80d5b521b0d77ddcbe5447c218d247929b6cc056ca5351342accfff0af"}, + {file = "numpy-2.5.1-cp314-cp314t-win_arm64.whl", hash = "sha256:5a6db61f9aaa57e369905c67d852045d3c4f7126405b29d09b19dec118e9c9cb"}, + {file = "numpy-2.5.1.tar.gz", hash = "sha256:a48a113e6afea91f5608793bafa7ef2ad481fefbda87ec5069f483de61cb9fa3"}, +] + +[[package]] +name = "numpydoc" +version = "1.10.0" +requires_python = ">=3.10" +summary = "Sphinx extension to support docstrings in Numpy format" +groups = ["doc"] +dependencies = [ + "sphinx>=6", + "tomli>=1.1.0; python_version < \"3.11\"", +] +files = [ + {file = "numpydoc-1.10.0-py3-none-any.whl", hash = "sha256:3149da9874af890bcc2a82ef7aae5484e5aa81cb2778f08e3c307ba6d963721b"}, + {file = "numpydoc-1.10.0.tar.gz", hash = "sha256:3f7970f6eee30912260a6b31ac72bba2432830cd6722569ec17ee8d3ef5ffa01"}, +] + +[[package]] +name = "packaging" +version = "26.2" +requires_python = ">=3.8" +summary = "Core utilities for Python packages" +groups = ["dev", "dev-test", "doc", "test"] +files = [ + {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, + {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +requires_python = ">=3.9" +summary = "Utility library for gitignore style pattern matching of file paths." +groups = ["dev", "dev-lint"] +files = [ + {file = "pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189"}, + {file = "pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a"}, +] + +[[package]] +name = "platformdirs" +version = "4.10.0" +requires_python = ">=3.10" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["test"] +marker = "python_version >= \"3.10\"" +files = [ + {file = "platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a"}, + {file = "platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7"}, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +requires_python = ">=3.9" +summary = "plugin and hook calling mechanisms for python" +groups = ["dev", "dev-test"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[[package]] +name = "propcache" +version = "0.5.2" +requires_python = ">=3.10" +summary = "Accelerated property cache" +groups = ["dev", "dev-test"] +files = [ + {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba"}, + {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a"}, + {file = "propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a"}, + {file = "propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031"}, + {file = "propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42"}, + {file = "propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4"}, + {file = "propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d"}, + {file = "propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757"}, + {file = "propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568"}, + {file = "propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191"}, + {file = "propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7"}, + {file = "propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4"}, + {file = "propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0"}, + {file = "propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c"}, + {file = "propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2"}, + {file = "propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821"}, + {file = "propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370"}, + {file = "propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6"}, + {file = "propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe"}, + {file = "propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427"}, +] + +[[package]] +name = "pygments" +version = "2.20.0" +requires_python = ">=3.9" +summary = "Pygments is a syntax highlighting package written in Python." +groups = ["dev", "dev-test", "doc"] +files = [ + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, +] + +[[package]] +name = "pytest" +version = "9.1.1" +requires_python = ">=3.10" +summary = "pytest: simple powerful testing with Python" +groups = ["dev", "dev-test"] +dependencies = [ + "colorama>=0.4; sys_platform == \"win32\"", + "exceptiongroup>=1; python_version < \"3.11\"", + "iniconfig>=1.0.1", + "packaging>=22", + "pluggy<2,>=1.5", + "pygments>=2.7.2", + "tomli>=1; python_version < \"3.11\"", +] +files = [ + {file = "pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c"}, + {file = "pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313"}, +] + +[[package]] +name = "python-discovery" +version = "1.4.3" +requires_python = ">=3.8" +summary = "Python interpreter discovery" +groups = ["test"] +marker = "python_version >= \"3.10\"" +dependencies = [ + "filelock>=3.15.4", + "platformdirs<5,>=4.3.6", +] +files = [ + {file = "python_discovery-1.4.3-py3-none-any.whl", hash = "sha256:b6e1e4a7d9e3f6948c39746ffe8218225162d738ba39d05ab1d2f6c1cac4878c"}, + {file = "python_discovery-1.4.3.tar.gz", hash = "sha256:ad57d7045a862460d4a235986c33f13ed707d3aeb9153fa47eb7dfd0d4673289"}, +] + +[[package]] +name = "requests" +version = "2.34.2" +requires_python = ">=3.10" +summary = "Python HTTP for Humans." +groups = ["dev", "dev-test", "doc"] +dependencies = [ + "certifi>=2023.5.7", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.26", +] +files = [ + {file = "requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0"}, + {file = "requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed"}, +] + +[[package]] +name = "roman-numerals" +version = "4.1.0" +requires_python = ">=3.10" +summary = "Manipulate well-formed Roman numerals" +groups = ["doc"] +files = [ + {file = "roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7"}, + {file = "roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2"}, +] + +[[package]] +name = "ruff" +version = "0.15.20" +requires_python = ">=3.7" +summary = "An extremely fast Python linter and code formatter, written in Rust." +groups = ["dev", "dev-lint"] +files = [ + {file = "ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078"}, + {file = "ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b"}, + {file = "ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b"}, + {file = "ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487"}, + {file = "ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3"}, + {file = "ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053"}, + {file = "ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4"}, + {file = "ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460"}, + {file = "ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21"}, + {file = "ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415"}, + {file = "ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca"}, + {file = "ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566"}, +] + +[[package]] +name = "scipy" +version = "1.18.0" +requires_python = ">=3.12" +summary = "Fundamental algorithms for scientific computing in Python" +groups = ["dev", "dev-test"] +dependencies = [ + "numpy<2.8,>=2.0.0", +] +files = [ + {file = "scipy-1.18.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:7bd21faaf5a1a3b2eff922d02db5f191b99a6518db9078a8fb23169f6d22259a"}, + {file = "scipy-1.18.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:265915e79107de9f946b855e50d7470d5893ec3f54b342e1aa6201cbdcd8bb6b"}, + {file = "scipy-1.18.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9ab7b758be6940954a713ee466e2043e9f6e2ed965c1fce5c91039f4be3d90a9"}, + {file = "scipy-1.18.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:97b6cddaaee0a779ef6b5ca83c9604b27cc16b2b8fc22c142652df8793319fb8"}, + {file = "scipy-1.18.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:52a96e21517c7292375c0e27dd796a811f03fcea5fd4d108fdfea8145dcf17ab"}, + {file = "scipy-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f55797419e16e7f30cf88ffb3113ce0467f00cfe3f70d5c281730b21769bfc2"}, + {file = "scipy-1.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ad033410e2e0672ffdc1042110cef20e1c46f8fd0616cee1d44d8d58fad8fc11"}, + {file = "scipy-1.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a55985d54c769c872e64b7f4c8a81cc30ef700cc04296abbbf3705439c126de"}, + {file = "scipy-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:71ccc8faa2dd16ac310233203474a8b5cb67f10dedd54a3116d34943f4b19132"}, + {file = "scipy-1.18.0-cp312-cp312-win_arm64.whl", hash = "sha256:d88363fd9d8fbd3511bd273f1a49efb2a540773ddf92a91d57498ce7dd7f3e76"}, + {file = "scipy-1.18.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:09143f676d157d9f546d663504ef9c1becb819824f1afc018814176411942446"}, + {file = "scipy-1.18.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5efe260f69417b97ddae455bfb5a95e8359f7f66ad7fa9522a60feb66f169520"}, + {file = "scipy-1.18.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:68363b7eaacd8b5dd426df56d782cc156468ac79a127a1b87ca597d6e2e82197"}, + {file = "scipy-1.18.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:c5557d8be5da8e41353fcd4d21491fdbab83b062fc579e94dc09a7c8ab4f669b"}, + {file = "scipy-1.18.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0d13bca67c096d89fb95ced0d8921807300fce0275643aef9533cc63a0773468"}, + {file = "scipy-1.18.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a46f9273dbd0eb1cefba61c9b8648b4dfe3cbc14a080176f9a73e44b8336dc7f"}, + {file = "scipy-1.18.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5aba46108853ddfc77906b6557aac839d2b52e900c1d72a1180adaaab58d265f"}, + {file = "scipy-1.18.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b6f758e35f12757b5d95c00bc6de2438e229c2664b7a92e96f205959d9f2dfa4"}, + {file = "scipy-1.18.0-cp313-cp313-win_amd64.whl", hash = "sha256:1afac4a847207c7ff8efd321734a50b06d0280b3b2a2c0fc2f413101747ad7c7"}, + {file = "scipy-1.18.0-cp313-cp313-win_arm64.whl", hash = "sha256:c5dbddf60e58c2312316d097271a8e73d40eaf2eabfa4d95ed7d3695bbf2ce7b"}, + {file = "scipy-1.18.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4c256ee70c0d1a8a2ace807e199ccd4e3f57037433842abb3fb36bc17eaa9578"}, + {file = "scipy-1.18.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:2ef3abc54a4ffc53765374b0d5728532dfdd2585ed23f6b11c206a1f0b1b9af8"}, + {file = "scipy-1.18.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2a6af57bd9e4a75d70e4117e78a1bbee84f79ae3fbb6d0111005d6ebcc4cb8d"}, + {file = "scipy-1.18.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:3f1ac564d3bf6c03d861d2cd87a1bea0da2887136f7fb1bf519c05a8971452d6"}, + {file = "scipy-1.18.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40395a5fcd1abee49a5c7aaa98c29db393eedc835138560a588c47ec16156690"}, + {file = "scipy-1.18.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ca01e8ae69f1b18e9a58d91afead31be3cef0dd905a10249dac559ee15460a0"}, + {file = "scipy-1.18.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7a7f3b01647384dbc3a711e8c6778e0aabbe93959249fef5c7393396bcac0867"}, + {file = "scipy-1.18.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6aa94e78ec192a30063a5e72e561c28af769dc311190b24fe91774eff1969709"}, + {file = "scipy-1.18.0-cp314-cp314-win_amd64.whl", hash = "sha256:2d8bbdc6c817f5b4006a54d799d4f5bab6f910193cbb9a1ff310833d4d270f61"}, + {file = "scipy-1.18.0-cp314-cp314-win_arm64.whl", hash = "sha256:18e9575f1569b2c54174e6159d32942e03731177f63dce7975f0a0c88d102f5b"}, + {file = "scipy-1.18.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f351e0dd702687d12a402b867a1b4146a256923e1c38317cbc472f6372b94707"}, + {file = "scipy-1.18.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7c7a51b33ce387193c97f228320cf8e87361daa1bba750638677729598b3e677"}, + {file = "scipy-1.18.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:84031d7b052a54fae2f8632e0ec802073d385476eb9a63079bce6e23ef9283d4"}, + {file = "scipy-1.18.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:56abf29a7c067dde59be8b9a22d606a4ea1b2f2a4b756d9d903c62818f5dacce"}, + {file = "scipy-1.18.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ad44305cfa24b1ba5803cbbebf033590ccbac1aa5d612d727b785325ab408b0"}, + {file = "scipy-1.18.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:945c1761b93f38d7f99ae81ae80c63e621471608c7eeead563f6df025585cd58"}, + {file = "scipy-1.18.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1a4441f15d620578772a49e5ab48c0ee1f7a0220e387110283062729136b2553"}, + {file = "scipy-1.18.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9aac6192fac56bf2ca534389d24623f07b39ff83317d58287285e7fbd622ff76"}, + {file = "scipy-1.18.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e40baea28ae7f5475c779741e2d90b1247c78531207b49c7030e698ff81cee3f"}, + {file = "scipy-1.18.0-cp314-cp314t-win_arm64.whl", hash = "sha256:368e0a705903c466aa5f08eefb39e6b1b6b2d659e7352a31fd9e2438365be0f8"}, + {file = "scipy-1.18.0.tar.gz", hash = "sha256:67b2ad2ad54c72ca6d04975a9b2df8c3638c34ddd5b28738e94fc2b57929d378"}, +] + +[[package]] +name = "shapely" +version = "2.1.2" +requires_python = ">=3.10" +summary = "Manipulation and analysis of geometric objects" +groups = ["default"] +dependencies = [ + "numpy>=1.21", +] +files = [ + {file = "shapely-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fe2533caae6a91a543dec62e8360fe86ffcdc42a7c55f9dfd0128a977a896b94"}, + {file = "shapely-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ba4d1333cc0bc94381d6d4308d2e4e008e0bd128bdcff5573199742ee3634359"}, + {file = "shapely-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0bd308103340030feef6c111d3eb98d50dc13feea33affc8a6f9fa549e9458a3"}, + {file = "shapely-2.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e7d4d7ad262a48bb44277ca12c7c78cb1b0f56b32c10734ec9a1d30c0b0c54b"}, + {file = "shapely-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e9eddfe513096a71896441a7c37db72da0687b34752c4e193577a145c71736fc"}, + {file = "shapely-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:980c777c612514c0cf99bc8a9de6d286f5e186dcaf9091252fcd444e5638193d"}, + {file = "shapely-2.1.2-cp312-cp312-win32.whl", hash = "sha256:9111274b88e4d7b54a95218e243282709b330ef52b7b86bc6aaf4f805306f454"}, + {file = "shapely-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:743044b4cfb34f9a67205cee9279feaf60ba7d02e69febc2afc609047cb49179"}, + {file = "shapely-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b510dda1a3672d6879beb319bc7c5fd302c6c354584690973c838f46ec3e0fa8"}, + {file = "shapely-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8cff473e81017594d20ec55d86b54bc635544897e13a7cfc12e36909c5309a2a"}, + {file = "shapely-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe7b77dc63d707c09726b7908f575fc04ff1d1ad0f3fb92aec212396bc6cfe5e"}, + {file = "shapely-2.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ed1a5bbfb386ee8332713bf7508bc24e32d24b74fc9a7b9f8529a55db9f4ee6"}, + {file = "shapely-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a84e0582858d841d54355246ddfcbd1fce3179f185da7470f41ce39d001ee1af"}, + {file = "shapely-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc3487447a43d42adcdf52d7ac73804f2312cbfa5d433a7d2c506dcab0033dfd"}, + {file = "shapely-2.1.2-cp313-cp313-win32.whl", hash = "sha256:9c3a3c648aedc9f99c09263b39f2d8252f199cb3ac154fadc173283d7d111350"}, + {file = "shapely-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:ca2591bff6645c216695bdf1614fca9c82ea1144d4a7591a466fef64f28f0715"}, + {file = "shapely-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2d93d23bdd2ed9dc157b46bc2f19b7da143ca8714464249bef6771c679d5ff40"}, + {file = "shapely-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01d0d304b25634d60bd7cf291828119ab55a3bab87dc4af1e44b07fb225f188b"}, + {file = "shapely-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8d8382dd120d64b03698b7298b89611a6ea6f55ada9d39942838b79c9bc89801"}, + {file = "shapely-2.1.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:19efa3611eef966e776183e338b2d7ea43569ae99ab34f8d17c2c054d3205cc0"}, + {file = "shapely-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:346ec0c1a0fcd32f57f00e4134d1200e14bf3f5ae12af87ba83ca275c502498c"}, + {file = "shapely-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6305993a35989391bd3476ee538a5c9a845861462327efe00dd11a5c8c709a99"}, + {file = "shapely-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:c8876673449f3401f278c86eb33224c5764582f72b653a415d0e6672fde887bf"}, + {file = "shapely-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:4a44bc62a10d84c11a7a3d7c1c4fe857f7477c3506e24c9062da0db0ae0c449c"}, + {file = "shapely-2.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:9a522f460d28e2bf4e12396240a5fc1518788b2fcd73535166d748399ef0c223"}, + {file = "shapely-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ff629e00818033b8d71139565527ced7d776c269a49bd78c9df84e8f852190c"}, + {file = "shapely-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f67b34271dedc3c653eba4e3d7111aa421d5be9b4c4c7d38d30907f796cb30df"}, + {file = "shapely-2.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:21952dc00df38a2c28375659b07a3979d22641aeb104751e769c3ee825aadecf"}, + {file = "shapely-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1f2f33f486777456586948e333a56ae21f35ae273be99255a191f5c1fa302eb4"}, + {file = "shapely-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cf831a13e0d5a7eb519e96f58ec26e049b1fad411fc6fc23b162a7ce04d9cffc"}, + {file = "shapely-2.1.2-cp314-cp314-win32.whl", hash = "sha256:61edcd8d0d17dd99075d320a1dd39c0cb9616f7572f10ef91b4b5b00c4aeb566"}, + {file = "shapely-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:a444e7afccdb0999e203b976adb37ea633725333e5b119ad40b1ca291ecf311c"}, + {file = "shapely-2.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5ebe3f84c6112ad3d4632b1fd2290665aa75d4cef5f6c5d77c4c95b324527c6a"}, + {file = "shapely-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5860eb9f00a1d49ebb14e881f5caf6c2cf472c7fd38bd7f253bbd34f934eb076"}, + {file = "shapely-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b705c99c76695702656327b819c9660768ec33f5ce01fa32b2af62b56ba400a1"}, + {file = "shapely-2.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a1fd0ea855b2cf7c9cddaf25543e914dd75af9de08785f20ca3085f2c9ca60b0"}, + {file = "shapely-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:df90e2db118c3671a0754f38e36802db75fe0920d211a27481daf50a711fdf26"}, + {file = "shapely-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:361b6d45030b4ac64ddd0a26046906c8202eb60d0f9f53085f5179f1d23021a0"}, + {file = "shapely-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:b54df60f1fbdecc8ebc2c5b11870461a6417b3d617f555e5033f1505d36e5735"}, + {file = "shapely-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:0036ac886e0923417932c2e6369b6c52e38e0ff5d9120b90eef5cd9a5fc5cae9"}, + {file = "shapely-2.1.2.tar.gz", hash = "sha256:2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9"}, +] + +[[package]] +name = "smart-open" +version = "8.0.0" +requires_python = "<4.0,>=3.10" +summary = "Utils for streaming large files (S3, HDFS, GCS, SFTP, Azure Blob Storage, gzip, bz2, zst...)" +groups = ["dev", "dev-test"] +dependencies = [ + "wrapt", +] +files = [ + {file = "smart_open-8.0.0-py3-none-any.whl", hash = "sha256:ff4f395c9e86f23e27771dc4ba756ad4bd145f181859a782c50d64168485761b"}, + {file = "smart_open-8.0.0.tar.gz", hash = "sha256:5a2008d60688bd3b33c52e2ef666d3c60cf956e73e215de8c7b242cf56fdd1b2"}, +] + +[[package]] +name = "smart-open" +version = "8.0.0" +extras = ["http"] +requires_python = "<4.0,>=3.10" +summary = "Utils for streaming large files (S3, HDFS, GCS, SFTP, Azure Blob Storage, gzip, bz2, zst...)" +groups = ["dev", "dev-test"] +dependencies = [ + "requests", + "smart-open==8.0.0", +] +files = [ + {file = "smart_open-8.0.0-py3-none-any.whl", hash = "sha256:ff4f395c9e86f23e27771dc4ba756ad4bd145f181859a782c50d64168485761b"}, + {file = "smart_open-8.0.0.tar.gz", hash = "sha256:5a2008d60688bd3b33c52e2ef666d3c60cf956e73e215de8c7b242cf56fdd1b2"}, +] + +[[package]] +name = "snowballstemmer" +version = "3.1.1" +requires_python = ">=3.3" +summary = "This package provides 36 stemmers for 34 languages generated from Snowball algorithms." +groups = ["doc"] +files = [ + {file = "snowballstemmer-3.1.1-py3-none-any.whl", hash = "sha256:7e207fa178741da09cdee59d3ecec3827ad5f92b1fc5c9ff3755b639f71f5752"}, + {file = "snowballstemmer-3.1.1.tar.gz", hash = "sha256:e07bbc54a0d798fe6010a12398422e62a8bfbba95c394fd0956ef58cb4d3e260"}, +] + +[[package]] +name = "sphinx" +version = "9.1.0" +requires_python = ">=3.12" +summary = "Python documentation generator" +groups = ["doc"] +dependencies = [ + "Jinja2>=3.1", + "Pygments>=2.17", + "alabaster>=0.7.14", + "babel>=2.13", + "colorama>=0.4.6; sys_platform == \"win32\"", + "docutils<0.23,>=0.21", + "imagesize>=1.3", + "packaging>=23.0", + "requests>=2.30.0", + "roman-numerals>=1.0.0", + "snowballstemmer>=2.2", + "sphinxcontrib-applehelp>=1.0.7", + "sphinxcontrib-devhelp>=1.0.6", + "sphinxcontrib-htmlhelp>=2.0.6", + "sphinxcontrib-jsmath>=1.0.1", + "sphinxcontrib-qthelp>=1.0.6", + "sphinxcontrib-serializinghtml>=1.1.9", +] +files = [ + {file = "sphinx-9.1.0-py3-none-any.whl", hash = "sha256:c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978"}, + {file = "sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb"}, +] + +[[package]] +name = "sphinx-rtd-theme" +version = "3.1.0" +requires_python = ">=3.8" +summary = "Read the Docs theme for Sphinx" +groups = ["doc"] +dependencies = [ + "docutils<0.23,>0.18", + "sphinx<10,>=6", + "sphinxcontrib-jquery<5,>=4", +] +files = [ + {file = "sphinx_rtd_theme-3.1.0-py2.py3-none-any.whl", hash = "sha256:1785824ae8e6632060490f67cf3a72d404a85d2d9fc26bce3619944de5682b89"}, + {file = "sphinx_rtd_theme-3.1.0.tar.gz", hash = "sha256:b44276f2c276e909239a4f6c955aa667aaafeb78597923b1c60babc76db78e4c"}, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +groups = ["doc"] +files = [ + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, +] + +[[package]] +name = "sphinxcontrib-autoprogram" +version = "0.1.9" +requires_python = ">=3.8" +summary = "Documenting CLI programs" +groups = ["doc"] +dependencies = [ + "Sphinx>=1.2", +] +files = [ + {file = "sphinxcontrib-autoprogram-0.1.9.tar.gz", hash = "sha256:219655507fadca29b3062b5d86c37d94db48f03bde4b58d61526872bf72f57cc"}, + {file = "sphinxcontrib_autoprogram-0.1.9-py2.py3-none-any.whl", hash = "sha256:79a5282d7640337e4bf11f624970a43709f1b704c5c59a59756d45e824db5301"}, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" +groups = ["doc"] +files = [ + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +groups = ["doc"] +files = [ + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, +] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +requires_python = ">=2.7" +summary = "Extension to include jQuery on newer Sphinx releases" +groups = ["doc"] +dependencies = [ + "Sphinx>=1.8", +] +files = [ + {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, + {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +requires_python = ">=3.5" +summary = "A sphinx extension which renders display math in HTML via JavaScript" +groups = ["doc"] +files = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" +groups = ["doc"] +files = [ + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" +groups = ["doc"] +files = [ + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +requires_python = ">=3.9" +summary = "Backported and Experimental Type Hints for Python 3.9+" +groups = ["dev", "dev-lint", "dev-test"] +files = [ + {file = "typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8"}, + {file = "typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5"}, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +requires_python = ">=3.10" +summary = "HTTP library with thread-safe connection pooling, file post, and more." +groups = ["dev", "dev-test", "doc"] +files = [ + {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"}, + {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"}, +] + +[[package]] +name = "virtualenv" +version = "21.5.2" +requires_python = ">=3.9" +summary = "Virtual Python Environment builder" +groups = ["test"] +marker = "python_version >= \"3.10\"" +dependencies = [ + "distlib<1,>=0.3.7", + "filelock<4,>=3.24.2; python_version >= \"3.10\"", + "filelock<=3.19.1,>=3.16.1; python_version < \"3.10\"", + "platformdirs<5,>=3.9.1", + "python-discovery>=1.4.2", + "typing-extensions>=4.13.2; python_version < \"3.11\"", +] +files = [ + {file = "virtualenv-21.5.2-py3-none-any.whl", hash = "sha256:4d9f76b4363ed04a4837e812110eb301367eb470f616b62399a50d39dee70e47"}, + {file = "virtualenv-21.5.2.tar.gz", hash = "sha256:465da6db2a5b615258cddefb749ceeb3627e4fddda93be88c97ba8321ca3c6d1"}, +] + +[[package]] +name = "wrapt" +version = "2.2.2" +requires_python = ">=3.9" +summary = "Module for decorators, wrappers and monkey patching." +groups = ["dev", "dev-test"] +files = [ + {file = "wrapt-2.2.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8417fd3c674d3c8023d080292d29301531a12daf8bd938dd419710dd2f464f2b"}, + {file = "wrapt-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e7070c7472582e31af3dfc2622b2381a0df7435110a9388ed8db5ffbce67efb"}, + {file = "wrapt-2.2.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2e096c9d39a59b35b63c9aacfbbbec2088ff51ff1fc31051acc60a07f42f273a"}, + {file = "wrapt-2.2.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d1a6050405bf334be33bf66296f113563622972a34900ae6fa60fd283a1a900"}, + {file = "wrapt-2.2.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10adb01371408c6de504a6658b9886480f1a4919a83752748a387a504a21df79"}, + {file = "wrapt-2.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3442eee2a5798f9b451f1b2cd7518ce8b7e28a2a364696c414460a0e295c012a"}, + {file = "wrapt-2.2.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6c99012a22f735a85eed7c4b86a3e99c30fdd57d9e115b2b45f796264b58d0bf"}, + {file = "wrapt-2.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b686cfc008776a3952d6213cb296ed7f45d782a8453936406faa89eac0835ab"}, + {file = "wrapt-2.2.2-cp312-cp312-win32.whl", hash = "sha256:ef2cce266b5b0b07e19fa82e59673b81142b7a3607c8ed1254113d048ed668da"}, + {file = "wrapt-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:abf8c20a2d72ee69e16328b3c91342c446e723bfe48bfcc4dded3b9722ac027f"}, + {file = "wrapt-2.2.2-cp312-cp312-win_arm64.whl", hash = "sha256:c6c64c5d02578bc4c4bca4f0aef1504de933c1d5b4ac2710b9131111459506c8"}, + {file = "wrapt-2.2.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9e8b648270c613720a202d9a45ebabc33261b22c3a839b115ac5bce8c0bb0d69"}, + {file = "wrapt-2.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6fb7e94e8fe3e4c3067bb1653a91cce7c5e83acc119fdd41501b1bf74654617"}, + {file = "wrapt-2.2.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb18fc51e813df0d9c98049e3bf2298a5495a648602040e21fa3c7329371159e"}, + {file = "wrapt-2.2.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94b00b00f806eb3ef2abe9049ed45994a81ee9284884d96e6b8314927c6cea3d"}, + {file = "wrapt-2.2.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:62415fd095bc590b842b6d092f2b5d9ccbaeb7e0b28535c03dcea2718b48636b"}, + {file = "wrapt-2.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a41e758d80dc0ab8c210f641ac892009d356cf1f955d97db544c8dd317b4d14c"}, + {file = "wrapt-2.2.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b84cd4058001c9727b0e9980b7a9e66325b5ca748b1b578e822cade1bc6b304f"}, + {file = "wrapt-2.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:26fc73a1b15e0946d2942b9a4426d162b51676338327dc067ccd8d2d76385f94"}, + {file = "wrapt-2.2.2-cp313-cp313-win32.whl", hash = "sha256:3c4095803491f6ef72128914c28ec05bbad9758433bb35f6715a3e9c8e46fb2d"}, + {file = "wrapt-2.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:2cb07f414fab25dbe6b5c7398e1491423a5c81a6209533639969a6c928d474a4"}, + {file = "wrapt-2.2.2-cp313-cp313-win_arm64.whl", hash = "sha256:1fc7691f070220215cccb2a20836b9adbaecb8ff22ad47abe63de5f110994fac"}, + {file = "wrapt-2.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ec8f83949028366531383603139403cac7a826e4011955813cdd640017845ce5"}, + {file = "wrapt-2.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b481fb0c40d9fd90a5809911208da700987d373a20a4709dc9e3944af7a6bec"}, + {file = "wrapt-2.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0065a3b657cec06813b4241d2462ccec287f6863103d7445b725fb3a889736f9"}, + {file = "wrapt-2.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30f7424af5c5c345b7f26490e097f74a2ef45b3d08b664dc33571aee3bd3b56c"}, + {file = "wrapt-2.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:07fdcb012821859168641acf68afad61ef9783cf37100af85f152550e9677194"}, + {file = "wrapt-2.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f90038ab58fafb584801ca62d72384d7d5225d93c76f7b773c22fae545bd8066"}, + {file = "wrapt-2.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c5d7825491bfa2d08b97e9557768987952c7b9ae687d06c3320b40a37ccb7f20"}, + {file = "wrapt-2.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ad520e6daa9bbf136f14de735474dbec7dcc0891f718e1d274ce8dc92e645af"}, + {file = "wrapt-2.2.2-cp313-cp313t-win32.whl", hash = "sha256:25904acb9475f46c24fe0423dbc8fda8cc5fbc282ab3dc6e72e919748c53f4e9"}, + {file = "wrapt-2.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:305d4c247d61c4115794a169141823c62f719525ddb90b23aa332741c77d2c28"}, + {file = "wrapt-2.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c20279cd1a29800815d7b2d6338b60a6c6e78263f9d6e62e0eda251ba9cae2d0"}, + {file = "wrapt-2.2.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0e64826f920c42d9d9f87e8cc09ffae66c51ede12d59061a5a426deb9aa71745"}, + {file = "wrapt-2.2.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dcaa5e1451bd8751d7bd1568dfa3321c78092a52a7ecb5d1a0f18a5791e1fd00"}, + {file = "wrapt-2.2.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0abfd648dac9ac9c5b3aa9b523d27f1789046640b58dcd5652a720ddb325e1fc"}, + {file = "wrapt-2.2.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f4bfd8d1eb438153eff8b8cfe87f032ba65731e1ce06138b5090f745a33f6f95"}, + {file = "wrapt-2.2.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c427c9d06d859848a69f0d928fe28b5c33a941b2265d10a0e1f15cd244f1ee33"}, + {file = "wrapt-2.2.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4250b43d1a129d947e083c4dc6baf333c9bb34edd26f912d5b0457841fc858ab"}, + {file = "wrapt-2.2.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:173e5bb5ca350a6e0abab60b7ec7cdd7992a814cb14b4de670a28f067f105663"}, + {file = "wrapt-2.2.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:aa14b01804bce36c6d63d7b6a4f55df390f29f8648cc13a1f40b166f4d54680d"}, + {file = "wrapt-2.2.2-cp314-cp314-win32.whl", hash = "sha256:58f9f8d637c9a6e245c6ef5b109b67ec187d2faed23d1405656b51d96e0a5b56"}, + {file = "wrapt-2.2.2-cp314-cp314-win_amd64.whl", hash = "sha256:385cb1866f20479e83299af585375bfa0a4b0c6c9907a981483ea782ea8ae406"}, + {file = "wrapt-2.2.2-cp314-cp314-win_arm64.whl", hash = "sha256:8ffbeaea6771a6eba6e6eeb09767864995726bc8240bb54baf88a9bb1db34d5c"}, + {file = "wrapt-2.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:09f811d43f6f33ec7515f0be76b159569f4057ab54d3e079c3204dddb90afa2a"}, + {file = "wrapt-2.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a795d3c06e5fbf9ea2f13196180b77aeab1b4685917256ee0d014cc163d90063"}, + {file = "wrapt-2.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:45c2f2768e790c9f8db90f239ef23a2af8e7570f25a35619ef902df4a738447f"}, + {file = "wrapt-2.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbf00ee0cb55ec24e2b0995a71942b85b21a066db8f3f46e1dbfdb9433ffba81"}, + {file = "wrapt-2.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2252f77663651b89255895f58cc6ac08fcb206d4371813e5af61bb62d4f7689c"}, + {file = "wrapt-2.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2cd7181ab1c31192ff5219269830744b5a62020b3a6d433588c4f1c95b8f8bff"}, + {file = "wrapt-2.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:6fe35fd51b74867d8b80174c277bd6bbf6a73e443f908129dc531c4b688a20d5"}, + {file = "wrapt-2.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:11d95fc2fbad3163596c39d440e6f21ca9fccece74b56e30a37ac2fca786a07c"}, + {file = "wrapt-2.2.2-cp314-cp314t-win32.whl", hash = "sha256:d8a15813215f33fa83667bfc978b300e35669ea8bb424e970a1426bcb7bc6cca"}, + {file = "wrapt-2.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d09db0f7e8357060d3c38fc22a018aba683a796bf184360fd1a58f6fc180dc77"}, + {file = "wrapt-2.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:f32fe639c39561ccc187bcae17e9271be0eb45f1c2952510d2f29b33ab577347"}, + {file = "wrapt-2.2.2-py3-none-any.whl", hash = "sha256:5bad217350f19ce99ca5b5e71d406765ea86fe541628426772b657375ee1c048"}, + {file = "wrapt-2.2.2.tar.gz", hash = "sha256:0788e321027c999bf221b667bd4a54aaefd1a36283749a860ac3eb77daed0302"}, +] + +[[package]] +name = "xmlschema" +version = "4.3.2" +requires_python = ">=3.10" +summary = "An XML Schema validator and decoder" +groups = ["xsdtypes-generation"] +dependencies = [ + "elementpath<6.0.0,>=5.1.3", +] +files = [ + {file = "xmlschema-4.3.2-py3-none-any.whl", hash = "sha256:cf5c970a30f6ebcb3da35260e694704cc0b6794d8ace46125bb2a95e38ed9307"}, + {file = "xmlschema-4.3.2.tar.gz", hash = "sha256:f3b33a21a2b2cdc404ddc3fb599d8bc1dee90b155d547370672e6e684746b8d6"}, +] + +[[package]] +name = "yarl" +version = "1.24.2" +requires_python = ">=3.10" +summary = "Yet another URL library" +groups = ["dev", "dev-test"] +dependencies = [ + "idna>=2.0", + "multidict>=4.0", + "propcache>=0.2.1", +] +files = [ + {file = "yarl-1.24.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b975866c184564c827e0877380f0dae57dcca7e52782128381b72feff6dfceb8"}, + {file = "yarl-1.24.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3b075301a2836a0e297b1b658cb6d6135df535d62efefdd60366bd589c2c82f2"}, + {file = "yarl-1.24.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ae44649b00947634ab0dab2a374a638f52923a6e67083f2c156cd5cbd1a881d"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:507cc19f0b45454e2d6dcd62ff7d062b9f77a2812404e62dbdaec05b50faa035"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4c17bad5a530912d2111825d3f05e89bab2dd376aaa8cbc77e449e6db63e576"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f5f0cbb112838a4a293985b6ed73948a547dadcc1ba6d2089938e7abdedceef8"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ec8356b8a6afcf81fc7aeeef13b1ff7a49dec00f313394bbb9e83830d32ccd7"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e7ebcdef69dec6c6451e616f32b622a6d4a2e92b445c992f7c8e5274a6bbc4c"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:47a55d6cf6db2f401017a9e96e5288844e5051911fb4e0c8311a3980f5e59a7d"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3065657c80a2321225e804048597ad55658a7e76b32d6f5ee4074d04c50401db"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cb84b80d88e19ede158619b80813968713d8d008b0e2497a576e6a0557d50712"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:990de4f680b1c217e77ff0d6aa0029f9eb79889c11fb3e9a3942c7eba29c1996"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:abb8ec0323b80161e3802da3150ef660b41d0e9be2048b76a363d93eee992c2b"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e7977781f83638a4c73e0f88425563d70173e0dfd90ac006a45c65036293ee3c"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e30dd55825dc554ec5b66a94953b8eda8745926514c5089dfcacecb9c99b5bd1"}, + {file = "yarl-1.24.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dafe10c12ddd4d120d528c4b5599c953bd7b12845347d507b95451195bb6cad"}, + {file = "yarl-1.24.2-cp312-cp312-win_arm64.whl", hash = "sha256:044a09d8401fcf8681977faef6d286b8ade1e2d2e9dceda175d1cfa5ca496f30"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:491ac9141decf49ee8030199e1ee251cdff0e131f25678817ff6aa5f837a3536"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e89418f65eda18f99030386305bd44d7d504e328a7945db1ead514fbe03a0607"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cdfcce633b4a4bb8281913c57fcafd4b5933fbc19111a5e3930bbd299d6102f1"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:863297ddede92ee49024e9a9b11ecb59f310ca85b60d8537f56bed9bbb5b1986"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:374423f70754a2c96942ede36a29d37dc6b0cb8f92f8d009ddf3ed78d3da5488"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33a29b5d00ccbf3219bb3e351d7875739c19481e030779f48cc46a7a71681a9b"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a9532c57211730c515341af11fef6e9b61d157487272a096d0c04da445642592"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91e72cf093fd833483a97ee648e0c053c7c629f51ff4a0e7edd84f806b0c5617"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b3177bc0a768ef3bacceb4f272632990b7bea352f1b2f1eee9d6d6ff16516f92"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e196952aacaf3b232e265ff02980b64d483dc0972bd49bcb061171ff22ac203a"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:204e7a61ce99919c0de1bf904ab5d7aa188a129ea8f690a8f76cfb6e2844dc44"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b156914620f0b9d78dc1adb3751141daee561cfec796088abb89ed49d220f1a"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8372a2b976cf70654b2be6619ab6068acabb35f724c0fda7b277fbf53d66a5cf"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f9a1e9b622ca284143aab5d885848686dcd85453bb1ca9abcdb7503e64dc0056"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:810e19b685c8c3c5862f6a38160a1f4e4c0916c9390024ec347b6157a45a0992"}, + {file = "yarl-1.24.2-cp313-cp313-win_amd64.whl", hash = "sha256:7d37fb7c38f2b6edab0f845c4f85148d4c44204f52bc127021bd2bc9fdbf1656"}, + {file = "yarl-1.24.2-cp313-cp313-win_arm64.whl", hash = "sha256:1e831894be7c2954240e49791fa4b50c05a0dc881de2552cfe3ffd8631c7f461"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:f9312b3c02d9b3d23840f67952913c9c8721d7f1b7db305289faefa878f364c2"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a4f4d6cd615823bfc7fb7e9b5987c3f41666371d870d51058f77e2680fbe9630"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0c3063e5c0a8e8e62fae6c2596fa01da1561e4cd1da6fec5789f5cf99a8aefd8"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fecd17873a096036c1c87ab3486f1aef7f269ada7f23f7f856f93b1cc7744f14"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a46d1ab4ba4d32e6dc80daf8a28ce0bd83d08df52fbc32f3e288663427734535"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73e68edf6dfd5f73f9ca127d84e2a6f9213c65bdffb736bda19524c0564fcd14"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a296ca617f2d25fbceafb962b88750d627e5984e75732c712154d058ae8d79a3"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51b2cf5ec89a8b8470177641ed62a3ba22d74e1e898e06ad53aa77972487208"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:310fc687f7b2044ec54e372c8cbe923bb88f5c37bded0d3079e5791c2fc3cf50"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:297a2fe352ecf858b30a98f87948746ec16f001d279f84aebdbd3bd965e2f1bd"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2a263e76b97bc42bdcd7c5f4953dec1f7cd62a1112fa7f869e57255229390d67"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:822519b64cf0b474f1a0aaef1dc621438ea46bb77c94df97a5b4d213a7d8a8b1"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b6067060d9dc594899ba83e6db6c48c68d1e494a6dab158156ed86977ca7bcb1"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0063adad533e57171b79db3943b229d40dfafeeee579767f96541f106bac5f1b"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ee8e3fb34513e8dc082b586ef4910c98335d43a6fab688cd44d4851bacfce3e8"}, + {file = "yarl-1.24.2-cp314-cp314-win_amd64.whl", hash = "sha256:afb00d7fd8e0f285ca29a44cc50df2d622ff2f7a6d933fa641577b5f9d5f3db0"}, + {file = "yarl-1.24.2-cp314-cp314-win_arm64.whl", hash = "sha256:68cf6eacd6028ef1142bc4b48376b81566385ca6f9e7dde3b0fa91be08ffcb57"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:221ce1dd921ac4f603957f17d7c18c5cc0797fbb52f156941f92e04605d1d67b"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5f3224db28173a00d7afacdee07045cc4673dfab2b15492c7ae10deddbece761"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c557165320d6244ebe3a02431b2a201a20080e02f41f0cfa0ccc47a183765da8"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:904065e6e85b1fa54d0d87438bd58c14c0bad97aad654ad1077fd9d87e8478ed"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8cec2a38d70edc10e0e856ceda886af5327a017ccbde8e1de1bd44d300357543"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e7484b9361ed222ee1ca5b4337aa4cbdcc4618ce5aff57d9ef1582fd95893fc0"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:84f9670b89f34db07f81e53aee83e0b938a3412329d51c8f922488be7fcc4024"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:abb2759733d63a28b4956500a5dd57140f26486c92b2caedfb964ab7d9b79dbf"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:081c2bf54efe03774d0311172bc04fedf9ca01e644d4cd8c805688e527209bdc"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:86746bef442aa479107fe28132e1277237f9c24c2f00b0b0cf22b3ee0904f2bb"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:2d07d21d0bc4b17558e8de0b02fbfdf1e347d3bb3699edd00bb92e7c57925420"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4fb1ac3fc5fecd8ae7453ea237e4d22b49befa70266dfe1629924245c21a0c7f"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4da31a5512ed1729ca8d8aacde3f7faeb8843cde3165d6bcf7f88f74f17bb8aa"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:533ded4dceb5f1f3da7906244f4e82cf46cfd40d84c69a1faf5ac506aa65ecbe"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7b3a85525f6e7eeabcfdd372862b21ee1915db1b498a04e8bf0e389b607ff0bd"}, + {file = "yarl-1.24.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a7624b1ca46ca5d7b864ef0d2f8efe3091454085ee1855b4e992314529972215"}, + {file = "yarl-1.24.2-cp314-cp314t-win_arm64.whl", hash = "sha256:e434a45ce2e7a947f951fc5a8944c8cc080b7e59f9c50ae80fd39107cf88126d"}, + {file = "yarl-1.24.2-py3-none-any.whl", hash = "sha256:2783d9226db8797636cd6896e4de81feed252d1db72265686c9558d97a4d94b9"}, + {file = "yarl-1.24.2.tar.gz", hash = "sha256:9ac374123c6fd7abf64d1fec93962b0bd4ee2c19751755a762a72dd96c0378f8"}, +] diff --git a/sarkit/sicd/Untitled-1.ipynb b/sarkit/sicd/Untitled-1.ipynb new file mode 100644 index 0000000..1bb16d0 --- /dev/null +++ b/sarkit/sicd/Untitled-1.ipynb @@ -0,0 +1,327 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 144, + "id": "bcf95646", + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "\n", + "from lxml import etree\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "from sarkit.verification._sicd_consistency import SicdConsistency\n", + "from sarkit.verification._sicdcheck import main\n", + "\n", + "DATAPATH = pathlib.Path(\"/home/vscuser/repos/sarkit-local/data\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "id": "9e08e7f7", + "metadata": {}, + "outputs": [], + "source": [ + "def _not_simple(poly_elem):\n", + " old_index = poly_elem[-2].get(\"index\")\n", + " poly_elem[-2].set(\"index\", poly_elem[-1].get(\"index\"))\n", + " poly_elem[-1].set(\"index\", old_index)" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "id": "7555d5de", + "metadata": {}, + "outputs": [], + "source": [ + "def _not_simple1(poly_elem):\n", + " sz = int(poly_elem.get(\"size\"))\n", + " old_index = poly_elem[int(sz/2)].get(\"index\")\n", + " poly_elem[int(sz/2)].set(\"index\", poly_elem[-1].get(\"index\"))\n", + " poly_elem[-1].set(\"index\", old_index)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d309b15c", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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0HbYv39/2H6Px6MDBw5Yph3mzJkTHIUZNmyYpkyZottvvz04OmeXdgiIVX2T4W9EIeHl888/V1lZWXD0RTZph7Vr12r//v3q27dv8P/l559/rjvuuEP9+/eXbNAOvXr1ktvtPuX/Syv0G5YOMMYYzZgxQy+99JJWrlypAQMGhO0fNWqUUlJStGLFiuC2bdu2aefOnSooKJAkFRQUaNOmTWG/sIE/7OY/4I7oiiuu0KZNm1RZWRlcLrzwQk2ePDn4ONnbQJIuueSSE26h//jjj9WvXz9J0oABA5STkxPWDvX19Vq3bl1YO9TW1mr9+vXBMitXrpTP59Po0aPjVpfTceTIETmd4X/WLpcr+KrLLu0QEKv6FhQUaM2aNWpsbAyWKSsr06BBg9SjR4+41qmtAuHlk08+0RtvvKEzzjgjbL8d2mHKlCnauHFj2P/L3NxczZkzR8uXL5ds0A6pqam66KKLTvr/0jJ9Z1ymCreTW2+91WRmZppVq1aZ6urq4HLkyJFgmenTp5u+ffualStXmvfff98UFBSYgoKC4P7ArWDjxo0zlZWV5rXXXjNnnnmmpW4hbi70LiRjkzZ49913jdvtNvfff7/55JNPzDPPPGPS09PN008/HSzzwAMPmO7du5s///nPZuPGjebaa69t8XbakSNHmnXr1pk333zTnHPOOR329uGWTJ061fTp0yd4G3Vpaanp1auXufPOO4Nlkq0dDh48aDZs2GA2bNhgJJnf/va3ZsOGDcG7a2JR39raWpOdnW2mTJliNm/ebJ577jmTnp7eYW6bNadoh2PHjplrrrnG5OXlmcrKyrD/l6F3jCR7O7Sk+V1IJgna4VRtUFpaalJSUswTTzxhPvnkE/PII48Yl8tl1q5dGzyGFfoNSwcYSS0uTz75ZLDMV199ZW677TbTo0cPk56ebr797W+b6urqsOPs2LHDjB8/3nTu3Nn06tXL3HHHHaaxsTEBNYqN5gHGLm3wl7/8xZx//vkmLS3NDB482DzxxBNh+30+n/nZz35msrOzTVpamrniiivMtm3bwsp88cUXZtKkSaZr164mIyPDfP/73zcHDx6Mc03arr6+3sycOdP07dvXdOrUyZx11lnmpz/9aVgnlWztUF5e3uL/galTpxoTw/p+8MEH5tJLLzVpaWmmT58+5oEHHohrPU/lZO1QVVXV6v/L8vLy4DGSvR1a0lKAsXo7RNIGf/jDH8zAgQNNp06dzIgRI8zLL78cdgwr9BsOE/oWnQAAABZg6TkwAADAnggwAADAcggwAADAcggwAADAcggwAADAcggwAADAcggwAADAcggwAADAcggwAADAcggwAADAcggwAADAcggwAADAcv4/e+lBrNPg9fEAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "import shapely.geometry as shg\n", + "xmltree = etree.parse(DATAPATH / \"example-sicd-1.5.xml\")\n", + "sicd_con = SicdConsistency.from_parts(xmltree)\n", + "vert1 = sicd_con.xmlhelp.load(\"{*}ImageData/{*}ValidData\")\n", + "x = [v[0] for v in vert1]\n", + "y = [v[1] for v in vert1]\n", + "plt.scatter(x, y, color='red')\n", + "\n", + "colors = ['red', 'blue', 'green', 'orange']\n", + "for i in range(len(x) - 1):\n", + " plt.plot(x[i:i+2], y[i:i+2], color=colors[i % len(colors)], zorder=1)\n", + "plt.show()\n", + "\n", + "shg_polygon = shg.Polygon(vert1)\n", + "print(shg_polygon.is_simple)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 154, + "id": "a8e1a754", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 257 1646]\n", + " [ 258 1995]\n", + " [ 258 2345]\n", + " [ 259 2694]\n", + " [ 260 3043]\n", + " [ 431 3049]\n", + " [ 602 3056]\n", + " [ 773 3062]\n", + " [ 945 3068]\n", + " [1116 3075]\n", + " [1287 3081]\n", + " [1459 3088]\n", + " [1630 3094]\n", + " [1629 2745]\n", + " [1628 2397]\n", + " [1628 2048]\n", + " [1627 1700]\n", + " [1628 1351]\n", + " [1628 1002]\n", + " [1629 654]\n", + " [1630 305]\n", + " [1459 298]\n", + " [1287 291]\n", + " [1116 284]\n", + " [ 945 277]\n", + " [ 773 271]\n", + " [ 602 264]\n", + " [ 431 257]\n", + " [ 260 250]\n", + " [ 259 599]\n", + " [ 258 1297]\n", + " [ 258 948]\n", + " [ 258 1995]]\n", + "False\n" + ] + } + ], + "source": [ + "vert2 = np.append(vert1, [vert1[1]], axis=0)\n", + "print(vert2)\n", + "shg_polygon = shg.Polygon(vert2)\n", + "print(shg_polygon.is_simple)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a328afe9", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "xmltree = etree.parse(DATAPATH / \"example-sicd-1.5.xml\")\n", + "sicd_con = SicdConsistency.from_parts(xmltree)\n", + "_not_simple1(sicd_con.sicdroot.find(\"{*}ImageData/{*}ValidData\"))\n", + "vert1 = sicd_con.xmlhelp.load(\"{*}ImageData/{*}ValidData\")\n", + "#_not_simple1(sicd_con.sicdroot.find(\"{*}GeoData/{*}ValidData\"))\n", + "#vert1 = sicd_con.xmlhelp.load(\"{*}GeoData/{*}ValidData\")\n", + "x = [v[0] for v in vert1]\n", + "y = [v[1] for v in vert1]\n", + "plt.scatter(x, y, color='red')\n", + "\n", + "\n", + "\n", + "colors = ['red', 'blue', 'green', 'orange']\n", + "for i in range(len(x) - 1):\n", + " plt.plot(x[i:i+2], y[i:i+2], color=colors[i % len(colors)], zorder=1)\n", + "#plt.plot(x + [x[0]], y + [y[0]], linestyle='-')\n", + "plt.show()\n", + "\n", + "shg_polygon = shg.Polygon(vert1)\n", + "print(shg_polygon.is_simple)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "id": "2d3f38f0", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjAAAAGdCAYAAAAMm0nCAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQAAeHlJREFUeJzt3XdYVGfexvHvzMDQi4g0xV6xoKIiCsZEYwFb1BhL1Ng1KCZmE9d9s6btrtl0sUdjSWJP7BKNmqggYEGxd1EsFBu9z5z3DyMbEmMFDgO/z3XNdTFznhnu4xHmZp5TNIqiKAghhBBCmBCt2gGEEEIIIZ6UFBghhBBCmBwpMEIIIYQwOVJghBBCCGFypMAIIYQQwuRIgRFCCCGEyZECI4QQQgiTIwVGCCGEECbHTO0AJcVoNHLjxg3s7OzQaDRqxxFCCCHEY1AUhfT0dDw8PNBq//pzlnJbYG7cuIGnp6faMYQQQgjxFK5evUq1atX+cnm5LTB2dnbw2z+Avb292nGEEEII8RjS0tLw9PQsfB//K+W2wNyfNrK3t5cCI4QQQpiYR+3+ITvxCiGEEMLkSIERQgghhMmRAiOEEEIIkyMFRgghhBAmRwqMEEIIIUyOFBghhBBCmBwpMEIIIYQwOVJghBBCCGFyyu2J7EqEwQDh4ZCQAO7uEBAAOp3aqYQQQojSU0beC6XAPK5162DyZLh27X+PVasGM2dC375qJhNCCCFKRxl6L5QppMexbh307190gwFcv37v8XXr1EomhBBClI4y9l6oURRFKdXvWErS0tJwcHAgNTX12a6FZDBAzZp/3mD3aTT32mdcnEwnCSGEKJ9K8b3wcd+/5ROYRwkPL7LB4h1cmdP2ZZJtHO89oChw9eq9cUIIIUR59If3wsMeDVjY+iVydb/tiaLCe6HsA/MoCQlF7s71G8Aq764s8enFV1s+w//K0QeOE0IIIcqN397jDBotc9u+zJf+gzFqddS6c53OFw/8aVxpkE9gHsXdvcjdLHMLAG7ZVmLoKx/xecCrFGi0fxonhBBClBvu7ty0dmTYgA/5vMNQjNp700RZess/jSstUmAeJSDg3ryeRlPk4WopiSgaLbPaDWTw8M9IbNZatYhCCCFESdrn4UX30XPYV7M5lvk5OGfeLTpAowFPz3vvmaVECsyj6HT3Dg+DIiVm5KFNzNz8GTZ5WRxwrU/gnEh2n01WL6cQQghRzAxGhS92nOPVJQe5ZeVA/ZtX2PztFOrfjP/foPvvjV99VaoHs0iBeRx9+8IPP0DVqkUe7p1+kc0+ZjRyt+dOZh6vLTnIf7edId9gVC2qEEIIURyS0nIYsiia0F3nURR4pZUnG7u5Uc/yD+9x1arde4+U88CUUX37wuXL0KnTvfsTJ0JcHLWHvMT619vxatvqAMzbfZGBX0dzIyVb3bxCCCHEU9pz7iaBM8OJvnQHa72Or15pzn/7N8Pq5d/eC1u2uDfwn/+8d+i0Cid0lQLzJHQ6cHG993XduoUflVma6/hXn6bMHtwCOwszYq7cJTA0nF2nk9TNK4QQQjyBAoORT7adYfjiA9zOzKOhmx2bJ/nTp8XvZiB0OqhU6d7XXl6qnQNNCkwx6tHMgy0h/jSt6kBKVj6jlh3iX1tOkVcgU0pCCCHKtoTUbAYtjGbu7osADPGtzobg9tSpYqt2tAeSAlPMalS24YcJfrzWriYAiyLiGLAgiqt3stSOJoQQQjzQL2eSCJwZzsHLd7G1MGPWoBb8+6WmWJqX3TPMS4EpARZmOt7v1Zj5r/pgb2lG7NUUgkLD2X4yUe1oQgghRKF8g5H/hJ1m5NJD3M3Kp0lVe7ZM8qent4fa0R5JCkwJ6tbEja0hAXh7OpKWU8C472J4f9NJcgsMakcTQghRwV27m8WABVF8vfcSAK+1q8mPE9pR09lG7WiPRQpMCfN0smbtOD/GBNQCYGnkZfrPi+LK7Uy1owkhhKigtp9MJHBmOEfiU7CzNGP+qy15v1djLMzK7pTRH0mBKQV6My3/F+TFomGtcLQ25/j1VHqERrD1mFw/SQghROnJKzDyweaTjPsuhrScAryrORAWEkC3JqZ3ORwpMKWos5crYSEBtKpRifTcAoJXHObdDcfJyZcpJSGEECUr/nYW/edHsmTfZQBG+9di7fh2eDpZqx3tqUiBKWUejlasHNuWCR3rAPB9dDwvzY3k0s0MtaMJIYQop8KOJxAUGs6xa6k4WJmzaFgr3u3hhd7MdGuA6SY3YeY6LVO7NWTpiNY42eg5nZBGz1kRbIy9rnY0IYQQ5UhOvoF/bjjB68sPk55bQMvqjoRNDqCzl6va0Z6ZFBgVdWzgQlhIAG1qOZGZZ2Dyqlj+/uMxsvNkSkkIIcSzibuVSd+5kXwXfQWAcc/VZvU4P6o6WqkdrVhIgVGZm4MlK0b7EvJCXTQaWHXwKn3m7ONCcrra0YQQQpiojbHX6REazqmENJxs9CwZ0Zpp3Rthris/b/vlZ01MmJlOy5QuDfhupC/OthacTUqn56x9/BBzTe1oQgghTEhOvoFp644xeVUsmXkG2tR0IiwkgOcbuKgdrdg9UYGZN28ezZo1w97eHnt7e/z8/Pjpp58Kl3fs2BGNRlPkNn78+CKvER8fT1BQENbW1ri4uPD2229TUFBQZMzu3btp2bIlFhYW1K1bl6VLlz7repoE/3rOhE32p12dymTnG/jb2qO8teYoWXkFj/FsIYQQFdmF5Az6zNnHygNX0Whg0gt1WTHGFzcHS7WjlYgnKjDVqlXj448/JiYmhkOHDvHCCy/Qu3dvTp48WThmzJgxJCQkFN4++eSTwmUGg4GgoCDy8vKIjIxk2bJlLF26lOnTpxeOiYuLIygoiOeff57Y2FjeeOMNRo8ezfbt24trncs0FztLvhvly5QX66PVwI+Hr9FzVgRnE2VKSQghxIP9GHPvveJMYjrOtnq+HdmGt7o0wKwcTRn9kdmTDO7Zs2eR+//+97+ZN28e0dHRNG7cGABra2vc3Nwe+Pyff/6ZU6dOsXPnTlxdXWnevDkfffQRU6dO5f3330ev1zN//nxq1arF559/DkCjRo2IiIjgyy+/pGvXrk+/piZEp9UQ0qkerWs6MXnVES7ezKTX7Ag+6NWYV1p7otFo1I4ohBCiDMjKK2D6xpOFuxz41a7MzIHNcbEvn5+6/N5TVzODwcCqVavIzMzEz8+v8PHly5fj7OxMkyZNmDZtGllZ/7sKc1RUFE2bNsXV9X+Hb3Xt2pW0tLTCT3GioqLo3Llzke/VtWtXoqKiHponNzeXtLS0IjdT51enMmGTA+hQvwq5BUb+vu44b6yOJSNXppSEEKKiO5eUTu/Z9/aX1Grgzc71+X60b4UoLzzpJzAAx48fx8/Pj5ycHGxtbVm/fj1eXl4ADB48mBo1auDh4cGxY8eYOnUqZ8+eZd26dQAkJiYWKS9A4f3ExMSHjklLSyM7Oxsrqwcf/jVjxgw++OCDJ12dMs/Z1oKlr7Vm/t6LfP7zOTbG3uDYtVRmD25BYw8HteMJIYQoZYqisObQVd7bdJKcfCNV7CwIHdgCvzqV1Y5Wqp64wDRo0IDY2FhSU1P54YcfGD58OHv27MHLy4uxY8cWjmvatCnu7u506tSJixcvUqdOneLOXsS0adOYMmVK4f20tDQ8PT1L9HuWFq1Ww+sd69K6phMhK48QdyuTl+ZG8s8eXrzqW12mlIQQooLIyC3g3fXH2RB7A4CAes58+UpznG0t1I5W6p54Ckmv11O3bl18fHyYMWMG3t7ezJw584FjfX19Abhw4QIAbm5uJCUlFRlz//79/Wb+aoy9vf1ffvoCYGFhUXh01P1bedP6t8PhXmjoQl6BkX9uOMHEFUdIy8lXO5oQQogSdupGGr1mRbAh9gZaDbzdtQHLRrSpkOWF4jgPjNFoJDc394HLYmNjAXB3v3eVSz8/P44fP05ycnLhmB07dmBvb184DeXn58euXbuKvM6OHTuK7GdTkVWy0bNoWCv+L7ARZloNW48n0CM0gmPXUtSOJoQQogQoisLy/VfoM3cfl25l4mZvyaqxfgQ/XxettuJ+Av9EBWbatGns3buXy5cvc/z4caZNm8bu3bsZMmQIFy9e5KOPPiImJobLly+zadMmhg0bRocOHWjWrBkAXbp0wcvLi6FDh3L06FG2b9/Ou+++S3BwMBYW9xrk+PHjuXTpEu+88w5nzpxh7ty5rFmzhjfffLNk/gVMkFarYUyH2qwZf++U0PF3sug3L5Il++JQFEXteEIIIYpJek4+E1ce4f/WnyCvwMjzDaoQNvneJWgquicqMMnJyQwbNowGDRrQqVMnDh48yPbt23nxxRfR6/Xs3LmTLl260LBhQ9566y369evH5s2bC5+v0+nYsmULOp0OPz8/Xn31VYYNG8aHH35YOKZWrVps3bqVHTt24O3tzeeff86iRYsqzCHUT6Jl9UqEhQTQxcuVfIPCB5tPMf77GFKzZEpJCCFM3YnrqfSYFcHWYwmYaTVM696Qb4bfuwiweMKdeL/55pu/XObp6cmePXse+Ro1atQgLCzsoWM6duzIkSNHniRaheVgbc6CoT4sjbzMf8JOs/1kEieuhzN7cAtaVK+kdjwhhBBPSFEUvo26wr+3nibPYKSqoxWhg1rgU0N+p/9e+T1FXwWi0WgY0b4WP05oR3Una66nZPPy/CgW7r0kU0pCCGFCUrPzmfD9Yd7bdJI8g5HOjVzZGuIv5eUBpMCUI82qObIlxJ/Apm4UGBX+HXaa0csOcTczT+1oQgghHiH2agpBoeFsO5mIuU7D9B5eLBzmg6O1TBk9iBSYcsbe0pw5g1vyUZ8m6M207DqTTGBoOIcu31E7mhBCiAdQFIVF4ZfoPy+Sa3ez8XSy4ofx7RjpX0vO8/UQUmDKIY1Gw9C2NVj/ejtqOduQkJrDK19HM3f3BYxGmVISQoiyIiUrjzHfHuJfW09TYFTo3sSNLZMC8PZ0VDtamScFphxr7OHA5kn+9PL2wGBU+GTbWUYsPcjtjAeft0cIIUTpiblyh8CZ4ew8nYxep+XD3o2ZO6QlDlbmakczCVJgyjlbCzNmDmzOx32bYmGmZc+5mwSGhhN96bba0YQQokIyGhXm77nIgAXR3EjNoWZla9a93o5hfjVlyugJSIGpADQaDQPbVGfjxPbUqWJDUlougxdGE7rrPAaZUhJCiFJzOyOXkcsO8vFPZzAYFXp6e7B5kj9NqsrFeZ+UFJgKpKGbPZsm+tO3ZVWMCnyx4xzDFu8nOT1H7WhCCFHu7b90m8DQcHafvYmFmZb/vNSU0IHNsbOUKaOnIQWmgrGxMOOLAc35tH8zrMx17Ltwm8CZEey7cEvtaEIIUS4ZjQqzfznPoIXRJKXlUruKDRuC2zPYt7pMGT0DKTAV1MutPNk0sT31XW25lZHLq9/s54sd52RKSQghitHN9FyGLznAZz+fw6hA3xZV2TzRn0bu9mpHM3lSYCqweq52bAz255VWnigKhO46z+CF0SSlyZSSEEI8q8gLtwgMDSf8/C0szbV80r8Znw/wxsbiia7iI/6CFJgKzkqv47/9m/HVK82x1uvYH3fvsL49526qHU0IIUySwajw5Y5zDPlmPzfTc6nnYsvmif4MaOUpU0bFSAqMAKBPi6psmXTvY83bmXkMX3yA/247Q4HBqHY0IYQwGUlpOQxZFM3MXedRFBjQqhqbJvpTz9VO7WjljhQYUah2FVvWv96OIb7VAZi3+yIDv47mRkq22tGEEKLM23vuJoEzw4m+dAdrvY4vX/Hmk/7eWOl1akcrl6TAiCIszXX8+6WmzB7cAlsLMw5duUtgaDi/nElSO5oQQpRJBQYjn24/w/AlB7idmUdDNzs2TfTnpRbV1I5WrkmBEQ/Uo5kHW0P8aVLVnpSsfEYuPcS/t54iX6aUhBCiUEJqNoMWRjPn14soCgz2rc6G4PbUdbFVO1q5JwVG/KUalW34cUI7XmtXE4CF4XG8PD+Kq3ey1I4mhBCq+/VMMoEzwzl4+S62FmaEDmrBf15qiqW5TBmVBikw4qEszHS836sx819tiZ2lGbFXUwgKDWf7yUS1owkhhCryDUZmhJ1mxNKD3M3Kp7GHPVt+u3CuKD1SYMRj6dbEnbCQe5d4T8spYNx3MXyw+SS5BQa1owkhRKm5djeLAQuiWLD3EgDD/Wrw44R21HS2UTtahSMFRjw2Tydr1o7zY7R/LQCW7LtM/3lRxN+WKSUhRPn388lEgkIjOBKfgp2lGfOGtOSD3k1kykglUmDEE9GbaXm3hxeLhrXCwcqc49dTCQoNJ+x4gtrRhBCiROQVGPlw8ynGfhdDanY+3tUcCAsJoHtTd7WjVWhSYMRT6ezlStjkAHxqVCI9t4DXlx/m3Q3HycmXKSUhRPlx9U4WL8+PZPG+OABG+ddi7fh2eDpZqx2twpMCI55aVUcrVo1ty/jn6gDwfXQ8fedGEncrU+1oQgjxzH46nkBgaDhHr6XiYGXOwmGt+GcPL/Rm8tZZFshWEM/EXKfl790bsnREa5xs9JxKSKNHaDgbY6+rHU0IIZ5KTr6B6RtPMGH5YdJzCmhZ3ZGtIf686OWqdjTxO1JgRLHo2MCFsJAA2tRyIjPPwORVsfz9x2MypSSEMClxtzLpNy+Sb6OuADDuudqsHudHtUoyZVTWSIERxcbNwZIVo32Z9EJdNBpYdfAqvWfv40JyutrRhBDikTYdvUHPWRGcvJFGJWtzlrzWmmndG2Guk7fKski2iihWZjotb3VpwHcjfXG21XM2KZ2es/bxY8w1taMJIcQD5eQbmLbuOCErj5CRW0DrmpUImxzA8w1d1I4mHkIKjCgR/vWcCQsJoF2dymTnG3hr7VH+tvYoWXkFakcTQohCF5Iz6DNnHysPxKPRwMTn67JyTFvcHazUjiYeQQqMKDEu9pZ8N8qXNzvXR6uBH2Ku0Wv2Ps4mypSSEEJ96w5fo9fsCM4kpuNsq+fbkW34W9cGmMmUkUmQrSRKlE6rYXLneiwf3RYXOwsuJGfQe04Eqw/GoyiK2vGEEBVQVl4Bb689ypQ1R8nKM+BXuzJhIQEE1KuidjTxBKTAiFLhV6cyYZMDCKjnTE6+kak/HufN1bFk5MqUkhCi9JxLSqf37H2sjbmGRgNvdK7H96N9cbG3VDuaeEJSYESpcba1YNmINrzdtQE6rYYNsTfoNSuCUzfS1I4mhCjnFEVhzaGr9JodwfnkDKrYWbB8tC9vdK6PTqtRO554ClJgRKnSajUEP1+XVWPb4mZvyaVbmfSZu4/vo6/IlJIQokRk5hYwZc1R3vnhGDn5RgIKDzJwVjuaeAZPVGDmzZtHs2bNsLe3x97eHj8/P3766afC5Tk5OQQHB1O5cmVsbW3p168fSUlJRV4jPj6eoKAgrK2tcXFx4e2336agoOg0wu7du2nZsiUWFhbUrVuXpUuXPut6ijKmdU0nwiYH8EJDF/IKjLy74QQTVx4hLSdf7WhCiHLkdEIaPWdFsP7IdbQaeLtrA5aNaEMVOwu1o4ln9EQFplq1anz88cfExMRw6NAhXnjhBXr37s3JkycBePPNN9m8eTNr165lz5493Lhxg759+xY+32AwEBQURF5eHpGRkSxbtoylS5cyffr0wjFxcXEEBQXx/PPPExsbyxtvvMHo0aPZvn17ca63KAOcbPQsGtaKfwQ2xEyrYeuxBHrOiuD4tVS1owkhTJyiKCzff4Xec/Zx6VYmbvaWrBrrR/DzddHKlFG5oFGe8XN7JycnPv30U/r370+VKlVYsWIF/fv3B+DMmTM0atSIqKgo2rZty08//USPHj24ceMGrq73rikxf/58pk6dys2bN9Hr9UydOpWtW7dy4sSJwu8xcOBAUlJS2LZt22PnSktLw8HBgdTUVOzt7Z9lFYsIWXmETUdvML2HFyP9axXb61Z0h+PvMmnFEa6nZKPXaflHYEOGt6uJRiO/aIQQTyY9J59p646z5VgCAB0bVOGLAc1xstGrHa3cGLwwmsiLtwkd1IJe3h7F+tqP+/791PvAGAwGVq1aRWZmJn5+fsTExJCfn0/nzp0LxzRs2JDq1asTFRUFQFRUFE2bNi0sLwBdu3YlLS2t8FOcqKioIq9xf8z91xDlU8vqlQovlpZnMPL+5lOM/z6G1CyZUhJCPL4T11PpOSuCLccS0Gk1TOvekMXDW0t5KYfMnvQJx48fx8/Pj5ycHGxtbVm/fj1eXl7Exsai1+txdHQsMt7V1ZXExEQAEhMTi5SX+8vvL3vYmLS0NLKzs7GyevDZEXNzc8nNzS28n5YmR7aYGkdrPV8P9WHJvsvM+Ok0208mcfJGOLMHt6S5p+NjvIIQoqJSFIVvo67w762nyTMYqepoReigFvjUqKR2NFFCnvgTmAYNGhAbG8v+/fuZMGECw4cP59SpUyWT7gnMmDEDBweHwpunp6fakcRT0Gg0jPSvxQ/j2+HpZMW1u9n0nxfJovBLcpSSEOKBUrPzeX35Yd7bdJI8g5HOjVzZGuIv5aWce+ICo9frqVu3Lj4+PsyYMQNvb29mzpyJm5sbeXl5pKSkFBmflJSEm5sbAG5ubn86Kun+/UeNsbe3/8tPXwCmTZtGampq4e3q1atPumqiDPH2dGRrSACBTd0oMCr8a+tpxnx7iJSsPLWjCSHKkKNXU+gxK5yfTiRirtPwzx5eLBzmg6O1TBmVd898Hhij0Uhubi4+Pj6Ym5uza9euwmVnz54lPj4ePz8/APz8/Dh+/DjJycmFY3bs2IG9vT1eXl6FY37/GvfH3H+Nv2JhYVF4ePf9mzBt9pbmzBncko96N0av07LzdDKBM8OJuXJH7WhCCJUpisI3EXH0nx/J1TvZVKtkxQ/j2zHKv5bs/F9BPNE+MNOmTaN79+5Ur16d9PR0VqxYwe7du9m+fTsODg6MGjWKKVOm4OTkhL29PZMmTcLPz4+2bdsC0KVLF7y8vBg6dCiffPIJiYmJvPvuuwQHB2Nhce+Y/PHjxzN79mzeeecdRo4cyS+//MKaNWvYunVryfwLiDJNo9Ew1K8mLapXYuKKw1y+ncWABdH8rUsDxnWoLYdDClEBpWTl8be1x9h5+t6n9d0au/Hf/s1wsDJXO5ooRU9UYJKTkxk2bBgJCQk4ODjQrFkztm/fzosvvgjAl19+iVarpV+/fuTm5tK1a1fmzp1b+HydTseWLVuYMGECfn5+2NjYMHz4cD788MPCMbVq1WLr1q28+eabzJw5k2rVqrFo0SK6du1anOstTEyTqg5sCQngH+uOs+noDf677Qz7427z+cveVLaVE1IJUVHEXLlLyMr/nXLh3R6NGNq2hnzqUgE983lgyio5D0z5pCgKqw5e5f1NJ8ktMOJqb0HowBb41q6sdjQhRAkyGhW+Dr/Ep9vPYjAq1KhszZzBLWlS1UHtaBWSSZ8HRgg1aDQaBrWpzobg9tSuYkNSWi6DFkYza9d5DMZy2cWFqPDuZOYxctlBPv7pDAajQo9m7myZ5C/lpYKTAiNMUiN3ezZP9Kdvi6oYFfh8xzmGLz7AzfTcx3i2EMJUHIi7Q+DMcHafvYneTMt/XmrKrEEtsLOU/V0qOikwwmTZWJjxxSvN+bR/MyzNtURcuEX3meFEXrildjQhxDMyGhVm/3KegV9HkZiWQ+0qNmwMbs9g3+qyv4sAKTCiPHi5lSebJ/pT39WWWxm5DPlmP1/sOCdTSkKYqJvpuQxfcoDPfj6HUYGXWlRl80R/GrnL6THE/0iBEeVCPVc7Ngb780orTxQFQnedZ8iiaJLSctSOJoR4ApEXbxEYGk74+VtYmmv5pH8zvhjgjY3FE1/5RpRzUmBEuWGl1/Hf/s346pXmWOt1RF+6N3e+99xNtaMJIR7BYFT4auc5Xl20n5vpudRzsWXTRH8GtPKUKSPxQFJgRLnTp0VVNk/yp6GbHbcz8xi2+ACfbDtDgcGodjQhxAMkp+Xw6qL9fLXzPEYFXvapxsaJ7anvaqd2NFGGSYER5VKdKrZsCG7PEN/qAMzdfZFBC6NJSM1WO5oQ4nfCz98kMDScqEu3sdbr+GKAN5++7I21XqaMxMNJgRHllqW5jn//dsilrYUZBy/fJXBmOL+cSXqMZwshSlKBwchn288ybPEBbmXk0dDNjk0T/enbspra0YSJkAIjyr2e3h6/nfTKnrtZ+Yxceoj/hJ0mX6aUhFBFQmo2gxfuZ/avF1AUCk9OWdfFVu1owoRIgREVQk1nG36c0I7X2tUE4Ou9lxiwIIprd7PUjiZEhfLrmXtXlT9w+Q42eh2hg1owo29TLM11akcTJkYKjKgwLMx0vN+rMfNfbYmdpRlH4lMInBnOzycT1Y4mRLmXbzAyI+w0I5Ye5G5WPo097NkSElDs19ERFYcUGFHhdGviTlhIAN7VHEjLKWDsdzF8sPkkeQUypSRESbieks0rC6JYsPcSAMP8avDjhHbUcrZRO5owYVJgRIXk6WTN2vHtGPXbFcWX7LtM//mRxN+WKSUhitOOU0kEzgzncHwKdpZmzBvSkg97N5EpI/HMpMCICktvpuWfPbxYOKwVDlbmHLuWSlBoOGHHE9SOJoTJyysw8tGWU4z59hCp2fl4V3Ng66QAujd1VzuaKCekwIgK70UvV8ImB9CyuiPpuQW8vvww/9xwgpx8g9rRhDBJV+9k8fL8SL6JiANgZPtarB3fjuqVrdWOJsoRKTBCAFUdrVg9zo9xz9UG4LvoK/SbF0ncrUy1owlhUradSCAwNJyj11KxtzTj66E+TO/phd5M3m5E8ZL/UUL8xlynZVr3RiwZ0RonGz0nb6TRIzScTUdvqB1NiDIvt8DAextPMP77w6TnFNCiuiNhkwPo0thN7WiinJICI8QfPN/AhbCQANrUdCIzz0DIyiNMW3dcppSE+AuXb2XSb14ky6KuADCuQ23WjPOjWiWZMhIlRwqMEA/g5mDJijG+THqhLhoNrDwQT585+7iQnKF2NCHKlM1Hb9BjVgQnrqdRydqcxa+1YlpgI8x18vYiSpb8DxPiL5jptLzVpQHfjmyDs62eM4np9JwVwY8x19SOJoTqcvIN/GP9cSatPEJGbgGta1YibHIALzR0VTuaqCCkwAjxCAH1qhAWEoBf7cpk5xt4a+1R/rb2KFl5BWpHE0IVF29m0GfOPlbsj0ejgeDn67ByTFvcHazUjiYqECkwQjwGF3tLvh/tyxud66HRwA8x1+g9ex/nktLVjiZEqVp/5Bo9Z0VwJjGdyjZ6lo1ow9tdG2ImU0ailMn/OCEek06r4Y3O9Vk+2pcqdhacT86g1+wI1hy8iqIoascTokRl5xl454ejvLn6KFl5BtrWduKnyQF0qF9F7WiigpICI8QTalfHmZ8mBxBQz5mcfCPv/HiMN1fHkpkrU0qifDqflH6vrB+6hkYDkzvVY/notrjYW6odTVRgUmCEeArOtha/fXTeAK0GNsTeoOesCE7dSFM7mhDFRlEU1hy6Ss/ZEZxPzqCKnQXLR/ny5ov10Wk1ascTFZwUGCGeklarIfj5uqwa64ebvSWXbmXSZ+4+lu+/IlNKwuRl5hbw1pqjvPPDMXLyjfjXdSYsJIB2dZ3VjiYESIER4tm1qeVE2OQAnm9QhbwCI/+3/gSTVh4hPSdf7WhCPJXTCWn0mh3BuiPX0Wrgb13q8+3INlSxs1A7mhCFpMAIUQycbPR8M7w107o3xEyrYcuxhN9O7pWqdjQhHpuiKKzYf++kjRdvZuJqb8HKMW2Z+EI9tDJlJMoYKTBCFBOtVsO45+qwepwfVR2tuHI7i75zI1kWeVmmlESZl56TT8iqWP6x/ji5BUY6Nrh3/iPf2pXVjibEA0mBEaKY+dSoxNYQfzo3ciXPYOS9TSeZ8P1hUrNlSkmUTSeup9JzVgSbj95Ap9Xw9+4NWTy8NZVtZcpIlF1SYIQoAY7WehYO8+GfPbww12nYdjKRoNBwYq+mqB1NiEKKovBt1GX6zo3k8u0sPBwsWTOuLeOfqyNTRqLMkwIjRAnRaDSM8q/FD+Pb4elkxbW72bw8P5JF4ZdkSkmoLjU7n+AVh5m+8SR5BiOdG7kQNjkAnxpOakcT4rFIgRGihHl7OrJlUgDdm7iRb1D419bTjPn2EClZeWpHExXU0asp9JgVTtjxRMx1Gt4NasTCYa1wtNarHU2Ix/ZEBWbGjBm0bt0aOzs7XFxc6NOnD2fPni0ypmPHjmg0miK38ePHFxkTHx9PUFAQ1tbWuLi48Pbbb1NQUPQsprt376Zly5ZYWFhQt25dli5d+izrKYSqHKzMmTukJR/2boxep2Xn6WQCZ4YTc+WO2tFEBaIoCt9ExNF/fiRX72RTrZIVa8e3Y3RAbTQamTISpuWJCsyePXsIDg4mOjqaHTt2kJ+fT5cuXcjMzCwybsyYMSQkJBTePvnkk8JlBoOBoKAg8vLyiIyMZNmyZSxdupTp06cXjomLiyMoKIjnn3+e2NhY3njjDUaPHs327duLY52FUIVGo2GYX03Wvd6OmpWtuZGaw4AF0czfcxGjUaaURMlKycpj7HcxfLTlFPkGhW6N3dgaEkBzT0e1ownxVMyeZPC2bduK3F+6dCkuLi7ExMTQoUOHwsetra1xc3N74Gv8/PPPnDp1ip07d+Lq6krz5s356KOPmDp1Ku+//z56vZ758+dTq1YtPv/8cwAaNWpEREQEX375JV27dn26NRWijGhS1YHNk/z5x/oTbD56g49/OkP0pdt8/rK3HPUhSsTh+LtMWnGE6ynZ6HVa/i+oEcP8asinLsKkPdM+MKmp907S5eRUdKev5cuX4+zsTJMmTZg2bRpZWVmFy6KiomjatCmurq6Fj3Xt2pW0tDROnjxZOKZz585FXrNr165ERUX9ZZbc3FzS0tKK3IQoq+wszQkd2Jz/vNQUCzMtu8/eJDA0nANxMqUkio/RqLBgz0UGzI/ieko2NSpb8+OEdgxvV1PKizB5T/QJzO8ZjUbeeOMN2rdvT5MmTQofHzx4MDVq1MDDw4Njx44xdepUzp49y7p16wBITEwsUl6AwvuJiYkPHZOWlkZ2djZWVlZ/yjNjxgw++OCDp10dIUqdRqNhsG91WlR3JHjFYS7dzGTg11FMebE+r3esK4eximdyJzOPv609yi9nkgHo0cydGX2bYmdprnY0IYrFUxeY4OBgTpw4QURERJHHx44dW/h106ZNcXd3p1OnTly8eJE6deo8W9qHmDZtGlOmTCm8n5aWhqenZ4l9PyGKSyN3ezZP9OefG06w7sh1Pvv5HPvj7vDFgOZy7RnxVA5evsOkFUdITMtBb6blvZ5eDG5TXT51EeXKU00hTZw4kS1btvDrr79SrVq1h4719fUF4MKFCwC4ubmRlJRUZMz9+/f3m/mrMfb29g/89AXAwsICe3v7IjchTIWNhRmfD/Dmk/7NsDTXEn7+FoGh4UReuKV2NGFCjEaFOb9eYODX0SSm5VDb2YYNr7dniK/s7yLKnycqMIqiMHHiRNavX88vv/xCrVq1Hvmc2NhYANzd3QHw8/Pj+PHjJCcnF47ZsWMH9vb2eHl5FY7ZtWtXkdfZsWMHfn5+TxJXCJOi0WgY0MqTTRP9qediy830XIZ8s58vd5zDIEcpiUe4lZHL8CUH+HT7WQxGhZdaVGXzJH+8POSPOVE+PVGBCQ4O5vvvv2fFihXY2dmRmJhIYmIi2dnZAFy8eJGPPvqImJgYLl++zKZNmxg2bBgdOnSgWbNmAHTp0gUvLy+GDh3K0aNH2b59O++++y7BwcFYWNz7uHz8+PFcunSJd955hzNnzjB37lzWrFnDm2++WRL/BkKUKfVd7dg00Z8BraqhKDBz13mGLIomOS1H7WiijIq6eJvAmeGEn7+FpbmWT/o144sB3thYPPVeAkKUeU9UYObNm0dqaiodO3bE3d298LZ69WoA9Ho9O3fupEuXLjRs2JC33nqLfv36sXnz5sLX0Ol0bNmyBZ1Oh5+fH6+++irDhg3jww8/LBxTq1Yttm7dyo4dO/D29ubzzz9n0aJFcgi1qDCs9Do+6e/Nl694Y63XEX3pDt1nhrP33E21o4kyxGBU+GrnuXsFNz2Xui6298pva0+ZMhLl3hPV80ddv8XT05M9e/Y88nVq1KhBWFjYQ8d07NiRI0eOPEk8Icqdl1pUo2lVRyauOMyZxHSGLznA6x3r8Gbn+pjp5EogFVlyeg5vrIol8uJtAF72qcYHvRtjrZdPXUTFIL8BhSjj6rrYsiG4PYN9q6MoMOfXiwxeuJ+E1Gy1owmVRJy/ReDMcCIv3sbKXMcXA7z59GVvKS+iQpECI4QJsDTX8Z+XmhI6qAW2FmYcuHyHwJnh/Hom+TGeLcqLAoORz7afZeji/dzKyKOhmx2bJ/nTt+XDjwYVojySAiOECenl7cGWSf409rDnblY+I5YeZEbYafINRrWjiRKWmJrD4EX7mf3rBRQFBrXxZENwe+q62KodTQhVSIERwsTUdLa5dzp4vxoALNh7iVcW3DtVvCifdp9NLrzUhI1ex8yBzZnRtxmW5jq1owmhGikwQpggS3MdH/RuwrwhLbGzNONwfAqBM8PZcSrpMZ4tTEW+wcjHP53htSUHuZOZh5e7PVtCAujdvKra0YRQnRQYIUxY96bubJ0UgHc1B1Kz8xnz7SE+3HyKvAKZUjJ111OyGfh1NPP3XARgmF8N1r3ejlrONmpHE6JMkAIjhImrXtmatePbMbL9vTNjL94Xx8vzI7l6J+uRzxVl085TSQTODCfmyl3sLMyYO6QlH/ZuIlNGQvyOFBghygG9mZbpPb1YOKwVDlbmHL2WSmBoOD8dT1A7mngCeQVG/rXlFKO/PURqdj7NqjmwNSSAwKbuakcTosyRAiNEOfKilytbQ/xpWd2R9JwCJiw/zPSNJ8jJN6gdTTzC1TtZvLwgikURcQCMbF+LteP9qF7ZWu1oQpRJUmCEKGeqVbJm9Tg/xj1XG4Bvo67Qb14kl29lqh1N/IVtJxIIDA3n6NUU7C3N+HqoD9N7emFhJlNGQvwVKTBClEPmOi3TujdiyWutqWRtzskbafSYFcGmozfUjiZ+J7fAwHsbTzD++8Ok5xTQorojYZMD6NLYTe1oQpR5UmCEKMeeb+hC2OQAWtesREZuASErjzBt3XGZUioDLt/KpN+8SJZFXQFgbIfarBnnR7VKMmUkxOOQAiNEOefuYMXKMW2Z+HxdNBpYeSCePnP2cfFmhtrRKqwtx27QY1YEJ66nUcnanMWvteIfgY0wlwt0CvHY5KdFiArATKflb10b8O3INlS20XMmMZ2esyJYf+Sa2tEqlJx8A/+3/jgTVxwhI7eA1jUrETY5gBcauqodTQiTIwVGiAokoF4VfpocgF/tymTlGXhz9VHeXnuUrLwCtaOVexdvZtBnzj6W748H4PWOdVg5pi3uDlZqRxPCJEmBEaKCcbG35PvRvkzuVA+NBtbGXKP37H2cS0pXO1q5teHIdXrOiuBMYjqVbfQsG9mGd7o1xEymjIR4avLTI0QFpNNqePPF+iwf5UsVOwvOJ2fQa3YEaw5dRVEUteOVG9l5Bqb+cIw3VseSlWegbW0nwiYH8Fz9KmpHE8LkSYERogJrV9eZsJAAAuo5k5Nv5J0fjjFlzVEyc2VK6VmdT0qn95wIVh+6ikYDIZ3qsXx0W1ztLdWOJkS5IAVGiAquip0Fy0a04e2uDdBqYP2R6/ScHcHphDS1o5mstYeu0mv2Ps4lZeBsa8HyUb5MebE+Oq1G7WhClBtSYIQQaLUagp+vy6qxfrjZW3LpZia95+xjxf54mVJ6Apm5BUxZE8vbPxwjO9+Af11nfpocQLu6zmpHE6LckQIjhCjUpta9fTQ6NqhCXoGRf6w/TsiqWNJz8tWOVuadSUyj1+wI1h2+jlYDb71Yn2Uj21DFzkLtaEKUS1JghBBFONnoWTy8NdO6N0Sn1bD56A16zorgxPVUtaOVSYqisPJAPL1n7+PizUxc7S1YMaYtkzrVkykjIUqQFBghxJ9otRrGPVeHNeP88HCw5PLtLPrOjeTbqMsypfQ7GbkFTF4Vy7R1x8ktMPJc/SqEhQTQtnZltaMJUe5JgRFC/CWfGvfOFNu5kSt5BiPTN57k9eWHSc2WKaUT11PpERrOpqM30Gk1TO3WkCWvtaayrUwZCVEapMAIIR7K0VrPwmE+vBvUCHOdhp9OJNJjVjhHr6aoHU0ViqLwXdRl+s6L5PLtLDwcLFkzri0TOtZBK1NGQpQaKTBCiEfSaDSMDqjN2vHtqFbJiqt3suk/P5JvIuIq1JRSWk4+wSsO88+NJ8krMNK5kQtbQwLwqeGkdjQhKhwpMEKIx9bc05GtIQF0a+xGvkHhoy2nGPNtDClZeWpHK3HHrqXQIzSCsOOJmGk1vBvUiIXDWlHJRq92NCEqJCkwQogn4mBlzrxXW/Jh78bodVp2nk4iKDSCmCt31Y5WIhRFYXFEHP3mRRJ/J4uqjlasHe/H6IDaaDQyZSSEWqTACCGemEajYZhfTda93o4ala25npLNKwuiWLDnIkZj+ZlSSs3KZ9x3MXy45RT5BoWujV0JCwmgRfVKakcTosKTAiOEeGpNqjqwZZI/PZq5U2BUmPHTGUYtO8idTNOfUjocf5fA0HB+PpWEXqfl/Z5ezH/VBwdrc7WjCSGkwAghnpWdpTmzBrXgPy81RW+m5dezNwmcGc6BuDtqR3sqRqPC13svMmB+FNdTsqnuZM2PE9rxWvtaMmUkRBkiBUYI8cw0Gg2DfauzMbg9tZ1tSEzLYdDCaOb8esGkppTuZuYx+ttD/CfsDAVGhaBm7mwJ8adpNQe1owkh/kAKjBCi2DRyt2fzJH9ealEVg1Hh0+1nGb7kALcyctWO9kgHL98hMDScX84kozfT8q8+TZg9qAX2ljJlJERZJAVGCFGsbCzM+GKAN5/0a4aluZbw87foPjOcyIu31I72QEajwpxfLzDw62gSUnOo7WzDhtfb82rbGjJlJEQZ9kQFZsaMGbRu3Ro7OztcXFzo06cPZ8+eLTImJyeH4OBgKleujK2tLf369SMpKanImPj4eIKCgrC2tsbFxYW3336bgoKCImN2795Ny5YtsbCwoG7duixduvRZ1lMIUYo0Gg0DWnuyaaI/9VxsuZmey6uL9vPVznMYytCU0q2MXF5bepBPt5/FYFTo09yDTZP88fKwVzuaEOIRnqjA7Nmzh+DgYKKjo9mxYwf5+fl06dKFzMzMwjFvvvkmmzdvZu3atezZs4cbN27Qt2/fwuUGg4GgoCDy8vKIjIxk2bJlLF26lOnTpxeOiYuLIygoiOeff57Y2FjeeOMNRo8ezfbt24trvYUQpaC+qx0bJ7bnZZ9qGBX4aud5hn6zn+S0HLWjEX3pNoEzw9l77iaW5lr+268pX77SHFsLM7WjCSEeg0Z5hvOA37x5ExcXF/bs2UOHDh1ITU2lSpUqrFixgv79+wNw5swZGjVqRFRUFG3btuWnn36iR48e3LhxA1dXVwDmz5/P1KlTuXnzJnq9nqlTp7J161ZOnDhR+L0GDhxISkoK27Zte6xsaWlpODg4kJqair198f01FbLyCJuO3mB6Dy9G+tcqttcVorxbd/ga7244QVaeAWdbPV++0pyAelVKPYfBqDD7lwvM3HUOowJ1XWyZM7glDdzsSj2LEKZq8MJoIi/eJnRQC3p5exTraz/u+/cz7QOTmpoKgJPTveuAxMTEkJ+fT+fOnQvHNGzYkOrVqxMVFQVAVFQUTZs2LSwvAF27diUtLY2TJ08Wjvn9a9wfc/81HiQ3N5e0tLQiNyFE2dG3ZTU2TfSnoZsdtzLyGLb4AJ9tP0uBwVhqGZLTcxj6zX6+3HmvvPT3qcamie2lvAhhgp66wBiNRt544w3at29PkyZNAEhMTESv1+Po6FhkrKurK4mJiYVjfl9e7i+/v+xhY9LS0sjOzn5gnhkzZuDg4FB48/T0fNpVE0KUkLoutmwIbs+gNtVRFJj96wUGL9xPQuqDf66LU8T5WwTOjCDy4m2szHV8/rI3n73sjbVepoyEMEVPXWCCg4M5ceIEq1atKt5ET2natGmkpqYW3q5evap2JCHEA1ia65jRtymhg1pgo9dx4PIdAmeG8+vZ5BL5fgUGI5//fJahi/dzKyOXBq52bJ7Unn4+1Urk+wkhSsdTFZiJEyeyZcsWfv31V6pV+98vATc3N/Ly8khJSSkyPikpCTc3t8Ixfzwq6f79R42xt7fHysrqgZksLCywt7cvchNClF29vD3YEhJAYw977mblM2LJQWb8dJr8YpxSSkzNYfCi/cz65QKKAoPaeLJxYnvqusiUkRCm7okKjKIoTJw4kfXr1/PLL79Qq1bRnVh9fHwwNzdn165dhY+dPXuW+Ph4/Pz8APDz8+P48eMkJ//vr60dO3Zgb2+Pl5dX4Zjfv8b9MfdfQwhRPtRytuHHCe0Y5lcDgAV7LvHKgnun8H9Wu88mExh675IGNnodMwc2Z0bfZlia64ohuRBCbU9UYIKDg/n+++9ZsWIFdnZ2JCYmkpiYWLhfioODA6NGjWLKlCn8+uuvxMTEMGLECPz8/Gjbti0AXbp0wcvLi6FDh3L06FG2b9/Ou+++S3BwMBYWFgCMHz+eS5cu8c4773DmzBnmzp3LmjVrePPNN0vi30AIoSJLcx0f9m7C3CEtsbMw43B8CoEzw9lxKukxnv1n+QYj/912hteW3LuopNdvZwfu3bxqsWcXQqjniQrMvHnzSE1NpWPHjri7uxfeVq9eXTjmyy+/pEePHvTr148OHTrg5ubGunXrCpfrdDq2bNmCTqfDz8+PV199lWHDhvHhhx8WjqlVqxZbt25lx44deHt78/nnn7No0SK6du1aXOsthChjApu6szUkgGbVHEjNzmfMt4f4aMsp8goef0rpRko2A7+OZt7uiwAMbVuDda+3o3YV2xJMLoRQwxPtfv84p4yxtLRkzpw5zJkz5y/H1KhRg7CwsIe+TseOHTly5MiTxBNCmLjqla35YXw7Pv7pDIv3xfFNRByHrtxl9qAWeDpZP/S5u04n8dbao6Rk5WNnYcbH/ZoR1My91LILIUqXXAtJCFGm6M20TO/pxddDfbC3NOPo1RQCQ8PZdiLhgePzCoz8a8spRi07REpWPk2rOrAlxF/KixDlnBQYIUSZ1KWxG2GTA2hR3ZH0nALGf3+Y9zaeILfAUDjm6p0sBiyIYlFEHAAj2tfkhwl+1Khso2JyIURpkAIjhCizqlWyZs04P8Z1qA3Asqgr9JsXyeVbmWw7kUhQaDixV1OwtzRjwVAf3uvZGAszOcpIiIpATkEphCjTzHVapgU2wre2E2+tOcqJ62l0/Gx34fLmno7Meox9ZIQQ5Yt8AiOEMAkvNHRl3qs+f3r8u1FtpLwIUQFJgRFCmIStxxIYs+zQnx5/eX4UF29mqJJJCKEeKTBCiDItJ9/AuxuOE7ziMOm5BbSqUYnIv7/AtyPbUNlGz5nEdHrOimD9kWtqRxVClCIpMEKIMuvSzQxemhvJ99HxALzesQ6rxrbFw9GKDvWrEDY5gLa1ncjKM/Dm6qO888NRsvMMj3xdIYTpkwIjhCiTNsZep+esCE4npFHZRs+ykW14p1tDzHT/+7Xlam/J8tFtmdypHhoNrDl0jd5zIjiflK5qdiFEyZMCI4QoU7LzDPz9x2NMXhVLZp4B31pOhE0O4Ln6VR44XqfV8OaL9Vk+ypcqdhacS8qg5+wI1h66WurZhRClRwqMEKLMuJCcTp85+1h18CoaDYR0qsfy0b642ls+8rnt6joTFhKAf11ncvKNvP3DMaasiSUzt6BUsgshSpcUGCFEmfBDzDV6ztrH2aR0nG0t+H6UL1NerF9kyuhRqthZ8O3INvytS320Glh3+Dq9Zt+bhhJClC9SYIQQqsrKK+CtNUf529qjZOcbaF+3MmGT/Wlf1/mpXk+r1TDxhXqsHNMWV3sLLt7MpM+cfazYH/9YF6QVQpgGKTBCCNWcSUyj56wIfjx8Da0G3nqxPt+O9MXF7tFTRo/iW7syYSH39p3JLTDyj/XHCVkVS3pOfrFkF0KoSwqMEKLUKYrCqgPx9J69j4s3M3G1t2DFmLZM6lQPnVZTbN+nsq0FS15rzd+7N0Sn1bD56A16zorgxPXUYvseQgh1SIERQpSqjNwC3lgdy9/XHSe3wMhz9asQFhJA29qVS+T7abUaxj9XhzXj2uLhYMnl21n0nRvJd1GXZUpJCBMmBUYIUWpO3kil56wINsbeQKfVMLVbQ5a81prKthYl/r19ajixNSSAzo1cyDMY+efGkwSvOEyaTCkJYZKkwAghSpyiKHwXfYWX5kYSdysTdwdLVo9ty4SOddAW45TRo1Sy0bNwWCveDWqEmVZD2PFEgkLDOXo1pdQyCCGKhxQYIUSJSsvJZ+KKI/xzwwnyCox0auhCWEgArWo6qZJHo9EwOqA2P0xoR7VKVly9k03/+ZEsjoiTKSUhTIgUGCFEiTl2LYUeoRFsPZ6AmVbDu0GNWDS8FZVs9GpHo7mnI1tDAujW2I18g8KHW04x9rsYUrLy1I4mhHgMUmCEEMVOURSW7Iuj37xI4u9kUdXRirXj/RgdUBuNpvSmjB7Fwcqcea+25INejdHrtOw4lURQaASH4++qHU0I8QhSYIQQxSo1K5/x38fwweZT5BsUuni5EhYSQIvqldSO9kAajYbh7Wry44R21KhszfWUbAbMj+LrvRcxGmVKSYiySgqMEKLYHIm/S2BoONtPJqHXaXm/pxcLhvrgYG2udrRHalrNgS2T/Alq5k6BUeE/YWcY/e0h7mTKlJIQZZEUGCHEM1MUhYV7L/Hy/Ciup2RT3cmaHye047X2tcrUlNGj2FmaM3tQC/79UhP0Zlp+OZNM4MxwDl6+o3Y0IcQfSIERQjyTu5l5jF52iH+HnabAqBDU1J0tIf40reagdrSnotFoGOJbgw2vt6e2sw2JaTkM/DqaOb9ekCklIcoQKTBCiKd26PIdAkPD2XUmGb2Zln/1acLswS2wtyz7U0aP4uVhz6ZJ/vRp7oHBqPDp9rMMX3KAWxm5akcTQkiBEUI8DaNRYe7uC7zydTQJqTnUcrZh/evteLVtDZOaMnoUWwszvnylOZ/0a4aluZbw87cInBlO1MXbakcTosKTAiOEeCK3M3IZsfQgn2w7i8Go0Lu5B5sn+dPYwzSnjB5Fo9EwoLUnG4P9qetiS3J6LkMWRTNz53kMMqUkhGqkwAghHlv0pdsEhoaz59xNLMy0/LdfU756pTm2FmZqRytxDdzs2DSxPS/7VMOowJc7zzH0m/0kp+eoHU2ICkkKjBDikQxGhdBd5xm8MJqktFzqVLFh00R/XmldvVxNGT2Ktd6MT1/25osB3liZ64i8eJvAmeFEnL+ldjQhKhwpMEKIh0pOz2HY4v18seMcRgX6tazG5kn+NHCzUzuaavr+9m/Q0M2OWxl5DF28n89/PkuBwah2NCEqDCkwQoi/tO/CLQJnRrDvwm2szHV89rI3nw/wxlpf/qeMHqWuiy0bgtszqI0nigKzfrnA4EX7SUyVKSUhSoMUGCHEnxiMCl/sOMer3+znVkYuDVzt2DypPf19qqkdrUyxNNcxo28zZg5sjo1ex4G4e4eV7z6brHY0Ico9KTBCiCKS0nIYvDCa0F3nURQY2NqTDcHtqetScaeMHqV386psCQnAy92eO5l5vLbkIB//dIZ8mVISosQ8cYHZu3cvPXv2xMPDA41Gw4YNG4osf+2119BoNEVu3bp1KzLmzp07DBkyBHt7exwdHRk1ahQZGRlFxhw7doyAgAAsLS3x9PTkk08+edp1FEI8pj3nbtJ9Zjj74+5go9cxc2BzPu7XDCu9Tu1oZV4tZxvWvd6OoW1rADB/z0UGfh3N9ZRstaMJUS49cYHJzMzE29ubOXPm/OWYbt26kZCQUHhbuXJlkeVDhgzh5MmT7Nixgy1btrB3717Gjh1buDwtLY0uXbpQo0YNYmJi+PTTT3n//ff5+uuvnzSuEOIxFBiM/HfbGYYvPsCdzDwauduzeZI/vZtXVTuaSbE01/FRnybMHdISOwszYq7cJSg0nJ2nktSOJkS588R74nXv3p3u3bs/dIyFhQVubm4PXHb69Gm2bdvGwYMHadWqFQCzZs0iMDCQzz77DA8PD5YvX05eXh6LFy9Gr9fTuHFjYmNj+eKLL4oUHSHEs7uRkk3IyiMcunIXgFfbVufdIC8szeVTl6cV2NSdJh4OTFx5mGPXUhn97SFG+9finW4N0ZvJzL0QxaFEfpJ2796Ni4sLDRo0YMKECdy+/b/TbkdFReHo6FhYXgA6d+6MVqtl//79hWM6dOiAXq8vHNO1a1fOnj3L3bt3H/g9c3NzSUtLK3ITQjzcL2eSCAwN59CVu9hZmDF7cAv+1aeplJdiUL2yNWvH+zGyfS0AFkXE8fKCKK7eyVI7mhDlQrEXmG7duvHtt9+ya9cu/vvf/7Jnzx66d++OwWAAIDExERcXlyLPMTMzw8nJicTExMIxrq6uRcbcv39/zB/NmDEDBweHwpunp2dxr5oQ5Ua+wci/t55i5NJDpGTl07SqA1tC/OnRzEPtaOWKhZmO6T29+HqoD/aWZhy9mkJgaDjbTjz495gQ4vEV+8kcBg4cWPh106ZNadasGXXq1GH37t106tSpuL9doWnTpjFlypTC+2lpaVJihHiAq3eymLTyCLFXUwB4rV1NpgU2xMJMPnUpKV0auxHmYc+klUc4Ep/C+O9j5N9diGdU4pOxtWvXxtnZmQsXLgDg5uZGcnLRcyQUFBRw586dwv1m3NzcSEoqutPb/ft/tW+NhYUF9vb2RW5CiKK2n0wkKDSc2Ksp2FuasWCoD+/3aixvoqWgWiVr1ozzY2yH2gAsjbxM/3lRXLmdqXY0IUxSiReYa9eucfv2bdzd3QHw8/MjJSWFmJiYwjG//PILRqMRX1/fwjF79+4lPz+/cMyOHTto0KABlSpVKunIQpQ7uQUGPth8knHfxZCWU0BzT0e2hgTQtfGD/yAQJcNcp+UfgY1Y/ForKlmbc/x6KkGhEWw5dkPtaEKYnCcuMBkZGcTGxhIbGwtAXFwcsbGxxMfHk5GRwdtvv010dDSXL19m165d9O7dm7p169K1a1cAGjVqRLdu3RgzZgwHDhxg3759TJw4kYEDB+LhcW/+ffDgwej1ekaNGsXJkydZvXo1M2fOLDJFJIR4PPG3s+g/L4ol+y4DMCagFmvG+eHpZK12tArrhYauhE0OoFWNSmTkFjBxxRH+b/1xcvINakcTwmQ8cYE5dOgQLVq0oEWLFgBMmTKFFi1aMH36dHQ6HceOHaNXr17Ur1+fUaNG4ePjQ3h4OBYWFoWvsXz5cho2bEinTp0IDAzE39+/yDleHBwc+Pnnn4mLi8PHx4e33nqL6dOnyyHUQjyhsOMJBIWGc/x6Ko7W5nwzvBX/F+Qlh/KWAe4OVqwa25bXO9YBYPn+ePrM2cfFmxmPfK4Q4il24u3YsSOKovzl8u3btz/yNZycnFixYsVDxzRr1ozw8PAnjSeEAHLyDfxr6ym+j44HoFWNSoQOaoGHo5Xa0cTvmOm0vNOtIb61KzNldSxnEtPpOSuC/7zUlD4t5CSCQjyM/BkmRDkTdyuTvnMjC8vLhI51WDm2rZSXMuy5+lUImxxA29pOZOUZeGN1LFN/OEZ2nkwpCfFXpMAIUY5sjL1Oj9BwTiWk4WSjZ+mI1kzt1hBznfyol3Wu9pYsH92WkE710Ghg9aGr9J4TwfmkdLWjCVEmyW81IcqBnHwDf//xGJNXxZKZZ6BNLSfCQgLo2MDlMZ4tygqdVsOUF+vz/ShfnG0tOJeUQa/Z+1h76Kra0YQoc6TACGHiLiSn03v2PlYdvIpGAyEv1GXFaF/cHCzVjiaeUvu6zvw0OQD/us5k5xt4+4djTFkTS2ZugdrRhCgzpMAIYcJ+jLlGz1n7OJuUjrOtBd+N9GVKlwaYyZSRyatiZ8GykW1468X6aDWw7vB1es2O4EyiXOdNCKTACGGasvIK+Nvao7y19ijZ+Qba161M2GR//Os5qx1NFCOdVsOkTvVYMaYtrvYWXLyZee/TtgPxDz0aVIiKQAqMECbmbGI6vWbv44eYa2g1MOXF+nw70hcXO5kyKq/a1q5MWEgAz9WvQm6Bkb+vO87kVbFkyJSSqMCkwAhhIhRFYfXBeHrPieBCcgYudhasGHPvqBWdVqN2PFHCKttasOS1e0eV6bQaNh29QY/QcE5cT1U7mhCqkAIjhAnIyC3gzdWxTP3xODn5RjoUnjekstrRRCnSajVM6FiH1WPb4u5gyeXbWfSdF8l3UZdlSklUOFJghCjjTt1Io9esCDbE3kCn1fBOtwYsfa01zrYWj/FsUR61qnnvMPlODV3IKzDyz40nCV5xmLSc/Md4thDlgxQYIcooRVH4PvoKfebu49KtTNwdLH+7dk5dtDJlVOFVstGzaHgr3g1qhJlWQ9jxRHqERnDsWora0YQoFVJghCiD0nLymbjyCO9uOEFegZEXGroQFhJA65pOakcTZYhGo2F0QG3WjvejqqMV8Xey6DcvksURcTKlJMo9KTBClDHHr6XSc1YEW48lYKbV8H+BjVg0rBWVbPRqRxNlVIvqlQgLCaBrY1fyDQofbjnFuO9iSM2SKSVRfkmBEaKMUBSFpfvi6Dcvkiu3s6jqaMWa8X6M6VBbpozEIzlYmzP/VR/e7+mFXqfl51NJBIaGcyT+rtrRhCgRUmCEKANSs/IZ/30M728+RZ7BSBcvV8JCAmhZvZLa0YQJ0Wg0vNa+Fj9OaEd1J2uup2Tz8vwoFu69hNEoU0qifJECI4TKYq+mEDQrnO0nkzDXaXivpxcLhvrgYG2udjRhoppWc2BLiD9BzdwpMCr8O+w0o789xN3MPLWjCVFspMAIoRJFUVgUfon+8yK5djeb6k7W/DihHSPa10KjkSkj8WzsLc2ZPagF/+rTBL2Zll/OJBMYGs6hy3fUjiZEsZACI4QKUrLyGPPtIf619TQFRoXApm5sCfGnWTVHtaOJckSj0fBq2xqsf70dtZxtSEjN4ZWvo5nz6wWZUhImTwqMEKUs5sodAmeGs/N0MnozLR/1acKcwS2xt5QpI1EyGns4sHmSP72be2AwKny6/SyvLT3IrYxctaMJ8dSkwAhRSoxGhXm7LzJgQTQ3UnOo5WzD+tfbMbRtDZkyEiXO1sKMr15pzn/7NcXCTMveczcJnBlO9KXbakcT4qlIgRGiFNzOyGXE0oP8d9sZDEaFXt4ebJ7kT2MPB7WjiQpEo9HwSuvqbJroT10XW5LTcxm8MJqZO89jkCklYWKkwAhRwvZfuk1gaDh7zt3EwkzLx32bMnNgc2wtzNSOJiqoBm52bJrYnv4+1TAq8OXOcwxbvJ/k9By1ownx2KTACFFCDEaFWbvOM2hhNElpudSpYsPGie0Z2Ka6TBkJ1VnrzfjsZW8+f9kbK3Md+y7cJnBmBPsu3FI7mhCPRQqMECXgZnouwxcf4PMd5zAq0K9lNTZP8qehm73a0YQoop9PNTZPak8DVztuZeTy6jf7+eLnsxQYjGpHE+KhpMAIUcwiL9yi+8xwIi7cwspcd++v3AHeWOtlykiUTXVd7Ng4sT2D2niiKBD6ywUGL9pPUppMKYmySwqMEMXEYFT4Ysc5hnyzn1sZudR3tS3cz0CIss7SXMeMvs2YObA5NnodB+Lu0H1mOLvPJqsdTYgHkgIjRDFISsthyKJoQnedR1FgYGtPNgb7U8/VTu1oQjyR3s2rsnmSP43c7bmTmcdrS+4dPSdTSqKskQIjxDP63/k07mCj1zFzYHM+7tcMK71O7WhCPJXaVWwLz1EEMG/3RQZ+Hc2NlGy1owlRSAqMEE+pwGDkk21nGLb4ALcz82jkbv/b2U6rqh1NiGdmaa4rPEu0nYUZh67cJTA0nF2nk9SOJgRIgRHi6SSkZjNoYTRzd18EYIhvdda/3o7aVWzVjiZEsQpq5s6WEH+aVnUgJSufUcsO8a8tp8grkCkloS4pMEI8oV/OJBE4M5yDl+9ia2HG7MEt+PdLTbE0lykjUT7VqGzDDxP8GNG+JgCLIuIYsCCKq3ey1I4mKjApMEI8pnyDkf+EnWbk0kPczcqnaVUHtob406OZh9rRhChxFmY63uvZmAVDfbC3NCP2agpBoeFsP5modjRRQUmBEeIxXLubxYAFUXy99xIAr7WryQ8T/KhR2UbtaEKUqq6N3dgaEkBzT0fScgoY910M7286SW6BQe1oooKRAiPEI/x8MpHAmeEciU/B3tKM+a/68H6vxliYyZSRqJg8naxZM86PMQG1AFgaeZn+86K4cjtT7WiiAnniArN371569uyJh4cHGo2GDRs2FFmuKArTp0/H3d0dKysrOnfuzPnz54uMuXPnDkOGDMHe3h5HR0dGjRpFRkZGkTHHjh0jICAAS0tLPD09+eSTT552HYV4KnkFRj7YfJKx38WQllOAt6cjW0MC6NbETe1oQqhOb6bl/4K8+GZ4KxytzTl+PZUeoRFsPZagdjRRQTxxgcnMzMTb25s5c+Y8cPknn3xCaGgo8+fPZ//+/djY2NC1a1dycv53SuohQ4Zw8uRJduzYwZYtW9i7dy9jx44tXJ6WlkaXLl2oUaMGMTExfPrpp7z//vt8/fXXT7ueQjyR+NtZ9J8fyZJ9lwEYE1CLteP88HSyVjuaEGVKp0auhIUE0KpGJdJzCwhecZh3NxwnJ1+mlETJeuKLs3Tv3p3u3bs/cJmiKHz11Ve8++679O7dG4Bvv/0WV1dXNmzYwMCBAzl9+jTbtm3j4MGDtGrVCoBZs2YRGBjIZ599hoeHB8uXLycvL4/Fixej1+tp3LgxsbGxfPHFF0WKjhAlIex4AlN/OEZ6bgGO1uZ81t+bzl6uascSoszycLRi5di2fLnjHHN3X+T76HhirqQwZ3ALObWAKDHFug9MXFwciYmJdO7cufAxBwcHfH19iYqKAiAqKgpHR8fC8gLQuXNntFot+/fvLxzToUMH9Hp94ZiuXbty9uxZ7t69+8DvnZubS1paWpGbEE8iJ9/APzec4PXlh0nPLcCnRiW2hgRIeRHiMZjrtLzTrSHLRrbByUbP6YQ0es6KYGPsdbWjiXKqWAtMYuK9w+lcXYv+wnd1dS1clpiYiIuLS5HlZmZmODk5FRnzoNf4/ff4oxkzZuDg4FB48/T0LMY1E+Vd3K1M+s2L5LvoKwCMf64Oq8a2paqjldrRhDApz9Wvwk+TA/Ct5URmnoHJq2L5+4/HyM6TKSVRvMrNUUjTpk0jNTW18Hb16lW1IwkTsTH2Oj1Cwzl5Iw0nGz1LR7Tm790bYq4rNz8eQpQqV3tLlo/2JeSFumg0sOrgVfrM2ceF5HS1o4lypFh/Q7u53Ts6Iymp6LUykpKSCpe5ubmRnFz08uwFBQXcuXOnyJgHvcbvv8cfWVhYYG9vX+QmxMPk5BuYtu4Yk1fFkplnoE0tJ8JCAujYwOUxni2EeBgznZYpXRrw3UhfnG0tOJuUTs9Z+/gh5pra0UQ5UawFplatWri5ubFr167Cx9LS0ti/fz9+fn4A+Pn5kZKSQkxMTOGYX375BaPRiK+vb+GYvXv3kp+fXzhmx44dNGjQgEqVKhVnZFFBXUjOoM+cfaw8cBWNBia9UJcVo31xc7BUO5oQ5Yp/PWfCJvvTvm5lsvMN/G3tUd5ac5SsvAK1owkT98QFJiMjg9jYWGJjY+G3HXdjY2OJj49Ho9Hwxhtv8K9//YtNmzZx/Phxhg0bhoeHB3369AGgUaNGdOvWjTFjxnDgwAH27dvHxIkTGThwIB4e907JPnjwYPR6PaNGjeLkyZOsXr2amTNnMmXKlOJef1EB/RhzjZ6zIjiTmI6zrQXfjfTlrS4NMJMpIyFKhIudJd+O9GXKi/XRauDHw/d+Bs8mypSSeHpPfBj1oUOHeP755wvv3y8Vw4cPZ+nSpbzzzjtkZmYyduxYUlJS8Pf3Z9u2bVha/u8v2+XLlzNx4kQ6deqEVqulX79+hIaGFi53cHDg559/Jjg4GB8fH5ydnZk+fbocQi2eSVZeAdM3niz8CLtdncp8NbA5LnbyqYsQJU2n1RDSqR5tajkxedURLt7MpNfsCD7o1ZhXWnui0WjUjihMjEZRFEXtECUhLS0NBwcHUlNTi3V/mJCVR9h09AbTe3gx0r9Wsb2uKFnnktIJXn6Y88kZaDUwuVN9Jr5QF51WfmkKUdpuZ+Ty5pqj7D13E4DezT3490tNsbV44r+phUoGL4wm8uJtQge1oJd38V7Q9nHfv+Uzc1GuKYrCmoNX6TU7gvPJGbjYWbB8dFsmd64n5UUIlVS2tWDpa615p1sDdFoNG2Nv0GtWBCdvpKodTZgQKTCi3MrMLeDN1bG88+MxcvKNBNRzJmxyAH51KqsdTYgKT6vV8HrHuqwe2xZ3B0su3crkpbn3zsVUTicGRDGTAiPKpVM37p0FdEPsDXRaDW93bcCyEW1wtrVQO5oQ4nda1bx3+oJODV3IKzDyzw0nmLjyCGk5+Y/xbFGRSYER5YqiKCzff4U+c/dx6VYmbvaWrBrbluDn66KVKSMhyqRKNnoWDW/F/wU2wkyrYeuxBHqERnDsWora0UQZJgVGlBvpOflMWnmE/1t/grwCIy80dCFscgCtazqpHU0I8QgajYYxHWqzZrwfVR2tiL+TRb95kSzZFydTSuKBpMCIcuHE9VR6zIpgy7EEzLQa/hHYkEXDWuFko3+MZwshyoqW1SsRFhJAFy9X8g0KH2w+xfjvY0jNkiklUZQUGGHSFEVhWeRl+s6N5MrtLKo6WrFmvB9jO9SRKSMhTJSDtTkLhvrwXk8vzHUatp9MIjA0nCPxd9WOJsoQKTDCZKVm5zPh+8O8t+kkeQYjL3q5EhYSQMvqcrkJIUydRqNhRPta/DihHdWdrLmeks3L86NYuPeSTCkJkAIjTFXs1RSCQsPZdjIRc52G6T28+HqoDw7W5mpHE0IUo2bVHNkS4k9QU3cKjAr/DjvN6GWHuJuZp3Y0oTIpMMKkKIrCovBLvDw/kmt3s/F0suKH8e0Y6V9LTkUuRDllb2nO7MEt+KhPE/RmWnadSSYoNJxDl++oHU2oSAqMMBkpWXmM+fYQ/9p6mnyDQmBTN7aGBODt6ah2NCFECdNoNAxtW4P1r7ejlrMNN1JzeOXraObuvoDRKFNKFZEUGGESYq7cIXBmODtPJ6PXafmod2PmDG6JvaVMGQlRkTT2cGDzJH96N/fAYFT4ZNtZRiw9yO2MXLWjiVImBUaUaUajwvw9FxmwIJobqTnUrGzNutfbMdSvpkwZCVFB2VqY8dUrzfm4b1MszLTsOXeTwNBwoi/dVjuaKEVSYESZdTsjl5HLDvLxT2cwGBV6eXuwJSSAJlUd1I4mhFCZRqNhYJvqbJzYnjpVbEhKy2XwwmhCd53HIFNKFYIUGFEmHYi7Q2BoOLvP3sTCTMuMvk2ZObA5thZmakcTQpQhDd3s2TzJn34tq2FU4Isd5xi2eD/J6TlqRxMlTAqMKFOMRoXZv5xn4NdRJKXlUqeKDRsntmdQm+oyZSSEeCBrvRmfD/Dms5e9sTLXse/CbQJnRrDvwi21o4kSJAVGlBk303MZvuQAn/18DqMCfVtWZdNEfxq62asdTQhhAvr7VGPTxPY0cLXjVkYur36zny92nJMppXJKCowoEyIv3CIwNJzw87ewMtfxaf9mfDGgOTYyZSSEeAL1XO3YENyega09URQI3XWewQujSUqTKaXyRgqMUJXBqPDljnMM+WY/N9Nzqe9qy6aJ7Xm5lafa0YQQJspKr+Pjfs2YObA5Nnod++PunYZhz7mbakcTxUgKjFBNcloOQxZFM3PXeRQFXmnlycZgf+q52qkdTQhRDvRuXpXNk/xp5G7P7cw8hi8+wH+3naHAYFQ7migGUmCEKvaeu0n3meFEX7qDtV7HV68057/9m2Gl16kdTQhRjtSuYsv619vxatvqAMzbfZGBX0dzIyVb7WjiGUmBEaWqwGDk0+1nGL7kALcz82joZsfmSf70aVFV7WhCiHLK0lzHv/o0ZfbgFthamHHoyl0CQ8P55UyS2tHEM5ACI0pNQmo2gxfuZ86vF1EUGOJbnQ3B7alTxVbtaEKICqBHMw+2hvjTtKoDKVn5jFx6iP+EnSZfppRMkhQYUSp+PZNM4MxwDly+g62FGbMGteDfLzXF0lymjIQQpadGZRt+mODHa+1qAvD13ku8PD+Kq3ey1I4mnpAUGFGi8g1GZoSdZsTSg9zNyqdJVXu2TPKnp7eH2tGEEBWUhZmO93s1Zv6rPthbmhF7NYWg0HC2n0xUO5p4AlJgRIm5djeLAQuiWLD3EgCvtavJjxPaUdPZRu1oQghBtyZubA0JwNvTkbScAsZ9F8MHm0+SW2BQO5p4DFJgRIn4+WQiQaERHIlPwc7SjPmvtuT9Xo2xMJMpIyFE2eHpZM3acX6MCagFwJJ9l+k/L4r42zKlVNZJgRHFKq/AyIebTzH2uxhSs/PxruZAWEgA3Zq4qx1NCCEeSG+m5f+CvFg0rBWO1uYcv55KUGg4YccT1I4mHkIKjCg2V+9k8fL8SBbviwNgtH8t1o5vh6eTtdrRhBDikTp7uRIWEoBPjUqk5xbw+vLD/HPDCXLyZUqpLJICI4rFT8cTCAwN5+i1VByszFk0rBXv9vBCbyb/xYQQpsPD0YpVY9syoWMdAL6LvkLfuZHE3cpUO5r4A3l3Ec8kJ9/A9I0nmLD8MOk5BbSs7kjY5AA6e7mqHU0IIZ6KuU7L1G4NWTqiNU42ek4lpNEjNJyNsdfVjiZ+RwqMeGqXb2XSb14k30ZdAWDcc7VZPc6Pqo5WakcTQohn1rGBC2EhAbSp5URmnoHJq2KZtu6YTCmVEVJgxFPZdPQGPWZFcPJGGk42epaMaM207o0w18l/KSFE+eHmYMmK0b5MeqEuGg2sPHCV3rP3cSE5Q+1oFV6xv9u8//77aDSaIreGDRsWLs/JySE4OJjKlStja2tLv379SEoqej2K+Ph4goKCsLa2xsXFhbfffpuCgoLijiqeQk6+gWnrjhOy8ggZuQW0qelEWEgAzzdwUTuaEEKUCDOdlre6NOC7kb4421pwNimdnrMi+DHmmtrRKrQS+XO5cePGJCQkFN4iIiIKl7355pts3ryZtWvXsmfPHm7cuEHfvn0LlxsMBoKCgsjLyyMyMpJly5axdOlSpk+fXhJRxRO4eDODPnP2sfJAPBoNTHqhLivG+OLmYKl2NCGEKHH+9ZwJm+xPuzqVyc438Nbao/xt7VGy8uQPbDWUSIExMzPDzc2t8Obs7AxAamoq33zzDV988QUvvPACPj4+LFmyhMjISKKjowH4+eefOXXqFN9//z3Nmzene/fufPTRR8yZM4e8vLySiCsew/oj1+g5K4Iziek42+r5dmQb3urSADOZMhJCVCAudpZ8N8qXKS/WR6uBH2Ku0Wv2Ps4mpqsdrcIpkXef8+fP4+HhQe3atRkyZAjx8fEAxMTEkJ+fT+fOnQvHNmzYkOrVqxMVFQVAVFQUTZs2xdX1f0exdO3albS0NE6ePFkSccVDZOUV8Pbao7y5+ihZeQb8alcmLCSAgHpV1I4mhBCq0Gk1hHSqx/LRbXGxs+BCcga950Sw+mA8iqKoHa/CKPYC4+vry9KlS9m2bRvz5s0jLi6OgIAA0tPTSUxMRK/X4+joWOQ5rq6uJCbeu4hWYmJikfJyf/n9ZX8lNzeXtLS0IjfxbM4lpdN79j7WxlxDq4E3O9fn+9G+uNjLlJEQQvjVqUzY5AAC6jmTk29k6o/HeXN1LBm5MqVUGsyK+wW7d+9e+HWzZs3w9fWlRo0arFmzBiurkju8dsaMGXzwwQcl9voViaIorI25xvSNJ8jJN1LFzoLQgS3wq1NZ7WhCCFGmONtasGxEG+bvvcjnP59jQ+wNjl1LZfbglnh52Ksdr1wr8R0YHB0dqV+/PhcuXMDNzY28vDxSUlKKjElKSsLNzQ0ANze3Px2VdP/+/TEPMm3aNFJTUwtvV69eLZH1Ke8ycwuYsuYo7/xwjJx8IwH1nPlpcoCUFyGE+AtarYbXO9Zl1di2uDtYculWJn3m7uP76CsypVSCSrzAZGRkcPHiRdzd3fHx8cHc3Jxdu3YVLj979izx8fH4+fkB4Ofnx/Hjx0lOTi4cs2PHDuzt7fHy8vrL72NhYYG9vX2Rm3gypxPS6Dk7gvVHrqPVwNtdG7BsRBucbS3UjiaEEGVe65pObA0J4IWGLuQVGHl3wwkmrjxCek6+2tHKpWIvMH/729/Ys2cPly9fJjIykpdeegmdTsegQYNwcHBg1KhRTJkyhV9//ZWYmBhGjBiBn58fbdu2BaBLly54eXkxdOhQjh49yvbt23n33XcJDg7GwkLeSEuCoiis2B9P7zn7uHQzEzd7S1aN9SP4+bpotRq14wkhhMlwstGzaFgr/hHYEDOthq3HEugxK4Lj11LVjlbuFPs+MNeuXWPQoEHcvn2bKlWq4O/vT3R0NFWq3Dtq5csvv0Sr1dKvXz9yc3Pp2rUrc+fOLXy+Tqdjy5YtTJgwAT8/P2xsbBg+fDgffvhhcUcVQHpOPv9Yf4LNR28A8HyDKnw+oDlONnq1owkhhEnSajWM7VCHVjWdmLTiCFduZ9FvXiT/CGzI8HY10WjkD8PiUOwFZtWqVQ9dbmlpyZw5c5gzZ85fjqlRowZhYWHFHU38wYnrqUxccZjLt7Mw02p4p1sDRvvXlk9dhBCiGLSsXomwkADe/uEoP59K4v3Np4i6dJtP+nnjYG2udjyTJ2chq4AUReHbqMv0nRvJ5dtZVHW0YvU4P8Z2qCPlRQghipGDtTkLhvrwXk8vzHUatp9MImhWOLFXUx7j2eJhpMBUMKnZ+by+/DDTN54kz2CkcyNXtob441OjktrRhBCiXNJoNIxoX4sfJ7SjupM11+5m039eJIvCL8lRSs9ACkwFcvRqCj1mhfPTiUTMdRqm9/Bi4TAfHK1lfxchhChpzao5siXEn8CmbhQYFf619TRjvj1ESpZcJudpSIGpABRF4ZuIOPrPj+TqnWw8naz4YXw7RvrXkp3JhBCiFNlbmjNncEs+6tMEvZmWnaeTCZwZTsyVO2pHMzlSYMq5lKw8xnwbw0dbTpFvUOjexI0tkwLw9nR8jGcLIYQobhqNhqFta7D+9XbUcrbhRmoOAxZEM2/3RYxGmVJ6XFJgyrGYK3cJCo1g5+kk9DotH/ZuzNwhLXGwkr3fhRBCbY09HNg8yZ9e3h4YjAr/3XaGkcsOcjsjV+1oJkEKTDlkNCos2HORVxZEcT0lm5qVrVn3ejuG+cn5B4QQoiyxtTBj5sDmzOjbFAszLbvP3iQwNJz9l26rHa3MkwJTztzJzGPUsoPM+OkMBUaFnt4ebJ7kT5OqDmpHE0II8QAajYZBbaqzcWJ76lSxISktl0ELo5m16zwGmVL6S1JgypEDcXcInBnOr2dvYmGmZUbfpoQObI6dpUwZCSFEWdfQzZ5NE/3p27IqRgU+33GO4YsPcDNdppQeRApMOWA0Ksz59QKDFkaTmJZD7So2bAhuz6A21WXKSAghTIiNhRlfDGjOp/2bYWWuI+LCLQJDw4m8cEvtaGWOFBgTdysjl+FLDvDp9rMYjAp9W1Rl80R/GrnL1biFEMJUvdzKk00T21Pf1Zab6bkM+WY/X+w4J1NKvyMFxoRFXrxF95nhhJ+/haW5lk/6N+PzAd7YWBT7Ja6EEEKUsnqudmwM9ueVVp4oCoTuOs+QRdEkpeWoHa1MkAJjggxGha92nuPVRfu5mZ5LPRdbNk/0Z0ArT5kyEkKIcsRKr+O//Zvx1SvNsdbriL50b1/Hveduqh1NdVJgTExyWg6vLtrPVzvPY1RgQKtqbJroTz1XO7WjCSGEKCF9WlRly6R7uwfczsxj2OIDfLLtDAUGo9rRVCMFxoSEn793foCoS7ex1uv48hVvPunvjZVep3Y0IYQQJax2FVvWv96OIb7VAZi7+yKDFkaTkJqtdjRVSIExAQUGI59tP8uwxQe4lZFHQzc7Nk3056UW1dSOJoQQohRZmuv490tNmT24BbYWZhy8fPfe6TPOJKsdrdRJgSnjElKzGbxwP7N/vYCiwGDf6mwIbk9dF1u1owkhhFBJj2YebJnkT5Oq9tzNymfE0oPMCDtNfgWaUpICU4b9evbeVUoPXL6DrYUZswa14D8vNcXSXKaMhBCioqvpbMOPE9rxWruaACzYe4kBC6K4djdL7WilQgpMGZRvMDLjp9OMWHKQu1n5NKlqz5ZJ/vT09lA7mhBCiDLEwkzH+70aM//VlthZmnEkPoWg0Ah+PpmodrQSJwWmjLmeks0rC6JYsOcSAMP9avDjhHbUdLZRO5oQQogyqlsTd8JCAvD2dCQ1O5+x38XwweaT5BWU3yklKTBlyI5TSQTODOdwfAp2lmbMG9KSD3o3wcJMpoyEEEI8nKeTNWvH+THavxYAS/Zdpv/8SOJvl88pJSkwZUBegZGPtpxizLeHSM3Ox7uaA2EhAXRv6q52NCGEECZEb6bl3R5eLBrWCgcrc45dSyUoNJyw4wlqRyt2UmBUdvVOFi8viOKbiDgARvnXYu34dng6WasdTQghhInq7OVK2OQAfGpUIj23gNeXH+afG06Qk29QO1qxkQKjom0nEggMDefo1RQcrMxZOKwV/+zhhd5MNosQQohnU9XRilVj2zL+uToAfBd9hX7zIom7lal2tGIh75QqyC0w8N7GE4z//jDpOQW0rO7I1hB/XvRyVTuaEEKIcsRcp+Xv3RuyZERrnGz0nLyRRo/QcDYdvaF2tGcmBaaUXb6VSb95kSyLugLAuOdqs3qcH9UqyZSREEKIkvF8AxfCQgJoU9OJzDwDISuPMG3dcZOeUpICU4o2H71Bj1kRnLieRiVrc5a81ppp3RthrpPNIIQQomS5OViyYowvk16oi0YDKw/E02fOPi4kZ6gd7anIO2cpyMk38I/1x5m08ggZuQW0qelE2OQAnm/oonY0IYQQFYiZTstbXRrw3UhfnG31nElMp9fsCNYdvqZ2tCcmBaaEXbyZQZ85+1ixPx6NBiY+X5cVY3xxd7BSO5oQQogKyr+eM2EhAbSrU5msPANT1hzl7bVHycorUDvaY5MCU4LWH7lGz1kRnElMx9lWz7cj2/C3rg0wkykjIYQQKnOxt+S7Ub682bk+Wg2sjblG79n7OJeUrna0xyLvpCUgO8/AOz8c5c3VR8nKM+BXuzJhIQEE1KuidjQhhBCikE6rYXLneiwf3RYXOwvOJ2fQa3YEaw5eRVEUteM9lBSYYnY+KZ3ecyJYc+gaGg280bke34/2xcXeUu1oQgghxAP51alM2OQAAuo5k5Nv5J0fj/Hm6lgyc8vulJIUmGKiKAprDl2l5+wIziVlUMXOguWjfXmjc310Wo3a8YQQQoiHcra1YNmINrzdtQE6rYYNsTfoOSuCUzfS1I72QFJgnoTBAMlJ976+cOHefSAzt4C31hzlnR+OkZNvJKBw5yhndfMKIYQQT0Cr1RD8fF1WjW2Lm70ll25l0mfuPpbvv/K/KSWDAe7evff1qVOF74WlnlWV7/qY5syZQ82aNbG0tMTX15cDBw6oF2bdOqhZE3btund/9myoWZPT36+/dwjaketoNfB21wYsG9GGKnYW6mUVQgghnkHr+6f7aFCFvAIj/7f+BJNWHiF97W/vhYeP3Bv40Uf37q9bV+oZy2yBWb16NVOmTOG9997j8OHDeHt707VrV5KTk0s/zLp10L8/XPvfcfKKBlY4N6HPEYWLNzNxs7dk1Vg/gp+vi1amjIQQQpg4Jxs93wxvzT8CG2Km1bDlWAI9dt7mRP4f/kC/fv3ee2QplxiNUkZ3M/b19aV169bMnj0bAKPRiKenJ5MmTeLvf//7I5+flpaGg4MDqamp2NvbP30Qg+Feu/ytvIT0/BubvDoWGdLxxgm+mB2Ck72c20UIIUT5ExN3i5AvwrhuUxl9QT42eVnctXYgdNMn9Dq9FzQaqFYN4uJAp3um7/W4799l8hOYvLw8YmJi6Ny5c+FjWq2Wzp07ExUV9cDn5ObmkpaWVuRWLMLDi3zyctK1TuHXOqOBab8uZvF303A6vL94vp8QQghRxvhcOcHWRcG8eC6KPDNz7lo7FB2gKHD16r33zFJSJgvMrVu3MBgMuLoWvTqzq6sriYmJD3zOjBkzcHBwKLx5enoWT5iEhMIvjWi4WPl/r7tm+VTGHViHFqXIOCGEEKJcSUjAMSeDr9f/m+k7v8bckA+AbW7Wn8aVljJZYJ7GtGnTSE1NLbxdvXq1eF7Y3b3wSy0KwZGrAfjmhw/wuXHmgeOEEEKIcuW39zgNMDJmExuXTeFf2+fgfzn2geNKg1mpfacn4OzsjE6nIykpqcjjSUlJuLm5PfA5FhYWWFiUwJE/AQH35vWuXwdF4e3w73g7/Lv/Lb8/7xcQUPzfWwghhCgL/vBe6HUzDq+bcf9brsJ7YZn8BEav1+Pj48Ou+4cs/7YT765du/Dz8yvdMDodzJx572vNH44uun//q6+eeaclIYQQoswqg++FZbLAAEyZMoWFCxeybNkyTp8+zYQJE8jMzGTEiBGlH6ZvX/jhB6hatejj1arde7xv39LPJIQQQpSmMvZeWGYPowaYPXs2n376KYmJiTRv3pzQ0FB8fX0f67nFdhj17xkM9/awTki4N88XECCfvAghhKhYSvi98HHfv8t0gXkWJVJghBBCCFGiTPo8MEIIIYQQDyMFRgghhBAmRwqMEEIIIUyOFBghhBBCmBwpMEIIIYQwOVJghBBCCGFypMAIIYQQwuRIgRFCCCGEyZECI4QQQgiTUyavRl0c7p9gOC0tTe0oQgghhHhM99+3H3WhgHJbYNLT0wHw9PRUO4oQQgghnlB6ejoODg5/ubzcXgvJaDRy48YN7Ozs0Pzx0t/PKC0tDU9PT65evVphrrMk61wx1pkKut6yzhVjnamg621q66woCunp6Xh4eKDV/vWeLuX2ExitVku1atVK9HvY29ubxH+G4iTrXHFUxPWWda44KuJ6m9I6P+yTl/tkJ14hhBBCmBwpMEIIIYQwOVJgnoKFhQXvvfceFhYWakcpNbLOFUdFXG9Z54qjIq53eV3ncrsTrxBCCCHKL/kERgghhBAmRwqMEEIIIUyOFBghhBBCmBwpMEIIIYQwOVJgntCcOXOoWbMmlpaW+Pr6cuDAAbUjPbUZM2bQunVr7OzscHFxoU+fPpw9e7bImI4dO6LRaIrcxo8fX2RMfHw8QUFBWFtb4+Liwttvv01BQUEpr83jef/99/+0Pg0bNixcnpOTQ3BwMJUrV8bW1pZ+/fqRlJRU5DVMaX3vq1mz5p/WW6PREBwcDOVkO+/du5eePXvi4eGBRqNhw4YNRZYrisL06dNxd3fHysqKzp07c/78+SJj7ty5w5AhQ7C3t8fR0ZFRo0aRkZFRZMyxY8cICAjA0tIST09PPvnkk1JZvwd52Drn5+czdepUmjZtio2NDR4eHgwbNowbN24UeY0H/d/4+OOPi4wpS+vMY2zr11577U/r1K1btyJjytO2Bh74863RaPj0008Lx5jitn4oRTy2VatWKXq9Xlm8eLFy8uRJZcyYMYqjo6OSlJSkdrSn0rVrV2XJkiXKiRMnlNjYWCUwMFCpXr26kpGRUTjmueeeU8aMGaMkJCQU3lJTUwuXFxQUKE2aNFE6d+6sHDlyRAkLC1OcnZ2VadOmqbRWD/fee+8pjRs3LrI+N2/eLFw+fvx4xdPTU9m1a5dy6NAhpW3btkq7du0Kl5va+t6XnJxcZJ137NihAMqvv/6qKOVkO4eFhSn/93//p6xbt04BlPXr1xdZ/vHHHysODg7Khg0blKNHjyq9evVSatWqpWRnZxeO6datm+Lt7a1ER0cr4eHhSt26dZVBgwYVLk9NTVVcXV2VIUOGKCdOnFBWrlypWFlZKQsWLCjVdb3vYeuckpKidO7cWVm9erVy5swZJSoqSmnTpo3i4+NT5DVq1KihfPjhh0W2/e9/B5S1dVYeY1sPHz5c6datW5F1unPnTpEx5WlbK4pSZF0TEhKUxYsXKxqNRrl48WLhGFPc1g8jBeYJtGnTRgkODi68bzAYFA8PD2XGjBmq5iouycnJCqDs2bOn8LHnnntOmTx58l8+JywsTNFqtUpiYmLhY/PmzVPs7e2V3NzcEs/8pN577z3F29v7gctSUlIUc3NzZe3atYWPnT59WgGUqKgoRTHB9f0rkydPVurUqaMYjUZFKYfb+Y+/4I1Go+Lm5qZ8+umnhY+lpKQoFhYWysqVKxVFUZRTp04pgHLw4MHCMT/99JOi0WiU69evK4qiKHPnzlUqVapUZJ2nTp2qNGjQoJTW7K896E3tjw4cOKAAypUrVwofq1GjhvLll1/+5XPK8jorf7Hew4cPV3r37v2Xz6kI27p3797KCy+8UOQxU9/WfyRTSI8pLy+PmJgYOnfuXPiYVqulc+fOREVFqZqtuKSmpgLg5ORU5PHly5fj7OxMkyZNmDZtGllZWYXLoqKiaNq0Ka6uroWPde3albS0NE6ePFmK6R/f+fPn8fDwoHbt2gwZMoT4+HgAYmJiyM/PL7KNGzZsSPXq1Qu3sSmu7x/l5eXx/fffM3LkyCIXOi1v2/n34uLiSExMLLJtHRwc8PX1LbJtHR0dadWqVeGYzp07o9Vq2b9/f+GYDh06oNfrC8d07dqVs2fPcvfu3VJdp6eRmpqKRqPB0dGxyOMff/wxlStXpkWLFnz66adFpgZNdZ13796Ni4sLDRo0YMKECdy+fbtwWXnf1klJSWzdupVRo0b9aVl52tbl9mKOxe3WrVsYDIYiv8ABXF1dOXPmjGq5iovRaOSNN96gffv2NGnSpPDxwYMHU6NGDTw8PDh27BhTp07l7NmzrFu3DoDExMQH/pvcX1bW+Pr6snTpUho0aEBCQgIffPABAQEBnDhxgsTERPR6/Z9+ubu6uhaui6mt74Ns2LCBlJQUXnvttcLHytt2/qP7GR+0Dr/fti4uLkWWm5mZ4eTkVGRMrVq1/vQa95dVqlSpRNfjWeTk5DB16lQGDRpU5IJ+ISEhtGzZEicnJyIjI5k2bRoJCQl88cUXYKLr3K1bN/r27UutWrW4ePEi//jHP+jevTtRUVHodLpyv62XLVuGnZ0dffv2LfJ4edvWUmAEAMHBwZw4cYKIiIgij48dO7bw66ZNm+Lu7k6nTp24ePEiderUUSHps+nevXvh182aNcPX15caNWqwZs0arKysVM1WWr755hu6d++Oh4dH4WPlbTuLovLz8xkwYACKojBv3rwiy6ZMmVL4dbNmzdDr9YwbN44ZM2aY7KnnBw4cWPh106ZNadasGXXq1GH37t106tRJ1WylYfHixQwZMgRLS8sij5e3bS1TSI/J2dkZnU73pyNSkpKScHNzUy1XcZg4cSJbtmzh119/pVq1ag8d6+vrC8CFCxcAcHNze+C/yf1lZZ2joyP169fnwoULuLm5kZeXR0pKSpExv9/Gpr6+V65cYefOnYwePfqh48rbdr6f8WE/v25ubiQnJxdZXlBQwJ07d0x6+98vL1euXGHHjh1FPn15EF9fXwoKCrh8+TKY6Dr/Ue3atXF2di7y/7k8bmuA8PBwzp49+8ifccrBtpYC85j0ej0+Pj7s2rWr8DGj0ciuXbvw8/NTNdvTUhSFiRMnsn79en755Zc/fXT4ILGxsQC4u7sD4Ofnx/Hjx4v8Mrj/S9LLy6sE0xePjIwMLl68iLu7Oz4+PpibmxfZxmfPniU+Pr5wG5v6+i5ZsgQXFxeCgoIeOq68bedatWrh5uZWZNumpaWxf//+Its2JSWFmJiYwjG//PILRqOxsND5+fmxd+9e8vPzC8fs2LGDBg0alLmP1/ldeTl//jw7d+6kcuXKj3xObGwsWq22cIrF1Nb5Qa5du8bt27eL/H8ub9v6vm+++QYfHx+8vb0fOdbkt7XaexGbklWrVikWFhbK0qVLlVOnTiljx45VHB0dixyZYUomTJigODg4KLt37y5yWF1WVpaiKIpy4cIF5cMPP1QOHTqkxMXFKRs3blRq166tdOjQofA17h9e26VLFyU2NlbZtm2bUqVKlTJ1eO3vvfXWW8ru3buVuLg4Zd++fUrnzp0VZ2dnJTk5WVF+O4y6evXqyi+//KIcOnRI8fPzU/z8/Aqfb2rr+3sGg0GpXr26MnXq1CKPl5ftnJ6erhw5ckQ5cuSIAihffPGFcuTIkcIjbj7++GPF0dFR2bhxo3Ls2DGld+/eDzyMukWLFsr+/fuViIgIpV69ekUOrU1JSVFcXV2VoUOHKidOnFBWrVqlWFtbq3aY6cPWOS8vT+nVq5dSrVo1JTY2tsjP+P2jTCIjI5Uvv/xSiY2NVS5evKh8//33SpUqVZRhw4aV2XV+1Hqnp6crf/vb35SoqCglLi5O2blzp9KyZUulXr16Sk5OTuFrlKdtfV9qaqpibW2tzJs370/PN9Vt/TBSYJ7QrFmzlOrVqyt6vV5p06aNEh0drXakpwY88LZkyRJFURQlPj5e6dChg+Lk5KRYWFgodevWVd5+++0i5wdRFEW5fPmy0r17d8XKykpxdnZW3nrrLSU/P1+ltXq4V155RXF3d1f0er1StWpV5ZVXXlEuXLhQuDw7O1t5/fXXlUqVKinW1tbKSy+9pCQkJBR5DVNa39/bvn27Aihnz54t8nh52c6//vrrA/8/Dx8+XFF+O5T6n//8p+Lq6qpYWFgonTp1+tO/xe3bt5VBgwYptra2ir29vTJixAglPT29yJijR48q/v7+ioWFhVK1alXl448/LtX1/L2HrXNcXNxf/ozfP/9PTEyM4uvrqzg4OCiWlpZKo0aNlP/85z9F3uiVMrbOyiPWOysrS+nSpYtSpUoVxdzcXKlRo4YyZsyYP/2hWZ629X0LFixQrKyslJSUlD8931S39cNolHtvZEIIIYQQJkP2gRFCCCGEyZECI4QQQgiTIwVGCCGEECZHCowQQgghTI4UGCGEEEKYHCkwQgghhDA5UmCEEEIIYXKkwAghhBDC5EiBEUIIIYTJkQIjhBBCCJMjBUYIIYQQJkcKjBBCCCFMzv8D4IYRTT5Lrw0AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xmltree = etree.parse(DATAPATH / \"example-sicd-1.5.xml\")\n", + "sicd_con = SicdConsistency.from_parts(xmltree)\n", + "_not_simple1(sicd_con.sicdroot.find(\"{*}RadarCollection/{*}Area/{*}Plane/{*}Polygon\"))\n", + "vert1 = sicd_con.xmlhelp.load(\"{*}RadarCollection/{*}Area/{*}Plane/{*}Polygon\")\n", + "x = [v[0] for v in vert1]\n", + "y = [v[1] for v in vert1]\n", + "plt.scatter(x, y, color='red')\n", + "plt.plot(x + [x[0]], y + [y[0]], linestyle='-')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bfe5239a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "[[-0.0066583 0.0012848 ]\n", + " [-0.00730503 -0.00202206]\n", + " [-0.00795176 -0.00532892]]\n", + "[[-0.00601157 0.00459167]\n", + " [-0.00536484 0.00789853]\n", + " [-0.0047181 0.01120539]]\n", + "False\n", + "True\n" + ] + } + ], + "source": [ + "import copy\n", + "import numpy as np\n", + "\n", + "xmltree = etree.parse(DATAPATH / \"example-sicd-1.5.xml\")\n", + "sicd_con = SicdConsistency.from_parts(copy.deepcopy(xmltree))\n", + "vertices = sicd_con.xmlhelp.load(\"./{*}GeoData/{*}ValidData\")\n", + "shg_polygon = shg.Polygon(vertices)\n", + "print(shg_polygon.exterior.is_ccw)\n", + "#row = [vertex[0] for vertex in vertices]\n", + "#col = [vertex[1] for vertex in vertices if vertex[0] == min(row)]\n", + "print(vertices[0:3])\n", + "poly_elem = sicd_con.sicdroot.find(\"./{*}GeoData/{*}ValidData\")\n", + "for vertex in poly_elem:\n", + " vertex.set(\"index\", str(len(poly_elem) + 1 - int(vertex.get(\"index\"))))\n", + "vertices1 = sicd_con.xmlhelp.load(\"./{*}GeoData/{*}ValidData\")\n", + "print(vertices1[0:3])\n", + "\n", + "\n", + "shg_polygon = shg.Polygon(vertices1)\n", + "print(shg_polygon.exterior.is_ccw)\n", + "shg_polygon = shg.Polygon(vertices1[::-1])\n", + "print(shg_polygon.exterior.is_ccw)\n", + "\n", + "#sicd_con.check(\"check_validdata_first_vertex\")\n", + "#assert not sicd_con.failures()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 195, + "id": "6e3e3573", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n" + ] + } + ], + "source": [ + "import copy\n", + "import numpy as np\n", + "\n", + "xmltree = etree.parse(DATAPATH / \"example-sicd-1.5.xml\")\n", + "sicd_con = SicdConsistency.from_parts(copy.deepcopy(xmltree))\n", + "vertices = sicd_con.xmlhelp.load(\"./{*}GeoData/{*}ValidData\")\n", + "shg_polygon = shg.Polygon(vertices)\n", + "print(shg_polygon.exterior.is_ccw)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3f6739c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "sarkit-local-3.13 (3.13.12)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/sarkit/sicd/__init__.py b/sarkit/sicd/__init__.py index fa3b138..4555b23 100644 --- a/sarkit/sicd/__init__.py +++ b/sarkit/sicd/__init__.py @@ -9,7 +9,15 @@ Supported Versions ================== -* `SICD 1.1.0`_ +.. note:: As of 2025-10-09, there are no links to any version 1.0.x schema files on the NSG standards registry. + + To get around this limitation, SARkit pulled SICD schemas from other sources. + Consult READMEs in the `SICD schema source directory `_ + for information on their provenance. + + +* `SICD 1.0`_ +* `SICD 1.1`_ * `SICD 1.2.1`_ * `SICD 1.3.0`_ * `SICD 1.4.0`_ @@ -113,8 +121,33 @@ References ========== -SICD 1.1.0 ----------- +SICD 1.0 +-------- +.. [NGA.STND.0024-1_1.0] National Center for Geospatial Intelligence Standards, + "Sensor Independent Complex Data (SICD), Vol. 1, Design & Implementation Description Document, + Version 1.0", 2011. + https://nsgreg.nga.mil/doc/view?i=2226 + +.. [NGA.STND.0024-2_1.0] National Center for Geospatial Intelligence Standards, + "Sensor Independent Complex Data (SICD), Vol. 2, File Format Description Document, + Version 1.0", 2011. + https://nsgreg.nga.mil/doc/view?i=2202 + +.. [NGA.STND.0024-3_1.0] National Center for Geospatial Intelligence Standards, + "Sensor Independent Complex Data (SICD), Vol. 3, Image Projections Description Document, + Version 1.0", 2011. + https://nsgreg.nga.mil/doc/view?i=2227 + +.. [SICD_schema_V1.0.1_2013_02_25.xsd] The schema documented in Table 1-1 of Volume 1 calls out + SICD_schema_V1.0_2011_06_10.xsd. This schema is not available in NSG Standards Registry or in + any commonly referenced libraries like six-library or sarpy. As such, a version that is + available in both six-library and sarpy will be used in sarkit. Furthermore, the version 1.0.1 + was selected as it was released in 2013 containing bugfixes only. SICD Volume 1, Table 1-1 was + not revised at the time to reflect the updated schema. + + +SICD 1.1 +-------- .. [NGA.STND.0024-1_1.1] National Center for Geospatial Intelligence Standards, "Sensor Independent Complex Data (SICD), Vol. 1, Design & Implementation Description Document, Version 1.1", 2014. diff --git a/sarkit/sicd/_constants.py b/sarkit/sicd/_constants.py index 831ac0c..7cf73c0 100644 --- a/sarkit/sicd/_constants.py +++ b/sarkit/sicd/_constants.py @@ -19,6 +19,11 @@ class VersionInfoType(TypedDict): # Keys must be in ascending order VERSION_INFO: Final[dict[str, VersionInfoType]] = { + "urn:SICD:1.0.1": { + "version": "1.0", + "date": "2011-09-28T00:00:00Z", # vols 1-3 have different dates, this is from DIDD + "schema": SCHEMA_DIR / "SICD_schema_V1.0.1_2013_02_25.xsd", + }, "urn:SICD:1.1.0": { "version": "1.1", "date": "2014-09-30T00:00:00Z", diff --git a/sarkit/sicd/_xml.py b/sarkit/sicd/_xml.py index 310327c..ea5b41d 100644 --- a/sarkit/sicd/_xml.py +++ b/sarkit/sicd/_xml.py @@ -199,42 +199,46 @@ def get_transcoder(self, typename, tag=None): "{http://www.w3.org/2001/XMLSchema}string": TxtType(), } typedef = self.xsdtypes[typename] - sicd_110 = { - "-{urn:SICD:1.1.0}DirParamType/{urn:SICD:1.1.0}WgtFunct": skxt.NdArrayType( + sicd_101 = { + "-{urn:SICD:1.0.1}DirParamType/{urn:SICD:1.0.1}WgtFunct": skxt.NdArrayType( "Wgt", DblType() ), - "-{urn:SICD:1.1.0}GeoDataType/{urn:SICD:1.1.0}ImageCorners": ImageCornersType(), - "-{urn:SICD:1.1.0}ImageDataType/{urn:SICD:1.1.0}AmpTable": skxt.NdArrayType( + "-{urn:SICD:1.0.1}GeoDataType/{urn:SICD:1.0.1}ImageCorners": ImageCornersType(), + "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}AmpTable": skxt.NdArrayType( "Amplitude", DblType(), index_start=0 ), - "-{urn:SICD:1.1.0}ImageDataType/{urn:SICD:1.1.0}ValidData": skxt.NdArrayType( + "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}ValidData": skxt.NdArrayType( "Vertex", RowColType() ), - "-{urn:SICD:1.1.0}LineType/{urn:SICD:1.1.0}Endpoint": LatLonType(), - "-{urn:SICD:1.1.0}PolygonType/{urn:SICD:1.1.0}Vertex": LatLonType(), - "-{urn:SICD:1.1.0}PositionType/{urn:SICD:1.1.0}RcvAPC": skxt.ListType( + "-{urn:SICD:1.0.1}LineType/{urn:SICD:1.0.1}Endpoint": LatLonType(), + "-{urn:SICD:1.0.1}PolygonType/{urn:SICD:1.0.1}Vertex": LatLonType(), + "-{urn:SICD:1.0.1}PositionType/{urn:SICD:1.0.1}RcvAPC": skxt.ListType( "RcvAPCPoly", XyzPolyType() ), ( - "-{urn:SICD:1.1.0}RadarCollectionType" - "/{urn:SICD:1.1.0}Area" - "/{urn:SICD:1.1.0}Corner" + "-{urn:SICD:1.0.1}RadarCollectionType" + "/{urn:SICD:1.0.1}Area" + "/{urn:SICD:1.0.1}Corner" ): skxt.NdArrayType("ACP", LatLonHaeType(), include_size_attr=False), - "{urn:SICD:1.1.0}ComplexType": CmplxType(), - "{urn:SICD:1.1.0}LatLonCornerStringType": LatLonType(), - "{urn:SICD:1.1.0}LatLonHAECornerRestrictType": LatLonHaeType(), - "{urn:SICD:1.1.0}LatLonHAERestrictionType": LatLonHaeType(), - "{urn:SICD:1.1.0}LatLonRestrictionType": LatLonType(), - "{urn:SICD:1.1.0}LineType": skxt.NdArrayType("Endpoint", LatLonType()), - "{urn:SICD:1.1.0}ParameterType": ParameterType(), - "{urn:SICD:1.1.0}Poly1DType": PolyType(), - "{urn:SICD:1.1.0}Poly2DType": Poly2dType(), - "{urn:SICD:1.1.0}PolygonType": skxt.NdArrayType("Vertex", LatLonType()), - "{urn:SICD:1.1.0}RowColType": RowColType(), - "{urn:SICD:1.1.0}RowColvertexType": RowColType(), - "{urn:SICD:1.1.0}XYZPolyAttributeType": XyzPolyType(), - "{urn:SICD:1.1.0}XYZPolyType": XyzPolyType(), - "{urn:SICD:1.1.0}XYZType": XyzType(), + "{urn:SICD:1.0.1}ComplexType": CmplxType(), + "{urn:SICD:1.0.1}LatLonCornerStringType": LatLonType(), + "{urn:SICD:1.0.1}LatLonHAECornerRestrictType": LatLonHaeType(), + "{urn:SICD:1.0.1}LatLonHAERestrictionType": LatLonHaeType(), + "{urn:SICD:1.0.1}LatLonRestrictionType": LatLonType(), + "{urn:SICD:1.0.1}LineType": skxt.NdArrayType("Endpoint", LatLonType()), + "{urn:SICD:1.0.1}ParameterType": ParameterType(), + "{urn:SICD:1.0.1}Poly1DType": PolyType(), + "{urn:SICD:1.0.1}Poly2DType": Poly2dType(), + "{urn:SICD:1.0.1}PolygonType": skxt.NdArrayType("Vertex", LatLonType()), + "{urn:SICD:1.0.1}RowColType": RowColType(), + "{urn:SICD:1.0.1}RowColvertexType": RowColType(), + "{urn:SICD:1.0.1}XYZPolyAttributeType": XyzPolyType(), + "{urn:SICD:1.0.1}XYZPolyType": XyzPolyType(), + "{urn:SICD:1.0.1}XYZType": XyzType(), + } + sicd_110 = { + k.replace("urn:SICD:1.0.1", "urn:SICD:1.1.0"): v + for k, v in sicd_101.items() } sicd_121 = { k.replace("urn:SICD:1.1.0", "urn:SICD:1.2.1"): v diff --git a/sarkit/sicd/nb_rfi.py b/sarkit/sicd/nb_rfi.py new file mode 100644 index 0000000..4f80c46 --- /dev/null +++ b/sarkit/sicd/nb_rfi.py @@ -0,0 +1,80 @@ +import argparse +import pprint + +import sarkit.cphd as skcphd + +def main(args=None): + parser = argparse.ArgumentParser(description="Clean up long-duration low-bandwidth signals in a CPHD") + parser.add_argument("input_cphd_filename") + parser.add_argument("output_cphd_filename") + parser.add_argument("--debug-stem", default="") + add_rfi_args(parser) + config = parser.parse_args(args) + + class ProcessChannel(mj.Chain): + def setup(self, chan_id, median_size, boxcar_size, trim_thresh): + self["read"] = sar_common_kit.cphd.ReadCphd(config.input_cphd_filename, chan_id) + signal_buff = self["read"].output("signal") + pvp_buff = self["read"].output("pvp") + + self["mitigate_rfi"] = RemoveNarrowbandRfi(signal_buff, pvp_buff, median_size, boxcar_size, + trim_thresh, config.debug_stem) + + self.__operation_outputs__["pvp"] = pvp_buff + self.__operation_outputs__["signal"] = self["mitigate_rfi"].output("result") + + with skcphd.Reader(config.input_cphd_filename) as r: + cphd_xmltree = r.metadata.xmltree + cphd_ew = skcphd.ElementWrapper(cphd_xmltree.getroot()) + ref_chan = cphd_ew.load("./{*}Channel/{*}RefChId") + assert cphd_ew.load("./{*}Global/{*}DomainType") == "FX" + + per_chan_pvp = {} + per_chan_signal = {} + for chan_id in [node.text for node in cphd_ew.cphdroot.xpath("./{*}Data/{*}Channel/{*}Identifier")]: + name = f"process_{chan_id}" + chain[name] = ProcessChannel(chan_id, config.median_size, config.boxcar_size, + config.trim_thresh) + + per_chan_pvp[chan_id] = chain[name].output("pvp") + per_chan_signal[chan_id] = chain[name].output("signal") + + classification = cphd_ew.load("./{*}CollectionID/{*}Classification") + release_info = cphd_ew.load("./{*}CollectionID/{*}ReleaseInfo") + + cphd_meta = skcphd.Metadata(xmltree=cphd_xmltree) + with skcphd.Writer(config.output_cphd_filename, cphd_meta) as w: + for ch_id, pvps in per_chan_pvp.items(): + w.write_pvp(ch_id, pvps) + w.write_signal(ch_id, per_chan_signal[ch_id]()) + for said_elem in cphd_xmltree.findall( + "{*}Data/{*}SupportArray/{*}Identifier" + ): + w.write_support_array( + said_elem.text, r.read_support_array(said_elem.text) + ) + + chain["write_cphd"] = sar_common_kit.cphd.WriteCphd( + config.output_cphd_filename, + mj.DictionaryOperationOutput(per_chan_pvp), + mj.DictionaryOperationOutput(per_chan_signal), + classification, + release_info, + ref_chan=ref_chan, + support_arrays=chain[f"process_{ref_chan}"]["read"].output("support_arrays") + ) + insights = mj.Orchestrator().run(chain)["insights"] + pprint.pprint(insights) + + +def add_rfi_args(parser, prefix=""): + """Adds RFI arguments to a parser with optional arg prefix.""" + detector_group = parser.add_argument_group("RFI detector arguments") + detector_group.add_argument(f"--{prefix}median-size", type=int, default=15, + help="Size of the 2D median filter used to create the denominator for thresholding") + detector_group.add_argument(f"--{prefix}boxcar-size", type=int, default=5, + help="Size of the 2D boxcar used to create the numerator for thresholding") + detector_group.add_argument(f"--{prefix}trim-thresh", type=float, default=4.0, + help=("Power in a bin, relative to median, above which bins are identified as " + "RFI. Bins with more power than this will be set to zero (default: %(default)g)")) + diff --git a/sarkit/sicd/schemas/README.md b/sarkit/sicd/schemas/README.md new file mode 100644 index 0000000..f8925d7 --- /dev/null +++ b/sarkit/sicd/schemas/README.md @@ -0,0 +1,25 @@ +# Overview +As of 2025-10-09, the XML schema files necessary to fully validate all SICD XML are not available on the NSG +standards registry. This README describes the provenance of the SICD schemas that SARkit uses. + +## `SICD_schema_V1.0.1_2013_02_25.xsd` +This file was copied from: +https://github.com/ngageoint/six-library/tree/448e6d659bb4b650fcc19e4b909353203c3a5195/six/modules/c%2B%2B/six.sicd/conf/schema + +## `SICD_schema_V1.1.0_2014_09_30.xsd` +This file was copied from: +https://nsgreg.nga.mil/doc/view?i=4251 + +The file was renamed from `*.xml` to `*.xsd` + +## `SICD_schema_V1.2.1_2018_12_13.xsd` +This file was copied from: +https://nsgreg.nga.mil/doc/view?i=5230 + +## `SICD_schema_V1.3.0_2021_11_30.xsd` +This file was copied from: +https://nsgreg.nga.mil/doc/view?i=5418 + +## `SICD_schema_V1.4.0_2024_05_01.xsd` +This file was copied from: +https://nsgreg.nga.mil/doc/view?i=5538 \ No newline at end of file diff --git a/sarkit/sicd/schemas/SICD_schema_V1.0.1_2013_02_25.xsd b/sarkit/sicd/schemas/SICD_schema_V1.0.1_2013_02_25.xsd new file mode 100755 index 0000000..edfe85d --- /dev/null +++ b/sarkit/sicd/schemas/SICD_schema_V1.0.1_2013_02_25.xsd @@ -0,0 +1,1111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sarkit/sicd/schemas/SICD_schema_V1.1.0_2014_09_30.xsd b/sarkit/sicd/schemas/SICD_schema_V1.1.0_2014_09_30.xsd index 412fb74..4a42f1f 100644 --- a/sarkit/sicd/schemas/SICD_schema_V1.1.0_2014_09_30.xsd +++ b/sarkit/sicd/schemas/SICD_schema_V1.1.0_2014_09_30.xsd @@ -1,1111 +1,1111 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sarkit/sicd/schemas/SICD_schema_V1.2.1_2018_12_13.xsd b/sarkit/sicd/schemas/SICD_schema_V1.2.1_2018_12_13.xsd index 90d2de8..43810f3 100644 --- a/sarkit/sicd/schemas/SICD_schema_V1.2.1_2018_12_13.xsd +++ b/sarkit/sicd/schemas/SICD_schema_V1.2.1_2018_12_13.xsd @@ -1,4 +1,4 @@ - + - \ No newline at end of file + diff --git a/sarkit/sicd/xsdtypes/SICD_schema_V1.0.1_2013_02_25.json b/sarkit/sicd/xsdtypes/SICD_schema_V1.0.1_2013_02_25.json new file mode 100644 index 0000000..1cd92d8 --- /dev/null +++ b/sarkit/sicd/xsdtypes/SICD_schema_V1.0.1_2013_02_25.json @@ -0,0 +1,2447 @@ +{ + "/": { + "{urn:SICD:1.0.1}SICD": "-{urn:SICD:1.0.1}SICD" + }, + "-{urn:SICD:1.0.1}AntParamType/{urn:SICD:1.0.1}EB": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DCXPoly", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DCYPoly", + "typename": "{urn:SICD:1.0.1}Poly1DType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}CollectionInfoType/{urn:SICD:1.0.1}CollectType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}CollectionInfoType/{urn:SICD:1.0.1}RadarMode": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ModeType", + "typename": "-{urn:SICD:1.0.1}CollectionInfoType/{urn:SICD:1.0.1}RadarMode/{urn:SICD:1.0.1}ModeType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ModeID", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}CollectionInfoType/{urn:SICD:1.0.1}RadarMode/{urn:SICD:1.0.1}ModeType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}DirParamType/{urn:SICD:1.0.1}Sgn": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + "-{urn:SICD:1.0.1}DirParamType/{urn:SICD:1.0.1}WgtFunct": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Wgt", + "typename": "{urn:SICD:1.0.1}ArrayDouble" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}DirParamType/{urn:SICD:1.0.1}WgtType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}WindowName", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Parameter", + "typename": "{urn:SICD:1.0.1}ParameterType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}AdditionalParms": { + "attributes": [], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Parameter", + "typename": "{urn:SICD:1.0.1}ParameterType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PosVelErr", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}PosVelErr" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RadarSensor", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}RadarSensor" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TropoError", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}TropoError" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IonoError", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}IonoError" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}IonoError": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IonoRangeVertical", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IonoRangeRateVertical", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IonoRgRgRateCC", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IonoRangeVertDecorr", + "typename": "{urn:SICD:1.0.1}ErrorDecorrFuncType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}PosVelErr": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Frame", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}PosVelErr/{urn:SICD:1.0.1}Frame" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}V1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}V2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}V3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CorrCoefs", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}PosVelErr/{urn:SICD:1.0.1}CorrCoefs" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PositionDecorr", + "typename": "{urn:SICD:1.0.1}ErrorDecorrFuncType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}PosVelErr/{urn:SICD:1.0.1}CorrCoefs": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P1P2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P1P3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P1V1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P1V2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P1V3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P2P3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P2V1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P2V2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P2V3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P3V1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P3V2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}P3V3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}V1V2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}V1V3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}V2V3", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}PosVelErr/{urn:SICD:1.0.1}Frame": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}RadarSensor": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RangeBias", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ClockFreqSF", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TransmitFreqSF", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RangeBiasDecorr", + "typename": "{urn:SICD:1.0.1}ErrorDecorrFuncType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components/{urn:SICD:1.0.1}TropoError": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TropoRangeVertical", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TropoRangeSlant", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TropoRangeDecorr", + "typename": "{urn:SICD:1.0.1}ErrorDecorrFuncType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}CompositeSCP": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Rg", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Az", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RgAz", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}GeoDataType/{urn:SICD:1.0.1}EarthModel": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}GeoDataType/{urn:SICD:1.0.1}ImageCorners": { + "attributes": [], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}ICP", + "typename": "{urn:SICD:1.0.1}LatLonCornerStringType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}GeoDataType/{urn:SICD:1.0.1}SCP": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ECF", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}LLH", + "typename": "{urn:SICD:1.0.1}LatLonHAERestrictionType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}GridType/{urn:SICD:1.0.1}ImagePlane": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}GridType/{urn:SICD:1.0.1}Type": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}AmpTable": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Amplitude", + "typename": "{urn:SICD:1.0.1}ArrayDouble" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}FullImage": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumRows", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumCols", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}PixelType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}ValidData": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Vertex", + "typename": "{urn:SICD:1.0.1}RowColvertexType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}AzAutofocus": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}ImageBeamComp": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}ImageFormAlgo": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}PolarizationCalibration": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DistortCorrectionApplied", + "typename": "{http://www.w3.org/2001/XMLSchema}boolean" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Distortion", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}PolarizationCalibration/{urn:SICD:1.0.1}Distortion" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}PolarizationCalibration/{urn:SICD:1.0.1}Distortion": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CalibrationDate", + "typename": "{http://www.w3.org/2001/XMLSchema}dateTime" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}A", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}F1", + "typename": "{urn:SICD:1.0.1}ComplexType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Q1", + "typename": "{urn:SICD:1.0.1}ComplexType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Q2", + "typename": "{urn:SICD:1.0.1}ComplexType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}F2", + "typename": "{urn:SICD:1.0.1}ComplexType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Q3", + "typename": "{urn:SICD:1.0.1}ComplexType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Q4", + "typename": "{urn:SICD:1.0.1}ComplexType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GainErrorA", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GainErrorF1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GainErrorF2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PhaseErrorF1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PhaseErrorF2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}Processing": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Type", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Applied", + "typename": "{http://www.w3.org/2001/XMLSchema}boolean" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Parameter", + "typename": "{urn:SICD:1.0.1}ParameterType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}RcvChanProc": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumChanProc", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PRFScaleFactor", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}ChanIndex", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}RgAutofocus": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}STBeamComp": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}TxFrequencyProc": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}MinProc", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}MaxProc", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}LineType/{urn:SICD:1.0.1}Endpoint": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lat", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lon", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}MatchInfoType/{urn:SICD:1.0.1}MatchType": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TypeID", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CurrentIndex", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumMatchCollections", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}MatchCollection", + "typename": "-{urn:SICD:1.0.1}MatchInfoType/{urn:SICD:1.0.1}MatchType/{urn:SICD:1.0.1}MatchCollection" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}MatchInfoType/{urn:SICD:1.0.1}MatchType/{urn:SICD:1.0.1}MatchCollection": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CoreName", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}MatchIndex", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Parameter", + "typename": "{urn:SICD:1.0.1}ParameterType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}PFAType/{urn:SICD:1.0.1}STDeskew": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Applied", + "typename": "{http://www.w3.org/2001/XMLSchema}boolean" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}STDSPhasePoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}PolygonType/{urn:SICD:1.0.1}Vertex": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lat", + "typename": "{urn:SICD:1.0.1}Neg90To90Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lon", + "typename": "{urn:SICD:1.0.1}Neg180To180Type" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}PositionType/{urn:SICD:1.0.1}RcvAPC": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}RcvAPCPoly", + "typename": "{urn:SICD:1.0.1}XYZPolyAttributeType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}INCA": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TimeCAPoly", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}R_CA_SCP", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}FreqZero", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DRateSFPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DopCentroidPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DopCentroidCOA", + "typename": "{http://www.w3.org/2001/XMLSchema}boolean" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}ImageType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}RMAT": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PosRef", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}VelRef", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DopConeAngRef", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}RMAlgoType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}RMCR": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PosRef", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}VelRef", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DopConeAngRef", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Corner", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Corner" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Plane", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Corner": { + "attributes": [], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}ACP", + "typename": "{urn:SICD:1.0.1}LatLonHAECornerRestrictType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RefPt", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}RefPt" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}XDir", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}XDir" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}YDir", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}YDir" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SegmentList", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}SegmentList" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Orientation", + "typename": "{urn:SICD:1.0.1}OrientationType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}RefPt": { + "attributes": [ + "name" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ECF", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Line", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Sample", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}SegmentList": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Segment", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}SegmentList/{urn:SICD:1.0.1}Segment" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}SegmentList/{urn:SICD:1.0.1}Segment": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}StartLine", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}StartSample", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}EndLine", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}EndSample", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Identifier", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}XDir": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}UVectECF", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}LineSpacing", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumLines", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}FirstLine", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area/{urn:SICD:1.0.1}Plane/{urn:SICD:1.0.1}YDir": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}UVectECF", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SampleSpacing", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumSamples", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}FirstSample", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}RcvChannels": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}ChanParameters", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}RcvChannels/{urn:SICD:1.0.1}ChanParameters" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}RcvChannels/{urn:SICD:1.0.1}ChanParameters": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxRcvPolarization", + "typename": "{urn:SICD:1.0.1}DualPolarizationType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvAPCIndex", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}TxFrequency": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Min", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Max", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}TxSequence": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}TxStep", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}TxSequence/{urn:SICD:1.0.1}TxStep" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}TxSequence/{urn:SICD:1.0.1}TxStep": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}WFIndex", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxPolarization", + "typename": "{urn:SICD:1.0.1}Polarization2Type" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Waveform": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}WFParameters", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Waveform/{urn:SICD:1.0.1}WFParameters" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Waveform/{urn:SICD:1.0.1}WFParameters": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxPulseLength", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxRFBandwidth", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxFreqStart", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxFMRate", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvDemodType", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Waveform/{urn:SICD:1.0.1}WFParameters/{urn:SICD:1.0.1}RcvDemodType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvWindowLength", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ADCSampleRate", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvIFBandwidth", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvFreqStart", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvFMRate", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Waveform/{urn:SICD:1.0.1}WFParameters/{urn:SICD:1.0.1}RcvDemodType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}RadiometricType/{urn:SICD:1.0.1}NoiseLevel": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NoiseLevelType", + "typename": "-{urn:SICD:1.0.1}RadiometricType/{urn:SICD:1.0.1}NoiseLevel/{urn:SICD:1.0.1}NoiseLevelType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NoisePoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}RadiometricType/{urn:SICD:1.0.1}NoiseLevel/{urn:SICD:1.0.1}NoiseLevelType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}SCPCOAType/{urn:SICD:1.0.1}SideOfTrack": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "-{urn:SICD:1.0.1}SICD": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CollectionInfo", + "typename": "{urn:SICD:1.0.1}CollectionInfoType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImageCreation", + "typename": "{urn:SICD:1.0.1}ImageCreationType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImageData", + "typename": "{urn:SICD:1.0.1}ImageDataType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GeoData", + "typename": "{urn:SICD:1.0.1}GeoDataType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Grid", + "typename": "{urn:SICD:1.0.1}GridType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Timeline", + "typename": "{urn:SICD:1.0.1}TimelineType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Position", + "typename": "{urn:SICD:1.0.1}PositionType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RadarCollection", + "typename": "{urn:SICD:1.0.1}RadarCollectionType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImageFormation", + "typename": "{urn:SICD:1.0.1}ImageFormationType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SCPCOA", + "typename": "{urn:SICD:1.0.1}SCPCOAType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Radiometric", + "typename": "{urn:SICD:1.0.1}RadiometricType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Antenna", + "typename": "{urn:SICD:1.0.1}AntennaType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ErrorStatistics", + "typename": "{urn:SICD:1.0.1}ErrorStatisticsType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}MatchInfo", + "typename": "{urn:SICD:1.0.1}MatchInfoType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RgAzComp", + "typename": "{urn:SICD:1.0.1}RgAzCompType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PFA", + "typename": "{urn:SICD:1.0.1}PFAType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RMA", + "typename": "{urn:SICD:1.0.1}RMAType" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}TimelineType/{urn:SICD:1.0.1}IPP": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Set", + "typename": "-{urn:SICD:1.0.1}TimelineType/{urn:SICD:1.0.1}IPP/{urn:SICD:1.0.1}Set" + } + ], + "text_typename": null + }, + "-{urn:SICD:1.0.1}TimelineType/{urn:SICD:1.0.1}IPP/{urn:SICD:1.0.1}Set": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TStart", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TEnd", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IPPStart", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IPPEnd", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IPPPoly", + "typename": "{urn:SICD:1.0.1}Poly1DType" + } + ], + "text_typename": null + }, + "{http://www.w3.org/2001/XMLSchema}boolean": { + "attributes": [], + "children": [], + "text_typename": null + }, + "{http://www.w3.org/2001/XMLSchema}dateTime": { + "attributes": [], + "children": [], + "text_typename": null + }, + "{http://www.w3.org/2001/XMLSchema}double": { + "attributes": [], + "children": [], + "text_typename": null + }, + "{http://www.w3.org/2001/XMLSchema}int": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}long" + }, + "{http://www.w3.org/2001/XMLSchema}long": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}integer" + }, + "{http://www.w3.org/2001/XMLSchema}string": { + "attributes": [], + "children": [], + "text_typename": null + }, + "{urn:SICD:1.0.1}AntParamType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}XAxisPoly", + "typename": "{urn:SICD:1.0.1}XYZPolyType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}YAxisPoly", + "typename": "{urn:SICD:1.0.1}XYZPolyType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}FreqZero", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}EB", + "typename": "-{urn:SICD:1.0.1}AntParamType/{urn:SICD:1.0.1}EB" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Array", + "typename": "{urn:SICD:1.0.1}GainPhasePolyType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Elem", + "typename": "{urn:SICD:1.0.1}GainPhasePolyType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GainBSPoly", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}EBFreqShift", + "typename": "{http://www.w3.org/2001/XMLSchema}boolean" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}MLFreqDilation", + "typename": "{http://www.w3.org/2001/XMLSchema}boolean" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}AntennaType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Tx", + "typename": "{urn:SICD:1.0.1}AntParamType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Rcv", + "typename": "{urn:SICD:1.0.1}AntParamType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TwoWay", + "typename": "{urn:SICD:1.0.1}AntParamType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}ArrayDouble": { + "attributes": [ + "index" + ], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + "{urn:SICD:1.0.1}CollectionInfoType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CollectorName", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IlluminatorName", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CoreName", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CollectType", + "typename": "-{urn:SICD:1.0.1}CollectionInfoType/{urn:SICD:1.0.1}CollectType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RadarMode", + "typename": "-{urn:SICD:1.0.1}CollectionInfoType/{urn:SICD:1.0.1}RadarMode" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Classification", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}CountryCode", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Parameter", + "typename": "{urn:SICD:1.0.1}ParameterType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}ComplexType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Real", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Imag", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}DirParamType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}UVectECF", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SS", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImpRespWid", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Sgn", + "typename": "-{urn:SICD:1.0.1}DirParamType/{urn:SICD:1.0.1}Sgn" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImpRespBW", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}KCtr", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DeltaK1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DeltaK2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DeltaKCOAPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}WgtType", + "typename": "-{urn:SICD:1.0.1}DirParamType/{urn:SICD:1.0.1}WgtType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}WgtFunct", + "typename": "-{urn:SICD:1.0.1}DirParamType/{urn:SICD:1.0.1}WgtFunct" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}DualPolarizationType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "{urn:SICD:1.0.1}ErrorDecorrFuncType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CorrCoefZero", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DecorrRate", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}ErrorStatisticsType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CompositeSCP", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}CompositeSCP" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Components", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}Components" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}AdditionalParms", + "typename": "-{urn:SICD:1.0.1}ErrorStatisticsType/{urn:SICD:1.0.1}AdditionalParms" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}GainPhasePolyType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GainPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PhasePoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}GeoDataType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}EarthModel", + "typename": "-{urn:SICD:1.0.1}GeoDataType/{urn:SICD:1.0.1}EarthModel" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SCP", + "typename": "-{urn:SICD:1.0.1}GeoDataType/{urn:SICD:1.0.1}SCP" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImageCorners", + "typename": "-{urn:SICD:1.0.1}GeoDataType/{urn:SICD:1.0.1}ImageCorners" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ValidData", + "typename": "{urn:SICD:1.0.1}PolygonType" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}GeoInfo", + "typename": "{urn:SICD:1.0.1}GeoInfoType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}GeoInfoType": { + "attributes": [ + "name" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Desc", + "typename": "{urn:SICD:1.0.1}ParameterType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Point", + "typename": "{urn:SICD:1.0.1}LatLonRestrictionType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Line", + "typename": "{urn:SICD:1.0.1}LineType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Polygon", + "typename": "{urn:SICD:1.0.1}PolygonType" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}GeoInfo", + "typename": "{urn:SICD:1.0.1}GeoInfoType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}GridType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImagePlane", + "typename": "-{urn:SICD:1.0.1}GridType/{urn:SICD:1.0.1}ImagePlane" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Type", + "typename": "-{urn:SICD:1.0.1}GridType/{urn:SICD:1.0.1}Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TimeCOAPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Row", + "typename": "{urn:SICD:1.0.1}DirParamType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Col", + "typename": "{urn:SICD:1.0.1}DirParamType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}ImageCreationType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Application", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DateTime", + "typename": "{http://www.w3.org/2001/XMLSchema}dateTime" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Site", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Profile", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}ImageDataType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PixelType", + "typename": "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}PixelType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}AmpTable", + "typename": "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}AmpTable" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumRows", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumCols", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}FirstRow", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}FirstCol", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}FullImage", + "typename": "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}FullImage" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SCPPixel", + "typename": "{urn:SICD:1.0.1}RowColType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ValidData", + "typename": "-{urn:SICD:1.0.1}ImageDataType/{urn:SICD:1.0.1}ValidData" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}ImageFormationType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvChanProc", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}RcvChanProc" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxRcvPolarizationProc", + "typename": "{urn:SICD:1.0.1}DualPolarizationType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TStartProc", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TEndProc", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxFrequencyProc", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}TxFrequencyProc" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SegmentIdentifier", + "typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImageFormAlgo", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}ImageFormAlgo" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}STBeamComp", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}STBeamComp" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImageBeamComp", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}ImageBeamComp" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}AzAutofocus", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}AzAutofocus" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RgAutofocus", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}RgAutofocus" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Processing", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}Processing" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PolarizationCalibration", + "typename": "-{urn:SICD:1.0.1}ImageFormationType/{urn:SICD:1.0.1}PolarizationCalibration" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}LatLonCornerStringType": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lat", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lon", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}LatLonHAECornerRestrictType": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lat", + "typename": "{urn:SICD:1.0.1}Neg90To90Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lon", + "typename": "{urn:SICD:1.0.1}Neg180To180Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}HAE", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}LatLonHAERestrictionType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lat", + "typename": "{urn:SICD:1.0.1}Neg90To90Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lon", + "typename": "{urn:SICD:1.0.1}Neg180To180Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}HAE", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}LatLonRestrictionType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lat", + "typename": "{urn:SICD:1.0.1}Neg90To90Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Lon", + "typename": "{urn:SICD:1.0.1}Neg180To180Type" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}LineType": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Endpoint", + "typename": "-{urn:SICD:1.0.1}LineType/{urn:SICD:1.0.1}Endpoint" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}MatchInfoType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NumMatchTypes", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}MatchType", + "typename": "-{urn:SICD:1.0.1}MatchInfoType/{urn:SICD:1.0.1}MatchType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}Neg180To180Type": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + "{urn:SICD:1.0.1}Neg90To90Type": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + "{urn:SICD:1.0.1}OrientationType": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "{urn:SICD:1.0.1}PFAType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}FPN", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IPN", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PolarAngRefTime", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}PolarAngPoly", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SpatialFreqSFPoly", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Krg1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Krg2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Kaz1", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Kaz2", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}STDeskew", + "typename": "-{urn:SICD:1.0.1}PFAType/{urn:SICD:1.0.1}STDeskew" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}ParameterType": { + "attributes": [ + "name" + ], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "{urn:SICD:1.0.1}Polarization1Type": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "{urn:SICD:1.0.1}Polarization2Type": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}string" + }, + "{urn:SICD:1.0.1}Poly1DType": { + "attributes": [ + "order1" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Coef", + "typename": "{urn:SICD:1.0.1}PolyCoef1DType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}Poly2DType": { + "attributes": [ + "order1", + "order2" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Coef", + "typename": "{urn:SICD:1.0.1}PolyCoef2DType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}PolyCoef1DType": { + "attributes": [ + "exponent1" + ], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + "{urn:SICD:1.0.1}PolyCoef2DType": { + "attributes": [ + "exponent1", + "exponent2" + ], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + "{urn:SICD:1.0.1}PolygonType": { + "attributes": [ + "size" + ], + "children": [ + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Vertex", + "typename": "-{urn:SICD:1.0.1}PolygonType/{urn:SICD:1.0.1}Vertex" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}PositionType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ARPPoly", + "typename": "{urn:SICD:1.0.1}XYZPolyType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GRPPoly", + "typename": "{urn:SICD:1.0.1}XYZPolyType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxAPCPoly", + "typename": "{urn:SICD:1.0.1}XYZPolyType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvAPC", + "typename": "-{urn:SICD:1.0.1}PositionType/{urn:SICD:1.0.1}RcvAPC" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}RMAType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RMAlgoType", + "typename": "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}RMAlgoType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ImageType", + "typename": "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}ImageType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RMAT", + "typename": "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}RMAT" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RMCR", + "typename": "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}RMCR" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}INCA", + "typename": "-{urn:SICD:1.0.1}RMAType/{urn:SICD:1.0.1}INCA" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}RadarCollectionType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxFrequency", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}TxFrequency" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RefFreqIndex", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Waveform", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Waveform" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxPolarization", + "typename": "{urn:SICD:1.0.1}Polarization1Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TxSequence", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}TxSequence" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RcvChannels", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}RcvChannels" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Area", + "typename": "-{urn:SICD:1.0.1}RadarCollectionType/{urn:SICD:1.0.1}Area" + }, + { + "repeat": true, + "tag": "{urn:SICD:1.0.1}Parameter", + "typename": "{urn:SICD:1.0.1}ParameterType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}RadiometricType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}NoiseLevel", + "typename": "-{urn:SICD:1.0.1}RadiometricType/{urn:SICD:1.0.1}NoiseLevel" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}RCSSFPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SigmaZeroSFPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}BetaZeroSFPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GammaZeroSFPoly", + "typename": "{urn:SICD:1.0.1}Poly2DType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}RgAzCompType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}AzSF", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}KazPoly", + "typename": "{urn:SICD:1.0.1}Poly1DType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}RowColType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Row", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Col", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}RowColvertexType": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Row", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Col", + "typename": "{http://www.w3.org/2001/XMLSchema}int" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}SCPCOAType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SCPTime", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ARPPos", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ARPVel", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}ARPAcc", + "typename": "{urn:SICD:1.0.1}XYZType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SideOfTrack", + "typename": "-{urn:SICD:1.0.1}SCPCOAType/{urn:SICD:1.0.1}SideOfTrack" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SlantRange", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GroundRange", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}DopplerConeAng", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}GrazeAng", + "typename": "{urn:SICD:1.0.1}ZeroTo90Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IncidenceAng", + "typename": "{urn:SICD:1.0.1}ZeroTo90Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}TwistAng", + "typename": "{urn:SICD:1.0.1}Neg90To90Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}SlopeAng", + "typename": "{urn:SICD:1.0.1}ZeroTo90Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}AzimAng", + "typename": "{urn:SICD:1.0.1}ZeroTo360Type" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}LayoverAng", + "typename": "{urn:SICD:1.0.1}ZeroTo360Type" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}TimelineType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CollectStart", + "typename": "{http://www.w3.org/2001/XMLSchema}dateTime" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}CollectDuration", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}IPP", + "typename": "-{urn:SICD:1.0.1}TimelineType/{urn:SICD:1.0.1}IPP" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}XYZPolyAttributeType": { + "attributes": [ + "index" + ], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}X", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Y", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Z", + "typename": "{urn:SICD:1.0.1}Poly1DType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}XYZPolyType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}X", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Y", + "typename": "{urn:SICD:1.0.1}Poly1DType" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Z", + "typename": "{urn:SICD:1.0.1}Poly1DType" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}XYZType": { + "attributes": [], + "children": [ + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}X", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Y", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + { + "repeat": false, + "tag": "{urn:SICD:1.0.1}Z", + "typename": "{http://www.w3.org/2001/XMLSchema}double" + } + ], + "text_typename": null + }, + "{urn:SICD:1.0.1}ZeroTo360Type": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}double" + }, + "{urn:SICD:1.0.1}ZeroTo90Type": { + "attributes": [], + "children": [], + "text_typename": "{http://www.w3.org/2001/XMLSchema}double" + } +} \ No newline at end of file diff --git a/sarkit/verification/_sicd_consistency.pySAV b/sarkit/verification/_sicd_consistency.pySAV new file mode 100644 index 0000000..819089b --- /dev/null +++ b/sarkit/verification/_sicd_consistency.pySAV @@ -0,0 +1,2169 @@ +""" +Functionality for verifying SICD files for internal consistency. +""" + +import copy +import datetime +import functools +import itertools +import os +from typing import Any, Optional + +import numpy as np +import numpy.linalg as npl +import numpy.polynomial.polynomial as npp +import shapely.geometry as shg +from jbpy import Jbp +from lxml import etree + +import sarkit.sicd as sksicd +import sarkit.sicd.projection as sicdproj +import sarkit.verification._consistency as con +import sarkit.wgs84 +from sarkit import _constants + +KAPFAC: float = 0.8859 + + +def _unit(vec, axis=-1): + return vec / np.linalg.norm(vec, axis=axis, keepdims=True) + + +def _uvecs_in_ground(xmlhelp): + look = 1.0 if xmlhelp.load("./{*}SCPCOA/{*}SideOfTrack") == "L" else -1.0 + scp_ecf = xmlhelp.load("./{*}GeoData/{*}SCP/{*}ECF") + arp_pos_ecf = xmlhelp.load("./{*}SCPCOA/{*}ARPPos") + arp_vel_ecf = xmlhelp.load("./{*}SCPCOA/{*}ARPVel") + spn = _unit(np.cross(look * (arp_pos_ecf - scp_ecf), arp_vel_ecf)) + + row_uvect = xmlhelp.load("./{*}Grid/{*}Row/{*}UVectECF") + col_uvect = xmlhelp.load("./{*}Grid/{*}Col/{*}UVectECF") + + scp_llh = xmlhelp.load("./{*}GeoData/{*}SCP/{*}LLH") + u_up = sarkit.wgs84.up(scp_llh) + scale_factor = np.dot(spn, u_up) + + row_in_ground = row_uvect - np.dot(row_uvect, u_up) * spn / scale_factor + col_in_ground = col_uvect - np.dot(col_uvect, u_up) * spn / scale_factor + assert np.abs(np.dot(row_in_ground, u_up)) < 1e-4 + assert np.abs(np.dot(col_in_ground, u_up)) < 1e-4 + return row_in_ground, col_in_ground + + +def _display_index_to_coord(xmlhelp, display_index): + spacing = np.array( + [ + xmlhelp.load( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}XDir/{*}LineSpacing" + ), + xmlhelp.load( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}YDir/{*}SampleSpacing" + ), + ] + ) + origin = np.array( + [ + xmlhelp.load("./{*}RadarCollection/{*}Area/{*}Plane/{*}RefPt/{*}Line"), + xmlhelp.load("./{*}RadarCollection/{*}Area/{*}Plane/{*}RefPt/{*}Sample"), + ] + ) + return (display_index - origin) * spacing + + +def _get_valid_data_vertices(xmlhelp): + """Returns a polygon describing the SICD's valid data region.""" + vertices = xmlhelp.load("./{*}ImageData/{*}ValidData") + if vertices is None: # Use edges of full image + nrows = xmlhelp.load("./{*}ImageData/{*}FullImage/{*}NumRows") + ncols = xmlhelp.load("./{*}ImageData/{*}FullImage/{*}NumCols") + + vertices = [(0, 0), (0, ncols - 1), (nrows - 1, ncols - 1), (nrows - 1, 0)] + + return np.asarray(vertices) + + +def _sample_valid_pixels(xmlhelp, shape=(5, 7)): + """Returns a number of row-column pairs that are inside ValidData.""" + validdata = _get_valid_data_vertices(xmlhelp) + min_index = validdata.min(axis=0) + max_index = validdata.max(axis=0) + grid = np.stack( + np.meshgrid( + *[ + np.linspace(min_index[dim], max_index[dim], shape[dim]) + for dim in range(2) + ], + indexing="ij", + ), + axis=-1, + ).reshape(-1, 2) + grid = np.concatenate([grid, validdata], axis=0) + points = shg.MultiPoint(grid) + intersecting_points = shg.polygon.orient(shg.Polygon(validdata)).intersection( + points + ) + return np.array([point.coords[0] for point in intersecting_points.geoms]) + + +def _grid_index_to_coord(xmlhelp, grid_index): + spacing = np.array( + [ + xmlhelp.load("./{*}Grid/{*}Row/{*}SS"), + xmlhelp.load("./{*}Grid/{*}Col/{*}SS"), + ] + ) + origin = np.array( + [ + xmlhelp.load("./{*}ImageData/{*}SCPPixel/{*}Row"), + xmlhelp.load("./{*}ImageData/{*}SCPPixel/{*}Col"), + ] + ) + return (grid_index - origin) * spacing + + +def _create_rectangle(x0, y0, num_x, num_y): + return shg.box(x0, y0, x0 + num_x - 1, y0 + num_y - 1, ccw=False) + + +def _compute_pfa_min_max_fx(xmlhelp): + """Computes min and max FX based on PFA parameters.""" + krg1 = xmlhelp.load("./{*}PFA/{*}Krg1") + krg2 = xmlhelp.load("./{*}PFA/{*}Krg2") + kaz1 = xmlhelp.load("./{*}PFA/{*}Kaz1") + kaz2 = xmlhelp.load("./{*}PFA/{*}Kaz2") + ksf = xmlhelp.load("./{*}PFA/{*}SpatialFreqSFPoly") + + def _k_rect_to_fx(krg, kaz): + """Converts k-space location to FX.""" + kap = np.sqrt(krg**2 + kaz**2) + theta = np.arctan2(kaz, krg) + + return _constants.c / 2.0 / npp.polyval(theta, ksf) * kap + + min_fx = min(_k_rect_to_fx(krg1, kaz) for kaz in [kaz1, kaz2]) + max_fx = max(_k_rect_to_fx(krg2, kaz) for kaz in [kaz1, kaz2]) + + if kaz1 < 0 < kaz2: + min_fx = min(min_fx, _k_rect_to_fx(krg1, 0)) + + return min_fx, max_fx + + +def _get_desdata_location(ntf): + """Return the first SICD DES""" + for deseg in ntf["DataExtensionSegments"]: + if deseg["subheader"]["DESSHTN"].encoded_value.startswith(b"urn:SICD"): + return deseg["DESDATA"].get_offset(), deseg["DESDATA"].get_size() + raise ValueError("Unable to find SICD DES") + + +def _get_root_path(node): + path = [] + while node is not None: + path.append(etree.QName(node).localname) + node = node.getparent() + return "/".join(reversed(path[:-1])) + + +def per_grid_dim(method): + method.per_grid_dim = True + return method + + +class SicdConsistency(con.ConsistencyChecker): + """Check SICD file structure and metadata for internal consistency + + `SicdConsistency` objects should be instantiated using `from_file` or `from_parts`. + + Parameters + ---------- + sicd_xml : lxml.etree.Element or lxml.etree.ElementTree + SICD XML + schema_override : `path-like object`, optional + Path to XML Schema. If None, tries to find a version-specific schema + file : `file object`, optional + SICD NITF file; when specified, NITF headers are extracted during object instantiation + """ + + def __init__( + self, + sicd_xml, + *, + schema_override=None, + file=None, + ): + super().__init__() + # handle element or tree -> element + try: + self.sicdroot = sicd_xml.getroot() + except AttributeError: + self.sicdroot = sicd_xml.getroottree().getroot() + self.xmlhelp = sksicd.XmlHelper(self.sicdroot.getroottree()) + if file is not None: + file.seek(0, os.SEEK_SET) + self.ntf = Jbp().load(file) + else: + self.ntf = None + + ns = etree.QName(self.sicdroot).namespace + self.schema = schema_override or sksicd.VERSION_INFO.get(ns, {}).get("schema") + + # process decorated methods to generate additional tests + # reverse the enumerated list so that we don't disturb indices on later iterations as we insert into the list + for index, func in reversed(list(enumerate(self.funcs))): + if getattr(func, "per_grid_dim", False): + subfuncs = [] + for grid_dim in ("Row", "Col"): + subfunc = functools.partial(func, grid_dim=grid_dim) + subfunc.__doc__ = ( + f"{func.__doc__.removesuffix('.')} for Grid/{grid_dim}." + ) + subfunc.__name__ = f"{func.__name__}_{grid_dim.lower()}" + subfuncs.append(subfunc) + self.funcs[index : index + 1] = subfuncs + + @staticmethod + def from_file( + file, + schema: Optional[str] = None, + ) -> "SicdConsistency": + """Create a SicdConsistency object from a file + + Parameters + ---------- + file : `file object` + SICD NITF or SICD XML file to check + schema : str, optional + Path to XML Schema. If None, tries to find a version-specific schema + + Returns + ------- + SicdConsistency + The initialized consistency checker object + + See Also + -------- + from_parts + + Examples + -------- + Use `from_file` to check an XML file: + + .. doctest:: + + >>> import sarkit.verification as skver + + >>> with open("data/example-sicd-1.4.0.xml", "r") as f: + ... con = skver.SicdConsistency.from_file(f) + >>> con.check() + >>> bool(con.passes()) + True + >>> bool(con.failures()) + False + + Use `from_file` to check a SICD NITF file: + + .. testsetup:: + + import lxml.etree + import numpy as np + + import sarkit.sicd as sksicd + + file = tmppath / "example.sicd" + sec = {"security": {"clas": "U"}} + example_sicd_xmltree = lxml.etree.parse("data/example-sicd-1.4.0.xml") + sicd_meta = sksicd.NitfMetadata( + xmltree=example_sicd_xmltree, + file_header_part={"ostaid": "nowhere"} | sec, + im_subheader_part={"isorce": "this sensor"} | sec, + de_subheader_part=sec, + ) + with open(file, "wb") as f, sksicd.NitfWriter(f, sicd_meta): + pass # don't currently care about the pixels + + .. doctest:: + + >>> with file.open("rb") as f: + ... con = skver.SicdConsistency.from_file(f) + >>> con.check() # open file only used for construction + >>> bool(con.passes()) + True + >>> bool(con.failures()) + False + """ + kwargs: dict[str, Any] = {"schema_override": schema} + try: + sicdroot = etree.parse(file) + ntf = None + except etree.XMLSyntaxError: + file.seek(0, os.SEEK_SET) + ntf = Jbp().load(file) + des_offset, des_length = _get_desdata_location(ntf) + file.seek(des_offset, os.SEEK_SET) + sicdroot = etree.fromstring(file.read(des_length)) + kwargs["file"] = file + + return SicdConsistency( + sicdroot, + **kwargs, + ) + + @staticmethod + def from_parts( + sicd_xml: "etree.Element | etree.ElementTree", + schema: Optional[str] = None, + ) -> "SicdConsistency": + """Create a SicdConsistency object from assorted parts + + Parameters + ---------- + sicd_xml : lxml.etree.Element or lxml.etree.ElementTree + SICD XML + schema : `path-like object`, optional + Path to XML Schema. If None, tries to find a version-specific schema + + Returns + ------- + SicdConsistency + The initialized consistency checker object + + See Also + -------- + from_file + + Examples + -------- + Use `from_parts` to check a parsed XML element tree: + + .. doctest:: + + >>> import lxml.etree + >>> import sarkit.verification as skver + >>> sicd_xmltree = lxml.etree.parse("data/example-sicd-1.4.0.xml") + >>> con = skver.SicdConsistency.from_parts(sicd_xmltree) + >>> con.check() + >>> bool(con.passes()) + True + >>> bool(con.failures()) + False + """ + return SicdConsistency( + sicd_xml, + schema_override=schema, + ) + + def _assert_poly_1d(self, poly, poly_label): + """Helper method for checking 1d polynomial nodes are consistent.""" + coef_nodes = poly.findall("./{*}Coef") + num_coefs = int(poly.attrib["order1"]) + 1 + coefs = [int(coef.attrib["exponent1"]) for coef in coef_nodes] + with self.need(f"{poly_label}: Exponents are unique"): + assert len(set(coefs)) == len(coef_nodes) + with self.need(f"{poly_label}: Coef exponents between 0 and order"): + assert all(coef >= 0 and coef < num_coefs for coef in coefs) + + def _assert_poly_2d(self, poly, poly_label): + """Helper method for checking 2d polynomial nodes are consistent.""" + coef_nodes = poly.findall("./{*}Coef") + num_coefs = (int(poly.attrib["order1"]) + 1, int(poly.attrib["order2"]) + 1) + coefs = [ + (int(coef.attrib["exponent1"]), int(coef.attrib["exponent2"])) + for coef in coef_nodes + ] + with self.need(f"{poly_label}: Exponents are unique"): + assert len(set(coefs)) == len(coef_nodes) + with self.need(f"{poly_label}: Coef exponents between 0 and order"): + assert all(coef[0] >= 0 and coef[0] < num_coefs[0] for coef in coefs) + assert all(coef[1] >= 0 and coef[1] < num_coefs[1] for coef in coefs) + + def _assert_poly_xyz(self, poly, poly_label): + """Helper method for checking XYZ polynomial nodes are consistent.""" + for dim in ["X", "Y", "Z"]: + self._assert_poly_1d(poly.find(f"./{{*}}{dim}"), f"{poly_label}/{{*}}{dim}") + + def check_against_schema(self) -> None: + """Checks against schema.""" + with self.need( + f"Schema available for checking xml whose root tag = {self.sicdroot.tag}" + ): + assert self.schema is not None + schema = etree.XMLSchema(file=str(self.schema)) + with self.need("XML passes schema"): + assert schema.validate(self.sicdroot), schema.error_log + + def check_nitf_imseg(self) -> None: + """Check NITF Image Subheaders""" + collect_start = self.xmlhelp.load("./{*}Timeline/{*}CollectStart") + pixel_info = sksicd.PIXEL_TYPES[ + self.xmlhelp.load("./{*}ImageData/{*}PixelType") + ] + expected_nbpp = pixel_info["bytes"] * 8 / 2 + with self.precondition(): + assert self.ntf is not None + imsegs = self.ntf["ImageSegments"] + for imseg in imsegs: + imhdr = imseg["subheader"] + idatim = datetime.datetime.strptime( + imhdr["IDATIM"].value + "+0000", "%Y%m%d%H%M%S%z" + ) + with self.need("Valid image subheaders"): + assert idatim <= collect_start + datetime.timedelta(seconds=1) + assert idatim >= collect_start - datetime.timedelta(seconds=1) + assert imhdr["PVTYPE"].value == pixel_info["pvtype"] + assert imhdr["IREP"].value == "NODISPLY" + assert imhdr["ICAT"].value == "SAR" + assert imhdr["ABPP"].value == expected_nbpp + assert imhdr["PJUST"].value == "R" + assert imhdr["ICORDS"].value == "G" + assert imhdr["IC"].value in ["NC", "NM", "C7", "M7"] + assert imhdr["ISYNC"].value == 0 + assert imhdr["IMODE"].value == "P" + assert imhdr["NBPR"].value == 1 + assert imhdr["NBPC"].value == 1 + + if imhdr["NCOLS"].value > 8192: + assert imhdr["NPPBH"].value == 0 + else: + assert imhdr["NPPBH"].value == imhdr["NCOLS"].value + + if imhdr["NROWS"].value > 8192: + assert imhdr["NPPBV"].value == 0 + else: + assert imhdr["NPPBV"].value == imhdr["NROWS"].value + + assert imhdr["NBPP"].value == expected_nbpp + assert imhdr["IMAG"].value == "1.0" + + with self.need("Sequential IID1"): + expected_iid1s = ( + ["SICD000"] + if len(imsegs) == 1 + else sorted([f"SICD{n + 1:03d}" for n in range(len(imsegs))]) + ) + actual_iid1s = sorted( + [imseg["subheader"]["IID1"].value for imseg in imsegs] + ) + assert actual_iid1s == expected_iid1s + + def check_nitf_imseg_lvls(self) -> None: + """Check NITF inter-Image Subheaders Display and Attachment levels""" + with self.precondition(): + assert self.ntf is not None + imsegs = self.ntf["ImageSegments"] + with self.need("Consistent NITF inter-Image Subheaders Display levels"): + assert np.array_equal( + [imseg["subheader"]["IDLVL"].value for imseg in imsegs], + np.arange(len(imsegs)) + 1, + ) + with self.need("Consistent NITF inter-Image Subheaders Attachment levels"): + assert np.array_equal( + [imseg["subheader"]["IALVL"].value for imseg in imsegs], + np.arange(len(imsegs)), + ) + + def _segmentation(self): + """Section 3.2.1 Image Segment Parameters and Equations""" + bytes_per_pixel = sksicd.PIXEL_TYPES[ + self.xmlhelp.load("./{*}ImageData/{*}PixelType") + ]["bytes"] + is_size_max = 9_999_999_998 + iloc_max = 99_999 + num_rows = self.xmlhelp.load("./{*}ImageData/{*}NumRows") + num_cols = self.xmlhelp.load("./{*}ImageData/{*}NumCols") + bytes_per_row = bytes_per_pixel * num_cols + product_size = bytes_per_pixel * num_rows * num_cols + limit1 = int(np.floor(is_size_max / bytes_per_row)) + num_rows_limit = min(limit1, iloc_max) + if product_size <= is_size_max: + num_is = 1 + num_rows_is = [num_rows] + first_row_is = [0] + row_offset_is = [0] + else: + num_is = int(np.ceil(num_rows / num_rows_limit)) + num_rows_is = [num_rows_limit] * num_is + first_row_is = [0] * num_is + row_offset_is = [0] * num_is + for n in range(num_is - 1): + first_row_is[n + 1] = (n + 1) * num_rows_limit + row_offset_is[n + 1] = num_rows_limit + num_rows_is[-1] = num_rows - (num_is - 1) * num_rows_limit + + return num_is, num_rows_is, first_row_is, row_offset_is + + def check_nitf_imseg_size(self) -> None: + """Check the size of each NITF image segment""" + with self.precondition(): + assert self.ntf is not None + imsegs = self.ntf["ImageSegments"] + num_is, num_rows_is, _, _ = self._segmentation() + num_cols = self.xmlhelp.load("./{*}ImageData/{*}NumCols") + with self.need("Consistent number of image segments"): + assert len(imsegs) == num_is + for imidx, imseg in enumerate(imsegs): + with self.need("Matching NROWS"): + assert imseg["subheader"]["NROWS"].value == num_rows_is[imidx] + expected_iloc_rows = 0 if imidx == 0 else num_rows_is[imidx - 1] + with self.need("ILOC matches expected"): + assert ( + int(imseg["subheader"]["ILOC"].value[0]) + == expected_iloc_rows + ) + assert int(imseg["subheader"]["ILOC"].value[1]) == 0 + with self.need("Matching NCOLS"): + assert imseg["subheader"]["NCOLS"].value == num_cols + + def check_nitf_igeolo(self) -> None: + """Check each NITF image segment's IGEOLO""" + num_is, _, first_row_is, _ = self._segmentation() + num_rows = self.xmlhelp.load("./{*}ImageData/{*}NumRows") + + icp_nodes = self.xmlhelp.load("./{*}GeoData/{*}ImageCorners") + icp_ecef = sarkit.wgs84.geodetic_to_cartesian( + np.concatenate((icp_nodes, np.zeros((4, 1))), axis=1) + ) + + iscp_ecef = np.zeros((num_is, 4, 3)) + for imidx in range(num_is): + wgt1 = (num_rows - 1 - first_row_is[imidx]) / (num_rows - 1) + wgt2 = first_row_is[imidx] / (num_rows - 1) + iscp_ecef[imidx][0] = wgt1 * icp_ecef[0] + wgt2 * icp_ecef[3] + iscp_ecef[imidx][1] = wgt1 * icp_ecef[1] + wgt2 * icp_ecef[2] + + for imidx in range(num_is - 1): + iscp_ecef[imidx][2] = iscp_ecef[imidx + 1][1] + iscp_ecef[imidx][3] = iscp_ecef[imidx + 1][0] + iscp_ecef[num_is - 1][2] = icp_ecef[2] + iscp_ecef[num_is - 1][3] = icp_ecef[3] + + iscp_ll = sarkit.wgs84.cartesian_to_geodetic(iscp_ecef)[:, :, :2] # Lat, Lon + + def _dms_to_dd(dms_str): + direction = dms_str[-1] + ss = int(dms_str[-3:-1]) + mm = int(dms_str[-5:-3]) + dd = int(dms_str[:-5]) + sign = 1 if direction in ["E", "N"] else -1 + return sign * (dd + mm / 60 + ss / 60 / 60) + + with self.precondition(): + assert self.ntf is not None + imsegs = self.ntf["ImageSegments"] + for imidx, imseg in enumerate(imsegs): + igeolo_ll = [ # Lat, Lon + [ + _dms_to_dd(imseg["subheader"]["IGEOLO"].value[0:7]), + _dms_to_dd(imseg["subheader"]["IGEOLO"].value[7:15]), + ], + [ + _dms_to_dd(imseg["subheader"]["IGEOLO"].value[15:22]), + _dms_to_dd(imseg["subheader"]["IGEOLO"].value[22:30]), + ], + [ + _dms_to_dd(imseg["subheader"]["IGEOLO"].value[30:37]), + _dms_to_dd(imseg["subheader"]["IGEOLO"].value[37:45]), + ], + [ + _dms_to_dd(imseg["subheader"]["IGEOLO"].value[45:52]), + _dms_to_dd(imseg["subheader"]["IGEOLO"].value[52:60]), + ], + ] + with self.need("IGEOLO close to ICP Lon/Lat"): + assert np.allclose( + igeolo_ll, iscp_ll[imidx], atol=1.0 / 60 / 60, rtol=0 + ) + + def check_des_subheader(self) -> None: + """Check NITF DES Subheaders""" + with self.precondition(): + assert self.ntf is not None + des_header = self.ntf["DataExtensionSegments"][0]["subheader"] + + xml_offset, _ = _get_desdata_location(self.ntf) + with self.need("XML from first DES matches sicdroot being used"): + assert ( + xml_offset + == self.ntf["DataExtensionSegments"][0]["DESDATA"].get_offset() + ) + + with self.need("DESID == XML_DATA_CONTENT"): + assert des_header["DESID"].value == "XML_DATA_CONTENT" + + with self.need("DESSHFT == XML"): + assert des_header["DESSHFT"].value == "XML" + + with self.need( + "DESSHSI == SICD Volume 1 Design & Implementation Description Document" + ): + assert ( + des_header["DESSHSI"].value + == "SICD Volume 1 Design & Implementation Description Document" + ) + + instance_namespace = etree.QName(self.sicdroot).namespace + with self.need("Consistent namespace"): + assert des_header["DESSHTN"].value == instance_namespace + + icp_nodes = self.xmlhelp.load("./{*}GeoData/{*}ImageCorners") + icp_strs = [f"{lat:+012.8f}{lon:+013.8f}" for (lat, lon) in icp_nodes] + icp_strs.append(icp_strs[0]) + with self.need("DESSHLPG consistent with image corners"): + assert des_header["DESSHLPG"].value == "".join(icp_strs) + + def check_bistatic_fields(self) -> None: + """Optional fields are consistent with CollectType = BISTATIC for SICD v1.4.0+""" + with self.precondition(): + assert ( + self.sicdroot.findtext("{*}CollectionInfo/{*}CollectType") == "BISTATIC" + ) + this_ns = etree.QName(self.sicdroot).namespace + sicd_versions = list(sksicd.VERSION_INFO) + assert sicd_versions.index(this_ns) >= sicd_versions.index("urn:SICD:1.4.0") + required_fields = ( + "{*}CollectionInfo/{*}IlluminatorName", + "{*}Position/{*}GRPPoly", + "{*}Position/{*}TxAPCPoly", + "{*}Position/{*}RcvAPC", + ) + for field in required_fields: + with self.need( + f"{field.replace('{*}', '')} required for CollectType=BISTATIC" + ): + assert self.sicdroot.find(field) is not None + + with self.need("Antenna/TwoWay not allowed when CollectType=BISTATIC"): + assert self.sicdroot.find("{*}Antenna/{*}TwoWay") is None + + def check_grid_sign(self) -> None: + """Grid signs match.""" + with self.need("Row and Col grid signs match"): + assert self.xmlhelp.load("./{*}Grid/{*}Col/{*}Sgn") == self.xmlhelp.load( + "./{*}Grid/{*}Row/{*}Sgn" + ) + + @per_grid_dim + def check_uniform_ipr_width(self, grid_dim) -> None: + """Uniform weighted IPR width matches bandwidth.""" + with self.precondition(): + assert ( + self.xmlhelp.load( + f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}WgtType/{{*}}WindowName" + ) + == "UNIFORM" + ) + imprespbw = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}ImpRespBW") + imprespwid = self.xmlhelp.load( + f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}ImpRespWid" + ) + with self.need( + f"Grid/{grid_dim} uniform weighted IPR width matches bandwidth" + ): + assert imprespwid == con.Approx(KAPFAC / imprespbw, rtol=1e-4) + + @per_grid_dim + def check_deltak_wrt_ss(self, grid_dim) -> None: + """DeltaK[12] must agree with SS.""" + dk1 = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}DeltaK1") + dk2 = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}DeltaK2") + ss = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}SS") + with self.need(f"{grid_dim} DeltaK2 >= DeltaK1"): + assert dk2 >= con.Approx(dk1) + with self.need(f"{grid_dim} DeltaKs must agree with SS"): + assert dk2 <= con.Approx(0.5 / ss) + assert dk1 >= con.Approx(-0.5 / ss) + + @per_grid_dim + def check_iprbw_to_deltak(self, grid_dim) -> None: + """ImpRespBW <= DeltaK2 - DeltaK1.""" + imprespbw = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}ImpRespBW") + dk1 = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}DeltaK1") + dk2 = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}DeltaK2") + with self.need(f"{grid_dim} ImpRespBW <= DeltaK2 - DeltaK1"): + assert imprespbw <= con.Approx(dk2 - dk1) + + @per_grid_dim + def check_iprbw_to_ss(self, grid_dim) -> None: + """Impulse Response BW is supported by sample spacing.""" + imprespbw = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}ImpRespBW") + ss = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}SS") + with self.need( + f"{grid_dim} Impulse Response BW is supported by sample spacing" + ): + assert imprespbw <= con.Approx(1.0 / ss) + + @per_grid_dim + def check_iprbw_to_ss_osr(self, grid_dim) -> None: + """Oversample ratio [1/(Grid//ImpRespBW * Grid//SS)] is between 1.1 and 2.2""" + imprespbw = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}ImpRespBW") + ss = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}SS") + osr = 1.0 / imprespbw / ss + with self.want(f"{grid_dim} OSR <= 2.2"): + assert osr <= con.Approx(2.2) + with self.want(f"{grid_dim} OSR >= 1.1"): + assert osr >= con.Approx(1.1) + + def _compute_deltaks_from_poly(self, direction, vertices): + """Computes DeltaK1 and DeltaK2 from other Grid information.""" + ipr_bw = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{direction}/{{*}}ImpRespBW") + dir_spacing = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{direction}/{{*}}SS") + + dkcoapoly = self.xmlhelp.load( + f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaKCOAPoly" + ) + if dkcoapoly is not None: + points = _grid_index_to_coord(self.xmlhelp, vertices) + + deltaks = npp.polyval2d(points[:, 0], points[:, 1], dkcoapoly) + min_dk = deltaks.min() + max_dk = deltaks.max() + else: + min_dk = 0 + max_dk = 0 + + dk1_comp = min_dk - (ipr_bw / 2.0) + dk2_comp = max_dk + (ipr_bw / 2.0) + + # Handle Wrapped spectrum + if dk1_comp < -0.5 / dir_spacing or dk2_comp > 0.5 / dir_spacing: + dk1_comp = -0.5 / dir_spacing + dk2_comp = -dk1_comp + + return dk1_comp, dk2_comp + + @per_grid_dim + def check_deltakpoly(self, grid_dim) -> None: + """DeltaKPoly matches DeltaK1.""" + vertices = _get_valid_data_vertices(self.xmlhelp) + dk1_comp, dk2_comp = self._compute_deltaks_from_poly(grid_dim, vertices) + + tolerance = 1e-2 + with self.need(f"{grid_dim} DeltaK1 matches computed value from the poly"): + assert self.xmlhelp.load( + f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}DeltaK1" + ) == con.Approx(dk1_comp, atol=tolerance) + with self.need(f"{grid_dim} DeltaK2 matches computed value from the poly"): + assert self.xmlhelp.load( + f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}DeltaK2" + ) == con.Approx(dk2_comp, atol=tolerance) + + def _compare_size_and_index(self, path_to_parent, rel_path_to_child): + """Helper method for making sure nodes with ``'index'`` attributes + are consistent with their parent's ``'size'``. + """ + parent = self.sicdroot.find(path_to_parent) + + indices = [int(node.get("index")) for node in parent.findall(rel_path_to_child)] + with self.need(f"All {rel_path_to_child} elements are present"): + assert not set(indices).symmetric_difference(range(1, len(indices) + 1)) + with self.need( + f"{path_to_parent} size attribute matches number of {rel_path_to_child}" + ): + assert int(parent.attrib["size"]) == len(indices) + + @per_grid_dim + def check_wgtfunct_indices(self, grid_dim) -> None: + """Checks consistency of the indices in the WgtFunct elements.""" + with self.precondition(): + assert ( + self.sicdroot.find( + f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}WgtFunct/{{*}}Wgt" + ) + is not None + ) + self._compare_size_and_index( + f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}WgtFunct", "./{*}Wgt" + ) + + def check_valid_ifa(self) -> None: + """ImageFormationAlgo must be paired with appropriate block.""" + with self.precondition(): + assert ( + algo := self.sicdroot.findtext("./{*}ImageFormation/{*}ImageFormAlgo") + ) != "OTHER" + with self.need("ImageFormationAlgo paired with appropriate block"): + if algo == "RGAZCOMP": + algo = "RgAzComp" + assert self.sicdroot.find("./{*}" + algo) is not None + + def check_pfa_grid_type(self) -> None: + """PFA has grid type of RGAZIM.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + with self.need("PFA grid type must be RGAZIM"): + assert self.sicdroot.find("./{*}Grid/{*}Type").text == "RGAZIM" + + def check_pfa_spot_kaz_to_grid(self) -> None: + """PFA Kaz within half of 1/Grid.Col.SS of KCtr.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + assert ( + self.sicdroot.find("./{*}CollectionInfo/{*}RadarMode/{*}ModeType").text + == "SPOTLIGHT" + ) + kaz1 = self.xmlhelp.load("./{*}PFA/{*}Kaz1") + kaz2 = self.xmlhelp.load("./{*}PFA/{*}Kaz2") + col_kctr = self.xmlhelp.load("./{*}Grid/{*}Col/{*}KCtr") + col_ss = self.xmlhelp.load("./{*}Grid/{*}Col/{*}SS") + with self.want("PFA Kaz1 within half of 1/Grid.Col.SS of KCtr"): + assert kaz1 - col_kctr >= con.Approx(-0.5 / col_ss) + with self.want("PFA Kaz2 within half of 1/Grid.Col.SS of KCtr"): + assert kaz2 - col_kctr <= con.Approx(0.5 / col_ss) + + def check_pfa_krg_to_grid(self) -> None: + """PFA Krg within half of 1/Grid.Row.SS of KCtr.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + krg1 = self.xmlhelp.load("./{*}PFA/{*}Krg1") + krg2 = self.xmlhelp.load("./{*}PFA/{*}Krg2") + row_kctr = self.xmlhelp.load("./{*}Grid/{*}Row/{*}KCtr") + row_ss = self.xmlhelp.load("./{*}Grid/{*}Row/{*}SS") + with self.want("PFA Krg1 within half of 1/Grid.Row.SS of KCtr"): + assert krg1 - row_kctr >= con.Approx(-0.5 / row_ss) + with self.want("PFA Krg2 within half of 1/Grid.Row.SS of KCtr"): + assert krg2 - row_kctr <= con.Approx(0.5 / row_ss) + + @per_grid_dim + def check_pfa_ipr_bw(self, grid_dim) -> None: + """IPR bandwidth supported by PFA spatial frequency extent.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + imprespbw = self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}ImpRespBW") + kpar = {"Row": "Krg", "Col": "Kaz"}[grid_dim] + k1 = self.xmlhelp.load(f"./{{*}}PFA/{{*}}{kpar}1") + k2 = self.xmlhelp.load(f"./{{*}}PFA/{{*}}{kpar}2") + with self.need(f"{grid_dim} IPR bandwidth supported by {kpar}"): + assert imprespbw <= con.Approx(k2 - k1) + + def check_pfa_stds_kcoa(self) -> None: + """Checks that the PFA/STDeskew/STDSPhasePoly is nominally correct.""" + stds_poly = self.xmlhelp.load("./{*}PFA/{*}STDeskew/{*}STDSPhasePoly") + delta_krow_poly = self.xmlhelp.load("./{*}Grid/{*}Row/{*}DeltaKCOAPoly") + delta_kcol_poly = self.xmlhelp.load("./{*}Grid/{*}Col/{*}DeltaKCOAPoly") + with self.precondition(): + assert stds_poly is not None + assert delta_krow_poly is not None + assert delta_kcol_poly is not None + grid = _sample_valid_pixels(self.xmlhelp) + image_coords = _grid_index_to_coord(self.xmlhelp, grid) + row_bw = self.xmlhelp.load("./{*}Grid/{*}Row/{*}ImpRespBW") + col_bw = self.xmlhelp.load("./{*}Grid/{*}Col/{*}ImpRespBW") + sgn = self.xmlhelp.load("./{*}Grid/{*}Row/{*}Sgn") + + if self.xmlhelp.load("./{*}PFA/{*}STDeskew/{*}Applied"): + with self.want( + "Col/DeltaKCOAPoly gives nearly zero when Deskew is applied" + ): + assert npp.polyval2d( + image_coords[..., 0], image_coords[..., 1], delta_kcol_poly + ) == con.Approx(0.0, atol=col_bw * 1e-3) + with self.want("STDS derived DeltaKrow matches Row/DeltaKCOAPoly"): + delta_krow_poly_stds = -sgn * npp.polyder(stds_poly, axis=0) + assert npp.polyval2d( + image_coords[..., 0], image_coords[..., 1], delta_krow_poly + ) == con.Approx( + npp.polyval2d( + image_coords[..., 0], + image_coords[..., 1], + delta_krow_poly_stds, + ), + atol=row_bw * 1e-3, + ) + else: + with self.want( + "Row/DeltaKCOAPoly gives nearly zero when Deskew is not applied" + ): + assert npp.polyval2d( + image_coords[..., 0], image_coords[..., 1], delta_krow_poly + ) == con.Approx(0.0, atol=row_bw * 1e-3) + with self.want("STDS derived DeltaKcol matches Col/DeltaKCOAPoly"): + delta_kcol_poly_stds = sgn * npp.polyder(stds_poly, axis=1) + assert npp.polyval2d( + image_coords[..., 0], image_coords[..., 1], delta_kcol_poly + ) == con.Approx( + npp.polyval2d( + image_coords[..., 0], + image_coords[..., 1], + delta_kcol_poly_stds, + ), + atol=col_bw * 1e-3, + ) + + def check_pfa_polar_ang_poly(self) -> None: + """Polar angle polynomial evaluates to 0 at reference time.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + polar_ang_poly = self.xmlhelp.load("./{*}PFA/{*}PolarAngPoly") + polar_ang_ref_time = self.xmlhelp.load("./{*}PFA/{*}PolarAngRefTime") + polar_angle_ref = npp.polyval(polar_ang_ref_time, polar_ang_poly) + with self.need("Polar angle reference is zero at the reference time"): + assert polar_angle_ref == con.Approx(0.0, atol=1e-4) + + def check_scp_ecf_llh(self) -> None: + """SCP ECF and LLH positions match.""" + computed_ecf = sarkit.wgs84.geodetic_to_cartesian( + self.xmlhelp.load("./{*}GeoData/{*}SCP/{*}LLH") + ) + scp_ecf = self.xmlhelp.load("./{*}GeoData/{*}SCP/{*}ECF") + diff = npl.norm(scp_ecf - computed_ecf) + with self.need("SCP ECF and LLH positions match"): + assert diff <= con.Approx(1) + + def check_image_corners(self) -> None: + """Checks that the image corner points (ICPs) are nominally correct.""" + icp_ll = self.xmlhelp.load("./{*}GeoData/{*}ImageCorners") + with self.need("Number of ICP is four"): + assert len(icp_ll) == 4 + + scp_ecf = self.xmlhelp.load("./{*}GeoData/{*}SCP/{*}ECF") + scp_height = self.xmlhelp.load("./{*}GeoData/{*}SCP/{*}LLH/{*}HAE") + + nrows = self.xmlhelp.load("./{*}ImageData/{*}NumRows") + ncols = self.xmlhelp.load("./{*}ImageData/{*}NumCols") + row = self.xmlhelp.load("./{*}ImageData/{*}FirstRow") + np.asarray( + [0, 0, nrows - 1, nrows - 1] + ) + col = self.xmlhelp.load("./{*}ImageData/{*}FirstCol") + np.asarray( + [0, ncols - 1, ncols - 1, 0] + ) + icp_coords = _grid_index_to_coord(self.xmlhelp, np.stack([row, col], axis=-1)) + icp_converted_ecef = sarkit.wgs84.geodetic_to_cartesian( + np.concatenate((icp_ll, np.full((len(icp_ll), 1), scp_height)), axis=1) + ) + urow_gnd, ucol_gnd = _uvecs_in_ground(self.xmlhelp) + icp_computed_ecef = ( + scp_ecf + urow_gnd * icp_coords[..., :1] + ucol_gnd * icp_coords[..., 1:2] + ) + chords = itertools.combinations(icp_converted_ecef, 2) + max_chord_length = max(np.linalg.norm(chord[1] - chord[0]) for chord in chords) + for index, (icp_reported, icp_predicted) in enumerate( + zip(icp_converted_ecef, icp_computed_ecef) + ): + icp_dist = np.linalg.norm(icp_predicted - icp_reported) + with self.want( + f"ICP{index + 1} must be consistent with with GeoData/SCP" + " and Grid unit vectors" + ): + assert icp_dist < 0.05 * max_chord_length + + def check_amptable(self) -> None: + """AmpTable of correct size with accurate Amplitude indices.""" + with self.precondition(): + assert self.sicdroot.find("./{*}ImageData/{*}AmpTable") is not None + # Though checked by the schema in v1.4.0 and later, added here for pre v1.4.0 completeness + with self.need("AmpTable size is 256"): + assert ( + self.sicdroot.find("./{*}ImageData/{*}AmpTable").get("size") + == "256" + ) + + amp_indices = [ + int(amp.get("index")) + for amp in self.sicdroot.findall( + "./{*}ImageData/{*}AmpTable/{*}Amplitude" + ) + ] + + with self.need("AmpTable indexed 0 to 255"): + assert np.array_equal(np.sort(amp_indices), np.arange(256)) + + def check_geoinfo_line(self) -> None: + """Checks that GeoInfo/Line has a size attribute and segments have the index attribute.""" + geoinfo_lines = self.sicdroot.findall(".//{*}GeoInfo/{*}Line") + with self.precondition(): + assert geoinfo_lines + for elem in geoinfo_lines: + self._compare_size_and_index( + elem.getroottree().getelementpath(elem), "./{*}Endpoint" + ) + + # Though checked by the schema in v1.4.0 and later, added here for pre v1.4.0 completeness + num_endpoints = len(elem.findall("{*}Endpoint")) + with self.need("Number of Endpoints >= 2"): + assert num_endpoints >= 2 + + def check_geoinfo_polygon(self) -> None: + """Checks that GeoInfo/Polygon has a size attribute and segments have the index attribute.""" + geoinfo_polygons = self.sicdroot.findall(".//{*}GeoInfo/{*}Polygon") + with self.precondition(): + assert geoinfo_polygons + for elem in geoinfo_polygons: + self._compare_size_and_index( + elem.getroottree().getelementpath(elem), "./{*}Vertex" + ) + + # Though checked by the schema in v1.4.0 and later, added here for pre v1.4.0 completeness + num_vertices = len(elem.findall("{*}Vertex")) + with self.need("Number of vertices >= 3"): + assert num_vertices >= 3 + + def check_validdata_presence(self) -> None: + """ValidData should be in both GeoData and ImageData or neither.""" + in_geodata = self.sicdroot.find("./{*}GeoData/{*}ValidData") is not None + in_imagedata = self.sicdroot.find("./{*}ImageData/{*}ValidData") is not None + with self.need("ValidData in both GeoData and ImageData or neither"): + assert in_geodata == in_imagedata + + def check_imagedata_validdata(self): + """ImageData/ValidData polygon is valid, simple, and clockwise.""" + valid_data_poly_elem = self.sicdroot.find("{*}ImageData/{*}ValidData") + with self.precondition(): + assert valid_data_poly_elem is not None + self._need_valid_polygon(valid_data_poly_elem) + + def check_validdata_first_vertex(self) -> None: + """First ValidData Vertex should be min row -> min col.""" + vertices = _get_valid_data_vertices(self.xmlhelp) + row = [vertex[0] for vertex in vertices] + col = [vertex[1] for vertex in vertices if vertex[0] == min(row)] + with self.need("First ValidData Vertex is min row -> min col"): + assert np.array_equal( + (min(row), min(col)), (vertices[0][0], vertices[0][1]) + ) + + def check_validdata_bounds(self) -> None: + """ValidData vertices contained within FullImage""" + vertices = _get_valid_data_vertices(self.xmlhelp) + nrows = self.xmlhelp.load("./{*}ImageData/{*}FullImage/{*}NumRows") + ncols = self.xmlhelp.load("./{*}ImageData/{*}FullImage/{*}NumCols") + with self.want("ValidData vertices contained within FullImage"): + pad = 1 + assert np.all(vertices >= (-pad, -pad)) + assert np.all(vertices <= (nrows + pad, ncols + pad)) + + def _away_from_earth(self, vector): + """Helper to check if a vector points away from earth.""" + scp_llh = self.xmlhelp.load("./{*}GeoData/{*}SCP/{*}LLH") + local_up = sarkit.wgs84.up(scp_llh) + + with self.need("Vector points away from earth"): + assert np.dot(local_up, vector) > con.Approx(0) + + def check_grid_normal_away_from_earth(self) -> None: + """ "Normal to Grid unit vectors points away from earth.""" + self._away_from_earth( + np.cross( + self.xmlhelp.load("./{*}Grid/{*}Row/{*}UVectECF"), + self.xmlhelp.load("./{*}Grid/{*}Col/{*}UVectECF"), + ) + ) + + def check_grid_shadows_downward(self) -> None: + """Grid should indicate that shadows are downward. Taken to mean more downward than leftward or rightward.""" + row_uvect = self.xmlhelp.load("./{*}Grid/{*}Row/{*}UVectECF") + col_uvect = self.xmlhelp.load("./{*}Grid/{*}Col/{*}UVectECF") + los_to_scp = self.xmlhelp.load( + "./{*}GeoData/{*}SCP/{*}ECF" + ) - self.xmlhelp.load("./{*}SCPCOA/{*}ARPPos") + with self.need("Grid indicates that shadows are downward"): + assert np.dot(row_uvect, los_to_scp) > np.abs(np.dot(col_uvect, los_to_scp)) + + @per_grid_dim + def check_grid_unit_vector(self, grid_dim) -> None: + """Unit vector must have unit magnitude.""" + with self.need(f"{grid_dim} unit vector have unit magnitude"): + assert npl.norm( + self.xmlhelp.load(f"./{{*}}Grid/{{*}}{grid_dim}/{{*}}UVectECF") + ) == con.Approx(1.0) + + def check_grid_uvect_orthogonal(self) -> None: + """Checks the grid unit vectors are orthogonal to within 1 milliradian.""" + row_uvect = _unit(self.xmlhelp.load("./{*}Grid/{*}Row/{*}UVectECF")) + col_uvect = _unit(self.xmlhelp.load("./{*}Grid/{*}Col/{*}UVectECF")) + with self.want("Grid unit vectors are orthogonal"): + assert np.dot(row_uvect, col_uvect) == con.Approx(0.0, atol=np.sin(1.0e-3)) + + def check_pfa_fpn_away_from_earth(self) -> None: + """FPN points away from Earth.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + fpn = self.xmlhelp.load("./{*}PFA/{*}FPN") + self._away_from_earth(fpn) + + def check_pfa_ipn_away_from_earth(self) -> None: + """IPN points away from Earth.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + ipn = self.xmlhelp.load("./{*}PFA/{*}IPN") + self._away_from_earth(ipn) + + def check_pfa_ipn_with_grid(self) -> None: + """PFA IPN is normal to grid.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + ipn = self.xmlhelp.load("./{*}PFA/{*}IPN") + unit_ipn = _unit(ipn) + + computed_ipn = _unit( + np.cross( + self.xmlhelp.load("./{*}Grid/{*}Row/{*}UVectECF"), + self.xmlhelp.load("./{*}Grid/{*}Col/{*}UVectECF"), + ) + ) + + with self.need("PFA IPN is consistent with the Grid"): + assert np.dot(unit_ipn, computed_ipn) == con.Approx(1.0) + + def check_pfa_proc_freq(self) -> None: + """Processed Frequency matches PFA inscription.""" + with self.precondition(): + assert self.sicdroot.find("./{*}PFA") is not None + min_fx, max_fx = _compute_pfa_min_max_fx(self.xmlhelp) + + min_proc = self.xmlhelp.load( + "./{*}ImageFormation/{*}TxFrequencyProc/{*}MinProc" + ) + max_proc = self.xmlhelp.load( + "./{*}ImageFormation/{*}TxFrequencyProc/{*}MaxProc" + ) + + bw_tolerance = 0.1 * (max_proc - min_proc) + with self.want("Minimum Fx should be >= MinProc frequency"): + assert min_fx >= con.Approx(min_proc, atol=bw_tolerance, rtol=1e-3) + with self.want("Maximum Fx should be <= MaxProc frequency"): + assert max_fx <= con.Approx(max_proc, atol=bw_tolerance, rtol=1e-3) + + def check_proc_freq(self) -> None: + """ImageFormation/TxFrequencyProc lies within RadarCollection/TxFrequency.""" + min_proc = self.xmlhelp.load( + "./{*}ImageFormation/{*}TxFrequencyProc/{*}MinProc" + ) + max_proc = self.xmlhelp.load( + "./{*}ImageFormation/{*}TxFrequencyProc/{*}MaxProc" + ) + min_coll = self.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Min") + max_coll = self.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Max") + + with self.want("Min processed frequency >= min collected frequency"): + assert min_proc >= con.Approx(min_coll) + with self.want("Max processed frequency <= max collected frequency"): + assert max_proc <= con.Approx(max_coll) + + with self.precondition(): + assert self.sicdroot.find("./{*}RadarCollection/{*}RefFreqIndex") is None + with self.need("Min collected frequency > 0.0"): + assert min_coll > 0.0 + with self.need("Max collected frequency > min collected"): + assert max_coll > con.Approx(min_coll) + with self.need("Max processed frequency > min processed"): + assert max_proc > con.Approx(min_proc) + + def check_inca(self) -> None: + """Checks that RMA/INCA parameters are consistent with other metadata.""" + inca = self.sicdroot.find("./{*}RMA/{*}INCA") + with self.precondition(): + assert inca is not None + time_ca_poly = self.xmlhelp.load("./{*}RMA/{*}INCA/{*}TimeCAPoly") + arp_poly = self.xmlhelp.load("./{*}Position/{*}ARPPoly") + scp_time_ca = npp.polyval(0.0, time_ca_poly) + arp_pos = npp.polyval(scp_time_ca, arp_poly) + arp_vel = npp.polyval(scp_time_ca, npp.polyder(arp_poly)) + scp_pos = self.xmlhelp.load("./{*}GeoData/{*}SCP/{*}ECF") + scp_range_ca = npl.norm(arp_pos - scp_pos) + los_arp_to_scp = scp_pos - arp_pos + along_track_error = np.abs(np.dot(los_arp_to_scp, _unit(arp_vel))) + grid = _sample_valid_pixels(self.xmlhelp) + coords = _grid_index_to_coord(self.xmlhelp, grid) + time_ca = npp.polyval(coords[..., 1], time_ca_poly) + ca_vel = 1.0 / np.abs( + npp.polyval(coords[..., 1], npp.polyder(time_ca_poly)) + ) + arp_speed_ca = npl.norm(npp.polyval(time_ca, npp.polyder(arp_poly)), axis=0) + drsf_poly = self.xmlhelp.load("./{*}RMA/{*}INCA/{*}DRateSFPoly") + drsf = npp.polyval2d(coords[..., 0], coords[..., 1], drsf_poly) + along_track_error_thresh = 2e-2 / self.xmlhelp.load( + "./{*}Grid/{*}Col/{*}ImpRespBW" + ) + with self.want("Along track error is relatively small"): + assert along_track_error <= con.Approx(along_track_error_thresh) + + r_ca_scp = self.xmlhelp.load("./{*}RMA/{*}INCA/{*}R_CA_SCP") + with self.want("Calculated SCP range ca matches the metadata"): + assert scp_range_ca == con.Approx(r_ca_scp) + + with self.want( + "Product of ARP speed and scale factor matches calculated ca_vel" + ): + assert arp_speed_ca * drsf == con.Approx(ca_vel, rtol=1e-2) + + def check_segmentlist_bounds(self) -> None: + """Checks that segments within the segment_list are bounded by the area plane.""" + + def bounded_by(segment, area): + return area.intersection(segment).equals(segment) + + plane = self.sicdroot.find("./{*}RadarCollection/{*}Area/{*}Plane") + with self.precondition(): + assert plane is not None + # create the line/sample polygon for the area plane + area_polygon = _create_rectangle( + int(plane.findtext("./{*}XDir/{*}FirstLine")), + int(plane.findtext("./{*}YDir/{*}FirstSample")), + int(plane.findtext("./{*}XDir/{*}NumLines")), + int(plane.findtext("./{*}YDir/{*}NumSamples")), + ) + + list_of_segs = plane.findall("./{*}SegmentList/{*}Segment") + with self.precondition(): + assert list_of_segs != [] + # create a polygon for each segment + for seg in list_of_segs: + segment_polygon = shg.box( + int(seg.findtext("{*}StartLine")), + int(seg.findtext("{*}StartSample")), + int(seg.findtext("{*}EndLine")), + int(seg.findtext("{*}EndSample")), + ccw=False, + ) + with self.need( + "All segments within the segment_list are bounded by the area plane" + ): + assert bounded_by(segment_polygon, area_polygon) + + def check_segment_identifier(self) -> None: + """Checks that segment identifier references a segment in the SegmentList.""" + # check if segment lists are included + segment_list = self.sicdroot.find( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}SegmentList" + ) + if segment_list is not None: + # then segment identifier must also be included + seg_id = self.sicdroot.findtext("./{*}ImageFormation/{*}SegmentIdentifier") + with self.need("SegmentIdentifier is included"): + assert seg_id is not None + + # and reference a segment within the list + with self.need("SegmentList has SegmentIdentifier"): + assert ( + segment_list.find(f'./{{*}}Segment[{{*}}Identifier="{seg_id}"]') + is not None + ) + else: + # segment list not present - segment identifier shouldn't be included + seg_id = self.sicdroot.findtext("./{*}ImageFormation/{*}SegmentIdentifier") + with self.need("SegmentIdentifier not present without SegmentList"): + assert seg_id is None + + def check_segmentlist_indices(self) -> None: + """Checks that SegmentList has a size attribute and segments have the index attribute.""" + with self.precondition(): + assert ( + self.sicdroot.find( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}SegmentList" + ) + is not None + ) + self._compare_size_and_index( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}SegmentList", "./{*}Segment" + ) + + def check_segment_unique_ids(self) -> None: + """Checks that identifiers in SegmentList are unique.""" + segment_list = self.sicdroot.find( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}SegmentList" + ) + with self.precondition(): + assert segment_list is not None + segment_ids = [ + segment_id.text + for segment_id in segment_list.findall("./{*}Segment/{*}Identifier") + ] + with self.need("SegmentList segments have unique identifiers"): + assert len(set(segment_ids)) == len(segment_ids) + + def _need_valid_polygon(self, polygon_node): + """Returns the polygon from the specified node, with basic polygon verification.""" + vertex_nodes = sorted(list(polygon_node), key=lambda x: int(x.attrib["index"])) + polygon = np.asarray( + [self.xmlhelp.load_elem(vertex) for vertex in vertex_nodes] + ) + root_path = _get_root_path(polygon_node) + with self.need(f"{root_path} indices are all present"): + assert [int(x.attrib["index"]) for x in vertex_nodes] == list( + range(1, len(vertex_nodes) + 1) + ) + size = int(polygon_node.attrib["size"]) + with self.need(f"{root_path} size attribute matches the number of vertices"): + assert size == len(vertex_nodes) + shg_polygon = shg.Polygon(polygon) + with self.need(f"{root_path} is simple"): + assert shg_polygon.is_simple + with self.need(f"{root_path} is clockwise"): + assert not shg_polygon.exterior.is_ccw + return polygon + + def check_segment_polygons(self) -> None: + """SegmentPolygons are simple, valid and clockwise.""" + segment_polygons = self.sicdroot.findall( + "{*}RadarCollection/{*}Area/{*}Plane/{*}SegmentList/{*}Segment/{*}SegmentPolygon" + ) + with self.precondition(): + assert segment_polygons + for segment_polygon in segment_polygons: + self._need_valid_polygon(segment_polygon) + + def check_area_plane_polygon(self) -> None: + """RadarCollection/Area/Plane/Polygon is simple, valid and clockwise.""" + area_plane_poly_elem = self.sicdroot.find( + "{*}RadarCollection/{*}Area/{*}Plane/{*}Polygon" + ) + with self.precondition(): + assert area_plane_poly_elem is not None + self._need_valid_polygon(area_plane_poly_elem) + + def _compute_area_plane_corners_ecef(self): + plane = self.sicdroot.find("./{*}RadarCollection/{*}Area/{*}Plane") + ref_ecf = self.xmlhelp.load_elem(plane.find("./{*}RefPt/{*}ECF")) + xdir = self.xmlhelp.load_elem(plane.find("./{*}XDir/{*}UVectECF")) + ydir = self.xmlhelp.load_elem(plane.find("./{*}YDir/{*}UVectECF")) + + # create the line/sample polygon for the area plane + ref_area_ls = _create_rectangle( + self.xmlhelp.load_elem(plane.find("./{*}XDir/{*}FirstLine")), + self.xmlhelp.load_elem(plane.find("./{*}YDir/{*}FirstSample")), + self.xmlhelp.load_elem(plane.find("./{*}XDir/{*}NumLines")), + self.xmlhelp.load_elem(plane.find("./{*}YDir/{*}NumSamples")), + ) + + # convert display index into area plane x, y coordinates + xy_coord = _display_index_to_coord( + self.xmlhelp, ref_area_ls.exterior.coords[:-1] + ) + + return ( + ref_ecf + + xy_coord[:, 0][:, np.newaxis] * xdir + + xy_coord[:, 1][:, np.newaxis] * ydir + ) + + def check_area_corners(self) -> None: + """Checks that area corners (ACPs) are nominally correct.""" + area = self.sicdroot.find("./{*}RadarCollection/{*}Area") + with self.precondition(): + assert area is not None + + indices = [ + int(acp.attrib["index"]) for acp in area.findall("./{*}Corner/{*}ACP") + ] + with self.need("ACPs must have 4 indices"): + assert np.array_equal(np.sort(indices), np.arange(1, 5)) + + acps_llh = self.xmlhelp.load_elem(area.find("./{*}Corner")) + acps_ecf = sarkit.wgs84.geodetic_to_cartesian(acps_llh) + u_east = sarkit.wgs84.east(acps_llh[1]) + u_north = sarkit.wgs84.north(acps_llh[1]) + + vertices = [ + (np.dot(v, u_east), np.dot(v, u_north)) + for v in acps_ecf - acps_ecf[0, :] + ] + ew_ring = shg.LinearRing(vertices) + with self.need("ACPs must be clockwise and simple"): + assert not ew_ring.is_ccw + assert ew_ring.is_simple + + area_plane = area.find("./{*}Plane") + with self.precondition(): + assert area_plane is not None + ref_pt = self.xmlhelp.load_elem(area_plane.find("./{*}RefPt/{*}ECF")) + + acps_ecf_computed = self._compute_area_plane_corners_ecef() + ref_pt_dist = npl.norm(acps_ecf - ref_pt) + with self.need("ACPs must be within the area plane"): + assert 0.1 * ref_pt_dist > con.Approx( + npl.norm(acps_ecf - acps_ecf_computed) + ) + + def check_area_plane_valid(self) -> None: + """Checks that area plane surface intersects with grid plane area of support.""" + plane = self.sicdroot.find("./{*}RadarCollection/{*}Area/{*}Plane") + with self.precondition(): + assert plane is not None + # compute scene center and slant plane normal + proj_metadata = sicdproj.MetadataParams.from_xml( + self.sicdroot.getroottree() + ) + spn = sicdproj.compute_scp_coa_slant_plane_normal(proj_metadata) + + # extract the reference plane + ref_ecf = self.xmlhelp.load_elem(plane.find("./{*}RefPt/{*}ECF")) + xdir = _unit(self.xmlhelp.load_elem(plane.find("./{*}XDir/{*}UVectECF"))) + ydir = _unit(self.xmlhelp.load_elem(plane.find("./{*}YDir/{*}UVectECF"))) + zdir = _unit(np.cross(xdir, ydir)) + + scp_ecf = self.xmlhelp.load("./{*}GeoData/{*}SCP/{*}ECF") + if np.abs(np.dot(scp_ecf - ref_ecf, zdir)) > 0.1: + gcp, _, success = sksicd.image_to_ground_plane( + self.sicdroot.getroottree(), [0, 0], ref_ecf, zdir + ) + assert success + u_proj = _unit(scp_ecf - gcp) + else: + u_proj = spn + + # project display coordinate into slant/grid plane + gpp = self._compute_area_plane_corners_ecef() + dist = np.dot(scp_ecf - gpp, spn) / np.dot(u_proj, spn) + ipp = gpp + dist[:, np.newaxis] * u_proj + + # convert into grid (xrow, ycol) coordinates + ipx = _unit(self.xmlhelp.load("./{*}Grid/{*}Row/{*}UVectECF")) + ipy = _unit(self.xmlhelp.load("./{*}Grid/{*}Col/{*}UVectECF")) + vertices_spxy = np.column_stack( + (np.dot(ipp - scp_ecf, ipx), np.dot(ipp - scp_ecf, ipy)) + ) + + # fetch the valid area and convert into grid (xrow, ycol) coordinates + grid = _get_valid_data_vertices(self.xmlhelp) + valid_area_spxy = _grid_index_to_coord(self.xmlhelp, grid) + with self.need("Area plane surface intersects with grid plane area"): + assert shg.Polygon(vertices_spxy).intersects( + shg.Polygon(valid_area_spxy) + ) + + def check_ipp_poly(self): + """Checks that the IPPPolys are nominally correct.""" + ipp_sets = self.sicdroot.findall("./{*}Timeline/{*}IPP/{*}Set") + with self.precondition(): + assert len(ipp_sets) > 0 + + isets = [] + for ipp_set in ipp_sets: + ipp_poly_node = ipp_set.find("./{*}IPPPoly") + iset = { + "t_start": float(ipp_set.findtext("./{*}TStart")), + "t_end": float(ipp_set.findtext("./{*}TEnd")), + "ipp_start": int(ipp_set.findtext("./{*}IPPStart")), + "ipp_end": int(ipp_set.findtext("./{*}IPPEnd")), + "ipp_poly": self.xmlhelp.load_elem(ipp_poly_node), + "index": int(ipp_set.get("index")), + } + with self.need("TEnd greater than TStart"): + assert iset["t_end"] > iset["t_start"] + with self.need("IPPEnd greater than IPPStart"): + assert iset["ipp_end"] > iset["ipp_start"] + with self.need( + "IPPStart is close to the polynomial evaluation at TStart" + ): + assert np.allclose( + iset["ipp_start"], + np.round(npp.polyval(iset["t_start"], iset["ipp_poly"])), + ) + with self.need("IPPEnd is close to the polynomial evaluation at TEnd"): + assert np.allclose( + iset["ipp_end"], + np.round(npp.polyval(iset["t_end"], iset["ipp_poly"]) - 1), + ) + isets.append(iset) + isets.sort(key=lambda x: x["index"]) + + t_starts = np.asarray([iset["t_start"] for iset in isets]) + min_time = np.min(t_starts) + t_ends = np.asarray([iset["t_end"] for iset in isets]) + max_time = np.max(t_ends) + # SICD Vol. 1 says "the IPP sequence spans the collection" which is impractical + # because the CollectStart may be before imaging occurs + t_start_proc = self.xmlhelp.load("./{*}ImageFormation/{*}TStartProc") + t_end_proc = self.xmlhelp.load("./{*}ImageFormation/{*}TEndProc") + with self.need("min(IPP.Set.TStart) <= TStartProc"): + assert min_time <= con.Approx(t_start_proc, atol=1e-2) + with self.need("max(IPP.Set.TEnd) >= TEndProc"): + assert max_time >= con.Approx(t_end_proc, atol=1e-2) + time_between = t_starts[1:] - t_ends[:-1] + with self.need("TStart values are increasing"): + assert np.array_equal(t_starts, sorted(t_starts)) + with self.need("TEnds values are increasing"): + assert np.array_equal(t_ends, sorted(t_ends)) + with self.need("No time gaps/overlap between IPP Sets"): + assert np.array_equal(time_between, [0] * time_between.size) + ipp_starts = np.asarray([iset["ipp_start"] for iset in isets]) + ipp_ends = np.asarray([iset["ipp_end"] for iset in isets]) + ipp_index_between = ipp_starts[1:] - ipp_ends[:-1] + with self.need("IPPStarts increase"): + assert np.array_equal(ipp_starts, sorted(ipp_starts)) + with self.need("IPPEnds increase"): + assert np.array_equal(ipp_ends, sorted(ipp_ends)) + with self.need("No IPP index gaps/overlap between IPP Sets"): + assert np.array_equal(ipp_index_between, [1] * ipp_index_between.size) + + def check_valid_data_indices(self) -> None: + """Checks consistency of the values in the ImageData child elements.""" + with self.precondition(): + assert self.sicdroot.find("./{*}ImageData/{*}ValidData") is not None + self._compare_size_and_index("./{*}ImageData/{*}ValidData", "./{*}Vertex") + + with self.precondition(): + assert self.sicdroot.find("./{*}GeoData/{*}ValidData") is not None + self._compare_size_and_index("./{*}GeoData/{*}ValidData", "./{*}Vertex") + + with self.precondition(): + assert self.sicdroot.find("./{*}ImageData/{*}ValidData") is not None + assert self.sicdroot.find("./{*}GeoData/{*}ValidData") is not None + + with self.need("GeoData size equal to ImageData size"): + image_validdata_size = self.sicdroot.find( + "./{*}ImageData/{*}ValidData" + ).get("size") + geo_validdata_size = self.sicdroot.find( + "./{*}GeoData/{*}ValidData" + ).get("size") + assert image_validdata_size == geo_validdata_size + + def check_icp_indices(self) -> None: + """Checks consistency of the indices in the GeoData ICP elements.""" + indices = sorted( + x.get("index") + for x in self.sicdroot.findall("./{*}GeoData/{*}ImageCorners/{*}ICP") + ) + with self.need("GeoData ICPs indexed correctly"): + assert indices == ["1:FRFC", "2:FRLC", "3:LRLC", "4:LRFC"] + + def check_collection_duration(self) -> None: + """Checks consistency of the collection duration in the Timeline element""" + with self.need("CollectionDuration > zero"): + assert self.xmlhelp.load("./{*}Timeline/{*}CollectDuration") > 0.0 + + def check_ipp_set_indices(self) -> None: + """Checks consistency of the indices in the Timeline IPP elements.""" + with self.precondition(): + assert self.sicdroot.find("./{*}Timeline/{*}IPP/{*}Set") is not None + self._compare_size_and_index("./{*}Timeline/{*}IPP", "./{*}Set") + + def check_waveform_params_indices(self) -> None: + """Checks consistency of the indices in the RadarCollection Waveform Parameter elements.""" + with self.precondition(): + assert ( + self.sicdroot.find("./{*}RadarCollection/{*}Waveform/{*}WFParameters") + is not None + ) + self._compare_size_and_index( + "./{*}RadarCollection/{*}Waveform", "./{*}WFParameters" + ) + + def check_waveform_params(self) -> None: + """Checks consistency of the values in the RadarCollection Waveform Parameter elements.""" + waveform = self.sicdroot.find("./{*}RadarCollection/{*}Waveform") + with self.precondition(): + assert waveform is not None + for wf_params in waveform.findall("./{*}WFParameters"): + for param in ( + "TxPulseLength", + "TxRFBandwidth", + "RcvWindowLength", + "ADCSampleRate", + "RcvIFBandwidth", + ): + node = wf_params.find(f"./{{*}}{param}") + with self.precondition(): + assert node is not None + with self.need(f"{param} > zero"): + assert float(node.text) > 0.0 + + node = wf_params.find("./{*}TxFMRate") + with self.precondition(): + assert node is not None + with self.need("TxFMRate not zero"): + assert float(node.text) != 0 + + def check_tx_polarization(self) -> None: + """Checks consistency of the RadarCollection/TxPolarization node.""" + tx_pol = self.sicdroot.find("./{*}RadarCollection/{*}TxPolarization").text + tx_seq_node = self.sicdroot.find("./{*}RadarCollection/{*}TxSequence") + with self.precondition(): + assert tx_pol == "SEQUENCE" + with self.want( + "RadarCollection TxSequence is not none if TxPolarization is SEQUENCE" + ): + assert tx_seq_node is not None + + def check_tx_rf_bandwidth(self) -> None: + """Checks consistency of the RadarCollection/Waveform/WFParameters/TxRFBandwidth values.""" + min_coll = self.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Min") + max_coll = self.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Max") + atol = max(0.1 * abs(max_coll - min_coll), 1e6) + for tx_rf_bandwidth_elem in self.sicdroot.findall( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters/{*}TxRFBandwidth" + ): + waveform_tx_bw = float(tx_rf_bandwidth_elem.text) + with self.need("Waveform TxBW must be within the collected BW"): + assert waveform_tx_bw <= con.Approx(max_coll - min_coll) + + for wf_parameters in self.sicdroot.findall( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters" + ): + with self.precondition(): + assert all( + wf_parameters.find(x) is not None + for x in ( + "./{*}TxPulseLength", + "./{*}TxRFBandwidth", + "./{*}TxFMRate", + ) + ) + tx_pulse_length = float(wf_parameters.findtext("./{*}TxPulseLength")) + tx_rf_bandwidth = float(wf_parameters.findtext("./{*}TxRFBandwidth")) + tx_fm_rate = float(wf_parameters.findtext("./{*}TxFMRate")) + if tx_fm_rate == 0: + continue + derived_bw = abs(tx_fm_rate * tx_pulse_length) + with self.want("Derived BW must be close to the TxRFBW"): + assert derived_bw == con.Approx(tx_rf_bandwidth, atol=atol, rtol=0) + + def check_tx_freq_start(self) -> None: + """Checks consistency of the RadarCollection/Waveform/WFParameters/TxFreqStart values.""" + min_coll = self.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Min") + max_coll = self.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Max") + atol = max(0.1 * abs(max_coll - min_coll), 1e6) + tx_freq_start_list = self.sicdroot.findall( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters/{*}TxFreqStart" + ) + with self.precondition(): + assert tx_freq_start_list != [] + for tx_freq_start_elem in tx_freq_start_list: + waveform_tx_freq_start = float(tx_freq_start_elem.text) + with self.need("Waveform TxFreqStart <= max collected frequency"): + assert waveform_tx_freq_start <= con.Approx(max_coll, atol=atol) + with self.need("Waveform TxFreqStart >= the min collected frequency"): + assert waveform_tx_freq_start >= con.Approx(min_coll, atol=atol) + + def check_tx_freq_bounds(self) -> None: + """Checks consistency of the frequency bounds implied by RadarCollection/Waveform/WFParameters values.""" + min_coll = self.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Min") + max_coll = self.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Max") + atol = max(0.1 * abs(max_coll - min_coll), 1e6) + wf_freq_bounds = [] + for wf_parameters in self.sicdroot.findall( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters" + ): + with self.precondition(): + assert all( + wf_parameters.find(x) is not None + for x in ("./{*}TxPulseLength", "./{*}TxFreqStart", "./{*}TxFMRate") + ) + tx_pulse_length = float(wf_parameters.findtext("./{*}TxPulseLength")) + tx_freq_start = float(wf_parameters.findtext("./{*}TxFreqStart")) + tx_fm_rate = float(wf_parameters.findtext("./{*}TxFMRate")) + tx_freq_end = tx_freq_start + tx_pulse_length * tx_fm_rate + wf_freq_bounds.extend([tx_freq_start, tx_freq_end]) + with self.need( + "Computed waveform end frequency <= max collected frequency" + ): + assert tx_freq_end <= con.Approx(max_coll) + with self.need( + "Computed waveform end frequency >= min collected frequency" + ): + assert tx_freq_end >= con.Approx(min_coll) + + with self.precondition(): + assert wf_freq_bounds + with self.want( + "WFParameters min frequency bounds close to min collected frequency" + ): + assert min(wf_freq_bounds) == con.Approx(min_coll, atol=atol, rtol=0) + with self.want( + "WFParameters max frequency bounds close to max collected frequency" + ): + assert max(wf_freq_bounds) == con.Approx(max_coll, atol=atol, rtol=0) + + def check_rcv_fmrate(self) -> None: + """Checks consistency of the receive FM rate for chirp/stretch demodulation types.""" + waveform = self.sicdroot.find("./{*}RadarCollection/{*}Waveform") + with self.precondition(): + assert waveform is not None + for wf_params in waveform.findall("./{*}WFParameters"): + demod = wf_params.find("./{*}RcvDemodType") + fmrate = wf_params.find("./{*}RcvFMRate") + with self.need( + "Consistent receive FM rate for chirp/stretch demodulation types" + ): + if demod is not None and fmrate is not None: + if demod.text == "CHIRP": + assert float(fmrate.text) == 0 + else: + assert float(fmrate.text) != 0 + + def check_rcv_channel_indices(self) -> None: + """Checks consistency of the values in the RadarCollection RcvChannels elements.""" + self._compare_size_and_index( + "./{*}RadarCollection/{*}RcvChannels", "./{*}ChanParameters" + ) + + def check_segment_start_and_end(self) -> None: + """Checks consistency of the values in the SegmentList StartLine and EndLine elements.""" + with self.precondition(): + assert ( + self.sicdroot.find( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}SegmentList/{*}Segment" + ) + is not None + ) + for node in self.sicdroot.iterfind( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}SegmentList/{*}Segment" + ): + with self.need("SegmentList EndLine >= StartLine"): + assert int(node.findtext("./{*}EndLine")) >= con.Approx( + int(node.findtext("./{*}StartLine")) + ) + with self.need("SegmentList EndSample >= StartSample"): + assert int(node.findtext("./{*}EndSample")) >= con.Approx( + int(node.findtext("./{*}StartSample")) + ) + + def check_image_formation_timeline(self) -> None: + """Checks that the slow time span for data processed to form the image is within collect.""" + t_start_proc = self.xmlhelp.load("./{*}ImageFormation/{*}TStartProc") + t_end_proc = self.xmlhelp.load("./{*}ImageFormation/{*}TEndProc") + collect_duration = self.xmlhelp.load("./{*}Timeline/{*}CollectDuration") + with self.need("0 <= TStartProc < TEndProc <= CollectDuration"): + assert 0 <= t_start_proc < t_end_proc <= collect_duration + + def check_scpcoa(self) -> None: + """Checks consistency of the values in the SCPCOA child elements.""" + newroot = copy.deepcopy(self.sicdroot) + newroot.replace( + newroot.find(".//{*}SCPCOA"), + sksicd.compute_scp_coa(self.sicdroot.getroottree()), + ) + expected_xmlhelp = sksicd.XmlHelper(newroot.getroottree()) + + def _compare_children(actual_parent, expected_parent): + with self.need(f"{actual_parent.tag} contains only expected elements"): + actual_names = [etree.QName(x).localname for x in actual_parent] + expected_names = [etree.QName(x).localname for x in expected_parent] + assert actual_names == expected_names + for actual, expected in zip( + actual_parent, expected_parent, strict=True + ): + param = etree.QName(actual).localname + assert param == etree.QName(expected).localname + if param in ("Bistatic", "TxPlatform", "RcvPlatform"): + _compare_children(actual, expected) + continue + actual_val = self.xmlhelp.load_elem(actual) + expected_val = expected_xmlhelp.load_elem(expected) + + approx_args = {} + if "Ang" in param: + approx_args["atol"] = 1 + elif "Time" in param: + approx_args["atol"] = 1e-6 + elif "Pos" in param: + approx_args["atol"] = 1e-2 + elif "Vel" in param: + approx_args["atol"] = 1e-3 + elif "Acc" in param: + approx_args["atol"] = 1e-4 + + with self.need(f"SCPCOA/{param} matches defined calculation"): + if param == "SideOfTrack": + assert actual_val == expected_val + else: + assert actual_val == con.Approx(expected_val, **approx_args) + + _compare_children( + self.xmlhelp.element_tree.find("./{*}SCPCOA"), + expected_xmlhelp.element_tree.find("./{*}SCPCOA"), + ) + + def check_antenna_oneway_apc(self) -> None: + """Checks that APC polys are provided when one way patterns are used""" + with self.precondition(): + assert self.sicdroot.find("./{*}Antenna/{*}Tx") is not None + with self.need("TxAPCPoly must be present when Antenna/Tx is present"): + assert self.sicdroot.find("./{*}Position/{*}TxAPCPoly") is not None + with self.precondition(): + assert self.sicdroot.find("./{*}Antenna/{*}Rcv") is not None + with self.need("RcvAPCPoly must be present when Antenna/Rcv is present"): + assert ( + self.sicdroot.find("./{*}Position/{*}RcvAPC/{*}RcvAPCPoly") + is not None + ) + + def check_antenna_array_gain_phase(self) -> None: + """Checks consistency of the gain/phase values in the Antenna Array elements.""" + for ant_param in ("Tx", "Rcv", "TwoWay"): + antenna = self.sicdroot.find(f"./{{*}}Antenna/{{*}}{ant_param}") + with self.precondition(): + assert antenna is not None + gain_poly = self.xmlhelp.load_elem( + antenna.find("./{*}Array/{*}GainPoly") + ) + with self.need( + f"Antenna {ant_param} gain poly constant is close to zero" + ): + assert gain_poly[0][0] == con.Approx(0.0) + + phase_poly = self.xmlhelp.load_elem( + antenna.find("./{*}Array/{*}PhasePoly") + ) + with self.need( + f"Antenna {ant_param} phase poly constant is close to zero" + ): + assert phase_poly[0][0] == con.Approx(0.0) + + def check_antenna_elem_gain_phase(self) -> None: + """Checks consistency of the gain/phase values in the Antenna Elem elements.""" + for ant_param in ("Tx", "Rcv", "TwoWay"): + antenna = self.sicdroot.find(f"./{{*}}Antenna/{{*}}{ant_param}/{{*}}Elem") + with self.precondition(): + assert antenna is not None + gain_poly = self.xmlhelp.load_elem(antenna.find("./{*}GainPoly")) + with self.need(f"{ant_param} elem gain poly constant is close to zero"): + assert gain_poly[0][0] == con.Approx(0.0) + + phase_poly = self.xmlhelp.load_elem(antenna.find("./{*}PhasePoly")) + with self.need( + f"{ant_param} elem phase poly constant is close to zero" + ): + assert phase_poly[0][0] == con.Approx(0.0) + + def check_antenna_bspoly_gain(self) -> None: + """Checks consistency of the values in the Antenna child elements.""" + for ant_param in ("Tx", "Rcv", "TwoWay"): + antenna = self.sicdroot.find( + f"./{{*}}Antenna/{{*}}{ant_param}/{{*}}GainBSPoly" + ) + with self.precondition(): + assert antenna is not None + gain_bs_poly = self.xmlhelp.load_elem(antenna) + with self.need( + f"Antenna {ant_param} gain BS poly constant is close to zero" + ): + assert gain_bs_poly[0] == con.Approx(0.0) + + def check_error_composite(self) -> None: + """Checks consistency of the values in the ErrorStatistics CompositeSCP elements.""" + composite = self.sicdroot.find("./{*}ErrorStatistics/{*}CompositeSCP") + with self.precondition(): + assert composite is not None + for param in ("Rg", "Az"): + with self.need(f"CompositeSCP {param} >= 0.0"): + assert float(composite.findtext(f"./{{*}}{param}")) >= con.Approx( + 0.0 + ) + + with self.need("CompositeSCP RgAz <= 1.0"): + rg_az = abs(float(composite.findtext("./{*}RgAz"))) + assert rg_az <= con.Approx(1.0) + + def check_error_components_posvel_stddev(self) -> None: + """Checks consistency of the values in the ErrorStatistics PosVelErr elements.""" + posvelerr = self.sicdroot.find( + "./{*}ErrorStatistics/{*}Components/{*}PosVelErr" + ) + with self.precondition(): + assert posvelerr is not None + for param in ("P1", "P2", "P3", "V1", "V2", "V3"): + with self.need(f"PosVelErr {param} >= 0.0"): + assert float(posvelerr.findtext("./{*}" + param)) >= con.Approx(0.0) + + def check_error_components_posvel_corr(self) -> None: + """Checks consistency of the values in the ErrorStatistics CorrCoefs elements.""" + corrcoefs = self.sicdroot.find( + "./{*}ErrorStatistics/{*}Components/{*}PosVelErr/{*}CorrCoefs" + ) + with self.precondition(): + assert corrcoefs is not None + for param in ( + "P1P2", + "P1P3", + "P1V1", + "P1V2", + "P1V3", + "P2P3", + "P2V1", + "P2V2", + "P2V3", + "P3V1", + "P3V2", + "P3V3", + "V1V2", + "V1V3", + "V2V3", + ): + with self.need(f"CorrCoefs {param} <= 1.0"): + corr_coef = abs(float(corrcoefs.findtext("./{*}" + param))) + assert corr_coef <= con.Approx(1.0) + + def check_error_radarsensor_rangebias(self) -> None: + """Checks consistency of the values in the ErrorStatistics RangeBias element.""" + components = self.sicdroot.find("./{*}ErrorStatistics/{*}Components") + with self.precondition(): + assert components is not None + with self.need("RangeBias >= 0.0"): + range_bias = float(components.findtext("./{*}RadarSensor/{*}RangeBias")) + assert range_bias >= con.Approx(0.0) + + def check_errorstatistics_conditionals(self) -> None: + """Presence of ErrorStatistics child elements is consistent with CollectType.""" + with self.precondition(): + this_ns = etree.QName(self.sicdroot).namespace + sicd_versions = list(sksicd.VERSION_INFO) + assert sicd_versions.index(this_ns) >= sicd_versions.index("urn:SICD:1.4.0") + is_bistatic = ( + self.sicdroot.findtext("{*}CollectionInfo/{*}CollectType") == "BISTATIC" + ) + coltype = "BISTATIC" if is_bistatic else "MONOSTATIC" + if is_bistatic: + forbidden_fields = ( + "{*}ErrorStatistics/{*}CompositeSCP", + "{*}ErrorStatistics/{*}Components", + "{*}ErrorStatistics/{*}AdjustableParameterOffsets", + ) + else: + forbidden_fields = ( + "{*}ErrorStatistics/{*}BistaticCompositeSCP", + "{*}ErrorStatistics/{*}BistaticComponents", + "{*}ErrorStatistics/{*}BistaticAdjustableParameterOffsets", + ) + for field in forbidden_fields: + with self.need( + f"{field.replace('{*}', '')} not allowed when CollectType={coltype}" + ): + assert self.sicdroot.find(field) is None + + def check_txsequence_indices(self) -> None: + """Checks consistency of the TxSequence/TxStep indexing.""" + with self.precondition(): + assert ( + self.sicdroot.find("./{*}RadarCollection/{*}TxSequence/{*}TxStep") + is not None + ) + self._compare_size_and_index( + "./{*}RadarCollection/{*}TxSequence", "./{*}TxStep" + ) + + def check_txsequence_waveform_index(self) -> None: + """Checks consistency of WFIndex""" + wfp_indices = [ + int(node.get("index")) + for node in self.sicdroot.findall( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters" + ) + ] + wf_index = [ + int(node.text) + for node in self.sicdroot.findall( + "./{*}RadarCollection/{*}TxSequence/{*}TxStep/{*}WFIndex" + ) + ] + with self.precondition(): + assert wfp_indices != [] + assert wf_index != [] + for index in wf_index: + with self.need( + f"WFIndex {index} must reference a WFParameters {wfp_indices}" + ): + assert index in wfp_indices + + def check_rcvapc_indices(self) -> None: + """Checks consistency of the RcvAPC indexing.""" + with self.precondition(): + assert ( + self.sicdroot.find("./{*}Position/{*}RcvAPC/{*}RcvAPCPoly") is not None + ) + self._compare_size_and_index("./{*}Position/{*}RcvAPC", "./{*}RcvAPCPoly") + + def check_rcvapcindex(self) -> None: + """Checks consistency of RcvAPCIndex.""" + rcvapc_indices = [ + int(node.get("index")) + for node in self.sicdroot.findall("./{*}Position/{*}RcvAPC/{*}RcvAPCPoly") + ] + rcvapcindex = [ + int(node.text) + for node in self.sicdroot.findall( + "./{*}RadarCollection/{*}RcvChannels/{*}ChanParameters/{*}RcvAPCIndex" + ) + ] + + for index in rcvapcindex: + with self.need( + f"RcvAPCIndex {index} must reference a RcvAPC {rcvapc_indices}" + ): + assert index in rcvapc_indices + + def check_chanindex(self) -> None: + """Checks consistency of ChanIndex.""" + cp_indices = [ + int(node.get("index")) + for node in self.sicdroot.findall( + "./{*}RadarCollection/{*}RcvChannels/{*}ChanParameters" + ) + ] + chanindex = [ + int(node.text) + for node in self.sicdroot.findall( + "./{*}ImageFormation/{*}RcvChanProc/{*}ChanIndex" + ) + ] + for index in chanindex: + with self.need( + f"ChanIndex {index} must reference a ChanParameters {cp_indices}" + ): + assert index in cp_indices + + def check_grid_polys(self) -> None: + """Checks consistency of all Grid polynomials.""" + poly_node = self.sicdroot.find("./{*}Grid/{*}TimeCOAPoly") + self._assert_poly_2d(poly_node, "TimeCOAPoly") + + for dir in ["Row", "Col"]: + poly_node = self.sicdroot.find(f"./{{*}}Grid/{{*}}{dir}/{{*}}DeltaKCOAPoly") + with self.precondition(): + assert poly_node is not None + self._assert_poly_2d(poly_node, f"{dir}/{{*}}DeltaKCOAPoly") + + def check_timeline_polys(self) -> None: + """Checks consistency of all Timeline polynomials.""" + ipp_sets = self.sicdroot.findall("./{*}Timeline/{*}IPP/{*}Set") + with self.precondition(): + assert ipp_sets is not None + for ipp_set in ipp_sets: + idx = ipp_set.attrib["index"] + ipp_poly_node = ipp_set.find("./{*}IPPPoly") + self._assert_poly_1d(ipp_poly_node, f"IPPPoly[{idx}]") + + def check_position_polys(self) -> None: + """Checks consistency of all Position polynomials.""" + poly_node = self.sicdroot.find("./{*}Position/{*}ARPPoly") + self._assert_poly_xyz(poly_node, "ARPPoly") + + for poly in ["GRPPoly", "TxAPCPoly"]: + poly_node = self.sicdroot.find(f"./{{*}}Position/{{*}}{poly}") + with self.precondition(): + assert poly_node is not None + self._assert_poly_xyz(poly_node, poly) + + rcv_apc_node = self.sicdroot.find("./{*}Position/{*}RcvAPC") + with self.precondition(): + assert rcv_apc_node is not None + rcvapc_poly_nodes = rcv_apc_node.findall("./{*}RcvAPCPoly") + for rcvapc_poly in rcvapc_poly_nodes: + idx = rcvapc_poly.attrib["index"] + self._assert_poly_xyz(rcvapc_poly, f"RcvAPCPoly[{idx}]") + + def check_radiometric_polys(self) -> None: + """Checks consistency of all Radiometric polynomials.""" + for poly in [ + "NoiseLevel/{*}NoisePoly", + "RCSSFPoly", + "SigmaZeroSFPoly", + "BetaZeroSFPoly", + "GammaZeroSFPoly", + ]: + poly_node = self.sicdroot.find(f"./{{*}}Radiometric/{{*}}{poly}") + with self.precondition(): + assert poly_node is not None + self._assert_poly_2d(poly_node, poly) + + def check_antenna_polys(self) -> None: + """Checks consistency of all Antenna polynomials.""" + for ant in ["Tx", "Rcv", "TwoWay"]: + for poly in ["EB/{*}DCXPoly", "EB/{*}DCYPoly", "GainBSPoly"]: + poly_node = self.sicdroot.find(f"./{{*}}Antenna/{{*}}{ant}/{{*}}{poly}") + with self.precondition(): + assert poly_node is not None + self._assert_poly_1d(poly_node, poly) + + for poly in [ + "Array/{*}GainPoly", + "Array/{*}PhasePoly", + "Elem/{*}GainPoly", + "Elem/{*}PhasePoly", + ]: + poly_node = self.sicdroot.find(f"./{{*}}Antenna/{{*}}{ant}/{{*}}{poly}") + with self.precondition(): + assert poly_node is not None + self._assert_poly_2d(poly_node, poly) + + for poly in ["XAxisPoly", "YAxisPoly"]: + poly_node = self.sicdroot.find(f"./{{*}}Antenna/{{*}}{ant}/{{*}}{poly}") + with self.precondition(): + assert poly_node is not None + self._assert_poly_xyz(poly_node, poly) + + def check_rgazcomp_polys(self) -> None: + """Checks consistency of all RgAzComp polynomials.""" + poly_node = self.sicdroot.find("./{*}RgAzComp/{*}KazPoly") + with self.precondition(): + assert poly_node is not None + self._assert_poly_1d(poly_node, "RgAzComp/{*}KazPoly") + + def check_match_type(self) -> None: + """Checks MatchType consistent with NumMatchTypes.""" + with self.precondition(): + assert self.sicdroot.find("./{*}MatchInfo") is not None + num_match_types = self.xmlhelp.load("./{*}MatchInfo/{*}NumMatchTypes") + num_matchtype_nodes = len( + self.sicdroot.findall("./{*}MatchInfo/{*}MatchType") + ) + with self.need("Number of MatchType nodes matches NumMatchTypes"): + assert num_match_types == num_matchtype_nodes + + mt_indices = [ + int(mt.get("index")) + for mt in self.sicdroot.findall("./{*}MatchInfo/{*}MatchType") + ] + + with self.need("MatchType indexed 1 to NumMatchTypes"): + assert np.array_equal( + np.sort(mt_indices), np.arange(1, num_matchtype_nodes + 1) + ) + + def check_match_collection(self) -> None: + """Checks MatchCollection consistent with NumMatchCollections.""" + with self.precondition(): + assert self.sicdroot.find("./{*}MatchInfo/{*}MatchType") is not None + for match_type in self.sicdroot.findall("./{*}MatchInfo/{*}MatchType"): + num_match_collections = self.xmlhelp.load_elem( + match_type.find("./{*}NumMatchCollections") + ) + num_matchcollection_nodes = len( + match_type.findall("./{*}MatchCollection") + ) + with self.need( + "Number of MatchCollection nodes matches NumMatchCollections" + ): + assert num_match_collections == num_matchcollection_nodes + + mtc_indices = [ + int(mtc.get("index")) + for mtc in match_type.findall("./{*}MatchCollection") + ] + + with self.need("MatchCollection indexed 1 to NumMatchCollections"): + assert np.array_equal( + np.sort(mtc_indices), + np.arange(1, num_matchcollection_nodes + 1), + ) + + def check_pfa_polys(self) -> None: + """Checks consistency of all PFA polynomials.""" + for poly in ["PolarAngPoly", "SpatialFreqSFPoly"]: + poly_node = self.sicdroot.find(f"./{{*}}PFA/{{*}}{poly}") + with self.precondition(): + assert poly_node is not None + self._assert_poly_1d(poly_node, poly) + + poly_node = self.sicdroot.find("./{*}PFA/{*}STDeskew/{*}STDSPhasePoly") + with self.precondition(): + assert poly_node is not None + self._assert_poly_2d(poly_node, "STDSPhasePoly") + + def check_rma_inca_polys(self) -> None: + """Checks consistency of all RMA/INCA polynomials.""" + poly_node = self.sicdroot.find("./{*}RMA/{*}INCA/{*}TimeCAPoly") + with self.precondition(): + assert poly_node is not None + self._assert_poly_1d(poly_node, "RMA/{*}INCA/{*}TimeCAPoly") + + for poly in ["DRateSFPoly", "DopCentroidPoly"]: + poly_node = self.sicdroot.find(f"./{{*}}RMA/{{*}}INCA/{{*}}{poly}") + with self.precondition(): + assert poly_node is not None + self._assert_poly_2d(poly_node, poly) + + +# Improve rendered docstring +con.modify_conchecker_docs(SicdConsistency) diff --git a/tests/core/sicd/test_io.py b/tests/core/sicd/test_io.py index bc8e500..d081efc 100644 --- a/tests/core/sicd/test_io.py +++ b/tests/core/sicd/test_io.py @@ -33,6 +33,7 @@ def _random_image(sicd_xmltree): @pytest.mark.parametrize( "sicd_xml,pixel_type", [ + (DATAPATH / "example-sicd-1.0.1.xml", "RE32F_IM32F"), (DATAPATH / "example-sicd-1.1.0.xml", "RE32F_IM32F"), (DATAPATH / "example-sicd-1.2.1.xml", "RE16I_IM16I"), (DATAPATH / "example-sicd-1.3.0.xml", "AMP8I_PHS8I"), diff --git a/tests/verification/test_sicd_consistency.pySAV b/tests/verification/test_sicd_consistency.pySAV new file mode 100644 index 0000000..1f3b8ed --- /dev/null +++ b/tests/verification/test_sicd_consistency.pySAV @@ -0,0 +1,2079 @@ +import copy +import pathlib +import unittest.mock + +import jbpy +import lxml.builder +import numpy as np +import pytest +from lxml import etree + +import sarkit.sicd as sksicd +import sarkit.verification._sicdcheck +import tests.utils +from sarkit.verification._sicd_consistency import SicdConsistency +from sarkit.verification._sicdcheck import main + +from . import testing + +DATAPATH = pathlib.Path(__file__).parents[2] / "data" + +good_sicd_xml_path = DATAPATH / "example-sicd-1.2.1.xml" + + +@pytest.fixture(scope="session") +def example_sicd_file(example_sicd): + assert not main([str(example_sicd)]) + with example_sicd.open("rb") as f: + yield f + + +@pytest.fixture(scope="module") +def good_xml(): + return etree.parse(good_sicd_xml_path) + + +@pytest.fixture +def sicd_con(good_xml): + return SicdConsistency.from_parts(copy.deepcopy(good_xml)) + + +@pytest.fixture +def em(sicd_con): + return lxml.builder.ElementMaker( + namespace=etree.QName(sicd_con.sicdroot).namespace, + nsmap=sicd_con.sicdroot.nsmap, + ) + + +def test_from_file_sicd(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + assert isinstance(sicdcon, SicdConsistency) + sicdcon.check() + assert len(sicdcon.failures()) == 0 + + +def test_from_file_xml(): + sicdcon = SicdConsistency.from_file(str(good_sicd_xml_path)) + assert isinstance(sicdcon, SicdConsistency) + sicdcon.check() + assert len(sicdcon.failures()) == 0 + + +def test_no_optional(): + """Make sure SicdConsistency does not rely on optional fields""" + + xmltree = etree.parse(good_sicd_xml_path) + assert xmltree.findtext("./{*}CollectionInfo/{*}CollectType") != "BISTATIC" + optional = [ + "./{*}CollectionInfo/{*}IlluminatorName", + "./{*}CollectionInfo/{*}CollectType", + "./{*}CollectionInfo/{*}RadarMode/{*}ModeID", + "./{*}CollectionInfo/{*}InformationSecurityMarking", + "./{*}CollectionInfo/{*}CountryCode", + "./{*}CollectionInfo/{*}Parameter", + "./{*}ImageCreation", + "./{*}ImageData/{*}AmpTable", + "./{*}ImageData/{*}ValidData", + "./{*}GeoData/{*}ValidData", + "./{*}GeoData/{*}GeoInfo", + "./{*}Grid/{*}Row/{*}DeltaKCOAPoly", + "./{*}Grid/{*}Row/{*}WgtType", + "./{*}Grid/{*}Row/{*}WgtFunct", + "./{*}Grid/{*}Col/{*}DeltaKCOAPoly", + "./{*}Grid/{*}Col/{*}WgtType", + "./{*}Grid/{*}Col/{*}WgtFunct", + "./{*}Timeline/{*}IPP", + "./{*}Position/{*}GRPPoly", + "./{*}Position/{*}TxAPCPoly", + "./{*}Position/{*}RcvAPC", + "./{*}RadarCollection/{*}RefFreqIndex", + "./{*}RadarCollection/{*}Waveform", + "./{*}RadarCollection/{*}TxSequence", + "./{*}RadarCollection/{*}RcvChannels/{*}ChanParameters/{*}RcvAPCIndex", + "./{*}RadarCollection/{*}Area", + "./{*}RadarCollection/{*}Parameter", + "./{*}ImageFormation/{*}RcvChanProc/{*}PRFScaleFactor", + "./{*}ImageFormation/{*}SegmentIdentifier", + "./{*}ImageFormation/{*}Processing", + "./{*}ImageFormation/{*}PolarizationCalibration", + "./{*}Radiometric", + "./{*}Antenna", + "./{*}ErrorStatistics", + "./{*}MatchInfo", + ] + for path in optional: + for node in xmltree.findall(path): + node.getparent().remove(node) + + sicdcon = SicdConsistency.from_parts(xmltree) + sicdcon.check() + assert len(sicdcon.failures()) == 0 + + +@pytest.mark.parametrize( + "file", + [ + good_sicd_xml_path, + ] + + list(DATAPATH.glob("example-sicd*.xml")), +) +def test_main(file): + assert not main([str(file), "-vv"]) + + +@pytest.mark.parametrize("xml_file", (DATAPATH / "syntax_only/sicd").glob("*.xml")) +def test_smoketest(xml_file): + main([str(xml_file)]) + + +def test_main_schema_override(): + good_schema = sksicd.VERSION_INFO["urn:SICD:1.2.1"]["schema"] + assert not main( + [str(good_sicd_xml_path), "--schema", str(good_schema)] + ) # pass with actual schema + assert main( + [ + str(good_sicd_xml_path), + "--schema", + str(good_sicd_xml_path), + ] + ) # fails with not schema + + +def _change_node(node, path, updated_val): + node.find(path).text = str(updated_val) + return node + + +def test_check_nitf_imseg_size_xtra_imseg(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + imsegs = sicdcon.ntf["ImageSegments"] + imsegs._append(imsegs[0]) + sicdcon.check("check_nitf_imseg_size") + testing.assert_failures(sicdcon, "Consistent number of image segments") + + +def test_check_nitf_imseg_size_mismatch_iloc(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + imsegs = sicdcon.ntf["ImageSegments"] + imsegs[0]["subheader"]["ILOC"].value = (10000, 10000) + sicdcon.check("check_nitf_imseg_size") + testing.assert_failures(sicdcon, "ILOC matches expected") + + +@pytest.mark.parametrize("dim", ["NROWS", "NCOLS"]) +def test_check_nitf_imseg_size_mismatch_dir(example_sicd_file, dim): + sicdcon = SicdConsistency.from_file(example_sicd_file) + imsegs = sicdcon.ntf["ImageSegments"] + imsegs[0]["subheader"][f"{dim}"].value = 10000 + sicdcon.check("check_nitf_imseg_size") + testing.assert_failures(sicdcon, f"Matching {dim}") + + +def test_check_nitf_imseg_lvls_idlvl(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + imsegs = sicdcon.ntf["ImageSegments"] + imsegs[0]["subheader"]["IDLVL"].value = 99 + sicdcon.check("check_nitf_imseg_lvls") + testing.assert_failures( + sicdcon, "Consistent NITF inter-Image Subheaders Display levels" + ) + + +def test_check_nitf_imseg_lvls_ialvl(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + imsegs = sicdcon.ntf["ImageSegments"] + imsegs[0]["subheader"]["IALVL"].value = 99 + sicdcon.check("check_nitf_imseg_lvls") + testing.assert_failures( + sicdcon, "Consistent NITF inter-Image Subheaders Attachment levels" + ) + + +def test_check_des_subheader_desid(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + des_header = sicdcon.ntf["DataExtensionSegments"][0]["subheader"] + des_header["DESID"].value = "CONTENT_DATA_XML" + + sicdcon.check("check_des_subheader") + testing.assert_failures(sicdcon, "DESID == XML_DATA_CONTENT") + + +def test_check_des_subheader_desshft(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + des_header = sicdcon.ntf["DataExtensionSegments"][0]["subheader"] + des_header["DESSHFT"].value = "LXM" + + sicdcon.check("check_des_subheader") + testing.assert_failures(sicdcon, "DESSHFT == XML") + + +def test_check_des_subheader_desshsi(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + des_header = sicdcon.ntf["DataExtensionSegments"][0]["subheader"] + des_header["DESSHSI"].value = "SICD Volume 20" + + sicdcon.check("check_des_subheader") + testing.assert_failures(sicdcon, "DESSHSI == SICD Volume 1...") + + +def test_check_des_subheader_desshtn(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + des_header = sicdcon.ntf["DataExtensionSegments"][0]["subheader"] + des_header["DESSHTN"].value = "urn:SICD:10.20.10" + + sicdcon.check("check_des_subheader") + testing.assert_failures(sicdcon, "Consistent namespace") + + +def test_check_des_subheader_desshlpg(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + des_header = sicdcon.ntf["DataExtensionSegments"][0]["subheader"] + des_header["DESSHLPG"].value = "badcorners" + + sicdcon.check("check_des_subheader") + testing.assert_failures(sicdcon, "DESSHLPG consistent with image corners") + + +def test_check_nitf_igeolo(example_sicd_file): + sicdcon = SicdConsistency.from_file(example_sicd_file) + corners = sicdcon.xmlhelp.load("./{*}GeoData/{*}ImageCorners") + corners[0] = [0, 0] + sicdcon.xmlhelp.set("./{*}GeoData/{*}ImageCorners", corners) + sicdcon.check("check_nitf_igeolo") + testing.assert_failures(sicdcon, "IGEOLO close to ICP Lon/Lat") + + +def _invalidate_1d_poly_coefs(node): + # append a duplicate entry. will fail checks: + # Exponents are unique + duplicate_coef = copy.deepcopy(node.find("./{*}Coef[last()]")) + node.append(duplicate_coef) + # add additional coefficient with exponent > order + new_coef = copy.deepcopy(duplicate_coef) + order = int(node.attrib["order1"]) + new_coef.attrib["exponent1"] = str(order + 1) + node.append(new_coef) + return node + + +def _invalidate_2d_poly_coefs(node): + # append a duplicate entry. will fail checks: + # Exponents are unique + duplicate_coef = copy.deepcopy(node.find("./{*}Coef[last()]")) + node.append(duplicate_coef) + # add additional coefficient with exponent > order + new_coef = copy.deepcopy(duplicate_coef) + order1 = int(node.attrib["order1"]) + order2 = int(node.attrib["order2"]) + new_coef.attrib["exponent1"] = str(order1 + 1) + new_coef.attrib["exponent2"] = str(order2 + 1) + node.append(new_coef) + return node + + +def _invalidate_xyz_poly_coefs(node): + for dim in ["X", "Y", "Z"]: + _invalidate_1d_poly_coefs(node.find(f"./{{*}}{dim}")) + + +def _tstart_greater_than_zero(xml): + _change_node(xml, "./{*}Timeline/{*}IPP/{*}Set/{*}TStart", 1) + + +def _tend_less_than_duration(xml): + duration = float(xml.find("./{*}Timeline/{*}CollectDuration").text) + xml.findall("./{*}Timeline/{*}IPP/{*}Set/{*}TEnd")[1].text = str(duration * 0.9) + + +def _tstart_greater_than_tend(xml): + _change_node(xml, "./{*}Timeline/{*}IPP/{*}Set/{*}TEnd", 0) + _change_node(xml, "./{*}Timeline/{*}IPP/{*}Set/{*}TStart", 1) + + +def _ippstart_greater_than_ippend(xml): + _change_node(xml, "./{*}Timeline/{*}IPP/{*}Set/{*}IPPEnd", 0) + _change_node(xml, "./{*}Timeline/{*}IPP/{*}Set/{*}IPPStart", 1) + + +def _increasing_tstart(xml): + ipp2_tstart = xml.findall("./{*}Timeline/{*}IPP/{*}Set/{*}TStart")[1].text + xml.findall("./{*}Timeline/{*}IPP/{*}Set/{*}TStart")[1].text = xml.findall( + "./{*}Timeline/{*}IPP/{*}Set/{*}TStart" + )[0].text + xml.findall("./{*}Timeline/{*}IPP/{*}Set/{*}TStart")[0].text = ipp2_tstart + + +def _increasing_tend(xml): + ipp2_tend = xml.findall("./{*}Timeline/{*}IPP/{*}Set/{*}TEnd")[1].text + xml.findall("./{*}Timeline/{*}IPP/{*}Set/{*}TEnd")[1].text = xml.findall( + "./{*}Timeline/{*}IPP/{*}Set/{*}TEnd" + )[0].text + xml.findall("./{*}Timeline/{*}IPP/{*}Set/{*}TEnd")[0].text = ipp2_tend + + +def _inconsistent_time_range(xml): + ipp2_tend = float(xml.findall("./{*}Timeline/{*}IPP/{*}Set/{*}TEnd")[1].text) + _change_node(xml, "./{*}Timeline/{*}IPP/{*}Set/{*}TEnd", ipp2_tend * 2) + + +@pytest.mark.parametrize( + "invalidate_func", + [ + _tstart_greater_than_zero, + _tend_less_than_duration, + _tstart_greater_than_tend, + _ippstart_greater_than_ippend, + _increasing_tstart, + _increasing_tend, + _inconsistent_time_range, + ], +) +def test_ipp_poly(sicd_con, invalidate_func): + invalidate_func(sicd_con.sicdroot) + sicd_con.check("check_ipp_poly") + assert sicd_con.failures() + + +def _invalid_position(xml): + _change_node(xml, "./{*}SCPCOA/{*}ARPPos/{*}X", 0) + + +def _invalid_velocity(xml): + _change_node(xml, "./{*}SCPCOA/{*}ARPVel/{*}X", 0) + + +def _invalid_acceleration(xml): + _change_node(xml, "./{*}SCPCOA/{*}ARPAcc/{*}X", 0) + + +@pytest.mark.parametrize( + "invalidate_func", [_invalid_position, _invalid_velocity, _invalid_acceleration] +) +def test_eval_scpcoa_bad_pos(sicd_con, invalidate_func): + invalidate_func(sicd_con.sicdroot) + sicd_con.check("check_scpcoa") + assert sicd_con.failures() + + +def _remove_bistatic_params(con): + bistatic_scpcoa = con.sicdroot.find("./{*}SCPCOA/{*}Bistatic") + bistatic_scpcoa.getparent().remove(bistatic_scpcoa) + + +def _change_tx_apc_poly(con): + con.xmlhelp.set( + "./{*}Position/{*}TxAPCPoly", + -1 * con.xmlhelp.load("./{*}Position/{*}TxAPCPoly"), + ) + + +def _change_slant_range(con): + con.xmlhelp.set( + ".//{*}TxPlatform/{*}SlantRange", + 10 * con.xmlhelp.load(".//{*}TxPlatform/{*}SlantRange"), + ) + + +@pytest.mark.parametrize( + "invalidate_func", + [_remove_bistatic_params, _change_tx_apc_poly, _change_slant_range], +) +def test_check_scpcoa_bistatic(invalidate_func): + sicdcon = SicdConsistency.from_file(DATAPATH / "example-sicd-1.4.0.xml") + assert sicdcon.xmlhelp.load(".//{*}CollectType") == "BISTATIC" + invalidate_func(sicdcon) + sicdcon.check("check_scpcoa") + assert sicdcon.failures() + + +def test_pfa_fpn_away_from_earth(sicd_con): + sicd_con.xmlhelp.set( + "./{*}PFA/{*}FPN", -1 * sicd_con.xmlhelp.load("./{*}PFA/{*}FPN") + ) + sicd_con.check("check_pfa_fpn_away_from_earth") + assert sicd_con.failures() + + +def test_pfa_ipn_away_from_earth(sicd_con): + sicd_con.xmlhelp.set( + "./{*}PFA/{*}IPN", -1 * sicd_con.xmlhelp.load("./{*}PFA/{*}IPN") + ) + sicd_con.check("check_pfa_ipn_away_from_earth") + assert sicd_con.failures() + + +def test_pfa_ipn_with_grid(sicd_con): + sicd_con.xmlhelp.set( + "./{*}PFA/{*}IPN/{*}X", -1000.0 * sicd_con.xmlhelp.load("./{*}PFA/{*}IPN/{*}X") + ) + sicd_con.check("check_pfa_ipn_with_grid") + assert sicd_con.failures() + + +def test_pfa_proc_freq_min(sicd_con): + min_proc = sicd_con.xmlhelp.load( + "./{*}ImageFormation/{*}TxFrequencyProc/{*}MinProc" + ) + sicd_con.xmlhelp.set( + "./{*}ImageFormation/{*}TxFrequencyProc/{*}MinProc", 1000.0 * min_proc + ) + sicd_con.check("check_pfa_proc_freq") + assert sicd_con.failures() + + +def test_pfa_proc_freq_max(sicd_con): + sicd_con.xmlhelp.set("./{*}ImageFormation/{*}TxFrequencyProc/{*}MaxProc", 0.0) + sicd_con.check("check_pfa_proc_freq") + assert sicd_con.failures() + + +def test_pfa_polar_ang_poly(sicd_con): + sicd_con.xmlhelp.set("./{*}PFA/{*}PolarAngRefTime", 10.0) + sicd_con.check("check_pfa_polar_ang_poly") + assert sicd_con.failures() + + +def _invalid_num_apcs(xml): + last_corner = xml.find("./{*}RadarCollection/{*}Area/{*}Corner/{*}ACP[last()]") + last_corner.getparent().remove(last_corner) + + +def _ewrings_not_clockwise(xml): + corners = xml.findall("./{*}RadarCollection/{*}Area/{*}Corner/{*}ACP") + tmp = corners[1] + corners[1] = corners[3] + corners[3] = tmp + corners[1].attrib["index"] = "2" + corners[3].attrib["index"] = "4" + + +def _area_not_within_plane(xml): + _change_node(xml, "./{*}RadarCollection/{*}Area/{*}Plane/{*}RefPt/{*}ECF/{*}X", 0) + + +@pytest.mark.parametrize( + "invalidate_func", + [_invalid_num_apcs, _ewrings_not_clockwise, _area_not_within_plane], +) +def test_radarcollection_area_corners(sicd_con, invalidate_func): + invalidate_func(sicd_con.sicdroot) + sicd_con.check("check_area_corners") + assert sicd_con.failures() + + +def test_area_plane_valid_smoke(sicd_con): + sicd_con.check("check_area_plane_valid") + assert not sicd_con.failures() + + # Force the projection path and still PASS + sicd_con.xmlhelp.set( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}RefPt/{*}ECF", + np.array([6378138.0, 0.0, 0.0]), + ) + sicd_con.check("check_area_plane_valid") + assert not sicd_con.failures() + + # Force the projection path and FAIL + sicd_con.xmlhelp.set( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}RefPt/{*}ECF", + np.array([6378138.0, 25000.0, 0.0]), + ) + sicd_con.check("check_area_plane_valid") + assert sicd_con.failures() + + +def test_scp_ecf_llh(sicd_con): + _change_node(sicd_con.sicdroot, "./{*}GeoData/{*}SCP/{*}ECF/{*}X", 1) + sicd_con.check("check_scp_ecf_llh") + assert sicd_con.failures() + + +def _invalid_num_icps(xml): + last_corner = xml.find("./{*}GeoData/{*}ImageCorners/{*}ICP[last()]") + last_corner.getparent().remove(last_corner) + + +def _misaligned_image_corners(xml): + last_corner = xml.find("./{*}GeoData/{*}ImageCorners/{*}ICP[last()]") + latitude = float(last_corner.findtext("./{*}Lat")) + _change_node(last_corner, "./{*}Lat", -1.0 * latitude) + + +def _subimage_image_corners(xml): + xml.find("./{*}ImageData/{*}FirstRow").text = str( + int(xml.find("./{*}ImageData/{*}NumRows").text) // 2 + ) + + +@pytest.mark.parametrize( + "invalidate_func", + [_invalid_num_icps, _misaligned_image_corners, _subimage_image_corners], +) +def test_image_corners(sicd_con, invalidate_func): + invalidate_func(sicd_con.sicdroot) + sicd_con.check("check_image_corners") + assert sicd_con.failures() + + +def _tx_polarization_sequence_mismatch(xml): + _change_node(xml, "./{*}RadarCollection/{*}TxPolarization", "SEQUENCE") + + +@pytest.mark.parametrize( + "invalidate_func", + [ + _tx_polarization_sequence_mismatch, + ], +) +def test_tx_polarization(sicd_con, invalidate_func): + invalidate_func(sicd_con.sicdroot) + sicd_con.check("check_tx_polarization") + assert sicd_con.failures() + + +def test_grid_normal_away_from_earth(sicd_con): + sicd_con.xmlhelp.set( + "./{*}Grid/{*}Row/{*}UVectECF", + -1.0 * sicd_con.xmlhelp.load("./{*}Grid/{*}Row/{*}UVectECF"), + ) + sicd_con.check("check_grid_normal_away_from_earth") + assert sicd_con.failures() + + +def test_grid_shadows_downward(sicd_con): + for d in ("Row", "Col"): + sicd_con.xmlhelp.set( + f"./{{*}}Grid/{{*}}{d}/{{*}}UVectECF", + -1.0 * sicd_con.xmlhelp.load(f"./{{*}}Grid/{{*}}{d}/{{*}}UVectECF"), + ) + sicd_con.check("check_grid_shadows_downward") + assert sicd_con.failures() + + +def test_check_grid_sign(sicd_con): + col_sgn = sicd_con.xmlhelp.load("./{*}Grid/{*}Col/{*}Sgn") + sicd_con.xmlhelp.set("./{*}Grid/{*}Row/{*}Sgn", -col_sgn) + sicd_con.check("check_grid_sign") + testing.assert_failures(sicd_con, "Row and Col grid signs match") + + +def test_grid_uvect_orthogonal(sicd_con): + sicd_con.xmlhelp.set( + "./{*}Grid/{*}Row/{*}UVectECF", + sicd_con.xmlhelp.load("./{*}Grid/{*}Col/{*}UVectECF"), + ) + sicd_con.check("check_grid_uvect_orthogonal") + assert sicd_con.failures() + + +@pytest.mark.parametrize("direction", ["Row", "Col"]) +class TestGridNode: + def test_deltak1_mismatch_with_poly(self, direction, sicd_con): + _change_node( + sicd_con.sicdroot, f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK1", 10000 + ) + sicd_con.check(f"check_deltakpoly_{direction.lower()}") + assert sicd_con.failures() + + def test_deltak2_mismatch_with_poly(self, direction, sicd_con): + _change_node( + sicd_con.sicdroot, f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK2", 10000 + ) + sicd_con.check(f"check_deltakpoly_{direction.lower()}") + assert sicd_con.failures() + + def test_deltak1_mismatch_with_ss(self, direction, sicd_con): + dk1 = sicd_con.xmlhelp.load(f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK1") + _change_node( + sicd_con.sicdroot, f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK1", dk1 * 2 + ) + sicd_con.check(f"check_deltak_wrt_ss_{direction.lower()}") + testing.assert_failures(sicd_con, f"{direction} DeltaKs must agree with SS") + + def test_deltak2_mismatch_with_ss(self, direction, sicd_con): + _change_node( + sicd_con.sicdroot, f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK2", 10000 + ) + sicd_con.check(f"check_deltak_wrt_ss_{direction.lower()}") + testing.assert_failures(sicd_con, f"{direction} DeltaKs must agree with SS") + + def test_deltak1_mismatch_with_deltak2(self, direction, sicd_con): + dk1 = sicd_con.xmlhelp.load(f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK1") + dk2 = sicd_con.xmlhelp.load(f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK2") + _change_node( + sicd_con.sicdroot, f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK1", dk2 + ) + _change_node( + sicd_con.sicdroot, f"./{{*}}Grid/{{*}}{direction}/{{*}}DeltaK2", dk1 + ) + sicd_con.check(f"check_deltak_wrt_ss_{direction.lower()}") + testing.assert_failures(sicd_con, f"{direction} DeltaK2 >= DeltaK1") + + def test_check_iprbw_to_deltak(self, direction, sicd_con): + sicd_con.xmlhelp.set(f"./{{*}}Grid/{{*}}{direction}/{{*}}ImpRespBW", 1e6) + sicd_con.check(f"check_iprbw_to_deltak_{direction.lower()}") + testing.assert_failures(sicd_con, f"{direction} ImpRespBW <= DeltaK2 - DeltaK1") + + def test_check_iprbw_to_ss(self, direction, sicd_con): + sicd_con.xmlhelp.set(f"./{{*}}Grid/{{*}}{direction}/{{*}}ImpRespBW", 1e6) + sicd_con.check(f"check_iprbw_to_ss_{direction.lower()}") + testing.assert_failures( + sicd_con, f"{direction} Impulse Response BW is supported by sample spacing" + ) + + def test_check_iprbw_to_ss_osr_too_small(self, direction, sicd_con): + sicd_con.xmlhelp.set(f"./{{*}}Grid/{{*}}{direction}/{{*}}ImpRespBW", 1e6) + sicd_con.check(f"check_iprbw_to_ss_osr_{direction.lower()}") + testing.assert_failures(sicd_con, f"{direction} OSR >= 1.1") + + def test_check_iprbw_to_ss_osr_too_large(self, direction, sicd_con): + sicd_con.xmlhelp.set(f"./{{*}}Grid/{{*}}{direction}/{{*}}ImpRespBW", 1e-6) + sicd_con.check(f"check_iprbw_to_ss_osr_{direction.lower()}") + testing.assert_failures(sicd_con, f"{direction} OSR <= 2.2") + + def test_check_pfa_ipr_bw(self, direction, sicd_con): + sicd_con.xmlhelp.set(f"./{{*}}Grid/{{*}}{direction}/{{*}}ImpRespBW", 1e6) + sicd_con.check(f"check_pfa_ipr_bw_{direction.lower()}") + testing.assert_failures(sicd_con, f"{direction} IPR bandwidth supported by") + + def test_check_wgtfunct_indices_bad_index(self, direction, sicd_con, em): + grid_node = sicd_con.sicdroot.find(f"./{{*}}Grid/{{*}}{direction}") + grid_node.append( + em.WgtFunct( + em.Wgt("0", index="10"), + em.Wgt("1", index="2"), + em.Wgt("2", index="3"), + em.Wgt("3", index="4"), + size="4", + ), + ) + sicd_con.check(f"check_wgtfunct_indices_{direction.lower()}") + testing.assert_failures(sicd_con, "Wgt elements are present") + + def test_check_wgtfunct_indices_bad_size(self, direction, sicd_con, em): + grid_node = sicd_con.sicdroot.find(f"./{{*}}Grid/{{*}}{direction}") + grid_node.append( + em.WgtFunct( + em.Wgt("0", index="10"), + em.Wgt("1", index="2"), + em.Wgt("2", index="3"), + em.Wgt("3", index="4"), + size="10", + ), + ) + sicd_con.check(f"check_wgtfunct_indices_{direction.lower()}") + testing.assert_failures(sicd_con, "WgtFunct size attribute matches number") + + def test_grid_unit_vectors(self, direction, sicd_con): + z_val = sicd_con.xmlhelp.load( + f"./{{*}}Grid/{{*}}{direction}/{{*}}UVectECF/{{*}}Z" + ) + sicd_con.xmlhelp.set( + f"./{{*}}Grid/{{*}}{direction}/{{*}}UVectECF/{{*}}Z", -100.0 * z_val + ) + sicd_con.check(f"check_grid_unit_vector_{direction.lower()}") + assert sicd_con.failures() + + def test_check_uniform_ipr_width(self, direction, sicd_con, em): + grid_node = sicd_con.sicdroot.find(f"./{{*}}Grid/{{*}}{direction}") + grid_node.append(em.WgtType(em.WindowName("UNIFORM"))) + sicd_con.xmlhelp.set(f"./{{*}}Grid/{{*}}{direction}/{{*}}ImpRespWid", 1e6) + sicd_con.check(f"check_uniform_ipr_width_{direction.lower()}") + testing.assert_failures( + sicd_con, f"Grid/{direction} uniform weighted IPR width matches bandwidth" + ) + + +@pytest.mark.parametrize("antenna", ["Tx", "Rcv", "TwoWay"]) +class TestAntennaNode: + @pytest.mark.parametrize("comptype", ("Array", "Elem")) + @pytest.mark.parametrize("polytype", ("Gain", "Phase")) + def test_gainphase_poly_constant(self, antenna, sicd_con, polytype, comptype): + sicd_con.xmlhelp.set( + f"./{{*}}Antenna/{{*}}{antenna}/{{*}}{comptype}/{{*}}{polytype}Poly/{{*}}Coef", + 1.0, + ) + sicd_con.check(f"check_antenna_{comptype.lower()}_gain_phase") + assert sicd_con.failures() + + def test_bs_poly_constant(self, antenna, sicd_con): + sicd_con.xmlhelp.set( + f"./{{*}}Antenna/{{*}}{antenna}/{{*}}GainBSPoly/{{*}}Coef", 1.0 + ) + sicd_con.check("check_antenna_bspoly_gain") + assert sicd_con.failures() + + +def test_check_antenna_oneway_apc_tx(sicd_con): + assert sicd_con.sicdroot.find("./{*}Antenna/{*}Tx") is not None + apc_poly = sicd_con.sicdroot.find("./{*}Position/{*}TxAPCPoly") + + apc_poly.getparent().remove(apc_poly) + sicd_con.check("check_antenna_oneway_apc") + testing.assert_failures( + sicd_con, "TxAPCPoly must be present when Antenna/Tx is present" + ) + + +def test_check_antenna_oneway_apc_rcv(sicd_con): + assert sicd_con.sicdroot.find("./{*}Antenna/{*}Rcv") is not None + apc_polys = sicd_con.sicdroot.findall("./{*}Position/{*}RcvAPC/{*}RcvAPCPoly") + for apc_poly in apc_polys: + apc_poly.getparent().remove(apc_poly) + sicd_con.check("check_antenna_oneway_apc") + testing.assert_failures( + sicd_con, "RcvAPCPoly must be present when Antenna/Rcv is present" + ) + + +def test_grid_polys(sicd_con): + _invalidate_2d_poly_coefs(sicd_con.sicdroot.find("./{*}Grid/{*}TimeCOAPoly")) + for dir in ["Row", "Col"]: + _invalidate_2d_poly_coefs( + sicd_con.sicdroot.find(f"./{{*}}Grid/{{*}}{dir}/{{*}}DeltaKCOAPoly") + ) + sicd_con.check("check_grid_polys") + details = sicd_con.failures()["check_grid_polys"]["details"] + assert np.all([det["passed"] is False for det in details]) + + +def test_timeline_polys(sicd_con): + ipp_sets = sicd_con.sicdroot.findall("./{*}Timeline/{*}IPP/{*}Set") + for ipp_set in ipp_sets: + _invalidate_1d_poly_coefs(ipp_set.find("./{*}IPPPoly")) + sicd_con.check("check_timeline_polys") + details = sicd_con.failures()["check_timeline_polys"]["details"] + assert np.all([det["passed"] is False for det in details]) + + +def test_check_segment_start_and_end(sicd_con, em): + rca_plane = sicd_con.sicdroot.find("./{*}RadarCollection/{*}Area/{*}Plane") + rca_plane.append( + em.SegmentList( + em.Segment( + em.StartLine(str(0)), + em.StartSample(str(0)), + em.EndLine(str(-1)), + em.EndSample(str(-1)), + ), + ) + ) + + sicd_con.check("check_segment_start_and_end") + testing.assert_failures(sicd_con, "SegmentList EndLine >= StartLine") + testing.assert_failures(sicd_con, "SegmentList EndSample >= StartSample") + + +def test_check_tx_rf_bandwidth(sicd_con): + max_coll = sicd_con.xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Max") + sicd_con.xmlhelp.set( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters/{*}TxRFBandwidth", max_coll + ) + sicd_con.check("check_tx_rf_bandwidth") + testing.assert_failures(sicd_con, "Waveform TxBW must be within the collected BW") + testing.assert_failures(sicd_con, "Derived BW must be close to the TxRFBW") + + +def _tx_freq_start_gt_max(xmlhelp): + max_freq = xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Max") + xmlhelp.set( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters/{*}TxFreqStart", max_freq * 2 + ) + + +def _tx_freq_start_lt_min(xmlhelp): + min_freq = xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Min") + xmlhelp.set( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters/{*}TxFreqStart", min_freq / 2 + ) + + +@pytest.mark.parametrize( + "invalidate_tx_freq_start", + [ + { + "func": _tx_freq_start_gt_max, + "error": "Waveform TxFreqStart <= max collected frequency", + }, + { + "func": _tx_freq_start_lt_min, + "error": "Waveform TxFreqStart >= the min collected frequency", + }, + ], +) +def test_check_tx_freq_start(sicd_con, invalidate_tx_freq_start): + invalidate_tx_freq_start["func"](sicd_con.xmlhelp) + sicd_con.check("check_tx_freq_start") + testing.assert_failures(sicd_con, invalidate_tx_freq_start["error"]) + + +@pytest.mark.parametrize( + "invalidate_tx_freq_bounds", + [ + { + "func": _tx_freq_start_gt_max, + "error": "Computed waveform end frequency <= max collected frequency", + }, + { + "func": _tx_freq_start_lt_min, + "error": "Computed waveform end frequency >= min collected frequency", + }, + ], +) +def test_check_tx_freq_bounds(sicd_con, invalidate_tx_freq_bounds): + invalidate_tx_freq_bounds["func"](sicd_con.xmlhelp) + sicd_con.check("check_tx_freq_bounds") + testing.assert_failures(sicd_con, invalidate_tx_freq_bounds["error"]) + + +def test_position_polys(sicd_con): + for poly in ["ARPPoly", "GRPPoly", "TxAPCPoly", "RcvAPC/{*}RcvAPCPoly"]: + _invalidate_xyz_poly_coefs( + sicd_con.sicdroot.find(f"./{{*}}Position/{{*}}{poly}") + ) + sicd_con.check("check_position_polys") + details = sicd_con.failures()["check_position_polys"]["details"] + assert np.all([det["passed"] is False for det in details]) + + +def test_radiometric_polys(sicd_con): + for poly in [ + "NoiseLevel/{*}NoisePoly", + "RCSSFPoly", + "SigmaZeroSFPoly", + "BetaZeroSFPoly", + "GammaZeroSFPoly", + ]: + _invalidate_2d_poly_coefs( + sicd_con.sicdroot.find(f"./{{*}}Radiometric/{{*}}{poly}") + ) + sicd_con.check("check_radiometric_polys") + details = sicd_con.failures()["check_radiometric_polys"]["details"] + assert np.all([det["passed"] is False for det in details]) + + +def _mismatch_chirp(xmlhelp): + xmlhelp.set( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters/{*}RcvDemodType", "CHIRP" + ) + + +def _mismatch_stretch(xmlhelp): + xmlhelp.set("./{*}RadarCollection/{*}Waveform/{*}WFParameters/{*}RcvFMRate", 0.0) + + +@pytest.mark.parametrize( + "invalidate_fmrate", + [ + { + "func": _mismatch_chirp, + "error": "Consistent receive FM rate for chirp/stretch demodulation types", + }, + { + "func": _mismatch_stretch, + "error": "Consistent receive FM rate for chirp/stretch demodulation types", + }, + ], +) +def test_check_rcv_fmrate(sicd_con, invalidate_fmrate): + sicd_con.check("check_rcv_fmrate") + assert not sicd_con.failures() + + invalidate_fmrate["func"](sicd_con.xmlhelp) + sicd_con.check("check_rcv_fmrate") + testing.assert_failures(sicd_con, invalidate_fmrate["error"]) + + +def test_antenna_polys(sicd_con): + for ant in ["Tx", "Rcv", "TwoWay"]: + for poly in ["EB/{*}DCXPoly", "EB/{*}DCYPoly", "GainBSPoly"]: + _invalidate_1d_poly_coefs( + sicd_con.sicdroot.find(f"./{{*}}Antenna/{{*}}{ant}/{{*}}{poly}") + ) + + for poly in [ + "Array/{*}GainPoly", + "Array/{*}PhasePoly", + "Elem/{*}GainPoly", + "Elem/{*}PhasePoly", + ]: + _invalidate_2d_poly_coefs( + sicd_con.sicdroot.find(f"./{{*}}Antenna/{{*}}{ant}/{{*}}{poly}") + ) + + for poly in ["XAxisPoly", "YAxisPoly"]: + _invalidate_xyz_poly_coefs( + sicd_con.sicdroot.find(f"./{{*}}Antenna/{{*}}{ant}/{{*}}{poly}") + ) + sicd_con.check("check_antenna_polys") + details = sicd_con.failures()["check_antenna_polys"]["details"] + assert np.all([det["passed"] is False for det in details]) + + +def test_rgazcomp_polys(sicd_con, em): + sicd_con.sicdroot.append( + em.RgAzComp( + em.AzSF("0.0"), + sksicd.PolyType().make_elem("KazPoly", np.zeros(4)), + ) + ) + sicd_con.check("check_rgazcomp_polys") + assert sicd_con.passes() + _invalidate_1d_poly_coefs(sicd_con.sicdroot.find("./{*}RgAzComp/{*}KazPoly")) + sicd_con.check("check_rgazcomp_polys") + assert sicd_con.failures() + + +def test_check_match_type(sicd_con, em): + sicd_con.sicdroot.append( + em.MatchInfo( + em.NumMatchTypes("2"), + em.MatchType( + em.TypeID("BOGUS"), + em.NumMatchCollections("0"), + index="1", + ), + ) + ) + sicd_con.check("check_match_type") + testing.assert_failures(sicd_con, "Number of MatchType nodes matches NumMatchTypes") + + +def test_check_match_type_indices(sicd_con, em): + sicd_con.sicdroot.append( + em.MatchInfo( + em.NumMatchTypes("2"), + em.MatchType( + em.TypeID("BOGUS1"), + em.NumMatchCollections("0"), + index="1", + ), + em.MatchType( + em.TypeID("BOGUS2"), + em.NumMatchCollections("0"), + index="10", + ), + ) + ) + sicd_con.check("check_match_type") + testing.assert_failures(sicd_con, "MatchType indexed 1 to NumMatchTypes") + + +def test_check_no_match_collections(sicd_con, em): + sicd_con.sicdroot.append( + em.MatchInfo( + em.NumMatchTypes("1"), + em.MatchType( + em.TypeID("BOGUS1"), + em.NumMatchCollections("24"), + ), + ) + ) + sicd_con.check("check_match_collection") + testing.assert_failures( + sicd_con, "Number of MatchCollection nodes matches NumMatchCollections" + ) + + +def test_check_match_collection(sicd_con, em): + sicd_con.sicdroot.append( + em.MatchInfo( + em.NumMatchTypes("2"), + em.MatchType( + em.TypeID("BOGUS1"), + em.NumMatchCollections("1"), + em.MatchCollection( + em.CoreName("CORENAME"), + index="1", + ), + ), + em.MatchType( + em.TypeID("BOGUS2"), + em.NumMatchCollections("2"), + em.MatchCollection( + em.CoreName("CORENAME"), + index="1", + ), + ), + ) + ) + sicd_con.check("check_match_collection") + testing.assert_failures( + sicd_con, "Number of MatchCollection nodes matches NumMatchCollections" + ) + + +def test_check_match_collection_indices(sicd_con, em): + sicd_con.sicdroot.append( + em.MatchInfo( + em.NumMatchTypes("2"), + em.MatchType( + em.TypeID("BOGUS1"), + em.NumMatchCollections("1"), + em.MatchCollection( + em.CoreName("CORENAME"), + index="1", + ), + ), + em.MatchType( + em.TypeID("BOGUS2"), + em.NumMatchCollections("2"), + em.MatchCollection( + em.CoreName("CORENAME1"), + index="1", + ), + em.MatchCollection( + em.CoreName("CORENAME2"), + index="10", + ), + ), + ) + ) + sicd_con.check("check_match_collection") + testing.assert_failures( + sicd_con, "MatchCollection indexed 1 to NumMatchCollections" + ) + + +@pytest.mark.parametrize( + "datanode", + [ + "ImageData", + "GeoData", + ], +) +def test_check_valid_data_indices(datanode, sicd_con): + sicd_con.check("check_valid_data_indices") + assert not sicd_con.failures() + + vertices = sicd_con.sicdroot.findall( + f"./{{*}}{datanode}/{{*}}ValidData/{{*}}Vertex" + ) + vertices[0].set("index", "99") + sicd_con.check("check_valid_data_indices") + testing.assert_failures(sicd_con, "Vertex elements are present") + + +def test_check_valid_data_indices_size(sicd_con): + ew = sksicd.ElementWrapper(sicd_con.sicdroot) + vertices = ew["ImageData"]["ValidData"] + assert len(vertices) > 0 + ew["ImageData"]["ValidData"] = vertices[:-1] + sicd_con.check("check_valid_data_indices") + testing.assert_failures(sicd_con, "GeoData size equal to ImageData size") + + +def test_check_icp_indices(sicd_con): + sicd_con.check("check_icp_indices") + assert not sicd_con.failures() + + icp_0 = sicd_con.sicdroot.find("./{*}GeoData/{*}ImageCorners/{*}ICP") + icp_0.set("index", "10:FRFR") + sicd_con.check("check_icp_indices") + testing.assert_failures(sicd_con, "GeoData ICPs indexed correctly") + + +@pytest.mark.parametrize( + "seglist_failures", + [ + { + "index": "10", + "size": "1", + "error": "Segment elements are present", + }, + { + "index": "1", + "size": "10", + "error": "SegmentList size attribute matches number", + }, + ], +) +def test_check_segmentlist_indices(sicd_con, seglist_failures, em): + plane_node = sicd_con.sicdroot.find("./{*}RadarCollection/{*}Area/{*}Plane") + plane_node.append( + em.SegmentList( + em.Segment( + em.StartLine("0"), + em.StartSample("0"), + em.EndLine("100"), + em.EndSample("100"), + em.Identifier("1"), + index=seglist_failures["index"], + ), + size=seglist_failures["size"], + ), + ) + sicd_con.check("check_segmentlist_indices") + testing.assert_failures(sicd_con, seglist_failures["error"]) + + +@pytest.mark.parametrize( + "txsequence_failures", + [ + { + "index": "10", + "size": "1", + "error": "TxStep elements are present", + }, + { + "index": "1", + "size": "10", + "error": "TxSequence size attribute matches number", + }, + ], +) +def test_check_txsequence_indices(sicd_con, txsequence_failures, em): + rc_node = sicd_con.sicdroot.find("./{*}RadarCollection") + rc_node.append( + em.TxSequence( + em.TxStep("25", index=txsequence_failures["index"]), + size=txsequence_failures["size"], + ), + ) + sicd_con.check("check_txsequence_indices") + testing.assert_failures(sicd_con, txsequence_failures["error"]) + + +@pytest.mark.parametrize( + "other_index_failures", + [ + { + "check": "check_waveform_params_indices", + "node": "./{*}RadarCollection/{*}Waveform/{*}WFParameters", + "error": "WFParameters elements are present", + }, + { + "check": "check_ipp_set_indices", + "node": "./{*}Timeline/{*}IPP/{*}Set", + "error": "Set elements are present", + }, + { + "check": "check_rcv_channel_indices", + "node": "./{*}RadarCollection/{*}RcvChannels/{*}ChanParameters", + "error": "ChanParameters elements are present", + }, + { + "check": "check_rcvapc_indices", + "node": "./{*}Position/{*}RcvAPC/{*}RcvAPCPoly", + "error": "RcvAPCPoly elements are present", + }, + ], +) +def test_check_indices_bad_index(sicd_con, other_index_failures): + sicd_con.check(other_index_failures["check"]) + assert not sicd_con.failures() + + index_0 = sicd_con.sicdroot.find(other_index_failures["node"]) + index_0.set("index", "10") + sicd_con.check(other_index_failures["check"]) + testing.assert_failures(sicd_con, other_index_failures["error"]) + + +@pytest.mark.parametrize( + "size_failures", + [ + { + "check": "check_waveform_params_indices", + "node": "./{*}RadarCollection/{*}Waveform", + "error": "Waveform size attribute matches number", + }, + { + "check": "check_ipp_set_indices", + "node": "./{*}Timeline/{*}IPP", + "error": "IPP size attribute matches number", + }, + { + "check": "check_rcv_channel_indices", + "node": "./{*}RadarCollection/{*}RcvChannels", + "error": "RcvChannels size attribute matches number", + }, + { + "check": "check_rcvapc_indices", + "node": "./{*}Position/{*}RcvAPC", + "error": "RcvAPC size attribute matches number", + }, + ], +) +def test_check_indices_bad_size(sicd_con, size_failures): + sicd_con.check(size_failures["check"]) + assert not sicd_con.failures() + + sicd_con.sicdroot.find(size_failures["node"]).set("size", "20") + sicd_con.check(size_failures["check"]) + testing.assert_failures(sicd_con, size_failures["error"]) + + +def test_check_waveform_params_rcvwinlen(sicd_con): + sicd_con.check("check_waveform_params") + assert not sicd_con.failures() + + wf_params_node = sicd_con.sicdroot.find( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters" + ) + wf_params_node.find("./{*}RcvWindowLength").text = "0.0" + sicd_con.check("check_waveform_params") + testing.assert_failures(sicd_con, "RcvWindowLength > zero") + + +def test_check_waveform_params_txfmrate(sicd_con): + sicd_con.check("check_waveform_params") + assert not sicd_con.failures() + + wf_params_node = sicd_con.sicdroot.find( + "./{*}RadarCollection/{*}Waveform/{*}WFParameters" + ) + wf_params_node.find("./{*}TxFMRate").text = "0.0" + sicd_con.check("check_waveform_params") + testing.assert_failures(sicd_con, "TxFMRate not zero") + + +def test_rgazcomp_ifa(sicd_con, em): + sicd_con.sicdroot.append( + em.RgAzComp( + em.AzSF("0.0"), + sksicd.PolyType().make_elem("KazPoly", np.zeros(4)), + ) + ) + + sicd_con.sicdroot.find("./{*}ImageFormation/{*}ImageFormAlgo").text = "RGAZCOMP" + sicd_con.check("check_valid_ifa") + assert not sicd_con.failures() + + +def test_check_validdata_first_vertex(sicd_con): + sicd_con.check("check_validdata_first_vertex") + assert not sicd_con.failures() + + vertices = sicd_con.xmlhelp.load("./{*}ImageData/{*}ValidData") + vertices[0] = [np.max(vertices[:, 0]), np.max(vertices[:, 1])] + sicd_con.xmlhelp.set("./{*}ImageData/{*}ValidData", vertices) + sicd_con.check("check_validdata_first_vertex") + testing.assert_failures(sicd_con, "First ValidData Vertex is min row -> min col") + + +def test_check_validdata_bounds(sicd_con): + sicd_con.check("check_validdata_bounds") + assert not sicd_con.failures() + + vertices = sicd_con.xmlhelp.load("./{*}ImageData/{*}ValidData") + vertices[0][0] = -2 + sicd_con.xmlhelp.set("./{*}ImageData/{*}ValidData", vertices) + sicd_con.check("check_validdata_bounds") + testing.assert_failures(sicd_con, "ValidData vertices contained within FullImage") + + vertices = sicd_con.xmlhelp.load("./{*}ImageData/{*}ValidData") + vertices[0][1] = sicd_con.xmlhelp.load("./{*}ImageData/{*}FullImage/{*}NumCols") + 2 + sicd_con.xmlhelp.set("./{*}ImageData/{*}ValidData", vertices) + sicd_con.check("check_validdata_bounds") + testing.assert_failures(sicd_con, "ValidData vertices contained within FullImage") + + +def test_check_amptable_bad_index(sicd_con, em): + img_data_node = sicd_con.sicdroot.find("./{*}ImageData") + img_data_node.append( + em.AmpTable( + em.Amplitude("1", index="256"), + em.Amplitude("2", index="1"), + em.Amplitude("3", index="2"), + em.Amplitude("4", index="3"), + size="256", + ) + ) + sicd_con.check("check_amptable") + testing.assert_failures(sicd_con, "AmpTable indexed 0 to 255") + + +def test_check_multiple_geoinfo_lines(sicd_con, em): + geo_data_node = sicd_con.sicdroot.find("./{*}GeoData") + geo_data_node.append( + em.GeoInfo( + em.Line( + em.Endpoint( + em.Lat("60.0"), + em.Lon("120.0"), + index="10", + ), + em.Endpoint( + em.Lat("70.0"), + em.Lon("130.0"), + index="2", + ), + size="2", + ), + ) + ) + geo_data_node.append( + em.GeoInfo( + em.Line( + em.Endpoint( + em.Lat("65.0"), + em.Lon("125.0"), + index="1", + ), + em.Endpoint( + em.Lat("75.0"), + em.Lon("135.0"), + index="2", + ), + size="2", + ), + ) + ) + sicd_con.check("check_geoinfo_line") + testing.assert_failures(sicd_con, "Endpoint elements are present") + + +def test_check_nested_geoinfo_lines(sicd_con, em): + geo_data_node = sicd_con.sicdroot.find("./{*}GeoData") + geo_data_node.append( + em.GeoInfo( + em.Line( + em.Endpoint( + em.Lat("60.0"), + em.Lon("120.0"), + index="10", + ), + em.Endpoint( + em.Lat("70.0"), + em.Lon("130.0"), + index="2", + ), + size="2", + ), + em.GeoInfo( + em.Line( + em.Endpoint( + em.Lat("65.0"), + em.Lon("125.0"), + index="1", + ), + em.Endpoint( + em.Lat("75.0"), + em.Lon("135.0"), + index="2", + ), + size="2", + ), + ), + ) + ) + sicd_con.check("check_geoinfo_line") + testing.assert_failures(sicd_con, "Endpoint elements are present") + + +def test_check_multiple_geoinfo_polygons(sicd_con, em): + geo_data_node = sicd_con.sicdroot.find("./{*}GeoData") + geo_data_node.append( + em.GeoInfo( + em.Polygon( + em.Vertex(em.Lat("60.0"), em.Lon("120.0"), index="10"), + em.Vertex(em.Lat("70.0"), em.Lon("130.0"), index="2"), + em.Vertex(em.Lat("80.0"), em.Lon("140'0"), index="3"), + size="3", + ), + ) + ) + geo_data_node.append( + em.GeoInfo( + em.Polygon( + em.Vertex(em.Lat("65.0"), em.Lon("125.0"), index="10"), + em.Vertex(em.Lat("75.0"), em.Lon("135.0"), index="2"), + em.Vertex(em.Lat("85.0"), em.Lon("145'0"), index="3"), + size="3", + ), + ) + ) + sicd_con.check("check_geoinfo_polygon") + testing.assert_failures(sicd_con, "Vertex elements are present") + + +def test_check_nested_geoinfo_polygons(sicd_con, em): + geo_data_node = sicd_con.sicdroot.find("./{*}GeoData") + geo_data_node.append( + em.GeoInfo( + em.Polygon( + em.Vertex(em.Lat("65.0"), em.Lon("125.0"), index="10"), + em.Vertex(em.Lat("75.0"), em.Lon("135.0"), index="2"), + em.Vertex(em.Lat("85.0"), em.Lon("145'0"), index="3"), + size="3", + ), + em.GeoInfo( + em.Polygon( + em.Vertex(em.Lat("65.0"), em.Lon("125.0"), index="1"), + em.Vertex(em.Lat("75.0"), em.Lon("135.0"), index="2"), + em.Vertex(em.Lat("85.0"), em.Lon("145'0"), index="3"), + size="3", + ), + ), + ) + ) + sicd_con.check("check_geoinfo_polygon") + testing.assert_failures(sicd_con, "Vertex elements are present") + + +def test_check_geoinfo_polygon_bad_size(sicd_con, em): + geo_data_node = sicd_con.sicdroot.find("./{*}GeoData") + geo_data_node.append( + em.GeoInfo( + em.Polygon( + em.Vertex(em.Lat("60.0"), em.Lon("120.0"), index="1"), + em.Vertex(em.Lat("70.0"), em.Lon("130.0"), index="2"), + em.Vertex(em.Lat("80.0"), em.Lon("140'0"), index="3"), + size="4", + ), + ) + ) + sicd_con.check("check_geoinfo_polygon") + testing.assert_failures(sicd_con, "Polygon size attribute matches number") + + +def test_check_no_validdata_presence(sicd_con): + id_validdata_node = sicd_con.sicdroot.find("./{*}ImageData/{*}ValidData") + id_validdata_node.getparent().remove(id_validdata_node) + gd_validdata_node = sicd_con.sicdroot.find("./{*}GeoData/{*}ValidData") + gd_validdata_node.getparent().remove(gd_validdata_node) + + sicd_con.check("check_validdata_presence") + assert not sicd_con.failures() + + +def _validdata_missing_from_imagedata(xml): + validdata_node = xml.find("./{*}ImageData/{*}ValidData") + validdata_node.getparent().remove(validdata_node) + + +def _validdata_missing_from_geodata(xml): + validdata_node = xml.find("./{*}GeoData/{*}ValidData") + validdata_node.getparent().remove(validdata_node) + + +@pytest.mark.parametrize( + "missing_validdata", + [ + { + "func": _validdata_missing_from_imagedata, + "error": "ValidData in both GeoData and ImageData or neither", + }, + { + "func": _validdata_missing_from_geodata, + "error": "ValidData in both GeoData and ImageData or neither", + }, + ], +) +def test_check_validdata_presence(sicd_con, missing_validdata): + missing_validdata["func"](sicd_con.sicdroot) + sicd_con.check("check_validdata_presence") + testing.assert_failures(sicd_con, missing_validdata["error"]) + + +def test_check_pfa_grid_type(sicd_con): + sicd_con.check("check_pfa_grid_type") + assert sicd_con.passes() + + sicd_con.xmlhelp.set("./{*}Grid/{*}Type", "RGZERO") + sicd_con.check("check_pfa_grid_type") + testing.assert_failures(sicd_con, "PFA grid type must be RGAZIM") + + +def _bad_kaz1(xmlhelp): + xmlhelp.set("./{*}PFA/{*}Kaz1", -10000.0) + + +def _bad_kaz2(xmlhelp): + xmlhelp.set("./{*}PFA/{*}Kaz2", 10000.0) + + +@pytest.mark.parametrize( + "invalidate_kaz", + [ + {"func": _bad_kaz1, "error": "PFA Kaz1 within half of 1/Grid.Col.SS of KCtr"}, + {"func": _bad_kaz2, "error": "PFA Kaz2 within half of 1/Grid.Col.SS of KCtr"}, + ], +) +def test_check_pfa_spot_kaz_to_grid(sicd_con, invalidate_kaz): + sicd_con.check("check_pfa_spot_kaz_to_grid") + assert not sicd_con.failures() + + invalidate_kaz["func"](sicd_con.xmlhelp) + sicd_con.check("check_pfa_spot_kaz_to_grid") + testing.assert_failures(sicd_con, invalidate_kaz["error"]) + + +def _bad_krg1(xmlhelp): + xmlhelp.set("./{*}PFA/{*}Krg1", -10000.0) + + +def _bad_krg2(xmlhelp): + xmlhelp.set("./{*}PFA/{*}Krg2", 10000.0) + + +@pytest.mark.parametrize( + "invalidate_krg", + [ + {"func": _bad_krg1, "error": "PFA Krg1 within half of 1/Grid.Row.SS of KCtr"}, + {"func": _bad_krg2, "error": "PFA Krg2 within half of 1/Grid.Row.SS of KCtr"}, + ], +) +def test_check_pfa_krg_to_grid(sicd_con, invalidate_krg): + sicd_con.check("check_pfa_krg_to_grid") + assert not sicd_con.failures() + + invalidate_krg["func"](sicd_con.xmlhelp) + sicd_con.check("check_pfa_krg_to_grid") + testing.assert_failures(sicd_con, invalidate_krg["error"]) + + +@pytest.mark.parametrize( + "poly_to_invalidate", + ("{*}PolarAngPoly", "{*}SpatialFreqSFPoly", "{*}STDeskew/{*}STDSPhasePoly"), +) +def test_pfa_polys(sicd_con, em, poly_to_invalidate): + assert sicd_con.sicdroot.find("./{*}PFA/{*}STDeskew") is None + # Add STDSPhasePoly node since example xml does not have it + sicd_con.sicdroot.find("./{*}PFA").append( + em.STDeskew( + em.Applied("true"), + sksicd.Poly2dType().make_elem("STDSPhasePoly", np.zeros((2, 3))), + ) + ) + sicd_con.check("check_pfa_polys") + assert sicd_con.passes() + _invalidate_1d_poly_coefs(sicd_con.sicdroot.find("./{*}PFA/" + poly_to_invalidate)) + sicd_con.check("check_pfa_polys") + assert sicd_con.failures() + + +def test_pfa_stds_kcoa(sicd_con, em): + # Make sure STDSPhasePoly does not exist, so we don't overwrite it + assert sicd_con.sicdroot.find("./{*}PFA/{*}STDeskew/{*}STDSPhasePoly") is None + + # Add non-zero STDSPhasePoly node since example xml does not have it + pfa_node = sicd_con.sicdroot.find("./{*}PFA") + pfa_node.append( + em.STDeskew( + em.Applied(), + em.STDSPhasePoly(), + ) + ) + sicd_con.xmlhelp.set("./{*}PFA/{*}STDeskew/{*}Applied", True) + sicd_con.xmlhelp.set( + "./{*}PFA/{*}STDeskew/{*}STDSPhasePoly", [[1.0, 0.0], [1.0, 0.0]] + ) + + # Use non-zero column DeltaKCOAPoly to force failure + sicd_con.xmlhelp.set( + "./{*}Grid/{*}Col/{*}DeltaKCOAPoly", np.array([[1, 0], [1, 0]]) + ) + + sicd_con.check("check_pfa_stds_kcoa") + details = sicd_con.failures()["check_pfa_stds_kcoa"]["details"] + assert np.all([det["passed"] is False for det in details]) + + # Use non-zero row DeltaKCOAPoly to force failure and applied=False for the other path + sicd_con.xmlhelp.set( + "./{*}Grid/{*}Row/{*}DeltaKCOAPoly", np.array([[1, 0], [1, 0]]) + ) + sicd_con.xmlhelp.set("./{*}PFA/{*}STDeskew/{*}Applied", "false") + + sicd_con.check("check_pfa_stds_kcoa") + details = sicd_con.failures()["check_pfa_stds_kcoa"]["details"] + assert np.all([det["passed"] is False for det in details]) + + +def _min_proc_lt_min_coll(xmlhelp): + min_coll = xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Min") + xmlhelp.set("./{*}ImageFormation/{*}TxFrequencyProc/{*}MinProc", min_coll / 2) + + +def _max_proc_gt_max_coll(xmlhelp): + max_coll = xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Max") + xmlhelp.set("./{*}ImageFormation/{*}TxFrequencyProc/{*}MaxProc", max_coll * 2) + + +def _max_coll_lt_min_coll(xmlhelp): + min_coll = xmlhelp.load("./{*}RadarCollection/{*}TxFrequency/{*}Min") + xmlhelp.set("./{*}RadarCollection/{*}TxFrequency/{*}Max", min_coll / 2) + + +def _max_proc_lt_min_proc(xmlhelp): + min_proc = xmlhelp.load("./{*}ImageFormation/{*}TxFrequencyProc/{*}MinProc") + xmlhelp.set("./{*}ImageFormation/{*}TxFrequencyProc/{*}MaxProc", min_proc / 2) + + +def _zero_min(xmlhelp): + xmlhelp.set("./{*}RadarCollection/{*}TxFrequency/{*}Min", 0.0) + + +@pytest.mark.parametrize( + "invalidate_proc_freq", + [ + { + "func": _min_proc_lt_min_coll, + "error": "Min processed frequency >= min collected frequency", + }, + { + "func": _max_proc_gt_max_coll, + "error": "Max processed frequency <= max collected frequency", + }, + { + "func": _max_coll_lt_min_coll, + "error": "Max collected frequency > min collected", + }, + { + "func": _max_proc_lt_min_proc, + "error": "Max processed frequency > min processed", + }, + {"func": _zero_min, "error": "Min collected frequency > 0.0"}, + ], +) +def test_check_proc_freq(sicd_con, invalidate_proc_freq): + invalidate_proc_freq["func"](sicd_con.xmlhelp) + sicd_con.check("check_proc_freq") + testing.assert_failures(sicd_con, invalidate_proc_freq["error"]) + + +@pytest.fixture +def sicd_con_bad_inca(sicd_con, em): + # Add RMA/INCA nodes since example xml does not have them + assert sicd_con.sicdroot.find("./{*}RMA/{*}INCA") is None + sicd_con.sicdroot.append( + em.RMA( + em.RMAlgoType("RG_DOP"), + em.ImageType("INCA"), + em.INCA( + sksicd.PolyType().make_elem("TimeCAPoly", np.ones(4)), + em.R_CA_SCP("10000.0"), + em.FreqZero("0.0"), + sksicd.Poly2dType().make_elem("DRateSFPoly", np.ones((4, 3))), + sksicd.Poly2dType().make_elem("DopCentroidPoly", np.ones((5, 4))), + em.DopCentroidCOA("false"), + ), + ) + ) + sicd_con.check("check_inca") + assert sicd_con.failures() + return sicd_con + + +@pytest.mark.parametrize( + "poly_to_invalidate", ("{*}TimeCAPoly", "{*}DRateSFPoly", "{*}DopCentroidPoly") +) +def test_check_rma_inca_polys(sicd_con_bad_inca, poly_to_invalidate): + sicd_con = sicd_con_bad_inca + sicd_con.check("check_rma_inca_polys") + assert sicd_con.passes() + _invalidate_1d_poly_coefs( + sicd_con.sicdroot.find("./{*}RMA/{*}INCA/" + poly_to_invalidate) + ) + sicd_con.check("check_rma_inca_polys") + assert sicd_con.failures() + + +def test_segment_bounds(sicd_con, em): + rca_plane = sicd_con.sicdroot.find("./{*}RadarCollection/{*}Area/{*}Plane") + assert rca_plane.find("./{*}SegmentList") is None + + first_line = sicd_con.xmlhelp.load( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}XDir/{*}FirstLine" + ) + first_sample = sicd_con.xmlhelp.load( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}YDir/{*}FirstSample" + ) + num_lines = sicd_con.xmlhelp.load( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}XDir/{*}NumLines" + ) + num_samples = sicd_con.xmlhelp.load( + "./{*}RadarCollection/{*}Area/{*}Plane/{*}YDir/{*}NumSamples" + ) + + rca_plane.append( + em.SegmentList( + em.Segment( + em.StartLine(str(first_line)), + em.StartSample(str(first_sample)), + em.EndLine(str(int(first_line + num_lines // 2 - 1))), + em.EndSample(str(int(first_sample + num_samples // 2 - 1))), + ), + em.Segment( + em.StartLine(str(int(first_line + num_lines // 2))), + em.StartSample(str(int(first_sample + num_samples // 2))), + em.EndLine(str(int(first_line + num_lines - 1))), + em.EndSample(str(int(first_sample + num_samples - 1))), + ), + ) + ) + sicd_con.check("check_segmentlist_bounds") + assert sicd_con.passes() + + rca_plane.find("./{*}XDir/{*}NumLines").text = str(num_lines - 10) + sicd_con.check("check_segmentlist_bounds") + testing.assert_failures( + sicd_con, "All segments within the segment_list are bounded" + ) + + +def test_segment_identifier(sicd_con, em): + imform = sicd_con.sicdroot.find("./{*}ImageFormation") + assert imform.find("./{*}SegmentIdentifier") is None + rca_plane = sicd_con.sicdroot.find("./{*}RadarCollection/{*}Area/{*}Plane") + assert rca_plane.find("./{*}SegmentList") is None + + rca_plane.append( + em.SegmentList( + em.Segment(em.Identifier("SegmentID 1")), + em.Segment(em.Identifier("SegmentID 2")), + ) + ) + sicd_con.check("check_segment_identifier") + testing.assert_failures(sicd_con, "SegmentIdentifier is included") + + segid = em.SegmentIdentifier("not found ID") + imform.append(segid) + sicd_con.check("check_segment_identifier") + testing.assert_failures(sicd_con, "SegmentList has SegmentIdentifier") + segid.text = "SegmentID 2" + sicd_con.check("check_segment_identifier") + assert sicd_con.passes() + + +def test_check_segment_unique_ids(sicd_con, em): + rca_plane = sicd_con.sicdroot.find("./{*}RadarCollection/{*}Area/{*}Plane") + rca_plane.append( + em.SegmentList( + em.Segment(em.Identifier("seg1")), + em.Segment(em.Identifier("seg1")), + ) + ) + sicd_con.check("check_segment_unique_ids") + testing.assert_failures(sicd_con, "SegmentList segments have unique identifiers") + + +def test_check_image_formation_timeline(sicd_con): + sicd_con.xmlhelp.set( + "./{*}ImageFormation/{*}TStartProc", + sicd_con.xmlhelp.load("./{*}ImageFormation/{*}TEndProc") + 1, + ) + sicd_con.check("check_image_formation_timeline") + assert sicd_con.failures() + + +def test_check_rcvapcindex(sicd_con): + # Invalid APCIndex + sicd_con.xmlhelp.set( + "./{*}RadarCollection/{*}RcvChannels/{*}ChanParameters/{*}RcvAPCIndex", + 100, + ) + sicd_con.check("check_rcvapcindex") + assert sicd_con.failures() + + # No APCIndex with APCPolys is OK + rcvapcindex = sicd_con.sicdroot.find( + "./{*}RadarCollection/{*}RcvChannels/{*}ChanParameters/{*}RcvAPCIndex" + ) + rcvapcindex.getparent().remove(rcvapcindex) + sicd_con.check("check_rcvapcindex") + assert not sicd_con.failures() + + +def test_check_rcvapcindex_nopolys(sicd_con): + # APCIndex with no APCPolys + rcvapcnode = sicd_con.sicdroot.find("./{*}Position/{*}RcvAPC") + rcvapcnode.getparent().remove(rcvapcnode) + sicd_con.check("check_rcvapcindex") + assert sicd_con.failures() + + +def test_check_chanindex(sicd_con): + sicd_con.check("check_chanindex") + assert sicd_con.passes() + + rcv_channels = sicd_con.sicdroot.findall("./{*}ImageFormation/{*}RcvChanProc") + # Change the first ChanIndex + rcv_channels[0].find("./{*}ChanIndex").text = "99" + sicd_con.check("check_chanindex") + testing.assert_failures(sicd_con, "ChanIndex 99 must reference a ChanParameters") + + +def test_check_collection_duration(sicd_con): + sicd_con.xmlhelp.set("./{*}Timeline/{*}CollectDuration", 0.0) + sicd_con.check("check_collection_duration") + testing.assert_failures(sicd_con, "CollectionDuration > zero") + + +def test_check_nitf_imseg(example_sicd_file, tmp_path): + example_sicd_file.seek(0) + with sksicd.NitfReader(example_sicd_file) as r: + sicd_meta = r.metadata + + # Use SICD v1.4.0 FFDD Example 2 parameters to force segmentation + sicd_meta.xmltree.find("{*}ImageData/{*}NumRows").text = "30000" + sicd_meta.xmltree.find("{*}ImageData/{*}NumCols").text = "90000" + sicd_meta.xmltree.find("{*}ImageData/{*}PixelType").text = "RE32F_IM32F" + assert sksicd.image_segment_sizing_calculations(sicd_meta.xmltree)[0] == 3 + tmp_sicd = tmp_path / "forced_segmentation.sicd" + with open(tmp_sicd, "wb") as f, sksicd.NitfWriter(f, sicd_meta): + pass # don't currently care about the pixels + + with tmp_sicd.open("rb") as f: + sicd_con = SicdConsistency.from_file(f) + sicd_con.check("check_nitf_imseg") + assert sicd_con.passes() and not sicd_con.failures() + + # monkey with the IID1s + with tmp_sicd.open("rb+") as fd: + ntf = jbpy.Jbp() + ntf.load(fd) + for imseg in ntf["ImageSegments"]: + imseg["subheader"]["IID1"].value = "SICD000" + imseg["subheader"]["IID1"].dump(fd, seek_first=True) + with tmp_sicd.open("rb") as f: + sicd_con = SicdConsistency.from_file(f) + sicd_con.check("check_nitf_imseg") + testing.assert_failures(sicd_con, "Sequential IID1") + + +def test_check_error_components_posvel_stddev(sicd_con, em): + p2 = em.P2("0.2") + assert sicd_con.sicdroot.find("./{*}ErrorStatistics") is None + sicd_con.sicdroot.append( + em.ErrorStatistics( + em.Components( + em.PosVelErr( + em.P1("0.1"), + p2, + em.P3("0.3"), + em.V1("0.4"), + em.V2("0.5"), + em.V3("0.6"), + ) + ) + ) + ) + sicd_con.check("check_error_components_posvel_stddev") + assert sicd_con.passes() + p2.text = "-1.0" + sicd_con.check("check_error_components_posvel_stddev") + testing.assert_failures(sicd_con, "PosVelErr P2 >= 0.0") + + +def test_check_error_components_posvel_corr(sicd_con, em): + p1v1 = em.P1V1("0.17") + assert sicd_con.sicdroot.find("./{*}ErrorStatistics") is None + sicd_con.sicdroot.append( + em.ErrorStatistics( + em.Components( + em.PosVelErr( + em.CorrCoefs( + em.P1P2("0.12"), + em.P1P3("0.13"), + p1v1, + em.P1V2("0.18"), + em.P1V3("0.19"), + em.P2P3("0.23"), + em.P2V1("0.27"), + em.P2V2("-0.28"), + em.P2V3("-0.29"), + em.P3V1("-0.37"), + em.P3V2("-0.38"), + em.P3V3("-0.39"), + em.V1V2("-0.78"), + em.V1V3("-0.79"), + em.V2V3("-0.89"), + ) + ) + ) + ) + ) + sicd_con.check("check_error_components_posvel_corr") + assert sicd_con.passes() + p1v1.text = "-1.1" + sicd_con.check("check_error_components_posvel_corr") + testing.assert_failures(sicd_con, "CorrCoefs P1V1 <= 1.0") + + +def _bad_composite_rg(xmlhelp): + xmlhelp.set("./{*}ErrorStatistics/{*}CompositeSCP/{*}Rg", -1.0) + + +def _bad_composite_az(xmlhelp): + xmlhelp.set("./{*}ErrorStatistics/{*}CompositeSCP/{*}Az", -1.0) + + +def _bad_composite_rgaz(xmlhelp): + xmlhelp.set("./{*}ErrorStatistics/{*}CompositeSCP/{*}RgAz", 2.0) + + +@pytest.mark.parametrize( + "invalidate_composite_scp", + [ + {"func": _bad_composite_rg, "error": "CompositeSCP Rg >= 0.0"}, + {"func": _bad_composite_az, "error": "CompositeSCP Az >= 0.0"}, + {"func": _bad_composite_rgaz, "error": "CompositeSCP RgAz <= 1.0"}, + ], +) +def test_check_error_composite(sicd_con, em, invalidate_composite_scp): + assert sicd_con.sicdroot.find("./{*}ErrorStatistics") is None + sicd_con.sicdroot.append( + em.ErrorStatistics( + em.CompositeSCP( + em.Rg("1.0"), + em.Az("2.0"), + em.RgAz("0.0"), + ) + ) + ) + sicd_con.check("check_error_composite") + assert sicd_con.passes() + + invalidate_composite_scp["func"](sicd_con.xmlhelp) + sicd_con.check("check_error_composite") + testing.assert_failures(sicd_con, invalidate_composite_scp["error"]) + + +def test_check_error_radarsensor_rangebias(sicd_con, em): + assert sicd_con.sicdroot.find("./{*}ErrorStatistics") is None + sicd_con.sicdroot.append( + em.ErrorStatistics( + em.Components( + em.RadarSensor( + em.RangeBias("1.0"), + ) + ) + ) + ) + sicd_con.check("check_error_radarsensor_rangebias") + assert sicd_con.passes() + + sicd_con.xmlhelp.set( + "./{*}ErrorStatistics/{*}Components/{*}RadarSensor/{*}RangeBias", -1.0 + ) + sicd_con.check("check_error_radarsensor_rangebias") + testing.assert_failures(sicd_con, "RangeBias >= 0.0") + + +def test_check_txsequence_waveform_index(sicd_con, em): + assert sicd_con.sicdroot.find("./{*}RadarCollection/{*}TxSequence") is None + rc_node = sicd_con.sicdroot.find("./{*}RadarCollection") + rc_node.append(em.TxSequence(em.TxStep(em.WFIndex("1")))) + sicd_con.check("check_txsequence_waveform_index") + assert sicd_con.passes() + + sicd_con.xmlhelp.set( + "./{*}RadarCollection/{*}TxSequence/{*}TxStep/{*}WFIndex", "100" + ) + sicd_con.check("check_txsequence_waveform_index") + testing.assert_failures(sicd_con, "WFIndex 100 must reference a WFParameters") + + +def test_smart_open_http(example_sicd): + with tests.utils.static_http_server(example_sicd.parent) as server_url: + assert not main([f"{server_url}/{example_sicd.name}"]) + + +def test_smart_open_contract(example_sicd, monkeypatch): + mock_open = unittest.mock.MagicMock(side_effect=tests.utils.simple_open_read) + monkeypatch.setattr(sarkit.verification._sicdcheck, "open", mock_open) + assert not main([str(example_sicd)]) + mock_open.assert_called_once_with(str(example_sicd), "rb") + + +def test_check_bistatic_fields(): + xmltree = lxml.etree.parse(DATAPATH / "example-sicd-1.5.xml") + assert xmltree.findtext(".//{*}CollectType") == "BISTATIC" + + req_elem = xmltree.find("{*}CollectionInfo/{*}IlluminatorName") + req_elem.getparent().remove(req_elem) + + ant_elem = xmltree.find("{*}Antenna") + ant_elem.remove(ant_elem[0]) + ant_elem[0].tag = ant_elem[0].tag.replace("Rcv", "TwoWay") + + sicd_con = SicdConsistency.from_parts(xmltree) + sicd_con.check("check_against_schema") + assert sicd_con.passes() and not sicd_con.failures() + sicd_con.check("check_bistatic_fields") + testing.assert_failures(sicd_con, "IlluminatorName required") + testing.assert_failures(sicd_con, "TwoWay not allowed") + + +def _invalid_index(poly_elem): + poly_elem[0].set("index", "-24") + + +def _invalid_size(poly_elem): + poly_elem.set("size", str(len(poly_elem) + 1)) + + +def _not_simple(poly_elem): + sz = int(poly_elem.get("size")) + poly_elem.set("size", str(sz + 1)) + duplicate_vertex = copy.deepcopy(poly_elem[1]) + duplicate_vertex.set("index", str(sz + 1)) + poly_elem.append(duplicate_vertex) + + +def _not_clockwise(poly_elem): + for vertex in poly_elem: + vertex.set("index", str(len(poly_elem) + 1 - int(vertex.get("index")))) + + +@pytest.mark.parametrize( + "elem_path,check", + [ + ( + "{*}RadarCollection/{*}Area/{*}Plane/{*}SegmentList/{*}Segment/{*}SegmentPolygon", + "check_segment_polygons", + ), + ("{*}RadarCollection/{*}Area/{*}Plane/{*}Polygon", "check_area_plane_polygon"), + ("{*}ImageData/{*}ValidData", "check_imagedata_validdata"), + ], +) +@pytest.mark.parametrize( + "perturb_func,fail_pattern", + [ + [_invalid_index, "indices are all present"], + [_invalid_size, "size attribute matches"], + [_not_simple, "is simple"], + [_not_clockwise, "is clockwise"], + ], +) +def test_valid_polygons(elem_path, check, perturb_func, fail_pattern): + xmltree = lxml.etree.parse(DATAPATH / "example-sicd-1.5.xml") + perturb_func(xmltree.find(elem_path)) + sicd_con = SicdConsistency.from_parts(xmltree) + sicd_con.check(check) + testing.assert_failures(sicd_con, fail_pattern) + + +def test_check_errorstatistics_conditionals_bi(): + xmltree = lxml.etree.parse(DATAPATH / "example-sicd-1.5.xml") + assert xmltree.findtext(".//{*}CollectType") == "BISTATIC" + sicd_ew = sksicd.ElementWrapper(xmltree.getroot()) + sicd_ew["ErrorStatistics"]["CompositeSCP"]["Rg"] = 1.0 + sicd_ew["ErrorStatistics"]["CompositeSCP"]["Az"] = 1.0 + sicd_ew["ErrorStatistics"]["CompositeSCP"]["RgAz"] = 1.0 + + sicd_con = SicdConsistency.from_parts(xmltree) + sicd_con.check("check_against_schema") + assert sicd_con.passes() and not sicd_con.failures() + + sicd_con.check("check_errorstatistics_conditionals") + testing.assert_failures(sicd_con, "CompositeSCP not allowed") + + +def test_check_errorstatistics_conditionals_mono(): + xmltree = lxml.etree.parse(DATAPATH / "example-sicd-1.5.xml") + sicd_ew = sksicd.ElementWrapper(xmltree.getroot()) + sicd_ew["CollectionInfo"]["CollectType"] = "MONOSTATIC" + sicd_ew["ErrorStatistics"]["BistaticCompositeSCP"]["RAvg"] = 1.0 + sicd_ew["ErrorStatistics"]["BistaticCompositeSCP"]["RdotAvg"] = 1.0 + sicd_ew["ErrorStatistics"]["BistaticCompositeSCP"]["RAvgRdotAvg"] = 1.0 + + sicd_con = SicdConsistency.from_parts(xmltree) + sicd_con.check("check_against_schema") + assert sicd_con.passes() and not sicd_con.failures() + + sicd_con.check("check_errorstatistics_conditionals") + testing.assert_failures(sicd_con, "BistaticCompositeSCP not allowed")