From e43aab6f05cbc9a24de7deb3ff2d024919770a96 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 24 Dec 2025 10:55:03 -0600 Subject: [PATCH 01/77] change doc to docs --- {doc => docs}/Makefile | 0 {doc => docs}/make.bat | 72 +++++++++---------- {doc => docs}/source/_static/.placeholder | 0 .../source/api/diffpy.labpdfproc.data.rst | 0 .../source/api/diffpy.labpdfproc.rst | 0 {doc => docs}/source/conf.py | 2 +- .../source/examples/example-data/zro2_mo.xy | 0 {doc => docs}/source/examples/examples.rst | 0 .../source/examples/functions-example.rst | 0 .../source/examples/labpdfprocapp-example.rst | 0 .../source/examples/tools-example.rst | 0 {doc => docs}/source/index.rst | 0 {doc => docs}/source/license.rst | 0 {doc => docs}/source/release.rst | 0 .../source/utilities/functions-utility.rst | 0 .../utilities/labpdfprocapp-utility.rst | 0 .../source/utilities/tools-utility.rst | 0 {doc => docs}/source/utilities/utilities.rst | 0 18 files changed, 37 insertions(+), 37 deletions(-) rename {doc => docs}/Makefile (100%) rename {doc => docs}/make.bat (95%) rename {doc => docs}/source/_static/.placeholder (100%) rename {doc => docs}/source/api/diffpy.labpdfproc.data.rst (100%) rename {doc => docs}/source/api/diffpy.labpdfproc.rst (100%) rename {doc => docs}/source/conf.py (99%) rename {doc => docs}/source/examples/example-data/zro2_mo.xy (100%) rename {doc => docs}/source/examples/examples.rst (100%) rename {doc => docs}/source/examples/functions-example.rst (100%) rename {doc => docs}/source/examples/labpdfprocapp-example.rst (100%) rename {doc => docs}/source/examples/tools-example.rst (100%) rename {doc => docs}/source/index.rst (100%) rename {doc => docs}/source/license.rst (100%) rename {doc => docs}/source/release.rst (100%) rename {doc => docs}/source/utilities/functions-utility.rst (100%) rename {doc => docs}/source/utilities/labpdfprocapp-utility.rst (100%) rename {doc => docs}/source/utilities/tools-utility.rst (100%) rename {doc => docs}/source/utilities/utilities.rst (100%) diff --git a/doc/Makefile b/docs/Makefile similarity index 100% rename from doc/Makefile rename to docs/Makefile diff --git a/doc/make.bat b/docs/make.bat similarity index 95% rename from doc/make.bat rename to docs/make.bat index ac53d5b..2be8306 100644 --- a/doc/make.bat +++ b/docs/make.bat @@ -1,36 +1,36 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build -set SPHINXPROJ=PackagingScientificPython - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build +set SPHINXPROJ=PackagingScientificPython + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/doc/source/_static/.placeholder b/docs/source/_static/.placeholder similarity index 100% rename from doc/source/_static/.placeholder rename to docs/source/_static/.placeholder diff --git a/doc/source/api/diffpy.labpdfproc.data.rst b/docs/source/api/diffpy.labpdfproc.data.rst similarity index 100% rename from doc/source/api/diffpy.labpdfproc.data.rst rename to docs/source/api/diffpy.labpdfproc.data.rst diff --git a/doc/source/api/diffpy.labpdfproc.rst b/docs/source/api/diffpy.labpdfproc.rst similarity index 100% rename from doc/source/api/diffpy.labpdfproc.rst rename to docs/source/api/diffpy.labpdfproc.rst diff --git a/doc/source/conf.py b/docs/source/conf.py similarity index 99% rename from doc/source/conf.py rename to docs/source/conf.py index 12c7366..2e73623 100644 --- a/doc/source/conf.py +++ b/docs/source/conf.py @@ -20,7 +20,7 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the -# documentation root, use Path().resolve() to make it absolute, like shown here. +# documentation root, use Path().resolve() to make it absolute, like shown here # sys.path.insert(0, str(Path(".").resolve())) sys.path.insert(0, str(Path("../..").resolve())) sys.path.insert(0, str(Path("../../src").resolve())) diff --git a/doc/source/examples/example-data/zro2_mo.xy b/docs/source/examples/example-data/zro2_mo.xy similarity index 100% rename from doc/source/examples/example-data/zro2_mo.xy rename to docs/source/examples/example-data/zro2_mo.xy diff --git a/doc/source/examples/examples.rst b/docs/source/examples/examples.rst similarity index 100% rename from doc/source/examples/examples.rst rename to docs/source/examples/examples.rst diff --git a/doc/source/examples/functions-example.rst b/docs/source/examples/functions-example.rst similarity index 100% rename from doc/source/examples/functions-example.rst rename to docs/source/examples/functions-example.rst diff --git a/doc/source/examples/labpdfprocapp-example.rst b/docs/source/examples/labpdfprocapp-example.rst similarity index 100% rename from doc/source/examples/labpdfprocapp-example.rst rename to docs/source/examples/labpdfprocapp-example.rst diff --git a/doc/source/examples/tools-example.rst b/docs/source/examples/tools-example.rst similarity index 100% rename from doc/source/examples/tools-example.rst rename to docs/source/examples/tools-example.rst diff --git a/doc/source/index.rst b/docs/source/index.rst similarity index 100% rename from doc/source/index.rst rename to docs/source/index.rst diff --git a/doc/source/license.rst b/docs/source/license.rst similarity index 100% rename from doc/source/license.rst rename to docs/source/license.rst diff --git a/doc/source/release.rst b/docs/source/release.rst similarity index 100% rename from doc/source/release.rst rename to docs/source/release.rst diff --git a/doc/source/utilities/functions-utility.rst b/docs/source/utilities/functions-utility.rst similarity index 100% rename from doc/source/utilities/functions-utility.rst rename to docs/source/utilities/functions-utility.rst diff --git a/doc/source/utilities/labpdfprocapp-utility.rst b/docs/source/utilities/labpdfprocapp-utility.rst similarity index 100% rename from doc/source/utilities/labpdfprocapp-utility.rst rename to docs/source/utilities/labpdfprocapp-utility.rst diff --git a/doc/source/utilities/tools-utility.rst b/docs/source/utilities/tools-utility.rst similarity index 100% rename from doc/source/utilities/tools-utility.rst rename to docs/source/utilities/tools-utility.rst diff --git a/doc/source/utilities/utilities.rst b/docs/source/utilities/utilities.rst similarity index 100% rename from doc/source/utilities/utilities.rst rename to docs/source/utilities/utilities.rst From 3c39c96d1bf06d00650456e6d3ca7e5c0fd7347c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 24 Dec 2025 11:02:02 -0600 Subject: [PATCH 02/77] change code of conduct --- CODE_OF_CONDUCT.rst => CODE-OF-CONDUCT.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CODE_OF_CONDUCT.rst => CODE-OF-CONDUCT.rst (100%) diff --git a/CODE_OF_CONDUCT.rst b/CODE-OF-CONDUCT.rst similarity index 100% rename from CODE_OF_CONDUCT.rst rename to CODE-OF-CONDUCT.rst From 50107ebe1a08423d58dcdc0e8e39ab405c78b5af Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 24 Dec 2025 11:02:41 -0600 Subject: [PATCH 03/77] COC in read me --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 358c54d..1b8908c 100644 --- a/README.rst +++ b/README.rst @@ -156,7 +156,7 @@ trying to commit again. Improvements and fixes are always appreciated. -Before contributing, please read our `Code of Conduct `_. +Before contributing, please read our `Code of Conduct `_. Contact ------- From 1b1fcd1453e60e45bd082e0b0fe84dbbe8db43e3 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 24 Dec 2025 11:04:54 -0600 Subject: [PATCH 04/77] news --- news/doc-change.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/doc-change.rst diff --git a/news/doc-change.rst b/news/doc-change.rst new file mode 100644 index 0000000..596d126 --- /dev/null +++ b/news/doc-change.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* Changed ``doc`` to ``docs`` and ``CODE_OF_CONDUCT.rst`` to ``CODE-OF-CONDUCT.rst`` to comply with scikit-package standards. + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 44b800fd675264a1d2b9e1e9de0a2a5e61af468d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 27 Jan 2026 11:46:16 -0500 Subject: [PATCH 05/77] add author list --- docs/source/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 1de5c3f..f8cb8c9 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,7 +13,7 @@ diffpy.labpdfproc - Tools for processing x-ray powder diffraction data from labo Authors ======= -diffpy.labpdfproc is developed by Billinge Group +diffpy.labpdfproc is developed by Yucong Chen, Till Schertenleib, Caden Myers, the Billinge Group and its community contributors. For a detailed list of contributors see From b5b8ed713024363f28d131096888ae3dd52a64f5 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 27 Jan 2026 11:48:24 -0500 Subject: [PATCH 06/77] add new data --- .../example-data/CeO2_635um_accum_0.xy | 5631 +++++++++++++++++ ...35um_zscan_200umSlit_chanClose_exported.xy | 152 + 2 files changed, 5783 insertions(+) create mode 100644 docs/source/examples/example-data/CeO2_635um_accum_0.xy create mode 100644 docs/source/examples/example-data/CeO2_635um_zscan_200umSlit_chanClose_exported.xy diff --git a/docs/source/examples/example-data/CeO2_635um_accum_0.xy b/docs/source/examples/example-data/CeO2_635um_accum_0.xy new file mode 100644 index 0000000..97b1f9e --- /dev/null +++ b/docs/source/examples/example-data/CeO2_635um_accum_0.xy @@ -0,0 +1,5631 @@ +2.00009989738464 22.6381633008874 +2.02462468668818 21.8208275836126 +2.04914947599173 21.0965692433941 +2.07367426529527 20.3054115384164 +2.09819905459881 19.2641083826002 +2.12272384390235 18.4351379931934 +2.14724863320589 18.0337418046386 +2.17177342250943 17.0477033414494 +2.19629821181297 16.5503211078054 +2.22082300111651 15.5206526241212 +2.24534779042006 15.439209919197 +2.2698725797236 14.7847596117706 +2.29439736902714 14.2088433412354 +2.31892215833068 13.6329270707001 +2.34344694763422 12.7806873370293 +2.36797173693776 12.3618391402764 +2.3924965262413 12.2076797345271 +2.41702131554484 11.7393841812131 +2.44154610484838 11.0965685459187 +2.46607089415193 11.0267605131266 +2.49059568345547 10.2385114761819 +2.51512047275901 10.28505016471 +2.53964526206255 9.7294945704058 +2.56417005136609 9.2641076851248 +2.58869484066963 9.09540493921044 +2.61321962997317 8.42350262358601 +2.63774441927671 8.28097788996871 +2.66226920858026 8.10645780798833 +2.6867939978838 7.60907557434427 +2.71131878718734 7.16114069726131 +2.73584357649088 7.11751067676621 +2.76036836579442 7.03897663987505 +2.78489315509796 6.5968590988581 +2.8094179444015 6.37289166031662 +2.83394273370504 6.27981428326042 +2.85846752300859 5.73298469305526 +2.88299231231213 5.62827264386703 +2.90751710161567 5.8464227463425 +2.93204189091921 5.45084389385365 +2.95656668022275 5.03781303316677 +2.98109146952629 5.15997709055303 +3.00561625882983 4.78475891429523 +3.03014104813337 4.89237963151646 +3.05466583743691 4.5375221314897 +3.07919062674046 4.18557329949595 +3.103715416044 4.03432256177963 +3.12824020534754 3.89470649619533 +3.15276499465108 3.85107647570023 +3.17728978395462 3.67073905765385 +3.20181457325816 3.47294963140942 +3.2263393625617 3.56311834043262 +3.25086415186524 3.40605026665028 +3.27538894116879 3.3187902256601 +3.29991373047233 3.01628875022745 +3.32443851977587 3.04537543055751 +3.34896330907941 2.81559065595002 +3.37348809838295 2.69051793053075 +3.39801288768649 2.4345551436262 +3.42253767699003 2.32402575837197 +3.44706246629357 2.23094838131577 +3.47158725559711 2.35892977476804 +3.49611204490066 2.19313569688669 +3.5206368342042 2.0564282993354 +3.54516162350774 2.1029669878635 +3.56968641281128 1.93135557391613 +3.59421120211482 1.81210018456287 +3.61873599141836 1.91099489768509 +3.6432607807219 1.67248411897858 +3.66778557002544 1.76556149603477 +3.69231035932899 1.6841187911106 +3.71683514863253 1.67539278701158 +3.74135993793607 1.72484014357269 +3.76588472723961 1.63176276651649 +3.79040951654315 1.73356614767171 +3.81493430584669 1.62594543045048 +3.83945909515023 1.60849342225244 +3.86398388445377 1.6375801025825 +3.88850867375731 1.68702745914361 +3.91303346306086 1.58522407798839 +3.9375582523644 1.53577672142728 +3.96208304166794 1.63467143454949 +3.98660783097148 1.52995938536127 +4.01113262027502 1.62885409848348 +4.03565740957856 1.51832471322925 +4.0601821988821 1.65794077881354 +4.08470698818564 1.56777206979035 +4.10923177748919 1.60267608618643 +4.13375656679273 1.39906932387599 +4.15828135609627 1.49214670093219 +4.18280614539981 1.50959870913023 +4.20733093470335 1.53286805339428 +4.23185572400689 1.53577672142728 +4.25638051331043 1.52123338126225 +4.28090530261397 1.52414204929526 +4.30543009191751 1.50087270503121 +4.32995488122106 1.52123338126225 +4.3544796705246 1.61721942635146 +4.37900445982814 1.46596868863513 +4.40352924913168 1.52123338126225 +4.42805403843522 1.46887735666814 +4.45257882773876 1.50087270503121 +4.4771036170423 1.43688200830507 +4.50162840634584 1.43979067633808 +4.52615319564939 1.52414204929526 +4.55067798495293 1.33798729518286 +4.57520277425647 1.39034331977697 +4.59972756356001 1.46596868863513 +4.62425235286355 1.43106467223906 +4.64877714216709 1.30017461075378 +4.67330193147063 1.41361266404102 +4.69782672077417 1.34671329928188 +4.72235151007771 1.50378137306421 +4.74687629938126 1.43106467223906 +4.7714010886848 1.48051202880016 +4.79592587798834 1.46306002060213 +4.82045066729188 1.4979640369982 +4.84497545659542 1.42524733617305 +4.86950024589896 1.27108793042372 +4.8940250352025 1.401977991909 +4.91854982450604 1.55322872962532 +4.94307461380959 1.37579997961194 +4.96759940311313 1.3089006148528 +4.99212419241667 1.43688200830507 +5.01664898172021 1.39906932387599 +5.04117377102375 1.3554393033809 +5.06569856032729 1.38452598371096 +5.09022334963083 1.45433401650311 +5.11474813893437 1.37579997961194 +5.13927292823792 1.34962196731489 +5.16379771754146 1.404886659942 +5.188322506845 1.36998264354593 +5.21284729614854 1.33507862714985 +5.23737208545208 1.27399659845672 +5.26189687475562 1.30017461075378 +5.28642166405916 1.38452598371096 +5.3109464533627 1.32635262305084 +5.33547124266624 1.31762661895182 +5.35999603196979 1.1692845492685 +5.38452082127333 1.36707397551292 +5.40904561057687 1.28272260255574 +5.43357039988041 1.33798729518286 +5.45809518918395 1.21000590173059 +5.48261997848749 1.32344395501783 +5.50714476779103 1.3089006148528 +5.53166955709457 1.3089006148528 +5.55619434639812 1.15183254107046 +5.58071913570166 1.29435727468777 +5.6052439250052 1.25363592222568 +5.62976871430874 1.2158232377966 +5.65429350361228 1.30308327878679 +5.67881829291582 1.2623619263247 +5.70334308221936 1.28563127058875 +5.7278678715229 1.29726594272077 +5.75239266082644 1.38161731567795 +5.77691745012999 1.18382788943353 +5.80144223943353 1.14601520500445 +5.82596702873707 1.31471795091881 +5.85049181804061 1.25072725419267 +5.87501660734415 1.23327524599464 +5.89954139664769 1.19255389353255 +5.92406618595123 1.19546256156556 +5.94859097525477 1.21000590173059 +5.97311576455832 1.25654459025869 +5.99764055386186 1.22164057386261 +6.0221653431654 1.25654459025869 +6.04669013246894 1.15183254107046 +6.07121492177248 1.36707397551292 +6.09573971107602 1.15183254107046 +6.12026450037956 1.2652705943577 +6.1447892896831 1.29144860665476 +6.16931407898664 1.25654459025869 +6.19383886829019 1.29435727468777 +6.21836365759373 1.24490991812666 +6.24288844689727 1.21291456976359 +6.26741323620081 1.18964522549954 +6.29193802550435 1.27690526648973 +6.31646281480789 1.17219321730151 +6.34098760411143 1.15764987713647 +6.36551239341497 1.3118092828858 +6.39003718271852 1.21873190582961 +6.41456197202206 1.13438053287243 +6.4390867613256 1.21873190582961 +6.46361155062914 1.19255389353255 +6.48813633993268 1.13728920090543 +6.51266112923622 1.21000590173059 +6.53718591853976 1.24490991812666 +6.5617107078433 1.28563127058875 +6.58623549714684 1.20127989763157 +6.61076028645039 1.15474120910347 +6.63528507575393 1.2158232377966 +6.65980986505747 1.10820252057537 +6.68433465436101 1.10238518450936 +6.70885944366455 1.15474120910347 +6.73338423296809 1.25654459025869 +6.75790902227163 1.17219321730151 +6.78243381157517 1.16346721320249 +6.80695860087872 1.25363592222568 +6.83148339018226 1.14601520500445 +6.8560081794858 1.17510188533451 +6.88053296878934 1.17801055336752 +6.90505775809288 1.30017461075378 +6.92958254739642 1.22745790992862 +6.95410733669996 1.07911584024531 +6.9786321260035 1.21873190582961 +7.00315691530705 1.25654459025869 +7.02768170461059 1.21873190582961 +7.05220649391413 1.20418856566457 +7.07673128321767 1.1692845492685 +7.10125607252121 1.14019786893844 +7.12578086182475 1.13728920090543 +7.15030565112829 1.17219321730151 +7.17483044043183 1.19546256156556 +7.19935522973537 1.09656784844334 +7.22388001903892 1.15474120910347 +7.24840480834246 1.10529385254236 +7.272929597646 1.2158232377966 +7.29745438694954 1.05875516401426 +7.32197917625308 1.18382788943353 +7.34650396555662 1.18382788943353 +7.37102875486016 1.19255389353255 +7.3955535441637 1.15474120910347 +7.42007833346725 1.09947651647635 +7.44460312277079 1.19255389353255 +7.46912791207433 1.15474120910347 +7.49365270137787 1.14892387303746 +7.51817749068141 1.15474120910347 +7.54270227998495 1.0267598156512 +7.56722706928849 1.1692845492685 +7.59175185859203 1.04130315581623 +7.61627664789557 1.16637588123549 +7.64080143719912 1.10820252057537 +7.66532622650266 1.29144860665476 +7.6898510158062 1.13438053287243 +7.71437580510974 1.11401985664138 +7.73890059441328 1.16055854516948 +7.76342538371682 1.20709723369758 +7.78795017302036 1.1227458607404 +7.8124749623239 1.18091922140052 +7.83699975162745 1.21873190582961 +7.86152454093099 1.06166383204727 +7.88604933023453 1.15764987713647 +7.91057411953807 1.04421182384923 +7.93509890884161 1.21000590173059 +7.95962369814515 1.13728920090543 +7.98414848744869 1.17801055336752 +8.00867327675223 1.17219321730151 +8.03319806605577 1.03548581975021 +8.05772285535932 1.02094247958518 +8.08224764466286 1.17801055336752 +8.1067724339664 1.15474120910347 +8.13129722326994 1.22454924189562 +8.15582201257348 1.05875516401426 +8.18034680187702 1.14310653697144 +8.20487159118056 1.11692852467439 +8.2293963804841 1.10820252057537 +8.25392116978765 1.05875516401426 +8.27844595909119 1.16346721320249 +8.30297074839473 1.18091922140052 +8.32749553769827 0.983129795156102 +8.35202032700181 1.10820252057537 +8.37654511630535 1.15183254107046 +8.40106990560889 1.1692845492685 +8.42559469491243 1.17510188533451 +8.45011948421597 1.07038983614629 +8.47464427351952 1.17219321730151 +8.49916906282306 1.15183254107046 +8.5236938521266 1.12856319680641 +8.54821864143014 1.24490991812666 +8.57274343073368 1.09365918041034 +8.59726822003722 1.13438053287243 +8.62179300934076 1.17219321730151 +8.6463177986443 1.17801055336752 +8.67084258794785 1.09947651647635 +8.69536737725139 1.0296684836842 +8.71989216655493 1.11983719270739 +8.74441695585847 1.00930780745316 +8.76894174516201 1.08493317631132 +8.79346653446555 1.05002915991524 +8.81799132376909 1.19255389353255 +8.84251611307263 1.00930780745316 +8.86704090237617 1.08493317631132 +8.89156569167972 1.13438053287243 +8.91609048098326 1.17219321730151 +8.9406152702868 1.07038983614629 +8.96514005959034 1.10529385254236 +8.98966484889388 1.04130315581623 +9.01418963819742 1.0296684836842 +9.03871442750096 1.07329850417929 +9.0632392168045 1.07038983614629 +9.08776400610805 1.08202450827831 +9.11228879541159 1.08784184434433 +9.13681358471513 1.11111118860838 +9.16133837401867 1.05002915991524 +9.18586316332221 1.10238518450936 +9.21038795262575 1.00930780745316 +9.23491274192929 1.08784184434433 +9.25943753123283 1.17510188533451 +9.28396232053638 1.08202450827831 +9.30848710983992 1.0296684836842 +9.33301189914346 0.980221127123096 +9.357536688447 1.0296684836842 +9.38206147775054 1.05584649598126 +9.40658626705408 1.11401985664138 +9.43111105635762 0.924956434495977 +9.45563584566116 1.03839448778322 +9.4801606349647 1.01221647548616 +9.50468542426825 1.05002915991524 +9.52921021357179 0.994764467288127 +9.55373500287533 1.10238518450936 +9.57825979217887 1.05584649598126 +9.60278458148241 1.07038983614629 +9.62730937078595 1.06748116811328 +9.65183416008949 1.10238518450936 +9.67635894939303 0.997673135321133 +9.70088373869658 1.01803381155218 +9.72540852800012 1.07329850417929 +9.74993331730366 1.06166383204727 +9.7744581066072 1.06166383204727 +9.79898289591074 0.948225778760027 +9.82350768521428 1.03839448778322 +9.84803247451782 0.968586454991071 +9.87255726382136 0.986038463189108 +9.8970820531249 0.933682438594996 +9.92160684242845 1.06457250008028 +9.94613163173199 1.11401985664138 +9.97065642103553 1.06457250008028 +9.99518121033907 0.90750442629794 +10.0197059996426 1.1227458607404 +10.0442307889462 0.988947131222114 +10.0687555782497 0.994764467288127 +10.0932803675532 0.93077377056199 +10.1178051568568 0.922047766462971 +10.1423299461603 1.00349047138715 +10.1668547354639 0.913321762363952 +10.1913795247674 0.983129795156102 +10.2159043140709 0.977312459090089 +10.2404291033745 0.997673135321133 +10.264953892678 1.0267598156512 +10.2894786819816 0.927865102528984 +10.3140034712851 0.951134446793033 +10.3385282605886 1.03839448778322 +10.3630530498922 1.15764987713647 +10.3875778391957 0.974403791057083 +10.4121026284993 0.887143750066897 +10.4366274178028 1.05293782794825 +10.4611522071064 0.971495123024077 +10.4856769964099 0.878417745967878 +10.5102017857134 0.942408442694015 +10.534726575017 1.01803381155218 +10.5592513643205 1.05002915991524 +10.5837761536241 0.988947131222114 +10.6083009429276 0.922047766462971 +10.6328257322311 1.02385114761819 +10.6573505215347 0.878417745967878 +10.6818753108382 0.924956434495977 +10.7064001001418 0.95404311482604 +10.7309248894453 0.922047766462971 +10.7554496787488 0.90750442629794 +10.7799744680524 0.933682438594996 +10.8044992573559 1.03257715171721 +10.8290240466595 0.977312459090089 +10.853548835963 1.00639913942015 +10.8780736252666 1.01803381155218 +10.9025984145701 0.927865102528984 +10.9271232038736 1.02385114761819 +10.9516479931772 0.99185579925512 +10.9761727824807 0.977312459090089 +11.0006975717843 0.922047766462971 +11.0252223610878 0.93077377056199 +11.0497471503913 0.88423508203389 +11.0742719396949 0.90750442629794 +11.0987967289984 0.951134446793033 +11.123321518302 0.951134446793033 +11.1478463076055 0.99185579925512 +11.172371096909 0.878417745967878 +11.1968958862126 0.913321762363952 +11.2214206755161 0.919139098429965 +11.2459454648197 0.962769118925058 +11.2704702541232 0.922047766462971 +11.2949950434268 0.945317110727021 +11.3195198327303 1.06748116811328 +11.3440446220338 0.898778422198921 +11.3685694113374 0.968586454991071 +11.3930942006409 0.956951782859046 +11.4176189899445 0.997673135321133 +11.442143779248 1.03257715171721 +11.4666685685515 1.10529385254236 +11.4911933578551 1.15183254107046 +11.5157181471586 1.16055854516948 +11.5402429364622 1.06748116811328 +11.5647677257657 1.09947651647635 +11.5892925150692 1.23909258206065 +11.6138173043728 1.18964522549954 +11.6383420936763 1.30017461075378 +11.6628668829799 1.31762661895182 +11.6873916722834 1.20127989763157 +11.711916461587 1.25363592222568 +11.7364412508905 1.25363592222568 +11.760966040194 1.14892387303746 +11.7854908294976 1.17219321730151 +11.8100156188011 1.20709723369758 +11.8345404081047 1.13147186483942 +11.8590651974082 1.36125663944691 +11.8835899867117 1.21291456976359 +11.9081147760153 1.33216995911685 +11.9326395653188 1.27690526648973 +11.9571643546224 1.27108793042372 +11.9816891439259 1.28853993862175 +12.0062139332294 1.22164057386261 +12.030738722533 1.28563127058875 +12.0552635118365 1.27981393452274 +12.0797883011401 1.25654459025869 +12.1043130904436 1.37579997961194 +12.1288378797472 1.37870864764495 +12.1533626690507 1.35253063534789 +12.1778874583542 1.33798729518286 +12.2024122476578 1.404886659942 +12.2269370369613 1.50087270503121 +12.2514618262649 1.64921477471453 +12.2759866155684 1.65794077881354 +12.3005114048719 1.62594543045048 +12.3250361941755 1.72193147553968 +12.349560983479 1.7306574796387 +12.3740857727826 1.97498559441122 +12.3986105620861 1.91099489768509 +12.4231353513896 2.12914500016055 +12.4476601406932 2.11460165999552 +12.4721849299967 2.28330440590988 +12.4967097193003 2.32984309443798 +12.5212345086038 2.55671920101247 +12.5457592979074 2.46655049198927 +12.5702840872109 2.9464807174353 +12.5948088765144 2.95520672153432 +12.619333665818 3.01628875022745 +12.6438584551215 3.77545110684207 +12.6683832444251 3.94124518472343 +12.6929080337286 4.50261811509363 +12.7174328230321 4.4909834429616 +12.7419576123357 5.11343840202493 +12.7664824016392 5.92786545126667 +12.7910071909428 6.56777241852804 +12.8155319802463 8.03374110716317 +12.8400567695498 9.33682438594996 +12.8645815588534 11.6404894680909 +12.8891063481569 14.6684128904504 +12.9136311374605 18.2926132595761 +12.938155926764 23.4700423583272 +12.9626807160676 29.1448536907223 +12.9872055053711 36.8411893060568 +13.0117302946746 43.6794678516544 +13.0362550839782 49.6451459873501 +13.0607798732817 52.4549193072341 +13.0853046625853 51.0238546349951 +13.1098294518888 45.6224580977025 +13.1343542411923 38.9645169701513 +13.1588790304959 31.7713809245269 +13.1834038197994 24.3979074608562 +13.207928609103 18.5951147350088 +13.2324533984065 14.2611993658295 +13.25697818771 10.9220484639383 +13.2815029770136 8.60965737769841 +13.3060277663171 7.26876141448254 +13.3305525556207 6.27108827916141 +13.3550773449242 5.20651577908113 +13.3796021342278 4.70040754133805 +13.4041269235313 4.22047731589202 +13.4286517128348 3.68819106585188 +13.4531765021384 3.23734752073592 +13.4777012914419 3.02501475432647 +13.5022260807455 2.85631200841211 +13.526750870049 2.49854584035234 +13.5512756593525 2.40546846329614 +13.5758004486561 2.26294372967884 +13.6003252379596 1.9633509222792 +13.6248500272632 1.92844690588312 +13.6493748165667 1.77137883210079 +13.6738996058702 1.66666678291256 +13.6984243951738 1.66375811487956 +13.7229491844773 1.53577672142728 +13.7474739737809 1.37870864764495 +13.7719987630844 1.4514253484701 +13.796523552388 1.45433401650311 +13.8210483416915 1.2652705943577 +13.845573130995 1.31762661895182 +13.8700979202986 1.27690526648973 +13.8946227096021 1.18673655746654 +13.9191474989057 1.2158232377966 +13.9436722882092 1.28272260255574 +13.9681970775127 1.27108793042372 +13.9927218668163 1.14601520500445 +14.0172466561198 1.14019786893844 +14.0417714454234 1.21000590173059 +14.0662962347269 1.14601520500445 +14.0908210240304 1.04712049188224 +14.115345813334 1.11692852467439 +14.1398706026375 0.994764467288127 +14.1643953919411 1.11111118860838 +14.1889201812446 1.08202450827831 +14.2134449705482 1.08493317631132 +14.2379697598517 1.04130315581623 +14.2624945491552 1.09365918041034 +14.2870193384588 1.09075051237733 +14.3115441277623 1.10238518450936 +14.3360689170659 1.05002915991524 +14.3605937063694 1.04712049188224 +14.3851184956729 1.06457250008028 +14.4096432849765 1.16637588123549 +14.43416807428 1.12565452877341 +14.4586928635836 1.15764987713647 +14.4832176528871 1.18964522549954 +14.5077424421906 1.22745790992862 +14.5322672314942 1.21873190582961 +14.5567920207977 1.18382788943353 +14.5813168101013 1.37870864764495 +14.6058415994048 1.39906932387599 +14.6303663887084 1.43397334027207 +14.6548911780119 1.28853993862175 +14.6794159673154 1.56777206979035 +14.703940756619 1.48923803289918 +14.7284655459225 1.57649807388937 +14.7529903352261 1.85863887309097 +14.7775151245296 1.95753358621318 +14.8020399138331 2.13205366819356 +14.8265647031367 2.26876106574485 +14.8510894924402 2.69342659856376 +14.8756142817438 2.96102405760033 +14.9001390710473 3.31588155762709 +14.9246638603508 4.28155934458515 +14.9491886496544 5.34031450859942 +14.9737134389579 6.58522442672608 +14.9982382282615 8.61547471376442 +15.022763017565 10.779523730321 +15.0472878068686 12.5538112304548 +15.0718125961721 14.1826653289383 +15.0963373854756 14.8254809642327 +15.1208621747792 13.9790585666279 +15.1453869640827 12.8650387099865 +15.1699117533863 11.1547419065788 +15.1944365426898 9.36881973431303 +15.2189613319933 7.45782483662794 +15.2434861212969 5.78824938568237 +15.2680109106004 4.41826674213644 +15.292535699904 3.56602700846562 +15.3170604892075 3.05410143465653 +15.341585278511 2.52181518461639 +15.3661100678146 2.1058756558965 +15.3906348571181 2.03897629113736 +15.4151596464217 1.73356614767171 +15.4396844357252 1.61140209028544 +15.4642092250288 1.56486340175735 +15.4887340143323 1.4514253484701 +15.5132588036358 1.27690526648973 +15.5377835929394 1.27399659845672 +15.5623083822429 1.23618391402764 +15.5868331715465 1.14019786893844 +15.61135796085 0.986038463189108 +15.6358827501535 0.988947131222114 +15.6604075394571 1.04421182384923 +15.6849323287606 0.956951782859046 +15.7094571180642 0.933682438594996 +15.7339819073677 0.904595758264934 +15.7585066966712 0.817335717274747 +15.7830314859748 0.794066373010698 +15.8075562752783 0.788249036944685 +15.8320810645819 0.756253688581617 +15.8566058538854 0.767888360713642 +15.881130643189 0.782431700878673 +15.9056554324925 0.747527684482598 +15.930180221796 0.750436352515604 +15.9547050110996 0.674810983657443 +15.9792298004031 0.767888360713642 +16.0037545897067 0.66899364759143 +16.0282793790102 0.651541639393393 +16.0528041683137 0.712623668086523 +16.0773289576173 0.593368278733268 +16.1018537469208 0.730075676284561 +16.1263785362244 0.639906967261368 +16.1509033255279 0.703897663987505 +16.1754281148314 0.64572430332738 +16.199952904135 0.703897663987505 +16.2244776934385 0.651541639393393 +16.2490024827421 0.677719651690449 +16.2735272720456 0.622454959063331 +16.2980520613492 0.602094282832287 +16.3225768506527 0.695171659888486 +16.3471016399562 0.631180963162349 +16.3716264292598 0.671902315624436 +16.3961512185633 0.570098934469219 +16.4206760078669 0.622454959063331 +16.4452007971704 0.567190266436213 +16.4697255864739 0.613728954964312 +16.4942503757775 0.53810358610615 +16.518775165081 0.64572430332738 +16.5432999543846 0.66899364759143 +16.5678247436881 0.660267643492411 +16.5923495329916 0.578824938568237 +16.6168743222952 0.642815635294374 +16.6413991115987 0.558464262337194 +16.6659239009023 0.6079116188983 +16.6904486902058 0.622454959063331 +16.7149734795094 0.680628319723455 +16.7394982688129 0.575916270535231 +16.7640230581164 0.654450307426399 +16.78854784742 0.593368278733268 +16.8130726367235 0.541012254139157 +16.8375974260271 0.578824938568237 +16.8621222153306 0.628272295129343 +16.8866470046341 0.573007602502225 +16.9111717939377 0.590459610700262 +16.9356965832412 0.567190266436213 +16.9602213725448 0.532286250040138 +16.9847461618483 0.602094282832287 +17.0092709511518 0.5613729303702 +17.0337957404554 0.546829590205169 +17.0583205297589 0.570098934469219 +17.0828453190625 0.546829590205169 +17.107370108366 0.517742909875107 +17.1318948976696 0.613728954964312 +17.1564196869731 0.546829590205169 +17.1809444762766 0.53810358610615 +17.2054692655802 0.517742909875107 +17.2299940548837 0.555555594304188 +17.2545188441873 0.5613729303702 +17.2790436334908 0.520651577908113 +17.3035684227943 0.543920922172163 +17.3280932120979 0.497382233644063 +17.3526180014014 0.491564897578051 +17.377142790705 0.5613729303702 +17.4016675800085 0.575916270535231 +17.426192369312 0.546829590205169 +17.4507171586156 0.541012254139157 +17.4752419479191 0.546829590205169 +17.4997667372227 0.488656229545045 +17.5242915265262 0.514834241842101 +17.5488163158298 0.503199569710076 +17.5733411051333 0.485747561512038 +17.5978658944368 0.596276946766275 +17.6223906837404 0.555555594304188 +17.6469154730439 0.517742909875107 +17.6714402623475 0.526468913974126 +17.695965051651 0.532286250040138 +17.7204898409545 0.596276946766275 +17.7450146302581 0.573007602502225 +17.7695394195616 0.471204221347007 +17.7940642088652 0.447934877082958 +17.8185889981687 0.555555594304188 +17.8431137874722 0.555555594304188 +17.8676385767758 0.526468913974126 +17.8921633660793 0.485747561512038 +17.9166881553829 0.541012254139157 +17.9412129446864 0.482838893479032 +17.96573773399 0.546829590205169 +17.9902625232935 0.526468913974126 +18.014787312597 0.541012254139157 +18.0393121019006 0.450843545115964 +18.0638368912041 0.491564897578051 +18.0883616805077 0.500290901677069 +18.1128864698112 0.546829590205169 +18.1374112591147 0.465386885280995 +18.1619360484183 0.497382233644063 +18.1864608377218 0.485747561512038 +18.2109856270254 0.570098934469219 +18.2355104163289 0.552646926271182 +18.2600352056324 0.558464262337194 +18.284559994936 0.517742909875107 +18.3090847842395 0.552646926271182 +18.3336095735431 0.529377582007132 +18.3581343628466 0.567190266436213 +18.3826591521502 0.543920922172163 +18.4071839414537 0.535194918073144 +18.4317087307572 0.482838893479032 +18.4562335200608 0.509016905776088 +18.4807583093643 0.465386885280995 +18.5052830986679 0.468295553314001 +18.5298078879714 0.482838893479032 +18.5543326772749 0.497382233644063 +18.5788574665785 0.474112889380014 +18.603382255882 0.47702155741302 +18.6279070451856 0.511925573809094 +18.6524318344891 0.500290901677069 +18.6769566237926 0.526468913974126 +18.7014814130962 0.450843545115964 +18.7260062023997 0.514834241842101 +18.7505309917033 0.494473565611057 +18.7750557810068 0.494473565611057 +18.7995805703104 0.529377582007132 +18.8241053596139 0.491564897578051 +18.8486301489174 0.511925573809094 +18.873154938221 0.514834241842101 +18.8976797275245 0.593368278733268 +18.9222045168281 0.53810358610615 +18.9467293061316 0.587550942667256 +18.9712540954351 0.535194918073144 +18.9957788847387 0.625363627096337 +19.0203036740422 0.683536987756461 +19.0448284633458 0.6079116188983 +19.0693532526493 0.567190266436213 +19.0938780419528 0.671902315624436 +19.1184028312564 0.622454959063331 +19.1429276205599 0.660267643492411 +19.1674524098635 0.64572430332738 +19.191977199167 0.671902315624436 +19.2165019884706 0.625363627096337 +19.2410267777741 0.573007602502225 +19.2655515670776 0.619546291030324 +19.2900763563812 0.58464227463425 +19.3146011456847 0.666084979558424 +19.3391259349883 0.654450307426399 +19.3636507242918 0.535194918073144 +19.3881755135953 0.610820286931306 +19.4127003028989 0.567190266436213 +19.4372250922024 0.599185614799281 +19.461749881506 0.555555594304188 +19.4862746708095 0.546829590205169 +19.510799460113 0.555555594304188 +19.5353242494166 0.549738258238175 +19.5598490387201 0.593368278733268 +19.5843738280237 0.657358975459405 +19.6088986173272 0.543920922172163 +19.6334234066308 0.590459610700262 +19.6579481959343 0.53810358610615 +19.6824729852378 0.546829590205169 +19.7069977745414 0.573007602502225 +19.7315225638449 0.541012254139157 +19.7560473531485 0.5613729303702 +19.780572142452 0.613728954964312 +19.8050969317555 0.570098934469219 +19.8296217210591 0.613728954964312 +19.8541465103626 0.596276946766275 +19.8786712996662 0.628272295129343 +19.9031960889697 0.610820286931306 +19.9277208782732 0.514834241842101 +19.9522456675768 0.596276946766275 +19.9767704568803 0.64572430332738 +20.0012952461839 0.590459610700262 +20.0258200354874 0.596276946766275 +20.050344824791 0.570098934469219 +20.0748696140945 0.666084979558424 +20.099394403398 0.657358975459405 +20.1239191927016 0.558464262337194 +20.1484439820051 0.654450307426399 +20.1729687713087 0.703897663987505 +20.1974935606122 0.700988995954499 +20.2220183499157 0.625363627096337 +20.2465431392193 0.663176311525418 +20.2710679285228 0.724258340218548 +20.2955927178264 0.69226299185548 +20.3201175071299 0.802792377109716 +20.3446422964334 0.875509077934872 +20.369167085737 0.750436352515604 +20.3936918750405 0.732984344317567 +20.4182166643441 0.852239733670822 +20.4427414536476 0.875509077934872 +20.4672662429512 0.817335717274747 +20.4917910322547 0.881326414000884 +20.5163158215582 0.945317110727021 +20.5408406108618 0.927865102528984 +20.5653654001653 0.974403791057083 +20.5898901894689 0.90750442629794 +20.6144149787724 1.06166383204727 +20.6389397680759 1.11692852467439 +20.6634645573795 1.15183254107046 +20.687989346683 1.21873190582961 +20.7125141359866 1.29726594272077 +20.7370389252901 1.11401985664138 +20.7615637145936 1.2158232377966 +20.7860885038972 1.34962196731489 +20.8106132932007 1.36998264354593 +20.8351380825043 1.52995938536127 +20.8596628718078 1.47178602470115 +20.8841876611114 1.57068073782336 +20.9087124504149 1.63176276651649 +20.9332372397184 1.75392682390275 +20.957762029022 1.79464817636484 +20.9822868183255 1.77428750013379 +21.0068116076291 1.9662595903122 +21.0313363969326 2.18440969278767 +21.0558611862361 2.4781851641213 +21.0803859755397 2.68179192643173 +21.1049107648432 2.88539868874217 +21.1294355541468 3.27806887319801 +21.1539603434503 3.67946506175287 +21.1784851327538 4.3979060659054 +21.2030099220574 5.39267053319353 +21.2275347113609 6.38743500048165 +21.2520595006645 8.53112334080724 +21.276584289968 10.3635842016012 +21.3011090792716 13.3478776034655 +21.3256338685751 16.9982559848883 +21.3501586578786 20.6922643868062 +21.3746834471822 23.9586985878722 +21.3992082364857 26.4805137724886 +21.4237330257893 26.5474131372478 +21.4482578150928 25.3228638953521 +21.4727826043963 23.374056313238 +21.4973073936999 20.9278664974797 +21.5218321830034 19.173939673577 +21.546356972307 16.6928458414227 +21.5708817616105 13.586388382172 +21.595406550914 11.2623626238001 +21.6199313402176 8.92670219329608 +21.6444561295211 6.82373520543259 +21.6689809188247 5.73880202912127 +21.6935057081282 4.43571875033448 +21.7180304974318 3.94997118882244 +21.7425552867353 3.23734752073592 +21.7670800760388 2.95811538956732 +21.7916048653424 2.54217586084743 +21.8161296546459 2.2920304100089 +21.8406544439495 2.06515430343442 +21.865179233253 1.89063422145404 +21.8897040225565 1.74520081980373 +21.9142288118601 1.53577672142728 +21.9387536011636 1.50669004109722 +21.9632783904672 1.48342069683317 +21.9878031797707 1.25654459025869 +22.0123279690742 1.16637588123549 +22.0368527583778 1.13728920090543 +22.0613775476813 1.12856319680641 +22.0859023369849 1.05293782794825 +22.1104271262884 0.988947131222114 +22.134951915592 0.983129795156102 +22.1594767048955 0.974403791057083 +22.184001494199 0.933682438594996 +22.2085262835026 0.788249036944685 +22.2330510728061 0.863874405802847 +22.2575758621097 0.849331065637816 +22.2821006514132 0.814427049241741 +22.3066254407167 0.869691741868859 +22.3311502300203 0.802792377109716 +22.3556750193238 0.750436352515604 +22.3801998086274 0.846422397604809 +22.4047245979309 0.762071024647629 +22.4292493872344 0.709715000053517 +22.453774176538 0.759162356614623 +22.4782989658415 0.703897663987505 +22.5028237551451 0.738801680383579 +22.5273485444486 0.700988995954499 +22.5518733337522 0.712623668086523 +22.5763981230557 0.654450307426399 +22.6009229123592 0.747527684482598 +22.6254477016628 0.66899364759143 +22.6499724909663 0.654450307426399 +22.6744972802699 0.69226299185548 +22.6990220695734 0.686445655789467 +22.7235468588769 0.6079116188983 +22.7480716481805 0.674810983657443 +22.772596437484 0.53810358610615 +22.7971212267876 0.674810983657443 +22.8216460160911 0.6079116188983 +22.8461708053947 0.526468913974126 +22.8706955946982 0.575916270535231 +22.8952203840017 0.53810358610615 +22.9197451733053 0.605002950865293 +22.9442699626088 0.497382233644063 +22.9687947519124 0.546829590205169 +22.9933195412159 0.625363627096337 +23.0178443305194 0.570098934469219 +23.042369119823 0.529377582007132 +23.0668939091265 0.570098934469219 +23.0914186984301 0.567190266436213 +23.1159434877336 0.491564897578051 +23.1404682770371 0.558464262337194 +23.1649930663407 0.549738258238175 +23.1895178556442 0.509016905776088 +23.2140426449478 0.529377582007132 +23.2385674342513 0.546829590205169 +23.2630922235549 0.482838893479032 +23.2876170128584 0.494473565611057 +23.3121418021619 0.543920922172163 +23.3366665914655 0.605002950865293 +23.361191380769 0.503199569710076 +23.3857161700726 0.514834241842101 +23.4102409593761 0.58464227463425 +23.4347657486796 0.53810358610615 +23.4592905379832 0.541012254139157 +23.4838153272867 0.555555594304188 +23.5083401165903 0.596276946766275 +23.5328649058938 0.587550942667256 +23.5573896951973 0.529377582007132 +23.5819144845009 0.578824938568237 +23.6064392738044 0.628272295129343 +23.630964063108 0.593368278733268 +23.6554888524115 0.485747561512038 +23.6800136417151 0.625363627096337 +23.7045384310186 0.605002950865293 +23.7290632203221 0.634089631195356 +23.7535880096257 0.651541639393393 +23.7781127989292 0.590459610700262 +23.8026375882328 0.625363627096337 +23.8271623775363 0.605002950865293 +23.8516871668398 0.703897663987505 +23.8762119561434 0.596276946766275 +23.9007367454469 0.651541639393393 +23.9252615347505 0.674810983657443 +23.949786324054 0.619546291030324 +23.9743111133575 0.666084979558424 +23.9988359026611 0.689354323822474 +24.0233606919646 0.709715000053517 +24.0478854812682 0.634089631195356 +24.0724102705717 0.759162356614623 +24.0969350598753 0.718441004152536 +24.1214598491788 0.796975041043704 +24.1459846384823 0.895869754165915 +24.1705094277859 0.744619016449592 +24.1950342170894 0.866783073835853 +24.219559006393 0.843513729571803 +24.2440837956965 0.919139098429965 +24.268608585 0.828970389406772 +24.2931333743036 0.828970389406772 +24.3176581636071 0.892961086132909 +24.3421829529107 0.924956434495977 +24.3667077422142 0.95404311482604 +24.3912325315177 0.942408442694015 +24.4157573208213 0.95404311482604 +24.4402821101248 0.939499774661008 +24.4648068994284 1.0762071722123 +24.4893316887319 1.16346721320249 +24.5138564780355 1.21000590173059 +24.538381267339 1.10529385254236 +24.5629060566425 1.25654459025869 +24.5874308459461 1.24490991812666 +24.6119556352496 1.31762661895182 +24.6364804245532 1.41652133207403 +24.6610052138567 1.37870864764495 +24.6855300031602 1.56195473372434 +24.7100547924638 1.62885409848348 +24.7345795817673 1.61431075831845 +24.7591043710709 1.74810948783674 +24.7836291603744 1.93426424194913 +24.8081539496779 1.95753358621318 +24.8326787389815 2.28621307394289 +24.857203528285 2.42582913952719 +24.8817283175886 2.57707987724351 +24.9062531068921 2.94066338136929 +24.9307778961957 3.81326379127115 +24.9553026854992 4.60442149624884 +24.9798274748027 5.38685319712752 +25.0043522641063 6.80919186526756 +25.0288770534098 8.66492207032552 +25.0534018427134 10.8638751032782 +25.0779266320169 13.577662378073 +25.1024514213204 16.4979650832113 +25.126976210624 19.2553823785012 +25.1515009999275 20.4886576244958 +25.1760257892311 20.5410136490899 +25.2005505785346 19.2175696940721 +25.2250753678381 17.751601005437 +25.2496001571417 16.3118103290989 +25.2741249464452 14.9214670093219 +25.2986497357488 14.5317054928991 +25.3231745250523 12.4607338533986 +25.3476993143559 10.7038983614629 +25.3722241036594 8.79872079984381 +25.3967488929629 7.17277536939333 +25.4212736822665 5.87841809470557 +25.44579847157 4.41826674213644 +25.4703232608736 3.85689381176624 +25.4948480501771 3.39441559451826 +25.5193728394806 2.79813864775198 +25.5438976287842 2.3880164550981 +25.5684224180877 2.1495056763916 +25.5929472073913 1.98371159851024 +25.6174719966948 1.90226889358607 +25.6419967859983 1.60267608618643 +25.6665215753019 1.54741139355931 +25.6910463646054 1.5415940574933 +25.715571153909 1.4514253484701 +25.7400959432125 1.33798729518286 +25.7646207325161 1.36998264354593 +25.7891455218196 1.31471795091881 +25.8136703111231 1.21291456976359 +25.8381951004267 1.14601520500445 +25.8627198897302 1.15764987713647 +25.8872446790338 1.14892387303746 +25.9117694683373 1.08202450827831 +25.9362942576408 1.18091922140052 +25.9608190469444 1.04421182384923 +25.9853438362479 1.23327524599464 +26.0098686255515 1.11692852467439 +26.034393414855 1.27981393452274 +26.0589182041585 1.24781858615967 +26.0834429934621 1.44560801240409 +26.1079677827656 1.58231540995538 +26.1324925720692 1.72774881160569 +26.1570173613727 1.92553823785012 +26.1815421506763 2.41128579936216 +26.2060669399798 2.76905196742192 +26.2305917292833 3.19662616827383 +26.2551165185869 3.96160586095447 +26.2796413078904 3.98487520521852 +26.304166097194 4.17393862736392 +26.3286908864975 3.98196653718551 +26.353215675801 3.9296105125914 +26.3777404651046 3.48749297157446 +26.4022652544081 3.46422362731041 +26.4267900437117 3.06573610678855 +26.4513148330152 2.82431666004904 +26.4758396223187 2.60325788954057 +26.5003644116223 2.32111709033896 +26.5248892009258 1.86445620915699 +26.5494139902294 1.46015135256912 +26.5739387795329 1.45433401650311 +26.5984635688365 1.23909258206065 +26.62298835814 1.19255389353255 +26.6475131474435 1.07911584024531 +26.6720379367471 0.869691741868859 +26.6965627260506 0.875509077934872 +26.7210875153542 0.770797028746648 +26.7456123046577 0.689354323822474 +26.7701370939612 0.683536987756461 +26.7946618832648 0.654450307426399 +26.8191866725683 0.651541639393393 +26.8437114618719 0.581733606601244 +26.8682362511754 0.58464227463425 +26.8927610404789 0.631180963162349 +26.9172858297825 0.555555594304188 +26.941810619086 0.514834241842101 +26.9663354083896 0.552646926271182 +26.9908601976931 0.573007602502225 +27.0153849869967 0.532286250040138 +27.0399097763002 0.407213524620871 +27.0644345656037 0.578824938568237 +27.0889593549073 0.514834241842101 +27.1134841442108 0.47702155741302 +27.1380089335144 0.506108237743082 +27.1625337228179 0.511925573809094 +27.1870585121214 0.488656229545045 +27.211583301425 0.494473565611057 +27.2361080907285 0.511925573809094 +27.2606328800321 0.497382233644063 +27.2851576693356 0.488656229545045 +27.3096824586391 0.506108237743082 +27.3342072479427 0.47702155741302 +27.3587320372462 0.459569549214982 +27.3832568265498 0.482838893479032 +27.4077816158533 0.340314159861727 +27.4323064051569 0.474112889380014 +27.4568311944604 0.43048286888492 +27.4813559837639 0.398487520521852 +27.5058807730675 0.506108237743082 +27.530405562371 0.404304856587864 +27.5549303516746 0.398487520521852 +27.5794551409781 0.398487520521852 +27.6039799302816 0.413030860686883 +27.6285047195852 0.488656229545045 +27.6530295088887 0.482838893479032 +27.6775542981923 0.389761516422833 +27.7020790874958 0.395578852488846 +27.7266038767993 0.363583504125777 +27.7511286661029 0.383944180356821 +27.7756534554064 0.418848196752895 +27.80017824471 0.354857500026759 +27.8247030340135 0.401396188554858 +27.8492278233171 0.375218176257802 +27.8737526126206 0.436300204950933 +27.8982774019241 0.340314159861727 +27.9228021912277 0.363583504125777 +27.9473269805312 0.392670184455839 +27.9718517698348 0.357766168059765 +27.9963765591383 0.395578852488846 +28.0209013484418 0.351948831993752 +28.0454261377454 0.459569549214982 +28.0699509270489 0.407213524620871 +28.0944757163525 0.389761516422833 +28.119000505656 0.389761516422833 +28.1435252949595 0.340314159861727 +28.1680500842631 0.410122192653877 +28.1925748735666 0.36940084019179 +28.2170996628702 0.360674836092771 +28.2416244521737 0.363583504125777 +28.2661492414773 0.381035512323815 +28.2906740307808 0.378126844290808 +28.3151988200843 0.337405491828721 +28.3397236093879 0.410122192653877 +28.3642483986914 0.389761516422833 +28.388773187995 0.36940084019179 +28.4132979772985 0.372309508224796 +28.437822766602 0.407213524620871 +28.4623475559056 0.340314159861727 +28.4868723452091 0.366492172158783 +28.5113971345127 0.407213524620871 +28.5359219238162 0.375218176257802 +28.5604467131197 0.424665532818908 +28.5849715024233 0.378126844290808 +28.6094962917268 0.36940084019179 +28.6340210810304 0.363583504125777 +28.6585458703339 0.386852848389827 +28.6830706596375 0.386852848389827 +28.707595448941 0.343222827894734 +28.7321202382445 0.410122192653877 +28.7566450275481 0.354857500026759 +28.7811698168516 0.395578852488846 +28.8056946061552 0.404304856587864 +28.8302193954587 0.378126844290808 +28.8547441847622 0.343222827894734 +28.8792689740658 0.381035512323815 +28.9037937633693 0.410122192653877 +28.9283185526729 0.340314159861727 +28.9528433419764 0.410122192653877 +28.9773681312799 0.354857500026759 +29.0018929205835 0.418848196752895 +29.026417709887 0.29959280739964 +29.0509424991906 0.424665532818908 +29.0754672884941 0.378126844290808 +29.0999920777977 0.351948831993752 +29.1245168671012 0.383944180356821 +29.1490416564047 0.36940084019179 +29.1735664457083 0.415939528719889 +29.1980912350118 0.421756864785902 +29.2226160243154 0.45375221314897 +29.2471408136189 0.424665532818908 +29.2716656029224 0.418848196752895 +29.296190392226 0.424665532818908 +29.3207151815295 0.424665532818908 +29.3452399708331 0.343222827894734 +29.3697647601366 0.398487520521852 +29.3942895494401 0.450843545115964 +29.4188143387437 0.479930225446026 +29.4433391280472 0.462478217247989 +29.4678639173508 0.386852848389827 +29.4923887066543 0.462478217247989 +29.5169134959579 0.450843545115964 +29.5414382852614 0.482838893479032 +29.5659630745649 0.47702155741302 +29.5904878638685 0.433391536917926 +29.615012653172 0.459569549214982 +29.6395374424756 0.421756864785902 +29.6640622317791 0.491564897578051 +29.6885870210826 0.450843545115964 +29.7131118103862 0.456660881181976 +29.7376365996897 0.523560245941119 +29.7621613889933 0.520651577908113 +29.7866861782968 0.503199569710076 +29.8112109676003 0.485747561512038 +29.8357357569039 0.526468913974126 +29.8602605462074 0.541012254139157 +29.884785335511 0.485747561512038 +29.9093101248145 0.514834241842101 +29.9338349141181 0.497382233644063 +29.9583597034216 0.543920922172163 +29.9828844927251 0.570098934469219 +30.0074092820287 0.575916270535231 +30.0319340713322 0.564281598403206 +30.0564588606358 0.590459610700262 +30.0809836499393 0.590459610700262 +30.1055084392428 0.654450307426399 +30.1300332285464 0.732984344317567 +30.1545580178499 0.735893012350573 +30.1790828071535 0.796975041043704 +30.203607596457 0.834787725472785 +30.2281323857605 1.01512514351917 +30.2526571750641 1.09365918041034 +30.2771819643676 1.15474120910347 +30.3017067536712 1.4950553689652 +30.3262315429747 1.84118686489294 +30.3507563322783 2.22222237721675 +30.3752811215818 2.7574172952899 +30.3998059108853 3.35660291008918 +30.4243307001889 4.00814454948257 +30.4488554894924 3.99941854538355 +30.473380278796 4.09831325850576 +30.4979050680995 3.68819106585188 +30.522429857403 3.42641094288132 +30.5469546467066 3.08318811498659 +30.5714794360101 2.87376401661014 +30.5960042253137 2.6207098977386 +30.6205290146172 2.73705661905885 +30.6450538039207 2.62361856577161 +30.6695785932243 2.24840038951381 +30.6941033825278 2.10005831983049 +30.7186281718314 1.64339743864851 +30.7431529611349 1.50087270503121 +30.7676777504385 1.21291456976359 +30.792202539742 1.0267598156512 +30.8167273290455 0.878417745967878 +30.8412521183491 0.817335717274747 +30.8657769076526 0.773705696779654 +30.8903016969562 0.738801680383579 +30.9148264862597 0.657358975459405 +30.9393512755632 0.552646926271182 +30.9638760648668 0.634089631195356 +30.9884008541703 0.660267643492411 +31.0129256434739 0.573007602502225 +31.0374504327774 0.552646926271182 +31.0619752220809 0.578824938568237 +31.0865000113845 0.494473565611057 +31.111024800688 0.555555594304188 +31.1355495899916 0.523560245941119 +31.1600743792951 0.485747561512038 +31.1845991685987 0.526468913974126 +31.2091239579022 0.485747561512038 +31.2336487472057 0.47702155741302 +31.2581735365093 0.520651577908113 +31.2826983258128 0.465386885280995 +31.3072231151164 0.389761516422833 +31.3317479044199 0.465386885280995 +31.3562726937234 0.471204221347007 +31.380797483027 0.520651577908113 +31.4053222723305 0.424665532818908 +31.4298470616341 0.439208872983939 +31.4543718509376 0.415939528719889 +31.4788966402411 0.468295553314001 +31.5034214295447 0.433391536917926 +31.5279462188482 0.442117541016945 +31.5524710081518 0.418848196752895 +31.5769957974553 0.53810358610615 +31.6015205867589 0.45375221314897 +31.6260453760624 0.36940084019179 +31.6505701653659 0.450843545115964 +31.6750949546695 0.462478217247989 +31.699619743973 0.447934877082958 +31.7241445332766 0.418848196752895 +31.7486693225801 0.456660881181976 +31.7731941118836 0.424665532818908 +31.7977189011872 0.447934877082958 +31.8222436904907 0.410122192653877 +31.8467684797943 0.445026209049951 +31.8712932690978 0.47702155741302 +31.8958180584013 0.471204221347007 +31.9203428477049 0.535194918073144 +31.9448676370084 0.564281598403206 +31.969392426312 0.479930225446026 +31.9939172156155 0.514834241842101 +32.0184420049191 0.532286250040138 +32.0429667942226 0.503199569710076 +32.0674915835261 0.5613729303702 +32.0920163728297 0.462478217247989 +32.1165411621332 0.520651577908113 +32.1410659514368 0.564281598403206 +32.1655907407403 0.555555594304188 +32.1901155300438 0.573007602502225 +32.2146403193474 0.581733606601244 +32.2391651086509 0.549738258238175 +32.2636898979545 0.529377582007132 +32.288214687258 0.6079116188983 +32.3127394765615 0.596276946766275 +32.3372642658651 0.605002950865293 +32.3617890551686 0.523560245941119 +32.3863138444722 0.610820286931306 +32.4108386337757 0.642815635294374 +32.4353634230793 0.709715000053517 +32.4598882123828 0.5613729303702 +32.4844130016863 0.66899364759143 +32.5089377909899 0.610820286931306 +32.5334625802934 0.619546291030324 +32.557987369597 0.698080327921492 +32.5825121589005 0.698080327921492 +32.607036948204 0.762071024647629 +32.6315617375076 0.747527684482598 +32.6560865268111 0.680628319723455 +32.6806113161147 0.721349672185542 +32.7051361054182 0.817335717274747 +32.7296608947217 0.671902315624436 +32.7541856840253 0.741710348416586 +32.7787104733288 0.814427049241741 +32.8032352626324 0.843513729571803 +32.8277600519359 0.933682438594996 +32.8522848412395 0.916230430396959 +32.876809630543 1.13147186483942 +32.9013344198465 1.05584649598126 +32.9258592091501 1.1227458607404 +32.9503839984536 1.18382788943353 +32.9749087877572 1.38743465174397 +32.9994335770607 1.55613739765833 +33.0239583663642 1.69575346324262 +33.0484831556678 1.93717290998214 +33.0730079449713 2.36183844280105 +33.0975327342749 2.71669594282781 +33.1220575235784 3.21116950843887 +33.1465823128819 4.01396188554858 +33.1711071021855 5.23269379137819 +33.195631891489 6.06748151685097 +33.2201566807926 7.24258340218548 +33.2446814700961 7.59744090221224 +33.2692062593997 7.92321172190894 +33.2937310487032 7.9988370907671 +33.3182558380067 7.26294407841653 +33.3427806273103 6.50669038983491 +33.3673054166138 6.2216409226003 +33.3918302059174 5.72135002092323 +33.4163549952209 5.45666122991967 +33.4408797845244 5.39267053319353 +33.465404573828 5.2414197954772 +33.4899293631315 4.8632929511864 +33.5144541524351 4.38918006180638 +33.5389789417386 3.80453778717213 +33.5635037310421 3.01628875022745 +33.5880285203457 2.77777797152094 +33.6125533096492 2.1495056763916 +33.6370780989528 1.9197209017841 +33.6616028882563 1.68993612717661 +33.6861276775599 1.50959870913023 +33.7106524668634 1.43106467223906 +33.7351772561669 1.5445027255263 +33.7597020454705 1.34380463124887 +33.784226834774 1.29435727468777 +33.8087516240776 1.23327524599464 +33.8332764133811 1.29726594272077 +33.8578012026846 1.35253063534789 +33.8823259919882 1.40779532797501 +33.9068507812917 1.5445027255263 +33.9313755705953 1.61431075831845 +33.9559003598988 1.81210018456287 +33.9804251492023 1.93426424194913 +34.0049499385059 2.29493907804191 +34.0294747278094 2.81849932398303 +34.053999517113 3.33624223385813 +34.0785243064165 3.93833651669042 +34.1030490957201 4.73822022576713 +34.1275738850236 5.30831916023635 +34.1520986743271 5.27632381187328 +34.1766234636307 5.40139653729255 +34.2011482529342 5.18615510285009 +34.2256730422378 4.46480543066455 +34.2501978315413 4.0692265781757 +34.2747226208448 3.9296105125914 +34.2992474101484 3.7870857789741 +34.3237721994519 3.51657965190452 +34.3482969887555 3.31006422156108 +34.372821778059 3.30133821746206 +34.3973465673625 3.2286215166369 +34.4218713566661 2.63234456987063 +34.4463961459696 2.13205366819356 +34.4709209352732 1.86736487718999 +34.4954457245767 1.55613739765833 +34.5199705138803 1.38161731567795 +34.5444953031838 1.34962196731489 +34.5690200924873 1.19255389353255 +34.5935448817909 0.901687090231928 +34.6180696710944 0.872600409901865 +34.642594460398 0.791157704977691 +34.6671192497015 0.860965737769841 +34.691644039005 0.782431700878673 +34.7161688283086 0.747527684482598 +34.7406936176121 0.680628319723455 +34.7652184069157 0.599185614799281 +34.7897431962192 0.66899364759143 +34.8142679855227 0.639906967261368 +34.8387927748263 0.622454959063331 +34.8633175641298 0.634089631195356 +34.8878423534334 0.596276946766275 +34.9123671427369 0.610820286931306 +34.9368919320405 0.500290901677069 +34.961416721344 0.532286250040138 +34.9859415106475 0.634089631195356 +35.0104662999511 0.567190266436213 +35.0349910892546 0.526468913974126 +35.0595158785582 0.526468913974126 +35.0840406678617 0.520651577908113 +35.1085654571652 0.526468913974126 +35.1330902464688 0.541012254139157 +35.1576150357723 0.488656229545045 +35.1821398250759 0.482838893479032 +35.2066646143794 0.488656229545045 +35.2311894036829 0.465386885280995 +35.2557141929865 0.445026209049951 +35.28023898229 0.456660881181976 +35.3047637715936 0.450843545115964 +35.3292885608971 0.479930225446026 +35.3538133502007 0.514834241842101 +35.3783381395042 0.459569549214982 +35.4028629288077 0.442117541016945 +35.4273877181113 0.494473565611057 +35.4519125074148 0.520651577908113 +35.4764372967184 0.491564897578051 +35.5009620860219 0.500290901677069 +35.5254868753254 0.439208872983939 +35.550011664629 0.43048286888492 +35.5745364539325 0.436300204950933 +35.5990612432361 0.479930225446026 +35.6235860325396 0.424665532818908 +35.6481108218431 0.482838893479032 +35.6726356111467 0.482838893479032 +35.6971604004502 0.509016905776088 +35.7216851897538 0.433391536917926 +35.7462099790573 0.43048286888492 +35.7707347683609 0.479930225446026 +35.7952595576644 0.43048286888492 +35.8197843469679 0.523560245941119 +35.8443091362715 0.485747561512038 +35.868833925575 0.445026209049951 +35.8933587148786 0.415939528719889 +35.9178835041821 0.459569549214982 +35.9424082934856 0.471204221347007 +35.9669330827892 0.415939528719889 +35.9914578720927 0.413030860686883 +36.0159826613963 0.445026209049951 +36.0405074506998 0.479930225446026 +36.0650322400033 0.462478217247989 +36.0895570293069 0.468295553314001 +36.1140818186104 0.523560245941119 +36.138606607914 0.413030860686883 +36.1631313972175 0.47702155741302 +36.1876561865211 0.485747561512038 +36.2121809758246 0.491564897578051 +36.2367057651281 0.506108237743082 +36.2612305544317 0.494473565611057 +36.2857553437352 0.462478217247989 +36.3102801330388 0.47702155741302 +36.3348049223423 0.43048286888492 +36.3593297116458 0.511925573809094 +36.3838545009494 0.503199569710076 +36.4083792902529 0.474112889380014 +36.4329040795565 0.491564897578051 +36.45742886886 0.552646926271182 +36.4819536581635 0.532286250040138 +36.5064784474671 0.494473565611057 +36.5310032367706 0.58464227463425 +36.5555280260742 0.500290901677069 +36.5800528153777 0.532286250040138 +36.6045776046813 0.555555594304188 +36.6291023939848 0.578824938568237 +36.6536271832883 0.619546291030324 +36.6781519725919 0.541012254139157 +36.7026767618954 0.543920922172163 +36.727201551199 0.5613729303702 +36.7517263405025 0.58464227463425 +36.776251129806 0.570098934469219 +36.8007759191096 0.511925573809094 +36.8253007084131 0.590459610700262 +36.8498254977167 0.648632971360387 +36.8743502870202 0.628272295129343 +36.8988750763237 0.66899364759143 +36.9233998656273 0.625363627096337 +36.9479246549308 0.703897663987505 +36.9724494442344 0.764979692680635 +36.9969742335379 0.703897663987505 +37.0214990228415 0.756253688581617 +37.046023812145 0.721349672185542 +37.0705486014485 0.788249036944685 +37.0950733907521 0.869691741868859 +37.1195981800556 0.805701045142722 +37.1441229693592 0.901687090231928 +37.1686477586627 0.945317110727021 +37.1931725479662 1.10529385254236 +37.2176973372698 1.14019786893844 +37.2422221265733 1.27981393452274 +37.2667469158769 1.37579997961194 +37.2912717051804 1.41652133207403 +37.3157964944839 1.80046551243085 +37.3403212837875 1.97789426244423 +37.364846073091 2.39674245919712 +37.3893708623946 2.85049467234609 +37.4138956516981 3.65328704945581 +37.4384204410017 4.40663207000442 +37.4629452303052 5.29377582007132 +37.4874700196087 6.08784219308201 +37.5119948089123 6.67248446771626 +37.5365195982158 6.9691686070829 +37.5610443875194 6.62012844312215 +37.5855691768229 6.06166418078496 +37.6100939661264 5.30541049220334 +37.63461875543 4.89819696758247 +37.6591435447335 4.54915680362172 +37.6836683340371 4.35718471344331 +37.7081931233406 4.34555004131129 +37.7327179126441 4.2553813322881 +37.7572427019477 4.49680077902761 +37.7817674912512 3.81617245930416 +37.8062922805548 3.61256569699372 +37.8308170698583 3.06864477482156 +37.8553418591619 2.68179192643173 +37.8798666484654 2.16114034852362 +37.9043914377689 1.93135557391613 +37.9289162270725 1.70157079930864 +37.953441016376 1.27690526648973 +37.9779658056796 1.13728920090543 +38.0024905949831 1.13147186483942 +38.0270153842866 0.866783073835853 +38.0515401735902 0.965677786958064 +38.0760649628937 0.898778422198921 +38.1005897521973 0.959860450892052 +38.1251145415008 0.875509077934872 +38.1496393308043 0.759162356614623 +38.1741641201079 0.709715000053517 +38.1986889094114 0.660267643492411 +38.223213698715 0.66899364759143 +38.2477384880185 0.666084979558424 +38.2722632773221 0.695171659888486 +38.2967880666256 0.587550942667256 +38.3213128559291 0.619546291030324 +38.3458376452327 0.698080327921492 +38.3703624345362 0.674810983657443 +38.3948872238398 0.689354323822474 +38.4194120131433 0.616637622997318 +38.4439368024468 0.541012254139157 +38.4684615917504 0.593368278733268 +38.4929863810539 0.497382233644063 +38.5175111703575 0.58464227463425 +38.542035959661 0.546829590205169 +38.5665607489645 0.660267643492411 +38.5910855382681 0.581733606601244 +38.6156103275716 0.590459610700262 +38.6401351168752 0.509016905776088 +38.6646599061787 0.558464262337194 +38.6891846954823 0.506108237743082 +38.7137094847858 0.575916270535231 +38.7382342740893 0.58464227463425 +38.7627590633929 0.520651577908113 +38.7872838526964 0.532286250040138 +38.811808642 0.549738258238175 +38.8363334313035 0.549738258238175 +38.860858220607 0.546829590205169 +38.8853830099106 0.514834241842101 +38.9099077992141 0.509016905776088 +38.9344325885177 0.541012254139157 +38.9589573778212 0.575916270535231 +38.9834821671247 0.45375221314897 +39.0080069564283 0.532286250040138 +39.0325317457318 0.567190266436213 +39.0570565350354 0.599185614799281 +39.0815813243389 0.53810358610615 +39.1061061136425 0.602094282832287 +39.130630902946 0.497382233644063 +39.1551556922495 0.581733606601244 +39.1796804815531 0.657358975459405 +39.2042052708566 0.564281598403206 +39.2287300601602 0.549738258238175 +39.2532548494637 0.596276946766275 +39.2777796387672 0.596276946766275 +39.3023044280708 0.587550942667256 +39.3268292173743 0.599185614799281 +39.3513540066779 0.657358975459405 +39.3758787959814 0.610820286931306 +39.4004035852849 0.634089631195356 +39.4249283745885 0.671902315624436 +39.449453163892 0.721349672185542 +39.4739779531956 0.66899364759143 +39.4985027424991 0.730075676284561 +39.5230275318027 0.791157704977691 +39.5475523211062 0.90750442629794 +39.5720771104097 0.968586454991071 +39.5966018997133 1.07038983614629 +39.6211266890168 1.08493317631132 +39.6456514783204 1.1227458607404 +39.6701762676239 1.44560801240409 +39.6947010569274 1.55613739765833 +39.719225846231 1.97789426244423 +39.7437506355345 2.19313569688669 +39.7682754248381 2.42582913952719 +39.7928002141416 3.17335682400978 +39.8173250034451 3.93542784865741 +39.8418497927487 4.68586420117302 +39.8663745820522 5.3315885045004 +39.8908993713558 5.76788870945133 +39.9154241606593 5.44793522582065 +39.9399489499629 5.33740584056641 +39.9644737392664 4.7236768856021 +39.9889985285699 4.31937202901423 +40.0135233178735 3.5573010043666 +40.038048107177 3.53112299206955 +40.0625728964806 3.43804561501335 +40.0870976857841 3.48458430354145 +40.1116224750876 3.56020967239961 +40.1361472643912 3.26352553303298 +40.1606720536947 3.35951157812218 +40.1851968429983 2.98720206989739 +40.2097216323018 2.53054118871541 +40.2342464216053 2.2454917214808 +40.2587712109089 1.83827819685993 +40.2832960002124 1.56486340175735 +40.307820789516 1.37289131157893 +40.3323455788195 1.16346721320249 +40.3568703681231 1.06166383204727 +40.3813951574266 0.968586454991071 +40.4059199467301 0.933682438594996 +40.4304447360337 0.794066373010698 +40.4549695253372 0.79988370907671 +40.4794943146408 0.782431700878673 +40.5040191039443 0.703897663987505 +40.5285438932478 0.689354323822474 +40.5530686825514 0.642815635294374 +40.5775934718549 0.642815635294374 +40.6021182611585 0.628272295129343 +40.626643050462 0.570098934469219 +40.6511678397655 0.570098934469219 +40.6756926290691 0.532286250040138 +40.7002174183726 0.543920922172163 +40.7247422076762 0.450843545115964 +40.7492669969797 0.497382233644063 +40.7737917862833 0.511925573809094 +40.7983165755868 0.546829590205169 +40.8228413648903 0.450843545115964 +40.8473661541939 0.506108237743082 +40.8718909434974 0.474112889380014 +40.896415732801 0.535194918073144 +40.9209405221045 0.485747561512038 +40.945465311408 0.413030860686883 +40.9699901007116 0.485747561512038 +40.9945148900151 0.407213524620871 +41.0190396793187 0.445026209049951 +41.0435644686222 0.433391536917926 +41.0680892579257 0.439208872983939 +41.0926140472293 0.462478217247989 +41.1171388365328 0.479930225446026 +41.1416636258364 0.407213524620871 +41.1661884151399 0.401396188554858 +41.1907132044435 0.418848196752895 +41.215237993747 0.413030860686883 +41.2397627830505 0.43048286888492 +41.2642875723541 0.407213524620871 +41.2888123616576 0.45375221314897 +41.3133371509612 0.459569549214982 +41.3378619402647 0.447934877082958 +41.3623867295682 0.418848196752895 +41.3869115188718 0.392670184455839 +41.4114363081753 0.427574200851914 +41.4359610974789 0.386852848389827 +41.4604858867824 0.404304856587864 +41.4850106760859 0.421756864785902 +41.5095354653895 0.395578852488846 +41.534060254693 0.407213524620871 +41.5585850439966 0.392670184455839 +41.5831098333001 0.439208872983939 +41.6076346226037 0.398487520521852 +41.6321594119072 0.395578852488846 +41.6566842012107 0.415939528719889 +41.6812089905143 0.445026209049951 +41.7057337798178 0.418848196752895 +41.7302585691214 0.407213524620871 +41.7547833584249 0.349040163960746 +41.7793081477284 0.363583504125777 +41.803832937032 0.413030860686883 +41.8283577263355 0.360674836092771 +41.8528825156391 0.375218176257802 +41.8774073049426 0.410122192653877 +41.9019320942461 0.36940084019179 +41.9264568835497 0.398487520521852 +41.9509816728532 0.372309508224796 +41.9755064621568 0.381035512323815 +42.0000312514603 0.401396188554858 +42.0245560407639 0.445026209049951 +42.0490808300674 0.366492172158783 +42.0736056193709 0.334496823795715 +42.0981304086745 0.404304856587864 +42.122655197978 0.378126844290808 +42.1471799872816 0.366492172158783 +42.1717047765851 0.360674836092771 +42.1962295658886 0.381035512323815 +42.2207543551922 0.354857500026759 +42.2452791444957 0.366492172158783 +42.2698039337993 0.354857500026759 +42.2943287231028 0.378126844290808 +42.3188535124063 0.418848196752895 +42.3433783017099 0.386852848389827 +42.3679030910134 0.360674836092771 +42.392427880317 0.404304856587864 +42.4169526696205 0.442117541016945 +42.4414774589241 0.381035512323815 +42.4660022482276 0.32286215166369 +42.4905270375311 0.378126844290808 +42.5150518268347 0.418848196752895 +42.5395766161382 0.462478217247989 +42.5641014054418 0.354857500026759 +42.5886261947453 0.366492172158783 +42.6131509840488 0.404304856587864 +42.6376757733524 0.372309508224796 +42.6622005626559 0.415939528719889 +42.6867253519595 0.447934877082958 +42.711250141263 0.383944180356821 +42.7357749305665 0.395578852488846 +42.7602997198701 0.509016905776088 +42.7848245091736 0.427574200851914 +42.8093492984772 0.418848196752895 +42.8338740877807 0.450843545115964 +42.8583988770843 0.386852848389827 +42.8829236663878 0.378126844290808 +42.9074484556913 0.433391536917926 +42.9319732449949 0.43048286888492 +42.9564980342984 0.474112889380014 +42.981022823602 0.479930225446026 +43.0055476129055 0.45375221314897 +43.030072402209 0.482838893479032 +43.0545971915126 0.410122192653877 +43.0791219808161 0.474112889380014 +43.1036467701197 0.482838893479032 +43.1281715594232 0.494473565611057 +43.1526963487267 0.529377582007132 +43.1772211380303 0.427574200851914 +43.2017459273338 0.474112889380014 +43.2262707166374 0.541012254139157 +43.2507955059409 0.573007602502225 +43.2753202952445 0.587550942667256 +43.299845084548 0.66899364759143 +43.3243698738515 0.613728954964312 +43.3488946631551 0.671902315624436 +43.3734194524586 0.759162356614623 +43.3979442417622 0.802792377109716 +43.4224690310657 0.866783073835853 +43.4469938203692 1.00639913942015 +43.4715186096728 1.23618391402764 +43.4960433989763 1.42524733617305 +43.5205681882799 1.6375801025825 +43.5450929775834 1.92262956981711 +43.569617766887 2.1029669878635 +43.5941425561905 2.13787100425957 +43.618667345494 2.13205366819356 +43.6431921347976 2.07678897556644 +43.6677169241011 1.90808622965208 +43.6922417134047 1.9168122337511 +43.7167665027082 1.51541604519624 +43.7412912920117 1.50669004109722 +43.7658160813153 1.4485166804371 +43.7903408706188 1.36998264354593 +43.8148656599224 1.47760336076716 +43.8393904492259 1.53577672142728 +43.8639152385294 1.401977991909 +43.888440027833 1.46306002060213 +43.9129648171365 1.28272260255574 +43.9374896064401 1.33507862714985 +43.9620143957436 1.09656784844334 +43.9865391850472 0.956951782859046 +44.0110639743507 0.837696393505791 +44.0355887636542 0.892961086132909 +44.0601135529578 0.718441004152536 +44.0846383422613 0.680628319723455 +44.1091631315649 0.636998299228362 +44.1336879208684 0.64572430332738 +44.1582127101719 0.573007602502225 +44.1827374994755 0.593368278733268 +44.207262288779 0.58464227463425 +44.2317870780826 0.532286250040138 +44.2563118673861 0.575916270535231 +44.2808366566896 0.500290901677069 +44.3053614459932 0.625363627096337 +44.3298862352967 0.599185614799281 +44.3544110246003 0.555555594304188 +44.3789358139038 0.43048286888492 +44.4034606032074 0.47702155741302 +44.4279853925109 0.497382233644063 +44.4525101818144 0.459569549214982 +44.477034971118 0.506108237743082 +44.5015597604215 0.570098934469219 +44.5260845497251 0.511925573809094 +44.5506093390286 0.622454959063331 +44.5751341283321 0.520651577908113 +44.5996589176357 0.509016905776088 +44.6241837069392 0.517742909875107 +44.6487084962428 0.529377582007132 +44.6732332855463 0.529377582007132 +44.6977580748498 0.541012254139157 +44.7222828641534 0.590459610700262 +44.7468076534569 0.58464227463425 +44.7713324427605 0.593368278733268 +44.795857232064 0.494473565611057 +44.8203820213676 0.503199569710076 +44.8449068106711 0.570098934469219 +44.8694315999746 0.526468913974126 +44.8939563892782 0.610820286931306 +44.9184811785817 0.66899364759143 +44.9430059678853 0.619546291030324 +44.9675307571888 0.575916270535231 +44.9920555464923 0.552646926271182 +45.0165803357959 0.642815635294374 +45.0411051250994 0.660267643492411 +45.065629914403 0.610820286931306 +45.0901547037065 0.703897663987505 +45.11467949301 0.642815635294374 +45.1392042823136 0.674810983657443 +45.1637290716171 0.66899364759143 +45.1882538609207 0.721349672185542 +45.2127786502242 0.695171659888486 +45.2373034395278 0.738801680383579 +45.2618282288313 0.71553233611953 +45.2863530181348 0.794066373010698 +45.3108778074384 0.82315305334076 +45.3354025967419 0.913321762363952 +45.3599273860455 0.866783073835853 +45.384452175349 0.869691741868859 +45.4089769646525 1.09365918041034 +45.4335017539561 1.25072725419267 +45.4580265432596 1.15474120910347 +45.4825513325632 1.43688200830507 +45.5070761218667 1.53286805339428 +45.5316009111702 1.83536952882692 +45.5561257004738 2.30075641410792 +45.5806504897773 2.46364182395627 +45.6051752790809 3.01628875022745 +45.6297000683844 3.6009310248617 +45.654224857688 4.09831325850576 +45.6787496469915 4.76439823806419 +45.703274436295 4.92728364791253 +45.7277992255986 5.27632381187328 +45.7523240149021 5.24432846351021 +45.7768488042057 4.40954073803743 +45.8013735935092 4.1623039552319 +45.8258983828127 3.6969170699509 +45.8504231721163 3.25770819696696 +45.8749479614198 3.26352553303298 +45.8994727507234 2.91739403710524 +45.9239975400269 3.15008747974573 +45.9485223293304 3.28097754123101 +45.973047118634 3.275160205165 +45.9975719079375 3.09191411908561 +46.0220966972411 3.1820828281088 +46.0466214865446 2.92612004120426 +46.0711462758482 2.82431666004904 +46.0956710651517 2.35020377066902 +46.1201958544552 2.05351963130239 +46.1447206437588 1.97789426244423 +46.1692454330623 1.88772555342104 +46.1937702223659 1.67539278701158 +46.2182950116694 1.75974415996876 +46.2428198009729 1.71611413947367 +46.2673445902765 1.72774881160569 +46.29186937958 1.88481688538803 +46.3163941688836 2.12332766409454 +46.3409189581871 2.35602110673504 +46.3654437474906 2.63525323790363 +46.3899685367942 2.79522997971898 +46.4144933260977 2.74287395512486 +46.4390181154013 2.48691116822032 +46.4635429047048 2.56253653707848 +46.4880676940084 2.16695768458963 +46.5125924833119 2.07388030753343 +46.5371172726154 1.89936022555306 +46.561642061919 1.67248411897858 +46.5861668512225 1.50087270503121 +46.6106916405261 1.55613739765833 +46.6352164298296 1.78301350423281 +46.6597412191331 1.64048877061551 +46.6842660084367 1.83827819685993 +46.7087907977402 1.59395008208741 +46.7333155870438 1.70738813537465 +46.7578403763473 1.42815600420605 +46.7823651656508 1.29435727468777 +46.8068899549544 1.09365918041034 +46.8314147442579 1.16055854516948 +46.8559395335615 1.00930780745316 +46.880464322865 0.826061721373766 +46.9049891121686 0.782431700878673 +46.9295139014721 0.744619016449592 +46.9540386907756 0.628272295129343 +46.9785634800792 0.625363627096337 +47.0030882693827 0.66899364759143 +47.0276130586863 0.686445655789467 +47.0521378479898 0.613728954964312 +47.0766626372933 0.671902315624436 +47.1011874265969 0.605002950865293 +47.1257122159004 0.596276946766275 +47.150237005204 0.529377582007132 +47.1747617945075 0.590459610700262 +47.199286583811 0.567190266436213 +47.2238113731146 0.58464227463425 +47.2483361624181 0.494473565611057 +47.2728609517217 0.506108237743082 +47.2973857410252 0.506108237743082 +47.3219105303288 0.506108237743082 +47.3464353196323 0.506108237743082 +47.3709601089358 0.488656229545045 +47.3954848982394 0.491564897578051 +47.4200096875429 0.474112889380014 +47.4445344768465 0.439208872983939 +47.46905926615 0.509016905776088 +47.4935840554535 0.491564897578051 +47.5181088447571 0.424665532818908 +47.5426336340606 0.526468913974126 +47.5671584233642 0.424665532818908 +47.5916832126677 0.485747561512038 +47.6162080019712 0.410122192653877 +47.6407327912748 0.497382233644063 +47.6652575805783 0.424665532818908 +47.6897823698819 0.47702155741302 +47.7143071591854 0.410122192653877 +47.738831948489 0.503199569710076 +47.7633567377925 0.494473565611057 +47.787881527096 0.447934877082958 +47.8124063163996 0.442117541016945 +47.8369311057031 0.509016905776088 +47.8614558950067 0.36940084019179 +47.8859806843102 0.436300204950933 +47.9105054736137 0.392670184455839 +47.9350302629173 0.421756864785902 +47.9595550522208 0.485747561512038 +47.9840798415244 0.433391536917926 +48.0086046308279 0.433391536917926 +48.0331294201314 0.450843545115964 +48.057654209435 0.43048286888492 +48.0821789987385 0.474112889380014 +48.1067037880421 0.47702155741302 +48.1312285773456 0.43048286888492 +48.1557533666492 0.459569549214982 +48.1802781559527 0.421756864785902 +48.2048029452562 0.479930225446026 +48.2293277345598 0.523560245941119 +48.2538525238633 0.407213524620871 +48.2783773131669 0.494473565611057 +48.3029021024704 0.468295553314001 +48.3274268917739 0.410122192653877 +48.3519516810775 0.45375221314897 +48.376476470381 0.503199569710076 +48.4010012596846 0.474112889380014 +48.4255260489881 0.45375221314897 +48.4500508382916 0.599185614799281 +48.4745756275952 0.506108237743082 +48.4991004168987 0.462478217247989 +48.5236252062023 0.468295553314001 +48.5481499955058 0.442117541016945 +48.5726747848094 0.529377582007132 +48.5971995741129 0.555555594304188 +48.6217243634164 0.546829590205169 +48.64624915272 0.619546291030324 +48.6707739420235 0.6079116188983 +48.6952987313271 0.599185614799281 +48.7198235206306 0.762071024647629 +48.7443483099341 0.680628319723455 +48.7688730992377 0.680628319723455 +48.7933978885412 0.727167008251555 +48.8179226778448 0.770797028746648 +48.8424474671483 0.852239733670822 +48.8669722564518 0.994764467288127 +48.8914970457554 1.10820252057537 +48.9160218350589 1.24200125009366 +48.9405466243625 1.45433401650311 +48.965071413666 1.83536952882692 +48.9895962029696 1.94008157801515 +49.0141209922731 2.48981983625332 +49.0386457815766 2.60616655757357 +49.0631705708802 2.73414795102584 +49.0876953601837 2.83013399611505 +49.1122201494873 2.52181518461639 +49.1367449387908 2.31820842230596 +49.1612697280943 2.17277502065564 +49.1857945173979 1.75101815586974 +49.2103193067014 1.80046551243085 +49.234844096005 1.72774881160569 +49.2593688853085 1.50669004109722 +49.283893674612 1.58522407798839 +49.3084184639156 1.64921477471453 +49.3329432532191 1.60267608618643 +49.3574680425227 1.81791752062889 +49.3819928318262 1.72193147553968 +49.4065176211298 1.67830145504459 +49.4310424104333 1.50378137306421 +49.4555671997368 1.37870864764495 +49.4800919890404 1.28853993862175 +49.5046167783439 1.01512514351917 +49.5291415676475 0.968586454991071 +49.553666356951 0.919139098429965 +49.5781911462545 0.794066373010698 +49.6027159355581 0.811518381208735 +49.6272407248616 0.677719651690449 +49.6517655141652 0.64572430332738 +49.6762903034687 0.657358975459405 +49.7008150927722 0.628272295129343 +49.7253398820758 0.648632971360387 +49.7498646713793 0.485747561512038 +49.7743894606829 0.529377582007132 +49.7989142499864 0.546829590205169 +49.82343903929 0.535194918073144 +49.8479638285935 0.575916270535231 +49.872488617897 0.491564897578051 +49.8970134072006 0.413030860686883 +49.9215381965041 0.465386885280995 +49.9460629858077 0.447934877082958 +49.9705877751112 0.439208872983939 +49.9951125644147 0.509016905776088 +50.0196373537183 0.465386885280995 +50.0441621430218 0.436300204950933 +50.0686869323254 0.494473565611057 +50.0932117216289 0.424665532818908 +50.1177365109324 0.511925573809094 +50.142261300236 0.506108237743082 +50.1667860895395 0.450843545115964 +50.1913108788431 0.532286250040138 +50.2158356681466 0.488656229545045 +50.2403604574502 0.418848196752895 +50.2648852467537 0.517742909875107 +50.2894100360572 0.488656229545045 +50.3139348253608 0.506108237743082 +50.3384596146643 0.509016905776088 +50.3629844039679 0.520651577908113 +50.3875091932714 0.535194918073144 +50.4120339825749 0.482838893479032 +50.4365587718785 0.552646926271182 +50.461083561182 0.616637622997318 +50.4856083504856 0.471204221347007 +50.5101331397891 0.53810358610615 +50.5346579290926 0.439208872983939 +50.5591827183962 0.479930225446026 +50.5837075076997 0.514834241842101 +50.6082322970033 0.511925573809094 +50.6327570863068 0.619546291030324 +50.6572818756104 0.5613729303702 +50.6818066649139 0.570098934469219 +50.7063314542174 0.69226299185548 +50.730856243521 0.727167008251555 +50.7553810328245 0.718441004152536 +50.7799058221281 0.796975041043704 +50.8044306114316 0.788249036944685 +50.8289554007351 0.852239733670822 +50.8534801900387 1.17510188533451 +50.8780049793422 1.05875516401426 +50.9025297686458 1.30308327878679 +50.9270545579493 1.55904606569133 +50.9515793472528 1.79173950833183 +50.9761041365564 1.88190821735502 +51.0006289258599 1.94299024604815 +51.0251537151635 2.01570694687331 +51.049678504467 1.81791752062889 +51.0742032937706 1.75683549193576 +51.0987280830741 1.50087270503121 +51.1232528723776 1.41652133207403 +51.1477776616812 1.29726594272077 +51.1723024509847 1.20127989763157 +51.1968272402883 1.23327524599464 +51.2213520295918 1.10529385254236 +51.2458768188953 1.27108793042372 +51.2704016081989 1.27399659845672 +51.2949263975024 1.31762661895182 +51.319451186806 1.401977991909 +51.3439759761095 1.23618391402764 +51.368500765413 1.32344395501783 +51.3930255547166 1.27108793042372 +51.4175503440201 1.23618391402764 +51.4420751333237 1.30017461075378 +51.4665999226272 1.15474120910347 +51.4911247119308 1.2158232377966 +51.5156495012343 1.24781858615967 +51.5401742905378 1.33216995911685 +51.5646990798414 1.48923803289918 +51.5892238691449 1.50087270503121 +51.6137486584485 1.55613739765833 +51.638273447752 1.72484014357269 +51.6627982370555 1.68121012307759 +51.6873230263591 1.61721942635146 +51.7118478156626 1.36707397551292 +51.7363726049662 1.25654459025869 +51.7608973942697 1.24490991812666 +51.7854221835732 1.09656784844334 +51.8099469728768 1.00639913942015 +51.8344717621803 1.0296684836842 +51.8589965514839 0.872600409901865 +51.8835213407874 1.03839448778322 +51.908046130091 1.04712049188224 +51.9325709193945 1.11692852467439 +51.957095708698 1.15764987713647 +51.9816204980016 1.01221647548616 +52.0061452873051 1.01512514351917 +52.0306700766087 0.922047766462971 +52.0551948659122 0.895869754165915 +52.0797196552157 0.747527684482598 +52.1042444445193 0.767888360713642 +52.1287692338228 0.671902315624436 +52.1532940231264 0.706806332020511 +52.1778188124299 0.555555594304188 +52.2023436017334 0.488656229545045 +52.226868391037 0.447934877082958 +52.2513931803405 0.532286250040138 +52.2759179696441 0.471204221347007 +52.3004427589476 0.456660881181976 +52.3249675482512 0.462478217247989 +52.3494923375547 0.488656229545045 +52.3740171268582 0.439208872983939 +52.3985419161618 0.383944180356821 +52.4230667054653 0.459569549214982 +52.4475914947689 0.506108237743082 +52.4721162840724 0.401396188554858 +52.4966410733759 0.363583504125777 +52.5211658626795 0.509016905776088 +52.545690651983 0.488656229545045 +52.5702154412866 0.421756864785902 +52.5947402305901 0.468295553314001 +52.6192650198936 0.45375221314897 +52.6437898091972 0.378126844290808 +52.6683145985007 0.494473565611057 +52.6928393878043 0.395578852488846 +52.7173641771078 0.45375221314897 +52.7418889664114 0.413030860686883 +52.7664137557149 0.36940084019179 +52.7909385450184 0.398487520521852 +52.815463334322 0.418848196752895 +52.8399881236255 0.375218176257802 +52.8645129129291 0.413030860686883 +52.8890377022326 0.325770819696696 +52.9135624915361 0.410122192653877 +52.9380872808397 0.433391536917926 +52.9626120701432 0.363583504125777 +52.9871368594468 0.383944180356821 +53.0116616487503 0.357766168059765 +53.0361864380538 0.401396188554858 +53.0607112273574 0.343222827894734 +53.0852360166609 0.413030860686883 +53.1097608059645 0.375218176257802 +53.134285595268 0.407213524620871 +53.1588103845716 0.418848196752895 +53.1833351738751 0.386852848389827 +53.2078599631786 0.413030860686883 +53.2323847524822 0.395578852488846 +53.2569095417857 0.328679487729703 +53.2814343310893 0.287958135267616 +53.3059591203928 0.418848196752895 +53.3304839096963 0.372309508224796 +53.3550086989999 0.447934877082958 +53.3795334883034 0.447934877082958 +53.404058277607 0.410122192653877 +53.4285830669105 0.421756864785902 +53.453107856214 0.447934877082958 +53.4776326455176 0.418848196752895 +53.5021574348211 0.401396188554858 +53.5266822241247 0.372309508224796 +53.5512070134282 0.436300204950933 +53.5757318027318 0.424665532818908 +53.6002565920353 0.491564897578051 +53.6247813813388 0.392670184455839 +53.6493061706424 0.459569549214982 +53.6738309599459 0.407213524620871 +53.6983557492495 0.43048286888492 +53.722880538553 0.474112889380014 +53.7474053278565 0.439208872983939 +53.7719301171601 0.471204221347007 +53.7964549064636 0.450843545115964 +53.8209796957672 0.421756864785902 +53.8455044850707 0.500290901677069 +53.8700292743742 0.47702155741302 +53.8945540636778 0.474112889380014 +53.9190788529813 0.482838893479032 +53.9436036422849 0.602094282832287 +53.9681284315884 0.564281598403206 +53.992653220892 0.625363627096337 +54.0171780101955 0.625363627096337 +54.041702799499 0.730075676284561 +54.0662275888026 0.788249036944685 +54.0907523781061 0.939499774661008 +54.1152771674097 0.948225778760027 +54.1398019567132 0.90750442629794 +54.1643267460167 0.913321762363952 +54.1888515353203 0.817335717274747 +54.2133763246238 0.642815635294374 +54.2379011139274 0.738801680383579 +54.2624259032309 0.613728954964312 +54.2869506925344 0.721349672185542 +54.311475481838 0.602094282832287 +54.3360002711415 0.596276946766275 +54.3605250604451 0.619546291030324 +54.3850498497486 0.532286250040138 +54.4095746390522 0.671902315624436 +54.4340994283557 0.64572430332738 +54.4586242176592 0.689354323822474 +54.4831490069628 0.712623668086523 +54.5076737962663 0.654450307426399 +54.5321985855699 0.58464227463425 +54.5567233748734 0.634089631195356 +54.5812481641769 0.543920922172163 +54.6057729534805 0.535194918073144 +54.630297742784 0.573007602502225 +54.6548225320876 0.494473565611057 +54.6793473213911 0.485747561512038 +54.7038721106946 0.447934877082958 +54.7283968999982 0.514834241842101 +54.7529216893017 0.410122192653877 +54.7774464786053 0.436300204950933 +54.8019712679088 0.474112889380014 +54.8264960572124 0.479930225446026 +54.8510208465159 0.468295553314001 +54.8755456358194 0.494473565611057 +54.900070425123 0.401396188554858 +54.9245952144265 0.439208872983939 +54.9491200037301 0.456660881181976 +54.9736447930336 0.520651577908113 +54.9981695823371 0.488656229545045 +55.0226943716407 0.471204221347007 +55.0472191609442 0.506108237743082 +55.0717439502478 0.511925573809094 +55.0962687395513 0.491564897578051 +55.1207935288548 0.45375221314897 +55.1453183181584 0.526468913974126 +55.1698431074619 0.468295553314001 +55.1943678967655 0.543920922172163 +55.218892686069 0.47702155741302 +55.2434174753726 0.523560245941119 +55.2679422646761 0.535194918073144 +55.2924670539796 0.424665532818908 +55.3169918432832 0.47702155741302 +55.3415166325867 0.53810358610615 +55.3660414218903 0.549738258238175 +55.3905662111938 0.520651577908113 +55.4150910004973 0.506108237743082 +55.4396157898009 0.58464227463425 +55.4641405791044 0.567190266436213 +55.488665368408 0.587550942667256 +55.5131901577115 0.660267643492411 +55.537714947015 0.69226299185548 +55.5622397363186 0.69226299185548 +55.5867645256221 0.666084979558424 +55.6112893149257 0.709715000053517 +55.6358141042292 0.689354323822474 +55.6603388935328 0.866783073835853 +55.6848636828363 0.881326414000884 +55.7093884721398 1.03257715171721 +55.7339132614434 1.09365918041034 +55.7584380507469 1.26817926239071 +55.7829628400505 1.46015135256912 +55.807487629354 1.62012809438446 +55.8320124186575 1.90808622965208 +55.8565372079611 2.17859235672166 +55.8810619972646 2.38219911903209 +55.9055867865682 2.57998854527652 +55.9301115758717 2.7574172952899 +55.9546363651752 2.65561391413468 +55.9791611544788 2.35020377066902 +56.0036859437823 2.1495056763916 +56.0282107330859 1.98080293047723 +56.0527355223894 1.80337418046386 +56.077260311693 1.70738813537465 +56.1017851009965 1.41652133207403 +56.1263098903 1.41943000010703 +56.1508346796036 1.46887735666814 +56.1753594689071 1.50669004109722 +56.1998842582107 1.51832471322925 +56.2244090475142 1.61721942635146 +56.2489338368177 1.78592217226582 +56.2734586261213 1.68121012307759 +56.2979834154248 1.70447946734164 +56.3225082047284 1.68121012307759 +56.3470329940319 1.75101815586974 +56.3715577833354 1.73647481570471 +56.396082572639 1.62012809438446 +56.4206073619425 1.4514253484701 +56.4451321512461 1.47469469273415 +56.4696569405496 1.62012809438446 +56.4941817298532 1.48923803289918 +56.5187065191567 1.46015135256912 +56.5432313084602 1.51250737716323 +56.5677560977638 1.25654459025869 +56.5922808870673 1.27981393452274 +56.6168056763709 1.25363592222568 +56.6413304656744 1.05002915991524 +56.6658552549779 1.03548581975021 +56.6903800442815 0.974403791057083 +56.714904833585 0.88423508203389 +56.7394296228886 0.785340368911679 +56.7639544121921 0.831879057439778 +56.7884792014956 0.933682438594996 +56.8130039907992 0.945317110727021 +56.8375287801027 0.866783073835853 +56.8620535694063 0.95404311482604 +56.8865783587098 1.0267598156512 +56.9111031480134 1.01221647548616 +56.9356279373169 0.866783073835853 +56.9601527266204 0.820244385307754 +56.984677515924 0.738801680383579 +57.0092023052275 0.718441004152536 +57.0337270945311 0.648632971360387 +57.0582518838346 0.596276946766275 +57.0827766731381 0.575916270535231 +57.1073014624417 0.564281598403206 +57.1318262517452 0.6079116188983 +57.1563510410488 0.517742909875107 +57.1808758303523 0.5613729303702 +57.2054006196558 0.546829590205169 +57.2299254089594 0.439208872983939 +57.2544501982629 0.532286250040138 +57.2789749875665 0.482838893479032 +57.30349977687 0.479930225446026 +57.3280245661736 0.497382233644063 +57.3525493554771 0.535194918073144 +57.3770741447806 0.546829590205169 +57.4015989340842 0.459569549214982 +57.4261237233877 0.558464262337194 +57.4506485126913 0.500290901677069 +57.4751733019948 0.488656229545045 +57.4996980912983 0.491564897578051 +57.5242228806019 0.447934877082958 +57.5487476699054 0.433391536917926 +57.573272459209 0.488656229545045 +57.5977972485125 0.497382233644063 +57.622322037816 0.494473565611057 +57.6468468271196 0.491564897578051 +57.6713716164231 0.462478217247989 +57.6958964057267 0.526468913974126 +57.7204211950302 0.529377582007132 +57.7449459843338 0.552646926271182 +57.7694707736373 0.479930225446026 +57.7939955629408 0.506108237743082 +57.8185203522444 0.45375221314897 +57.8430451415479 0.485747561512038 +57.8675699308515 0.570098934469219 +57.892094720155 0.520651577908113 +57.9166195094585 0.503199569710076 +57.9411442987621 0.488656229545045 +57.9656690880656 0.462478217247989 +57.9901938773692 0.506108237743082 +58.0147186666727 0.485747561512038 +58.0392434559762 0.543920922172163 +58.0637682452798 0.526468913974126 +58.0882930345833 0.517742909875107 +58.1128178238869 0.468295553314001 +58.1373426131904 0.488656229545045 +58.161867402494 0.511925573809094 +58.1863921917975 0.500290901677069 +58.210916981101 0.509016905776088 +58.2354417704046 0.648632971360387 +58.2599665597081 0.602094282832287 +58.2844913490117 0.558464262337194 +58.3090161383152 0.567190266436213 +58.3335409276187 0.6079116188983 +58.3580657169223 0.590459610700262 +58.3825905062258 0.555555594304188 +58.4071152955294 0.636998299228362 +58.4316400848329 0.613728954964312 +58.4561648741364 0.634089631195356 +58.48068966344 0.700988995954499 +58.5052144527435 0.721349672185542 +58.5297392420471 0.753345020548611 +58.5542640313506 0.718441004152536 +58.5787888206542 0.840605061538797 +58.6033136099577 0.878417745967878 +58.6278383992612 1.0267598156512 +58.6523631885648 1.09365918041034 +58.6768879778683 1.29144860665476 +58.7014127671719 1.32926129108384 +58.7259375564754 1.4979640369982 +58.7504623457789 1.93717290998214 +58.7749871350825 2.12332766409454 +58.799511924386 2.27457840181086 +58.8240367136896 2.67888325839873 +58.8485615029931 2.58871454937553 +58.8730862922966 2.70506127069578 +58.8976110816002 2.47236782805529 +58.9221358709037 2.5247238526494 +58.9466606602073 2.1524143444246 +58.9711854495108 1.88772555342104 +58.9957102388144 1.67248411897858 +59.0202350281179 1.48923803289918 +59.0447598174214 1.36125663944691 +59.069284606725 1.55322872962532 +59.0938093960285 1.43106467223906 +59.1183341853321 1.3554393033809 +59.1428589746356 1.43979067633808 +59.1673837639391 1.60849342225244 +59.1919085532427 1.64921477471453 +59.2164333425462 1.73647481570471 +59.2409581318498 1.62012809438446 +59.2654829211533 1.51541604519624 +59.2900077104568 1.49214670093219 +59.3145324997604 1.41361266404102 +59.3390572890639 1.404886659942 +59.3635820783675 1.21000590173059 +59.388106867671 1.0762071722123 +59.4126316569746 1.00639913942015 +59.4371564462781 0.904595758264934 +59.4616812355816 0.922047766462971 +59.4862060248852 0.831879057439778 +59.5107308141887 0.706806332020511 +59.5352556034923 0.677719651690449 +59.5597803927958 0.794066373010698 +59.5843051820993 0.642815635294374 +59.6088299714029 0.590459610700262 +59.6333547607064 0.639906967261368 +59.65787955001 0.636998299228362 +59.6824043393135 0.663176311525418 +59.706929128617 0.613728954964312 +59.7314539179206 0.5613729303702 +59.7559787072241 0.58464227463425 +59.7805034965277 0.53810358610615 +59.8050282858312 0.564281598403206 +59.8295530751348 0.628272295129343 +59.8540778644383 0.622454959063331 +59.8786026537418 0.570098934469219 +59.9031274430454 0.575916270535231 +59.9276522323489 0.564281598403206 +59.9521770216525 0.564281598403206 +59.976701810956 0.610820286931306 +60.0012266002595 0.506108237743082 +60.0257513895631 0.634089631195356 +60.0502761788666 0.570098934469219 +60.0748009681702 0.66899364759143 +60.0993257574737 0.6079116188983 +60.1238505467772 0.619546291030324 +60.1483753360808 0.689354323822474 +60.1729001253843 0.753345020548611 +60.1974249146879 0.735893012350573 +60.2219497039914 0.703897663987505 +60.246474493295 0.730075676284561 +60.2709992825985 0.811518381208735 +60.295524071902 0.866783073835853 +60.3200488612056 1.01221647548616 +60.3445736505091 1.06457250008028 +60.3690984398127 1.27690526648973 +60.3936232291162 1.45724268453612 +60.4181480184197 1.56195473372434 +60.4426728077233 1.73647481570471 +60.4671975970268 2.06806297146742 +60.4917223863304 2.1495056763916 +60.5162471756339 2.51308918051737 +60.5407719649374 2.62943590183762 +60.565296754241 2.87958135267616 +60.5898215435445 2.81849932398303 +60.6143463328481 2.71669594282781 +60.6388711221516 2.46073315592326 +60.6633959114552 2.25421772557982 +60.6879207007587 1.9662595903122 +60.7124454900622 1.74520081980373 +60.7369702793658 1.5881327460214 +60.7614950686693 1.41652133207403 +60.7860198579729 1.404886659942 +60.8105446472764 1.49214670093219 +60.8350694365799 1.50378137306421 +60.8595942258835 1.44560801240409 +60.884119015187 1.48342069683317 +60.9086438044906 1.68993612717661 +60.9331685937941 1.66957545094557 +60.9576933830976 1.81210018456287 +60.9822181724012 1.70157079930864 +61.0067429617047 1.60558475421943 +61.0312677510083 1.46596868863513 +61.0557925403118 1.42233866814004 +61.0803173296154 1.28853993862175 +61.1048421189189 1.21291456976359 +61.1293669082224 0.93077377056199 +61.153891697526 0.988947131222114 +61.1784164868295 0.837696393505791 +61.2029412761331 0.788249036944685 +61.2274660654366 0.689354323822474 +61.2519908547401 0.703897663987505 +61.2765156440437 0.724258340218548 +61.3010404333472 0.634089631195356 +61.3255652226508 0.514834241842101 +61.3500900119543 0.5613729303702 +61.3746148012578 0.541012254139157 +61.3991395905614 0.677719651690449 +61.4236643798649 0.532286250040138 +61.4481891691685 0.555555594304188 +61.472713958472 0.570098934469219 +61.4972387477756 0.459569549214982 +61.5217635370791 0.546829590205169 +61.5462883263826 0.471204221347007 +61.5708131156862 0.462478217247989 +61.5953379049897 0.485747561512038 +61.6198626942933 0.459569549214982 +61.6443874835968 0.45375221314897 +61.6689122729003 0.392670184455839 +61.6934370622039 0.517742909875107 +61.7179618515074 0.511925573809094 +61.742486640811 0.456660881181976 +61.7670114301145 0.442117541016945 +61.791536219418 0.424665532818908 +61.8160610087216 0.378126844290808 +61.8405857980251 0.488656229545045 +61.8651105873287 0.357766168059765 +61.8896353766322 0.468295553314001 +61.9141601659358 0.392670184455839 +61.9386849552393 0.488656229545045 +61.9632097445428 0.386852848389827 +61.9877345338464 0.474112889380014 +62.0122593231499 0.407213524620871 +62.0367841124535 0.500290901677069 +62.061308901757 0.479930225446026 +62.0858336910605 0.366492172158783 +62.1103584803641 0.436300204950933 +62.1348832696676 0.445026209049951 +62.1594080589712 0.45375221314897 +62.1839328482747 0.372309508224796 +62.2084576375782 0.378126844290808 +62.2329824268818 0.398487520521852 +62.2575072161853 0.372309508224796 +62.2820320054889 0.424665532818908 +62.3065567947924 0.383944180356821 +62.331081584096 0.421756864785902 +62.3556063733995 0.456660881181976 +62.380131162703 0.43048286888492 +62.4046559520066 0.363583504125777 +62.4291807413101 0.395578852488846 +62.4537055306137 0.36940084019179 +62.4782303199172 0.383944180356821 +62.5027551092207 0.404304856587864 +62.5272798985243 0.372309508224796 +62.5518046878278 0.407213524620871 +62.5763294771314 0.319953483630684 +62.6008542664349 0.413030860686883 +62.6253790557384 0.395578852488846 +62.649903845042 0.418848196752895 +62.6744286343455 0.383944180356821 +62.6989534236491 0.311227479531665 +62.7234782129526 0.410122192653877 +62.7480030022562 0.386852848389827 +62.7725277915597 0.337405491828721 +62.7970525808632 0.415939528719889 +62.8215773701668 0.410122192653877 +62.8461021594703 0.389761516422833 +62.8706269487739 0.407213524620871 +62.8951517380774 0.34613149592774 +62.9196765273809 0.407213524620871 +62.9442013166845 0.45375221314897 +62.968726105988 0.375218176257802 +62.9932508952916 0.404304856587864 +63.0177756845951 0.378126844290808 +63.0423004738986 0.407213524620871 +63.0668252632022 0.392670184455839 +63.0913500525057 0.482838893479032 +63.1158748418093 0.398487520521852 +63.1403996311128 0.474112889380014 +63.1649244204164 0.47702155741302 +63.1894492097199 0.479930225446026 +63.2139739990234 0.447934877082958 +63.238498788327 0.500290901677069 +63.2630235776305 0.558464262337194 +63.2875483669341 0.541012254139157 +63.3120731562376 0.639906967261368 +63.3365979455411 0.634089631195356 +63.3611227348447 0.581733606601244 +63.3856475241482 0.613728954964312 +63.4101723134518 0.596276946766275 +63.4346971027553 0.578824938568237 +63.4592218920588 0.5613729303702 +63.4837466813624 0.593368278733268 +63.5082714706659 0.488656229545045 +63.5327962599695 0.541012254139157 +63.557321049273 0.497382233644063 +63.5818458385766 0.439208872983939 +63.6063706278801 0.494473565611057 +63.6308954171836 0.462478217247989 +63.6554202064872 0.517742909875107 +63.6799449957907 0.462478217247989 +63.7044697850943 0.517742909875107 +63.7289945743978 0.555555594304188 +63.7535193637013 0.541012254139157 +63.7780441530049 0.558464262337194 +63.8025689423084 0.570098934469219 +63.827093731612 0.503199569710076 +63.8516185209155 0.450843545115964 +63.876143310219 0.541012254139157 +63.9006680995226 0.474112889380014 +63.9251928888261 0.465386885280995 +63.9497176781297 0.395578852488846 +63.9742424674332 0.47702155741302 +63.9987672567368 0.47702155741302 +64.0232920460403 0.424665532818908 +64.0478168353438 0.474112889380014 +64.0723416246474 0.482838893479032 +64.0968664139509 0.43048286888492 +64.1213912032545 0.436300204950933 +64.145915992558 0.442117541016945 +64.1704407818615 0.433391536917926 +64.1949655711651 0.433391536917926 +64.2194903604686 0.418848196752895 +64.2440151497722 0.410122192653877 +64.2685399390757 0.459569549214982 +64.2930647283793 0.43048286888492 +64.3175895176828 0.439208872983939 +64.3421143069863 0.450843545115964 +64.3666390962899 0.43048286888492 +64.3911638855934 0.445026209049951 +64.415688674897 0.482838893479032 +64.4402134642005 0.450843545115964 +64.464738253504 0.445026209049951 +64.4892630428076 0.491564897578051 +64.5137878321111 0.520651577908113 +64.5383126214147 0.517742909875107 +64.5628374107182 0.43048286888492 +64.5873622000217 0.415939528719889 +64.6118869893253 0.5613729303702 +64.6364117786288 0.45375221314897 +64.6609365679324 0.503199569710076 +64.6854613572359 0.445026209049951 +64.7099861465395 0.555555594304188 +64.734510935843 0.523560245941119 +64.7590357251465 0.610820286931306 +64.7835605144501 0.570098934469219 +64.8080853037536 0.660267643492411 +64.8326100930572 0.64572430332738 +64.8571348823607 0.631180963162349 +64.8816596716642 0.744619016449592 +64.9061844609678 0.869691741868859 +64.9307092502713 0.919139098429965 +64.9552340395749 0.942408442694015 +64.9797588288784 1.1227458607404 +65.0042836181819 1.0267598156512 +65.0288084074855 1.03548581975021 +65.053333196789 1.0267598156512 +65.0778579860926 0.956951782859046 +65.1023827753961 0.956951782859046 +65.1269075646997 0.922047766462971 +65.1514323540032 0.852239733670822 +65.1759571433067 0.927865102528984 +65.2004819326103 0.773705696779654 +65.2250067219138 0.782431700878673 +65.2495315112174 0.855148401703828 +65.2740563005209 0.741710348416586 +65.2985810898244 0.936591106628002 +65.323105879128 0.951134446793033 +65.3476306684315 0.933682438594996 +65.3721554577351 1.03257715171721 +65.3966802470386 1.08202450827831 +65.4212050363421 1.23327524599464 +65.4457298256457 1.29726594272077 +65.4702546149492 1.39906932387599 +65.4947794042528 1.44560801240409 +65.5193041935563 1.60267608618643 +65.5438289828599 1.60558475421943 +65.5683537721634 1.46887735666814 +65.5928785614669 1.401977991909 +65.6174033507705 1.32344395501783 +65.641928140074 1.25654459025869 +65.6664529293776 1.14601520500445 +65.6909777186811 0.962769118925058 +65.7155025079846 0.980221127123096 +65.7400272972882 0.878417745967878 +65.7645520865917 0.924956434495977 +65.7890768758953 0.782431700878673 +65.8136016651988 0.855148401703828 +65.8381264545023 0.747527684482598 +65.8626512438059 0.785340368911679 +65.8871760331094 0.753345020548611 +65.911700822413 0.933682438594996 +65.9362256117165 0.939499774661008 +65.9607504010201 0.90750442629794 +65.9852751903236 0.910413094330946 +66.0097999796271 0.898778422198921 +66.0343247689307 0.922047766462971 +66.0588495582342 0.88423508203389 +66.0833743475378 0.869691741868859 +66.1078991368413 0.762071024647629 +66.1324239261448 0.695171659888486 +66.1569487154484 0.689354323822474 +66.1814735047519 0.602094282832287 +66.2059982940555 0.616637622997318 +66.230523083359 0.549738258238175 +66.2550478726625 0.462478217247989 +66.2795726619661 0.555555594304188 +66.3040974512696 0.491564897578051 +66.3286222405732 0.532286250040138 +66.3531470298767 0.523560245941119 +66.3776718191803 0.506108237743082 +66.4021966084838 0.546829590205169 +66.4267213977873 0.43048286888492 +66.4512461870909 0.450843545115964 +66.4757709763944 0.482838893479032 +66.500295765698 0.456660881181976 +66.5248205550015 0.45375221314897 +66.549345344305 0.442117541016945 +66.5738701336086 0.488656229545045 +66.5983949229121 0.442117541016945 +66.6229197122157 0.497382233644063 +66.6474445015192 0.404304856587864 +66.6719692908227 0.401396188554858 +66.6964940801263 0.436300204950933 +66.7210188694298 0.514834241842101 +66.7455436587334 0.465386885280995 +66.7700684480369 0.427574200851914 +66.7945932373405 0.479930225446026 +66.819118026644 0.462478217247989 +66.8436428159475 0.415939528719889 +66.8681676052511 0.450843545115964 +66.8926923945546 0.482838893479032 +66.9172171838582 0.442117541016945 +66.9417419731617 0.447934877082958 +66.9662667624652 0.488656229545045 +66.9907915517688 0.415939528719889 +67.0153163410723 0.427574200851914 +67.0398411303759 0.456660881181976 +67.0643659196794 0.45375221314897 +67.0888907089829 0.485747561512038 +67.1134154982865 0.433391536917926 +67.13794028759 0.517742909875107 +67.1624650768936 0.494473565611057 +67.1869898661971 0.523560245941119 +67.2115146555007 0.511925573809094 +67.2360394448042 0.506108237743082 +67.2605642341077 0.479930225446026 +67.2850890234113 0.509016905776088 +67.3096138127148 0.564281598403206 +67.3341386020184 0.485747561512038 +67.3586633913219 0.564281598403206 +67.3831881806254 0.602094282832287 +67.407712969929 0.532286250040138 +67.4322377592325 0.654450307426399 +67.4567625485361 0.700988995954499 +67.4812873378396 0.686445655789467 +67.5058121271431 0.846422397604809 +67.5303369164467 0.791157704977691 +67.5548617057502 0.890052418099903 +67.5793864950538 1.05584649598126 +67.6039112843573 1.06166383204727 +67.6284360736609 1.16055854516948 +67.6529608629644 1.4514253484701 +67.6774856522679 1.34380463124887 +67.7020104415715 1.48342069683317 +67.726535230875 1.51832471322925 +67.7510600201786 1.43979067633808 +67.7755848094821 1.2652705943577 +67.8001095987856 1.18382788943353 +67.8246343880892 1.08493317631132 +67.8491591773927 0.956951782859046 +67.8736839666963 0.956951782859046 +67.8982087559998 0.942408442694015 +67.9227335453033 0.756253688581617 +67.9472583346069 0.878417745967878 +67.9717831239104 0.834787725472785 +67.996307913214 0.802792377109716 +68.0208327025175 0.840605061538797 +68.0453574918211 0.820244385307754 +68.0698822811246 0.875509077934872 +68.0944070704281 0.881326414000884 +68.1189318597317 1.01803381155218 +68.1434566490352 0.988947131222114 +68.1679814383388 1.01512514351917 +68.1925062276423 0.913321762363952 +68.2170310169458 0.890052418099903 +68.2415558062494 0.898778422198921 +68.2660805955529 0.805701045142722 +68.2906053848565 0.802792377109716 +68.31513017416 0.796975041043704 +68.3396549634635 0.721349672185542 +68.3641797527671 0.695171659888486 +68.3887045420706 0.663176311525418 +68.4132293313742 0.581733606601244 +68.4377541206777 0.578824938568237 +68.4622789099813 0.520651577908113 +68.4868036992848 0.570098934469219 +68.5113284885883 0.593368278733268 +68.5358532778919 0.526468913974126 +68.5603780671954 0.456660881181976 +68.584902856499 0.578824938568237 +68.6094276458025 0.541012254139157 +68.633952435106 0.570098934469219 +68.6584772244096 0.581733606601244 +68.6830020137131 0.567190266436213 +68.7075268030167 0.5613729303702 +68.7320515923202 0.546829590205169 +68.7565763816237 0.509016905776088 +68.7811011709273 0.482838893479032 +68.8056259602308 0.526468913974126 +68.8301507495344 0.541012254139157 +68.8546755388379 0.520651577908113 +68.8792003281415 0.567190266436213 +68.903725117445 0.610820286931306 +68.9282499067485 0.674810983657443 +68.9527746960521 0.639906967261368 +68.9772994853556 0.680628319723455 +69.0018242746592 0.703897663987505 +69.0263490639627 0.706806332020511 +69.0508738532662 0.718441004152536 +69.0753986425698 0.817335717274747 +69.0999234318733 0.808609713175729 +69.1244482211769 0.997673135321133 +69.1489730104804 1.05293782794825 +69.1734977997839 1.12856319680641 +69.1980225890875 1.15474120910347 +69.222547378391 1.32344395501783 +69.2470721676946 1.39034331977697 +69.2715969569981 1.68702745914361 +69.2961217463017 1.56486340175735 +69.3206465356052 1.62594543045048 +69.3451713249087 1.52414204929526 +69.3696961142123 1.36998264354593 +69.3942209035158 1.41652133207403 +69.4187456928194 1.2158232377966 +69.4432704821229 1.20709723369758 +69.4677952714264 1.14892387303746 +69.49232006073 1.05293782794825 +69.5168448500335 0.927865102528984 +69.5413696393371 1.0267598156512 +69.5658944286406 0.922047766462971 +69.5904192179441 0.939499774661008 +69.6149440072477 0.968586454991071 +69.6394687965512 1.04130315581623 +69.6639935858548 1.18382788943353 +69.6885183751583 1.13147186483942 +69.7130431644619 1.19546256156556 +69.7375679537654 1.28853993862175 +69.7620927430689 1.36707397551292 +69.7866175323725 1.38452598371096 +69.811142321676 1.41361266404102 +69.8356671109796 1.26817926239071 +69.8601919002831 1.2158232377966 +69.8847166895866 1.18091922140052 +69.9092414788902 1.01221647548616 +69.9337662681937 0.924956434495977 +69.9582910574973 0.927865102528984 +69.9828158468008 0.750436352515604 +70.0073406361043 0.738801680383579 +70.0318654254079 0.639906967261368 +70.0563902147114 0.721349672185542 +70.080915004015 0.735893012350573 +70.1054397933185 0.636998299228362 +70.1299645826221 0.64572430332738 +70.1544893719256 0.622454959063331 +70.1790141612291 0.616637622997318 +70.2035389505327 0.648632971360387 +70.2280637398362 0.605002950865293 +70.2525885291398 0.767888360713642 +70.2771133184433 0.686445655789467 +70.3016381077468 0.724258340218548 +70.3261628970504 0.622454959063331 +70.3506876863539 0.703897663987505 +70.3752124756575 0.616637622997318 +70.399737264961 0.599185614799281 +70.4242620542645 0.69226299185548 +70.4487868435681 0.587550942667256 +70.4733116328716 0.541012254139157 +70.4978364221752 0.587550942667256 +70.5223612114787 0.570098934469219 +70.5468860007823 0.509016905776088 +70.5714107900858 0.58464227463425 +70.5959355793893 0.459569549214982 +70.6204603686929 0.450843545115964 +70.6449851579964 0.445026209049951 +70.6695099473 0.517742909875107 +70.6940347366035 0.459569549214982 +70.718559525907 0.381035512323815 +70.7430843152106 0.503199569710076 +70.7676091045141 0.494473565611057 +70.7921338938177 0.497382233644063 +70.8166586831212 0.494473565611057 +70.8411834724247 0.45375221314897 +70.8657082617283 0.488656229545045 +70.8902330510318 0.474112889380014 +70.9147578403354 0.442117541016945 +70.9392826296389 0.491564897578051 +70.9638074189425 0.456660881181976 +70.988332208246 0.442117541016945 +71.0128569975495 0.485747561512038 +71.0373817868531 0.471204221347007 +71.0619065761566 0.517742909875107 +71.0864313654602 0.418848196752895 +71.1109561547637 0.465386885280995 +71.1354809440672 0.471204221347007 +71.1600057333708 0.523560245941119 +71.1845305226743 0.506108237743082 +71.2090553119779 0.529377582007132 +71.2335801012814 0.471204221347007 +71.2581048905849 0.433391536917926 +71.2826296798885 0.468295553314001 +71.307154469192 0.471204221347007 +71.3316792584956 0.468295553314001 +71.3562040477991 0.488656229545045 +71.3807288371027 0.552646926271182 +71.4052536264062 0.459569549214982 +71.4297784157097 0.456660881181976 +71.4543032050133 0.511925573809094 +71.4788279943168 0.45375221314897 +71.5033527836204 0.485747561512038 +71.5278775729239 0.517742909875107 +71.5524023622274 0.541012254139157 +71.576927151531 0.5613729303702 +71.6014519408345 0.450843545115964 +71.6259767301381 0.503199569710076 +71.6505015194416 0.581733606601244 +71.6750263087451 0.535194918073144 +71.6995510980487 0.628272295129343 +71.7240758873522 0.564281598403206 +71.7486006766558 0.66899364759143 +71.7731254659593 0.764979692680635 +71.7976502552629 0.82315305334076 +71.8221750445664 0.828970389406772 +71.8466998338699 0.895869754165915 +71.8712246231735 0.968586454991071 +71.895749412477 0.99185579925512 +71.9202742017806 0.99185579925512 +71.9447989910841 1.06748116811328 +71.9693237803876 0.945317110727021 +71.9938485696912 0.919139098429965 +72.0183733589947 0.82315305334076 +72.0428981482983 0.808609713175729 +72.0674229376018 0.770797028746648 +72.0919477269053 0.677719651690449 +72.1164725162089 0.648632971360387 +72.1409973055124 0.636998299228362 +72.165522094816 0.613728954964312 +72.1900468841195 0.599185614799281 +72.2145716734231 0.619546291030324 +72.2390964627266 0.674810983657443 +72.2636212520301 0.654450307426399 +72.2881460413337 0.622454959063331 +72.3126708306372 0.654450307426399 +72.3371956199408 0.686445655789467 +72.3617204092443 0.79988370907671 +72.3862451985478 0.660267643492411 +72.4107699878514 0.791157704977691 +72.4352947771549 0.712623668086523 +72.4598195664585 0.770797028746648 +72.484344355762 0.613728954964312 +72.5088691450655 0.732984344317567 +72.5333939343691 0.642815635294374 +72.5579187236726 0.666084979558424 +72.5824435129762 0.602094282832287 +72.6069683022797 0.58464227463425 +72.6314930915833 0.570098934469219 +72.6560178808868 0.587550942667256 +72.6805426701903 0.625363627096337 +72.7050674594939 0.602094282832287 +72.7295922487974 0.529377582007132 +72.754117038101 0.58464227463425 +72.7786418274045 0.575916270535231 +72.803166616708 0.509016905776088 +72.8276914060116 0.552646926271182 +72.8522161953151 0.450843545115964 +72.8767409846187 0.552646926271182 +72.9012657739222 0.494473565611057 +72.9257905632257 0.517742909875107 +72.9503153525293 0.587550942667256 +72.9748401418328 0.622454959063331 +72.9993649311364 0.53810358610615 +73.0238897204399 0.58464227463425 +73.0484145097435 0.616637622997318 +73.072939299047 0.605002950865293 +73.0974640883505 0.709715000053517 +73.1219888776541 0.587550942667256 +73.1465136669576 0.712623668086523 +73.1710384562612 0.666084979558424 +73.1955632455647 0.756253688581617 +73.2200880348682 0.79988370907671 +73.2446128241718 0.90750442629794 +73.2691376134753 0.913321762363952 +73.2936624027789 1.05293782794825 +73.3181871920824 1.14601520500445 +73.3427119813859 1.22454924189562 +73.3672367706895 1.37289131157893 +73.391761559993 1.55904606569133 +73.4162863492966 1.55904606569133 +73.4408111386001 1.8266435247279 +73.4653359279037 1.57068073782336 +73.4898607172072 1.71320547144066 +73.5143855065107 1.81210018456287 +73.5389102958143 1.53577672142728 +73.5634350851178 1.49214670093219 +73.5879598744214 1.27399659845672 +73.6124846637249 1.43106467223906 +73.6370094530284 1.16637588123549 +73.661534242332 1.0296684836842 +73.6860590316355 1.05002915991524 +73.7105838209391 1.17219321730151 +73.7351086102426 1.06748116811328 +73.7596333995461 0.994764467288127 +73.7841581888497 1.07038983614629 +73.8086829781532 1.14601520500445 +73.8332077674568 1.22164057386261 +73.8577325567603 1.28853993862175 +73.8822573460639 1.36998264354593 +73.9067821353674 1.43688200830507 +73.9313069246709 1.71320547144066 +73.9558317139745 1.70157079930864 +73.980356503278 1.6841187911106 +74.0048812925816 1.61721942635146 +74.0294060818851 1.64048877061551 +74.0539308711886 1.37870864764495 +74.0784556604922 1.4979640369982 +74.1029804497957 1.15183254107046 +74.1275052390993 1.04712049188224 +74.1520300284028 1.03257715171721 +74.1765548177063 0.983129795156102 +74.2010796070099 0.892961086132909 +74.2256043963134 0.933682438594996 +74.250129185617 0.779523032845666 +74.2746539749205 0.764979692680635 +74.2991787642241 0.759162356614623 +74.3237035535276 0.767888360713642 +74.3482283428311 0.759162356614623 +74.3727531321347 0.826061721373766 +74.3972779214382 0.820244385307754 +74.4218027107418 0.741710348416586 +74.4463275000453 0.863874405802847 +74.4708522893488 0.895869754165915 +74.4953770786524 0.788249036944685 +74.5199018679559 0.820244385307754 +74.5444266572595 0.770797028746648 +74.568951446563 0.779523032845666 +74.5934762358665 0.712623668086523 +74.6180010251701 0.732984344317567 +74.6425258144736 0.636998299228362 +74.6670506037772 0.636998299228362 +74.6915753930807 0.53810358610615 +74.7161001823843 0.581733606601244 +74.7406249716878 0.488656229545045 +74.7651497609913 0.593368278733268 +74.7896745502949 0.570098934469219 +74.8141993395984 0.546829590205169 +74.838724128902 0.526468913974126 +74.8632489182055 0.491564897578051 +74.887773707509 0.541012254139157 +74.9122984968126 0.541012254139157 +74.9368232861161 0.497382233644063 +74.9613480754197 0.514834241842101 +74.9858728647232 0.45375221314897 +75.0103976540267 0.503392714112542 +75.0349224433303 0.521717706120348 +75.0594472326338 0.496433525672776 +75.0839720219374 0.485264700505873 +75.1084968112409 0.477390832176908 +75.1330216005445 0.471707930392888 +75.157546389848 0.47940566836043 +75.1820711791515 0.475838008959836 +75.2065959684551 0.521541575758926 +75.2311207577586 0.506981221552851 +75.2556455470622 0.469092812962252 +75.2801703363657 0.465349023200236 +75.3046951256692 0.486116836275927 +75.3292199149728 0.458092450159429 +75.3537447042763 0.501554008290442 +75.3782694935799 0.465890594326875 +75.4027942828834 0.489235662752443 +75.4273190721869 0.497969334848804 +75.4518438614905 0.445622656298394 +75.476368650794 0.486368690798867 +75.5008934400976 0.486717117523041 +75.5254182294011 0.488286954781156 +75.5499430187047 0.49055747948629 +75.5744678080082 0.499476627987775 +75.5989925973117 0.499048643103412 +75.6235173866153 0.522939116654291 +75.6480421759188 0.517159642669037 +75.6725669652224 0.513012550061045 +75.6970917545259 0.498158645252599 +75.7216165438294 0.562393528504334 +75.746141333133 0.600293439090946 +75.7706661224365 0.577683086194484 +75.7951909117401 0.596932104135191 +75.8197157010436 0.659256391401979 +75.8442404903471 0.662345023795079 +75.8687652796507 0.672443886751076 +75.8932900689542 0.705232660763724 +75.9178148582578 0.72739801473478 +75.9423396475613 0.77979190140965 +75.9668644368649 0.84362731581408 +75.9913892261684 0.867849202048088 +76.0159140154719 0.853419448125334 +76.0404388047755 0.918677085463515 +76.064963594079 0.872638271982624 +76.0894883833826 0.85561424866895 +76.1140131726861 0.813578747470359 +76.1385379619896 0.752030871812106 +76.1630627512932 0.680221182878808 +76.1875875405967 0.668821351228679 +76.2121123299003 0.621720243534225 +76.2366371192038 0.584680136715009 +76.2611619085073 0.642542932731719 +76.2856866978109 0.602425695515417 +76.3102114871144 0.626643747750753 +76.334736276418 0.609985165202296 +76.3592610657215 0.629166126978827 +76.3837858550251 0.638374992084011 +76.4083106443286 0.613200563880045 +76.4328354336321 0.67312756015705 +76.4573602229357 0.627281891078626 +76.4818850122392 0.647701277430144 +76.5064098015428 0.704090808389971 +76.5309345908463 0.67768178960969 +76.5554593801498 0.669069371752948 +76.5799841694534 0.666709942843924 +76.6045089587569 0.687256095480091 +76.6290337480605 0.666533812482502 +76.653558537364 0.650144098498028 +76.6780833266675 0.619919399792884 +76.7026081159711 0.601376581344225 +76.7271329052746 0.586736668977961 +76.7516576945782 0.558464262337194 +76.7761824838817 0.53141710022904 +76.8007072731853 0.502851142985902 +76.8252320624888 0.518750327966868 +76.8497568517923 0.574749736123092 +76.8742816410959 0.540684675454698 +76.8988064303994 0.519799442138059 +76.923331219703 0.512508841015164 +76.9478560090065 0.493852436324228 +76.97238079831 0.516907788146097 +76.9969055876136 0.512294848572983 +77.0214303769171 0.522628552010876 +77.0459551662207 0.497226951322356 +77.0704799555242 0.5265276240946 +77.0950047448277 0.510393598631738 +77.1195295341313 0.525281531522271 +77.1440543234348 0.564595997045292 +77.1685791127384 0.508068197804801 +77.1931039020419 0.538275882468901 +77.2176286913455 0.572327763094922 +77.242153480649 0.59592468604343 +77.2666782699525 0.6233279428731 +77.2912030592561 0.671142918056944 +77.3157278485596 0.679738321872642 +77.3402526378632 0.705073544443346 +77.3647774271667 0.767481223868994 +77.3893022164702 0.792589273955144 +77.4138270057738 0.878917621015087 +77.4383517950773 0.947038396308173 +77.4628765843809 1.04033359980522 +77.4874013736844 1.06376757243468 +77.5119261629879 1.14305166084964 +77.5364509522915 1.14779520070608 +77.560975741595 1.12436122807662 +77.5855005308986 1.12379114091292 +77.6100253202021 1.04792158552916 +77.6345501095057 0.952808524249725 +77.6590748988092 0.873884364554953 +77.6835996881127 0.800215121759839 +77.7081244774163 0.783325532728157 +77.7326492667198 0.765735256249456 +77.7571740560234 0.719490118323727 +77.7816988453269 0.689727432585033 +77.8062236346304 0.657258569259501 +77.830748423934 0.680493885441463 +77.8552732132375 0.667927519379195 +77.8797980025411 0.667810099138247 +77.9043227918446 0.673182436278853 +77.9288475811481 0.67814380257614 +77.9533723704517 0.698021617801018 +77.9778971597552 0.756211992502187 +78.0024219490588 0.753310992466523 +78.0269467383623 0.738038448817416 +78.0514715276659 0.821835070605584 +78.0759963169694 0.804072497764133 +78.1005211062729 0.78994012844242 +78.1250458955765 0.768950654927205 +78.14957068488 0.784043234216219 +78.1740954741836 0.754725547402931 +78.1986202634871 0.646017853929751 +78.2231450527906 0.650437649100399 +78.2476698420942 0.616113065911723 +78.2721946313977 0.62195125001745 +78.2967194207013 0.570161478588364 +78.3212442100048 0.587143805822609 +78.3457689993083 0.546926162406402 +78.3702937886119 0.563135912030782 +78.3948185779154 0.547299271168962 +78.419343367219 0.525226655400468 +78.4438681565225 0.493894132403659 +78.4683929458261 0.49594683066794 +78.4929177351296 0.468820110399597 +78.5174425244331 0.470486519858946 +78.5419673137367 0.462730071770929 +78.5664921030402 0.472484342001424 +78.5910168923438 0.487686673534043 +78.6155416816473 0.476924985211787 +78.6400664709508 0.446247619583894 +78.6645912602544 0.46916853712377 +78.6891160495579 0.46482446611464 +78.7136408388615 0.44318366922918 +78.738165628165 0.466318579211238 +78.7626904174685 0.452413382374079 +78.7872152067721 0.461684791598409 +78.8117399960756 0.435699923703819 +78.8362647853792 0.447448182078121 +78.8607895746827 0.468954544681589 +78.8853143639863 0.454683907079213 +78.9098391532898 0.46398934438563 +78.9343639425933 0.464534749510941 +78.9588887318969 0.459745679576405 +78.9834135212004 0.468467849676752 +79.007938310504 0.458734427485972 +79.0324630998075 0.478498656468574 +79.056987889111 0.432556415188916 +79.0815126784146 0.43917101090318 +79.1060374677181 0.456446888739795 +79.1305622570217 0.471456075869948 +79.1550870463252 0.425034807582796 +79.1796118356287 0.439788306191337 +79.2041366249323 0.465676601884694 +79.2286614142358 0.473533456172615 +79.2531862035394 0.439443713465835 +79.2777109928429 0.43670734179558 +79.3022357821465 0.438974032502043 +79.32676057145 0.436476335312355 +79.3512853607535 0.454680073080542 +79.3758101500571 0.465525153561658 +79.4003349393606 0.434923512095283 +79.4248597286642 0.45751301695203 +79.4493845179677 0.467947126589828 +79.4739093072712 0.444791368568055 +79.4984340965748 0.470158941174487 +79.5229588858783 0.470348251578282 +79.5474836751819 0.478477808428858 +79.5720084644854 0.506553236668488 +79.5965332537889 0.515103110406085 +79.6210580430925 0.499770178590145 +79.645582832396 0.508454486609734 +79.6701076216996 0.501453602090538 +79.6946324110031 0.486058126155453 +79.7191572003067 0.503120011549887 +79.7436819896102 0.538628143191746 +79.7682067789137 0.50564239077796 +79.7927315682173 0.546943176447446 +79.8172563575208 0.57516070696641 +79.8417811468244 0.601759036150486 +79.8663059361279 0.635059187206358 +79.8908307254314 0.647701277430144 +79.915355514735 0.694743675004123 +79.9398803040385 0.71574249456304 +79.9644050933421 0.745084863414713 +79.9889298826456 0.77799105766831 +80.0134546719491 0.797164351447499 +80.0379794612527 0.848420219747288 +80.0625042505562 0.811753221690631 +80.0870290398598 0.825226599644756 +80.1115538291633 0.801612662655204 +80.1360786184669 0.738956962705287 +80.1606034077704 0.76203316256687 +80.1851281970739 0.719628386604391 +80.2096529863775 0.654840430230003 +80.234177775681 0.639730836899946 +80.2587025649846 0.619084278063874 +80.2832273542881 0.597771059862872 +80.3077521435916 0.581905902963995 +80.3322769328952 0.629959552628407 +80.3568017221987 0.61380467912583 +80.3813265115023 0.576675668102723 +80.4058513008058 0.591232188310127 +80.4303760901093 0.625577619538518 +80.4549008794129 0.60925044967319 +80.4794256687164 0.606434519842746 +80.50395045802 0.65524756707465 +80.5284752473235 0.629703864106796 +80.5530000366271 0.67287570563411 +80.5775248259306 0.680137790719947 +80.6020496152341 0.680321589078712 +80.6265744045377 0.655650869920626 +80.6510991938412 0.681849730257397 +80.6756239831448 0.670198044084329 +80.7001487724483 0.64651772897696 +80.7246735617518 0.634811166682089 +80.7491983510554 0.614967379539298 +80.7737231403589 0.608049887178963 +80.7982479296625 0.580650464347965 +80.822772718966 0.565058010011742 +80.8472975082695 0.572789776061372 +80.8718222975731 0.576365103459309 +80.8963470868766 0.55276434651213 +80.9208718761802 0.571047642440506 +80.9453966654837 0.570237202749882 +80.9699214547873 0.558346842096246 +80.9944462440908 0.567362562798964 +81.0189710333943 0.594513965105693 +81.0434958226979 0.565192444293734 +81.0680206120014 0.576730544224526 +81.092545401305 0.613338832160709 +81.1170701906085 0.661778770630053 +81.141594979912 0.626316169066295 +81.1661197692156 0.626622899711038 +81.1906445585191 0.615084799780247 +81.2151693478227 0.662341189796408 +81.2396941371262 0.659998774928427 +81.2642189264297 0.702903425938117 +81.2887437157333 0.747040989477761 +81.3132685050368 0.760870462153402 +81.3377932943404 0.7962496715583 +81.3623180836439 0.861645577177143 +81.3868428729475 0.891287008676218 +81.411367662251 1.01659457457738 +81.4358924515545 1.11861194817478 +81.4604172408581 1.20061707226531 +81.4849420301616 1.24565781369814 +81.5094668194652 1.31435251015359 +81.5339916087687 1.29978448795018 +81.5585163980722 1.31999371585818 +81.5830411873758 1.354234906888 +81.6075659766793 1.29988872814875 +81.6320907659829 1.19482441823768 +81.6566155552864 1.18127148212337 +81.6811403445899 1.13374622354322 +81.7056651338935 0.964909043346871 +81.730189923197 0.965014961591806 +81.7547147125006 0.925929824505651 +81.7792395018041 0.921585753496521 +81.8037642911077 0.898409147435033 +81.8282890804112 0.8918362478002 +81.8528138697147 0.875685208296294 +81.8773386590183 0.875488229895157 +81.9018634483218 0.901120837066902 +81.9263882376254 0.925111716817685 +81.9509130269289 0.963193269810749 +81.9754378162324 0.999201276499818 +81.999962605536 1.03921259547119 +82.0244873948395 1.08511865271644 +82.0490121841431 1.17285220866909 +82.0735369734466 1.16387435004713 +82.0980617627501 1.17979821706649 +82.1225865520537 1.11075892788553 +82.1471113413572 1.1440590789414 +82.1716361306608 1.09307974720294 +82.1961609199643 1.03256013767616 +82.2206857092679 0.967776015300447 +82.2452104985714 0.902018502915057 +82.2697352878749 0.93265417246352 +82.2942600771785 0.896763586015399 +82.318784866482 0.800378072078889 +82.3433096557856 0.717568020342767 +82.3678344450891 0.715435763918297 +82.3923592343926 0.699653999178279 +82.4168840236962 0.665850139076528 +82.4414088129997 0.674462556933269 +82.4659336023033 0.690013315190061 +82.4904583916068 0.679990176395582 +82.5149831809103 0.669963203602432 +82.5395079702139 0.669224654074655 +82.5640327595174 0.672175018187092 +82.588557548821 0.657745264264338 +82.6130823381245 0.696741497146602 +82.6376071274281 0.71929313992259 +82.6621319167316 0.69852916084557 +82.6866567060351 0.67814380257614 +82.7111814953387 0.677530341286654 +82.7357062846422 0.629359271381294 +82.7602310739458 0.639827409101179 +82.7847558632493 0.621254396569103 +82.8092806525528 0.594883239869581 +82.8338054418564 0.599999888488576 +82.8583302311599 0.588289492195033 +82.8828550204635 0.558308980015487 +82.907379809767 0.565075024052786 +82.9319045990705 0.565313698533354 +82.9564293883741 0.516110528497846 +82.9809541776776 0.554099343288349 +83.0054789669812 0.578921510769471 +83.0300037562847 0.596453077127697 +83.0545285455883 0.561607770852096 +83.0790533348918 0.539186728359429 +83.1035781241953 0.548944832588596 +83.1281029134989 0.575546995771343 +83.1526277028024 0.578980220889945 +83.177152492106 0.558871399181841 +83.2016772814095 0.562321638341487 +83.226202070713 0.534909035468116 +83.2507268600166 0.549910554600926 +83.2752516493201 0.541226246581338 +83.2997764386237 0.548651281986225 +83.3243012279272 0.580743202550526 +83.3488260172307 0.595345252836032 +83.3733508065343 0.606010368957055 +83.3978755958378 0.570954904237944 +83.4224003851414 0.566569137149384 +83.4469251744449 0.583089451417178 +83.4714499637485 0.58869662903968 +83.495974753052 0.566451716908436 +83.5204995423555 0.614967379539298 +83.5450243316591 0.646794265538287 +83.5695491209626 0.622782537747789 +83.5940739102662 0.60490637866406 +83.6185986995697 0.647235430465022 +83.6431234888732 0.661778770630053 +83.6676482781768 0.686345249589563 +83.6921730674803 0.693101947583161 +83.7166978567839 0.698152218084339 +83.7412226460874 0.778839359439692 +83.7657474353909 0.8218559186453 +83.7902722246945 0.82198651892862 +83.814797013998 0.905116481351858 +83.8393218033016 0.939285782218827 +83.8638465926051 0.982504831870602 +83.8883713819087 1.08015728641916 +83.9128961712122 1.20276250873215 +83.9374209605157 1.27863038606955 +83.9619457498193 1.39097762910617 +83.9864705391228 1.44816441971425 +84.0109953284264 1.47014046328151 +84.0355201177299 1.4538890175777 +84.0600449070334 1.52554893623432 +84.084569696337 1.49599473089278 +84.1090944856405 1.38030316694145 +84.1336192749441 1.28282684275432 +84.1581440642476 1.17103435088671 +84.1826688535511 1.11076659588287 +84.2071936428547 1.0240064299399 +84.2317184321582 0.972220492509481 +84.2562432214618 0.931856912815269 +84.2807680107653 0.891760523638682 +84.3052928000689 0.894513909349981 +84.3298175893724 0.82674539477974 +84.3543423786759 0.809789427630241 +84.3788671679795 0.839794621848173 +84.403391957283 0.783573553252426 +84.4279167465866 0.826196155655758 +84.4524415358901 0.833893893623301 +84.4769663251936 0.853889129089127 +84.5014911144972 0.848571668070324 +84.5260159038007 0.91393905765211 +84.5505406931043 0.959025329163042 +84.5750654824078 0.96536722231465 +84.5995902717113 1.01467631059509 +84.6241150610149 1.0607908482375 +84.6486398503184 1.04921488622595 +84.673164639622 1.05714363067672 +84.6976894289255 1.03765977225411 +84.7222142182291 0.957580580143217 +84.7467390075326 0.933930459119265 +84.7712637968361 0.912280316190104 +84.7957885861397 0.850917916936975 +84.8203133754432 0.827487778306188 +84.8448381647468 0.770541340225036 +84.8693629540503 0.770473284060861 +84.8938877433538 0.719679428727522 +84.9184125326574 0.707876294231417 +84.9429373219609 0.689295613702 +84.9674621112645 0.6695769147975 +84.991986900568 0.684544405848222 +85.0165116898716 0.682101584780338 +85.0410364791751 0.688888476857352 +85.0655612684786 0.689492592103137 +85.0900860577822 0.669417798477122 +85.1146108470857 0.688905490898396 +85.1391356363893 0.701748393521991 +85.1636604256928 0.689782308706836 +85.1881852149963 0.702441412971666 +85.2127100042999 0.694957667446305 +85.2372347936034 0.712909550691551 +85.261759582907 0.803237376035123 +85.2862843722105 0.82068938423316 +85.310809161514 0.840080504453201 +85.3353339508176 0.887295198389932 +85.3598587401211 0.976339069080416 +85.3843835294247 0.995751037340173 +85.4089083187282 1.09508691538912 +85.4334331080318 1.18109151776328 +85.4579578973353 1.24238370489992 +85.4824826866388 1.22967355851195 +85.5070074759424 1.25466035435849 +85.5315322652459 1.27878566839126 +85.5560570545495 1.23442476636573 +85.580581843853 1.22371795416528 +85.6051066331565 1.14333754345467 +85.6296314224601 1.13657533341604 +85.6541562117636 1.07927495656569 +85.6786810010672 0.97112968225886 +85.7032057903707 0.96164811459102 +85.7277305796742 0.925653287944324 +85.7522553689778 0.906945841130257 +85.7767801582813 0.823870754828822 +85.8013049475849 0.851366749861053 +85.8258297368884 0.901179547187376 +85.850354526192 0.885750043170203 +85.8748793154955 0.922316635026955 +85.899404104799 0.919991234200019 +85.9239288941026 0.923483169439095 +85.9484536834061 0.948729487805908 +85.9729784727097 1.01971723505257 +85.9975032620132 1.03530968938879 +86.0220280513167 1.06550419401052 +86.0465528406203 1.02489642779071 +86.0710776299238 1.06110141288092 +86.0956024192274 1.07927112256701 +86.1201272085309 1.07862914524047 +86.1446519978344 1.06139496348329 +86.169176787138 1.0573576231189 +86.1937015764415 1.02780892982239 +86.2182263657451 0.981429357614665 +86.2427511550486 0.946131384416316 +86.2672759443522 0.883348918181749 +86.2918007336557 0.853264165803627 +86.3163255229592 0.799190689627035 +86.3408503122628 0.736731968078254 +86.3653751015663 0.734743491979478 +86.3898998908699 0.757050948229868 +86.4144246801734 0.727540117014114 +86.4389494694769 0.682508721624985 +86.4634742587805 0.655012726592754 +86.487999048084 0.693967263395588 +86.5125238373876 0.709425283449818 +86.5370486266911 0.683398719475798 +86.5615734159946 0.674252398489759 +86.5860982052982 0.681169890850094 +86.6106229946017 0.668469090505835 +86.6351477839053 0.712061248920169 +86.6596725732088 0.675045824139339 +86.6841973625124 0.634576326200192 +86.7087221518159 0.663155463485703 +86.7332469411194 0.642429346489442 +86.757771730423 0.574291557155313 +86.7822965197265 0.576302559340164 +86.8068213090301 0.608394479904465 +86.8313460983336 0.577683086194484 +86.8558708876371 0.556663418595853 +86.8803956769407 0.563232484232015 +86.9049204662442 0.531009963384393 +86.9294452555478 0.504865979169425 +86.9539700448513 0.52456766403288 +86.9784948341548 0.527400607904368 +87.0030196234584 0.5262379074909 +87.0275444127619 0.500307915718113 +87.0520692020655 0.526913912899532 +87.076593991369 0.512995536020001 +87.1011187806726 0.516093514456802 +87.1256435699761 0.495871106506422 +87.1501683592796 0.501936463096703 +87.1746931485832 0.509407028579692 +87.1992179378867 0.478847083192747 +87.2237427271903 0.479788123166691 +87.2482675164938 0.513402672864648 +87.2727923057973 0.510120896069082 +87.2973170951009 0.485789257591469 +87.3218418844044 0.511925573809094 +87.346366673708 0.467363859383758 +87.3708914630115 0.484429578776863 +87.395416252315 0.490440059245342 +87.4199410416186 0.528425040037174 +87.4444658309221 0.497692798287478 +87.4689906202257 0.515203516605989 +87.4935154095292 0.489353082993391 +87.5180401988328 0.471770474512033 +87.5425649881363 0.47480974282836 +87.5670897774398 0.475875871040595 +87.5916145667434 0.488811511866752 +87.6161393560469 0.478553532590377 +87.6406641453505 0.516731657784674 +87.665188934654 0.513092108221234 +87.6897137239575 0.495522679782248 +87.7142385132611 0.488031266259545 +87.7387633025646 0.474410273981055 +87.7632880918682 0.4771900197771 +87.7878128811717 0.494960260615894 +87.8123376704752 0.504089567560889 +87.8368624597788 0.491724013898429 +87.8613872490823 0.4775252664589 +87.8859120383859 0.501180899527882 +87.9104368276894 0.484295144494871 +87.934961616993 0.500266219638683 +87.9594864062965 0.525385771720847 +87.9840111956 0.490481755324772 +88.0085359849036 0.468195147114097 +88.0330607742071 0.495018970736368 +88.0575855635107 0.513667707429961 +88.0821103528142 0.502309571859263 +88.1066351421177 0.505697266899763 +88.1311599314213 0.518191742799184 +88.1556847207248 0.495871106506422 +88.1802095100284 0.472757044564079 +88.2047342993319 0.474285185742765 +88.2292590886354 0.516286658859268 +88.253783877939 0.508651465010871 +88.2783086672425 0.496916386678942 +88.3028334565461 0.481890185507745 +88.3273582458496 0.458213704399048 +88.3518830351532 0.459062006170431 +88.3764078244567 0.510704163275152 +88.4009326137602 0.488597519424571 +88.4254574030638 0.481600468904046 +88.4499821923673 0.493579733761573 +88.4745069816709 0.498137797212884 +88.4990317709744 0.49916606334436 +88.5235565602779 0.497306509482545 +88.5480813495815 0.476362566045432 +88.572606138885 0.478456960389143 +88.5971309281886 0.525629958246444 +88.6216557174921 0.547005720566591 +88.6461805067956 0.519740732017585 +88.6707052960992 0.500290901677069 +88.6952300854027 0.532848669206493 +88.7197548747063 0.522939116654291 +88.7442796640098 0.536378466526327 +88.7688044533134 0.512895129820096 +88.7933292426169 0.482221598190875 +88.8178540319204 0.487393122931672 +88.842378821224 0.530246731818229 +88.8669036105275 0.549952250680357 +88.8914283998311 0.543455075207041 +88.9159531891346 0.564226722281403 +88.9404779784381 0.548706158108028 +88.9650027677417 0.554279307648443 +88.9895275570452 0.556349019953767 +89.0140523463488 0.551404667697524 +89.0385771356523 0.574888004403755 +89.0631019249558 0.587492232546782 +89.0876267142594 0.601548877706976 +89.1121515035629 0.629380119421008 +89.1366762928665 0.586929813380427 +89.16120108217 0.628696446015034 +89.1857258714736 0.642001361605079 +89.2102506607771 0.65921852932122 +89.2347754500806 0.69226299185548 +89.2593002393842 0.697186496072008 +89.2838250286877 0.744459900129213 +89.3083498179913 0.788072906583263 +89.3328746072948 0.815589749655209 +89.3573993965983 0.872248149179021 +89.3819241859019 0.915143454145008 +89.4064489752054 0.922803330031792 +89.430973764509 0.944671299401806 +89.4554985538125 0.986777012716885 +89.480023343116 1.02294030172766 +89.5045481324196 0.956565494054114 +89.5290729217231 0.983616490160938 +89.5535977110267 0.938958203534369 +89.5781225003302 0.870954848482232 +89.6026472896338 0.875081093050509 +89.6271720789373 0.876188917342175 +89.6516968682408 0.866552067352628 +89.6762216575444 0.826896843102776 +89.7007464468479 0.867924926209606 +89.7252712361515 0.849020500994401 +89.749796025455 0.859685617115424 +89.7743208147585 0.893637091541541 +89.7988456040621 0.909153821716245 +89.8233703933656 0.920066958361537 +89.8478951826692 0.976628785684115 +89.8724199719727 1.049097465985 +89.8969447612762 1.07767660327051 +89.9214695505798 1.10213332998642 +89.9459943398833 1.12235957193547 +89.9705191291869 1.11072489980344 +89.9950439184904 1.11056578348306 +90.019568707794 1.1429891167305 +90.0440934970975 1.15359552273104 +90.068618286401 1.11123627684667 +90.0931430757046 1.02255017892406 +90.1176678650081 0.992535638662423 +90.1421926543117 0.988623386536327 +90.1667174436152 0.946555535302007 +90.1912422329187 0.928293087413346 +90.2157670222223 0.894031048343815 +90.2402918115258 0.863311986636492 +90.2648166008294 0.866862631996042 +90.2893413901329 0.777084045776453 +90.3138661794364 0.803720237041288 +90.33839096874 0.785827063916516 +90.3629157580435 0.741848616697249 +90.3874405473471 0.734768174017864 +90.4119653366506 0.710491411662053 +90.4364901259542 0.728871279791662 +90.4610149152577 0.708904560362894 +90.4855397045612 0.737072726805085 +90.5100644938648 0.703880649946461 +90.5345892831683 0.75000453363257 +90.5591140724719 0.774209405825535 +90.5836388617754 0.784622667423617 +90.6081636510789 0.786368635043155 +90.6326884403825 0.75555683513327 +90.657213229686 0.785978512239552 +90.6817380189896 0.811421809007502 +90.7062628082931 0.748887363297204 +90.7307875975966 0.737890834493052 +90.7553123869002 0.727477572894969 +90.7798371762037 0.715087337194123 +90.8043619655073 0.682046708658535 +90.8288867548108 0.634790318642374 +90.8534115441144 0.625749915901269 +90.8779363334179 0.642232368088305 +90.9024611227214 0.614815931216262 +90.926985912025 0.634110479235071 +90.9515107013285 0.622727661625986 +90.9760354906321 0.595055536232332 +91.0005602799356 0.623735079717747 +91.0250850692391 0.580667478389009 +91.0496098585427 0.573066312622699 +91.0741346478462 0.566703571431376 +91.0986594371498 0.570837483996996 +91.1231842264533 0.564281598403206 +91.1477090157568 0.574833128281952 +91.1722338050604 0.550183257163582 +91.1967585943639 0.558926275303644 +91.2212833836675 0.578673490245202 +91.245808172971 0.558833537101082 +91.2703329622746 0.573835056233893 +91.2948577515781 0.595424810996221 +91.3193825408816 0.590459610700262 +91.3439073301852 0.599340897120988 +91.3684321194887 0.56985091394495 +91.3929569087923 0.563950185720077 +91.4174816980958 0.574791432202522 +91.4420064873993 0.559551238589144 +91.4665312767029 0.546094874676063 +91.4910560660064 0.54992756864197 +91.51558085531 0.594765819628633 +91.5401056446135 0.593444002894787 +91.564630433917 0.655222885036264 +91.5891552232206 0.653501599455112 +91.6136800125241 0.648863977843612 +91.6382048018277 0.655168008914461 +91.6627295911312 0.695868513336833 +91.6872543804348 0.705291370884198 +91.7117791697383 0.724455318619686 +91.7363039590418 0.737400305489544 +91.7608287483454 0.776169365887254 +91.7853535376489 0.816438051426592 +91.8098783269525 0.875681374297623 +91.834403116256 0.915219178306526 +91.8589279055595 0.958887060882379 +91.8834526948631 1.01570841072524 +91.9079774841666 1.03955335419802 +91.9325022734702 1.07388177138536 +91.9570270627737 1.04558851670488 +91.9815518520772 1.01237559180654 +92.0060766413808 0.961920817153675 +92.0306014306843 0.884738791079771 +92.0551262199879 0.877741740559246 +92.0796510092914 0.81697027650953 +92.104175798595 0.783111540285976 +92.1287005878985 0.764652113996177 +92.153225377202 0.745105711454429 +92.1777501665056 0.711922980639506 +92.2022749558091 0.71557403219896 +92.2267997451127 0.690596582396131 +92.2513245344162 0.656682970050774 +92.2758493237197 0.629707698105467 +92.3003741130233 0.624566367448086 +92.3248989023268 0.629048706737879 +92.3494236916304 0.661002359021517 +92.3739484809339 0.640431524346964 +92.3984732702374 0.680276059000611 +92.422998059541 0.732170070628272 +92.4475228488445 0.711578387914004 +92.4720476381481 0.696489642623662 +92.4965724274516 0.749639092867353 +92.5210972167552 0.753790019474017 +92.5456220060587 0.744463734127885 +92.5701467953622 0.781051174024352 +92.5946715846658 0.801322946051505 +92.6191963739693 0.798734188705614 +92.6437211632729 0.791278959217311 +92.6682459525764 0.770990173149114 +92.6927707418799 0.804165235966695 +92.7172955311835 0.815769714015303 +92.741820320487 0.7509609096012 +92.7663451097906 0.725907735636853 +92.7908698990941 0.718906851117658 +92.8153946883976 0.701807103642465 +92.8399194777012 0.680086748596816 +92.8644442670047 0.617006897761207 +92.8889690563083 0.626215762866391 +92.9134938456118 0.631084390961116 +92.9380186349154 0.608083915261051 +92.9625434242189 0.679155054666572 +92.9870682135224 0.638299267922493 +93.011593002826 0.646807445580659 +93.0361177921295 0.660909620818955 +93.0606425814331 0.656679136052102 +93.0851673707366 0.621812981736787 +93.1096921600401 0.69493681940659 +93.1342169493437 0.680556429560608 +93.1587417386472 0.654391597305925 +93.1832665279508 0.641162405877398 +93.2077913172543 0.705992058331216 +93.2323161065578 0.709597579812569 +93.2568408958614 0.770948477069684 +93.2813656851649 0.842112354677767 +93.3058904744685 0.856277074035209 +93.330415263772 0.875118955131268 +93.3549400530756 0.909557124562221 +93.3794648423791 0.919663655515561 +93.4039896316826 0.881674840725058 +93.4285144209862 0.942152754172403 +93.4530392102897 0.934521394322677 +93.4775639995933 0.904982047069866 +93.5020887888968 0.914139870051919 +93.5266135782003 0.812433061097934 +93.5511383675039 0.795153349262648 +93.5756631568074 0.758175786562577 +93.600187946111 0.686953198834019 +93.6247127354145 0.687780652565687 +93.649237524718 0.676543771234608 +93.6737623140216 0.636297611781344 +93.6982871033251 0.626761167991702 +93.7228118926287 0.621913387936691 +93.7473366819322 0.609867744961348 +93.7718614712358 0.625325765015578 +93.7963862605393 0.629628139945278 +93.8209110498428 0.614778069135503 +93.8454358391464 0.614581090734366 +93.8699606284499 0.614211815970477 +93.8944854177535 0.615437060503091 +93.919010207057 0.619659877272601 +93.9435349963605 0.657552119861871 +93.9680597856641 0.686718358352123 +93.9925845749676 0.668120663781661 +94.0171093642712 0.739108411028323 +94.0416341535747 0.71503246107232 +94.0661589428782 0.658718654274011 +94.0906837321818 0.67998250839824 +94.1152085214853 0.737366277407456 +94.1397333107889 0.721290962065068 +94.1642581000924 0.748518088533315 +94.188782889396 0.678848324021829 +94.2133076786995 0.673744855445207 +94.237832468003 0.63114310108159 +94.2623572573066 0.659021550920083 +94.2868820466101 0.684586101927653 +94.3114068359137 0.644368458511446 +94.3359316252172 0.60202239266944 +94.3604564145207 0.582778886773764 +94.3849812038243 0.565095872092501 +94.4095059931278 0.584235137789602 +94.4340307824314 0.562497768702909 +94.4585555717349 0.567269824596402 +94.4830803610384 0.534170485940339 +94.507605150342 0.537499470860366 +94.5321299396455 0.534749919147738 +94.5566547289491 0.521113590874563 +94.5811795182526 0.544428465216715 +94.6057043075562 0.556563012395949 +94.6302290968597 0.54382434997093 +94.6547538861632 0.551463377817998 +94.6792786754668 0.571047642440506 +94.7038034647703 0.569670949584856 +94.7283282540739 0.577082804947371 +94.7528530433774 0.511329126560652 +94.7773778326809 0.487644977454612 +94.8019026219845 0.513902547911858 +94.826427411288 0.529549878369883 +94.8509522005916 0.520168716901948 +94.8754769898951 0.513012550061045 +94.9000017791986 0.523425811659127 +94.9245265685022 0.480647926934088 +94.9490513578057 0.526620362297161 +94.9735761471093 0.528059599271956 +94.9981009364128 0.521331417315416 +95.0226257257164 0.524722946354587 +95.0471505150199 0.520282303144225 +95.0716753043234 0.557242851803252 +95.096200093627 0.540156284370431 +95.1207248829305 0.555169305499255 +95.1452496722341 0.550728662288892 +95.1697744615376 0.533759515097021 +95.1942992508411 0.555593456384947 +95.2188240401447 0.546753866043651 +95.2433488294482 0.488756635744949 +95.2678736187518 0.484329172576959 +95.2923984080553 0.511438878804258 +95.3169231973588 0.532151815758146 +95.3414479866624 0.517335773030459 +95.3659727759659 0.537986165865202 +95.3904975652695 0.543841364011974 +95.415022354573 0.565427284775631 +95.4395471438766 0.558502124417953 +95.4640719331801 0.562090631858262 +95.4885967224836 0.56922595065945 +95.5131215117872 0.566707405430047 +95.5376463010907 0.542972214200876 +95.5621710903943 0.542968380202205 +95.5866958796978 0.548013138658352 +95.6112206690013 0.571026794400791 +95.6357454583049 0.584411268151025 +95.6602702476084 0.583186023618411 +95.684795036912 0.574774418161478 +95.7093198262155 0.604184843177327 +95.733844615519 0.630987818759883 +95.7583694048226 0.612213993827999 +95.7828941941261 0.640259227984213 +95.8074189834297 0.64246337457153 +95.8319437727332 0.640490234467438 +95.8564685620368 0.621212700489673 +95.8809933513403 0.70930786320887 +95.9055181406438 0.67764009353026 +95.9300429299474 0.656896962492955 +95.9545677192509 0.653887888260045 +95.9790925085545 0.63711571946931 +96.003617297858 0.611479278298894 +96.0281420871615 0.611147865615764 +96.0526668764651 0.629900842507933 +96.0771916657686 0.604792792421783 +96.1017164550722 0.625498061378329 +96.1262412443757 0.592071144037808 +96.1507660336792 0.614446656452374 +96.1752908229828 0.577351673511355 +96.1998156122863 0.597670653662968 +96.2243404015899 0.609288311753949 +96.2488651908934 0.599924164327058 +96.273389980197 0.586018967489899 +96.2979147695005 0.580453485946827 +96.322439558804 0.583093285415849 +96.3469643481076 0.577599694035624 +96.3714891374111 0.611231257774625 +96.3960139267147 0.60753851013574 +96.4205387160182 0.645572855004344 +96.4450635053217 0.6224132629839 +96.4695882946253 0.609985165202296 +96.4941130839288 0.634362333758011 +96.5186378732324 0.61062714252884 +96.5431626625359 0.616385768474378 +96.5676874518394 0.603239969204712 +96.592212241143 0.659487397885204 +96.6167370304465 0.648943536003801 +96.6412618197501 0.699919033743592 +96.6657866090536 0.672506430870221 +96.6903113983572 0.725551640915337 +96.7148361876607 0.72585285951505 +96.7393609769642 0.656296681245841 +96.7638857662678 0.649695265573951 +96.7884105555713 0.664380708018316 +96.8129353448749 0.704107822431015 +96.8374601341784 0.698139038041967 +96.8619849234819 0.690151583470725 +96.8865097127855 0.678181664656899 +96.911034502089 0.733022206398326 +96.9355592913926 0.720497536415488 +96.9600840806961 0.739964380797048 +96.9846088699996 0.777424804503284 +97.0091336593032 0.782859685763035 +97.0336584486067 0.827879579156151 +97.0581832379103 0.856294088076253 +97.0827080272138 0.837230546540669 +97.1072328165174 0.934472030245905 +97.1317576058209 0.983302091518853 +97.1562823951244 1.06723865963404 +97.180807184428 1.17922812990279 +97.2053319737315 1.25156237592168 +97.2298567630351 1.26030539406175 +97.2543815523386 1.2866727167626 +97.2789063416421 1.41517866730047 +97.3034311309457 1.46904965303089 +97.3279559202492 1.5206709620959 +97.3524807095528 1.51225552264029 +97.3770054988563 1.53410647796926 +97.4015302881598 1.51268350752466 +97.4260550774634 1.45411067801723 +97.4505798667669 1.40682193796534 +97.4751046560705 1.34989850387621 +97.499629445374 1.29459211516966 +97.5241542346776 1.21908416655245 +97.5486790239811 1.13246610288881 +97.5732038132846 1.09961095075834 +97.5977286025882 1.05100254992492 +97.6222533918917 1.03994731100029 +97.6467781811953 1.04555065462412 +97.6713029704988 1.00600901661655 +97.6958277598023 1.02891675411405 +97.7203525491059 0.995343900495525 +97.7448773384094 1.03922577551356 +97.769402127713 1.0540248042002 +97.7939269170165 1.04482911913739 +97.81845170632 1.11196332437843 +97.8429764956236 1.12803863972082 +97.8675012849271 1.11175316593492 +97.8920260742307 1.11688682859496 +97.9165508635342 1.14927229976163 +97.9410756528378 1.13746533126685 +97.9656004421413 1.17166866021591 +97.9901252314448 1.14757186222019 +98.0146500207484 1.1408700403484 +98.0391748100519 1.15606302583732 +98.0636995993555 1.12373243079245 +98.088224388659 1.159530279038 +98.1127491779625 1.19793941071553 +98.1372739672661 1.2248636405377 +98.1617987565696 1.18390361359505 +98.1863235458732 1.20318498157148 +98.2108483351767 1.12152445020646 +98.2353731244802 1.1066952274364 +98.2598979137838 1.01923820804507 +98.2844227030873 1.00670970406357 +98.3089474923909 0.957228319420372 +98.3334722816944 0.926346307393999 +98.357997070998 0.927155069038264 +98.3825218603015 0.948570371485529 +98.407046649605 0.914084993930116 +98.4315714389086 0.80636003651031 +98.4560962282121 0.798548712300491 +98.4806210175157 0.785495651233386 +98.5051458068192 0.812601523462014 +98.5296705961227 0.829742967016637 +98.5541953854263 0.831186037990103 +98.5787201747298 0.789256455036446 +98.6032449640334 0.798079031336698 +98.6277697533369 0.830892487387732 +98.6522945426404 0.795094639142174 +98.676819331944 0.770041465177827 +98.7013441212475 0.76876134452341 +98.7258689105511 0.735893012350573 +98.7503936998546 0.753055303944911 +98.7749184891582 0.720925521299851 +98.7994432784617 0.720124427652929 +98.8239680677652 0.722650640879674 +98.8484928570688 0.711250809229545 +98.8730176463723 0.660322519614214 +98.8975424356759 0.690986705199735 +98.9220672249794 0.671394772579885 +98.9465920142829 0.711616249994762 +98.9711168035865 0.678886186102588 +98.99564159289 0.658248973310218 +99.0201663821936 0.620926817884645 +99.0446911714971 0.631974388811929 +99.0692159608006 0.637502008274242 +99.0937407501042 0.621544113172803 +99.1182655394077 0.653266758973216 +99.1427903287113 0.63653245226324 +99.1673151180148 0.655050588673513 +99.1918399073184 0.659784782486246 +99.2163646966219 0.640683378869904 +99.2408894859254 0.624587215487801 +99.265414275229 0.653887888260045 +99.2899390645325 0.652410789204491 +99.3144638538361 0.693912387273785 +99.3389886431396 0.657531271822156 +99.3635134324431 0.68390626252035 +99.3880382217467 0.678126788535096 +99.4125630110502 0.688053355128342 +99.4370878003538 0.704888068038222 +99.4616125896573 0.683923276561394 +99.4861373789608 0.719393546122494 +99.5106621682644 0.709480159571621 +99.5351869575679 0.715960321003892 +99.5597117468715 0.709110884807732 +99.584236536175 0.753382882629369 +99.6087613254786 0.734944304379286 +99.6332861147821 0.783359560810245 +99.6578109040856 0.79800330717518 +99.6823356933892 0.828869983206868 +99.7068604826927 0.861762997418092 +99.7313852719963 0.897918618431525 +99.7559100612998 0.92726482128187 +99.7804348506033 0.930673364362086 +99.8049596399069 1.01710211762193 +99.8294844292104 1.00349047138715 +99.854009218514 0.994823177408601 +99.8785340078175 0.999612247343137 +99.903058797121 0.973962626130348 +99.9275835864246 0.950668599827912 +99.9521083757281 0.923269176996913 +99.9766331650317 0.894979756315102 +100.001157954335 0.91343534860623 +100.025682743639 0.913694871126512 +100.050207532942 0.839635505527795 +100.074732322246 0.816407857343175 +100.099257111549 0.792089398907934 +100.123781900853 0.76963432833318 +100.148306690156 0.739208817228227 +100.17283147946 0.749739499067258 +100.197356268764 0.729475395037447 +100.221881058067 0.728333542663694 +100.246405847371 0.703738547667126 +100.270930636674 0.752703043222067 +100.295455425978 0.739968214795719 +100.319980215281 0.719351850043064 +100.344505004585 0.74068208228511 +100.369029793888 0.720594108616721 +100.393554583192 0.706344319054061 +100.418079372495 0.698832057491642 +100.442604161799 0.757685257559069 +100.467128951102 0.76048417334847 +100.491653740406 0.776127669807824 +100.51617852971 0.832538048807366 +100.540703319013 0.788483877426582 +100.565228108317 0.79984201299728 +100.58975289762 0.834204458266715 +100.614277686924 0.844114010818917 +100.638802476227 0.860323760443297 +100.663327265531 0.857553360690954 +100.687852054834 0.912818053318072 +100.712376844138 0.879328591858406 +100.736901633441 0.857401912367918 +100.761426422745 0.813457493230739 +100.785951212049 0.818439707567741 +100.810476001352 0.807547418962165 +100.835000790656 0.80197426942175 +100.859525579959 0.82047922578965 +100.884050369263 0.823770348628917 +100.908575158566 0.829301802089902 +100.93309994787 0.785461623151298 +100.957624737173 0.773177305695387 +100.982149526477 0.789801860161757 +101.00667431578 0.813902492156146 +101.031199105084 0.818687728092011 +101.055723894387 0.852046589268356 +101.080248683691 0.858136627897024 +101.104773472995 0.893813221902963 +101.129298262298 0.904751040586641 +101.153823051602 0.85448941033624 +101.178347840905 0.899744144211252 +101.202872630209 0.968448186710407 +101.227397419512 1.0323214631956 +101.251922208816 1.06788830495793 +101.276446998119 1.05041544872018 +101.300971787423 1.14889919099907 +101.325496576726 1.13866972775975 +101.35002136603 1.12441227019975 +101.374546155334 1.19827082339866 +101.399070944637 1.13834214907529 +101.423595733941 1.11136304313132 +101.448120523244 1.04597863950849 +101.472645312548 1.07318108393835 +101.497170101851 1.03448223565712 +101.521694891155 0.974151936534143 +101.546219680458 0.997031157994589 +101.570744469762 0.981097944931536 +101.595269259065 0.973572503326744 +101.619794048369 0.932729896625038 +101.644318837672 0.918887243907025 +101.668843626976 0.912293496232476 +101.69336841628 0.965132381832754 +101.717893205583 0.968200166186138 +101.742417994887 0.940565902873244 +101.76694278419 0.961933997196048 +101.791467573494 1.01948622856934 +101.815992362797 1.01729909602307 +101.840517152101 0.996275594425768 +101.865041941404 1.00389760823179 +101.889566730708 0.99996067406731 +101.914091520011 0.995133742052015 +101.938616309315 0.982491651828229 +101.963141098619 0.968200166186138 +101.987665887922 0.947470215191206 +102.012190677226 0.952645573930675 +102.036715466529 0.958017911071281 +102.061240255833 0.996082450023302 +102.085765045136 0.957165775301227 +102.11028983444 0.96966959724435 +102.134814623743 0.990499954439186 +102.159339413047 0.953635977981392 +102.18386420235 0.97133984070237 +102.208388991654 0.981715240219693 +102.232913780957 0.978164594860143 +102.257438570261 0.911117615776636 +102.281963359565 0.906765876770163 +102.306488148868 0.902870638685111 +102.331012938172 0.883114077699852 +102.355537727475 0.826993415304009 +102.380062516779 0.823812044708347 +102.404587306082 0.80640173258974 +102.429112095386 0.820765108394678 +102.453636884689 0.779833597489081 +102.478161673993 0.794590930096293 +102.502686463296 0.786855330047992 +102.5272112526 0.743183613473468 +102.551736041903 0.745509014300405 +102.576260831207 0.782607831240095 +102.600785620511 0.792202985150211 +102.625310409814 0.793600526045576 +102.649835199118 0.774171543744776 +102.674359988421 0.791098994857217 +102.698884777725 0.812059952335374 +102.723409567028 0.836882119816496 +102.747934356332 0.762889132335595 +102.772459145635 0.765521263807275 +102.796983934939 0.739057368905191 +102.821508724242 0.705933348210742 +102.846033513546 0.733139626639274 +102.87055830285 0.729005714073654 +102.895083092153 0.722730199039863 +102.919607881457 0.731255390739073 +102.94413267076 0.710457383579965 +102.968657460064 0.679192916747331 +102.993182249367 0.691003719240779 +103.017707038671 0.645199746241785 +103.042231827974 0.686525213949657 +103.066756617278 0.658366393551166 +103.091281406581 0.67225074234861 +103.115806195885 0.651310632910168 +103.140330985188 0.633468501908527 +103.164855774492 0.686324401549848 +103.189380563796 0.711464801671727 +103.213905353099 0.633216647385587 +103.238430142403 0.687008074955822 +103.262954931706 0.65954994200435 +103.28747972101 0.679096344546098 +103.312004510313 0.68299158263115 +103.336529299617 0.704556655355092 +103.36105408892 0.669694335038448 +103.385578878224 0.684426985607274 +103.410103667527 0.684061544842057 +103.434628456831 0.683264285193806 +103.459153246135 0.684195979124049 +103.483678035438 0.691586986446848 +103.508202824742 0.688515368094792 +103.532727614045 0.712917218688894 +103.557252403349 0.700233432385678 +103.581777192652 0.714210519385683 +103.606301981956 0.745899137104008 +103.630826771259 0.744698574609781 +103.655351560563 0.734495471455208 +103.679876349866 0.791775000265849 +103.70440113917 0.809054712101135 +103.728925928473 0.803627498838726 +103.753450717777 0.842095340636723 +103.777975507081 0.847992234862925 +103.802500296384 0.855441952306199 +103.827025085688 0.828597280644213 +103.851549874991 0.915067729983491 +103.876074664295 0.8499351808836 +103.900599453598 0.855920979313693 +103.925124242902 0.825931121090445 +103.949649032205 0.803044231632656 +103.974173821509 0.786948068250554 +103.998698610812 0.812491771218408 +104.023223400116 0.76691880470264 +104.04774818942 0.756056710180479 +104.072272978723 0.769075743165496 +104.096797768027 0.739091396987279 +104.12132255733 0.740199221278944 +104.145847346634 0.738491115740165 +104.170372135937 0.70630262297463 +104.194896925241 0.73228749086922 +104.219421714544 0.686155939185768 +104.243946503848 0.675415098903227 +104.268471293151 0.656423447530491 +104.292996082455 0.69635520834167 +104.317520871758 0.68227771514176 +104.342045661062 0.701568429161897 +104.366570450366 0.655986116602427 +104.391095239669 0.68921605554181 +104.415620028973 0.708628023801567 +104.440144818276 0.70930786320887 +104.46466960758 0.725051765868128 +104.489194396883 0.741534218055163 +104.513719186187 0.731380478977363 +104.53824397549 0.664339011938886 +104.562768764794 0.7130269709325 +104.587293554097 0.71803770130656 +104.611818343401 0.710798142306796 +104.636343132704 0.749114535781758 +104.660867922008 0.780592995056573 +104.685392711312 0.767905374754685 +104.709917500615 0.771376461954046 +104.734442289919 0.806788021394673 +104.758967079222 0.780261582373443 +104.783491868526 0.804496648649824 +104.808016657829 0.763917398467072 +104.832541447133 0.750453366556648 +104.857066236436 0.769672190413939 +104.88159102574 0.783342546769201 +104.906115815043 0.757244092632334 +104.930640604347 0.76249517553332 +104.955165393651 0.807136448118846 +104.979690182954 0.776383358329435 +105.004214972258 0.78906331063398 +105.028739761561 0.762088038688673 +105.053264550865 0.815417453292458 +105.077789340168 0.767577796070227 +105.102314129472 0.78128984850492 +105.126838918775 0.795577500148339 +105.151363708079 0.803485396559392 +105.175888497382 0.844021272616355 +105.200413286686 0.853730012768748 +105.224938075989 0.891777537679726 +105.249462865293 0.92120881073529 +105.273987654597 0.927634096045758 +105.2985124439 0.978047174619195 +105.323037233204 0.996527448948709 +105.347562022507 1.03387428641267 +105.372086811811 1.01252704012958 +105.396611601114 1.00477059204156 +105.421136390418 1.02008650981646 +105.445661179721 1.02019075001503 +105.470185969025 1.0055470036501 +105.494710758328 0.948015620316517 +105.519235547632 0.937153525794357 +105.543760336936 0.884449074476072 +105.568285126239 0.920809341887985 +105.592809915543 0.837641517383988 +105.617334704846 0.863438752921142 +105.64185949415 0.912804873275699 +105.666384283453 0.844810864267264 +105.690909072757 0.844369699340528 +105.71543386206 0.865364684900773 +105.739958651364 0.842006436432833 +105.764483440667 0.838040986231293 +105.789008229971 0.857649932892187 +105.813533019274 0.874401253643206 +105.838057808578 0.854258403853015 +105.862582597882 0.835139986195629 +105.887107387185 0.831610188875794 +105.911632176489 0.817021318632662 +105.936156965792 0.865985814187602 +105.960681755096 0.86183872157961 +105.985206544399 0.863063966112223 +106.009731333703 0.826175307616043 +106.034256123006 0.837251394580384 +106.05878091231 0.856504246519763 +106.083305701613 0.843534577611518 +106.107830490917 0.812912088105428 +106.132355280221 0.874673956205862 +106.156880069524 0.868474165333588 +106.181404858828 0.861175896213351 +106.205929648131 0.890556127145783 +106.230454437435 0.853481992244479 +106.254979226738 0.870409443356921 +106.279504016042 0.850069615165593 +106.304028805345 0.840622075579841 +106.328553594649 0.87696532895071 +106.353078383952 0.846695100167465 +106.377603173256 0.804869757412384 +106.402127962559 0.834939173795821 +106.426652751863 0.794649640216767 +106.451177541167 0.799635688552441 +106.47570233047 0.768895778805403 +106.500227119774 0.763582151785271 +106.524751909077 0.79854487830182 +106.549276698381 0.770335015780197 +106.573801487684 0.771842308919168 +106.598326276988 0.714994598991561 +106.622851066291 0.67893722822572 +106.647375855595 0.755867399776684 +106.671900644898 0.728539867108533 +106.696425434202 0.770624732383897 +106.720950223505 0.754121432157146 +106.745475012809 0.749949657510768 +106.769999802113 0.790457017530673 +106.794524591416 0.815396605252743 +106.81904938072 0.783442952969105 +106.843574170023 0.742583332226355 +106.868098959327 0.784639681464661 +106.89262374863 0.773419814174626 +106.917148537934 0.75576699357678 +106.941673327237 0.719020437359934 +106.966198116541 0.734889428257483 +106.990722905844 0.75225804429666 +107.015247695148 0.734461005420652 +107.039772484452 0.736866928340825 +107.064297273755 0.722087316395547 +107.088822063059 0.712182982601605 +107.113346852362 0.696046942780403 +107.137871641666 0.704852763527506 +107.162396430969 0.710657547067015 +107.186921220273 0.716186194337457 +107.211446009576 0.724073802394208 +107.23597079888 0.706375183236734 +107.260495588183 0.686649467667162 +107.285020377487 0.712519949913152 +107.30954516679 0.71536986271759 +107.334069956094 0.734236082512953 +107.358594745398 0.716346781152258 +107.383119534701 0.733003467330338 +107.407644324005 0.758494573060883 +107.432169113308 0.760161226743534 +107.456693902612 0.757853028532198 +107.481218691915 0.745913177356058 +107.505743481219 0.739408752187235 +107.530268270522 0.761845869593142 +107.554793059826 0.803823105314201 +107.579317849129 0.78472338403622 +107.603842638433 0.791560130929887 +107.628367427737 0.820476976317991 +107.65289221704 0.808224830211686 +107.677417006344 0.858307794137904 +107.701941795647 0.896750967404696 +107.726466584951 0.954799262107067 +107.750991374254 0.960976820180037 +107.775516163558 1.00467043071718 +107.800040952861 1.04386153302885 +107.824565742165 1.06707083509505 +107.849090531468 1.10407901918516 +107.873615320772 1.15783372521092 +107.898140110075 1.1834662497406 +107.922664899379 1.22757414231607 +107.947189688683 1.2321895244378 +107.971714477986 1.22842650869705 +107.99623926729 1.21263042733375 +108.020764056593 1.20557182296823 +108.045288845897 1.16334086709216 +108.0698136352 1.12604247729953 +108.094338424504 1.08893463899343 +108.118863213807 1.02654925756764 +108.143388003111 0.984888831520522 +108.167912792414 0.970627451933738 +108.192437581718 0.969160609289071 +108.216962371022 0.932538613247054 +108.241487160325 0.904197294840024 +108.266011949629 0.8992111195116 +108.290536738932 0.891452918519668 +108.315061528236 0.869046899631301 +108.339586317539 0.848712131057548 +108.364111106843 0.838739980925535 +108.388635896146 0.815784036024629 +108.41316068545 0.812661347777667 +108.437685474753 0.838597559123519 +108.462210264057 0.807355491173816 +108.48673505336 0.83214123675108 +108.511259842664 0.83954989979019 +108.535784631968 0.826449694705138 +108.560309421271 0.832661080756144 +108.584834210575 0.832669713675378 +108.609358999878 0.842354536396832 +108.633883789182 0.837686656153578 +108.658408578485 0.870382888112342 +108.682933367789 0.880232898106167 +108.707458157092 0.900905900889328 +108.731982946396 0.911194051526758 +108.756507735699 0.920879807442955 +108.781032525003 0.981929432534494 +108.805557314306 0.96425811391504 +108.83008210361 0.971455220349066 +108.854606892914 1.0047167911503 +108.879131682217 1.02427025777953 +108.903656471521 1.04767282728557 +108.928181260824 1.04001600488436 +108.952706050128 1.03939599067636 +108.977230839431 1.02971725811571 +109.001755628735 1.02370799788009 +109.026280418038 0.995567112535677 +109.050805207342 0.979294078779556 +109.075329996645 0.98953999593268 +109.099854785949 0.986542249617251 +109.124379575253 0.983274669268927 +109.148904364556 0.967962931125061 +109.17342915386 0.988300639151795 +109.197953943163 0.989721398513028 +109.222478732467 0.993093787960521 +109.24700352177 1.00389585686374 +109.271528311074 1.00835224361958 +109.296053100377 1.03301312180728 +109.320577889681 1.07619384870347 +109.345102678984 1.12101223611774 +109.369627468288 1.1400510451208 +109.394152257591 1.16847575282536 +109.418677046895 1.20415301539469 +109.443201836199 1.24257807534207 +109.467726625502 1.27168821770909 +109.492251414806 1.28037781275922 +109.516776204109 1.26200269393968 +109.541300993413 1.30250533768109 +109.565825782716 1.27153585133955 +109.59035057202 1.2224624052406 +109.614875361323 1.2148406009642 +109.639400150627 1.17883297988201 +109.66392493993 1.12715245194708 +109.688449729234 1.06690423013671 +109.712974518538 1.02871134651648 +109.737499307841 1.01206499270088 +109.762024097145 0.974188467968195 +109.786548886448 0.948217695974401 +109.811073675752 0.949343741579812 +109.835598465055 0.901448643290558 +109.860123254359 0.879910721599916 +109.884648043662 0.861831114280426 +109.909172832966 0.864847512624577 +109.933697622269 0.857934798881953 +109.958222411573 0.859778103520563 +109.982747200876 0.838852151564722 +110.00727199018 0.837950954325042 +110.031796779484 0.847286331624178 +110.056321568787 0.850882609354532 +110.080846358091 0.813622573708014 +110.105371147394 0.838153330401993 +110.129895936698 0.857238454835277 +110.154420726001 0.83614255520932 +110.178945515305 0.848214407775846 +110.203470304608 0.870775281574103 +110.227995093912 0.844277112283746 +110.252519883215 0.851724284990902 +110.277044672519 0.872098798634846 +110.301569461823 0.890832083718846 +110.326094251126 0.909792780250896 +110.35061904043 0.920832845182856 +110.375143829733 0.937713162818001 +110.399668619037 0.944983905291688 +110.42419340834 0.982376388633633 +110.448718197644 0.974043724698298 +110.473242986947 0.962661438224402 +110.497767776251 0.985895457674885 +110.522292565554 0.971056080681446 +110.546817354858 0.967209423298733 +110.571342144161 0.947507521331533 +110.595866933465 0.946139456009076 +110.620391722769 0.913424276883368 +110.644916512072 0.874110076433519 +110.669441301376 0.851265166243104 +110.693966090679 0.849281858408451 +110.718490879983 0.852235401463347 +110.743015669286 0.842770831257644 +110.76754045859 0.825228955806316 +110.792065247893 0.797391881430532 +110.816590037197 0.770193173419426 +110.8411148265 0.779370716086617 +110.865639615804 0.774881788195785 +110.890164405107 0.774562877776455 +110.914689194411 0.767707992758131 +110.939213983715 0.736797387754261 +110.963738773018 0.737567171797117 +110.988263562322 0.740455186403222 +111.012788351625 0.732697035021779 +111.037313140929 0.729373420005791 +111.061837930232 0.733551720787755 +111.086362719536 0.750027123930353 +111.110887508839 0.703326951622253 +111.135412298143 0.701597246606865 +111.159937087446 0.715289061055157 +111.18446187675 0.721801812580693 +111.208986666054 0.74010397368616 +111.233511455357 0.723700130769312 +111.258036244661 0.708307803038381 +111.282561033964 0.720585293161188 +111.307085823268 0.731830549470624 +111.331610612571 0.713327560817108 +111.356135401875 0.696494086023431 +111.380660191178 0.693634329955331 +111.405184980482 0.71578124165872 +111.429709769785 0.718903521913067 +111.454234559089 0.703821922594863 +111.478759348392 0.69887785659829 +111.503284137696 0.700824879410271 +111.527808927 0.726899775360934 +111.552333716303 0.711272343400405 +111.576858505607 0.693303482217422 +111.60138329491 0.740611328156155 +111.625908084214 0.712268831026649 +111.650432873517 0.708181006015426 +111.674957662821 0.714569969652897 +111.699482452124 0.727582444333356 +111.724007241428 0.745831724256159 +111.748532030731 0.745248723006909 +111.773056820035 0.722465270617431 +111.797581609339 0.71684950815032 +111.822106398642 0.743480438389096 +111.846631187946 0.772662823915045 +111.871155977249 0.75851878114869 +111.895680766553 0.754775866744591 +111.920205555856 0.781706954070116 +111.94473034516 0.788179246096562 +111.969255134463 0.781229388552257 +111.993779923767 0.821953637421076 +112.01830471307 0.844044602379714 +112.042829502374 0.867345678610234 +112.067354291677 0.876092976275557 +112.091879080981 0.848464460668031 +112.116403870285 0.871978853855435 +112.140928659588 0.890325513612129 +112.165453448892 0.868790670864518 +112.189978238195 0.874432710542874 +112.214503027499 0.854239806820823 +112.239027816802 0.83624730119082 +112.263552606106 0.810173126485766 +112.288077395409 0.819700953156632 +112.312602184713 0.836993278448011 +112.337126974016 0.811907909759481 +112.36165176332 0.793323073520631 +112.386176552624 0.794585094468011 +112.410701341927 0.785092610725483 +112.435226131231 0.763664885037741 +112.459750920534 0.768383437723936 +112.484275709838 0.757220224917079 +112.508800499141 0.754087573987825 +112.533325288445 0.744816602715964 +112.557850077748 0.730317082750331 +112.582374867052 0.738413957313767 +112.606899656355 0.734629379756622 +112.631424445659 0.747932957231037 +112.655949234962 0.724276203276403 +112.680474024266 0.730144175555815 +112.70499881357 0.737647509165974 +112.729523602873 0.724585489071678 +112.754048392177 0.734657669790345 +112.77857318148 0.740907214070215 +112.803097970784 0.773163882965576 +112.827622760087 0.750536622065754 +112.852147549391 0.725146168946495 +112.876672338694 0.745501591073384 +112.901197127998 0.748539057527524 +112.925721917301 0.744729938431925 +112.950246706605 0.751059073903565 +112.974771495908 0.775676582804497 +112.999296285212 0.777639437737084 +113.023821074516 0.778235561844098 +113.048345863819 0.790124625766256 +113.072870653123 0.797403110884449 +113.097395442426 0.822565913718397 +113.12192023173 0.81413566469051 +113.146445021033 0.824810296431373 +113.170969810337 0.851517570016004 +113.19549459964 0.843082348641238 +113.220019388944 0.842908206297049 +113.244544178247 0.843663062001208 +113.269068967551 0.815080224526485 +113.293593756855 0.831034239742708 +113.318118546158 0.852897818184775 +113.342643335462 0.839019773033132 +113.367168124765 0.823002059654297 +113.391692914069 0.843065037799874 +113.416217703372 0.838307910245079 +113.440742492676 0.851828604991251 +113.465267281979 0.844274177564589 +113.489792071283 0.827250534471755 +113.514316860586 0.826700883399784 +113.53884164989 0.857884300075719 +113.563366439193 0.870567250217091 +113.587891228497 0.867676508233373 +113.612416017801 0.89581101023541 +113.636940807104 0.900150400438176 +113.661465596408 0.887623955039455 +113.685990385711 0.915148112460442 +113.710515175015 0.93430393821423 +113.735039964318 0.949611794937017 +113.759564753622 0.923808207132418 +113.784089542925 0.943927589499613 +113.808614332229 0.932085336923207 +113.833139121532 0.935451356535503 +113.857663910836 0.940693922969357 +113.88218870014 0.957028678295155 +113.906713489443 0.947987268700988 +113.931238278747 0.953804460543126 +113.95576306805 0.97996437763554 +113.980287857354 0.991699551464503 +114.004812646657 0.992807562900058 +114.029337435961 0.98633053749023 +114.053862225264 1.01680146001207 +114.078387014568 1.04756981697686 +114.102911803871 1.08234306713222 +114.127436593175 1.0880106198562 +114.151961382478 1.12253767165233 +114.176486171782 1.14223645857319 +114.201010961086 1.16396763211361 +114.225535750389 1.19569808729495 +114.250060539693 1.20858582069495 +114.274585328996 1.23104531590248 +114.2991101183 1.22669532969473 +114.323634907603 1.20646913878683 +114.348159696907 1.18587067374236 +114.37268448621 1.18783968447813 +114.397209275514 1.17413124893836 +114.421734064817 1.131081101139 +114.446258854121 1.10561859408758 +114.470783643425 1.04776091398941 +114.495308432728 1.01863584801752 +114.519833222032 1.00585825419323 +114.544358011335 1.00361153858807 +114.568882800639 0.986964175079115 +114.593407589942 0.960225996811306 +114.617932379246 0.966417725747824 +114.642457168549 0.96886799627864 +114.666981957853 0.92910799377312 +114.691506747156 0.915079964754607 +114.71603153646 0.927843044797056 +114.740556325763 0.919012337636553 +114.765081115067 0.92455901907685 +114.789605904371 0.931277556990133 +114.814130693674 0.922891335503188 +114.838655482978 0.9126818857828 +114.863180272281 0.906260331399848 +114.887705061585 0.902412238216391 +114.912229850888 0.889785016180164 +114.936754640192 0.893984653448447 +114.961279429495 0.902265044718567 +114.985804218799 0.90607537889242 +115.010329008102 0.8828946171215 +115.034853797406 0.896512062860223 +115.059378586709 0.907903466744584 +115.083903376013 0.910073286913629 +115.108428165317 0.923194558025787 +115.13295295462 0.922221782698057 +115.157477743924 0.954640656619026 +115.182002533227 0.97299396127772 +115.206527322531 0.966691511009941 +115.231052111834 0.975853999103096 +115.255576901138 0.994389848961307 +115.280101690441 0.998483441980749 +115.304626479745 1.01676971466465 +115.329151269048 0.993172112506901 +115.353676058352 1.00389470282027 +115.378200847656 1.0104658352866 +115.402725636959 0.957502556352532 +115.427250426263 0.97829737238747 +115.451775215566 0.981930561772718 +115.47630000487 0.978426276846289 +115.500824794173 0.936705333009682 +115.525349583477 0.940195115578565 +115.54987437278 0.937429414873591 +115.574399162084 0.925479413745034 +115.598923951387 0.901217512886309 +115.623448740691 0.890858649504076 +115.647973529994 0.880725310856519 +115.672498319298 0.874393222550951 +115.697023108602 0.868308477874726 +115.721547897905 0.869864912705881 +115.746072687209 0.861776508723032 +115.770597476512 0.832829103526696 +115.795122265816 0.85645500240864 +115.819647055119 0.850803619989741 +115.844171844423 0.858169064530195 +115.868696633726 0.837745787879045 +115.89322142303 0.867677574353927 +115.917746212333 0.861571831375855 +115.942271001637 0.853919259949678 +115.966795790941 0.858566437029307 +115.991320580244 0.861118536937237 +116.015845369548 0.859968328246918 +116.040370158851 0.869413480175392 +116.064894948155 0.897406908253243 +116.089419737458 0.898587909024818 +116.113944526762 0.885791767126604 +116.138469316065 0.899195012324191 +116.162994105369 0.917784381421587 +116.187518894672 0.943766921578607 +116.212043683976 0.940341161849629 +116.236568473279 0.939506376642993 +116.261093262583 1.01108506973891 +116.285618051887 1.03046326017814 +116.31014284119 1.03147883932144 +116.334667630494 1.05364043579244 +116.359192419797 1.06235867717553 +116.383717209101 1.08931182223299 +116.408241998404 1.10927798418546 +116.432766787708 1.10124233066858 +116.457291577011 1.11798075839431 +116.481816366315 1.10913536185861 +116.506341155618 1.09053920142622 +116.530865944922 1.12103474002848 +116.555390734226 1.08155323817992 +116.579915523529 1.04882932470488 +116.604440312833 1.04177568599577 +116.628965102136 1.01931614786822 +116.65348989144 1.02582835386774 +116.678014680743 0.994762053289743 +116.702539470047 0.966414716612935 +116.72706425935 0.943060527052961 +116.751589048654 0.923359990952127 +116.776113837957 0.937325396828173 +116.800638627261 0.93046856671263 +116.825163416564 0.927813575914622 +116.849688205868 0.906965082909442 +116.874212995172 0.896915586554925 +116.898737784475 0.884675278419988 +116.923262573779 0.863440410222827 +116.947787363082 0.893415408379656 +116.972312152386 0.894364577572792 +116.996836941689 0.896254053417751 +117.021361730993 0.91072355228446 +117.045886520296 0.892769274691464 +117.0704113096 0.90222430806979 +117.094936098903 0.898624651524357 +117.119460888207 0.88986744078723 +117.143985677511 0.905875743574028 +117.168510466814 0.911602998354733 +117.193035256118 0.900105036317467 +117.217560045421 0.909012312153905 +117.242084834725 0.922608942127081 +117.266609624028 0.946263732995962 +117.291134413332 0.949161178265523 +117.315659202635 0.937453516923714 +117.340183991939 0.958349605511687 +117.364708781242 0.956931041509231 +117.389233570546 0.982361622633581 +117.413758359849 0.972751826875869 +117.438283149153 1.01247102488112 +117.462807938457 1.03471809814032 +117.48733272776 1.04160634684311 +117.511857517064 1.07376129700663 +117.536382306367 1.07890674945821 +117.560907095671 1.07510156808466 +117.585431884974 1.0795557165617 +117.609956674278 1.12378207519583 +117.634481463581 1.0885531167297 +117.659006252885 1.11537508755382 +117.683531042188 1.1111850299067 +117.708055831492 1.09513305783485 +117.732580620795 1.1378351033559 +117.757105410099 1.16529632217231 +117.781630199403 1.17546229656824 +117.806154988706 1.18687349970808 +117.83067977801 1.19647168964122 +117.855204567313 1.2127297366748 +117.879729356617 1.24850605163314 +117.90425414592 1.23970786749286 +117.928778935224 1.27916793824171 +117.953303724527 1.33872675156427 +117.977828513831 1.38677053545305 +118.002353303134 1.40298305615351 +118.026878092438 1.42729454730274 +118.051402881742 1.44727874134218 +118.075927671045 1.51816160637838 +118.100452460349 1.5535884759144 +118.124977249652 1.54644577912053 +118.149502038956 1.54067842113997 +118.174026828259 1.5134436106425 +118.198551617563 1.47614970409792 +118.223076406866 1.42166751719552 +118.24760119617 1.37600137749125 +118.272125985473 1.37315189275085 +118.296650774777 1.3121097962718 +118.32117556408 1.29236349695723 +118.345700353384 1.2733817391319 +118.370225142688 1.23583514693092 +118.394749931991 1.20719239336745 +118.419274721295 1.15700663985501 +118.443799510598 1.15517460285651 +118.468324299902 1.1519040944795 +118.492849089205 1.12203658779656 +118.517373878509 1.11850413894551 +118.541898667812 1.11351021428211 +118.566423457116 1.09263287902671 +118.590948246419 1.09177359728452 +118.615473035723 1.11044486566062 +118.639997825027 1.14011606427312 +118.66452261433 1.08613140669182 +118.689047403634 1.09085141525018 +118.713572192937 1.08408576416245 +118.738096982241 1.05817037539885 +118.762621771544 1.0681041397628 +118.787146560848 1.07877805234094 +118.811671350151 1.0699467681587 +118.836196139455 1.0634666390006 +118.860720928758 1.02253158639426 +118.885245718062 1.04168289740427 +118.909770507365 1.04367169609746 +118.934295296669 1.07023606547172 +118.958820085973 1.0530559289343 +118.983344875276 1.06240782128723 +119.00786966458 1.07286997004497 +119.032394453883 1.06519163531161 +119.056919243187 1.09166160918163 +119.08144403249 1.1236583685402 +119.105968821794 1.12983104218921 +119.130493611097 1.15408381433941 +119.155018400401 1.13169595377335 +119.179543189704 1.17328325295105 +119.204067979008 1.21724978328082 +119.228592768312 1.20653525555542 +119.253117557615 1.21557944882816 +119.277642346919 1.23020058612833 +119.302167136222 1.2210630588643 +119.326691925526 1.2067879860885 +119.351216714829 1.22105793560308 +119.375741504133 1.17184715277715 +119.400266293436 1.13516700112442 +119.42479108274 1.11518945880369 +119.449315872043 1.11590296934162 +119.473840661347 1.09502868822401 +119.49836545065 1.07168037940041 +119.522890239954 1.03854106133929 +119.547415029258 1.01786179475862 +119.571939818561 1.00110658139366 +119.596464607865 0.986445259661204 +119.620989397168 0.971375034020792 +119.645514186472 0.997136343464421 +119.670038975775 0.971400741027011 +119.694563765079 0.947754308010561 +119.719088554382 0.965754612586031 +119.743613343686 0.963411955030612 +119.768138132989 0.93914589099353 +119.792662922293 0.946334477236481 +119.817187711596 0.935923773986893 +119.8417125009 0.932160138304398 +119.866237290204 0.927727808722018 +119.890762079507 0.935689007689297 +119.915286868811 0.950615862869121 +119.939811658114 0.906163704433517 +119.964336447418 0.910255579768704 +119.988861236721 0.916142882528666 +120.013386026025 0.908677044285606 +120.037910815328 0.922816917183132 +120.062435604632 0.892899646446743 +120.086960393935 0.88458368679197 +120.111485183239 0.897407710731292 +120.136009972543 0.887069539088385 +120.160534761846 0.860787914655642 +120.18505955115 0.851504535081153 +120.209584340453 0.862887648712107 +120.234109129757 0.895856399161363 +120.25863391906 0.873626310109582 +120.283158708364 0.871014544374467 +120.307683497667 0.868826942380008 +120.332208286971 0.882423083254365 +120.356733076274 0.884703173968277 +120.381257865578 0.874527895017988 +120.405782654881 0.875300212604094 +120.430307444185 0.866509144349861 +120.454832233489 0.861268439697902 +120.479357022792 0.879616616361545 +120.503881812096 0.881647355357463 +120.528406601399 0.885227142839273 +120.552931390703 0.901077266245416 +120.577456180006 0.912000476765294 +120.60198096931 0.937459442662988 +120.626505758613 0.902781602439056 +120.651030547917 0.905582082557814 +120.67555533722 0.89755941897289 +120.700080126524 0.918157200957946 +120.724604915828 0.938018229133959 +120.749129705131 0.942202248313653 +120.773654494435 0.967417887453603 +120.798179283738 0.973088424507226 +120.822704073042 0.98853818439414 +120.847228862345 0.980023121566045 +120.871753651649 0.993269271492067 +120.896278440952 0.996013509727853 +120.920803230256 0.996041229430315 +120.945328019559 1.00668251768437 +120.969852808863 0.985049700092599 +120.994377598166 0.9719609249863 +121.01890238747 0.999870104987615 +121.043427176774 0.982981785799283 +121.067951966077 0.994339532691373 +121.092476755381 0.966619123627134 +121.117001544684 0.957996066719154 +121.141526333988 0.936577864351608 +121.166051123291 0.955308415367522 +121.190575912595 0.930226188739693 +121.215100701898 0.914385739568093 +121.239625491202 0.930250565856618 +121.264150280505 0.913092250296747 +121.288675069809 0.908939009564891 +121.313199859113 0.913102037259447 +121.337724648416 0.871398994666885 +121.36224943772 0.871138846166597 +121.386774227023 0.902215091438351 +121.411299016327 0.900003306161329 +121.43582380563 0.913746685536407 +121.460348594934 0.875840615422673 +121.484873384237 0.89155079205997 +121.509398173541 0.896294332463425 +121.533922962844 0.915419314568821 +121.558447752148 0.908935849515654 +121.582972541451 0.917712697169617 +121.607497330755 0.914658007797026 +121.632022120059 0.937858099922261 +121.656546909362 0.922101901036315 +121.681071698666 0.915532945813996 +121.705596487969 0.93529960998148 +121.730121277273 0.950455803465566 +121.754646066576 0.933027683285634 +121.77917085588 0.945911981569591 +121.803695645183 0.944584375746224 +121.828220434487 0.965929908973688 +121.85274522379 0.951335644021272 +121.877270013094 0.949115764534326 +121.901794802397 0.968852051429877 +121.926319591701 0.957412375720013 +121.950844381005 0.989492474765619 +121.975369170308 0.976072288533093 +121.999893959612 1.01107528277621 +122.024418748915 1.02763711136559 +122.048943538219 1.03844437794577 +122.073468327522 1.05078981524957 +122.097993116826 1.07990985718121 +122.122517906129 1.08560929291225 +122.147042695433 1.09424750557188 +122.171567484736 1.10026036338842 +122.19609227404 1.09865319968713 +122.220617063344 1.11390085856389 +122.245141852647 1.15276118755339 +122.269666641951 1.15715301276002 +122.294191431254 1.18263416041586 +122.318716220558 1.17487707515497 +122.343241009861 1.20010421408182 +122.367765799165 1.24326858826286 +122.392290588468 1.26131347928623 +122.416815377772 1.29309855132302 +122.441340167075 1.29165112695559 +122.465864956379 1.33087308894754 +122.490389745682 1.37413662351193 +122.514914534986 1.40966355525656 +122.53943932429 1.46812457677789 +122.563964113593 1.4899976469182 +122.588488902897 1.54156268169983 +122.6130136922 1.61651895743885 +122.637538481504 1.57334417439671 +122.662063270807 1.59735849278883 +122.686588060111 1.5857720678033 +122.711112849414 1.5747999881123 +122.735637638718 1.60806040487006 +122.760162428021 1.58756380764136 +122.784687217325 1.53810926734271 +122.809212006629 1.4819736106502 +122.833736795932 1.48467206534837 +122.858261585236 1.4728513632903 +122.882786374539 1.40470200938951 +122.907311163843 1.37992861568767 +122.931835953146 1.36524237131228 +122.95636074245 1.37206793167204 +122.980885531753 1.35047587553429 +123.005410321057 1.34671188828638 +123.02993511036 1.33888771474974 +123.054459899664 1.29405576972319 +123.078984688967 1.28296789713307 +123.103509478271 1.31610839391666 +123.128034267575 1.31260692429076 +123.152559056878 1.33394682691717 +123.177083846182 1.33741529124074 +123.201608635485 1.36940495270179 +123.226133424789 1.34245411573128 +123.250658214092 1.33241125954493 +123.275183003396 1.35527342427575 +123.299707792699 1.30358756113046 +123.324232582003 1.32481419537517 +123.348757371306 1.33459481121543 +123.37328216061 1.27983372248015 +123.397806949914 1.25850910644833 +123.422331739217 1.22749579978116 +123.446856528521 1.21787365871225 +123.471381317824 1.18292348253413 +123.495906107128 1.19111556637792 +123.520430896431 1.1961697901912 +123.544955685735 1.18386258761488 +123.569480475038 1.1930169003919 +123.594005264342 1.20791911468606 +123.618530053645 1.19266346763705 +123.643054842949 1.18872370159314 +123.667579632252 1.21278121367867 +123.692104421556 1.20572138085395 +123.71662921086 1.22327047362143 +123.741154000163 1.20905045731564 +123.765678789467 1.2450969578723 +123.79020357877 1.23746004284714 +123.814728368074 1.24229432739766 +123.839253157377 1.2573163556283 +123.863777946681 1.31382948205146 +123.888302735984 1.32608367260219 +123.912827525288 1.31342318149489 +123.937352314591 1.3103265337048 +123.961877103895 1.31464237855529 +123.986401893198 1.29494867210187 +124.010926682502 1.27275215329764 +124.035451471806 1.26407620193125 +124.059976261109 1.24719504457442 +124.084501050413 1.2195812938687 +124.109025839716 1.2058062331349 +124.13355062902 1.20618961777384 +124.158075418323 1.1859189836194 +124.182600207627 1.17812567665549 +124.20712499693 1.17607599451533 +124.231649786234 1.13630928224388 +124.256174575537 1.137873106694 +124.280699364841 1.14465000218612 +124.305224154145 1.10857734488039 +124.329748943448 1.12219401179336 +124.354273732752 1.13185117886837 +124.378798522055 1.11154082726825 +124.403323311359 1.12132117617126 +124.427848100662 1.13337570554639 +124.452372889966 1.12802836991215 +124.476897679269 1.12707178964425 +124.501422468573 1.13144171402527 +124.525947257876 1.13302360953542 +124.55047204718 1.13380136829383 +124.574996836483 1.10924000070417 +124.599521625787 1.11504711414829 +124.624046415091 1.11623071349956 +124.648571204394 1.09140394262801 +124.673095993698 1.07550744876566 +124.697620783001 1.08215306153359 +124.722145572305 1.05224879778354 +124.746670361608 1.03750708912224 +124.771195150912 1.03016077797952 +124.795719940215 1.02924961188464 +124.820244729519 1.02939261736941 +124.844769518822 1.01138972010101 +124.869294308126 1.0117691230838 +124.89381909743 1.01147504753598 +124.918343886733 1.00909918134255 +124.942868676037 1.0052173027392 +124.96739346534 1.00347734512944 +124.991918254644 1.00414155717407 +125.016443043947 0.990652520605602 +125.040967833251 0.990584935337111 +125.065492622554 0.996456911473258 +125.090017411858 1.00306085313953 +125.114542201161 1.00124399588161 +125.139066990465 0.994391148836046 +125.163591779768 0.996869175328321 +125.188116569072 1.01998975042926 +125.212641358376 1.01135279424465 +125.237166147679 1.00968366270957 +125.261690936983 1.02646113473946 +125.286215726286 1.03630992316233 +125.31074051559 1.03927088600643 +125.335265304893 1.03399003653063 +125.359790094197 1.05155522941212 +125.3843148835 1.07095753872864 +125.408839672804 1.09664967463179 +125.433364462107 1.12545609977674 +125.457889251411 1.13593964126707 +125.482414040715 1.1511987986305 +125.506938830018 1.15944987216397 +125.531463619322 1.17217696799835 +125.555988408625 1.21499204638382 +125.580513197929 1.18782802373697 +125.605037987232 1.17687103464756 +125.629562776536 1.1984485119544 +125.654087565839 1.18670922769662 +125.678612355143 1.19104741929905 +125.703137144446 1.20838676805363 +125.72766193375 1.19504618981059 +125.752186723053 1.18061942296941 +125.776711512357 1.17079008191681 +125.801236301661 1.1468520712301 +125.825761090964 1.11999324409686 +125.850285880268 1.08854021893271 +125.874810669571 1.09140824481251 +125.899335458875 1.09039775907999 +125.923860248178 1.05339930053488 +125.948385037482 1.02476141539715 +125.972909826785 1.02475842015657 +125.997434616089 1.02650083192017 +126.021959405392 1.01638925186466 +126.046484194696 1.0095465897387 +126.071008983999 1.0014088670144 +126.095533773303 0.982702404848601 +126.120058562607 0.975308961840186 +126.14458335191 0.970959154280684 +126.169108141214 1.00044420661602 +126.193632930517 0.981065082144692 +126.218157719821 0.966581535599087 +126.242682509124 0.981989051111792 +126.267207298428 0.981739699225483 +126.291732087731 0.95337963732802 +126.316256877035 0.94361410115318 +126.340781666338 0.958337369272033 +126.365306455642 0.953653722386444 +126.389831244946 0.953354103865936 +126.414356034249 0.963506226487599 +126.438880823553 0.979667814208001 +126.463405612856 0.98044107611439 +126.48793040216 0.968693090021298 +126.512455191463 0.973168845843623 +126.536979980767 0.981300089989401 +126.56150477007 0.978733449748126 +126.586029559374 0.977447908800731 +126.610554348677 0.979190601416925 +126.635079137981 0.993702637372347 +126.659603927284 0.982635418339569 +126.684128716588 0.985548600161169 +126.708653505892 1.00536140220887 +126.733178295195 1.01003928962817 +126.757703084499 1.02285910257539 +126.782227873802 1.05181257556784 +126.806752663106 1.04833694397623 +126.831277452409 1.07338294999928 +126.855802241713 1.08051767964331 +126.880327031016 1.08729595056202 +126.90485182032 1.08764568487812 +126.929376609623 1.09334215571554 +126.953901398927 1.11066433399403 +126.978426188231 1.12099816950775 +127.002950977534 1.12956200080905 +127.027475766838 1.12771308276264 +127.052000556141 1.11094272008822 +127.076525345445 1.11883367206019 +127.101050134748 1.13362700007254 +127.125574924052 1.1157705238511 +127.150099713355 1.11735172449041 +127.174624502659 1.13423882844059 +127.199149291962 1.13118341020199 +127.223674081266 1.15300933792754 +127.248198870569 1.12867636876535 +127.272723659873 1.13056318833264 +127.297248449177 1.15219652811793 +127.32177323848 1.1492926771413 +127.346298027784 1.14108874619511 +127.370822817087 1.17235133280287 +127.395347606391 1.18895720419504 +127.419872395694 1.19873094409317 +127.444397184998 1.20228311872232 +127.468921974301 1.19502120529971 +127.493446763605 1.16865574998139 +127.517971552908 1.16284336475597 +127.542496342212 1.16522392691662 +127.567021131516 1.14688217936408 +127.591545920819 1.13275038971505 +127.616070710123 1.11415917984973 +127.640595499426 1.09565456866395 +127.66512028873 1.08860154677016 +127.689645078033 1.09590549977539 +127.714169867337 1.09399775561506 +127.73869465664 1.05169654350746 +127.763219445944 1.02147764901062 +127.787744235247 1.01984672185184 +127.812269024551 1.02221228082886 +127.836793813854 1.0117845130988 +127.861318603158 1.01083934225012 +127.885843392462 1.00188662483918 +127.910368181765 0.988758170241945 +127.934892971069 0.981580703198967 +127.959417760372 0.986677484774103 +127.983942549676 0.97041745361134 +128.008467338979 0.963460720385796 +128.032992128283 0.975837771066389 +128.057516917586 0.968476651024639 +128.08204170689 0.955799933841486 +128.106566496193 0.948553062482993 +128.131091285497 0.93595566631853 +128.1556160748 0.963899622762891 +128.180140864104 0.961234691567335 +128.204665653408 0.948744023716807 +128.229190442711 0.946134217301425 +128.253715232015 0.940995551960156 +128.278240021318 0.923634504478538 +128.302764810622 0.938166543235508 +128.327289599925 0.960263983545255 +128.351814389229 0.950281943278398 +128.376339178532 0.942824372154014 +128.400863967836 0.944380198741228 +128.425388757139 0.944209208733297 +128.449913546443 0.939962050777646 +128.474438335747 0.942820227995116 +128.49896312505 0.950767474048368 +128.523487914354 0.967745484517927 +128.548012703657 0.950681909619174 +128.572537492961 0.951449604134752 +128.597062282264 0.972525450763781 +128.621587071568 0.992289384284156 +128.646111860871 0.98583564823817 +128.670636650175 0.985990007943657 +128.695161439478 1.00655986498021 +128.719686228782 0.997114334219486 +128.744211018085 1.00895517657043 +128.768735807389 1.01031498236516 +128.793260596693 1.0176815158369 +128.817785385996 1.01145557221301 +128.8423101753 1.03664334593704 +128.866834964603 1.03123768065143 +128.891359753907 1.02782673210634 +128.91588454321 1.03168855865953 +128.940409332514 1.03281748091584 +128.964934121817 1.00440861449658 +128.989458911121 1.01167315977452 +129.013983700424 0.993567350841919 +129.038508489728 0.999478463513975 +129.063033279032 0.979735279860092 +129.087558068335 0.979832795619989 +129.112082857639 0.973310123179226 +129.136607646942 0.972431000111523 +129.161132436246 0.958059636517259 +129.185657225549 0.952993007670842 +129.210182014853 0.961456396631051 +129.234706804156 0.969356144075497 +129.25923159346 0.96586107901634 +129.283756382763 0.947372808296666 +129.308281172067 0.943702295434772 +129.33280596137 0.937619441742883 +129.357330750674 0.927049244077037 +129.381855539978 0.936001568117626 +129.406380329281 0.941503124547985 +129.430905118585 0.931423641009771 +129.455429907888 0.924277592402553 +129.479954697192 0.926470812631209 +129.504479486495 0.926353916805521 +129.529004275799 0.90939023099623 +129.553529065102 0.918830281169773 +129.578053854406 0.920878737779395 +129.602578643709 0.912502737008191 +129.627103433013 0.916112990656858 +129.651628222317 0.926309564393727 +129.67615301162 0.926902309778235 +129.700677800924 0.919970639089636 +129.725202590227 0.931459888342778 +129.749727379531 0.929556909221446 +129.774252168834 0.906292024990776 +129.798776958138 0.903994078910949 +129.823301747441 0.930538786723035 +129.847826536745 0.934952409616791 +129.872351326048 0.936344254933566 +129.896876115352 0.931167341946736 +129.921400904655 0.933986932109688 +129.945925693959 0.929484203982264 +129.970450483263 0.914066770440914 +129.994975272566 0.914478841955399 +130.01950006187 0.912834388069926 +130.044024851173 0.933928911558168 +130.068549640477 0.924155096108188 +130.09307442978 0.924276680537375 +130.117599219084 0.93468725178267 +130.142124008387 0.923342495104458 +130.166648797691 0.917798247077539 +130.191173586994 0.943756490853549 +130.215698376298 0.9391551303305 +130.240223165601 0.933802624711127 +130.264747954905 0.930292335821592 +130.289272744209 0.942313852307652 +130.313797533512 0.942035922087145 +130.338322322816 0.936897104611255 +130.362847112119 0.93243811847202 +130.387371901423 0.942722841424465 +130.411896690726 0.941227137762598 +130.43642148003 0.927782446477839 +130.460946269333 0.9395336753506 +130.485471058637 0.941860136583837 +130.50999584794 0.962201794484869 +130.534520637244 0.973450544908534 +130.559045426548 0.961260269152878 +130.583570215851 0.949895554591858 +130.608095005155 0.962284476279607 +130.632619794458 0.960776565765673 +130.657144583762 0.968837645129007 +130.681669373065 0.967286475746356 +130.706194162369 0.975972727790162 +130.730718951672 0.966916891558613 +130.755243740976 0.94895569743883 +130.779768530279 0.972737290758785 +130.804293319583 0.962706580019432 +130.828818108886 0.957279298274352 +130.85334289819 0.955960944996379 +130.877867687494 0.964807102634396 +130.902392476797 0.962335237226145 +130.926917266101 0.955564557928193 +130.951442055404 0.957467065358558 +130.975966844708 0.955991402436167 +131.000491634011 0.955413885594824 +131.025016423315 0.958948143566591 +131.049541212618 0.947758876808308 +131.074066001922 0.963425382915033 +131.098590791225 0.979228294367577 +131.123115580529 0.962441268695763 +131.147640369833 0.940359207090324 +131.172165159136 0.964038953865158 +131.19668994844 0.965550239735323 +131.221214737743 0.964084455460359 +131.245739527047 0.98280890468078 +131.27026431635 0.964570129911392 +131.294789105654 0.955003888147995 +131.319313894957 0.952373700170345 +131.343838684261 0.961651775807175 +131.368363473564 0.975352828864479 +131.392888262868 0.988497678095401 +131.417413052171 0.977369432283835 +131.441937841475 0.977233007939597 +131.466462630779 0.972150524338578 +131.490987420082 0.981807955329604 +131.515512209386 0.986497771487683 +131.540036998689 0.990427028288161 +131.564561787993 0.99980897334513 +131.589086577296 1.00974191430542 +131.6136113666 1.00176854448419 +131.638136155903 1.00455661146971 +131.662660945207 1.0133177686812 +131.68718573451 1.00641594368331 +131.711710523814 1.0155898093423 +131.736235313118 1.00309281557806 +131.760760102421 1.02091169319293 +131.785284891725 1.03595220267692 +131.809809681028 1.05781263429921 +131.834334470332 1.04684751868785 +131.858859259635 1.05512651650918 +131.883384048939 1.06775969344084 +131.907908838242 1.079056333664 +131.932433627546 1.0879711279047 +131.956958416849 1.06983237936684 +131.981483206153 1.07212365190608 +132.006007995456 1.11601670957472 +132.03053278476 1.12178224301076 +132.055057574064 1.12147878479254 +132.079582363367 1.13248848224191 +132.104107152671 1.13901678653128 +132.128631941974 1.16015016175018 +132.153156731278 1.15206139540676 +132.177681520581 1.17897632722525 +132.202206309885 1.2059572072576 +132.226731099188 1.22461922049641 +132.251255888492 1.23951293250252 +132.275780677795 1.26813959282351 +132.300305467099 1.27712734803948 +132.324830256402 1.29779401842844 +132.349355045706 1.32349813383259 +132.37387983501 1.33072128059317 +132.398404624313 1.35676567662816 +132.422929413617 1.3831433420937 +132.44745420292 1.41493364551432 +132.471978992224 1.43310183239095 +132.496503781527 1.46205705563704 +132.521028570831 1.46513874822475 +132.545553360134 1.4926583198335 +132.570078149438 1.50974692203542 +132.594602938741 1.51334538414819 +132.619127728045 1.50990944744836 +132.643652517349 1.51672852884655 +132.668177306652 1.51232139068454 +132.692702095956 1.50907032622682 +132.717226885259 1.4927873745083 +132.741751674563 1.47050796838001 +132.766276463866 1.45777640251753 +132.79080125317 1.44017702067977 +132.815326042473 1.41963479489176 +132.839850831777 1.4026394108887 +132.86437562108 1.38324114539625 +132.888900410384 1.36093791741753 +132.913425199687 1.35336579899789 +132.937949988991 1.34848432146368 +132.962474778295 1.33552272386179 +132.986999567598 1.32636778708109 +133.011524356902 1.32880406501098 +133.036049146205 1.33522944702858 +133.060573935509 1.34083109839643 +133.085098724812 1.34347155432519 +133.109623514116 1.34336763183585 +133.134148303419 1.34986765755652 +133.158673092723 1.35823358236374 +133.183197882026 1.34617557192154 +133.20772267133 1.32903858706152 +133.232247460634 1.31155569162522 +133.256772249937 1.33953824507225 +133.281297039241 1.33019210444523 +133.305821828544 1.32786638780462 +133.330346617848 1.32890757285592 +133.354871407151 1.32000561237424 +133.379396196455 1.29430059180164 +133.403920985758 1.29063538978397 +133.428445775062 1.29620640581006 +133.452970564365 1.2941989037572 +133.477495353669 1.27677799612701 +133.502020142972 1.26502677271671 +133.526544932276 1.24907666100461 +133.55106972158 1.24758838981956 +133.575594510883 1.23034774368776 +133.600119300187 1.22595442304845 +133.62464408949 1.21867274985677 +133.649168878794 1.22518821368091 +133.673693668097 1.20711548209899 +133.698218457401 1.20219594564444 +133.722743246704 1.2084373279932 +133.747268036008 1.19829176755165 +133.771792825311 1.21725592865941 +133.796317614615 1.21384636900465 +133.820842403919 1.21080021196819 +133.845367193222 1.22403094929029 +133.869891982526 1.23311839500881 +133.894416771829 1.24791403337328 +133.918941561133 1.25717039358879 +133.943466350436 1.24828014967266 +133.96799113974 1.2777782062644 +133.992515929043 1.27588712267192 +134.017040718347 1.28790643950693 +134.04156550765 1.28471168378194 +134.066090296954 1.30167057129574 +134.090615086257 1.31949210567434 +134.115139875561 1.31781267084892 +134.139664664865 1.32137181089593 +134.164189454168 1.32082919585394 +134.188714243472 1.32934603499039 +134.213239032775 1.32686525146226 +134.237763822079 1.32112760311529 +134.262288611382 1.34228791826264 +134.286813400686 1.33355374653971 +134.311338189989 1.32746013119628 +134.335862979293 1.31174672142152 +134.360387768596 1.28556495601753 +134.3849125579 1.27324434192394 +134.409437347203 1.27035478601489 +134.433962136507 1.26399366863488 +134.458486925811 1.23856245935534 +134.483011715114 1.24596292618026 +134.507536504418 1.24030022112133 +134.532061293721 1.24002931420615 +134.556586083025 1.24038869416231 +134.581110872328 1.24239975127108 +134.605635661632 1.2356246182602 +134.630160450935 1.21490096082513 +134.654685240239 1.21406992261116 +134.679210029542 1.23586376985334 +134.703734818846 1.25099042356367 +134.72825960815 1.24156628971119 +134.752784397453 1.2262120964891 +134.777309186757 1.24236992830055 +134.80183397606 1.24699770183787 +134.826358765364 1.25110655194541 +134.850883554667 1.24533065560608 +134.875408343971 1.23687800491401 +134.899933133274 1.23602452953929 +134.924457922578 1.2271990892999 +134.948982711881 1.23994939666752 +134.973507501185 1.2306529486203 +134.998032290488 1.22357418438159 +135.022557079792 1.22369931419407 +135.047081869096 1.20883963682139 +135.071606658399 1.20996404036159 +135.096131447703 1.21308132793295 +135.120656237006 1.20455199194182 +135.14518102631 1.20822549173612 +135.169705815613 1.21011534419403 +135.194230604917 1.21706687405727 +135.21875539422 1.20675782697973 +135.243280183524 1.2055103909926 +135.267804972827 1.20728804875332 +135.292329762131 1.20343898540038 +135.316854551435 1.19340271829966 +135.341379340738 1.20588151514968 +135.365904130042 1.21857690912078 +135.390428919345 1.22650973960925 +135.414953708649 1.22593229999584 +135.439478497952 1.23003777136363 +135.464003287256 1.24588828243443 +135.488528076559 1.23837532506147 +135.513052865863 1.2525929537887 +135.537577655166 1.26284629543663 +135.56210244447 1.27345014824262 +135.586627233773 1.28352010569635 +135.611152023077 1.30892082074692 +135.635676812381 1.33212266494129 +135.660201601684 1.32711195119975 +135.684726390988 1.35583197590623 +135.709251180291 1.36222578652871 +135.733775969595 1.38383094029548 +135.758300758898 1.41413963159788 +135.782825548202 1.43132165986958 +135.807350337505 1.45787751855707 +135.831875126809 1.48036819693313 +135.856399916112 1.50046635682284 +135.880924705416 1.5046524733416 +135.90544949472 1.55082645860798 +135.929974284023 1.55600919644436 +135.954499073327 1.5864485079454 +135.97902386263 1.58453975233188 +136.003548651934 1.57500665177457 +136.028073441237 1.57689199443835 +136.052598230541 1.59143497584255 +136.077123019844 1.58434623207523 +136.101647809148 1.57158168073955 +136.126172598451 1.56114132014224 +136.150697387755 1.55224963167645 +136.175222177058 1.52888150749422 +136.199746966362 1.49232689384815 +136.224271755666 1.47493230119393 +136.248796544969 1.46312021521693 +136.273321334273 1.43626751033094 +136.297846123576 1.42645998266385 +136.32237091288 1.41069340173164 +136.346895702183 1.37841978535723 +136.371420491487 1.36127324534739 +136.39594528079 1.34057803473034 +136.420470070094 1.32935326104528 +136.444994859397 1.31268564824779 +136.469519648701 1.30237617920012 +136.494044438004 1.30222429169009 +136.518569227308 1.29219896679477 +136.543094016612 1.27067532653354 +136.567618805915 1.2569792229505 +136.592143595219 1.25509037239193 +136.616668384522 1.25434747590818 +136.641193173826 1.24513613047134 +136.665717963129 1.24501880947919 +136.690242752433 1.24216088767572 +136.714767541736 1.23653724906616 +136.73929233104 1.23833144303322 +136.763817120343 1.23649769739461 +136.788341909647 1.22355356023722 +136.812866698951 1.22007504383434 +136.837391488254 1.23375726101296 +136.861916277558 1.22517390262691 +136.886441066861 1.22203302968056 +136.910965856165 1.22273889716348 +136.935490645468 1.21379194567611 +136.960015434772 1.21087171830978 +136.984540224075 1.2255356517842 +137.009065013379 1.22860259983186 +137.033589802682 1.22039898831945 +137.058114591986 1.22448483712866 +137.082639381289 1.22600326443355 +137.107164170593 1.23952187528471 +137.131688959897 1.23272833296309 +137.1562137492 1.24618816599974 +137.180738538504 1.25310988202824 +137.205263327807 1.23411461993932 +137.229788117111 1.24316495243972 +137.254312906414 1.27585946141642 +137.278837695718 1.2708036529974 +137.303362485021 1.29664031413907 +137.327887274325 1.31445681323841 +137.352412063628 1.32579098819754 +137.376936852932 1.34037797931702 +137.401461642236 1.32721976381837 +137.425986431539 1.35046931463784 +137.450511220843 1.38981892416131 +137.475036010146 1.40440982068863 +137.49956079945 1.4224004005008 +137.524085588753 1.43254477769576 +137.548610378057 1.44033423353345 +137.57313516736 1.43285530453712 +137.597659956664 1.46878054481794 +137.622184745967 1.49015397531619 +137.646709535271 1.51053618942575 +137.671234324574 1.52663752860606 +137.695759113878 1.543884206187 +137.720283903182 1.55710749014305 +137.744808692485 1.57285331421275 +137.769333481789 1.59506430556806 +137.793858271092 1.59947949196182 +137.818383060396 1.62998081668096 +137.842907849699 1.63792151954111 +137.867432639003 1.63917906902918 +137.891957428306 1.65489745566272 +137.91648221761 1.67000475723906 +137.941007006913 1.68716724034259 +137.965531796217 1.68719045079455 +137.990056585521 1.69795005599889 +138.014581374824 1.72111752742218 +138.039106164128 1.7276316728872 +138.063630953431 1.73595944493643 +138.088155742735 1.74583698781867 +138.112680532038 1.74064180058802 +138.137205321342 1.74325089297832 +138.161730110645 1.74025058686473 +138.186254899949 1.73562758392578 +138.210779689252 1.73656319489379 +138.235304478556 1.7197631989784 +138.259829267859 1.711176428274 +138.284354057163 1.69195539708933 +138.308878846467 1.69350081481884 +138.33340363577 1.67156345533343 +138.357928425074 1.63803532816322 +138.382453214377 1.6198317556846 +138.406978003681 1.59672980195363 +138.431502792984 1.58114313695668 +138.456027582288 1.55860102552905 +138.480552371591 1.54187166608991 +138.505077160895 1.53592747786868 +138.529601950198 1.51232761928683 +138.554126739502 1.50409723297401 +138.578651528805 1.49372358209506 +138.603176318109 1.48687759039912 +138.627701107413 1.49586552146092 +138.652225896716 1.48697196336832 +138.67675068602 1.47004231710003 +138.701275475323 1.45062438117525 +138.725800264627 1.46204517502664 +138.75032505393 1.46633098429982 +138.774849843234 1.4647773456425 +138.799374632537 1.46809458821918 +138.823899421841 1.47254338344236 +138.848424211144 1.4660596460222 +138.872949000448 1.45869688400305 +138.897473789752 1.46613388361804 +138.921998579055 1.45730113799503 +138.946523368359 1.43975399014968 +138.971048157662 1.43956480637825 +138.995572946966 1.43882767032046 +139.020097736269 1.43483212829156 +139.044622525573 1.41565594540353 +139.069147314876 1.40952656125445 +139.09367210418 1.40820808041771 +139.118196893483 1.39877541928258 +139.142721682787 1.386486695196 +139.16724647209 1.36784097772594 +139.191771261394 1.36172419128136 +139.216296050698 1.35771929490437 +139.240820840001 1.34767523909343 +139.265345629305 1.337062263683 +139.289870418608 1.33628851650408 +139.314395207912 1.3332491983567 +139.338919997215 1.32150668185175 +139.363444786519 1.3285236093738 +139.387969575822 1.31746347776494 +139.412494365126 1.30317330288545 +139.437019154429 1.30252268968739 +139.461543943733 1.31243750346179 +139.486068733037 1.30229732125446 +139.51059352234 1.3225740372174 +139.535118311644 1.31954152701717 +139.559643100947 1.30202390002045 +139.584167890251 1.3058846800102 +139.608692679554 1.31825837274907 +139.633217468858 1.32506371065141 +139.657742258161 1.33585682310848 +139.682267047465 1.32036629531122 +139.706791836768 1.33294485751727 +139.731316626072 1.34835650131552 +139.755841415375 1.34488543089596 +139.780366204679 1.35058009115227 +139.804890993983 1.37987409282868 +139.829415783286 1.39247202980149 +139.85394057259 1.40107460530875 +139.878465361893 1.40436854569092 +139.902990151197 1.4152229056999 +139.9275149405 1.4218101588038 +139.952039729804 1.4247243749451 +139.976564519107 1.43077213584533 +140.001089308411 1.39585523985731 +140.025614097714 1.4053089333558 +140.050138887018 1.40941275317868 +140.074663676322 1.43070108873493 diff --git a/docs/source/examples/example-data/CeO2_635um_zscan_200umSlit_chanClose_exported.xy b/docs/source/examples/example-data/CeO2_635um_zscan_200umSlit_chanClose_exported.xy new file mode 100644 index 0000000..ff53fff --- /dev/null +++ b/docs/source/examples/example-data/CeO2_635um_zscan_200umSlit_chanClose_exported.xy @@ -0,0 +1,152 @@ +'Id: "" Comment: "" Operator: "Lab Manager" Anode: "Mo" Scantype: "Z" TimePerStep: "0.1" +-0.5000 438699.993 +-0.4900 437939.993 +-0.4800 436679.993 +-0.4700 434109.994 +-0.4600 439659.993 +-0.4500 436119.994 +-0.4400 435829.994 +-0.4300 438749.993 +-0.4200 432339.994 +-0.4100 431319.994 +-0.4000 435779.994 +-0.3900 437599.993 +-0.3800 434739.994 +-0.3700 433929.994 +-0.3600 436689.993 +-0.3500 433569.994 +-0.3400 435229.994 +-0.3300 437549.993 +-0.3200 434419.994 +-0.3100 435259.994 +-0.3000 437439.993 +-0.2900 437869.993 +-0.2800 434529.994 +-0.2700 436509.993 +-0.2600 434709.994 +-0.2500 432969.994 +-0.2400 434899.994 +-0.2300 432389.994 +-0.2200 436019.994 +-0.2100 437949.993 +-0.2000 437949.993 +-0.1900 435849.994 +-0.1800 437349.993 +-0.1700 435199.994 +-0.1600 439539.993 +-0.1500 434519.994 +-0.1400 436629.993 +-0.1300 435779.994 +-0.1200 437839.993 +-0.1100 433019.994 +-0.1000 440589.993 +-0.0900 440729.993 +-0.0800 432909.994 +-0.0700 435749.994 +-0.0600 439069.993 +-0.0500 437979.993 +-0.0400 437069.993 +-0.0300 436549.993 +-0.0200 430119.994 +-0.0100 426019.994 +0.0000 418459.994 +0.0100 403369.994 +0.0200 383859.994 +0.0300 365809.995 +0.0400 344199.995 +0.0500 320469.995 +0.0600 294339.996 +0.0700 266309.996 +0.0800 239429.996 +0.0900 209889.997 +0.1000 176649.997 +0.1100 144879.998 +0.1200 115089.998 +0.1300 92299.999 +0.1400 72569.999 +0.1500 58649.999 +0.1600 46629.999 +0.1700 38329.999 +0.1800 33500.000 +0.1900 29950.000 +0.2000 26210.000 +0.2100 24490.000 +0.2200 22100.000 +0.2300 21030.000 +0.2400 20140.000 +0.2500 18260.000 +0.2600 17220.000 +0.2700 17280.000 +0.2800 16080.000 +0.2900 16040.000 +0.3000 15250.000 +0.3100 15030.000 +0.3200 14610.000 +0.3300 13840.000 +0.3400 14300.000 +0.3500 14400.000 +0.3600 14140.000 +0.3700 13810.000 +0.3800 13060.000 +0.3900 13520.000 +0.4000 13930.000 +0.4100 13230.000 +0.4200 14140.000 +0.4300 14110.000 +0.4400 14730.000 +0.4500 13240.000 +0.4600 14850.000 +0.4700 14670.000 +0.4800 16110.000 +0.4900 16920.000 +0.5000 18110.000 +0.5100 18900.000 +0.5200 19600.000 +0.5300 21530.000 +0.5400 22640.000 +0.5500 25950.000 +0.5600 27170.000 +0.5700 31850.000 +0.5800 35309.999 +0.5900 40459.999 +0.6000 48749.999 +0.6100 60139.999 +0.6200 77359.999 +0.6300 98939.999 +0.6400 119429.998 +0.6500 144089.998 +0.6600 173249.997 +0.6700 196839.997 +0.6800 222189.997 +0.6900 251099.996 +0.7000 276849.996 +0.7100 306689.995 +0.7200 324769.995 +0.7300 349759.995 +0.7400 370219.994 +0.7500 389929.994 +0.7600 403689.994 +0.7700 415189.994 +0.7800 419159.994 +0.7900 426049.994 +0.8000 430569.994 +0.8100 433369.994 +0.8200 433519.994 +0.8300 431809.994 +0.8400 432409.994 +0.8500 431049.994 +0.8600 432439.994 +0.8700 429879.994 +0.8800 432939.994 +0.8900 430969.994 +0.9000 429989.994 +0.9100 432439.994 +0.9200 433599.994 +0.9300 431779.994 +0.9400 436329.993 +0.9500 432509.994 +0.9600 429609.994 +0.9700 432349.994 +0.9800 429109.994 +0.9900 430159.994 +1.0000 432219.994 From d585c9b8076b22af11d05f67975777b7554b80ba Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 27 Jan 2026 11:49:44 -0500 Subject: [PATCH 07/77] explicit CVE in docstring --- src/diffpy/labpdfproc/functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffpy/labpdfproc/functions.py b/src/diffpy/labpdfproc/functions.py index 46c9ade..5972349 100644 --- a/src/diffpy/labpdfproc/functions.py +++ b/src/diffpy/labpdfproc/functions.py @@ -245,7 +245,7 @@ def _cve_method(method): def compute_cve( input_pattern, mud, method="polynomial_interpolation", xtype="tth" ): - f"""Compute and interpolate the cve + f"""Compute and interpolate the cylindrical volume effect (cve) for the given input diffraction data and mu*D using the selected method. From 3c2234941d689b5a40693802284a164ae915e13c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 27 Jan 2026 11:50:25 -0500 Subject: [PATCH 08/77] labpdfprocapp.py --- src/diffpy/labpdfproc/labpdfprocapp.py | 523 ++++++++++++------------- 1 file changed, 258 insertions(+), 265 deletions(-) diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index d73caab..7e824f2 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -1,314 +1,307 @@ +import argparse import sys -from argparse import ArgumentParser from gooey import Gooey, GooeyParser from diffpy.labpdfproc.functions import CVE_METHODS, apply_corr, compute_cve from diffpy.labpdfproc.tools import ( - known_sources, + WAVELENGTHS, load_metadata, + load_wavelength_from_config_file, preprocessing_args, + set_wavelength, ) from diffpy.utils.diffraction_objects import XQUANTITIES, DiffractionObject from diffpy.utils.parsers.loaddata import loadData -theoretical_mud_hmsg_suffix = ( - "in that exact order, " - "separated by commas (e.g., ZrO2,17.45,0.5). " - "If you add whitespaces, " - "enclose it in quotes (e.g., 'ZrO2, 17.45, 0.5'). " -) - - -def _define_arguments(): - args = [ - { - "name": ["input"], - "help": ( - "The filename(s) or folder(s) of the datafile(s) to load. " - "Required.\n" - "Supply a space-separated list of files or directories. " - "Avoid spaces in filenames when possible; " - "if present, enclose the name in quotes. " - "Long lists can be supplied, one per line, " - "in a file with name file_list.txt. " - "If one or more directory is provided, all valid " - "data-files in that directory will be processed. " - "Examples of valid inputs are 'file.xy', 'data/file.xy', " - "'file.xy data/file.xy', " - "'.' (load everything in the current directory), " - "'data' (load everything in the folder ./data), " - "'data/file_list.txt' (load the list of files " - "contained in the text-file called file_list.txt " - "that can be found in the folder ./data), " - "'./*.chi', 'data/*.chi' " - "(load all files with extension .chi in the folder ./data)." - ), - "nargs": "+", - "widget": "MultiFileChooser", - }, - { - "name": ["-a", "--anode-type"], - "help": ( - f"The type of the x-ray source. " - f"Allowed values are {*known_sources, }. " - f"Either specify a known x-ray source or specify wavelength." - ), - "default": None, - }, - { - "name": ["-w", "--wavelength"], - "help": ( - "X-ray source wavelength in angstroms. " - "Not needed if the anode-type is specified." - ), - "type": float, - }, - { - "name": ["-o", "--output-directory"], - "help": ( - "The name of the output directory. " - "If not specified then corrected files will be " - "written to the current directory. " - "If the specified directory doesn't exist it will be created." - ), - "default": None, - "widget": "DirChooser", - }, - { - "name": ["-x", "--xtype"], - "help": ( - f"The quantity on the independent variable axis. " - f"Allowed values: {*XQUANTITIES, }. " - f"If not specified then two-theta " - f"is assumed for the independent variable." - ), - "default": "tth", - }, - { - "name": ["-c", "--output-correction"], - "help": ( - "The absorption correction will be output to a file " - "if this flag is set. " - "Default is that it is not output." - ), - "action": "store_true", - }, - { - "name": ["-f", "--force-overwrite"], - "help": "Outputs will not overwrite existing file " - "unless --force is specified.", - "action": "store_true", - }, - { - "name": ["-m", "--method"], - "help": ( - f"The method for computing absorption correction. " - f"Allowed methods: {*CVE_METHODS, }. " - f"Default method is polynomial interpolation " - f"if not specified." - ), - "default": "polynomial_interpolation", - }, - { - "name": ["-u", "--user-metadata"], - "help": ( - "Specify key-value pairs to be loaded into metadata " - "using the format key=value. " - "Separate pairs with whitespace, " - "and ensure no whitespaces before or after the = sign. " - "Avoid using = in keys. If multiple = signs are present, " - "only the first separates the key and value. " - "If a key or value contains whitespace, enclose it in quotes. " - "For example, facility='NSLS II', " - "'facility=NSLS II', beamline=28ID-2, " - "'beamline'='28ID-2', 'favorite color'=blue, " - "are all valid key=value items." - ), - "nargs": "+", - "metavar": "KEY=VALUE", - }, - { - "name": ["-n", "--username"], - "help": ( - "Username will be loaded from config files. " - "Specify here only if you want to " - "override that behavior at runtime." - ), - "default": None, - }, - { - "name": ["-e", "--email"], - "help": ( - "Email will be loaded from config files. " - "Specify here only if you want to " - "override that behavior at runtime." - ), - "default": None, - }, - { - "name": ["--orcid"], - "help": ( - "ORCID will be loaded from config files. " - "Specify here only if you want to " - "override that behavior at runtime." - ), - "default": None, - }, - ] - return args - -def _add_mud_selection_group(p, use_gui=False): - """Current Options: - 1. Manually enter muD (`--mud`). - 2. Estimate from a z-scan file (`-z` or `--z-scan-file`). - 3. Estimate theoretically based on sample mass density - (`-d` or `--theoretical-from-density`). - 4. Estimate theoretically based on packing fraction - (`-p` or `--theoretical-from-packing`). - """ - g = p.add_argument_group("Options for setting mu*D value (Required)") - g = g.add_mutually_exclusive_group(required=True) - g.add_argument( - "--mud", - type=float, - help="Enter the mu*D value manually.", - **({"widget": "DecimalField"} if use_gui else {}), +def _add_common_args(parser, use_gui=False): + parser.add_argument( + "-w", + "--wavelength", + help=( + "X-ray wavelength in angstroms (numeric) or X-ray source name " + f"(allowed: {', '.join(sorted(WAVELENGTHS.keys()))}). " + "Will be loaded from config files if not specified." + ), + default=None, ) - g.add_argument( - "-z", - "--z-scan-file", + parser.add_argument( + "-x", + "--xtype", help=( - "Estimate mu*D experimentally from a z-scan file. " - "Specify the path to the file " - "used to compute the mu*D value." + "X-axis type (default: tth). Allowed values: " + f"{', '.join(XQUANTITIES)}" ), - **({"widget": "FileChooser"} if use_gui else {}), + default="tth", ) - g.add_argument( - "-d", - "--theoretical-from-density", + parser.add_argument( + "-m", + "--method", help=( - "Estimate mu*D theoretically using sample mass density. " - "Specify the chemical formula, incident x-ray energy (in keV), " - "and sample mass density (in g/cm^3), " - + theoretical_mud_hmsg_suffix + "Method for cylindrical volume element (CVE) calculation " + "(default: polynomial_interpolation). Allowed methods: " + f"{', '.join(CVE_METHODS)}" ), + default="polynomial_interpolation", + choices=CVE_METHODS, ) - g.add_argument( - "-p", - "--theoretical-from-packing", + parser.add_argument( + "-o", + "--output-directory", help=( - "Estimate mu*D theoretically using packing fraction. " - "Specify the chemical formula, incident x-ray energy (in keV), " - "and packing fraction (0 to 1), " + theoretical_mud_hmsg_suffix + "Directory to save corrected files (created if needed). " + "Defaults to current directory." ), + default=None, + **({"widget": "DirChooser"} if use_gui else {}), + ) + parser.add_argument( + "-f", "--force", help="Overwrite existing files", action="store_true" + ) + parser.add_argument( + "-c", + "--output-correction", + help="Also output the absorption correction to a separate file", + action="store_true", ) - return p + parser.add_argument( + "-u", + "--user-metadata", + help=( + "Specify key-value pairs to be loaded into metadata " + "using the format key=value. " + "Separate pairs with whitespace, " + "and ensure no whitespaces before or after the = sign. " + "Avoid using = in keys. If multiple = signs are present, " + "only the first separates the key and value. " + "If a key or value contains whitespace, enclose it in quotes. " + "For example, facility='NSLS II', " + "'facility=NSLS II', beamline=28ID-2, " + "'beamline'='28ID-2', 'favorite color'=blue, " + "are all valid key=value items." + ), + nargs="+", + metavar="KEY=VALUE", + ) + _add_credit_args(parser, use_gui) + return parser -def _register_applymud_subparser(subp, use_gui=False): - applymudp = subp.add_parser( - "applymud", help="Apply absorption correction." +def _add_credit_args(parser, use_gui=False): + parser.add_argument( + "--username", + help=( + "Your name (optional, for dataset credit). " + "Will be loaded from config files if not specified." + ), + default=None, + **({"widget": "TextField"} if use_gui else {}), + ) + parser.add_argument( + "--email", + help=( + "Your email (optional, for dataset credit). " + "Will be loaded from config files if not specified." + ), + default=None, + **({"widget": "TextField"} if use_gui else {}), + ) + parser.add_argument( + "--orcid", + help=( + "Your ORCID ID (optional, for dataset credit). " + "Will be loaded from config files if not specified." + ), + default=None, + **({"widget": "TextField"} if use_gui else {}), ) - _add_mud_selection_group(applymudp, use_gui=use_gui) - for arg in _define_arguments(): - names = arg["name"] - options = {k: v for k, v in arg.items() if k != "name"} - if not use_gui and "widget" in options: - options.pop("widget") - applymudp.add_argument(*names, **options) -def create_parser(use_gui=False): - p = GooeyParser() if use_gui else ArgumentParser() - subp = p.add_subparsers(title="subcommand", dest="subcommand") - _register_applymud_subparser(subp, use_gui) - return p +def _save_corrected(corrected, input_path, args): + outfile = args.output_directory / (input_path.stem + "_corrected.chi") + if outfile.exists() and not args.force: + print(f"WARNING: {outfile} exists. Use --force to overwrite.") + return + corrected.metadata = corrected.metadata or {} + corrected.dump(str(outfile), xtype=args.xtype) + print(f"Saved corrected data to {outfile}") -@Gooey( - required_cols=1, - optional_cols=1, - show_sidebar=True, - program_name="labpdfproc GUI", -) -def _get_args_gui(): - p = create_parser(use_gui=True) - args = p.parse_args() - return args +def _save_correction(correction, input_path, args): + corrfile = args.output_directory / (input_path.stem + "_cve.chi") + if corrfile.exists() and not args.force: + print(f"WARNING: {corrfile} exists. Use --force to overwrite.") + return + correction.metadata = correction.metadata or {} + correction.dump(str(corrfile), xtype=args.xtype) + print(f"Saved correction data to {corrfile}") -def _get_args_cli(override_cli_inputs=None): - p = create_parser(use_gui=False) - args = p.parse_args(override_cli_inputs) - return args +def _load_pattern(path, xtype, wavelength, metadata): + x, y = loadData(path, unpack=True) + return DiffractionObject( + xarray=x, + yarray=y, + xtype=xtype, + wavelength=wavelength, + scat_quantity="x-ray", + name=path.stem, + metadata=metadata, + ) -def get_args(override_cli_inputs=None, use_gui=False): - return _get_args_gui() if use_gui else _get_args_cli(override_cli_inputs) +def apply_absorption_correction(args): + """Process all input files with absorption correction.""" + for path in args.input_paths: + metadata = load_metadata(args, path) + pattern = _load_pattern(path, args.xtype, args.wavelength, metadata) + correction = compute_cve( + pattern, args.mud, method=args.method, xtype=args.xtype + ) + correction.metadata = metadata.copy() + corrected_data = apply_corr(pattern, correction) + corrected_data.name = ( + f"Absorption corrected input_data: {pattern.name}" + ) + corrected_data.metadata = metadata.copy() + _save_corrected(corrected_data, path, args) + if args.output_correction: + _save_correction(correction, path, args) -def applymud(args): - args = preprocessing_args(args) - for filepath in args.input_paths: - outfilestem = filepath.stem + "_corrected" - corrfilestem = filepath.stem + "_cve" - outfile = args.output_directory / (outfilestem + ".chi") - corrfile = args.output_directory / (corrfilestem + ".chi") +def create_parser(use_gui=False): + Parser = GooeyParser if use_gui else argparse.ArgumentParser + parser = Parser( + prog="labpdfproc", + description=( + "Apply absorption corrections to laboratory X-ray diffraction " + "data prior to PDF analysis. Supports manual mu*d, " + "z-scan, or sample-based corrections." + ), + formatter_class=argparse.RawTextHelpFormatter, + ) + subp = parser.add_subparsers( + dest="command", required=True, title="Correction method" + ) - if outfile.exists() and not args.force_overwrite: - sys.exit( - f"Output file {str(outfile)} already exists. " - f"Please rerun specifying -f if you want to overwrite it." - ) - if ( - corrfile.exists() - and args.output_correction - and not args.force_overwrite - ): - sys.exit( - f"Corrections file {str(corrfile)} " - f"was requested and already exists. " - f"Please rerun specifying -f if you want to overwrite it." - ) + # MUD parser + mud_parser = subp.add_parser( + "mud", help="Correct diffraction data using known mu*d value" + ) + mud_parser.add_argument( + "input", + nargs="+", + help=( + "Input X-ray diffraction data file(s) or directory. " + "Can specify multiple files, directories, or use wildcards." + ), + **({"widget": "MultiFileChooser"} if use_gui else {}), + ) + mud_parser.add_argument( + "mud", type=float, help="mu*d value", metavar="mud" + ) + _add_common_args(mud_parser, use_gui) - xarray, yarray = loadData(filepath, unpack=True) - input_pattern = DiffractionObject( - xarray=xarray, - yarray=yarray, - xtype=args.xtype, - wavelength=args.wavelength, - scat_quantity="x-ray", - name=filepath.stem, - metadata=load_metadata(args, filepath), - ) + # ZSCAN parser + zscan_parser = subp.add_parser( + "zscan", help="Correct diffraction data using a z-scan measurement" + ) + zscan_parser.add_argument( + "input", + nargs="+", + help=( + "Input X-ray diffraction data file(s) or directory. " + "Can specify multiple files, directories, or use wildcards." + ), + **({"widget": "MultiFileChooser"} if use_gui else {}), + ) + zscan_parser.add_argument( + "z_scan_file", + help=( + "Z-scan measurement file. " + "See diffpy.labpdfproc documentation for more information." + ), + **({"widget": "FileChooser"} if use_gui else {}), + ) + _add_common_args(zscan_parser, use_gui) - absorption_correction = compute_cve( - input_pattern, args.mud, args.method, args.xtype - ) - corrected_data = apply_corr(input_pattern, absorption_correction) - corrected_data.name = ( - f"Absorption corrected input_data: " f"{input_pattern.name}" - ) - corrected_data.dump(f"{outfile}", xtype=args.xtype) + # SAMPLE parser + sample_parser = subp.add_parser( + "sample", + help="Correct diffraction data using sample composition/density", + ) + sample_parser.add_argument( + "input", + nargs="+", + help=( + "Input X-ray diffraction data file(s) or directory. " + "Can specify multiple files, directories, or use wildcards." + ), + **({"widget": "MultiFileChooser"} if use_gui else {}), + ) + sample_parser.add_argument( + "sample_composition", + help="Chemical formula, e.g. Fe2O3", + ) + sample_parser.add_argument( + "sample_mass_density", + type=float, + help=( + "Sample mass density in capillary (g/cm^3). " + "If unsure, a good estimate is ~1/3 of the " + "theoretical packing fraction density." + ), + ) + sample_parser.add_argument( + "diameter", + type=float, + help="Outer diameter of the capillary in mm", + ) + _add_common_args(sample_parser, use_gui) - if args.output_correction: - absorption_correction.dump(f"{corrfile}", xtype=args.xtype) + return parser + + +def _handle_old_api_conversion(args): + """Convert `sample` command arguments to previous format so functions can + accept them without modification.""" + if args.command == "sample": + # Convert sample args to theoretical_from_density format + args = load_wavelength_from_config_file(args) + args = set_wavelength(args) + energy_kev = 12.398 / args.wavelength if args.wavelength else None + if energy_kev: + args.theoretical_from_density = ( + f"{args.sample_composition}," + f"{energy_kev}," + f"{args.sample_mass_density}" + ) + return args + + +@Gooey( + program_name="labpdfproc", + required_cols=1, + optional_cols=1, + show_sidebar=True, +) +def get_args_gui(): + parser = create_parser(use_gui=True) + return parser.parse_args() -def run_subcommand(args): - if args.subcommand == "applymud": - return applymud(args) - else: - raise ValueError(f"Unknown subcommand: {args.subcommand}") +def get_args_cli(override=None): + parser = create_parser(use_gui=False) + return parser.parse_args(override) def main(): use_gui = len(sys.argv) == 1 or "--gui" in sys.argv - args = get_args(use_gui=use_gui) - return run_subcommand(args) + args = get_args_gui() if use_gui else get_args_cli() + args = _handle_old_api_conversion(args) + args = preprocessing_args(args) + apply_absorption_correction(args) if __name__ == "__main__": From 53c97c6ffc76b2ce2f529446d15732123bdc0bba Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 27 Jan 2026 11:50:56 -0500 Subject: [PATCH 09/77] tools.py --- src/diffpy/labpdfproc/tools.py | 165 +++++++++++++++++++-------------- 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/src/diffpy/labpdfproc/tools.py b/src/diffpy/labpdfproc/tools.py index ee5c6e8..0184f9f 100644 --- a/src/diffpy/labpdfproc/tools.py +++ b/src/diffpy/labpdfproc/tools.py @@ -39,13 +39,10 @@ # and will be written into separate arguments for clarity. METADATA_KEYS_TO_EXCLUDE = [ "output_correction", - "force_overwrite", "input", "input_paths", - "wavelength", - "theoretical_from_density", - "theoretical_from_packing", - "subcommand", + "force", + "energy", ] @@ -166,8 +163,52 @@ def set_input_lists(args): return args +def normalize_wavelength(args): + """Normalize args.wavelength to a float. + + If args.wavelength is: + - None: return args unchanged + - float-like: convert to float + - string: look up corresponding value in WAVELENGTHS (case-insensitive) + + Parameters + ---------- + args : argparse.Namespace + The arguments from the parser. + + Returns + ------- + args : argparse.Namespace + The updated arguments with args.wavelength. + + Raises + ------ + ValueError + If a string wavelength is not a known source. + """ + if args.wavelength is None: + return args + try: + args.wavelength = float(args.wavelength) + return args + except (TypeError, ValueError): + pass + key = str(args.wavelength).strip() + matched = next( + (k for k in WAVELENGTHS if k.lower() == key.lower()), + None, + ) + if matched is None: + raise ValueError( + f"Anode type '{args.wavelength}' not recognized. " + f"Please rerun specifying an anode type from {*known_sources, }." + ) + args.wavelength = WAVELENGTHS[matched] + return args + + def load_wavelength_from_config_file(args): - """Load wavelength and anode type from config files. + """Load wavelength from config files. It prioritizes values in the following order: 1. cli inputs, 2. local config file, 3. global config file. @@ -184,12 +225,8 @@ def load_wavelength_from_config_file(args): """ global_config = _load_config(Path().home() / "diffpyconfig.json") local_config = _load_config(Path().cwd() / "diffpyconfig.json") - local_has_data = local_config and ( - "wavelength" in local_config or "anode_type" in local_config - ) - global_has_data = global_config and ( - "wavelength" in global_config or "anode_type" in global_config - ) + local_has_data = local_config and "wavelength" in local_config + global_has_data = global_config and "wavelength" in global_config if not local_has_data and not global_has_data: print( "No configuration file was found containing information " @@ -202,76 +239,54 @@ def load_wavelength_from_config_file(args): "For more information, please refer to www.diffpy.org/" "diffpy.labpdfproc/examples/toolsexample.html" ) - - if args.wavelength or args.anode_type: - return args + if args.wavelength is not None: + return normalize_wavelength(args) config = local_config if local_has_data else global_config if config: - args.wavelength = args.wavelength or config.get("wavelength") - args.anode_type = args.anode_type or config.get("anode_type") + args.wavelength = config.get("wavelength") + return normalize_wavelength(args) return args def set_wavelength(args): - """Set the wavelength based on the given anode_type or wavelength. + """Set the wavelength based on args.wavelength. - First checks from args. If neither is provided, - it attempts to load from local and then global config file. + args.wavelength may be: + - None + - a number (explicit wavelength in Å) + - a string (X-ray source name) + + If a string is provided, it must match a key in WAVELENGTHS. Parameters ---------- args : argparse.Namespace - The arguments from the parser. Raises ------ ValueError - Raised if: - (1) neither wavelength or anode type is provided - and xtype is not the two-theta grid, - (2) both are provided, - (3) anode_type is not one of the known sources, - (4) wavelength is non-positive. + If wavelength is required but missing, + if a string wavelength is not a known source, + or if a numeric wavelength is non-positive. Returns ------- args : argparse.Namespace - The updated arguments with the wavelength. + Updated arguments with args.wavelength as a float. """ - args = load_wavelength_from_config_file(args) - if args.wavelength is None and args.anode_type is None: + args = normalize_wavelength(args) + if args.wavelength is None: if args.xtype not in ANGLEQUANTITIES: raise ValueError( f"Please provide a wavelength or anode type " f"because the independent variable axis is not on two-theta. " f"Allowed anode types are {*known_sources, }." ) - elif args.wavelength is not None and args.anode_type is not None: - raise ValueError( - f"Please provide either a wavelength or an anode type, not both. " - f"Allowed anode types are {*known_sources, }." - ) - elif args.anode_type is not None: - matched_anode_type = next( - ( - key - for key in WAVELENGTHS - if key.lower() == args.anode_type.lower() - ), - None, - ) - if matched_anode_type is None: - raise ValueError( - f"Anode type '{args.anode_type}' not recognized. " - f"Please rerun specifying an anode_type " - f"from {*known_sources, }." - ) - args.anode_type = matched_anode_type - args.wavelength = WAVELENGTHS[args.anode_type] - elif args.wavelength is not None and args.wavelength <= 0: + return args + if args.wavelength <= 0: raise ValueError( f"Wavelength = {args.wavelength} is not valid. " - "Please rerun specifying a known anode_type " + "Please rerun specifying a known anode type " "or a positive wavelength." ) return args @@ -336,16 +351,18 @@ def _parse_theoretical_input(input_str): def _set_theoretical_mud_from_density(args): """Theoretical estimation of mu*D from sample composition, energy, and sample mass density.""" - sample_composition, energy, sample_mass_density = _parse_theoretical_input( - args.theoretical_from_density - ) - args.sample_composition = sample_composition + args = normalize_wavelength(args) + if args.wavelength is None: + args = load_wavelength_from_config_file(args) + energy = 12.398 / args.wavelength args.energy = energy - args.sample_mass_density = sample_mass_density - args.mud = compute_mu_using_xraydb( - args.sample_composition, - args.energy, - sample_mass_density=args.sample_mass_density, + args.mud = ( + compute_mu_using_xraydb( + args.sample_composition, + args.energy, + sample_mass_density=args.sample_mass_density, + ) + * args.diameter ) return args @@ -359,10 +376,13 @@ def _set_theoretical_mud_from_packing(args): args.sample_composition = sample_composition args.energy = energy args.packing_fraction = packing_fraction - args.mud = compute_mu_using_xraydb( - args.sample_composition, - args.energy, - packing_fraction=args.packing_fraction, + args.mud = ( + compute_mu_using_xraydb( + args.sample_composition, + args.energy, + packing_fraction=args.packing_fraction, + ) + * args.diameter ) return args @@ -386,12 +406,12 @@ def set_mud(args): args : argparse.Namespace The updated arguments with mu*D. """ - if args.z_scan_file: + if args.command == "mud": + return args + if args.command == "zscan": return _set_mud_from_zscan(args) - elif args.theoretical_from_density: + if args.command == "sample": return _set_theoretical_mud_from_density(args) - elif args.theoretical_from_packing: - return _set_theoretical_mud_from_packing(args) return args @@ -507,6 +527,7 @@ def preprocessing_args(args): args : argparse.Namespace The updated argparse Namespace with arguments preprocessed. """ + args = load_wavelength_from_config_file(args) args = set_mud(args) args = set_input_lists(args) args = set_output_directory(args) @@ -518,6 +539,7 @@ def preprocessing_args(args): return args +# Update load_metadata to use 'input_directory' consistently: def load_metadata(args, filepath): """Load the relevant metadata from args to write into the header of the output files. @@ -538,6 +560,7 @@ def load_metadata(args, filepath): metadata = copy.deepcopy(vars(args)) for key in METADATA_KEYS_TO_EXCLUDE: metadata.pop(key, None) + metadata["mud"] = round(float(metadata["mud"]), 4) metadata["input_directory"] = str(filepath) metadata["output_directory"] = str(metadata["output_directory"]) return metadata From a240711b573a54a8432c0f7f27636c40d543e101 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 27 Jan 2026 11:51:28 -0500 Subject: [PATCH 10/77] test_tools.py --- tests/test_tools.py | 383 +++++++++++++++++++++++--------------------- 1 file changed, 197 insertions(+), 186 deletions(-) diff --git a/tests/test_tools.py b/tests/test_tools.py index e2028e9..05ff84d 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -5,7 +5,7 @@ import pytest -from diffpy.labpdfproc.labpdfprocapp import get_args +from diffpy.labpdfproc.labpdfprocapp import get_args_cli from diffpy.labpdfproc.tools import ( known_sources, load_metadata, @@ -13,6 +13,7 @@ load_user_info, load_user_metadata, load_wavelength_from_config_file, + normalize_wavelength, preprocessing_args, set_input_lists, set_mud, @@ -115,8 +116,8 @@ def test_set_input_lists(inputs, expected, user_filesystem): base_dir.resolve() / expected_path for expected_path in expected ] - cli_inputs = ["applymud"] + inputs + ["--mud", "2.5"] - actual_args = get_args(cli_inputs) + cli_inputs = ["mud"] + inputs + ["2.5"] + actual_args = get_args_cli(cli_inputs) actual_args = set_input_lists(actual_args) assert sorted(actual_args.input_paths) == sorted(expected_paths) @@ -161,8 +162,8 @@ def test_set_input_lists(inputs, expected, user_filesystem): def test_set_input_files_bad(inputs, expected_error_msg, user_filesystem): base_dir = Path(user_filesystem) os.chdir(base_dir) - cli_inputs = ["applymud"] + inputs + ["--mud", "2.5"] - actual_args = get_args(cli_inputs) + cli_inputs = ["mud"] + inputs + ["2.5"] + actual_args = get_args_cli(cli_inputs) with pytest.raises(FileNotFoundError, match=re.escape(expected_error_msg)): actual_args = set_input_lists(actual_args) @@ -179,8 +180,8 @@ def test_set_input_files_bad(inputs, expected_error_msg, user_filesystem): def test_set_output_directory(inputs, expected, user_filesystem): os.chdir(user_filesystem) expected_output_directory = Path(user_filesystem) / expected[0] - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) actual_args = set_output_directory(actual_args) assert actual_args.output_directory == expected_output_directory assert Path(actual_args.output_directory).exists() @@ -190,42 +191,69 @@ def test_set_output_directory(inputs, expected, user_filesystem): def test_set_output_directory_bad(user_filesystem): os.chdir(user_filesystem) cli_inputs = [ - "applymud", + "mud", "data.xy", - "--mud", "2.5", "--output-directory", "good_data.chi", ] - actual_args = get_args(cli_inputs) + actual_args = get_args_cli(cli_inputs) with pytest.raises(FileExistsError): actual_args = set_output_directory(actual_args) assert Path(actual_args.output_directory).exists() assert not Path(actual_args.output_directory).is_dir() +@pytest.mark.parametrize( + "inputs, expected", + [ + # UC1: input is numeric wavelength + # expect to return the same value + (["--wavelength", "0.25"], 0.25), + # UC2: input is valid source name (case-sensitive canonical) + # expect to return the corresponding wavelength from dict + (["--wavelength", "Mo"], 0.71073), + # UC3: input is valid source name, mismatched case + # expect to return the corresponding wavelength from dict + (["--wavelength", "agka1Ka2"], 0.56087), + ], +) +def test_normalize_wavelength(inputs, expected): + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + args = get_args_cli(cli_inputs) + args = normalize_wavelength(args) + assert args.wavelength == expected + + +def test_normalize_wavelength_bad(): + cli_inputs = ["mud", "data.xy", "2.5", "--wavelength", "invalid_source"] + args = get_args_cli(cli_inputs) + with pytest.raises( + ValueError, + match=( + "Anode type 'invalid_source' not recognized\\. " + "Please rerun specifying an anode type from " + ), + ): + normalize_wavelength(args) + + @pytest.mark.parametrize( "inputs, expected", [ # Test with only a home config file (no local config), # expect to return values directly from args - # if either wavelength or anode type is specified, + # if wavelength is specified, # otherwise update args with values from the home config file - # (wavelength=0.3, no anode type). + # (wavelength=0.3). # This test only checks loading behavior, # not value validation (which is handled by `set_wavelength`). # C1: no args, expect to update arg values from home config - ([], {"wavelength": 0.3, "anode_type": None}), + ([], {"wavelength": 0.3}), # C2: wavelength provided, expect to return args unchanged - (["--wavelength", "0.25"], {"wavelength": 0.25, "anode_type": None}), + (["--wavelength", "0.25"], {"wavelength": 0.25}), # C3: anode type provided, expect to return args unchanged - (["--anode-type", "Mo"], {"wavelength": None, "anode_type": "Mo"}), - # C4: both wavelength and anode type provided, - # expect to return args unchanged - ( - ["--wavelength", "0.7", "--anode-type", "Mo"], - {"wavelength": 0.7, "anode_type": "Mo"}, - ), + (["--wavelength", "Mo"], {"wavelength": 0.71073}), ], ) def test_load_wavelength_from_config_file_with_home_conf_file( @@ -236,11 +264,10 @@ def test_load_wavelength_from_config_file_with_home_conf_file( mocker.patch("pathlib.Path.home", lambda _: home_dir) os.chdir(cwd) - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) actual_args = load_wavelength_from_config_file(actual_args) assert actual_args.wavelength == expected["wavelength"] - assert actual_args.anode_type == expected["anode_type"] @pytest.mark.parametrize( @@ -255,17 +282,11 @@ def test_load_wavelength_from_config_file_with_home_conf_file( # This test only checks loading behavior, # not value validation (which is handled by `set_wavelength`). # C1: no args, expect to update arg values from local config - ([], {"wavelength": 0.6, "anode_type": None}), + ([], {"wavelength": 0.6}), # C2: wavelength provided, expect to return args unchanged - (["--wavelength", "0.25"], {"wavelength": 0.25, "anode_type": None}), + (["--wavelength", "0.25"], {"wavelength": 0.25}), # C3: anode type provided, expect to return args unchanged - (["--anode-type", "Mo"], {"wavelength": None, "anode_type": "Mo"}), - # C4: both wavelength and anode type provided, - # expect to return args unchanged - ( - ["--wavelength", "0.7", "--anode-type", "Mo"], - {"wavelength": 0.7, "anode_type": "Mo"}, - ), + (["--wavelength", "Mo"], {"wavelength": 0.71073}), ], ) def test_load_wavelength_from_config_file_with_local_conf_file( @@ -279,17 +300,15 @@ def test_load_wavelength_from_config_file_with_local_conf_file( with open(cwd / "diffpyconfig.json", "w") as f: json.dump(local_config_data, f) - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) actual_args = load_wavelength_from_config_file(actual_args) assert actual_args.wavelength == expected["wavelength"] - assert actual_args.anode_type == expected["anode_type"] # remove home config file, expect the same results confile = home_dir / "diffpyconfig.json" os.remove(confile) assert actual_args.wavelength == expected["wavelength"] - assert actual_args.anode_type == expected["anode_type"] @pytest.mark.parametrize( @@ -300,16 +319,11 @@ def test_load_wavelength_from_config_file_with_local_conf_file( # This test only checks loading behavior, # not value validation (which is handled by `set_wavelength`). # C1: no args - ([], {"wavelength": None, "anode_type": None}), + ([], {"wavelength": None}), # C1: wavelength provided - (["--wavelength", "0.25"], {"wavelength": 0.25, "anode_type": None}), + (["--wavelength", "0.25"], {"wavelength": 0.25}), # C2: anode type provided - (["--anode-type", "Mo"], {"wavelength": None, "anode_type": "Mo"}), - # C4: both wavelength and anode type provided - ( - ["--wavelength", "0.7", "--anode-type", "Mo"], - {"wavelength": 0.7, "anode_type": "Mo"}, - ), + (["--wavelength", "Mo"], {"wavelength": 0.71073}), ], ) def test_load_wavelength_from_config_file_without_conf_files( @@ -322,11 +336,10 @@ def test_load_wavelength_from_config_file_without_conf_files( confile = home_dir / "diffpyconfig.json" os.remove(confile) - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) actual_args = load_wavelength_from_config_file(actual_args) assert actual_args.wavelength == expected["wavelength"] - assert actual_args.anode_type == expected["anode_type"] @pytest.mark.parametrize( @@ -334,58 +347,55 @@ def test_load_wavelength_from_config_file_without_conf_files( [ # C1: only a valid anode type was entered (case independent), # expect to match the corresponding wavelength - # and preserve the correct case anode type - (["--anode-type", "Mo"], {"wavelength": 0.71073, "anode_type": "Mo"}), + (["--wavelength", "Mo"], {"wavelength": 0.71073}), ( - ["--anode-type", "MoKa1"], - {"wavelength": 0.70930, "anode_type": "MoKa1"}, + ["--wavelength", "MoKa1"], + {"wavelength": 0.70930}, ), ( - ["--anode-type", "MoKa1Ka2"], - {"wavelength": 0.71073, "anode_type": "MoKa1Ka2"}, + ["--wavelength", "MoKa1Ka2"], + {"wavelength": 0.71073}, ), - (["--anode-type", "Ag"], {"wavelength": 0.56087, "anode_type": "Ag"}), + (["--wavelength", "Ag"], {"wavelength": 0.56087}), ( - ["--anode-type", "AgKa1"], - {"wavelength": 0.55941, "anode_type": "AgKa1"}, + ["--wavelength", "AgKa1"], + {"wavelength": 0.55941}, ), ( - ["--anode-type", "AgKa1Ka2"], - {"wavelength": 0.56087, "anode_type": "AgKa1Ka2"}, + ["--wavelength", "AgKa1Ka2"], + {"wavelength": 0.56087}, ), - (["--anode-type", "Cu"], {"wavelength": 1.54184, "anode_type": "Cu"}), + (["--wavelength", "Cu"], {"wavelength": 1.54184}), ( - ["--anode-type", "CuKa1"], - {"wavelength": 1.54056, "anode_type": "CuKa1"}, + ["--wavelength", "CuKa1"], + {"wavelength": 1.54056}, ), ( - ["--anode-type", "CuKa1Ka2"], - {"wavelength": 1.54184, "anode_type": "CuKa1Ka2"}, + ["--wavelength", "CuKa1Ka2"], + {"wavelength": 1.54184}, ), ( - ["--anode-type", "moKa1Ka2"], - {"wavelength": 0.71073, "anode_type": "MoKa1Ka2"}, + ["--wavelength", "moKa1Ka2"], + {"wavelength": 0.71073}, ), - (["--anode-type", "ag"], {"wavelength": 0.56087, "anode_type": "Ag"}), + (["--wavelength", "ag"], {"wavelength": 0.56087}), ( - ["--anode-type", "cuka1"], - {"wavelength": 1.54056, "anode_type": "CuKa1"}, + ["--wavelength", "cuka1"], + {"wavelength": 1.54056}, ), # C2: a valid wavelength was entered, - # expect to include the wavelength only and anode type is None - (["--wavelength", "0.25"], {"wavelength": 0.25, "anode_type": None}), + (["--wavelength", "0.25"], {"wavelength": 0.25}), # C3: nothing passed in, but mu*D was provided and xtype is on tth - # expect wavelength and anode type to be None + # expect wavelength to be None # and program proceeds without error - ([], {"wavelength": None, "anode_type": None}), + ([], {"wavelength": None}), ], ) def test_set_wavelength(inputs, expected): - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) actual_args = set_wavelength(actual_args) assert actual_args.wavelength == expected["wavelength"] - assert actual_args.anode_type == expected["anode_type"] @pytest.mark.parametrize( @@ -398,30 +408,24 @@ def test_set_wavelength(inputs, expected): f"because the independent variable axis is not on two-theta. " f"Allowed anode types are {*known_sources, }.", ), - ( # C2: both wavelength and anode type were specified - # expect error asking not to specify both - ["--wavelength", "0.7", "--anode-type", "Mo"], - f"Please provide either a wavelength or an anode type, not both. " - f"Allowed anode types are {*known_sources, }.", - ), - ( # C3: invalid anode type + ( # C2: invalid anode type # expect error asking to specify a valid anode type - ["--anode-type", "invalid"], + ["--wavelength", "invalid"], f"Anode type 'invalid' not recognized. " - f"Please rerun specifying an anode_type from {*known_sources, }.", + f"Please rerun specifying an anode type from {*known_sources, }.", ), - ( # C4: invalid wavelength + ( # C3: invalid wavelength # expect error asking to specify a valid wavelength or anode type ["--wavelength", "-0.2"], "Wavelength = -0.2 is not valid. " - "Please rerun specifying a known anode_type " + "Please rerun specifying a known anode type " "or a positive wavelength.", ), ], ) def test_set_wavelength_bad(inputs, expected_error_msg): - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) with pytest.raises(ValueError, match=re.escape(expected_error_msg)): actual_args = set_wavelength(actual_args) @@ -436,15 +440,15 @@ def test_set_wavelength_bad(inputs, expected_error_msg): ], ) def test_set_xtype(inputs, expected_xtype): - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) actual_args = set_xtype(actual_args) assert actual_args.xtype == expected_xtype def test_set_xtype_bad(): - cli_inputs = ["applymud", "data.xy", "--mud", "2.5", "--xtype", "invalid"] - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5", "--xtype", "invalid"] + actual_args = get_args_cli(cli_inputs) with pytest.raises( ValueError, match=re.escape( @@ -454,29 +458,52 @@ def test_set_xtype_bad(): actual_args = set_xtype(actual_args) +def test_set_mud_from_mud(user_filesystem): + cwd = Path(user_filesystem) + os.chdir(cwd) + cli_inputs = ["mud", "data.xy", "2.5"] + actual_args = get_args_cli(cli_inputs) + actual_args = set_mud(actual_args) + expected_mud = 2.5 + assert actual_args.mud == expected_mud + + +def test_set_mud_from_zscan(user_filesystem): + cwd = Path(user_filesystem) + os.chdir(cwd) + cli_inputs = ["zscan", "data.xy", "test_dir/testfile.xy"] + actual_args = get_args_cli(cli_inputs) + actual_args = set_mud(actual_args) + expected_mud = 3.0 + assert actual_args.mud == pytest.approx(expected_mud, rel=1e-4, abs=0.1) + + @pytest.mark.parametrize( - "inputs, expected_mud", + "inputs,expected_mud", + # C1: user specifies a wavelength + # and the wavelength is used to compute mu*D [ - # C1: user enters muD manually, expect to return the same value - (["--mud", "2.5"], 2.5), - # C2: user provides a z-scan file, expect to estimate through the file - (["--z-scan-file", "test_dir/testfile.xy"], 3), - # C3: user specifies sample composition, energy, - # and sample mass density, - # both with and without whitespaces, expect to estimate theoretically - (["--theoretical-from-density", "ZrO2,17.45,1.2"], 1.49), - (["--theoretical-from-density", "ZrO2, 17.45, 1.2"], 1.49), - # C4: user specifies sample composition, energy, and packing fraction - # both with and without whitespaces, expect to estimate theoretically - # (["--theoretical-from-packing", "ZrO2,17.45,0.3"], 1.49), - # (["--theoretical-from-packing", "ZrO2, 17.45, 0.3"], 1.49), + (["--wavelength", ".71"], 4.32), + # C2: user specifies an anode type + # and the corresponding wavelength is used + # to compute mu*D + (["--wavelength", "Mo"], 4.32), + # C3: user does not specify wavelength or anode type + # and the wavelength is retrieved from a config file + ([], 4.32), ], ) -def test_set_mud(user_filesystem, inputs, expected_mud): +def test_set_mud_from_sample(mocker, user_filesystem, inputs, expected_mud): cwd = Path(user_filesystem) + home_dir = cwd / "home_dir" + mocker.patch("pathlib.Path.home", lambda _: home_dir) os.chdir(cwd) - cli_inputs = ["applymud", "data.xy"] + inputs - actual_args = get_args(cli_inputs) + local_config_data = {"wavelength": 0.71} + with open(cwd / "diffpyconfig.json", "w") as f: + json.dump(local_config_data, f) + # [command,datafile,sample_composition,sample_mass_density,diameter] + cli_inputs = ["sample", "data.xy", "ZrO2", "1.745", "2"] + inputs + actual_args = get_args_cli(cli_inputs) actual_args = set_mud(actual_args) assert actual_args.mud == pytest.approx(expected_mud, rel=1e-4, abs=0.1) @@ -487,72 +514,20 @@ def test_set_mud(user_filesystem, inputs, expected_mud): # C1: user provides an invalid z-scan file, # expect FileNotFoundError and message to specify a valid file path ( - ["--z-scan-file", "invalid file"], + ["invalid file"], [ FileNotFoundError, "Cannot find invalid file. Please specify a valid file path.", ], ), - # C2.1: (sample mass density option) - # user provides fewer than three input values - # expect ValueError with a message indicating the correct format - ( - ["--theoretical-from-density", "ZrO2,0.5"], - [ - ValueError, - "Invalid mu*D input 'ZrO2,0.5'. " - "Expected format is 'sample composition, energy, " - "sample mass density or packing fraction' " - "(e.g., 'ZrO2,17.45,0.5').", - ], - ), - # C2.2: (packing fraction option) - # user provides fewer than three input values - # expect ValueError with a message indicating the correct format - ( - ["--theoretical-from-packing", "ZrO2,0.5"], - [ - ValueError, - "Invalid mu*D input 'ZrO2,0.5'. " - "Expected format is 'sample composition, energy, " - "sample mass density or packing fraction' " - "(e.g., 'ZrO2,17.45,0.5').", - ], - ), - # C3.1: (sample mass density option) - # user provides more than 3 input values - # expect ValueError with a message indicating the correct format - ( - ["--theoretical-from-density", "ZrO2,17.45,1.5,0.5"], - [ - ValueError, - "Invalid mu*D input 'ZrO2,17.45,1.5,0.5'. " - "Expected format is 'sample composition, energy, " - "sample mass density or packing fraction' " - "(e.g., 'ZrO2,17.45,0.5').", - ], - ), - # C3.2: (packing fraction option) - # user provides more than 3 input values - # expect ValueError with a message indicating the correct format - ( - ["--theoretical-from-packing", "ZrO2,17.45,1.5,0.5"], - [ - ValueError, - "Invalid mu*D input 'ZrO2,17.45,1.5,0.5'. " - "Expected format is 'sample composition, energy, " - "sample mass density or packing fraction' " - "(e.g., 'ZrO2,17.45,0.5').", - ], - ), ], ) def test_set_mud_bad(user_filesystem, inputs, expected): expected_error, expected_error_msg = expected cwd = Path(user_filesystem) os.chdir(cwd) - cli_inputs = ["applymud", "data.xy"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["zscan", "data.xy"] + inputs + actual_args = get_args_cli(cli_inputs) with pytest.raises(expected_error, match=re.escape(expected_error_msg)): actual_args = set_mud(actual_args) @@ -578,13 +553,13 @@ def test_set_mud_bad(user_filesystem, inputs, expected): ], ) def test_load_user_metadata(inputs, expected): - expected_args = get_args(["applymud", "data.xy", "--mud", "2.5"]) + expected_args = get_args_cli(["mud", "data.xy", "2.5"]) for expected_pair in expected: setattr(expected_args, expected_pair[0], expected_pair[1]) delattr(expected_args, "user_metadata") - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) actual_args = load_user_metadata(actual_args) assert actual_args == expected_args @@ -619,8 +594,8 @@ def test_load_user_metadata(inputs, expected): ], ) def test_load_user_metadata_bad(inputs, expected_error_msg): - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] + inputs - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + inputs + actual_args = get_args_cli(cli_inputs) with pytest.raises(ValueError, match=re.escape(expected_error_msg)): actual_args = load_user_metadata(actual_args) @@ -682,9 +657,8 @@ def test_load_user_info(monkeypatch, inputs, expected, user_filesystem): os.chdir(cwd) cli_inputs = [ - "applymud", + "mud", "data.xy", - "--mud", "2.5", "--username", inputs["username"], @@ -693,7 +667,7 @@ def test_load_user_info(monkeypatch, inputs, expected, user_filesystem): "--orcid", inputs["orcid"], ] - actual_args = get_args(cli_inputs) + actual_args = get_args_cli(cli_inputs) actual_args = load_user_info(actual_args) assert actual_args.username == expected["username"] assert actual_args.email == expected["email"] @@ -707,8 +681,8 @@ def test_load_package_info(mocker): "3.3.0" if package_name == "diffpy.utils" else "1.2.3" ), ) - cli_inputs = ["applymud", "data.xy", "--mud", "2.5"] - actual_args = get_args(cli_inputs) + cli_inputs = ["mud", "data.xy", "2.5"] + actual_args = get_args_cli(cli_inputs) actual_args = load_package_info(actual_args) assert actual_args.package_info == { "diffpy.labpdfproc": "1.2.3", @@ -716,7 +690,44 @@ def test_load_package_info(mocker): } -def test_load_metadata(mocker, user_filesystem): +@pytest.mark.parametrize( + "inputs,expected", + # C1: user corrects data using `mud` command + # expect to include mud value and method + [ + ( + ["mud", ".", "2.5"], + { + "mud": 2.5, + "command": "mud", + }, + ), + # C2: user corrects data using `zscan` command + # expect to include z-scan file and method + ( + ["zscan", ".", "test_dir/testfile.xy"], + { + "z_scan_file": "test_dir/testfile.xy", + "command": "zscan", + "mud": 3.0, + }, + ), + # C3: user corrects data using `sample` command + # expected to include sample composition, + # mass density, diameter, and method + ( + ["sample", ".", "ZrO2", "1.745", "2"], + { + "sample_composition": "ZrO2", + "sample_mass_density": 1.745, + "diameter": 2.0, + "command": "sample", + "mud": 4.3321, + }, + ), + ], +) +def test_load_metadata(mocker, user_filesystem, inputs, expected): # Test if the function loads args # (which will be loaded into the header file). # Expect to include mu*D, anode type, xtype, cve method, @@ -732,12 +743,8 @@ def test_load_metadata(mocker, user_filesystem): "3.3.0" if package_name == "diffpy.utils" else "1.2.3" ), ) - cli_inputs = [ - "applymud", - ".", - "--mud", - "2.5", - "--anode-type", + cli_inputs = inputs + [ + "--wavelength", "Mo", "--user-metadata", "key=value", @@ -748,14 +755,18 @@ def test_load_metadata(mocker, user_filesystem): "--orcid", "cli_orcid", ] - actual_args = get_args(cli_inputs) + actual_args = get_args_cli(cli_inputs) actual_args = preprocessing_args(actual_args) for filepath in actual_args.input_paths: + if "z_scan_file" in expected: + # adjust path to be relative to cwd + expected["z_scan_file"] = str( + (cwd / expected["z_scan_file"]).resolve() + ) actual_metadata = load_metadata(actual_args, filepath) expected_metadata = { - "mud": 2.5, "input_directory": str(filepath), - "anode_type": "Mo", + "wavelength": 0.71073, "output_directory": str(Path.cwd().resolve()), "xtype": "tth", "method": "polynomial_interpolation", @@ -767,6 +778,6 @@ def test_load_metadata(mocker, user_filesystem): "diffpy.labpdfproc": "1.2.3", "diffpy.utils": "3.3.0", }, - "z_scan_file": None, + **expected, } assert actual_metadata == expected_metadata From f1d393031acee17f97ddf14b6f82415435a9f40c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 27 Jan 2026 11:52:28 -0500 Subject: [PATCH 11/77] news --- news/improved-cli.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/improved-cli.rst diff --git a/news/improved-cli.rst b/news/improved-cli.rst new file mode 100644 index 0000000..e50f193 --- /dev/null +++ b/news/improved-cli.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* Compartmentalize commands into the subcommands ``mud``, ``zscan``, and ``sample``. See documentation for more info. + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 5bba5a97abbd1e3ae4a5227f2ee7160df070afa1 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:09:11 -0500 Subject: [PATCH 12/77] .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d418364..099e294 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ __pycache__/ .Python env/ build/ +_build/ develop-eggs/ dist/ downloads/ From b1cbe61ccb54490a75d3573ed2a8e76d59c7a39b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:09:32 -0500 Subject: [PATCH 13/77] AUTHORS.rst --- AUTHORS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 251218d..30b069c 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,7 +1,7 @@ Authors ======= -Billinge Group and community contributors. +Yucong Chen, Till Schertenleib, Caden Myers, Billinge Group members Contributors ------------ From 7902264eb11df4ca4f1c240fc930d23542a7bd30 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:09:49 -0500 Subject: [PATCH 14/77] cookiecutter.json --- cookiecutter.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 cookiecutter.json diff --git a/cookiecutter.json b/cookiecutter.json new file mode 100644 index 0000000..7c013d4 --- /dev/null +++ b/cookiecutter.json @@ -0,0 +1,20 @@ +{ + "author_names": "Yucong Chen, Till Schertenleib, Caden Myers, Simon Billinge", + "author_emails": "yc4372@columbia.edu, ts@chem.ku.dk, cjm2304@columbia.edu, sbillinge@ucsb.edu", + "maintainer_names": "Simon Billinge", + "maintainer_emails": "sbillinge@ucsb.edu", + "maintainer_github_usernames": "sbillinge", + "contributors": "Yucong Chen, Till Schertenleib, Caden Myers, Billinge Group members", + "license_holders": "The Trustees of Columbia University in the City of New York", + "project_name": "diffpy.labpdfproc", + "github_username_or_orgname": "diffpy", + "github_repo_name": "diffpy.labpdfproc", + "conda_pypi_package_dist_name": "diffpy.labpdfproc", + "package_dir_name": "diffpy.labpdfproc", + "project_short_description": "Tools for processing x-ray powder diffraction data from laboratory sources.", + "project_keywords": "powder XRD, absorption correction, PDF, diffpy", + "minimum_supported_python_version": "3.12", + "maximum_supported_python_version": "3.14", + "project_needs_c_code_compiled": "No", + "project_has_gui_tests": "No" +} From b27a1055fb4803427a0735c0eb6145b64d3b33db Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:10:18 -0500 Subject: [PATCH 15/77] CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 94114aa..33d7032 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,5 @@ ============= -Release Notes +Release notes ============= .. current developments From 5338006d3d647abfeb8e0c854615236f351fbd01 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:11:29 -0500 Subject: [PATCH 16/77] LICENSE.rst --- LICENSE.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/LICENSE.rst b/LICENSE.rst index 9cc6a9d..d5f6da9 100644 --- a/LICENSE.rst +++ b/LICENSE.rst @@ -1,6 +1,9 @@ BSD 3-Clause License -Copyright (c) 2025, The Trustees of Columbia University in the City of New York. +Copyright (c) 2025-2026, The Trustees of Columbia University in the City of New York. +All rights reserved. + +Copyright (c) 2026-present, diffpy.labpdfproc developers and contributors. All rights reserved. Redistribution and use in source and binary forms, with or without From 16c4fc275db1a92cf4b7dd0bc5aebc26f7cb819c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:12:01 -0500 Subject: [PATCH 17/77] CODE-OF-CONDUCT.rst --- CODE-OF-CONDUCT.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE-OF-CONDUCT.rst b/CODE-OF-CONDUCT.rst index e8199ca..25fafe2 100644 --- a/CODE-OF-CONDUCT.rst +++ b/CODE-OF-CONDUCT.rst @@ -67,7 +67,7 @@ Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -sb2896@columbia.edu. All complaints will be reviewed and investigated promptly and fairly. +sbillinge@ucsb.edu. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. From d4c8f5f45218ea469b844f257320a9dafd679a14 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:14:55 -0500 Subject: [PATCH 18/77] pyproject.toml --- pyproject.toml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 09a5bd9..a55f107 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,15 +6,18 @@ build-backend = "setuptools.build_meta" name = "diffpy.labpdfproc" dynamic=['version', 'dependencies'] authors = [ - { name="Simon J.L. Billinge group", email="simon.billinge@gmail.com" }, + {name='Yucong Chen', email='yc4372@columbia.edu'}, + {name='Till Schertenleib', email='ts@chem.ku.dk'}, + {name='Caden Myers', email='cjm2304@columbia.edu'}, + {name='Simon Billinge', email='sbillinge@ucsb.edu'}, ] maintainers = [ - { name="Simon J.L. Billinge group", email="simon.billinge@gmail.com" }, + {name='Simon Billinge', email='sbillinge@ucsb.edu'}, ] description = "Tools for processing x-ray powder diffraction data from laboratory sources." -keywords = ['powder xrd', 'absorption correction', 'pdf', 'diffpy'] +keywords = ['powder XRD', 'absorption correction', 'PDF', 'diffpy'] readme = "README.rst" -requires-python = ">=3.11, <3.14" +requires-python = ">=3.12, <3.15" classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', @@ -25,9 +28,9 @@ classifiers = [ 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Operating System :: Unix', - 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', 'Topic :: Scientific/Engineering :: Physics', 'Topic :: Scientific/Engineering :: Chemistry', ] @@ -57,7 +60,12 @@ dependencies = {file = ["requirements/pip.txt"]} [tool.codespell] exclude-file = ".codespell/ignore_lines.txt" ignore-words = ".codespell/ignore_words.txt" -skip = "*.cif" +skip = "*.cif,*.dat" + +[tool.docformatter] +recursive = true +wrap-summaries = 72 +wrap-descriptions = 72 [tool.black] line-length = 79 From 27d7045fe10df60e7ff4ac2758c0c4c36a387160 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:15:25 -0500 Subject: [PATCH 19/77] release_checklist.md --- .github/ISSUE_TEMPLATE/release_checklist.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/release_checklist.md b/.github/ISSUE_TEMPLATE/release_checklist.md index fa94779..56c5fca 100644 --- a/.github/ISSUE_TEMPLATE/release_checklist.md +++ b/.github/ISSUE_TEMPLATE/release_checklist.md @@ -11,32 +11,33 @@ assignees: "" - [ ] All PRs/issues attached to the release are merged. - [ ] All the badges on the README are passing. - [ ] License information is verified as correct. If you are unsure, please comment below. -- [ ] Locally rendered documentation contains all appropriate pages, including API references (check no modules are - missing), tutorials, and other human-written text is up-to-date with any changes in the code. -- [ ] Installation instructions in the README, documentation, and the website (e.g., diffpy.org) are updated. +- [ ] Locally rendered documentation contains all appropriate pages, tutorials, and other human-written text is up-to-date with any changes in the code. +- [ ] All API references are included. To check this, run `conda install scikit-package` and then `package build api-doc`. Review any edits made by rerendering the docs locally. +- [ ] Installation instructions in the README, documentation, and the website are updated. - [ ] Successfully run any tutorial examples or do functional testing with the latest Python version. - [ ] Grammar and writing quality are checked (no typos). - [ ] Install `pip install build twine`, run `python -m build` and `twine check dist/*` to ensure that the package can be built and is correctly formatted for PyPI release. +- [ ] Dispatch matrix testing to test the release on all Python versions and systems. If you do not have permission to run this workflow, tag the maintainer and say `@maintainer, please dispatch matrix testing workflow`. -Please mention @sbillinge here when you are ready for PyPI/GitHub release. Include any additional comments necessary, such as version information and details about the pre-release here: +Please tag the maintainer (e.g., @username) in the comment here when you are ready for the PyPI/GitHub release. Include any additional comments necessary, such as version information and details about the pre-release here: ### PyPI/GitHub full-release preparation checklist: - [ ] Create a new conda environment and install the rc from PyPI (`pip install ==??`) - [ ] License information on PyPI is correct. -- [ ] Docs are deployed successfully to `https://www.diffpy.org/`. +- [ ] Docs are deployed successfully to `https:///`. - [ ] Successfully run all tests, tutorial examples or do functional testing. -Please let @sbillinge know that all checks are done and the package is ready for full release. +Please let the maintainer know that all checks are done and the package is ready for full release. ### conda-forge release preparation checklist: - + - [ ] Ensure that the full release has appeared on PyPI successfully. -- [ ] New package dependencies listed in `conda.txt` and `test.txt` are added to `meta.yaml` in the feedstock. -- [ ] Close any open issues on the feedstock. Reach out to @bobleesj if you have questions. -- [ ] Tag @sbillinge and @bobleesj for conda-forge release. +- [ ] New package dependencies listed in `conda.txt` and `tests.txt` are added to `meta.yaml` in the feedstock. +- [ ] Close any open issues on the feedstock. Reach out to the maintainer if you have questions. +- [ ] Tag the maintainer for conda-forge release. ### Post-release checklist From ecdab371f430ede4996eda71478765a966d0ef90 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:17:12 -0500 Subject: [PATCH 20/77] README.rst --- README.rst | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/README.rst b/README.rst index 1b8908c..facbcad 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,7 @@ :target: https://diffpy.github.io/diffpy.labpdfproc :height: 100px -|PyPi| |Forge| |PythonVersion| |PR| +|PyPI| |Forge| |PythonVersion| |PR| |CI| |Codecov| |Black| |Tracking| @@ -25,8 +25,9 @@ :target: https://anaconda.org/conda-forge/diffpy.labpdfproc .. |PR| image:: https://img.shields.io/badge/PR-Welcome-29ab47ff + :target: https://github.com/diffpy/diffpy.labpdfproc/pulls -.. |PyPi| image:: https://img.shields.io/pypi/v/diffpy.labpdfproc +.. |PyPI| image:: https://img.shields.io/pypi/v/diffpy.labpdfproc :target: https://pypi.org/project/diffpy.labpdfproc/ .. |PythonVersion| image:: https://img.shields.io/pypi/pyversions/diffpy.labpdfproc @@ -84,10 +85,6 @@ The following creates and activates a new environment named ``diffpy.labpdfproc_ conda create -n diffpy.labpdfproc_env diffpy.labpdfproc conda activate diffpy.labpdfproc_env -To confirm that the installation was successful, type :: - - python -c "import diffpy.labpdfproc; print(diffpy.labpdfproc.__version__)" - The output should print the latest version displayed on the badges above. If the above does not work, you can use ``pip`` to download and install the latest release from @@ -102,26 +99,18 @@ and run the following :: pip install . -Example -------- - -Navigate to the directory that contains 1D diffraction patterns that you would like to process. -Activate the conda environment (`conda activate diffpy.labpdfproc_env`) that contains the package and run the following command :: +This package also provides command-line utilities. To check the software has been installed correctly, type :: - labpdfproc --mud + labpdfproc --version -Here replace with the value of muD for your sample -and with the path and filename of your input file. -For example, if the uncorrected data case is called zro2_mo.xy and is in the current directory -and it has a muD of 2.5 then the command would be :: +You can also type the following command to verify the installation. :: - labpdfproc zro2_mo.xy --mud 2.5 + python -c "import diffpy.labpdfproc; print(diffpy.labpdfproc.__version__)" -Please type :: - labpdfproc --help +To view the basic usage and available commands, type :: -for more information on the available options. + labpdfproc -h Getting Started --------------- @@ -131,9 +120,7 @@ You may consult our `online documentation `_ is the discussion forum for general questions and discussions about the use of diffpy.labpdfproc. Please join the diffpy.labpdfproc users community by joining the Google group. The diffpy.labpdfproc project welcomes your expertise and enthusiasm! - -If you see a bug or want to request a feature, please `report it as an issue `_ and/or `submit a fix as a PR `_. You can also post it to the `Diffpy user group `_. +If you see a bug or want to request a feature, please `report it as an issue `_ and/or `submit a fix as a PR `_. Feel free to fork the project and contribute. To install diffpy.labpdfproc in a development mode, with its sources being directly used by Python @@ -161,4 +148,9 @@ Before contributing, please read our `Code of Conduct `_ or email Prof. Simon Billinge at sb2896@columbia.edu. +For more information on diffpy.labpdfproc please visit the project `web-page `_ or email the maintainers ``Simon Billinge(sbillinge@ucsb.edu)``. + +Acknowledgements +---------------- + +``diffpy.labpdfproc`` is built and maintained with `scikit-package `_. From 5529a129d11f26e616aeb1f73f0dfb0fe488edaa Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:18:29 -0500 Subject: [PATCH 21/77] .github/workflows/ --- .../build-and-publish-docs-on-dispatch.yml | 18 +++++++ .../workflows/build-wheel-release-upload.yml | 8 +-- .github/workflows/check-news-item.yml | 2 +- .github/workflows/matrix-and-codecov.yml | 21 ++++++++ .github/workflows/tests-on-pr.yml | 54 +++---------------- 5 files changed, 52 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/build-and-publish-docs-on-dispatch.yml create mode 100644 .github/workflows/matrix-and-codecov.yml diff --git a/.github/workflows/build-and-publish-docs-on-dispatch.yml b/.github/workflows/build-and-publish-docs-on-dispatch.yml new file mode 100644 index 0000000..a059aea --- /dev/null +++ b/.github/workflows/build-and-publish-docs-on-dispatch.yml @@ -0,0 +1,18 @@ +name: Build and Publish Docs on Dispatch + +on: + workflow_dispatch: + +jobs: + get-python-version: + uses: scikit-package/release-scripts/.github/workflows/_get-python-version-latest.yml@v0 + with: + python_version: 0 + + docs: + uses: scikit-package/release-scripts/.github/workflows/_release-docs.yml@v0 + with: + project: diffpy.labpdfproc + c_extension: false + headless: false + python_version: ${{ fromJSON(needs.get-python-version.outputs.latest_python_version) }} diff --git a/.github/workflows/build-wheel-release-upload.yml b/.github/workflows/build-wheel-release-upload.yml index b60acca..7f42d6d 100644 --- a/.github/workflows/build-wheel-release-upload.yml +++ b/.github/workflows/build-wheel-release-upload.yml @@ -1,4 +1,4 @@ -name: Release (GitHub/PyPI) and Deploy Docs +name: Build Wheel, Release on GitHub/PyPI, and Deploy Docs on: workflow_dispatch: @@ -7,12 +7,12 @@ on: - "*" # Trigger on all tags initially, but tag and release privilege are verified in _build-wheel-release-upload.yml jobs: - release: - uses: Billingegroup/release-scripts/.github/workflows/_build-wheel-release-upload.yml@v0 + build-release: + uses: scikit-package/release-scripts/.github/workflows/_build-wheel-release-upload.yml@v0 with: project: diffpy.labpdfproc c_extension: false - github_admin_username: sbillinge + maintainer_GITHUB_username: sbillinge secrets: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} PAT_TOKEN: ${{ secrets.PAT_TOKEN }} diff --git a/.github/workflows/check-news-item.yml b/.github/workflows/check-news-item.yml index 3588c8a..1f2a0cc 100644 --- a/.github/workflows/check-news-item.yml +++ b/.github/workflows/check-news-item.yml @@ -7,6 +7,6 @@ on: jobs: check-news-item: - uses: Billingegroup/release-scripts/.github/workflows/_check-news-item.yml@v0 + uses: scikit-package/release-scripts/.github/workflows/_check-news-item.yml@v0 with: project: diffpy.labpdfproc diff --git a/.github/workflows/matrix-and-codecov.yml b/.github/workflows/matrix-and-codecov.yml new file mode 100644 index 0000000..5fb55d6 --- /dev/null +++ b/.github/workflows/matrix-and-codecov.yml @@ -0,0 +1,21 @@ +name: Matrix and Codecov + +on: + # push: + # branches: + # - main + release: + types: + - prereleased + - published + workflow_dispatch: + +jobs: + matrix-coverage: + uses: scikit-package/release-scripts/.github/workflows/_matrix-and-codecov-on-merge-to-main.yml@v0 + with: + project: diffpy.labpdfproc + c_extension: false + headless: false + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index db5cacf..7dc796d 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -1,53 +1,15 @@ name: Tests on PR on: - push: - branches: - - main pull_request: workflow_dispatch: jobs: - validate: - defaults: - run: - shell: bash -l {0} - - runs-on: ubuntu-latest - steps: - - name: Check out diffpy.labpdfproc repository - uses: actions/checkout@v4 - - - name: Initialize miniconda - uses: conda-incubator/setup-miniconda@v3 - with: - activate-environment: test - auto-update-conda: true - environment-file: environment.yml - auto-activate-base: false - python-version: 3.13 - - - name: Conda config - run: >- - conda config --set always_yes yes - --set changeps1 no - - - name: Install diffpy.labpdfproc and requirements - run: | - conda install --file requirements/tests.txt - conda install --file requirements/conda.txt - pip install gooey - python -m pip install . --no-deps - - - name: Validate diffpy.labpdfproc - run: | - pytest --cov - coverage report -m - codecov - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - with: - verbose: true - fail_ci_if_error: true - token: ${{ secrets.CODECOV_TOKEN }} + tests-on-pr: + uses: scikit-package/release-scripts/.github/workflows/_tests-on-pr.yml@v0 + with: + project: diffpy.labpdfproc + c_extension: false + headless: false + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From b4b1560d31419fce7d4a06a0d6210388693d1d7e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:21:30 -0500 Subject: [PATCH 22/77] conf.py --- docs/source/conf.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 2e73623..ae18bcd 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -18,6 +18,15 @@ from importlib.metadata import version from pathlib import Path +# Attempt to import the version dynamically from GitHub tag. +try: + fullversion = version("diffpy.labpdfproc") +except Exception: + fullversion = ( + "No version found. " + "The correct version will appear in the released version." + ) + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use Path().resolve() to make it absolute, like shown here @@ -26,7 +35,9 @@ sys.path.insert(0, str(Path("../../src").resolve())) # abbreviations -ab_authors = "Billinge Group members and community contributors" +ab_authors = ( + "Yucong Chen, Till Schertenleib, Caden Myers, Billinge Group members" +) # -- General configuration ------------------------------------------------ @@ -43,7 +54,8 @@ "sphinx.ext.viewcode", "sphinx.ext.intersphinx", "sphinx_rtd_theme", - "m2r", + "sphinx_copybutton", + "m2r2", ] # Add any paths that contain templates here, relative to this directory. @@ -68,7 +80,6 @@ # |version| and |release|, also used in various other places throughout the # built documents. -fullversion = version(project) # The short X.Y version. version = "".join(fullversion.split(".post")[:1]) # The full version, including alpha/beta/rc tags. @@ -88,6 +99,11 @@ # substitute YEAR in the copyright string copyright = copyright.replace("%Y", year) +# For sphinx_copybutton extension. +# Do not copy "$" for shell commands in code-blocks. +copybutton_prompt_text = r"^\$ " +copybutton_prompt_is_regexp = True + # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ["build"] @@ -123,6 +139,14 @@ # html_theme = "sphinx_rtd_theme" +html_context = { + "display_github": True, + "github_user": "diffpy", + "github_repo": "diffpy.labpdfproc", + "github_version": "main", + "conf_py_path": "/docs/source/", +} + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. From b2849f0a17616d99371d0d17537b18040c43b745 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:23:22 -0500 Subject: [PATCH 23/77] index.rst --- docs/source/index.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index f8cb8c9..1bf6d0f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,19 +4,16 @@ .. |title| replace:: diffpy.labpdfproc documentation -diffpy.labpdfproc - Tools for processing x-ray powder diffraction data from laboratory sources. +``diffpy.labpdfproc`` - Tools for processing x-ray powder diffraction data from laboratory sources. -| Software version |release|. +| Software version |release| | Last updated |today|. ======= Authors ======= -diffpy.labpdfproc is developed by Yucong Chen, Till Schertenleib, Caden Myers, the Billinge Group -and its community contributors. - -For a detailed list of contributors see +``diffpy.labpdfproc`` is developed by Yucong Chen, Till Schertenleib, Caden Myers, Billinge Group members. This project is maintained by Simon Billinge. For a detailed list of contributors see https://github.com/diffpy/diffpy.labpdfproc/graphs/contributors. ============ @@ -26,6 +23,12 @@ Installation See the `README `_ file included with the distribution. +================ +Acknowledgements +================ + +``diffpy.labpdfproc`` is built and maintained with `scikit-package `_. + ================= Table of contents ================= From 15a30ca891ea6e943cbef60041731227c8aa4b89 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:24:12 -0500 Subject: [PATCH 24/77] license.rst --- docs/source/license.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/license.rst b/docs/source/license.rst index 9ae52a9..2abd4ff 100644 --- a/docs/source/license.rst +++ b/docs/source/license.rst @@ -9,8 +9,10 @@ OPEN SOURCE LICENSE AGREEMENT ============================= BSD 3-Clause License -Copyright (c) 2024, The Trustees of Columbia University in -the City of New York. +Copyright (c) 2024-2025, The Trustees of Columbia University in the City of New York. +All Rights Reserved. + +Copyright (c) 2026-present, diffpy.labpdfproc developers and contributors. All Rights Reserved. Redistribution and use in source and binary forms, with or without From b10fa02310c8f4e3124ec8110260acf3dd8ddf26 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:25:17 -0500 Subject: [PATCH 25/77] img/ and snippets/ placeholders --- docs/source/img/.placeholder | 0 docs/source/snippets/.placeholder | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/source/img/.placeholder create mode 100644 docs/source/snippets/.placeholder diff --git a/docs/source/img/.placeholder b/docs/source/img/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/docs/source/snippets/.placeholder b/docs/source/snippets/.placeholder new file mode 100644 index 0000000..e69de29 From bfd3dfbf2596ebb92722ad8d12a33fb2014d2797 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:25:42 -0500 Subject: [PATCH 26/77] .flake8 --- .flake8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 7b2865c..88077af 100644 --- a/.flake8 +++ b/.flake8 @@ -6,7 +6,7 @@ exclude = __pycache__, build, dist, - doc/source/conf.py + docs/source/conf.py max-line-length = 79 # Ignore some style 'errors' produced while formatting by 'black' # https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#labels-why-pycodestyle-warnings From fbd6c17e74c876f2732df65aa05636130b9cb876 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:26:05 -0500 Subject: [PATCH 27/77] .readthedocs.yaml --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 47f7a01..aaa8889 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -10,4 +10,4 @@ python: - requirements: requirements/docs.txt sphinx: - configuration: doc/source/conf.py + configuration: docs/source/conf.py From 4633b9ee223653a77d18fa05167225ff768b0dde Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:26:42 -0500 Subject: [PATCH 28/77] api/diffpy.labpdfproc.rst --- docs/source/api/diffpy.labpdfproc.rst | 32 ++++++++------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/docs/source/api/diffpy.labpdfproc.rst b/docs/source/api/diffpy.labpdfproc.rst index a3f53e1..1bcc98d 100644 --- a/docs/source/api/diffpy.labpdfproc.rst +++ b/docs/source/api/diffpy.labpdfproc.rst @@ -1,7 +1,9 @@ :tocdepth: -1 -diffpy.labpdfproc package -========================= +|title| +======= + +.. |title| replace:: diffpy.labpdfproc package .. automodule:: diffpy.labpdfproc :members: @@ -12,33 +14,17 @@ Subpackages ----------- .. toctree:: - :titlesonly: - - diffpy.labpdfproc.data + diffpy.labpdfproc.example_package Submodules ---------- -diffpy.labpdfproc.functions module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. automodule:: diffpy.labpdfproc.functions - :members: - :undoc-members: - :show-inheritance: - -diffpy.labpdfproc.tools module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. automodule:: diffpy.labpdfproc.tools - :members: - :undoc-members: - :show-inheritance: +|module| +-------- -diffpy.labpdfproc.labpdfprocapp module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. |module| replace:: diffpy.labpdfproc.example_submodule module -.. automodule:: diffpy.labpdfproc.labpdfprocapp +.. automodule:: diffpy.labpdfproc.example_submodule :members: :undoc-members: :show-inheritance: From a1f296e31a2e91d7095f53692f721249d02b9076 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:27:29 -0500 Subject: [PATCH 29/77] docs.txt --- requirements/docs.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements/docs.txt b/requirements/docs.txt index ab17b1c..1de813f 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -1,4 +1,5 @@ sphinx sphinx_rtd_theme +sphinx-copybutton doctr -m2r +m2r2 From e39f94332740c366b7cdf1fa80d80269935487bd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:31:01 -0500 Subject: [PATCH 30/77] __init__.py --- src/diffpy/__init__.py | 8 ++++++-- src/diffpy/labpdfproc/__init__.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/diffpy/__init__.py b/src/diffpy/__init__.py index 78ce07b..263df6a 100644 --- a/src/diffpy/__init__.py +++ b/src/diffpy/__init__.py @@ -1,10 +1,14 @@ #!/usr/bin/env python ############################################################################## # -# (c) 2024 The Trustees of Columbia University in the City of New York. +# (c) 2024-2025, The Trustees of Columbia University in the City of New York. # All rights reserved. # -# File coded by: Billinge Group members and community contributors. +# (c) 2026-present, diffpy.labpdfproc developers and contributors. +# All rights reserved. +# +# File coded by: Yucong Chen, Till Schertenleib, Caden Myers, +# Billinge Group members. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.labpdfproc/graphs/contributors diff --git a/src/diffpy/labpdfproc/__init__.py b/src/diffpy/labpdfproc/__init__.py index 3316df6..694c534 100644 --- a/src/diffpy/labpdfproc/__init__.py +++ b/src/diffpy/labpdfproc/__init__.py @@ -1,10 +1,14 @@ #!/usr/bin/env python ############################################################################## # -# (c) 2024 The Trustees of Columbia University in the City of New York. +# (c) 2024-2025, The Trustees of Columbia University in the City of New York. # All rights reserved. # -# File coded by: Billinge Group members and community contributors. +# (c) 2026-present, diffpy.labpdfproc developers and contributors. +# All rights reserved. +# +# File coded by: Yucong Chen, Till Schertenleib, Caden Myers, +# Billinge Group members. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.labpdfproc/graphs/contributors From 1ae29266b6d80ded1ffa0590a079e976ff5392bb Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:31:49 -0500 Subject: [PATCH 31/77] version.py --- src/diffpy/labpdfproc/version.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/diffpy/labpdfproc/version.py b/src/diffpy/labpdfproc/version.py index 13d3b31..26fc43b 100644 --- a/src/diffpy/labpdfproc/version.py +++ b/src/diffpy/labpdfproc/version.py @@ -1,10 +1,14 @@ #!/usr/bin/env python ############################################################################## # -# (c) 2024 The Trustees of Columbia University in the City of New York. +# (c) 2024-2025, The Trustees of Columbia University in the City of New York. # All rights reserved. # -# File coded by: Billinge Group members and community contributors. +# (c) 2026-present, diffpy.labpdfproc developers and contributors. +# All rights reserved. +# +# File coded by: Yucong Chen, Till Schertenleib, Caden Myers, +# Billinge Group members. # # See GitHub contributions for a more detailed list of contributors. # https://github.com/diffpy/diffpy.labpdfproc/graphs/contributors @@ -18,8 +22,9 @@ # __all__ = ["__date__", "__git_commit__", "__timestamp__", "__version__"] # obtain version information -from importlib.metadata import version - -__version__ = version("diffpy.labpdfproc") +from importlib.metadata import PackageNotFoundError, version -# End of file +try: + __version__ = version("diffpy.labpdfproc") +except PackageNotFoundError: + __version__ = "unknown" From 06dcfcc71fe877ac847dba2c90994614478a24b0 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:47:09 -0500 Subject: [PATCH 32/77] update deprecate loadData with load_data --- docs/source/examples/functions-example.rst | 4 ++-- src/diffpy/labpdfproc/labpdfprocapp.py | 8 ++++---- tests/test_fixtures.py | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/source/examples/functions-example.rst b/docs/source/examples/functions-example.rst index 2a909e1..33d64ac 100644 --- a/docs/source/examples/functions-example.rst +++ b/docs/source/examples/functions-example.rst @@ -13,11 +13,11 @@ For example, if you want to load data from ``zro2_mo.xy`` in the ``example-data` .. code-block:: python - from diffpy.utils.parsers.loaddata import loadData + from diffpy.utils.parsers import load_data from diffpy.utils.diffraction_objects import DiffractionObject filepath = "../example-data/zro2_mo.xy" - xarray, yarray = loadData(filepath, unpack=True) + xarray, yarray = load_data(filepath, unpack=True) input_pattern = DiffractionObject( xarray=xarray, yarray=yarray, diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index 7e824f2..e5575ec 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -12,7 +12,7 @@ set_wavelength, ) from diffpy.utils.diffraction_objects import XQUANTITIES, DiffractionObject -from diffpy.utils.parsers.loaddata import loadData +from diffpy.utils.parsers import load_data def _add_common_args(parser, use_gui=False): @@ -139,7 +139,7 @@ def _save_correction(correction, input_path, args): def _load_pattern(path, xtype, wavelength, metadata): - x, y = loadData(path, unpack=True) + x, y = load_data(path, unpack=True) return DiffractionObject( xarray=x, yarray=y, @@ -264,8 +264,8 @@ def create_parser(use_gui=False): def _handle_old_api_conversion(args): - """Convert `sample` command arguments to previous format so functions can - accept them without modification.""" + """Convert `sample` command arguments to previous format so + functions can accept them without modification.""" if args.command == "sample": # Convert sample args to theoretical_from_density format args = load_wavelength_from_config_file(args) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index d7a05d2..044e8fa 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -2,17 +2,17 @@ import pytest -from diffpy.utils.parsers.loaddata import loadData +from diffpy.utils.parsers import load_data # Test that our readable and unreadable files are indeed readable and -# unreadable by loadData (which is our definition of readable and unreadable) -def test_loadData_with_input_files(user_filesystem): +# unreadable by load_data (which is our definition of readable and unreadable) +def test_load_data_with_input_files(user_filesystem): os.chdir(user_filesystem) - xarray_chi, yarray_chi = loadData("good_data.chi", unpack=True) - xarray_xy, yarray_xy = loadData("good_data.xy", unpack=True) - xarray_txt, yarray_txt = loadData("good_data.txt", unpack=True) + xarray_chi, yarray_chi = load_data("good_data.chi", unpack=True) + xarray_xy, yarray_xy = load_data("good_data.xy", unpack=True) + xarray_txt, yarray_txt = load_data("good_data.txt", unpack=True) with pytest.raises(ValueError): - xarray_txt, yarray_txt = loadData("unreadable_file.txt", unpack=True) + xarray_txt, yarray_txt = load_data("unreadable_file.txt", unpack=True) with pytest.raises(ValueError): - xarray_pkl, yarray_pkl = loadData("binary.pkl", unpack=True) + xarray_pkl, yarray_pkl = load_data("binary.pkl", unpack=True) From d9172d00a000ee3c694f4d377ff46ecbac2ca734 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:51:13 -0500 Subject: [PATCH 33/77] news --- news/package-update030.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 news/package-update030.rst diff --git a/news/package-update030.rst b/news/package-update030.rst new file mode 100644 index 0000000..d8fdd79 --- /dev/null +++ b/news/package-update030.rst @@ -0,0 +1,24 @@ +**Added:** + +* Updated package standards to scikit-package 0.3.0. +* Added ``cookiecutter.json`` file for the ``package update`` command. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From e813667f450c1a2c35a3253df11bc5f04d518263 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 15 Feb 2026 17:52:33 +0000 Subject: [PATCH 34/77] [pre-commit.ci] auto fixes from pre-commit hooks --- src/diffpy/labpdfproc/functions.py | 29 +++++++++++----------- src/diffpy/labpdfproc/tools.py | 40 ++++++++++++++++-------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/diffpy/labpdfproc/functions.py b/src/diffpy/labpdfproc/functions.py index 5972349..7ecd126 100644 --- a/src/diffpy/labpdfproc/functions.py +++ b/src/diffpy/labpdfproc/functions.py @@ -40,8 +40,8 @@ def __init__( self._get_grid_points() def _get_grid_points(self): - """Given a radius and a grid size, return a grid of points to uniformly - sample that circle.""" + """Given a radius and a grid size, return a grid of points to + uniformly sample that circle.""" xs = np.linspace(-self.radius, self.radius, self.npoints) ys = np.linspace(-self.radius, self.radius, self.npoints) self.grid = { @@ -50,8 +50,8 @@ def _get_grid_points(self): self.total_points_in_grid = len(self.grid) def _get_entry_exit_coordinates(self, coordinate, angle): - """Get the coordinates where the beam enters and leaves the circle for - a given angle and grid point. + """Get the coordinates where the beam enters and leaves the + circle for a given angle and grid point. It is calculated in the following way: For the entry coordinate, @@ -108,8 +108,9 @@ def _get_entry_exit_coordinates(self, coordinate, angle): return entry_point, exit_point def _get_path_length(self, grid_point, angle): - """Return the path length of a horizontal line entering the circle at - the same height to the grid point then exiting at angle. + """Return the path length of a horizontal line entering the + circle at the same height to the grid point then exiting at + angle. Parameters ---------- @@ -136,8 +137,8 @@ def _get_path_length(self, grid_point, angle): return total_distance, primary_distance, secondary_distance def set_distances_at_angle(self, angle): - """Given an angle, set the distances from the grid points to the entry - and exit coordinates. + """Given an angle, set the distances from the grid points to the + entry and exit coordinates. Parameters ---------- @@ -170,8 +171,8 @@ def set_muls_at_angle(self, angle): def _cve_brute_force(input_pattern, mud): - """Compute cve for the given mud on a global grid using the brute-force - method. + """Compute cve for the given mud on a global grid using the brute- + force method. Assume mu=mud/2, given that the same mu*D yields the same cve and D/2=1. @@ -202,8 +203,8 @@ def _cve_brute_force(input_pattern, mud): def _cve_polynomial_interpolation(input_pattern, mud): - """Compute cve using polynomial interpolation method, default to brute- - force computation if mu*D is out of the range (0.5 to 7).""" + """Compute cve using polynomial interpolation method, default to + brute- force computation if mu*D is out of the range (0.5 to 7).""" if mud > 7 or mud < 0.5: warnings.warn( f"Input mu*D = {mud} is out of the acceptable range " @@ -286,8 +287,8 @@ def compute_cve( def apply_corr(input_pattern, absorption_correction): - """Apply absorption correction to the given diffraction object with the - correction diffraction object. + """Apply absorption correction to the given diffraction object with + the correction diffraction object. Parameters ---------- diff --git a/src/diffpy/labpdfproc/tools.py b/src/diffpy/labpdfproc/tools.py index 0184f9f..01c4a0e 100644 --- a/src/diffpy/labpdfproc/tools.py +++ b/src/diffpy/labpdfproc/tools.py @@ -76,7 +76,8 @@ def set_output_directory(args): def _expand_user_input(args): - """Expand the list of inputs by adding files from file lists and wildcards. + """Expand the list of inputs by adding files from file lists and + wildcards. Parameters ---------- @@ -112,9 +113,9 @@ def _expand_user_input(args): def set_input_lists(args): - """Set input directory and files. It takes cli inputs, checks if they are - files or directories and creates a list of files to be processed which is - stored in the args Namespace. + """Set input directory and files. It takes cli inputs, checks if + they are files or directories and creates a list of files to be + processed which is stored in the args Namespace. Parameters ---------- @@ -293,8 +294,8 @@ def set_wavelength(args): def set_xtype(args): - """Set the xtype based on the given input arguments, raise an error if - xtype is not one of {*XQUANTITIES, }. + """Set the xtype based on the given input arguments, raise an error + if xtype is not one of {*XQUANTITIES, }. Parameters ---------- @@ -349,8 +350,8 @@ def _parse_theoretical_input(input_str): def _set_theoretical_mud_from_density(args): - """Theoretical estimation of mu*D from sample composition, energy, and - sample mass density.""" + """Theoretical estimation of mu*D from sample composition, energy, + and sample mass density.""" args = normalize_wavelength(args) if args.wavelength is None: args = load_wavelength_from_config_file(args) @@ -368,8 +369,8 @@ def _set_theoretical_mud_from_density(args): def _set_theoretical_mud_from_packing(args): - """Theoretical estimation of mu*D from sample composition, energy, and - packing fraction.""" + """Theoretical estimation of mu*D from sample composition, energy, + and packing fraction.""" sample_composition, energy, packing_fraction = _parse_theoretical_input( args.theoretical_from_packing ) @@ -424,8 +425,8 @@ def _load_key_value_pair(s): def load_user_metadata(args): - """Load user metadata into args, raise ValueError if it is in incorrect - format. + """Load user metadata into args, raise ValueError if it is in + incorrect format. Parameters ---------- @@ -465,8 +466,9 @@ def load_user_metadata(args): def load_user_info(args): """Load user info into args. If none is provided, call - check_and_build_global_config function from diffpy.utils to prompt the user - for inputs. Otherwise, call get_user_info with the provided arguments. + check_and_build_global_config function from diffpy.utils to prompt + the user for inputs. Otherwise, call get_user_info with the provided + arguments. Parameters ---------- @@ -513,9 +515,9 @@ def load_package_info(args): def preprocessing_args(args): - """Perform preprocessing on the provided args. The process includes loading - package and user information, setting input, output, wavelength, anode - type, xtype, mu*D, and loading user metadata. + """Perform preprocessing on the provided args. The process includes + loading package and user information, setting input, output, + wavelength, anode type, xtype, mu*D, and loading user metadata. Parameters ---------- @@ -541,8 +543,8 @@ def preprocessing_args(args): # Update load_metadata to use 'input_directory' consistently: def load_metadata(args, filepath): - """Load the relevant metadata from args to write into the header of the - output files. + """Load the relevant metadata from args to write into the header of + the output files. Parameters ---------- From 8c2be79382ba05bdfc4ace4827db0b510cda8f0c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Sun, 15 Feb 2026 12:56:11 -0500 Subject: [PATCH 35/77] rm unnecessary requirement files, add gooey as dependency in tests.txt --- requirements/README.txt | 11 ----------- requirements/conda.txt | 1 + requirements/requirements-dev.txt | 20 -------------------- requirements/tests.txt | 1 + 4 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 requirements/README.txt delete mode 100644 requirements/requirements-dev.txt diff --git a/requirements/README.txt b/requirements/README.txt deleted file mode 100644 index 3de372a..0000000 --- a/requirements/README.txt +++ /dev/null @@ -1,11 +0,0 @@ -# YOU MAY DELETE THIS FILE AFTER SETTING UP DEPENDENCIES! -# -# This directory is where you should place your project dependencies. -# "pip.txt" should contain all required packages not available on conda. -# All other files should contain only packages available to download from conda. -# build.txt should contain all packages required to build (not run) the project. -# run.txt should contain all packages (including optional packages) required for a user to run the program. -# test.txt should contain all packages required for the testing suite and to ensure all tests pass. -# docs.txt should contain all packages required for building the package documentation page. -# -# YOU MAY DELETE THIS FILE AFTER SETTING UP DEPENDENCIES! diff --git a/requirements/conda.txt b/requirements/conda.txt index 5aef5a8..e687e1c 100644 --- a/requirements/conda.txt +++ b/requirements/conda.txt @@ -3,3 +3,4 @@ diffpy.utils pandas scipy wxpython +gooey diff --git a/requirements/requirements-dev.txt b/requirements/requirements-dev.txt deleted file mode 100644 index c601d11..0000000 --- a/requirements/requirements-dev.txt +++ /dev/null @@ -1,20 +0,0 @@ -# These are required for developing the package (running the tests, building -# the documentation) but not necessarily required for _using_ it. -black -codecov -coverage -flake8 -isort -nbstripout -pre-commit -pre-commit-hooks -pytest -pytest-mock -sphinx -twine -# These are dependencies of various sphinx extensions for documentation. -ipython -matplotlib -numpydoc -sphinx-copybutton -sphinx_rtd_theme diff --git a/requirements/tests.txt b/requirements/tests.txt index d9d0c8c..7d48144 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -5,3 +5,4 @@ coverage pytest-cov pytest-env pytest-mock +gooey From 9febcfacb80196caed13e95d97c4a68fb703318f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Feb 2026 09:25:21 -0500 Subject: [PATCH 36/77] rm gooey fro tests.txt and conda.txt --- requirements/conda.txt | 1 - requirements/tests.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/requirements/conda.txt b/requirements/conda.txt index e687e1c..5aef5a8 100644 --- a/requirements/conda.txt +++ b/requirements/conda.txt @@ -3,4 +3,3 @@ diffpy.utils pandas scipy wxpython -gooey diff --git a/requirements/tests.txt b/requirements/tests.txt index 7d48144..d9d0c8c 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -5,4 +5,3 @@ coverage pytest-cov pytest-env pytest-mock -gooey From 1553ad8613bc711f88f68c5468c195f8e0b3b718 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Feb 2026 09:25:49 -0500 Subject: [PATCH 37/77] revert back tests-on-pr --- .github/workflows/tests-on-pr.yml | 54 ++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 7dc796d..db5cacf 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -1,15 +1,53 @@ name: Tests on PR on: + push: + branches: + - main pull_request: workflow_dispatch: jobs: - tests-on-pr: - uses: scikit-package/release-scripts/.github/workflows/_tests-on-pr.yml@v0 - with: - project: diffpy.labpdfproc - c_extension: false - headless: false - secrets: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + validate: + defaults: + run: + shell: bash -l {0} + + runs-on: ubuntu-latest + steps: + - name: Check out diffpy.labpdfproc repository + uses: actions/checkout@v4 + + - name: Initialize miniconda + uses: conda-incubator/setup-miniconda@v3 + with: + activate-environment: test + auto-update-conda: true + environment-file: environment.yml + auto-activate-base: false + python-version: 3.13 + + - name: Conda config + run: >- + conda config --set always_yes yes + --set changeps1 no + + - name: Install diffpy.labpdfproc and requirements + run: | + conda install --file requirements/tests.txt + conda install --file requirements/conda.txt + pip install gooey + python -m pip install . --no-deps + + - name: Validate diffpy.labpdfproc + run: | + pytest --cov + coverage report -m + codecov + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + verbose: true + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} From 1d77dbb917448e219d3e6dd7d5defb8bbb4fb6ec Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Feb 2026 15:57:02 -0500 Subject: [PATCH 38/77] update reference for new published paper --- README.rst | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index facbcad..30380d1 100644 --- a/README.rst +++ b/README.rst @@ -49,15 +49,19 @@ which is the most common geometry for lab PDF measurements. The theory is described in the following paper: -Chen, Y., Schertenleib, T., Yang, A., Schouwink, P., Queen, W.L. and Billinge, S.J.L., -An Absorption Correction for Reliable Pair-Distribution Functions from Low Energy x-ray Sources. -Arxiv.org. https://doi.org/10.48550/arXiv.2504.12499 + Chen, Y., Schertenleib, T., Yang, A., Schouwink, P., Queen, W. L., and Billinge, S. J. L. + *Absorption Correction for Reliable Pair Distribution Functions from Low Energy X-ray Sources*. + Crystal Growth & Design, 2026, 26 (3), 1036–1047. + https://doi.org/10.1021/acs.cgd.5c00551 + The related experimental data acquisition protocols are described in the following paper: -Schertenleib, T., Schmuckler, D., Chen, Y., Jin, G.B., Queen, W.L. and Billinge, S.J.L. (2025), -Testing Protocols for Obtaining Reliable Pair Distribution Functions from Laboratory X-Ray Sources Using PDFgetX3. -Chem. Methods 2500001. https://doi.org/10.1002/cmtd.202500001 + Schertenleib, T., Schmuckler, D., Chen, Y., Jin, G. B., Queen, W. L., and Billinge, S. J. L. (2025). + *Testing Protocols for Obtaining Reliable Pair Distribution Functions from Laboratory X-Ray Sources Using PDFgetX3*. + Chem. Methods, 2500001. + https://doi.org/10.1002/cmtd.202500001 + For more information about the diffpy.labpdfproc library, please consult our `online documentation `_. @@ -66,7 +70,10 @@ Citation If you use diffpy.labpdfproc in a scientific publication, we would like you to cite this package as - diffpy.labpdfproc Package, https://github.com/diffpy/diffpy.labpdfproc + Chen, Y., Schertenleib, T., Yang, A., Schouwink, P., Queen, W. L., and Billinge, S. J. L. + *Absorption Correction for Reliable Pair Distribution Functions from Low Energy X-ray Sources*. + Crystal Growth & Design, 2026, 26 (3), 1036–1047. + https://doi.org/10.1021/acs.cgd.5c00551 Installation ------------ From 0a016748ca3e364f7ae764c29692743854b4882c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Feb 2026 15:57:31 -0500 Subject: [PATCH 39/77] news --- news/update-ref.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/update-ref.rst diff --git a/news/update-ref.rst b/news/update-ref.rst new file mode 100644 index 0000000..c8175ec --- /dev/null +++ b/news/update-ref.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added published reference to ``README.rst``. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 2b65c555f4f3ac6b565bd697df155f418a9fa8e1 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Feb 2026 16:00:13 -0500 Subject: [PATCH 40/77] minor formating change --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 30380d1..da278ac 100644 --- a/README.rst +++ b/README.rst @@ -70,7 +70,7 @@ Citation If you use diffpy.labpdfproc in a scientific publication, we would like you to cite this package as - Chen, Y., Schertenleib, T., Yang, A., Schouwink, P., Queen, W. L., and Billinge, S. J. L. + Chen, Y., Schertenleib, T., Yang, A., Schouwink, P., Queen, W. L., and Billinge, S. J. L., *Absorption Correction for Reliable Pair Distribution Functions from Low Energy X-ray Sources*. Crystal Growth & Design, 2026, 26 (3), 1036–1047. https://doi.org/10.1021/acs.cgd.5c00551 From 6635518a7dee2570f7c4b506368368b8ddd1566a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 17 Feb 2026 16:00:46 -0500 Subject: [PATCH 41/77] minor formatting pt 2 --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index da278ac..48b6c98 100644 --- a/README.rst +++ b/README.rst @@ -49,7 +49,7 @@ which is the most common geometry for lab PDF measurements. The theory is described in the following paper: - Chen, Y., Schertenleib, T., Yang, A., Schouwink, P., Queen, W. L., and Billinge, S. J. L. + Chen, Y., Schertenleib, T., Yang, A., Schouwink, P., Queen, W. L., and Billinge, S. J. L., *Absorption Correction for Reliable Pair Distribution Functions from Low Energy X-ray Sources*. Crystal Growth & Design, 2026, 26 (3), 1036–1047. https://doi.org/10.1021/acs.cgd.5c00551 From 68453245d453b9c7be8f33400363076d42d7f01a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 10:22:18 -0500 Subject: [PATCH 42/77] rm duplicated workflow --- .../matrix-and-codecov-on-merge-to-main.yml | 62 ------------------- 1 file changed, 62 deletions(-) delete mode 100644 .github/workflows/matrix-and-codecov-on-merge-to-main.yml diff --git a/.github/workflows/matrix-and-codecov-on-merge-to-main.yml b/.github/workflows/matrix-and-codecov-on-merge-to-main.yml deleted file mode 100644 index 3114aa2..0000000 --- a/.github/workflows/matrix-and-codecov-on-merge-to-main.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: CI - -on: - push: - branches: - - main - release: - types: - - prereleased - - published - workflow_dispatch: - -jobs: - matrix-coverage: - defaults: - run: - shell: bash -l {0} - - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-13, macos-14] - python-version: ["3.11", "3.12", "3.13"] - env: - LATEST_PYTHON_VERSION: "3.13" - steps: - - name: Check out diffpy.labpdfproc - uses: actions/checkout@v4 - - - name: Initialize miniconda - uses: conda-incubator/setup-miniconda@v3 - with: - activate-environment: test - auto-update-conda: true - environment-file: environment.yml - auto-activate-base: false - python-version: ${{ matrix.python-version }} - - - name: Conda config - run: >- - conda config --set always_yes yes - --set changeps1 no - - - name: Install diffpy.labpdfproc and requirements - run: | - conda install --file requirements/tests.txt - conda install --file requirements/conda.txt - pip install gooey - python -m pip install . --no-deps - - - name: Validate diffpy.labpdfproc - run: | - pytest --cov - coverage report -m - codecov - - - name: Upload coverage to Codecov - if: matrix.os == 'ubuntu-latest' && matrix.python-version == env.LATEST_PYTHON_VERSION - uses: codecov/codecov-action@v4 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 3fbb01a22a964e9fea1cd2f0a04c2fbf24c8563c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 10:22:33 -0500 Subject: [PATCH 43/77] add 'labpdf' as cli entry point --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index a55f107..cd5ddc9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ dirty_template = "{tag}" [project.scripts] labpdfproc = "diffpy.labpdfproc.labpdfprocapp:main" +labpdf = "diffpy.labpdfproc.labpdfprocapp:main" [tool.setuptools.packages.find] where = ["src"] # list of folders that contain the packages (["."] by default) From caaf3e73704bc1017a52316b2e283a431f4e8e10 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 10:44:54 -0500 Subject: [PATCH 44/77] add condition to remove colors when running GOOEY --- src/diffpy/labpdfproc/labpdfprocapp.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index e5575ec..e5dd808 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -1,4 +1,5 @@ import argparse +import os import sys from gooey import Gooey, GooeyParser @@ -15,6 +16,17 @@ from diffpy.utils.parsers import load_data +def _running_in_gui(): + """Determine if the application is running in a GUI environment. + + This function checks if the standard output (sys.stdout) is + connected to a terminal. If not, it assumes the application is + running in a GUI environment, such as when launched by Gooey. This + is used to prevent ANSI escape sequences from rendering in the GUI. + """ + return not sys.stdout.isatty() + + def _add_common_args(parser, use_gui=False): parser.add_argument( "-w", @@ -172,6 +184,13 @@ def apply_absorption_correction(args): def create_parser(use_gui=False): Parser = GooeyParser if use_gui else argparse.ArgumentParser + + # Force no colors when gui is running to avoid ANSI escape codes + # in Gooey output + if use_gui or _running_in_gui(): + os.environ["NO_COLOR"] = "1" + os.environ["CLICOLOR"] = "0" + parser = Parser( prog="labpdfproc", description=( From d63b678137b46f7f6e46540a4bacf74827968f0a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 10:45:52 -0500 Subject: [PATCH 45/77] remove entrypoint to ensure Gooey renders nicely --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index cd5ddc9..a55f107 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,6 @@ dirty_template = "{tag}" [project.scripts] labpdfproc = "diffpy.labpdfproc.labpdfprocapp:main" -labpdf = "diffpy.labpdfproc.labpdfprocapp:main" [tool.setuptools.packages.find] where = ["src"] # list of folders that contain the packages (["."] by default) From c73c2828480eaf990c64ce849857fcbbaa956c13 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 13:26:30 -0500 Subject: [PATCH 46/77] behavior: if no wavelength is specified, ValueError is raised instead of print statement --- src/diffpy/labpdfproc/tools.py | 35 +++++++++++------- tests/test_tools.py | 65 ++++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/src/diffpy/labpdfproc/tools.py b/src/diffpy/labpdfproc/tools.py index 01c4a0e..a46667d 100644 --- a/src/diffpy/labpdfproc/tools.py +++ b/src/diffpy/labpdfproc/tools.py @@ -224,12 +224,28 @@ def load_wavelength_from_config_file(args): args : argparse.Namespace The updated arguments with the updated wavelength and anode type. """ - global_config = _load_config(Path().home() / "diffpyconfig.json") - local_config = _load_config(Path().cwd() / "diffpyconfig.json") - local_has_data = local_config and "wavelength" in local_config - global_has_data = global_config and "wavelength" in global_config - if not local_has_data and not global_has_data: - print( + + if args.wavelength is not None: + return normalize_wavelength(args) + + global_config_file = _load_config(Path().home() / "diffpyconfig.json") + local_config_file = _load_config(Path().cwd() / "diffpyconfig.json") + config_file = None + if ( + isinstance(local_config_file, dict) + and "wavelength" in local_config_file + ): + config_file = local_config_file + elif ( + isinstance(global_config_file, dict) + and "wavelength" in global_config_file + ): + config_file = global_config_file + if config_file is not None: + args.wavelength = config_file.get("wavelength") + return normalize_wavelength(args) + else: + raise ValueError( "No configuration file was found containing information " "about the wavelength or anode type. \n" "You can add the wavelength or anode type " @@ -240,13 +256,6 @@ def load_wavelength_from_config_file(args): "For more information, please refer to www.diffpy.org/" "diffpy.labpdfproc/examples/toolsexample.html" ) - if args.wavelength is not None: - return normalize_wavelength(args) - config = local_config if local_has_data else global_config - if config: - args.wavelength = config.get("wavelength") - return normalize_wavelength(args) - return args def set_wavelength(args): diff --git a/tests/test_tools.py b/tests/test_tools.py index 05ff84d..a6c27b1 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -311,6 +311,69 @@ def test_load_wavelength_from_config_file_with_local_conf_file( assert actual_args.wavelength == expected["wavelength"] +@pytest.mark.parametrize( + "local_config, home_config", + [ + # C1: no config files exist + # expected: raise ValueError + (None, None), + # C2: local config is empty, no home config + # expected: raise ValueError + ({}, None), + # C3: no local config, home config is empty + # expected: raise ValueError + (None, {}), + # C4: both config files are empty + # expected: raise ValueError + ({}, {}), + ], +) +def test_load_wavelength_from_config_file_without_conf_files_bad( + mocker, + user_filesystem, + local_config, + home_config, +): + # User tries to correct data without specifying wavelength and + # no config files + # with wavelength exist -- expected to raise ValueError + cwd = Path(user_filesystem) + home_dir = cwd / "home_dir" + mocker.patch("pathlib.Path.home", return_value=home_dir) + os.chdir(cwd) + + local_config_file = cwd / "diffpyconfig.json" + if local_config_file.exists(): + local_config_file.unlink() + home_config_file = home_dir / "diffpyconfig.json" + if home_config_file.exists(): + home_config_file.unlink() + + if local_config is not None: + with open(local_config_file, "w") as f: + json.dump(local_config, f) + if home_config is not None: + with open(home_config_file, "w") as f: + json.dump(home_config, f) + + cli_inputs = ["mud", "data.xy", "2.5"] + actual_args = get_args_cli(cli_inputs) + + msg = re.escape( + "No configuration file was found containing information " + "about the wavelength or anode type. \n" + "You can add the wavelength or anode type " + "to a configuration file on the current computer " + "and it will be automatically associated with " + "subsequent diffpy data by default. \n" + "You will only have to do that once. \n" + "For more information, please refer to www.diffpy.org/" + "diffpy.labpdfproc/examples/toolsexample.html" + ) + with pytest.raises(ValueError, match=msg): + load_wavelength_from_config_file(actual_args) + + @pytest.mark.parametrize( "inputs, expected", [ @@ -318,8 +381,6 @@ def test_load_wavelength_from_config_file_with_local_conf_file( # expect to return args without modification. # This test only checks loading behavior, # not value validation (which is handled by `set_wavelength`). - # C1: no args - ([], {"wavelength": None}), # C1: wavelength provided (["--wavelength", "0.25"], {"wavelength": 0.25}), # C2: anode type provided From 6edcd83406e2d5f787e95a3ec9202e21f5ac4d25 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 14:20:28 -0500 Subject: [PATCH 47/77] add documentation that reflects the new cli --- ...nClose_exported.xy => CeO2_635um_zscan.xy} | 0 .../source/examples/labpdfprocapp-example.rst | 236 ++++++++++++------ docs/source/img/.placeholder | 0 docs/source/img/labpdfproc-gui.jpeg | Bin 0 -> 164976 bytes 4 files changed, 160 insertions(+), 76 deletions(-) rename docs/source/examples/example-data/{CeO2_635um_zscan_200umSlit_chanClose_exported.xy => CeO2_635um_zscan.xy} (100%) delete mode 100644 docs/source/img/.placeholder create mode 100644 docs/source/img/labpdfproc-gui.jpeg diff --git a/docs/source/examples/example-data/CeO2_635um_zscan_200umSlit_chanClose_exported.xy b/docs/source/examples/example-data/CeO2_635um_zscan.xy similarity index 100% rename from docs/source/examples/example-data/CeO2_635um_zscan_200umSlit_chanClose_exported.xy rename to docs/source/examples/example-data/CeO2_635um_zscan.xy diff --git a/docs/source/examples/labpdfprocapp-example.rst b/docs/source/examples/labpdfprocapp-example.rst index a553c8f..3a83ce4 100644 --- a/docs/source/examples/labpdfprocapp-example.rst +++ b/docs/source/examples/labpdfprocapp-example.rst @@ -1,4 +1,3 @@ -.. _labpdfprocapp Example: :tocdepth: -1 @@ -10,121 +9,206 @@ to apply absorption correction to your 1D diffraction data using the command-lin Check ``labpdfproc --help`` for more information. A graphical user interface (GUI) is also available and is designed to be intuitive and easy to use. +There are three ways to correct dirraction data within ``diffpy.labpdfproc``, these are, -1. To use this application, you will need: -(1) your input diffraction data file(s), and (2) information required to compute the muD value. -To launch the GUI, use ``labpdfproc`` or ``labpdfproc --gui``. -Note that the GUI is currently not supported on Python 3.13. +1. ``labpdfproc mud``: Provide the diffraction data file(s) and muD value directly. +2. ``labpdfproc zscan``: Provide the diffraction data file(s) and a z-scan file, which will be used to calculate the muD value. +3. ``labpdfproc sample``: Provide the diffraction data file(s) and information about the sample to calculate the theoretical muD value. +We will go through all three methods in this tutorial. -2. Here we first provide a basic CLI example. -Assume you have an uncorrected diffraction data file named ``zro2_mo.xy`` in the current directory -with a muD of 2.5 on the two-theta x-axis. Then the minimum command would be: +.. admonition:: Example Data -.. code-block:: python + Example data for these examples can be found at: https://github.com/diffpy/diffpy.labpdfproc/tree/main/docs/source/examples/example-data - labpdfproc zro2_mo.xy --mud 2.5 +Launching the Graphical User Interface (GUI) +-------------------------------------------- -3. You must provide at least one file path, and filepath(s) should immediately follow ``labpdfproc``. +To launch the GUI, run one of the following commands in your terminal, -To process multiple files at once in the CLI, separate each file path with a whitespace. -In general, avoid spaces in filenames, but if necessary, enclose them in quotes; otherwise, quotes are optional. -For example, the following is a valid and more complex CLI command: +.. code-block:: bash -.. code-block:: python + labpdfproc + labpdfproc --gui - labpdfproc "SiO2 uncorrected.xy" input_dir file_list.txt ./*.chi data* --mud 2.5 +.. note:: Note that the GUI is currently not supported on Python>=3.12. -This command will process ``"SiO2 uncorrected.xy"``, -all files in the ``input_dir`` directory, all files listed in ``file_list.txt``, -all ``.chi`` files in the current directory, and all files matching the pattern ``data``, -using a muD value of 2.5. -Check ``labpdfproc --help`` to see all supported file types. +This will open the GUI, which should look something like, -In the GUI, you can select multiple individual files via the file browser, but not entire directories. -To include directories, you can either: -(1) create a text file named ``file_list.txt`` containing the desired paths and load it, -(2) manually select all files in a folder, or -(3) enter paths manually separated by a colon with no spaces. +.. image:: ../img/labpdfproc-gui.jpeg + :align: center -We will now continue using ``zro2_mo.xy`` as the example input throughout the rest of this tutorial. +Below we will go through all the commands using the CLI, but the same principles apply to the GUI. +.. note:: The first time you run any of the below commands, + you will be prompted to enter your name, email, and ORCID. This will be + appended to metadata in the output file header for reproducibility and tracking purposes. -4. The muD value is required for absorption correction, and you can specify it in one of the four ways: -.. code-block:: python +``labpdfproc mud`` Command +--------------------------- - # Option 1: Manual value - labpdfproc zro2_mo.xy --mud 2.5 - # Option 2: From a z-scan file - labpdfproc zro2_mo.xy -z zscan.xy - # Option 3: Using sample mass density - labpdfproc zro2_mo.xy -d ZrO2,17.45,1.2 - # Option 4: Using packing fraction - labpdfproc zro2_mo.xy -p ZrO2,17.45,0.2 +If you know the muD value for your sample, you can use the ``labpdfproc mud`` +command to apply absorption correction directly. -Note that you can only use one method at a time. The following examples are not allowed: +To see all the options for this command, type, -.. code-block:: python +.. code-block:: bash - labpdfproc zro2_mo.xy --mud 2.5 -z zscan.xy - labpdfproc zro2_mo.xy --mud 2.5 -d ZrO2,17.45,1.2 + labpdfproc mud -h -If the packing fraction option is not supported at the moment, you can approximate the sample mass density as: -``mass density = packing fraction * material density``, where the material density can be looked up manually. +To run the correction, specify the path to your diffraction data file(s) and the muD value, +.. code-block:: bash -5. You can specify the wavelength in two ways: + labpdfproc mud + labpdfproc mud zro2_mo.xy 2.5 -.. code-block:: python +If the flag ``--wavelength`` is not specified, the program will attempt to fetch +the wavelength from a configuration file. +If the wavelength is not found in the configuration file, a ``ValueError`` +will be raised, prompting you to provide the wavelength either through the CLI or the configuration file. - # Option 1: Manually enter wavelength - labpdfproc zro2_mo.xy --mud 2.5 -w 0.71303 - # Option 2: Use a known anode type - labpdfproc zro2_mo.xy --mud 2.5 -a Mo +To provide the wavelength through the CLI, you can use the ``-w`` or ``--wavelength`` flag followed by the wavelength value in angstroms or the X-ray source. +For example, -Do not use both ``-w`` and ``-a`` at the same time. For example: +.. code-block:: bash -.. code-block:: python + labpdfproc mud zro2_mo.xy 2.5 -w 0.71303 + labpdfproc mud zro2_mo.xy 2.5 -w Mo - labpdfproc zro2_mo.xy --mud 2.5 -w 0.71303 -a Mo +This will then save the corrected file in the same directory as the input file with the name ``zro2_mo_corrected.chi``. -is not valid. This is to avoid confusion when wavelength conflicts with anode type. -To avoid retyping, you can save your wavelength or anode type in a diffpy configuration file. -See full instructions at https://www.diffpy.org/diffpy.labpdfproc/examples/tools_example.html. +To save the correction file, specify the ``-c`` or ``--output-correction`` flag, +.. code-block:: bash -6. You are also encouraged to provide your information (name, email, and orcid) for reproducibility: + labpdfproc mud zro2_mo.xy 2.5 -w 0.71303 -c -.. code-block:: python +This will then save the correction file in the same directory as the input file with the name ``zro2_mo_cve.chi``. - labpdfproc zro2_mo.xy --mud 2.5 -n Joe -e Joe@email.com --orcid 0000-0000-0000-0000 +``labpdfproc zscan`` Command +---------------------------- +The ``labpdfproc zscan`` command allows you to calculate the muD value from a z-scan file and apply absorption correction to your diffraction data. +For more information on what a z-scan is, please see the "Examples --> Linear Absorption Coefficient Examples" +section in the ``diffpy.utils`` documentation: https://www.diffpy.org/diffpy.utils/examples/mu_calc_examples.html. -Alternatively, you can enter this information during the interactive prompts -or save it in your diffpy configuration file. -For more details, refer to https://www.diffpy.org/diffpy.utils/examples/tools_example.html. +To see the options for this command, type, +.. code-block:: bash -7. You can further customize the diffraction correction process using the following options: + labpdfproc zscan -h -- Choose xtype: use ``-x`` to specify your input data's xtype, which will be used for the output. -- Select correction method: use ``-m`` to choose between "brute_force" or "polynomial_interpolation" (faster and preferred for muD 0.5-7). -- Specify output directory: use ``-o`` to save the corrected file(s) to a specific folder. -- Add custom metadata: use ``-u`` to provide key-value pair for information tracking (e.g., experimental details). -- Output the cve file: use ``-c`` to export the cve file along with the corrected data. -- Overwrite existing files: use ``-f`` to replace any previous corrected files with the same names. +To run this command, provide the path to your diffraction data file(s) and the z-scan file, +.. code-block:: bash -8. To summarize, a full command might look like this: + labpdfproc zscan + labpdfproc zscan CeO2_635um_accum_0.xy CeO2_635um_zscan.xy -.. code-block:: python +Like the ``labpdfproc mud`` command, you can also specify the +wavelength or source type using the ``-w`` flag if it's not found in the configuration file, - labpdfproc zro2_mo.xy --mud 2.5 -w 0.71303 -n Joe -x q -m brute_force -o results -u "facility=NSLS II" beamline=28ID-2 -c -f +.. code-block:: bash -After running the command, check your output folder (in this case, ``results``) -for the corrected data file and cve file (if ``-c`` was used). -In this example, the corrected and cve files are called ``zro2_mo_corrected.chi`` and ``zro2_mo_cve.chi``. -The headers include all the arguments you provided -—such as diffraction settings, personal information, and metadata—making it easy to track your analysis. + labpdfproc zscan CeO2_635um_accum_0.xy CeO2_635um_zscan.xy -w 0.71303 + labpdfproc zscan CeO2_635um_accum_0.xy CeO2_635um_zscan.xy -w Mo + +This will save the corrected file in the same directory as the input file with the name ``CeO2_635um_accum_0.chi``. + +To save the correction file, specify the ``-c`` or ``--output-correction`` flag, + +.. code-block:: bash + + labpdfproc zscan CeO2_635um_accum_0.xy CeO2_635um_zscan.xy -w 0.71303 -c + +This will then save the correction file in the same directory as the input file with the name ``CeO2_635um_accum_0_cve.chi``. + +``labpdfproc sample`` Command +----------------------------- + +The ``labpdfproc sample`` command allows you to calculate the muD value from information +about your sample and apply absorption correction to your diffraction data. + +To see the options for this command, type, + +.. code-block:: bash + + labpdfproc sample -h + +To run this command, provide the path to your diffraction data file(s) along with: + +1) ``sample_composition``: The chemical formula of your sample. +2) ``sample_mass_density``: The mass density of your sample in g/cm^3. If you don't know the mass density, a good approximation is typically ~1/3 of the theoretical packing fraction. +3) ``diameter``: The outer diameter of your capillary. + +.. code-block:: bash + + labpdfproc sample + labpdfproc sample zro2_mo.xy ZrO2 17.45 1.2 + +Once again, you can specify the wavelength or source type using the ``-w`` flag if it's not found in the configuration file, + +.. code-block:: bash + + labpdfproc sample zro2_mo.xy ZrO2 17.45 1.2 -w 0.71303 + labpdfproc sample zro2_mo.xy ZrO2 17.45 1.2 -w Mo + +This will save the corrected file in the same directory as the input file with the name ``zro2_mo.chi``. + +To save the correction file, specify the ``-c`` or ``--output-correction`` flag, + +.. code-block:: bash + + labpdfproc sample zro2_mo.xy ZrO2 17.45 1.2 -w 0.71303 -c + +This will then save the correction file in the same directory as the input file with the name ``zro2_mo_cve.chi``. + +Additional CLI options +---------------------- + +Below is a summary of all the additional flags that can be used with all three commands, + +- ``-h, --help`` + Show this help message and exit. + +- ``-w, --wavelength WAVELENGTH`` + X-ray wavelength in angstroms (numeric) or X-ray source name. + Allowed: ``Ag``, ``AgKa1``, ``AgKa1Ka2``, ``Cu``, ``CuKa1``, ``CuKa1Ka2``, ``Mo``, ``MoKa1``, ``MoKa1Ka2``. + Will be loaded from config files if not specified. + +- ``-x, --xtype XTYPE`` + X-axis type (default: ``tth``). Allowed values: ``angle``, ``tth``, ``twotheta``, ``2theta``, ``d``, ``dspace``, ``q``. + +- ``-m, --method {brute_force, polynomial_interpolation}`` + Method for cylindrical volume element (CVE) calculation (default: ``polynomial_interpolation``). + Allowed methods: ``brute_force``, ``polynomial_interpolation``. + +- ``-o, --output-directory OUTPUT_DIRECTORY`` + Directory to save corrected files (created if needed). Defaults to current directory. + +- ``-f, --force`` + Overwrite existing files. + +- ``-c, --output-correction`` + Also output the absorption correction to a separate file. + +- ``-u, --user-metadata KEY=VALUE [KEY=VALUE ...]`` + Specify key-value pairs to be loaded into metadata. Format: ``key=value``. + - Separate multiple pairs with whitespace. + - No spaces before or after ``=``. + - Avoid using ``=`` in keys. Only the first ``=`` separates key and value. + - If a key or value contains whitespace, enclose it in quotes. + Examples: + ``facility='NSLS II', beamline=28ID-2, 'favorite color'=blue``. + +- ``--username USERNAME`` + Your name (optional, for dataset credit). Will be loaded from config files if not specified. + +- ``--email EMAIL`` + Your email (optional, for dataset credit). Will be loaded from config files if not specified. + +- ``--orcid ORCID`` + Your ORCID ID (optional, for dataset credit). Will be loaded from config files if not specified. diff --git a/docs/source/img/.placeholder b/docs/source/img/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/docs/source/img/labpdfproc-gui.jpeg b/docs/source/img/labpdfproc-gui.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9dc8de824c4a5a666f7dd4c33fc98284ed903a43 GIT binary patch literal 164976 zcmeFYcT`kOmp6Kv93|%{IinIK2gx9kbB;~UG#Nz6IVuQ928oh0l0ifyOQstTk<<+W ztrBkgJn!RtGi%*hv%YoL{BdWhyH5RjpIy6Z*Qu(rt9JG6=i4oSSY267832I*Ko#`? zZlQps5(MlB09slA4*&o-04Np=V4x6+1)xPm06@=(0kBaiDJnjCjrPx741w3^|6uf^ z-;DBlifU@8RL{=G!NJ4V+0*a#2oQgQN__6hI7BLh-@*v*sVOR2J<-)xR?}4atICATHeOzCXv6^E?&0U7tD?YcY+}lc z{S80^=m1=R4dAu0^YxN{@2G}X8{7VcF;JSIc=UA@ z0RV#y)%XN9Ha<=OKyVL5XAZD)LdhZcUDiDhd$0!zN20KdySt}73co{PE)&O3>7k4**RD1muI8j#uXCGBv zR7#C%vmIAYjX&7K_ObRqbTCT0f3UN^s=+_l&Q}rDmVf8=^D{s;TI>iwxtu(RSHx{tr^A6*t$#2Z}oTZkpDNCzQ%v*X7BJw=^uUv4}(AYdig2*Da*_4uW|BMTRFI?{Gs~> z=>5s-hw7aF$no-f@}~`5Y}9}E%fIphj{qe=6ZK&R41foK2rAw~(RBSBAgKNe0E(Vo zK|Ww7XFq0n)QEFnR`akE;A4Jp?|~=){2sr*c>v%{_pfmYqU`%Onr9iRTVJ5YPx`;n zY_kBMJqA_u%D>Ur3ITxV8342m+WGqg{4EdTcY+Dv0Ym^fKm#xWtN<6lkE)v}APLB! zYOD@u1NwjoU3hK@#nMvlgS#(^e?CXObLrh%r9W`X8} z=8YDN_6#ir?FCv1S}j@|+5p-l+5*}Z+5y@*I)ILkPKkaOogZBsT@hUy-4xvs-3L7! zJpnxjy#&1;y$gK|eGYvK{Sf^J1{MYx1~Udfh9rh6h5?2hhBrnyMiNFIMioXI#xTYl z1{4F1af3;SNsq~kDS@emX^iQF8HgE!nS)t@*@`)Wxq!Kgd4Yw6MTy0UC5EMnWrF2` z6@rz7Re;ri^$u$WYa8nv8ylMjn-^OeTN~R3+YdVi`z3ZQc0cwk_AWLO2OozC=K+o~ zjwy}@&QqKmoHsaqII}o=IKOa-aoKStaJ6ymaf5JEam#SKaHny1aev{F;Bn$frRz^lg_!CS*S!^g*G!GDOagAc}!#D9U`h(C@G#s5J-O29*)NMKIjPmn@TN$`$f znc$3&kdT8=j?k3Qk1&O>nsA74gAjR#?2f=4wLA8ABJSkhX}dFf=a>kWh@D8D$dV|S zD2J$-XqxDd7?+rXSdrLqr}(@E0V(IwC|(XG&<(eu#j(udHO(tn^oXJBMdVen#j z$uPul$Vka3$LPYC#n{KV&qT%~!vto^V(Mr5#!SI1&+Nwhf_a!3ewY5P>Rtc4#dkm6 z{l&t`V!-m0rGaIg6^~V%)sZ!eb&wU##>A$@7Rpw`w!)6fF3#@Ep36SQe#ybfVZ;&3 z(a!OelbTbFGnli6bB&9TOP0%?;)QDUkTq5KLNiye*k|CKU9EHKvUqUK)b-PAe*46V7lO#;LSaedv5p2?ycS@ zy{~@%>HV(zrw@1@*geR9FfT+Xq%0I6)FFfr<`s4jE)@POLMEam5-Tz&axE$*>LXe& zx-Z5iW-azgY)PD4{E2vy`1nK2hYAlP9`-!^At5T^C($HvBFQi5D)~n8s}!e{gH)N+ zwls^hjdZc}mJG9uwajaoE!n%WHnJtMFgaE^d$|g^J$Y_<7x`NGV}*MPJ_@Z0mx>aK zVT$h_p+8c2l~s)lO1>XI6Rnw?s;8eCmW zJxqOAgFr)1BToaS$)o9`*`veZdh%2Y4pe_!)VJ`&^XL^(uCFo zY|>$hZE9#*VR~++WR`8VYc66QW4>s?X#ugAu%xwgv+T7Zva+#iw#KwJvVLQIWut9V zVsmb*X8Xz(Zl`FMYj>C)k)eZ(`nyX);Y)d5UdE!10!5i zU5Z>TUA0{+U2olt+#1|*+^yX^JxD!VJ%&9QJt3YmUc6p0UR&N0-r3%89}S-hUy!eb zZ-*Z_%24{?&*lHz9~vMNkRN~yGz@HpkU%^jAA)#-;)C{rm4nMeFhcA?21Dt=n(_2|v{7`|Glpl8&$gedJgr;^oy9v=xaJ z*OeZXTUEMM!_{Kd)o$n%91+dsNp^&tG5MK-rMk2sHXPetT>EcCksL zX|P$mxxR(Hp2_r8zr0En+;o{TfNXn&<`*@*y^_3_Q8(t&eiU- zFN9xm_L%mnzdrcdv#-4W>6_WN-2<-SeqAOYX^>Sv#D9$aH2S&sEAR^Y>cutpb=Qr?&DyQ|?X8!MkIi4U z06OZ5=7?J3oK^w=p$PzxeF6YHv%l@@zc@gDuL)2X^so4v{2%b&Hu&!wC>sJOT>=38 z5CG7e0)Ur!0KkEgPh<`NPl!--NdQeq=uiAB3u?{sm)-vR2XQR`6dT_ zK~#D%4y(f30Set2IGd2I&r@7HN-Am^T6PXjE^Z!S5m7PmhZ2g9l$2Fe)ztO$4GfJ? z=9!(ngQJr(*u~e+KOhhi6de8Rc}#3vd_qQMR(4MAi7)sdeSXB+IO`W;e8kVcO|74BH|pGO;l=3(HBPprB$v&WlOcB@!!Xfx z5e9XxwK4YdERxX-$Wj&Tw<3q(LUXMQRs$=?nWg>N5g`?pW-EQ(Z9z7E zNqcS7(Ro){tcR;d$HXfWZkl?ET&EjUk7*bl<7KmA(EhMw|L9H4s3gztS+legzPWV^ z#CB?v@@Z+l_xOI8WqWwu-}61Jw&zmTqD4AT6(O4G-r#Jc7Gwh{v=>r&b?+k%^HvN7 z@q0NQc?>k3%D7PNGNj|i!&Xk)Gt$N((vuwBo`TY-sI?4o@67QAn(LRs1xA`kk4xGN zDQ_3kq{}v)alCXF#BfwwpZ7sa+VSJ#vhSD+ zxs2UJ<&aR%5y)C)Ol3Y4Y*|-Ys#SF+{3>r_@~S@6>SsfADw)AVwx!FHtc;x8(DvD1 zR;Awqq^X8(WIkOf1_&c_LL@6NOJnv8OyznCl2X2^(x-O^JRAkpZ}jQGk9tQgc*xNRY+yC_B10G1FgG%Wtz&ZcSw-JCg8s;knC z!}LqJP;J^TQi@pyBVWjuq}XP?4RvRvTNf-puDAvDcxOUS6RtWWC)dC1_O74L?YR?C zFWdqyf-%9C^*`_aXyQo8Ni??elJf@hE_%_$DD8#Xmg>*-uuDbmA!_#B1UJohlq(FrS56D>Ht>% zqke}eR>RpFn%>ch3?<6SYV9yP`p9a^26|OG@D5)F>v&)Bz*pCKXgJsC7wY9F4HT1( z-?dEFna+KG0%W%H$di0<@UL@ZFZ|r^QhpF9-ZR&94`5$-8S_4|ooQ^1pU4z#*2S;c8 ze$^l3hRK8sl$_O zbF6MWhxS$C#l!aJt_A8}zBqf>dcXhStwI{W%0p;OG*cA2Aq&3+hNlUYVABM`Q#Qhv zl;50E--lhy3TvP4AUYpQD+RRvV1Q3TPZHe(qzJLnw;HINZ$w)V`4$_lMqU>m-cqHekNEtuf`WcA~mh6_5Umj>I+O{kJVT&rL4jD{un+%$Bn9N?7pYmz&UU|2^Sp@o{m{@ zFYn8){Th&Pmaipil|Mbtf3#wFzxLT~y7znK;U;dpU~7)Z^Y>gOX_(|Xa{sOIA-JWq zPNajVjFW*IT&Mr;_S5xny^{{yD!MgHNhH}!VNTFZK7rI2(ka5eE zW41gREXIfA68F9{!(FRxfoCBaH;0=@60uu=O67`m#p=@W7I+umkL-G>r~CN9f)LwE zpbA|jnAR|zPO)s+Y*~4auMNSbu3e1-h!k5;{ktr(P{!F?pj+$)L+ch8nV%h+E604C zq0U=kXyvu{Q0q)7N?M+!%Q)>Jx8B zj{Yda1WyG=tfO>9%zy60&$whzUa1hLq4%6Z|P*|#C>7P5XyKipxxEPjAWZ)o0V$uGeOh_~D zvH4xyJssQ$3(8!{iIv|f(Gu{m5b#8O2JZ0$|L+v>_p9W82j~CL!TJB+7nr35tRdbC zqlbdK9U+_G=2mId3z}!kaQHb!*PJ?RFql+vgc+b&R?@)X|J^7$Vn{E1(lTQC7Jv%6 z{}>IQesgpS^z{_<*9BWW4`&Z0MbwsT4l#1S?Jej#M1PX;Fn^yur9J{=I*nW9FbJYkr`j)emLj>=*qpasI=MhcX9euCGcGxPbqOv4IoW zjmRIc!n_h+xlHtk2w`?;e)}xiH<0;;dOkh!f!M>rhWW@~rnn86Pkq!#Aw5KUT#hP<~369>RN?u5{ulANzYWhI(C=bsJ^5sDh)h*y^mC#S&!P%Vf<2xbY1a2kx*lw-p z`-)C%R^b*@n%rpe@NlO&WB4q?SF5CNBbnB(bVAF7Nm940;zz|X`EGy$4X*CPaq)^7 z)3h)pc=SapvIhPJhX2sB$m-Ll$e#hPk2vOUfr*a2I4`%u(L$wiNgWA+4$e|%JioEr?MS z&dBsWZs1$3EU}jgGcBT-zOax*K!2eUwMz)R{AzRmtn7&2HbPb3hy=bjwn8<0f(0%V zg&!QZ%-e1@rdiS$?PhR}A(Y=$pO30w7Zsx$`HbOFdTQNcE*b!7`-JESOW(@^mV64&$*Yuf3D!gCMl1NaGkc^q-PeSfR$( zaV5y&+AEXAqETJ&3F3j(oi#S8_2);fCp~_iP}jCx45 z>{d~5-F57+xQKR~sD|vYG}YtTdMa)B2Sdudko~2AC6d43DXPjZ_~8-!~Si4HWfxrx`=TCMG28G4oVkh!mGC z62OeWy4fUi-GoOSY;Yp2YLUJJMZ_ZPGk%*SlVP5|L>GzUGd$EJhT6Qr>0d+#72fJw zSM-HmSM|GF(Lt8B+7m=%pWVmatjPdNf}flRVPKJNcSQzEb-y*%^37}*2TH^+iG#%(738!=btlCX!9>dSE<$PhqJadQJ$K)FuCNxxWnH& zr4c_3NY0(Y%*w!fWm}l}i^?UOb3qFAnp?ph%S4_GTXMoDk&o%R-6a?}_$9RiHoLe= zos{#Z(By_OF&cRWn&lYA22xj?MrFya6ifEQ*^yc>CS0&3_uQR^;)7(q;FKciYHd;3 zmPs_O<_zQ0@r+kRSrMdr2XB6$Zv`G6A@rd2y`>w-6WC%ote0xAOMFIH`p)9?FOFfk z1lAO@&)bDc-8tfYj~<}uN3O=xheiDN?y3BD@8O`zW6JD@KWT^;+JM9=BQ5N>DZBhw zb^D$`LgG)~@zG-XPgL9wHIWVby@rz%`8Nm-QK=9D~1KF>9Zi-)g*)*~N;M=q%$ z$hJI+p}cej5z5_EKOH(YdDKPC2cJb{re?pJX0!ffl!A;f>xFN$JJjzV#UECf=m%Jf zJIH+K#Qwarazl@-+nSDl8iBi}Bjxu)$WB8>R>hKmh zv~33dPLb}XMTyTzKd$C z0mEW=SL)gnpEczG68=$T`-{QjgxEz8vJ#Ow zQbZc6=nvz7XSeP?PmR42a%*eLO%`c;*>)|+s5>i+W}$UTA=UZxUDD=23;Kb32+U}x z2;T+298xr5%8?#=M9SZKQ|jq{AAA|4PHI9CpK0et{iE%b6IQYrinR{iFja0T)Sv|1 z^=gj2C%`B;xra(nIDvuHxKPRGu$D%jAWa?}s}Hj?c5H(UnT?=!*~BYBh{cPbd{>2( zb0T!gJ#+eCu}iOSjBdIUQc&8d-HE_9u+^p7ueNdC>D4P~L>6uTNJ9)|A6E3(N-t`^ zpobS~;y>2e{G8vDWrmVWdZHWhh4RKO2wJzO7TBl}8Gjk%AI^*B`Rv5 z`OM97(cWolA#G+)YNK9h21HxwTv5Vf`k_qE+TOaPKPu!~Ts*N{qzuivSy@;=-b+z< z$W4%eqb$4o$_0Q$3PSR?JtKuvaUe^>8;pxB{iN$iI@Ng*3l+^de`=1-)I;Kl`w2R9 zs-K#v-|sF(ueSPaP$1K{JZVhLr=iyo>ixOe$xOO2vp?};8yzi11Ri;4DtY<#2r63T zFIu79$he?P(XQO*4Se-QP|u`Le)ewJm_t8kjZ4~USl*IWv^sIu=LtUdUFn^q$)t|N zoXkbH8xrK$2nSayQ49&hN_$3z?%U0s-nr5RzB<$j>TZ#anUaQUNFuAGA{eJVZA=Qa z)AQvPFvL2OV{+KHBJHC;SYbbjZ;_>N&Pz$HXy!jI23M_4gWV=3aVyjaywfC(Z4w?K zU&3M9cSc~yE29$8=Tb3TtxEImQ&|~2&E#gOLhl{%YE=nep@q;Q9fzRUqtYsJ^DDmw zPc1%!^Ol~S^YZf!TYY|V&^6T-&sXPb7Z_Mh<{(8JlU$p(Q$uA)>TWo(&xRD-)}}%} z)uwc@BuG@6Z7quHV_4dS?|!&=(A%1mX~W)gxx|anWJXi*qWJy@TU{&htF}WR%$0Lw z`ZvuM<2gi4>3oZ$F!nM<#z!x%!s0= z!Zp9}r^%6G$`-cn5_>wWZ&SPw)0|nHIhv1bjfK2Uxr|9w*FP>cWL~*L3j&9k$opg= zMnkf9+^>(y7C^P;M!mQh`ps zDUUpxdH#_D%_x&n;-Eqse?wh;0XgfCq$}-h?Pyt2kHZ@l2+Q1nw=0z_iNN=oI?0i# zK>PUOy58*U`qk_l`2Z&EoaMc?U&6k;x%8zTB8#rK0D7oS(Cbi*?q>LRA{c`!%rPD& z&3N#k%`CTZZg1xE$7U)lL4N+@#-#CE0D>v`&YI}0lp@TN5UHY(YmRWNu`AhcOk?Yr z_pobiS6CO*;N>B>n5a$GfC&yA(G6Yn@hwVeml}T!9Ko!w^sO=*a(I}@j^W!Kx7Kz? z^zF3EX@Bw!8G@r6CI}$6AE8`?SL_#k#PcT}4Sp0kE8G=k-4FS4_{t>|#qkz1E>&nCynz|NMXue*a^yB62w<%kV@yFDvh7@TvZUXwEb4goE zleYj!1_M$$z$pC5f0O!ajv8Y=6u(9?Fh$jab@sTSb+S&$jenXHv$ZXc>si9n2dsl_ z;`O>G7r}^;{zK>%6F!($WB-O3J{`}0C0`5fvd^>Ku;TNz$RU{wVi+yr`?iGZRpk7h zGKuj0XJ+&xaNk`d+UnrMc48`-GXmlxpS8$%gE{w^)QDxLKO@{)W#ij@^OR=9Ce$z% zW`zr}JR3F*F-I;tgfSYQ@ULvxCxs^WPtllcUV3E_ux0MjFTFR#9!Ok`ZQhH7c*$g#{ zz}&aIhd8b-LF!5y6pD{5HiP-!X4~82QhfH0al9)(NGdP>jnLC|lQf(GY4X~N3|Xl( zOE{~WT_wo|KF=$6=N?{HTY8prHJfryRnqX<<+hInpS5g#yuQ17cx`{9%e zSF(X6DuI^bq zUgffdl|13pmhbaZmOvr_ZFK90B2frI*ewtlPBK)o201fmpJQF}=kl90Ds;BdVe579 z<%`3(Pe5btWX;N&hxEFlMvj#`-w-FNz>`;zSxAk673F5>qmB3)NWgIz1GzS3ooh&b zN8Uo>i!XD9R`=4D*LV-KSBM4+SrHsj&;pggpWFz-y_g<@GS`g#x09X(m!fSMBoYdj zx=PqD-(G^);_BLIu*pH+s2HW;{FQO;p{)KeX%2>fbBwkX^W0DThhK;8mbMFi=}Q0f zCf%fv8?nPkjR<^t#mSz(CY$7szl!t42(NAQ;~)&#EN}-txb_-IqMUYPO1mIV zL~*o_1Aft3j?6iEx1wD9=9`3Le${};hY0H!wItoR73JqIMvVk|7}sm6;i<#g7)Tgy z{*c7+%W88IHm4_TO}#PS%xD;Vch~sbMn&n9#PtRmrn&{ABA7(NB%fGl3@+suX~Ww` zWhgV&i-rOuycSwj-TS6oD+bDOEZppKL{AG(l^sUSl_u4`F7;#du|sYFja=2a9y;tH z8sYvJ)9I&Iw?OOi1Y>nrRo&~S;x~h*9gXdxA0K7%`GzBpk{ISe7aK1TV$inM3KxmR zWZ2Z5Tj24`M-kM@QhmiWL};39JcB&3_}7l#8zUxa8B$Zz6{~f~>QLIM3l-^#sTN0_ z^V>CZxmETAjt7ya%A34A8Sf#iB8Z5Ta1zug$Sgy4U8*9z3USWD8K$6gVe}jO<>wm9 z^{?}!lU;@0wJoL(?&E(zJUm<7(aGDqF1sPW(m+s_hoJT$Vr8fVp{plY=FV-YuZN(& zObmZIy%1@=`dOwhKeb8-jKCUgaO>l0p0l3cX$3{7clHvITsQ@A0u#{jMe3us)4$#f`xv5T-8IMBwLtPQL9 zEby|oJ zs?oejIYXH5kTu}0p}svEoI$-%o+2Ms#AM8(Pf>iGMwDT&ybVl37-^98TEXnrpKNVxYnp&b!9|DI{&m9oWc|_yQb5M8B&~0npstRk!>BR##W!uINSlg z7nr3>ECf}>5{n5Jg6NIj2)4lcpNbvioPPCky)><>)^l)j4~w>=PkMYJvmZE~9+jPp zFAB0)uZ+L)-s;C#E#FK!zZR5xsuZB+ukqP!CP%t^99#gx?+hfF^P1MNVhN?WF6i-u zd;SW67Q{4!q1^c=i5HNRy%AH{&wMA}Pl&&;^|cwZ$Il%G%2U*}y}MD5XZ68Vk;$&P zVp?!SCc@ip0iB$aQ3=oI5m1)AOZ_F&k7h3_`ku12v9l(u8$V?r9>e9q{t%Kz&0t%eufp?V%t)8FIHrUcZGE$; zx%eS*Bi7Bd;sri>+>LUKJDJH#N+(?g*6Uu{?h86c#S^Q9O zszPkI)=|qKjOLKNTWoH;UPjj@`p{4^Exl{u$4(XS(+XBODvJ@y3BPElK3J)LCE_lt z+`q^#Y|^mR);F&^h|9r^;Ujt>xSLH-^^S4P2y=USMNtvy54DIG31@9-j$yd>_0#?* z2HP3Vd4cm6GqY4GJd1snun)87FLb`3+vXv(Q<(7j?tTljq7|N^f*x9m%96E&IJda# zZy3vUnYVR$wNhT99UE6@^Z1F09^s8wn1uT>;wO8OT~Q&U-|Y9vwk0Z=Y?{u8GpvEX zEm3avrYhzPeZzBko@QZqQ?V9J|VSvt={d-!qQ&opw;M`~}e+lY^DT(pvx* zv((H~1U7zv*{|G1QX8_Hg)_qnS-S;l(Ry`HV3&iggb!9t`w$JW?kxwCFWrvncNg4s zH(X!PxuuPs>fubjQH@2)DoC0q;D?JfuqX9 zmTpIna=s&$pJT-O9k=9T*6ZSM+AGC{^F%^k=u%7~(huqMWH$Xfj+89sj#w^Vv2|yz zag5@f7lo#I5D|vVRRkBECH3m~% zwXcy&FI{ed7QrZ+`5tem=berHpSkfpgkXk+jePGnrp9dDOMDoo2KI+vg<=kNz0A3keo^W~#Xd8c@oZ^^x-QCg~5|8_f_5G+F zf61DV%;8;0+S%0%h zPa?Ul-LX+KCdv_?CNusaFv+*Y2L9>%9+I1##OtQUH4#uzHNtL3BTAd}>C7)|TuLvQ0#BKxX_^3p!b6 zr5$Z(=GmACZq*UVx~CSedorQNHTX=oKu%_P;YRdIXhzB(8WEeja+L9HL$EpTmpa-P zA^~GN=L`YOsQ50hw|lFxrmkG&j>y8-8yUD@Tx-n;eh}3nW#A`si7BYNwl_ac*EF&z-)VCBg51(W1Fj^@4TeZ zHap{KxuPOBQomeI_*9=^N{-13nF>=G>c_U=PfhI6EBTtsch@0S2X#D;jRjg@d)FZy zmsD66WBUu&J16jve}7yd{*2(`c;5yvZrub)#*#*nPJ4T2haKGn?Hg5SpMP?k8%e84 z7k5K?IIH3trj^tYA#l;1Oc>b|d|G90g-B+Us{NN`X${nTQ;jq%&;7-#(J7WAbLFjq zu1)MdG)VKi?O|M4K3$lKj#X?S1$?pS%}I=M-kDZQZ^Eg#NnDQjaKV?nk0x{Fdb_qPiSp07pG{aW&24g@@|NU| zG2%rJry(UgiNW3nmjsh{vX&a_z9+p6IwW1|&l^^d8bpH^iLHO>!)QkeA|!`42>anj zCqv_*R)Mh1m<>93i?3Qp}y*WDTr)3jHy+&9-OEDbkQ3n7eN7 z7pwmBbLLlmg{C}Y-MI@om6Zj(H}9LkkMO?{o9_&H$td=fjVULP$Atys2KG6 z0k<$Ol0TxwzAabRwW{I=TZcTUHshim<)gaR7t!qk(?j86$cG3c^A4mpeC5&#-n;kg zO0XD=HKse~&VO_#=4ae}?TgixPCVAm#5?Kg+R|D;09AiWNG zLE!MHZnt&rOPd7^G~rk>Jwg~SV}x(RtOBN3dS|)87k<%PiO1QiOUFyskhZ_7q|`w$}lbpv}8BW zUulK7hfuVTu1vf8!K=?$f5<4GUP{z&@$MHfB8|*jkoOyqlF*|b)3%!H_&}!$Gh{;G zJgh4l=3soh(;H;!^<&^{IlDPl(pQdd#S^trVfr!E7skLkvO;)~>mU`-F1EN*(6abx zP4j@>Ta8Cmhb_>-Kv&+88I)!S?+Hja%K)_)-84#B4iBK!3ICE21k?CA%tZr+@#e3!Mc-=3H)Wc0$_>{xxY;Ft%KEpq`4DVb2`#lF$mA&4H9g5VN|5qW zIeqIm#CbxOfpmw@M#NdtBIC=$5}2qVW&?R1>t6ruOu7=QiQ5GBG-H$o{<*ou|PzmW45yfZjkBb4QJ*!&@1 zng7#|q&sq3OKKI6vv)ri`$M48bi<}vH|-TqJ^fZ)zjE}p;VBeJVED2@*w8ywL=a9f zGSs1VeO+^&B6W8lM|?d&&}&ngbH5q>D}|r_&&v?z8dYkg9W5QkCNumOnGdyAbIZY@ z!pJ~`&_EGc#(@Uhe<3%fWe-8Imh*GuV`9|^!^p3mnF#A|#Bt}UH_N<^etiaybdA`e zMk0jU#<8W55I4EDac=uLCulq(>%h&^AUbrq1B9JbL)r(sgnEMe znkzr|1ndVK`1+HxyYHkaWTYM5r&Aw551ZZLdMI97C-&Q=;-uES^gWfrId{de=w5qw zZ`-{4m$vqoFPKwIbQR)uOQS+>F<6n ztuVTMWSV+$RMw=dly%AOzWkU{ae{_je~Ye&zK06dt2Yoq78(??rP@PQv55>E3a5`% z>gsIrtzI{C#lM^9d3agK_Eb1ao{aJgkCL4n(-gSIow>P-L?4zgxafWj$yb?gS-;n{ zX=$=KAl+M?L<$4j1*pD{)bL10xEm8 zG15C}XvfnmeY^z4UKI3aR-EO@aMR@0AO5mkP0BLHWgFQo78Xv{Edf?v<6MT7;k zooTq38kZSgmF1{Fww@@fngTz4A0dChbBBwF>7ez|FblCKs6X{Ixu3sCZar%Gr0wbZ zrKy%Lqgg7E+|swoDu+r5vj7qS#`*kMwU)L!??R9QLqvEyYUdz%Oq|Dl_ONLvW6ck5H#cCJGY6O2m&#yNq+3 zS+Yil_==U4oer0`8sZAc7tcMBYQmDeymE;ubHYa=t>-h2OF0_KFGL!9X2Q)9aY%9} zTwiH*zSu%j1AgLN!cvE%C5fn8V+c7mIy0ZGbVHjD?n{baBp|=)jZUGDR0OY8J1fUs)_V|4PFc$ z?S}P|J#Iw#dDaUSHcCA)s3^bLVHuYNQP?NZ*kNX+;iLT0A9wrXLm&Ec#Vi>#xPtw~Rb~~gXw0$(x$1&Xl1A$MjlwgJL1)?P|3eX=a9RJSehm%>9i zuEp*h#^4TX{jm;WWr=x4a>R}dH^M17l$RmjtUubHS6V{tmVCBj;(1IKtT4LG@ zww?Nrt?)p|*;ee>x&}17Xp2r3UrPwpsFgE4A~dt9u@wESb^PoaHCl$3Iwl@TB=4WB z;#1-FGzX<;ei2+{!U<)76%j&)U@~uEl6n|2%nQPt!btmWshyl>onORl&|8P1~j&uo>`(Ip(@{V}eFWNDFt7ZHno zCrJHfR~d>XGGxeT;l0Jyv4|#B#OgQKn*4_a(QmW5r<~=q4xin%?lW1{9<;jC#}mr8 zaK!+t6C3b#P5XLjMIyZay+Gz-5cjCIN2$J|xMEG^A~DYW0|ytm1TIE;EYsb)SwKkc zaQ})gRCcgC6;Hn58=1w}Ht$%|9OvxOPXALi;w;&oNQulZM~Tkt?P6MQMgseIu6*EP zgHr-O8d~`!&MaFJXy)W-pAml(8WFCh{Qf*X*Clq%_%1cYL?{VTg`#MX2>WXhMURLb zYWD#v{$j!s_bPwJoqhO{z`#N4{nwcfkdHW0kt$5mp}I&}1P^NQjq<_v3PR^CIXV%s ziTqM(m5|pP`v?`n7H!83{Suh-@hoh?8d9vUNOzY>VmAu7rfQIFL^i`4^btf?ED}yh zJ+guIKW0~N0f&J%rjsFiirpVl$4v;j=UhE3IxQ-t3AML2>CKR+S%3JVEx^}o2wLZ& zMLf-|+par=L8ieb=R?A1MDkbZ0TyKkTYbE( z7VX#~iYxJ=JE5Mi2+%U5VozaCN~^*O5~xmV@T|?}fU0rL%xVmO@=l(IC5~obpMG)R zha<{!J{;_&pY6k`vB3m+<`O3feijm1ZoJ_5z$&wMO9P0O)!1~+fu{S-0Y2OwzulXS zOWW}B%LHLpcMp@1+F-Y?=UtXkhw)tT)?ke1AADG!;}_IdQnShyF;Vs1xpGAa#3 zAYGx~X+?6Xw+v>#UrP=>fIwDPHo7e)*;7ix-Y5tX_Gqy=uDdBPr@uN$ji;IoRfDsR zN;JgWJTPyFEiOWx+d{1;f{NE#7B|5!z!Cx3H2yEkJ}A>w35cH9Kg7(v8)Z$@7_#pAx&v5I}BaI`1sof2$7goT7{jt1Uvwl+8CZ7>nK z>N>{+sb_cPP&4P5u%M^Kol$r01&g^Le|Jws1S!9wI{Z-|VLaPhIJ?%iT2IhL4J*S) z^fx^hY8)oi5oouZ4SDOYHY6Amq~z~j6Seqh(?fWNyPhv*LZ^wr!FA^e$6dc&7BFY3 z5S5p#$;)Y;%I1ws57Osp9g0$=2&*7DdjmO)EVCY=^7b(r1srr=+4`ff9?Y86ynN#G z&;dQ~OnZ41dcHT*AIqw~*it1tWxHp*aj)iR(Lx879jNRb~im!M$Od`p08OaYBXG{&9oQ`(_A!Z*sn z0;TXkEBG_Y_6(%Q$Ik~wS{~MIP3<$!)F_Hbao9Qocse)i#y5{G?_U>roV3a^PL?1w zwC}kT;qdqHmb;m$4t<+xEA3jBceoF=Z@b=hPX&410(VzH=LV=D-ViHc*~t_mf;u&k zllNf>AIw-FQ|d{vx+cMvNIE!+OAzx=XApDEV1AoG=y}DJ;U~_;(4fkLRIGTrEq;ZM zqh~sOohiIdRC!@_@brQUKJ}8XDrfg6%=caqMY6*MlS8$F5UbFQZ1_)xKtse`_|3CW zdH(e*aG9kFwD(?6yD}JaKtm<-h`9C5$0;tG=Rb^pRt}#;MUb5zp#DhstxI3bml+ua zZ6Gr(FCTr?p4Xf5^7YF8*$btg+K$aCesw(TYtBiZp5nZh2L2!R-ZLtyZCe*D6v;t? zWXVa%S;;1XfCMFn0s#p{Q6i~`h2$I+1O!xaRw#0k3?d*ohbjalR}qU;-nn+WcdxzA z+o$dGPP^~5+umD0W}^)zH5p^n9KH9^`}ch#VB`~|ks}J(6yVGO=1RMS>CmVnTXuCG$83AeHgWkmBg0SU_P#?&m-`lyJ9&vMiF-g1rBhK#!x1Cx{by4uyL08;LnYz|lkQ*JS^vtt>7ysntxga!kHT-^`z1xp6#hX?fW zm0TiUXQ>sRX7*+i>(W=g&gn9Hj7u6Dv}9XSmAT5kFc$_SU+z>ay4NwS=Lf?4t#Fj* zs+)ndEx3TZ4P%y0u@FV2TvO*pi60`lt<9s$S5|AxTb@W2r<%U0DXJ9=@fM9Wji|A_ zkikXSV`pj-$Z%$BOX_V{JC?~(x8lKEfGYeWzpCTpxYfC$+P*kUHHyvV1EGW0sN>bG za=9Kn`K0I89=YQgJ}sc!DJXM6e)bqh@~Cp@W?i|PtVm1zJvUn@ScR>b(hp0liUUgT zT2HXoCM!jAugzz8eZ1B_W*(t?%MM_>ukshbvQ>gxNCuX>mFvUjWMzu zrYHtM3vy%Wz_SE zH<7JUSfaNd__o7^UQCGDRGa28o$^S@6T7Nk6-d&aX!cu%5*v*jQhIlpJ;^HGoC|EX z_YNRrl=F+9__H*AaMCSCf-4zAkLO%3^C!%qIc!ny5a^64jLBrO`_f=u?BL~Aq)Cr> z(X6S@?>O@l%!Tmkys@$VESLRzHx8db=)1?isriA2)!`n z-z#~coE|32_HX+^!ghB%5}n`w1~K4om~GgaH)3-lK90q$IHC7-j3%IiXj{*=cXp)f zqH4B7sH7yY%vKIzv#}crF)P9~%H1;M?^)OqAL6^`Qpb{984eY`&P<-b%i5jpc1x91 zrl1%MrF zH{V-PA#{>EX3V~YagA;4n)MvYh1jy8RhdwvaHcwLMt5(uhkZPhKRTj zxcQx3315z=;uXyeiSW7)537Q9CS~=9*@1`6031!?`AR zbK-;GopnC9ct~kw1TrDKjYc{lexSsWouQ!$bAcCXn>@N(2>`(WTy$DrG*Laph|Cdv){8Rbh$|^V`-pOSeXnB3o7LaXF>z9DeJhF6Be9N+vBejhT@ov?S$m6_Kvbo=dU>_vV}Iq zW_pkPCR&A^N8l;OQYLV-j+a(wNdriKF6XK2&NwLWB4qcFLry*LI}1@tDHz^lpu;{4 z1h*rHuo}3ZdK=k~`FU4vwf*VWJZiGbh??nrrMi`f9*)Rt2Am8EK>?mI!>M;=b7_4k zo;ImW5~;|cgU0rdY%VbTm&IbQ(XslAIH>#_3JbI!vR_UHgtwyFiTd~ka zIY=D|rfVjKp)I}J14&!z>r)lHYg4s+n7N5m4dCc{wZ%mf#q6KUbiojmE*(zRlJwd_ ziuAERkuVW%_}pZLc}vNs*V|y<>Q7XLtL8lwCllJj9*>6A zPI>JFcpz(aOv^n_ccXtb8y3tunav-2>AVXvB7eUvENP6v8xBo{MR)2_n|a)ZF^rvZ zc&4p5t%xJB9u{9Y$j*Q?vzf6AN?YX0kw|JRiuZp@BO>>3=Q;wrd} z9=`b?dAn9l(8ccR>qL2Unf@aXJ#gKynjD?%Sr8GniC-k?p%qNz7TgLd0da(xdmTD)rx)*Fx*x;jB|4|d{NiUy zd|q}z-lu4g;Qzd$IKu^!HCCSam`KNdxUvn>Gl|aw5$RfA(|SY?(*M7I5uj9%y6tnY zI56d&qI4$D1T)gk3yErN(GuJtS7X!&1qQ?(OGI6PCX2=nv_+YG+;9 zmb?}nax4RG{0*YU5vRYiUU)Q2Iot(N7#LJuQ&><&o14FT@@wt&?A_~UrMD=ke~j%N zQ9dwi^1C$H^qWg}YxRp_F*Uy_xvRw%073L969Xw)nPPzIK`FVS-5Pqp_Dj{~@+Yiu z(@!#)y8PAKV>h?JedT}xq>XO8CYKwpXx~cit=sD8y9N42nNNPDrWpB=egCc{!JCq- z%bPJWau}xzo)Gb{WSP|(*qSjQhjUvF^Txj{Aui^x^}o4{U;w~iW)You>M>Cnt&Iel zuc2Wai(cnNxlIxv->L1k?cwuVP8>uwy7aj8PvaMs((nVuwcvIO|9((zJ}W*@v<<@# zh;#%gGzx|OLp$N0{_twkUmyMZG!5Au80_A;);%;8H=lzXd|#}ml5km)Ie<9D0Wa&< zbU@q%bVw#Nd{OrsloL~VLHaidnZIuTH7$R=4!M6VgTI!+U(4X1m%#+q`*kzN%7XL; zyX2^djNg-zG>Hho0R7f|xyD4uN+koLT_uoqOG>6Uyym8^s<7t%+tgixLs|lXb*{=X z#sAdJY<`TZRL2=W&bDozQa>r|sqnw{8$>lL>p>_YMhR_zZ$Zya;1`bPq4;&gD-rMq)t)GhZGpiHa zQz*)4rNPLBTwE)N<7sbvRFLE}kvuCNHe6b_=ymd3$J28iZ~hxJ+&zUS90U@LBdcu} z7nX=+Z9rJfXEY_HIcsJ-`EeiMK40?>O@7RR%hmr##*?wRp- ztLwNUSc$(XE(un-wa6ON-by=m2z@ey=0J7^z#v7lL>6(dzGkJ>8lRzP>xCik&wJ9|=RiZ)EH0yq>(M zev5h~n;I9LOhqLru>mecAYm7Y34j>Klos`+a7|@@#Znvy@q6mBuX1pYBXBT>6)%k+ z!HeKt`;-F(YJv|Nv(i?qn4K}x=`Co{#)Ke)_NaZ(|IOMR71Q)W!)D#tkV%7^W~EtLJ}aD7Tzp)USmHtmbV z2f_xqjd^pH4@<-N9#0iq+ygMH!)V41O_}LdW&p8b#iw$8+utbr=14(ZT}$KVs)Ink z^D(iR!q&w80m=~Ao%zSqqkFZ0%Fi&oZLcPGrxtOrD0aT%c=do7&A2^+jX`JUpWnB- z$?JF(&7XrJ&!XFrs~ycdF?%RJ;OQig!czrJmSQ+DygzOI*!`IuP6>N}-izD5a6*ek z7%fqAW4t>rA)Q8(QN?DKnq^C1rxOOZN6cZtk6h!#?GC6WdZ}J{;R^z4hw*;hzd-@z z9MJ0DplmE+38Ko8ai+e#j(wnmncD7lf}!fITXB9x78dX{M%kQSLK4O=gsTHDq*mYE zw@9&iiWxYDUw*vc!h$T8pK>q9#%GH*E!f)j% zw`-|>a(Ew||9!;g(432t82q^zsQQu7-y6zv4!=Q4057a{GDvvDu=USo!ry1@1G%&z z?C-5V=kUtl4fFr)k1quU6A*JAN)zO$T!dQx231HQe(6tSl>bu;$S$;{E-HV+fkNP$Mi%=eW?PaK7Y8DU0${jZgD*#~WBcj*@@ry*O#xd+({= zpt_+fv=|NCp;P6GGW!;ocCRLfLLGhim{lt?Kv_pjE2;Lajf7ps2J5P$;W)$XqFr;) z)kBu(3p~#6+}9DWGKQzzWWZB3RD)yACTnuPRtCmcL5L*1Fb6f ziQ4R2KbjwXGHXYJDO7?2g?}y5rXF<8_Epu7v*;rIhtPB}#sJvghhPY=Y!eN-H2Bm? zFrnhwcQ_mk=&(=%rgF=;;YTaOfN-`TR+#Z+rj`(WO)`pqKmEq6Q??YF-YvfPC(8sC zDk#_meQtZJ1Xd|LW@VU6B?P(Stv)U@$f&R5JYaHAE%}8wEke57IkE>hyRc;?a3|X;A5w4KKULvGQBObmt19D~AAnbw#~XB|$!JFX{q@ah%^uRyw*!GnQ+#tA%>9hg~9RVpt^kD*PfbeEO=-Jq?*+xeNNtju4b__yriY-1G%lyL9jfJxmunQ}cv~i%szP zV;Y$`-Qsz|U_l=9NCdo3*`ZwzIE&{D{3y^-?1Db6Q_5fV3pOt8bq)D~KW=U5t8ZEa zREE_&${HvaJK3gA?ut*IBx(M96ZbmKvijf}LFRj0{<(|4)`aqPf5?b*0>Ne=0WJ+Q zwAfv_obvQbGlOhnqS%c?_mX!7x0nn@Zr466(a$6Xag;nWUR}&T4}gcDaza|^aem!_ zBrFke7v?BI&+~~1#Ycs|CJQFKAF*xuNnU1{XQF7*MV^%w9I17>fj_EH_(KJ{5TIY# zcQV!5Fb7)ePNq-(AF3*>BL9%&)6v(cdO(9*%6A?M(UfJ+oL52B>lrQ`tE;H)qhSFO>jv zBd!E=&{vAEbY*i zT|dn$Oc%Nww;YmFutur#|KadGO95xf3Oio~p4#|dd+L4y?nw>ebOrhwTwto%mHL2#^-G zi~;v4yL19f#vkIl{~J1E35!rv^UUR?>*2|kXj(llYv>JBqXc;xwwoe)-*X)Gt0Yz& z*9(c^4npt^0{ip?R)|xQ_TL~2Ab0sAw^YXLpPJGjV*nU@86kYAJHyzeQdPbe!>DKJ zwYIq<(=!?zkYT#ZQ?JGlzH!2oAuhFkO9@`t;`o93J2fDF)2`qdQ|{H<9Y~G~DcoqB zm{VrE;;EM5Oq`%Hb_}nAx$=9W* z6J^3lZcMW>?bJGyW%RB|Pw7g>lSe)tMr#ikv@E|dLzuvd?b zaO&>tHANSqxYwAauEw?U{CQ_HiFyz7rb4P}Qwt}dng#~5;vPoP{993!& z?1k7_UD~Z==M0Bl{zyx+2hJk)V?6PTjwJE6!k-*2caLmYuH9BPs=R^I`3)kx$Z4?@*6; zbv?XoIU69!Ne{GzH#$Tr%UD3zX>nTUn45@BGu~{DU`df3(MJRKl)hP%CGc3QCD*P- zc|&8v$=WpWqd8SQndeU+*;itEd{-VV?~yu7ZJOmo7|qO`JDbwjMpA|_0)rDz2R;M5xt33B`48XKp zhi9rKs85JhNFO0yE<`2D77Oc2h}A`Bo+AjH zTR}A(nD|bIn>BGq$XZO_C)O`59}i5I;9|Fy8-pkV-vUFWhCet4psAt8rnqaRhz^_M zN}T>|V5JRU5MKBo<~U|+@oE>B#jOLY0o%`^3z996K2K^K|7u<~#g{SUZxGufU~#KO ztUzsheaCnJWQ4SN``K*5O6Xt^UV{3zDf^^Ct@BWPh_sAcLq1;5!5>WqLf!Y6So%}!6 z&HqnpQ{TAEMf?nfSK=E@5F7U8fjV9nkfXF?AnHj503c@@HormnsWqoEbJ!2mfS&2U z^IF8ch<%a>d@EqlReetxSK1;kbWpGe1Lr{M799nnOyeIeT#dzUd(*zrZ_{V&ixwHxNU3Rkt98b&>qKixD-jP*a^lCEafL;2vo#(z?gxc)n{r=x*{v3t zp`RktK+57>Ka>8*q1R;9_BmS$R)nG(R-7(yCS-7ng@VXXgK|{v95wANr!-GA39y z)|O*ttAn^p7k!LbilA!Zjgs1Y(Zl0A+WqZrPXB>i1re*48nGf7=;EXW>ky-84@CBJ zJ@SChEdQwkMnCil=|IoUO4uB;#uQEPBoWV=!Be@`Pb>PoFG_Mm5%-IUw~tUXXi`NJ zMLE>)PJ_MXlEFCz*u^RLt|rBz?mJ6et~xvRqd7ze`5#^#0z2OTym~YUT~slJzitV} z`EgZm$j`7QJ?+H>C?OB^BeS&hxpPBc-sB=vIzj+^$*P-1cqiE-P28TUEh0o z-xz4Bgqc-Hb>dYpZBZ9mXcdxQW5c3_D9!Q@6Sm2daNDRo?t@P>1Husc z*19o~{03;L$m*O+_zk5+HI%yVrsI{IV=v$vPzJbPOThe+sZ;}2_w+ade_4q${3iI< z?Z2kwuh-$PW$>4E`2VFA#=8w(6OR`z6{q-=1dK1ydQ0>o`BmGQ$L+TGKh`XsH zCK2=(lqGOt{RvMImSN*Kn}&u_yKseE5>JOnY0NN3+U*dw=#j*cYO(u{SJ(PgAe65L zzRDZN%T$s$%^J40Ra!W)SYGb7{&1u0y*n3+gAMJ+drqEHZ|4A`V0+D4H&0ZQAK_|++KW#l=;~}v)!_% za*d<|C+?|Q> zHYZ9yovE7Rly<&m0ThB^8mIMivZpB6E=Lc-8;=$etKLl(Ts)Hy+j~~DDtFQDfKA)Z zT3%wh`GOj!*{q*u0#DKWJaSa3#X8{45^81gy3ms>P8)v*;G(&jpYbtzN_=(z@QFq`tu#F4KVQMC=^uPT>1{Se2t$eEv zBaA?*gd2A@8a6Gdy9X3lZk*g-qrAOlbYOpw?!^^j=F4Ls7&B;v?F`9#hc$vau}DRD180O{yukV5|lwZSU#}j#?`TT)^^P z1Y27`YDo$8c@J`T({iho^CoNZlyGxbD~KBsCJNvN_Ih=dw=1XAD!TV-&bL{aQ@e)$%%nJ8Tb$EU22nBo|V zt=Z}EWqZGO-^*FLB!o0}`0*-mWna*7fZTBsPN=lK+;U@)R}*@8lY0f+l(U@%A>S~{ z*{T$=bG%}8kNK-Ztz=M_m;u3xzsH#+aG#Y!4+P(EY^dFUSw&~W#~s`@$Zg(l}`voJ{((ba@;MP$QWF0 zY*}&%pOj{B3$2ZFm6eh>pdwOLem~WE$6o|99Ao_TY_TzQwk;h(SbXdkC9+e{%4x3d z?vW%@gG@_&#mh?z4pLkXri`DKcz&%KC6(HYmM`bG+!KHd*{WmBv zmgA@gc1b2*Z3t`-|7@vV^N%Y9R4@WrvA;pFW&YC8iV9CLpaA}`R!676&)lR^8lLC< zFm60ne($z8)6bVrP)CDqavW6tte&NVfU`WWtdLRAd9LYy8osr~bPY+nLydF^h0YRn zPP|t9K^%hUSj6SZRuaGRbdJ^&68o1K* zRiXC*3K6q-s}0K^g`)Ht(=|WAvR9*a3?TYqNjy%I9Inw2yv(B3OXms>Uxa! zxUlrj9b7{9?4!Y=U>}AxN(LuxqZCHLvK_K3g|4&~tz;J=KU5r*?w@pIGXp{)zl`10 z%W<#pbhd?Rqc(~K7f4?EN}wLZgVVqK_4^V}>0i&2)u=9AKKeug#YI%{FPV@})qnyc-? z8>`LPdN!<@pWhnW3%|~EVvSc-WJN{9e;mcLZ!D@zA!?f+72{?#Jr&yXrY$%1Hx6v{ zrXxRUQZ|}_I6JS2a4T@UtAVOx1$vAFrLfM0$G|EElbD)YS!fpbx>NqlaUL7|L94t| zJ3zkNH%K2>E%aG@!K&p0PPY@!l=&>@Ud=hzBn+(I{3uy1Za1H->hYIq`qg~m z!?cSe%a)8!CRRrei*qUL8W=Q^79Q`^7wdbjb!DoeC7-zW3Io~yX1Na=@(maYQdk90 zFF012^K2^Jv68U+E=8AjB0R`)3np?^kof9uGIanz7H#(hcUBVqY9$_d1(i0xv!g$K z&B>H_n1|r26I*qyLW(Mf=qCOyE)39krj8Lceq4j;DPJiyhbWjR9*uvB2ZREX3g5o( z7R%s%jum#a?K{mRW|HTI;6<^BP7)+4-|6hJ1+G_5M_B_V%EOppRmLOrMJ}fCKAW_8 z)fWvr&Kq{m&P_cQo>@tnPG03<-S>77 zP!dhSY_-qc97^}e-@redl{-$Xg2_AVx7DmMGQO8eTy!a6T^pLWk&PF;`g1sn z0&c85F5NG!aEa)}D^Gef#S9GieJ-l4+U(Brw^XH%l?aAI^{G17H9lb!@ zn-Lho<78I*evxy`U(UbLE3M>9H2QoXYBk_d#57m(-Ms!9es$6y`^A?^$5W`Kkh1c_ zQY}jrJ2U=b&vFy7EQx*Co=$(ZMH*jSW&_@6J_PYC*LfwY3CD+-Jm~^s-pp^L$m|`z zm;Z4O0Z$DvsI&KIWGKB;OJ~pM9=X55RmJ=owB|3g0*hvsY*gkMg&s0Bi}6<%ZQO#o z9fysNDv+)r<#hP5bW*ycuxcM?|7v`lr;k`jvoSg!Q~A0kfkVfsa=>k6$7_^yQs~`! zjh00DE|9p>bmO6}K7CnwrI?h&Fzdn8NRmGX&WAV}fs%;PvLAo6vdI-V;eIUBn)JBk zNA*GAH&G_K^oQpCyz9If*}W*;*V0?vt<__B>ItT4T{K)x4UW&p3*#O0Gwzr@rT3de zTlSUk2(L!(f`X`T{=iFI+?UO!2ME6|hqn3f1D)p9(eiCTh0*ylybP@WTGYSwls?`EM`xVX9iqTlclAY^ONkT(p1Cs znoJ*~B8L118J8;ovK6?$$jR)1I?p|KC_T*EU78_r5mBk7!Ta_T(o`i*hwJd6S{A5$l_}RO$LSE!t8+>%8~RzZ?w*agZrKWR|hyb_h2Yg380W z$6?Ur`nqbJR5bik{lj#W6;HD2Q1kVfs~~nK>Ue)2R1S^5&4gzbOd~+q)L)agtM`1$+U%LgRnONNwv*0$e>)LbzR+f@WOmI8+s&ZIkA_m zBu0^6dVk%}^qC;R*K!VGe|bz=(9dxJ%tRU1!g-iJ?SxS-O|E*rpX`l#vU$3_mvtfY zkVcO$8R%5#p{4UTAbXz8k2TxKn3y=}rsPqlC8=0W=Av9^29EZssozH#Q&O1Ba=0PH zWv?YrUYKCz!Y;&6OQi5u)GB%tux1;C%+IqIx#hw}$MW;o+vLzY%u!zHYWv@kZXeWF z6`wWWZ^G}QQ;Ej*Qy^}*sNO6&`8-M9VwI)7&YnW+%b6as&Y4@#Y8 z-#Dlz51sWI1k1S5HZw}5A;+H%1PqEaso6fSe>(14wnTw!x~bdV7!mf+*9@+@V6N^; z->6l%*j)wJ6lrox;(l{iSWErD!A&LyhJkb}-V8rG|N5gfv#cg=Av@j8)6?4zTEN=O za4v%!L+Ww8EbAwUmHp9h^#c+3bs)D@@42GW5}p6U$^h>|oP7=JPQ-dcau1P{2^+h; zMDiUK-+CQ~73!|xYrjss1BGjTR8+wHnE_okP5hA7Yc{%#>zzV#mZW^P($M43uD<6( zldMGdDnB;MpePwT@RVczp+ zvoEwFiDzze)~->cV;*c}QRP&9rP9fD?8y$4fOuEc78In;X?+C^FYLlI;p|Ir>%C64 zp56r;b!JWGP7(ub&q+9?BCkH)m+F&!D{1rKr5D+0TQ|!|mpWE9su+GMt@X}T@hW=Z zF{`E6j>JRn2iAKq<&7AP>(;^}Nc#}k8zh96MaK*V)3RyOw?uL~po`2zhw$hf!S?Eg z$C!IV>Sp_K0?Qm7EetQ}t419pWwYG#Zsq8=*6$ktNx{vL8*RF-7 z)NwfWC^e!K0%S(!=G&=)Wc;)uk#WWv$Y|_pH2s&1fcqjTu2Q8@=vgw}(4ITPV`dJo z6$Ntp{Y1jEqdi&4btE_Jywmxszi9FV^J_AvktNqF+P^-Haf=75;RG;a59(Tx$Wa!! z3^~zgemH)26E8islv)$!nh%IoCsLrr?5+6%j`EdDI6?Jxr=CO}ITt$>wXUvDo%dqpE zqJ?tPllWy*^b7N6*XwE0l}8%(NkK1KBzplH4x!{R9bwc;U7G{fY3ZmgE-ow%%OK60 ziyofPX-d0w*PlAaeCqcq(xd$#rJ0rSss8Ns-@M~QP+I-M~Ltlq9^MLj|d37uXU z3XrqHaO?0n<0%WvLE$x1uGD=Y$DNNpbO@3!oh((o)m-i;Q364@01UXZl>!re4&5E8Z*Q!TO>siqfps0RZ|&h;!)mb@4Th79JcIf08Dy_^KbK z)QtTp{CSw1_lpJrr=;Y2T6sE)Xh71*wUM$nV(v+{Mnxsy?3T=i=;Jno>Ul<|kT0>5Len+wC<{fA9SG7`_ zH^;RN-)b8uYZ6lsP$>1Hrs8DwZs36Otign^wftI2k#nQrU`r-_ZT6OSeJaStiPT=R z_KIAxu@~u`{>;uLl0bHxk)L@Boi^N|dfe61F+X{C4Xs;eIY+L!?v-IIshCJv-uziW zEbeEGCyPVqg;MUcGmB+dMt(u5r;ncxUG=wW-M}5bP7aC8DCX(6O#1IZz=;a`T^t-2 zJ~qn35RC}%4{4gxiYTSWhDS2eB=R~saM<*+-!JX*awPZo6oLBqG@N)hSwOAKq&+k7i87y@? zGfF64*kCD$DzH#48!EFRKRW0~?!T+oWYTOECrjn@VCS9i_lEi`@5uGYHc}2%ip6An z>%b51+@CQ-#%!!K$hN}aKaC%-KHUEn8~T|m`pqFZA{gMIaE{c7km<-m1_CU1em19` zo$c=Lsv#B1`x>*IMCtkzyQ?1U4+{lr${r#@7q9$SsWPXOf4~=BcJcYII)gJZme(ybSP_u`ue6D#4Nd6(Obeo zdo0E@KiNFWFhqwmH0#4P_!|Ob>WK(rFP^&%C+3Zn#}6$o?(2x@O_o8u?%Z=M6`tg_ z2D^C&soA%K-z8p|0JC4Pj5X_H7F9wUIcAW}bw-u;B8_w`nLgKh`p9nFmSv;NqnQKVoT>|b+!k+~ zBRA%gu0Uu?H?|@8DEUtK15?S%4~$;VC0;V$P`w*gCGkb9H|rIc0Dj(Ml*-`N7Vcpw zX81YSa+_(B#l<*ZfNT7-abnS}YEIt+t6z!)D86@3gjL|uh;5Mn2I42{`%@Lf6b}Cz zbZ*!M0avegfUm1@jvqQ@TrD(rGH9pD^@CA%=V!RoX+@&yA7y<6AHf72tVmpfREfiI zOD5RXEOY{^T*#5*;YJQxJw!OGFy8c8x3@!Hk8PLxeg6W7%YBEFNYi@;-c&J9aj(%! z)bKHrAI-OHaz!gk;Y->-L|u2gr&0v6P}6&6tGRUVrCnYdN#ACszojtUZ*^XFA%RhA zgI3ILX1Kjo)bxY|6jfR1(kEM*n8N5?WP>3) z$)~BEqlKrQ-2=Kld=vQrYu>iiHLTMBoiiXTP|OtDr0F$)5JYpR$>@_QuTRE!&2;7fGa6q zLw$zVcwV>$`b&@J*Ag*@)ih)#i+jEsYWXn*qhoKC`>*Rg5cv|CS~D%RGgV( zvxMTwnQO7Fi;Ngf{Rjf_kv>O?h|K$1_NMtMn9ILO7R-O{Efn7K$Pd;@%`m(ICNbYi z^Y-=JY0p5D+K(}y1-0%8@w1TUo9?WFs3n;tZC&ENi$5{ApvQSND$Yt&HG5|7i`?7e zc-k7EweylI{+7{Y1?4Q#@o@nk!LvjnQX(A=RA4%4nC4d+o+DLDiAN1N@of5ZO#8%m zHt(~>i7}lPPxGi?{JqBe-?j7Bqd~n`SZuS8K*HQt0F9^-ucPuX!J;L{m`?tC^|0{u zxehM)MU^%!V|w$~pvv7j835E9qRiurr@(om7QEHR%Jyn9VG%4cUB--6PqYixpK7_& zXWGqFuZz_4V-_^QsjUN8?~Xs5=-S!bQ|!&yS*FHOv+q~CWDxh zAzEi7JJ3q!MPWN4JZU4*aU&N!G^JfTf=<|xQxS>FL$5Jauk9-E>&-ihu)z;)X(Ky%b*nEUAezqF$5&2q&eC_gmZS3TwO@)BBvHN}x$hyUX zg9a~vt2UXKYL|bJVgo_-A!}Q|OoesHP0=mQcKh*ijenZ;kK+- zhjA(zW3zWZnz+hn2=mk~+{!T2pq~$~pJTT?>B}dWmR1A~o<_rhSEerRmdyS#i--hJ zPdK$*VNsFfHFDCOqaEGzJ9#70RRi=%l6NV1t-qE+my3_Hv{10uG67l^6EaHT7FuX6 z=`RzxK5OSn^Agu+(&`Qrb7Zarr4Z5S zCyr+3^@mLfqQ_pfp0{}QA9w8TgO5%oe@=RIH7ax0A#2B*`+2)YrlneH zK`(h6Gt}(i$Mr63tIy&C0?GUpEZLzxN%K9W z4Jy&NN*GK~is|gG#!YoFoUJY_X8FB*Q6FsT(On-+`{Qwcc<_dipO5O*@8R0-=6KvG z=mv02J?zRky$Q=45&gOC?zW%!>%85|^7eZL>$6R`g870qqLZ!NdGp_M3hm26!0I?~ z0o=XImk&5-Xf=6QW29WhP*&MvOljh{SeRC6qHDBoPdb_>(KWG}?$%v2ve_2X)~>AB z7<}H9YS8ZqBTOw-DqkIp9fnE}Y4G})K6kQtMIg~&Cs4;9q*(cNiJ=*S73!83R_3S~ zJzOB$>X;Rag5jrAbm3I_GCB+OAb* zu=KjiB$weJNB7V$e!11eWE?}#uXtEdt%-q!ON(f4o+*WTd8^FSW~hp%noRbz=R@EI zoc>6Y@58|*R8*v#AaS6}m0$6SZFLihTDHH4oe?(!IcFWSX|ckSzE(-OTgptMo~7jm_+GvGF{|U#2fB_^vf=j%c^@05 zLPFm@!AR^ULl=N^Zu9VR+Fh6M zEta-|!tZIq!gfFJ`(#ZJCP1zykpIVpIvPO6O<(o0r_2`lmN5}RZqsV?Aut5F28bag(&U4{5g?|D2OL-hxpd5 z1vX+kcIU*s5H2#4OV(2VTNw5_ry|p(jWV_Tl8OfDFBbFnJs)7H9NS`cqdCtdY6>@#s@ zQ#8Qf>|aS>byj9bd4wEAUW(~q;u2zHY~9&Tg5w~8v(a_0OYdVmnAjqeuUxA~!zvN|n=l5_^|L|LMH6{VdBs%BOcvv5A< zIOkYx3|WL!uwB;?ODp`k_AufkzWsAo)?k{_bTsHRnwkYTV^}?^l^Wh@Qa4JKg}y7J zWUe!IxSpZ#Zc>M8-%(_j@9pf}0iKGD8{8)Iwva0%N7NxXbj_wKB1U^^*rKs*nL93A zEh(A|j6kZ+Zg-VeO=}Rl@U;+Rsfr?Z`)tSZ>u@+Ihs-0+Y|6B1#6;KHwY8fqtkC$F6RSA?k`6+kZR-xmD;gBsnxMAiRE@42x!^$)n%^jYkK2^q#?GEi2z2L4wNTy<#80N2qe;Xi%OMD1 zy^%AY2JCkL)>8M#Wk>&_b&*oN%S>b~3nDTnZ=P32BY7(+SCfrXAi1dbCcy`4KFrb%W!Xly&}6d| z)^(usn4wWFtis>Ytqcx%mScjft*T0*b=>^~(cllatgwr`hLF)ejxD~ipnI-)!BRKs z;#oMk%QE-WsXMtl-&u0l{YH^mDq6^+#woAn9yi^qBI{1-MdKl}!tG8#@8J3z{LQqZ z6(R1Gj2Izs&XxW&+`v3M#IR{%*`$1RJdY(HITFgO#XrrLq*Y7xKiGTEpeDa|-#^k6 z>Am-+(xgif6r_tthtQ-6A@mv~6hV3i0R`zzgwP2s^d?<8gqk2IJwd@xfB)<`v)`Qm zb7t@7oZ0i7v*-7UfgyM9S@*rJwbpfgug_Q6=&0*HE(9y2jU9@?V{nUIfYC)DRHc$c zaK(Ng-l!bSCv7zBO>}nlN93;7JEhm${Homw4D`1aY@s2z#}zKDwecQT1}^OyaZY7> zW-VVD5H!pC&kcv1{8ah1mvt&r0+^}2o>q17;pQ>3ec7y0`OQ@gYoKg+j@uc0AZJB%7A&U*p4P-fOQOm%E(ou1mx3^Xq-- zL}aY(qL*dct6$ozOlNu{-H>ItOxmdMGTHz84n6DVsWX>lm4RNP!8~{pJ@&YXylMZ&)m8&FKLy zudS_WGvuBJO3E}*YkSjLc8@7)v&LG+-Nipl={(Eli%lJmJ=NReFZJiRlXn(&Zququ z)7|q+WA+*yeM;m{(#6<$opU4B2r(MWNp5C}ztS)J*&ZG9dDtHv;;CxexVphMrp8%T z&bw-rYs||+jv@4+akNh+4hg~Z_tsrK#s#B}iJnrx+FjbAjQJ*Mtzh$US3(iNJk!%;wJb=3nN}>4#2_&(F24!KRJP8YT^1TEy{hk9?@`4bG!@EayKb z5ug8;Zo_t^xz0(1uKn>nPa2)R{u$ndcuAMc#Cje`srFB4I#GZdxsOgdq>#$67*TLT zlR^>pO>h`*m0p5xWOKoboE-XXf0NeZnThyca5;d}cwzkh7sZTOye4o9!?3E{2;#k= zlw|O2in&}@Bq@IZ;tHwE|Gw1UWA*pT@b|>|J2LzoMgPy2iOB_(?{vX`0c`Nc{+}d> zt^aA20!`z5`=_-U2FsTDipZ>K!awyJf!6yReSC~jqgTCF1e%WqJ^yi^fcpOe{r-RX-*3nNgC0Vei?M&y z#`Ep=zd;56g^%k>;kpRwjm?=F?B==xqq^g6gukWqr!Yfg$5dwyJn2DT&W6-sFTs{{ zIocY_H$z$}0lLB-wX48;gqV%NFnVQSC^Ob95g`?bWg2`_`!19X>WG70WYvCIf4p{J z!!hr6^m?wiBa7ZNSR?hB5-e8%(5AElX*|ouE+$B)a6uCKZS{Tr3X?J_os@t*ksBRi3B2#USj?%PvJi0&7%CZzv8nM2mk?A} zOO|pD_zeO=UxoF`dp1qz4{~uHH>uFLa*EChVEsSVEu20HT?um$)rtUpOqb%5#w)cA zpuI6YYqp<_!vPN;5oG-@oeBQk1>paspZ{bE`9Fi#`mYNacr|A?$0^>TY@bsgVybtd za#xvQzG;H@ln<+HmdFx>knp!J9A4-e!HA@-rwpz9M zj8(2L+c(SQd}z3(&1lb%An{3K!#)M#KJK&R^c8t)1jNPKd>^U{-rS(UdHbz7T|H~3 z827SG=zwHdi&+~A$8MkSN|I>7>F-6EXQbbLr2H7$J&4D%LTrsZBjAjw`>f*ewi>NW z!;{ID!DcCb2V`MSBVa@FVF z1BJA005KA;M?C;em94P&eEIrmsCwZ~WiEG3L(E3>7GklPs55z_`ltrxm?~PW`1)5_ zBG3EUoOqINH3RX7Qz;%$0Zc-FzU(}Ah>mR2^ovR<-3F~9#EC=xVVvp4_w#&*WXYmr zjeFRN-Vm-KV18v~O$*GWU}b@{eE%WHsGl8})MPhL)a6DesZgERfp%G{L~1jvwnR2r zK{-HnV!Y!vG_p0E1f8b^aBcyO zy0(wA>b-9iArl=)k^ZT}FDaK6y8z;R;#KsNZwy}taM7-H_@>MUs#7`huZX_#4GJsm zhv2n1Yc6ya8XaOZI$H0}qgf)j(w`rGk3ZeP(V)H}L{YVrpf~W^idCHHiMvL>S-ftL zC-Ug$b1}gWtCnL#wQ>bKKHsjlG6zkYuJfTZB>C-5+v}B|d(UiXfqG{hv1>n41|^4O zcGDIF>`^70mIQZ*j#j;%5O=d*xlea-t-9K-WO<(H$@QxZ=u7GpeQNGo5oo9)ww^pF zl=qShB7{A~6l?|LV&%-|p^DoetgC``bMvmkiz>=`kU;0GR>Do%T}`;7%hz~%3zw-($b;I8|OlPh4ZhMPo@AytKhrJCm*hmIeqMQIp02>{^M>hwQvCGsB>#{ReL zN&Zi+`OoEC{$s!r@V~J1wK)CzP#N9(y0tmlg4Lp7inWnlr^iPF!fvYWmqT?GNq5se zg)davgbUq#oeBFfx^Z(YgfqBKE5&a;GrO-Z^f55jdxVOYeA;+-3gNKJ-vubmGmQ*9 zwZ`->z@J@}z9yGK^5cUfp&KadFTn9kSQOVXtNzuwC7xP=zsB9^;&7?%2I+$HlNNlj zO#6mD%n_vWYuocLKxoF5utq#!^6&5cdz}A%ul}A#f5(mg8{#BGQuWd@5LSg;86=aw z)J|g1=Cq1o0eGhhf2j!@P}zg2?Bo02LE2B4{qPWeNbNrYJlIzMBWw+xP5+-D)chAN zg^lI7?EW18+NDzp)6oUUb}rP&N|UW-mnGWd15N5vc0Ubzca zSN3P5jZOxWV@saEs|Y#bSW|xTRH;36wf|xC^H1(G{u6kq|H6I7zgHLjoBjMJ)3yIv z#qWQ!vH$n9{y+H){=kF0eaR-1u31eYK6JWUgx1vO2`?yx}91O~@_BxApO^*!t;b1yx2NIcJPymW!| z8{uHsebnJQU{(S?Xp`U+ei(mKdg@tpU3nnbQWv!HGIt{TYYy_Yt>my5saF|^*W9g( zBy}jA(~%CHu043Ak$+lF7z6F zd)toU375NpEz{D?x(a~@-h(9@J@|7`x+;v+HO(cbJnl1SXu~qW=u=eu95DNVlW#|g z6j}Wr2Bh~s7jd_XKIxT5uH~#>9@~Ho>jL!A!j|ETl3saNZt&f;DkU){zqI!DO77C6 zw-H_}+JHat|4pXHKRF%#rA22+|7+ISfj5jLsQnZ4ig8o^qyq~Qt@zGm1@z-KxmO7I z#7O-*rW*wAz763!bHk>@DsgVyL6D)}qVM>Fi8^d)Y%PZ$5A1qOD_rLby>3mFA~}~V zmCn@)Tf!%3F}kSX-dd#aR(Djli+EHwrN8Z6P!|zabMV?{(Wbymw|u^OeP(ZcN84@S z!MCphPiYTRD~T!Z9*cF`;8M=yaaB%RwegZTG6T%jIz280vmj0^epbC`;3{jT5Snpa z@cO$tQJSup=EZUT zK{2+3)Z+D&6{uSF{rpGRU}1fFNvnNoWFPPB%O@)f5^jjG@88ok6sYEP?h*bX8~6)Q zA2{f4ri0rDI|ZZ2x^Wiyl1*67T&Jo*??8}fW_Jz{iHXHC-d{VLTEKEN3|q-1^#bvq z5;~Z|s-1;)Vl#gv*7{uwKV8fjyX5M|^dxrCSPOqM6|O z`oE9u;6J&e`qv5ozASh(GKz|6Ptj@JR_?8PFi(F=|KQyco?TyPMw| ze{S?|9@H2-p}*;;`cwXIy*Xi6hjq$b{{_I; zKH{t1za&%ZRZKE5irGU2j|xttB#I9I`a5tHFiooY+2S zltz4~)MDwu8$nS)O8RZY>fFuxa+;Hy9W!*@78OFq17F4!+NTfM2s%-*5mdL0rbXN; zq@enTU(u!xF#6xPv%f#~|9e<}56Ry{@*hv>zu%Johu#t^yu;u>r9}MK%8ITYUl%D0 zhfa4>-YDTNQ5(?+O;}ehDj26M*3Z+H7KyW8SW{jpCx@$lXnXyX>7qNk!u7hZI9vta zL%{)c#SL=x+s0g!cWkB5|9lfO0KvC92V1aN=V~^@la>?e)Wt*GJv}^FAJNK1^f4sM zO8E@PYHHWqd<$z5j|!!Sis33Na4}|B`VHnTu64+R^*cXAIVutdzeSI|R43vOG}N&0 zDG@;1_sd*1Ob=~a%t@%VX|o``G&GBP`LGq=ZvXm)1*26C1u&OeoXwb{V{~#^@qRu{ zLf?Wi-OabTQ*l1)U%atatMHHDGFJ+i%y-m4)OR&9*>5anu6xiIcuMl1IKc+gu?-Vi z;*B~~F~QB2o8zj?>N>J|tNqUXPDLoLO#etOtDZ!ewwhaH0NfSh3)UARm@)++^Q9?@ z?4LzCS|2^u2uA1egC0oxeD?EF6DE(Kdiit@zbS4+4JU>^y3$$fB7@4$DT{#%Fe$i- z!F;8<7;DT~QQ+AMjO+O<%)>51cmGg%>Trs@%MApnle`)jGD#&)9^Nt=2<`?zMW%0r zuXM3^|3PA^L?!n^T+C3r(oB-8g>)9z62{u9pJ-BP@wK6U4Q&khwU0RdZDG&BWZ&N0v zpoU&NQK3iBp_814NiP+kdbosM4OvDk*!O#p zC4B*(#h^6%Y>A;v7|sIBkDjxJ!BWtK$QO??aBf^hYg&00s4PR|M4OLMsBn@V0N~7g z^8W&h{y)0Mf0kAMuhs9I^Pv|9YFVK&xVN60YjQ86ce@0Nfe<|OO2(SXC6h@!&oW84rZ2WU})W7VLy0V%dZ99xbN@i15_TU)BDPQ6>Z!h zJK8Uf#{9&b9&S%;f>r9r0_F9a#>qo1wYF&-ez8^Z5d0{9I~X)sfdQ){rmwilLCCJE z(p4Pin!6uNV;Yw8^O@+v{6Iu-P@x0AtK_pM(Ja=T_XyMQ{g)htV4!RsTKAH$VwW`~ zra8o2?B-hrPqu37LtD%HCU-9ZwCdb$S|1fP1vHN|Be1Qs)limx|*ZJtmtHUx$?~(6-ALY!g(yT$FxkqQfyw96lkgcvxU}r{Fm{ z%VH;I*3Db|Q?|R;^jC}bcZMfA>%c$78F9`pum#aF`lNe1CXMqjr>4x!SB)A1hH^s# z4=t!ssi|H)?5qH6H|14WJy!Nhj#ysF*jXjQNcpWt$|FwyM8;oM9D1Spr(*CEBBS|m zwrFs2%2}y_Z!05#Q8R79cUwmFTEg5J_^4J>K`8f!l=Lu*!j?o44kdu*w2iiR_u zL(SEDSQntlLR^J~tGMd|{32u{qn$f-Mb+vpLDJFqfh0#RSrZ}CPIO z53jUgAmDdXxsebDxuxIW+-8Z@XAI6UB=QXL_sQ=(V9|TSnTa9mMGCzYxgslFcZKhl z@99=qxJIDZ3?oh@>%a25jJt35LBng=?!O~`wVKiGgsIYx-+I=)AOmx->il*}HlZyh zb03{LC3;wz<-=F}ERA27zQXZksSevGcK9Y0Bj)(f9koHN_@P=P-umZ7R(;tZxY}}U zT>}#j)u9%2> zqN-NjGw(Y!g!RdYYQ;cVIXl6d6J~>qa<@%%ztV^RnU~GU3_haiSXd>?W$%4v zj}c4L#xkKhYm=J#!G*(LRwp+7=RKuM=b;JwX&zrCt0&w7_4tETYtu{kE4`S!BYVOK zm9%})9Qww%IJQBDK$LFxU1_SCRj?V|(-3~W`xdVwZV?$&TRH%w6RmSJ`0wIvR4K2- zXZ^@ltY2808O@8k`>EhG2maLF3KAt6a&kU-75BU<^=&xdGYfIU0AW5hdw`5WbCUtj z61^2hocAXNJzr$0`_?&xJ&;D^OQr0{GataxT64H^b4&V~{BhyG-sJY_xOvt2d*klaW4XTA8!DN>pVK8XJk!rmTbItu zs3Zqd@$K_aI};XVn^nAUTP+xq-JgA-A1e*2@igV41;f|5JDec>W%E@?1^#D4PhxW) zoiIzig8!ROPBuDbfJK?(=UMxwfD5;7*EYr-Yg@BOjfQt_ug9hyrhTZl{*tE7N9*(C zrPeQNp|iJh2ur)oWdte8Z@va$>rlN`?duA1_jE-H44BSFD)c{0mrGaWOJmyU%PW+) zzh|R>^L5%vm|!x!nVXZgHhPj1Pp_Tdc{&^bwpUFeS0-9n?mZ&eBOdqxaysA?X}huz@tO)EqEom`{1(@ z8A@J8cO{P*{3f$=;ws?vD4npbbBWAPFNaR0O<;aJ!BEzt-EGLg6a*Ax#?7;( zkq2_vFE^MEHLxEiOZBfB2Dc{~0WDl3)+AD)@{A37*-R^}m%E43B-!T4= zdS=BlSWh%AIj&n5``Kij61A{;WrV%htH%NRdoXK|cv0znrUl!Tduf&y+EV>)#bJ#! z0^>XPRRX9r$|#-qh<@%D5JDwjBekFBWOUh7Xn&qv$QC)dizurNyU6xRezZ$h&v|qb z9c~$Zi>GpRjSaq84driKI8C8+EwFQ!42E&KI0WYk`f^7?CaDNy!#gKd+O2CDdvGd~8LxROZXlcHj^#Z^lSh1z zM-<(kuL2ejiWLwT!VD!?Kd&U?S-KvQwegb4YYbei$4{dxvQKbMMmVsudG5idE>bq= zmx5vI*~ix~s3A5ZwQfxtG%lu`oH_Rd^nV9GR*)}_`RbhXHN$P9t#l*(*09xY;9|d? zirIopEw$wy5}r{BHhtrsvAVlRO4ieEJUd0E{$YuB!V9gQs?AnIUoMqOrb2NAQb|!# z@LxWxF644arw@@ciZN|yeRlU*omC&*1K*?uP4>6%x4k2v0sZKT*rrar1I1v1op`Ju zmMi%PAyo>(6ZaYGR-QWZ!zJooo0*tq&1gG5T7~v6y265m!b7=01yl#8%x)e>&1A6G zH+uRnI}y~?Elh^|-c0vB>8ZJwX~XM>N)kWS^J8U)OaZy4%lvznRwjqk-o>#c zmPDIo#QudQz#LQCn?ixpIo9lI>Yf)DlLmLbzL576OxDbC_r4m-kT8D_XL~<1qY{hn zMmS2k)Y21;&PA&*K!AF5{TJ}ODw~zHgzxQb7SdWa;MVOH^LZ1ULGkzd!c2GN9x(R& z_PxzD@pUZwNrE8v?wdrN* zC#t*Je~`I;=;(R!z;nOOfQOA#`o9r{vfcfmpy+dLe`fNCyRr&J~igiykj16Cs}X8r!0_?4W{yHim* zExh(FQm?&b&hUaXe;_xy=~J~=L&qJsF6UxW+9dy@T79fszdkvx+pNH3aRD6F{>>Ai z__zjBr|tAvn?C&q*$%1H-6$vTaDA3u&fr=o`@&Qt^l2d||NcUA$1yc%`X_IQ&z@}Z z@QaU#w)K05n^BxjQL8a&KnoUQ>2SwzD!gAyN>exam2xXC#-Dr^sOG@2_mq)*=3~UU zftZ%{(a{&lCnG=NPeOw6Cdg1ek`gC$0ZDGin}x>@c4qaP=eFA7&o+$b_-3P5BFXIp zqAf^%JFa}~PYtAUTSRab;xhWoY)I$1U(eJWDi2^w-uuViGr6~UWcr+-TAql|#vQMh z7gFtDlETHx?mlQPpX|)~>3Hha&#D1k{O8b<^PBZfJ-{_t~sBY@rP+rWaZmI0Y(j;mmP*M~& z|K5?A7RADn2V3!uo6j6NBR7|zzcseM!RodO0V%Trfw)n9x{Wo^!W6{?az$OVtSMW} zF?%d~+a&R*FN-6Rop5SB^qY3sl}0^=q^f*3b>y?FZmCAy{=%X{yp=YcR{EG7t<SU{V+)PxO_;mS?QOHbT~H zUAQX=cJQhd{JHv&`-Rs*T2%U8Kzfjgna2)$Iw{PP1Ij%c%59^CT`EX|BH`EzELZ{&ZXRWWb6tXeV5L!g!6@-7S7TK42@b;#7>R#e5yA%01IUw$73 z;`hIDz!;{ddZD7$GKbzGqKGH!LXjF4_{Nb&^xSsZc4p6|O1`0H+R~8IgR;1n70iI1 zdfYKu_?ni&Rs1%feW*n|<~MWl=X|H@1G?2gVcpAc(M_#G$J92l@AnC$PO@?b3phRS zhlgFz76-|q8kPk1d3E<}At$+>7@ji%rv7-;-NdSb`}1J5>H|@<2HEzXno--xe6}zW z3y37yn#Qv9grU2${v1z^OjlD^&JH+(-+h}onfyd>G3ou#pt&6XLhk1L`wRCRZL}@5 zY)i!+oom3wyFezIAjx|g;mA9zB0{O61LiDb9Xo}$A+}p2+34;lV9LOu?40E8 zOILSq5J%th=n#>w{8~p2LojM8FiHbqL?fxzoolI8+yo7ItpVHuZwJ z5tR5lCvw&JRc|Vj1i1C`-k{GqH|{=)iq4|9VsBwjo}a_(pTy|p8KTBkfRf+x+8T^q~6L7n}HX!QRo93plc#hX4jTM24*-Db{prc*_J-zNe4+s z4h5my(?#=|q&8L`)NMbnM}CN75C5LXPQ7pYZUGn;_j*yfmUf}S zMMflO>M!st_T6TX=38a4eFch7oPt>E>$6H{=gq1l4NFg{;8p7+drJsBh6lRH#%rk6 zGxS0j=~obL!#RDrrf3RZlz}(mZAClZ^lJyXcl8r*pRAHjG4=&9B#ou*=p1|^epME! z55^Goz%Lwglum5dkh(<^g$jC-1n%YS!40UAB$n3}w%?t&0k>IL3dw_OlP)%5nn|V+ zo~Wl~wnO-+DtgL*2nQka_LiE5KX4}=!#~bWro3Xa^y#2+(%!m&&CVv?dYAEfl$)5{CBeN zv1}>6O@dDHztZM_XJa%q8fV0=WWMZQoV69|m+2Pwm+mon=UReU-t(xR@J4G}za-Wc z3UXAxtS03jF215`p7C!(==!2JX!qV!{WP=Tj5s>kSsDR5`(U+L#UCul{Mv%NwJ?{G z;2-J6CuL@usc0=-^66T!p0UO5vSb{OPsx@_9i8D?#ge0mUoBWt2}li}@!@sl3n{kM3|UKmEs-hgy?vPLTIuwf&;x?L^2g}*f>s=|1R(3OW=U~&pEkpRn3RDqde<(6+#XJGOuLKR z^w0h3(r>Q9pP%yUtE5uXkn<~iI{w4JngYO@|{z05Y zB;FL(w1g~a<2D;x=fbIDZDxK9tl!fuDFe4hzom>UAM=Ij!Bz)`eEC+{;$SHA83C2H zBnN>HQu3?wzq6ANWF^oimks-lJg&8e#BfEIMljqVB+>d+2EM7TG2Jw-kt$|%j!DjelO*kQ&6QnUfr$GeISbY z?&0o@3Qh>0p;D{dYo{y#Q&##HkCo=C4o&tQKF6;1IfMOvrE3YK_|XpamWT~g^l%1m z;_)EJg{ly=o)KCkTQ;G(x7c!+cAu)+CZl*==43>4{0z%mHBwLHJwP(ZpLYZdmxEGZ zg$M9#k#`7fY{5(4GxPOeMJ}?b$6W>2AK->~el6YVdvi~YuAmn9QVH@i`^i;#1vY!o zmNt|fg52)`CTF9rb$hY;GS_Fh{+ykjB4qY|3__weHR+w!dXhEL`L@HCh~a7bT@P?< zC~*cGNW_sPOjF;MPTl#sggCLDpVkKSi+^FUmp}fwwT6RI?hvc5jz`QwoB(3M=60%7p%nR^dSCJ|M3%@f7H0HoHddz|#sp2zHC z-o6#c3E@u!Q~WyPFCKmWv^b6jWJ}rNgwT{ppmK0PPCzayR`j%h7C6BV7QKdD&sdZp zo-Rp1>@L+u$kKH*Bz_UvT%v3#agq3KLvf27Ogv_D_IIa>X7g+Ek+WwRQ#sEcT%BaA z{~mZ1E@iBO(#J6dPtorw3`V&AQ5Me*D3ZDI)73y$Y}Yd=W;NLw+|tkX)IV5ioD=s;pj2gQW4RiC zB-FasLPb#k=hT;b544NWV2ZQ(x4(~ZUJkM3txog(3c14c~ zEi1!i>&)dGp;hSFSj23{je|kI_g&m!JIzi{rgfR$@|z08raF3`e7nttrP`XP?SqA` z^drk)NfVz`mN8>8lWkzm+D9E}c9JW*y*3sDPLW!Z-+t`eVuL$?_KNMV_T(ggSktHuSLr~VQ)DRVCu{KGTP7nn!^M!>@UNCm}ex3?Kds0`w z**NpdK}hJnuKH}X3!?YZmkP;%*w>Z+PD&T#QxxvNiuY3x4g#aw@TYR7w6R*8k3P9o ztc{FuV`jNMHaaObS4x&8L7Z@VKb49T_ZX`N#C=9)C!3xGhp_dVYP*xfj&U@vmq^2> zSHoPaSVi7APQtg63~Tw9!-q5PLm7bu7PvvD`xTML^~4SW(fL zpy%Q{O%lbTbIeoOmjnEjt7D(=_l_~^Q#c)6(-%E$)GnMtRh_~!`K)#I^7)vP_y0IH zs-#ho{I6vEv;z_myYh`)4FDpT^-otFkW}$rp z68uN~0K(0)BG@XVV2ITbi04qmD~XnCJG+JI=($SDjqw4`LcyDz zY{NNpKNY6)rRmgsJ$=DE(K`!!YXhlMMByCi8k^K!n)Y}2si}nLHilG)rERHkjRuP~ zR}QEZ4jB)J=6SrygF~kUL7i@_=$0B$>~cSkqf_4%?Cmc6=Ap$6uPub|pbR*s-msuN zzvK7_(b^t4w%n4`{d%p#d-C9wgHRk7k#vYgzjYHfxf2E{#^-+AdBHGM7rx+NK}ERb zFqjx20Y8vW9kTxTl>cq~a0l*jtqTUsx)BYvsNPe)zu+$2DbOqm1iP&)A=gE>$Cxk^1{X>R-wZASon>Ph{+p-8ep>0RLu79zqt+!ogIC8j)O zOO#7%qhj4fnPay3`&?RNYD@O4rR1G>P80W~A3}=tZxcTtZexY5umPFq?gZZvkvAS$ z9=|WC?v7%X^jzJ{v$GA-e-3fC7ewDZs_(yL7$`+&nSvoy?@F-7FCj4l`P>Ufh^OVt zATzVTM&NmsyPe{yDlZLim=(Tz$D!_MPXld!fa};yc?ZSE^_-~HKW8eK^xf&*i)vZP zVRpIKYyB%$?MaVS2`9%#wV*{O%w;A)1D{V&_+I9DL?(?ZEA0-}egcoC6< zhjgBREyV;Eh*}?TBkHty7Tuk8C0dFL)|viYWx)Z|$e$Y*YRz@Mw?2J`nkL+9*rkw? z@>G(1WLrSm7K*DzT~-o3HOgxe3eN)X#9%66H1sjC zLoJISk>;2hSfD#c-tP;wmBY>m+93()K+``o=V>vo(!W&4Q%XJoyt26>#B7y+Y8Py& z`RVC|--F_%j&q(e*NG=ArMe%*?D7(ts*iVu44+un_45HZ8PMHGUF&+R;JbFi>qOi} zZz$(n6RsvEx58zSwR3fPEF@U6xIpk0zr?3QT6y)pBaz3>XraM`+P7~6^X$GnF7G-+ zy0w@AqnlyNyJms4x5cs+ZY&Xhs78#G(N zOVaN*tx!qXrHZ&buib&45sB-4DR0xATAo$wfJd+5jTh@$&X}(F@N2|im6gq|&I!Ux zPZ%jh$dxn7pW>K^P?X;Ze=v;pWV43aW89Y)QgKFuz}IEIPNn@GpH1(H9y%pk###Cz z#%JY5I}GS=MGM6J@?73WFUE&T>lT4#_kJz)qdFzY4o$Y>>^rc;bG0J;gKdCIil+Jo z9c;LbcjLCn`AuFVYCXZT5@KYmU6a^FRo6Ou@YHXG-%LV{jwO1$kvPiBxNt=NcDOtY zZ=@FGm#5OZkmIya?wGH7YGvczXiAB>4Td7x#di`nsH+Qn~1YoNkH z@wEtR2fO0ic=QSg(9*DIqm?KDY?9Dy9Dg@DMPfPjl!c%1ycsHU`S_;|L)%QnEJ7Pi zlF)zFvH%oCWB`K{{1hVG!bC*BG$ntc56aOX0t`k!ttz`>T)g3gNSV(lbKr)p+7Y?> z-6=03P2H7xa*~ksmTgWEeZp}97B5bY`55KbI_hqlVfW3jB$1eeft=bXaZ9~?n`GS(TRs)TrY-HwBiv9}lrppD-BIZcMpwEYHcRyIJkAtv4tP01Lmkn& z3ohrAteSUsyWmS#H$Vy|hh0@M3q~e9;({%<*g9OvI z^u^~^_g-psYPN(_^%V-i{5HsMgmGtK#1PH?X;A-=%|pbD$LV98;DoQge=?GR;c#+C z>XDE9VOi2N;i~E5trKt5Q+o6X&G$lS=QEGX3VO>i%R%Yo%Qwq>I?6LutZ_y=`msS4_mFU~s?KO{-SA!cSN-z{ zcdW1>jt>RnoHA>x$8yX9^}YSSfOF>aV?9b^$VWUGhe7-y!(&N&G+)A5pKs=GXyRlx zlW27fz(fs5ATH=i>P$Gs0=841Wgrs$a?kpET4QGds)arA(;{z}vpdNnX`Gvq9$Ha$ z_V-v4xgN)0Qal(-%FT)2R5{({iLRJ+P+>{kA4YN3qr7+sRxxuoc z|F}GbqrJM8Y*!HL)bTMv;=PVnCFh)pLEgZp5P2IA7&ELsa|mV3lCu7K184+W-_z!I znBuaRRXgO@{KX~ysl2!2lSBMEhBFr}%GdiwEDycERS8bDP;Jkg=8p3ijg&AXxGEYU z>p6c?ND2R+dJm}>u1mtczk}4?w3~AEq0YUIYsdd5F6@cC7xr1=M;cri| z&DH5#^taU0AnO2o|FF>H{FGxo_h9HL!U`E@7C2Vd`p7<#o4ulc3Msp94aYK8)$V4j z@^=a7iTAa8d<3Ll+)VCFh`Se1@oIh)jca`!`0Uvpgk=_6aVUV#^ph_^0tcD_-> zXb)Ef%~;qeTSyB$eHpYUCk#*zu$AA|3Se-yU{ptjzS6k<(^EoOk4K{21xx(Ac&{*+ z4=c%V6oNNcx(hz$IV?+z7;}B2oK_8rF|3O~ zYB?rVd)QwZtGGr8rH;6#N3#s>RbROkQW|>V^ z&R2vtHpXuya}8pQWr0U9^c{p|>E1WXTi&H>y&z98Yhw4sGe^}M zdkJ;F%+$AkQdrO`%jLfY)`i=!%0;!HbiJT2AYjL;UQzW$BJD2BZNeQKBrpvQmVZtZ zn;CfDH`}|-oUmvSYKb-L50(9vT;X3PlM)Nnx==5Ov4exe*>qoi-?;v)_h(C;PN&N( zE4G((BO-(h|4zl7T3ec8!=hytEj*!8FqtOb2k(Bl)pEz5%*VcD^3hazKX5C9b8AFq zcz1&=l*b(Ud@htn7kw!9+m)_Vmv|wHZxsk4<@T(zw4zWqK3|k@?jYe3pakG0cN^0TP;l{E`L5#1f*(h9*u(^eDW}Cx-|n;#hTWl zgpWzBk#};R&-q`52pLnBwhxA}r&+ekdX-v#F#gUS&6nK#>pJF;5PfZ_h0U?F1ol_{ z1#mY<;#B;cvX1rV{cq2TR-^?|;Ih_1mP8aEu0qpsX`8*++r0|4@6`7}jkX%m$aA{! zVBOFB7O)@2tGS6rypPzjAMGhD=2i4Orlbf%Ez~6NXkMpuRw zT2c{J{Z5~LEQH@1#4-WHVlQlCL{9IERUauid~sQ<*8|Zj8=JPXbZOc9y#_HjA#cEL zKH93X;V*)4AJK!?@6FJSRzpf^_(EpGUisFDzWAXa_aLI$Z73{;xu$Du^Utyph$`VP zK=Yq-<$K*&q2-&2#On?nR_Csbmc;sf-S=(QLRO)G!X5yC8 zV5JQ{yaeXFAPJz%mAp)^>U1h7)XjO)n72+fF?5`V2eB zmL5F$j7<~Y=hHWV<=s!;aB(lRcntrP1qOTk8upp}nj+da;Whh|OyZpHdY$MMowa7) z)VnRz_D;#?Nk1y(vwQCIeq2&hD~_h@lCXOf~x<9 zdwx6TXm2P)d1iumK65ZlSizd5EdGuT&D(a*b;qFKU*=5R#Ldj79o>w$zyVUbnwHp_ z=KcE>^_O~0pddR>JDJjNaa$mRtX1XHbU}(lO3EW!^XuH5c~R+>0;~Et&%;v=Gvm4F z=92QFa@#f6p~olJk%u&;o*sNAaFG)?tLRm2>04`IeP@{F?dZ2bD43KvmVTXQ_WQj1 z!S6BS;16y^PRZKN7EWs? zwBwdpbbA(kzHz!1K?L=eVvo#GS?W~0R5PZF5WIe879rhr2Wus(P##sf>XOZ51~go? zT(_9=KFj1?6XQK8iyFDtyDZOLbek~SbNR&#hl-lHj3}4UToX*tnl-q98uy06hGi36 z=~0sPi2tKfLM$?fWb+`IYWxELK)E&4&E=;^L1xs7@z1ZU>FkclwsKd~YqmHP5k2M( zau;m<#lajy*6j%5d&lbB4 z>f1K2?Ot-1!qIhuz`rTds1BnaZ}-j3|C(}EZ658;%Mu9tMCFlz6p^%41M|e4NyZ|% z0ZR#Q@dxqPF19ewE6#SD{&mUskP1~+@s+EjOK(8T#0hk8>iOaNW4XXWO0Xub#xLPo zrDvUQwt0WeN0fKNbYA>*b3?SSqQ!PTpUkY9_xItto`F*JrJB1jJZIf6aOWuS66?{i z_QLP6pr(XQU%i}*X~dIBs=#$?vmDcNA#Yzv)eenb0`_z>A#MU&97vQj^QxN^0^4Qmk(!qMX;6t;gi@y)mWynIrI9SmW z${YUv0UanyU-nw}2Mr|l=#W^NmdxJjWn~qJH{;~I^y4?yuE)j&8VbC?{_7&*)6Uuz za-Zl=stmBNX^s{^$!gM9l4_^oQ8%(!l3a@6Sf~^G4bNV5Z3UE3JA0<0aEZH<_1CRHADSos8|F&IEZc8-teb{o>i$?T>{joWgxU)0Az`>JYAOQJz-}3o5`R<(v zlKZS*Pe=tu^KwTFs>-08H{%O_A-0#c<2R#Nn+|lC_`wQv>af+5_fi=;+cI)#10CnM zlxPlg3@V6MW`pGR1m=XrUNQUU9_lrV)9ODyO7L_LsRx1=i~j-~G%RmCuap#dt2)|n z-&Ai%2`At-97<&SZk_$O+ zM?lQbElEcRLi~bH4Zg_yt}xlQc^x?5y`ooPQPz|MCjK<7l|o;$ORljQ^q>dvWnirC z^X)}tGKjb}W~vuooW|vjM;hf`8iLFFclzDgdcx8?AasOMk8#*^+4b3dfa1 z)|Vr6ws@7mNj9g%vvZw&qpZB<>3ka*aK0fp)!=b*veL2zSxLY3f(m)N|3V|p5qVfs z_T~&|njM7Zcrl5TZJ1?y86`mB^*k1bTz9zRkTI4R{famsAdK;MlIDul*2*vmb}MIifzd&A7342w({ z1=4lVvS|f!_zrHkDsSm4VsOtfUGW`}2ci6w?H4EwV!lgY8FI2^Ru}(RLZo@} z>@#y-oY`~cJahj4{mkt1d$IB+nPjb%d)?)GU)S}C&xphiM}b^7{p|0DEaR))%{SDU+~K?_BG^V%u#RYt zY~n%YbHTNA5>-)_va5$Ves(ttt+)^9@VQzUG4d6h844sK58m}~E_XPjZD8Ix73Fn| zODB((eQD(Qo#ah0x5aJ<`9xnAqvbM~aqc3Zs~wSMyc7T2n~XlCV6|I~4b$sOskVI_ zEC*)MiOlQEI*x*Alz!QhRdDl7Sr`;Pr`;2-be}sUI_XxBk|!BS%QPf@jBfh`dx+-8 zy;fokss4IVUMH*bJoahgup7mfF(;+efv=^En$Guc+@M2brvud(lD;;oNZY|)xw(pv z3S46^DlelD-1~IuSNX5Ya4}C02a#`klq8wrwD#)x#P{;4tW?>rq=+N-T@}n4UshSV zGG@K}?kHZ~&;p5P&6NF^a&TEE&{jNs%jW}Y)N0nvYSE2cXn2(5@aRS?Y-~Wzcvv>3G++^9J<;WT8LOA(gc3Z<#&Dc#OvBqJC|%pMlrl)vGE@y62P9%RC`y`S>TeZY!@??*hA1Z+Cm*FQxA~k z{LSC?&KibB%2Uwy-o5f)^h)MJ1+q?rzg=m#@HvmZGP+1Ff)x5k>E&)!nectwA9L^C zNO%NDP<-jmz{9ujF@DOCcJ{a7dj><8@q~ z^N@O#}SRJ~{2mBY!f)A^&uR zhv0(~>pPPb)m`_U|iasou)Wpkve^`$`S|D5=vKzC^dAciE)Bk>e zMooG9|5i`=pOQoWn?CdJ)o%W?xm5p9Q2*h#{==>Phu8ZLr}!VbGd?#5PqX+hrdm7h zwfR)XEb6(j1IOx{^^flUaepgCGjn&pG7n32QE7Pb=Pv+dVsx9G-dOG5bz%Q!;{^X9 zSN?-g{0E`<4?^)DgyR2qgyKKY-hZgX{~ZM9ohyx-FVi=jA!i@c@H+h-iS^nGB0SDv zO*-VtzzRMI4^nxi91+n34`&b~f5`gcH?t9?d_ILBJ`45V%n|+1#_IknyHzkJx2SAS zCFCqPB zUX~v*@!^IV2i(X@P$Jpjq#3P-3FCG|o6#b7A%A!k@*;x2*A2^jlh;Z+P8#NI0|A}yv1Ty6tNujA+mV^+@mG__UnK;#0UM6qc#jbcU=L5CGHaL>Lb5u=UiK}Ry$IW27>@%CM`H_e$Ei(}h!FpN& z)+lC%yjmC;hO(>jN@;d8G*A_1MvKhlM8K1DJXkvF;50*VRkqUMfPBdfb^|~#zpEWb zunK2nFynhz0Qxr0&JWAl|JJlN;Wvf$hDPU%wBkKzLV|mff0g@Agh1L+NWht|q~yIH z+H^t}gO{|pjKNNk>s)CH2%4jVGsdGh3o9b?5m*d4RC$yM-At|(5iUvV3C;CLDKsiL z>5t{CzUh6*_;rhQK$LiKf zDqhFJ$b^L{bMS|mVMW4kGee7WRhyT9P|^VA`AxNhFE*Wf32!NLU#=aaSat^9&Q-75 zh-pn7{oYrmg}RPUJi$_Q7N$h=>Dtb1`*TYyS|29^2*=_!uW&^3on29fM@aD-#@QNC znS1>8vP@D-lCiPTE2_#*iRP|N*2m;l^H6uC{s=$``lbfqd6=~fm{ zHF@CuCs%;enZ|M;R{9mgqL7fput-aUAi-E(yjka?N%*y&_H+|anHrbfi?WuBedFdX z(9zZ!FPiUf#mG-)?n%G#nzkiHMvy6Bw-XP-%^1uT@5IblX;l}SdD-@IBPz*U5d-7T zs3BuAQ;!Ptux=UhIUQRPbwtNzIfg z(WySoTVF21ytykcEXUx6<_!&A7O$+Ko!B$&THiCDt2wpATSA}s%b5%QDa!r2z%cW3 zd=#hYbrF2ugFKJk9t8>Cw8yFKCU}tz@-HDgD=V19#E+#GChan&mMTl`Mj6 zQ;YZN_8C(^%hJ(ZyVS*jue9Sn@Cco3={E`yKI_Mb_4?85lcD25mRRAe&dlrB9ale^ zKZtaKt8RJ<5Bhr^;zF5ru&SYw&**m5e}|*Fm37=V+C_=$8bn?HY;B*0-3J%$$|{() zhhN&3RW=N#wnVJ*7(i*IJXwxa`@9DCI9Xu8wc2~QQM~lER5sZ;-yfuvt1L>PC0fnb z+BqY-mSC~t{r=gQ1DlCbbh}c+)91H>@O~*n#x8USQ)xL67dT+$``P`8l(d|0TW@U%*JzSi-k5 zl<3PCJwS@(6G?druDDu(?|JL&9XDYi1^%ghsGIid0>3hwjTt5G*Zsw+#N+N6H}VeXr< zgP$y_a-)0Q8ZX}w?|a12EV-aw)n0!bkr88B!adPBd*>_DaoC@SlG-|9J-9r3;ovLB z=JTQt4 zhIe@dZe2G#__ce)5L2DZc=+jC_A{k{igsE?yQ(YIqT&4A*wW$hmA$xz2?3N3DI+j! zM}LY)I6BNN5W%(B^MEKt%GR>%ihNSK8ZUgH%&UPI)ker@&%i;+eD%3w91po5S|V=7 zhjAut_F4hrtNZfz0H%;u3ZKbprOZtRJ|4lzG9NjIar zA3fq9!E=ex;7M@k_W4LuKP|4wFq2~=NMtjkR1$^^xTSZ8EdKJf+)k=S4?fUa1{5S@ z8)RqFGA(0BgG(`Zi?$Jc!6Col@6gFw;~`HQ1&a z@f-SdKx-j{W$(4l_O`6kLq9OLR9td~(*a~xjLDxw4cosGp&C7V1pP(!7jP)=_DOrL zajD8gi}h(joZav#*#LpHE+O06-7OClQh(VE>$bT=it(JY#Y4Jhxl^OVF|#$ln34Md zz5$w%Nzep0xiOXpth&o;9MCnxm|Q^>&PkYZ$?h1smd>>~_hFl=TPNe|?lSP(zPaw= z&x4Ad+Zyz`^$5>lqt;5go2j$F-V1xv`@Xsx{tRrFnW+Or9i*g#OG&oAt{oe*y4em}aWXf|JNYaL>|f^YanbGJ1mUef%58 zQSkDtKvp35MN6JOeER6P>E5r)M>R66bQP+3O3|Z4udP0Psyk&ynQA@Rkd;P3A+>D24utOXs4qpP;mS9MXVJ6ESw?lc2i{OQPS5n@cWA37r*fLKcJ6Gy30uf1ELLS{ROP%WTH!< zdP+Lz2M&$xpQY49j(2pcpH#N0_t9(L4F#~>5>lDi_@+>kS%R0W^H>}Bt+!85yE2}v z^g^ybL)k@c#)KRHczQtcWVsK9zT8hvd}3aFrGjBh!)&O9P=T4uo0EnE1A4awko>5HZqmjfcs`+Rq)K_TRK{Wcj6Cj5S$jE$NIa zTpo1YMZ$A`0Sj2yH$x{QYe9Jv4|#?T93<0B`pTch0X#bit}9>?8xxFRTh7MNVJK34 zzM@1KQAxb~N7ej8 zW{ts7Nja>p3wBl`b;@a@zX5-e$*CPl2--RC!g%U2K?j@*!T0AEwdJ3YopP_6g3xK052XyO|z}kK-ebYxn5xB7;$Yy2nhh{vFV4lL>E9!yd zqfrFtoiB+!JkZV z@lotFc`g*_9FHU@^*`>x;vCG{k>QV(bC#G8hxgiI_69Vwn4>aT`@XRg+~06?f73MN z(na`-UBEQfrghFI$K2Q;Sd~`KD^R3edcLAeB{Px+G*BqUH|nO=ZcR~QM3hf1uOjc- zeAX76R*JJ5!}=UGmj6sF9xWF(t1~Dm%k~tq{UdBe!>k_hLb!j%jYNJkA2(Uyx+3^p zhT_#+2>Ak7u2ZOCt}1?N3Gd_nF_)}6CB^-vp+b0g@TvbeiSb5PI1~5i;mY0j$3Ajc z_Q7cO&6&-qqr**P*w81-<;Udj2?!o1xNPc}eEodL-PJ4hp2j5$TD=qZqq8_Gp|xD5 zSk5ERqtRL`Mz^dbS0-z#PnS&ZvSW%-et;Mtw{CZMA5TojisVI3p$1R}AcKtO(>H^a zk1L+k^*F3D92kAc2F5p3-Z|w?V)IxkHuu6V_S^Dfbb3_j{cC%KsLo0=%f>wEzI_!2 z-G1`^$s6Igu%vLnV5p82e!>u8jHbHl4>E1U=*0XUZO3^7bHsWPZ6!;uMh*PpgvFxs zv)I<9JSWm zZ^*Eh<@^r$XamX!41npZyEL&<*wm&Ufp&%05T~f^`z)UvKR)5J%Qg6#(+}c$D+GH8 z&oG;6+OH0=$TOb)l^xHxy}mN9d}u111&M{)RH~AR0J?0or>R? zmy$)zVu#(pvl0X8J+<){GM@d74^QpDh@lt3mWtQafCcmtRiQj=PqR%aag(3w z$JHJQ;Qj&_i$XXu)(*+{%@yJQE5!gc&I4%MjRATp&zKMLjlSsGp3^P+se$*63+KM<;V z7L0L^U5^c+bdhT-&E|`26m5T50UBdkbUWJ8j-tuh@ji~pa0FuhHZ4zvBu%Rv_Yw1NI1aep zH(fYQJa(K$6~l*h&689fxBv}{J#qZwe?pW(&BS`P<}txfMR~>Ffa$Df*iJ>W`zmv< zY;T{es$D*Tl=jOk_@*AIH&b!!GN&{1`==$SV_E2vfpEKLEtYScB+}SlHdOz?HZ=HcI zCmf{74^L*HwMdh!90|W_0062J39sa5ZaDX{Y(Esb`aSbE1Wq>z_XkLhdU;j2nyLu`ZA!kcpBZicIl%77v zB!7J;ouWd@MPRL+v9TH#i>{XIS>dm5cqjLc&TN)hRNa8G7+_hV3GzA>UWn7=TS)vY ztM+UUF9-yBY~b@mJNZ-l+P34p@`WQuL>^UTE%Se*p8j-nDEj#G{U5d6ro5tZvThTY zhVgx?X(cVMn!S@fSr&tVST9AHa)q>#!Eahqu`jYyo+!YD7+J&8_;g7UV2^M+)nFAe z47`iZ8(b~op+vjF6=lIx8KAreHcJBfp7w4P#8}ck7Nn9i__`j0Q0vV*D`~|tg)3Qf zGQy_{u@q6^wMxL!>r|`enT-Up*F;^eCk5QBl_3(2)C}GqLkrai#m@^cUOghE_%yF} zNM*Yi89qUYJ(M{|cIn6RVlU)D3o6F)+iS50Mvl$wfNH!By`gbRMvQ8ogBN?dtJIZ6 zvyBDiYHob5`rws8TzQ=aN(p?F+OpK)<%U!&-@eX$;u-225I#SdrBVT{0W&JhrXM%%F@9gxK)yt_CMj(C z%JayeSuzfO7rQ2FHu_igd5(LF;k1uy3e(4&XQcZBY`8N!2h=44stVR=6vbAB18UB@ zIaubAa^-tx^UV_~AIPns2~q9`%!P;sxMqq@PdP16B4{~Ui--9u0COCh$8=@C!h!{3 zY(Gd_nT1s>{yb;-<+o4q%`X(<`7m;Rly6<*LHyE4b;=KIK-R?^lBb^&prnkB&9PQ# zuLYxQI|3L>%6DbusQEsgfB!TxaXA{mXEMMm8p{>`!?8l<=L-Gwm7%jAnzfd8C8$8G z3CutJ(rhUmK}K&pcn_a@&NH+e0CSE3{P|ZG&2;5ZT^ftG`!GT{DXjgE^}nZDC0uKs zlijXL&j1|~y{N7lW2=iiwaktiU}#X7xO)|l+Rw7xR61CQ>ZVL+OHSdb)VQuBn9ljg z+VN;3!Gd6+PlWypSXW6_Oe3R+OD}#4-%DS3%?u>204CG+Bzj0~umnU52?V(}~-XUoSp4 zlrCU8O1KS>P!hsUThDG_wvMBb92d%oanh|#?6jIQ1uZG&q4S54q_a~*?~B8w1_rdP z#g3I4lf>bws6;JfSYMfWU4s-ZL@&ym=BHI3%aWJyRJIQSY_FT5SRmW~Fx~Jo^`@8k z75k<9Zu$+?BwUpp!h&dUQ^3%MmXrxEvCvfL%Sni9)@k{kKaDi};_4X!MHJPnxTX$F zPq?P1>afF&HOP&$=nOa0EsEk^T7D4L<6_}Zz;2hVcQ|NZY9qa!@TsUUn^9uqy#2t6 z5QI2xLb@@)OPru2-qcK1c;d$`*TG&+_6aOi?>x)wN*aHxC-{pii}l=_Z;i+|yXREy zf4m9aSdxAnV*jw`gl+EKS7lxXTUEU+Eh=!m;2ED&NKeO9VN0gMbGe&o49Nz$OoeM% zUwlap72;gmc`w5m6@0G?b5o>f!z{CGdqG z(F2VC>kk5S7u@42DUsnXU>-*qKl$rW1>OCsr76;q#j;_7rIAhl>lU3@^zAmGof#DC|+`!bJI=_<|M6s_%3{X`jtgi~dDpdpqFE zm;4kx072@r(u^YgSYfmDngl{2Vco|hNskGWAg9@A(PT8cs>OA2!ORt;e4nNl^LE_W z!-paq@|L%Lp666IbdFo8O#M&P3z3IZt(va6e*u_mb6n!TT)zla$}1bR2Tl)u_^g}p z=Ki~32ai{COh(pPP+{?GZ}qdIh6-be6jPyZQT*>zKHm&Yh3t&1-dqddjIWc6{{kk` zx~?w_G1Yi5qv9ox-d{kTP{`%4ymg&3?bN>j6|=v9^Ig>*xJy3y@j<-64GbTEdOQ^p z!MVU(+N$t}( zRs8*MHou;mUC{I)U(78Pkh!{P!M(W9$JQ)+JhQjs@Exq(wRhcLz|^SKRn{TyJIQ}IbnbuXHETe9 z!E%_4a1U=A#lE)c&Kxha(AKncc^S0Y&wtP6Wt`ueFHe=r2`dU)>IpwSMAb(GyHw-J!;}33$Va02X{{N~V{muz49gArpEdpjQ_t}AEsiQV0!-K~IraZR=bOMy>W|GbE^?)52OESc2sVPjH^ zB^nj|R&}O&3u(aAdmLfQhc%BtI-?D#es(d63MBLd-M+ztDS(*%8Lo!MWz{zYfgHK+ z4$E{;_XT&h*SkYjPvV0*mk0CfKPGfmn+@CJytGo`bA5 z`Gc@m2f@cTnVc(M9uWRHm{pvgW@8{_BgC{~ZO;|2N;WzaT`mLhp#F(n z)v8%p*pu58PC-K|iDKkAqgZ8&ACx?EZ6OkWF_uJ?0As>BpvA%qu_R}0V*zMRMqJyE zMGY@VK!r{*X!Yl$Yo}Uc1BIv9LP4Lp{K(dO-xme(Z&|J$@V<6fnLhK-6-nEuSuYKY{@ay5Fj z?!|P|k5AS^N9<{%LyI$qZV3+vca91Dr_m%4HLu!|y+>=wT|?-6mPrdeAI&7KxHjvt z?Tck@5hYj)q;Am~Im(Yu{`eWfg!Fp5!iIG(a4t@~>tAV`p#g`78(vpHFGr*Eb1j*_ znRvLU2GI6JiZ84z8UzYnDPUYtI`(bBT(O`K8o_{R&o6qf=M7Z+b~1CaU%@&(o85_> zz<&WGH|)E%e0Gc$yINu!tyyREa^_TE;@P2>(ioIDn}%XZOzmoe^bM6u6fq`*XRx z^;5htr-sN3qXxTXn`{U$voF-Fxk-xEUo+PMuUa!rAZ0e?>1xMp$A{GH-te_IpUQ{` zvQ`G_HMg9gJ5G?lf868oIC+*%6pwTe;Nnzp3AuN3pVjcLe{7%ZTZt)TK%O5Jol)y^3dxywZ_vbpn^;=OM{Y zVu|F$d9!%~9FvCrxNWJwKM!_um-yL59L(bX_QpU%e~RT13t6^HQDA#!K0NaD`mNPt z-fD)z;VX5b!~_LT+xLY(FZ`n5ffR%~Q3q!%PHi?W@swR86hkcZ#BPn!ig^sGoS`xZBVCR{ZhVim-)XQ$2j-?$NgoLz|rW(yL)N z#F*{68v)GtC&WdS`Vo*uW^86oHg&~a63G}Z5xP1i4C}pn|Ap=Ze?5{4W7xaGfl;Ym z=cLxTUAV$KThlb=xX7FS8W`XspGPA&3iYHP}ew@#PDzAE#p(owEHoUL9mpFbG$ z;x!k4k~+XAx|qy%pM>=_0Kh2^lfX9jod%WpE9$Tao1?ZnHY%4*(7&v0dfmLotau-~ z@uV{*leRb+_4}h1{^&OwtlM$mzMMY87kjAIe@j6c#MQcsHW9bAG=YM6%r5T> zQRg_O1b*N*gXt#^5HdVrusRnbhdsoQguTM^Dd#>4=K*cBMDFDJ(TG+Gd)d6>&?Xs6 zp?8107{~uzSNgYDSP12Bki}uy^sDgRkdO*3PjHYQ*pFeng2%vr*o$a#{DWe>7)whW zMs^JVP>Mq940v$*i#Pb(`ksOokD4_LR(wx37zy| zakKL<{&~(mTNUhh1K}XU@7lYH3HZlx}KY^A+kdv{|z3sC6tEUpmdJ{hQ>ep?YN6$Pytdb#b!3h~TPP#aj zVu1ajwF!z-6ldjOeIpL4bUan#5dRCfccpQ=13xElob!#cZN_TNrp@4Stt`Y%&1dgA zG*8Jq0?lKn{TMDaHtw-PNS@%THx3PfnDG)c#OA(tNHogy_dq6N-cIb8d@QNhI_LvC zN-_RB4~e60sNOq5!mJBYC7Si;*w1;?&kW=IBcV!Q!@$;aRtbUZt%K#Q>nqwtKWcyg zfME1z2=NUI&dVssP2{wz?O8i!P3mY%%m8=0dxeVNYByB-*(I(_zx*__ zBG0l5FZ#ZfMb^~HB-e$S)I8zVPjL$ym2|QmZ@@ z>L)K|#Gq49*;#!J;;)h3muk^;b)y|0PbdRwO83_@LdBpyfr>eDFolzan*2^!?>Nib zFQ5}%Vp+ilf9@U)j^(-#_P`!vy9PT+6Z=@GqO0JCK-+qJXroF`km&gDYD=GfUkZ^b zsMnkAB@KQv*>7d8|n$!=SW`ahZ(;|>oK}OYiA5O z=3d3mWDq1J_0iZ+Hesf_IqnD98#q4!Wz0w9Eq)pmY((VhHF*oJ_44w4FpqU09Dj3L z3Ne#d00-mDB*tQ3iO$6{HLBK1(0?CEfyon0;DYlrH!rrNKf=%DlNvVYn96YhX3~q`q}(J4S@Z zAXdBilJ9z}2$2oAo8E||D_T+qT&6NH^X6J?5)Q%)u+8ZBe5^`q0a)P)i(SO}cX$5j z-xfzjGtM{jkq>#_=U9s%lbFRV3xk7A-h~<@QsV_)$Ds~*5&>FBMA2lv%Ey4pur3eS z*a0!K@w5p8LRhVrTAQhd)8ZQ+qP|c!a~%3$M!(Ldw{?8HunNkv1<7=M;7gZI^Zxz3 z`7X_jHqUb-qQJ+4kIEo+6iPH`ra9g@@BY>xf6MFExQ0qa@MgBTdJVaxx<#5lLR@Kw z>jh!=;SIjcwl_^le}Y3m26o0+D;Jv8y)3hm(ghpK;nF3$pc+lvaue9*%mecNLBQ}H6m ziwK1Ww-&<$F#OR7JBPX~J^1yLeF^JjTN@kera#Ro^W*6OTLG`QNm;~sUm4x`dhcG) zc~9*vSE1N=6|IoNQoLT7V)+{#f9dWPd|23|vUGDqQs~Zt9`S1ffR`Pss3_mmmDGCq zrpw_K5FIb|q(e|Yy^;8+G?u6ETlzNtZ*!iG*9sxwP!&=CS~SIZ>~E;m3Y5@7K{S;( zq0H+=)^qWN#c});jaEBeX+lwNTc7g*gUU}K+eIw?4s9qiu1w8sTJEv97dd^|Jr~Zk zAM|mM9BI$s`k1VNCkOdH8k9*!=Y@q(Ass3WYanKFLIDAHLAD)f*IS{hkMG@gXaian zg2Ih-Zy7DYy8L1Q*lP2E`4AGH?D!D#IlI0#k7y;1W?#R@jSSnZ1^MdtHDATE8b`YP z5M-~Klwjzw^9R~Z+Fgb8Tt@#^|zEv{!^!D>j^r&ZI#2`?H9z}wvt$n_|-w#5Goj;?Kx9z zv0=6K3WR1tn)|`FE>EOba<_+_@aP@jXg1l$ zn4nHKTc6^(A^TL9m53O`ZEdxDs@!0{t6*&HyY&uCARU+7 zAeEC;r#n0Ch42GVybZ3sRKDV#+mM~lV%2dyGrNEx(leUVeet8K=%`ORS-?h&S%iQ5 zGO+d@*ZYKQ5YBW>mHICL+*whYkzwA2m=$$S*hVw|U&|4#|8qI=y}{A>(b5873qM@5 z;`Vy`JLxfgvDNToAAEi{G`8Z`Sz3|LbUM>}v?Z%Izt+b;$*oBhY!YmFoKu|-_E-{Q ztFHnp^WJ?}EN^$)B9lZ` z0yYinU7K$m?FlQz-!%A8vL5q`N9fQKoHE6zNM9MuDKTvr@RL>As6L;p^0qNqeHNxW zD;;_^e{S-a7wi$j`)teVKEj9p5zQy483{*PmH(v`#v?|_s2;pI?zwvMc5GrGh13g7(*6PmusVi?Wda_iZ!t=F4RC@ zI=f7kwB+g$#0@PnTS&$MUVpg_&%3Kc?D?{McfJi`t5LaNv3ovnw1?i-Tbl-E+e`t4 zhPO4Rq)0VL$zH}X0^U)v&2@^xo?s3x^1?ktycJhzE%rHB8Y1`TTcQlJ7Wp`Z6ni(1St@n@?(eh6{3UY>rmElho6(IaU4UZpL5M)x+XG<26Ws(kBKv zc&BTW9#^>xLp^J8wP^BOy6IITNmfNxs4SDFXmZ*sEf9F?PF2KK_A&W(>%AKR|HZE? zwTYb1L-9V8KC7~L@1VQ<4NV=$hUnoU&^Kq0ywYMR#}nZJBKscg#V$Zc5Z=voH$<%? zgl-pwjy+_uo6VnpfiO#1K@S>ROgg2rM%(bJPtcCU#nseId4eSF!MY>mGJdtH)o4hbw(pW%lKfv{ge_Tv=y z`LOe6T4+}V?Gh)C%3k)kdEav~sHaR*4=SgsL4E5~@)j?uSk;ee(1RwVXRz*j#-*Ie zcOM&k__|gkkX`YaF;RMw^+=r0qe)?R$7MGYi~G!RsZp=vAgEtm5xKXgM5Hej6-n<* z%V<=03!nSRF;SGm4GCJZz)oOiFZ#H=4(EG=oPrztgKHVRHgbKkHv)}Q+rWLrKfe{V zzAQ%g=nZM%0oNS|4#^tc9Q8E;B3~HwJFT?re4KBbdL()<}+eWp;N50LP}chV8< zFZpZl?%Z2N;Oy376>F(h7A*9ja*@(_rI*Bddu!a_%X$ZDJ%sU2{@r5I=Jj`;r(SCG zFiUhEJx*i&cI$?L$y_(=ap6z7wvXxGk*PnfzsxOf-MJTC>@xa*B*M+_*jBL`2Em1` zvHE5YTm;7lU*ts|$t*vVPE}H8KHO>wU$jxG7R8O)YHRgG58%auzVfv$_!R7R3XS!r zwU}nLq}{WOHold32=4^n86f78rj-xP!P20xXj3UjaCV>H$gVa@>%jug?zqOuUj zWwOQC*uG2B%en6*eGRdJZ109-=Olsp#qo8gKWl=~&G{k`OhGv2qf~pBkvKaKdE+DkXJ{Ej4A*78qtY>iPxg~d- z+^Y^)aOHpthblcpi%~E99Ms2dX9on8fEGw^W?x_}I*V@M%T~j$IqobtI_moBy(1uz zIbvL;M6!Zk7USIj!HZC;XW15YiQ}LC$W3RW^xin~owH^Jn+u2e-4$=?nGC*rC5`!g zl@*y*Ed55BNp@2E+)wH;m}2MR7d%wYN=Pde7f#CgKUPrYk8wrVc{}K>se4xf#DgDT zyfBal4``*$s-J41cTqQVjoDVaE!Hh&h=-utQk=A!WI!i#8#~)knpWa!Rr_9vucBWW z+mQo1v_HZUH>bJr23$2zrLq}SHMB#W0ik*NyDI=pda7)OO5V#Yy&{*xe2Y8V%c*<9IZC#phJ3U1#TFM|*!7-*pL%J#;U~P(!w9Llig8K2aUN zHc|h2NLd^zbg&C>S+H=Ve#|kuqsnbU1(v@{Iwz6`;+!UnK0Bj{c zZOsf9)ex#T=WV?87a+r*v#uJ0xQKvXWF*=n;R!A)fiDZXNwfG~*h+AH`nb}{`i|FG z9zS=1F=GwUO1V_iP$jZb+}oaBU0h&^f2pqM+=+EZukCGkMCW9yQFZeuZ`?uDG0F1D z0qDvK8<~OTjOL{F5PjK>8Bbm7pz1S2$)!EW44$X>RsKQj^W?z6BsxH;kXikOXbyhr^~lfINfe?r66cY-BH3?u(Hl9%_edqY#4v$o48{v&;WBD?IA-&HK;rr5fQN! zf6yjcTLd0c9^3StS{T00k2(6;P+6SZ{7v$S1DK=@iFF?6!aWsHVFRDwEcP6FkE>Vg z3?Tj@=hqFowDK91YuAr!(E2E}7#}&dv+iGObr6%9(QhT8=Is022dlg|MdwgOd zK7QS`tvM1V@v@{BP2o3~!6Lb0O_tuU>`~Mmq`Xug(7!OEZG1mLcjgKiCnZ_-d6HB5KGO}6i)KhM~XPm(sc-+N@UaeU_`wzIu*j{|^xRl+9Q)?XXv z6GF6ywaj2_mLP7A&l2D4oKP4i{V1#dGV*Qe5sMt&A%6=81FJ45IHz3jEzkb`9Iteu zk8h>^HT>y%yw16LwA$p;OiDZDM2@4FMqN8Pm$xPF8Qa{GEB3Ok(gOl01{y1b3R;|# z7hMY{9^JVu*OrE2A|jj>T011$AZOx)8(#6gf%q8|L99CF-$Q@xBzW4#LRgxbHs8=w zE2Y}?dr_MHNJ}PhNNn;>q})}Y_rrochiUiBQ&*RcaxKZMtv?Tq*!&nEWfO#&-cSqO zfyrQWF;02Czo*rI%HCe6u1*JsX`iK3VOl<^=5#ozU5*}!3=81PIp)sy{aUg9RAvPXo7)Auk`}EbarKX_Nrjt3G~I~lZHRkbfNaK_OIpF zUJwo*cDb;7Jja@zM@d(*@&gY;o=ziW-YhPAR0U5ecUC9@HoQPVFKVS{J?a7=pa@Ckk#u1W>3rKMu9 z05|Bo&7fP+VnQ8Rjj&cG^?=b0V1p_zy^dzxWFhv!+^1?vgg|UapB)o!bge4}rY#*C z#MyVQ5LxB~Da-61gFkc0Na?5O9XiM$8dz&A)TEhb1#u;6;xe#gXweVoF`eFg9})&qSKqzkSzWi{){Tr+FqXKT^S-UbHqr;fhMzt}VCx)BH9v9VOD2>lWMD zy^vFgs-kzwNmwI1oi72v76P!RgB$r~XpWn4i9s=bDUHr)Mw#e<%-F4gO+qRuJ09l0RKt$j&UF%Xz@-s&hI${3*12v{+V8O%59a_&@DJbH;Si zV^{m2AsQK)$c)|_+V4KfPZe9-%~&%KHu^dVQ!<~kL!^1GPL$ep)ifOIR_B6caf_F7 z{VIx>>x7R=Vr#7;4qb30U5@^FP<7K*?_+L-e#)VmGqt!0IemLzfj>ch#gY#!N1UtXNX~1&@QU}AgvSl(mDJ2{-KM~0He@*> zmKW&vCcRnp#a)s3*#>>CHW&4B?HsmufC>D3gAf}vs7j60SzBdWcG)kn@`pU0tA;;x z$e6G(0du!BojU88_8FI_7%}p&GO0cNJw!5Dqw)|p)r)Sy`cM#&5VI+^N)&T&rG=4OkBa#X>2S85;>`;DW1o8@e_V5TSR?T6 zK@1qWp2-!E#2t~G)B^DOS}lOnTYIQvjNcm!{PD!&<_EseeYRLzAJl4YzZ?`hekqX4 zRNQHHb^7^KjU{Ca&4e*45&Mu2Z<^8SxY?}F+z!_!&()*cWp$T;3d_bxa5(}X+aZyh zG{M|ByRTgo`B+{nt?f*-D!GHf<%7J#^i%MKISLJ_;Lz5ab18scGV-v6i`pHV&%QN` zfE!S0giwO(6u>8}=`O{&mY=d)IV?j0c;IjZBewF<9)8QMIYds>E!Lh-2z57sx?%atov zt2In3OE;~!e?&-8{awXkc!pSL7uR`*-MaJp-(8e0oeaqOG+`wLE*4`1vbCwT@lsm* z&Np)-{fxVsnguGaEI6}ev`7C{l$IUTn}#2X0xjUm`cT{Mf{u1Qya)3YID3qal$lSo zd*hWvouYnnKfwR^U8fRmejr$2swB2|dU$;dV$xA>%ozJ+P&SXaHOIa^&nR8OK~NVH z;Xe(I9=g3F_%-MuI#b31DOWLCFh`uGXU#2Iwz-Yd*nCW1qnD|IQYB!h~m(2dlxzAQM z)^u9eskOm|L&!ney+r>{g@oh&=l5BFKbLDO^;i-^jPrXW={jLSO=Ts{jFWNIRUwY) z4ey6HT&CJut*3l#Y0Gibe_~?aXQgNML#Z_Toc7IE&qwzJ`r6Fz?1 zK%XF}az}+8w|d!u;~>w&!T*E3_YP~SYu9~)QdF8Cy#*2h$=Z9LwZC^=`@Cm;=Ui*OYoGJ}F|Ui6876a1 zp7D$^=6LSk?dpwy{@5}jk!Q27dmfrOl&4AF94wHiImR}6wl}&)%Kao7FLSo_w_S&Q zk^=`75zH$zJ zVIth-8;TbLYJ~`k1L@#l^D z-0%__aa^x2AEEtpGNtzxi9(^)21&t-SZvtBq@C%)f^?k>g6Z1B%?^tN94Wf7B)Ezd z*hX!#>28!>R+Vt(x!t#k8rvKt9+gVALV{$d2-pYx)yMk$=t=1o4(0B;7^aNYnJT$$r$~}^;sQXCY8d7*< z;x*ul7CZOsSOASTXqDi#-#p>2q*95`O6$U8y&rcjYE{+P7C-r18M7CApEiP8Wr&gB zYXlKsa{N-}^~}(ZZ8~{Y@X!rgnQWQoS#Z*E^#nUIz5^v&i+cul?Y^jW>NqmnKcH1@ zU8JsJl`^dxt-=V-C%{)CouBxh88#Wy)qK(d6Sw7^zQ6HHSN01(gh94;ar}}TtMF=K zUznn%z}QYE1;><|mEP)nZ8On5;nGl@^_hw*nfYT(m#E6>BP-DQckDNGs+@ZZve_SW z|6MZf6^dw5Sb{lunXt~dVPt^oq)Ep!C9Zdt$&#g}|NK4gwW_pT0ulZ+II)pUUMqgs7W@DlXKG?>3=dT?@0?wT-#GL)q(gtIKL zFL#2!9yTae8$ocep0sRM+iqJf~s@`}&MH;f4U=_Qr^-0Va!PnM$Gd@NA1;^cotnMukGo7hR zGMKROWN}VobK?k{r?&Q6c#l9dgFt^*tojx>Y1D@VtD!pOvTHQk{-MHf<7{G~F>h1Y z34FpJES#|P99DCuyU6i%w5Y!25`8~Do zVo!dx!zqR8(FFUd2n|YV<$U|5hfPs}HpYoh5-!9G10`)2SQ|b26gUUN`w4okdCzor zYc_wV#KR3s+Squ~OdD$P5ICXZnWOLuCoqVgJ7q8grJ)WvZQo*eNc72HS>8{Zu2ILoP;&W6P2QVBf8 zw3ddNhdwiT3O0rtjkX;u+>qc;HdqPKynowc1QgRAE{(57l4@zZgnM1vrT)Qk%I z)X<``iN4fi)2KLCaMrTzp+S&{22EL|1O1dZ|S(&)Ov!zcyVowX4>kYlb*^pCsFI zCrQ?qf8_Es;5ks!7upL<^s;}>{}t~;wO!{1hoIyPi;leQ@jhTjiM3VdWb}!B?|4AQ zp}+K`gjB!rm%pR+ParQy_u@bY2mczurMx}cnpGS>X4TNF{FyYLQN#3IOi8eI_Ex=O zrU&EovUgoXy?&Jh0hu`0@sh+RYdU9P&Z z?e2j4i62aZ^r8`q5g)q3tAr_Lu)zot#o!Jk^LCPWpHEGYK?dC}*DH<=U>v*g7uQvU z(0kqTj5=Ve0*P&fVIlaeIKw;(X<}%bX@d+(M5qhJ?1fbw}}p?CGrr6-J0+#PDGwSu++fDN zmXk9K+! zJ5RoK>K0Zi8@bc*xrQ@oP27aEU7=DcxIq>Z&{0Qz=-Xz#5>09NdUJ#%2I9hc4Y{?j z(r?S?j~vMFaod@>fl+60@E0XG^Huh7+DfB17N$UMnKIzPS!EvRk|)?4fm0t~X~oa) zn#-FHA zFOewm@?qeU7(%Wxt&sHZ6zW}hjTSH{9_;Zc z?osJfQ>%B*MH6A#j?otdn}z_`U{7YBL(B)!UrSRhzPEfROkk4d_{A%ieex|gnK>UZ zjN7*&Qw`dlS}h7ywi>!*@-g+;YQE3Y;cu`JK;EuC|3w*Wb1R;Nw|7Yivq4OyUK?M* z5Qn2{G&SikIB7gj_1h%%eWZb)>B82+?30EnR~5V5(7eR=`G(huo?Jg3Qp6NTqO@+q zk`YGlzM8_GpCA$1hqw6{i;I?;v;_R!h2!3R<06w(bx2{=GP&%ZaEatUm%rRTH?_;a zJHxYCRprHz4m52ZfU>=lZ!hh|#Cxtad0fyE(_%JIHh&}B= z?G#{pW|*cd@Cq=@>{bbm(Ut9|P1ZJ3dr~&i(tnTt;hwk# zHUpgSsjj{J>EpZauge4Q>t9)pj&CZe6ZTfCm9B}$imcnS_kf&RXj7JVebq3gA9G<@ zh*N%#oNc;yX47-|R)+B6EW@{-iEp*YJb1`Xm8vN5y9eF3#B7VVS&$<1p>C*Y!q5j) zX$p64dqAZ2lT0MI{8_c1QH-&Ue)^;t06eQ~`3(*MQdYTOjnNjGaczl7Hi1V96!QkK zWc5b0bwN>)51*QYg_OID=JykQvEM&^h$Y3Ze$1dn${fnW#b)h2@)<-D#UH1& z!BtxpXr^|&Y@j8kud#9MiFEGj7EbBDxrJT#(yss;Q`$XsG&R+#?txRXx3j1T&hqk2 z5xLW^x1^*G;O4O&k`dM2<7F*-@Ax@eFL}p6&}G3pok_f3?9MJz?0y*C{KD0w{7XaJ zbDWyC`eAoZ>%Q4{`CDk!5cb42x-;KTUaEOGjk07TXh_nd=Suxz;3Xsa9CkPC{fN%NG`Y(9nMFP7>)H%JH zWgthyt|8kKLO=NIcYPNM74RWHiV^`X^jwUZl4QF%4s34{Mq7V#&9Rr10gWdAe8w!n zK)1#a1|OUIlnhO=nJ5h26((Sc9$C#(L2-r(GLL3*3n;whFnsa#bJObysX2O2Ln&*U}f4zoMKwv zIRu)y`aX+40-=+Z%r>Q3Yx_51f=J2Sq9h_S^if5 zBhP@70xGM6w^dYo$f#Qh7QCw;0oOa#IJdTN_!0pBkKJggk2$R~_{u_E!Rb3EkBPmX zQ?8n2z;xryD};F4mN1`R1*}2jQZnxI7uV(Fy+V1Z^gA)Iv9-T_SMHRwT47u`cz?D! z+PVD-u>9jv+IM)+7fsxE1&G<+iJn2A)*3N3N|P2C{dmc|bae-x85%HEDs%G#B3DKF z_mwuE0j(@HTsUHRc?02KJy-N<5_ZO+xtzFx*3CQE_7Ts_$oU&7{(!IRARwppnZCXr;XeKl-lG*Wb zw|PYA-V1Mj<8$cc*DJuv72v|YHPcUUTQdh6u3kS}RZrM3w!iG@ne1VFU*IK~Xld8u zhvK^&n*55RyW*OZn*Io_(m=so2*kgG>~`n1OqH++cgvN6g8X#y{oUp>iz`6% z72r7kau$z$R>058@r|O?_7BGjd6Z0;5i+_>!OIt-tO{C{L~p8V+MQJJ{`NoU@zSKT zq!MKS^dIg*^?%;nM8MyN{(c&N$HxC?>wh-~_k8T3i7PeTqg6osDg4ra`+@rIrLeY zCK7Ak4x@3RS}l}k^gLI9*7(IM0BeZ}I{G6>Y>8D;jy9J}JLC1LWG`1#!PnXB<3!3aksBGSlRg=w&2%dYb&(Ggzi#5oZA$yf7` zh3e{;1+n`*3)eqmmIA&DvG{pkD0{KOedd`cQkH~66>bZFL?kYv5&JZDO)SdB%fOS^ zEiK2g`MVE*_aDy@Pb=Mtu(XMO&~#DL#N(wf)%4H|d)TsFV5>k0Qp&PDvuaB7CUZBO zVB^h-jOscx)rlJ-xkbZd!5fWeSt*>qO$qY=ZPJnK3s0dzE)3gN5J_ zmqb0Li?&vxes?!agGWTIsA}cX=Zv2D8ikX*iwZ9%^vVp*Qcn;32rd4$S_d_dLM;#}*S?ns@Q$iu!o5U`E1T%kvtJ zNq0rd;6X(?Ex}NeEr5fi{%T$qbT$rUdFEEY)7pH?Y*U_j#OJO7mQRaCT_Upm)dJ#u zxTmA|CMx!c|C8RFAx>`9?k>RfUol7M7*su<2?e5q}1!9Hi0%}$^Vi@UsKx9m%dUDLXOEop6@8Qw_z;1-YaFm9(K z_s-pNw@tGTL$l}i6i`~^FvlT8fKHTB!4T@xp`c~h>Ki2O3vS^mECMYlmmUPyogGU=j=C?w#muB-0gBfrha}asozLs-8(`yqz&>p2j|d4vGR6qTgdn)SeA4#V zt_L-tb^R>~4#M--cOzv{&|p_-ICQsoM;~!oC(hI^Q#3V<`0_KcH_~X~ae3zV2(@XG z^}h2ty(}*k?1zK|`h8R+Bc#fZE2zyP-#BFNS7^WE=W3i<_fjDdR}ceen4~xOgbb^n z53}e>q7TPEuf;oCzPF!$mjF`PBO_jc=`fqr0@dme(b;UL5JQ?nX6VKY!?hb%fH%HD zVpubjRxsW=XNVCS$!KWbZI;pM>Z(vqf5;2R z@nqV&B?(o*?IxLm(iJN!>*~Xp!~LHRb3{(d{z6Lz3^>;TJIt=Zg4<2G(bXx1Mpbwc z0oP1^mKFt-o_MS}F-w{d_2uiL*2ij$lpKE2h0M^%OSZD=VV4bY!4FfM zYCb(S*Y@|!sTl*sfNJM?5)bxxSo8-!OyTaFF6V{1Myl#IVpPMAB4v#*gz~}-=+5{b zkHvX$imY5oYrMIYHs+i{H!M!ok@Pq2>=bIT!GPK$zwqGvkjlaoKE{LvjSc9V*qM87 zItEDH_aA3wbnZ)YeT<0FD#bMWADf8o8;u@c2pwvbMi122*E9qf2(H{Rb1CPKS4NUr zg)pq+YZ zKHM;c<-u>}h1f#vpwX$9&6Q)jzw9iOh21$ifkIoLd;~P+qbw&;-L1*A&L;Az@tsOz zxaYHA?eP(=^2*o)+SFCxUZqIlB1g^J^Z-SmIMS!H={nxOL7`m(cn9`l_IVvf3^oY8 ziOA=|OUln9Bxc(_hbB7%b{W59Nol`YE%rG-p~BiZ=WZp?ncl;grU-V0XJe|P-R(S~ ztV6-a9y3U{v0vwsPhLUWL#2{Ghx;=)mXx_R-?o)!99z`K+{>}cG3ZqEEZiJL5(%~t ztKZ7!sn)dIl2<_Ai_V*|N7jTKh4Zs&0pHfuHu>}7W$vJFtZhBtqw6#QUIR-*({ant z0113*juo_MH%e_@-ltxKReKw2*9Unvn(2Er1-#s}N9Zdl@L9`TQZc zN$#S~B`sQJ?;`~7p3^GBWISW){gWrrWI|FQMhwXj04P7#>19(97+|9Ptp$W=poA$A zbQ$8vl=$M&l)686>(7~Z78dVjx{{p8*93&JB#FgEgfek!8ju6e%E zrWA558S3qISF(C^zAfb2GE+8Knx*BAZ}61TC4rOEeRPqEJTQd|r3!YWlt%MY3+ zTqKyC3E4jEh4;txBU9fVB!|pNGp18ahOM~*nebeSktGa8Nr_#8jP7JB(ec195u?5} zvf>_-Hp%7g*7d440~r05&#=X3Sf8`1l9TF^yrvxMOqiPnb%SkKp3hqBi+dYi?k|Mw zP|ysMWWIQP`3*Hh3O0&di_QYecwbz8f4X2aYoaWE(#}F9VB3);y|Q*aX=S%b5T>Dv zsgA)H3@;jjH4BXGod=xFJ!spE%UhF*-m zi*+kjT^c4j;~#K= zhMCegqjwj>kHhOtD3!ur)sMlURm}Oj%RlL2E6I87Zt(>tNMF0AZmGT4@o{))C5_0a z&zxu|M7%b8!YjIzbD<6HdXg|h8B4mRB@r|}o6_|$PLWlUcF1l)2%TG&Z@MX?QkA!8 zW|tj43kK)sBuxkS--~3Zgn_(T^hFAACRk`5?A2?`chkFLuB>8+Qqa`Cxd%~exluYU}I3g zJ9hFw$v8vo`(1~o338lRpA$QvK7_MRm15_I+Q4}m+)qT2twQ-d2D{Swa$94$w&77u zQ}F{TYN0x=7##(H*IDiKf1{I*K;;;ds{1W}z!pgHESA!*!33 zPJ>TZXb6U1yuOGI2MPYLKlNc7lSq-@*C{2OpKf)fsgYb_0ZMYe-R$Y=Cz0q%3pb^% z!=y$pH4G>#<*fGf2ULWTzc2>hge{wx)jC(vK zKCkYA(!;=oP~VMj-{g21wP4ty;K@qvk(+_(LX>zG8etWUv6*r_h*PG+fm}0XQS}o; zub+Znx*ENfnja8Ge81oM9w1j2mXTxcCbN)eQ?wZyy0gEFs;l|p0?XCjKui}9Hy}EE zX{uOBIwP0hlx;G3p^oXJ=@Wa#TB(D=dSU?e()5kyi6p6?Qm^FE_%ThfS`t7kMOGs~DT=&E7)`vd#u|3N}l-RB|`I}`) zotJn~F?{`r@eBWXj&dTJXQGBVcHyW6abT0xno8Rv%p;iVO_vKkh$%mBF_rbt>Hu4t z=>0ovCIs(t9$6hT0*?6j2X^EIy%feluTVget|FvzKK8A6vbLe)U1hZycUj5>8wZd; zhaXiL;JCQ?F$Ngi@FFkL7$K9BQ1Z54`}Oo|Rp*;lTcGZ5iJYJaj3TqR{x_KZ3MC?q zVUww;F&kXXfq2}II(UXM&Zm3$OtkW`o)ae@Lgevq{cSE&Wp^W$sw`}PR=EDK@NN}9 zW2=aXVSijJI|+$HOoCo3!_qKu3T^)^cC2;kL(X0>xWq2b-pF1&F~Mo!@f2NmnnzBE zG_37Z06^=6Q(vCWsHu(9DOW4rwQQ=v_bUREpMNyOWe5g^(oTHq)K$9n{6;$Y5B{Jy zlrO@-A$vR*;~13ixsQwbIWoR9lskk|En-bGBgX1+?{h_0o_(^NF4WMiff9wlx084Q zbC#CK(L`Oy0-uH33IO^*NV@0sTR)jw{E;=-aP--MMm`**mG%5Ya=^o-Y>RGh*qB{l zOpWkUwmkv&>@5=MTrYX-$K~kI1=@8(|G!~H2?(w*M7Ig(T~;apmg*^Y3%nqT!1 zHf9;F`h3L9aQrAmSa))FH#hkC<#_c^H*jMcci>3NcWKodBmO|U+3zfX59IhM2zl2hx zxI^D>^T?VLSav1-GQa)V0L^=S+_qSL9Yycw02e<$AEMqkIjO6`1*|1p5=QOU>@j}7 z>AOTYUe_Fjqg+0($lG4HJ6buLqxGQG!;_GjaC)dVI|?2dGVtBPK5m!^u(k1nQ)f)` z=z~GM--5<<6IJM%@OLynU*(T)a~5R1qy&CyjK6fZ0KA!D{~;U33@LS~rW$qy*v<*Q zOfZ`IH3jW#HvC^Lt^odGJn8QWg*!MPUTZ|0vAj?C8vGd>wXgMa3>uYT0kI@+N`X4G zy*s=pc-+TG;y|YM%dI4P^KID4GHBM*kSp4m_sxjk)7ZSAcOL?fe)0^H@&N4M5Q21B z)>y6T>safVW1M&)*9#@NEik{QD^qrH5hqn5e=X5$AW*8$c#$4Ik4t-rDb6d{s58we z*!VCNw0k68Il?^xY3d(Qe>bWubpmf_GHGaYg^JD!73IB`3-1ul1Up?+IT@ zt4<#){60v$JP*GDL}`Q5$X~piNB|jU1|&ytDPnl{~rn zXga9Xkjs`eANv|24>)!39(6V=az>}9+{8TFm;os2+mVTxR-MO^hVjtOuX2qP$u|c5 zk@bOpT zPbsK3En^2lNk4B9;H4%#=WKa+FP4{hw-qN}Oz%gR`l^)TL``$qe3j1(O6A3BL^Z!Y z#(h*|Q^u4aK1_w+IIZxct&>y<<6TaZ5!b*nN*XO^x)g8n_A-@2(I>?tSr(prajl@K zP}tb=P?Utl%D}auHhxdxXs7_x0rW_4Aj#K)%WbmM!~K@!A!54cdLQM?r0&}}T4|nL zVA+=M;i~Y(Dg70IC2QwH8t%6SzWNYff!M`+z1>FwYom>!i_GlH+5C{2+0GO@FcH~1SC zEYAAbSmz!p%yuAc9(L25?^MBDZ(jaDRC0Y^;m@uC^$~5+1uZ zxW^%Q6JIPGFXQ68p8VOm@^e@Hs+BZeJ^Kg^?Tqny@{=htx60i@DiXiAdq3bsRl`X7 zSXS`hoxCK=$~axo_JHmO88aN@nL3Z1PU-(K3SXSaX;Z z8M_Mn$M{qP-uGh0DwSZR+V!R`dB%3L!NNqFMw*SIAZJp~uluf~p}XchryuV|+1{3) z(7RR3HER(OV3S^M;f=(z0e! z46Og+bxyw}cS5Qtr%NnvGL=BRg^jlJ%rq9*j)aCc(3Tj&^vLfG!)$biOCT=w;qIEZ zz_Z~RA(q6iD3e)yGzt!M!^(c^lt>(t{Mmov_wS`4zXf?szFEYF$fh#9XP!ckL?nfv zp78*yOLdxdwdC^dXz#GSSQppV?-vCtu$e~|oa^$5OL%kpvL-I9uxTCo8cd}N;ltQG z0_8DIW&~~ilJt40QaxHoa4VH0Ct!VXJ z5>!&DN%VSZteyJOBAl!>Nay0<8bPbMsXhwN0KDxQN!d>4HknJGri|utdcspR@T-pS zaKO`^EYmi=y8M%v%5Z&5{d;KF?4Knj1O|5>!;(Z?Q8Wkh?4Vv;*gmr^pn18KL?crv zYKInod~!n&9;b0gycBdl$5(>hiMRL1q7sf}v_Uruc28D|VP&wDv?lf@<3d4 zaGxddzE!eWm0F%lC$;uZE^24fia*BwAA%C#CATz00rLlv;Xo5bN7qp{Xu`|8!^e@d zmNj9kLcbDwjcWsEJ4j_hdYH2xzpb77IY^m-f1OgC55n7|8!z6P#+nkMzfVdIBQ=P6 z@h0y~pQea7_=vftw>is&6C2|7-iZ1nYsz1W?y{wBSwaSt9+OG}dVc?Y2(TH}N&91y zAb{Oj8fy0@?(G~k;rLzUO9q4LjX`Y2i!1epp+d!QT()x9=&;$`?A%j2eR?S4Ypedq z@6+hhHigg+`IxU0M}@PrQ}RH~7_Y8ntizV zlSWB|Em?MNC;zbPS{O|MemiS~j?W8TAFVux6IhogP3#el%&Ggbj=x1NJuMfgjvBot z59=c&#SbHHH8_K_VCM))HvGK%Q_GosREJPMzzwp9N*u>t;bkN3Fv9d_SlB)zsIUZ=OLA$R2PYeknQdZyBt3L$g z1>qG^V_KN`BBO!aDkq}E@cjl=wnFlSNQ$o`bDHA$yO$wn75yW;tp@76eD3YYdz{-alK9L{f`P|R^OmuZuic=v-IL-( zO13V7zV6=i0bpBN2ouiq&M>5bmOkJY`ZQ3YnPP66-`%=*N(u?94l*EWh?IS_7A@uy zQceu5r9k-{{qYa~F)=DARPKLllAZ99E;8uJwMRN;rsBz8pL}R1pf0+lKdq8(Mi#x; zlnmuGF8!3Av^)}H`G!OGYqVl@%|xXF12zpc6#}~5L_X|*qd1}FikndvI7If3?ug9v zaqLdJJ@F6#5DMvncmB{r=l>epUsGa1de*U68D?+>#I*W!`hk3xbrVCq?k_=(dAy<4;Z6CcnL(-$$Bd1J0)ueIT<)*7?iXQ$ z4JVFP+%a`@U8lCDwlYkmI&4Ambs?@)d9{tWrJcz7Z0Jv80(Xh7X;TPiipOabZyavk z#oZ~v`mE+$cGQe5HICEG_C@uQ-`6uM+gGs^`^ExU)jl}IsV_x`H_43bL9Ef1XU`Iv z$&Z0#oi$8>pMutPQay=Df${H_9``wRaDC2Gsuk|5-xvO~u3?pu2?v_00#bRY)%e~T zfNz=#j#Y-jZ7Q3q%bexEw^{~xW!Gt?R6H?~{Mfq_GtRVkdCT@vY_#Zj)62|qGV}C> zp+k0KFn%Ij8~7%abc;me-l+QZ`#M%yAV&~jscdjHr_vtTyK>M^LpR2%9{jvggA z6qZ>fMHfy{lV_^w%BM=V`5?~d+o)pVH7;SMU5oG0Z?MYCjm~Px9mva)97>8V6vWnE zGU-7qqv@!4Wlgosm)VN8d$qB2@sm=n%)$M}uAXLpmWU20{d|D1EY0DgwBWO$kC3}{ zBM=E=50HuAL?PFxNteJ|)C`B9%jo-Au|AtcQI@ z5olZI8z?^et2x?%%>+JP{Z5JTW?D*kVPrQmtNJgdLrQWS3nn*hrCzNnS<@ax3Z!3z zMak(gH!`t`WZ_|8FJ>>Oj%~hWet9Io?f+nq+o0{^DdnHuzrx2Rs_iDWG5I?;#nl9b z#mQCm6HP2(QrwNlDQCEyVy|Vc1EtS7gYVP`)Y&4@st8j~^m-esR4W_%*sl=@IgXhl z1bghw1Pi8Jjanmm-*pUj<9{;3MV$w zAOZ1hy180Dp5b};uI!854UylaKg|zBI!Phy-tm8y0erk+o=Z~EP>_`K@^-SOnaX%k z18qLmo^-Zvp4DY4VejD=)oXUu;qDUkmFBp<1a(fvw)zUDqvqQ%o^~HOG-ZT~tX9xT zD&@E^hz}|Ey?oxVvPKFZtpV%EQVRz&TlB^1tMvI6zKAn3`LhSXiA_fMh&D{Q`qI=O zI;S`>W`Tk(wny9Ha5<}yVs_6gu2+f4y^>=W8H}m(s}5bgz(l6YYgpBLfd$|$6j4>x z@%K~;^q${Y_Aaw`x&i)mdj9*a{z&Ez2?8_^*bggLw*HWdbLE0E_{3jMt8FY5@{4ob zhOtND@XJ2TxNB^JGHh8Zn>)?R+;vs4L#;{T)u$pH^BYNm2;-*A*lyh$sj3Oq*S`@y zrHKnWr%S<4<_OgZnLN8#-tcjV^Zm$52gn0xdHyllv#!_$uMQ%F}q! zM~_^}JbCv+^!fF;mZNmy5oNP62P3Tb;HYt2-i_??M3vq|QWkr^Oe>@}bpZwg)p2-slNw~L2C9B4{X8KTi zL)GyMLCQaG}Rnfl*@j&LOhUPPZbc&aCKuX{4`wH9euFI$o>px7y+L;_bN1GS+ zC)gJsD2sPlK9AC1`T1Knfck-2cc<7OK=#A$^^?jgK%6BO59oPYji3H!GBt)@-Vr9b z0t~xrUIAKaeX(_e6UWWLGMC?6Gr=`y_j2;go(!89nG8VX8ZZwLTru5-tPJmTKN7m8 zQx3qby^WXLBk^=eZyr^&dqCAs{MuI1wptaM(KuYI%66L^Id5O80dc5bffU*=Xz&xq zFh(hsWb#bP3kXMmcXQp3c=QQyzUA)7P_st)0!}Hw|G<#2p zOdfrGQ+nck2d_b@NDFdsWfewz;PH1UlzThBE5Yo^tSN(J?z1D%4|9pswTk?BH>UL^ z#SM5g%{1-~rX#ZY+lm@Uuw-WDVJvd-m9cDhhAV(L^4>!JJCV;MEZQXPqCO)))~XV+ zjXIm)VhDXlGj)Spt_k*0!l;x>^rldC4x@=QXsQDA5Ie; zfIVDJ%@;iK_U(}T;1g}-;8I)lO}r2ypzb3+w2Pkv(C29%(sao$mA0KLI;NS+owm&g zy9_+lh$JXJGFT1PtQEGmDvxs2i4k0s%`l|WHMpzYo6h3LPoh11dELH=-i&a|jg7h< zz4dhJX7&JW__V;_E~i@c4%s85s=EL^_t)>g;uL`_b6#Hf5}yRLO(2fy$F`ILWY`t{ z{M4{=Oq`$m>DuYjan0~q4RDc}s&%-n&PCCz7~@U-kPb#!pGB-XO5rxPc{w@|r-kZv zSemR76hfjd#LvGv?pzLUfDnX}2bwf7VpgBCqaKBfvWfdMv`<#% zrolOJiYw8lNw?$=9uI0oy1Ib8EKVjJHDL{uHc;A>)UupMgg44MXxtxgsDwQD@q+=7 zP6l{*%}=H-10RH45ou`P#SJ}u+&xpuD?s{Q@)h9YJG=vv>(hNaA}dpGNbQ?2ZIo5g zohB|t(FZH5)`C$44;cp^b`$+SP*VQ2o;*?H#wKIKNTh+$>nFuK6p!#b?bc5 zCiMAlKfUa7fyxgJ;jHkk8Qi3PV4r3D=TesV-(SRB zp|gFyqIY8#Wx@!2JxIVH0&$bWxQC@({K{qw=o>aA1v5?mHUhc)Gb69Ztg;wRyBX6mlw0J?`>Ta7Q=o(Kv|v zI)ZSl&HUygX^UzFDbK-I%(|l z=eE}mlZ`F{yfjwk`Ma3XIw(Uej4(A(LLhmb$-Bd&$iYzr;*@HLwNg*rMbugZcfhDZ zal@3^_lK9k#n%RJlyA69a7WrFAhp@@S_Vp!coEUWK9k**-zV2t1n1JHD{sIsd&VoR z1|i66*{?~T)9avDn#$$59jQ z`vO1OU0OGGi|;m6hwaVOAY=q$N>|=L>;@fnixWuDyig>fjd3cxNHeM!@#*m3nPpFf zR&~*Bt9b=5%m{q@&88(L62aPPJQ`<)A&y>#aIBb4?dgrSjo(kQCTo={RbGAssvv0D zS7fHqQ%)#38F=+#^s>X9BQdh*l|pTh6ioFj1VmWoMt;7`?<5C?1HF zra~PqJ90PVSq9g|TqI*R;m5=K`=fPF|3hl8{-bKT{^h*mqnA62$75FjE2D{B?4(}e zsWo0HpLWhSSpx0!Q}~M|@o8!kyOs4e<&Em`33e%lcVl&}5>%Xe`F%YJnf${5KJ`D0 zx9LcpmmW^4bA?6((TAu|Argp{0jUpJ4$VlRQ^76Q&t@N4CQ^TOs^{pw78*m)A(p^a~)m5o;`ETDzd&O<6-zbe^`<+Z&)1f*fx z;H2;E(5Y9CD?@ty4DRXZn>Q>Tc?dHiEOHDbndpI{tZ7Aoy)AUo3>pFui6J%B@4d4* z=D^fj#Dic}y@*y8C-E53%#bN?(gh&XPyX6i6Eilv1xN%USOF4X-ybM2x4uoN%VvAl z>=<)wOkXwsz6dm2U84!*BxVTX{rZNW(=7|#*Lh+}jadvJPWds9gmEI=ljwtZs5H3h z!oX6GF-eQI_w;N0`90tF#WIK<6E`d6r&C7B-^1Ol^o+D<^PxsB?B0V0%X8LLhqBvL zLrlTR>hJ)ynOE-*^1kML{b?nfdb30lQ}RiuiVNM4P{+EO7%q$}*p?KP!yQ$1 z5=!24PF^+ez1m&WicFtcXsj~cmBiU6H0%1)O}26WmztX=&(x|Y8rysiK_SmD=Z6yOo;)4o^6eFOT+P%`f3pc0UD z-lkEzJT%#dqyA@oJUi8GVMbKc{dlj+LpCL|^doJO4mM`=WL?3sxHo;fq?FqN0|s8) z404j1H8c8|sCCE_wf2ZbRKt}+ojW@@o>g(SN+#XxztNy1!wo*o!r6|f-QJ`q&5j6Y2AN)YVQ~<2Sl8u)C3&^ zsbS=J2z}>Tx6rq1?LvTvY$(mUTs`x^gP-J;VQ`ef^}gj@o0sUV4SIbAN=Sp9l{3Cn zZRdJ#)aB&L6Xwyu`)m?FgZOb8+?AI8-PqR!w5L{YV2N!_%$TSIq;ObepNU>aisb{7 z_VV-?X?=p=-rf%nT3I6jFyKxPdA5vu`wao{*+`BaFFUvDN&4q_fGL&v8$ug!cRqd0 zY7mF;u@|IesX+ogf)mR#5DHlSCO*TAYMkgtA$u|{avr&Q3Fdg`D~!bQuohE|Khloe>3nR*A(6xxB{3coan+$7bC6geBGdDn^%Bxxc$k$utxr38T9|? zyYXbTTmK*0B*dHRr7rL_KQnq&o<0)sITtg{+j*D0RfV&dbjqv0SW`-Zvf1r(U-G5K zZhA?hr(R;T0_5pU@HK&5?Vs)SCgE0clk?kPE52_+xRfPnO12x)ZOcQ86BzyWv}v>D z#P$*fYVA4X?v4zBubj?5Pk&%rZmlwCRBu5Rn&-r%Wv_8_O zNT$-&)p_IRot8eoRTmVTw+OC-jk@xO+gjC^-hp>lr3^FPJ^V}**Y{TcgC8>^?Ez)b z6#(o@g|}a4%gDq-3ry>aVZf&tm(*L07)bm$HG>5I`$Et_9>MxW5cP~_M4 zo8%%hPR;_7zBz1bbX=T5=2m8(G+6RJDSoRhgYZ-Xn(M*g;Z&z3ygK*%VF}l$uLYEN z8mFQ_6&!-ow1K#y?ykrV-9XwuZDRGMs{6=2mB6k(uMye7q*$alSMT!_a0n&4T-ZjD zn;~S5t^gFS{J_8_af~6_Enr1&9G)#D6Q|B4BA#TQpTz88725K-`yEXz0Rsq6eew_9 zzTSdNYtKLj=tJ>L?l1+?R<|U08AR!&XHAU=vSalo(4NTQtQecLm|(P$Zb=;Y)qt*hK`=r?h{t0s;7>5i%dH5_$ht`}*AwIZLy$Aq1}v z-Lw~{iI%C1dyG^o3q?syITNjjI z*9}LSXuX7|yxf<~$V@g9WEMlj>%Z#R-Wy*r44$c6XY(FaVh-RZew+t_AlPb93Onvg zX(0;K5(=S{rhFKiPk7z5k_8mS>m`++6JgZw;Tm@K9&n$urh!b|;} z-b(>P(hgDT`V33#_#l^1?}0D>T@Mx?P=7NjVGQS{ll2gy@3s4_b4@!=_^XPRG}rZ2 z6SI?_*iG)dcHr);Fji#=-PHl%Y;)5$vP{swBUm-wU2gcSqJyvJ%bQ)9AKxV>kS$3k zv?64OmATl!|CATiV;_VKYVvrvvh5V^Xgnx)Iw)8C`Bs$5}YnU6lJ5IE!? zK|D`*uuv2$xWgz1U(lyXlo#Hhm5XgVeCEG3ZlqkeSA9#GU1CoXAC9iFbl<$Q1xxfw;(=9k`r1eAc9{U^ROp*TpRPyY>o@(73(L_rKkw z?*E)H{@+dRMlZVIyOfuY@PIcHn=8ObiGf5TeyO`#+IJgoxOyhBaoym4@DN>Xw(nX3Wy@}KiLO@!O(4}_}P!NzVLg*oMr1#!K zO=toF2`WTE{*!0c%&d9mUF-caYt}O#&L>vjaB|LlpS|~W{VwT0%HK7ivddxbcKG6xinnV&y1%{i9-XP7> z8LNM(9q}`&BUjyX)?-sK{XE|AD8lD~Z0p`9P}5>(%Eu{ZUW~zC0V)^j#E#7)jb8bD zAp%>m1Gf33<`=K(y2_I?j;HnD#SAO?fz$zxmIVJP8nUo+mE_Vb1{ya^W`0uT;Tyl? z!p~dZ{m}~E8Y&Z8;XB&jxt``zP6gH^{gRHdXOtx^vS4I65oVlW7lnA{nX$A6R$vUY zDnqKw$)BISNxQ2DR)%u7^<2GvUFy^CPAtF{^wD@+f(wT?59!@c2Cd{jI72Hiq#fUPBb#BYn+$ufEc#dcYUIxpv;C zqR^A{Y8>~M-!7(C+|LF5+IndjRoYiNV_%0HTX*@}>3?HD<|0{?e52i(5QN=}fXR+B zFhcx|4ZgU?=ox!D@M-m^pT+z**DaINymu^;Dbt_!1L;dXXh%(Ic|GX7J(G+SA7-|o zT?(0-WV&;3d!xOcQ3D{uVD%dg2jb+Wvj^Bancmro^z{)G!Ia1S#|2NId@9OmA_ZsO zce=)=Kj?`1XK`D$s3`TU3ldx}MeI1HE`i*`pD(p@ej}dkVTvqixtBlzegW)u2ndr! z)`MjZHHj`#%prO*)|ZUw0+c=59{L z`D2nMBY$y7FY0&Z4{T~lnA~*(!TZ9rPcAB&*rFyB$^|vq-yLr0t%vP;0OO>~i*6+q| z%ClW1Z{H^kB;shqP9$&P*;KjH>*&}up{|9VW-s4D0hmesb1 zN+9zk*{_9+%6-MNf}6;~^_2s81wf;Me0m9fh>R3!PAg6q@jwNV(MHVJB$OVWWB6*y zA?B()jm@nc_4V!1;3D~N6DC?D-=~oOWpAX7d3P5z#Eu1D-8qY~U$%!>A=k@!JJH^b z%Ii*bS{#AwPb0W3D3bVg}UM}v9S>prb6E8Ec!C}Wg8Fuch4 zjdf&QJS~UsGz=KWxmqZPm!dqq6veMnmO7Q9GAeesb*GGlaak<#6 zyF0EgJO<1k2u1uvs)!G)(=GarB4L_~KRYxG>m;PAk6^cR)~`iM?&>B#lTS9p-4)-4 zDqvv=D5Qw`G>SiF`kNOV*4>&P`B}R)sRU@1{s$u(GEQ-Zl#RP3BU@&f_GCEa-Q}2b zBhi(h@B&{R>*3j`6Xeu}Uz<=){gdVubi^WkJ;X9Re(YyFWXh*?{|LCqXSnT4=i3 zr6FA_Qa9qrwIlCkmM(3Z5i^Az=yjbKu(pq27g>3z#u!3+V^ha#ssb}?XMOX8xqIcR z?ky?pZ{IGMB&9`1^@V)}1rH~EI+7*(X;(qW=wZv5j8_&bx3jV#M)v%%I(WTo6by6A zpwufEWga3X4%{9aJ75#?b-`BFWenuAHg?rc%h@^_)Xo1AozV|gwO-O1Tlo|CEQ?-X z67X5ztR}bJ6hAx2q|nDJZ8T#~QZ2r1z|J?tK`TnmrbGK?dN5bFct&OGhUkY|5-Y=u zecG$t#2~@<_z4Hv zR4EA%Y_|RYZvqj+4le#g&6ki`*W^Let>72ehDgg;EgcQV5XGB?EL4qK2>0yve7n|X z4A|@*BdDb#PZIn1jc2;HDd)M|58(!UwtdTVdw@5zs1LJHxiv0sGb^R=RU}C1q3^(b ziPG+rSH0eEUm?$HyB@54`v<_LtW>=L3Assd$tVu((T8CxFDi~3{nDv--r1}uiz%yt z-8R85T}CQf5mie{VV@WtcamT>KRdWK`rhPsm14jO&RQLp=c$8`dx#^Zu?Z&h%PorC zywEKpDzNsLd(PPh7r*N|jTc(m_ks(Zoi*Li57s&JOrPuth4G{nN zk4bL|&eOg>e;ROg6i{K)M7gQ+EWSZH3BgSjv)JDN!8pC)POL6lOid7`NbB3VY#0Kb z_|;_kF+{9O@KgUZxNkU{vuHJ|>==OKeZ0{B{rcKbo4sATHKY^qjD}-TSsKZBKvj=4%5%yA-+hjjQxH{d|V@Pza^}c>$wjt0-3NyRjX|fjGVb zr^N#JH4h5dJNdwhC()N`e#m9nD{*G|4}vy54w=RXWY-ucGkTcGcx7XUXFgXgcAYP> zcM2Za|0g;V`|a5C7zw=4uJFLOtxSUMuz8JgD^UzT3IH-E{Sd1G@-YxVis;@+R!cb7 zhJMP^dB2!BSqN>eS&*pT%Y$r*vFXQS)tU_@5=$zX97}@pLO3Xd)f+qy-{VSIA7GWtS!r>F(r_p{y`p)p;63~ z=d8Nx88Hag;d*9a6rFunlyILYweb`#lF38=SV=aq_z7offt>#dow@QJ&lDAM_3|;E zKC`SKG!SRYx4vlh4A8I9^B#zo zvHTEwZXtJoCV%Xd|yI{+OqiU7WdKlPV3{}H0 zeK=Y-8$%TS_FgCE_VCHp5vd@XdCcOrL4EREhMA56ZOJrSt&r!}R$Gyqr(7nnCk!9u z19SBWIe=dsRDGSi1k;$a@~B_dlCMSsQ;y`>nbtHqyfZg$$!t40xe8XUz`J_PTfbki zH7xwx|CMVht(wQWY81$v_!>_sBf9~QJ7RKRc8O=EBeC)yVjW!9!+{?q#l6@JQEML$@N^A!?F+w%RE>a)YIT}*O^ zOkd!xUt2?CoM#ZMs*$|NttDIQ!&^3^ZU=G9jcIc2Ox?i8o^J!wjk)f&eIq{HH9AEn|S`0C$OO7cej0p+Fc+L5$=o+#R=Czw!*92THiLU3wGj_Q`M0M#c_L) zdUFU;aV9S*tK$|f066;nVb(p`od1jd+r5_Y)|E{4d`rV!0KXBqfE7Vg32(5+n^q&;NkA*@^o@ZZeb)v?Tb2+z zbqv>DJ^Jq~lS*}hNDSh+lb>V1ZMLPYDsSujLQ7;oDB@A+q2fP)xJDR# zce#B(Hur*F-g3hdg$9?mrLRA{p}j2lpmVzR-b?2XbfOB2jzyOy`1#$)3V2E%yICh+ z-7KoZNE1wAAYtQ5XRAw5YrDG7baGxvRDKNeo)90FD~Qe)Z=Oa3L0wBL3ap6Xg@EDS~ zEqFvCuKwE&t{nTd+^g2m@0C^^U0fsoVQ@S}_0PZ8%F_Iq?B?P>S&s}PR0-RG! zyypt6(*H9V<&IoDC?J!`bbH_oaBYc$Qw6U`QgM-yoE-nvK@LiOSnTGa1z%-#cF1&A zW>nvdGz5@^e`RU>FF*HR{m%avKcg)B57Yem#{YddB1`tqzgOBVTGKO$xpfvpT;43e z=xoJ=%Z`WIPPdZ>RKnQ}7nIG(CxiJTd{>T?X}0T{)|oNZ`$C{`z8N~FFlW&hl%X%@0@O4l z$yITVH2mvVrk@z*-Nk<}korLEA>vmPYEAj%K#q+;20K{o7fH zSObAFO{luUEycCMhF2;O3WR|3&@etXviniaLsW;XtVBOtSMrtWl$tX)0~@h?FozUd zuXUkCyt2*{H*T4e(jY$XLHd`LG+uk!O(#E8&bXP`!m-CuS8_G8exHE;9)zDb=p9ge zn=gjn=ucwkZaqdihAR6UWKEBYCF?ogtRJUetJJg^(#@PtaM}a#qZ`e8H_$Z+i07M= z(Vf)umy%TnT-;rKM)WK8Hv8u$nEMvvpi0^2%1=v3rLL%-BdU2w?nlg#0YL;O97CAh zGRwwxu^d{3DW{uW6<&dNyu2uV!kW=-5G0? zU~-txOGrufos5@1W9Q@3@2-I7;wZSz5`yLC?rkPX3I(PPfxv=NYJQ0dAq;i6D^1qpONj3nN?lV>}E zdX|Z#4l-oZW>T^yW<-N(Dc&3*j%pBAgf`+suVvmK+37;u0BFj zSoH5GLSMWr(>?-njh4_UWdE&EKdl=M84?72nLSF6uQ~YofUkR9uJ3e!)!Nnk{qp zlufIXS%%6V!<*}lHNOGiizyEox4+(4^EM~tYn#e7_01&963DoW?UO5)cOwT!R~bUR zwo;ZXSZ9D^G7YlBXe+yyp53wqf7VdNt@60X8Vd}I-LYq44{hF zi3BaMxJMsJ+=vyCAANJc3C;PY4b8%abHomTK;dX*^Gt?h^eM!ip^!O4)-YQ!tt8vb?UoY)Uz@qQ3 za`+x{3Nk8tuY7n)@jgrgSghAb))tRdw!h%Jng~(K?yDyj^w@(*{f(|?we!E;#hA=N zfi0c0g6Z7g9&6I$tq7W6c*pqAqjMLK;y9~%o2X!!(mS)ClfEh)Uz`O6dc1bQJplf2 zdUb=GL+fJQW%b^TkXK|oo>$^v41bccQ6W4>*Q0TbdGT>N#@SM+xus=+@A%%0zVLN( z;WbS#7u!Q+zOQ_KMIrqg4Ms8T{5X5S{?*MNq&VsX^(xEtgEvX|k4v&io-6}+c!W?f+ya%I1ihZzA-PZ(>=PK|UQA2VmW8bbCh2I! zYx0oKxpdfES`ptUn<#Vn`EeDtuvtI7_4^tjV~lNpgh_tTEH;_$#O%M4f9G#ZAB@sH z3&Xk=UDBX~vyMahwrhz7?lxK4IWHN@h8Ra1>^>@dvYDz&LEaz26*5rJkkZ4zwglh9 z?nNDw+UQU998r0{kXA=POPrfcpn`dN&vMcd{gC&^L`LdA5p{B*Oy4l96Cc2pHVJ`p zx!n%VEj(3d;fF#@$Hu1mAP;RE8IT+l22Zlz(&>fLjiCQDG^VbvSty$=1em}6eRe0w zCw4Ph$05e}KMW$2)C(oD?1y@39qVJDSP>DQf1Yx-`P8rARq9;yXW` z-`AoD2ogdyqhwZ|=;~oFG@t#Rs^ehpZ(%rZVV$tJbjMd+-6MoX$uX(sZN?@PzG+XjAuw{?f`p`*oa6XXknz}~<;gdWtv+rRYgqha{tkCELf-^ja) z+Pk!gllVdVu3V#8xutwvhn5y*eU>Tf@#_VDeoGz;CEae;ZEbse%<|e$%-24#i{9@- z#mKmJ!R&!-kldU!-`P5DaJ1g5-xJUpFNl{PSP`VuNTvt831ffC@AQ9|GOzPhT^4cfY`0yo^NIDYP1);%gSmN&wzwbZdE6@sL?=6VWvS(`7$03z;F@O9c7MOa0 z8gi)N^aJ5Q6S(V(bOmjj>rT&;b+@@lE=$^io*Zsl4cw8{lHs3;(sB!pvgHk%ae>)0 z_SnAKwvImc&91B)Oe0R@VGM3X?Plj&HIapjmz*X01#WXk2sbINnLjg_U5jGIMEVs0 z&!=IP5ij~9X0F>oil$YiE|m!Eu{u#dp$<}VR6(&=zNh=wM={JI){vN_m(6aq0kI{o zKQY6p0DNg$fqRLacZj#Xve)jf-*9V$8rB(Conx_Cl^bz0YdRYEt6$@u`hOEfwRF7vbKuz1>2!;w1~J@|Uvs zQ;aCHWvU+i7yu^7vEGV37n-4Bab}(lij<6&C#Y#tG_+w2L z&cq8CznxL;NOIA}NoIj>`7+tqXy!kaRN!XX)F50H#a}=Y zg0$@$R+X7n*TP;#TW2P&^h*?GJHZ6oJUOU<0(?nY@PL?3RicPREkU^a^WT~$P5AX{ zjDAOd-jc#iTgQZv=blxkBYW2<814|#qB(zd(GUlF^B>HtSm67YTbq&tB}+G0nofI_ zbr@J`$I?bw64EmLo=4ogs|E0#Gv{<5&~{_;I>Q4TKUa~E<+~|*Fexo|NeYum0q#_f z6&|S#)#=mC*N>DbO9_kJ3hUg9atzcE{{oL$*=0G=vN@!5QGNO{&+TSy#^@F_-6I+6 zz(|nK&=6J2Gdo-9fzaqFc-kdUwGRCv{z^sa#f9W#2J6pmI%Ac=%x&Okho-|vmGpE}hWXr*J|vQH7Y%8C*PgZi+VMhZBA&)AOG9vT2QD`TKf&cK#;6Lx6|fW8fcx;M zvgY>YoQYF7t}%SeAWfEL=XbsATlRou09h$O(GzgiDn2G_pSVGZyu%Jca zw1BW~!0)=v<7bhH6`g9Aa@l$de!Of~wohz<1_dt|bzJ?Uk1^L6hdstAr38O)nwG|l zX|2*SKK#VsUerD^iIe5p=m`uF{g{Ca7BR*J)ygKjqM=*gp@Bp#@M*)xg6-q9HE%x(%X3TCo{pXMLI zYHXeS5Qv+HoJQxl374j~5!4$hW8Wz0RcpX94N6t&E6o^xar0hdy0)bsAp@(O=i}#G z32)Px6=`VA8L{|9J5-fBiC)?LLK~ejMr|Q3<7vEXb4&qXcv93X&JeH0AomPT>To#* z(?{q1MXK~y7?e&$ zIn6zDLdAo}1UZC1*gnw`FNyK`{aOp~2Fbd8MM*4h#XT&YmCK5reV%JeVEfQZGl!JNbnrj<1F9#B0$dS3S5hqE6vo!$=72 zXJB8seAG$|-h?V>w|31owgsDLF8Hz6W&HyI7*n<$bZb{VQA9#OxN&?cr?7Ld&tfDz|mkqRpC-< z%I|QJ-W{_P@ejZ-hgv#jx!R6fr&V|R?W$oNhl3uQ=?WwW`8|$e$G8LF_I9M=o+YBTL+-5Z?A>A&G=8+JR$WtxsXP)?z1=*9P121>3 z?{8T4S)&eCEyqT9FAse@T=bYYIbS)Mr`{FI`F`9fd8u4akbyrwG`IMrkk4%rO*3|H zbyd{uW!9$l%lJTYG2MKvwEDZ{q zE{Gm&rIA)_|L}B~M-LthwGc<~>x=5M2))16o)V})q4*&ytJSsDr)R%^yt7tk$p-Yi zh*M7tbaFVGqAH)ZQVxU!q?@>bh0CFI24Sd<>v9Zr z0F83@52+oy047vjKYV2i7IP_tgL3QKDp{z9m~+Y39>Tn3n`W!upA&R$XePR3{-DOh z?=d7&ej_`UHBYcXIOD(XJzZ#&)LyvIY@b2pp2bPla6ijz{2-956%UGicbadKp(7Zl z!HOxTkN=}^bRGZayxWeCkX)xSk%iEBg-)|TWv-r!Qg{zPq~UEz+l(0_t9~2^V(hNf z0t6+o?s82Iz@p#KE>{;L%SI0$_;Ku_BZ59NkL<+v`p8b{fV|X!*Vyzd88$^$uw#6()O`xA`SCZ`EB8!iBj~o+@|a@mK3Kh zY)1ji+39OiPeWY;r`08yhn#G9YAC~0nBz}tZeBu3VLffcpKA=(mZdpjyHVRs&FBbI z)NsLQj$67I7bC;_FFP4jUM%BkTQR-#CKHFos09vnFmL1WtmRsFC+)BqweVa08=Tm5 zvl~LO%7JP@EM$i)=GSr3aqHLdsq-nZs2BBI%;3|5>$uFQR`&*3w!|le6#92$E?ZU- zo2cYsf(fJ8==YM`CiB~k7f!Uk6lV%)sE)RwY0#p>C(0RN-g;BK)Zc)=8D=C>`6Ig%O{p%8oRtNN4k+{D}vY88)_u=TKXgvX!8-#YB$Nf&E zs=+k3_%bxxM z=9(y)wK~9%bM!Q5Iy7aLiwVf|nYrEE#VnJH9Ng%KF%bhF1e*+p&T8k5_c{KRYqbtO z`8BAlbN=@;`L+l#kf3ip*C{~+KDnBJ^7qZ|V@%g;DnD$slMF1YSvQEIbHBzv{T|4neRJy(PjdKX zL0kyiBJ5|L=r?vgj=6R{pPJzy_-tn}Pe4X+8N|7X>9>KvyUci>2TSk&F5e-m+%$UI z3B-3y_U_jldz9GI?C1Q-{1&zC2+AorJALf1#&v9JVI6W*!hDze;~QT!<|}^v(tX9g zeBjI{)S}L%em>+IqpiHxFq3o~ul0_ziLR&O0_r5;QmE|EtdncbuS0RsyaTWT{;}52 zySkZ9mdxe=+)hM%nxdNIr$7MxNIN1`f2Zh*!X;4Ac78n%E7#nVHJ>hN=-f5W$?R-) z?{8Jrvj@hdf&xya8=NHOlN6F*cCtkkBaIYTXe7#}754i{bUCLXqqYNT*R|{FzZlVv zRQU)5zItf^kf}K~yHdn!t=D(*pa?fJ<*SbFAm0YmqNd$A(~WQ6w0XbAX`k}0f{KDG ze`7$Esco?gkF0Jf8%J7KfE$;Nagd=oy7VcM&S3C$BiRqFg0H+GD+3L7HX4q>#s6B2 zN>+`k4@J*TRlc^}6V9efTN(zD+;d;@-qU}&-`DqYmFT=#;m4oAcYk5Y5Fu1*v!VV8 zRBPa7c5Z!Iw!kHbXUd8x=KsFdocVM$$UGS*Qpo{Pt%(FZlERc0!vHq`9ma zEpVjj;nqJ(mGb_kyUP86eEJ1!XY(}bNajjXTFo=addS7v_EW|l%WL3QioB(7!J_2j z2o1cot`U{{8}o2Xkb#|E)h}MfEt5G|O>x4rS)mK9;#=O5y*iw!(Ckr8r&rXT*S**` zC_{jj-$GcYf7+UGe}+m*=h~sK7UyJNv@XbTn&GVf0Vo;St76T}a@kI0-Ma@Yn9_dc zhvP!&iPgg>X0mtpP$b5?A3HOhV^c+0*Hlt$-I7>$P|~ z`C6M>?oE2tSxr>ldq)NmP!1H*{x)B*e}9Xgx*DYry<#(~jf67gL&yWzF~zY`xRaYl z2Ze#Fk2rSQH@=c^`j@<0lKeJ=r;C5=vOn!BzQZ5_7P(4WEH!1??L0m)HXVv3Hr`(P z0K7dw#zH3DqZacgJJM;<59&TLGeA0*oYhwAgFpFAyGj-#x3f;3drfTIf2l*~U=GOs z3hZwOZt}<33C;eJre7oZJFhrHV_WmvgjUOND(1s=i=eh-(alpt(~or)aqm4kO(OLY z#b3S8@E>0>h96)^_fEkXkDnLK80(<6gl~coZj0Rc4>@~el6pbRlsZUjQo0Xo?*B~p z(f(iQK1Tz9^_Mn2>COEB#4t7`VuMA1n2D_+m6;}}x#zu@=o)X8?>Q5tev;qK&lc}$ z?0`=Pn#}BsGg;Fmwy$XrP=9Ko?5PlXn{I^$cEK_`#dxU%Yy|sQzHr-YNk^b%+KlAc zvD9;ZnFfb&+HTdo8e(}b9}7DEq@SxJI)&m`Fy8v&J@VPM3agcwvGtPAGkf@8kD~2b zUUYdixG7sPJjw%`e=J(ktRPv>#N0sXBc4>z$osE&C%%XH0PJ9LJ42PtaOEht>>JQ9 zeukd8*R*rqqkl%#VC>ozC`j}SkpSh^4dd@PjgK6#r~a3O!*LLAZEK-XLR{3JT~LbS z)9?X*-v7W<`4xD&gU*Q98#m(+Z;VVkS{ESUM%#s8tb6gOBsJ{_*VCeGw5xDfCl4{aN^*O#-oQ(amfHo5LT7sjGDv|fU#eQjd`hZa$yG96QhrFt z#n!|rvpN#4@rD}JO`j|~TEdPu(Wm7vxrg3;xKZ+z@o5m6Zqbqy1w*xuHZ!wIZY#sA zx@(iU(k*%o3JteFQ-41hqsxaN{>OFZm)p1mEb>+3_%?ZUKeg953Ymtp)+!e9if-4q9-awnDdW;yh`g({n_P9KWeXRE6g zhcPAW42l`e)hx_34=7LKRE3GsJ$84d5ZpEH##Zhjf-(uBJ2|2Qjy$mSgWhpix-xmk z)w6LIA}wz6?Pb6X>)v2zaFxnHF~gaLo#uIwis~`sx%4~g49DL>-78@Xb~2BYVMat1 z!pm=0ocPs0Wl5zvo07s;gOBGM&+@I?aw~j)%O2|OMd+q0d9%C@OcxxM|IOkEFn{QL zp-4P8%ik4U? z9tkV`79IV>tjoOF^GCTIW;kt-I69EC+?(v{cu{n6x<0kc&<5D zH3NlMEDE+<^#|I%YHRBfn&+R)7-d{Z5zXrx@?t+!%FPW@3iLeQ(G`f|(sNFW5EM*o zxX%LsY-fCB?KL1UJnEQ1$`w%CgF|kkNC|MVgE@=On-~WcnX5cB+dlBUpiiS#+J0cV z9S_(I;ezW7V2t7~9k=+or7|h5M6(Ukxoz)&tC`n4kYm^FEFHpz1|!==C!Yc+12-5D zKmuFl)`c{yt&K$ovbqBYH7-()wimb3H3N{vO8q)r8RM=cRubnfl9o22ZVnB^p_s^fY^3}E&iLbF$VUOqbvami({!)tH6eSP?~PvwbWHD&`l$< zMP9-qcE1hsgPig{Qv!n7npO+nR9g7m-$4N*EhV|5{q=FDg@vwTo4jNbEZ#$hS*i{fr6G3^BE)IJot0-1K^^jAPXKS!+ovH%v6aN8h zF7``vz?=SjKk!Fey~x>3`(n{C(NOWI$>0B$)u`mB8EoRR?)RyoL*=NYEOPgciovX( z;TKKo^HiyQNCf2fO^eU&U<`FmA&H{aG1AeizGzR`-VsInqP92(A4 zH4dVZ#YdC0R|ChrY2L>q*1Fw@Qqnj*psg7ZB_HsEMf0;@>j*BHSmfh@^%Zl1W{3b9 z?#JDsdT_iDTmY%dfxx-+pT6T32`_QsVYSoy9zumsT)g7hClN3Rv@4vyCK-*Yw6hk` zZ&ET@78a&rw_7@|1=?D%jmihm@nvY0$8Sh;<{c0c9U z#bsxE@G+{e81jc9_9*AP_fKY7xo0vE?6IdGJ3k^3uCF~tCVH@RhzkEky4bT=hPPcT zzEJ(It%eoC5xxv$>j&w*ek|wAcJ>;9-~cFDkbgKZuK42d?|5Oa%hb^@?%b43>Aqo- z+tQxadKGNNmtFCVoy)c}1N`NHz11drW|UiK&TH+lwLu({Eh3i7lmt3iCJCBss*yOS z8MzDIJNwY0hL*a{j{MW0p-*niL%rz&ulY3lS_0X3639b0tN^FH)>!sf=}UzzTS3n6 zW?Oyv_i72Ol?_9zl1QOh+bk17kbZ&!hDBz(W=zJPXr3t1Zpqj11#t&|I_V9rARdg` zFd7wZ1eZItW_J7?O(5j**K2og-(vd#um_bHLXJ9a^LS?TWmlH2Ky#8nb5r_#iDyrTR-|afPM4e?0jYp- ztwb#xO(U=MQ@!t+=T~Zt1RFy;gQAHIV^ph?%#QBQ$6lI+O|>R*8Rj-oAzrE_4;4>@dW zaV(m&=_O%dX!RVx?~LAm007h)_W;|GA8+1OoGVVhhH+(m5_zclhI21#AIN3$BfK zSU>pB*r!3>EcNQj*bNXO{H4H_2*{W!{97p16)-rZCxnMU_XqUGKCE$Nlvn0pL~nee z=yXXnk9<`VUu1o!_jaHusK7UjDNMX+MwJ8dCb*{Ofl$s^0l?}vSM&fvcVk(`!e!%L zQt!A|NN|C$k$o0gl@mcSL5tbJ6XBuX>%o6mf7izE(th(SX}#ANJIhft9M9&Ys(+tf z?)6u|!*4>wJp2Nu)T`Y793GhSEu+`S3Ttu--79P5u;J4?!>7zkWX*?<_@0$q3J|pO zN{KSlFppQw_`SGGE#%}KcJJ+jEz?uwPt(=E88mroVvJ4?50 zpDY9z(H$zXu3;DaB&~wl@^r1k{YkZLs#W3X`$k5n>87W5Qh~)1F{Kw%utdTp`{^rn z9dYm-Ob#_C8#S&Byil%#I__$hPTiM!Bq0;Xy4wjPu5FSk?R9sf&qgdc+8?mX${NC@ z*ZYiE;&^+lgY%^xx7P?@B16ZvMV>!m^M%n6k)5<86w&qSBvpE_FQ@Ozvy4%>T$vSA zyU7XMF_ntjGTUKE56~ooke@t*66}&Txoe^^W|d&!3?Nu>t!>iBH~Sf+iMd;H45m!W zGYR&cI<|Zpr%bmYn93+U)f&*Zaq}SH?iyx&zg)d}rg$#HR57z@ZN?DV=OWM_#&G)k z!}4y($;pix9I1T1HLJ}21wPxmxL^k)<*7z<&KkDIzpU4n(WuLp!CLBXM^3Vk{Wy;c z;d2kUNd)88{4WgkVJ!A*`->O}Md(=_4w5}Dn=UlFpr0_~43lv_U2%FQsM)70Q@cCjlw5Z@imAgw;o`$D{_Xp9D8fvJfHioEU zzdTh*7p(G-?_O&h3}o1r#k}rF7eE{TO_Y4MfbWu-pceoAC-v<`$+8x8?-F?Yfxfp3 ztX(Bk)@QYw$LwH8=cW{Kw`X$pp>@uRg{4aqB1DMs@I;%wo1I=Abhp zqeeLkmJ*Bl5%(Q|Y*A~jscp<(q0eKCsv+SW#3XFM^skE(x`S3jbP)E?a<8=^=6REm z7*-pa&739fL1RKY8fB-q$ps)Rb+V8;0>`Cg@Pb}w@rJu1EcVj;bFR|pha==}ErEA- zB63ncFi+%dU{Lmmvxpb{RKD=ySs>x;17!>{aDgie4Td3?H&)cE-7&nCQsrO9KaNAVKdcg#$ZbgY&OL&6)jBoBfvUBmwx{WB9Jwn^^k;+dZo@_K6 zP5!XbT=fCoHorcfw~auVO<4)*S(9+;h?2^Al^~G#*yiEu8ej^j|S&_c34}pgJD@8k!vo zzUPTk`0{?O`78GrInSQwy>UJPLg?E|P%24?0Wq9T-@k0;Hg1cbd$PrUhto2EPluee zh>Ab^o2zV1mM#jDyfkd>iuu{WZklbnD3>R}=^=^1=;hO^8lY>(xt)5&2bL#KRQ=_I zCVMyH6nAR~J|r(u(+ska;g-!3*kt2CcvmS_@*hB*2Xr@oUb)5WyNASQKDWyjK)*!e>wHq$#k)Q-d z^EtzPr10|t@eJ~hSf|tFCIzbKZd{n^D?(SdQQVaXL2k6V0v1q0@2WlL`&;T4@(F*v zC3priEL48xbT3!T$t7ydQ%I`+{k1P%`JJ25j< zm`UM@O^``_L=Ixqv1*V`XcwbI^GBC2G=BRPs89X#yfw~qwJOBt`djpSZ}thV2S&N& zvSg=c*?0w<@P|_O?Ap%Ezetfp*#Z^|jE#G1)K6h0S~r29z?0*`^!<wm&qGY@ z(>&}*6>SM2tI}u3(w$4V4acFZuAKem7)5T?+Ri-8F$*n8p4rK=&`=j|4^p)q>ISIk zfjbrOc6APcU-r4KvV)z=J=wG67i-7qo4)D?RwtV&1N2t4?>&tf%%^O@U*=1o32Yfs zF*M@BW!Y15>5PwVm)~@x0^PK3{=@(xHaKoQ3=u&*oJX)aLV|qC>HW5?e@MvZI-}#{ zRr;Pied$8+9VS_?z4|i!A#Fiq7whd=*&nVI7z4@O8YG1D_aT)Bib5sXTvhS-Kn4G2 zx#h{TbaWoTTWk_5hS!5{1#N9y+s8OJp+Cb@^iZ=kKrpm=w=+U1u=pvZ+qNt9L20xu zh%Uvdcm9f$5=I zw;c@Gq`4G6$2_;u+x(y`%cJl0>f-svs4q`eT*2_^DqY@W8;}AqIIDX1QkGDjfch+# zLQ$6I9FhZBRJC7^Ns1zQ zEhl|SfWx0PSiegP<>;Ja{BAx~4~=aG1bn&)AxY0r8*B*G42_u@0lwRf^5z)7Uo-FC zy1((AUey3a-0gq16H9f2VWqhp%u08JWo5U$4Sa^6! z+i$Pb>qGpudHYKcHBT?3(1hpRXR7~Nu6=n8d+lL2_DScnR#p&1H^Wfh^CQsH(e-pR z>Z^p(9_!2sv8}g$|M|g>12ccTMF})y#%6$RxFku4Mv0jMTCe3H|KQ~trbqm076=}~ zKqk!987iMCYtB!9gkb-Ce^N$PA?u#ejsbx2ZWbr#W2NWm@(WM0lu^6zPYA{Np9L&L zahoh_BVca`Q!D=O%)n&Fv2d_TTG4gDJu--}J}Xc>YJ01k(ABp=iBM{pIzm`~?tXbC z&?zq;4Sp3%X|b-IHkSN8PCm+&v$vJ}JjxaB_^DF0L% zwU!`5ZomSnin10d`uOt4BOd;~(D3?8b;6}p$M|?F-18s6lOO~4adhA!yF7kf-BB>C zlseIVY)oH_p2uS1LHTA)WT*7>;@8&fI9Qdm9};N0Ah*G|syXA)Qee{1ic0x@QGC4} zmBsS=3=wOn_f_?TpA;i5)qcgAU^%;C6{kEnYjyyHS0otp7Ccr>Z#?niQe z?F8Wm-|}FLD&aXN!|~j?M31+3MU~1Ng)I~AE;HZR)w?;R{^=$+X{Dz`sFxAPAn0tf z$NlAmlEm8fBvB(~TPq`2)V(jqTH%+|ZDg?+3uYa1hOe;LEKES;i4zxey#kwZQ#wkh z2~D_JQ@k<>@pyHif>~V}NUw@WEr^No`e0QO*a0}pex)p`9&I!C~#LtbgXdep}Eav6}8G8 zN$EjVnnekipUSO1F0(?{vc02hHqu_j+BBv2!oB-HM(YpVoy<~S54xN{X|+zg)=0g zS-SMUam|+)TNI7)JG}g&2iODT&ux=hjV1UW@Fq1zFtku)eQx3Gmea$Pv5U*P;lcI8 zNBmMm1uT19$So@jF~+p6VIGLT8S|N5ahKQCs;jlr?I>O#!7$&bZkZEkqo^%%y%tCf z7@P_bn{D^Tbw!=CaY&mJ~&;5yzzCzTd$HZUC=dc_fhytcU-j|HhZzLe?c&DTsR+g zn;pzmeR@P{pxhO;f1lnws3J=K->7@fu%_N_-8YJWN=NBUDI&dt(u*`B20?mLI)s2o z3lN$}?;s%Xr}y4_0O?JngM=P>PpF}YXTEE#ea?FK+2`6H_jNwsc|O;^$7KBf*sSoMFBZ z>(?bfV=pT@b>p^r9VKz#yn97mU0}E*UHtf{z|a^4p&Dj)FkfaG6ly8UH+Y}8Mzy^} zjqAm%^)6AjV3X1-es|~V8;?RgWJaba@>><8e$eZlJj@x=Mkt3aGw_hsk1xZII_a$= zU}z0+kEBjP0$g!^dDQ!!doA^^doChhKYw!m;t~!*%TnW%`XmXe*90hVlh;E0H`*me zyA+-I>b%tojN-cI?MBkouM7f0k{?R^+2?nU;RcF2KlnUUutBXRsy2Q(2DtdW9`TFX zJ+IM>V9$*fwZ3oh`TnUdIe4~?xQCN$Q&MVA&BAY>tD^*PDNXEBy$AjFm0OxAa$x&a zbAYT3#}^(0;$#v>zUh<( zIy@drLg_C;v9@@z!fjGrLGtf~XPD$3RN zOq7&9ihqxHCYz525|FmDy5f?3jfMIPyOu<>j*jSHaE{k~o!@j14(jMfv5k?e7^|c- zZ?Rev60pIf=%Sj*&cm}Pbi9!=p=yiJZNaJ1xD>Y|uQE>Fpu*DO$12a>=S zw(9yO;>7Lw)Va?^o;hFH0uV6YWqUbQ)&qr$9^WGVCu~m-u}yd-3_VI@x|e{n9yOTU zn&Hz!Tp{${0hfwDTVI9ZRGZ()GvQMuSJ+o=8}etDFR-aoXF|p1b1YnV?;8jFLmc~J z#FHeZA40afB!X%D;+oe8U8b;mQ2wTo2BRSM&m)z1W%3Z-6JyDSBR=QQsdlw2vd{nJ z(}kz~-vuQGhX1`=7xaG^VP_0;3_fHP0OEi>3vfm*tF9-GPvh98Obu>|!c={!m`JgS zcQx4WgDT87WqKUD^?2VDz? zgK%tJvea0baK1AcGF43Er$8)NYbLGN)Tg9O$PTq0|N1q}^}A-vpz`roDk2PDj7f&X z_}Uo}##6Fvwy8Wy}zEgbI74Bav^bmyqeLX`e{xifyOA~;^)8L%Zm(oN~3~KGic`89+9^6Q4Y_>NO z+VEl4gL>KK5$Zm1GB3Z`#U$MXYhi8u=UWDx5ZdlEU6+L%ZeyIXhVjOE?0d9SgxTQF z***1pHn!t#Kd(K+_jvYAtNL$??pA@t#F1`vIlmvxBJSzE4wSeTtfKTOw{&Ig;)t}+ zYHj@d!7>{ovCAlkSq}qN!dArJK5fEUeQij(&<4_^Hp9hA1qJoO%B20*4yo_NCrTK3 z`7%WuJuJeprI6qZskk!;k;E5^n&fx5D7kQRtb9w2RdBD^M|e%50m&?2&<^2Zqez^4 zvNU{BbnOlddO~+5!HvzwwN`z%QW@*brQzO-B{q%!v^_;Pr`qXc{=aNbTP-lNeay^b zH%ujitNAmQnB_1eq-b$FZp5A=iA3x0vYh{;ou!d`((?ip9Z&KgcRErbGc$mb&4!a& zWeLs3N_;(Q^OkRDsA`x&=#f0?`{g@=fD2y6qRaYDx-v| zZPsUa=ElCsIYWo`3s)v{ks$GDb?=35v{T-&<O`PNZhI)GpM=T%0f;AHU983e1WA z3LFR{-B)jTo#9RIyb2G8~$%0DW7=1?6T8@YfgZ%SSJ9Z<-WDsjIWZ*rmP3j8tO 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 Date: Fri, 27 Feb 2026 14:20:53 -0500 Subject: [PATCH 48/77] strengthen the ValueError message --- src/diffpy/labpdfproc/tools.py | 23 ++++++++++++++--------- tests/test_tools.py | 23 ++++++++++++++--------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/diffpy/labpdfproc/tools.py b/src/diffpy/labpdfproc/tools.py index a46667d..2aa6754 100644 --- a/src/diffpy/labpdfproc/tools.py +++ b/src/diffpy/labpdfproc/tools.py @@ -246,15 +246,20 @@ def load_wavelength_from_config_file(args): return normalize_wavelength(args) else: raise ValueError( - "No configuration file was found containing information " - "about the wavelength or anode type. \n" - "You can add the wavelength or anode type " - "to a configuration file on the current computer " - "and it will be automatically associated with " - "subsequent diffpy data by default. \n" - "You will only have to do that once. \n" - "For more information, please refer to www.diffpy.org/" - "diffpy.labpdfproc/examples/toolsexample.html" + "\nThe wavelength was not specified and no " + "configuration file 'diffpyconfig.json' containing " + "the wavelength or X-ray source was found in either the " + "local or home directories. Either specify the wavelength " + "or source using the -w/--wavelength option or " + "create a configuration file.\n\n" + "You can add the wavelength or anode type to a " + "configuration file on this computer. Once created, it " + "will be automatically used for subsequent diffpy data " + "by default, and you will only need to do this once.\n\n" + "For detailed instructions on creating the configuration " + "file, please refer to:\n" + "https://www.diffpy.org/diffpy.labpdfproc/examples/" + "toolsexample.html" ) diff --git a/tests/test_tools.py b/tests/test_tools.py index a6c27b1..e7a137e 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -360,15 +360,20 @@ def test_load_wavelength_from_config_file_without_conf_files_bad( actual_args = get_args_cli(cli_inputs) msg = re.escape( - "No configuration file was found containing information " - "about the wavelength or anode type. \n" - "You can add the wavelength or anode type " - "to a configuration file on the current computer " - "and it will be automatically associated with " - "subsequent diffpy data by default. \n" - "You will only have to do that once. \n" - "For more information, please refer to www.diffpy.org/" - "diffpy.labpdfproc/examples/toolsexample.html" + "\nThe wavelength was not specified and no " + "configuration file 'diffpyconfig.json' containing " + "the wavelength or X-ray source was found in either the " + "local or home directories. Either specify the wavelength " + "or source using the -w/--wavelength option or " + "create a configuration file.\n\n" + "You can add the wavelength or anode type to a " + "configuration file on this computer. Once created, it " + "will be automatically used for subsequent diffpy data " + "by default, and you will only need to do this once.\n\n" + "For detailed instructions on creating the configuration " + "file, please refer to:\n" + "https://www.diffpy.org/diffpy.labpdfproc/examples/" + "toolsexample.html" ) with pytest.raises(ValueError, match=msg): load_wavelength_from_config_file(actual_args) From d4b93598edf5eb51874333c1f4898ba6fe002381 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 14:44:50 -0500 Subject: [PATCH 49/77] update tools examples to reflect new cli --- docs/source/examples/tools-example.rst | 37 ++++++++++++++------------ 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/docs/source/examples/tools-example.rst b/docs/source/examples/tools-example.rst index 674d244..7291658 100644 --- a/docs/source/examples/tools-example.rst +++ b/docs/source/examples/tools-example.rst @@ -20,15 +20,13 @@ You can do this in one of the following four ways: # Option 2: From a z-scan file args = Namespace(z_scan_file="zscan.xy") # Option 3: Using sample mass density - args = Namespace(theoretical_from_density="ZrO2,17.45,1.2") - # Option 4: Using packing fraction - args = Namespace(theoretical_from_packing="ZrO2,17.45,0.3") + args = Namespace(sample_composition="ZrO2", sample_mass_density="17.45", diameter="1.2") # Set and view the computed mu*D value args = set_mud(args) print(args.mud) -2. Next, we load the input files for correction using ``set_input_lists(args)``: +1. Next, we load the input files for correction using ``set_input_lists(args)``: .. code-block:: python @@ -59,24 +57,13 @@ If no output directory is specified, it defaults to the current working director # Option 1: Specify wavelength directly args = Namespace(wavelength=0.7) # Option 2: Use a valid anode type - args = Namespace(anode_type="Mo") + args = Namespace(wavelength="Mo") args = set_wavelength(args) Note that you should specify either a wavelength or an anode type, not both, to avoid conflicts. If you provide an anode type, the corresponding wavelength will be retrieved from global parameters. You may use ``labpdfproc --help`` to view a list of valid anode types. If neither is given, it's only acceptable if the input diffraction data is already on a two-theta grid. -To simplify workflows and avoid re-entering it every time, -we recommend saving the wavelength or anode type to a diffpy config file. For example: - -.. code-block:: python - - from pathlib import Path - import json - home_dir = Path.home() - wavelength_data = {"wavelength": 0.3} - with open(home_dir / "diffpyconfig.json", "w") as f: - json.dump(wavelength_data, f) To set the x-axis type (xtype) for your diffraction data: @@ -88,7 +75,7 @@ To set the x-axis type (xtype) for your diffraction data: This sets the xtype to ``tth``. Other valid options including ``q`` and ``d`` spacing. -5. Finally, we load user metadata, user information, and package information into ``args``. +1. Finally, we load user metadata, user information, and package information into ``args``. To load metadata, pass key-value pairs as a list: .. code-block:: python @@ -137,3 +124,19 @@ Using the function ``load_metadata(args, filepath)`` requires both the ``argument.Namespace`` and the current input file path. For more details about working with diffraction objects and how they are written to output files, see https://www.diffpy.org/diffpy.utils/examples/diffraction_objects_example.html. + + +Creating ``diffpyconfig.json`` file +----------------------------------- + +To simplify workflows and avoid re-entering it every time, +we recommend saving the wavelength or anode type to a diffpy config file. For example, + +.. code-block:: python + + from pathlib import Path + import json + home_dir = Path.home() + wavelength_data = {"wavelength": 0.3} + with open(home_dir / "diffpyconfig.json", "w") as f: + json.dump(wavelength_data, f) From e0b254716218d770d424ee207bbca6ffa037840d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 14:54:33 -0500 Subject: [PATCH 50/77] rebuild api docs --- docs/source/api/diffpy.labpdfproc.rst | 32 +++++++++++++------ .../source/examples/labpdfprocapp-example.rst | 1 + 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/source/api/diffpy.labpdfproc.rst b/docs/source/api/diffpy.labpdfproc.rst index 1bcc98d..a3f53e1 100644 --- a/docs/source/api/diffpy.labpdfproc.rst +++ b/docs/source/api/diffpy.labpdfproc.rst @@ -1,9 +1,7 @@ :tocdepth: -1 -|title| -======= - -.. |title| replace:: diffpy.labpdfproc package +diffpy.labpdfproc package +========================= .. automodule:: diffpy.labpdfproc :members: @@ -14,17 +12,33 @@ Subpackages ----------- .. toctree:: - diffpy.labpdfproc.example_package + :titlesonly: + + diffpy.labpdfproc.data Submodules ---------- -|module| --------- +diffpy.labpdfproc.functions module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: diffpy.labpdfproc.functions + :members: + :undoc-members: + :show-inheritance: + +diffpy.labpdfproc.tools module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: diffpy.labpdfproc.tools + :members: + :undoc-members: + :show-inheritance: -.. |module| replace:: diffpy.labpdfproc.example_submodule module +diffpy.labpdfproc.labpdfprocapp module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: diffpy.labpdfproc.example_submodule +.. automodule:: diffpy.labpdfproc.labpdfprocapp :members: :undoc-members: :show-inheritance: diff --git a/docs/source/examples/labpdfprocapp-example.rst b/docs/source/examples/labpdfprocapp-example.rst index 3a83ce4..c33cadf 100644 --- a/docs/source/examples/labpdfprocapp-example.rst +++ b/docs/source/examples/labpdfprocapp-example.rst @@ -1,3 +1,4 @@ +.. _labpdfprocapp Example: :tocdepth: -1 From be60e6149768c43b481405bb46fb50fc9bd51e8d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 14:55:36 -0500 Subject: [PATCH 51/77] news --- news/doc0.3.0.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/doc0.3.0.rst diff --git a/news/doc0.3.0.rst b/news/doc0.3.0.rst new file mode 100644 index 0000000..b0af63d --- /dev/null +++ b/news/doc0.3.0.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added documentation for new CLI updates. + +**Changed:** + +* Return a ``ValueError`` if no wavelength is found on config file or if its not specified. + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 050c0a4c6d733c23f4a2cdd7b9d100512783bf94 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 16:08:11 -0500 Subject: [PATCH 52/77] load interpolation data with importlib --- src/diffpy/labpdfproc/functions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/diffpy/labpdfproc/functions.py b/src/diffpy/labpdfproc/functions.py index 7ecd126..8d7a76a 100644 --- a/src/diffpy/labpdfproc/functions.py +++ b/src/diffpy/labpdfproc/functions.py @@ -1,6 +1,6 @@ import math import warnings -from pathlib import Path +from importlib.resources import files import numpy as np import pandas as pd @@ -17,11 +17,11 @@ CVE_METHODS = ["brute_force", "polynomial_interpolation"] # Pre-computed datasets for polynomial interpolation (fast calculation) +data_dir = files("diffpy.labpdfproc") / "data" MUD_LIST = np.array([0.5, 1, 2, 3, 4, 5, 6, 7]) -CWD = Path(__file__).parent.resolve() -MULS = np.loadtxt(CWD / "data" / "inverse_cve.xy") +MULS = np.loadtxt(data_dir / "inverse_cve.xy") COEFFICIENT_LIST = np.array( - pd.read_csv(CWD / "data" / "coefficient_list.csv", header=None) + pd.read_csv(data_dir / "coefficient_list.csv", header=None) ) INTERPOLATION_FUNCTIONS = [ interp1d(MUD_LIST, coeffs, kind="quadratic") for coeffs in COEFFICIENT_LIST From 9e35c846e6bb064273d66810c0c278d9c10b7c4a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 16:14:05 -0500 Subject: [PATCH 53/77] news --- news/load-data.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/load-data.rst diff --git a/news/load-data.rst b/news/load-data.rst new file mode 100644 index 0000000..4b614de --- /dev/null +++ b/news/load-data.rst @@ -0,0 +1,23 @@ +**Added:** + +* No news added: change how data path is referenced. Remove ``__file__`` reference. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 19dfb6231984507852294c7765e27be9ba9d1941 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 16:22:49 -0500 Subject: [PATCH 54/77] add package-data so the data dir will be included at runtime --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a55f107..b7ac149 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,9 @@ include = ["*"] # package names should match these glob patterns (["*"] by defa exclude = ["diffpy.labpdfproc.tests*"] # exclude packages matching these glob patterns (empty by default) namespaces = false # to disable scanning PEP 420 namespaces (true by default) +[tool.setuptools.package-data] +"diffpy.labpdfproc" = ["data/*"] + [tool.setuptools.dynamic] dependencies = {file = ["requirements/pip.txt"]} From 26a8a0127c411f969fca39f5a8097556429021ee Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 16:34:25 -0500 Subject: [PATCH 55/77] use tests-on-pr workflow from skpkg 0.3.0 --- .github/workflows/tests-on-pr.yml | 55 +++++-------------------------- 1 file changed, 9 insertions(+), 46 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index db5cacf..6f96ab7 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -1,53 +1,16 @@ name: Tests on PR on: - push: - branches: - - main pull_request: workflow_dispatch: jobs: - validate: - defaults: - run: - shell: bash -l {0} - - runs-on: ubuntu-latest - steps: - - name: Check out diffpy.labpdfproc repository - uses: actions/checkout@v4 - - - name: Initialize miniconda - uses: conda-incubator/setup-miniconda@v3 - with: - activate-environment: test - auto-update-conda: true - environment-file: environment.yml - auto-activate-base: false - python-version: 3.13 - - - name: Conda config - run: >- - conda config --set always_yes yes - --set changeps1 no - - - name: Install diffpy.labpdfproc and requirements - run: | - conda install --file requirements/tests.txt - conda install --file requirements/conda.txt - pip install gooey - python -m pip install . --no-deps - - - name: Validate diffpy.labpdfproc - run: | - pytest --cov - coverage report -m - codecov - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - with: - verbose: true - fail_ci_if_error: true - token: ${{ secrets.CODECOV_TOKEN }} + tests-on-pr: + uses: scikit-package/release-scripts/.github/workflows/_tests-on-pr.yml@v0 + with: + project: diffpy.labpdfproc + c_extension: false + headless: false + run: pip install gooey + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 24c43cb1ee5ea0fa566cd00e0c4967510b289b47 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 16:35:09 -0500 Subject: [PATCH 56/77] news --- news/tests-on-pr-wf.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/tests-on-pr-wf.rst diff --git a/news/tests-on-pr-wf.rst b/news/tests-on-pr-wf.rst new file mode 100644 index 0000000..2dfcfe2 --- /dev/null +++ b/news/tests-on-pr-wf.rst @@ -0,0 +1,23 @@ +**Added:** + +* No news added: Use the tests-on-pr.yml workflow template with pip install gooey + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 85ee83a1b852d575883a305e36d9573cfcfec36b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 18:09:56 -0500 Subject: [PATCH 57/77] mock diffpy.utils and add it to docs.txt --- docs/source/conf.py | 3 +++ requirements/docs.txt | 1 + 2 files changed, 4 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index ae18bcd..4ef7771 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -108,6 +108,9 @@ # directories to ignore when looking for source files. exclude_patterns = ["build"] +# Mock imports so API docs render without installing dependencies. +autodoc_mock_imports = ["diffpy.utils"] + # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None diff --git a/requirements/docs.txt b/requirements/docs.txt index 1de813f..59a83b1 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -3,3 +3,4 @@ sphinx_rtd_theme sphinx-copybutton doctr m2r2 +diffpy.utils From b7e1b1ef072760ce4c46571684a698e8817ca1d1 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 18:10:28 -0500 Subject: [PATCH 58/77] news --- news/docs-render.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/docs-render.rst diff --git a/news/docs-render.rst b/news/docs-render.rst new file mode 100644 index 0000000..8519b70 --- /dev/null +++ b/news/docs-render.rst @@ -0,0 +1,23 @@ +**Added:** + +* No news added: mock diffpy.utils and add it as dependency to docs.txt + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From a01de7ea3aa8e2198a917d9d192b2c44ce5a157b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 3 Mar 2026 18:14:48 -0500 Subject: [PATCH 59/77] rm diffpy.utils from docs.txt --- requirements/docs.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements/docs.txt b/requirements/docs.txt index 59a83b1..1de813f 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -3,4 +3,3 @@ sphinx_rtd_theme sphinx-copybutton doctr m2r2 -diffpy.utils From a645d40a317364525f66640bcab3c6acfea92d15 Mon Sep 17 00:00:00 2001 From: sbillinge <4254545+sbillinge@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:28:55 +0000 Subject: [PATCH 60/77] update changelog --- CHANGELOG.rst | 50 ++++++++++++++++++++++++++++++++++++ news/applymud.rst | 23 ----------------- news/codecov.rst | 23 ----------------- news/codespell.rst | 23 ----------------- news/doc-change.rst | 23 ----------------- news/doc0.3.0.rst | 23 ----------------- news/docs-render.rst | 23 ----------------- news/docstring-tests.rst | 23 ----------------- news/fastcalto7.rst | 24 ----------------- news/folder-rst-readme.rst | 23 ----------------- news/functions-docs.rst | 23 ----------------- news/gui.rst | 23 ----------------- news/improved-cli.rst | 23 ----------------- news/load-data.rst | 23 ----------------- news/main-doc.rst | 23 ----------------- news/muD-options.rst | 23 ----------------- news/muD-theoretical.rst | 23 ----------------- news/muD.rst | 23 ----------------- news/muD2.rst | 23 ----------------- news/output-wavelength.rst | 23 ----------------- news/package-update030.rst | 24 ----------------- news/py313.rst | 23 ----------------- news/recut.rst | 23 ----------------- news/recut2.rst | 23 ----------------- news/remove-namespace.rst | 23 ----------------- news/tests-on-pr-wf.rst | 23 ----------------- news/tools-doc.rst | 23 ----------------- news/update-ref.rst | 23 ----------------- news/utils-updates.rst | 23 ----------------- news/wavelength-config.rst | 23 ----------------- news/wavelength-workflow.rst | 23 ----------------- news/wavelength.rst | 23 ----------------- news/xtype.rst | 23 ----------------- 33 files changed, 50 insertions(+), 738 deletions(-) delete mode 100644 news/applymud.rst delete mode 100644 news/codecov.rst delete mode 100644 news/codespell.rst delete mode 100644 news/doc-change.rst delete mode 100644 news/doc0.3.0.rst delete mode 100644 news/docs-render.rst delete mode 100644 news/docstring-tests.rst delete mode 100644 news/fastcalto7.rst delete mode 100644 news/folder-rst-readme.rst delete mode 100644 news/functions-docs.rst delete mode 100644 news/gui.rst delete mode 100644 news/improved-cli.rst delete mode 100644 news/load-data.rst delete mode 100644 news/main-doc.rst delete mode 100644 news/muD-options.rst delete mode 100644 news/muD-theoretical.rst delete mode 100644 news/muD.rst delete mode 100644 news/muD2.rst delete mode 100644 news/output-wavelength.rst delete mode 100644 news/package-update030.rst delete mode 100644 news/py313.rst delete mode 100644 news/recut.rst delete mode 100644 news/recut2.rst delete mode 100644 news/remove-namespace.rst delete mode 100644 news/tests-on-pr-wf.rst delete mode 100644 news/tools-doc.rst delete mode 100644 news/update-ref.rst delete mode 100644 news/utils-updates.rst delete mode 100644 news/wavelength-config.rst delete mode 100644 news/wavelength-workflow.rst delete mode 100644 news/wavelength.rst delete mode 100644 news/xtype.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 33d7032..2824fd1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,56 @@ Release notes .. current developments +0.3.0 +===== + +**Added:** + +* Functionalities to estimate mu*D theoretically. +* Added published reference to ``README.rst``. +* Fast calculation supports values up to muD = 7 +* Recookiecut with updated ``scikit-package`` to enable docs preview in PRs. +* Updated package standards to scikit-package 0.3.0. +* Added ``cookiecutter.json`` file for the ``package update`` command. +* Functionality to read wavelength and anode type directly from a diffpy configuration file. +* Utility and example documentation for ``tools`` module. +* Gooey support so that the app can be run with GUI +* Coverage report in each PR +* doi in Readme for papers. +* Support for independent variables other than two-theta. +* new subcommand ``applymud`` to run the original absorption correction process through CLI. +* Utility and example documentation for the main module. +* Added documentation for new CLI updates. +* Documentation for functions module. +* Spelling check via Codespell in pre-commit +* Python 3.13 support +* Functionality in `load_user_info` to enable user to enter an ORCID. + +**Changed:** + +* Default to brute-force computation when muD < 0.5 or > 7. +* Print a warning message instead of error, explicitly stating the input muD value +* Functions that use DiffractionObject` in `diffpy.utils` to follow the new API. +* Workflow for loading wavelength - raise an error when both wavelength and anode type are specified. +* Readme: muD now requires the ``--mud`` flag instead of a required argument. +* Made muD an optional argument and provided different options (manually entry / z-scan file path) for users to specify muD +* Increased the number of significant figures for wavelength and separated values for Ka1 and Ka2. +* hyphens / underscores format according to new scikit-package group standard. +* GitHub workflows for renamed test file. +* Return a ``ValueError`` if no wavelength is found on config file or if its not specified. +* Compartmentalize commands into the subcommands ``mud``, ``zscan``, and ``sample``. See documentation for more info. +* Changed ``doc`` to ``docs`` and ``CODE_OF_CONDUCT.rst`` to ``CODE-OF-CONDUCT.rst`` to comply with scikit-package standards. +* All function docstrings and tests to be more informative, incorporating new ORCID function and improving overall clarity. + +**Fixed:** + +* duplicated wavelength information in output files + +**Removed:** + +* Remove the import of extend_path from pkgutil in diffpy/__init__.py since we are not strictly following the Python namespace package convention. + + 0.2.0 ===== diff --git a/news/applymud.rst b/news/applymud.rst deleted file mode 100644 index e618a21..0000000 --- a/news/applymud.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* new subcommand ``applymud`` to run the original absorption correction process through CLI. - -**Changed:** - -* GitHub workflows for renamed test file. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/codecov.rst b/news/codecov.rst deleted file mode 100644 index e3c89a7..0000000 --- a/news/codecov.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Coverage report in each PR - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/codespell.rst b/news/codespell.rst deleted file mode 100644 index 8c5ba6d..0000000 --- a/news/codespell.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Spelling check via Codespell in pre-commit - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/doc-change.rst b/news/doc-change.rst deleted file mode 100644 index 596d126..0000000 --- a/news/doc-change.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* - -**Changed:** - -* Changed ``doc`` to ``docs`` and ``CODE_OF_CONDUCT.rst`` to ``CODE-OF-CONDUCT.rst`` to comply with scikit-package standards. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/doc0.3.0.rst b/news/doc0.3.0.rst deleted file mode 100644 index b0af63d..0000000 --- a/news/doc0.3.0.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Added documentation for new CLI updates. - -**Changed:** - -* Return a ``ValueError`` if no wavelength is found on config file or if its not specified. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/docs-render.rst b/news/docs-render.rst deleted file mode 100644 index 8519b70..0000000 --- a/news/docs-render.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* No news added: mock diffpy.utils and add it as dependency to docs.txt - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/docstring-tests.rst b/news/docstring-tests.rst deleted file mode 100644 index 137f773..0000000 --- a/news/docstring-tests.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Functionality in `load_user_info` to enable user to enter an ORCID. - -**Changed:** - -* All function docstrings and tests to be more informative, incorporating new ORCID function and improving overall clarity. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/fastcalto7.rst b/news/fastcalto7.rst deleted file mode 100644 index b82bd94..0000000 --- a/news/fastcalto7.rst +++ /dev/null @@ -1,24 +0,0 @@ -**Added:** - -* Fast calculation supports values up to muD = 7 - -**Changed:** - -* Default to brute-force computation when muD < 0.5 or > 7. -* Print a warning message instead of error, explicitly stating the input muD value - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/folder-rst-readme.rst b/news/folder-rst-readme.rst deleted file mode 100644 index 24d8f13..0000000 --- a/news/folder-rst-readme.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* doi in Readme for papers. - -**Changed:** - -* hyphens / underscores format according to new scikit-package group standard. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/functions-docs.rst b/news/functions-docs.rst deleted file mode 100644 index 8142dc4..0000000 --- a/news/functions-docs.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Documentation for functions module. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/gui.rst b/news/gui.rst deleted file mode 100644 index 11ed94f..0000000 --- a/news/gui.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Gooey support so that the app can be run with GUI - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/improved-cli.rst b/news/improved-cli.rst deleted file mode 100644 index e50f193..0000000 --- a/news/improved-cli.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* - -**Changed:** - -* Compartmentalize commands into the subcommands ``mud``, ``zscan``, and ``sample``. See documentation for more info. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/load-data.rst b/news/load-data.rst deleted file mode 100644 index 4b614de..0000000 --- a/news/load-data.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* No news added: change how data path is referenced. Remove ``__file__`` reference. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/main-doc.rst b/news/main-doc.rst deleted file mode 100644 index b4674dd..0000000 --- a/news/main-doc.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Utility and example documentation for the main module. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/muD-options.rst b/news/muD-options.rst deleted file mode 100644 index 1766a48..0000000 --- a/news/muD-options.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* - -**Changed:** - -* Made muD an optional argument and provided different options (manually entry / z-scan file path) for users to specify muD - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/muD-theoretical.rst b/news/muD-theoretical.rst deleted file mode 100644 index 4fde53b..0000000 --- a/news/muD-theoretical.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Functionalities to estimate mu*D theoretically. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/muD.rst b/news/muD.rst deleted file mode 100644 index feae116..0000000 --- a/news/muD.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* no news added - minor edits in mud_calculator.py - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/muD2.rst b/news/muD2.rst deleted file mode 100644 index 617eb2b..0000000 --- a/news/muD2.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* no news added - rename variables in `mud_calculator.py` and edit tests - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/output-wavelength.rst b/news/output-wavelength.rst deleted file mode 100644 index 7522d38..0000000 --- a/news/output-wavelength.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* duplicated wavelength information in output files - -**Security:** - -* diff --git a/news/package-update030.rst b/news/package-update030.rst deleted file mode 100644 index d8fdd79..0000000 --- a/news/package-update030.rst +++ /dev/null @@ -1,24 +0,0 @@ -**Added:** - -* Updated package standards to scikit-package 0.3.0. -* Added ``cookiecutter.json`` file for the ``package update`` command. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/py313.rst b/news/py313.rst deleted file mode 100644 index 524608e..0000000 --- a/news/py313.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Python 3.13 support - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/recut.rst b/news/recut.rst deleted file mode 100644 index 93e880c..0000000 --- a/news/recut.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* no news: modified .github, .pre-commit-config.yaml and related files to follow new practice for commit and issues. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/recut2.rst b/news/recut2.rst deleted file mode 100644 index 35f4d9d..0000000 --- a/news/recut2.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Recookiecut with updated ``scikit-package`` to enable docs preview in PRs. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/remove-namespace.rst b/news/remove-namespace.rst deleted file mode 100644 index 3ba530e..0000000 --- a/news/remove-namespace.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* Remove the import of extend_path from pkgutil in diffpy/__init__.py since we are not strictly following the Python namespace package convention. - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/tests-on-pr-wf.rst b/news/tests-on-pr-wf.rst deleted file mode 100644 index 2dfcfe2..0000000 --- a/news/tests-on-pr-wf.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* No news added: Use the tests-on-pr.yml workflow template with pip install gooey - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/tools-doc.rst b/news/tools-doc.rst deleted file mode 100644 index d126b65..0000000 --- a/news/tools-doc.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Utility and example documentation for ``tools`` module. - -**Changed:** - -* Readme: muD now requires the ``--mud`` flag instead of a required argument. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/update-ref.rst b/news/update-ref.rst deleted file mode 100644 index c8175ec..0000000 --- a/news/update-ref.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Added published reference to ``README.rst``. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/utils-updates.rst b/news/utils-updates.rst deleted file mode 100644 index fd6d1fc..0000000 --- a/news/utils-updates.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* - -**Changed:** - -* Functions that use DiffractionObject` in `diffpy.utils` to follow the new API. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/wavelength-config.rst b/news/wavelength-config.rst deleted file mode 100644 index 1bf4566..0000000 --- a/news/wavelength-config.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Functionality to read wavelength and anode type directly from a diffpy configuration file. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/wavelength-workflow.rst b/news/wavelength-workflow.rst deleted file mode 100644 index 09891c6..0000000 --- a/news/wavelength-workflow.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* - -**Changed:** - -* Workflow for loading wavelength - raise an error when both wavelength and anode type are specified. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/wavelength.rst b/news/wavelength.rst deleted file mode 100644 index 17fff49..0000000 --- a/news/wavelength.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* - -**Changed:** - -* Increased the number of significant figures for wavelength and separated values for Ka1 and Ka2. - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* diff --git a/news/xtype.rst b/news/xtype.rst deleted file mode 100644 index 20ecef3..0000000 --- a/news/xtype.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Support for independent variables other than two-theta. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* From ff2958e05da13f1f1eac625d83ccf9cd03baca39 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 22:36:40 -0400 Subject: [PATCH 61/77] add back support for python 3.10 and 3.11 --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b7ac149..4c359ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ maintainers = [ description = "Tools for processing x-ray powder diffraction data from laboratory sources." keywords = ['powder XRD', 'absorption correction', 'PDF', 'diffpy'] readme = "README.rst" -requires-python = ">=3.12, <3.15" +requires-python = ">=3.10, <3.15" classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', @@ -28,6 +28,8 @@ classifiers = [ 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Operating System :: Unix', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', From ec61fd0cc37f2f19571ad5b829d2aef721f08bca Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 16 Mar 2026 22:37:25 -0400 Subject: [PATCH 62/77] news --- news/py10.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/py10.rst diff --git a/news/py10.rst b/news/py10.rst new file mode 100644 index 0000000..b41da42 --- /dev/null +++ b/news/py10.rst @@ -0,0 +1,23 @@ +**Added:** + +* Add back support for Python 3.10 and 3.11. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 52f002c2d0d2cc2fa928a7ab1f6fc6632af3a796 Mon Sep 17 00:00:00 2001 From: sbillinge <4254545+sbillinge@users.noreply.github.com> Date: Tue, 17 Mar 2026 02:56:54 +0000 Subject: [PATCH 63/77] update changelog --- CHANGELOG.rst | 8 ++++++++ news/py10.rst | 23 ----------------------- 2 files changed, 8 insertions(+), 23 deletions(-) delete mode 100644 news/py10.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2824fd1..3e10213 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,14 @@ Release notes .. current developments +0.3.1 +===== + +**Added:** + +* Add back support for Python 3.10 and 3.11. + + 0.3.0 ===== diff --git a/news/py10.rst b/news/py10.rst deleted file mode 100644 index b41da42..0000000 --- a/news/py10.rst +++ /dev/null @@ -1,23 +0,0 @@ -**Added:** - -* Add back support for Python 3.10 and 3.11. - -**Changed:** - -* - -**Deprecated:** - -* - -**Removed:** - -* - -**Fixed:** - -* - -**Security:** - -* From 238da5775bcfd3b39bd245aa1bec8399dd0de2a1 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 23 Mar 2026 15:30:01 -0400 Subject: [PATCH 64/77] checkpoint commit --- src/diffpy/labpdfproc/labpdfprocapp.py | 37 +++++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index e5dd808..118f098 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -132,9 +132,6 @@ def _add_credit_args(parser, use_gui=False): def _save_corrected(corrected, input_path, args): outfile = args.output_directory / (input_path.stem + "_corrected.chi") - if outfile.exists() and not args.force: - print(f"WARNING: {outfile} exists. Use --force to overwrite.") - return corrected.metadata = corrected.metadata or {} corrected.dump(str(outfile), xtype=args.xtype) print(f"Saved corrected data to {outfile}") @@ -142,9 +139,6 @@ def _save_corrected(corrected, input_path, args): def _save_correction(correction, input_path, args): corrfile = args.output_directory / (input_path.stem + "_cve.chi") - if corrfile.exists() and not args.force: - print(f"WARNING: {corrfile} exists. Use --force to overwrite.") - return correction.metadata = correction.metadata or {} correction.dump(str(corrfile), xtype=args.xtype) print(f"Saved correction data to {corrfile}") @@ -310,9 +304,37 @@ def get_args_gui(): return parser.parse_args() +# def get_args_cli(override=None): +# parser = create_parser(use_gui=False) +# return parser.parse_args(override) + + def get_args_cli(override=None): parser = create_parser(use_gui=False) - return parser.parse_args(override) + argv = override if override is not None else sys.argv[1:] + argv = [arg for arg in argv if arg != "--ignore-gooey"] + return parser.parse_args(argv) + + +def _check_saved_file_exists(args): + """Check if the output files already exist based on the input paths + and output directory.""" + existing_files = [] + for path in args.input_paths: + outfile = args.output_directory / (path.stem + "_corrected.chi") + if outfile.exists() and not args.force: + existing_files.append(outfile) + if args.output_correction: + corrfile = args.output_directory / (path.stem + "_cve.chi") + if corrfile.exists() and not args.force: + existing_files.append(corrfile) + if existing_files: + existing_files_str = "\n".join(str(f) for f in existing_files) + raise FileExistsError( + "The following output files already exist:" + f"\n{existing_files_str}\n" + "Use --force to overwrite them." + ) def main(): @@ -320,6 +342,7 @@ def main(): args = get_args_gui() if use_gui else get_args_cli() args = _handle_old_api_conversion(args) args = preprocessing_args(args) + _check_saved_file_exists(args) apply_absorption_correction(args) From e53954c5974d3adfb4299e4a8086e195afc9fd9a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 10:30:45 -0400 Subject: [PATCH 65/77] rm pip install gooey from tests-on-pr.yml --- .github/workflows/tests-on-pr.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 6f96ab7..7dc796d 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -11,6 +11,5 @@ jobs: project: diffpy.labpdfproc c_extension: false headless: false - run: pip install gooey secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From b46fa7fb5cbfa3554742b99ef706eaec6949a3f0 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 10:32:47 -0400 Subject: [PATCH 66/77] add gooey dependency to conda.txt --- requirements/conda.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements/conda.txt b/requirements/conda.txt index 5aef5a8..e687e1c 100644 --- a/requirements/conda.txt +++ b/requirements/conda.txt @@ -3,3 +3,4 @@ diffpy.utils pandas scipy wxpython +gooey From 0c4e3edb17b85b7a1e3ffb2819e5a07280b57a7f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 10:33:40 -0400 Subject: [PATCH 67/77] news --- news/gooey-fix.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/gooey-fix.rst diff --git a/news/gooey-fix.rst b/news/gooey-fix.rst new file mode 100644 index 0000000..9f6ed45 --- /dev/null +++ b/news/gooey-fix.rst @@ -0,0 +1,23 @@ +**Added:** + +* No news needed: updates for new gooey. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 5d04ec260bb1198949083e50ba974dd7fe4ae9ac Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 11:51:56 -0400 Subject: [PATCH 68/77] drop 3.10 and 3.11 support --- pyproject.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4c359ba..b7ac149 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ maintainers = [ description = "Tools for processing x-ray powder diffraction data from laboratory sources." keywords = ['powder XRD', 'absorption correction', 'PDF', 'diffpy'] readme = "README.rst" -requires-python = ">=3.10, <3.15" +requires-python = ">=3.12, <3.15" classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', @@ -28,8 +28,6 @@ classifiers = [ 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Operating System :: Unix', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', From cd66cfc4ae275d8e4ad7726b3cf2d9b40a0186d5 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 11:55:03 -0400 Subject: [PATCH 69/77] rm note about gooey only being supported for python<3.12 --- docs/source/examples/labpdfprocapp-example.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/source/examples/labpdfprocapp-example.rst b/docs/source/examples/labpdfprocapp-example.rst index c33cadf..1b08a07 100644 --- a/docs/source/examples/labpdfprocapp-example.rst +++ b/docs/source/examples/labpdfprocapp-example.rst @@ -33,8 +33,6 @@ To launch the GUI, run one of the following commands in your terminal, labpdfproc labpdfproc --gui -.. note:: Note that the GUI is currently not supported on Python>=3.12. - This will open the GUI, which should look something like, .. image:: ../img/labpdfproc-gui.jpeg From 3ce0b2af435a1451c4438dfe6c7a0f0d71eff980 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 11:57:06 -0400 Subject: [PATCH 70/77] news pt2 --- news/gooey-fix.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/news/gooey-fix.rst b/news/gooey-fix.rst index 9f6ed45..988fd84 100644 --- a/news/gooey-fix.rst +++ b/news/gooey-fix.rst @@ -1,6 +1,6 @@ **Added:** -* No news needed: updates for new gooey. +* **Changed:** @@ -12,7 +12,7 @@ **Removed:** -* +* Removed support for Python 3.10 and 3.11. **Fixed:** From 75b02ba8264482c44598e89861e2ca2f574d971f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 12:19:51 -0400 Subject: [PATCH 71/77] checkpoint 2 --- tests/conftest.py | 4 ++++ tests/test_labpdfprocapp.py | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/test_labpdfprocapp.py diff --git a/tests/conftest.py b/tests/conftest.py index 63d4646..015b64b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -24,6 +24,10 @@ def user_filesystem(tmp_path): ) binary_data = b"\x00\x01\x02\x03\x04" + with open(base_dir / "data.chi", "w") as f: + f.write(chi_data) + with open(base_dir / "data_corrected.chi", "w") as f: + f.write(chi_data) with open(base_dir / "good_data.chi", "w") as f: f.write(chi_data) with open(base_dir / "good_data.xy", "w") as f: diff --git a/tests/test_labpdfprocapp.py b/tests/test_labpdfprocapp.py new file mode 100644 index 0000000..cecfc0d --- /dev/null +++ b/tests/test_labpdfprocapp.py @@ -0,0 +1,27 @@ +import pytest + +from diffpy.labpdfproc.labpdfprocapp import ( + apply_absorption_correction, + get_args_cli, +) + + +# Case: user tries to run absorption correction, but the output +# filename already exists. +# expected: the function should raise a FileExistsError, telling the +# user that the output +# file already exists and asking if they want to overwrite it. +def test_file_exists_error(user_filesystem): + input_data_file = str(user_filesystem / "data.chi") + existing_corrected_file = str(user_filesystem / "data_corrected.chi") + + cli_inputs = ["mud"] + [input_data_file] + ["2.5"] + args = get_args_cli(cli_inputs) + # assert args == [] + msg = ( + "The following output files already exist:" + f"\n{existing_corrected_file}\n" + "Use --force to overwrite them." + ) + with pytest.raises(FileExistsError, match=msg): + apply_absorption_correction(args) From b9be468a20967024a1b86a996ba4fb59b5b48ee5 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 15:08:43 -0400 Subject: [PATCH 72/77] add function that raises an error if output file(s) already exist, and add a test for this --- src/diffpy/labpdfproc/labpdfprocapp.py | 22 ------------------- src/diffpy/labpdfproc/tools.py | 27 ++++++++++++++++++++++++ tests/conftest.py | 11 +++++----- tests/test_labpdfprocapp.py | 27 ------------------------ tests/test_tools.py | 29 ++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 54 deletions(-) delete mode 100644 tests/test_labpdfprocapp.py diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index 118f098..34ab7b9 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -316,33 +316,11 @@ def get_args_cli(override=None): return parser.parse_args(argv) -def _check_saved_file_exists(args): - """Check if the output files already exist based on the input paths - and output directory.""" - existing_files = [] - for path in args.input_paths: - outfile = args.output_directory / (path.stem + "_corrected.chi") - if outfile.exists() and not args.force: - existing_files.append(outfile) - if args.output_correction: - corrfile = args.output_directory / (path.stem + "_cve.chi") - if corrfile.exists() and not args.force: - existing_files.append(corrfile) - if existing_files: - existing_files_str = "\n".join(str(f) for f in existing_files) - raise FileExistsError( - "The following output files already exist:" - f"\n{existing_files_str}\n" - "Use --force to overwrite them." - ) - - def main(): use_gui = len(sys.argv) == 1 or "--gui" in sys.argv args = get_args_gui() if use_gui else get_args_cli() args = _handle_old_api_conversion(args) args = preprocessing_args(args) - _check_saved_file_exists(args) apply_absorption_correction(args) diff --git a/src/diffpy/labpdfproc/tools.py b/src/diffpy/labpdfproc/tools.py index 2aa6754..4e35381 100644 --- a/src/diffpy/labpdfproc/tools.py +++ b/src/diffpy/labpdfproc/tools.py @@ -528,6 +528,27 @@ def load_package_info(args): return args +def _check_saved_file_exists(args): + """Check if the output files already exist based on the input paths + and output directory.""" + existing_files = [] + for path in args.input_paths: + outfile = args.output_directory / (path.stem + "_corrected.chi") + if outfile.exists() and not args.force: + existing_files.append(outfile) + if args.output_correction: + corrfile = args.output_directory / (path.stem + "_cve.chi") + if corrfile.exists() and not args.force: + existing_files.append(corrfile) + if existing_files: + existing_files_str = "\n".join(str(f) for f in existing_files) + raise FileExistsError( + "The following output files already exist:" + f"\n{existing_files_str}\n" + "Use --force to overwrite them." + ) + + def preprocessing_args(args): """Perform preprocessing on the provided args. The process includes loading package and user information, setting input, output, @@ -542,6 +563,11 @@ def preprocessing_args(args): ------- args : argparse.Namespace The updated argparse Namespace with arguments preprocessed. + + Raises + ------ + FileExistsError + If the output files already exist and --force is not used. """ args = load_wavelength_from_config_file(args) args = set_mud(args) @@ -552,6 +578,7 @@ def preprocessing_args(args): args = load_user_metadata(args) args = load_user_info(args) args = load_package_info(args) + _check_saved_file_exists(args) return args diff --git a/tests/conftest.py b/tests/conftest.py index 015b64b..d6eb523 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,7 +13,8 @@ def user_filesystem(tmp_path): home_dir.mkdir(parents=True, exist_ok=True) test_dir = base_dir / "test_dir" test_dir.mkdir(parents=True, exist_ok=True) - + output_dir = base_dir / "output_dir" + output_dir.mkdir(parents=True, exist_ok=True) chi_data = ( "dataformat = twotheta\n mode = " "xray\n # chi_Q chi_I\n 1 2\n 3 4\n 5 6\n 7 8\n" @@ -24,10 +25,6 @@ def user_filesystem(tmp_path): ) binary_data = b"\x00\x01\x02\x03\x04" - with open(base_dir / "data.chi", "w") as f: - f.write(chi_data) - with open(base_dir / "data_corrected.chi", "w") as f: - f.write(chi_data) with open(base_dir / "good_data.chi", "w") as f: f.write(chi_data) with open(base_dir / "good_data.xy", "w") as f: @@ -63,6 +60,10 @@ def user_filesystem(tmp_path): f.write("good_data.xy \n") f.write(f"{str(input_dir.resolve() / 'good_data.txt')}\n") + with open(output_dir / "good_data_corrected.chi", "w") as f: + f.write(chi_data) + with open(output_dir / "good_data_cve.chi", "w") as f: + f.write(chi_data) home_config_data = { "wavelength": 0.3, "owner_name": "home_username", diff --git a/tests/test_labpdfprocapp.py b/tests/test_labpdfprocapp.py deleted file mode 100644 index cecfc0d..0000000 --- a/tests/test_labpdfprocapp.py +++ /dev/null @@ -1,27 +0,0 @@ -import pytest - -from diffpy.labpdfproc.labpdfprocapp import ( - apply_absorption_correction, - get_args_cli, -) - - -# Case: user tries to run absorption correction, but the output -# filename already exists. -# expected: the function should raise a FileExistsError, telling the -# user that the output -# file already exists and asking if they want to overwrite it. -def test_file_exists_error(user_filesystem): - input_data_file = str(user_filesystem / "data.chi") - existing_corrected_file = str(user_filesystem / "data_corrected.chi") - - cli_inputs = ["mud"] + [input_data_file] + ["2.5"] - args = get_args_cli(cli_inputs) - # assert args == [] - msg = ( - "The following output files already exist:" - f"\n{existing_corrected_file}\n" - "Use --force to overwrite them." - ) - with pytest.raises(FileExistsError, match=msg): - apply_absorption_correction(args) diff --git a/tests/test_tools.py b/tests/test_tools.py index e7a137e..3307eba 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -847,3 +847,32 @@ def test_load_metadata(mocker, user_filesystem, inputs, expected): **expected, } assert actual_metadata == expected_metadata + + +def test_preprocess_args_bad(user_filesystem): + # Case: user tries to run absorption correction, but the output + # filenames already for *_corrected.chi and *_cve.chi exists. + # expected: preprocess_args catches this early and raises an Error + input_data_file = str(user_filesystem / "good_data.chi") + existing_corrected_file = str( + user_filesystem / "output_dir" / "good_data_corrected.chi" + ) + existing_corrected_cve_file = str( + user_filesystem / "output_dir" / "good_data_cve.chi" + ) + cli_inputs = ( + ["mud"] + + [input_data_file] + + ["2.5", "-w", "Mo", "-o", str(user_filesystem / "output_dir")] + + ["-c"] # -c flag saves the cve file + ) + args = get_args_cli(cli_inputs) + args = set_input_lists(args) + msg = ( + "The following output files already exist:" + f"\n{existing_corrected_file}\n" + f"{existing_corrected_cve_file}\n" + "Use --force to overwrite them." + ) + with pytest.raises(FileExistsError, match=re.escape(msg)): + preprocessing_args(args) From cc422c7baa7da8d687447daff88b7f2ceb27393c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 15:09:45 -0400 Subject: [PATCH 73/77] rm unnecessary comment --- src/diffpy/labpdfproc/labpdfprocapp.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index 34ab7b9..37e92ab 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -304,11 +304,6 @@ def get_args_gui(): return parser.parse_args() -# def get_args_cli(override=None): -# parser = create_parser(use_gui=False) -# return parser.parse_args(override) - - def get_args_cli(override=None): parser = create_parser(use_gui=False) argv = override if override is not None else sys.argv[1:] From fc68ff761956ced5cf93065c70e903bedc3a16eb Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 15:17:24 -0400 Subject: [PATCH 74/77] changed _corrected to -mud-corrected --- .../source/examples/labpdfprocapp-example.rst | 2 +- news/check-saved-files.rst | 23 +++++++++++++++++++ src/diffpy/labpdfproc/labpdfprocapp.py | 2 +- src/diffpy/labpdfproc/tools.py | 2 +- tests/conftest.py | 2 +- tests/test_tools.py | 4 ++-- 6 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 news/check-saved-files.rst diff --git a/docs/source/examples/labpdfprocapp-example.rst b/docs/source/examples/labpdfprocapp-example.rst index c33cadf..cc9b79d 100644 --- a/docs/source/examples/labpdfprocapp-example.rst +++ b/docs/source/examples/labpdfprocapp-example.rst @@ -79,7 +79,7 @@ For example, labpdfproc mud zro2_mo.xy 2.5 -w 0.71303 labpdfproc mud zro2_mo.xy 2.5 -w Mo -This will then save the corrected file in the same directory as the input file with the name ``zro2_mo_corrected.chi``. +This will then save the corrected file in the same directory as the input file with the name ``zro2_mo-mud-corrected.chi``. To save the correction file, specify the ``-c`` or ``--output-correction`` flag, diff --git a/news/check-saved-files.rst b/news/check-saved-files.rst new file mode 100644 index 0000000..699c696 --- /dev/null +++ b/news/check-saved-files.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* Changed output file behavior to raise an error early if the saved file exists. + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index 37e92ab..c8c9829 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -131,7 +131,7 @@ def _add_credit_args(parser, use_gui=False): def _save_corrected(corrected, input_path, args): - outfile = args.output_directory / (input_path.stem + "_corrected.chi") + outfile = args.output_directory / (input_path.stem + "-mud-corrected.chi") corrected.metadata = corrected.metadata or {} corrected.dump(str(outfile), xtype=args.xtype) print(f"Saved corrected data to {outfile}") diff --git a/src/diffpy/labpdfproc/tools.py b/src/diffpy/labpdfproc/tools.py index 4e35381..2a0bfc7 100644 --- a/src/diffpy/labpdfproc/tools.py +++ b/src/diffpy/labpdfproc/tools.py @@ -533,7 +533,7 @@ def _check_saved_file_exists(args): and output directory.""" existing_files = [] for path in args.input_paths: - outfile = args.output_directory / (path.stem + "_corrected.chi") + outfile = args.output_directory / (path.stem + "-mud-corrected.chi") if outfile.exists() and not args.force: existing_files.append(outfile) if args.output_correction: diff --git a/tests/conftest.py b/tests/conftest.py index d6eb523..629020a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -60,7 +60,7 @@ def user_filesystem(tmp_path): f.write("good_data.xy \n") f.write(f"{str(input_dir.resolve() / 'good_data.txt')}\n") - with open(output_dir / "good_data_corrected.chi", "w") as f: + with open(output_dir / "good_data-mud-corrected.chi", "w") as f: f.write(chi_data) with open(output_dir / "good_data_cve.chi", "w") as f: f.write(chi_data) diff --git a/tests/test_tools.py b/tests/test_tools.py index 3307eba..9c818ab 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -851,11 +851,11 @@ def test_load_metadata(mocker, user_filesystem, inputs, expected): def test_preprocess_args_bad(user_filesystem): # Case: user tries to run absorption correction, but the output - # filenames already for *_corrected.chi and *_cve.chi exists. + # filenames already for *-mud-corrected.chi and *_cve.chi exists. # expected: preprocess_args catches this early and raises an Error input_data_file = str(user_filesystem / "good_data.chi") existing_corrected_file = str( - user_filesystem / "output_dir" / "good_data_corrected.chi" + user_filesystem / "output_dir" / "good_data-mud-corrected.chi" ) existing_corrected_cve_file = str( user_filesystem / "output_dir" / "good_data_cve.chi" From 9f10e112c202096b1d71011c107233379b448346 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Wed, 1 Apr 2026 15:18:03 -0400 Subject: [PATCH 75/77] news --- news/check-saved-files.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/news/check-saved-files.rst b/news/check-saved-files.rst index 699c696..519174e 100644 --- a/news/check-saved-files.rst +++ b/news/check-saved-files.rst @@ -5,6 +5,7 @@ **Changed:** * Changed output file behavior to raise an error early if the saved file exists. +* Changed saved file name from ``_corrected.chi`` to ``-mud-corrected.chi``. **Deprecated:** From ce7ca2d4b6f9c4cddf75773bf5009d13ffd59aa4 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 2 Apr 2026 11:50:25 -0400 Subject: [PATCH 76/77] set cwd in test so config file can be found --- .../source/examples/labpdfprocapp-example.rst | 6 ++--- news/check-saved-files.rst | 1 + src/diffpy/labpdfproc/labpdfprocapp.py | 2 +- src/diffpy/labpdfproc/tools.py | 2 +- tests/conftest.py | 2 +- tests/test_tools.py | 24 ++++++++++++------- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/docs/source/examples/labpdfprocapp-example.rst b/docs/source/examples/labpdfprocapp-example.rst index cc9b79d..249c5de 100644 --- a/docs/source/examples/labpdfprocapp-example.rst +++ b/docs/source/examples/labpdfprocapp-example.rst @@ -87,7 +87,7 @@ To save the correction file, specify the ``-c`` or ``--output-correction`` flag, labpdfproc mud zro2_mo.xy 2.5 -w 0.71303 -c -This will then save the correction file in the same directory as the input file with the name ``zro2_mo_cve.chi``. +This will then save the correction file in the same directory as the input file with the name ``zro2_mo-cve.chi``. ``labpdfproc zscan`` Command ---------------------------- @@ -125,7 +125,7 @@ To save the correction file, specify the ``-c`` or ``--output-correction`` flag, labpdfproc zscan CeO2_635um_accum_0.xy CeO2_635um_zscan.xy -w 0.71303 -c -This will then save the correction file in the same directory as the input file with the name ``CeO2_635um_accum_0_cve.chi``. +This will then save the correction file in the same directory as the input file with the name ``CeO2_635um_accum_0-cve.chi``. ``labpdfproc sample`` Command ----------------------------- @@ -165,7 +165,7 @@ To save the correction file, specify the ``-c`` or ``--output-correction`` flag, labpdfproc sample zro2_mo.xy ZrO2 17.45 1.2 -w 0.71303 -c -This will then save the correction file in the same directory as the input file with the name ``zro2_mo_cve.chi``. +This will then save the correction file in the same directory as the input file with the name ``zro2_mo-cve.chi``. Additional CLI options ---------------------- diff --git a/news/check-saved-files.rst b/news/check-saved-files.rst index 519174e..514ba98 100644 --- a/news/check-saved-files.rst +++ b/news/check-saved-files.rst @@ -6,6 +6,7 @@ * Changed output file behavior to raise an error early if the saved file exists. * Changed saved file name from ``_corrected.chi`` to ``-mud-corrected.chi``. +* Changed saved file name from ``_cve.chi`` to ``-cve.chi``. **Deprecated:** diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index c8c9829..f8ec7e7 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -138,7 +138,7 @@ def _save_corrected(corrected, input_path, args): def _save_correction(correction, input_path, args): - corrfile = args.output_directory / (input_path.stem + "_cve.chi") + corrfile = args.output_directory / (input_path.stem + "-cve.chi") correction.metadata = correction.metadata or {} correction.dump(str(corrfile), xtype=args.xtype) print(f"Saved correction data to {corrfile}") diff --git a/src/diffpy/labpdfproc/tools.py b/src/diffpy/labpdfproc/tools.py index 2a0bfc7..6945f20 100644 --- a/src/diffpy/labpdfproc/tools.py +++ b/src/diffpy/labpdfproc/tools.py @@ -537,7 +537,7 @@ def _check_saved_file_exists(args): if outfile.exists() and not args.force: existing_files.append(outfile) if args.output_correction: - corrfile = args.output_directory / (path.stem + "_cve.chi") + corrfile = args.output_directory / (path.stem + "-cve.chi") if corrfile.exists() and not args.force: existing_files.append(corrfile) if existing_files: diff --git a/tests/conftest.py b/tests/conftest.py index 629020a..cda2974 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -62,7 +62,7 @@ def user_filesystem(tmp_path): with open(output_dir / "good_data-mud-corrected.chi", "w") as f: f.write(chi_data) - with open(output_dir / "good_data_cve.chi", "w") as f: + with open(output_dir / "good_data-cve.chi", "w") as f: f.write(chi_data) home_config_data = { "wavelength": 0.3, diff --git a/tests/test_tools.py b/tests/test_tools.py index 9c818ab..9112699 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -849,23 +849,29 @@ def test_load_metadata(mocker, user_filesystem, inputs, expected): assert actual_metadata == expected_metadata -def test_preprocess_args_bad(user_filesystem): +def test_preprocess_args_bad(user_filesystem, monkeypatch): # Case: user tries to run absorption correction, but the output - # filenames already for *-mud-corrected.chi and *_cve.chi exists. + # filenames already for *-mud-corrected.chi and *-cve.chi exists. # expected: preprocess_args catches this early and raises an Error + cwd = Path(user_filesystem) + home_dir = cwd / "home_dir" + # set cwd so program can find diffpyconfig.json + monkeypatch.setattr("pathlib.Path.home", lambda _: home_dir) input_data_file = str(user_filesystem / "good_data.chi") existing_corrected_file = str( user_filesystem / "output_dir" / "good_data-mud-corrected.chi" ) existing_corrected_cve_file = str( - user_filesystem / "output_dir" / "good_data_cve.chi" - ) - cli_inputs = ( - ["mud"] - + [input_data_file] - + ["2.5", "-w", "Mo", "-o", str(user_filesystem / "output_dir")] - + ["-c"] # -c flag saves the cve file + user_filesystem / "output_dir" / "good_data-cve.chi" ) + cli_inputs = [ + "mud", + input_data_file, + "2.5", + "-o", + str(user_filesystem / "output_dir"), + "-c", # -c flag saves the cve file + ] args = get_args_cli(cli_inputs) args = set_input_lists(args) msg = ( From 5125fa96d018c06d8f0b9b78c396d5f5e57b0aa8 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 2 Apr 2026 11:52:02 -0400 Subject: [PATCH 77/77] use f-strings instead of + --- src/diffpy/labpdfproc/labpdfprocapp.py | 4 ++-- src/diffpy/labpdfproc/tools.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/diffpy/labpdfproc/labpdfprocapp.py b/src/diffpy/labpdfproc/labpdfprocapp.py index f8ec7e7..db7f873 100644 --- a/src/diffpy/labpdfproc/labpdfprocapp.py +++ b/src/diffpy/labpdfproc/labpdfprocapp.py @@ -131,14 +131,14 @@ def _add_credit_args(parser, use_gui=False): def _save_corrected(corrected, input_path, args): - outfile = args.output_directory / (input_path.stem + "-mud-corrected.chi") + outfile = args.output_directory / (f"{input_path.stem}-mud-corrected.chi") corrected.metadata = corrected.metadata or {} corrected.dump(str(outfile), xtype=args.xtype) print(f"Saved corrected data to {outfile}") def _save_correction(correction, input_path, args): - corrfile = args.output_directory / (input_path.stem + "-cve.chi") + corrfile = args.output_directory / (f"{input_path.stem}-cve.chi") correction.metadata = correction.metadata or {} correction.dump(str(corrfile), xtype=args.xtype) print(f"Saved correction data to {corrfile}") diff --git a/src/diffpy/labpdfproc/tools.py b/src/diffpy/labpdfproc/tools.py index 6945f20..305291e 100644 --- a/src/diffpy/labpdfproc/tools.py +++ b/src/diffpy/labpdfproc/tools.py @@ -533,11 +533,11 @@ def _check_saved_file_exists(args): and output directory.""" existing_files = [] for path in args.input_paths: - outfile = args.output_directory / (path.stem + "-mud-corrected.chi") + outfile = args.output_directory / (f"{path.stem}-mud-corrected.chi") if outfile.exists() and not args.force: existing_files.append(outfile) if args.output_correction: - corrfile = args.output_directory / (path.stem + "-cve.chi") + corrfile = args.output_directory / (f"{path.stem}-cve.chi") if corrfile.exists() and not args.force: existing_files.append(corrfile) if existing_files: